From 0be40e005e19c6527f3421ad4870be67b0390e10 Mon Sep 17 00:00:00 2001 From: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com> Date: Thu, 5 May 2022 20:50:28 +0600 Subject: [PATCH] Custom attributes (#1650) Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com> --- models/core/src/component.ts | 5 - models/core/src/core.ts | 15 ++- models/view/src/index.ts | 16 +++ models/view/src/plugin.ts | 6 +- packages/core/lang/en.json | 13 +- packages/core/lang/ru.json | 13 +- packages/core/src/classes.ts | 1 + packages/core/src/component.ts | 15 ++- packages/model/src/dsl.ts | 22 ++-- packages/platform/src/i18n.ts | 36 +++--- packages/platform/src/platform.ts | 12 ++ .../src/components/DropdownLabelsIntl.svelte | 2 +- .../src/components/utils.ts | 7 +- plugins/view-assets/lang/en.json | 6 +- plugins/view-assets/lang/ru.json | 6 +- plugins/view-resources/package.json | 1 + .../src/components/ClassAttributeBar.svelte | 61 +++++++++ .../src/components/CreateAttribute.svelte | 118 ++++++++++++++++++ .../src/components/DocAttributeBar.svelte | 33 +++++ .../src/components/EditDoc.svelte | 44 ++----- .../typeEditors/BooleanTypeEditor.svelte | 25 ++++ .../typeEditors/DateTypeEditor.svelte | 40 ++++++ .../typeEditors/NumberTypeEditor.svelte | 25 ++++ .../typeEditors/StringTypeEditor.svelte | 25 ++++ plugins/view-resources/src/index.ts | 10 ++ plugins/view-resources/src/plugin.ts | 6 +- plugins/view-resources/src/utils.ts | 32 +++++ plugins/view/src/index.ts | 1 + 28 files changed, 520 insertions(+), 76 deletions(-) create mode 100644 plugins/view-resources/src/components/ClassAttributeBar.svelte create mode 100644 plugins/view-resources/src/components/CreateAttribute.svelte create mode 100644 plugins/view-resources/src/components/DocAttributeBar.svelte create mode 100644 plugins/view-resources/src/components/typeEditors/BooleanTypeEditor.svelte create mode 100644 plugins/view-resources/src/components/typeEditors/DateTypeEditor.svelte create mode 100644 plugins/view-resources/src/components/typeEditors/NumberTypeEditor.svelte create mode 100644 plugins/view-resources/src/components/typeEditors/StringTypeEditor.svelte diff --git a/models/core/src/component.ts b/models/core/src/component.ts index e07a36310d..b114cb1d3a 100644 --- a/models/core/src/component.ts +++ b/models/core/src/component.ts @@ -13,16 +13,11 @@ // limitations under the License. // -import type { Class, Ref, Type } from '@anticrm/core' import core, { coreId } from '@anticrm/core' import { IntlString, mergeIds } from '@anticrm/platform' export default mergeIds(coreId, core, { - class: { - Type: '' as Ref>> - }, string: { - Name: '' as IntlString, Description: '' as IntlString, Private: '' as IntlString, Archived: '' as IntlString, diff --git a/models/core/src/core.ts b/models/core/src/core.ts index 880612a538..d0a8a0daf8 100644 --- a/models/core/src/core.ts +++ b/models/core/src/core.ts @@ -36,7 +36,7 @@ import { Type, Version } from '@anticrm/core' -import { Index, Model, Prop, TypeIntlString, TypeRef, TypeString, TypeTimestamp } from '@anticrm/model' +import { Index, Model, Prop, TypeIntlString, TypeRef, TypeString, TypeTimestamp, UX } from '@anticrm/model' import type { IntlString } from '@anticrm/platform' import core from './component' @@ -106,46 +106,57 @@ export class TAttribute extends TDoc implements AnyAttribute { name!: string type!: Type label!: IntlString + isCustom?: boolean } -@Model(core.class.Type, core.class.Obj) +@Model(core.class.Type, core.class.Obj, DOMAIN_MODEL) export class TType extends TObj implements Type { label!: IntlString } +@UX(core.string.String) @Model(core.class.TypeString, core.class.Type) export class TTypeString extends TType {} +@UX(core.string.IntlString) @Model(core.class.TypeIntlString, core.class.Type) export class TTypeIntlString extends TType {} +@UX(core.string.Number) @Model(core.class.TypeNumber, core.class.Type) export class TTypeNumber extends TType {} +@UX(core.string.Markup) @Model(core.class.TypeMarkup, core.class.Type) export class TTypeMarkup extends TType {} +@UX(core.string.Ref) @Model(core.class.RefTo, core.class.Type) export class TRefTo extends TType implements RefTo { to!: Ref> } +@UX(core.string.Collection) @Model(core.class.Collection, core.class.Type) export class TCollection extends TType implements Collection { of!: Ref> } +@UX(core.string.Array) @Model(core.class.ArrOf, core.class.Type) export class TArrOf extends TType implements ArrOf { of!: Type } +@UX(core.string.Boolean) @Model(core.class.TypeBoolean, core.class.Type) export class TTypeBoolean extends TType {} +@UX(core.string.Timestamp) @Model(core.class.TypeTimestamp, core.class.Type) export class TTypeTimestamp extends TType {} +@UX(core.string.Date) @Model(core.class.TypeDate, core.class.Type) export class TTypeDate extends TType {} diff --git a/models/view/src/index.ts b/models/view/src/index.ts index c67ead5f2d..dac42cbabe 100644 --- a/models/view/src/index.ts +++ b/models/view/src/index.ts @@ -236,6 +236,22 @@ export function createModel (builder: Builder): void { classPresenter(builder, core.class.TypeDate, view.component.DatePresenter, view.component.DateEditor) classPresenter(builder, core.class.Space, view.component.ObjectPresenter) + builder.mixin(core.class.TypeString, core.class.Class, view.mixin.ObjectEditor, { + editor: view.component.StringTypeEditor + }) + + builder.mixin(core.class.TypeBoolean, core.class.Class, view.mixin.ObjectEditor, { + editor: view.component.BooleanTypeEditor + }) + + builder.mixin(core.class.TypeDate, core.class.Class, view.mixin.ObjectEditor, { + editor: view.component.DateTypeEditor + }) + + builder.mixin(core.class.TypeNumber, core.class.Class, view.mixin.ObjectEditor, { + editor: view.component.NumberTypeEditor + }) + builder.createDoc( view.class.ActionCategory, core.space.Model, diff --git a/models/view/src/plugin.ts b/models/view/src/plugin.ts index 8b9c31bf50..340adcb963 100644 --- a/models/view/src/plugin.ts +++ b/models/view/src/plugin.ts @@ -73,7 +73,11 @@ export default mergeIds(viewId, view, { TableView: '' as AnyComponent, RolePresenter: '' as AnyComponent, YoutubePresenter: '' as AnyComponent, - GithubPresenter: '' as AnyComponent + GithubPresenter: '' as AnyComponent, + StringTypeEditor: '' as AnyComponent, + BooleanTypeEditor: '' as AnyComponent, + NumberTypeEditor: '' as AnyComponent, + DateTypeEditor: '' as AnyComponent }, string: { Table: '' as IntlString, diff --git a/packages/core/lang/en.json b/packages/core/lang/en.json index 01e9e4ea99..43e68eda4e 100644 --- a/packages/core/lang/en.json +++ b/packages/core/lang/en.json @@ -11,6 +11,17 @@ "Description": "Description", "Private": "Private", "Archived": "Archived", - "ClassLabel": "Label" + "ClassLabel": "Label", + "String": "String", + "Markup": "Markup", + "Number": "Number", + "Boolean": "Boolean", + "Timestamp": "Timestamp", + "Date": "Date", + "IntlString": "IntlString", + "Ref": "Ref", + "Collection": "Collection", + "Array": "Array", + "Bag": "Bag" } } diff --git a/packages/core/lang/ru.json b/packages/core/lang/ru.json index 9c4ddfafad..9ef3d6ccd7 100644 --- a/packages/core/lang/ru.json +++ b/packages/core/lang/ru.json @@ -11,6 +11,17 @@ "Description": "Описание", "Private": "Личный", "Archived": "Архивный", - "ClassLabel": "Тип" + "ClassLabel": "Тип", + "String": "Строка", + "Markup": "Разметка", + "Number": "Число", + "Boolean": "Логическое", + "Timestamp": "Времянная отметка", + "Date": "Дата", + "IntlString": "Интернационализированная строка", + "Ref": "Ссылка", + "Collection": "Коллекция", + "Array": "Массив", + "Bag": "Bag" } } \ No newline at end of file diff --git a/packages/core/src/classes.ts b/packages/core/src/classes.ts index a54f1e811b..dd8244a520 100644 --- a/packages/core/src/classes.ts +++ b/packages/core/src/classes.ts @@ -98,6 +98,7 @@ export interface Attribute extends Doc, UXObject { name: string type: Type index?: IndexKind + isCustom?: boolean } /** diff --git a/packages/core/src/component.ts b/packages/core/src/component.ts index 8f3ef9c2a5..c456f8c75f 100644 --- a/packages/core/src/component.ts +++ b/packages/core/src/component.ts @@ -71,6 +71,7 @@ export default plugin(coreId, { TxPutBag: '' as Ref>>, Space: '' as Ref>, Account: '' as Ref>, + Type: '' as Ref>>, TypeString: '' as Ref>>, TypeIntlString: '' as Ref>>, TypeNumber: '' as Ref>>, @@ -109,6 +110,18 @@ export default plugin(coreId, { ModifiedBy: '' as IntlString, Class: '' as IntlString, AttachedTo: '' as IntlString, - AttachedToClass: '' as IntlString + AttachedToClass: '' as IntlString, + String: '' as IntlString, + Markup: '' as IntlString, + Number: '' as IntlString, + Boolean: '' as IntlString, + Timestamp: '' as IntlString, + Date: '' as IntlString, + IntlString: '' as IntlString, + Ref: '' as IntlString, + Collection: '' as IntlString, + Array: '' as IntlString, + Bag: '' as IntlString, + Name: '' as IntlString } }) diff --git a/packages/model/src/dsl.ts b/packages/model/src/dsl.ts index 8efbf35238..6fd05bf265 100644 --- a/packages/model/src/dsl.ts +++ b/packages/model/src/dsl.ts @@ -339,75 +339,75 @@ export class Builder { * @public */ export function TypeString (): Type { - return { _class: core.class.TypeString, label: 'TypeString' as IntlString } + return { _class: core.class.TypeString, label: core.string.String } } /** * @public */ export function TypeNumber (): Type { - return { _class: core.class.TypeNumber, label: 'TypeNumber' as IntlString } + return { _class: core.class.TypeNumber, label: core.string.Number } } /** * @public */ export function TypeMarkup (): Type { - return { _class: core.class.TypeMarkup, label: 'TypeMarkup' as IntlString } + return { _class: core.class.TypeMarkup, label: core.string.Markup } } /** * @public */ export function TypeIntlString (): Type { - return { _class: core.class.TypeIntlString, label: 'TypeIntlString' as IntlString } + return { _class: core.class.TypeIntlString, label: core.string.IntlString } } /** * @public */ export function TypeBoolean (): Type { - return { _class: core.class.TypeBoolean, label: 'TypeBoolean' as IntlString } + return { _class: core.class.TypeBoolean, label: core.string.Boolean } } /** * @public */ export function TypeTimestamp (): Type { - return { _class: core.class.TypeTimestamp, label: 'TypeTimestamp' as IntlString } + return { _class: core.class.TypeTimestamp, label: core.string.Timestamp } } /** * @public */ export function TypeDate (withTime?: boolean): TypeDateType { - return { _class: core.class.TypeDate, label: 'TypeDate' as IntlString, withTime } + return { _class: core.class.TypeDate, label: core.string.Date, withTime } } /** * @public */ export function TypeRef (_class: Ref>): RefTo { - return { _class: core.class.RefTo, to: _class, label: 'TypeRef' as IntlString } + return { _class: core.class.RefTo, label: core.string.Ref, to: _class } } /** * @public */ export function Collection (clazz: Ref>, itemLabel?: IntlString): TypeCollection { - return { _class: core.class.Collection, of: clazz, label: 'Collection' as IntlString, itemLabel } + return { _class: core.class.Collection, label: core.string.Collection, of: clazz, itemLabel } } /** * @public */ export function ArrOf> (type: Type): TypeArrOf { - return { _class: core.class.ArrOf, of: type, label: 'Array' as IntlString } + return { _class: core.class.ArrOf, label: core.string.Array, of: type } } /** * @public */ export function Bag (): Type> { - return { _class: core.class.Bag, label: 'Bag' as IntlString } + return { _class: core.class.Bag, label: core.string.Bag } } diff --git a/packages/platform/src/i18n.ts b/packages/platform/src/i18n.ts index 5b5902a976..3d8c17feb5 100644 --- a/packages/platform/src/i18n.ts +++ b/packages/platform/src/i18n.ts @@ -16,7 +16,7 @@ import type { Plugin, IntlString } from './platform' import { Status, Severity, unknownError } from './status' -import { _parseId } from './ident' +import { _IdInfo, _parseId } from './ident' import { setPlatformStatus } from './event' import { IntlMessageFormat } from 'intl-messageformat' @@ -73,9 +73,8 @@ async function loadTranslationsForComponent (plugin: Plugin, locale: string): Pr } } -async function getTranslation (message: IntlString, locale: string): Promise { +async function getTranslation (id: _IdInfo, locale: string): Promise { try { - const id = _parseId(message) let messages = translations.get(id.component) if (messages === undefined) { messages = await loadTranslationsForComponent(id.component, locale) @@ -84,11 +83,9 @@ async function getTranslation (message: IntlString, locale: string): Promise)?.[id.name] - : (messages[id.name] as IntlString)) ?? message - ) + return id.kind !== undefined + ? (messages[id.kind] as Record)?.[id.name] + : (messages[id.name] as IntlString) } catch (err) { const status = unknownError(err) await setPlatformStatus(status) @@ -111,13 +108,24 @@ export async function translate

> (message: IntlStr } return compiled.format(params) } else { - const translation = await getTranslation(message, locale) - if (translation instanceof Status) { - cache.set(message, translation) + try { + const id = _parseId(message) + if (id.component === 'embedded') { + return id.name + } + const translation = (await getTranslation(id, locale)) ?? message + if (translation instanceof Status) { + cache.set(message, translation) + return message + } + const compiled = new IntlMessageFormat(translation, locale) + cache.set(message, compiled) + return compiled.format(params) + } catch (err) { + const status = unknownError(err) + await setPlatformStatus(status) + cache.set(message, status) return message } - const compiled = new IntlMessageFormat(translation, locale) - cache.set(message, compiled) - return compiled.format(params) } } diff --git a/packages/platform/src/platform.ts b/packages/platform/src/platform.ts index e49e95ce1f..cef8f52ac6 100644 --- a/packages/platform/src/platform.ts +++ b/packages/platform/src/platform.ts @@ -71,6 +71,11 @@ export type Namespace = Record> */ export const _ID_SEPARATOR = ':' +/** + * @internal + */ +export const _EmbeddedId = 'embedded' + function identify (result: Record, prefix: string, namespace: Record): Namespace { for (const key in namespace) { const value = namespace[key] @@ -83,6 +88,13 @@ function identify (result: Record, prefix: string, namespace: Recor return result } +/** + * @public + */ +export function getEmbeddedLabel (str: string): IntlString { + return (_EmbeddedId + _ID_SEPARATOR + _EmbeddedId + _ID_SEPARATOR + str) as IntlString +} + /** * Defines plugin Ids. * diff --git a/packages/ui/src/components/DropdownLabelsIntl.svelte b/packages/ui/src/components/DropdownLabelsIntl.svelte index 7ddb8a62d8..1a26a1e6dd 100644 --- a/packages/ui/src/components/DropdownLabelsIntl.svelte +++ b/packages/ui/src/components/DropdownLabelsIntl.svelte @@ -35,10 +35,10 @@ let container: HTMLElement let opened: boolean = false - let selectedItem = items.find((x) => x.id === selected) $: selectedItem = items.find((x) => x.id === selected) $: if (selected === undefined && items[0] !== undefined) { selected = items[0].id + dispatch('selected', selected) } const dispatch = createEventDispatcher() diff --git a/plugins/activity-resources/src/components/utils.ts b/plugins/activity-resources/src/components/utils.ts index 216e6bb9b9..cd03f138af 100644 --- a/plugins/activity-resources/src/components/utils.ts +++ b/plugins/activity-resources/src/components/utils.ts @@ -37,14 +37,17 @@ async function createPseudoViewlet ( // Check if it is attached doc and collection have title override. const presenter = await getObjectPresenter(client, doc._class, { key: 'doc-presenter' }) if (presenter !== undefined) { + let collection = '' + if (dtx.collectionAttribute?.label !== undefined) { + collection = await translate(dtx.collectionAttribute.label, {}) + } return { display, icon: docClass.icon ?? activity.icon.Activity, label: label, labelParams: { _class: trLabel, - collection: - dtx.collectionAttribute?.label !== undefined ? await translate(dtx.collectionAttribute?.label, {}) : '' + collection }, component: presenter.presenter, pseudo: true diff --git a/plugins/view-assets/lang/en.json b/plugins/view-assets/lang/en.json index 0a5833a2cf..51006077ba 100644 --- a/plugins/view-assets/lang/en.json +++ b/plugins/view-assets/lang/en.json @@ -32,6 +32,10 @@ "General": "General", "Navigation": "Navigation", "Editor": "Editor", - "MarkdownFormatting": "Formatting" + "MarkdownFormatting": "Formatting", + "Type": "Type", + "WithTime": "WithTime", + "CreatingAttribute": "Creating an attribute", + "CreatingAttributeConfirm": "Do you want to create an attribute? It will not be possible to change or delete it." } } diff --git a/plugins/view-assets/lang/ru.json b/plugins/view-assets/lang/ru.json index 025f298b75..39f475d05d 100644 --- a/plugins/view-assets/lang/ru.json +++ b/plugins/view-assets/lang/ru.json @@ -20,6 +20,10 @@ "General": "Общее", "Navigation": "Навигация", "Editor": "Редактор", - "MarkdownFormatting": "Форматирование" + "MarkdownFormatting": "Форматирование", + "Type": "Тип", + "WithTime": "Со временем", + "CreatingAttribute": "Создание атрибута", + "CreatingAttributeConfirm": "Вы хотите создать атрибут? Изменить или удалить его будет невозможно" } } diff --git a/plugins/view-resources/package.json b/plugins/view-resources/package.json index d4cef9521f..88253269d0 100644 --- a/plugins/view-resources/package.json +++ b/plugins/view-resources/package.json @@ -33,6 +33,7 @@ "svelte": "^3.47", "@anticrm/platform": "~0.6.6", "@anticrm/contact": "~0.6.5", + "@anticrm/model": "~0.6.0", "@anticrm/panel": "~0.6.0", "@anticrm/core": "~0.6.16", "@anticrm/view": "~0.6.0", diff --git a/plugins/view-resources/src/components/ClassAttributeBar.svelte b/plugins/view-resources/src/components/ClassAttributeBar.svelte new file mode 100644 index 0000000000..34ef29e48c --- /dev/null +++ b/plugins/view-resources/src/components/ClassAttributeBar.svelte @@ -0,0 +1,61 @@ + + + +{#if vertical} +

+
+{/if} +{#if keys.length || !vertical} + +{/if} diff --git a/plugins/view-resources/src/components/CreateAttribute.svelte b/plugins/view-resources/src/components/CreateAttribute.svelte new file mode 100644 index 0000000000..45b992c247 --- /dev/null +++ b/plugins/view-resources/src/components/CreateAttribute.svelte @@ -0,0 +1,118 @@ + + + +
+
+
+
+ {#if is} + { + type = e.detail + }} + /> + {/if} +
+
+
+ + diff --git a/plugins/view-resources/src/components/DocAttributeBar.svelte b/plugins/view-resources/src/components/DocAttributeBar.svelte new file mode 100644 index 0000000000..074817b33c --- /dev/null +++ b/plugins/view-resources/src/components/DocAttributeBar.svelte @@ -0,0 +1,33 @@ + + + + +{#each mixins as mixin} +
+ +{/each} diff --git a/plugins/view-resources/src/components/EditDoc.svelte b/plugins/view-resources/src/components/EditDoc.svelte index 8eeaa0db49..f8d303c193 100644 --- a/plugins/view-resources/src/components/EditDoc.svelte +++ b/plugins/view-resources/src/components/EditDoc.svelte @@ -15,7 +15,7 @@ --> diff --git a/plugins/view-resources/src/components/typeEditors/DateTypeEditor.svelte b/plugins/view-resources/src/components/typeEditors/DateTypeEditor.svelte new file mode 100644 index 0000000000..18cfe466b7 --- /dev/null +++ b/plugins/view-resources/src/components/typeEditors/DateTypeEditor.svelte @@ -0,0 +1,40 @@ + + + +
+
diff --git a/plugins/view-resources/src/components/typeEditors/NumberTypeEditor.svelte b/plugins/view-resources/src/components/typeEditors/NumberTypeEditor.svelte new file mode 100644 index 0000000000..5fd9b3c119 --- /dev/null +++ b/plugins/view-resources/src/components/typeEditors/NumberTypeEditor.svelte @@ -0,0 +1,25 @@ + + diff --git a/plugins/view-resources/src/components/typeEditors/StringTypeEditor.svelte b/plugins/view-resources/src/components/typeEditors/StringTypeEditor.svelte new file mode 100644 index 0000000000..65ac6e1693 --- /dev/null +++ b/plugins/view-resources/src/components/typeEditors/StringTypeEditor.svelte @@ -0,0 +1,25 @@ + + diff --git a/plugins/view-resources/src/index.ts b/plugins/view-resources/src/index.ts index 20d3b401ac..ad9ce527a4 100644 --- a/plugins/view-resources/src/index.ts +++ b/plugins/view-resources/src/index.ts @@ -38,6 +38,11 @@ import UpDownNavigator from './components/UpDownNavigator.svelte' import GithubPresenter from './components/linkPresenters/GithubPresenter.svelte' import YoutubePresenter from './components/linkPresenters/YoutubePresenter.svelte' import ActionsPopup from './components/ActionsPopup.svelte' +import CreateAttribute from './components/CreateAttribute.svelte' +import StringTypeEditor from './components/typeEditors/StringTypeEditor.svelte' +import BooleanTypeEditor from './components/typeEditors/BooleanTypeEditor.svelte' +import DateTypeEditor from './components/typeEditors/DateTypeEditor.svelte' +import NumberTypeEditor from './components/typeEditors/NumberTypeEditor.svelte' export { getActions } from './actions' export { default as ActionContext } from './components/ActionContext.svelte' @@ -53,6 +58,11 @@ export { Table, TableView, EditDoc, ColorsPopup, Menu, SpacePresenter, UpDownNav export default async (): Promise => ({ actionImpl: actionImpl, component: { + CreateAttribute, + StringTypeEditor, + BooleanTypeEditor, + NumberTypeEditor, + DateTypeEditor, SpacePresenter, StringEditor, StringPresenter, diff --git a/plugins/view-resources/src/plugin.ts b/plugins/view-resources/src/plugin.ts index 31bc5a638a..f26e7ad8d8 100644 --- a/plugins/view-resources/src/plugin.ts +++ b/plugins/view-resources/src/plugin.ts @@ -35,6 +35,10 @@ export default mergeIds(viewId, view, { DeleteObjectConfirm: '' as IntlString, Assignees: '' as IntlString, Labels: '' as IntlString, - ActionPlaceholder: '' as IntlString + WithTime: '' as IntlString, + Type: '' as IntlString, + ActionPlaceholder: '' as IntlString, + CreatingAttribute: '' as IntlString, + CreatingAttributeConfirm: '' as IntlString } }) diff --git a/plugins/view-resources/src/utils.ts b/plugins/view-resources/src/utils.ts index 5690b24858..329aa5f8e5 100644 --- a/plugins/view-resources/src/utils.ts +++ b/plugins/view-resources/src/utils.ts @@ -283,3 +283,35 @@ export function getCollectionCounter (hierarchy: Hierarchy, object: Doc, key: Ke } return (object as any)[key.key] ?? 0 } + +function filterKeys (hierarchy: Hierarchy, keys: KeyedAttribute[], ignoreKeys: string[]): KeyedAttribute[] { + const docKeys: Set = new Set(hierarchy.getAllAttributes(core.class.AttachedDoc).keys()) + keys = keys.filter((k) => !docKeys.has(k.key)) + keys = keys.filter((k) => !ignoreKeys.includes(k.key)) + return keys +} + +export function getFiltredKeys ( + hierarchy: Hierarchy, + objectClass: Ref>, + ignoreKeys: string[], + to?: Ref> +): KeyedAttribute[] { + const keys = [...hierarchy.getAllAttributes(objectClass, to).entries()] + .filter(([, value]) => value.hidden !== true) + .map(([key, attr]) => ({ key, attr })) + + return filterKeys(hierarchy, keys, ignoreKeys) +} + +export function collectionsFilter (hierarchy: Hierarchy, keys: KeyedAttribute[], get: boolean): KeyedAttribute[] { + const result: KeyedAttribute[] = [] + for (const key of keys) { + if (isCollectionAttr(hierarchy, key) === get) result.push(key) + } + return result +} + +function isCollectionAttr (hierarchy: Hierarchy, key: KeyedAttribute): boolean { + return hierarchy.isDerived(key.attr.type._class, core.class.Collection) +} diff --git a/plugins/view/src/index.ts b/plugins/view/src/index.ts index 5c15384fa7..f9e1f5e583 100644 --- a/plugins/view/src/index.ts +++ b/plugins/view/src/index.ts @@ -311,6 +311,7 @@ const view = plugin(viewId, { component: { ObjectPresenter: '' as AnyComponent, EditDoc: '' as AnyComponent, + CreateAttribute: '' as AnyComponent, SpacePresenter: '' as AnyComponent }, icon: {