wuic-framework-lib 1.5.0 → 1.7.1

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.
Files changed (27) hide show
  1. package/fesm2022/{wuic-framework-lib-chart-list.component-0J1ghIrS.mjs → wuic-framework-lib-chart-list.component-Dq9IEKsY.mjs} +50 -38
  2. package/fesm2022/{wuic-framework-lib-code-editor.component-C21mvjyr.mjs → wuic-framework-lib-code-editor.component-B6IpTSo8.mjs} +174 -274
  3. package/fesm2022/{wuic-framework-lib-designer.component-x10ZzUEy.mjs → wuic-framework-lib-designer.component-D6cbqNFg.mjs} +499 -581
  4. package/fesm2022/wuic-framework-lib-first-run-wizard.component-D1ZQUl-q.mjs +1630 -0
  5. package/fesm2022/{wuic-framework-lib-framework-docs.component-xTGLbEnp.mjs → wuic-framework-lib-framework-docs.component-C_o5r7pg.mjs} +4320 -1255
  6. package/fesm2022/{wuic-framework-lib-pivot-builder.component-BkFFjPm4.mjs → wuic-framework-lib-pivot-builder.component-DkWGzJpr.mjs} +580 -68
  7. package/fesm2022/{wuic-framework-lib-prompt-dialog-fallback-host.component-Bi-TrJB6.mjs → wuic-framework-lib-prompt-dialog-fallback-host.component-D29go5yA.mjs} +2 -2
  8. package/fesm2022/wuic-framework-lib-report-designer.component-DcpCWghx.mjs +380 -0
  9. package/fesm2022/wuic-framework-lib-report-scaffold-dialog.component-CgUjG7Bi.mjs +431 -0
  10. package/fesm2022/{wuic-framework-lib-report-viewer.component-BR-BfI2r.mjs → wuic-framework-lib-report-viewer.component-C4Opgl_M.mjs} +8 -13
  11. package/fesm2022/{wuic-framework-lib-scene3d-designer.component-BQzFxSXP.mjs → wuic-framework-lib-scene3d-designer.component-8l3vsyEb.mjs} +323 -88
  12. package/fesm2022/{wuic-framework-lib-scene3d-light-baker-gpu-0LjqhSNn.mjs → wuic-framework-lib-scene3d-light-baker-gpu-C1w-8Aai.mjs} +2 -2
  13. package/fesm2022/{wuic-framework-lib-scene3d-shader-effect-CQLWkuh1.mjs → wuic-framework-lib-scene3d-shader-effect-DjHyCAFK.mjs} +612 -32
  14. package/fesm2022/{wuic-framework-lib-scene3d-viewer.component-imoV3HOs.mjs → wuic-framework-lib-scene3d-viewer.component-nMSl5jbe.mjs} +149 -18
  15. package/fesm2022/{wuic-framework-lib-scheduler-list.component-xzlTEkoq.mjs → wuic-framework-lib-scheduler-list.component-Cvk3Zg0Q.mjs} +169 -53
  16. package/fesm2022/{wuic-framework-lib-spreadsheet-list-sf.component-CrS6fOGj.mjs → wuic-framework-lib-spreadsheet-list-sf.component-C1U7JPiq.mjs} +149 -108
  17. package/fesm2022/{wuic-framework-lib-stimulsoft-license.service-BIyxB4pO.mjs → wuic-framework-lib-stimulsoft-license.service-CsNNSFYs.mjs} +3 -3
  18. package/fesm2022/wuic-framework-lib-timeline-list.component-cZbPgNh1.mjs +805 -0
  19. package/fesm2022/{wuic-framework-lib-workflow-designer.component-5xtQ7-6z.mjs → wuic-framework-lib-workflow-designer.component-C_4RQGa0.mjs} +180 -150
  20. package/fesm2022/{wuic-framework-lib-wuic-framework-lib-3TZ-j-yL.mjs → wuic-framework-lib-wuic-framework-lib-BZZwta8b.mjs} +6785 -2347
  21. package/fesm2022/wuic-framework-lib.mjs +1 -1
  22. package/package.json +21 -2
  23. package/styles/_wuic-tokens.scss +82 -0
  24. package/styles/styles.scss +160 -0
  25. package/types/wuic-framework-lib.d.ts +4269 -2691
  26. package/fesm2022/wuic-framework-lib-first-run-wizard.component-BuSxs_CM.mjs +0 -1316
  27. 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 i10 from 'primeng/contextmenu';
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 i6$1 from 'primeng/select';
19
+ import * as i5 from 'primeng/select';
20
20
  import { SelectModule } from 'primeng/select';
21
- import * as i6 from 'primeng/tooltip';
21
+ import * as i7 from 'primeng/tooltip';
22
22
  import { TooltipModule } from 'primeng/tooltip';
