diff --git a/packages/core/src/objvalue.ts b/packages/core/src/objvalue.ts index c3661803b5..819e582f0e 100644 --- a/packages/core/src/objvalue.ts +++ b/packages/core/src/objvalue.ts @@ -1,4 +1,6 @@ +import { PlatformError, Severity, Status } from '@hcengineering/platform' import { Doc } from './classes' +import core from './component' /** * @public @@ -27,6 +29,40 @@ export function getObjectValue (key: string, doc: Doc): any { return value } +/** + * @public + */ +export function setObjectValue (key: string, doc: Doc, newValue: any): void { + // Check dot notation + if (key.length === 0) { + return + } + key = key.split('\\$').join('$') + let dots = key.split('.') + // Replace escapting, since memdb is not escape keys + + const last = dots[dots.length - 1] + dots = dots.slice(0, -1) + + // We have dots, so iterate in depth + let value = doc as any + for (const d of dots) { + if (Array.isArray(value) && isNestedArrayQuery(value, d)) { + // Arrays are not supported + throw new PlatformError(new Status(Severity.ERROR, core.status.ObjectNotFound, { _id: 'dots' })) + } + const lvalue = value?.[d] + if (lvalue === undefined) { + value[d] = {} + value = value?.[d] + } else { + value = lvalue + } + } + value[last] = newValue + return value +} + function isNestedArrayQuery (value: any, d: string): boolean { return Number.isNaN(Number.parseInt(d)) && value?.[d as any] === undefined } diff --git a/packages/core/src/tx.ts b/packages/core/src/tx.ts index f1de061f62..ad107fb182 100644 --- a/packages/core/src/tx.ts +++ b/packages/core/src/tx.ts @@ -16,6 +16,7 @@ import type { KeysByType } from 'simplytyped' import type { Account, Arr, AttachedDoc, Class, Data, Doc, Domain, Mixin, PropertyType, Ref, Space } from './classes' import core from './component' +import { setObjectValue } from './objvalue' import { _getOperator } from './operator' import { _toDoc } from './proxy' import type { DocumentQuery, TxResult } from './storage' @@ -295,7 +296,7 @@ export abstract class TxProcessor implements WithTx { const operator = _getOperator(key) operator(doc, ops[key]) } else { - ;(doc as any)[key] = ops[key] + setObjectValue(key, doc, ops[key]) } } doc.modifiedBy = tx.modifiedBy @@ -312,7 +313,7 @@ export abstract class TxProcessor implements WithTx { const operator = _getOperator(key) operator(mixin, ops[key]) } else { - mixin[key] = ops[key] + setObjectValue(key, mixin, ops[key]) } } rawDoc.modifiedBy = tx.modifiedBy diff --git a/packages/presentation/src/components/AttributeBarEditor.svelte b/packages/presentation/src/components/AttributeBarEditor.svelte index ff12dcd193..b04a4f6fdd 100644 --- a/packages/presentation/src/components/AttributeBarEditor.svelte +++ b/packages/presentation/src/components/AttributeBarEditor.svelte @@ -18,20 +18,24 @@ import { getResource } from '@hcengineering/platform' import { AnySvelteComponent, Label, tooltip } from '@hcengineering/ui' import view from '@hcengineering/view' + import { createEventDispatcher } from 'svelte' import { getAttribute, KeyedAttribute, updateAttribute } from '../attributes' import { AttributeCategory, getAttributePresenterClass, getClient } from '../utils' export let key: KeyedAttribute | string - export let object: Doc + export let object: Doc | Record export let _class: Ref> export let maxWidth: string | undefined = undefined export let focus: boolean = false export let showHeader: boolean = true export let readonly = false + export let draft = false const client = getClient() const hierarchy = client.getHierarchy() + const dispatch = createEventDispatcher() + $: attribute = typeof key === 'string' ? hierarchy.getAttribute(_class, key) : key.attr $: attributeKey = typeof key === 'string' ? key : key.key $: presenterClass = attribute !== undefined ? getAttributePresenterClass(hierarchy, attribute) : undefined @@ -67,7 +71,12 @@ function onChange (value: any) { const doc = object as Doc - updateAttribute(client, doc, _class, { key: attributeKey, attr: attribute }, value) + if (draft) { + ;(doc as any)[attributeKey] = value + dispatch('update', { key, value }) + } else { + updateAttribute(client, doc, _class, { key: attributeKey, attr: attribute }, value) + } } $: isReadonly = (attribute.readonly ?? false) || readonly diff --git a/packages/presentation/src/components/AttributesBar.svelte b/packages/presentation/src/components/AttributesBar.svelte index d6220403e6..74ad1855b2 100644 --- a/packages/presentation/src/components/AttributesBar.svelte +++ b/packages/presentation/src/components/AttributesBar.svelte @@ -18,16 +18,17 @@ import { KeyedAttribute } from '../attributes' import AttributeBarEditor from './AttributeBarEditor.svelte' - export let object: Doc + export let object: Doc | Record export let _class: Ref> export let keys: (string | KeyedAttribute)[] export let showHeader: boolean = true export let readonly = false + export let draft = false
{#each keys as key (typeof key === 'string' ? key : key.key)} - + {/each}
diff --git a/plugins/view-resources/src/components/ClassAttributeBar.svelte b/plugins/view-resources/src/components/ClassAttributeBar.svelte index 7332cfaa25..58f8c07807 100644 --- a/plugins/view-resources/src/components/ClassAttributeBar.svelte +++ b/plugins/view-resources/src/components/ClassAttributeBar.svelte @@ -20,7 +20,7 @@ import { Button, getCurrentLocation, Label, navigate } from '@hcengineering/ui' import { getFiltredKeys, isCollectionAttr } from '../utils' - export let object: Doc + export let object: Doc | Record export let _class: Ref> export let to: Ref> | undefined = core.class.Doc export let ignoreKeys: string[] = [] @@ -28,6 +28,7 @@ export let readonly = false export let showLabel: IntlString | undefined = undefined export let defaultCollapsed = false + export let draft = false const client = getClient() const hierarchy = client.getHierarchy() @@ -84,7 +85,7 @@ {#if keys.length}
- p.key)} {readonly} /> + p.key)} {readonly} {draft} on:update />
{/if} diff --git a/plugins/view-resources/src/index.ts b/plugins/view-resources/src/index.ts index 8693f2562a..b594a34236 100644 --- a/plugins/view-resources/src/index.ts +++ b/plugins/view-resources/src/index.ts @@ -93,7 +93,9 @@ export { getObjectPresenter, LoadingProps, setActiveViewletId, - getActiveViewletId + getActiveViewletId, + getFiltredKeys, + isCollectionAttr } from './utils' export { HTMLPresenter,