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