Change card type (#8331)
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-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
CI / uitest (push) Waiting to run

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov 2025-03-24 19:41:04 +05:00 committed by GitHub
parent 34fc0024d3
commit 2cbb74495a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 157 additions and 13 deletions

View File

@ -435,6 +435,25 @@ export function createModel (builder: Builder): void {
}
})
createAction(builder, {
action: view.actionImpl.ShowPopup,
actionProps: {
component: card.component.ChangeType,
fillProps: {
_object: 'value'
}
},
label: card.string.ChangeType,
input: 'focus',
icon: card.icon.MasterTag,
category: setting.category.Settings,
target: card.class.Card,
context: {
mode: ['context', 'browser'],
group: 'edit'
}
})
createAction(builder, {
action: view.actionImpl.ShowPopup,
actionProps: {

View File

@ -28,6 +28,7 @@
"CreateView": "Vytvořit zobrazení",
"EditView": "Upravit zobrazení",
"SelectViewType": "Vybrat typ zobrazení",
"Document": "Dokument"
"Document": "Dokument",
"ChangeType": "Změnit typ"
}
}

View File

@ -28,6 +28,7 @@
"CreateView": "Ansicht erstellen",
"EditView": "Ansicht bearbeiten",
"SelectViewType": "Ansichtstyp auswählen",
"Document": "Dokument"
"Document": "Dokument",
"ChangeType": "Typ ändern"
}
}

View File

@ -28,6 +28,7 @@
"CreateView": "Create View",
"EditView": "Edit View",
"SelectViewType": "Select View Type",
"Document": "Document"
"Document": "Document",
"ChangeType": "Change type"
}
}

View File

@ -28,6 +28,7 @@
"CreateView": "Crear vista",
"EditView": "Editar vista",
"SelectViewType": "Seleccionar tipo de vista",
"Document": "Documento"
"Document": "Documento",
"ChangeType": "Cambiar tipo"
}
}

View File

@ -28,6 +28,7 @@
"CreateView": "Créer une vue",
"EditView": "Modifier la vue",
"SelectViewType": "Sélectionner le type de vue",
"Document": "Document"
"Document": "Document",
"ChangeType": "Changer de type"
}
}

View File

@ -28,6 +28,7 @@
"CreateView": "Crea vista",
"EditView": "Modifica vista",
"SelectViewType": "Seleziona il tipo di vista",
"Document": "Documento"
"Document": "Documento",
"ChangeType": "Cambia tipo"
}
}

View File

@ -28,6 +28,7 @@
"CreateView": "Criar visualização",
"EditView": "Editar visualização",
"SelectViewType": "Selecionar tipo de visualização",
"Document": "Documento"
"Document": "Documento",
"ChangeType": "Alterar tipo"
}
}

View File

@ -28,6 +28,7 @@
"CreateView": "Создать представление",
"EditView": "Редактировать представление",
"SelectViewType": "Выбрать тип представления",
"Document": "Документ"
"Document": "Документ",
"ChangeType": "Изменить тип"
}
}

View File

@ -28,6 +28,7 @@
"CreateView": "创建视图",
"EditView": "编辑视图",
"SelectViewType": "选择视图类型",
"Document": "文档"
"Document": "文档",
"ChangeType": "更改类型"
}
}

View File

