diff --git a/models/contact/src/index.ts b/models/contact/src/index.ts index 51257cfc3b..f6ef3ea74f 100644 --- a/models/contact/src/index.ts +++ b/models/contact/src/index.ts @@ -229,6 +229,11 @@ export function createModel (builder: Builder): void { builder.mixin(contact.class.Member, core.class.Class, view.mixin.CollectionEditor, { editor: contact.component.Members }) + + builder.mixin(contact.class.Employee, core.class.Class, view.mixin.ArrayEditor, { + editor: contact.component.EmployeeArrayEditor + }) + builder.mixin(contact.class.Member, core.class.Class, view.mixin.AttributePresenter, { presenter: contact.component.MemberPresenter }) diff --git a/models/contact/src/plugin.ts b/models/contact/src/plugin.ts index 184539b09e..2cf207e832 100644 --- a/models/contact/src/plugin.ts +++ b/models/contact/src/plugin.ts @@ -38,7 +38,8 @@ export default mergeIds(contactId, contact, { PersonEditor: '' as AnyComponent, Members: '' as AnyComponent, MemberPresenter: '' as AnyComponent, - EditMember: '' as AnyComponent + EditMember: '' as AnyComponent, + EmployeeArrayEditor: '' as AnyComponent }, string: { Persons: '' as IntlString, diff --git a/models/recruit/src/migration.ts b/models/recruit/src/migration.ts index 6c2f663eaf..031b705d37 100644 --- a/models/recruit/src/migration.ts +++ b/models/recruit/src/migration.ts @@ -13,10 +13,9 @@ // limitations under the License. // -import core, { Class, Doc, DOMAIN_TX, Ref, Space, TxOperations } from '@anticrm/core' +import core, { Doc, Ref, Space, TxOperations } from '@anticrm/core' import { createOrUpdate, MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@anticrm/model' import { DOMAIN_CALENDAR } from '@anticrm/model-calendar' -import { DOMAIN_SPACE } from '@anticrm/model-core' import tags, { TagCategory } from '@anticrm/model-tags' import { createKanbanTemplate, createSequence } from '@anticrm/model-task' import { getCategories } from '@anticrm/skillset' @@ -35,19 +34,6 @@ export const recruitOperation: MigrateOperation = { space: recruit.space.Reviews } ) - const categories = await client.find(DOMAIN_SPACE, { - _class: 'recruit:class:ReviewCategory' as Ref> - }) - for (const cat of categories) { - await client.delete(DOMAIN_SPACE, cat._id) - } - - const catTx = await client.find(DOMAIN_TX, { - objectClass: 'recruit:class:ReviewCategory' as Ref> - }) - for (const cat of catTx) { - await client.delete(DOMAIN_TX, cat._id) - } }, async upgrade (client: MigrationUpgradeClient): Promise { const tx = new TxOperations(client, core.account.System) diff --git a/models/view/src/index.ts b/models/view/src/index.ts index 6400a44f00..a6a7d805ac 100644 --- a/models/view/src/index.ts +++ b/models/view/src/index.ts @@ -22,6 +22,7 @@ import type { AnyComponent } from '@anticrm/ui' import type { Action, ActionCategory, + ArrayEditor, AttributeEditor, AttributeFilter, AttributePresenter, @@ -114,6 +115,11 @@ export class TCollectionEditor extends TClass implements CollectionEditor { editor!: AnyComponent } +@Mixin(view.mixin.ArrayEditor, core.class.Class) +export class TArrayEditor extends TClass implements ArrayEditor { + editor!: AnyComponent +} + @Mixin(view.mixin.AttributePresenter, core.class.Class) export class TAttributePresenter extends TClass implements AttributePresenter { presenter!: AnyComponent @@ -274,7 +280,8 @@ export function createModel (builder: Builder): void { TTextPresenter, TIgnoreActions, TPreviewPresenter, - TLinkPresenter + TLinkPresenter, + TArrayEditor ) classPresenter( diff --git a/packages/core/src/tx.ts b/packages/core/src/tx.ts index 57605acc14..993f9155ba 100644 --- a/packages/core/src/tx.ts +++ b/packages/core/src/tx.ts @@ -103,7 +103,7 @@ export interface TxMixin extends TxCUD { * @public */ export type ArrayAsElement = { - [P in keyof T]: T[P] extends Arr ? X : never + [P in keyof T]: T[P] extends Arr ? X | PullArray : never } /** diff --git a/packages/presentation/src/attributes.ts b/packages/presentation/src/attributes.ts index e2bec5c272..82d7790fe9 100644 --- a/packages/presentation/src/attributes.ts +++ b/packages/presentation/src/attributes.ts @@ -1,4 +1,4 @@ -import { AnyAttribute, Class, Client, Doc, Ref, TxOperations } from '@anticrm/core' +import core, { AnyAttribute, Class, Client, Doc, Ref, TxOperations } from '@anticrm/core' /** * @public @@ -22,7 +22,21 @@ export async function updateAttribute ( if (client.getHierarchy().isMixin(attr.attributeOf)) { await client.updateMixin(doc._id, _class, doc.space, attr.attributeOf, { [attributeKey]: value }) } else { - await client.update(object, { [attributeKey]: value }) + if (client.getHierarchy().isDerived(attribute.attr.type._class, core.class.ArrOf)) { + const oldvalue: any[] = (object as any)[attributeKey] ?? [] + const val: any[] = value + const toPull = oldvalue.filter((it: any) => !val.includes(it)) + + const toPush = val.filter((it) => !oldvalue.includes(it)) + if (toPull.length > 0) { + await client.update(object, { $pull: { [attributeKey]: { $in: toPull } } }) + } + if (toPush.length > 0) { + await client.update(object, { $push: { [attributeKey]: { $each: toPush, $position: 0 } } }) + } + } else { + await client.update(object, { [attributeKey]: value }) + } } } diff --git a/packages/presentation/src/components/AttributeBarEditor.svelte b/packages/presentation/src/components/AttributeBarEditor.svelte index 385ddb02ec..46d20d205f 100644 --- a/packages/presentation/src/components/AttributeBarEditor.svelte +++ b/packages/presentation/src/components/AttributeBarEditor.svelte @@ -16,40 +16,47 @@ {#if editor} - {#await editor} - ... - {:then instance} - {#if attribute.icon} - {#if !vertical} -
- - {#if !minimize} -
- {#if showHeader} -
- {/if} -
- {:else} - {#if showHeader} - - {/if} + {#await editor then instance} + {#if showHeader} + +
- {/if} - {:else if showHeader} - {#if !vertical} -
- -
- -
-
- {:else} - -
- -
- {/if} +
{:else}
| undefined - $: if (typeClassId !== undefined) { - const typeClass = hierarchy.getClass(typeClassId) + $: if (presenterClass !== undefined) { + const typeClass = hierarchy.getClass(presenterClass.attrClass) const editorMixin = hierarchy.as(typeClass, view.mixin.AttributeEditor) editor = getResource(editorMixin.editor) } diff --git a/packages/presentation/src/components/AttributesBar.svelte b/packages/presentation/src/components/AttributesBar.svelte index 10250781b7..f5f7b0202a 100644 --- a/packages/presentation/src/components/AttributesBar.svelte +++ b/packages/presentation/src/components/AttributesBar.svelte @@ -22,18 +22,11 @@ export let _class: Ref> export let keys: (string | KeyedAttribute)[] export let showHeader: boolean = true - export let vertical: boolean = false -
+
{#each keys as key (typeof key === 'string' ? key : key.key)} - {#if !vertical} -
- -
- {:else} - - {/if} + {/each}
diff --git a/packages/presentation/src/components/UserBoxList.svelte b/packages/presentation/src/components/UserBoxList.svelte index d726c40ba9..6004fd71e7 100644 --- a/packages/presentation/src/components/UserBoxList.svelte +++ b/packages/presentation/src/components/UserBoxList.svelte @@ -55,9 +55,9 @@ selectedUsers: items }, evt.target as HTMLElement, - () => {}, + undefined, (result) => { - if (result !== undefined) { + if (result != null) { items = result dispatch('update', items) } diff --git a/packages/presentation/src/utils.ts b/packages/presentation/src/utils.ts index ae89796555..7eb987a350 100644 --- a/packages/presentation/src/utils.ts +++ b/packages/presentation/src/utils.ts @@ -26,6 +26,7 @@ import core, { FindOptions, FindResult, getCurrentAccount, + Hierarchy, Ref, RefTo, Tx, @@ -143,20 +144,28 @@ export async function getBlobURL (blob: Blob): Promise { }) } +export type AttributeCategory = 'attribute' | 'collection' | 'array' /** * @public */ -export function getAttributePresenterClass (attribute: AnyAttribute): Ref> { +export function getAttributePresenterClass ( + hierarchy: Hierarchy, + attribute: AnyAttribute +): { attrClass: Ref>, category: AttributeCategory } { let attrClass = attribute.type._class - if (attrClass === core.class.RefTo) { + let category: AttributeCategory = 'attribute' + if (hierarchy.isDerived(attrClass, core.class.RefTo)) { attrClass = (attribute.type as RefTo).to + category = 'attribute' } - if (attrClass === core.class.Collection) { + if (hierarchy.isDerived(attrClass, core.class.Collection)) { attrClass = (attribute.type as Collection).of + category = 'collection' } - if (attrClass === core.class.ArrOf) { + if (hierarchy.isDerived(attrClass, core.class.ArrOf)) { const of = (attribute.type as ArrOf).of attrClass = of._class === core.class.RefTo ? (of as RefTo).to : of._class + category = 'array' } - return attrClass + return { attrClass, category } } diff --git a/plugins/activity-resources/src/components/TxView.svelte b/plugins/activity-resources/src/components/TxView.svelte index 8a1036765d..0c3dad6117 100644 --- a/plugins/activity-resources/src/components/TxView.svelte +++ b/plugins/activity-resources/src/components/TxView.svelte @@ -20,6 +20,7 @@ import { Asset, getResource } from '@anticrm/platform' import { getClient } from '@anticrm/presentation' import { + Button, Component, Icon, IconEdit, @@ -28,8 +29,7 @@ Menu, ShowMore, showPopup, - TimeSince, - Button + TimeSince } from '@anticrm/ui' import type { AttributeModel } from '@anticrm/view' import { getActions } from '@anticrm/view-resources' @@ -116,7 +116,22 @@ return attr?.type._class === core.class.TypeMarkup } - $: hasMessageType = model.find((m) => isMessageType(m.attribute)) + async function updateMessageType (model: AttributeModel[], tx: DisplayTx): Promise { + for (const m of model) { + if (isMessageType(m.attribute)) { + return true + } + const val = await getValue(client, m, tx) + if (val.added.length > 1 || val.removed.length > 1) { + return true + } + } + return false + } + let hasMessageType = false + $: updateMessageType(model, tx).then((res) => { + hasMessageType = res + }) {#if (viewlet !== undefined && !((viewlet?.hideOnRemove ?? false) && tx.removed)) || model.length > 0} @@ -182,8 +197,11 @@