Contacts: Type Filter ()

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>

Co-authored-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Denis Bykhov 2022-05-24 23:40:37 +06:00 committed by GitHub
parent 51d29fbe12
commit 578283d78b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 68 additions and 27 deletions
models
contact/src
core/src
lead/src
recruit/src
view/src
packages/core/lang
plugins
view-resources/src
workbench-resources/src/components

View File

@ -68,6 +68,9 @@ export class TContact extends TDoc implements Contact {
@Prop(TypeString(), contact.string.Location)
@Index(IndexKind.FullText)
city!: string
@Prop(TypeRef(core.class.Class), core.string.ClassLabel)
declare _class: Ref<Class<this>>
}
@Model(contact.class.Channel, core.class.AttachedDoc, DOMAIN_CHANNEL)
@ -162,7 +165,7 @@ export function createModel (builder: Builder): void {
descriptor: view.viewlet.Table,
config: [
'',
{ key: '$lookup._class.label', label: contact.string.TypeLabel },
'$lookup._class',
'city',
'attachments',
'modifiedOn',
@ -291,7 +294,7 @@ export function createModel (builder: Builder): void {
})
builder.mixin(contact.class.Contact, core.class.Class, view.mixin.ClassFilters, {
filters: ['city', 'modifiedOn']
filters: ['_class', 'city', 'modifiedOn']
})
builder.createDoc(

View File

@ -21,6 +21,7 @@ export default mergeIds(coreId, core, {
Description: '' as IntlString,
Private: '' as IntlString,
Archived: '' as IntlString,
ClassLabel: '' as IntlString
ClassLabel: '' as IntlString,
ClassPropertyLabel: '' as IntlString
}
})

View File

@ -45,7 +45,7 @@ import core from './component'
// C O R E
@Model(core.class.Obj, core.class.Obj)
export class TObj implements Obj {
@Prop(TypeRef(core.class.Class), core.string.Class)
@Prop(TypeRef(core.class.Class), core.string.ClassLabel)
@Index(IndexKind.Indexed)
_class!: Ref<Class<this>>
}
@ -86,7 +86,7 @@ export class TAttachedDoc extends TDoc implements AttachedDoc {
export class TClass extends TDoc implements Class<Obj> {
kind!: ClassifierKind
@Prop(TypeIntlString(), core.string.ClassLabel)
@Prop(TypeIntlString(), core.string.ClassPropertyLabel)
label!: IntlString
extends!: Ref<Class<Obj>>

View File

@ -15,7 +15,7 @@
// To help typescript locate view plugin properly
import type { Employee } from '@anticrm/contact'
import { Doc, FindOptions, IndexKind, Ref } from '@anticrm/core'
import { Class, Doc, FindOptions, IndexKind, Ref } from '@anticrm/core'
import type { Customer, Funnel, Lead } from '@anticrm/lead'
import { Builder, Collection, Index, Mixin, Model, Prop, TypeRef, TypeString, UX } from '@anticrm/model'
import attachment from '@anticrm/model-attachment'
@ -60,6 +60,9 @@ export class TCustomer extends TContact implements Customer {
@Prop(TypeString(), core.string.Description)
@Index(IndexKind.FullText)
description!: string
@Prop(TypeRef(core.class.Class), core.string.ClassLabel)
declare _class: Ref<Class<this>>
}
export function createModel (builder: Builder): void {
@ -123,7 +126,7 @@ export function createModel (builder: Builder): void {
descriptor: view.viewlet.Table,
config: [
'',
{ key: '$lookup._class.label', label: contact.string.TypeLabel },
'$lookup._class',
{ key: 'leads', presenter: lead.component.LeadsPresenter, label: lead.string.Leads },
'modifiedOn',
'$lookup.channels'

View File

@ -452,11 +452,11 @@ export function createModel (builder: Builder): void {
})
builder.mixin(recruit.mixin.Candidate, core.class.Class, view.mixin.ClassFilters, {
filters: ['title', 'source', 'city', 'skills', 'modifiedOn', 'onsite', 'remote']
filters: ['_class', 'title', 'source', 'city', 'skills', 'modifiedOn', 'onsite', 'remote']
})
builder.mixin(recruit.class.Applicant, core.class.Class, view.mixin.ClassFilters, {
filters: ['attachedTo', 'assignee', 'modifiedOn']
filters: ['attachedTo', 'assignee', 'state', 'doneState', 'modifiedOn']
})
createReviewModel(builder)

View File

@ -275,6 +275,7 @@ export function createModel (builder: Builder): void {
classPresenter(builder, core.class.TypeTimestamp, view.component.TimestampPresenter)
classPresenter(builder, core.class.TypeDate, view.component.DatePresenter, view.component.DateEditor)
classPresenter(builder, core.class.Space, view.component.ObjectPresenter)
classPresenter(builder, core.class.Class, view.component.ClassPresenter)
builder.mixin(core.class.TypeString, core.class.Class, view.mixin.ObjectEditor, {
editor: view.component.StringTypeEditor

View File

@ -82,7 +82,8 @@ export default mergeIds(viewId, view, {
BooleanTypeEditor: '' as AnyComponent,
NumberTypeEditor: '' as AnyComponent,
DateTypeEditor: '' as AnyComponent,
RefEditor: '' as AnyComponent
RefEditor: '' as AnyComponent,
ClassPresenter: '' as AnyComponent
},
string: {
Table: '' as IntlString,

View File

@ -11,7 +11,8 @@
"Description": "Description",
"Private": "Private",
"Archived": "Archived",
"ClassLabel": "Label",
"ClassLabel": "Type",
"ClassPropertyLabel": "Label",
"String": "String",
"Markup": "Markup",
"Number": "Number",

View File

@ -12,6 +12,7 @@
"Private": "Личный",
"Archived": "Архивный",
"ClassLabel": "Тип",
"ClassPropertyLabel": "Название",
"String": "Строка",
"Markup": "Разметка",
"Number": "Число",

View File

@ -0,0 +1,22 @@
<!--
// Copyright © 2022 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
-->
<script lang="ts">
import type { Class, Doc } from '@anticrm/core'
import { Label } from '@anticrm/ui'
export let value: Class<Doc>
</script>
<Label label={value.label} />

View File

@ -78,7 +78,11 @@
let merged = false
for (const key in newValue) {
if (newQuery[filter.key.key][key] === undefined) {
newQuery[filter.key.key][key] = newValue[key]
if (key === '$in' && typeof newQuery[filter.key.key] === 'string') {
newQuery[filter.key.key] = { $in: newValue[key].filter((p: any) => p === newQuery[filter.key.key]) }
} else {
newQuery[filter.key.key][key] = newValue[key]
}
merged = true
continue
}

View File

@ -59,7 +59,8 @@
let values: (Doc | undefined | null)[] = []
let objectsPromise: Promise<FindResult<Doc>> | undefined
const targetClass = (hierarchy.getAttribute(_class, filter.key.key).type as RefTo<Doc>).to
const clazz = hierarchy.getClass(targetClass)
const targets = new Map<any, number>()
async function getValues (search: string): Promise<void> {
if (objectsPromise) {
@ -71,8 +72,7 @@
const value = getObjectValue(filter.key.key, object) ?? undefined
targets.set(value, (targets.get(value) ?? 0) + 1)
}
const targetClass = (hierarchy.getAttribute(_class, filter.key.key).type as RefTo<Doc>).to
const clazz = hierarchy.getClass(targetClass)
const resultQuery =
search !== '' && clazz.sortingKey
? {
@ -130,17 +130,19 @@
</script>
<div class="selectPopup">
<div class="header">
<input
bind:this={searchInput}
type="text"
bind:value={search}
on:change={() => {
getValues(search)
}}
placeholder={phTraslate}
/>
</div>
{#if clazz.sortingKey}
<div class="header">
<input
bind:this={searchInput}
type="text"
bind:value={search}
on:change={() => {
getValues(search)
}}
placeholder={phTraslate}
/>
</div>
{/if}
<div class="scroll">
<div class="box">
{#await promise then attribute}

View File

@ -49,6 +49,7 @@ import TableBrowser from './components/TableBrowser.svelte'
import ValueFilter from './components/filter/ValueFilter.svelte'
import ObjectFilter from './components/filter/ObjectFilter.svelte'
import TimestampFilter from './components/filter/TimestampFilter.svelte'
import ClassPresenter from './components/ClassPresenter.svelte'
export { getActions, invokeAction } from './actions'
export { default as ActionContext } from './components/ActionContext.svelte'
@ -76,6 +77,7 @@ export {
export default async (): Promise<Resources> => ({
actionImpl: actionImpl,
component: {
ClassPresenter,
ObjectFilter,
ValueFilter,
TimestampFilter,

View File

@ -32,7 +32,7 @@
{#if model}
<TableBrowser
_class={core.class.Space}
config={['', '$lookup._class.label', 'modifiedOn']}
config={['', '$lookup._class', 'modifiedOn']}
showNotification
baseMenuClass={core.class.Space}
query={{