Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions packages/presentation/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Analytics } from '@hcengineering/analytics'
import core, {
type Account,
AccountRole,
type AnyAttribute,
type ArrOf,
type AttachedDoc,
type Class,
Expand Down Expand Up @@ -737,13 +738,8 @@ export function getAttrEditor (type: Type<any>, hierarchy: Hierarchy): AnyCompon
return editorMixin?.inlineEditor
}

export function findAttributeEditor (
client: Client,
_class: Ref<Class<Obj>>,
key: KeyedAttribute | string
): AnyComponent | undefined {
export function findAttributeEditorByAttribute (client: Client, attribute: AnyAttribute): AnyComponent | undefined {
const hierarchy = client.getHierarchy()
const attribute = typeof key === 'string' ? hierarchy.findAttribute(_class, key) : key.attr
if (attribute === undefined) return

if (attribute.type._class === core.class.TypeAny) {
Expand Down Expand Up @@ -779,16 +775,22 @@ export function findAttributeEditor (
const editorMixin = hierarchy.classHierarchyMixin(presenterClass.attrClass, mixin)

if (editorMixin?.inlineEditor === undefined) {
// if (presenterClass.category === 'array') {
// // NOTE: Don't show error for array attributes for compatibility with previous implementation
// } else {
console.error(getAttributeEditorNotFoundError(_class, key))
// }
return
}
return editorMixin.inlineEditor
}

export function findAttributeEditor (
client: Client,
_class: Ref<Class<Obj>>,
key: KeyedAttribute | string
): AnyComponent | undefined {
const hierarchy = client.getHierarchy()
const attribute = typeof key === 'string' ? hierarchy.findAttribute(_class, key) : key.attr
if (attribute === undefined) return
return findAttributeEditorByAttribute(client, attribute)
}

export async function getAttributeEditor (
client: Client,
_class: Ref<Class<Obj>>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import { Process } from '@hcengineering/process'
import { Component, Label, tooltip } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { getCirteriaEditor, getContext } from '../../utils'
import { getCriteriaEditor, getContext } from '../../utils'

export let _class: Ref<Class<Doc>>
export let readonly: boolean
Expand All @@ -34,7 +34,7 @@
$: attribute = hierarchy.getAttribute(_class, key)
$: presenterClass = getAttributePresenterClass(hierarchy, attribute.type)

$: updateCriteria = getCirteriaEditor(presenterClass.attrClass, presenterClass.category)
$: updateCriteria = getCriteriaEditor(presenterClass.attrClass, presenterClass.category)
$: editor = updateCriteria?.editor

$: value = params[key]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

<script lang="ts">
import { AnyAttribute } from '@hcengineering/core'
import { findAttributeEditor, getAttributePresenterClass, getClient } from '@hcengineering/presentation'
import { findAttributeEditorByAttribute, getAttributePresenterClass, getClient } from '@hcengineering/presentation'
import { Context, createContext, parseContext, Process, SelectedContext } from '@hcengineering/process'
import { Button, Component, eventToHTMLElement, IconAdd, IconClose, showPopup } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
Expand Down Expand Up @@ -60,7 +60,7 @@
const hierarchy = client.getHierarchy()

$: presenterClass = getAttributePresenterClass(hierarchy, attribute.type)
$: baseEditor = findAttributeEditor(client, attribute.attributeOf, attribute.name)
$: baseEditor = findAttributeEditorByAttribute(client, attribute)
</script>

<div class="text-input" class:context={contextValue}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<!--
// 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 { getAttributePresenterClass, getClient } from '@hcengineering/presentation'
import {
Context,
ContextId,
Process,
SelectedExecutionContext,
UpdateCriteriaComponent
} from '@hcengineering/process'
import { AnyComponent, Component } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { getContext, getCriteriaEditor, getMockAttribute } from '../../utils'
import ExecutionContextPresenter from '../attributeEditors/ExecutionContextPresenter.svelte'
import { AnyAttribute } from '@hcengineering/core'

export let process: Process
export let value: string | undefined
export let contextId: string
export let readonly: boolean = false

const client = getClient()
const hierarchy = client.getHierarchy()
const dispatch = createEventDispatcher()

let editor: AnyComponent | undefined
let context: Context | undefined
let updateCriteria: UpdateCriteriaComponent | undefined
let attribute: AnyAttribute | undefined

$: fill(contextId)

function fill (contextId: string): void {
const _ctx = process.context[contextId as ContextId]
if (_ctx === undefined) {
editor = undefined
context = undefined
attribute = undefined
updateCriteria = undefined
return
}
const type = _ctx.type
if (type === undefined) {
editor = undefined
context = undefined
attribute = undefined
updateCriteria = undefined
return
}

const presenterClass = getAttributePresenterClass(hierarchy, type)
updateCriteria = getCriteriaEditor(presenterClass.attrClass, presenterClass.category)
attribute = getMockAttribute(process.masterTag, type.label, type)
editor = updateCriteria?.editor
context = getContext(client, process, presenterClass?.attrClass, presenterClass?.category)
}

function onChange (e: CustomEvent<any>): void {
if (e.detail !== undefined) {
dispatch('change', e.detail)
}
}

let contextValue: SelectedExecutionContext = {
type: 'context',
id: contextId as ContextId,
key: ''
}

$: contextValue = {
type: 'context',
id: contextId as ContextId,
key: ''
}
</script>

{#if editor}
<ExecutionContextPresenter {process} {contextValue} />
<Component
is={editor}
props={{ value, readonly, context, process, attribute, ...updateCriteria?.props }}
on:change={onChange}
on:delete
/>
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

<script lang="ts">
import { AnyAttribute } from '@hcengineering/core'
import { findAttributeEditor, getAttributePresenterClass, getClient } from '@hcengineering/presentation'
import { findAttributeEditorByAttribute, getAttributePresenterClass, getClient } from '@hcengineering/presentation'
import { Context, createContext, parseContext, Process, SelectedContext } from '@hcengineering/process'
import { Button, Component, eventToHTMLElement, IconAdd, IconClose, showPopup } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
Expand Down Expand Up @@ -81,7 +81,7 @@

$: presenterClass = getAttributePresenterClass(hierarchy, attribute.type)

$: baseEditor = findAttributeEditor(client, process.masterTag, attribute.name)
$: baseEditor = findAttributeEditorByAttribute(client, attribute)
</script>

<div class="flex-row-center flex-gap-2">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
// limitations under the License.
-->
<script lang="ts">
import core, { AnyAttribute, Association, generateId, Ref, Relation } from '@hcengineering/core'
import core, { AnyAttribute, Association, Ref, 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 { getContext, getMockAttribute } from '../../utils'
import ProcessAttribute from '../ProcessAttribute.svelte'
import AssociationSelector from './AssociationSelector.svelte'

Expand Down Expand Up @@ -56,23 +56,15 @@
}
}

let attribute: AnyAttribute
$: attribute = {
attributeOf: targetClass ?? 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
$: type = {
label: core.string.Ref,
_class: core.class.RefTo,
to: targetClass ?? process.masterTag
}

let attribute: AnyAttribute
$: attribute = getMockAttribute(targetClass ?? process.masterTag, core.string.Object, type)

$: context = targetClass && getContext(client, process, targetClass, 'object')
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import { Process } from '@hcengineering/process'
import { Button, eventToHTMLElement, SelectPopup, showPopup } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import { getCirteriaEditor } from '../../utils'
import { getCriteriaEditor } from '../../utils'
import CriteriasEditor from '../criterias/CriteriasEditor.svelte'

export let readonly: boolean
Expand All @@ -46,7 +46,7 @@
if (attr.hidden === true) continue
if (ignoreKeys.includes(key)) continue
const presenterClass = getAttributePresenterClass(hierarchy, attr.type)
const updateCriteria = getCirteriaEditor(presenterClass.attrClass, presenterClass.category)
const updateCriteria = getCriteriaEditor(presenterClass.attrClass, presenterClass.category)
const editor = updateCriteria?.editor
if (editor == null) continue
res.push(attr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import { Button, eventToHTMLElement, SelectPopup, showPopup } from '@hcengineering/ui'
import view from '@hcengineering/view'
import { createEventDispatcher } from 'svelte'
import { getCirteriaEditor } from '../../utils'
import { getCriteriaEditor } from '../../utils'
import CriteriasEditor from '../criterias/CriteriasEditor.svelte'

export let readonly: boolean
Expand All @@ -47,7 +47,7 @@
if (attr.hidden === true) continue
if (ignoreKeys.includes(key)) continue
const presenterClass = getAttributePresenterClass(hierarchy, attr.type)
const updateCriteria = getCirteriaEditor(presenterClass.attrClass, presenterClass.category)
const updateCriteria = getCriteriaEditor(presenterClass.attrClass, presenterClass.category)
const editor = updateCriteria?.editor
if (editor == null) continue
res.push(attr)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<!--
// 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 presentation, { getClient } from '@hcengineering/presentation'
import { ContextId, parseContext, Process, SelectedExecutionContext, UserResult } from '@hcengineering/process'
import { Button, eventToHTMLElement, SelectPopup, showPopup } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte'
import ContextCriteria from '../criterias/ContextCriteria.svelte'

export let process: Process
export let result: Record<ContextId, any> = {}
export let value: string | undefined
export let readonly: boolean

const client = getClient()
const dispatch = createEventDispatcher()

let results: UserResult[] = []

let keys = Object.keys(result) as ContextId[]

function getResults (_id: string | undefined): void {
results = []
if (_id == null) return
const ctx = parseContext(_id)
if (ctx?.type !== 'context') return
const context = process.context[ctx.id]
if (context === undefined) return
const transition = client.getModel().findObject(context.producer)
if (transition == null) return
results = transition.actions.find((a) => a._id === context.action)?.results ?? []
}

$: getResults(value)

$: availableResults = results.filter((r) => !keys.includes(r._id))

function addKey (key: ContextId): void {
keys = [...keys, key]
}

function onAdd (e: MouseEvent): void {
showPopup(
SelectPopup,
{
value: availableResults.map((p) => {
return { id: p._id, text: p.name }
})
},
eventToHTMLElement(e),
(res) => {
if (res != null) {
addKey(res)
}
}
)
}

function change (e: CustomEvent<any>, key: string): void {
if (e.detail !== undefined) {
;(result as any)[key] = e.detail
dispatch('change', result)
}
}

function remove (key: string): void {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete (result as any)[key]
keys = keys.filter((k) => k !== key)
dispatch('change', result)
}
</script>

{#each keys as key}
<ContextCriteria
{process}
value={result[key]}
contextId={key}
on:change={(e) => {
change(e, key)
}}
on:delete={() => {
remove(key)
}}
/>
{/each}
{#if !readonly && availableResults.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}
Loading