mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-11 01:40:32 +00:00
Card refs (#8319)
Some checks are pending
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / uitest-workspaces (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions
Some checks are pending
CI / build (push) Waiting to run
CI / svelte-check (push) Blocked by required conditions
CI / formatting (push) Blocked by required conditions
CI / test (push) Blocked by required conditions
CI / uitest (push) Waiting to run
CI / uitest-pg (push) Waiting to run
CI / uitest-qms (push) Waiting to run
CI / uitest-workspaces (push) Waiting to run
CI / docker-build (push) Blocked by required conditions
CI / dist-build (push) Blocked by required conditions
This commit is contained in:
parent
2a735553e9
commit
34fc0024d3
@ -43,7 +43,7 @@ import presentation from '@hcengineering/model-presentation'
|
||||
import setting from '@hcengineering/model-setting'
|
||||
import view, { createAction } from '@hcengineering/model-view'
|
||||
import workbench from '@hcengineering/model-workbench'
|
||||
import { getEmbeddedLabel, type IntlString } from '@hcengineering/platform'
|
||||
import { type Asset, getEmbeddedLabel, type IntlString } from '@hcengineering/platform'
|
||||
import time, { type ToDo } from '@hcengineering/time'
|
||||
import { type AnyComponent } from '@hcengineering/ui/src/types'
|
||||
import { type BuildModelKey } from '@hcengineering/view'
|
||||
@ -102,58 +102,43 @@ export class MasterTagEditorSection extends TDoc implements MasterTagEditorSecti
|
||||
|
||||
export * from './migration'
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(TMasterTag, TTag, TCard, MasterTagEditorSection)
|
||||
const listConfig: (BuildModelKey | string)[] = [
|
||||
{ key: '', props: { showParent: true }, displayProps: { fixed: 'left', key: 'card' } },
|
||||
{ key: '_class', displayProps: { fixed: 'left', key: 'type' } },
|
||||
{ key: '', displayProps: { grow: true } },
|
||||
{
|
||||
key: '',
|
||||
presenter: view.component.RolePresenter,
|
||||
label: card.string.Tags,
|
||||
props: { fullSize: true },
|
||||
displayProps: { key: 'tags', fixed: 'right' }
|
||||
},
|
||||
{
|
||||
key: 'modifiedOn',
|
||||
displayProps: { fixed: 'right', dividerBefore: true }
|
||||
}
|
||||
]
|
||||
|
||||
export function createSystemType (
|
||||
builder: Builder,
|
||||
type: Ref<MasterTag>,
|
||||
label: IntlString,
|
||||
icon: Asset = card.icon.MasterTag
|
||||
): void {
|
||||
builder.createDoc(
|
||||
card.class.MasterTag,
|
||||
core.space.Model,
|
||||
{
|
||||
label: attachment.string.File,
|
||||
label,
|
||||
extends: card.class.Card,
|
||||
icon: card.icon.File,
|
||||
icon,
|
||||
kind: ClassifierKind.CLASS
|
||||
},
|
||||
card.types.File
|
||||
type
|
||||
)
|
||||
|
||||
builder.mixin(card.types.File, card.class.MasterTag, setting.mixin.Editable, {
|
||||
value: false
|
||||
})
|
||||
|
||||
builder.createDoc(view.class.Viewlet, core.space.Model, {
|
||||
attachTo: card.types.File,
|
||||
descriptor: view.viewlet.Table,
|
||||
configOptions: {
|
||||
hiddenKeys: ['content', 'title']
|
||||
},
|
||||
config: [
|
||||
'',
|
||||
'_class',
|
||||
{ key: '', presenter: view.component.RolePresenter, label: card.string.Tags, props: { fullSize: true } },
|
||||
'modifiedOn'
|
||||
]
|
||||
})
|
||||
|
||||
const listConfig: (BuildModelKey | string)[] = [
|
||||
{ key: '', props: { showParent: true }, displayProps: { fixed: 'left', key: 'card' } },
|
||||
{ key: '_class', displayProps: { fixed: 'left', key: 'type' } },
|
||||
{ key: '', displayProps: { grow: true } },
|
||||
{
|
||||
key: '',
|
||||
presenter: view.component.RolePresenter,
|
||||
label: card.string.Tags,
|
||||
props: { fullSize: true },
|
||||
displayProps: { key: 'tags', fixed: 'right' }
|
||||
},
|
||||
{
|
||||
key: 'modifiedOn',
|
||||
displayProps: { fixed: 'right', dividerBefore: true }
|
||||
}
|
||||
]
|
||||
|
||||
builder.createDoc(view.class.Viewlet, core.space.Model, {
|
||||
attachTo: card.types.File,
|
||||
attachTo: type,
|
||||
descriptor: view.viewlet.List,
|
||||
viewOptions: {
|
||||
groupBy: ['_class', 'createdBy', 'modifiedBy'],
|
||||
@ -169,6 +154,31 @@ export function createModel (builder: Builder): void {
|
||||
config: listConfig
|
||||
})
|
||||
|
||||
builder.mixin(type, card.class.MasterTag, setting.mixin.Editable, {
|
||||
value: false
|
||||
})
|
||||
|
||||
builder.createDoc(view.class.Viewlet, core.space.Model, {
|
||||
attachTo: type,
|
||||
descriptor: view.viewlet.Table,
|
||||
configOptions: {
|
||||
hiddenKeys: ['content', 'title']
|
||||
},
|
||||
config: [
|
||||
'',
|
||||
'_class',
|
||||
{ key: '', presenter: view.component.RolePresenter, label: card.string.Tags, props: { fullSize: true } },
|
||||
'modifiedOn'
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
export function createModel (builder: Builder): void {
|
||||
builder.createModel(TMasterTag, TTag, TCard, MasterTagEditorSection)
|
||||
|
||||
createSystemType(builder, card.types.File, attachment.string.File, card.icon.File)
|
||||
createSystemType(builder, card.types.Document, card.string.Document, card.icon.Document)
|
||||
|
||||
builder.createDoc(
|
||||
workbench.class.Application,
|
||||
core.space.Model,
|
||||
@ -210,6 +220,10 @@ export function createModel (builder: Builder): void {
|
||||
card.action.SetParent
|
||||
)
|
||||
|
||||
builder.mixin(card.class.Card, core.class.Class, view.mixin.AttributeEditor, {
|
||||
inlineEditor: card.component.CardEditor
|
||||
})
|
||||
|
||||
createAction(
|
||||
builder,
|
||||
{
|
||||
@ -304,6 +318,10 @@ export function createModel (builder: Builder): void {
|
||||
presenter: card.component.CardPresenter
|
||||
})
|
||||
|
||||
builder.mixin(card.class.Card, core.class.Class, view.mixin.AttributePresenter, {
|
||||
presenter: card.component.CardRefPresenter
|
||||
})
|
||||
|
||||
builder.mixin(card.class.Card, core.class.Class, activity.mixin.ActivityDoc, {})
|
||||
|
||||
builder.createDoc(activity.class.ActivityExtension, core.space.Model, {
|
||||
|
@ -103,6 +103,7 @@
|
||||
{justify}
|
||||
type={attribute?.type}
|
||||
{maxWidth}
|
||||
{attribute}
|
||||
{attributeKey}
|
||||
value={getAttribute(client, object, { key: attributeKey, attr: attribute })}
|
||||
space={object.space}
|
||||
@ -123,6 +124,7 @@
|
||||
disabled={isReadonly}
|
||||
space={object.space}
|
||||
{onChange}
|
||||
{attribute}
|
||||
{focus}
|
||||
{object}
|
||||
{size}
|
||||
|
@ -76,6 +76,7 @@
|
||||
{focus}
|
||||
{focusIndex}
|
||||
{editKind}
|
||||
{attribute}
|
||||
/>
|
||||
{/await}
|
||||
{/if}
|
||||
|
@ -43,4 +43,7 @@
|
||||
<symbol id="view" viewBox="0 0 32 32">
|
||||
<path d="M25.8,2H6.2C3.9,2,2,3.9,2,6.2v19.5C2,28.1,3.9,30,6.2,30h19.5c2.3,0,4.2-1.9,4.2-4.2V6.2C30,3.9,28.1,2,25.8,2z M28,6.2v5.5H13.8V4h12C27,4,28,5,28,6.2z M6.2,4h5.5v7.8H4V6.2C4,5,5,4,6.2,4z M4,25.8v-12h7.8V28H6.2C5,28,4,27,4,25.8z M25.8,28h-12V13.8H28v12C28,27,27,28,25.8,28z" />
|
||||
</symbol>
|
||||
<symbol id="document" viewBox="0 0 32 32">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 4C7.89543 4 7 4.89543 7 6V26C7 27.1046 7.89543 28 9 28H23C24.1046 28 25 27.1046 25 26V12H21C18.7909 12 17 10.2091 17 8V4H9ZM19 4.41421V8C19 9.10457 19.8954 10 21 10H24.5858L19 4.41421ZM5 6C5 3.79086 6.79086 2 9 2H18.5858C19.1162 2 19.6249 2.21071 20 2.58579L26.4142 9C26.7893 9.37507 27 9.88378 27 10.4142V26C27 28.2091 25.2091 30 23 30H9C6.79086 30 5 28.2091 5 26V6ZM10 17C10 16.4477 10.4477 16 11 16H21C21.5523 16 22 16.4477 22 17C22 17.5523 21.5523 18 21 18H11C10.4477 18 10 17.5523 10 17ZM10 23C10 22.4477 10.4477 22 11 22H21C21.5523 22 22 22.4477 22 23C22 23.5523 21.5523 24 21 24H11C10.4477 24 10 23.5523 10 23Z" />
|
||||
</symbol>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 6.4 KiB |
@ -27,6 +27,7 @@
|
||||
"Views": "Zobrazení",
|
||||
"CreateView": "Vytvořit zobrazení",
|
||||
"EditView": "Upravit zobrazení",
|
||||
"SelectViewType": "Vybrat typ zobrazení"
|
||||
"SelectViewType": "Vybrat typ zobrazení",
|
||||
"Document": "Dokument"
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
"Views": "Ansichten",
|
||||
"CreateView": "Ansicht erstellen",
|
||||
"EditView": "Ansicht bearbeiten",
|
||||
"SelectViewType": "Ansichtstyp auswählen"
|
||||
"SelectViewType": "Ansichtstyp auswählen",
|
||||
"Document": "Dokument"
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
"Views": "Views",
|
||||
"CreateView": "Create View",
|
||||
"EditView": "Edit View",
|
||||
"SelectViewType": "Select View Type"
|
||||
"SelectViewType": "Select View Type",
|
||||
"Document": "Document"
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
"Views": "Vistas",
|
||||
"CreateView": "Crear vista",
|
||||
"EditView": "Editar vista",
|
||||
"SelectViewType": "Seleccionar tipo de vista"
|
||||
"SelectViewType": "Seleccionar tipo de vista",
|
||||
"Document": "Documento"
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
"Views": "Vues",
|
||||
"CreateView": "Créer une vue",
|
||||
"EditView": "Modifier la vue",
|
||||
"SelectViewType": "Sélectionner le type de vue"
|
||||
"SelectViewType": "Sélectionner le type de vue",
|
||||
"Document": "Document"
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
"Views": "Viste",
|
||||
"CreateView": "Crea vista",
|
||||
"EditView": "Modifica vista",
|
||||
"SelectViewType": "Seleziona il tipo di vista"
|
||||
"SelectViewType": "Seleziona il tipo di vista",
|
||||
"Document": "Documento"
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
"Views": "Visualizações",
|
||||
"CreateView": "Criar visualização",
|
||||
"EditView": "Editar visualização",
|
||||
"SelectViewType": "Selecionar tipo de visualização"
|
||||
"SelectViewType": "Selecionar tipo de visualização",
|
||||
"Document": "Documento"
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
"Views": "Представления",
|
||||
"CreateView": "Создать представление",
|
||||
"EditView": "Редактировать представление",
|
||||
"SelectViewType": "Выбрать тип представления"
|
||||
"SelectViewType": "Выбрать тип представления",
|
||||
"Document": "Документ"
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
"Views": "视图",
|
||||
"CreateView": "创建视图",
|
||||
"EditView": "编辑视图",
|
||||
"SelectViewType": "选择视图类型"
|
||||
"SelectViewType": "选择视图类型",
|
||||
"Document": "文档"
|
||||
}
|
||||
}
|
@ -22,5 +22,6 @@ loadMetadata(card.icon, {
|
||||
Tag: `${icons}#tag`,
|
||||
Card: `${icons}#card`,
|
||||
File: `${icons}#file`,
|
||||
View: `${icons}#view`
|
||||
View: `${icons}#view`,
|
||||
Document: `${icons}#document`
|
||||
})
|
||||
|
105
plugins/card-resources/src/components/CardEditor.svelte
Normal file
105
plugins/card-resources/src/components/CardEditor.svelte
Normal file
@ -0,0 +1,105 @@
|
||||
<!--
|
||||
// Copyright © 2025 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Card, MasterTag } from '@hcengineering/card'
|
||||
import { AnyAttribute, Ref, RefTo } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import {
|
||||
Button,
|
||||
ButtonKind,
|
||||
ButtonSize,
|
||||
eventToHTMLElement,
|
||||
IconWithEmoji,
|
||||
Label,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import card from '../plugin'
|
||||
import CardsPopup from './CardsPopup.svelte'
|
||||
|
||||
export let value: Ref<Card>
|
||||
export let readonly: boolean = false
|
||||
export let label: IntlString = card.string.Card
|
||||
export let onChange: (value: any) => void
|
||||
export let attribute: AnyAttribute
|
||||
|
||||
export let focusIndex: number | undefined = undefined
|
||||
export let shouldShowLabel: boolean = true
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'left'
|
||||
export let width: string | undefined = 'min-content'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
const handleOpen = (event: MouseEvent): void => {
|
||||
event.stopPropagation()
|
||||
const _class = (attribute.type as RefTo<Card>).to
|
||||
|
||||
if (readonly) {
|
||||
return
|
||||
}
|
||||
|
||||
showPopup(CardsPopup, { selected: value, _class }, eventToHTMLElement(event), change)
|
||||
}
|
||||
|
||||
const change = (val: Card | undefined): void => {
|
||||
if (readonly || val == null || value === val._id) {
|
||||
return
|
||||
}
|
||||
|
||||
value = val._id
|
||||
dispatch('change', value)
|
||||
onChange(value)
|
||||
}
|
||||
|
||||
let doc: Card | undefined
|
||||
|
||||
const query = createQuery()
|
||||
$: query.query(card.class.Card, { _id: value }, (res) => {
|
||||
doc = res[0]
|
||||
})
|
||||
|
||||
$: _classRef = doc?._class ?? (attribute?.type as RefTo<Card>)?.to
|
||||
$: _class = _classRef !== undefined ? (hierarchy.findClass(_classRef) as MasterTag) : undefined
|
||||
|
||||
$: icon = _class?.icon === view.ids.IconWithEmoji ? IconWithEmoji : _class?.icon
|
||||
$: iconProps = _class?.icon === view.ids.IconWithEmoji ? { icon: _class?.color } : {}
|
||||
</script>
|
||||
|
||||
<Button
|
||||
showTooltip={!readonly ? { label } : undefined}
|
||||
{justify}
|
||||
{focusIndex}
|
||||
{width}
|
||||
{size}
|
||||
{icon}
|
||||
{iconProps}
|
||||
{kind}
|
||||
disabled={readonly}
|
||||
on:click={handleOpen}
|
||||
>
|
||||
<div slot="content" class="overflow-label">
|
||||
{#if doc}
|
||||
{doc.title}
|
||||
{:else}
|
||||
<Label {label} />
|
||||
{/if}
|
||||
</div>
|
||||
</Button>
|
@ -0,0 +1,43 @@
|
||||
<!--
|
||||
// Copyright © 2025 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Card } from '@hcengineering/card'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { Asset } from '@hcengineering/platform'
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { AnySvelteComponent } from '@hcengineering/ui'
|
||||
import { ObjectPresenterType } from '@hcengineering/view'
|
||||
import card from '../plugin'
|
||||
import CardPresenter from './CardPresenter.svelte'
|
||||
|
||||
export let value: Ref<Card> | undefined
|
||||
export let kind: 'list' | undefined = undefined
|
||||
export let type: ObjectPresenterType = 'link'
|
||||
export let icon: Asset | AnySvelteComponent | undefined = undefined
|
||||
|
||||
let doc: Card | undefined
|
||||
const query = createQuery()
|
||||
$: value &&
|
||||
query.query(
|
||||
card.class.Card,
|
||||
{ _id: value },
|
||||
(res) => {
|
||||
;[doc] = res
|
||||
},
|
||||
{ limit: 1 }
|
||||
)
|
||||
</script>
|
||||
|
||||
<CardPresenter value={doc} {kind} {type} {icon} />
|
64
plugins/card-resources/src/components/CardsPopup.svelte
Normal file
64
plugins/card-resources/src/components/CardsPopup.svelte
Normal file
@ -0,0 +1,64 @@
|
||||
<!--
|
||||
// Copyright © 2025 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { getClient, ObjectPopup } from '@hcengineering/presentation'
|
||||
import { Card } from '@hcengineering/card'
|
||||
import { Class, Ref } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { Label } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
export let _class: Ref<Class<Card>>
|
||||
export let selected: Ref<Card> | undefined
|
||||
export let multiSelect: boolean = false
|
||||
export let allowDeselect: boolean = true
|
||||
export let titleDeselect: IntlString | undefined = undefined
|
||||
export let readonly = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
</script>
|
||||
|
||||
<ObjectPopup
|
||||
{_class}
|
||||
{selected}
|
||||
{multiSelect}
|
||||
{allowDeselect}
|
||||
{titleDeselect}
|
||||
type={'object'}
|
||||
groupBy={'_class'}
|
||||
on:update
|
||||
on:close
|
||||
on:changeContent
|
||||
on:created={(doc) => dispatch('close', doc.detail)}
|
||||
{readonly}
|
||||
>
|
||||
<svelte:fragment slot="item" let:item={it}>
|
||||
<div class="flex-row-center flex-grow">
|
||||
{it.title}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="category" let:item={it}>
|
||||
{@const cl = hierarchy.getClass(it._class)}
|
||||
<div class="menu-group__header">
|
||||
<span class="overflow-label">
|
||||
<Label label={cl.label} />
|
||||
</span>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</ObjectPopup>
|
@ -39,10 +39,10 @@
|
||||
icon: isMasterTag ? card.icon.MasterTag : card.icon.Tag
|
||||
}
|
||||
|
||||
await client.createDoc(_class, core.space.Model, data)
|
||||
const id = await client.createDoc(_class, core.space.Model, data)
|
||||
Analytics.handleEvent(isMasterTag ? CardEvents.TypeCreated : CardEvents.TagCreated)
|
||||
|
||||
dispatch('close')
|
||||
dispatch('close', id)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -70,7 +70,7 @@
|
||||
size={'medium'}
|
||||
showTooltip={{ label: setting.string.AddAttribute }}
|
||||
on:click={(ev) => {
|
||||
showPopup(setting.component.CreateAttributePopup, { _class: value._class }, 'top')
|
||||
showPopup(setting.component.CreateAttributePopup, { _class: value._class, isCard: true }, 'top')
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
|
@ -69,7 +69,7 @@
|
||||
size={'medium'}
|
||||
showTooltip={{ label: setting.string.AddAttribute }}
|
||||
on:click={(ev) => {
|
||||
showPopup(setting.component.CreateAttributePopup, { _class: tag._id }, 'top')
|
||||
showPopup(setting.component.CreateAttributePopup, { _class: tag._id, isCard: true }, 'top')
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
|
@ -16,7 +16,6 @@
|
||||
import { MasterTag } from '@hcengineering/card'
|
||||
import { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { ClassHierarchy } from '@hcengineering/setting-resources'
|
||||
import { ButtonIcon, getCurrentLocation, Icon, IconAdd, Label, navigate, showPopup } from '@hcengineering/ui'
|
||||
import card from '../../plugin'
|
||||
import CreateTag from '../CreateTag.svelte'
|
||||
|
@ -13,15 +13,30 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { ButtonIcon, IconAdd, showPopup } from '@hcengineering/ui'
|
||||
import { ButtonIcon, getCurrentResolvedLocation, IconAdd, navigate, showPopup } from '@hcengineering/ui'
|
||||
import CreateTag from '../CreateTag.svelte'
|
||||
import card from '../../plugin'
|
||||
import { clearSettingsStore } from '@hcengineering/setting-resources'
|
||||
|
||||
function handleAdd (): void {
|
||||
showPopup(CreateTag, {
|
||||
parent: undefined,
|
||||
_class: card.class.MasterTag
|
||||
})
|
||||
showPopup(
|
||||
CreateTag,
|
||||
{
|
||||
parent: undefined,
|
||||
_class: card.class.MasterTag
|
||||
},
|
||||
undefined,
|
||||
(res) => {
|
||||
if (res != null) {
|
||||
clearSettingsStore()
|
||||
const loc = getCurrentResolvedLocation()
|
||||
loc.path[3] = 'types'
|
||||
loc.path[4] = res
|
||||
loc.path.length = 5
|
||||
navigate(loc)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -20,4 +20,11 @@
|
||||
export let masterTag: MasterTag
|
||||
</script>
|
||||
|
||||
<ClassAttributes ofClass={card.class.Card} _class={masterTag._id} showHierarchy showHeader={false} disabled={false} />
|
||||
<ClassAttributes
|
||||
ofClass={card.class.Card}
|
||||
_class={masterTag._id}
|
||||
showHierarchy
|
||||
showHeader={false}
|
||||
disabled={false}
|
||||
isCard
|
||||
/>
|
||||
|
@ -13,10 +13,11 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import cardPlugin from '@hcengineering/card'
|
||||
import cardPlugin, { MasterTag } from '@hcengineering/card'
|
||||
import core, { Class, ClassifierKind, Doc, Ref } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Icon, Label } from '@hcengineering/ui'
|
||||
import { Icon, IconWithEmoji, Label } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
export let classes: Ref<Class<Doc>>[] = []
|
||||
@ -54,10 +55,14 @@
|
||||
})
|
||||
|
||||
$: fillDescendants(classes)
|
||||
|
||||
function getMasterTag (cl: Ref<Class<Doc>>): MasterTag {
|
||||
return client.getHierarchy().getClass(cl) as MasterTag
|
||||
}
|
||||
</script>
|
||||
|
||||
{#each classes as cl}
|
||||
{@const clazz = client.getHierarchy().getClass(cl)}
|
||||
{@const clazz = getMasterTag(cl)}
|
||||
<button
|
||||
class="hulyTableAttr-content__row justify-start cursor-pointer"
|
||||
on:click={() => {
|
||||
@ -68,7 +73,11 @@
|
||||
class="hulyTableAttr-content__row-label font-medium-14 flex flex-gap-2"
|
||||
style:margin-left={`${level * 1.25}rem`}
|
||||
>
|
||||
<Icon icon={clazz.icon ?? cardPlugin.icon.Tag} size="small" />
|
||||
<Icon
|
||||
icon={clazz.icon === view.ids.IconWithEmoji ? IconWithEmoji : clazz.icon ?? cardPlugin.icon.Tag}
|
||||
iconProps={clazz.icon === view.ids.IconWithEmoji ? { icon: clazz.color, size: 'small' } : {}}
|
||||
size="small"
|
||||
/>
|
||||
<Label label={clazz.label} />
|
||||
</div>
|
||||
</button>
|
||||
|
@ -38,6 +38,8 @@ import SetParentActionPopup from './components/SetParentActionPopup.svelte'
|
||||
import RelationSetting from './components/settings/RelationSetting.svelte'
|
||||
import ViewsSection from './components/settings/view/ViewsSection.svelte'
|
||||
import EditView from './components/settings/view/EditView.svelte'
|
||||
import CardEditor from './components/CardEditor.svelte'
|
||||
import CardRefPresenter from './components/CardRefPresenter.svelte'
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
component: {
|
||||
@ -57,7 +59,9 @@ export default async (): Promise<Resources> => ({
|
||||
SetParentActionPopup,
|
||||
RelationSetting,
|
||||
ViewsSection,
|
||||
EditView
|
||||
EditView,
|
||||
CardEditor,
|
||||
CardRefPresenter
|
||||
},
|
||||
completion: {
|
||||
CardQuery: queryCard
|
||||
|
@ -38,7 +38,9 @@ export default mergeIds(cardId, card, {
|
||||
SetParentActionPopup: '' as AnyComponent,
|
||||
RelationSetting: '' as AnyComponent,
|
||||
ViewsSection: '' as AnyComponent,
|
||||
EditView: '' as AnyComponent
|
||||
EditView: '' as AnyComponent,
|
||||
CardEditor: '' as AnyComponent,
|
||||
CardRefPresenter: '' as AnyComponent
|
||||
},
|
||||
completion: {
|
||||
CardQuery: '' as Resource<ObjectSearchFactory>,
|
||||
@ -71,6 +73,7 @@ export default mergeIds(cardId, card, {
|
||||
Children: '' as IntlString,
|
||||
CreateView: '' as IntlString,
|
||||
EditView: '' as IntlString,
|
||||
SelectViewType: '' as IntlString
|
||||
SelectViewType: '' as IntlString,
|
||||
Document: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
@ -67,7 +67,8 @@ const cardPlugin = plugin(cardId, {
|
||||
MasterTagEditorSection: '' as Ref<Class<MasterTagEditorSection>>
|
||||
},
|
||||
types: {
|
||||
File: '' as Ref<MasterTag>
|
||||
File: '' as Ref<MasterTag>,
|
||||
Document: '' as Ref<MasterTag>
|
||||
},
|
||||
icon: {
|
||||
MasterTags: '' as Asset,
|
||||
@ -76,7 +77,8 @@ const cardPlugin = plugin(cardId, {
|
||||
Tags: '' as Asset,
|
||||
Card: '' as Asset,
|
||||
File: '' as Asset,
|
||||
View: '' as Asset
|
||||
View: '' as Asset,
|
||||
Document: '' as Asset
|
||||
},
|
||||
extensions: {
|
||||
EditCardExtension: '' as ComponentExtensionId
|
||||
|
@ -46,6 +46,7 @@
|
||||
export let showTitle: boolean = !showHierarchy
|
||||
export let showHeader: boolean = true
|
||||
export let disabled: boolean = true
|
||||
export let isCard: boolean = false
|
||||
export let attributeMapper:
|
||||
| {
|
||||
component: AnySvelteComponent
|
||||
@ -90,7 +91,9 @@
|
||||
}
|
||||
|
||||
showPopup(TypesPopup, { _class }, getEventPositionElement(ev), (_id) => {
|
||||
if (_id !== undefined) $settingsStore = { component: CreateAttribute, props: { selectedType: _id, _class } }
|
||||
if (_id !== undefined) {
|
||||
$settingsStore = { component: CreateAttribute, props: { selectedType: _id, _class, isCard } }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@
|
||||
|
||||
export let _id: Ref<Class<Type<PropertyType>>> | undefined = undefined
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let isCard: boolean = false
|
||||
|
||||
let name: string
|
||||
let icon: Asset | undefined
|
||||
@ -93,19 +94,20 @@
|
||||
const items = getTypes()
|
||||
export let selectedType: Ref<Class<Type<PropertyType>>> | undefined = undefined
|
||||
|
||||
$: selectedType && selectType(selectedType)
|
||||
$: selectType(selectedType)
|
||||
|
||||
function selectType (type: Ref<Class<Type<PropertyType>>>): void {
|
||||
function selectType (type: Ref<Class<Type<PropertyType>>> | undefined): void {
|
||||
if (type === undefined) return
|
||||
const _class = hierarchy.getClass(type)
|
||||
const editor = hierarchy.as(_class, view.mixin.ObjectEditor)
|
||||
if (editor.editor !== undefined) {
|
||||
is = editor.editor
|
||||
}
|
||||
}
|
||||
const handleSelection = (e: { detail: Ref<Class<Type<any>>> }) => {
|
||||
const handleSelection = (e: { detail: Ref<Class<Type<any>>> }): void => {
|
||||
selectType(e.detail)
|
||||
}
|
||||
const handleChange = (e: any) => {
|
||||
const handleChange = (e: any): void => {
|
||||
type = e.detail?.type
|
||||
index = e.detail?.index
|
||||
defaultValue = e.detail?.defaultValue
|
||||
@ -169,6 +171,7 @@
|
||||
props={{
|
||||
type,
|
||||
defaultValue,
|
||||
isCard,
|
||||
kind: 'regular',
|
||||
size: 'large'
|
||||
}}
|
||||
|
@ -42,6 +42,8 @@
|
||||
import { IconPicker } from '@hcengineering/view-resources'
|
||||
|
||||
export let _class: Ref<Class<Doc>>
|
||||
export let isCard: boolean = false
|
||||
|
||||
let selectedType: Ref<Class<Type<PropertyType>>> | undefined = undefined
|
||||
|
||||
let name: string
|
||||
@ -159,6 +161,7 @@
|
||||
props={{
|
||||
type,
|
||||
defaultValue,
|
||||
isCard,
|
||||
kind: 'regular',
|
||||
size: 'large'
|
||||
}}
|
||||
|
@ -26,6 +26,7 @@
|
||||
export let editable: boolean = true
|
||||
export let kind: ButtonKind = 'regular'
|
||||
export let size: ButtonSize = 'medium'
|
||||
export let isCard: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
@ -49,7 +50,7 @@
|
||||
|
||||
$: selected = types.find((p) => p._id === refClass)
|
||||
|
||||
const handleChange = (e: any) => {
|
||||
const handleChange = (e: any): void => {
|
||||
const type = e.detail?.type
|
||||
const res = { type: createArrOf(type) }
|
||||
dispatch('change', res)
|
||||
@ -86,6 +87,7 @@
|
||||
props={{
|
||||
type: type?.of,
|
||||
nested: true,
|
||||
isCard,
|
||||
editable,
|
||||
kind,
|
||||
size
|
||||
|
@ -18,37 +18,58 @@
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { DropdownLabelsIntl, Label } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view-resources/src/plugin'
|
||||
import card from '@hcengineering/card'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { ButtonKind, ButtonSize } from '@hcengineering/ui'
|
||||
import type { ButtonKind, ButtonSize, DropdownIntlItem } from '@hcengineering/ui'
|
||||
import contactPlugin from '@hcengineering/contact'
|
||||
|
||||
export let type: RefTo<Doc> | undefined
|
||||
export let editable: boolean = true
|
||||
export let kind: ButtonKind = 'regular'
|
||||
export let size: ButtonSize = 'medium'
|
||||
export let isCard: boolean = false
|
||||
|
||||
const _classes = isCard ? [card.class.Card, contactPlugin.class.Contact] : [core.class.Doc]
|
||||
const exclude = !isCard ? [card.class.Card] : []
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
const descendants = hierarchy.getDescendants(core.class.Doc)
|
||||
const classes = descendants
|
||||
.map((p) => hierarchy.getClass(p))
|
||||
.filter((p) => {
|
||||
return (
|
||||
hierarchy.hasMixin(p, view.mixin.AttributeEditor) &&
|
||||
p.label !== undefined &&
|
||||
hierarchy.getDomain(p._id) !== DOMAIN_STATUS
|
||||
)
|
||||
})
|
||||
.map((p) => {
|
||||
return { id: p._id, label: p.label }
|
||||
})
|
||||
const classes = fillClasses(_classes, exclude)
|
||||
|
||||
function fillClasses (classes: Ref<Class<Doc>>[], exclude: Ref<Class<Doc>>[]): DropdownIntlItem[] {
|
||||
const res: DropdownIntlItem[] = []
|
||||
const descendants = new Set(
|
||||
classes
|
||||
.map((p) => hierarchy.getDescendants(p))
|
||||
.reduce((a, b) => a.concat(b))
|
||||
.filter((p) => p !== card.class.Card)
|
||||
)
|
||||
const excluded = new Set()
|
||||
for (const _class of exclude) {
|
||||
const desc = hierarchy.getDescendants(_class)
|
||||
for (const _id of desc) {
|
||||
excluded.add(_id)
|
||||
}
|
||||
}
|
||||
for (const desc of descendants) {
|
||||
if (excluded.has(desc)) continue
|
||||
const domain = hierarchy.findDomain(desc)
|
||||
if (domain === DOMAIN_STATUS || domain === undefined) continue
|
||||
if (hierarchy.classHierarchyMixin(desc, view.mixin.AttributeEditor) === undefined) continue
|
||||
const _class = hierarchy.getClass(desc)
|
||||
if (_class.label === undefined) continue
|
||||
res.push({ id: _class._id, label: _class.label })
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
let refClass: Ref<Class<Doc>> | undefined = type?.to
|
||||
|
||||
$: selected = classes.find((p) => p.id === refClass)
|
||||
|
||||
$: refClass && dispatch('change', { type: TypeRef(refClass) })
|
||||
$: refClass !== undefined && dispatch('change', { type: TypeRef(refClass) })
|
||||
</script>
|
||||
|
||||
<div class="hulyModal-content__settingsSet-line">
|
||||
|
Loading…
Reference in New Issue
Block a user