mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-29 13:05:08 +02:00
Required attributes (#10918)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
@@ -14,13 +14,15 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import cardPlugin, { Tag } from '@hcengineering/card'
|
||||
import { Process, Step } from '@hcengineering/process'
|
||||
import { Process, Step, createContext } from '@hcengineering/process'
|
||||
import ParamsEditor from './ParamsEditor.svelte'
|
||||
import { Ref } from '@hcengineering/core'
|
||||
import presentation, { getClient } from '@hcengineering/presentation'
|
||||
import { Button, eventToHTMLElement, Label, SelectPopup, showPopup, tooltip } from '@hcengineering/ui'
|
||||
import { generateContextId } from '../../utils'
|
||||
import { Button, eventToHTMLElement, Label, SelectPopup, showPopup, Toggle, tooltip } from '@hcengineering/ui'
|
||||
import TagSelector from './TagSelector.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import plugin from '../../plugin'
|
||||
|
||||
export let process: Process
|
||||
export let step: Step<Tag>
|
||||
@@ -41,6 +43,16 @@
|
||||
params._id = _id
|
||||
props = {}
|
||||
params.props = props
|
||||
if (params.askRequired) {
|
||||
params.requiredProperties = createContext({
|
||||
type: 'userRequest',
|
||||
id: generateContextId(),
|
||||
_class: _id,
|
||||
key: 'requiredProperties'
|
||||
})
|
||||
} else {
|
||||
delete params.requiredProperties
|
||||
}
|
||||
step.params = params
|
||||
if (step.context != null) {
|
||||
step.context._class = _id
|
||||
@@ -91,6 +103,27 @@
|
||||
step.params = params
|
||||
dispatch('change', step)
|
||||
}
|
||||
|
||||
let askRequired = params.askRequired ?? false
|
||||
$: askRequired = params.askRequired ?? false
|
||||
|
||||
function changeAskRequired (e: CustomEvent<boolean>): void {
|
||||
if (e.detail !== undefined) {
|
||||
params.askRequired = e.detail
|
||||
if (e.detail) {
|
||||
params.requiredProperties = createContext({
|
||||
type: 'userRequest',
|
||||
id: generateContextId(),
|
||||
_class: _id,
|
||||
key: 'requiredProperties'
|
||||
})
|
||||
} else {
|
||||
delete params.requiredProperties
|
||||
}
|
||||
step.params = params
|
||||
dispatch('change', step)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex-col flex-gap-2">
|
||||
@@ -104,6 +137,17 @@
|
||||
<Label label={cardPlugin.string.Tag} />
|
||||
</span>
|
||||
<TagSelector {process} tag={_id} on:change={changeTag} />
|
||||
<span
|
||||
class="labelOnPanel"
|
||||
use:tooltip={{
|
||||
props: { label: plugin.string.AskRequired }
|
||||
}}
|
||||
>
|
||||
<Label label={plugin.string.AskRequired} />
|
||||
</span>
|
||||
<div>
|
||||
<Toggle on={askRequired} on:change={changeAskRequired} />
|
||||
</div>
|
||||
</div>
|
||||
<ParamsEditor
|
||||
{process}
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
}
|
||||
|
||||
let keys = Object.keys(params).filter((key) => {
|
||||
return key !== '_class' && key !== 'targetClass'
|
||||
return key !== '_class' && key !== 'targetClass' && key !== 'askRequired' && key !== 'requiredFields'
|
||||
})
|
||||
|
||||
$: allAttrs = getKeys(targetClass)
|
||||
@@ -116,7 +116,7 @@
|
||||
|
||||
function typeChange (_id: Ref<Class<MasterTag>>): void {
|
||||
if (_id === undefined) return
|
||||
const attrKeys = ['_class', 'targetClass', ...getKeys(_id).map((p) => p.name)]
|
||||
const attrKeys = ['_class', 'targetClass', 'askRequired', 'requiredFields', ...getKeys(_id).map((p) => p.name)]
|
||||
const oldParams = { ...params }
|
||||
params = {}
|
||||
for (const key of attrKeys) {
|
||||
@@ -125,12 +125,22 @@
|
||||
}
|
||||
}
|
||||
keys = Object.keys(params).filter((key) => {
|
||||
return key !== '_class' && key !== 'targetClass'
|
||||
return key !== '_class' && key !== 'targetClass' && key !== 'askRequired' && key !== 'requiredFields'
|
||||
})
|
||||
if (params.targetClass !== _id) {
|
||||
params._class = _id
|
||||
params.targetClass = _id
|
||||
}
|
||||
if (params.askRequired) {
|
||||
params.requiredFields = createContext({
|
||||
type: 'userRequest',
|
||||
id: generateContextId(),
|
||||
_class: _id,
|
||||
key: 'requiredFields'
|
||||
})
|
||||
} else {
|
||||
delete params.requiredFields
|
||||
}
|
||||
step.params = params
|
||||
if (step.context != null) {
|
||||
step.context._class = _id
|
||||
@@ -158,6 +168,27 @@
|
||||
dispatch('change', step)
|
||||
}
|
||||
}
|
||||
|
||||
let askRequired = params.askRequired ?? false
|
||||
$: askRequired = params.askRequired ?? false
|
||||
|
||||
function changeAskRequired (e: CustomEvent<boolean>): void {
|
||||
if (e.detail !== undefined) {
|
||||
params.askRequired = e.detail
|
||||
if (e.detail) {
|
||||
params.requiredFields = createContext({
|
||||
type: 'userRequest',
|
||||
id: generateContextId(),
|
||||
_class: targetClass,
|
||||
key: 'requiredFields'
|
||||
})
|
||||
} else {
|
||||
delete params.requiredFields
|
||||
}
|
||||
step.params = params
|
||||
dispatch('change', step)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="grid">
|
||||
@@ -191,6 +222,17 @@
|
||||
<Toggle on={askSubclass} on:change={changeAskSubclass} />
|
||||
</div>
|
||||
{/if}
|
||||
<span
|
||||
class="labelOnPanel"
|
||||
use:tooltip={{
|
||||
props: { label: plugin.string.AskRequired }
|
||||
}}
|
||||
>
|
||||
<Label label={plugin.string.AskRequired} />
|
||||
</span>
|
||||
<div>
|
||||
<Toggle on={askRequired} on:change={changeAskRequired} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider" />
|
||||
{#key targetClass}
|
||||
|
||||
@@ -286,6 +286,7 @@ export default mergeIds(processId, process, {
|
||||
TextFromSelect: '' as IntlString,
|
||||
SelectFromText: '' as IntlString,
|
||||
AskSubclass: '' as IntlString,
|
||||
AskRequired: '' as IntlString,
|
||||
RequiredSlots: '' as IntlString,
|
||||
Bindings: '' as IntlString
|
||||
},
|
||||
|
||||
@@ -543,10 +543,59 @@ export async function getTransitionUserInput (
|
||||
skipExisting: boolean = false
|
||||
): Promise<ExecutionContext | undefined> {
|
||||
let changed = false
|
||||
const client = getClient()
|
||||
const hierarchy = client.getHierarchy()
|
||||
|
||||
for (const action of transition.actions) {
|
||||
if (action == null) continue
|
||||
const inputs: SelectedUserRequest[] = []
|
||||
|
||||
// Map of: tempInputId -> { attrName, virtualContextId }
|
||||
const dynamicMappings: Record<string, { attrName: string, virtualContextId: string }> = {}
|
||||
|
||||
// Check for virtual required attributes
|
||||
let virtualContext: SelectedUserRequest | undefined
|
||||
let virtualKey = ''
|
||||
if (action.params.requiredFields !== undefined) {
|
||||
virtualContext = parseContext(action.params.requiredFields) as SelectedUserRequest
|
||||
virtualKey = 'requiredFields'
|
||||
} else if (action.params.requiredProperties !== undefined) {
|
||||
virtualContext = parseContext(action.params.requiredProperties) as SelectedUserRequest
|
||||
virtualKey = 'requiredProperties'
|
||||
}
|
||||
|
||||
if (virtualContext !== undefined && virtualContext.type === 'userRequest') {
|
||||
const classId = virtualContext._class
|
||||
const allAttributes =
|
||||
virtualKey === 'requiredFields'
|
||||
? Array.from(hierarchy.getAllAttributes(classId, core.class.Doc).values())
|
||||
: Array.from(hierarchy.getOwnAttributes(classId).values())
|
||||
|
||||
for (const attr of allAttributes) {
|
||||
if (virtualKey === 'requiredFields' && attr.name === 'title') continue
|
||||
if (attr.hidden === true) continue
|
||||
|
||||
const isConfigured =
|
||||
virtualKey === 'requiredFields'
|
||||
? action.params[attr.name] !== undefined
|
||||
: action.params.props !== undefined && action.params.props[attr.name] !== undefined
|
||||
|
||||
if (attr.required === true && !isConfigured) {
|
||||
const tempInputId = generateContextId()
|
||||
dynamicMappings[tempInputId] = { attrName: attr.name, virtualContextId: virtualContext.id }
|
||||
inputs.push({
|
||||
type: 'userRequest',
|
||||
id: tempInputId,
|
||||
key: attr.name,
|
||||
_class: classId
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const key in action.params) {
|
||||
if (key === 'requiredFields' || key === 'requiredProperties') continue
|
||||
|
||||
const value = (action.params as any)[key]
|
||||
if (typeof value === 'string') {
|
||||
const context = parseContext(value)
|
||||
@@ -564,6 +613,7 @@ export async function getTransitionUserInput (
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inputs.length > 0) {
|
||||
const promise = new Promise<void>((resolve, reject) => {
|
||||
showPopup(
|
||||
@@ -580,9 +630,24 @@ export async function getTransitionUserInput (
|
||||
const isComplete = res?.value !== undefined && inputs.every((input) => res.value[input.id] != null)
|
||||
if (isComplete) {
|
||||
changed = true
|
||||
const groupedValues: Record<string, Record<string, any>> = {}
|
||||
|
||||
for (const [key, value] of Object.entries(res.value)) {
|
||||
userContext[key as ContextId] = value
|
||||
const mapping = dynamicMappings[key]
|
||||
if (mapping !== undefined) {
|
||||
if (groupedValues[mapping.virtualContextId] === undefined) {
|
||||
groupedValues[mapping.virtualContextId] = {}
|
||||
}
|
||||
groupedValues[mapping.virtualContextId][mapping.attrName] = value
|
||||
} else {
|
||||
userContext[key as ContextId] = value
|
||||
}
|
||||
}
|
||||
|
||||
for (const [virtualId, obj] of Object.entries(groupedValues)) {
|
||||
userContext[virtualId as ContextId] = obj
|
||||
}
|
||||
|
||||
resolve()
|
||||
} else {
|
||||
reject(new PlatformError(new Status(Severity.ERROR, process.error.ResultNotProvided, {})))
|
||||
|
||||
Reference in New Issue
Block a user