Related subprocesses (#9097)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov
2025-05-26 22:36:48 +07:00
committed by GitHub
parent 9017ad2310
commit 4785a7acc5
6 changed files with 101 additions and 28 deletions
@@ -42,6 +42,7 @@
export let attribute: AnyAttribute
export let editor: AnySvelteComponent | undefined
export let allowRemove: boolean = false
export let forbidValue: boolean = false
const dispatch = createEventDispatcher()
@@ -96,19 +97,21 @@
/>
{:else}
<div class="w-full">
<svelte:component
this={editor}
label={attribute?.label}
placeholder={attribute?.label}
kind={'ghost'}
size={'large'}
width={'100%'}
justify={'left'}
type={attribute?.type}
{value}
{onChange}
{focus}
/>
{#if !forbidValue}
<svelte:component
this={editor}
label={attribute?.label}
placeholder={attribute?.label}
kind={'ghost'}
size={'large'}
width={'100%'}
justify={'left'}
type={attribute?.type}
{value}
{onChange}
{focus}
/>
{/if}
</div>
{/if}
<div class="button flex-row-center">
@@ -26,6 +26,7 @@
export let key: string
export let object: Record<string, any>
export let allowRemove: boolean = false
export let forbidValue: boolean = false
const client = getClient()
const hierarchy = client.getHierarchy()
@@ -67,6 +68,7 @@
{value}
masterTag={process.masterTag}
{allowRemove}
{forbidValue}
on:remove
on:change={(e) => {
onChange(e.detail)
@@ -13,15 +13,26 @@
// limitations under the License.
-->
<script lang="ts">
import { createQuery, getClient } from '@hcengineering/presentation'
import { Process, Step } from '@hcengineering/process'
import { DropdownLabels, DropdownTextItem, Label } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import card from '@hcengineering/card'
import { Doc, RefTo } from '@hcengineering/core'
import { createQuery, getClient } from '@hcengineering/presentation'
import { Execution, parseContext, Process, Step } from '@hcengineering/process'
import { DropdownLabels, DropdownTextItem, Label, Toggle } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import plugin from '../../plugin'
import { getContextAttribute } from '../../utils'
import ProcessAttributeEditor from './ProcessAttributeEditor.svelte'
export let process: Process
export let step: Step<Process>
export let step: Step<Execution>
const client = getClient()
const hierarchy = client.getHierarchy()
let _id = step.params._id
$: context = parseContext(step.params.card)
$: attr = getContextAttribute(client, context, process.masterTag)
$: masterTag = (attr?.type as RefTo<Doc>)?.to ?? process.masterTag
const dispatch = createEventDispatcher()
@@ -32,10 +43,10 @@
}
}
const client = getClient()
const hierarchy = client.getHierarchy()
let thisCard: boolean = step.params.card === undefined
$: ancestors = hierarchy
.getAncestors(process.masterTag)
.getAncestors(masterTag)
.filter((it) => !hierarchy.isMixin(it) && hierarchy.isDerived(it, card.class.Card))
let processes: Process[] = []
@@ -46,21 +57,49 @@
label: it.name
}))
$: selected =
(step.params as any)._id !== undefined ? items.find((it) => it.id === (step.params as any)._id)?.id : undefined
$: selected = _id !== undefined ? items.find((it) => it.id === _id)?.id : undefined
const query = createQuery()
$: query.query(plugin.class.Process, { masterTag: { $in: ancestors } }, (res) => {
processes = res.filter((it) => it._id !== process._id)
})
function changeThis (): void {
_id = undefined
step.params = {}
dispatch('change', step)
}
function changeTarget (e: CustomEvent<any>): void {
_id = undefined
step.params.card = e.detail.value
}
</script>
<div class="grid">
<Label label={plugin.string.CurrentCard} />
<Toggle bind:on={thisCard} on:change={changeThis} />
{#if !thisCard}
<ProcessAttributeEditor
{process}
_class={plugin.class.Execution}
key={'card'}
object={step.params}
allowRemove
forbidValue
on:remove={() => {
thisCard = true
changeThis()
}}
on:change={changeTarget}
/>
{/if}
<Label label={plugin.string.Process} />
<DropdownLabels
autoSelect={false}
enableSearch={false}
width={'100%'}
{items}
{selected}
placeholder={plugin.string.Process}
+2 -1
View File
@@ -115,6 +115,7 @@ export default mergeIds(processId, process, {
DeleteTransition: '' as IntlString,
DeleteTransitionConfirm: '' as IntlString,
AddTransition: '' as IntlString,
ToDo: '' as IntlString
ToDo: '' as IntlString,
CurrentCard: '' as IntlString
}
})
+28 -1
View File
@@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { type Card } from '@hcengineering/card'
import { type Card, type MasterTag } from '@hcengineering/card'
import core, {
generateId,
type AnyAttribute,
@@ -42,6 +42,7 @@ import {
type Process,
type ProcessFunction,
type RelatedContext,
type SelectedContext,
type SelectedUserRequest,
type State,
type Step,
@@ -67,6 +68,32 @@ export function generateContextId (): ContextId {
return generateId() as string as ContextId
}
export function getContextAttribute (
client: Client,
context: SelectedContext | undefined,
masterTag: Ref<MasterTag>
): AnyAttribute | undefined {
if (context === undefined) return
const h = client.getHierarchy()
const model = client.getModel()
if (context.type === 'attribute') {
return h.findAttribute(masterTag, context.key)
}
if (context.type === 'nested') {
const attr = h.findAttribute(masterTag, context.path)
if (attr === undefined) return
const parentType = attr.type._class === core.class.ArrOf ? (attr.type as ArrOf<Doc>).of : attr.type
const targetClass = parentType._class === core.class.RefTo ? (parentType as RefTo<Doc>).to : parentType._class
return h.findAttribute(targetClass, context.key)
}
if (context.type === 'relation') {
const assoc = model.findObject(context.association)
if (assoc === undefined) return
const targetClass = context.direction === 'A' ? assoc.classA : assoc.classB
return h.findAttribute(targetClass, context.key)
}
}
export async function pickTransition (
model: ModelDb,
execution: Execution,
@@ -608,18 +608,19 @@ export async function UpdateCard (
}
export async function RunSubProcess (
params: MethodParams<Process>,
params: MethodParams<Execution>,
execution: Execution,
control: TriggerControl
): Promise<ExecuteResult | undefined> {
if (params._id === undefined) return
const card = params.card ?? execution.card
const processId = params._id as Ref<Process>
const target = control.modelDb.findObject(processId)
if (target === undefined) return
if (target.parallelExecutionForbidden === true) {
const currentExecution = await control.findAll(control.ctx, process.class.Execution, {
process: target._id,
card: execution.card,
card,
done: false
})
if (currentExecution.length > 0) {
@@ -634,7 +635,7 @@ export async function RunSubProcess (
control.txFactory.createTxCreateDoc(process.class.Execution, core.space.Workspace, {
process: processId,
currentState: target.initState,
card: execution.card,
card,
context: emptyContext,
status: ExecutionStatus.Active,
rollback: [],