mirror of
https://github.com/hcengineering/platform.git
synced 2026-08-17 18:05:42 +02:00
Create card process (#9522)
This commit is contained in:
@@ -898,6 +898,34 @@ export function createModel (builder: Builder): void {
|
||||
process.method.UpdateCard
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
process.class.Method,
|
||||
core.space.Model,
|
||||
{
|
||||
label: process.string.CreateCard,
|
||||
objectClass: card.class.Card,
|
||||
editor: process.component.CreateCardEditor,
|
||||
presenter: process.component.CreateCardPresenter,
|
||||
contextClass: card.class.Card,
|
||||
requiredParams: ['title', '_class']
|
||||
},
|
||||
process.method.CreateCard
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
process.class.Method,
|
||||
core.space.Model,
|
||||
{
|
||||
label: core.string.AddRelation,
|
||||
objectClass: core.class.Relation,
|
||||
editor: process.component.AddRelationEditor,
|
||||
presenter: process.component.AddRelationPresenter,
|
||||
contextClass: core.class.Relation,
|
||||
requiredParams: ['association', 'direction', '_id']
|
||||
},
|
||||
process.method.AddRelation
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
process.class.Trigger,
|
||||
core.space.Model,
|
||||
|
||||
@@ -104,7 +104,10 @@ export function createModel (builder: Builder): void {
|
||||
})
|
||||
|
||||
builder.mixin(card.class.Card, core.class.Class, serverCore.mixin.SearchPresenter, {
|
||||
searchIcon: card.icon.Card,
|
||||
iconConfig: {
|
||||
component: card.component.CardIcon,
|
||||
fields: [['_id']]
|
||||
},
|
||||
title: [['title']]
|
||||
})
|
||||
}
|
||||
|
||||
@@ -65,6 +65,14 @@ export function createModel (builder: Builder): void {
|
||||
func: serverProcess.func.UpdateCard
|
||||
})
|
||||
|
||||
builder.mixin(process.method.CreateCard, process.class.Method, serverProcess.mixin.MethodImpl, {
|
||||
func: serverProcess.func.CreateCard
|
||||
})
|
||||
|
||||
builder.mixin(process.method.AddRelation, process.class.Method, serverProcess.mixin.MethodImpl, {
|
||||
func: serverProcess.func.AddRelation
|
||||
})
|
||||
|
||||
builder.mixin(process.function.FirstValue, process.class.ProcessFunction, serverProcess.mixin.FuncImpl, {
|
||||
func: serverProcess.transform.FirstValue
|
||||
})
|
||||
@@ -222,14 +230,6 @@ export function createModel (builder: Builder): void {
|
||||
}
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverProcess.trigger.OnStateActionsUpdate,
|
||||
txMatch: {
|
||||
_class: core.class.TxUpdateDoc,
|
||||
objectClass: process.class.State
|
||||
}
|
||||
})
|
||||
|
||||
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
|
||||
trigger: serverProcess.trigger.OnTransition,
|
||||
txMatch: {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import ui from '../plugin'
|
||||
import { showPopup } from '../popups'
|
||||
import type { DropdownIntlItem } from '../types'
|
||||
import type { ButtonKind, DropdownIntlItem } from '../types'
|
||||
import Button from './Button.svelte'
|
||||
import DropdownIcon from './icons/Dropdown.svelte'
|
||||
import NestedMenu from './NestedMenu.svelte'
|
||||
@@ -28,6 +28,9 @@
|
||||
export let disabled: boolean = false
|
||||
export let selected: DropdownIntlItem | undefined = undefined
|
||||
|
||||
export let width: string | undefined = undefined
|
||||
export let kind: ButtonKind = 'regular'
|
||||
|
||||
let container: HTMLElement
|
||||
let opened: boolean = false
|
||||
|
||||
@@ -48,7 +51,7 @@
|
||||
</script>
|
||||
|
||||
<div bind:this={container}>
|
||||
<Button width={'min-content'} {disabled} on:click={openPopup}>
|
||||
<Button width={width ?? 'min-content'} {kind} {disabled} on:click={openPopup}>
|
||||
<span slot="content" class="overflow-label disabled flex-grow text-left mr-2">
|
||||
<Label label={selected !== undefined ? selected.label : label} />
|
||||
</span>
|
||||
|
||||
@@ -14,15 +14,16 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Card, MasterTag } from '@hcengineering/card'
|
||||
import { Asset, getEmbeddedLabel } from '@hcengineering/platform'
|
||||
import { AnySvelteComponent, Icon, tooltip } from '@hcengineering/ui'
|
||||
import view, { ObjectPresenterType } from '@hcengineering/view'
|
||||
import { DocNavLink, ObjectMention } from '@hcengineering/view-resources'
|
||||
import { getClient, IconWithEmoji } from '@hcengineering/presentation'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { Asset, getEmbeddedLabel } from '@hcengineering/platform'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { AnySvelteComponent, tooltip } from '@hcengineering/ui'
|
||||
import { ObjectPresenterType } from '@hcengineering/view'
|
||||
import { DocNavLink, ObjectMention } from '@hcengineering/view-resources'
|
||||
|
||||
import ParentNamesPresenter from './ParentNamesPresenter.svelte'
|
||||
import card from '../plugin'
|
||||
import CardIcon from './CardIcon.svelte'
|
||||
import ParentNamesPresenter from './ParentNamesPresenter.svelte'
|
||||
|
||||
export let value: Card | Ref<Card> | undefined
|
||||
export let disabled: boolean = false
|
||||
@@ -77,11 +78,7 @@
|
||||
>
|
||||
{#if shouldShowAvatar}
|
||||
<div class="icon" use:tooltip={{ label: _class?.label ?? card.string.Card }}>
|
||||
<Icon
|
||||
icon={icon === view.ids.IconWithEmoji ? IconWithEmoji : icon ?? card.icon.Card}
|
||||
iconProps={{ icon: _class?.color }}
|
||||
size={'small'}
|
||||
/>
|
||||
<CardIcon value={cardObj} />
|
||||
</div>
|
||||
{/if}
|
||||
<span class="overflow-label">
|
||||
@@ -105,11 +102,7 @@
|
||||
>
|
||||
{#if shouldShowAvatar}
|
||||
<div class="icon" use:tooltip={{ label: _class?.label ?? card.string.Card }}>
|
||||
<Icon
|
||||
icon={icon === view.ids.IconWithEmoji ? IconWithEmoji : icon ?? card.icon.Card}
|
||||
iconProps={{ icon: _class?.color }}
|
||||
size={'small'}
|
||||
/>
|
||||
<CardIcon value={cardObj} />
|
||||
</div>
|
||||
{/if}
|
||||
<span class="overflow-label cropped-text-presenter">
|
||||
|
||||
@@ -14,16 +14,16 @@
|
||||
//
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Card } from '@hcengineering/card'
|
||||
import { WithLookup } from '@hcengineering/core'
|
||||
import card, { Card } from '@hcengineering/card'
|
||||
import { Icon } from '@hcengineering/ui'
|
||||
import CardIcon from './CardIcon.svelte'
|
||||
|
||||
export let value: WithLookup<Card>
|
||||
</script>
|
||||
|
||||
<div class="flex-row-center">
|
||||
<div class="flex-center p-1 content-dark-color flex-no-shrink mr-2-5">
|
||||
<Icon icon={card.icon.Card} size={'medium'} />
|
||||
<CardIcon {value} size={'medium'} />
|
||||
</div>
|
||||
<span class="overflow-label">
|
||||
{value.title}
|
||||
|
||||
@@ -15,19 +15,20 @@
|
||||
<script lang="ts">
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { Card, CardEvents, MasterTag } from '@hcengineering/card'
|
||||
import { AnyAttribute, Class, ClassifierKind, Doc, fillDefaults, Ref } from '@hcengineering/core'
|
||||
import { AnyAttribute, fillDefaults, Ref } from '@hcengineering/core'
|
||||
import { Card as CardModal, getClient } from '@hcengineering/presentation'
|
||||
import { DropdownIntlItem, Label, NestedDropdown } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Label } from '@hcengineering/ui'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import card from '../plugin'
|
||||
import TypeSelector from './TypeSelector.svelte'
|
||||
|
||||
export let value: Card
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
let selected: Ref<MasterTag> | undefined = value._class
|
||||
let selected: Ref<MasterTag> = value._class
|
||||
|
||||
$: mapping = buildMapping(selected, value._class)
|
||||
|
||||
@@ -74,47 +75,6 @@
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function filterClasses (): [DropdownIntlItem, DropdownIntlItem[]][] {
|
||||
const descendants = hierarchy.getDescendants(card.class.Card).filter((p) => p !== card.class.Card)
|
||||
const added = new Set<Ref<Class<Doc>>>()
|
||||
const base = new Map<Ref<Class<Doc>>, Class<Doc>[]>()
|
||||
for (const _id of descendants) {
|
||||
if (added.has(_id)) continue
|
||||
const _class = hierarchy.getClass(_id)
|
||||
if (_class.label === undefined) continue
|
||||
if (_class.kind !== ClassifierKind.CLASS) continue
|
||||
if ((_class as MasterTag).removed === true) continue
|
||||
added.add(_id)
|
||||
const descendants = hierarchy.getDescendants(_id)
|
||||
const toAdd: Class<Doc>[] = []
|
||||
for (const desc of descendants) {
|
||||
if (added.has(desc)) continue
|
||||
const _class = hierarchy.getClass(desc)
|
||||
if (_class.label === undefined) continue
|
||||
if (_class.kind !== ClassifierKind.CLASS) continue
|
||||
if ((_class as MasterTag).removed === true) continue
|
||||
added.add(desc)
|
||||
toAdd.push(_class)
|
||||
}
|
||||
base.set(_id, toAdd)
|
||||
}
|
||||
const result: [DropdownIntlItem, DropdownIntlItem[]][] = []
|
||||
for (const [key, value] of base) {
|
||||
try {
|
||||
const clazz = hierarchy.getClass(key)
|
||||
result.push([
|
||||
{ id: key, label: clazz.label, icon: clazz.icon },
|
||||
value
|
||||
.map((it) => ({ id: it._id, label: it.label, icon: it.icon }))
|
||||
.sort((a, b) => a.label.localeCompare(b.label))
|
||||
])
|
||||
} catch {}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const classes = filterClasses()
|
||||
</script>
|
||||
|
||||
<CardModal
|
||||
@@ -130,10 +90,5 @@
|
||||
<div class="mb-2">
|
||||
<Label label={card.string.ChangeTypeWarning} />
|
||||
</div>
|
||||
<NestedDropdown
|
||||
items={classes}
|
||||
on:selected={(e) => {
|
||||
selected = e.detail
|
||||
}}
|
||||
/>
|
||||
<TypeSelector bind:value={selected} />
|
||||
</CardModal>
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
<!--
|
||||
// Copyright © 2025 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 { MasterTag } from '@hcengineering/card'
|
||||
import { Class, ClassifierKind, Doc, Ref } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { DropdownIntlItem, NestedDropdown } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import card from '../plugin'
|
||||
|
||||
export let value: Ref<MasterTag>
|
||||
export let width: string | undefined = undefined
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
function filterClasses (): [DropdownIntlItem, DropdownIntlItem[]][] {
|
||||
const descendants = hierarchy.getDescendants(card.class.Card).filter((p) => p !== card.class.Card)
|
||||
const added = new Set<Ref<Class<Doc>>>()
|
||||
const base = new Map<Ref<Class<Doc>>, Class<Doc>[]>()
|
||||
for (const _id of descendants) {
|
||||
if (added.has(_id)) continue
|
||||
const _class = hierarchy.getClass(_id)
|
||||
if (_class.label === undefined) continue
|
||||
if (_class.kind !== ClassifierKind.CLASS) continue
|
||||
if ((_class as MasterTag).removed === true) continue
|
||||
added.add(_id)
|
||||
const descendants = hierarchy.getDescendants(_id)
|
||||
const toAdd: Class<Doc>[] = []
|
||||
for (const desc of descendants) {
|
||||
if (added.has(desc)) continue
|
||||
const _class = hierarchy.getClass(desc)
|
||||
if (_class.label === undefined) continue
|
||||
if (_class.kind !== ClassifierKind.CLASS) continue
|
||||
if ((_class as MasterTag).removed === true) continue
|
||||
added.add(desc)
|
||||
toAdd.push(_class)
|
||||
}
|
||||
base.set(_id, toAdd)
|
||||
}
|
||||
const result: [DropdownIntlItem, DropdownIntlItem[]][] = []
|
||||
for (const [key, value] of base) {
|
||||
try {
|
||||
const clazz = hierarchy.getClass(key)
|
||||
result.push([
|
||||
{ id: key, label: clazz.label },
|
||||
value.map((it) => ({ id: it._id, label: it.label })).sort((a, b) => a.label.localeCompare(b.label))
|
||||
])
|
||||
} catch {}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const classes = filterClasses()
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
$: selectedClass = hierarchy.getClass(value)
|
||||
$: selected = {
|
||||
id: selectedClass._id,
|
||||
label: selectedClass.label
|
||||
}
|
||||
</script>
|
||||
|
||||
<NestedDropdown
|
||||
items={classes}
|
||||
{width}
|
||||
{selected}
|
||||
on:selected={(e) => {
|
||||
value = e.detail
|
||||
dispatch('change', value)
|
||||
}}
|
||||
/>
|
||||
@@ -72,6 +72,8 @@ export { default as CardIcon } from './components/CardIcon.svelte'
|
||||
export { default as Navigator } from './components/navigator-next/Navigator.svelte'
|
||||
export { default as Favorites } from './components/Favorites.svelte'
|
||||
export { default as CardPresenter } from './components/CardPresenter.svelte'
|
||||
export { default as TypeSelector } from './components/TypeSelector.svelte'
|
||||
export { default as AssociationsSelect } from './components/settings/view/AssociationsSelect.svelte'
|
||||
|
||||
export * from './types'
|
||||
export { getCardIconInfo } from './utils'
|
||||
|
||||
@@ -89,7 +89,8 @@
|
||||
"Absolute": "Absolutní hodnota",
|
||||
"LogAction": "Událost",
|
||||
"Started": "Spuštěno",
|
||||
"Each": "Každý"
|
||||
"Each": "Každý",
|
||||
"CreateCard": "Vytvořit kartu"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Metoda nenalezena: {methodId}",
|
||||
@@ -103,6 +104,7 @@
|
||||
"InternalServerError": "Vnitřní chyba serveru, kontaktujte podporu, chybové id: {errorId}",
|
||||
"ResultNotProvided": "Výsledek nebyl poskytnut",
|
||||
"EmptyFunctionResult": "Prázdný výsledek funkce {func}",
|
||||
"ContextValueNotProvided": "Hodnota kontextu nebyla poskytnuta: {name}"
|
||||
"ContextValueNotProvided": "Hodnota kontextu nebyla poskytnuta: {name}",
|
||||
"RequiredParamsNotProvided": "Chybí požadované parametry: {params}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@
|
||||
"Absolute": "Absolutwert",
|
||||
"LogAction": "Ereignis",
|
||||
"Started": "Gestartet",
|
||||
"Each": "Jeder"
|
||||
"Each": "Jeder",
|
||||
"CreateCard": "Karte erstellen"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Methode nicht gefunden: {methodId}",
|
||||
@@ -103,6 +104,7 @@
|
||||
"InternalServerError": "Interner Serverfehler, bitte kontaktieren Sie den Support, Fehler-ID: {errorId}",
|
||||
"ResultNotProvided": "Ergebnis nicht bereitgestellt",
|
||||
"EmptyFunctionResult": "Leerer Funktionsresultat {func}",
|
||||
"ContextValueNotProvided": "Kontextwert nicht bereitgestellt: {name}"
|
||||
"ContextValueNotProvided": "Kontextwert nicht bereitgestellt: {name}",
|
||||
"RequiredParamsNotProvided": "Erforderliche Parameter nicht bereitgestellt: {params}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@
|
||||
"Floor": "Floor",
|
||||
"LogAction": "Event",
|
||||
"Started": "Started",
|
||||
"Each": "Each"
|
||||
"Each": "Each",
|
||||
"CreateCard": "Create card"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Method not found: {methodId}",
|
||||
@@ -103,6 +104,7 @@
|
||||
"InternalServerError": "Internal server error, contact support, error id: {errorId}",
|
||||
"ResultNotProvided": "Result not provided",
|
||||
"EmptyFunctionResult": "Empty function result {func}",
|
||||
"ContextValueNotProvided": "Context value not provided: {name}"
|
||||
"ContextValueNotProvided": "Context value not provided: {name}",
|
||||
"RequiredParamsNotProvided": "Required parameters not provided: {params}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@
|
||||
"Absolute": "Valor absoluto",
|
||||
"LogAction": "Evento",
|
||||
"Started": "Iniciado",
|
||||
"Each": "Cada"
|
||||
"Each": "Cada",
|
||||
"CreateCard": "Crear tarjeta"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Método no encontrado: {methodId}",
|
||||
@@ -103,6 +104,7 @@
|
||||
"InternalServerError": "Error interno del servidor, contacte con el soporte, id de error: {errorId}",
|
||||
"ResultNotProvided": "Resultado no proporcionado",
|
||||
"EmptyFunctionResult": "Resultado de función vacío {func}",
|
||||
"ContextValueNotProvided": "Valor de contexto no proporcionado: {name}"
|
||||
"ContextValueNotProvided": "Valor de contexto no proporcionado: {name}",
|
||||
"RequiredParamsNotProvided": "Faltan parámetros requeridos: {params}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@
|
||||
"Absolute": "Valeur absolue",
|
||||
"LogAction": "Événement",
|
||||
"Started": "Démarré",
|
||||
"Each": "Chaque"
|
||||
"Each": "Chaque",
|
||||
"CreateCard": "Créer une carte"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Méthode introuvable : {methodId}",
|
||||
@@ -103,6 +104,7 @@
|
||||
"InternalServerError": "Erreur interne du serveur, contactez le support, id d'erreur : {errorId}",
|
||||
"ResultNotProvided": "Résultat non fourni",
|
||||
"EmptyFunctionResult": "Résultat de fonction vide {func}",
|
||||
"ContextValueNotProvided": "Valeur de contexte non fournie : {name}"
|
||||
"ContextValueNotProvided": "Valeur de contexte non fournie : {name}",
|
||||
"RequiredParamsNotProvided": "Paramètres requis non fournis : {params}"
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,8 @@
|
||||
"Absolute": "Valore assoluto",
|
||||
"LogAction": "Evento",
|
||||
"Started": "Avviato",
|
||||
"Each": "Ogni"
|
||||
"Each": "Ogni",
|
||||
"CreateCard": "Crea scheda"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Metodo non trovato: {methodId}",
|
||||
@@ -103,6 +104,7 @@
|
||||
"InternalServerError": "Errore interno del server, contatta il supporto, id errore: {errorId}",
|
||||
"ResultNotProvided": "Risultato non fornito",
|
||||
"EmptyFunctionResult": "Risultato funzione vuoto {func}",
|
||||
"ContextValueNotProvided": "Valore di contesto non fornito: {name}"
|
||||
"ContextValueNotProvided": "Valore di contesto non fornito: {name}",
|
||||
"RequiredParamsNotProvided": "Parametri richiesti non forniti: {params}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,8 @@
|
||||
"Absolute": "絶対値",
|
||||
"LogAction": "イベント",
|
||||
"Started": "開始",
|
||||
"Each": "各"
|
||||
"Each": "各",
|
||||
"CreateCard": "カードを作成"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "メソッドが見つかりません: {methodId}",
|
||||
@@ -101,6 +102,7 @@
|
||||
"EmptyRelatedObjectValue": "関連オブジェクト {parent} の値が空です: {attr}",
|
||||
"InternalServerError": "内部サーバーエラー。サポートにお問い合わせください。エラーID: {errorId}",
|
||||
"EmptyFunctionResult": "関数結果が空です {func}",
|
||||
"ContextValueNotProvided": "コンテキスト値が提供されていません: {name}"
|
||||
"ContextValueNotProvided": "コンテキスト値が提供されていません: {name}",
|
||||
"RequiredParamsNotProvided": "必須パラメータが提供されていません: {params}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@
|
||||
"Absolute": "Valor absoluto",
|
||||
"LogAction": "Evento",
|
||||
"Started": "Iniciado",
|
||||
"Each": "Cada"
|
||||
"Each": "Cada",
|
||||
"CreateCard": "Criar Cartão"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Método não encontrado: {methodId}",
|
||||
@@ -103,6 +104,7 @@
|
||||
"InternalServerError": "Erro interno do servidor, contate o suporte, id de erro: {errorId}",
|
||||
"ResultNotProvided": "Resultado não fornecido",
|
||||
"EmptyFunctionResult": "Resultado da função vazio {func}",
|
||||
"ContextValueNotProvided": "Valor de contexto não fornecido: {name}"
|
||||
"ContextValueNotProvided": "Valor de contexto não fornecido: {name}",
|
||||
"RequiredParamsNotProvided": "Parâmetros obrigatórios não fornecidos: {params}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@
|
||||
"Absolute": "Абсолютное значение",
|
||||
"LogAction": "Событие",
|
||||
"Started": "Начат",
|
||||
"Each": "Каждый"
|
||||
"Each": "Каждый",
|
||||
"CreateCard": "Создать карточку"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "Метод не найден: {methodId}",
|
||||
@@ -103,6 +104,7 @@
|
||||
"AttributeNotExists": "Атрибут не существует: {key}",
|
||||
"ResultNotProvided": "Результат не предоставлен",
|
||||
"EmptyFunctionResult": "Отсутствуют результат функции {func}",
|
||||
"ContextValueNotProvided": "Значение контекста не предоставлено: {name}"
|
||||
"ContextValueNotProvided": "Значение контекста не предоставлено: {name}",
|
||||
"RequiredParamsNotProvided": "Отсутствуют обязательные параметры: {params}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@
|
||||
"Absolute": "绝对值",
|
||||
"LogAction": "事件",
|
||||
"Started": "已启动",
|
||||
"Each": "每个"
|
||||
"Each": "每个",
|
||||
"CreateCard": "创建卡片"
|
||||
},
|
||||
"error": {
|
||||
"MethodNotFound": "找不到方法:{methodId}",
|
||||
@@ -103,6 +104,7 @@
|
||||
"InternalServerError": "内部服务器错误,请联系支持,错误 ID:{errorId}",
|
||||
"ResultNotProvided": "未提供结果",
|
||||
"EmptyFunctionResult": "空函数结果 {func}",
|
||||
"ContextValueNotProvided": "未提供上下文值:{name}"
|
||||
"ContextValueNotProvided": "未提供上下文值:{name}",
|
||||
"RequiredParamsNotProvided": "未提供必需的参数:{params}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,11 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Execution } from '@hcengineering/process'
|
||||
import { Doc, WithLookup } from '@hcengineering/core'
|
||||
import presentation, { ActionContext, Card, createQuery } from '@hcengineering/presentation'
|
||||
import presentation, { ActionContext, createQuery } from '@hcengineering/presentation'
|
||||
import { Execution } from '@hcengineering/process'
|
||||
import { Modal, registerFocus } from '@hcengineering/ui'
|
||||
import view, { Viewlet, ViewletPreference, ViewOptions } from '@hcengineering/view'
|
||||
import {
|
||||
List,
|
||||
ListSelectionProvider,
|
||||
@@ -26,7 +27,6 @@
|
||||
} from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import process from '../plugin'
|
||||
import view, { Viewlet, ViewletPreference, ViewOptions } from '@hcengineering/view'
|
||||
|
||||
export let execution: Execution
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
}
|
||||
)
|
||||
let docs: Doc[] = []
|
||||
function select () {
|
||||
function select (): void {
|
||||
listProvider.update(docs)
|
||||
listProvider.updateFocus(docs[0])
|
||||
list?.select(0, undefined)
|
||||
@@ -68,6 +68,7 @@
|
||||
let preference: ViewletPreference | undefined = undefined
|
||||
|
||||
const query = createQuery()
|
||||
const viewletId = process.viewlet.ExecutionLogList
|
||||
|
||||
$: query.query(
|
||||
view.class.Viewlet,
|
||||
@@ -86,8 +87,6 @@
|
||||
|
||||
const preferenceQuery = createQuery()
|
||||
|
||||
const viewletId = process.viewlet.ExecutionLogList
|
||||
|
||||
$: if (viewlet != null) {
|
||||
preferenceQuery.query(
|
||||
view.class.ViewletPreference,
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { MasterTag, Tag } from '@hcengineering/card'
|
||||
import { AnyAttribute, Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { Context, parseContext, SelectedContext, Process } from '@hcengineering/process'
|
||||
import { Context, parseContext, Process, SelectedContext } from '@hcengineering/process'
|
||||
import {
|
||||
AnySvelteComponent,
|
||||
Button,
|
||||
@@ -29,7 +30,6 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import ContextSelectorPopup from './attributeEditors/ContextSelectorPopup.svelte'
|
||||
import ContextValue from './attributeEditors/ContextValue.svelte'
|
||||
import { MasterTag, Tag } from '@hcengineering/card'
|
||||
|
||||
export let process: Process
|
||||
export let masterTag: Ref<MasterTag | Tag>
|
||||
@@ -61,6 +61,7 @@
|
||||
masterTag,
|
||||
context,
|
||||
attribute,
|
||||
forbidValue,
|
||||
onSelect
|
||||
},
|
||||
eventToHTMLElement(e)
|
||||
@@ -73,69 +74,68 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if editor}
|
||||
<span
|
||||
class="labelOnPanel"
|
||||
use:tooltip={{
|
||||
props: { label: attribute.label }
|
||||
}}
|
||||
>
|
||||
<Label label={attribute.label} />
|
||||
</span>
|
||||
<div class="text-input" class:context={contextValue}>
|
||||
{#if contextValue}
|
||||
<ContextValue
|
||||
{process}
|
||||
{masterTag}
|
||||
{contextValue}
|
||||
{context}
|
||||
{attribute}
|
||||
{allowArray}
|
||||
category={presenterClass.category}
|
||||
attrClass={presenterClass.attrClass}
|
||||
on:update={(e) => {
|
||||
onSelect(e.detail)
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<div class="w-full">
|
||||
{#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">
|
||||
<Button
|
||||
icon={IconAdd}
|
||||
kind="ghost"
|
||||
on:click={(e) => {
|
||||
selectContext(e)
|
||||
}}
|
||||
/>
|
||||
{#if allowRemove}
|
||||
<Button
|
||||
icon={IconClose}
|
||||
kind="ghost"
|
||||
on:click={() => {
|
||||
dispatch('remove', { key: attribute.name })
|
||||
}}
|
||||
<span
|
||||
class="labelOnPanel"
|
||||
use:tooltip={{
|
||||
props: { label: attribute.label }
|
||||
}}
|
||||
>
|
||||
<Label label={attribute.label} />
|
||||
</span>
|
||||
<div class="text-input" class:context={contextValue}>
|
||||
{#if contextValue}
|
||||
<ContextValue
|
||||
{process}
|
||||
{masterTag}
|
||||
{contextValue}
|
||||
{context}
|
||||
{attribute}
|
||||
{allowArray}
|
||||
category={presenterClass.category}
|
||||
attrClass={presenterClass.attrClass}
|
||||
{forbidValue}
|
||||
on:update={(e) => {
|
||||
onSelect(e.detail)
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
<div class="w-full">
|
||||
{#if !forbidValue && editor}
|
||||
<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">
|
||||
<Button
|
||||
icon={IconAdd}
|
||||
kind="ghost"
|
||||
on:click={(e) => {
|
||||
selectContext(e)
|
||||
}}
|
||||
/>
|
||||
{#if allowRemove}
|
||||
<Button
|
||||
icon={IconClose}
|
||||
kind="ghost"
|
||||
on:click={() => {
|
||||
dispatch('remove', { key: attribute.name })
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.text-input {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { MasterTag, Tag } from '@hcengineering/card'
|
||||
import { AnyAttribute, Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Context, Func, Process, ProcessFunction, SelectedContext } from '@hcengineering/process'
|
||||
@@ -33,7 +34,6 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import plugin from '../../plugin'
|
||||
import FallbackEditor from '../contextEditors/FallbackEditor.svelte'
|
||||
import { MasterTag, Tag } from '@hcengineering/card'
|
||||
|
||||
export let process: Process
|
||||
export let masterTag: Ref<MasterTag | Tag>
|
||||
@@ -44,6 +44,7 @@
|
||||
export let category: AttributeCategory
|
||||
export let onChange: (contextValue: SelectedContext) => void
|
||||
export let allowArray: boolean = false
|
||||
export let forbidValue: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
|
||||
@@ -321,50 +322,52 @@
|
||||
{/if}
|
||||
<div class="menu-separator" />
|
||||
{/if}
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<button
|
||||
bind:this={elements[functionButtonIndex + 1]}
|
||||
on:keydown={(event) => {
|
||||
keyDown(event, functionButtonIndex + 1)
|
||||
}}
|
||||
on:mouseover={() => {
|
||||
elements[functionButtonIndex + 1]?.focus()
|
||||
}}
|
||||
on:click={onFallbackChange}
|
||||
class="menu-item flex-gap-2 fallback"
|
||||
>
|
||||
<div>
|
||||
<div class="label">
|
||||
<Label label={plugin.string.Required} />
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
<Label label={plugin.string.FallbackValueError} />
|
||||
</div>
|
||||
</div>
|
||||
<CheckBox
|
||||
on:click={onFallbackChange}
|
||||
checked={contextValue.fallbackValue === undefined}
|
||||
size={'medium'}
|
||||
kind={'primary'}
|
||||
/>
|
||||
</button>
|
||||
{#if contextValue.fallbackValue !== undefined}
|
||||
{#if !forbidValue}
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<button
|
||||
bind:this={elements[functionButtonIndex + 2]}
|
||||
bind:this={elements[functionButtonIndex + 1]}
|
||||
on:keydown={(event) => {
|
||||
keyDown(event, functionButtonIndex + 2)
|
||||
keyDown(event, functionButtonIndex + 1)
|
||||
}}
|
||||
on:mouseover={() => {
|
||||
elements[functionButtonIndex + 2]?.focus()
|
||||
elements[functionButtonIndex + 1]?.focus()
|
||||
}}
|
||||
on:click={onFallback}
|
||||
class="menu-item"
|
||||
on:click={onFallbackChange}
|
||||
class="menu-item flex-gap-2 fallback"
|
||||
>
|
||||
<span class="overflow-label pr-1">
|
||||
<Label label={plugin.string.FallbackValue} />
|
||||
</span>
|
||||
<div>
|
||||
<div class="label">
|
||||
<Label label={plugin.string.Required} />
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
<Label label={plugin.string.FallbackValueError} />
|
||||
</div>
|
||||
</div>
|
||||
<CheckBox
|
||||
on:click={onFallbackChange}
|
||||
checked={contextValue.fallbackValue === undefined}
|
||||
size={'medium'}
|
||||
kind={'primary'}
|
||||
/>
|
||||
</button>
|
||||
{#if contextValue.fallbackValue !== undefined}
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<button
|
||||
bind:this={elements[functionButtonIndex + 2]}
|
||||
on:keydown={(event) => {
|
||||
keyDown(event, functionButtonIndex + 2)
|
||||
}}
|
||||
on:mouseover={() => {
|
||||
elements[functionButtonIndex + 2]?.focus()
|
||||
}}
|
||||
on:click={onFallback}
|
||||
class="menu-item"
|
||||
>
|
||||
<span class="overflow-label pr-1">
|
||||
<Label label={plugin.string.FallbackValue} />
|
||||
</span>
|
||||
</button>
|
||||
{/if}
|
||||
{/if}
|
||||
</Scroller>
|
||||
<div class="menu-space" />
|
||||
|
||||
+16
-25
@@ -18,7 +18,6 @@
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import {
|
||||
Context,
|
||||
ContextId,
|
||||
Process,
|
||||
ProcessContext,
|
||||
ProcessFunction,
|
||||
@@ -28,7 +27,7 @@
|
||||
import { Label, resizeObserver, Scroller, Submenu } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import plugin from '../../plugin'
|
||||
import { generateContextId, getRelationObjectReduceFunc, getValueReduceFunc, isTypeEqual } from '../../utils'
|
||||
import { generateContextId, getRelationObjectReduceFunc, getValueReduceFunc } from '../../utils'
|
||||
import ExecutionContextPresenter from './ExecutionContextPresenter.svelte'
|
||||
|
||||
export let process: Process
|
||||
@@ -36,6 +35,7 @@
|
||||
export let context: Context
|
||||
export let attribute: AnyAttribute
|
||||
export let onSelect: (val: SelectedContext | null) => void
|
||||
export let forbidValue: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -58,18 +58,7 @@
|
||||
})
|
||||
}
|
||||
|
||||
$: processContext = getProcessContext(process, attribute)
|
||||
|
||||
function getProcessContext (process: Process, attribute: AnyAttribute): ProcessContext[] {
|
||||
const res: ProcessContext[] = []
|
||||
for (const key in process?.context ?? {}) {
|
||||
const ctx = process.context[key as ContextId]
|
||||
if (ctx._class === attribute.type._class && isTypeEqual(ctx.type, attribute.type)) {
|
||||
res.push(ctx)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
$: processContext = Object.values(context.executionContext)
|
||||
|
||||
$: nested = Object.values(context.nested)
|
||||
$: relations = Object.entries(context.relations)
|
||||
@@ -236,17 +225,19 @@
|
||||
{/each}
|
||||
<div class="menu-separator" />
|
||||
{/if}
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<button
|
||||
on:click={() => {
|
||||
onCustom()
|
||||
}}
|
||||
class="menu-item"
|
||||
>
|
||||
<span class="overflow-label pr-1">
|
||||
<Label label={plugin.string.CustomValue} />
|
||||
</span>
|
||||
</button>
|
||||
{#if !forbidValue}
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
<button
|
||||
on:click={() => {
|
||||
onCustom()
|
||||
}}
|
||||
class="menu-item"
|
||||
>
|
||||
<span class="overflow-label pr-1">
|
||||
<Label label={plugin.string.CustomValue} />
|
||||
</span>
|
||||
</button>
|
||||
{/if}
|
||||
</Scroller>
|
||||
<div class="menu-space" />
|
||||
</div>
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { SelectedContext, Context, Process } from '@hcengineering/process'
|
||||
import { MasterTag, Tag } from '@hcengineering/card'
|
||||
import { AnyAttribute, Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { Context, Process, SelectedContext } from '@hcengineering/process'
|
||||
import { eventToHTMLElement, showPopup } from '@hcengineering/ui'
|
||||
import ConfigurePopup from './ConfigurePopup.svelte'
|
||||
import { Ref, Class, Doc, AnyAttribute } from '@hcengineering/core'
|
||||
import ContextValuePresenter from './ContextValuePresenter.svelte'
|
||||
import { AttributeCategory } from '@hcengineering/view'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { MasterTag, Tag } from '@hcengineering/card'
|
||||
import ConfigurePopup from './ConfigurePopup.svelte'
|
||||
import ContextValuePresenter from './ContextValuePresenter.svelte'
|
||||
|
||||
export let process: Process
|
||||
export let masterTag: Ref<MasterTag | Tag>
|
||||
@@ -30,6 +30,7 @@
|
||||
export let attrClass: Ref<Class<Doc>>
|
||||
export let category: AttributeCategory
|
||||
export let allowArray: boolean = false
|
||||
export let forbidValue: boolean = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -50,7 +51,7 @@
|
||||
}
|
||||
showPopup(
|
||||
ConfigurePopup,
|
||||
{ contextValue, attrClass, masterTag, category, attribute, context, onChange, allowArray },
|
||||
{ contextValue, attrClass, masterTag, category, attribute, context, onChange, allowArray, forbidValue },
|
||||
eventToHTMLElement(e)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<script lang="ts">
|
||||
export let size: 'small' | 'medium' | 'large' | 'full'
|
||||
const fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="svg-{size}" viewBox="0 0 16 45" fill="none">
|
||||
<path d="M8 0L8 43" stroke={fill} />
|
||||
<path
|
||||
d="M12.295 37.295L8.5 41.085V31.5C8.5 31.22386 8.27614 31 8 31C7.72386 31 7.5 31.22386 7.5 31.5V41.085L3.705 37.295L3 38L8 43L13 38L12.295 37.295Z"
|
||||
{fill}
|
||||
/>
|
||||
</svg>
|
||||
@@ -1,11 +0,0 @@
|
||||
<script lang="ts">
|
||||
export let size: 'small' | 'medium' | 'large' | 'full'
|
||||
const fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" viewBox="0 0 6 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3 0.333333C1.52724 0.333333 0.333333 1.52724 0.333333 3C0.333333 4.47276 1.52724 5.66667 3 5.66667C4.47276 5.66667 5.66667 4.47276 5.66667 3C5.66667 1.52724 4.47276 0.333333 3 0.333333ZM2.5 3L2.5 48L3.5 48L3.5 3L2.5 3Z"
|
||||
{fill}
|
||||
/>
|
||||
</svg>
|
||||
@@ -1,33 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { ColorDefinition, IconSize, getPlatformColorDef, themeStore } from '@hcengineering/ui'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
|
||||
export let size: IconSize = 'small'
|
||||
|
||||
export let fill: number = 21
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const dispatchAccentColor = (color?: ColorDefinition) => dispatch('accent-color', color)
|
||||
|
||||
$: color = getPlatformColorDef(fill, $themeStore.dark)
|
||||
$: dispatchAccentColor(color)
|
||||
|
||||
onMount(() => {
|
||||
dispatchAccentColor(color)
|
||||
})
|
||||
</script>
|
||||
|
||||
<svg
|
||||
class="svg-{size}"
|
||||
fill={color?.icon ?? 'currentColor'}
|
||||
style:flex-shrink={0}
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M6.97975 1.07389C3.92356 1.52014 1.50831 3.94118 1.0708 7.0002H2.08287C2.50337 4.49345 4.47822 2.51374 6.9825 2.08599L6.97975 1.07389ZM8.98249 2.08014L8.97974 1.06812C12.055 1.49885 14.4896 3.92773 14.9291 7.0002H13.917C13.4945 4.48183 11.5033 2.4954 8.98249 2.08014ZM9.01467 13.9146C11.5201 13.4879 13.4962 11.5077 13.917 9.00019H14.929C14.4913 12.06 12.0748 14.4815 9.01742 14.9267L9.01467 13.9146ZM2.0829 9.0002C2.50529 11.5176 4.49522 13.5034 7.01468 13.9196L7.01743 14.9317C3.94351 14.4999 1.51022 12.0717 1.07083 9.0002H2.0829Z"
|
||||
/>
|
||||
</svg>
|
||||
@@ -1,34 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { ColorDefinition, IconSize, getPlatformColorDef, themeStore } from '@hcengineering/ui'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
|
||||
export let size: IconSize = 'small'
|
||||
|
||||
export let fill: number = 17
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const dispatchAccentColor = (color?: ColorDefinition) => dispatch('accent-color', color)
|
||||
|
||||
$: color = getPlatformColorDef(fill, $themeStore.dark)
|
||||
$: dispatchAccentColor(color)
|
||||
|
||||
onMount(() => {
|
||||
dispatchAccentColor(color)
|
||||
})
|
||||
</script>
|
||||
|
||||
<svg
|
||||
class="svg-{size}"
|
||||
fill={color?.icon ?? 'currentColor'}
|
||||
style:flex-shrink={0}
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M8,1C4.1,1,1,4.1,1,8c0,3.9,3.1,7,7,7c3.9,0,7-3.1,7-7C15,4.1,11.9,1,8,1z M8,14c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S11.3,14,8,14z"
|
||||
/>
|
||||
<path
|
||||
d="M10.6,6.1L7.5,9.2L5.9,7.6c-0.2-0.2-0.6-0.2-0.8,0s-0.2,0.6,0,0.8l2,2c0.1,0.1,0.3,0.2,0.4,0.2s0.3-0.1,0.4-0.2l3.5-3.5c0.2-0.2,0.2-0.6,0-0.8S10.8,5.8,10.6,6.1z"
|
||||
/>
|
||||
</svg>
|
||||
@@ -1,53 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { ColorDefinition, IconSize, getPlatformColorDef, themeStore } from '@hcengineering/ui'
|
||||
import { createEventDispatcher, onMount } from 'svelte'
|
||||
|
||||
export let size: IconSize = 'small'
|
||||
|
||||
export let fill: number = 11
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const dispatchAccentColor = (color?: ColorDefinition) => dispatch('accent-color', color)
|
||||
|
||||
export let count: number | undefined = undefined
|
||||
export let index: number | undefined = undefined
|
||||
|
||||
$: color = getPlatformColorDef(fill, $themeStore.dark)
|
||||
$: dispatchAccentColor(color)
|
||||
|
||||
onMount(() => {
|
||||
dispatchAccentColor(color)
|
||||
})
|
||||
</script>
|
||||
|
||||
<svg
|
||||
class="svg-{size}"
|
||||
fill={color?.icon ?? 'currentColor'}
|
||||
style:flex-shrink={0}
|
||||
style:transform={'rotate(-90deg)'}
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 15C11.866 15 15 11.866 15 8C15 4.13401 11.866 1 8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15Z"
|
||||
/>
|
||||
{#if count !== undefined && index !== undefined}
|
||||
<path
|
||||
d="M 4.5 4.5 L 9 4.5 A 4.5 4.5 0 {index > (count - 1) / 2 ? 1 : 0} 1 {Math.cos(
|
||||
((2 * Math.PI) / count) * index - 0.01
|
||||
) *
|
||||
4.5 +
|
||||
4.5} {Math.sin(((2 * Math.PI) / count) * index - 0.01) * 4.5 + 4.5} Z"
|
||||
transform="translate(3.5,3.5)"
|
||||
/>
|
||||
{:else}
|
||||
<path
|
||||
d="M 4.5 4.5 L 9 4.5 A 4.5 4.5 0 1 1 {Math.cos(Math.PI - 0.01) * 4.5 + 4.5} {Math.sin(Math.PI - 0.01) * 4.5 +
|
||||
4.5} Z"
|
||||
transform="translate(3.5,3.5)"
|
||||
/>
|
||||
{/if}
|
||||
</svg>
|
||||
@@ -0,0 +1,62 @@
|
||||
<!--
|
||||
// Copyright © 2025 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 { Card } from '@hcengineering/card'
|
||||
import { Association, Ref } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { MethodParams, parseContext, Process, Step } from '@hcengineering/process'
|
||||
import { Label } from '@hcengineering/ui'
|
||||
import plugin from '../../plugin'
|
||||
import { getContext } from '../../utils'
|
||||
import ContextValuePresenter from '../attributeEditors/ContextValuePresenter.svelte'
|
||||
|
||||
export let step: Step<Card>
|
||||
export let process: Process
|
||||
export let params: MethodParams<Card>
|
||||
|
||||
const client = getClient()
|
||||
$: method = client.getModel().findAllSync(plugin.class.Method, { _id: step.methodId })[0]
|
||||
|
||||
$: association = params.association as Ref<Association> | undefined
|
||||
$: selected = association && client.getModel().findObject(association)
|
||||
$: direction = params.direction as 'A' | 'B' | undefined
|
||||
|
||||
$: assoc = association && client.getModel().findObject(association)
|
||||
$: targetClass = assoc && direction ? (direction === 'A' ? assoc.classA : assoc.classB) : undefined
|
||||
|
||||
$: contextValue = params._id !== undefined ? parseContext(params._id) : undefined
|
||||
$: context = targetClass !== undefined ? getContext(client, process, targetClass, 'object') : undefined
|
||||
</script>
|
||||
|
||||
<div class="flex-row-center flex-gap-1">
|
||||
<Label label={method.label} />:
|
||||
<div class="title">
|
||||
{#if selected && direction}
|
||||
{direction === 'A' ? selected.nameA : selected.nameB}
|
||||
{/if}
|
||||
</div>
|
||||
{#if contextValue !== undefined && context !== undefined}
|
||||
<ContextValuePresenter {contextValue} {context} {process} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.title {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,71 @@
|
||||
<!--
|
||||
// Copyright © 2025 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 card, { Card, MasterTag } from '@hcengineering/card'
|
||||
import core, { Ref } from '@hcengineering/core'
|
||||
import { getClient, IconWithEmoji } from '@hcengineering/presentation'
|
||||
import { MethodParams, parseContext, Process, Step } from '@hcengineering/process'
|
||||
import { Icon, Label, tooltip } from '@hcengineering/ui'
|
||||
import view from '@hcengineering/view'
|
||||
import plugin from '../../plugin'
|
||||
import { getContext } from '../../utils'
|
||||
import ContextValuePresenter from '../attributeEditors/ContextValuePresenter.svelte'
|
||||
|
||||
export let step: Step<Card>
|
||||
export let process: Process
|
||||
export let params: MethodParams<Card>
|
||||
|
||||
const client = getClient()
|
||||
$: method = client.getModel().findAllSync(plugin.class.Method, { _id: step.methodId })[0]
|
||||
|
||||
$: contextValue = params.title !== undefined ? parseContext(params.title) : undefined
|
||||
$: context = getContext(client, process, core.class.TypeString, 'attribute')
|
||||
|
||||
$: _class = params?._class
|
||||
? (client.getHierarchy().getClass(params._class as Ref<MasterTag>) as MasterTag)
|
||||
: undefined
|
||||
$: icon = _class?.icon
|
||||
</script>
|
||||
|
||||
<div class="flex-row-center flex-gap-1">
|
||||
<Label label={method.label} />:
|
||||
{#if icon}
|
||||
<div class="icon" use:tooltip={{ label: _class?.label ?? card.string.Card }}>
|
||||
<Icon
|
||||
icon={icon === view.ids.IconWithEmoji ? IconWithEmoji : icon ?? card.icon.Card}
|
||||
iconProps={{ icon: _class?.color }}
|
||||
size={'small'}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if params.title}
|
||||
<div class="title">
|
||||
{#if contextValue}
|
||||
<ContextValuePresenter {contextValue} {context} {process} />
|
||||
{:else}
|
||||
{params.title}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.title {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,120 @@
|
||||
<!--
|
||||
// Copyright © 2025 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 core, { AnyAttribute, Association, Doc, generateId, Ref, RefTo, Relation } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Process, Step } from '@hcengineering/process'
|
||||
import { Label, tooltip } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { getContext } from '../../utils'
|
||||
import ProcessAttribute from '../ProcessAttribute.svelte'
|
||||
import AssociationSelector from './AssociationSelector.svelte'
|
||||
|
||||
export let process: Process
|
||||
export let step: Step<Relation>
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const params = step.params
|
||||
let association = params.association as Ref<Association> | undefined
|
||||
let direction = params.direction as 'A' | 'B' | undefined
|
||||
const _id = params._id
|
||||
|
||||
const client = getClient()
|
||||
|
||||
$: assoc = association && client.getModel().findObject(association)
|
||||
$: targetClass = assoc && direction ? (direction === 'A' ? assoc.classA : assoc.classB) : undefined
|
||||
|
||||
function changeAssociation (e: CustomEvent<any>): void {
|
||||
if (e.detail !== undefined) {
|
||||
association = e.detail.association
|
||||
direction = e.detail.direction
|
||||
params.association = association
|
||||
params.direction = direction
|
||||
;(step.params as any) = params
|
||||
dispatch('change', step)
|
||||
}
|
||||
}
|
||||
|
||||
function changeParam (e: CustomEvent<any>): void {
|
||||
if (e.detail !== undefined) {
|
||||
params._id = e.detail
|
||||
;(step.params as any)._id = e.detail
|
||||
dispatch('change', step)
|
||||
}
|
||||
}
|
||||
|
||||
let attribute: AnyAttribute
|
||||
$: attribute = {
|
||||
attributeOf: process.masterTag,
|
||||
name: '',
|
||||
type: {
|
||||
label: core.string.Ref,
|
||||
_class: core.class.RefTo,
|
||||
to: targetClass
|
||||
},
|
||||
_id: generateId(),
|
||||
space: core.space.Model,
|
||||
modifiedOn: 0,
|
||||
modifiedBy: core.account.System,
|
||||
_class: core.class.Attribute,
|
||||
label: core.string.Object
|
||||
}
|
||||
|
||||
$: context = targetClass && getContext(client, process, targetClass, 'object')
|
||||
</script>
|
||||
|
||||
<div class="grid">
|
||||
<span
|
||||
class="labelOnPanel"
|
||||
use:tooltip={{
|
||||
props: { label: core.string.Relation }
|
||||
}}
|
||||
>
|
||||
<Label label={core.string.Relation} />
|
||||
</span>
|
||||
<AssociationSelector {process} {association} {direction} on:change={changeAssociation} />
|
||||
{#if targetClass && context && attribute}
|
||||
<ProcessAttribute
|
||||
value={_id}
|
||||
{process}
|
||||
{attribute}
|
||||
{context}
|
||||
masterTag={process.masterTag}
|
||||
editor={undefined}
|
||||
presenterClass={{
|
||||
attrClass: targetClass,
|
||||
category: 'object'
|
||||
}}
|
||||
forbidValue
|
||||
on:change={changeParam}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.5fr;
|
||||
grid-auto-rows: minmax(2rem, max-content);
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
row-gap: 0.5rem;
|
||||
column-gap: 1rem;
|
||||
margin: 0.25rem 2rem 0;
|
||||
width: calc(100% - 4rem);
|
||||
height: min-content;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,84 @@
|
||||
<!--
|
||||
// Copyright © 2025 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 core, { Association, Ref } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Process } from '@hcengineering/process'
|
||||
import { Button, eventToHTMLElement, Label, SelectPopup, SelectPopupValueType, showPopup } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
export let process: Process
|
||||
export let association: Ref<Association> | undefined = undefined
|
||||
export let direction: 'A' | 'B' | undefined = undefined
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function open (e: MouseEvent): void {
|
||||
const descendants = hierarchy.getDescendants(process.masterTag)
|
||||
const leftAssociations = client.getModel().findAllSync(core.class.Association, { classA: { $in: descendants } })
|
||||
const rightAssociations = client.getModel().findAllSync(core.class.Association, { classB: { $in: descendants } })
|
||||
const items: SelectPopupValueType[] = []
|
||||
rightAssociations.forEach((a) => {
|
||||
items.push({
|
||||
id: 'A_' + a._id,
|
||||
text: a.nameA,
|
||||
isSelected: association !== undefined && association === a._id && direction === 'A'
|
||||
})
|
||||
})
|
||||
leftAssociations.forEach((a) => {
|
||||
items.push({
|
||||
id: 'B_' + a._id,
|
||||
text: a.nameB,
|
||||
isSelected: association !== undefined && association === a._id && direction === 'B'
|
||||
})
|
||||
})
|
||||
showPopup(
|
||||
SelectPopup,
|
||||
{
|
||||
value: items
|
||||
},
|
||||
eventToHTMLElement(e),
|
||||
(res) => {
|
||||
if (res !== undefined) {
|
||||
const [dir, id] = res.split('_')
|
||||
association = id as Ref<Association>
|
||||
direction = dir as 'A' | 'B'
|
||||
} else {
|
||||
association = undefined
|
||||
direction = undefined
|
||||
}
|
||||
dispatch('change', {
|
||||
association,
|
||||
direction
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
$: selected = association !== undefined && client.getModel().findObject(association)
|
||||
</script>
|
||||
|
||||
<Button on:click={open} width={'100%'}>
|
||||
<div slot="content">
|
||||
{#if selected && direction !== undefined}
|
||||
{direction === 'A' ? selected.nameA : selected.nameB}
|
||||
{:else}
|
||||
<Label label={core.string.Relation} />
|
||||
{/if}
|
||||
</div>
|
||||
</Button>
|
||||
@@ -27,12 +27,12 @@
|
||||
|
||||
const client = getClient()
|
||||
|
||||
async function save () {
|
||||
async function save (): Promise<void> {
|
||||
await client.update(process, { context: process.context })
|
||||
clearSettingsStore()
|
||||
}
|
||||
|
||||
function onNameChange (ev: Event, _id: string, ctx: ProcessContext) {
|
||||
function onNameChange (ev: Event, _id: string, ctx: ProcessContext): void {
|
||||
const value = (ev.target as HTMLInputElement).value?.trim()
|
||||
ctx.name = value
|
||||
process.context[_id as ContextId] = ctx
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
<!--
|
||||
// Copyright © 2025 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 cardPlugin, { Card, MasterTag } from '@hcengineering/card'
|
||||
import { TypeSelector } from '@hcengineering/card-resources'
|
||||
import core, { AnyAttribute, Class, Ref } from '@hcengineering/core'
|
||||
import { translateCB } from '@hcengineering/platform'
|
||||
import presentation, { getClient } from '@hcengineering/presentation'
|
||||
import { MethodParams, Process, Step } from '@hcengineering/process'
|
||||
import { Button, eventToHTMLElement, Label, SelectPopup, showPopup, tooltip } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import ParamsEditor from './ParamsEditor.svelte'
|
||||
|
||||
export let process: Process
|
||||
export let step: Step<Card>
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
step.params.title = step.params.title ?? ''
|
||||
step.params._class = step.params._class ?? process.masterTag
|
||||
|
||||
let params = step.params
|
||||
|
||||
let _class: Ref<Class<MasterTag>> = (params._class as Ref<Class<MasterTag>>) ?? process.masterTag
|
||||
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
translateCB(cardPlugin.string.Card, {}, undefined, (res) => {
|
||||
if (params.title === undefined || params.title === '') {
|
||||
params.title = res
|
||||
;(step.params as any) = params
|
||||
dispatch('change', step)
|
||||
}
|
||||
})
|
||||
|
||||
function change (e: CustomEvent<any>): void {
|
||||
if (e.detail !== undefined) {
|
||||
params = e.detail
|
||||
;(step.params as any) = e.detail
|
||||
dispatch('change', step)
|
||||
}
|
||||
}
|
||||
|
||||
function getKeys (_class: Ref<Class<MasterTag>>): AnyAttribute[] {
|
||||
const ignoreKeys = ['_class', 'content', 'parent', 'attachments', 'todos']
|
||||
const attributes = hierarchy.getAllAttributes(_class, core.class.Doc)
|
||||
const res: AnyAttribute[] = []
|
||||
for (const [key, attr] of attributes) {
|
||||
if (attr.hidden === true) continue
|
||||
if (ignoreKeys.includes(key)) continue
|
||||
res.push(attr)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
let keys = Object.keys(params).filter((key) => {
|
||||
return key !== '_class'
|
||||
})
|
||||
|
||||
$: allAttrs = getKeys(_class)
|
||||
$: possibleAttrs = allAttrs.filter((attr) => !keys.includes(attr.name))
|
||||
|
||||
function addKey (key: string): void {
|
||||
keys = [...keys, key]
|
||||
}
|
||||
|
||||
function onAdd (e: MouseEvent): void {
|
||||
showPopup(
|
||||
SelectPopup,
|
||||
{
|
||||
value: possibleAttrs.map((p) => {
|
||||
return { id: p.name, label: p.label }
|
||||
})
|
||||
},
|
||||
eventToHTMLElement(e),
|
||||
(res) => {
|
||||
if (res != null) {
|
||||
addKey(res)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function remove (e: CustomEvent<any>): void {
|
||||
if (e.detail !== undefined) {
|
||||
const key = e.detail.key
|
||||
if (key === 'title') return
|
||||
keys = keys.filter((k) => k !== key)
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete (params as any)[key]
|
||||
;(step.params as any) = params
|
||||
dispatch('change', step)
|
||||
}
|
||||
}
|
||||
|
||||
function typeChange (e: CustomEvent<Ref<Class<MasterTag>>>): void {
|
||||
if (e.detail === undefined || e.detail === _class) return
|
||||
allAttrs = getKeys(e.detail)
|
||||
const oldParams = { ...params }
|
||||
params = {}
|
||||
for (const attr of allAttrs) {
|
||||
const key = attr.name
|
||||
if (oldParams[key] !== undefined) {
|
||||
;(params as any)[key] = oldParams[key]
|
||||
}
|
||||
}
|
||||
_class = e.detail
|
||||
keys = Object.keys(params)
|
||||
params._class = _class
|
||||
step.params = params
|
||||
if (step.context != null) {
|
||||
step.context._class = _class
|
||||
}
|
||||
dispatch('change', step)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="grid">
|
||||
<span
|
||||
class="labelOnPanel"
|
||||
use:tooltip={{
|
||||
props: { label: cardPlugin.string.MasterTag }
|
||||
}}
|
||||
>
|
||||
<Label label={cardPlugin.string.MasterTag} />
|
||||
</span>
|
||||
<TypeSelector value={_class} width={'100%'} on:change={typeChange} />
|
||||
</div>
|
||||
<div class="divider" />
|
||||
{#key _class}
|
||||
<ParamsEditor {_class} {process} {keys} {params} allowRemove on:remove={remove} on:change={change} />
|
||||
{/key}
|
||||
{#if possibleAttrs.length > 0}
|
||||
<div class="flex-center mt-4">
|
||||
<Button label={presentation.string.Add} width={'100%'} kind={'link-bordered'} size={'large'} on:click={onAdd} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style lang="scss">
|
||||
.divider {
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1.5fr;
|
||||
grid-auto-rows: minmax(2rem, max-content);
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
row-gap: 0.5rem;
|
||||
column-gap: 1rem;
|
||||
margin: 0.25rem 2rem 0;
|
||||
width: calc(100% - 4rem);
|
||||
height: min-content;
|
||||
}
|
||||
</style>
|
||||
@@ -14,7 +14,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Class, Doc, Ref } from '@hcengineering/core'
|
||||
import { MethodParams, Process, State } from '@hcengineering/process'
|
||||
import { MethodParams, Process } from '@hcengineering/process'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import ProcessAttributeEditor from './ProcessAttributeEditor.svelte'
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<script lang="ts">
|
||||
import core, { Class, Doc, PropertyType, Ref, Type } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { ContextId, Step } from '@hcengineering/process'
|
||||
import { Step } from '@hcengineering/process'
|
||||
import setting from '@hcengineering/setting-resources/src/plugin'
|
||||
import {
|
||||
AnyComponent,
|
||||
|
||||
@@ -24,13 +24,13 @@
|
||||
const client = getClient()
|
||||
|
||||
const query = createQuery()
|
||||
$: from = transition.from && client.getModel().findObject(transition.from)
|
||||
$: to = client.getModel().findObject(transition.to)
|
||||
|
||||
$: query.query(plugin.class.State, { process: transition.process }, () => {
|
||||
from = transition.from && client.getModel().findObject(transition.from)
|
||||
to = client.getModel().findObject(transition.to)
|
||||
})
|
||||
|
||||
$: from = transition.from && client.getModel().findObject(transition.from)
|
||||
$: to = client.getModel().findObject(transition.to)
|
||||
</script>
|
||||
|
||||
<span>
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Process, Transition } from '@hcengineering/process'
|
||||
import { Button, getCurrentLocation, IconAdd, Label, navigate, showPopup } from '@hcengineering/ui'
|
||||
import plugin from '../../plugin'
|
||||
@@ -25,8 +24,6 @@
|
||||
export let transitions: Transition[]
|
||||
export let readonly: boolean
|
||||
|
||||
const client = getClient()
|
||||
|
||||
function addTransition (): void {
|
||||
showPopup(AddTransitionPopup, { process }, 'top')
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
import { Card, MasterTag } from '@hcengineering/card'
|
||||
import core, { AnyAttribute, Class, Ref } from '@hcengineering/core'
|
||||
import presentation, { getClient } from '@hcengineering/presentation'
|
||||
import { Process, State, Step } from '@hcengineering/process'
|
||||
import { Process, Step } from '@hcengineering/process'
|
||||
import { Button, eventToHTMLElement, SelectPopup, showPopup } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import ParamsEditor from './ParamsEditor.svelte'
|
||||
import { Button, eventToHTMLElement, SelectPopup, showPopup } from '@hcengineering/ui'
|
||||
|
||||
export let process: Process
|
||||
export let step: Step<Card>
|
||||
|
||||
@@ -44,15 +44,19 @@ import UpdateCardEditor from './components/settings/UpdateCardEditor.svelte'
|
||||
import DateOffsetEditor from './components/transformEditors/DateOffsetEditor.svelte'
|
||||
import NumberEditor from './components/transformEditors/NumberEditor.svelte'
|
||||
|
||||
import LogActionPresenter from './components/LogActionPresenter.svelte'
|
||||
import NotifierExtension from './components/NotifierExtension.svelte'
|
||||
import AddRelationPresenter from './components/presenters/AddRelationPresenter.svelte'
|
||||
import CreateCardPresenter from './components/presenters/CreateCardPresenter.svelte'
|
||||
import AddRelationEditor from './components/settings/AddRelationEditor.svelte'
|
||||
import CreateCardEditor from './components/settings/CreateCardEditor.svelte'
|
||||
import TransitionRefPresenter from './components/settings/TransitionRefPresenter.svelte'
|
||||
import AppendEditor from './components/transformEditors/AppendEditor.svelte'
|
||||
import CutEditor from './components/transformEditors/CutEditor.svelte'
|
||||
import ReplaceEditor from './components/transformEditors/ReplaceEditor.svelte'
|
||||
import SplitEditor from './components/transformEditors/SplitEditor.svelte'
|
||||
import { ProcessMiddleware } from './middleware'
|
||||
import { continueExecution, showDoneQuery, todoTranstionCheck } from './utils'
|
||||
import LogActionPresenter from './components/LogActionPresenter.svelte'
|
||||
import TransitionRefPresenter from './components/settings/TransitionRefPresenter.svelte'
|
||||
import NotifierExtension from './components/NotifierExtension.svelte'
|
||||
|
||||
export default async (): Promise<Resources> => ({
|
||||
actionImpl: {
|
||||
@@ -90,7 +94,11 @@ export default async (): Promise<Resources> => ({
|
||||
TransitionEditor,
|
||||
TransitionRefPresenter,
|
||||
LogActionPresenter,
|
||||
NotifierExtension
|
||||
NotifierExtension,
|
||||
CreateCardEditor,
|
||||
CreateCardPresenter,
|
||||
AddRelationEditor,
|
||||
AddRelationPresenter
|
||||
},
|
||||
transformEditor: {
|
||||
DateOffsetEditor,
|
||||
|
||||
@@ -56,7 +56,11 @@ export default mergeIds(processId, process, {
|
||||
StateEditor: '' as AnyComponent,
|
||||
TransitionRefPresenter: '' as AnyComponent,
|
||||
LogActionPresenter: '' as AnyComponent,
|
||||
NotifierExtension: '' as AnyComponent
|
||||
NotifierExtension: '' as AnyComponent,
|
||||
CreateCardEditor: '' as AnyComponent,
|
||||
CreateCardPresenter: '' as AnyComponent,
|
||||
AddRelationEditor: '' as AnyComponent,
|
||||
AddRelationPresenter: '' as AnyComponent
|
||||
},
|
||||
transformEditor: {
|
||||
DateOffsetEditor: '' as AnyComponent,
|
||||
@@ -151,6 +155,7 @@ export default mergeIds(processId, process, {
|
||||
Start: '' as IntlString,
|
||||
End: '' as IntlString,
|
||||
Started: '' as IntlString,
|
||||
Each: '' as IntlString
|
||||
Each: '' as IntlString,
|
||||
CreateCard: '' as IntlString
|
||||
}
|
||||
})
|
||||
|
||||
@@ -40,6 +40,7 @@ import {
|
||||
type Method,
|
||||
type NestedContext,
|
||||
type Process,
|
||||
type ProcessContext,
|
||||
type ProcessFunction,
|
||||
type RelatedContext,
|
||||
type SelectedContext,
|
||||
@@ -140,7 +141,13 @@ export async function initState<T extends Doc> (methodId: Ref<Method<T>>): Promi
|
||||
}
|
||||
const step: Step<T> = {
|
||||
_id: generateId() as string as StepId,
|
||||
contextId: method.contextClass !== null ? generateContextId() : null,
|
||||
context:
|
||||
method.contextClass !== null
|
||||
? {
|
||||
_id: generateContextId(),
|
||||
_class: method.contextClass
|
||||
}
|
||||
: null,
|
||||
methodId,
|
||||
params: {}
|
||||
}
|
||||
@@ -164,6 +171,7 @@ export function getContext (
|
||||
const functions = getContextFunctions(client, process.masterTag, target, category)
|
||||
const nested: Record<string, NestedContext> = {}
|
||||
const relations: Record<string, RelatedContext> = {}
|
||||
const executionContext: Record<string, ProcessContext> = {}
|
||||
|
||||
const refs = getClassAttributes(client, process.masterTag, core.class.RefTo, 'attribute')
|
||||
for (const ref of refs) {
|
||||
@@ -230,11 +238,21 @@ export function getContext (
|
||||
}
|
||||
}
|
||||
|
||||
if (category === 'object') {
|
||||
for (const key in process.context) {
|
||||
const value = process.context[key as ContextId]
|
||||
if (client.getHierarchy().isDerived(value._class, target)) {
|
||||
executionContext[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
functions,
|
||||
attributes,
|
||||
nested,
|
||||
relations
|
||||
relations,
|
||||
executionContext
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,8 +461,8 @@ export async function getSubProcessesUserInput (
|
||||
if (processId === undefined) continue
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
const res = await newExecutionUserInput(processId, {} as ExecutionContext)
|
||||
if (action.contextId == null) continue
|
||||
userContext[action.contextId] = res
|
||||
if (action.context == null) continue
|
||||
userContext[action.context._id] = res
|
||||
}
|
||||
return userContext
|
||||
}
|
||||
@@ -501,11 +519,13 @@ export function getToDoEndAction (prevState: State): Step<Doc> {
|
||||
key: 'user',
|
||||
_class: process.class.ProcessToDo
|
||||
}
|
||||
const endAction = {
|
||||
const endAction: Step<Doc> = {
|
||||
_id: generateId() as string as StepId,
|
||||
contextId: generateContextId(),
|
||||
context: {
|
||||
_id: context.id,
|
||||
_class: process.class.ProcessToDo
|
||||
},
|
||||
methodId: process.method.CreateToDo,
|
||||
system: true,
|
||||
params: {
|
||||
state: prevState._id,
|
||||
title: prevState.title,
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { Card, MasterTag, Tag } from '@hcengineering/card'
|
||||
import { Class, Doc, DocumentUpdate, ObjQueryType, Ref, Tx, Type } from '@hcengineering/core'
|
||||
import { Association, Class, 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'
|
||||
@@ -116,7 +116,8 @@ export interface ProcessToDo extends ToDo {
|
||||
|
||||
export type MethodParams<T extends Doc> = {
|
||||
[P in keyof T]?: ObjQueryType<T[P]> | string
|
||||
} & DocumentUpdate<T>
|
||||
} & DocumentUpdate<T> &
|
||||
Record<string, any>
|
||||
|
||||
export interface State extends Doc {
|
||||
process: Ref<Process>
|
||||
@@ -127,12 +128,17 @@ export type StepId = string & { __stepId: true }
|
||||
|
||||
export interface Step<T extends Doc> {
|
||||
_id: StepId
|
||||
contextId: ContextId | null
|
||||
context: StepContext | null
|
||||
methodId: Ref<Method<T>>
|
||||
params: MethodParams<T>
|
||||
result?: StepResult
|
||||
}
|
||||
|
||||
export interface StepContext {
|
||||
_id: ContextId // context id
|
||||
_class?: Ref<Class<Doc>> // class of the context
|
||||
}
|
||||
|
||||
export interface StepResult {
|
||||
_id: ContextId // context id
|
||||
name: string
|
||||
@@ -177,7 +183,9 @@ export default plugin(processId, {
|
||||
method: {
|
||||
RunSubProcess: '' as Ref<Method<Process>>,
|
||||
CreateToDo: '' as Ref<Method<ProcessToDo>>,
|
||||
UpdateCard: '' as Ref<Method<Card>>
|
||||
UpdateCard: '' as Ref<Method<Card>>,
|
||||
CreateCard: '' as Ref<Method<Card>>,
|
||||
AddRelation: '' as Ref<Method<Association>>
|
||||
},
|
||||
trigger: {
|
||||
OnSubProcessesDone: '' as Ref<Trigger>,
|
||||
@@ -211,7 +219,8 @@ export default plugin(processId, {
|
||||
UserRequestedValueNotProvided: '' as IntlString,
|
||||
ResultNotProvided: '' as IntlString,
|
||||
EmptyFunctionResult: '' as IntlString,
|
||||
ContextValueNotProvided: '' as IntlString
|
||||
ContextValueNotProvided: '' as IntlString,
|
||||
RequiredParamsNotProvided: '' as IntlString
|
||||
},
|
||||
icon: {
|
||||
Process: '' as Asset,
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Class, Doc, type AnyAttribute, type Association, type Ref } from '@hcengineering/core'
|
||||
import { ContextId, ProcessFunction } from '.'
|
||||
import { ContextId, ProcessContext, ProcessFunction } from '.'
|
||||
|
||||
export interface Context {
|
||||
functions: Ref<ProcessFunction>[]
|
||||
attributes: AnyAttribute[]
|
||||
nested: Record<string, NestedContext>
|
||||
relations: Record<string, RelatedContext>
|
||||
executionContext: Record<ContextId, ProcessContext>
|
||||
}
|
||||
|
||||
export interface NestedContext {
|
||||
|
||||
@@ -13,15 +13,18 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import card, { Card } from '@hcengineering/card'
|
||||
import card, { Card, MasterTag } from '@hcengineering/card'
|
||||
import contact, { Employee } from '@hcengineering/contact'
|
||||
import core, {
|
||||
ArrOf,
|
||||
Association,
|
||||
Data,
|
||||
Doc,
|
||||
generateId,
|
||||
getObjectValue,
|
||||
Ref,
|
||||
RefTo,
|
||||
Relation,
|
||||
Tx,
|
||||
TxCreateDoc,
|
||||
TxCUD,
|
||||
@@ -205,11 +208,8 @@ async function executeAction<T extends Doc> (
|
||||
const params = await fillParams(action.params, execution, control)
|
||||
const f = await getResource(impl.func)
|
||||
const res = await f(params, execution, control)
|
||||
if (action.contextId != null && !isError(res)) {
|
||||
const resId = (res.txes[0] as TxCUD<Doc>)?.objectId
|
||||
if (resId !== undefined) {
|
||||
execution.context[action.contextId] = resId
|
||||
}
|
||||
if (!isError(res) && action.context?._id != null && res.context != null) {
|
||||
execution.context[action.context._id] = res.context
|
||||
}
|
||||
return res
|
||||
} catch (err) {
|
||||
@@ -593,6 +593,12 @@ export async function CreateToDo (
|
||||
execution: Execution,
|
||||
control: TriggerControl
|
||||
): Promise<ExecuteResult | undefined> {
|
||||
for (const key in { user: params.user, title: params.title }) {
|
||||
const val = (params as any)[key]
|
||||
if (isEmpty(val)) {
|
||||
throw processError(process.error.RequiredParamsNotProvided, { params: key })
|
||||
}
|
||||
}
|
||||
if (params.user === undefined || params.title === undefined) return
|
||||
const res: Tx[] = []
|
||||
const rollback: Tx[] = []
|
||||
@@ -619,7 +625,59 @@ export async function CreateToDo (
|
||||
id
|
||||
)
|
||||
)
|
||||
return { txes: res, rollback }
|
||||
return { txes: res, rollback, context: id }
|
||||
}
|
||||
|
||||
export async function CreateCard (
|
||||
params: MethodParams<Card>,
|
||||
execution: Execution,
|
||||
control: TriggerControl
|
||||
): Promise<ExecuteResult | undefined> {
|
||||
const { _class, title, ...attrs } = params
|
||||
for (const key in { _class, title }) {
|
||||
const val = (params as any)[key]
|
||||
if (isEmpty(val)) {
|
||||
throw processError(process.error.RequiredParamsNotProvided, { params: key })
|
||||
}
|
||||
}
|
||||
const _id = generateId<Card>()
|
||||
const data = {
|
||||
title,
|
||||
...attrs
|
||||
} as any
|
||||
const res: Tx[] = [control.txFactory.createTxCreateDoc(_class as Ref<MasterTag>, execution.space, data, _id)]
|
||||
const rollback: Tx[] = [control.txFactory.createTxRemoveDoc(_class as Ref<MasterTag>, execution.space, _id)]
|
||||
return { txes: res, rollback, context: _id }
|
||||
}
|
||||
|
||||
export async function AddRelation (
|
||||
params: MethodParams<Relation>,
|
||||
execution: Execution,
|
||||
control: TriggerControl
|
||||
): Promise<ExecuteResult | undefined> {
|
||||
const _id = generateId<Relation>()
|
||||
const association = params.association as Ref<Association>
|
||||
if (isEmpty(association)) {
|
||||
throw processError(process.error.RequiredParamsNotProvided, { params: 'association' })
|
||||
}
|
||||
if (isEmpty(params._id)) {
|
||||
throw processError(process.error.RequiredParamsNotProvided, { params: '_id' })
|
||||
}
|
||||
if (isEmpty(params.direction)) {
|
||||
throw processError(process.error.RequiredParamsNotProvided, { params: 'direction' })
|
||||
}
|
||||
const targetId = params._id as Ref<Doc>
|
||||
const direction = params.direction as 'A' | 'B'
|
||||
const docA = direction === 'A' ? targetId : execution.card
|
||||
const docB = direction === 'A' ? execution.card : targetId
|
||||
const data: Data<Relation> = {
|
||||
association,
|
||||
docA,
|
||||
docB
|
||||
}
|
||||
const res: Tx[] = [control.txFactory.createTxCreateDoc(core.class.Relation, core.space.Workspace, data, _id)]
|
||||
const rollback: Tx[] = [control.txFactory.createTxRemoveDoc(core.class.Relation, core.space.Workspace, _id)]
|
||||
return { txes: res, rollback, context: _id }
|
||||
}
|
||||
|
||||
export async function UpdateCard (
|
||||
@@ -638,7 +696,7 @@ export async function UpdateCard (
|
||||
}
|
||||
const res: Tx[] = [control.txFactory.createTxUpdateDoc(target._class, target.space, target._id, update)]
|
||||
const rollback: Tx[] = [control.txFactory.createTxUpdateDoc(target._class, target.space, target._id, prevValue)]
|
||||
return { txes: res, rollback }
|
||||
return { txes: res, rollback, context: null }
|
||||
}
|
||||
|
||||
export async function RunSubProcess (
|
||||
@@ -652,6 +710,7 @@ export async function RunSubProcess (
|
||||
const target = control.modelDb.findObject(processId)
|
||||
if (target === undefined) return
|
||||
const res: Tx[] = []
|
||||
const context: Ref<Execution>[] = []
|
||||
for (const _card of Array.isArray(card) ? card : [card]) {
|
||||
if (target.parallelExecutionForbidden === true) {
|
||||
const currentExecution = await control.findAll(control.ctx, process.class.Execution, {
|
||||
@@ -667,19 +726,26 @@ export async function RunSubProcess (
|
||||
const initTransition = control.modelDb.findAllSync(process.class.Transition, { process: target._id, from: null })[0]
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
const emptyContext = {} as ExecutionContext
|
||||
const id = generateId<Execution>()
|
||||
res.push(
|
||||
control.txFactory.createTxCreateDoc(process.class.Execution, core.space.Workspace, {
|
||||
process: processId,
|
||||
currentState: initTransition.to,
|
||||
card: _card,
|
||||
context: emptyContext,
|
||||
status: ExecutionStatus.Active,
|
||||
rollback: [],
|
||||
parentId: execution._id
|
||||
})
|
||||
control.txFactory.createTxCreateDoc(
|
||||
process.class.Execution,
|
||||
core.space.Workspace,
|
||||
{
|
||||
process: processId,
|
||||
currentState: initTransition.to,
|
||||
card: _card,
|
||||
context: emptyContext,
|
||||
status: ExecutionStatus.Active,
|
||||
rollback: [],
|
||||
parentId: execution._id
|
||||
},
|
||||
id
|
||||
)
|
||||
)
|
||||
context.push(id)
|
||||
}
|
||||
return { txes: res, rollback: undefined }
|
||||
return { txes: res, rollback: undefined, context }
|
||||
}
|
||||
|
||||
export async function RoleContext (
|
||||
@@ -763,24 +829,6 @@ export function CheckToDo (params: Record<string, any>, doc: Doc): boolean {
|
||||
return doc._id === params._id
|
||||
}
|
||||
|
||||
export async function OnStateActionsUpdate (txes: Tx[], control: TriggerControl): Promise<Tx[]> {
|
||||
const res: Tx[] = []
|
||||
for (const tx of txes) {
|
||||
if (!control.hierarchy.isDerived(tx._class, core.class.TxCUD)) continue
|
||||
const cudTx = tx as TxUpdateDoc<State>
|
||||
if (!control.hierarchy.isDerived(cudTx.objectClass, process.class.State)) continue
|
||||
const state = control.modelDb.findObject(cudTx.objectId)
|
||||
if (state === undefined) continue
|
||||
const _process = control.modelDb.findObject(state.process)
|
||||
if (_process === undefined) continue
|
||||
const syncTx = await syncContext(control, _process)
|
||||
if (syncTx !== undefined) {
|
||||
res.push(syncTx)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
export async function OnTransition (txes: Tx[], control: TriggerControl): Promise<Tx[]> {
|
||||
const res: Tx[] = []
|
||||
for (const tx of txes) {
|
||||
@@ -806,25 +854,22 @@ async function syncContext (control: TriggerControl, _process: Process): Promise
|
||||
let changed = false
|
||||
for (const transition of transitions) {
|
||||
for (const action of transition.actions) {
|
||||
if (action.contextId != null) {
|
||||
exists.add(action.contextId)
|
||||
const context = _process.context[action.contextId]
|
||||
if (context === undefined) {
|
||||
const method = control.modelDb.findObject(action.methodId)
|
||||
if (method?.contextClass != null) {
|
||||
changed = true
|
||||
const ctx: SelectedExecutonContext = {
|
||||
type: 'context',
|
||||
id: action.contextId,
|
||||
key: ''
|
||||
}
|
||||
_process.context[action.contextId] = {
|
||||
name: '',
|
||||
_class: method.contextClass,
|
||||
action: action._id,
|
||||
producer: transition._id,
|
||||
value: ctx
|
||||
}
|
||||
if (action.context != null) {
|
||||
exists.add(action.context._id)
|
||||
const method = control.modelDb.findObject(action.methodId)
|
||||
if (method?.contextClass != null) {
|
||||
changed = true
|
||||
const ctx: SelectedExecutonContext = {
|
||||
type: 'context',
|
||||
id: action.context._id,
|
||||
key: ''
|
||||
}
|
||||
_process.context[action.context._id] = {
|
||||
name: '',
|
||||
_class: action.context._class ?? method.contextClass,
|
||||
action: action._id,
|
||||
producer: transition._id,
|
||||
value: ctx
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -865,12 +910,18 @@ async function syncContext (control: TriggerControl, _process: Process): Promise
|
||||
}
|
||||
}
|
||||
|
||||
function isEmpty (value: any): boolean {
|
||||
return value === undefined || value === null || (typeof value === 'string' && value.trim() === '')
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
export default async () => ({
|
||||
func: {
|
||||
RunSubProcess,
|
||||
CreateToDo,
|
||||
UpdateCard,
|
||||
CreateCard,
|
||||
AddRelation,
|
||||
CheckToDo
|
||||
},
|
||||
transform: {
|
||||
@@ -904,7 +955,6 @@ export default async () => ({
|
||||
trigger: {
|
||||
OnProcessRemove,
|
||||
OnStateRemove,
|
||||
OnStateActionsUpdate,
|
||||
OnTransition,
|
||||
OnExecutionCreate,
|
||||
OnProcessToDoClose,
|
||||
|
||||
@@ -37,6 +37,8 @@ export default plugin(serverProcessId, {
|
||||
RunSubProcess: '' as Resource<ExecuteFunc>,
|
||||
CreateToDo: '' as Resource<ExecuteFunc>,
|
||||
UpdateCard: '' as Resource<ExecuteFunc>,
|
||||
CreateCard: '' as Resource<ExecuteFunc>,
|
||||
AddRelation: '' as Resource<ExecuteFunc>,
|
||||
WaitSubProcess: '' as Resource<ExecuteFunc>,
|
||||
CheckToDo: '' as Resource<CheckFunc>
|
||||
},
|
||||
@@ -69,7 +71,6 @@ export default plugin(serverProcessId, {
|
||||
RoleContext: '' as Resource<TransformFunc>
|
||||
},
|
||||
trigger: {
|
||||
OnStateActionsUpdate: '' as Resource<TriggerFunc>,
|
||||
OnTransition: '' as Resource<TriggerFunc>,
|
||||
OnProcessRemove: '' as Resource<TriggerFunc>,
|
||||
OnStateRemove: '' as Resource<TriggerFunc>,
|
||||
|
||||
@@ -13,6 +13,7 @@ export type ExecuteResult = SuccessExecutionResult | ExecutionError
|
||||
export interface SuccessExecutionResult {
|
||||
txes: Tx[]
|
||||
rollback: Tx[] | undefined
|
||||
context: any | null
|
||||
}
|
||||
|
||||
export type TransformFunc = (
|
||||
|
||||
Reference in New Issue
Block a user