23
- import * as i2$2 from '@ngx-translate/core';
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, d as ParametricDialogComponent, k as WuicClientException, l as WuicErrorCodes, G as GlobalHandler, f as DataProviderService, C as ChatbotHostRegistryService, b as DataSourceComponent, j as MetadataEditorComponent } from './wuic-framework-lib-wuic-framework-lib-3TZ-j-yL.mjs';
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-BZZwta8b.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[stack.length - 1];
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
- || !(Number(cfg.duration_minutes) > 0);
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) => (a.severity === b.severity
937
- ? a.code.localeCompare(b.code)
938
- : (a.severity === 'error' ? -1 : 1)));
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(' ').replace(/\u2026/g, '').length;
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: 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: "pipe", type: ImpureKeyvaluePipe, name: "keyvalueimpure" }] });
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).__wuicCmp = this;
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
- delete (this.hostElementRef?.nativeElement).__wuicCmp;
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
- const bundleActions = Array.isArray(bundle.tableActions)
2381
- ? bundle.tableActions
2382
- : (bundle.tableActions = []);
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 = Object.assign({}, normalizedOriginal || {}, normalizedData || {}, { mm_id: mmId });
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] = Object.assign({}, menus[idx], normalizedMenu);
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
- const routeConfig = type === 'route'
3505
- ? { routeName: String(spec?.route || '').trim(), action: String(spec?.action || '').trim() || 'list' }
3506
- : (type === 'condition'
3507
- ? { routeName: '', action: '', conditionExpression: String(spec?.conditionExpression || '') }
3508
- : (type === 'switch'
3509
- ? { routeName: '', action: '', switchConfig: spec?.switchConfig || null }
3510
- : undefined));
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 && localMap.has(key)) {
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
- const dashboardDatasources = sourceType === 'dashboard'
3784
- ? (restoredDashboardDatasources.length
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 normalized = (raw.startsWith('#/') ? raw.substring(1) : (raw.startsWith('/') ? raw : '/' + raw)).toLowerCase();
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
- .replace(/_/g, '.')
4360
- .replace(/\s+/g, '.')
4361
- .replace(/-+/g, '.');
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 human = minutes % 1440 === 0 ? `${minutes / 1440}g` : (minutes % 60 === 0 ? `${minutes / 60}h` : `${minutes}m`);
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 === null || flag === undefined ? grantByDefault : 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
- .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
4814
+ .replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
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 header = `<b>Start</b>${caption ? ` <span style="color:#93c5fd">${esc(caption)}</span>` : ''}`;
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
- const who = userId > 0
4898
- ? (this.userDirectory.get(String(userId))?.username || `Utente ${userId}`) + (roleId > 0 ? ` (${esc(this.roleLabel(roleId))})` : '')
4899
- : (roleId > 0 ? this.roleLabel(roleId) : 'Tutti');
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) => row(`Task ${i + 1}`, `${b?.caption || ''}${b?.assignee_user_id ? ` → utente ${b.assignee_user_id}` : ''}`))
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) => v === true
5031
- ? `<td style="${S.tdc};color:#4ade80">✓</td>`
5032
- : (v === false ? `<td style="${S.tdc};color:#f87171">✗</td>` : `<td style="${S.tdc};color:#64748b">·</td>`);
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 kind = isView ? 'Vista' : (isStored ? 'Stored' : 'Tabella');
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
- header = `<b>${kind}</b> <span style="color:#93c5fd">${esc(physical)}</span>${routeSuffix}${action ? ` <span style="opacity:.6">[${esc(action)}]</span>` : ''}`;
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
- .replace(/\.action/gi, '')
5129
- .replace(/\./g, ' ')
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
- const target = String((action === 'notify_role' ? resp?.target_role?.value
5530
- : action === 'notify' ? resp?.target_user?.value
5531
- : resp?.target_state?.value) ?? '').trim();
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}:${selectedRoleIds.map((id) => `role:${id}`).join(',')}`
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 id = byPrefix ? Number(byPrefix[1]) : (/^\d+$/.test(token) ? Number(token) : NaN);
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[nums.length - 2];
6459
- const y1 = nums[nums.length - 1];
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
- const path = (event.composedPath?.() || []);
6603
- for (const target of path) {
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, '').replace(/\./g, ' ').trim();
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 || {}), ...((existing.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
- .replace(/[^a-z0-9_]+/g, '_')
7078
- .replace(/_+/g, '_')
7079
- .replace(/^_+|_+$/g, '');
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
- versions = Array.isArray(res?.versions) ? res.versions : (Array.isArray(res) ? res : []);
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 versions = Array.isArray(res?.versions) ? res.versions : (Array.isArray(res) ? res : []);
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().replace(/[-:.TZ]/g, '').slice(0, 14);
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
- .replace(/\$STATE_FIELD/g, stateField || 'stato')
7701
- .replace(/\$APPROVED/g, approvedValue || 'APPROVATO')
7702
- .replace(/\$AMOUNT/g, amountField || 'importo');
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
- const routeConfig = spec.type === 'route'
7715
- ? { routeName: spec.route === '$MAIN' ? mainRoute : String(spec.route || ''), action: String(spec.action || 'list'), sourceType: 'route' }
7716
- : (spec.type === 'condition' ? { routeName: '', action: '', conditionExpression: resolveTokens(spec.conditionExpression || '') } : undefined);
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 || window.location.origin);
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
- const routeConfig = type === 'route'
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
- : (type === 'switch'
8119
- ? { routeName: '', action: '', switchConfig: item?.switchConfig || null }
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)) || Promise.resolve()));
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
- : Array.isArray(root?.routeMetadata)
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().replace(/[^a-z0-9]/g, '');
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().replace(/[^a-z0-9]/g, '');
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 = Object.assign({}, normalized);
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 = Object.assign({}, normalized);
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 = Object.assign({}, normalized);
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 = Object.assign({}, normalized);
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 = Object.assign({}, normalized);
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 = Object.assign({}, normalized);
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 = Object.assign({}, normalized);
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 = Object.assign({}, normalized);
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 = Object.assign({}, normalized);
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 = Object.assign({}, bundle.tableMetadata || {}, normalized);
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] = Object.assign({}, list[idx] || {}, record);
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 = Object.assign({}, metaInfo.tableMetadata || {}, bundle.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 Object.assign({}, metaInfo, {
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.replace(/\{(\d+)\}/g, (match, idx) => {
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-5xtQ7-6z.mjs.map
9504
+ //# sourceMappingURL=wuic-framework-lib-workflow-designer.component-C_4RQGa0.mjs.map