wuic-framework-lib 1.5.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/{wuic-framework-lib-chart-list.component-0J1ghIrS.mjs → wuic-framework-lib-chart-list.component-Bl424n7x.mjs} +50 -38
- package/fesm2022/{wuic-framework-lib-code-editor.component-C21mvjyr.mjs → wuic-framework-lib-code-editor.component-N6HMl2mf.mjs} +174 -274
- package/fesm2022/{wuic-framework-lib-designer.component-x10ZzUEy.mjs → wuic-framework-lib-designer.component-Bd2fwl6H.mjs} +499 -581
- package/fesm2022/{wuic-framework-lib-first-run-wizard.component-BuSxs_CM.mjs → wuic-framework-lib-first-run-wizard.component-NN6cWVHL.mjs} +22 -24
- package/fesm2022/{wuic-framework-lib-framework-docs.component-xTGLbEnp.mjs → wuic-framework-lib-framework-docs.component-B867JAYe.mjs} +2912 -294
- package/fesm2022/{wuic-framework-lib-pivot-builder.component-BkFFjPm4.mjs → wuic-framework-lib-pivot-builder.component-DWukH0L-.mjs} +580 -68
- package/fesm2022/{wuic-framework-lib-prompt-dialog-fallback-host.component-Bi-TrJB6.mjs → wuic-framework-lib-prompt-dialog-fallback-host.component-DWO1Rcgv.mjs} +2 -2
- package/fesm2022/wuic-framework-lib-report-designer.component-QcrU81m6.mjs +380 -0
- package/fesm2022/wuic-framework-lib-report-scaffold-dialog.component-U-zdOoRV.mjs +431 -0
- package/fesm2022/{wuic-framework-lib-report-viewer.component-BR-BfI2r.mjs → wuic-framework-lib-report-viewer.component-B4LhA3SL.mjs} +8 -13
- package/fesm2022/{wuic-framework-lib-scene3d-designer.component-BQzFxSXP.mjs → wuic-framework-lib-scene3d-designer.component-DjOfzKLo.mjs} +323 -88
- package/fesm2022/{wuic-framework-lib-scene3d-light-baker-gpu-0LjqhSNn.mjs → wuic-framework-lib-scene3d-light-baker-gpu-C96T9uIW.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-scene3d-shader-effect-CQLWkuh1.mjs → wuic-framework-lib-scene3d-shader-effect-DjHyCAFK.mjs} +612 -32
- package/fesm2022/{wuic-framework-lib-scene3d-viewer.component-imoV3HOs.mjs → wuic-framework-lib-scene3d-viewer.component-Dboz1fjl.mjs} +149 -18
- package/fesm2022/{wuic-framework-lib-scheduler-list.component-xzlTEkoq.mjs → wuic-framework-lib-scheduler-list.component--wY21R3o.mjs} +169 -53
- package/fesm2022/{wuic-framework-lib-spreadsheet-list-sf.component-CrS6fOGj.mjs → wuic-framework-lib-spreadsheet-list-sf.component-Ek30J8v-.mjs} +149 -108
- package/fesm2022/{wuic-framework-lib-stimulsoft-license.service-BIyxB4pO.mjs → wuic-framework-lib-stimulsoft-license.service-CsNNSFYs.mjs} +3 -3
- package/fesm2022/wuic-framework-lib-timeline-list.component-aqCH4P0G.mjs +805 -0
- package/fesm2022/{wuic-framework-lib-workflow-designer.component-5xtQ7-6z.mjs → wuic-framework-lib-workflow-designer.component-DMM8BeXm.mjs} +180 -150
- package/fesm2022/{wuic-framework-lib-wuic-framework-lib-3TZ-j-yL.mjs → wuic-framework-lib-wuic-framework-lib-dfLTqam5.mjs} +6761 -2347
- package/fesm2022/wuic-framework-lib.mjs +1 -1
- package/package.json +4 -2
- package/styles/_wuic-tokens.scss +82 -0
- package/styles/styles.scss +160 -0
- package/types/wuic-framework-lib.d.ts +4264 -2691
- package/fesm2022/wuic-framework-lib-report-designer.component-ZvB46-LV.mjs +0 -194
|
@@ -10,20 +10,20 @@ import * as i1$1 from '@angular/forms';
|
|
|
10
10
|
import { FormsModule } from '@angular/forms';
|
|
11
11
|
import * as i2$1 from 'primeng/autocomplete';
|
|
12
12
|
import { AutoCompleteModule } from 'primeng/autocomplete';
|
|
13
|
-
import * as
|
|
13
|
+
import * as i14 from 'primeng/contextmenu';
|
|
14
14
|
import { ContextMenuModule } from 'primeng/contextmenu';
|
|
15
15
|
import * as i2 from 'primeng/dialog';
|
|
16
16
|
import { DialogModule } from 'primeng/dialog';
|
|
17
|
-
import * as i7 from 'primeng/menu';
|
|
17
|
+
import * as i7$1 from 'primeng/menu';
|
|
18
18
|
import { MenuModule } from 'primeng/menu';
|
|
19
|
-
import * as
|
|
19
|
+
import * as i5 from 'primeng/select';
|
|
20
20
|
import { SelectModule } from 'primeng/select';
|
|
21
|
-
import * as
|
|
21
|
+
import * as i7 from 'primeng/tooltip';
|
|
22
22
|
import { TooltipModule } from 'primeng/tooltip';
|
|
23
|
-
import * as
|
|
23
|
+
import * as i8 from '@ngx-translate/core';
|
|
24
24
|
import { TranslateModule } from '@ngx-translate/core';
|
|
25
25
|
import { BehaviorSubject } from 'rxjs';
|
|
26
|
-
import { W as WtoolboxService, M as MetadataProviderService,
|
|
26
|
+
import { W as WtoolboxService, M as MetadataProviderService, f as ParametricDialogComponent, m as WuicClientException, n as WuicErrorCodes, G as GlobalHandler, h as DataProviderService, C as ChatbotHostRegistryService, b as DataSourceComponent, l as MetadataEditorComponent } from './wuic-framework-lib-wuic-framework-lib-dfLTqam5.mjs';
|
|
27
27
|
|
|
28
28
|
class WorkflowDesignerLayoutHelper {
|
|
29
29
|
/**
|
|
@@ -106,7 +106,7 @@ class WorkflowDesignerLayoutHelper {
|
|
|
106
106
|
const stack = [{ id: rootId, idx: 0 }];
|
|
107
107
|
color.set(rootId, 1);
|
|
108
108
|
while (stack.length) {
|
|
109
|
-
const frame = stack
|
|
109
|
+
const frame = stack.at(-1);
|
|
110
110
|
const targets = outgoing.get(frame.id) || [];
|
|
111
111
|
if (frame.idx >= targets.length) {
|
|
112
112
|
color.set(frame.id, 2);
|
|
@@ -419,7 +419,7 @@ class WorkflowDesignerLayoutHelper {
|
|
|
419
419
|
const actionId = String(node.id || '');
|
|
420
420
|
const explicitRouteId = String(node?.workflowRouteNodeId || '').trim();
|
|
421
421
|
const incomingSourceId = resolveIncomingSourceId(actionId);
|
|
422
|
-
const fallbackRouteId = incomingSourceId && String(nodeById.get(incomingSourceId)?.workflowType || '') === 'route'
|
|
422
|
+
const fallbackRouteId = incomingSourceId && String((nodeById.get(incomingSourceId))?.workflowType || '') === 'route'
|
|
423
423
|
? incomingSourceId
|
|
424
424
|
: '';
|
|
425
425
|
const routeId = explicitRouteId || fallbackRouteId;
|
|
@@ -870,10 +870,12 @@ function lintWorkflowGraph(ctx) {
|
|
|
870
870
|
}
|
|
871
871
|
if (type === 'timer') {
|
|
872
872
|
const cfg = n?.workflowTimerConfig || null;
|
|
873
|
+
const duration = Number(cfg?.duration_minutes);
|
|
873
874
|
const incomplete = !cfg
|
|
874
875
|
|| !String(cfg.state_value || '').trim()
|
|
875
876
|
|| !String(cfg.reference_date_field || '').trim()
|
|
876
|
-
||
|
|
877
|
+
|| Number.isNaN(duration)
|
|
878
|
+
|| duration <= 0;
|
|
877
879
|
if (incomplete) {
|
|
878
880
|
findings.push({
|
|
879
881
|
severity: 'error', code: 'WF-E06', nodeId: id,
|
|
@@ -916,7 +918,7 @@ function lintWorkflowGraph(ctx) {
|
|
|
916
918
|
// WF-W06 — permessi transizione che citano ruoli inesistenti.
|
|
917
919
|
if (ctx.knownRoleIds) {
|
|
918
920
|
(ctx.connections || []).forEach((c) => {
|
|
919
|
-
const permission = String(c?.workflowTransition?.permission || '').trim();
|
|
921
|
+
const permission = String((c)?.workflowTransition?.permission || '').trim();
|
|
920
922
|
if (!permission) {
|
|
921
923
|
return;
|
|
922
924
|
}
|
|
@@ -925,7 +927,7 @@ function lintWorkflowGraph(ctx) {
|
|
|
925
927
|
const roleId = Number(m.slice('role:'.length));
|
|
926
928
|
if (Number.isFinite(roleId) && roleId > 0 && !ctx.knownRoleIds.has(roleId)) {
|
|
927
929
|
findings.push({
|
|
928
|
-
severity: 'warn', code: 'WF-W06', connectionId: String(c?.id || ''),
|
|
930
|
+
severity: 'warn', code: 'WF-W06', connectionId: String((c)?.id || ''),
|
|
929
931
|
message: t('workflow.lint.w06_unknown_role', 'Permesso di transizione con ruolo inesistente') + `: role:${roleId}`
|
|
930
932
|
});
|
|
931
933
|
}
|
|
@@ -933,9 +935,12 @@ function lintWorkflowGraph(ctx) {
|
|
|
933
935
|
});
|
|
934
936
|
}
|
|
935
937
|
// Errori prima dei warn, poi per codice (elenco stabile e scansionabile).
|
|
936
|
-
return findings.sort((a, b) =>
|
|
937
|
-
|
|
938
|
-
|
|
938
|
+
return findings.sort((a, b) => {
|
|
939
|
+
if (a.severity === b.severity) {
|
|
940
|
+
return a.code.localeCompare(b.code);
|
|
941
|
+
}
|
|
942
|
+
return a.severity === 'error' ? -1 : 1;
|
|
943
|
+
});
|
|
939
944
|
}
|
|
940
945
|
|
|
941
946
|
/**
|
|
@@ -1420,8 +1425,7 @@ class WorkflowDesignerNodeComponent {
|
|
|
1420
1425
|
for (let i = 1; i <= n; i++) {
|
|
1421
1426
|
points.push([100, (i * 100) / (n + 1)]);
|
|
1422
1427
|
}
|
|
1423
|
-
points.push([50, 100]);
|
|
1424
|
-
points.push([0, 50]);
|
|
1428
|
+
points.push([50, 100], [0, 50]);
|
|
1425
1429
|
return { width, titlePadX: 12, titleInsetX: 28, path: this.polygonPath(points, width, this.effectiveHeight), kind: 'switch' };
|
|
1426
1430
|
}
|
|
1427
1431
|
if (type === 'parallel_split' || type === 'parallel_join') {
|
|
@@ -1558,7 +1562,7 @@ class WorkflowDesignerNodeComponent {
|
|
|
1558
1562
|
lines.splice(maxLines);
|
|
1559
1563
|
}
|
|
1560
1564
|
if (lines.length === maxLines) {
|
|
1561
|
-
const consumed = lines.join(' ').
|
|
1565
|
+
const consumed = lines.join(' ').replaceAll(/\u2026/g, '').length;
|
|
1562
1566
|
if (raw.length > consumed && !lines[maxLines - 1].endsWith('…')) {
|
|
1563
1567
|
lines[maxLines - 1] = lines[maxLines - 1].slice(0, Math.max(1, maxCharsPerLine - 1)).trimEnd() + '…';
|
|
1564
1568
|
}
|
|
@@ -1579,7 +1583,7 @@ class WorkflowDesignerNodeComponent {
|
|
|
1579
1583
|
return value.slice(0, Math.max(1, limit - 1)) + '…';
|
|
1580
1584
|
}
|
|
1581
1585
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WorkflowDesignerNodeComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
1582
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: WorkflowDesignerNodeComponent, isStandalone: true, selector: "wuic-workflow-designer-node", inputs: { data: "data", emit: "emit", rendered: "rendered" }, host: { attributes: { "data-testid": "node" }, properties: { "style.width.px": "this.width", "style.height.px": "this.height", "class.selected": "this.selected", "attr.data-wf-node-type": "this.nodeType", "attr.data-wf-action-scope": "this.actionScope", "attr.data-wf-action-type": "this.actionType", "style.--wf-node-accent": "this.accentColor", "style.--wf-node-bg": "this.backgroundColor" } }, usesOnChanges: true, ngImport: i0, template: "<svg class=\"wf-shape-layer\" [attr.viewBox]=\"svgViewBox\" aria-hidden=\"true\">\n <path class=\"wf-shape-fill\" [attr.d]=\"shapePath\"></path>\n <rect class=\"wf-shape-title-band\" [attr.x]=\"titleBandX\" y=\"2\" [attr.width]=\"titleBandWidth\" [attr.height]=\"titleBandHeight\" rx=\"5\" ry=\"5\"></rect>\n <text class=\"wf-shape-title-text\" [attr.x]=\"titleTextX\" [attr.y]=\"titleTextY\">\n @for (line of titleLines; track $index; let i = $index) {\n <tspan [attr.x]=\"titleTextX\" [attr.dy]=\"i === 0 ? 0 : titleLineDy\">{{ line }}</tspan>\n }\n </text>\n <path class=\"wf-shape-stroke\" [attr.d]=\"shapePath\" [attr.stroke-dasharray]=\"dashedStroke\"></path>\n</svg>\n\n<!-- Overlay TRASPARENTE per il tooltip: l'`.wf-shape-layer` ha\n pointer-events:none (serve al drag di rete), quindi il hover reale non lo\n raggiunge. Questo target riempie il nodo con pointer-events:auto: il\n mouseenter arriva a pTooltip; pointerdown/contextmenu BOLLONO all'host\n (drag + context menu invariati); i socket sono DOPO nel DOM (stacking piu'\n alto) quindi restano cliccabili. -->\n<div class=\"wf-node-hover-target\"\n [pTooltip]=\"tooltipHtml\" [escape]=\"false\" tooltipPosition=\"top\"\n [tooltipDisabled]=\"!tooltipHtml\" [showDelay]=\"250\" tooltipStyleClass=\"wf-node-tooltip\"></div>\n\n<!-- SOCKET/CONTROL: `@for` con track per KEY (chiave stabile del socket). La\n pipe impura `keyvalueimpure` restituisce un nuovo array a ogni CD; tracciare\n per key fa RIUSARE le view invece di ricrearle (niente warning NG0956).\n rete-angular-plugin e' costruito sul ciclo mount/unmount del RefDirective\n (emit('render')/emit('unmount')) e senza guardia crasherebbe in teardown\n con \"this.emit is not a function\": la guardia idempotente nel .ts del\n componente (RefDirective.prototype) tollera quei momenti. -->\n@for (output of data.outputs | keyvalueimpure: sortByIndex; track output.key) {\n <!-- Switch: socket posizionato inline sul VERTICE del poligono (ngStyle null\n per gli altri tipi = CSS default) + tooltip nativo con la condizione. -->\n <div class=\"wf-output\" [attr.data-testid]=\"'output-'+output.key\" [attr.data-wf-output-key]=\"output.key\"\n [ngStyle]=\"switchOutputStyle(output.key)\" [attr.title]=\"switchOutputTitle(output.key)\">\n <div class=\"wf-output-title\" data-testid=\"output-title\">{{ output.value?.label }}</div>\n <div\n class=\"wf-output-socket\"\n refComponent\n [data]=\"{type: 'socket', side: 'output', key: output.key, nodeId: data.id, payload: output.value?.socket, seed: seed }\"\n [emit]=\"emit\"\n data-testid=\"output-socket\">\n </div>\n </div>\n}\n\n@for (control of data.controls | keyvalueimpure: sortByIndex; track control.key) {\n <div\n class=\"wf-control\"\n refComponent\n [data]=\"{type: 'control', payload: control.value }\"\n [emit]=\"emit\"\n [attr.data-testid]=\"'control-'+control.key\">\n </div>\n}\n\n@for (input of data.inputs | keyvalueimpure: sortByIndex; track input.key) {\n <div class=\"wf-input\" [attr.data-testid]=\"'input-'+input.key\">\n <div\n class=\"wf-input-socket\"\n refComponent\n [data]=\"{type: 'socket', side: 'input', key: input.key, nodeId: data.id, payload: input.value?.socket, seed: seed }\"\n [emit]=\"emit\"\n data-testid=\"input-socket\">\n </div>\n @if (!input.value?.control || !input.value?.showControl) {\n <div class=\"wf-input-title\" data-testid=\"input-title\">{{ input.value?.label }}</div>\n }\n <div\n class=\"wf-input-control\"\n [style.display]=\"input.value?.control && input.value?.showControl ? '' : 'none'\"\n refComponent\n [data]=\"{type: 'control', payload: input.value?.control }\"\n [emit]=\"emit\"\n data-testid=\"input-control\">\n </div>\n </div>\n}\n", styles: [":host{display:block;box-sizing:border-box;min-height:92px;cursor:pointer;-webkit-user-select:none;user-select:none;line-height:initial;font-family:Arial,sans-serif;position:relative;overflow:visible;color:#0f172a}.wf-shape-layer{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:0}.wf-shape-fill{fill:var(--wf-node-bg, #f8fafc)}.wf-shape-stroke{fill:none;stroke:var(--wf-node-accent, #475569);stroke-width:2.2;vector-effect:non-scaling-stroke}.wf-shape-title-band{fill:var(--wf-node-accent, #475569)}.wf-shape-title-text{fill:#fff;font-size:12px;font-weight:700;font-family:Arial,sans-serif;dominant-baseline:hanging;text-anchor:start}:host.selected{filter:drop-shadow(0 0 .35rem color-mix(in srgb,var(--wf-node-accent, #475569) 42%,transparent))}:host>*{position:relative;z-index:1}.wf-output{position:absolute;top:50%;right:0;transform:translate(50%,-50%);width:0;height:0;display:flex;align-items:center;justify-content:center;z-index:2}.wf-input{position:absolute;top:50%;left:0;transform:translate(-50%,-50%);width:0;height:0;display:flex;align-items:center;justify-content:center;z-index:2}:host[data-wf-node-type=action][data-wf-action-type=\"0\"] .wf-input{left:10%}.wf-input-title,.wf-output-title{display:none}.wf-output-socket{line-height:0;vertical-align:top;margin-right:0;display:block}.wf-input-socket{line-height:0;vertical-align:top;margin-left:0;display:block}.wf-input-control{z-index:1;width:calc(100% - 36px);vertical-align:middle;display:inline-block}.wf-control{padding:6px 18px}:host[data-wf-node-type=condition] .wf-output[data-wf-output-key=true]{inset:50% 0 auto auto;transform:translate(50%,-50%)}:host[data-wf-node-type=condition] .wf-output[data-wf-output-key=false]{inset:auto auto 0 50%;transform:translate(-50%,50%)}:host[data-wf-node-type=condition] .wf-output-title{display:block;position:absolute;white-space:nowrap;font-size:9px;font-weight:700;letter-spacing:.3px;color:var(--wf-node-accent, #0f766e);pointer-events:none}:host[data-wf-node-type=condition] .wf-output[data-wf-output-key=true] .wf-output-title{right:12px;top:50%;transform:translateY(-50%)}:host[data-wf-node-type=condition] .wf-output[data-wf-output-key=false] .wf-output-title{bottom:10px;left:50%;transform:translate(-50%)}:host[data-wf-node-type=switch] .wf-output-title{display:block;position:absolute;white-space:nowrap;font-size:9px;font-weight:700;letter-spacing:.3px;color:var(--wf-node-accent, #4338ca);pointer-events:none;right:14px;top:50%;transform:translateY(-50%)}:host[data-wf-node-type=switch] .wf-output[data-wf-output-key=else] .wf-output-title{inset:auto auto 12px 50%;transform:translate(-50%)}.wf-node-hover-target{position:absolute;inset:0;z-index:0;pointer-events:auto;background:transparent}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: RefDirective, selector: "[refComponent]", inputs: ["data", "emit"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type:
|
|
1586
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: WorkflowDesignerNodeComponent, isStandalone: true, selector: "wuic-workflow-designer-node", inputs: { data: "data", emit: "emit", rendered: "rendered" }, host: { attributes: { "data-testid": "node" }, properties: { "style.width.px": "this.width", "style.height.px": "this.height", "class.selected": "this.selected", "attr.data-wf-node-type": "this.nodeType", "attr.data-wf-action-scope": "this.actionScope", "attr.data-wf-action-type": "this.actionType", "style.--wf-node-accent": "this.accentColor", "style.--wf-node-bg": "this.backgroundColor" } }, usesOnChanges: true, ngImport: i0, template: "<svg class=\"wf-shape-layer\" [attr.viewBox]=\"svgViewBox\" aria-hidden=\"true\">\n <path class=\"wf-shape-fill\" [attr.d]=\"shapePath\"></path>\n <rect class=\"wf-shape-title-band\" [attr.x]=\"titleBandX\" y=\"2\" [attr.width]=\"titleBandWidth\" [attr.height]=\"titleBandHeight\" rx=\"5\" ry=\"5\"></rect>\n <text class=\"wf-shape-title-text\" [attr.x]=\"titleTextX\" [attr.y]=\"titleTextY\">\n @for (line of titleLines; track $index; let i = $index) {\n <tspan [attr.x]=\"titleTextX\" [attr.dy]=\"i === 0 ? 0 : titleLineDy\">{{ line }}</tspan>\n }\n </text>\n <path class=\"wf-shape-stroke\" [attr.d]=\"shapePath\" [attr.stroke-dasharray]=\"dashedStroke\"></path>\n</svg>\n\n<!-- Overlay TRASPARENTE per il tooltip: l'`.wf-shape-layer` ha\n pointer-events:none (serve al drag di rete), quindi il hover reale non lo\n raggiunge. Questo target riempie il nodo con pointer-events:auto: il\n mouseenter arriva a pTooltip; pointerdown/contextmenu BOLLONO all'host\n (drag + context menu invariati); i socket sono DOPO nel DOM (stacking piu'\n alto) quindi restano cliccabili. -->\n<div class=\"wf-node-hover-target\"\n [pTooltip]=\"tooltipHtml\" [escape]=\"false\" tooltipPosition=\"top\"\n [tooltipDisabled]=\"!tooltipHtml\" [showDelay]=\"250\" tooltipStyleClass=\"wf-node-tooltip\"></div>\n\n<!-- SOCKET/CONTROL: `@for` con track per KEY (chiave stabile del socket). La\n pipe impura `keyvalueimpure` restituisce un nuovo array a ogni CD; tracciare\n per key fa RIUSARE le view invece di ricrearle (niente warning NG0956).\n rete-angular-plugin e' costruito sul ciclo mount/unmount del RefDirective\n (emit('render')/emit('unmount')) e senza guardia crasherebbe in teardown\n con \"this.emit is not a function\": la guardia idempotente nel .ts del\n componente (RefDirective.prototype) tollera quei momenti. -->\n@for (output of data.outputs | keyvalueimpure: sortByIndex; track output.key) {\n <!-- Switch: socket posizionato inline sul VERTICE del poligono (ngStyle null\n per gli altri tipi = CSS default) + tooltip nativo con la condizione. -->\n <div class=\"wf-output\" [attr.data-testid]=\"'output-'+output.key\" [attr.data-wf-output-key]=\"output.key\"\n [ngStyle]=\"switchOutputStyle(output.key)\" [attr.title]=\"switchOutputTitle(output.key)\">\n <div class=\"wf-output-title\" data-testid=\"output-title\">{{ output.value?.label }}</div>\n <div\n class=\"wf-output-socket\"\n refComponent\n [data]=\"{type: 'socket', side: 'output', key: output.key, nodeId: data.id, payload: output.value?.socket, seed: seed }\"\n [emit]=\"emit\"\n data-testid=\"output-socket\">\n </div>\n </div>\n}\n\n@for (control of data.controls | keyvalueimpure: sortByIndex; track control.key) {\n <div\n class=\"wf-control\"\n refComponent\n [data]=\"{type: 'control', payload: control.value }\"\n [emit]=\"emit\"\n [attr.data-testid]=\"'control-'+control.key\">\n </div>\n}\n\n@for (input of data.inputs | keyvalueimpure: sortByIndex; track input.key) {\n <div class=\"wf-input\" [attr.data-testid]=\"'input-'+input.key\">\n <div\n class=\"wf-input-socket\"\n refComponent\n [data]=\"{type: 'socket', side: 'input', key: input.key, nodeId: data.id, payload: input.value?.socket, seed: seed }\"\n [emit]=\"emit\"\n data-testid=\"input-socket\">\n </div>\n @if (!input.value?.control || !input.value?.showControl) {\n <div class=\"wf-input-title\" data-testid=\"input-title\">{{ input.value?.label }}</div>\n }\n <div\n class=\"wf-input-control\"\n [style.display]=\"input.value?.control && input.value?.showControl ? '' : 'none'\"\n refComponent\n [data]=\"{type: 'control', payload: input.value?.control }\"\n [emit]=\"emit\"\n data-testid=\"input-control\">\n </div>\n </div>\n}\n", styles: [":host{display:block;box-sizing:border-box;min-height:92px;cursor:pointer;-webkit-user-select:none;user-select:none;line-height:initial;font-family:Arial,sans-serif;position:relative;overflow:visible;color:#0f172a}.wf-shape-layer{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:0}.wf-shape-fill{fill:var(--wf-node-bg, #f8fafc)}.wf-shape-stroke{fill:none;stroke:var(--wf-node-accent, #475569);stroke-width:2.2;vector-effect:non-scaling-stroke}.wf-shape-title-band{fill:var(--wf-node-accent, #475569)}.wf-shape-title-text{fill:#fff;font-size:12px;font-weight:700;font-family:Arial,sans-serif;dominant-baseline:hanging;text-anchor:start}:host.selected{filter:drop-shadow(0 0 .35rem color-mix(in srgb,var(--wf-node-accent, #475569) 42%,transparent))}:host>*{position:relative;z-index:1}.wf-output{position:absolute;top:50%;right:0;transform:translate(50%,-50%);width:0;height:0;display:flex;align-items:center;justify-content:center;z-index:2}.wf-input{position:absolute;top:50%;left:0;transform:translate(-50%,-50%);width:0;height:0;display:flex;align-items:center;justify-content:center;z-index:2}:host[data-wf-node-type=action][data-wf-action-type=\"0\"] .wf-input{left:10%}.wf-input-title,.wf-output-title{display:none}.wf-output-socket{line-height:0;vertical-align:top;margin-right:0;display:block}.wf-input-socket{line-height:0;vertical-align:top;margin-left:0;display:block}.wf-input-control{z-index:1;width:calc(100% - 36px);vertical-align:middle;display:inline-block}.wf-control{padding:6px 18px}:host[data-wf-node-type=condition] .wf-output[data-wf-output-key=true]{inset:50% 0 auto auto;transform:translate(50%,-50%)}:host[data-wf-node-type=condition] .wf-output[data-wf-output-key=false]{inset:auto auto 0 50%;transform:translate(-50%,50%)}:host[data-wf-node-type=condition] .wf-output-title{display:block;position:absolute;white-space:nowrap;font-size:9px;font-weight:700;letter-spacing:.3px;color:var(--wf-node-accent, #0f766e);pointer-events:none}:host[data-wf-node-type=condition] .wf-output[data-wf-output-key=true] .wf-output-title{right:12px;top:50%;transform:translateY(-50%)}:host[data-wf-node-type=condition] .wf-output[data-wf-output-key=false] .wf-output-title{bottom:10px;left:50%;transform:translate(-50%)}:host[data-wf-node-type=switch] .wf-output-title{display:block;position:absolute;white-space:nowrap;font-size:9px;font-weight:700;letter-spacing:.3px;color:var(--wf-node-accent, #4338ca);pointer-events:none;right:14px;top:50%;transform:translateY(-50%)}:host[data-wf-node-type=switch] .wf-output[data-wf-output-key=else] .wf-output-title{inset:auto auto 12px 50%;transform:translate(-50%)}.wf-node-hover-target{position:absolute;inset:0;z-index:0;pointer-events:auto;background:transparent}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: RefDirective, selector: "[refComponent]", inputs: ["data", "emit"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "pipe", type: ImpureKeyvaluePipe, name: "keyvalueimpure" }] });
|
|
1583
1587
|
}
|
|
1584
1588
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WorkflowDesignerNodeComponent, decorators: [{
|
|
1585
1589
|
type: Component,
|
|
@@ -1915,7 +1919,9 @@ class WorkflowDesignerComponent {
|
|
|
1915
1919
|
// (mirror DataSourceComponent.ngOnInit, vedi commento in data-source.component.ts
|
|
1916
1920
|
// 2026-05-25 sul perche' window.ng.getComponent non e' affidabile in prod).
|
|
1917
1921
|
try {
|
|
1918
|
-
(this.hostElementRef?.nativeElement)
|
|
1922
|
+
if (this.hostElementRef?.nativeElement) {
|
|
1923
|
+
this.hostElementRef.nativeElement.__wuicCmp = this;
|
|
1924
|
+
}
|
|
1919
1925
|
}
|
|
1920
1926
|
catch { /* defensive */ }
|
|
1921
1927
|
const canvas = this.workflowCanvasRef?.nativeElement;
|
|
@@ -1997,7 +2003,9 @@ class WorkflowDesignerComponent {
|
|
|
1997
2003
|
*/
|
|
1998
2004
|
ngOnDestroy() {
|
|
1999
2005
|
try {
|
|
2000
|
-
|
|
2006
|
+
if (this.hostElementRef?.nativeElement) {
|
|
2007
|
+
delete this.hostElementRef.nativeElement.__wuicCmp;
|
|
2008
|
+
}
|
|
2001
2009
|
}
|
|
2002
2010
|
catch { /* defensive */ }
|
|
2003
2011
|
// Deregistra handler/state provider chatbot: il prossimo mount registrera'
|
|
@@ -2377,9 +2385,10 @@ class WorkflowDesignerComponent {
|
|
|
2377
2385
|
// integra le action fresche appena caricate dal datasource prima di
|
|
2378
2386
|
// applicare l'overlay — altrimenti il click "Metadata action" era un no-op.
|
|
2379
2387
|
if (metadataTargetType === 'table_action') {
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2388
|
+
if (!Array.isArray(bundle.tableActions)) {
|
|
2389
|
+
bundle.tableActions = [];
|
|
2390
|
+
}
|
|
2391
|
+
const bundleActions = bundle.tableActions;
|
|
2383
2392
|
if (!bundleActions.some((x) => Number(x?.Id) === metadataTargetId)) {
|
|
2384
2393
|
const fresh = this.sanitizeForSerialization(this.routeMetadataDs.metaInfo?.tableMetadata?._Metadati_Custom_Actions_Tabelles || []) || [];
|
|
2385
2394
|
fresh.forEach((fa) => {
|
|
@@ -2553,14 +2562,14 @@ class WorkflowDesignerComponent {
|
|
|
2553
2562
|
const menus = this.normalizeStartMenuItems(startNode.workflowStartMenus || []);
|
|
2554
2563
|
const parsedMmId = Number(normalizedData?.mm_id ?? normalizedOriginal?.mm_id ?? ctx.menuId ?? 0);
|
|
2555
2564
|
const mmId = Number.isFinite(parsedMmId) && parsedMmId !== 0 ? parsedMmId : this.nextLocalMenuId(menus);
|
|
2556
|
-
const merged =
|
|
2565
|
+
const merged = { ...normalizedOriginal, ...normalizedData, mm_id: mmId };
|
|
2557
2566
|
const normalizedMenu = this.normalizeStartMenuItems([merged])[0];
|
|
2558
2567
|
if (!normalizedMenu) {
|
|
2559
2568
|
return false;
|
|
2560
2569
|
}
|
|
2561
2570
|
const idx = menus.findIndex((x) => Number(x.mm_id) === Number(mmId));
|
|
2562
2571
|
if (idx >= 0) {
|
|
2563
|
-
menus[idx] =
|
|
2572
|
+
menus[idx] = { ...menus[idx], ...normalizedMenu };
|
|
2564
2573
|
}
|
|
2565
2574
|
else {
|
|
2566
2575
|
menus.push(normalizedMenu);
|
|
@@ -3501,13 +3510,16 @@ class WorkflowDesignerComponent {
|
|
|
3501
3510
|
const y = Number.isFinite(Number(spec?.y)) ? Number(spec.y) : fallbackY;
|
|
3502
3511
|
// routeConfig veicola anche conditionExpression/switchConfig: createNode li
|
|
3503
3512
|
// legge da qui (cast `as any` gia' fatto internamente da createNode).
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
: (
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3513
|
+
let routeConfig;
|
|
3514
|
+
if (type === 'route') {
|
|
3515
|
+
routeConfig = { routeName: String(spec?.route || '').trim(), action: String(spec?.action || '').trim() || 'list' };
|
|
3516
|
+
}
|
|
3517
|
+
else if (type === 'condition') {
|
|
3518
|
+
routeConfig = { routeName: '', action: '', conditionExpression: String(spec?.conditionExpression || '') };
|
|
3519
|
+
}
|
|
3520
|
+
else if (type === 'switch') {
|
|
3521
|
+
routeConfig = { routeName: '', action: '', switchConfig: spec?.switchConfig || null };
|
|
3522
|
+
}
|
|
3511
3523
|
const actionType = type === 'action' ? (this.getActionTypeById(Number(spec?.actionTypeId ?? 1)) || undefined) : undefined;
|
|
3512
3524
|
const actionScope = type === 'action' ? (this.getActionScopeById(Number(spec?.actionScopeId ?? 0)) || undefined) : undefined;
|
|
3513
3525
|
const node = await this.addNodeByType(type, x, y, routeConfig, actionType || undefined, actionScope || undefined, undefined, false);
|
|
@@ -3535,7 +3547,7 @@ class WorkflowDesignerComponent {
|
|
|
3535
3547
|
if (!key) {
|
|
3536
3548
|
return null;
|
|
3537
3549
|
}
|
|
3538
|
-
if (localMap
|
|
3550
|
+
if (localMap?.has(key)) {
|
|
3539
3551
|
return localMap.get(key) || null;
|
|
3540
3552
|
}
|
|
3541
3553
|
const byId = this.getNodeById(key);
|
|
@@ -3780,11 +3792,12 @@ class WorkflowDesignerComponent {
|
|
|
3780
3792
|
node.workflowRouteSourceType = sourceType;
|
|
3781
3793
|
node.workflowDashboardBoardcontent = sourceType === 'dashboard' ? dashboardBoardcontent : '';
|
|
3782
3794
|
const restoredDashboardDatasources = this.sanitizeForSerialization(routeConfig?.dashboardDatasources || []) || [];
|
|
3783
|
-
|
|
3784
|
-
|
|
3795
|
+
let dashboardDatasources = [];
|
|
3796
|
+
if (sourceType === 'dashboard') {
|
|
3797
|
+
dashboardDatasources = restoredDashboardDatasources.length
|
|
3785
3798
|
? restoredDashboardDatasources
|
|
3786
|
-
: this.extractDashboardDatasourceMetadata(dashboardBoardcontent)
|
|
3787
|
-
|
|
3799
|
+
: this.extractDashboardDatasourceMetadata(dashboardBoardcontent);
|
|
3800
|
+
}
|
|
3788
3801
|
node.workflowDashboardDatasources = dashboardDatasources;
|
|
3789
3802
|
node.workflowRouteMetadataBundle = routeMetadata
|
|
3790
3803
|
|| (dashboardDatasources[0]?.metadataBundle || null);
|
|
@@ -3996,7 +4009,8 @@ class WorkflowDesignerComponent {
|
|
|
3996
4009
|
const uriKey = uri.toLowerCase();
|
|
3997
4010
|
const alreadyCovered = menus.some((menu) => {
|
|
3998
4011
|
const raw = String(menu?.mm_uri_menu || '').trim();
|
|
3999
|
-
const
|
|
4012
|
+
const withLeadingSlash = raw.startsWith('/') ? raw : '/' + raw;
|
|
4013
|
+
const normalized = (raw.startsWith('#/') ? raw.substring(1) : withLeadingSlash).toLowerCase();
|
|
4000
4014
|
return normalized === uriKey;
|
|
4001
4015
|
});
|
|
4002
4016
|
if (alreadyCovered) {
|
|
@@ -4356,9 +4370,9 @@ class WorkflowDesignerComponent {
|
|
|
4356
4370
|
return NaN;
|
|
4357
4371
|
}
|
|
4358
4372
|
const normalized = input
|
|
4359
|
-
.
|
|
4360
|
-
.
|
|
4361
|
-
.
|
|
4373
|
+
.replaceAll('_', '.')
|
|
4374
|
+
.replaceAll(/\s+/g, '.')
|
|
4375
|
+
.replaceAll(/-+/g, '.');
|
|
4362
4376
|
const byNeedle = new Map([
|
|
4363
4377
|
['navigation', 0],
|
|
4364
4378
|
['method.call', 1],
|
|
@@ -4402,7 +4416,8 @@ class WorkflowDesignerComponent {
|
|
|
4402
4416
|
if (!cfg || !Number.isFinite(minutes) || minutes <= 0) {
|
|
4403
4417
|
return 'Timer (da configurare)';
|
|
4404
4418
|
}
|
|
4405
|
-
const
|
|
4419
|
+
const hoursOrMinutes = minutes % 60 === 0 ? `${minutes / 60}h` : `${minutes}m`;
|
|
4420
|
+
const human = minutes % 1440 === 0 ? `${minutes / 1440}g` : hoursOrMinutes;
|
|
4406
4421
|
return `Timer ${human} · ${String(cfg.state_value || '')}`;
|
|
4407
4422
|
}
|
|
4408
4423
|
if (type === 'parallel_split') {
|
|
@@ -4488,7 +4503,7 @@ class WorkflowDesignerComponent {
|
|
|
4488
4503
|
if (this.roleNamesById.size > 0) {
|
|
4489
4504
|
return Promise.resolve();
|
|
4490
4505
|
}
|
|
4491
|
-
if (this.roleNamesLoading) {
|
|
4506
|
+
if (this.roleNamesLoading !== null) {
|
|
4492
4507
|
return this.roleNamesLoading;
|
|
4493
4508
|
}
|
|
4494
4509
|
this.roleNamesLoading = (async () => {
|
|
@@ -4539,7 +4554,7 @@ class WorkflowDesignerComponent {
|
|
|
4539
4554
|
if (this.userDirectory.size > 0) {
|
|
4540
4555
|
return Promise.resolve();
|
|
4541
4556
|
}
|
|
4542
|
-
if (this.userDirectoryLoading) {
|
|
4557
|
+
if (this.userDirectoryLoading !== null) {
|
|
4543
4558
|
return this.userDirectoryLoading;
|
|
4544
4559
|
}
|
|
4545
4560
|
this.userDirectoryLoading = (async () => {
|
|
@@ -4674,7 +4689,7 @@ class WorkflowDesignerComponent {
|
|
|
4674
4689
|
: undefined;
|
|
4675
4690
|
const flag = this.tooltipPermFlag(rowUser, ['muat_view', 'muatview'])
|
|
4676
4691
|
?? this.tooltipPermFlag(rowRole, ['muat_view', 'muatview']);
|
|
4677
|
-
return flag
|
|
4692
|
+
return flag ?? grantByDefault;
|
|
4678
4693
|
}
|
|
4679
4694
|
/**
|
|
4680
4695
|
* La permission di transizione (`grant:...`/`deny:...`/legacy) ammette il
|
|
@@ -4796,7 +4811,7 @@ class WorkflowDesignerComponent {
|
|
|
4796
4811
|
/** HTML-escape minimale per il contenuto tooltip (pTooltip con escape=false). */
|
|
4797
4812
|
escapeTooltip(text) {
|
|
4798
4813
|
return String(text ?? '')
|
|
4799
|
-
.
|
|
4814
|
+
.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>');
|
|
4800
4815
|
}
|
|
4801
4816
|
/** Legge un flag tri-state (true/false/null) da una riga permesso. */
|
|
4802
4817
|
tooltipPermFlag(row, keys) {
|
|
@@ -4827,7 +4842,7 @@ class WorkflowDesignerComponent {
|
|
|
4827
4842
|
* evento derivato. '' se la connessione non ha nulla di rilevante.
|
|
4828
4843
|
*/
|
|
4829
4844
|
computeConnectionTooltip(conn) {
|
|
4830
|
-
const t = conn?.workflowTransition || {};
|
|
4845
|
+
const t = (conn)?.workflowTransition || {};
|
|
4831
4846
|
const permission = String(t.permission || '').trim();
|
|
4832
4847
|
const guard = String(t.guard || '').trim();
|
|
4833
4848
|
const event = String(t.event || '').trim();
|
|
@@ -4880,7 +4895,8 @@ class WorkflowDesignerComponent {
|
|
|
4880
4895
|
th: 'text-align:left;font-weight:600;color:#94a3b8;padding:1px 6px 1px 0;border-bottom:1px solid #334155',
|
|
4881
4896
|
td: 'padding:1px 6px 1px 0;color:#e2e8f0;white-space:nowrap'
|
|
4882
4897
|
};
|
|
4883
|
-
const
|
|
4898
|
+
const captionHtml = caption ? ` <span style="color:#93c5fd">${esc(caption)}</span>` : '';
|
|
4899
|
+
const header = `<b>Start</b>${captionHtml}`;
|
|
4884
4900
|
if (!menus.length) {
|
|
4885
4901
|
return `<div style="min-width:220px"><div style="font-size:12px">${header}</div>Nessuna voce di menu</div>`;
|
|
4886
4902
|
}
|
|
@@ -4894,9 +4910,14 @@ class WorkflowDesignerComponent {
|
|
|
4894
4910
|
const authParts = auths.map((a) => {
|
|
4895
4911
|
const userId = Number(a?.utenteid || 0);
|
|
4896
4912
|
const roleId = Number(a?.ruoloid || 0);
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4913
|
+
let who;
|
|
4914
|
+
if (userId > 0) {
|
|
4915
|
+
const roleSuffix = roleId > 0 ? ` (${esc(this.roleLabel(roleId))})` : '';
|
|
4916
|
+
who = (this.userDirectory.get(String(userId))?.username || `Utente ${userId}`) + roleSuffix;
|
|
4917
|
+
}
|
|
4918
|
+
else {
|
|
4919
|
+
who = roleId > 0 ? this.roleLabel(roleId) : 'Tutti';
|
|
4920
|
+
}
|
|
4900
4921
|
const allowed = Number(a?.muamview || 0) === 1;
|
|
4901
4922
|
return `${esc(who)} <span style="color:${allowed ? '#4ade80' : '#f87171'}">${allowed ? '✓' : '✗'}</span>`;
|
|
4902
4923
|
});
|
|
@@ -4932,8 +4953,7 @@ class WorkflowDesignerComponent {
|
|
|
4932
4953
|
if (type === 'action') {
|
|
4933
4954
|
const caption = this.resolveActionButtonCaption(node);
|
|
4934
4955
|
const typeLabel = this.getActionTypeVisualLabel(Number(node.workflowActionTypeId), String(node.workflowActionType || ''));
|
|
4935
|
-
lines.push(`<b>${esc(caption || typeLabel)}</b
|
|
4936
|
-
lines.push(`Tipo: ${esc(typeLabel)}`);
|
|
4956
|
+
lines.push(`<b>${esc(caption || typeLabel)}</b>`, `Tipo: ${esc(typeLabel)}`);
|
|
4937
4957
|
return lines.join('<br>');
|
|
4938
4958
|
}
|
|
4939
4959
|
if (type === 'start') {
|
|
@@ -4974,7 +4994,10 @@ class WorkflowDesignerComponent {
|
|
|
4974
4994
|
};
|
|
4975
4995
|
const row = (k, v) => `<tr><th style="${S.th}">${k}</th><td style="${S.td}">${esc2(v)}</td></tr>`;
|
|
4976
4996
|
const branches = (Array.isArray(cfg.branches) ? cfg.branches : [])
|
|
4977
|
-
.map((b, i) =>
|
|
4997
|
+
.map((b, i) => {
|
|
4998
|
+
const assigneeSuffix = b?.assignee_user_id ? ` → utente ${b.assignee_user_id}` : '';
|
|
4999
|
+
return row(`Task ${i + 1}`, `${b?.caption || ''}${assigneeSuffix}`);
|
|
5000
|
+
})
|
|
4978
5001
|
.join('');
|
|
4979
5002
|
return `<div style="min-width:220px"><div style="font-size:12px;margin-bottom:2px"><b>Split ∥ — task paralleli</b></div>`
|
|
4980
5003
|
+ `<table style="${S.table}"><tbody>`
|
|
@@ -5027,9 +5050,15 @@ class WorkflowDesignerComponent {
|
|
|
5027
5050
|
td: 'padding:1px 6px 1px 0;color:#e2e8f0;white-space:nowrap',
|
|
5028
5051
|
tdc: 'text-align:center;padding:1px 5px'
|
|
5029
5052
|
};
|
|
5030
|
-
const cell = (v) =>
|
|
5031
|
-
|
|
5032
|
-
|
|
5053
|
+
const cell = (v) => {
|
|
5054
|
+
if (v === true) {
|
|
5055
|
+
return `<td style="${S.tdc};color:#4ade80">✓</td>`;
|
|
5056
|
+
}
|
|
5057
|
+
if (v === false) {
|
|
5058
|
+
return `<td style="${S.tdc};color:#f87171">✗</td>`;
|
|
5059
|
+
}
|
|
5060
|
+
return `<td style="${S.tdc};color:#64748b">·</td>`;
|
|
5061
|
+
};
|
|
5033
5062
|
// 1) Header: nome tabella/vista/dashboard
|
|
5034
5063
|
let header;
|
|
5035
5064
|
if (sourceType === 'dashboard') {
|
|
@@ -5038,10 +5067,12 @@ class WorkflowDesignerComponent {
|
|
|
5038
5067
|
else {
|
|
5039
5068
|
const isView = tm.md_is_view === true || tm.md_is_view === 1;
|
|
5040
5069
|
const isStored = tm.md_is_stored === true || tm.md_is_stored === 1;
|
|
5041
|
-
const
|
|
5070
|
+
const storedKind = isStored ? 'Stored' : 'Tabella';
|
|
5071
|
+
const kind = isView ? 'Vista' : storedKind;
|
|
5042
5072
|
const physical = String(tm.md_nome_tabella || route || '').trim();
|
|
5043
5073
|
const routeSuffix = route && route !== physical ? ` <span style="opacity:.6">(route ${esc(route)})</span>` : '';
|
|
5044
|
-
|
|
5074
|
+
const actionSuffix = action ? ` <span style="opacity:.6">[${esc(action)}]</span>` : '';
|
|
5075
|
+
header = `<b>${kind}</b> <span style="color:#93c5fd">${esc(physical)}</span>${routeSuffix}${actionSuffix}`;
|
|
5045
5076
|
}
|
|
5046
5077
|
const rows = [];
|
|
5047
5078
|
// 2) Permessi (matrice V/E/I/D + override) — regola grant-by-default
|
|
@@ -5052,8 +5083,7 @@ class WorkflowDesignerComponent {
|
|
|
5052
5083
|
const denyKeys = ['muat_view', 'muatview', 'muat_edit', 'muatedit', 'muat_insert', 'muatinsert', 'muat_delete', 'muatdelete', 'muac_view', 'muacview', 'muac_editable', 'muaceditable'];
|
|
5053
5084
|
const hasAnyDeny = allPerms.some((p) => denyKeys.some((k) => this.tooltipPermFlag(p, [k]) === false));
|
|
5054
5085
|
if (allPerms.length && ((grantByDefault && hasAnyDeny) || !grantByDefault)) {
|
|
5055
|
-
rows.push(`<tr><td colspan="6" style="${S.sect}">Permessi <span style="font-weight:400;opacity:.6">(${grantByDefault ? 'grant-by-default' : 'deny-by-default'})</span></td></tr>`);
|
|
5056
|
-
rows.push(`<tr><th style="${S.th}">Chi</th><th style="${S.thc}">V</th><th style="${S.thc}">E</th><th style="${S.thc}">I</th><th style="${S.thc}">D</th><th style="${S.th}">Extra</th></tr>`);
|
|
5086
|
+
rows.push(`<tr><td colspan="6" style="${S.sect}">Permessi <span style="font-weight:400;opacity:.6">(${grantByDefault ? 'grant-by-default' : 'deny-by-default'})</span></td></tr>`, `<tr><th style="${S.th}">Chi</th><th style="${S.thc}">V</th><th style="${S.thc}">E</th><th style="${S.thc}">I</th><th style="${S.thc}">D</th><th style="${S.th}">Extra</th></tr>`);
|
|
5057
5087
|
tablePerms.forEach((p) => {
|
|
5058
5088
|
const extra = this.tooltipPermFlag(p, ['muat_override_record_restriction', 'muatoverriderecordrestriction']) === true
|
|
5059
5089
|
? '<span style="color:#fbbf24">override-restriction</span>' : '';
|
|
@@ -5095,8 +5125,7 @@ class WorkflowDesignerComponent {
|
|
|
5095
5125
|
const tableStyles = Array.isArray(bundle.tableStyles) ? bundle.tableStyles : [];
|
|
5096
5126
|
const colStyles = Array.isArray(bundle.columnStyles) ? bundle.columnStyles : [];
|
|
5097
5127
|
if (tableStyles.length || colStyles.length) {
|
|
5098
|
-
rows.push(`<tr><td colspan="6" style="${S.sect}">Stili</td></tr>`);
|
|
5099
|
-
rows.push(`<tr><td colspan="6" style="${S.td}">${tableStyles.length} tabella, ${colStyles.length} colonna</td></tr>`);
|
|
5128
|
+
rows.push(`<tr><td colspan="6" style="${S.sect}">Stili</td></tr>`, `<tr><td colspan="6" style="${S.td}">${tableStyles.length} tabella, ${colStyles.length} colonna</td></tr>`);
|
|
5100
5129
|
}
|
|
5101
5130
|
const body = rows.length ? `<table style="${S.table}"><tbody>${rows.join('')}</tbody></table>` : '';
|
|
5102
5131
|
return `<div style="min-width:220px"><div style="font-size:12px;margin-bottom:2px">${header}</div>${body}</div>`;
|
|
@@ -5125,8 +5154,8 @@ class WorkflowDesignerComponent {
|
|
|
5125
5154
|
return fromMap;
|
|
5126
5155
|
}
|
|
5127
5156
|
const normalized = String(fallbackDescription || '')
|
|
5128
|
-
.
|
|
5129
|
-
.
|
|
5157
|
+
.replaceAll(/\.action/gi, '')
|
|
5158
|
+
.replaceAll('.', ' ')
|
|
5130
5159
|
.trim();
|
|
5131
5160
|
return normalized || 'action';
|
|
5132
5161
|
}
|
|
@@ -5526,9 +5555,17 @@ class WorkflowDesignerComponent {
|
|
|
5526
5555
|
return;
|
|
5527
5556
|
}
|
|
5528
5557
|
const action = String(resp?.action?.value ?? 'notify_role').trim();
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5558
|
+
let targetRaw;
|
|
5559
|
+
if (action === 'notify_role') {
|
|
5560
|
+
targetRaw = resp?.target_role?.value;
|
|
5561
|
+
}
|
|
5562
|
+
else if (action === 'notify') {
|
|
5563
|
+
targetRaw = resp?.target_user?.value;
|
|
5564
|
+
}
|
|
5565
|
+
else {
|
|
5566
|
+
targetRaw = resp?.target_state?.value;
|
|
5567
|
+
}
|
|
5568
|
+
const target = String(targetRaw ?? '').trim();
|
|
5532
5569
|
if (!target) {
|
|
5533
5570
|
WtoolboxService.messageNotificationService?.add?.({
|
|
5534
5571
|
severity: 'error',
|
|
@@ -5865,8 +5902,9 @@ class WorkflowDesignerComponent {
|
|
|
5865
5902
|
const selectedRoleIds = roles
|
|
5866
5903
|
.filter((role) => !!resp?.[`role_${role.id}`]?.value)
|
|
5867
5904
|
.map((role) => role.id);
|
|
5905
|
+
const selectedRolesCsv = selectedRoleIds.map((id) => `role:${id}`).join(',');
|
|
5868
5906
|
const permission = selectedRoleIds.length
|
|
5869
|
-
? `${mode}:${
|
|
5907
|
+
? `${mode}:${selectedRolesCsv}`
|
|
5870
5908
|
: '';
|
|
5871
5909
|
if (!event && !guard && !permission) {
|
|
5872
5910
|
delete connection.workflowTransition;
|
|
@@ -6225,7 +6263,8 @@ class WorkflowDesignerComponent {
|
|
|
6225
6263
|
const tokens = (listMatch ? listMatch[2] : value).split(',').map((x) => x.trim()).filter((x) => !!x);
|
|
6226
6264
|
tokens.forEach((token) => {
|
|
6227
6265
|
const byPrefix = /^role:(\d+)$/i.exec(token);
|
|
6228
|
-
const
|
|
6266
|
+
const numericToken = /^\d+$/.test(token) ? Number(token) : NaN;
|
|
6267
|
+
const id = byPrefix ? Number(byPrefix[1]) : numericToken;
|
|
6229
6268
|
if (Number.isFinite(id)) {
|
|
6230
6269
|
ids.add(id);
|
|
6231
6270
|
return;
|
|
@@ -6455,8 +6494,8 @@ class WorkflowDesignerComponent {
|
|
|
6455
6494
|
}
|
|
6456
6495
|
const x0 = nums[0];
|
|
6457
6496
|
const y0 = nums[1];
|
|
6458
|
-
const x1 = nums
|
|
6459
|
-
const y1 = nums
|
|
6497
|
+
const x1 = nums.at(-2);
|
|
6498
|
+
const y1 = nums.at(-1);
|
|
6460
6499
|
// Back-edge solo se torna indietro in modo significativo (isteresi 24px:
|
|
6461
6500
|
// evita flip-flop sui collegamenti quasi verticali).
|
|
6462
6501
|
if (x1 >= x0 - 24) {
|
|
@@ -6515,7 +6554,7 @@ class WorkflowDesignerComponent {
|
|
|
6515
6554
|
if (!el) {
|
|
6516
6555
|
continue;
|
|
6517
6556
|
}
|
|
6518
|
-
const svg = el.querySelector?.('svg') || el.closest?.('svg');
|
|
6557
|
+
const svg = (el.querySelector?.('svg')) || (el.closest?.('svg'));
|
|
6519
6558
|
if (!svg) {
|
|
6520
6559
|
continue;
|
|
6521
6560
|
}
|
|
@@ -6599,25 +6638,8 @@ class WorkflowDesignerComponent {
|
|
|
6599
6638
|
* Variante drag event di risoluzione id nodo (`node-<id>`) dal path DOM.
|
|
6600
6639
|
*/
|
|
6601
6640
|
getNodeIdFromDragEvent(event) {
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
if (!(target instanceof HTMLElement)) {
|
|
6605
|
-
continue;
|
|
6606
|
-
}
|
|
6607
|
-
const tagName = String(target.tagName || '').toLowerCase();
|
|
6608
|
-
if (tagName.startsWith('node-')) {
|
|
6609
|
-
return tagName.substring(5);
|
|
6610
|
-
}
|
|
6611
|
-
}
|
|
6612
|
-
let element = event.target;
|
|
6613
|
-
while (element) {
|
|
6614
|
-
const tagName = String(element.tagName || '').toLowerCase();
|
|
6615
|
-
if (tagName.startsWith('node-')) {
|
|
6616
|
-
return tagName.substring(5);
|
|
6617
|
-
}
|
|
6618
|
-
element = element.parentElement;
|
|
6619
|
-
}
|
|
6620
|
-
return null;
|
|
6641
|
+
// DragEvent estende MouseEvent: stessa risoluzione `node-<id>` dal path DOM.
|
|
6642
|
+
return this.getNodeIdFromEvent(event);
|
|
6621
6643
|
}
|
|
6622
6644
|
/**
|
|
6623
6645
|
* Apre il popup configurazione route inizializzando i campi
|
|
@@ -6790,7 +6812,7 @@ class WorkflowDesignerComponent {
|
|
|
6790
6812
|
// `key` e' una chiave i18n (es. 'generic.navigation.action'): il p-select
|
|
6791
6813
|
// non ha un pipe translate, quindi traduco qui. Fallback humanizzato
|
|
6792
6814
|
// (rimuove '.action', punti -> spazi) se la traduzione manca.
|
|
6793
|
-
const fallback = key.replace(/\.action$/i, '').
|
|
6815
|
+
const fallback = key.replace(/\.action$/i, '').replaceAll('.', ' ').trim();
|
|
6794
6816
|
return { label: this.t(key, fallback), value: id };
|
|
6795
6817
|
})
|
|
6796
6818
|
.filter((x) => !!x);
|
|
@@ -6905,24 +6927,24 @@ class WorkflowDesignerComponent {
|
|
|
6905
6927
|
// patch SPEGNENDOLI a runtime. IDRATA dai metadata live della route e
|
|
6906
6928
|
// riapplica sopra il patch autorato; le collezioni overlay (azioni,
|
|
6907
6929
|
// permessi, stili, colonne autorate) restano quelle del bundle.
|
|
6908
|
-
const isSlim = !Number.isFinite(Number(existing?.tableMetadata?.md_id));
|
|
6930
|
+
const isSlim = !Number.isFinite(Number((existing)?.tableMetadata?.md_id));
|
|
6909
6931
|
if (isSlim && serializeFromDatasourceIfMissing && this.routeMetadataDs) {
|
|
6910
6932
|
this.routeMetadataDs.hardcodedRoute = route;
|
|
6911
6933
|
this.routeMetadataDs.route.next(route);
|
|
6912
6934
|
await this.routeMetadataDs.getSchemaAndData(true);
|
|
6913
6935
|
const full = this.buildRouteMetadataBundle(route);
|
|
6914
6936
|
if (full) {
|
|
6915
|
-
const existingColumns = Array.isArray(existing.columnMetadata) ? existing.columnMetadata : [];
|
|
6937
|
+
const existingColumns = Array.isArray((existing).columnMetadata) ? (existing).columnMetadata : [];
|
|
6916
6938
|
const hydrated = {
|
|
6917
6939
|
...full,
|
|
6918
|
-
tableMetadata: { ...(full.tableMetadata
|
|
6940
|
+
tableMetadata: { ...(full.tableMetadata), ...(((existing).tableMetadata)) },
|
|
6919
6941
|
columnMetadata: existingColumns.length ? existingColumns : (full.columnMetadata || []),
|
|
6920
|
-
tableActions: existing.tableActions || [],
|
|
6921
|
-
columnActions: existing.columnActions || [],
|
|
6922
|
-
tablePermissions: existing.tablePermissions || [],
|
|
6923
|
-
columnPermissions: existing.columnPermissions || [],
|
|
6924
|
-
tableStyles: existing.tableStyles || [],
|
|
6925
|
-
columnStyles: existing.columnStyles || []
|
|
6942
|
+
tableActions: (existing).tableActions || [],
|
|
6943
|
+
columnActions: (existing).columnActions || [],
|
|
6944
|
+
tablePermissions: (existing).tablePermissions || [],
|
|
6945
|
+
columnPermissions: (existing).columnPermissions || [],
|
|
6946
|
+
tableStyles: (existing).tableStyles || [],
|
|
6947
|
+
columnStyles: (existing).columnStyles || []
|
|
6926
6948
|
};
|
|
6927
6949
|
routeNode.workflowRouteMetadataBundle = this.sanitizeForSerialization(hydrated);
|
|
6928
6950
|
return routeNode.workflowRouteMetadataBundle;
|
|
@@ -7074,9 +7096,9 @@ class WorkflowDesignerComponent {
|
|
|
7074
7096
|
toMetadataSafeName(raw) {
|
|
7075
7097
|
return String(raw || '')
|
|
7076
7098
|
.toLowerCase()
|
|
7077
|
-
.
|
|
7078
|
-
.
|
|
7079
|
-
.
|
|
7099
|
+
.replaceAll(/[^a-z0-9_]+/g, '_')
|
|
7100
|
+
.replaceAll(/_+/g, '_')
|
|
7101
|
+
.replaceAll(/^_+|_+$/g, '');
|
|
7080
7102
|
}
|
|
7081
7103
|
/**
|
|
7082
7104
|
* Attende la disponibilita del `routeMetadataEditor` (render async dialog),
|
|
@@ -7291,7 +7313,8 @@ class WorkflowDesignerComponent {
|
|
|
7291
7313
|
let versions = [];
|
|
7292
7314
|
try {
|
|
7293
7315
|
const res = this.parseMaybeJson(await this.dataSrv.getWorkflowGraphVersions({ user_id: '', graph_key: key }));
|
|
7294
|
-
|
|
7316
|
+
const resAsList = Array.isArray(res) ? res : [];
|
|
7317
|
+
versions = Array.isArray(res?.versions) ? res.versions : resAsList;
|
|
7295
7318
|
}
|
|
7296
7319
|
catch (error) {
|
|
7297
7320
|
WtoolboxService.errorHandler?.handleError?.(error);
|
|
@@ -7382,7 +7405,8 @@ class WorkflowDesignerComponent {
|
|
|
7382
7405
|
}
|
|
7383
7406
|
try {
|
|
7384
7407
|
const res = this.parseMaybeJson(await this.dataSrv.getWorkflowGraphVersions({ user_id: '', graph_key: graphKey }));
|
|
7385
|
-
const
|
|
7408
|
+
const resAsList = Array.isArray(res) ? res : [];
|
|
7409
|
+
const versions = Array.isArray(res?.versions) ? res.versions : resAsList;
|
|
7386
7410
|
let max = 0;
|
|
7387
7411
|
for (const v of versions) {
|
|
7388
7412
|
const n = Number(this.pickFirstDefined(v, ['version_no', 'versionno']) ?? 0);
|
|
@@ -7401,7 +7425,7 @@ class WorkflowDesignerComponent {
|
|
|
7401
7425
|
* usata come candidato `wg_key` per nuovi grafi.
|
|
7402
7426
|
*/
|
|
7403
7427
|
generateWorkflowKey() {
|
|
7404
|
-
const stamp = new Date().toISOString().
|
|
7428
|
+
const stamp = new Date().toISOString().replaceAll(/[-:.TZ]/g, '').slice(0, 14);
|
|
7405
7429
|
const rand = Math.random().toString(36).slice(2, 8);
|
|
7406
7430
|
return `wf_${stamp}_${rand}`;
|
|
7407
7431
|
}
|
|
@@ -7697,9 +7721,9 @@ class WorkflowDesignerComponent {
|
|
|
7697
7721
|
amountField = String(params?.amount_field?.value || '').trim();
|
|
7698
7722
|
}
|
|
7699
7723
|
const resolveTokens = (text) => String(text || '')
|
|
7700
|
-
.
|
|
7701
|
-
.
|
|
7702
|
-
.
|
|
7724
|
+
.replaceAll('$STATE_FIELD', stateField || 'stato')
|
|
7725
|
+
.replaceAll('$APPROVED', approvedValue || 'APPROVATO')
|
|
7726
|
+
.replaceAll('$AMOUNT', amountField || 'importo');
|
|
7703
7727
|
await this.createNewWorkflow();
|
|
7704
7728
|
// Istanziazione nodi (lo start riusa quello creato da createNewWorkflow).
|
|
7705
7729
|
const nodeByKey = new Map();
|
|
@@ -7711,9 +7735,14 @@ class WorkflowDesignerComponent {
|
|
|
7711
7735
|
}
|
|
7712
7736
|
continue;
|
|
7713
7737
|
}
|
|
7714
|
-
|
|
7715
|
-
|
|
7716
|
-
|
|
7738
|
+
let routeConfig;
|
|
7739
|
+
if (spec.type === 'route') {
|
|
7740
|
+
const routeName = spec.route === '$MAIN' ? mainRoute : String(spec.route || '');
|
|
7741
|
+
routeConfig = { routeName, action: String(spec.action || 'list'), sourceType: 'route' };
|
|
7742
|
+
}
|
|
7743
|
+
else if (spec.type === 'condition') {
|
|
7744
|
+
routeConfig = { routeName: '', action: '', conditionExpression: resolveTokens(spec.conditionExpression || '') };
|
|
7745
|
+
}
|
|
7717
7746
|
const actionType = spec.type === 'action' ? (this.getActionTypeById(Number(spec.actionTypeId ?? 5)) || { id: 5, description: 'approve.action' }) : undefined;
|
|
7718
7747
|
const actionScope = spec.type === 'action' ? (this.getActionScopeById(Number(spec.actionScopeId ?? 0)) || { id: 0, description: 'azione_tab' }) : undefined;
|
|
7719
7748
|
const node = await this.addNodeByType(spec.type, spec.x, spec.y, routeConfig, actionType, actionScope, null, false);
|
|
@@ -7918,7 +7947,7 @@ class WorkflowDesignerComponent {
|
|
|
7918
7947
|
return;
|
|
7919
7948
|
}
|
|
7920
7949
|
const encodedKey = encodeURIComponent(key);
|
|
7921
|
-
const base = new URL(document.baseURI ||
|
|
7950
|
+
const base = new URL(document.baseURI || globalThis.location.origin);
|
|
7922
7951
|
const target = new URL(`#/workflow-runner/${encodedKey}`, base);
|
|
7923
7952
|
window.open(target.toString(), '_blank');
|
|
7924
7953
|
}
|
|
@@ -8105,19 +8134,21 @@ class WorkflowDesignerComponent {
|
|
|
8105
8134
|
if (type === 'start' && this.findStartNode()) {
|
|
8106
8135
|
continue;
|
|
8107
8136
|
}
|
|
8108
|
-
|
|
8109
|
-
|
|
8137
|
+
let routeConfig;
|
|
8138
|
+
if (type === 'route') {
|
|
8139
|
+
routeConfig = {
|
|
8110
8140
|
routeName: String(item?.route || ''),
|
|
8111
8141
|
action: String(item?.action || '') || 'list',
|
|
8112
8142
|
sourceType: this.getRouteSourceType(item),
|
|
8113
8143
|
dashboardBoardcontent: String(item?.dashboardBoardcontent || ''),
|
|
8114
8144
|
dashboardDatasources: this.sanitizeForSerialization(item?.dashboardDatasources || []) || []
|
|
8115
|
-
}
|
|
8145
|
+
};
|
|
8146
|
+
}
|
|
8147
|
+
else if (type === 'switch') {
|
|
8116
8148
|
// Switch: la config va passata a createNode PRIMA delle connessioni,
|
|
8117
8149
|
// che referenziano gli output `case_<n>`/`else` in sourceOutput.
|
|
8118
|
-
:
|
|
8119
|
-
|
|
8120
|
-
: undefined);
|
|
8150
|
+
routeConfig = { routeName: '', action: '', switchConfig: item?.switchConfig || null };
|
|
8151
|
+
}
|
|
8121
8152
|
const actionType = type === 'action' && Number.isInteger(Number(item?.actionTypeId))
|
|
8122
8153
|
? this.getActionTypeById(Number(item?.actionTypeId))
|
|
8123
8154
|
: undefined;
|
|
@@ -8424,7 +8455,7 @@ class WorkflowDesignerComponent {
|
|
|
8424
8455
|
const attempts = 4;
|
|
8425
8456
|
for (let i = 0; i < attempts; i++) {
|
|
8426
8457
|
this.editor.getNodes().forEach((node) => this.applyNodeVisualState(node));
|
|
8427
|
-
await Promise.all(this.editor.getNodes().map((node) => this.area?.update('node', String(node.id))
|
|
8458
|
+
await Promise.all(this.editor.getNodes().map((node) => this.area?.update('node', String(node.id)) ?? Promise.resolve()));
|
|
8428
8459
|
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
8429
8460
|
}
|
|
8430
8461
|
}
|
|
@@ -8483,11 +8514,10 @@ class WorkflowDesignerComponent {
|
|
|
8483
8514
|
}
|
|
8484
8515
|
const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
8485
8516
|
const connections = Array.isArray(graph?.connections) ? graph.connections : [];
|
|
8517
|
+
const routeMetadataCamel = Array.isArray(root?.routeMetadata) ? root.routeMetadata : [];
|
|
8486
8518
|
const routeMetadata = Array.isArray(root?.route_metadata)
|
|
8487
8519
|
? root.route_metadata
|
|
8488
|
-
:
|
|
8489
|
-
? root.routeMetadata
|
|
8490
|
-
: [];
|
|
8520
|
+
: routeMetadataCamel;
|
|
8491
8521
|
const graphName = String(this.pickFirstDefined(root, ['graph_name', 'wg_name', 'graphname']) || '');
|
|
8492
8522
|
return {
|
|
8493
8523
|
graph: { nodes, connections },
|
|
@@ -8600,7 +8630,7 @@ class WorkflowDesignerComponent {
|
|
|
8600
8630
|
if (!key || key === '__proto__' || key === 'constructor' || transientSerializationKeys.has(key)) {
|
|
8601
8631
|
return;
|
|
8602
8632
|
}
|
|
8603
|
-
const field = input[key];
|
|
8633
|
+
const field = (input)[key];
|
|
8604
8634
|
if (typeof field === 'function') {
|
|
8605
8635
|
return;
|
|
8606
8636
|
}
|
|
@@ -8726,9 +8756,9 @@ class WorkflowDesignerComponent {
|
|
|
8726
8756
|
const route = String(metaInfo?.tableMetadata?.md_route_name || routeFallback || '').trim();
|
|
8727
8757
|
const tableMetadata = this.sanitizeForSerialization(metaInfo.tableMetadata || {});
|
|
8728
8758
|
const columnMetadata = this.sanitizeForSerialization(metaInfo.columnMetadata || []) || [];
|
|
8729
|
-
const tableActions = this.sanitizeForSerialization(metaInfo.tableMetadata?._Metadati_Custom_Actions_Tabelles || []) || [];
|
|
8730
|
-
const tablePermissions = this.sanitizeForSerialization(metaInfo.tableMetadata?._Metadati_Utenti_Autorizzazioni_Tabelles || []) || [];
|
|
8731
|
-
const tableStyles = this.sanitizeForSerialization(metaInfo.tableMetadata?._Metadati_UI_Stili_Tabelles || []) || [];
|
|
8759
|
+
const tableActions = this.sanitizeForSerialization((metaInfo.tableMetadata)?._Metadati_Custom_Actions_Tabelles || []) || [];
|
|
8760
|
+
const tablePermissions = this.sanitizeForSerialization((metaInfo.tableMetadata)?._Metadati_Utenti_Autorizzazioni_Tabelles || []) || [];
|
|
8761
|
+
const tableStyles = this.sanitizeForSerialization((metaInfo.tableMetadata)?._Metadati_UI_Stili_Tabelles || []) || [];
|
|
8732
8762
|
const columnActions = (columnMetadata || []).filter((x) => String(x?.mc_ui_column_type || '') === 'button');
|
|
8733
8763
|
const columnPermissions = (columnMetadata || []).flatMap((x) => Array.isArray(x?._Metadati_Utenti_Autorizzazioni_Colonnes) ? x._Metadati_Utenti_Autorizzazioni_Colonnes : []);
|
|
8734
8764
|
const columnStyles = (columnMetadata || []).flatMap((x) => Array.isArray(x?._Metadati_UI_Stili_Colonnes) ? x._Metadati_UI_Stili_Colonnes : []);
|
|
@@ -9002,7 +9032,7 @@ class WorkflowDesignerComponent {
|
|
|
9002
9032
|
}
|
|
9003
9033
|
const normalized = this.sanitizeForSerialization(record) || {};
|
|
9004
9034
|
const originalNormalized = this.sanitizeForSerialization(original) || {};
|
|
9005
|
-
const normalizeKey = (key) => String(key || '').toLowerCase().
|
|
9035
|
+
const normalizeKey = (key) => String(key || '').toLowerCase().replaceAll(/[^a-z0-9]/g, '');
|
|
9006
9036
|
const forcedEditorKey = normalizeKey(String(editorKey || ''));
|
|
9007
9037
|
const readNumeric = (keys) => {
|
|
9008
9038
|
const source = this.pickFirstDefined(normalized, keys) ?? this.pickFirstDefined(originalNormalized, keys);
|
|
@@ -9032,7 +9062,6 @@ class WorkflowDesignerComponent {
|
|
|
9032
9062
|
const columnStyleId = readNumeric(['musc_id', 'muscid']);
|
|
9033
9063
|
if (forcedEditorKey === normalizeKey('musc_id') || (Number.isFinite(columnStyleId) && columnStyleId !== 0)) {
|
|
9034
9064
|
bundle.columnStyles = (bundle.columnStyles || []).filter((x) => Number(x?.musc_id || 0) !== Number(columnStyleId || 0));
|
|
9035
|
-
return;
|
|
9036
9065
|
}
|
|
9037
9066
|
}
|
|
9038
9067
|
isLinkedActionNode(node, routeNodeId, targetType, targetId) {
|
|
@@ -9090,7 +9119,7 @@ class WorkflowDesignerComponent {
|
|
|
9090
9119
|
return result;
|
|
9091
9120
|
}
|
|
9092
9121
|
Object.keys(raw).forEach((key) => {
|
|
9093
|
-
result[key] = this.unwrapEditorFieldValue(raw[key]);
|
|
9122
|
+
result[key] = this.unwrapEditorFieldValue((raw)[key]);
|
|
9094
9123
|
});
|
|
9095
9124
|
return result;
|
|
9096
9125
|
}
|
|
@@ -9152,7 +9181,7 @@ class WorkflowDesignerComponent {
|
|
|
9152
9181
|
}
|
|
9153
9182
|
const normalized = this.sanitizeForSerialization(record) || {};
|
|
9154
9183
|
const originalNormalized = this.sanitizeForSerialization(original) || {};
|
|
9155
|
-
const normalizeKey = (key) => String(key || '').toLowerCase().
|
|
9184
|
+
const normalizeKey = (key) => String(key || '').toLowerCase().replaceAll(/[^a-z0-9]/g, '');
|
|
9156
9185
|
const keySet = new Set([
|
|
9157
9186
|
...Object.keys(normalized || {}).map((k) => normalizeKey(k)),
|
|
9158
9187
|
...Object.keys(originalNormalized || {}).map((k) => normalizeKey(k))
|
|
@@ -9190,7 +9219,7 @@ class WorkflowDesignerComponent {
|
|
|
9190
9219
|
|| hasAnyKey(['buttoncaption', 'mdactiontype', 'mdactionscope']);
|
|
9191
9220
|
const forcedEditorKey = normalizeKey(String(editorKey || ''));
|
|
9192
9221
|
if (forcedEditorKey === normalizeKey('must_id')) {
|
|
9193
|
-
const row =
|
|
9222
|
+
const row = { ...normalized };
|
|
9194
9223
|
if (!(Number.isFinite(tableStyleId) && tableStyleId !== 0)) {
|
|
9195
9224
|
row.must_id = this.nextLocalBundleItemId(bundle.tableStyles, 'must_id');
|
|
9196
9225
|
}
|
|
@@ -9198,7 +9227,7 @@ class WorkflowDesignerComponent {
|
|
|
9198
9227
|
return;
|
|
9199
9228
|
}
|
|
9200
9229
|
if (forcedEditorKey === normalizeKey('musc_id')) {
|
|
9201
|
-
const row =
|
|
9230
|
+
const row = { ...normalized };
|
|
9202
9231
|
if (!(Number.isFinite(columnStyleId) && columnStyleId !== 0)) {
|
|
9203
9232
|
row.musc_id = this.nextLocalBundleItemId(bundle.columnStyles, 'musc_id');
|
|
9204
9233
|
}
|
|
@@ -9206,7 +9235,7 @@ class WorkflowDesignerComponent {
|
|
|
9206
9235
|
return;
|
|
9207
9236
|
}
|
|
9208
9237
|
if (forcedEditorKey === normalizeKey('muat_id')) {
|
|
9209
|
-
const row =
|
|
9238
|
+
const row = { ...normalized };
|
|
9210
9239
|
if (!(Number.isFinite(tablePermissionId) && tablePermissionId !== 0)) {
|
|
9211
9240
|
row.muat_id = this.nextLocalBundleItemId(bundle.tablePermissions, 'muat_id');
|
|
9212
9241
|
}
|
|
@@ -9214,7 +9243,7 @@ class WorkflowDesignerComponent {
|
|
|
9214
9243
|
return;
|
|
9215
9244
|
}
|
|
9216
9245
|
if (forcedEditorKey === normalizeKey('muac_id')) {
|
|
9217
|
-
const row =
|
|
9246
|
+
const row = { ...normalized };
|
|
9218
9247
|
if (!(Number.isFinite(columnPermissionId) && columnPermissionId !== 0)) {
|
|
9219
9248
|
row.muac_id = this.nextLocalBundleItemId(bundle.columnPermissions, 'muac_id');
|
|
9220
9249
|
}
|
|
@@ -9222,7 +9251,7 @@ class WorkflowDesignerComponent {
|
|
|
9222
9251
|
return;
|
|
9223
9252
|
}
|
|
9224
9253
|
if ((Number.isFinite(tableActionId) && tableActionId !== 0) || looksLikeTableAction) {
|
|
9225
|
-
const row =
|
|
9254
|
+
const row = { ...normalized };
|
|
9226
9255
|
if (!(Number.isFinite(tableActionId) && tableActionId !== 0)) {
|
|
9227
9256
|
row.Id = this.nextLocalBundleItemId(bundle.tableActions, 'Id');
|
|
9228
9257
|
}
|
|
@@ -9230,7 +9259,7 @@ class WorkflowDesignerComponent {
|
|
|
9230
9259
|
return;
|
|
9231
9260
|
}
|
|
9232
9261
|
if ((Number.isFinite(tablePermissionId) && tablePermissionId !== 0) || looksLikeTablePermission) {
|
|
9233
|
-
const row =
|
|
9262
|
+
const row = { ...normalized };
|
|
9234
9263
|
if (!(Number.isFinite(tablePermissionId) && tablePermissionId !== 0)) {
|
|
9235
9264
|
row.muat_id = this.nextLocalBundleItemId(bundle.tablePermissions, 'muat_id');
|
|
9236
9265
|
}
|
|
@@ -9238,7 +9267,7 @@ class WorkflowDesignerComponent {
|
|
|
9238
9267
|
return;
|
|
9239
9268
|
}
|
|
9240
9269
|
if ((Number.isFinite(columnPermissionId) && columnPermissionId !== 0) || looksLikeColumnPermission) {
|
|
9241
|
-
const row =
|
|
9270
|
+
const row = { ...normalized };
|
|
9242
9271
|
if (!(Number.isFinite(columnPermissionId) && columnPermissionId !== 0)) {
|
|
9243
9272
|
row.muac_id = this.nextLocalBundleItemId(bundle.columnPermissions, 'muac_id');
|
|
9244
9273
|
}
|
|
@@ -9246,7 +9275,7 @@ class WorkflowDesignerComponent {
|
|
|
9246
9275
|
return;
|
|
9247
9276
|
}
|
|
9248
9277
|
if ((Number.isFinite(tableStyleId) && tableStyleId !== 0) || looksLikeTableStyle) {
|
|
9249
|
-
const row =
|
|
9278
|
+
const row = { ...normalized };
|
|
9250
9279
|
if (!(Number.isFinite(tableStyleId) && tableStyleId !== 0)) {
|
|
9251
9280
|
row.must_id = this.nextLocalBundleItemId(bundle.tableStyles, 'must_id');
|
|
9252
9281
|
}
|
|
@@ -9254,7 +9283,7 @@ class WorkflowDesignerComponent {
|
|
|
9254
9283
|
return;
|
|
9255
9284
|
}
|
|
9256
9285
|
if ((Number.isFinite(columnStyleId) && columnStyleId !== 0) || looksLikeColumnStyle) {
|
|
9257
|
-
const row =
|
|
9286
|
+
const row = { ...normalized };
|
|
9258
9287
|
if (!(Number.isFinite(columnStyleId) && columnStyleId !== 0)) {
|
|
9259
9288
|
row.musc_id = this.nextLocalBundleItemId(bundle.columnStyles, 'musc_id');
|
|
9260
9289
|
}
|
|
@@ -9267,7 +9296,7 @@ class WorkflowDesignerComponent {
|
|
|
9267
9296
|
return;
|
|
9268
9297
|
}
|
|
9269
9298
|
if (Number.isFinite(mdId) && mdId > 0) {
|
|
9270
|
-
bundle.tableMetadata =
|
|
9299
|
+
bundle.tableMetadata = { ...bundle.tableMetadata, ...normalized };
|
|
9271
9300
|
}
|
|
9272
9301
|
}
|
|
9273
9302
|
/**
|
|
@@ -9296,7 +9325,7 @@ class WorkflowDesignerComponent {
|
|
|
9296
9325
|
}
|
|
9297
9326
|
const idx = list.findIndex((x) => String(x?.[idKey] || '').trim() === targetId);
|
|
9298
9327
|
if (idx >= 0) {
|
|
9299
|
-
list[idx] =
|
|
9328
|
+
list[idx] = { ...list[idx], ...record };
|
|
9300
9329
|
}
|
|
9301
9330
|
else {
|
|
9302
9331
|
list.push(record);
|
|
@@ -9344,7 +9373,7 @@ class WorkflowDesignerComponent {
|
|
|
9344
9373
|
buildMetaInfoFromRouteMetadataBundle(bundleInput, route, seedMetaInfo) {
|
|
9345
9374
|
const bundle = this.sanitizeForSerialization(bundleInput) || this.createEmptyRouteBundle(route);
|
|
9346
9375
|
const metaInfo = this.sanitizeForSerialization(seedMetaInfo || {}) || {};
|
|
9347
|
-
const tableMetadata =
|
|
9376
|
+
const tableMetadata = { ...metaInfo.tableMetadata, ...bundle.tableMetadata };
|
|
9348
9377
|
tableMetadata.md_route_name = route;
|
|
9349
9378
|
tableMetadata._Metadati_Custom_Actions_Tabelles = this.sanitizeForSerialization(bundle.tableActions || []);
|
|
9350
9379
|
tableMetadata._Metadati_Utenti_Autorizzazioni_Tabelles = this.sanitizeForSerialization(bundle.tablePermissions || []);
|
|
@@ -9387,10 +9416,11 @@ class WorkflowDesignerComponent {
|
|
|
9387
9416
|
]);
|
|
9388
9417
|
return cloned;
|
|
9389
9418
|
});
|
|
9390
|
-
return
|
|
9419
|
+
return {
|
|
9420
|
+
...metaInfo,
|
|
9391
9421
|
tableMetadata,
|
|
9392
9422
|
columnMetadata
|
|
9393
|
-
}
|
|
9423
|
+
};
|
|
9394
9424
|
}
|
|
9395
9425
|
updateDashboardBoardcontentMetadata(boardcontentRaw, uniqueName, route, bundleInput) {
|
|
9396
9426
|
const parsed = this.parseMaybeJson(boardcontentRaw);
|
|
@@ -9434,13 +9464,13 @@ class WorkflowDesignerComponent {
|
|
|
9434
9464
|
*/
|
|
9435
9465
|
tf(resource, fallback, ...args) {
|
|
9436
9466
|
const template = this.t(resource, fallback);
|
|
9437
|
-
return template.
|
|
9467
|
+
return template.replaceAll(/\{(\d+)\}/g, (match, idx) => {
|
|
9438
9468
|
const value = args[Number(idx)];
|
|
9439
9469
|
return value !== undefined && value !== null ? String(value) : match;
|
|
9440
9470
|
});
|
|
9441
9471
|
}
|
|
9442
9472
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WorkflowDesignerComponent, deps: [{ token: i0.Injector }, { token: DataProviderService }, { token: ChatbotHostRegistryService }], target: i0.ɵɵFactoryTarget.Component });
|
|
9443
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: WorkflowDesignerComponent, isStandalone: true, selector: "wuic-workflow-designer", outputs: { workflowChange: "workflowChange" }, viewQueries: [{ propertyName: "workflowCanvasRef", first: true, predicate: ["workflowCanvas"], descendants: true, static: true }, { propertyName: "primeContextMenu", first: true, predicate: ["primeContextMenu"], descendants: true }, { propertyName: "routeMetadataDs", first: true, predicate: ["routeMetadataDs"], descendants: true }, { propertyName: "startMenuDs", first: true, predicate: ["startMenuDs"], descendants: true }, { propertyName: "menuAuthDs", first: true, predicate: ["menuAuthDs"], descendants: true }, { propertyName: "routeMetadataEditor", first: true, predicate: ["routeMetadataEditor"], descendants: true }, { propertyName: "actionMetadataEditor", first: true, predicate: ["actionMetadataEditor"], descendants: true }], ngImport: i0, template: "<div class=\"workflow-designer\">\n <div class=\"workflow-toolbar\">\n <div class=\"workflow-current-graph\">{{ currentGraphCaption }}</div>\n <!-- Filtro \"anteprima autorizzazioni\": simula cosa vede un ruolo/utente.\n Opzioni dai principal citati nel grafo (permessi bundle + permission\n transizioni); il dropdown utenti appare solo se esistono auth\n per-utente. Selezione vuota = mostra tutto. -->\n @if (authFilterRoleOptions.length > 1) {\n <div class=\"workflow-toolbar-filter\">\n <p-select\n [options]=\"authFilterRoleOptions\"\n [(ngModel)]=\"authFilterRoleId\"\n (onChange)=\"onAuthFilterChanged('role')\"\n appendTo=\"body\"\n data-testid=\"wf-auth-filter-role\" />\n </div>\n }\n @if (authFilterUserOptions.length > 1) {\n <div class=\"workflow-toolbar-filter\">\n <p-select\n [options]=\"authFilterUserOptions\"\n [(ngModel)]=\"authFilterUserId\"\n (onChange)=\"onAuthFilterChanged('user')\"\n appendTo=\"body\"\n data-testid=\"wf-auth-filter-user\" />\n </div>\n }\n <div class=\"workflow-toolbar-menu-group\">\n <button type=\"button\" (click)=\"graphActionsMenu.toggle($event)\">\n Azioni grafo\n </button>\n <p-menu #graphActionsMenu [popup]=\"true\" [model]=\"graphActionsMenuItems\" appendTo=\"body\"></p-menu>\n </div>\n <div class=\"workflow-toolbar-menu-group\">\n <button type=\"button\" (click)=\"runnerActionsMenu.toggle($event)\" [disabled]=\"!canOpenWorkflowRunner\">\n Runner\n </button>\n <p-menu #runnerActionsMenu [popup]=\"true\" [model]=\"runnerActionsMenuItems\" appendTo=\"body\"></p-menu>\n </div>\n </div>\n\n <aside class=\"workflow-palette\">\n <div class=\"workflow-palette-title\">{{ 'workflow.palette' | translate }}</div>\n <div class=\"workflow-palette-list\">\n @for (item of paletteNodes; track item) {\n <div\n class=\"workflow-palette-item\"\n [ngClass]=\"{\n 'workflow-palette-item-route': item.type === 'route',\n 'workflow-palette-item-action': item.type === 'action',\n 'workflow-palette-item-start': item.type === 'start',\n 'workflow-palette-item-condition': item.type === 'condition',\n 'workflow-palette-item-end': item.type === 'end',\n 'workflow-palette-item-disabled': !isPaletteNodeEnabled(item)\n }\"\n [attr.draggable]=\"isPaletteNodeEnabled(item) ? 'true' : 'false'\"\n (dragstart)=\"onPaletteDragStart($event, item)\"\n [pTooltip]=\"item.tooltip || ''\"\n [escape]=\"false\"\n tooltipPosition=\"right\"\n [tooltipStyleClass]=\"'workflow-palette-tooltip'\">\n <div class=\"workflow-palette-item-title\">{{ item.label }}</div>\n @if (item.type === 'route') {\n <div class=\"workflow-palette-item-badge\">{{ 'workflow.badge.route' | translate }}</div>\n }\n @if (item.type === 'action') {\n <div class=\"workflow-palette-item-badge\">{{ 'workflow.badge.action_scope' | translate }}</div>\n }\n <div class=\"workflow-palette-item-description\">{{ item.description }}</div>\n </div>\n }\n </div>\n </aside>\n\n <section\n #workflowCanvas\n class=\"workflow-canvas\"\n (dragover)=\"onCanvasDragOver($event)\"\n (drop)=\"onCanvasDrop($event)\"\n (contextmenu)=\"onCanvasContextMenu($event)\"\n (click)=\"onCanvasClick()\">\n @if (showEmptyGraphChecklist) {\n <div class=\"workflow-canvas-checklist\">\n <div class=\"workflow-canvas-checklist-title\">{{ hintChecklistTitle }}</div>\n <ol>\n @for (step of hintChecklistStepStates; track $index) {\n <li [ngClass]=\"{ 'workflow-canvas-checklist-done': step.done }\">{{ step.text }}</li>\n }\n </ol>\n @if (showChecklistTemplateLink) {\n <button type=\"button\" class=\"workflow-canvas-checklist-link\" (click)=\"createWorkflowFromTemplate()\">\n {{ hintOrTemplateLabel }}\n </button>\n }\n </div>\n }\n </section>\n <p-contextMenu\n #primeContextMenu\n [model]=\"contextMenuItems\"\n appendTo=\"body\"\n [autoZIndex]=\"true\"\n [baseZIndex]=\"13000\">\n </p-contextMenu>\n</div>\n\n<p-dialog\n [header]=\"'Riapri grafo'\"\n [(visible)]=\"reopenWorkflowDialogVisible\"\n [modal]=\"true\"\n [closable]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [appendTo]=\"'body'\"\n [style]=\"{ width: '34rem' }\"\n (onHide)=\"cancelReopenWorkflowDialog()\">\n <div class=\"route-popup-form\">\n <label for=\"workflow-reopen-select\">Grafi esistenti</label>\n <p-select\n inputId=\"workflow-reopen-select\"\n [options]=\"savedGraphOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"reopenDialogSelectedGraphKey\"\n [filter]=\"true\"\n [showClear]=\"true\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"cancelReopenWorkflowDialog()\">{{ 'cancel' | translate }}</button>\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"confirmReopenWorkflowDialog()\"\n [disabled]=\"!reopenDialogSelectedGraphKey || loadingWorkflow\">Riapri</button>\n </div>\n </div>\n</p-dialog>\n\n<div style=\"display:none\">\n <wuic-data-source #routeMetadataDs [hardcodedRoute]=\"routeMetadataRoute\"></wuic-data-source>\n <wuic-data-source #startMenuDs [hardcodedRoute]=\"' metadati menu'\"></wuic-data-source>\n <wuic-data-source #menuAuthDs [hardcodedRoute]=\"' mtdt tnt trizzazioni menus'\"></wuic-data-source>\n @if (routeMetadataDs) {\n <wuic-metadata-editor\n #actionMetadataEditor\n [hardcodedDatasource]=\"routeMetadataDs!\"\n [saveCallback]=\"routeMetadataSaveCallback\"\n [hideReports]=\"true\"\n [hideRelatedTableActions]=\"true\"\n [hideRelatedColumnActions]=\"true\">\n </wuic-metadata-editor>\n }\n</div>\n\n<p-dialog\n [header]=\"'workflow.configure_route' | translate\"\n [(visible)]=\"routePopupVisible\"\n [modal]=\"true\"\n [closable]=\"false\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [style]=\"{ width: '32rem' }\">\n <div class=\"route-popup-form\">\n <label for=\"workflow-route-source-select\">Sorgente nodo</label>\n <p-select\n inputId=\"workflow-route-source-select\"\n [options]=\"routeSourceOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"selectedRouteSourceType\"\n (ngModelChange)=\"onRouteSourceTypeChanged()\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n\n @if (selectedRouteSourceType === 'route') {\n <label for=\"workflow-route-select\">{{ 'workflow.route' | translate }}</label>\n <p-autoComplete\n inputId=\"workflow-route-select\"\n [(ngModel)]=\"selectedRouteName\"\n [suggestions]=\"filteredRouteOptions\"\n [forceSelection]=\"true\"\n [dropdown]=\"true\"\n dropdownMode=\"current\"\n [optionLabel]=\"'label'\"\n [optionValue]=\"'value'\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\"\n (completeMethod)=\"filterRouteOptions($event)\" />\n <label for=\"workflow-action-select\">{{ 'workflow.action' | translate }}</label>\n <p-select\n inputId=\"workflow-action-select\"\n [options]=\"routeActionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"selectedRouteAction\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n } @else {\n <label for=\"workflow-dashboard-select\">Dashboard</label>\n <p-autoComplete\n inputId=\"workflow-dashboard-select\"\n [(ngModel)]=\"selectedDashboardRoute\"\n [suggestions]=\"filteredDashboardOptions\"\n [forceSelection]=\"true\"\n [dropdown]=\"true\"\n dropdownMode=\"current\"\n [optionLabel]=\"'label'\"\n [optionValue]=\"'value'\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\"\n (completeMethod)=\"filterDashboardOptions($event)\" />\n }\n\n\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"cancelRouteDrop()\">{{ 'cancel' | translate }}</button>\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"confirmRouteDrop()\"\n [disabled]=\"selectedRouteSourceType === 'dashboard' ? !selectedDashboardRoute : (!selectedRouteName || !selectedRouteAction)\">{{ 'confirmation' | translate }}</button>\n </div>\n </div>\n</p-dialog>\n\n<p-dialog\n [header]=\"'workflow.metadata_route' | translate\"\n [(visible)]=\"routeMetadataDialogVisible\"\n [modal]=\"true\"\n position=\"top\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [appendTo]=\"'body'\"\n styleClass=\"workflow-route-metadata-dialog\"\n [style]=\"{ width: '78rem', maxHeight: 'calc(100vh - 2rem)' }\"\n [contentStyle]=\"{ overflow: 'visible', maxHeight: 'calc(100vh - 10rem)' }\">\n @if (routeMetadataDialogVisible && routeMetadataDs) {\n <wuic-metadata-editor\n #routeMetadataEditor\n [hardcodedDatasource]=\"routeMetadataDs!\"\n [saveCallback]=\"routeMetadataSaveCallback\"\n [hideReports]=\"true\"\n [hideRelatedTableActions]=\"false\"\n [hideRelatedColumnActions]=\"false\">\n </wuic-metadata-editor>\n }\n</p-dialog>\n\n<p-dialog\n [header]=\"'workflow.configure_action' | translate\"\n [(visible)]=\"actionPopupVisible\"\n [modal]=\"true\"\n [closable]=\"false\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [style]=\"{ width: '32rem' }\">\n <div class=\"route-popup-form\">\n <label for=\"workflow-action-scope-select\">{{ 'workflow.action_scope' | translate }}</label>\n <p-select\n inputId=\"workflow-action-scope-select\"\n [options]=\"actionScopeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"selectedActionScopeId\"\n (onChange)=\"onActionScopeChanged()\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n\n <label for=\"workflow-action-type-select\">{{ 'workflow.action_type' | translate }}</label>\n <p-select\n inputId=\"workflow-action-type-select\"\n [options]=\"visibleActionTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"selectedActionTypeId\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"cancelActionDrop()\">{{ 'cancel' | translate }}</button>\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"confirmActionDrop()\"\n [disabled]=\"selectedActionTypeId === null || selectedActionTypeId === undefined || selectedActionScopeId === null || selectedActionScopeId === undefined\">{{ 'confirmation' | translate }}</button>\n </div>\n </div>\n</p-dialog>\n\n<p-dialog\n [header]=\"'Opzioni workflow'\"\n [(visible)]=\"workflowOptionsDialogVisible\"\n [modal]=\"true\"\n [closable]=\"false\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [style]=\"{ width: '32rem' }\">\n <div class=\"route-popup-form\">\n <label for=\"workflow-options-caption\">Caption menu start</label>\n <input\n id=\"workflow-options-caption\"\n class=\"workflow-options-input\"\n type=\"text\"\n [(ngModel)]=\"workflowOptionsCaption\" />\n\n <label class=\"workflow-options-toggle\">\n <input type=\"checkbox\" [(ngModel)]=\"workflowOptionsInheritMetadata\" />\n <span>Eredita metadati</span>\n </label>\n\n <label class=\"workflow-options-toggle\">\n <input type=\"checkbox\" [(ngModel)]=\"workflowOptionsExclusiveMenu\" />\n <span>Menu esclusivo</span>\n </label>\n\n <label class=\"workflow-options-toggle\">\n <input type=\"checkbox\" [(ngModel)]=\"workflowOptionsShowExit\" />\n <span>Mostra esci</span>\n </label>\n\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"cancelWorkflowOptionsDialog()\">{{ 'cancel' | translate }}</button>\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"confirmWorkflowOptionsDialog()\">{{ 'confirmation' | translate }}</button>\n </div>\n </div>\n</p-dialog>\n\n<!-- Lint del grafo: elenco findings (on-demand \"Valida grafo\" o conferma pre-save).\n Il save non e' mai bloccato: con findings serve la conferma esplicita. -->\n<p-dialog\n [header]=\"lintDialogTitle\"\n [(visible)]=\"lintDialogVisible\"\n [modal]=\"true\"\n [closable]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [appendTo]=\"'body'\"\n [style]=\"{ width: '46rem', maxHeight: '80vh' }\"\n (onHide)=\"onLintDialogClose()\">\n <div class=\"workflow-lint-summary\">\n @if (lintErrorCount) {\n <span class=\"workflow-lint-count workflow-lint-count-error\">\n <i class=\"pi pi-times-circle\"></i> {{ lintErrorCount }} {{ lintErrorsCountLabel }}\n </span>\n }\n @if (lintWarnCount) {\n <span class=\"workflow-lint-count workflow-lint-count-warn\">\n <i class=\"pi pi-exclamation-triangle\"></i> {{ lintWarnCount }} {{ lintWarningsCountLabel }}\n </span>\n }\n </div>\n <ul class=\"workflow-lint-list\">\n @for (finding of lintFindings; track $index) {\n <li\n class=\"workflow-lint-item\"\n [ngClass]=\"finding.severity === 'error' ? 'workflow-lint-item-error' : 'workflow-lint-item-warn'\"\n [class.workflow-lint-item-clickable]=\"!!finding.nodeId\"\n (click)=\"zoomToLintFinding(finding)\">\n <i [class]=\"finding.severity === 'error' ? 'pi pi-times-circle' : 'pi pi-exclamation-triangle'\"></i>\n <span class=\"workflow-lint-code\">{{ finding.code }}</span>\n <span class=\"workflow-lint-message\">{{ finding.message }}</span>\n </li>\n }\n </ul>\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"onLintDialogClose()\">\n {{ lintDialogMode === 'confirm-save' ? ('cancel' | translate) : ('close' | translate) }}\n </button>\n @if (lintDialogMode === 'confirm-save') {\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"onLintDialogSaveAnyway()\">\n {{ lintSaveAnywayLabel }}\n </button>\n }\n </div>\n</p-dialog>\n\n<!-- Guida rapida: legenda tipi nodo (dal nodeRegistry) + glossario workflow. -->\n<p-dialog\n [header]=\"quickGuideTitle\"\n [(visible)]=\"quickGuideDialogVisible\"\n [modal]=\"true\"\n [closable]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [appendTo]=\"'body'\"\n styleClass=\"workflow-quick-guide-dialog\"\n [style]=\"{ width: '52rem', maxHeight: '85vh' }\"\n [contentStyle]=\"{ overflow: 'auto' }\">\n <div class=\"workflow-guide-section-title\">{{ quickGuideLegendTitle }}</div>\n <div class=\"workflow-guide-legend\">\n @for (entry of guideLegendEntries; track entry.type) {\n <div class=\"workflow-guide-legend-item\">\n <span class=\"workflow-guide-legend-chip\" [style.background]=\"entry.background\" [style.borderColor]=\"entry.accent\" [style.color]=\"entry.accent\">\n {{ entry.label }}\n </span>\n <span class=\"workflow-guide-legend-desc\">{{ entry.description }}</span>\n </div>\n }\n </div>\n <div class=\"workflow-guide-section-title\">{{ quickGuideGlossaryTitle }}</div>\n <dl class=\"workflow-guide-glossary\">\n @for (entry of guideGlossaryEntries; track entry.term) {\n <dt>{{ entry.term }}</dt>\n <dd>{{ entry.text }}</dd>\n }\n </dl>\n</p-dialog>\n", styles: [":host{display:block;height:100%}.workflow-designer{display:grid;grid-template-rows:auto 1fr;grid-template-columns:260px 1fr;gap:12px;height:100%;min-height:520px}.workflow-toolbar{grid-column:1 / span 2;display:flex;align-items:center;flex-wrap:wrap;gap:8px;border:1px solid #d5dce6;border-radius:10px;background:#f7f9fc;padding:10px 12px}.workflow-toolbar label{font-size:.82rem;font-weight:600;color:#2f3f58}.workflow-toolbar input{height:30px;border:1px solid #c7d2e2;border-radius:6px;background:#fff;padding:0 8px;min-width:170px}.workflow-toolbar button{height:30px;border:1px solid #2f67d8;border-radius:6px;background:#2f67d8;color:#fff;padding:0 10px;font-size:.82rem;cursor:pointer}.workflow-toolbar button[disabled]{opacity:.6;cursor:not-allowed}.workflow-toolbar-menu-group{display:inline-flex}.workflow-toolbar-filter{display:inline-flex;align-items:center}.workflow-toolbar-filter ::ng-deep .p-select{min-width:170px;font-size:.82rem}.workflow-current-graph{flex:1 1 auto;min-width:240px;font-size:.82rem;font-weight:600;color:#2f3f58}.workflow-palette{border:1px solid #d5dce6;border-radius:10px;background:#f7f9fc;overflow:auto}.workflow-palette-title{padding:10px 12px;font-size:.86rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:#3d4f67;border-bottom:1px solid #d5dce6}.workflow-palette-list{display:flex;flex-direction:column;gap:8px;padding:10px}.workflow-palette-item{border:1px solid #c8d3e2;border-radius:8px;background:#fff;padding:10px;cursor:grab;-webkit-user-select:none;user-select:none}.workflow-palette-item-badge{display:inline-block;margin-top:4px;margin-bottom:4px;padding:2px 7px;border-radius:999px;font-size:.68rem;font-weight:700;letter-spacing:.03em;text-transform:uppercase;background:#e2e8f0;color:#334155}.workflow-palette-item-route{border-color:#93c5fd;background:#eff6ff}.workflow-palette-item-route .workflow-palette-item-badge{background:#dbeafe;color:#1d4ed8}.workflow-palette-item-action{border-color:#c4b5fd;background:#f5f3ff}.workflow-palette-item-action .workflow-palette-item-badge{background:#ede9fe;color:#6d28d9}.workflow-palette-item-start{border-color:#86efac;background:#f0fdf4}.workflow-palette-item-condition{border-color:#99f6e4;background:#f0fdfa}.workflow-palette-item-end{border-color:#fda4af;background:#fff1f2}.workflow-palette-item:active{cursor:grabbing}.workflow-palette-item-disabled{opacity:.6;cursor:not-allowed;filter:grayscale(.2)}:host-context(.theme-dark) .workflow-palette-item-disabled{opacity:.5}.workflow-palette-item-title{font-size:.94rem;font-weight:600;color:#21324a}.workflow-palette-item-description{margin-top:4px;font-size:.82rem;color:#60738f}.workflow-canvas{position:relative;border:1px solid #d5dce6;border-radius:10px;overflow:hidden;background:radial-gradient(circle at 1px 1px,#dbe3ef 1px,transparent 0);background-size:24px 24px;background-color:#f8fbff;user-select:none;-webkit-user-select:none}.workflow-canvas-hint{position:absolute;right:12px;bottom:12px;font-size:.82rem;color:#60738f;background:#ffffffeb;border:1px solid #d5dce6;border-radius:6px;padding:5px 8px}.route-popup-form{display:flex;flex-direction:column;gap:8px}.route-popup-form label{font-size:.85rem;font-weight:600;color:#2f3f58;margin-top:2px}.workflow-options-input{width:100%;height:34px;border:1px solid #c7d2e2;border-radius:6px;background:#fff;padding:0 8px;color:#1f2f49}.workflow-options-toggle{display:flex;align-items:center;gap:8px;font-size:.85rem;font-weight:600;color:#2f3f58;margin-top:2px}.workflow-options-toggle input[type=checkbox]{width:16px;height:16px}.route-popup-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:10px}.route-popup-btn{border:1px solid #c7d2e2;background:#fff;color:#1f2f49;border-radius:6px;padding:7px 12px;font-size:.85rem;cursor:pointer}.route-popup-btn-primary{border-color:#2f67d8;background:#2f67d8;color:#fff}:host ::ng-deep .workflow-route-metadata-dialog.p-dialog{max-height:calc(100vh - 2rem)}:host ::ng-deep .workflow-route-metadata-dialog .p-dialog-content{overflow:visible;max-height:calc(100vh - 10rem)}:host ::ng-deep .workflow-canvas [data-wf-node-type] .node{border:1px solid var(--wf-node-accent, #64748b)!important;background:var(--wf-node-bg, #f8fafc)!important}:host ::ng-deep .workflow-canvas [data-wf-node-type] .title{background:var(--wf-node-accent, #64748b)!important;color:#fff!important;font-weight:700}:host ::ng-deep .workflow-canvas [data-wf-node-type=action][data-wf-action-scope=col] .node{border-style:dashed!important}:host ::ng-deep .workflow-canvas [data-wf-node-type=action][data-wf-action-scope=tab] .node{border-style:solid!important}:host-context(.theme-dark) .workflow-toolbar{border-color:#2a3447;background:#141b27}:host-context(.theme-dark) .workflow-current-graph,:host-context(.theme-dark) .workflow-toolbar label{color:#d8e2f1}:host-context(.theme-dark) .workflow-toolbar input{border-color:#334155;background:#0f1724;color:#e5ecf8}:host-context(.theme-dark) .workflow-toolbar button{border-color:#335fcf;background:#335fcf}:host-context(.theme-dark) .workflow-palette{border-color:#2a3447;background:#141b27}:host-context(.theme-dark) .workflow-palette-title{color:#dbe4f2;border-bottom-color:#2a3447}:host-context(.theme-dark) .workflow-palette-item{border-color:#334155;background:#0f1724}:host-context(.theme-dark) .workflow-palette-item-title{color:#e6edf8}:host-context(.theme-dark) .workflow-palette-item-description{color:#9fb0c7}:host-context(.theme-dark) .workflow-palette-item-badge{background:#273247;color:#c9d7ec}:host-context(.theme-dark) .workflow-palette-item-route{border-color:#3b82f6;background:#0f1f35}:host-context(.theme-dark) .workflow-palette-item-route .workflow-palette-item-badge{background:#1e3a6a;color:#c8ddff}:host-context(.theme-dark) .workflow-palette-item-action{border-color:#8b5cf6;background:#24183d}:host-context(.theme-dark) .workflow-palette-item-action .workflow-palette-item-badge{background:#3a2370;color:#ded1ff}:host-context(.theme-dark) .workflow-palette-item-start{border-color:#22c55e;background:#11281c}:host-context(.theme-dark) .workflow-palette-item-condition{border-color:#14b8a6;background:#0f2726}:host-context(.theme-dark) .workflow-palette-item-end{border-color:#ef4444;background:#30171b}:host-context(.theme-dark) .workflow-canvas{border-color:#2a3447;background:radial-gradient(circle at 1px 1px,#334155 1px,transparent 0);background-size:24px 24px;background-color:#0f1724}:host-context(.theme-dark) .workflow-canvas-hint{color:#b9c8de;background:#0f1724e6;border-color:#334155}:host-context(.theme-dark) .route-popup-form label,:host-context(.theme-dark) .workflow-options-toggle{color:#d8e2f1}:host-context(.theme-dark) .workflow-options-input{border-color:#334155;background:#0f1724;color:#e5ecf8}:host-context(.theme-dark) .route-popup-btn{border-color:#334155;background:#111b2b;color:#d8e2f1}:host-context(.theme-dark) .route-popup-btn-primary{border-color:#335fcf;background:#335fcf;color:#fff}:host-context(.theme-dark) ::ng-deep .p-menu,:host-context(.theme-dark) ::ng-deep .p-contextmenu{background:#121b2b;border-color:#334155;color:#dbe4f2}:host-context(.theme-dark) ::ng-deep .p-menu .p-menu-item-content,:host-context(.theme-dark) ::ng-deep .p-contextmenu .p-menu-item-content{color:#dbe4f2}:host-context(.theme-dark) ::ng-deep .p-menu .p-menu-item-content:hover,:host-context(.theme-dark) ::ng-deep .p-contextmenu .p-menu-item-content:hover{background:#1f2a3d}:host-context(.theme-dark) ::ng-deep .p-dialog{background:#121b2b;border-color:#334155;color:#dbe4f2}:host-context(.theme-dark) ::ng-deep .p-dialog .p-dialog-header,:host-context(.theme-dark) ::ng-deep .p-dialog .p-dialog-content,:host-context(.theme-dark) ::ng-deep .p-dialog .p-dialog-footer{background:#121b2b;color:#dbe4f2;border-color:#334155}.workflow-canvas-checklist{position:absolute;right:18px;bottom:18px;max-width:340px;padding:14px 16px;border:1px solid #cbd5e1;border-radius:10px;background:#fffffff0;color:#334155;font-size:12.5px;line-height:1.5;box-shadow:0 4px 14px #0f172a14;pointer-events:auto;z-index:5}.workflow-canvas-checklist-title{font-weight:700;margin-bottom:6px;color:#0f172a}.workflow-canvas-checklist ol{margin:0 0 8px;padding-left:18px}.workflow-canvas-checklist li{margin:2px 0}.workflow-canvas-checklist-done{text-decoration:line-through;opacity:.55}.workflow-canvas-checklist-link{border:none;background:none;padding:0;color:#2563eb;cursor:pointer;font-size:12.5px;text-decoration:underline}:host-context(.theme-dark) .workflow-canvas-checklist{background:#121b2bf0;border-color:#334155;color:#cbd5e1}:host-context(.theme-dark) .workflow-canvas-checklist-title{color:#e2e8f0}.workflow-lint-summary{display:flex;gap:14px;margin-bottom:10px;font-size:12.5px}.workflow-lint-count{display:inline-flex;align-items:center;gap:6px;font-weight:600}.workflow-lint-count-error{color:#dc2626}.workflow-lint-count-warn{color:#d97706}.workflow-lint-list{list-style:none;margin:0 0 12px;padding:0;max-height:46vh;overflow:auto}.workflow-lint-item{display:flex;align-items:flex-start;gap:8px;padding:7px 8px;border-radius:6px;font-size:12.5px;line-height:1.45}.workflow-lint-item+.workflow-lint-item{margin-top:4px}.workflow-lint-item-error{background:#fef2f2;color:#7f1d1d}.workflow-lint-item-error .pi{color:#dc2626;margin-top:2px}.workflow-lint-item-warn{background:#fffbeb;color:#78350f}.workflow-lint-item-warn .pi{color:#d97706;margin-top:2px}.workflow-lint-item-clickable{cursor:pointer}.workflow-lint-item-clickable:hover{filter:brightness(.97)}.workflow-lint-code{font-family:monospace;font-size:11px;opacity:.75;white-space:nowrap;margin-top:1px}:host-context(.theme-dark) .workflow-lint-item-error{background:#dc26261f;color:#fca5a5}:host-context(.theme-dark) .workflow-lint-item-warn{background:#d977061f;color:#fcd34d}.workflow-guide-section-title{font-weight:700;font-size:13px;margin:10px 0 8px;color:#0f172a}.workflow-guide-legend{display:grid;grid-template-columns:1fr 1fr;gap:8px 18px;margin-bottom:8px}.workflow-guide-legend-item{display:flex;align-items:center;gap:8px;font-size:12.5px}.workflow-guide-legend-chip{display:inline-block;min-width:74px;text-align:center;padding:3px 8px;border:1.5px solid;border-radius:7px;font-weight:700;font-size:11.5px;white-space:nowrap}.workflow-guide-legend-desc{color:#475569;line-height:1.4}.workflow-guide-glossary{margin:0;font-size:12.5px}.workflow-guide-glossary dt{font-weight:700;margin-top:8px;color:#0f172a}.workflow-guide-glossary dd{margin:2px 0 0;color:#475569;line-height:1.5}:host-context(.theme-dark) .workflow-guide-section-title,:host-context(.theme-dark) .workflow-guide-glossary dt{color:#e2e8f0}:host-context(.theme-dark) .workflow-guide-legend-desc,:host-context(.theme-dark) .workflow-guide-glossary dd{color:#94a3b8}::ng-deep .workflow-palette-tooltip .p-tooltip-text{max-width:340px;font-size:12px;line-height:1.45}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i6$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i2$1.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: MenuModule }, { kind: "component", type: i7.Menu, selector: "p-menu", inputs: ["model", "popup", "style", "styleClass", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaLabel", "ariaLabelledBy", "id", "tabindex", "appendTo", "motionOptions"], outputs: ["onShow", "onHide", "onBlur", "onFocus"] }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: i10.ContextMenu, selector: "p-contextMenu, p-contextmenu, p-context-menu", inputs: ["model", "triggerEvent", "target", "global", "style", "styleClass", "autoZIndex", "baseZIndex", "id", "breakpoint", "ariaLabel", "ariaLabelledBy", "pressDelay", "appendTo", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: DataSourceComponent, selector: "wuic-data-source", inputs: ["route", "routeFromRouting", "hardcodedRoute", "autoload", "loading", "changeTracking", "parentRecord", "parentMetaInfo", "parentDatasource", "useComboEndpoint", "comboFormulaLookup", "comboMcId", "comboField", "comboExtraFields", "comboCurrentRecord", "componentRef"] }, { kind: "component", type: MetadataEditorComponent, selector: "wuic-metadata-editor", inputs: ["datasource", "hardcodedDatasource", "saveCallback", "hideReports", "hideRelatedTableActions", "hideRelatedColumnActions"] }, { kind: "pipe", type: i2$2.TranslatePipe, name: "translate" }] });
|
|
9473
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: WorkflowDesignerComponent, isStandalone: true, selector: "wuic-workflow-designer", outputs: { workflowChange: "workflowChange" }, viewQueries: [{ propertyName: "workflowCanvasRef", first: true, predicate: ["workflowCanvas"], descendants: true, static: true }, { propertyName: "primeContextMenu", first: true, predicate: ["primeContextMenu"], descendants: true }, { propertyName: "routeMetadataDs", first: true, predicate: ["routeMetadataDs"], descendants: true }, { propertyName: "startMenuDs", first: true, predicate: ["startMenuDs"], descendants: true }, { propertyName: "menuAuthDs", first: true, predicate: ["menuAuthDs"], descendants: true }, { propertyName: "routeMetadataEditor", first: true, predicate: ["routeMetadataEditor"], descendants: true }, { propertyName: "actionMetadataEditor", first: true, predicate: ["actionMetadataEditor"], descendants: true }], ngImport: i0, template: "<div class=\"workflow-designer\">\n <div class=\"workflow-toolbar\">\n <div class=\"workflow-current-graph\">{{ currentGraphCaption }}</div>\n <!-- Filtro \"anteprima autorizzazioni\": simula cosa vede un ruolo/utente.\n Opzioni dai principal citati nel grafo (permessi bundle + permission\n transizioni); il dropdown utenti appare solo se esistono auth\n per-utente. Selezione vuota = mostra tutto. -->\n @if (authFilterRoleOptions.length > 1) {\n <div class=\"workflow-toolbar-filter\">\n <p-select\n [options]=\"authFilterRoleOptions\"\n [(ngModel)]=\"authFilterRoleId\"\n (onChange)=\"onAuthFilterChanged('role')\"\n appendTo=\"body\"\n data-testid=\"wf-auth-filter-role\" />\n </div>\n }\n @if (authFilterUserOptions.length > 1) {\n <div class=\"workflow-toolbar-filter\">\n <p-select\n [options]=\"authFilterUserOptions\"\n [(ngModel)]=\"authFilterUserId\"\n (onChange)=\"onAuthFilterChanged('user')\"\n appendTo=\"body\"\n data-testid=\"wf-auth-filter-user\" />\n </div>\n }\n <div class=\"workflow-toolbar-menu-group\">\n <button type=\"button\" (click)=\"graphActionsMenu.toggle($event)\">\n Azioni grafo\n </button>\n <p-menu #graphActionsMenu [popup]=\"true\" [model]=\"graphActionsMenuItems\" appendTo=\"body\"></p-menu>\n </div>\n <div class=\"workflow-toolbar-menu-group\">\n <button type=\"button\" (click)=\"runnerActionsMenu.toggle($event)\" [disabled]=\"!canOpenWorkflowRunner\">\n Runner\n </button>\n <p-menu #runnerActionsMenu [popup]=\"true\" [model]=\"runnerActionsMenuItems\" appendTo=\"body\"></p-menu>\n </div>\n </div>\n\n <aside class=\"workflow-palette\">\n <div class=\"workflow-palette-title\">{{ 'workflow.palette' | translate }}</div>\n <div class=\"workflow-palette-list\">\n @for (item of paletteNodes; track item) {\n <div\n class=\"workflow-palette-item\"\n [ngClass]=\"{\n 'workflow-palette-item-route': item.type === 'route',\n 'workflow-palette-item-action': item.type === 'action',\n 'workflow-palette-item-start': item.type === 'start',\n 'workflow-palette-item-condition': item.type === 'condition',\n 'workflow-palette-item-end': item.type === 'end',\n 'workflow-palette-item-disabled': !isPaletteNodeEnabled(item)\n }\"\n [attr.draggable]=\"isPaletteNodeEnabled(item) ? 'true' : 'false'\"\n (dragstart)=\"onPaletteDragStart($event, item)\"\n [pTooltip]=\"item.tooltip || ''\"\n [escape]=\"false\"\n tooltipPosition=\"right\"\n [tooltipStyleClass]=\"'workflow-palette-tooltip'\">\n <div class=\"workflow-palette-item-title\">{{ item.label }}</div>\n @if (item.type === 'route') {\n <div class=\"workflow-palette-item-badge\">{{ 'workflow.badge.route' | translate }}</div>\n }\n @if (item.type === 'action') {\n <div class=\"workflow-palette-item-badge\">{{ 'workflow.badge.action_scope' | translate }}</div>\n }\n <div class=\"workflow-palette-item-description\">{{ item.description }}</div>\n </div>\n }\n </div>\n </aside>\n\n <section\n #workflowCanvas\n class=\"workflow-canvas\"\n (dragover)=\"onCanvasDragOver($event)\"\n (drop)=\"onCanvasDrop($event)\"\n (contextmenu)=\"onCanvasContextMenu($event)\"\n (click)=\"onCanvasClick()\">\n @if (showEmptyGraphChecklist) {\n <div class=\"workflow-canvas-checklist\">\n <div class=\"workflow-canvas-checklist-title\">{{ hintChecklistTitle }}</div>\n <ol>\n @for (step of hintChecklistStepStates; track $index) {\n <li [ngClass]=\"{ 'workflow-canvas-checklist-done': step.done }\">{{ step.text }}</li>\n }\n </ol>\n @if (showChecklistTemplateLink) {\n <button type=\"button\" class=\"workflow-canvas-checklist-link\" (click)=\"createWorkflowFromTemplate()\">\n {{ hintOrTemplateLabel }}\n </button>\n }\n </div>\n }\n </section>\n <p-contextMenu\n #primeContextMenu\n [model]=\"contextMenuItems\"\n appendTo=\"body\"\n [autoZIndex]=\"true\"\n [baseZIndex]=\"13000\">\n </p-contextMenu>\n</div>\n\n<p-dialog\n [header]=\"'Riapri grafo'\"\n [(visible)]=\"reopenWorkflowDialogVisible\"\n [modal]=\"true\"\n [closable]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [appendTo]=\"'body'\"\n [style]=\"{ width: '34rem' }\"\n (onHide)=\"cancelReopenWorkflowDialog()\">\n <div class=\"route-popup-form\">\n <label for=\"workflow-reopen-select\">Grafi esistenti</label>\n <p-select\n inputId=\"workflow-reopen-select\"\n [options]=\"savedGraphOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"reopenDialogSelectedGraphKey\"\n [filter]=\"true\"\n [showClear]=\"true\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"cancelReopenWorkflowDialog()\">{{ 'cancel' | translate }}</button>\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"confirmReopenWorkflowDialog()\"\n [disabled]=\"!reopenDialogSelectedGraphKey || loadingWorkflow\">Riapri</button>\n </div>\n </div>\n</p-dialog>\n\n<div style=\"display:none\">\n <wuic-data-source #routeMetadataDs [hardcodedRoute]=\"routeMetadataRoute\"></wuic-data-source>\n <wuic-data-source #startMenuDs [hardcodedRoute]=\"' metadati menu'\"></wuic-data-source>\n <wuic-data-source #menuAuthDs [hardcodedRoute]=\"' mtdt tnt trizzazioni menus'\"></wuic-data-source>\n @if (routeMetadataDs) {\n <wuic-metadata-editor\n #actionMetadataEditor\n [hardcodedDatasource]=\"routeMetadataDs!\"\n [saveCallback]=\"routeMetadataSaveCallback\"\n [hideReports]=\"true\"\n [hideRelatedTableActions]=\"true\"\n [hideRelatedColumnActions]=\"true\">\n </wuic-metadata-editor>\n }\n</div>\n\n<p-dialog\n [header]=\"'workflow.configure_route' | translate\"\n [(visible)]=\"routePopupVisible\"\n [modal]=\"true\"\n [closable]=\"false\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [style]=\"{ width: '32rem' }\">\n <div class=\"route-popup-form\">\n <label for=\"workflow-route-source-select\">Sorgente nodo</label>\n <p-select\n inputId=\"workflow-route-source-select\"\n [options]=\"routeSourceOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"selectedRouteSourceType\"\n (ngModelChange)=\"onRouteSourceTypeChanged()\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n\n @if (selectedRouteSourceType === 'route') {\n <label for=\"workflow-route-select\">{{ 'workflow.route' | translate }}</label>\n <p-autoComplete\n inputId=\"workflow-route-select\"\n [(ngModel)]=\"selectedRouteName\"\n [suggestions]=\"filteredRouteOptions\"\n [forceSelection]=\"true\"\n [dropdown]=\"true\"\n dropdownMode=\"current\"\n [optionLabel]=\"'label'\"\n [optionValue]=\"'value'\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\"\n (completeMethod)=\"filterRouteOptions($event)\" />\n <label for=\"workflow-action-select\">{{ 'workflow.action' | translate }}</label>\n <p-select\n inputId=\"workflow-action-select\"\n [options]=\"routeActionOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"selectedRouteAction\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n } @else {\n <label for=\"workflow-dashboard-select\">Dashboard</label>\n <p-autoComplete\n inputId=\"workflow-dashboard-select\"\n [(ngModel)]=\"selectedDashboardRoute\"\n [suggestions]=\"filteredDashboardOptions\"\n [forceSelection]=\"true\"\n [dropdown]=\"true\"\n dropdownMode=\"current\"\n [optionLabel]=\"'label'\"\n [optionValue]=\"'value'\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\"\n (completeMethod)=\"filterDashboardOptions($event)\" />\n }\n\n\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"cancelRouteDrop()\">{{ 'cancel' | translate }}</button>\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"confirmRouteDrop()\"\n [disabled]=\"selectedRouteSourceType === 'dashboard' ? !selectedDashboardRoute : (!selectedRouteName || !selectedRouteAction)\">{{ 'confirmation' | translate }}</button>\n </div>\n </div>\n</p-dialog>\n\n<p-dialog\n [header]=\"'workflow.metadata_route' | translate\"\n [(visible)]=\"routeMetadataDialogVisible\"\n [modal]=\"true\"\n position=\"top\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [appendTo]=\"'body'\"\n styleClass=\"workflow-route-metadata-dialog\"\n [style]=\"{ width: '78rem', maxHeight: 'calc(100vh - 2rem)' }\"\n [contentStyle]=\"{ overflow: 'visible', maxHeight: 'calc(100vh - 10rem)' }\">\n @if (routeMetadataDialogVisible && routeMetadataDs) {\n <wuic-metadata-editor\n #routeMetadataEditor\n [hardcodedDatasource]=\"routeMetadataDs!\"\n [saveCallback]=\"routeMetadataSaveCallback\"\n [hideReports]=\"true\"\n [hideRelatedTableActions]=\"false\"\n [hideRelatedColumnActions]=\"false\">\n </wuic-metadata-editor>\n }\n</p-dialog>\n\n<p-dialog\n [header]=\"'workflow.configure_action' | translate\"\n [(visible)]=\"actionPopupVisible\"\n [modal]=\"true\"\n [closable]=\"false\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [style]=\"{ width: '32rem' }\">\n <div class=\"route-popup-form\">\n <label for=\"workflow-action-scope-select\">{{ 'workflow.action_scope' | translate }}</label>\n <p-select\n inputId=\"workflow-action-scope-select\"\n [options]=\"actionScopeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"selectedActionScopeId\"\n (onChange)=\"onActionScopeChanged()\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n\n <label for=\"workflow-action-type-select\">{{ 'workflow.action_type' | translate }}</label>\n <p-select\n inputId=\"workflow-action-type-select\"\n [options]=\"visibleActionTypeOptions\"\n optionLabel=\"label\"\n optionValue=\"value\"\n [(ngModel)]=\"selectedActionTypeId\"\n [style]=\"{ width: '100%' }\"\n appendTo=\"body\" />\n\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"cancelActionDrop()\">{{ 'cancel' | translate }}</button>\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"confirmActionDrop()\"\n [disabled]=\"selectedActionTypeId === null || selectedActionTypeId === undefined || selectedActionScopeId === null || selectedActionScopeId === undefined\">{{ 'confirmation' | translate }}</button>\n </div>\n </div>\n</p-dialog>\n\n<p-dialog\n [header]=\"'Opzioni workflow'\"\n [(visible)]=\"workflowOptionsDialogVisible\"\n [modal]=\"true\"\n [closable]=\"false\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [style]=\"{ width: '32rem' }\">\n <div class=\"route-popup-form\">\n <label for=\"workflow-options-caption\">Caption menu start</label>\n <input\n id=\"workflow-options-caption\"\n class=\"workflow-options-input\"\n type=\"text\"\n [(ngModel)]=\"workflowOptionsCaption\" />\n\n <label class=\"workflow-options-toggle\">\n <input type=\"checkbox\" [(ngModel)]=\"workflowOptionsInheritMetadata\" />\n <span>Eredita metadati</span>\n </label>\n\n <label class=\"workflow-options-toggle\">\n <input type=\"checkbox\" [(ngModel)]=\"workflowOptionsExclusiveMenu\" />\n <span>Menu esclusivo</span>\n </label>\n\n <label class=\"workflow-options-toggle\">\n <input type=\"checkbox\" [(ngModel)]=\"workflowOptionsShowExit\" />\n <span>Mostra esci</span>\n </label>\n\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"cancelWorkflowOptionsDialog()\">{{ 'cancel' | translate }}</button>\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"confirmWorkflowOptionsDialog()\">{{ 'confirmation' | translate }}</button>\n </div>\n </div>\n</p-dialog>\n\n<!-- Lint del grafo: elenco findings (on-demand \"Valida grafo\" o conferma pre-save).\n Il save non e' mai bloccato: con findings serve la conferma esplicita. -->\n<p-dialog\n [header]=\"lintDialogTitle\"\n [(visible)]=\"lintDialogVisible\"\n [modal]=\"true\"\n [closable]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [appendTo]=\"'body'\"\n [style]=\"{ width: '46rem', maxHeight: '80vh' }\"\n (onHide)=\"onLintDialogClose()\">\n <div class=\"workflow-lint-summary\">\n @if (lintErrorCount) {\n <span class=\"workflow-lint-count workflow-lint-count-error\">\n <i class=\"pi pi-times-circle\"></i> {{ lintErrorCount }} {{ lintErrorsCountLabel }}\n </span>\n }\n @if (lintWarnCount) {\n <span class=\"workflow-lint-count workflow-lint-count-warn\">\n <i class=\"pi pi-exclamation-triangle\"></i> {{ lintWarnCount }} {{ lintWarningsCountLabel }}\n </span>\n }\n </div>\n <ul class=\"workflow-lint-list\">\n @for (finding of lintFindings; track $index) {\n <li\n class=\"workflow-lint-item\"\n [ngClass]=\"finding.severity === 'error' ? 'workflow-lint-item-error' : 'workflow-lint-item-warn'\"\n [class.workflow-lint-item-clickable]=\"!!finding.nodeId\"\n (click)=\"zoomToLintFinding(finding)\">\n <i [class]=\"finding.severity === 'error' ? 'pi pi-times-circle' : 'pi pi-exclamation-triangle'\"></i>\n <span class=\"workflow-lint-code\">{{ finding.code }}</span>\n <span class=\"workflow-lint-message\">{{ finding.message }}</span>\n </li>\n }\n </ul>\n <div class=\"route-popup-actions\">\n <button type=\"button\" class=\"route-popup-btn\" (click)=\"onLintDialogClose()\">\n {{ lintDialogMode === 'confirm-save' ? ('cancel' | translate) : ('close' | translate) }}\n </button>\n @if (lintDialogMode === 'confirm-save') {\n <button type=\"button\" class=\"route-popup-btn route-popup-btn-primary\" (click)=\"onLintDialogSaveAnyway()\">\n {{ lintSaveAnywayLabel }}\n </button>\n }\n </div>\n</p-dialog>\n\n<!-- Guida rapida: legenda tipi nodo (dal nodeRegistry) + glossario workflow. -->\n<p-dialog\n [header]=\"quickGuideTitle\"\n [(visible)]=\"quickGuideDialogVisible\"\n [modal]=\"true\"\n [closable]=\"true\"\n [draggable]=\"false\"\n [resizable]=\"false\"\n [appendTo]=\"'body'\"\n styleClass=\"workflow-quick-guide-dialog\"\n [style]=\"{ width: '52rem', maxHeight: '85vh' }\"\n [contentStyle]=\"{ overflow: 'auto' }\">\n <div class=\"workflow-guide-section-title\">{{ quickGuideLegendTitle }}</div>\n <div class=\"workflow-guide-legend\">\n @for (entry of guideLegendEntries; track entry.type) {\n <div class=\"workflow-guide-legend-item\">\n <span class=\"workflow-guide-legend-chip\" [style.background]=\"entry.background\" [style.borderColor]=\"entry.accent\" [style.color]=\"entry.accent\">\n {{ entry.label }}\n </span>\n <span class=\"workflow-guide-legend-desc\">{{ entry.description }}</span>\n </div>\n }\n </div>\n <div class=\"workflow-guide-section-title\">{{ quickGuideGlossaryTitle }}</div>\n <dl class=\"workflow-guide-glossary\">\n @for (entry of guideGlossaryEntries; track entry.term) {\n <dt>{{ entry.term }}</dt>\n <dd>{{ entry.text }}</dd>\n }\n </dl>\n</p-dialog>\n", styles: [":host{display:block;height:100%}.workflow-designer{display:grid;grid-template-rows:auto 1fr;grid-template-columns:260px 1fr;gap:12px;height:100%;min-height:520px}.workflow-toolbar{grid-column:1 / span 2;display:flex;align-items:center;flex-wrap:wrap;gap:8px;border:1px solid #d5dce6;border-radius:10px;background:#f7f9fc;padding:10px 12px}.workflow-toolbar label{font-size:.82rem;font-weight:600;color:#2f3f58}.workflow-toolbar input{height:30px;border:1px solid #c7d2e2;border-radius:6px;background:#fff;padding:0 8px;min-width:170px}.workflow-toolbar button{height:30px;border:1px solid #2f67d8;border-radius:6px;background:#2f67d8;color:#fff;padding:0 10px;font-size:.82rem;cursor:pointer}.workflow-toolbar button[disabled]{opacity:.6;cursor:not-allowed}.workflow-toolbar-menu-group{display:inline-flex}.workflow-toolbar-filter{display:inline-flex;align-items:center}.workflow-toolbar-filter ::ng-deep .p-select{min-width:170px;font-size:.82rem}.workflow-current-graph{flex:1 1 auto;min-width:240px;font-size:.82rem;font-weight:600;color:#2f3f58}.workflow-palette{border:1px solid #d5dce6;border-radius:10px;background:#f7f9fc;overflow:auto}.workflow-palette-title{padding:10px 12px;font-size:.86rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:#3d4f67;border-bottom:1px solid #d5dce6}.workflow-palette-list{display:flex;flex-direction:column;gap:8px;padding:10px}.workflow-palette-item{border:1px solid #c8d3e2;border-radius:8px;background:#fff;padding:10px;cursor:grab;-webkit-user-select:none;user-select:none}.workflow-palette-item-badge{display:inline-block;margin-top:4px;margin-bottom:4px;padding:2px 7px;border-radius:999px;font-size:.68rem;font-weight:700;letter-spacing:.03em;text-transform:uppercase;background:#e2e8f0;color:#334155}.workflow-palette-item-route{border-color:#93c5fd;background:#eff6ff}.workflow-palette-item-route .workflow-palette-item-badge{background:#dbeafe;color:#1d4ed8}.workflow-palette-item-action{border-color:#c4b5fd;background:#f5f3ff}.workflow-palette-item-action .workflow-palette-item-badge{background:#ede9fe;color:#6d28d9}.workflow-palette-item-start{border-color:#86efac;background:#f0fdf4}.workflow-palette-item-condition{border-color:#99f6e4;background:#f0fdfa}.workflow-palette-item-end{border-color:#fda4af;background:#fff1f2}.workflow-palette-item:active{cursor:grabbing}.workflow-palette-item-disabled{opacity:.6;cursor:not-allowed;filter:grayscale(.2)}:host-context(.theme-dark) .workflow-palette-item-disabled{opacity:.5}.workflow-palette-item-title{font-size:.94rem;font-weight:600;color:#21324a}.workflow-palette-item-description{margin-top:4px;font-size:.82rem;color:#60738f}.workflow-canvas{position:relative;border:1px solid #d5dce6;border-radius:10px;overflow:hidden;background:radial-gradient(circle at 1px 1px,#dbe3ef 1px,transparent 0);background-size:24px 24px;background-color:#f8fbff;user-select:none;-webkit-user-select:none}.workflow-canvas-hint{position:absolute;right:12px;bottom:12px;font-size:.82rem;color:#60738f;background:#ffffffeb;border:1px solid #d5dce6;border-radius:6px;padding:5px 8px}.route-popup-form{display:flex;flex-direction:column;gap:8px}.route-popup-form label{font-size:.85rem;font-weight:600;color:#2f3f58;margin-top:2px}.workflow-options-input{width:100%;height:34px;border:1px solid #c7d2e2;border-radius:6px;background:#fff;padding:0 8px;color:#1f2f49}.workflow-options-toggle{display:flex;align-items:center;gap:8px;font-size:.85rem;font-weight:600;color:#2f3f58;margin-top:2px}.workflow-options-toggle input[type=checkbox]{width:16px;height:16px}.route-popup-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:10px}.route-popup-btn{border:1px solid #c7d2e2;background:#fff;color:#1f2f49;border-radius:6px;padding:7px 12px;font-size:.85rem;cursor:pointer}.route-popup-btn-primary{border-color:#2f67d8;background:#2f67d8;color:#fff}:host ::ng-deep .workflow-route-metadata-dialog.p-dialog{max-height:calc(100vh - 2rem)}:host ::ng-deep .workflow-route-metadata-dialog .p-dialog-content{overflow:visible;max-height:calc(100vh - 10rem)}:host ::ng-deep .workflow-canvas [data-wf-node-type] .node{border:1px solid var(--wf-node-accent, #64748b)!important;background:var(--wf-node-bg, #f8fafc)!important}:host ::ng-deep .workflow-canvas [data-wf-node-type] .title{background:var(--wf-node-accent, #64748b)!important;color:#fff!important;font-weight:700}:host ::ng-deep .workflow-canvas [data-wf-node-type=action][data-wf-action-scope=col] .node{border-style:dashed!important}:host ::ng-deep .workflow-canvas [data-wf-node-type=action][data-wf-action-scope=tab] .node{border-style:solid!important}:host-context(.theme-dark) .workflow-toolbar{border-color:#2a3447;background:#141b27}:host-context(.theme-dark) .workflow-current-graph,:host-context(.theme-dark) .workflow-toolbar label{color:#d8e2f1}:host-context(.theme-dark) .workflow-toolbar input{border-color:#334155;background:#0f1724;color:#e5ecf8}:host-context(.theme-dark) .workflow-toolbar button{border-color:#335fcf;background:#335fcf}:host-context(.theme-dark) .workflow-palette{border-color:#2a3447;background:#141b27}:host-context(.theme-dark) .workflow-palette-title{color:#dbe4f2;border-bottom-color:#2a3447}:host-context(.theme-dark) .workflow-palette-item{border-color:#334155;background:#0f1724}:host-context(.theme-dark) .workflow-palette-item-title{color:#e6edf8}:host-context(.theme-dark) .workflow-palette-item-description{color:#9fb0c7}:host-context(.theme-dark) .workflow-palette-item-badge{background:#273247;color:#c9d7ec}:host-context(.theme-dark) .workflow-palette-item-route{border-color:#3b82f6;background:#0f1f35}:host-context(.theme-dark) .workflow-palette-item-route .workflow-palette-item-badge{background:#1e3a6a;color:#c8ddff}:host-context(.theme-dark) .workflow-palette-item-action{border-color:#8b5cf6;background:#24183d}:host-context(.theme-dark) .workflow-palette-item-action .workflow-palette-item-badge{background:#3a2370;color:#ded1ff}:host-context(.theme-dark) .workflow-palette-item-start{border-color:#22c55e;background:#11281c}:host-context(.theme-dark) .workflow-palette-item-condition{border-color:#14b8a6;background:#0f2726}:host-context(.theme-dark) .workflow-palette-item-end{border-color:#ef4444;background:#30171b}:host-context(.theme-dark) .workflow-canvas{border-color:#2a3447;background:radial-gradient(circle at 1px 1px,#334155 1px,transparent 0);background-size:24px 24px;background-color:#0f1724}:host-context(.theme-dark) .workflow-canvas-hint{color:#b9c8de;background:#0f1724e6;border-color:#334155}:host-context(.theme-dark) .route-popup-form label,:host-context(.theme-dark) .workflow-options-toggle{color:#d8e2f1}:host-context(.theme-dark) .workflow-options-input{border-color:#334155;background:#0f1724;color:#e5ecf8}:host-context(.theme-dark) .route-popup-btn{border-color:#334155;background:#111b2b;color:#d8e2f1}:host-context(.theme-dark) .route-popup-btn-primary{border-color:#335fcf;background:#335fcf;color:#fff}:host-context(.theme-dark) ::ng-deep .p-menu,:host-context(.theme-dark) ::ng-deep .p-contextmenu{background:#121b2b;border-color:#334155;color:#dbe4f2}:host-context(.theme-dark) ::ng-deep .p-menu .p-menu-item-content,:host-context(.theme-dark) ::ng-deep .p-contextmenu .p-menu-item-content{color:#dbe4f2}:host-context(.theme-dark) ::ng-deep .p-menu .p-menu-item-content:hover,:host-context(.theme-dark) ::ng-deep .p-contextmenu .p-menu-item-content:hover{background:#1f2a3d}:host-context(.theme-dark) ::ng-deep .p-dialog{background:#121b2b;border-color:#334155;color:#dbe4f2}:host-context(.theme-dark) ::ng-deep .p-dialog .p-dialog-header,:host-context(.theme-dark) ::ng-deep .p-dialog .p-dialog-content,:host-context(.theme-dark) ::ng-deep .p-dialog .p-dialog-footer{background:#121b2b;color:#dbe4f2;border-color:#334155}.workflow-canvas-checklist{position:absolute;right:18px;bottom:18px;max-width:340px;padding:14px 16px;border:1px solid #cbd5e1;border-radius:10px;background:#fffffff0;color:#334155;font-size:12.5px;line-height:1.5;box-shadow:0 4px 14px #0f172a14;pointer-events:auto;z-index:5}.workflow-canvas-checklist-title{font-weight:700;margin-bottom:6px;color:#0f172a}.workflow-canvas-checklist ol{margin:0 0 8px;padding-left:18px}.workflow-canvas-checklist li{margin:2px 0}.workflow-canvas-checklist-done{text-decoration:line-through;opacity:.55}.workflow-canvas-checklist-link{border:none;background:none;padding:0;color:#2563eb;cursor:pointer;font-size:12.5px;text-decoration:underline}:host-context(.theme-dark) .workflow-canvas-checklist{background:#121b2bf0;border-color:#334155;color:#cbd5e1}:host-context(.theme-dark) .workflow-canvas-checklist-title{color:#e2e8f0}.workflow-lint-summary{display:flex;gap:14px;margin-bottom:10px;font-size:12.5px}.workflow-lint-count{display:inline-flex;align-items:center;gap:6px;font-weight:600}.workflow-lint-count-error{color:#dc2626}.workflow-lint-count-warn{color:#d97706}.workflow-lint-list{list-style:none;margin:0 0 12px;padding:0;max-height:46vh;overflow:auto}.workflow-lint-item{display:flex;align-items:flex-start;gap:8px;padding:7px 8px;border-radius:6px;font-size:12.5px;line-height:1.45}.workflow-lint-item+.workflow-lint-item{margin-top:4px}.workflow-lint-item-error{background:#fef2f2;color:#7f1d1d}.workflow-lint-item-error .pi{color:#dc2626;margin-top:2px}.workflow-lint-item-warn{background:#fffbeb;color:#78350f}.workflow-lint-item-warn .pi{color:#d97706;margin-top:2px}.workflow-lint-item-clickable{cursor:pointer}.workflow-lint-item-clickable:hover{filter:brightness(.97)}.workflow-lint-code{font-family:monospace;font-size:11px;opacity:.75;white-space:nowrap;margin-top:1px}:host-context(.theme-dark) .workflow-lint-item-error{background:#dc26261f;color:#fca5a5}:host-context(.theme-dark) .workflow-lint-item-warn{background:#d977061f;color:#fcd34d}.workflow-guide-section-title{font-weight:700;font-size:13px;margin:10px 0 8px;color:#0f172a}.workflow-guide-legend{display:grid;grid-template-columns:1fr 1fr;gap:8px 18px;margin-bottom:8px}.workflow-guide-legend-item{display:flex;align-items:center;gap:8px;font-size:12.5px}.workflow-guide-legend-chip{display:inline-block;min-width:74px;text-align:center;padding:3px 8px;border:1.5px solid;border-radius:7px;font-weight:700;font-size:11.5px;white-space:nowrap}.workflow-guide-legend-desc{color:#475569;line-height:1.4}.workflow-guide-glossary{margin:0;font-size:12.5px}.workflow-guide-glossary dt{font-weight:700;margin-top:8px;color:#0f172a}.workflow-guide-glossary dd{margin:2px 0 0;color:#475569;line-height:1.5}:host-context(.theme-dark) .workflow-guide-section-title,:host-context(.theme-dark) .workflow-guide-glossary dt{color:#e2e8f0}:host-context(.theme-dark) .workflow-guide-legend-desc,:host-context(.theme-dark) .workflow-guide-glossary dd{color:#94a3b8}::ng-deep .workflow-palette-tooltip .p-tooltip-text{max-width:340px;font-size:12px;line-height:1.45}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i2$1.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: MenuModule }, { kind: "component", type: i7$1.Menu, selector: "p-menu", inputs: ["model", "popup", "style", "styleClass", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaLabel", "ariaLabelledBy", "id", "tabindex", "appendTo", "motionOptions"], outputs: ["onShow", "onHide", "onBlur", "onFocus"] }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: i14.ContextMenu, selector: "p-contextMenu, p-contextmenu, p-context-menu", inputs: ["model", "triggerEvent", "target", "global", "style", "styleClass", "autoZIndex", "baseZIndex", "id", "breakpoint", "ariaLabel", "ariaLabelledBy", "pressDelay", "appendTo", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: DataSourceComponent, selector: "wuic-data-source", inputs: ["route", "routeFromRouting", "hardcodedRoute", "autoload", "loading", "changeTracking", "parentRecord", "parentMetaInfo", "parentDatasource", "useComboEndpoint", "comboFormulaLookup", "comboMcId", "comboField", "comboExtraFields", "comboCurrentRecord", "componentRef"] }, { kind: "component", type: MetadataEditorComponent, selector: "wuic-metadata-editor", inputs: ["datasource", "hardcodedDatasource", "saveCallback", "hideReports", "hideRelatedTableActions", "hideRelatedColumnActions"] }, { kind: "pipe", type: i8.TranslatePipe, name: "translate" }] });
|
|
9444
9474
|
}
|
|
9445
9475
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WorkflowDesignerComponent, decorators: [{
|
|
9446
9476
|
type: Component,
|
|
@@ -9471,4 +9501,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
9471
9501
|
}] } });
|
|
9472
9502
|
|
|
9473
9503
|
export { WorkflowDesignerComponent };
|
|
9474
|
-
//# sourceMappingURL=wuic-framework-lib-workflow-designer.component-
|
|
9504
|
+
//# sourceMappingURL=wuic-framework-lib-workflow-designer.component-DMM8BeXm.mjs.map
|