mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-08 02:37:44 +02:00
Create card process (#9522)
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user