mirror of
https://github.com/hcengineering/platform.git
synced 2026-08-17 18:05:42 +02:00
Type export/import (#10373)
* Type export/import Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Fix formatting Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * Fix ID attributes Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> --------- Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
@@ -22,6 +22,8 @@ import {
|
||||
type CardViewDefaults,
|
||||
type CreateCardExtension,
|
||||
DOMAIN_CARD,
|
||||
type ExportExtension,
|
||||
type ExportFunc,
|
||||
type FavoriteCard,
|
||||
type FavoriteType,
|
||||
type MasterTag,
|
||||
@@ -202,6 +204,11 @@ export class TCreateCardExtension extends TMasterTag implements CreateCardExtens
|
||||
canCreate?: CanCreateCardResource
|
||||
}
|
||||
|
||||
@Model(card.class.ExportExtension, core.class.Doc, DOMAIN_MODEL)
|
||||
export class TExportExtension extends TDoc implements ExportExtension {
|
||||
func!: Resource<ExportFunc>
|
||||
}
|
||||
|
||||
export * from './migration'
|
||||
|
||||
const listConfig: (BuildModelKey | string)[] = [
|
||||
@@ -387,7 +394,8 @@ export function createModel (builder: Builder): void {
|
||||
TCardViewDefaults,
|
||||
TFavoriteCard,
|
||||
TFavoriteType,
|
||||
TCreateCardExtension
|
||||
TCreateCardExtension,
|
||||
TExportExtension
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
|
||||
@@ -606,6 +606,10 @@ export function createModel (builder: Builder): void {
|
||||
props: {}
|
||||
})
|
||||
|
||||
builder.createDoc(card.class.ExportExtension, core.space.Model, {
|
||||
func: process.function.ExportProcess
|
||||
})
|
||||
|
||||
builder.createDoc(
|
||||
card.class.CardSection,
|
||||
core.space.Model,
|
||||
|
||||
@@ -315,7 +315,7 @@
|
||||
<slot name="item" item={obj} />
|
||||
{/if}
|
||||
{#if (allowDeselect && selected) || multiSelect || selected}
|
||||
<div class="check" class:disabled={readonly}>
|
||||
<div class="check mr-2" class:disabled={readonly}>
|
||||
{#if obj._id === selected || selectedElements.has(obj._id)}
|
||||
{#if loading}
|
||||
<Spinner size={'small'} />
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"EnableVersioning": "Povolit verzování",
|
||||
"EnableVersioningConfirm": "Chcete povolit verzování?",
|
||||
"NewVersionConfirmation": "Chcete vytvořit novou verzi?",
|
||||
"RelationCopyDescr": "Které vztahy chcete zkopírovat?"
|
||||
"RelationCopyDescr": "Které vztahy chcete zkopírovat?",
|
||||
"Import": "Importovat",
|
||||
"Export": "Exportovat"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"EnableVersioning": "Versionsverwaltung aktivieren",
|
||||
"EnableVersioningConfirm": "Möchten Sie die Versionsverwaltung aktivieren?",
|
||||
"NewVersionConfirmation": "Möchten Sie eine neue Version erstellen?",
|
||||
"RelationCopyDescr": "Welche Beziehungen möchten Sie kopieren?"
|
||||
"RelationCopyDescr": "Welche Beziehungen möchten Sie kopieren?",
|
||||
"Import": "Importieren",
|
||||
"Export": "Exportieren"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"EnableVersioning": "Enable versioning",
|
||||
"EnableVersioningConfirm": "Do you want to enable versioning?",
|
||||
"NewVersionConfirmation": "Do you want to create a new version?",
|
||||
"RelationCopyDescr": "Which relations do you want to copy?"
|
||||
"RelationCopyDescr": "Which relations do you want to copy?",
|
||||
"Import": "Import",
|
||||
"Export": "Export"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"EnableVersioning": "Habilitar control de versiones",
|
||||
"EnableVersioningConfirm": "¿Desea habilitar el control de versiones?",
|
||||
"NewVersionConfirmation": "¿Desea crear una nueva versión?",
|
||||
"RelationCopyDescr": "¿Qué relaciones quieres copiar?"
|
||||
"RelationCopyDescr": "¿Qué relaciones quieres copiar?",
|
||||
"Import": "Importar",
|
||||
"Export": "Exportar"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"EnableVersioning": "Activer la gestion des versions",
|
||||
"EnableVersioningConfirm": "Voulez-vous activer la gestion des versions ?",
|
||||
"NewVersionConfirmation": "Voulez-vous créer une nouvelle version ?",
|
||||
"RelationCopyDescr": "Quelles relations souhaitez-vous copier ?"
|
||||
"RelationCopyDescr": "Quelles relations souhaitez-vous copier ?",
|
||||
"Import": "Importer",
|
||||
"Export": "Exporter"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"EnableVersioning": "Abilita versionamento",
|
||||
"EnableVersioningConfirm": "Vuoi abilitare il versionamento?",
|
||||
"NewVersionConfirmation": "Vuoi creare una nuova versione?",
|
||||
"RelationCopyDescr": "Quali relazioni vuoi copiare?"
|
||||
"RelationCopyDescr": "Quali relazioni vuoi copiare?",
|
||||
"Import": "Importa",
|
||||
"Export": "Esporta"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"EnableVersioning": "バージョン管理を有効にする",
|
||||
"EnableVersioningConfirm": "バージョン管理を有効にしますか?",
|
||||
"NewVersionConfirmation": "新しいバージョンを作成しますか?",
|
||||
"RelationCopyDescr": "どの関連をコピーしますか?"
|
||||
"RelationCopyDescr": "どの関連をコピーしますか?",
|
||||
"Import": "インポート",
|
||||
"Export": "エクスポート"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"EnableVersioning": "Ativar controle de versões",
|
||||
"EnableVersioningConfirm": "Deseja ativar o controle de versões?",
|
||||
"NewVersionConfirmation": "Deseja criar uma nova versão?",
|
||||
"RelationCopyDescr": "Quais relações você deseja copiar?"
|
||||
"RelationCopyDescr": "Quais relações você deseja copiar?",
|
||||
"Import": "Importar",
|
||||
"Export": "Exportar"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"EnableVersioning": "Включить управление версиями",
|
||||
"EnableVersioningConfirm": "Вы хотите включить управление версиями?",
|
||||
"NewVersionConfirmation": "Вы хотите создать новую версию?",
|
||||
"RelationCopyDescr": "Какие связи вы хотите скопировать?"
|
||||
"RelationCopyDescr": "Какие связи вы хотите скопировать?",
|
||||
"Import": "Импортировать",
|
||||
"Export": "Экспортировать"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"EnableVersioning": "Sürümlemeyi etkinleştir",
|
||||
"EnableVersioningConfirm": "Sürümlemeyi etkinleştirmek istiyor musunuz?",
|
||||
"NewVersionConfirmation": "Yeni bir sürüm oluşturmak istiyor musunuz?",
|
||||
"RelationCopyDescr": "Hangi ilişkileri kopyalamak istiyorsunuz?"
|
||||
"RelationCopyDescr": "Hangi ilişkileri kopyalamak istiyorsunuz?",
|
||||
"Import": "İçe aktar",
|
||||
"Export": "Dışa aktar"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
"EnableVersioning": "启用版本控制",
|
||||
"EnableVersioningConfirm": "您要启用版本控制吗?",
|
||||
"NewVersionConfirmation": "您想创建一个新版本吗?",
|
||||
"RelationCopyDescr": "您想复制哪些关系?"
|
||||
"RelationCopyDescr": "您想复制哪些关系?",
|
||||
"Import": "导入",
|
||||
"Export": "导出"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
{noSelect}
|
||||
inline
|
||||
component={card.component.EditCard}
|
||||
shrink={1}
|
||||
shrink={0}
|
||||
title={cardObj?.title}
|
||||
>
|
||||
{#if shouldShowAvatar}
|
||||
@@ -136,7 +136,7 @@
|
||||
{noSelect}
|
||||
inline
|
||||
component={card.component.EditCard}
|
||||
shrink={1}
|
||||
shrink={0}
|
||||
title={cardObj?.title}
|
||||
>
|
||||
{#if shouldShowAvatar}
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Card, MasterTag } from '@hcengineering/card'
|
||||
import { AnyAttribute, Class, Ref, RefTo } from '@hcengineering/core'
|
||||
import { Class, Ref } from '@hcengineering/core'
|
||||
import { IntlString } from '@hcengineering/platform'
|
||||
import { IconWithEmoji, createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Button, ButtonKind, ButtonSize, eventToHTMLElement, Label, showPopup } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import card from '../plugin'
|
||||
import CardPresenter from './CardPresenter.svelte'
|
||||
import CardsPopup from './CardsPopup.svelte'
|
||||
|
||||
export let value: Ref<Card> | undefined
|
||||
@@ -70,9 +70,6 @@
|
||||
|
||||
$: _classRef = doc?._class ?? _class
|
||||
$: clazz = _classRef !== undefined ? (hierarchy.findClass(_classRef) as MasterTag) : undefined
|
||||
|
||||
$: icon = clazz?.icon === view.ids.IconWithEmoji ? IconWithEmoji : clazz?.icon
|
||||
$: iconProps = clazz?.icon === view.ids.IconWithEmoji ? { icon: clazz?.color } : {}
|
||||
</script>
|
||||
|
||||
<Button
|
||||
@@ -81,15 +78,13 @@
|
||||
{focusIndex}
|
||||
{width}
|
||||
{size}
|
||||
{icon}
|
||||
{iconProps}
|
||||
{kind}
|
||||
disabled={readonly}
|
||||
on:click={handleOpen}
|
||||
>
|
||||
<div slot="content" class="overflow-label">
|
||||
{#if doc}
|
||||
{doc.title}
|
||||
<CardPresenter value={doc} type={'text'} />
|
||||
{:else}
|
||||
<Label {label} />
|
||||
{/if}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
let versions: Card[] = []
|
||||
|
||||
const query = createQuery()
|
||||
$: if (enabled) {
|
||||
$: if (enabled === true) {
|
||||
query.query(
|
||||
card.class.Card,
|
||||
{
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
{readonly}
|
||||
>
|
||||
<svelte:fragment slot="item" let:item={it}>
|
||||
<CardPresenter value={it} disabled />
|
||||
<CardPresenter value={it} disabled showVersion={false} type={'text'} />
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="category" let:item={it}>
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { MasterTag } from '@hcengineering/card'
|
||||
import core from '@hcengineering/core'
|
||||
import { TypeNumber } from '@hcengineering/model'
|
||||
import { getEmbeddedLabel, translateCB } from '@hcengineering/platform'
|
||||
import { getClient, IconWithEmoji, MessageBox } from '@hcengineering/presentation'
|
||||
import { getClient, IconDownload, IconWithEmoji, MessageBox } from '@hcengineering/presentation'
|
||||
import setting from '@hcengineering/setting'
|
||||
import {
|
||||
ButtonIcon,
|
||||
@@ -33,9 +34,9 @@
|
||||
} from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import { ColorsPopup, IconPicker } from '@hcengineering/view-resources'
|
||||
import { exportModule } from '../../exporter'
|
||||
import card from '../../plugin'
|
||||
import { deleteMasterTag } from '../../utils'
|
||||
import core from '@hcengineering/core'
|
||||
|
||||
export let masterTag: MasterTag
|
||||
|
||||
@@ -99,6 +100,18 @@
|
||||
)
|
||||
}
|
||||
|
||||
async function handleExport (): Promise<void> {
|
||||
const str = await exportModule(masterTag._id)
|
||||
const blob = new Blob([str], { type: 'application/json' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = `${name}.json`
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
}
|
||||
|
||||
function getTagStyle (color: ColorDefinition): string {
|
||||
return `
|
||||
background: ${color.color + '33'};
|
||||
@@ -130,6 +143,7 @@
|
||||
})
|
||||
}
|
||||
|
||||
let versioningEnabled = h.classHierarchyMixin(masterTag._id, core.mixin.VersionableClass)?.enabled
|
||||
$: versioningEnabled = h.classHierarchyMixin(masterTag._id, core.mixin.VersionableClass)?.enabled
|
||||
</script>
|
||||
|
||||
@@ -165,12 +179,19 @@
|
||||
on:click={showColorPopup}
|
||||
/>
|
||||
</div>
|
||||
<ButtonIcon
|
||||
icon={IconDownload}
|
||||
size={'large'}
|
||||
tooltip={{ label: card.string.Export }}
|
||||
kind={'tertiary'}
|
||||
on:click={handleExport}
|
||||
/>
|
||||
{#if isEditable}
|
||||
<ButtonIcon icon={IconDelete} size={'large'} kind={'tertiary'} on:click={handleDelete} />
|
||||
{/if}
|
||||
</div>
|
||||
{#if !h.isMixin(masterTag._id)}
|
||||
<div>
|
||||
<div class="mx-2">
|
||||
<ToggleWithLabel
|
||||
label={card.string.Versioning}
|
||||
on={versioningEnabled}
|
||||
|
||||
@@ -13,10 +13,17 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { ButtonIcon, getCurrentResolvedLocation, IconAdd, navigate, showPopup } from '@hcengineering/ui'
|
||||
import CreateTag from '../CreateTag.svelte'
|
||||
import card from '../../plugin'
|
||||
import { clearSettingsStore } from '@hcengineering/setting-resources'
|
||||
import {
|
||||
ButtonIcon,
|
||||
getCurrentResolvedLocation,
|
||||
IconAdd,
|
||||
IconAttachment,
|
||||
navigate,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import card from '../../plugin'
|
||||
import CreateTag from '../CreateTag.svelte'
|
||||
|
||||
function handleAdd (): void {
|
||||
showPopup(
|
||||
@@ -38,6 +45,39 @@
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function handleImprot (): Promise<void> {
|
||||
const { importModule } = await import('../../exporter')
|
||||
const input = document.createElement('input')
|
||||
input.type = 'file'
|
||||
input.accept = 'application/json'
|
||||
input.onchange = async (e: Event) => {
|
||||
const target = e.target as HTMLInputElement
|
||||
if (target.files && target.files.length > 0) {
|
||||
const file = target.files[0]
|
||||
const reader = new FileReader()
|
||||
reader.onload = async (event: ProgressEvent<FileReader>) => {
|
||||
if (event.target?.result !== undefined && typeof event.target.result === 'string') {
|
||||
try {
|
||||
await importModule(event.target.result)
|
||||
} catch (err: any) {
|
||||
console.error('Failed to import module:', err)
|
||||
}
|
||||
}
|
||||
}
|
||||
reader.readAsText(file)
|
||||
}
|
||||
}
|
||||
input.click()
|
||||
}
|
||||
</script>
|
||||
|
||||
<ButtonIcon
|
||||
id={'new-master-tag'}
|
||||
icon={IconAttachment}
|
||||
tooltip={{ label: card.string.Import }}
|
||||
kind={'tertiary'}
|
||||
size={'extra-small'}
|
||||
on:click={handleImprot}
|
||||
/>
|
||||
<ButtonIcon id={'new-master-tag'} icon={IconAdd} kind={'tertiary'} size={'extra-small'} on:click={handleAdd} />
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
import core, {
|
||||
type AnyAttribute,
|
||||
type Class,
|
||||
type Doc,
|
||||
type EnumOf,
|
||||
type ModelDb,
|
||||
type Hierarchy,
|
||||
type Ref,
|
||||
type RefTo,
|
||||
type ArrOf,
|
||||
type Data,
|
||||
type AttachedDoc,
|
||||
type AttachedData,
|
||||
type TypeIdentifier
|
||||
} from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import view from '@hcengineering/view'
|
||||
import card from './plugin'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
|
||||
export async function importModule (json: string): Promise<void> {
|
||||
try {
|
||||
const data = JSON.parse(json) as Doc[]
|
||||
const client = getClient()
|
||||
const m = client.getModel()
|
||||
const h = client.getHierarchy()
|
||||
const apply = client.apply('Import')
|
||||
for (const elem of data) {
|
||||
if (m.findObject(elem._id) !== undefined) continue
|
||||
if (h.isDerived(elem._class, core.class.AttachedDoc)) {
|
||||
const attachedDoc = elem as AttachedDoc
|
||||
await apply.addCollection(
|
||||
attachedDoc._class,
|
||||
attachedDoc.space,
|
||||
attachedDoc.attachedTo,
|
||||
attachedDoc.attachedToClass,
|
||||
attachedDoc.collection,
|
||||
stripAttached(attachedDoc),
|
||||
attachedDoc._id
|
||||
)
|
||||
} else {
|
||||
await apply.createDoc(elem._class, elem.space, stripData(elem), elem._id)
|
||||
}
|
||||
}
|
||||
await apply.commit(true)
|
||||
} catch (e) {
|
||||
console.error('Failed to import process module:', e)
|
||||
}
|
||||
}
|
||||
|
||||
function stripAttached (doc: AttachedDoc): AttachedData<AttachedDoc> {
|
||||
const { collection, attachedTo, attachedToClass, ...rest } = strip(doc)
|
||||
return rest
|
||||
}
|
||||
|
||||
function stripData<T extends Doc> (doc: T): Data<T> {
|
||||
const { _id, _class, space, ...rest } = strip(doc)
|
||||
return rest as Data<T>
|
||||
}
|
||||
|
||||
export async function exportModule (_id: Ref<Class<Doc>>): Promise<string> {
|
||||
const processed = new Set<Ref<Doc>>()
|
||||
const res = await exportType(_id, processed)
|
||||
const clear = res.map(strip)
|
||||
const str = JSON.stringify(clear)
|
||||
return str
|
||||
}
|
||||
|
||||
function strip<T extends Doc> (doc: T): Omit<T, 'modifiedBy' | 'modifiedOn' | 'createdBy' | 'createdOn'> {
|
||||
const { modifiedBy, modifiedOn, createdBy, createdOn, ...rest } = doc
|
||||
return rest
|
||||
}
|
||||
|
||||
async function exportAttribute (
|
||||
attr: AnyAttribute,
|
||||
m: ModelDb,
|
||||
h: Hierarchy
|
||||
): Promise<{
|
||||
docs: Doc[]
|
||||
required: Array<Ref<Class<Doc>>>
|
||||
}> {
|
||||
const client = getClient()
|
||||
const docs: Doc[] = []
|
||||
const required: Array<Ref<Class<Doc>>> = []
|
||||
docs.push(attr)
|
||||
|
||||
docs.push(...m.findAllSync(core.class.AttributePermission, { attribute: attr._id }))
|
||||
if (attr.type._class === core.class.TypeIdentifier) {
|
||||
const of = (attr.type as TypeIdentifier).of
|
||||
const seq = await client.findOne(core.class.Sequence, { _id: of })
|
||||
if (seq !== undefined) {
|
||||
seq.sequence = 0
|
||||
docs.push(seq)
|
||||
}
|
||||
}
|
||||
if (attr.type._class === core.class.EnumOf) {
|
||||
const of = (attr.type as EnumOf).of
|
||||
const val = m.findObject(of)
|
||||
if (val !== undefined) docs.push(val)
|
||||
}
|
||||
if (attr.type._class === core.class.RefTo) {
|
||||
const to = (attr.type as RefTo<Doc>).to
|
||||
if (h.isDerived(to, card.class.Card)) {
|
||||
required.push(to)
|
||||
}
|
||||
}
|
||||
if (attr.type._class === core.class.ArrOf) {
|
||||
const of = (attr.type as ArrOf<Doc>).of
|
||||
if (of._class === core.class.RefTo) {
|
||||
const to = (of as RefTo<Doc>).to
|
||||
if (h.isDerived(to, card.class.Card)) {
|
||||
required.push(to)
|
||||
}
|
||||
}
|
||||
if (of._class === core.class.EnumOf) {
|
||||
const val = m.findObject((of as EnumOf).of)
|
||||
if (val !== undefined) docs.push(val)
|
||||
}
|
||||
}
|
||||
return { docs, required }
|
||||
}
|
||||
|
||||
async function exportType (_id: Ref<Class<Doc>>, processed: Set<Ref<Doc>>): Promise<Doc[]> {
|
||||
if (processed.has(_id)) return []
|
||||
const res: Doc[] = []
|
||||
const required: Array<Ref<Class<Doc>>> = []
|
||||
const client = getClient()
|
||||
const m = client.getModel()
|
||||
const h = client.getHierarchy()
|
||||
const type = m.findObject(_id)
|
||||
processed.add(_id)
|
||||
if (type === undefined) return res
|
||||
res.push(type)
|
||||
|
||||
res.push(...m.findAllSync(core.class.ClassPermission, { targetClass: _id }))
|
||||
|
||||
const attrs = h.getOwnAttributes(_id)
|
||||
for (const attr of attrs) {
|
||||
const at = await exportAttribute(attr[1], m, h)
|
||||
res.push(...at.docs)
|
||||
required.push(...at.required)
|
||||
}
|
||||
|
||||
const descendants = h.getDescendants(_id)
|
||||
for (const desc of descendants) {
|
||||
if (h.getClass(desc).extends !== _id) continue
|
||||
required.push(desc)
|
||||
}
|
||||
|
||||
res.push(...m.findAllSync(card.class.Role, { types: _id }))
|
||||
|
||||
res.push(...m.findAllSync(view.class.Viewlet, { attachedTo: _id }))
|
||||
|
||||
const assocA = m.findAllSync(core.class.Association, { classA: _id })
|
||||
for (const assoc of assocA) {
|
||||
res.push(assoc)
|
||||
required.push(assoc.classB)
|
||||
}
|
||||
|
||||
const assocB = m.findAllSync(core.class.Association, { classB: _id })
|
||||
for (const assoc of assocB) {
|
||||
res.push(assoc)
|
||||
required.push(assoc.classA)
|
||||
}
|
||||
|
||||
const extensions = m.findAllSync(card.class.ExportExtension, {})
|
||||
for (const ext of extensions) {
|
||||
const f = await getResource(ext.func)
|
||||
const extRes = f(_id)
|
||||
res.push(...extRes.docs)
|
||||
required.push(...extRes.required)
|
||||
}
|
||||
|
||||
const parent = h.getClass(_id).extends
|
||||
if (parent !== undefined && h.isDerived(parent, card.class.Card) && parent !== card.class.Card) {
|
||||
if (!processed.has(parent)) {
|
||||
required.push(parent)
|
||||
}
|
||||
}
|
||||
|
||||
for (const req of required) {
|
||||
res.push(...(await exportType(req, processed)))
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -128,6 +128,8 @@ export default mergeIds(cardId, card, {
|
||||
Post: '' as IntlString,
|
||||
ShowLess: '' as IntlString,
|
||||
Duplicate: '' as IntlString,
|
||||
Export: '' as IntlString,
|
||||
Import: '' as IntlString,
|
||||
NewVersion: '' as IntlString,
|
||||
Versioning: '' as IntlString,
|
||||
EnableVersioning: '' as IntlString,
|
||||
|
||||
@@ -119,6 +119,15 @@ export interface PermissionObjectClass extends Doc {
|
||||
export type CanCreateCardFn = (space: Ref<Space>, data: Partial<Data<Card>>) => Promise<boolean | Ref<Card>>
|
||||
export type CanCreateCardResource = Resource<CanCreateCardFn>
|
||||
|
||||
export interface ExportExtension extends Doc {
|
||||
func: Resource<ExportFunc>
|
||||
}
|
||||
|
||||
export type ExportFunc = (id: Ref<MasterTag>) => {
|
||||
docs: Doc[]
|
||||
required: Ref<Class<Doc>>[]
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@@ -140,7 +149,8 @@ const cardPlugin = plugin(cardId, {
|
||||
CardSection: '' as Ref<Class<CardSection>>,
|
||||
FavoriteCard: '' as Ref<Class<FavoriteCard>>,
|
||||
FavoriteType: '' as Ref<Class<FavoriteType>>,
|
||||
PermissionObjectClass: '' as Ref<Class<PermissionObjectClass>>
|
||||
PermissionObjectClass: '' as Ref<Class<PermissionObjectClass>>,
|
||||
ExportExtension: '' as Ref<Class<ExportExtension>>
|
||||
},
|
||||
mixin: {
|
||||
CardViewDefaults: '' as Ref<Mixin<CardViewDefaults>>,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { type MasterTag } from '@hcengineering/card'
|
||||
import { type Class, type Doc, type Ref } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import process from './plugin'
|
||||
|
||||
export function exportProcess (_id: Ref<MasterTag>): {
|
||||
docs: Doc[]
|
||||
required: Array<Ref<Class<Doc>>>
|
||||
} {
|
||||
const docs: Doc[] = []
|
||||
const client = getClient()
|
||||
const m = client.getModel()
|
||||
const processes = m.findAllSync(process.class.Process, { masterTag: _id })
|
||||
for (const proc of processes) {
|
||||
docs.push(proc)
|
||||
|
||||
docs.push(...m.findAllSync(process.class.State, { process: proc._id }))
|
||||
|
||||
docs.push(...m.findAllSync(process.class.Transition, { process: proc._id }))
|
||||
}
|
||||
return { docs, required: [] }
|
||||
}
|
||||
@@ -89,6 +89,7 @@ import {
|
||||
eventCheck
|
||||
} from './utils'
|
||||
import FieldChangesEditor from './components/settings/FieldChangesEditor.svelte'
|
||||
import { exportProcess } from './exporter'
|
||||
|
||||
export * from './query'
|
||||
|
||||
@@ -178,6 +179,7 @@ export default async (): Promise<Resources> => ({
|
||||
OnEventCheck: eventCheck
|
||||
},
|
||||
function: {
|
||||
ExportProcess: exportProcess,
|
||||
ShowDoneQuery: showDoneQuery,
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
CreateMiddleware: ProcessMiddleware.create
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Card, MasterTag, Tag } from '@hcengineering/card'
|
||||
import { Card, ExportFunc, MasterTag, Tag } from '@hcengineering/card'
|
||||
import { Association, Class, Client, Doc, DocumentUpdate, ObjQueryType, Rank, Ref, Tx, Type } from '@hcengineering/core'
|
||||
import { Asset, IntlString, Plugin, plugin, Resource } from '@hcengineering/platform'
|
||||
import { ToDo } from '@hcengineering/time'
|
||||
@@ -339,6 +339,7 @@ export default plugin(processId, {
|
||||
ExecutionEmployeeInitiator: '' as Ref<ProcessFunction>,
|
||||
ExecutionInitiator: '' as Ref<ProcessFunction>,
|
||||
EmptyArray: '' as Ref<ProcessFunction>,
|
||||
CurrentDate: '' as Ref<ProcessFunction>
|
||||
CurrentDate: '' as Ref<ProcessFunction>,
|
||||
ExportProcess: '' as Resource<ExportFunc>
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user