diff --git a/models/process/src/index.ts b/models/process/src/index.ts index 3e5820e4fe..9b04243839 100644 --- a/models/process/src/index.ts +++ b/models/process/src/index.ts @@ -1118,6 +1118,7 @@ export function createModel (builder: Builder): void { { label: process.string.OnSubProcessesDone, icon: process.icon.WaitSubprocesses, + checkFunction: process.triggerCheck.SubProcessesDoneCheck, requiredParams: [], init: false, auto: true diff --git a/models/server-process/src/index.ts b/models/server-process/src/index.ts index bdd6d59bf5..7a0d7238e8 100644 --- a/models/server-process/src/index.ts +++ b/models/server-process/src/index.ts @@ -16,7 +16,7 @@ import core, { type Doc } from '@hcengineering/core' import { Mixin, type Builder } from '@hcengineering/model' import { TMethod, TProcessFunction, TTrigger } from '@hcengineering/model-process' import type { Resource } from '@hcengineering/platform' -import process, { ExecutionStatus, type CheckFunc } from '@hcengineering/process' +import process, { ExecutionStatus } from '@hcengineering/process' import serverCore from '@hcengineering/server-core' import serverProcess, { type RollbackFunc, @@ -24,7 +24,8 @@ import serverProcess, { type FuncImpl, type MethodImpl, type TransformFunc, - type TriggerImpl + type TriggerImpl, + type CheckFunc } from '@hcengineering/server-process' export { serverProcessId } from '@hcengineering/server-process' @@ -68,7 +69,8 @@ export function createModel (builder: Builder): void { }) builder.mixin(process.trigger.OnSubProcessesDone, process.class.Trigger, serverProcess.mixin.TriggerImpl, { - preventRollback: true + preventRollback: true, + serverCheckFunc: serverProcess.func.CheckSubProcessesDone }) builder.mixin(process.method.RunSubProcess, process.class.Method, serverProcess.mixin.MethodImpl, { diff --git a/plugins/process-resources/src/components/settings/AsideTransitionEditor.svelte b/plugins/process-resources/src/components/settings/AsideTransitionEditor.svelte index dd5251d58d..c593bb205c 100644 --- a/plugins/process-resources/src/components/settings/AsideTransitionEditor.svelte +++ b/plugins/process-resources/src/components/settings/AsideTransitionEditor.svelte @@ -78,6 +78,10 @@ items={triggersItems} bind:selected={selectedTrigger} label={plugin.string.Trigger} + on:change={() => { + params = {} + result = null + }} justify={'left'} width={'100%'} kind={'no-border'} diff --git a/plugins/process-resources/src/index.ts b/plugins/process-resources/src/index.ts index daf11a4726..612de16c9c 100644 --- a/plugins/process-resources/src/index.ts +++ b/plugins/process-resources/src/index.ts @@ -80,7 +80,8 @@ import { showDoneQuery, timeTransitionCheck, todoTranstionCheck, - updateCardTranstionCheck + updateCardTranstionCheck, + subProcessesDoneCheck } from './utils' export * from './query' @@ -160,6 +161,7 @@ export default async (): Promise => ({ }, triggerCheck: { UpdateCheck: updateCardTranstionCheck, + SubProcessesDoneCheck: subProcessesDoneCheck, ToDo: todoTranstionCheck, Time: timeTransitionCheck }, diff --git a/plugins/process-resources/src/middleware.ts b/plugins/process-resources/src/middleware.ts index 23cb079f27..984e5d3684 100644 --- a/plugins/process-resources/src/middleware.ts +++ b/plugins/process-resources/src/middleware.ts @@ -88,13 +88,7 @@ export class ProcessMiddleware extends BasePresentationMiddleware implements Pre from: execution.currentState, trigger: process.trigger.OnCardUpdate }) - const transition = await pickTransition( - this.client.getModel(), - this.client.getHierarchy(), - execution, - transitions, - updated - ) + const transition = await pickTransition(this.client, execution, transitions, updated) if (transition === undefined) return const context = await getNextStateUserInput(execution, transition, execution.context) const txop = new TxOperations(this.client, getCurrentAccount().primarySocialId) @@ -158,13 +152,7 @@ export class ProcessMiddleware extends BasePresentationMiddleware implements Pre from: execution.currentState, trigger: process.trigger.OnToDoClose }) - const transition = await pickTransition( - this.client.getModel(), - this.client.getHierarchy(), - execution, - transitions, - todo - ) + const transition = await pickTransition(this.client, execution, transitions, todo) if (transition === undefined) return const context = await getNextStateUserInput(execution, transition, execution.context) const txop = new TxOperations(this.client, getCurrentAccount().primarySocialId) diff --git a/plugins/process-resources/src/query.ts b/plugins/process-resources/src/query.ts index 97bbe7a163..d93249d62e 100644 --- a/plugins/process-resources/src/query.ts +++ b/plugins/process-resources/src/query.ts @@ -149,7 +149,7 @@ export function parseValue (modes: Mode[], value: any): [any, Mode] { if (mode.parse !== undefined) { return [mode.parse(obj2[key2]), mode] } - return [obj2[key2], mode] + return [mode.withoutEditor === true ? undefined : obj2[key2], mode] } obj1 = obj1[key1] obj2 = obj2[key2] @@ -168,10 +168,10 @@ export function buildResult (mode: Mode, value: any): any { const key = Object.keys(q)[0] const v: any = (q as any)[key] if (typeof v !== 'object') { - if (typeof value === 'string') { + if (typeof value === 'string' && typeof v === 'string') { res[key] = v.replace('$val', value) } else { - res[key] = value + res[key] = mode.withoutEditor === true ? v : value ?? v } return result } diff --git a/plugins/process-resources/src/utils.ts b/plugins/process-resources/src/utils.ts index 58e4b8c7ea..6b5c4affa4 100644 --- a/plugins/process-resources/src/utils.ts +++ b/plugins/process-resources/src/utils.ts @@ -21,9 +21,7 @@ import core, { type Doc, type DocumentQuery, generateId, - type Hierarchy, matchQuery, - type ModelDb, type Ref, type RefTo, type Space, @@ -110,20 +108,19 @@ export function getContextMasterTag ( } export async function pickTransition ( - model: ModelDb, - hierarchy: Hierarchy, + client: Client, execution: Execution, transitions: Transition[], doc: Doc ): Promise { for (const tr of transitions) { - const trigger = model.findObject(tr.trigger) + const trigger = client.getModel().findObject(tr.trigger) if (trigger === undefined) continue if (trigger.checkFunction === undefined) return tr const filled = fillParams(tr.triggerParams, execution) const checkFunc = await getResource(trigger.checkFunction) if (checkFunc === undefined) continue - const res = await checkFunc(filled, doc, hierarchy) + const res = await checkFunc(client, execution, filled, doc) if (res) return tr } } @@ -596,21 +593,49 @@ export async function requestResult ( }) } -export function todoTranstionCheck (params: Record, doc: Doc): boolean { +export function todoTranstionCheck ( + client: Client, + execution: Execution, + params: Record, + doc: Doc +): boolean { if (params._id === undefined) return false return doc._id === params._id } -export function timeTransitionCheck (params: Record): boolean { +export function timeTransitionCheck ( + client: Client, + execution: Execution, + params: Record, + context: Record +): boolean { if (params.value === undefined) return false return params.value <= Date.now() } -export function updateCardTranstionCheck (params: Record, doc: Doc, hierarchy: Hierarchy): boolean { - const res = matchQuery([doc], params, doc._class, hierarchy, true) +export function updateCardTranstionCheck ( + client: Client, + execution: Execution, + params: Record, + doc: Doc +): boolean { + const res = matchQuery([doc], params, doc._class, client.getHierarchy(), true) return res.length > 0 } +export async function subProcessesDoneCheck ( + client: Client, + execution: Execution, + params: Record, + context: Record +): Promise { + const res = client.findOne(process.class.Execution, { + parentId: execution._id, + status: ExecutionStatus.Active + }) + return res === undefined +} + export function getCirteriaEditor (of: Ref>, category: AttributeCategory): AnyComponent | undefined { const client = getClient() if (category !== 'attribute') { diff --git a/plugins/process/src/index.ts b/plugins/process/src/index.ts index 65420b7c61..4bf33dedb7 100644 --- a/plugins/process/src/index.ts +++ b/plugins/process/src/index.ts @@ -12,7 +12,7 @@ // limitations under the License. import { Card, MasterTag, Tag } from '@hcengineering/card' -import { Association, Class, Doc, DocumentUpdate, Hierarchy, ObjQueryType, Ref, Tx, Type } from '@hcengineering/core' +import { Association, Class, Client, Doc, DocumentUpdate, ObjQueryType, Ref, Tx, Type } from '@hcengineering/core' import { Asset, IntlString, Plugin, plugin, Resource } from '@hcengineering/platform' import { ToDo } from '@hcengineering/time' import { AnyComponent } from '@hcengineering/ui' @@ -84,9 +84,10 @@ export enum ExecutionLogAction { } export type CheckFunc = ( + client: Client, + execution: Execution, params: Record, - context: Record, - hierarchy: Hierarchy + context: Record ) => Promise export enum ExecutionStatus { @@ -216,6 +217,7 @@ export default plugin(processId, { triggerCheck: { ToDo: '' as Resource, UpdateCheck: '' as Resource, + SubProcessesDoneCheck: '' as Resource, Time: '' as Resource }, string: { diff --git a/server-plugins/process-resources/src/functions.ts b/server-plugins/process-resources/src/functions.ts index 051122ca75..95b6927d3e 100644 --- a/server-plugins/process-resources/src/functions.ts +++ b/server-plugins/process-resources/src/functions.ts @@ -14,7 +14,7 @@ // import cardPlugin, { Card, MasterTag, Tag } from '@hcengineering/card' -import core, { Association, Data, Doc, generateId, Hierarchy, matchQuery, Ref, Relation, Tx } from '@hcengineering/core' +import core, { Association, Data, Doc, generateId, matchQuery, Ref, Relation, Tx } from '@hcengineering/core' import process, { Execution, ExecutionContext, @@ -27,23 +27,37 @@ import process, { import { ExecuteResult, ProcessControl } from '@hcengineering/server-process' import time, { ToDoPriority } from '@hcengineering/time' -export function CheckToDo (params: Record, context: Record): boolean { +export function CheckToDo ( + control: ProcessControl, + execution: Execution, + params: Record, + context: Record +): boolean { if (params._id === undefined) return false if (context.todo === undefined) return false return context.todo._id === params._id } +export async function CheckSubProcessesDone (control: ProcessControl, execution: Execution): Promise { + const res = control.client.findOne(process.class.Execution, { + parentId: execution._id, + status: ExecutionStatus.Active + }) + return res === undefined +} + export function OnCardUpdateCheck ( + control: ProcessControl, + execution: Execution, params: Record, - context: Record, - hierarchy: Hierarchy + context: Record ): boolean { if (context.card === undefined) return false - const res = matchQuery([context.card], params, context.card._class, hierarchy, true) + const res = matchQuery([context.card], params, context.card._class, control.client.getHierarchy(), true) return res.length > 0 } -export function CheckTime (params: Record): boolean { +export function CheckTime (control: ProcessControl, execution: Execution, params: Record): boolean { if (params.value === undefined) return false return params.value <= Date.now() } diff --git a/server-plugins/process-resources/src/index.ts b/server-plugins/process-resources/src/index.ts index c4311bd267..8ca58b1292 100644 --- a/server-plugins/process-resources/src/index.ts +++ b/server-plugins/process-resources/src/index.ts @@ -80,6 +80,7 @@ import { AddTag, CheckToDo, OnCardUpdateCheck, + CheckSubProcessesDone, CheckTime } from './functions' import { ToDoCancellRollback, ToDoCloseRollback } from './rollback' @@ -356,6 +357,7 @@ export default async () => ({ AddTag, CheckToDo, OnCardUpdateCheck, + CheckSubProcessesDone, CheckTime }, transform: { diff --git a/server-plugins/process/src/index.ts b/server-plugins/process/src/index.ts index 783dd8e998..8e5a36e42f 100644 --- a/server-plugins/process/src/index.ts +++ b/server-plugins/process/src/index.ts @@ -1,9 +1,9 @@ import { Doc, Mixin, Ref } from '@hcengineering/core' import type { Plugin, Resource } from '@hcengineering/platform' import { plugin } from '@hcengineering/platform' -import { CheckFunc, Method, ProcessFunction, Trigger } from '@hcengineering/process' +import { Execution, Method, ProcessFunction, Trigger } from '@hcengineering/process' import { TriggerFunc } from '@hcengineering/server-core' -import { ExecuteFunc, RollbackFunc, TransformFunc } from './types' +import { ExecuteFunc, ProcessControl, RollbackFunc, TransformFunc } from './types' export * from './types' @@ -12,6 +12,13 @@ export * from './types' */ export const serverProcessId = 'server-process' as Plugin +export type CheckFunc = ( + control: ProcessControl, + execution: Execution, + params: Record, + context: Record +) => Promise + export interface TriggerImpl extends Trigger { serverCheckFunc?: Resource rollbackFunc?: Resource @@ -49,6 +56,7 @@ export default plugin(serverProcessId, { AddTag: '' as Resource, CheckToDo: '' as Resource, OnCardUpdateCheck: '' as Resource, + CheckSubProcessesDone: '' as Resource, CheckTime: '' as Resource }, transform: { diff --git a/services/process/src/main.ts b/services/process/src/main.ts index afffc78b21..17ad8aad7b 100644 --- a/services/process/src/main.ts +++ b/services/process/src/main.ts @@ -529,13 +529,12 @@ export async function pickTransition ( for (const tr of transitions) { const trigger = control.client.getModel().findObject(tr.trigger) if (trigger === undefined) continue - if (trigger.checkFunction === undefined) return tr const impl = control.client.getHierarchy().as(trigger, serverProcess.mixin.TriggerImpl) if (impl?.serverCheckFunc === undefined) return tr const filled = await fillParams(tr.triggerParams, execution, control) const checkFunc = await getResource(impl.serverCheckFunc) if (checkFunc === undefined) continue - const res = await checkFunc(filled, context, control.client.getHierarchy()) + const res = await checkFunc(control, execution, filled, context) if (res) return tr } }