mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-23 00:37:47 +00:00
UBER-1187: AnyType field support (#4343)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
f972066df6
commit
262c2dd82c
@ -14,6 +14,13 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
DOMAIN_BLOB,
|
||||||
|
DOMAIN_CONFIGURATION,
|
||||||
|
DOMAIN_DOC_INDEX_STATE,
|
||||||
|
DOMAIN_FULLTEXT_BLOB,
|
||||||
|
DOMAIN_MIGRATION,
|
||||||
|
DOMAIN_MODEL,
|
||||||
|
IndexKind,
|
||||||
type Account,
|
type Account,
|
||||||
type AnyAttribute,
|
type AnyAttribute,
|
||||||
type ArrOf,
|
type ArrOf,
|
||||||
@ -27,21 +34,15 @@ import {
|
|||||||
type Doc,
|
type Doc,
|
||||||
type DocIndexState,
|
type DocIndexState,
|
||||||
type Domain,
|
type Domain,
|
||||||
DOMAIN_BLOB,
|
|
||||||
DOMAIN_CONFIGURATION,
|
|
||||||
DOMAIN_MIGRATION,
|
|
||||||
DOMAIN_DOC_INDEX_STATE,
|
|
||||||
DOMAIN_FULLTEXT_BLOB,
|
|
||||||
DOMAIN_MODEL,
|
|
||||||
type Enum,
|
type Enum,
|
||||||
type EnumOf,
|
type EnumOf,
|
||||||
type FieldIndex,
|
type FieldIndex,
|
||||||
type FullTextData,
|
type FullTextData,
|
||||||
type FullTextSearchContext,
|
type FullTextSearchContext,
|
||||||
type IndexingConfiguration,
|
|
||||||
IndexKind,
|
|
||||||
type IndexStageState,
|
type IndexStageState,
|
||||||
|
type IndexingConfiguration,
|
||||||
type Interface,
|
type Interface,
|
||||||
|
type MigrationState,
|
||||||
type Mixin,
|
type Mixin,
|
||||||
type Obj,
|
type Obj,
|
||||||
type PluginConfiguration,
|
type PluginConfiguration,
|
||||||
@ -50,8 +51,8 @@ import {
|
|||||||
type Space,
|
type Space,
|
||||||
type Timestamp,
|
type Timestamp,
|
||||||
type Type,
|
type Type,
|
||||||
type Version,
|
type TypeAny,
|
||||||
type MigrationState
|
type Version
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import {
|
import {
|
||||||
Hidden,
|
Hidden,
|
||||||
@ -243,6 +244,13 @@ export class TEnumOf extends TType implements EnumOf {
|
|||||||
of!: Ref<Enum>
|
of!: Ref<Enum>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UX(getEmbeddedLabel('Any'))
|
||||||
|
@Model(core.class.TypeAny, core.class.Type)
|
||||||
|
export class TTypeAny extends TType implements TypeAny {
|
||||||
|
presenter!: any
|
||||||
|
editor!: any
|
||||||
|
}
|
||||||
|
|
||||||
@Model(core.class.Version, core.class.Doc, DOMAIN_MODEL)
|
@Model(core.class.Version, core.class.Doc, DOMAIN_MODEL)
|
||||||
export class TVersion extends TDoc implements Version {
|
export class TVersion extends TDoc implements Version {
|
||||||
major!: number
|
major!: number
|
||||||
|
@ -15,13 +15,13 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
AccountRole,
|
AccountRole,
|
||||||
|
systemAccountEmail,
|
||||||
type AttachedDoc,
|
type AttachedDoc,
|
||||||
type Class,
|
type Class,
|
||||||
type Doc,
|
type Doc,
|
||||||
type DocIndexState,
|
type DocIndexState,
|
||||||
type IndexingConfiguration,
|
type IndexingConfiguration,
|
||||||
type TxCollectionCUD,
|
type TxCollectionCUD
|
||||||
systemAccountEmail
|
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import { type Builder } from '@hcengineering/model'
|
import { type Builder } from '@hcengineering/model'
|
||||||
import core from './component'
|
import core from './component'
|
||||||
@ -49,6 +49,7 @@ import {
|
|||||||
TPluginConfiguration,
|
TPluginConfiguration,
|
||||||
TRefTo,
|
TRefTo,
|
||||||
TType,
|
TType,
|
||||||
|
TTypeAny,
|
||||||
TTypeAttachment,
|
TTypeAttachment,
|
||||||
TTypeBoolean,
|
TTypeBoolean,
|
||||||
TTypeCollaborativeMarkup,
|
TTypeCollaborativeMarkup,
|
||||||
@ -126,6 +127,7 @@ export function createModel (builder: Builder): void {
|
|||||||
TPluginConfiguration,
|
TPluginConfiguration,
|
||||||
TUserStatus,
|
TUserStatus,
|
||||||
TEnum,
|
TEnum,
|
||||||
|
TTypeAny,
|
||||||
TBlobData,
|
TBlobData,
|
||||||
TFulltextData,
|
TFulltextData,
|
||||||
TTypeRelatedDocument,
|
TTypeRelatedDocument,
|
||||||
|
@ -291,6 +291,16 @@ export interface EnumOf extends Type<string> {
|
|||||||
*/
|
*/
|
||||||
export interface TypeHyperlink extends Type<Hyperlink> {}
|
export interface TypeHyperlink extends Type<Hyperlink> {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*
|
||||||
|
* A type for some custom serialized field with a set of editors
|
||||||
|
*/
|
||||||
|
export interface TypeAny<AnyComponent = any> extends Type<any> {
|
||||||
|
presenter: AnyComponent
|
||||||
|
editor?: AnyComponent
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
@ -45,6 +45,7 @@ import type {
|
|||||||
Space,
|
Space,
|
||||||
Timestamp,
|
Timestamp,
|
||||||
Type,
|
Type,
|
||||||
|
TypeAny,
|
||||||
UserStatus
|
UserStatus
|
||||||
} from './classes'
|
} from './classes'
|
||||||
import { Status, StatusCategory } from './status'
|
import { Status, StatusCategory } from './status'
|
||||||
@ -109,6 +110,7 @@ export default plugin(coreId, {
|
|||||||
Enum: '' as Ref<Class<Enum>>,
|
Enum: '' as Ref<Class<Enum>>,
|
||||||
EnumOf: '' as Ref<Class<EnumOf>>,
|
EnumOf: '' as Ref<Class<EnumOf>>,
|
||||||
Collection: '' as Ref<Class<Collection<AttachedDoc>>>,
|
Collection: '' as Ref<Class<Collection<AttachedDoc>>>,
|
||||||
|
TypeAny: '' as Ref<Class<TypeAny>>,
|
||||||
Version: '' as Ref<Class<Version>>,
|
Version: '' as Ref<Class<Version>>,
|
||||||
PluginConfiguration: '' as Ref<Class<PluginConfiguration>>,
|
PluginConfiguration: '' as Ref<Class<PluginConfiguration>>,
|
||||||
UserStatus: '' as Ref<Class<UserStatus>>,
|
UserStatus: '' as Ref<Class<UserStatus>>,
|
||||||
|
@ -15,25 +15,22 @@
|
|||||||
|
|
||||||
import core, {
|
import core, {
|
||||||
Account,
|
Account,
|
||||||
ArrOf as TypeArrOf,
|
|
||||||
AttachedDoc,
|
AttachedDoc,
|
||||||
Attribute,
|
Attribute,
|
||||||
Class,
|
Class,
|
||||||
Classifier,
|
Classifier,
|
||||||
ClassifierKind,
|
ClassifierKind,
|
||||||
Collection as TypeCollection,
|
|
||||||
Data,
|
Data,
|
||||||
DateRangeMode,
|
DateRangeMode,
|
||||||
Doc,
|
Doc,
|
||||||
Domain,
|
Domain,
|
||||||
Enum,
|
Enum,
|
||||||
EnumOf,
|
EnumOf,
|
||||||
generateId,
|
|
||||||
Hyperlink,
|
Hyperlink,
|
||||||
|
Mixin as IMixin,
|
||||||
IndexKind,
|
IndexKind,
|
||||||
Interface,
|
Interface,
|
||||||
Markup,
|
Markup,
|
||||||
Mixin as IMixin,
|
|
||||||
MixinUpdate,
|
MixinUpdate,
|
||||||
Obj,
|
Obj,
|
||||||
PropertyType,
|
PropertyType,
|
||||||
@ -46,7 +43,11 @@ import core, {
|
|||||||
TxFactory,
|
TxFactory,
|
||||||
TxProcessor,
|
TxProcessor,
|
||||||
Type,
|
Type,
|
||||||
TypeDate as TypeDateType
|
TypeAny as TypeAnyType,
|
||||||
|
ArrOf as TypeArrOf,
|
||||||
|
Collection as TypeCollection,
|
||||||
|
TypeDate as TypeDateType,
|
||||||
|
generateId
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import type { Asset, IntlString } from '@hcengineering/platform'
|
import type { Asset, IntlString } from '@hcengineering/platform'
|
||||||
import toposort from 'toposort'
|
import toposort from 'toposort'
|
||||||
@ -464,6 +465,17 @@ export function TypeEnum (of: Ref<Enum>): EnumOf {
|
|||||||
return { _class: core.class.EnumOf, label: core.string.Enum, of }
|
return { _class: core.class.EnumOf, label: core.string.Enum, of }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
export function TypeAny<AnyComponent = any> (
|
||||||
|
presenter: AnyComponent,
|
||||||
|
label: IntlString,
|
||||||
|
editor?: AnyComponent
|
||||||
|
): TypeAnyType<AnyComponent> {
|
||||||
|
return { _class: core.class.TypeAny, label, presenter, editor }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
let editor: AnySvelteComponent | undefined
|
let editor: AnySvelteComponent | undefined
|
||||||
|
|
||||||
function onChange (value: any) {
|
function onChange (value: any): void {
|
||||||
const doc = object as Doc
|
const doc = object as Doc
|
||||||
|
|
||||||
dispatch('update', { key, value })
|
dispatch('update', { key, value })
|
||||||
@ -48,12 +48,14 @@
|
|||||||
if (draft) {
|
if (draft) {
|
||||||
;(doc as any)[attributeKey] = value
|
;(doc as any)[attributeKey] = value
|
||||||
} else {
|
} else {
|
||||||
updateAttribute(client, doc, doc._class, { key: attributeKey, attr: attribute }, value)
|
void updateAttribute(client, doc, doc._class, { key: attributeKey, attr: attribute }, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEditor (_class: Ref<Class<Doc>>, key: KeyedAttribute | string) {
|
function getEditor (_class: Ref<Class<Doc>>, key: KeyedAttribute | string): void {
|
||||||
getAttributeEditor(client, _class, key).then((p) => (editor = p))
|
void getAttributeEditor(client, _class, key).then((p) => {
|
||||||
|
editor = p
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
$: getEditor(_class, key)
|
$: getEditor(_class, key)
|
||||||
|
@ -48,10 +48,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onChange (value: any) {
|
function onChange (value: any): void {
|
||||||
if (!editable) return
|
if (!editable) return
|
||||||
const doc = object as Doc
|
const doc = object as Doc
|
||||||
updateAttribute(client, doc, _class, { key: attributeKey, attr: attribute }, value)
|
void updateAttribute(client, doc, _class, { key: attributeKey, attr: attribute }, value)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import core, {
|
import core, {
|
||||||
|
TxOperations,
|
||||||
|
type TypeAny,
|
||||||
|
getCurrentAccount,
|
||||||
type AnyAttribute,
|
type AnyAttribute,
|
||||||
type ArrOf,
|
type ArrOf,
|
||||||
type AttachedDoc,
|
type AttachedDoc,
|
||||||
@ -25,28 +28,26 @@ import core, {
|
|||||||
type DocumentQuery,
|
type DocumentQuery,
|
||||||
type FindOptions,
|
type FindOptions,
|
||||||
type FindResult,
|
type FindResult,
|
||||||
getCurrentAccount,
|
|
||||||
type Hierarchy,
|
type Hierarchy,
|
||||||
type Mixin,
|
type Mixin,
|
||||||
type Obj,
|
type Obj,
|
||||||
type Ref,
|
type Ref,
|
||||||
type RefTo,
|
type RefTo,
|
||||||
type Tx,
|
|
||||||
TxOperations,
|
|
||||||
type TxResult,
|
|
||||||
type WithLookup,
|
|
||||||
type SearchQuery,
|
|
||||||
type SearchOptions,
|
type SearchOptions,
|
||||||
type SearchResult
|
type SearchQuery,
|
||||||
|
type SearchResult,
|
||||||
|
type Tx,
|
||||||
|
type TxResult,
|
||||||
|
type WithLookup
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import { getMetadata, getResource } from '@hcengineering/platform'
|
import { getMetadata, getResource } from '@hcengineering/platform'
|
||||||
import { LiveQuery as LQ } from '@hcengineering/query'
|
import { LiveQuery as LQ } from '@hcengineering/query'
|
||||||
import { type AnySvelteComponent, type IconSize } from '@hcengineering/ui'
|
import { type AnyComponent, type AnySvelteComponent, type IconSize } from '@hcengineering/ui'
|
||||||
import view, { type AttributeEditor } from '@hcengineering/view'
|
import view, { type AttributeEditor } from '@hcengineering/view'
|
||||||
import { deepEqual } from 'fast-equals'
|
import { deepEqual } from 'fast-equals'
|
||||||
import { onDestroy } from 'svelte'
|
import { onDestroy } from 'svelte'
|
||||||
import { type KeyedAttribute } from '..'
|
import { type KeyedAttribute } from '..'
|
||||||
import { OptimizeQueryMiddleware, type PresentationPipeline, PresentationPipelineImpl } from './pipeline'
|
import { OptimizeQueryMiddleware, PresentationPipelineImpl, type PresentationPipeline } from './pipeline'
|
||||||
import plugin from './plugin'
|
import plugin from './plugin'
|
||||||
|
|
||||||
let liveQuery: LQ
|
let liveQuery: LQ
|
||||||
@ -406,6 +407,12 @@ export async function getAttributeEditor (
|
|||||||
): Promise<AnySvelteComponent | undefined> {
|
): Promise<AnySvelteComponent | undefined> {
|
||||||
const hierarchy = client.getHierarchy()
|
const hierarchy = client.getHierarchy()
|
||||||
const attribute = typeof key === 'string' ? hierarchy.getAttribute(_class, key) : key.attr
|
const attribute = typeof key === 'string' ? hierarchy.getAttribute(_class, key) : key.attr
|
||||||
|
|
||||||
|
if (attribute.type._class === core.class.TypeAny) {
|
||||||
|
const _type: TypeAny = attribute.type as TypeAny<AnyComponent>
|
||||||
|
return await getResource(_type.editor ?? _type.presenter)
|
||||||
|
}
|
||||||
|
|
||||||
const presenterClass = attribute !== undefined ? getAttributePresenterClass(hierarchy, attribute) : undefined
|
const presenterClass = attribute !== undefined ? getAttributePresenterClass(hierarchy, attribute) : undefined
|
||||||
|
|
||||||
if (presenterClass === undefined) {
|
if (presenterClass === undefined) {
|
||||||
|
@ -19,13 +19,14 @@
|
|||||||
import { Panel } from '@hcengineering/panel'
|
import { Panel } from '@hcengineering/panel'
|
||||||
import { getResource } from '@hcengineering/platform'
|
import { getResource } from '@hcengineering/platform'
|
||||||
import presentation, {
|
import presentation, {
|
||||||
createQuery,
|
|
||||||
getClient,
|
|
||||||
ActionContext,
|
ActionContext,
|
||||||
|
ComponentExtensions,
|
||||||
contextStore,
|
contextStore,
|
||||||
ComponentExtensions
|
createQuery,
|
||||||
|
getClient
|
||||||
} from '@hcengineering/presentation'
|
} from '@hcengineering/presentation'
|
||||||
import setting, { settingId } from '@hcengineering/setting'
|
import setting, { settingId } from '@hcengineering/setting'
|
||||||
|
import { taskTypeStore, typeStore } from '@hcengineering/task-resources'
|
||||||
import { Issue, Project } from '@hcengineering/tracker'
|
import { Issue, Project } from '@hcengineering/tracker'
|
||||||
import {
|
import {
|
||||||
AnyComponent,
|
AnyComponent,
|
||||||
@ -42,8 +43,8 @@
|
|||||||
navigate,
|
navigate,
|
||||||
showPopup
|
showPopup
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import { ContextMenu, DocNavLink, ParentsNavigator } from '@hcengineering/view-resources'
|
|
||||||
import view from '@hcengineering/view'
|
import view from '@hcengineering/view'
|
||||||
|
import { ContextMenu, DocNavLink, ParentsNavigator } from '@hcengineering/view-resources'
|
||||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||||
import { generateIssueShortLink, getIssueId } from '../../../issues'
|
import { generateIssueShortLink, getIssueId } from '../../../issues'
|
||||||
import tracker from '../../../plugin'
|
import tracker from '../../../plugin'
|
||||||
@ -161,6 +162,10 @@
|
|||||||
$: editorFooter = getEditorFooter(issue?._class)
|
$: editorFooter = getEditorFooter(issue?._class)
|
||||||
|
|
||||||
let content: HTMLElement
|
let content: HTMLElement
|
||||||
|
|
||||||
|
$: taskType = issue?.kind !== undefined ? $taskTypeStore.get(issue?.kind) : undefined
|
||||||
|
|
||||||
|
$: projectType = taskType?.parent !== undefined ? $typeStore.get(taskType.parent) : undefined
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if !embedded}
|
{#if !embedded}
|
||||||
@ -187,12 +192,24 @@
|
|||||||
on:select
|
on:select
|
||||||
>
|
>
|
||||||
<svelte:fragment slot="title">
|
<svelte:fragment slot="title">
|
||||||
{#if !embedded}<ParentsNavigator element={issue} />{/if}
|
{#if !embedded}
|
||||||
|
<ParentsNavigator element={issue} />
|
||||||
|
{/if}
|
||||||
{#if embedded && issueId}
|
{#if embedded && issueId}
|
||||||
<DocNavLink noUnderline object={issue}>
|
<DocNavLink noUnderline object={issue}>
|
||||||
<div class="title">{issueId}</div>
|
<div class="title">{issueId}</div>
|
||||||
</DocNavLink>
|
</DocNavLink>
|
||||||
{:else if issueId}<div class="title not-active">{issueId}</div>{/if}
|
{:else if issueId}
|
||||||
|
<div class="title not-active">{issueId}</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if (projectType?.tasks.length ?? 0) > 1 && taskType !== undefined}
|
||||||
|
({taskType.name})
|
||||||
|
{/if}
|
||||||
|
<ComponentExtensions
|
||||||
|
extension={tracker.extensions.EditIssueTitle}
|
||||||
|
props={{ size: 'medium', value: issue, space: currentProject }}
|
||||||
|
/>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="pre-utils">
|
<svelte:fragment slot="pre-utils">
|
||||||
<ComponentExtensions
|
<ComponentExtensions
|
||||||
|
@ -532,7 +532,8 @@ const pluginState = plugin(trackerId, {
|
|||||||
},
|
},
|
||||||
extensions: {
|
extensions: {
|
||||||
IssueListHeader: '' as ComponentExtensionId,
|
IssueListHeader: '' as ComponentExtensionId,
|
||||||
EditIssueHeader: '' as ComponentExtensionId
|
EditIssueHeader: '' as ComponentExtensionId,
|
||||||
|
EditIssueTitle: '' as ComponentExtensionId
|
||||||
},
|
},
|
||||||
taskTypes: {
|
taskTypes: {
|
||||||
Issue: '' as Ref<TaskType>,
|
Issue: '' as Ref<TaskType>,
|
||||||
|
Loading…
Reference in New Issue
Block a user