mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-10 19:57:43 +02:00
Merge branch 'develop' into staging-new
This commit is contained in:
@@ -221,6 +221,9 @@ export class TApproveRequest extends TProcessToDo implements ApproveRequest {
|
||||
group!: string
|
||||
|
||||
card!: Ref<Card>
|
||||
|
||||
@Prop(TypeString(), process.string.ActionType)
|
||||
actionType?: 'approve' | 'review'
|
||||
}
|
||||
|
||||
@Model(process.class.Method, core.class.Doc, DOMAIN_MODEL)
|
||||
@@ -478,7 +481,17 @@ export function createModel (builder: Builder): void {
|
||||
strict: true
|
||||
},
|
||||
config: [
|
||||
{
|
||||
key: 'execution',
|
||||
label: process.string.Process,
|
||||
presenter: process.component.ExecutionRefPresenter
|
||||
},
|
||||
'user',
|
||||
{
|
||||
key: 'actionType',
|
||||
label: process.string.ActionType,
|
||||
presenter: process.component.ActionTypePresenter
|
||||
},
|
||||
{
|
||||
key: '',
|
||||
presenter: view.component.GrowPresenter,
|
||||
@@ -495,6 +508,10 @@ export function createModel (builder: Builder): void {
|
||||
process.viewlet.CardRequests
|
||||
)
|
||||
|
||||
builder.mixin(process.class.ApproveRequest, core.class.Class, view.mixin.IgnoreActions, {
|
||||
actions: [view.action.Delete]
|
||||
})
|
||||
|
||||
builder.createDoc(
|
||||
view.class.Viewlet,
|
||||
core.space.Model,
|
||||
|
||||
@@ -145,7 +145,12 @@
|
||||
"CancelToDo": "Zrušit akční položku",
|
||||
"Export": "Exportovat",
|
||||
"Import": "Importovat",
|
||||
"CancelProcess": "Zrušit proces"
|
||||
"CancelProcess": "Zrušit proces",
|
||||
"SyncWithField": "Synchronizovat s polem",
|
||||
"ActionType": "Typ",
|
||||
"ApproveAction": "Schválit",
|
||||
"ReviewAction": "Zkontrolovat",
|
||||
"Review": "Zkontrolovat"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Metoda nenalezena: {methodId}",
|
||||
|
||||
@@ -145,7 +145,12 @@
|
||||
"CancelToDo": "Action Item abbrechen",
|
||||
"Export": "Exportieren",
|
||||
"Import": "Importieren",
|
||||
"CancelProcess": "Prozess abbrechen"
|
||||
"CancelProcess": "Prozess abbrechen",
|
||||
"SyncWithField": "Synchronisieren mit Feld",
|
||||
"ActionType": "Typ",
|
||||
"ApproveAction": "Genehmigen",
|
||||
"ReviewAction": "Prüfen",
|
||||
"Review": "Prüfen"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Methode nicht gefunden: {methodId}",
|
||||
|
||||
@@ -150,7 +150,12 @@
|
||||
"CancelToDo": "Cancel Action item",
|
||||
"Export": "Export",
|
||||
"Import": "Import",
|
||||
"CancelProcess": "Cancel process"
|
||||
"CancelProcess": "Cancel process",
|
||||
"SyncWithField": "Sync with field",
|
||||
"ActionType": "Type",
|
||||
"ApproveAction": "Approve",
|
||||
"ReviewAction": "Review",
|
||||
"Review": "Review"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Method not found: {methodId}",
|
||||
|
||||
@@ -150,7 +150,12 @@
|
||||
"CancelToDo": "Cancelar acción",
|
||||
"Export": "Exportar",
|
||||
"Import": "Importar",
|
||||
"CancelProcess": "Cancelar proceso"
|
||||
"CancelProcess": "Cancelar proceso",
|
||||
"SyncWithField": "Sincronizar con campo",
|
||||
"ActionType": "Tipo",
|
||||
"ApproveAction": "Aprobar",
|
||||
"ReviewAction": "Revisar",
|
||||
"Review": "Revisar"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Método no encontrado: {methodId}",
|
||||
|
||||
@@ -150,7 +150,12 @@
|
||||
"CancelToDo": "Annuler l'action",
|
||||
"Export": "Exporter",
|
||||
"Import": "Importer",
|
||||
"CancelProcess": "Annuler le processus"
|
||||
"CancelProcess": "Annuler le processus",
|
||||
"SyncWithField": "Synchroniser avec le champ",
|
||||
"ActionType": "Type",
|
||||
"ApproveAction": "Approuver",
|
||||
"ReviewAction": "Revoir",
|
||||
"Review": "Revoir"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Méthode introuvable : {methodId}",
|
||||
|
||||
@@ -150,7 +150,12 @@
|
||||
"CancelToDo": "Annulla azione",
|
||||
"Export": "Esporta",
|
||||
"Import": "Importa",
|
||||
"CancelProcess": "Annulla processo"
|
||||
"CancelProcess": "Annulla processo",
|
||||
"SyncWithField": "Sincronizza con campo",
|
||||
"ActionType": "Tipo",
|
||||
"ApproveAction": "Approva",
|
||||
"ReviewAction": "Revisa",
|
||||
"Review": "Revisa"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Metodo non trovato: {methodId}",
|
||||
|
||||
@@ -149,7 +149,12 @@
|
||||
"CancelToDo": "アクションをキャンセル",
|
||||
"Export": "エクスポート",
|
||||
"Import": "インポート",
|
||||
"CancelProcess": "プロセスをキャンセル"
|
||||
"CancelProcess": "プロセスをキャンセル",
|
||||
"SyncWithField": "フィールドと同期",
|
||||
"ActionType": "タイプ",
|
||||
"ApproveAction": "承認",
|
||||
"ReviewAction": "レビュー",
|
||||
"Review": "レビュー"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "メソッドが見つかりません: {methodId}",
|
||||
|
||||
@@ -138,7 +138,12 @@
|
||||
"CancelToDo": "Cancelar ação",
|
||||
"Export": "Exportar",
|
||||
"Import": "Importar",
|
||||
"CancelProcess": "Cancelar processo"
|
||||
"CancelProcess": "Cancelar processo",
|
||||
"SyncWithField": "Sincronizar com campo",
|
||||
"ActionType": "Tipo",
|
||||
"ApproveAction": "Aprovar",
|
||||
"ReviewAction": "Revisar",
|
||||
"Review": "Revisar"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Método não encontrado: {methodId}",
|
||||
|
||||
@@ -150,7 +150,12 @@
|
||||
"CancelToDo": "Cancelar ação",
|
||||
"Export": "Exportar",
|
||||
"Import": "Importar",
|
||||
"CancelProcess": "Cancelar processo"
|
||||
"CancelProcess": "Cancelar processo",
|
||||
"SyncWithField": "Sincronizar com campo",
|
||||
"ActionType": "Tipo",
|
||||
"ApproveAction": "Aprovar",
|
||||
"ReviewAction": "Revisar",
|
||||
"Review": "Revisar"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Método não encontrado: {methodId}",
|
||||
|
||||
@@ -150,7 +150,12 @@
|
||||
"CancelToDo": "Отменить задачу",
|
||||
"Export": "Экспорт",
|
||||
"Import": "Импорт",
|
||||
"CancelProcess": "Отменить процесс"
|
||||
"CancelProcess": "Отменить процесс",
|
||||
"SyncWithField": "Синхронизировать с полем",
|
||||
"ActionType": "Тип",
|
||||
"ApproveAction": "Утверждение",
|
||||
"ReviewAction": "Рецензирование",
|
||||
"Review": "Рецензировать"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Метод не найден: {methodId}",
|
||||
|
||||
@@ -147,7 +147,12 @@
|
||||
"CancelToDo": "Eylem öğesini iptal et",
|
||||
"Export": "Dışa aktar",
|
||||
"Import": "İçe aktar",
|
||||
"CancelProcess": "Süreci iptal et"
|
||||
"CancelProcess": "Süreci iptal et",
|
||||
"SyncWithField": "Alan ile senkronize et",
|
||||
"ActionType": "Tür",
|
||||
"ApproveAction": "Onayla",
|
||||
"ReviewAction": "Gözden geçir",
|
||||
"Review": "Gözden geçir"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Metod bulunamadı: {methodId}",
|
||||
|
||||
@@ -150,7 +150,12 @@
|
||||
"CancelToDo": "取消任务",
|
||||
"Export": "导出",
|
||||
"Import": "导入",
|
||||
"CancelProcess": "取消过程"
|
||||
"CancelProcess": "取消过程",
|
||||
"SyncWithField": "字段同步",
|
||||
"ActionType": "类型",
|
||||
"ApproveAction": "批准",
|
||||
"ReviewAction": "审查",
|
||||
"Review": "审查"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "找不到方法:{methodId}",
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<!--
|
||||
// Copyright © 2026 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 { Label } from '@hcengineering/ui'
|
||||
import plugin from '../plugin'
|
||||
|
||||
export let value: 'approve' | 'review' | undefined
|
||||
</script>
|
||||
|
||||
<Label label={value === 'review' ? plugin.string.ReviewAction : plugin.string.ApproveAction} />
|
||||
@@ -45,5 +45,9 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<Button label={process.string.Approve} kind="positive" on:click={(ev) => changeApprovalRequestState(ev, false)} />
|
||||
<Button
|
||||
label={todo.actionType === 'review' ? process.string.Review : process.string.Approve}
|
||||
kind="positive"
|
||||
on:click={(ev) => changeApprovalRequestState(ev, false)}
|
||||
/>
|
||||
<Button label={process.string.Reject} kind="negative" on:click={(ev) => changeApprovalRequestState(ev, true)} />
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<!--
|
||||
// Copyright © 2026 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 { Ref } from '@hcengineering/core'
|
||||
import { createQuery, getClient } from '@hcengineering/presentation'
|
||||
import { Execution } from '@hcengineering/process'
|
||||
import plugin from '../plugin'
|
||||
|
||||
export let value: Ref<Execution>
|
||||
|
||||
const client = getClient()
|
||||
|
||||
const query = createQuery()
|
||||
|
||||
let execution: Execution | undefined
|
||||
|
||||
$: query.query(plugin.class.Execution, { _id: value }, (res) => {
|
||||
execution = res[0]
|
||||
})
|
||||
|
||||
$: process = execution !== undefined ? client.getModel().findObject(execution.process) : undefined
|
||||
</script>
|
||||
|
||||
{#if process}
|
||||
{process.name}
|
||||
{/if}
|
||||
@@ -16,8 +16,8 @@
|
||||
import contact from '@hcengineering/contact'
|
||||
import core, { AnyAttribute } from '@hcengineering/core'
|
||||
import { getAttributeEditor, getAttributePresenterClass, getClient } from '@hcengineering/presentation'
|
||||
import { ApproveRequest, Process, Step } from '@hcengineering/process'
|
||||
import { AnySvelteComponent } from '@hcengineering/ui'
|
||||
import { ApproveRequest, parseContext, Process, Step } from '@hcengineering/process'
|
||||
import { AnySvelteComponent, Label, Toggle } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import plugin from '../../plugin'
|
||||
import { getContext, getMockAttribute } from '../../utils'
|
||||
@@ -78,6 +78,33 @@
|
||||
}
|
||||
|
||||
getBaseEditor(attribute)
|
||||
|
||||
$: contextValue = typeof params.user === 'string' ? parseContext(params.user) : undefined
|
||||
$: userContext = contextValue?.type === 'attribute'
|
||||
|
||||
$: if (!userContext && params.field) {
|
||||
delete (params as any).field
|
||||
step.params = params
|
||||
dispatch('change', step)
|
||||
}
|
||||
|
||||
function toggleField (e: CustomEvent<boolean>): void {
|
||||
if (e.detail) {
|
||||
if (contextValue?.type === 'attribute') {
|
||||
params.field = contextValue.key
|
||||
}
|
||||
} else {
|
||||
delete (params as any).field
|
||||
}
|
||||
step.params = params
|
||||
dispatch('change', step)
|
||||
}
|
||||
|
||||
function toggleActionType (e: CustomEvent<any>): void {
|
||||
params.actionType = e.detail ? 'review' : 'approve'
|
||||
step.params = params
|
||||
dispatch('change', step)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="grid">
|
||||
@@ -93,6 +120,14 @@
|
||||
on:remove
|
||||
on:change={onChange}
|
||||
/>
|
||||
<div>
|
||||
<Label label={plugin.string.SyncWithField} />
|
||||
</div>
|
||||
<Toggle disabled={!userContext} on={params.field !== undefined} on:change={toggleField} />
|
||||
<div>
|
||||
<Label label={plugin.string.ReviewAction} />
|
||||
</div>
|
||||
<Toggle on={params.actionType === 'review'} on:change={toggleActionType} />
|
||||
</div>
|
||||
<ParamsEditor _class={plugin.class.ApproveRequest} {process} {keys} {params} on:change={changeParams} />
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Process, ProcessToDo, Step, UserResult } from '@hcengineering/process'
|
||||
import { parseContext, Process, ProcessToDo, Step, UserResult } from '@hcengineering/process'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import plugin from '../../plugin'
|
||||
import ParamsEditor from './ParamsEditor.svelte'
|
||||
@@ -43,6 +43,27 @@
|
||||
}
|
||||
|
||||
const keys = ['title', 'user', 'dueDate']
|
||||
|
||||
$: contextValue = typeof params.user === 'string' ? parseContext(params.user) : undefined
|
||||
$: userContext = contextValue?.type === 'attribute'
|
||||
|
||||
$: if (!userContext && params.field) {
|
||||
delete (params as any).field
|
||||
step.params = params
|
||||
dispatch('change', step)
|
||||
}
|
||||
|
||||
function toggleField (e: CustomEvent<boolean>): void {
|
||||
if (e.detail) {
|
||||
if (contextValue?.type === 'attribute') {
|
||||
params.field = contextValue.key
|
||||
}
|
||||
} else {
|
||||
delete (params as any).field
|
||||
}
|
||||
step.params = params
|
||||
dispatch('change', step)
|
||||
}
|
||||
</script>
|
||||
|
||||
<ParamsEditor _class={plugin.class.ProcessToDo} {process} {keys} {params} on:change={changeParams} />
|
||||
@@ -60,6 +81,12 @@
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div>
|
||||
<Label label={plugin.string.SyncWithField} />
|
||||
</div>
|
||||
<Toggle disabled={!userContext} on={params.field !== undefined} on:change={toggleField} />
|
||||
</div>
|
||||
<div class="divider" />
|
||||
<ResultsEditor {process} result={step.results} on:change={changeResults} />
|
||||
|
||||
|
||||
@@ -89,6 +89,9 @@ import ReplaceEditor from './components/transformEditors/ReplaceEditor.svelte'
|
||||
import SplitEditor from './components/transformEditors/SplitEditor.svelte'
|
||||
import NumberPresenter from './components/transformPresenters/NumberPresenter.svelte'
|
||||
import RolePresenter from './components/transformPresenters/RolePresenter.svelte'
|
||||
import ExecutionRefPresenter from './components/ExecutionRefPresenter.svelte'
|
||||
import ActionTypePresenter from './components/ActionTypePresenter.svelte'
|
||||
|
||||
import { exportProcesses, importProcess } from './exporter'
|
||||
import { ProcessMiddleware } from './middleware'
|
||||
import {
|
||||
@@ -175,7 +178,9 @@ export default async (): Promise<Resources> => ({
|
||||
UnLockSectionPresenter,
|
||||
CancelToDoEditor,
|
||||
CancelSubProcessEditor,
|
||||
ToDoValuePresenter
|
||||
ToDoValuePresenter,
|
||||
ExecutionRefPresenter,
|
||||
ActionTypePresenter
|
||||
},
|
||||
criteriaEditor: {
|
||||
BaseCriteria,
|
||||
|
||||
@@ -90,7 +90,9 @@ export default mergeIds(processId, process, {
|
||||
LockSectionPresenter: '' as AnyComponent,
|
||||
UnLockSectionPresenter: '' as AnyComponent,
|
||||
CancelToDoEditor: '' as AnyComponent,
|
||||
ToDoValuePresenter: '' as AnyComponent
|
||||
ToDoValuePresenter: '' as AnyComponent,
|
||||
ActionTypePresenter: '' as AnyComponent,
|
||||
ExecutionRefPresenter: '' as AnyComponent
|
||||
},
|
||||
criteriaEditor: {
|
||||
BaseCriteria: '' as AnyComponent,
|
||||
|
||||
@@ -124,6 +124,7 @@ export interface ProcessToDo extends ToDo {
|
||||
withRollback: boolean
|
||||
|
||||
results?: UserResult[]
|
||||
field?: string
|
||||
}
|
||||
|
||||
export interface ApproveRequest extends ProcessToDo {
|
||||
@@ -134,6 +135,8 @@ export interface ApproveRequest extends ProcessToDo {
|
||||
reason?: string
|
||||
|
||||
group: string
|
||||
field?: string
|
||||
actionType?: 'approve' | 'review'
|
||||
}
|
||||
|
||||
export type MethodParams<T extends Doc> = {
|
||||
@@ -291,7 +294,12 @@ export default plugin(processId, {
|
||||
Actions: '' as IntlString,
|
||||
ProcessRunned: '' as IntlString,
|
||||
ProcessStateChanged: '' as IntlString,
|
||||
ProcessFinished: '' as IntlString
|
||||
ProcessFinished: '' as IntlString,
|
||||
SyncWithField: '' as IntlString,
|
||||
ActionType: '' as IntlString,
|
||||
ApproveAction: '' as IntlString,
|
||||
ReviewAction: '' as IntlString,
|
||||
Review: '' as IntlString
|
||||
},
|
||||
error: {
|
||||
MethodNotFound: '' as IntlString,
|
||||
|
||||
@@ -465,7 +465,9 @@ export async function RequestApproval (
|
||||
control: ProcessControl,
|
||||
results: UserResult[] | undefined
|
||||
): Promise<ExecuteResult> {
|
||||
if (params.user === undefined) throw processError(process.error.RequiredParamsNotProvided, { params: 'user' })
|
||||
if (params.user === undefined || params.user.length === 0) {
|
||||
throw processError(process.error.RequiredParamsNotProvided, { params: 'user' })
|
||||
}
|
||||
const group = generateId()
|
||||
const res: TxCreateDoc<ApproveRequest>[] = []
|
||||
const rollback: Tx[] = []
|
||||
@@ -491,7 +493,9 @@ export async function RequestApproval (
|
||||
rank: '',
|
||||
withRollback: params.withRollback ?? false,
|
||||
results,
|
||||
group
|
||||
group,
|
||||
actionType: params.actionType,
|
||||
field: (params as any).field
|
||||
},
|
||||
id
|
||||
)
|
||||
@@ -652,7 +656,8 @@ export async function CreateToDo (
|
||||
doneOn: null,
|
||||
rank: '',
|
||||
withRollback: params.withRollback ?? false,
|
||||
results
|
||||
results,
|
||||
field: (params as any).field
|
||||
},
|
||||
id
|
||||
)
|
||||
|
||||
@@ -17,6 +17,8 @@ import cardPlugin, { Card } from '@hcengineering/card'
|
||||
import core, {
|
||||
ArrOf,
|
||||
Doc,
|
||||
DocumentUpdate,
|
||||
generateId,
|
||||
Ref,
|
||||
RefTo,
|
||||
Tx,
|
||||
@@ -227,6 +229,7 @@ export async function OnProcessToDoRemove (txes: Tx[], control: TriggerControl):
|
||||
if (tx._class !== core.class.TxRemoveDoc) continue
|
||||
const removeTx = tx as TxRemoveDoc<ProcessToDo>
|
||||
if (!control.hierarchy.isDerived(removeTx.objectClass, process.class.ProcessToDo)) continue
|
||||
if (removeTx.space === core.space.DerivedTx) continue
|
||||
const removedTodo = control.removedMap.get(removeTx.objectId) as ProcessToDo
|
||||
if (removedTodo === undefined) continue
|
||||
await putEventToQueue(
|
||||
@@ -346,6 +349,83 @@ async function getExecutionReassignTxes (card: Card, control: TriggerControl): P
|
||||
return res
|
||||
}
|
||||
|
||||
async function reassignToDos (card: Card, ops: DocumentUpdate<Card>, control: TriggerControl): Promise<Tx[]> {
|
||||
const res: Tx[] = []
|
||||
const todos = await control.findAll(control.ctx, process.class.ProcessToDo, {
|
||||
attachedTo: card._id,
|
||||
doneOn: null,
|
||||
field: { $ne: null }
|
||||
} as any)
|
||||
const handledGroups = new Set<string>()
|
||||
for (const todo of todos as any[]) {
|
||||
if (todo.field === undefined || !TxProcessor.hasUpdate(ops, todo.field)) continue
|
||||
|
||||
if (todo._class === process.class.ApproveRequest) {
|
||||
const request = todo as ApproveRequest
|
||||
if (handledGroups.has(request.group)) continue
|
||||
handledGroups.add(request.group)
|
||||
|
||||
const newUsers = (card[todo.field as keyof Card] as any[]) ?? []
|
||||
if (newUsers.length === 0) {
|
||||
continue
|
||||
}
|
||||
const currentRequests = await control.findAll(control.ctx, process.class.ApproveRequest, {
|
||||
group: request.group,
|
||||
doneOn: null
|
||||
})
|
||||
const currentUsers = currentRequests.map((r) => r.user)
|
||||
|
||||
// Remove users not in new list
|
||||
for (const req of currentRequests) {
|
||||
if (!newUsers.includes(req.user)) {
|
||||
res.push(control.txFactory.createTxRemoveDoc(req._class, req.space, req._id))
|
||||
}
|
||||
}
|
||||
|
||||
// Add users not in current list
|
||||
for (const user of newUsers) {
|
||||
if (!currentUsers.includes(user)) {
|
||||
const id = generateId<ApproveRequest>()
|
||||
const { _id, modifiedBy, modifiedOn, ...data } = request as any
|
||||
res.push(
|
||||
control.txFactory.createTxCreateDoc(
|
||||
request._class,
|
||||
request.space,
|
||||
{
|
||||
...data,
|
||||
user
|
||||
},
|
||||
id
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const newUser = card[todo.field as keyof Card]
|
||||
if (newUser === todo.user) continue
|
||||
|
||||
if (newUser != null) {
|
||||
res.push(control.txFactory.createTxRemoveDoc(todo._class, todo.space, todo._id))
|
||||
|
||||
const id = generateId<ProcessToDo>()
|
||||
const { _id, modifiedBy, modifiedOn, ...data } = todo
|
||||
res.push(
|
||||
control.txFactory.createTxCreateDoc(
|
||||
todo._class,
|
||||
todo.space,
|
||||
{
|
||||
...data,
|
||||
user: newUser
|
||||
},
|
||||
id
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
export async function OnCardCreate (txes: Tx[], control: TriggerControl): Promise<Tx[]> {
|
||||
const res: Tx[] = []
|
||||
for (const tx of txes) {
|
||||
@@ -403,6 +483,8 @@ export async function OnCardUpdate (txes: Tx[], control: TriggerControl): Promis
|
||||
},
|
||||
control
|
||||
)
|
||||
const reassignTxes = await reassignToDos(card[0], ops ?? {}, control)
|
||||
res.push(...reassignTxes)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ async function processExecution (control: ProcessControl, record: ProcessMessage
|
||||
}
|
||||
}
|
||||
if (isRollback(record)) {
|
||||
await rollback(control, record, execution)
|
||||
await rollback(control, execution)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,7 +298,8 @@ function isRollback (record: ProcessMessage): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
async function rollback (control: ProcessControl, record: ProcessMessage, execution: Execution): Promise<void> {
|
||||
async function rollback (control: ProcessControl, execution: Execution): Promise<void> {
|
||||
if (execution.rollback.length === 0) return
|
||||
const rollbackTxes = execution.rollback.pop() ?? []
|
||||
for (const tx of rollbackTxes) {
|
||||
const timeout = setTimeout(() => {
|
||||
@@ -719,6 +720,12 @@ async function fillParams<T extends Doc> (
|
||||
execution: Execution,
|
||||
control: ProcessControl
|
||||
): Promise<MethodParams<T>> {
|
||||
if (!control.cache.has(execution.card)) {
|
||||
const card = await control.client.findOne(cardPlugin.class.Card, { _id: execution.card })
|
||||
if (card !== undefined) {
|
||||
control.cache.set(execution.card, card)
|
||||
}
|
||||
}
|
||||
const res: MethodParams<T> = {}
|
||||
for (const key in params) {
|
||||
const value = control.client.getHierarchy().clone((params as any)[key])
|
||||
|
||||
@@ -26,7 +26,7 @@ export interface Config {
|
||||
const config: Config = {
|
||||
DbUrl: process.env.DB_URL ?? 'postgres://localhost:5432/huly',
|
||||
PollInterval: process.env.POLL_INTERVAL != null ? Number(process.env.POLL_INTERVAL) : 20000,
|
||||
QueueRegion: process.env.QUEUE_REGION ?? 'cockroach',
|
||||
QueueRegion: process.env.QUEUE_REGION ?? '',
|
||||
QueueConfig: process.env.QUEUE_CONFIG ?? ''
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user