From 4a9e49aa6e5ba30cefbc6a90796a61182deb02f5 Mon Sep 17 00:00:00 2001 From: Denis Bykhov Date: Sun, 22 Feb 2026 16:13:28 +0500 Subject: [PATCH 1/2] Process fixes Signed-off-by: Denis Bykhov --- models/card/src/index.ts | 20 +++++ models/card/src/plugin.ts | 1 + plugins/card-assets/lang/cs.json | 3 +- plugins/card-assets/lang/de.json | 3 +- plugins/card-assets/lang/en.json | 3 +- plugins/card-assets/lang/es.json | 3 +- plugins/card-assets/lang/fr.json | 3 +- plugins/card-assets/lang/it.json | 3 +- plugins/card-assets/lang/ja.json | 3 +- plugins/card-assets/lang/pt-br.json | 3 +- plugins/card-assets/lang/pt.json | 3 +- plugins/card-assets/lang/ru.json | 3 +- plugins/card-assets/lang/tr.json | 3 +- plugins/card-assets/lang/zh.json | 3 +- plugins/card-resources/src/plugin.ts | 3 +- .../process-resources/src/functions.ts | 81 ++++++++++++++++--- 16 files changed, 119 insertions(+), 22 deletions(-) diff --git a/models/card/src/index.ts b/models/card/src/index.ts index bf8285fa0b8..653800d84f5 100644 --- a/models/card/src/index.ts +++ b/models/card/src/index.ts @@ -459,6 +459,26 @@ export function createModel (builder: Builder): void { card.ids.CardNotificationGroup ) + builder.createDoc( + notification.class.NotificationType, + core.space.Model, + { + hidden: false, + generated: false, + label: card.string.CardCreated, + group: card.ids.CardNotificationGroup, + txClasses: [core.class.TxCreateDoc], + objectClass: card.class.Card, + defaultEnabled: true, + templates: { + textTemplate: '{body}', + htmlTemplate: '

{body}

{link}

', + subjectTemplate: '{title} created' + } + }, + card.ids.CardCreateNotification + ) + builder.createDoc( notification.class.NotificationType, core.space.Model, diff --git a/models/card/src/plugin.ts b/models/card/src/plugin.ts index 09c392a7554..1aff4c71682 100644 --- a/models/card/src/plugin.ts +++ b/models/card/src/plugin.ts @@ -55,6 +55,7 @@ export default mergeIds(cardId, card, { ManageMasterTags: '' as Ref, TagRelations: '' as Ref, CardNotificationGroup: '' as Ref, + CardCreateNotification: '' as Ref, CardNotification: '' as Ref, CardMessageNotification: '' as Ref }, diff --git a/plugins/card-assets/lang/cs.json b/plugins/card-assets/lang/cs.json index c66e477bd6b..51c4d78f81d 100644 --- a/plugins/card-assets/lang/cs.json +++ b/plugins/card-assets/lang/cs.json @@ -71,6 +71,7 @@ "RelationCopyDescr": "Které vztahy chcete zkopírovat?", "Import": "Importovat", "Export": "Exportovat", - "CardUpdated": "Karta aktualizována" + "CardUpdated": "Karta aktualizována", + "CardCreated": "Karta vytvořena" } } diff --git a/plugins/card-assets/lang/de.json b/plugins/card-assets/lang/de.json index 1524d538ea9..902126e9678 100644 --- a/plugins/card-assets/lang/de.json +++ b/plugins/card-assets/lang/de.json @@ -71,6 +71,7 @@ "RelationCopyDescr": "Welche Beziehungen möchten Sie kopieren?", "Import": "Importieren", "Export": "Exportieren", - "CardUpdated": "Karte aktualisiert" + "CardUpdated": "Karte aktualisiert", + "CardCreated": "Karte erstellt" } } diff --git a/plugins/card-assets/lang/en.json b/plugins/card-assets/lang/en.json index b3eb41e468c..0b9023c4874 100644 --- a/plugins/card-assets/lang/en.json +++ b/plugins/card-assets/lang/en.json @@ -71,6 +71,7 @@ "RelationCopyDescr": "Which relations do you want to copy?", "Import": "Import", "Export": "Export", - "CardUpdated": "Card updated" + "CardUpdated": "Card updated", + "CardCreated": "Card created" } } diff --git a/plugins/card-assets/lang/es.json b/plugins/card-assets/lang/es.json index ac1f754c3b6..8205357c9f6 100644 --- a/plugins/card-assets/lang/es.json +++ b/plugins/card-assets/lang/es.json @@ -71,6 +71,7 @@ "RelationCopyDescr": "¿Qué relaciones quieres copiar?", "Import": "Importar", "Export": "Exportar", - "CardUpdated": "Tarjeta actualizada" + "CardUpdated": "Tarjeta actualizada", + "CardCreated": "Tarjeta creada" } } diff --git a/plugins/card-assets/lang/fr.json b/plugins/card-assets/lang/fr.json index 0a4867c3aff..2657f7634cc 100644 --- a/plugins/card-assets/lang/fr.json +++ b/plugins/card-assets/lang/fr.json @@ -71,6 +71,7 @@ "RelationCopyDescr": "Quelles relations souhaitez-vous copier ?", "Import": "Importer", "Export": "Exporter", - "CardUpdated": "Carte mise à jour" + "CardUpdated": "Carte mise à jour", + "CardCreated": "Carte créée" } } diff --git a/plugins/card-assets/lang/it.json b/plugins/card-assets/lang/it.json index 98976f5e50e..ba7f95d464d 100644 --- a/plugins/card-assets/lang/it.json +++ b/plugins/card-assets/lang/it.json @@ -71,6 +71,7 @@ "RelationCopyDescr": "Quali relazioni vuoi copiare?", "Import": "Importa", "Export": "Esporta", - "CardUpdated": "Scheda aggiornata" + "CardUpdated": "Scheda aggiornata", + "CardCreated": "Scheda creata" } } diff --git a/plugins/card-assets/lang/ja.json b/plugins/card-assets/lang/ja.json index 5b18951fe03..c589cf68d3b 100644 --- a/plugins/card-assets/lang/ja.json +++ b/plugins/card-assets/lang/ja.json @@ -71,6 +71,7 @@ "RelationCopyDescr": "どの関連をコピーしますか?", "Import": "インポート", "Export": "エクスポート", - "CardUpdated": "カードが更新されました" + "CardUpdated": "カードが更新されました", + "CardCreated": "カードが作成されました" } } diff --git a/plugins/card-assets/lang/pt-br.json b/plugins/card-assets/lang/pt-br.json index b5b5f4860ad..304615abac9 100644 --- a/plugins/card-assets/lang/pt-br.json +++ b/plugins/card-assets/lang/pt-br.json @@ -71,6 +71,7 @@ "RelationCopyDescr": "Quais relações você deseja copiar?", "Import": "Importar", "Export": "Exportar", - "CardUpdated": "Cartão atualizado" + "CardUpdated": "Cartão atualizado", + "CardCreated": "Cartão criado" } } diff --git a/plugins/card-assets/lang/pt.json b/plugins/card-assets/lang/pt.json index c2148a4c4b4..e5eb7e1ae93 100644 --- a/plugins/card-assets/lang/pt.json +++ b/plugins/card-assets/lang/pt.json @@ -71,6 +71,7 @@ "RelationCopyDescr": "Quais relações você deseja copiar?", "Import": "Importar", "Export": "Exportar", - "CardUpdated": "Cartão atualizado" + "CardUpdated": "Cartão atualizado", + "CardCreated": "Cartão criado" } } diff --git a/plugins/card-assets/lang/ru.json b/plugins/card-assets/lang/ru.json index 98ef2647baf..cfe4838c571 100644 --- a/plugins/card-assets/lang/ru.json +++ b/plugins/card-assets/lang/ru.json @@ -71,6 +71,7 @@ "RelationCopyDescr": "Какие связи вы хотите скопировать?", "Import": "Импортировать", "Export": "Экспортировать", - "CardUpdated": "Карточка обновлена" + "CardUpdated": "Карточка обновлена", + "CardCreated": "Карточка создана" } } diff --git a/plugins/card-assets/lang/tr.json b/plugins/card-assets/lang/tr.json index f0522bfaae5..42629f235aa 100644 --- a/plugins/card-assets/lang/tr.json +++ b/plugins/card-assets/lang/tr.json @@ -71,6 +71,7 @@ "RelationCopyDescr": "Hangi ilişkileri kopyalamak istiyorsunuz?", "Import": "İçe aktar", "Export": "Dışa aktar", - "CardUpdated": "Kart güncellendi" + "CardUpdated": "Kart güncellendi", + "CardCreated": "Kart oluşturuldu" } } diff --git a/plugins/card-assets/lang/zh.json b/plugins/card-assets/lang/zh.json index 371a92de03c..f16cc1e542b 100644 --- a/plugins/card-assets/lang/zh.json +++ b/plugins/card-assets/lang/zh.json @@ -71,6 +71,7 @@ "RelationCopyDescr": "您想复制哪些关系?", "Import": "导入", "Export": "导出", - "CardUpdated": "卡片已更新" + "CardUpdated": "卡片已更新", + "CardCreated": "卡片已创建" } } diff --git a/plugins/card-resources/src/plugin.ts b/plugins/card-resources/src/plugin.ts index 0ea733cab93..215ee5ce4e5 100644 --- a/plugins/card-resources/src/plugin.ts +++ b/plugins/card-resources/src/plugin.ts @@ -160,6 +160,7 @@ export default mergeIds(cardId, card, { ForbidCreateCardPermission: '' as IntlString, ForbidAddTagPermission: '' as IntlString, ForbidRemoveTag: '' as IntlString, - CardUpdated: '' as IntlString + CardUpdated: '' as IntlString, + CardCreated: '' as IntlString } }) diff --git a/server-plugins/process-resources/src/functions.ts b/server-plugins/process-resources/src/functions.ts index a9bd804fae4..268be394006 100644 --- a/server-plugins/process-resources/src/functions.ts +++ b/server-plugins/process-resources/src/functions.ts @@ -20,6 +20,7 @@ import core, { Class, Data, Doc, + fillDefaults, findProperty, generateId, getObjectValue, @@ -110,6 +111,7 @@ export async function CheckSubProcessMatch ( const subExecutions = await control.client.findAll(process.class.Execution, { parentId: execution._id, + status: { $ne: ExecutionStatus.Cancelled }, process: targetProcess }) @@ -315,19 +317,31 @@ export async function AddTag ( const res: Tx[] = [] const _process = control.client.getModel().findObject(execution.process) if (_process === undefined) throw processError(process.error.ObjectNotFound, { _id: execution.process }) + // todo fill default for tag and set parent tags const tx = control.client.txFactory.createTxMixin(execution.card, _process.masterTag, execution.space, tagId, props) res.push(tx) const card = control.cache.get(execution.card) const cardWithMixin = card !== undefined ? TxProcessor.updateMixin4Doc(control.client.getHierarchy().clone(card), tx) : undefined - const rollback = control.client.txFactory.createTxUpdateDoc(_process.masterTag, execution.space, execution.card, { - $unset: { [tagId]: true } - }) + const rollback: Tx[] = [ + control.client.txFactory.createTxUpdateDoc(_process.masterTag, execution.space, execution.card, { + $unset: { [tagId]: true } + }) + ] + + const processes = control.client + .getModel() + .findAllSync(process.class.Process, { masterTag: _process.masterTag, autoStart: true }) + for (const proc of processes) { + const [txes, rbTxes] = await createExecution(proc._id, execution.card, execution, control) + res.push(...txes) + rollback.push(...rbTxes) + } return { txes: res, - rollback: [rollback], + rollback, context: [ { _id: execution.card, @@ -704,11 +718,10 @@ export async function CreateCard ( throw processError(process.error.RequiredParamsNotProvided, { params: key }) } } + const masterTag = _class as Ref const _id = generateId() const newContent = - content !== undefined && !isEmpty(content) - ? await getContent(control, content, _id, _class as Ref>) - : content + content !== undefined && !isEmpty(content) ? await getContent(control, content, _id, masterTag) : content const data = { title, ...attrs @@ -716,9 +729,26 @@ export async function CreateCard ( if (newContent !== undefined) { data.content = content } - const tx = control.client.txFactory.createTxCreateDoc(_class as Ref, execution.space, data, _id) + const filledData = fillDefaults(control.client.getHierarchy(), data, masterTag) + + const tx = control.client.txFactory.createTxCreateDoc(masterTag, execution.space, filledData, _id) const res: Tx[] = [tx] - const rollback: Tx[] = [control.client.txFactory.createTxRemoveDoc(_class as Ref, execution.space, _id)] + const rollback: Tx[] = [control.client.txFactory.createTxRemoveDoc(masterTag, execution.space, _id)] + + const ancestors = control.client + .getHierarchy() + .getAncestors(masterTag) + .filter((p) => control.client.getHierarchy().isDerived(p, cardPlugin.class.Card)) + + const processes = control.client.getModel().findAllSync(process.class.Process, { + masterTag: { $in: ancestors }, + autoStart: true + }) + for (const proc of processes) { + const [txes, rbTxes] = await createExecution(proc._id, _id, execution, control) + res.push(...txes) + rollback.push(...rbTxes) + } return { txes: res, rollback, @@ -734,3 +764,36 @@ export async function CreateCard ( function isEmpty (value: any): boolean { return value === undefined || value === null || (typeof value === 'string' && value.trim() === '') } + +async function createExecution ( + proc: Ref, + _id: Ref, + execution: Execution, + control: ProcessControl +): Promise<[Tx[], Tx[]]> { + const res: Tx[] = [] + const rollback: Tx[] = [] + const initTransition = control.client.getModel().findAllSync(process.class.Transition, { + process: proc, + from: null + })[0] + if (initTransition === undefined) return [res, rollback] + const execId = generateId() + const tx = control.client.txFactory.createTxCreateDoc( + process.class.Execution, + execution.space, + { + process: proc, + currentState: initTransition.to, + card: _id, + rollback: [], + context: {}, + status: ExecutionStatus.Active + }, + execId + ) + + res.push(tx) + rollback.push(control.client.txFactory.createTxRemoveDoc(process.class.Execution, execution.space, execId)) + return [res, rollback] +} From 29f9a765a17d74cd3abe59e3143ddd881cc67bab Mon Sep 17 00:00:00 2001 From: Denis Bykhov Date: Sun, 22 Feb 2026 16:37:17 +0500 Subject: [PATCH 2/2] Some fixes Signed-off-by: Denis Bykhov --- .../src/components/settings/SubProcessEditor.svelte | 4 +--- server-plugins/process-resources/src/transform.ts | 2 +- server-plugins/process-resources/src/utils.ts | 7 +++++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/plugins/process-resources/src/components/settings/SubProcessEditor.svelte b/plugins/process-resources/src/components/settings/SubProcessEditor.svelte index 557bb4ed96c..5a2f2c9ca47 100644 --- a/plugins/process-resources/src/components/settings/SubProcessEditor.svelte +++ b/plugins/process-resources/src/components/settings/SubProcessEditor.svelte @@ -60,9 +60,7 @@ $: selected = _id !== undefined ? items.find((it) => it.id === _id)?.id : undefined - $: processes = client - .getModel() - .findAllSync(plugin.class.Process, { masterTag: { $in: ancestors }, _id: { $ne: process._id } }) + $: processes = client.getModel().findAllSync(plugin.class.Process, { masterTag: { $in: ancestors } }) function changeThis (): void { step.params = {} diff --git a/server-plugins/process-resources/src/transform.ts b/server-plugins/process-resources/src/transform.ts index 88762a5ec17..e88a452ce9a 100644 --- a/server-plugins/process-resources/src/transform.ts +++ b/server-plugins/process-resources/src/transform.ts @@ -39,7 +39,7 @@ export function Random (value: Doc[]): Doc { } export function All (value: Doc[]): Doc[] { - return value + return value ?? [] } export async function FirstMatchValue ( diff --git a/server-plugins/process-resources/src/utils.ts b/server-plugins/process-resources/src/utils.ts index bd8a7306c85..e26f9996cac 100644 --- a/server-plugins/process-resources/src/utils.ts +++ b/server-plugins/process-resources/src/utils.ts @@ -178,11 +178,14 @@ async function getRelationValue ( const q = context.direction === 'A' ? { docB: execution.card } : { docA: execution.card } const relations = await control.client.findAll(core.class.Relation, { association: assoc._id, ...q }) const name = context.direction === 'A' ? assoc.nameA : assoc.nameB - if (relations.length === 0) throw processError(process.error.RelatedObjectNotFound, { attr: name }) + const shouldBeArray = assoc.type === 'N:N' || (assoc.type === '1:N' && context.direction === 'A') + if (relations.length === 0) { + if (shouldBeArray) return [] + throw processError(process.error.RelatedObjectNotFound, { attr: name }) + } const ids = relations.map((it) => { return context.direction === 'A' ? it.docA : it.docB }) - const shouldBeArray = assoc.type === 'N:N' || (assoc.type === '1:N' && context.direction === 'A') const target = await control.client.findAll(targetClass, { _id: { $in: ids } }) if (target.length === 0) throw processError(process.error.RelatedObjectNotFound, { attr: context.name }) const attr = context.key !== '' ? control.client.getHierarchy().findAttribute(targetClass, context.key) : undefined