From f7e220d0f22a5705a4d514ceab75e4505f6b8d68 Mon Sep 17 00:00:00 2001 From: Denis Bykhov Date: Tue, 31 Jan 2023 23:18:07 +0600 Subject: [PATCH] Filters improve (#2572) Signed-off-by: Denis Bykhov --- models/contact/src/index.ts | 2 + models/core/src/core.ts | 6 + models/recruit/src/index.ts | 5 +- models/task/src/index.ts | 1 + models/view/src/index.ts | 2 +- models/view/src/plugin.ts | 3 +- packages/core/src/component.ts | 3 +- packages/core/src/hierarchy.ts | 28 +++++ packages/core/src/lang/en.json | 3 +- packages/core/src/lang/ru.json | 3 +- .../ui/src/components/ToggleButton.svelte | 17 ++- .../src/components/Contacts.svelte | 13 +- .../src/components/Vacancies.svelte | 11 +- .../src/components/EditDoc.svelte | 19 +-- .../src/components/EnumEditor.svelte | 2 +- .../src/components/SpaceRefPresenter.svelte | 22 ++++ .../src/components/ViewletSetting.svelte | 105 +++++++++++++--- .../components/filter/FilterTypePopup.svelte | 112 +++++++++++------- plugins/view-resources/src/index.ts | 4 +- 19 files changed, 263 insertions(+), 98 deletions(-) create mode 100644 plugins/view-resources/src/components/SpaceRefPresenter.svelte diff --git a/models/contact/src/index.ts b/models/contact/src/index.ts index 3647e96e0f..54f45495b3 100644 --- a/models/contact/src/index.ts +++ b/models/contact/src/index.ts @@ -35,6 +35,7 @@ import { DOMAIN_MODEL, IndexKind } from '@hcengineering/core' import { Builder, Collection, + Hidden, Index, Model, Prop, @@ -76,6 +77,7 @@ export class TChannelProvider extends TDoc implements ChannelProvider { export class TContact extends TDoc implements Contact { @Prop(TypeString(), contact.string.Name) @Index(IndexKind.FullText) + @Hidden() name!: string avatar?: string | null diff --git a/models/core/src/core.ts b/models/core/src/core.ts index e4c4fb4797..dc758576c9 100644 --- a/models/core/src/core.ts +++ b/models/core/src/core.ts @@ -70,17 +70,21 @@ import core from './component' export class TObj implements Obj { @Prop(TypeRef(core.class.Class), core.string.ClassLabel) @Index(IndexKind.Indexed) + @Hidden() _class!: Ref> } @Model(core.class.Doc, core.class.Obj) +@UX(core.string.Object) export class TDoc extends TObj implements Doc { @Prop(TypeRef(core.class.Doc), core.string.Id) + @Hidden() // @Index(IndexKind.Indexed) // - automatically indexed by default. _id!: Ref @Prop(TypeRef(core.class.Space), core.string.Space) @Index(IndexKind.Indexed) + @Hidden() space!: Ref @Prop(TypeTimestamp(), core.string.Modified) @@ -94,10 +98,12 @@ export class TDoc extends TObj implements Doc { export class TAttachedDoc extends TDoc implements AttachedDoc { @Prop(TypeRef(core.class.Doc), core.string.AttachedTo) @Index(IndexKind.Indexed) + @Hidden() attachedTo!: Ref @Prop(TypeRef(core.class.Class), core.string.AttachedToClass) @Index(IndexKind.Indexed) + @Hidden() attachedToClass!: Ref> @Prop(TypeString(), core.string.Collection) diff --git a/models/recruit/src/index.ts b/models/recruit/src/index.ts index f57dfd0a8f..97271698e6 100644 --- a/models/recruit/src/index.ts +++ b/models/recruit/src/index.ts @@ -16,7 +16,6 @@ import type { Employee, Organization } from '@hcengineering/contact' import { Doc, FindOptions, IndexKind, Lookup, Ref, Timestamp } from '@hcengineering/core' import { - ArrOf, Builder, Collection, Index, @@ -125,7 +124,7 @@ export class TCandidate extends TPerson implements Candidate { @Mixin(recruit.mixin.VacancyList, contact.class.Organization) @UX(recruit.string.VacancyList, recruit.icon.RecruitApplication, undefined, 'name') export class TVacancyList extends TOrganization implements VacancyList { - @Prop(ArrOf(TypeRef(recruit.class.Vacancy)), recruit.string.Vacancies) + @Prop(Collection(recruit.class.Vacancy), recruit.string.Vacancies) vacancies!: number } @@ -192,7 +191,7 @@ export function createModel (builder: Builder): void { editor: recruit.component.Applications }) - builder.mixin(recruit.class.Vacancy, core.class.Class, view.mixin.ArrayEditor, { + builder.mixin(recruit.class.Vacancy, core.class.Class, view.mixin.CollectionEditor, { editor: recruit.component.VacancyList }) diff --git a/models/task/src/index.ts b/models/task/src/index.ts index bccc03b700..3bb2e2acf7 100644 --- a/models/task/src/index.ts +++ b/models/task/src/index.ts @@ -121,6 +121,7 @@ export class TTask extends TAttachedDoc implements Task { @Prop(TypeString(), task.string.TaskNumber) @Index(IndexKind.FullText) + @Hidden() number!: number // @Prop(TypeRef(contact.class.Employee), task.string.TaskAssignee) diff --git a/models/view/src/index.ts b/models/view/src/index.ts index 45c0339ac1..5778485794 100644 --- a/models/view/src/index.ts +++ b/models/view/src/index.ts @@ -512,7 +512,7 @@ export function createModel (builder: Builder): void { ) builder.mixin(core.class.Space, core.class.Class, view.mixin.AttributePresenter, { - presenter: view.component.SpacePresenter + presenter: view.component.SpaceRefPresenter }) // Selection stuff diff --git a/models/view/src/plugin.ts b/models/view/src/plugin.ts index 39587b70e2..afc7f13e10 100644 --- a/models/view/src/plugin.ts +++ b/models/view/src/plugin.ts @@ -64,7 +64,8 @@ export default mergeIds(viewId, view, { MarkupEditor: '' as AnyComponent, MarkupEditorPopup: '' as AnyComponent, ListView: '' as AnyComponent, - IndexedDocumentPreview: '' as AnyComponent + IndexedDocumentPreview: '' as AnyComponent, + SpaceRefPresenter: '' as AnyComponent }, string: { Table: '' as IntlString, diff --git a/packages/core/src/component.ts b/packages/core/src/component.ts index 58e6fdd4eb..33c05ea747 100644 --- a/packages/core/src/component.ts +++ b/packages/core/src/component.ts @@ -150,6 +150,7 @@ export default plugin(coreId, { Name: '' as IntlString, Enum: '' as IntlString, Description: '' as IntlString, - Hyperlink: '' as IntlString + Hyperlink: '' as IntlString, + Object: '' as IntlString } }) diff --git a/packages/core/src/hierarchy.ts b/packages/core/src/hierarchy.ts index 0c17e6031f..529fad17a7 100644 --- a/packages/core/src/hierarchy.ts +++ b/packages/core/src/hierarchy.ts @@ -394,6 +394,34 @@ export class Hierarchy { return result } + getOwnAttributes (clazz: Ref): Map { + const result = new Map() + + const attributes = this.attributes.get(clazz) + if (attributes !== undefined) { + for (const [name, attr] of attributes) { + result.set(name, attr) + } + } + + return result + } + + getParentClass (_class: Ref>): Ref> { + const baseDomain = this.getDomain(_class) + const ancestors = this.getAncestors(_class) + let result: Ref> = _class + for (const ancestor of ancestors) { + try { + const domain = this.getClass(ancestor).domain + if (domain === baseDomain) { + result = ancestor + } + } catch {} + } + return result + } + getAttribute (classifier: Ref, name: string): AnyAttribute { const attr = this.findAttribute(classifier, name) if (attr === undefined) { diff --git a/packages/core/src/lang/en.json b/packages/core/src/lang/en.json index 5f481c80ce..f7f85fcdeb 100644 --- a/packages/core/src/lang/en.json +++ b/packages/core/src/lang/en.json @@ -25,6 +25,7 @@ "Array": "Array", "Enum": "Enum", "Members": "Members", - "Hyperlink": "URL" + "Hyperlink": "URL", + "Object": "Object" } } diff --git a/packages/core/src/lang/ru.json b/packages/core/src/lang/ru.json index 3f8d12a9fb..1598695b70 100644 --- a/packages/core/src/lang/ru.json +++ b/packages/core/src/lang/ru.json @@ -25,6 +25,7 @@ "Array": "Массив", "Enum": "Справочник", "Members": "Участники", - "Hyperlink": "URL" + "Hyperlink": "URL", + "Object": "Объект" } } diff --git a/packages/ui/src/components/ToggleButton.svelte b/packages/ui/src/components/ToggleButton.svelte index 756654a64b..9d9dd1fe3c 100644 --- a/packages/ui/src/components/ToggleButton.svelte +++ b/packages/ui/src/components/ToggleButton.svelte @@ -148,18 +148,9 @@ transition-duration: 0.15s; .btn-icon { - color: var(--content-color); transition: color 0.15s; pointer-events: none; } - &:hover { - color: var(--accent-color); - transition-duration: 0; - - .btn-icon { - color: var(--caption-color); - } - } &.disabled { color: rgb(var(--caption-color) / 40%); @@ -167,6 +158,14 @@ opacity: 0.5; } } + &:hover { + color: var(--caption-color); + transition-duration: 0; + + .btn-icon { + color: var(--caption-color); + } + } &.jf-left { justify-content: flex-start; diff --git a/plugins/contact-resources/src/components/Contacts.svelte b/plugins/contact-resources/src/components/Contacts.svelte index c972bf4568..47c90244f0 100644 --- a/plugins/contact-resources/src/components/Contacts.svelte +++ b/plugins/contact-resources/src/components/Contacts.svelte @@ -20,6 +20,7 @@ import view, { Viewlet, ViewletPreference } from '@hcengineering/view' import { ActionContext, + FilterBar, FilterButton, getViewOptions, setActiveViewletId, @@ -31,10 +32,11 @@ import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui' let search = '' - let resultQuery: DocumentQuery = {} + let searchQuery: DocumentQuery = {} + let resultQuery: DocumentQuery = searchQuery function updateResultQuery (search: string): void { - resultQuery = search === '' ? {} : { $search: search } + searchQuery = search === '' ? {} : { $search: search } } let viewlet: Viewlet | undefined @@ -109,6 +111,13 @@ + (resultQuery = e.detail)} + /> + {#if viewlet} {#if loading} diff --git a/plugins/recruit-resources/src/components/Vacancies.svelte b/plugins/recruit-resources/src/components/Vacancies.svelte index 23bc4bab08..19529fc07a 100644 --- a/plugins/recruit-resources/src/components/Vacancies.svelte +++ b/plugins/recruit-resources/src/components/Vacancies.svelte @@ -19,6 +19,7 @@ import { Button, Icon, IconAdd, Label, Loading, SearchEdit, showPopup } from '@hcengineering/ui' import view, { BuildModelKey, Viewlet, ViewletPreference } from '@hcengineering/view' import { + FilterBar, FilterButton, getViewOptions, setActiveViewletId, @@ -30,9 +31,10 @@ import { deviceOptionsStore as deviceInfo } from '@hcengineering/ui' let search: string = '' + let searchQuery: DocumentQuery = {} let resultQuery: DocumentQuery = {} - $: resultQuery = search === '' ? {} : { $search: search } + $: searchQuery = search === '' ? {} : { $search: search } type ApplicationInfo = { count: number; modifiedOn: number } let applications: Map, ApplicationInfo> = new Map, ApplicationInfo>() @@ -169,6 +171,13 @@ + (resultQuery = e.detail)} +/> + {#if descr} {#if loading} diff --git a/plugins/view-resources/src/components/EditDoc.svelte b/plugins/view-resources/src/components/EditDoc.svelte index bbef43a14e..77bef7f2e4 100644 --- a/plugins/view-resources/src/components/EditDoc.svelte +++ b/plugins/view-resources/src/components/EditDoc.svelte @@ -123,8 +123,8 @@ } } const filtredKeys = Array.from(keysMap.values()) - const { attributes, collections } = categorizeFields(hierarchy, filtredKeys, collectionArrays, allowedCollections) + keys = attributes.map((it) => it.key) const editors: { key: KeyedAttribute; editor: AnyComponent; category: AttributeCategory }[] = [] @@ -171,7 +171,7 @@ $: getEditorOrDefault(realObjectClass, showAllMixins, _id) function getEditorOrDefault (_class: Ref>, showAllMixins: boolean, _id: Ref): void { - parentClass = getParentClass(_class) + parentClass = hierarchy.getParentClass(_class) mainEditor = getEditor(_class) updateKeys(showAllMixins) } @@ -210,21 +210,6 @@ $: icon = getIcon(realObjectClass) - function getParentClass (_class: Ref>): Ref> { - const baseDomain = hierarchy.getDomain(_class) - const ancestors = hierarchy.getAncestors(_class) - let result: Ref> = _class - for (const ancestor of ancestors) { - try { - const domain = hierarchy.getClass(ancestor).domain - if (domain === baseDomain) { - result = ancestor - } - } catch {} - } - return result - } - let title: string = '' $: if (object !== undefined) { diff --git a/plugins/view-resources/src/components/EnumEditor.svelte b/plugins/view-resources/src/components/EnumEditor.svelte index edd9f242d2..8f754e031e 100644 --- a/plugins/view-resources/src/components/EnumEditor.svelte +++ b/plugins/view-resources/src/components/EnumEditor.svelte @@ -34,7 +34,7 @@ _id: type.of }, (res) => { - items = res[0].enumValues.map((p) => { + items = res[0]?.enumValues?.map((p) => { return { id: p, label: p } }) }, diff --git a/plugins/view-resources/src/components/SpaceRefPresenter.svelte b/plugins/view-resources/src/components/SpaceRefPresenter.svelte new file mode 100644 index 0000000000..45ef4417a9 --- /dev/null +++ b/plugins/view-resources/src/components/SpaceRefPresenter.svelte @@ -0,0 +1,22 @@ + + + + diff --git a/plugins/view-resources/src/components/ViewletSetting.svelte b/plugins/view-resources/src/components/ViewletSetting.svelte index 3205796684..f5bb7d9aa0 100644 --- a/plugins/view-resources/src/components/ViewletSetting.svelte +++ b/plugins/view-resources/src/components/ViewletSetting.svelte @@ -14,10 +14,17 @@ -->
- {#each attributes as attribute, i} + {#each enabled as attribute, i}
- + +
+ {/each} +
+
+ {#each Array.from(classes.keys()) as _class} +
+
{/each}
diff --git a/plugins/view-resources/src/components/filter/FilterTypePopup.svelte b/plugins/view-resources/src/components/filter/FilterTypePopup.svelte index 3b97f361ea..1c8f1cd053 100644 --- a/plugins/view-resources/src/components/filter/FilterTypePopup.svelte +++ b/plugins/view-resources/src/components/filter/FilterTypePopup.svelte @@ -22,11 +22,20 @@ Doc, Ref, RefTo, - Type, - Space + Space, + Type } from '@hcengineering/core' import { getClient } from '@hcengineering/presentation' - import { closePopup, closeTooltip, Icon, Label, showPopup, Submenu, resizeObserver } from '@hcengineering/ui' + import { + closePopup, + closeTooltip, + Icon, + Label, + resizeObserver, + Scroller, + showPopup, + Submenu + } from '@hcengineering/ui' import { Filter, KeyFilter } from '@hcengineering/view' import { createEventDispatcher } from 'svelte' import { FilterQuery } from '../../filter' @@ -86,9 +95,6 @@ } function buildFilterForAttr (_class: Ref>, attribute: AnyAttribute, result: KeyFilter[]): void { - if (attribute.isCustom !== true) { - return - } if (attribute.label === undefined || attribute.hidden) { return } @@ -101,6 +107,7 @@ result.push(filter) } } + function buildFilterFor ( _class: Ref>, allAttributes: Map, @@ -118,7 +125,7 @@ const desc = hierarchy.getDescendants(_class) for (const d of desc) { - const extra = hierarchy.getAllAttributes(d, _class) + const extra = hierarchy.getOwnAttributes(d) for (const [k, v] of extra) { if (!allAttributes.has(k)) { allAttributes.set(k, v) @@ -127,6 +134,23 @@ } } + const ancestors = new Set(hierarchy.getAncestors(_class)) + const parent = hierarchy.getParentClass(_class) + const parentMixins = hierarchy + .getDescendants(parent) + .map((p) => hierarchy.getClass(p)) + .filter((p) => hierarchy.isMixin(p._id) && p.extends && ancestors.has(p.extends)) + + for (const d of parentMixins) { + const extra = hierarchy.getOwnAttributes(d._id) + for (const [k, v] of extra) { + if (!allAttributes.has(k)) { + allAttributes.set(k, v) + buildFilterForAttr(d._id, v, result) + } + } + } + return result } @@ -207,44 +231,42 @@
dispatch('changeContent')}> -
-
- {#each getTypes(_class) as type, i} - {#if filter === undefined && type.component === view.component.ObjectFilter && hasNested(type)} - keyDown(event, i)} - on:click={(event) => { - click(type) - }} - icon={type.icon} - label={type.label} - props={getNestedProps(type)} - options={{ component: view.component.FilterTypePopup }} - withHover - /> - {:else} - - - {/if} - {/each} -
-
+ + {#each getTypes(_class) as type, i} + {#if filter === undefined && type.component === view.component.ObjectFilter && hasNested(type)} + keyDown(event, i)} + on:click={(event) => { + click(type) + }} + icon={type.icon} + label={type.label} + props={getNestedProps(type)} + options={{ component: view.component.FilterTypePopup }} + withHover + /> + {:else} + + + {/if} + {/each} +