@ -0,0 +1,111 @@
<!--
// 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 { Analytics } from '@hcengineering/analytics'
import { Card, CardEvents, MasterTag } from '@hcengineering/card'
import { AnyAttribute, fillDefaults, Ref } from '@hcengineering/core'
import { Card as CardModal, createQuery, getClient } from '@hcengineering/presentation'
import { createFocusManager, DropdownLabelsIntl, FocusHandler } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { deepEqual } from 'fast-equals'
import card from '../plugin'
export let value: Card
const client = getClient()
const hierarchy = client.getHierarchy()
let selected: Ref<MasterTag> | undefined = value._class
$: mapping = buildMapping(selected, value._class)
async function changeType (): Promise<void> {
if (selected === undefined || selected === value._class) return
const cloned = hierarchy.clone(value)
applyMapping(cloned, mapping)
const update = fillDefaults(hierarchy, cloned, selected)
const ops = client.apply('changeType', 'ChangeType')
await ops.update(value, { _class: selected } as any)
if (Object.keys(update).length > 0) {
await ops.diffUpdate(value, update)
}
await ops.commit()
Analytics.handleEvent(CardEvents.TypeCreated)
}
function applyMapping (object: Card, mapping: Record<string, AnyAttribute>): void {
for (const [key, value] of Object.entries(mapping)) {
if ((object as any)[key] !== undefined) {
;(object as any)[value.name] = (object as any)[key]
}
}
}
let types: MasterTag[] = []
$: items = types.map((x) => ({
id: x._id,
label: x.label
}))
function buildMapping (selected: Ref<MasterTag> | undefined, current: Ref<MasterTag>): Record<string, AnyAttribute> {
if (selected === undefined || selected === current) return {}
const selectedAttributes = hierarchy.getAllAttributes(selected, card.class.Card)
const currentAttributes = hierarchy.getAllAttributes(current, card.class.Card)
const res: Record<string, AnyAttribute> = {}
for (const curr of currentAttributes) {
// matched, don't need to do anything
if ((selectedAttributes as any)[curr[0]] !== undefined) {
res[curr[0]] = curr[1]
continue
}
const selectedValues = [...selectedAttributes.values()]
const matched = selectedValues.find((p) => p.label === curr[1].label && deepEqual(p.type, curr[1].type))
if (matched !== undefined) {
res[curr[0]] = matched
}
}
return res
}
const clQuery = createQuery()
clQuery.query(card.class.MasterTag, { _class: card.class.MasterTag }, (res) => {
types = res
})
const manager = createFocusManager()
async function select (event: CustomEvent): Promise<void> {
selected = event.detail
}
const dispatch = createEventDispatcher()
</script>
<FocusHandler {manager} />
<CardModal
label={card.string.ChangeType}
okAction={changeType}
canSave={selected !== undefined && selected !== value._class}
gap={'gapV-4'}
on:close={() => {
dispatch('close')
}}
on:changeContent
>
<DropdownLabelsIntl {items} {selected} focusIndex={0} label={card.string.MasterTag} on:selected={select} />
</CardModal>

View File

@ -40,6 +40,7 @@ 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'
import ChangeType from './components/ChangeType.svelte'
export default async (): Promise<Resources> => ({
component: {
@ -61,7 +62,8 @@ export default async (): Promise<Resources> => ({
ViewsSection,
EditView,
CardEditor,
CardRefPresenter
CardRefPresenter,
ChangeType
},
completion: {
CardQuery: queryCard

View File

@ -40,7 +40,8 @@ export default mergeIds(cardId, card, {
ViewsSection: '' as AnyComponent,
EditView: '' as AnyComponent,
CardEditor: '' as AnyComponent,
CardRefPresenter: '' as AnyComponent
CardRefPresenter: '' as AnyComponent,
ChangeType: '' as AnyComponent
},
completion: {
CardQuery: '' as Resource<ObjectSearchFactory>,
@ -74,6 +75,7 @@ export default mergeIds(cardId, card, {
CreateView: '' as IntlString,
EditView: '' as IntlString,
SelectViewType: '' as IntlString,
Document: '' as IntlString
Document: '' as IntlString,
ChangeType: '' as IntlString
}
})

View File

@ -3,5 +3,6 @@ export enum CardEvents {
TagCreated = 'card.card.TagCreated',
RelationCreated = 'card.card.RelationCreated',
CardCreated = 'card.card.Created',
CardOpened = 'card.card.Opened'
CardOpened = 'card.card.Opened',
TypeChanged = 'card.card.TypeChanged'
}