diff --git a/models/all/src/migration.ts b/models/all/src/migration.ts index 51fed6fe91..8025ba696b 100644 --- a/models/all/src/migration.ts +++ b/models/all/src/migration.ts @@ -58,6 +58,7 @@ import { cardOperation } from '@hcengineering/model-card' import { aiBotId, aiBotOperation } from '@hcengineering/model-ai-bot' import { chatId, chatOperation } from '@hcengineering/model-chat' import { inboxId, inboxOperation } from '@hcengineering/model-inbox' +import { processId, processOperation } from '@hcengineering/model-process' export const migrateOperations: [string, MigrateOperation][] = [ ['core', coreOperation], @@ -104,5 +105,6 @@ export const migrateOperations: [string, MigrateOperation][] = [ ['survey', surveyOperation], [aiBotId, aiBotOperation], [chatId, chatOperation], - [inboxId, inboxOperation] + [inboxId, inboxOperation], + [processId, processOperation] ] diff --git a/models/process/src/index.ts b/models/process/src/index.ts index a150fee908..abc4d630a7 100644 --- a/models/process/src/index.ts +++ b/models/process/src/index.ts @@ -139,10 +139,14 @@ export class TState extends TDoc implements State { @Model(process.class.ProcessFunction, core.class.Doc, DOMAIN_MODEL) export class TProcessFunction extends TDoc implements ProcessFunction { of!: Ref>> - category?: AttributeCategory | undefined + category: AttributeCategory | undefined label!: IntlString + editor?: AnyComponent + allowMany?: boolean } +export * from './migration' + export function createModel (builder: Builder): void { builder.createModel(TProcess, TExecution, TProcessToDo, TMethod, TState, TProcessFunction) @@ -218,6 +222,7 @@ export function createModel (builder: Builder): void { core.space.Model, { of: core.class.ArrOf, + category: undefined, label: process.string.FirstValue }, process.function.FirstValue @@ -228,6 +233,7 @@ export function createModel (builder: Builder): void { core.space.Model, { of: core.class.ArrOf, + category: undefined, label: process.string.LastValue }, process.function.LastValue @@ -238,11 +244,61 @@ export function createModel (builder: Builder): void { core.space.Model, { of: core.class.ArrOf, + category: undefined, label: process.string.Random }, process.function.Random ) + builder.createDoc( + process.class.ProcessFunction, + core.space.Model, + { + of: core.class.TypeNumber, + category: 'attribute', + label: process.string.Add, + allowMany: true, + editor: process.component.NumberOffsetEditor + }, + process.function.Add + ) + + builder.createDoc( + process.class.ProcessFunction, + core.space.Model, + { + of: core.class.TypeNumber, + category: 'attribute', + label: process.string.Subtract, + allowMany: true, + editor: process.component.NumberOffsetEditor + }, + process.function.Subtract + ) + + builder.createDoc( + process.class.ProcessFunction, + core.space.Model, + { + of: core.class.TypeDate, + category: 'attribute', + label: process.string.Offset, + editor: process.component.DateOffsetEditor + }, + process.function.Offset + ) + + builder.createDoc( + process.class.ProcessFunction, + core.space.Model, + { + of: core.class.TypeDate, + category: 'attribute', + label: process.string.FirstWorkingDayAfter + }, + process.function.FirstWorkingDayAfter + ) + builder.mixin(process.class.Process, core.class.Class, view.mixin.AttributePresenter, { presenter: process.component.ProcessPresenter }) diff --git a/models/process/src/migration.ts b/models/process/src/migration.ts new file mode 100644 index 0000000000..9ce5ec2a2e --- /dev/null +++ b/models/process/src/migration.ts @@ -0,0 +1,93 @@ +// +// 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. +// + +import core, { type Ref, TxOperations } from '@hcengineering/core' +import { + tryUpgrade, + type MigrateOperation, + type MigrationClient, + type MigrationUpgradeClient +} from '@hcengineering/model' +import { type Func, parseContext, type ProcessFunction } from '@hcengineering/process' +import { processId } from '.' +import process from './plugin' + +export const processOperation: MigrateOperation = { + async migrate (client: MigrationClient, mode): Promise {}, + async upgrade (state: Map>, client: () => Promise, mode): Promise { + await tryUpgrade(mode, state, client, processId, [ + { + state: 'migrateStateFuncs', + func: migrateStateFuncs + } + ]) + } +} + +function getContext (value: string): string | undefined { + const context = parseContext(value) + if (context !== undefined) { + let contextChanged = false + if (context.functions !== undefined) { + for (let i = 0; i < context.functions.length; i++) { + const func = context.functions[i] as any + if (typeof func === 'string') { + const res: Func = { + func: func as Ref, + props: {} + } + context.functions[i] = res + contextChanged = true + } + } + } + if (contextChanged) { + return '$' + JSON.stringify(context) + } + } +} + +async function migrateStateFuncs (client: MigrationUpgradeClient): Promise { + const txOp = new TxOperations(client, core.account.System) + const states = await client.findAll(process.class.State, {}) + for (const state of states) { + let changed = false + const actions = state.actions + for (const action of actions) { + for (const key of Object.keys(action.params)) { + const value = (action.params as any)[key] + const context = getContext(value) + if (context !== undefined) { + ;(action.params as any)[key] = context + changed = true + } + } + } + const endAction = state.endAction + if (endAction != null) { + for (const key of Object.keys(endAction.params)) { + const value = (endAction.params as any)[key] + const context = getContext(value) + if (context !== undefined) { + ;(endAction.params as any)[key] = context + changed = true + } + } + } + if (changed) { + await txOp.updateDoc(state._class, state.space, state._id, { actions, endAction }) + } + } +} diff --git a/models/server-process/src/index.ts b/models/server-process/src/index.ts index 3c0010d7ca..4c77613fdc 100644 --- a/models/server-process/src/index.ts +++ b/models/server-process/src/index.ts @@ -75,6 +75,22 @@ export function createModel (builder: Builder): void { func: serverProcess.transform.Trim }) + builder.mixin(process.function.Add, process.class.ProcessFunction, serverProcess.mixin.FuncImpl, { + func: serverProcess.transform.Add + }) + + builder.mixin(process.function.Subtract, process.class.ProcessFunction, serverProcess.mixin.FuncImpl, { + func: serverProcess.transform.Subtract + }) + + builder.mixin(process.function.Offset, process.class.ProcessFunction, serverProcess.mixin.FuncImpl, { + func: serverProcess.transform.Offset + }) + + builder.mixin(process.function.FirstWorkingDayAfter, process.class.ProcessFunction, serverProcess.mixin.FuncImpl, { + func: serverProcess.transform.FirstWorkingDayAfter + }) + builder.createDoc(serverCore.class.Trigger, core.space.Model, { trigger: serverProcess.trigger.OnProcessRemove, txMatch: { diff --git a/packages/ui/lang/cs.json b/packages/ui/lang/cs.json index 498fd985ce..6573557647 100644 --- a/packages/ui/lang/cs.json +++ b/packages/ui/lang/cs.json @@ -111,6 +111,9 @@ "UseMaxWidth": "Maximální šířka", "Sidebar": "Postranní panel", "FontSize": "Velikost písma", - "Language": "Jazyk" + "Language": "Jazyk", + "DaysWOValue": "{days, plural, =1 {den} other {dny}}", + "WeeksWOValue": "{weeks, plural, =1 {týden} other {týdny}}", + "MonthsWOValue": "{months, plural, =1 {měsíc} other {měsíce}}" } } diff --git a/packages/ui/lang/de.json b/packages/ui/lang/de.json index ed5a5391a3..be4d24f95a 100644 --- a/packages/ui/lang/de.json +++ b/packages/ui/lang/de.json @@ -111,6 +111,9 @@ "UseMaxWidth": "Maximale Breite", "Sidebar": "Seitenleiste", "FontSize": "Schriftgröße", - "Language": "Sprache" + "Language": "Sprache", + "DaysWOValue": "{days, plural, =1 {Tag} other {Tage}}", + "WeeksWOValue": "{weeks, plural, =1 {Woche} other {Wochen}}", + "MonthsWOValue": "{months, plural, =1 {Monat} other {Monate}}" } } diff --git a/packages/ui/lang/en.json b/packages/ui/lang/en.json index 1b6a9d2254..b4406b35ca 100644 --- a/packages/ui/lang/en.json +++ b/packages/ui/lang/en.json @@ -112,6 +112,9 @@ "UseMaxWidth": "Max width", "Sidebar": "Sidebar", "FontSize": "Font size", - "Language": "Language" + "Language": "Language", + "DaysWOValue": "{days, plural, =1 {day} other {days}}", + "WeeksWOValue": "{weeks, plural, =1 {week} other {weeks}}", + "MonthsWOValue": "{months, plural, =1 {month} other {months}}" } } diff --git a/packages/ui/lang/es.json b/packages/ui/lang/es.json index 78baea9d75..55c7b81ee3 100644 --- a/packages/ui/lang/es.json +++ b/packages/ui/lang/es.json @@ -112,6 +112,9 @@ "UseMaxWidth": "Ancho máximo", "Sidebar": "Barra lateral", "FontSize": "Tamaño de fuente", - "Language": "Idioma" + "Language": "Idioma", + "DaysWOValue": "{days, plural, =1 {día} other {días}}", + "WeeksWOValue": "{weeks, plural, =1 {semana} other {semanas}}", + "MonthsWOValue": "{months, plural, =1 {mes} other {meses}}" } } diff --git a/packages/ui/lang/fr.json b/packages/ui/lang/fr.json index 9c7d833b37..9aa2978cd3 100644 --- a/packages/ui/lang/fr.json +++ b/packages/ui/lang/fr.json @@ -112,6 +112,9 @@ "UseMaxWidth": "Largeur maximale", "Sidebar": "Barre latérale", "FontSize": "Taille de police", - "Language": "Langue" + "Language": "Langue", + "DaysWOValue": "{days, plural, =1 {jour} other {jours}}", + "WeeksWOValue": "{weeks, plural, =1 {semaine} other {semaines}}", + "MonthsWOValue": "{months, plural, =1 {mois} other {mois}}" } } diff --git a/packages/ui/lang/it.json b/packages/ui/lang/it.json index 3b18ec331c..983a309568 100644 --- a/packages/ui/lang/it.json +++ b/packages/ui/lang/it.json @@ -112,6 +112,9 @@ "UseMaxWidth": "Larghezza massima", "Sidebar": "Barra laterale", "FontSize ": "Dimensione del carattere", - "Language": "Lingua" + "Language": "Lingua", + "DaysWOValue": "{days, plural, =1 {giorno} other {giorni}}", + "WeeksWOValue": "{weeks, plural, =1 {settimana} other {settimane}}", + "MonthsWOValue": "{months, plural, =1 {mese} other {mesi}}" } } diff --git a/packages/ui/lang/pt.json b/packages/ui/lang/pt.json index f6bc4fed47..97ec7af7f4 100644 --- a/packages/ui/lang/pt.json +++ b/packages/ui/lang/pt.json @@ -112,6 +112,9 @@ "UseMaxWidth": "Largura máxima", "Sidebar": "Barra lateral", "FontSize": "Tamanho da fonte", - "Language": "Idioma" + "Language": "Idioma", + "DaysWOValue": "{days, plural, =1 {dia} other {dias}}", + "WeeksWOValue": "{weeks, plural, =1 {semana} other {semanas}}", + "MonthsWOValue": "{months, plural, =1 {mês} other {meses}}" } } diff --git a/packages/ui/lang/ru.json b/packages/ui/lang/ru.json index 592410569d..a3be19b6d5 100644 --- a/packages/ui/lang/ru.json +++ b/packages/ui/lang/ru.json @@ -112,6 +112,9 @@ "UseMaxWidth": "Максимальная ширина", "Sidebar": "Боковая панель", "FontSize": "Размер шрифта", - "Language": "Язык" + "Language": "Язык", + "DaysWOValue": "{days, plural, one {день} few {дня} other {дней}}", + "WeeksWOValue": "{weeks, plural, one {неделя} few {недели} other {недель}}", + "MonthsWOValue": "{months, plural, one {месяц} few {месяца} other {месяцев}}" } } diff --git a/packages/ui/lang/zh.json b/packages/ui/lang/zh.json index f9854e4c72..208679a123 100644 --- a/packages/ui/lang/zh.json +++ b/packages/ui/lang/zh.json @@ -112,6 +112,9 @@ "UseMaxWidth": "使用最大宽度", "Sidebar": "侧边栏", "FontSize": "字体大小", - "Language": "语言" + "Language": "语言", + "DaysWOValue": "{days, plural, =1 {天} other {天}}", + "WeeksWOValue": "{weeks, plural, =1 {周} other {周}}", + "MonthsWOValue": "{months, plural, =1 {月} other {月}}" } } diff --git a/packages/ui/src/plugin.ts b/packages/ui/src/plugin.ts index 4f54fdd9d6..59a324de95 100644 --- a/packages/ui/src/plugin.ts +++ b/packages/ui/src/plugin.ts @@ -139,7 +139,10 @@ export const uis = plugin(uiId, { UseMaxWidth: '' as IntlString, Sidebar: '' as IntlString, FontSize: '' as IntlString, - Language: '' as IntlString + Language: '' as IntlString, + DaysWOValue: '' as IntlString, + WeeksWOValue: '' as IntlString, + MonthsWOValue: '' as IntlString }, metadata: { DefaultApplication: '' as Metadata, diff --git a/plugins/calendar-resources/src/plugin.ts b/plugins/calendar-resources/src/plugin.ts index 771952852c..7ef47559b5 100644 --- a/plugins/calendar-resources/src/plugin.ts +++ b/plugins/calendar-resources/src/plugin.ts @@ -55,9 +55,6 @@ export default mergeIds(calendarId, calendar, { Ends: '' as IntlString, Never: '' as IntlString, After: '' as IntlString, - Day: '' as IntlString, - Week: '' as IntlString, - Month: '' as IntlString, Year: '' as IntlString, MondayShort: '' as IntlString, TuesdayShort: '' as IntlString, diff --git a/plugins/calendar/src/index.ts b/plugins/calendar/src/index.ts index 1efc7442e8..64df05bcb7 100644 --- a/plugins/calendar/src/index.ts +++ b/plugins/calendar/src/index.ts @@ -234,7 +234,10 @@ const calendarPlugin = plugin(calendarId, { ScheduleTitlePlaceholder: '' as IntlString, ScheduleUnavailable: '' as IntlString, MeetingDuration: '' as IntlString, - MeetingInterval: '' as IntlString + MeetingInterval: '' as IntlString, + Day: '' as IntlString, + Week: '' as IntlString, + Month: '' as IntlString }, handler: { DisconnectHandler: '' as Handler diff --git a/plugins/card-resources/src/components/CardEditor.svelte b/plugins/card-resources/src/components/CardEditor.svelte index 4e1913a71d..a51a90678e 100644 --- a/plugins/card-resources/src/components/CardEditor.svelte +++ b/plugins/card-resources/src/components/CardEditor.svelte @@ -13,23 +13,12 @@ // limitations under the License. --> -{#if readonly || attribute.readonly} +{#if readonly || attribute?.readonly} {:else} + + +{#if editor} + + +
+ {#if contextValue} + { + onSelect(e.detail) + }} + /> + {:else} +
+ +
+ {/if} +
+
+
+{/if} + + diff --git a/plugins/process-resources/src/components/ProcessAttributeEditor.svelte b/plugins/process-resources/src/components/ProcessAttributeEditor.svelte index ebc2d90f91..7fecc61627 100644 --- a/plugins/process-resources/src/components/ProcessAttributeEditor.svelte +++ b/plugins/process-resources/src/components/ProcessAttributeEditor.svelte @@ -15,11 +15,10 @@ -{#if editor} - - -
- {#if contextValue} - { - onSelect(e.detail) - }} - /> - {:else} -
- -
- {/if} -
-
-
-{/if} - - + { + onChange(e.detail) + }} +/> diff --git a/plugins/process-resources/src/components/attributeEditors/ConfigurePopup.svelte b/plugins/process-resources/src/components/attributeEditors/ConfigurePopup.svelte index 75b11316e1..862c878ab0 100644 --- a/plugins/process-resources/src/components/attributeEditors/ConfigurePopup.svelte +++ b/plugins/process-resources/src/components/attributeEditors/ConfigurePopup.svelte @@ -13,16 +13,28 @@ // limitations under the License. -->
dispatch('changeContent')}> @@ -175,12 +245,22 @@
+ {#if f.editor} + { + onConfigure(e, f, i) + }} + /> + {/if} { - onFunctionRemove(f._id) + onFunctionRemove(i) }} />
@@ -189,12 +269,12 @@ {/each} {#if availableFunctions.length > 0} { - keyDown(event, functionsLength + (sourceFunc !== undefined ? 1 : 0)) + keyDown(event, functionButtonIndex) }} on:mouseover={() => { - elements[functionsLength + (sourceFunc !== undefined ? 1 : 0)]?.focus() + elements[functionButtonIndex]?.focus() }} label={plugin.string.Functions} props={{ diff --git a/plugins/process-resources/src/components/attributeEditors/ContextSelectorPopup.svelte b/plugins/process-resources/src/components/attributeEditors/ContextSelectorPopup.svelte index 474ef714d7..d3ac7540d2 100644 --- a/plugins/process-resources/src/components/attributeEditors/ContextSelectorPopup.svelte +++ b/plugins/process-resources/src/components/attributeEditors/ContextSelectorPopup.svelte @@ -57,7 +57,7 @@ onClick({ type: 'attribute', key: val.name, - functions: valueFunc !== undefined ? [valueFunc] : [] + functions: valueFunc !== undefined ? [{ func: valueFunc, props: {} }] : [] }) } diff --git a/plugins/process-resources/src/components/attributeEditors/ContextValue.svelte b/plugins/process-resources/src/components/attributeEditors/ContextValue.svelte index a778dbf7cb..ec97349731 100644 --- a/plugins/process-resources/src/components/attributeEditors/ContextValue.svelte +++ b/plugins/process-resources/src/components/attributeEditors/ContextValue.svelte @@ -16,13 +16,14 @@ import { SelectedContext, Context } from '@hcengineering/process' import { eventToHTMLElement, showPopup } from '@hcengineering/ui' import ConfigurePopup from './ConfigurePopup.svelte' - import { Ref, Class, Doc } from '@hcengineering/core' + import { Ref, Class, Doc, AnyAttribute } from '@hcengineering/core' import ContextValuePresenter from './ContextValuePresenter.svelte' import { AttributeCategory } from '@hcengineering/view' import { createEventDispatcher } from 'svelte' export let contextValue: SelectedContext export let context: Context + export let attribute: AnyAttribute export let attrClass: Ref> export let category: AttributeCategory @@ -40,7 +41,11 @@ dispatch('update', res) } } - showPopup(ConfigurePopup, { contextValue, attrClass, category, context, onChange }, eventToHTMLElement(e)) + showPopup( + ConfigurePopup, + { contextValue, attrClass, category, attribute, context, onChange }, + eventToHTMLElement(e) + ) } diff --git a/plugins/process-resources/src/components/attributeEditors/NestedContextSelector.svelte b/plugins/process-resources/src/components/attributeEditors/NestedContextSelector.svelte index 210122aaff..678b2496b3 100644 --- a/plugins/process-resources/src/components/attributeEditors/NestedContextSelector.svelte +++ b/plugins/process-resources/src/components/attributeEditors/NestedContextSelector.svelte @@ -48,7 +48,7 @@ type: 'nested', key: attr.name, path: context.attribute.name, - functions: valueFunc !== undefined ? [valueFunc] : [], + functions: valueFunc !== undefined ? [{ func: valueFunc, props: {} }] : [], sourceFunction: pathReduce }) } diff --git a/plugins/process-resources/src/components/attributeEditors/RelatedContextSelector.svelte b/plugins/process-resources/src/components/attributeEditors/RelatedContextSelector.svelte index 58a0b9d4c3..d810aacc26 100644 --- a/plugins/process-resources/src/components/attributeEditors/RelatedContextSelector.svelte +++ b/plugins/process-resources/src/components/attributeEditors/RelatedContextSelector.svelte @@ -53,7 +53,7 @@ association: context.association, direction: context.direction, name: context.name, - functions: valueFunc !== undefined ? [valueFunc] : [], + functions: valueFunc !== undefined ? [{ func: valueFunc, props: {} }] : [], sourceFunction: reduceFunc }) } diff --git a/plugins/process-resources/src/components/contextEditors/DateOffsetEditor.svelte b/plugins/process-resources/src/components/contextEditors/DateOffsetEditor.svelte new file mode 100644 index 0000000000..a7e45b87a2 --- /dev/null +++ b/plugins/process-resources/src/components/contextEditors/DateOffsetEditor.svelte @@ -0,0 +1,61 @@ + + + + +
+ + + +
diff --git a/plugins/process-resources/src/components/contextEditors/NumberOffsetEditor.svelte b/plugins/process-resources/src/components/contextEditors/NumberOffsetEditor.svelte new file mode 100644 index 0000000000..554b5a2dad --- /dev/null +++ b/plugins/process-resources/src/components/contextEditors/NumberOffsetEditor.svelte @@ -0,0 +1,74 @@ + + + + + { + value = e.detail + }} + /> + diff --git a/plugins/process-resources/src/index.ts b/plugins/process-resources/src/index.ts index 060b34df0c..d463f151c1 100644 --- a/plugins/process-resources/src/index.ts +++ b/plugins/process-resources/src/index.ts @@ -31,6 +31,8 @@ import FunctionSelector from './components/attributeEditors/FunctionSelector.sve import Main from './components/Main.svelte' import RunProcessCardPopup from './components/RunProcessCardPopup.svelte' import { showDoneQuery } from './utils' +import DateOffsetEditor from './components/contextEditors/DateOffsetEditor.svelte' +import NumberOffsetEditor from './components/contextEditors/NumberOffsetEditor.svelte' export default async (): Promise => ({ component: { @@ -51,7 +53,9 @@ export default async (): Promise => ({ RelatedContextSelector, FunctionSelector, Main, - RunProcessCardPopup + RunProcessCardPopup, + DateOffsetEditor, + NumberOffsetEditor }, function: { ShowDoneQuery: showDoneQuery diff --git a/plugins/process-resources/src/plugin.ts b/plugins/process-resources/src/plugin.ts index 60ac61eebc..9bd33172dc 100644 --- a/plugins/process-resources/src/plugin.ts +++ b/plugins/process-resources/src/plugin.ts @@ -40,7 +40,9 @@ export default mergeIds(processId, process, { NestedContextSelector: '' as AnyComponent, RelatedContextSelector: '' as AnyComponent, FunctionSelector: '' as AnyComponent, - RunProcessCardPopup: '' as AnyComponent + RunProcessCardPopup: '' as AnyComponent, + DateOffsetEditor: '' as AnyComponent, + NumberOffsetEditor: '' as AnyComponent }, function: { ShowDoneQuery: '' as ViewQueryAction @@ -76,6 +78,13 @@ export default mergeIds(processId, process, { Random: '' as IntlString, MyProcesses: '' as IntlString, AllProcesses: '' as IntlString, - ShowDone: '' as IntlString + ShowDone: '' as IntlString, + Increment: '' as IntlString, + Decrement: '' as IntlString, + Add: '' as IntlString, + Subtract: '' as IntlString, + Offset: '' as IntlString, + Value: '' as IntlString, + FirstWorkingDayAfter: '' as IntlString } }) diff --git a/plugins/process-resources/src/utils.ts b/plugins/process-resources/src/utils.ts index 9e76dd55a8..650ad81f35 100644 --- a/plugins/process-resources/src/utils.ts +++ b/plugins/process-resources/src/utils.ts @@ -51,7 +51,7 @@ export function getContext ( attr?: Ref ): Context { let attributes = getClassAttributes(client, process.masterTag, target, category) - if (attr !== undefined) { + if (attr !== undefined && category === 'object') { attributes = attributes.filter((it) => it._id !== attr) } const nested: Record = {} diff --git a/plugins/process/src/index.ts b/plugins/process/src/index.ts index e716988eef..6fdc061d34 100644 --- a/plugins/process/src/index.ts +++ b/plugins/process/src/index.ts @@ -72,10 +72,11 @@ export interface Method extends Doc { presenter?: AnyComponent } -// add impl in server export interface ProcessFunction extends Doc { of: Ref> - category?: AttributeCategory + editor?: AnyComponent + category: AttributeCategory | undefined + allowMany?: boolean label: IntlString } @@ -113,6 +114,10 @@ export default plugin(processId, { Random: '' as Ref, UpperCase: '' as Ref, LowerCase: '' as Ref, - Trim: '' as Ref + Trim: '' as Ref, + Add: '' as Ref, + Subtract: '' as Ref, + Offset: '' as Ref, + FirstWorkingDayAfter: '' as Ref } }) diff --git a/plugins/process/src/types.ts b/plugins/process/src/types.ts index 90c928237e..dbd728e799 100644 --- a/plugins/process/src/types.ts +++ b/plugins/process/src/types.ts @@ -19,6 +19,11 @@ export interface RelatedContext { attributes: AnyAttribute[] } +export interface Func { + func: Ref + props: Record +} + interface BaseSelectedContext { type: 'attribute' | 'relation' | 'nested' // attribute key @@ -28,7 +33,7 @@ interface BaseSelectedContext { sourceFunction?: Ref // process one by one - functions?: Array> + functions?: Func[] fallbackValue?: any } diff --git a/plugins/process/src/utils.ts b/plugins/process/src/utils.ts index ec201fafc1..ddf16a8253 100644 --- a/plugins/process/src/utils.ts +++ b/plugins/process/src/utils.ts @@ -5,7 +5,7 @@ export function parseContext (value: any): SelectedContext | undefined { if (typeof value !== 'string') return const index = value.indexOf('${') if (index === -1) return - const endIndex = value.indexOf('}') + const endIndex = value.lastIndexOf('}') if (endIndex === -1) return const content = value.substring(index + 1, endIndex + 1) try { diff --git a/plugins/view-resources/src/components/NumberEditor.svelte b/plugins/view-resources/src/components/NumberEditor.svelte index 3a564234da..ed9fdd7021 100644 --- a/plugins/view-resources/src/components/NumberEditor.svelte +++ b/plugins/view-resources/src/components/NumberEditor.svelte @@ -15,7 +15,7 @@ --> -{#if kind === 'button' || kind === 'link' || kind === 'list'} +{#if kind}