@esfaenza/flow-builder 20.0.0 → 20.3.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.
- package/README.md +372 -354
- package/fesm2022/esfaenza-flow-builder.mjs +1001 -172
- package/fesm2022/esfaenza-flow-builder.mjs.map +1 -1
- package/index.d.ts +451 -42
- package/package.json +1 -1
- package/styles/flow-builder.css +12 -0
|
@@ -37,9 +37,9 @@ const FLOW_NODE_COLLECTIONS = [
|
|
|
37
37
|
'transforms',
|
|
38
38
|
'waits',
|
|
39
39
|
'customErrors',
|
|
40
|
+
'orchestratedStages',
|
|
40
41
|
'steps',
|
|
41
42
|
'experiments',
|
|
42
|
-
'orchestratedStages',
|
|
43
43
|
];
|
|
44
44
|
/** Le collection di risorse (§4.6). Condividono lo spazio dei nomi con i node (§3.3). */
|
|
45
45
|
const FLOW_RESOURCE_COLLECTIONS = [
|
|
@@ -217,7 +217,19 @@ class FlowBuilderApi {
|
|
|
217
217
|
void request;
|
|
218
218
|
return missing('resumeInterview');
|
|
219
219
|
}
|
|
220
|
-
/**
|
|
220
|
+
/**
|
|
221
|
+
* `POST /interviews/{key}/stage-step` — un assegnatario conclude uno step (§5.13).
|
|
222
|
+
* Se lo stage si sospende di nuovo, la risposta porta una `interviewKey` **nuova**: la
|
|
223
|
+
* vecchia non e' piu' valida e va sostituita, non conservata.
|
|
224
|
+
*/
|
|
225
|
+
completeStageStep(request) {
|
|
226
|
+
void request;
|
|
227
|
+
return missing('completeStageStep');
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* `GET /interviews/{key}` — ispeziona una sospesa senza consumarla.
|
|
231
|
+
* Con `isWaitingForStageStep` porta `stageSteps` con lo stato di ognuno (§5.13).
|
|
232
|
+
*/
|
|
221
233
|
inspectInterview(interviewKey) {
|
|
222
234
|
void interviewKey;
|
|
223
235
|
return missing('inspectInterview');
|
|
@@ -316,128 +328,134 @@ class HttpFlowBuilderApi extends FlowBuilderApi {
|
|
|
316
328
|
}
|
|
317
329
|
// ---------------------------------------------------------------- §6.1
|
|
318
330
|
listFlows(query) {
|
|
319
|
-
return this.get('/flows', HttpFlowBuilderApi.params({ ...query }));
|
|
331
|
+
return this.get('/flows/editor/list', HttpFlowBuilderApi.params({ ...query }));
|
|
320
332
|
}
|
|
321
333
|
listVersions(flowName) {
|
|
322
|
-
return this.get(`/flows/${HttpFlowBuilderApi.segment(flowName)}/versions`);
|
|
334
|
+
return this.get(`/flows/editor/${HttpFlowBuilderApi.segment(flowName)}/versions`);
|
|
323
335
|
}
|
|
324
336
|
loadFlow(flowName, version) {
|
|
325
|
-
return this.get(`/flows/${HttpFlowBuilderApi.segment(flowName)}`, HttpFlowBuilderApi.params({ version }));
|
|
337
|
+
return this.get(`/flows/editor/${HttpFlowBuilderApi.segment(flowName)}`, HttpFlowBuilderApi.params({ version }));
|
|
326
338
|
}
|
|
327
339
|
exportFlow(flowName, query) {
|
|
328
|
-
return this.request(firstValueFrom(this.http.get(this.url(`/flows/${HttpFlowBuilderApi.segment(flowName)}/export`), {
|
|
340
|
+
return this.request(firstValueFrom(this.http.get(this.url(`/flows/editor/${HttpFlowBuilderApi.segment(flowName)}/export`), {
|
|
329
341
|
params: HttpFlowBuilderApi.params({ ...query }),
|
|
330
342
|
responseType: 'text',
|
|
331
343
|
})));
|
|
332
344
|
}
|
|
333
345
|
parseFlow(definition) {
|
|
334
|
-
return this.post('/flows/parse', definition);
|
|
346
|
+
return this.post('/flows/editor/parse', definition);
|
|
335
347
|
}
|
|
336
348
|
// ---------------------------------------------------------------- §6.2
|
|
337
349
|
createFlow(request) {
|
|
338
|
-
return this.post('/flows', request);
|
|
350
|
+
return this.post('/flows/editor/create', request);
|
|
339
351
|
}
|
|
340
352
|
saveFlow(flowName, request) {
|
|
341
|
-
return this.put(`/flows
|
|
353
|
+
return this.put(`/flows/editor/save`, request);
|
|
342
354
|
}
|
|
343
355
|
createVersion(flowName, request) {
|
|
344
|
-
return this.post(`/flows/${HttpFlowBuilderApi.segment(flowName)}/
|
|
356
|
+
return this.post(`/flows/editor/${HttpFlowBuilderApi.segment(flowName)}/new-version`, { author: request?.author }, HttpFlowBuilderApi.params({ from: request?.from }));
|
|
345
357
|
}
|
|
346
358
|
cloneFlow(flowName, request) {
|
|
347
|
-
return this.post(`/flows/${HttpFlowBuilderApi.segment(flowName)}/clone`, request);
|
|
359
|
+
return this.post(`/flows/editor/${HttpFlowBuilderApi.segment(flowName)}/clone`, request);
|
|
348
360
|
}
|
|
349
361
|
activateVersion(flowName, version) {
|
|
350
|
-
return this.
|
|
362
|
+
return this.put(`/flows/editor/${HttpFlowBuilderApi.segment(flowName)}/activate/${version}`);
|
|
351
363
|
}
|
|
352
364
|
deactivateFlow(flowName) {
|
|
353
|
-
return this.
|
|
365
|
+
return this.put(`/flows/editor/${HttpFlowBuilderApi.segment(flowName)}/deactivate`);
|
|
354
366
|
}
|
|
355
367
|
deleteVersion(flowName, version) {
|
|
356
|
-
return this.del(`/flows/${HttpFlowBuilderApi.segment(flowName)}/versions/${version}`);
|
|
368
|
+
return this.del(`/flows/editor/${HttpFlowBuilderApi.segment(flowName)}/versions/${version}`);
|
|
357
369
|
}
|
|
358
370
|
deleteFlow(flowName) {
|
|
359
|
-
return this.del(`/flows/${HttpFlowBuilderApi.segment(flowName)}`);
|
|
371
|
+
return this.del(`/flows/editor/${HttpFlowBuilderApi.segment(flowName)}`);
|
|
360
372
|
}
|
|
361
373
|
// ---------------------------------------------------------------- §6.3
|
|
362
374
|
validateDefinition(definition) {
|
|
363
|
-
return this.post(
|
|
375
|
+
return this.post(`/flows/editor/${HttpFlowBuilderApi.segment(definition.fullName.toString())}/validate`, definition);
|
|
364
376
|
}
|
|
365
377
|
validateVersion(flowName, version) {
|
|
366
|
-
return this.get(`/flows/${HttpFlowBuilderApi.segment(flowName)}/
|
|
378
|
+
return this.get(`/flows/editor/${HttpFlowBuilderApi.segment(flowName)}/validate`, HttpFlowBuilderApi.params({ version: version }));
|
|
367
379
|
}
|
|
368
380
|
// ---------------------------------------------------------------- §6.4
|
|
369
|
-
getDictionaries() {
|
|
370
|
-
|
|
381
|
+
getDictionaries(processType) {
|
|
382
|
+
// `processType` filtra le globali: `$Record` non esiste in uno screen flow (§4.1).
|
|
383
|
+
return this.get('/flows/editor/dictionaries', HttpFlowBuilderApi.params({ processType }));
|
|
371
384
|
}
|
|
372
385
|
getReferences(query) {
|
|
373
|
-
return this.post('/flows/references', query);
|
|
386
|
+
return this.post('/flows/editor/references', query);
|
|
374
387
|
}
|
|
375
388
|
getWritableReferences(query) {
|
|
376
|
-
return this.post('/flows/
|
|
389
|
+
return this.post('/flows/editor/writable-references', query);
|
|
377
390
|
}
|
|
378
391
|
getConnectorTargets(definition, excluding) {
|
|
379
|
-
return this.post('/flows/connector-targets', definition, HttpFlowBuilderApi.params({ excluding }));
|
|
392
|
+
return this.post('/flows/editor/connector-targets', definition, HttpFlowBuilderApi.params({ excluding }));
|
|
380
393
|
}
|
|
381
394
|
getOutline(definition) {
|
|
382
|
-
return this.post('/flows/outline', definition);
|
|
395
|
+
return this.post('/flows/editor/outline', definition);
|
|
383
396
|
}
|
|
384
397
|
listObjects() {
|
|
385
|
-
return this.get('/
|
|
398
|
+
return this.get('/flows/objects');
|
|
386
399
|
}
|
|
387
400
|
describeObject(object) {
|
|
388
|
-
return this.get(`/
|
|
401
|
+
return this.get(`/flows/objects/${HttpFlowBuilderApi.segment(object)}`);
|
|
389
402
|
}
|
|
390
403
|
listFields(object, usage) {
|
|
391
|
-
return this.get(`/
|
|
404
|
+
return this.get(`/flows/objects/${HttpFlowBuilderApi.segment(object)}/fields`, HttpFlowBuilderApi.params({ usage }));
|
|
392
405
|
}
|
|
393
406
|
listFieldValues(object, field) {
|
|
394
|
-
return this.get(`/
|
|
407
|
+
return this.get(`/flows/objects/${HttpFlowBuilderApi.segment(object)}/fields/${HttpFlowBuilderApi.segment(field)}/picklist`);
|
|
395
408
|
}
|
|
396
409
|
listActionTypes() {
|
|
397
|
-
return this.get('/
|
|
410
|
+
return this.get('/flows/action-types');
|
|
398
411
|
}
|
|
399
412
|
listActions(actionType) {
|
|
400
|
-
return this.get('/
|
|
413
|
+
return this.get('/flows/actions', HttpFlowBuilderApi.params({ type: actionType }));
|
|
401
414
|
}
|
|
402
415
|
listActionParameters(actionType, actionName) {
|
|
403
|
-
return this.get(`/
|
|
416
|
+
return this.get(`/flows/actions/${HttpFlowBuilderApi.segment(actionType)}/${HttpFlowBuilderApi.segment(actionName)}/parameters`);
|
|
404
417
|
}
|
|
405
418
|
listScripts() {
|
|
406
|
-
return this.get('/
|
|
419
|
+
return this.get('/flows/editor/scripts');
|
|
407
420
|
}
|
|
408
421
|
listScriptParameters(scriptName) {
|
|
409
|
-
return this.get(`/
|
|
422
|
+
return this.get(`/flows/editor/scripts/${HttpFlowBuilderApi.segment(scriptName)}/parameters`);
|
|
410
423
|
}
|
|
411
424
|
listForms() {
|
|
412
|
-
return this.get('/
|
|
425
|
+
return this.get('/flows/editor/forms');
|
|
413
426
|
}
|
|
414
427
|
listFormParameters(formName) {
|
|
415
|
-
return this.get(`/
|
|
428
|
+
return this.get(`/flows/editor/forms/${HttpFlowBuilderApi.segment(formName)}/parameters`);
|
|
416
429
|
}
|
|
417
430
|
listEnumTypes() {
|
|
418
|
-
return this.get('/
|
|
431
|
+
return this.get('/flows/editor/enum-types');
|
|
419
432
|
}
|
|
420
433
|
listEvents() {
|
|
421
|
-
return this.get('/
|
|
434
|
+
return this.get('/flows/editor/events');
|
|
422
435
|
}
|
|
423
436
|
listSubflowCandidates(excluding) {
|
|
424
|
-
return this.get('/flows/
|
|
437
|
+
return this.get('/flows/editor/subflows', HttpFlowBuilderApi.params({ excluding }));
|
|
425
438
|
}
|
|
426
439
|
// ---------------------------------------------------------------- §6.5
|
|
427
440
|
startInterview(request) {
|
|
428
|
-
return this.post('/
|
|
441
|
+
return this.post('/flows/start', request);
|
|
429
442
|
}
|
|
430
443
|
respondToScreen(request) {
|
|
431
|
-
return this.post('/
|
|
444
|
+
return this.post('/flows/submit-screen', request);
|
|
432
445
|
}
|
|
433
446
|
resumeInterview(request) {
|
|
434
|
-
return this.post('/
|
|
447
|
+
return this.post('/flows/resume-wait', request);
|
|
448
|
+
}
|
|
449
|
+
completeStageStep(request) {
|
|
450
|
+
// La chiave sta nell'URL, il resto nel corpo: la risposta puo' portarne una nuova (§5.13).
|
|
451
|
+
let body = { stepName: request.stepName, status: request.status, stepOutputs: request.stepOutputs, debug: request.debug };
|
|
452
|
+
return this.post(`/flows/${HttpFlowBuilderApi.segment(request.interviewKey)}/resume-stage-step`, body);
|
|
435
453
|
}
|
|
436
454
|
inspectInterview(interviewKey) {
|
|
437
|
-
return this.get(`/
|
|
455
|
+
return this.get(`/flows/${HttpFlowBuilderApi.segment(interviewKey)}`);
|
|
438
456
|
}
|
|
439
457
|
abandonInterview(interviewKey) {
|
|
440
|
-
return this.del(`/
|
|
458
|
+
return this.del(`/flows/${HttpFlowBuilderApi.segment(interviewKey)}`);
|
|
441
459
|
}
|
|
442
460
|
}
|
|
443
461
|
|
|
@@ -574,6 +592,15 @@ function outletsOf(type, node) {
|
|
|
574
592
|
}
|
|
575
593
|
return outlets;
|
|
576
594
|
}
|
|
595
|
+
// Lo `faultConnector` di uno stage **non** e' un ramo di guasto: e' il ramo dello step
|
|
596
|
+
// rifiutato, e senza di esso un rifiuto fa fallire l'interview (§5.13). L'etichetta lo
|
|
597
|
+
// dice, altrimenti chi disegna un'approvazione lo lascia vuoto credendo di rinunciare
|
|
598
|
+
// solo alla gestione degli errori.
|
|
599
|
+
case 'OrchestratedStage':
|
|
600
|
+
return [
|
|
601
|
+
field('next', 'Next', 'Stage concluso', 'connector'),
|
|
602
|
+
field('fault', 'Fault', 'Step rifiutato', 'faultConnector'),
|
|
603
|
+
];
|
|
577
604
|
case 'ScriptCall':
|
|
578
605
|
case 'RecordLookup':
|
|
579
606
|
case 'RecordCreate':
|
|
@@ -653,8 +680,8 @@ const FALLBACK_TYPE_LABEL = {
|
|
|
653
680
|
Experiment: 'Esperimento',
|
|
654
681
|
OrchestratedStage: 'Stage di orchestrazione',
|
|
655
682
|
};
|
|
656
|
-
/** I
|
|
657
|
-
const UNSUPPORTED_TYPES = new Set(['Step', 'Experiment'
|
|
683
|
+
/** I due tipi che il motore rifiuta: nascosti dalla palette (§3.2, §13.9). */
|
|
684
|
+
const UNSUPPORTED_TYPES = new Set(['Step', 'Experiment']);
|
|
658
685
|
/** Elementi che espongono il proprio risultato sotto il nome dell'elemento (§4.5). */
|
|
659
686
|
const TYPES_WITH_AUTOMATIC_OUTPUT = new Set([
|
|
660
687
|
'RecordLookup',
|
|
@@ -691,6 +718,7 @@ const FLOW_ELEMENT_ICONS = {
|
|
|
691
718
|
Transform: '⇄',
|
|
692
719
|
Wait: '◷',
|
|
693
720
|
CustomError: '!',
|
|
721
|
+
OrchestratedStage: '☰',
|
|
694
722
|
};
|
|
695
723
|
/**
|
|
696
724
|
* Il glifo del tipo. Per un tipo che il dizionario del backend aggiunge e questa mappa non
|
|
@@ -946,6 +974,137 @@ function checkConditionLogic(logic, conditionCount) {
|
|
|
946
974
|
return null;
|
|
947
975
|
}
|
|
948
976
|
|
|
977
|
+
/**
|
|
978
|
+
* Testo e numero non si confrontano — FRONTEND.md §4.3, §13.13.
|
|
979
|
+
*
|
|
980
|
+
* `Importo > "1000"` con `Importo` numerico e' `CONDITION_TYPE_MISMATCH`, un **errore** che
|
|
981
|
+
* blocca l'attivazione: la conversione implicita renderebbe l'esito dipendente dal formato
|
|
982
|
+
* del testo, e chi disegna il flow non ha modo di accorgersene.
|
|
983
|
+
*
|
|
984
|
+
* Il backend segnala solo quando conosce **entrambi** i tipi, e su un campo di un record o
|
|
985
|
+
* sull'output automatico di un elemento non li conosce: il posto giusto in cui fermare
|
|
986
|
+
* l'utente e' il picker, cioe' l'editor delle condizioni. Questo file e' la regola, in un
|
|
987
|
+
* posto solo.
|
|
988
|
+
*
|
|
989
|
+
* Vale per i soli operatori di uguaglianza e ordine. `Contains`, `StartsWith`, `EndsWith`,
|
|
990
|
+
* `In` e `NotIn` hanno una semantica propria e non sono soggetti alla regola; gli unari non
|
|
991
|
+
* hanno un secondo operando.
|
|
992
|
+
*/
|
|
993
|
+
/** Gli operatori con una semantica propria: la regola non li riguarda (§4.3). */
|
|
994
|
+
const OPERATORS_WITHOUT_TYPE_CHECK = new Set([
|
|
995
|
+
'Contains',
|
|
996
|
+
'StartsWith',
|
|
997
|
+
'EndsWith',
|
|
998
|
+
'In',
|
|
999
|
+
'NotIn',
|
|
1000
|
+
'None',
|
|
1001
|
+
]);
|
|
1002
|
+
/** `Integer` e `Number` sono intercambiabili fra loro. */
|
|
1003
|
+
const NUMERIC_TYPES = new Set(['Integer', 'Number']);
|
|
1004
|
+
/**
|
|
1005
|
+
* `true` → per questo operatore i due lati devono essere compatibili.
|
|
1006
|
+
* `isUnary` arriva dal dizionario: un unario non ha un termine di confronto.
|
|
1007
|
+
*/
|
|
1008
|
+
function isTypeCheckedOperator(operator, isUnary) {
|
|
1009
|
+
if (!operator || isUnary) {
|
|
1010
|
+
return false;
|
|
1011
|
+
}
|
|
1012
|
+
return !OPERATORS_WITHOUT_TYPE_CHECK.has(operator);
|
|
1013
|
+
}
|
|
1014
|
+
function isNumericType(dataType) {
|
|
1015
|
+
return !!dataType && NUMERIC_TYPES.has(dataType);
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* `false` solo per la coppia vietata: testo con numero.
|
|
1019
|
+
*
|
|
1020
|
+
* È l'**unica** coppia vietata. Un `Enum` confrontato con un testo resta lecito, perche' un
|
|
1021
|
+
* enum si confronta anche per nome; e con un tipo ignoto da un lato non si segnala nulla,
|
|
1022
|
+
* perche' non sapere non e' sapere che e' sbagliato.
|
|
1023
|
+
*/
|
|
1024
|
+
function areTypesComparable(left, right) {
|
|
1025
|
+
if (!left || !right) {
|
|
1026
|
+
return true;
|
|
1027
|
+
}
|
|
1028
|
+
if (isNumericType(left) && right === 'String') {
|
|
1029
|
+
return false;
|
|
1030
|
+
}
|
|
1031
|
+
if (left === 'String' && isNumericType(right)) {
|
|
1032
|
+
return false;
|
|
1033
|
+
}
|
|
1034
|
+
return true;
|
|
1035
|
+
}
|
|
1036
|
+
/**
|
|
1037
|
+
* I numeri viaggiano in **cultura invariante**: il separatore decimale e' il punto, la virgola
|
|
1038
|
+
* non e' accettata (§4.3). Un campo che mostra `1.234,50` deve scrivere `1234.50`.
|
|
1039
|
+
*
|
|
1040
|
+
* Accetta la virgola come separatore decimale digitato — e' quello che un utente italiano
|
|
1041
|
+
* scrive — e la traduce, invece di lasciare che `parseFloat` tronchi silenziosamente a `1`.
|
|
1042
|
+
*/
|
|
1043
|
+
function parseInvariantNumber(raw) {
|
|
1044
|
+
const trimmed = raw.trim();
|
|
1045
|
+
if (!trimmed) {
|
|
1046
|
+
return undefined;
|
|
1047
|
+
}
|
|
1048
|
+
// Una sola virgola e nessun punto: e' il separatore decimale.
|
|
1049
|
+
const normalized = !trimmed.includes('.') && (trimmed.match(/,/g) ?? []).length === 1
|
|
1050
|
+
? trimmed.replace(',', '.')
|
|
1051
|
+
: trimmed;
|
|
1052
|
+
if (!/^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$/.test(normalized)) {
|
|
1053
|
+
return undefined;
|
|
1054
|
+
}
|
|
1055
|
+
const parsed = Number(normalized);
|
|
1056
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* Gli step di uno stage di orchestrazione — FRONTEND.md §5.13.
|
|
1061
|
+
*
|
|
1062
|
+
* Tre regole del contratto che non si vedono guardando il tipo, e che qui stanno in un posto
|
|
1063
|
+
* solo perche' le usano l'inspector, lo spazio dei nomi del documento e la validazione locale:
|
|
1064
|
+
*
|
|
1065
|
+
* 1. il `name` di uno step vive nello **stesso spazio dei nomi** di node e risorse (§3.3):
|
|
1066
|
+
* uno step omonimo di una variabile e' `NAME_DUPLICATED`;
|
|
1067
|
+
* 2. l'output di uno step e' sempre referenziabile come `<NomeStep>.<NomeOutput>`, ma una
|
|
1068
|
+
* condizione **non** puo' referenziarlo: finche' lo step non ha girato il riferimento e'
|
|
1069
|
+
* irrisolvibile, e a runtime un riferimento irrisolvibile e' un errore;
|
|
1070
|
+
* 3. gli step non sono una sequenza: l'ordine nell'array e' solo l'ordine d'esame.
|
|
1071
|
+
*/
|
|
1072
|
+
/** I nomi di tutti gli step del documento: entrano nello spazio dei nomi comune (§3.3). */
|
|
1073
|
+
function stageStepNames(definition) {
|
|
1074
|
+
const names = [];
|
|
1075
|
+
for (const stage of definition.orchestratedStages ?? []) {
|
|
1076
|
+
for (const step of stage.stageSteps ?? []) {
|
|
1077
|
+
if (step.name) {
|
|
1078
|
+
names.push(step.name);
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
return names;
|
|
1083
|
+
}
|
|
1084
|
+
/** Gli step di uno stage, con l'array assente trattato come vuoto. */
|
|
1085
|
+
function stepsOf(stage) {
|
|
1086
|
+
return stage?.stageSteps ?? [];
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Il nome dello step il cui output un riferimento sta leggendo, se e' uno degli step passati.
|
|
1090
|
+
* `undefined` quando il riferimento e' legittimo. Serve a impedire nell'editor la condizione
|
|
1091
|
+
* che referenzia l'output di un altro step (§5.13, punto 4): la strada corretta e' scrivere
|
|
1092
|
+
* quel risultato in una variabile con `outputParameters.assignToReference` e condizionare
|
|
1093
|
+
* su quella.
|
|
1094
|
+
*/
|
|
1095
|
+
function stageStepOutputReferenced(reference, steps) {
|
|
1096
|
+
if (!reference) {
|
|
1097
|
+
return undefined;
|
|
1098
|
+
}
|
|
1099
|
+
const root = referenceRoot(reference.trim());
|
|
1100
|
+
return steps.find((step) => !!step.name && step.name === root)?.name;
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* L'unico output che il runtime legge da un evaluation flow di condizione. Dichiararne altri
|
|
1104
|
+
* e' `STAGE_ACTION_INVALID` (§5.13, punto 7).
|
|
1105
|
+
*/
|
|
1106
|
+
const ORCHESTRATION_CONDITION_OUTPUT = 'isOrchestrationConditionMet';
|
|
1107
|
+
|
|
949
1108
|
/**
|
|
950
1109
|
* Lo store del documento in lavorazione.
|
|
951
1110
|
*
|
|
@@ -1020,13 +1179,15 @@ class FlowDocumentStore {
|
|
|
1020
1179
|
return result;
|
|
1021
1180
|
}, ...(ngDevMode ? [{ debugName: "resources" }] : []));
|
|
1022
1181
|
/**
|
|
1023
|
-
* §3.3 — l'insieme dei nomi già usati: node **e**
|
|
1024
|
-
* Il controllo di unicita' che guarda solo le variabili lascia passare una
|
|
1025
|
-
* omonima di un node (§13.5)
|
|
1182
|
+
* §3.3 — l'insieme dei nomi già usati: node, risorse **e** step di orchestrazione, un unico
|
|
1183
|
+
* spazio di nomi. Il controllo di unicita' che guarda solo le variabili lascia passare una
|
|
1184
|
+
* variabile omonima di un node (§13.5); quello che dimentica gli step lascia passare uno
|
|
1185
|
+
* step omonimo di una variabile, che e' `NAME_DUPLICATED` allo stesso modo (§5.13).
|
|
1026
1186
|
*/
|
|
1027
1187
|
usedNames = computed(() => [
|
|
1028
1188
|
...this.nodes().map((reference) => reference.name),
|
|
1029
1189
|
...this.resources().map((reference) => reference.name),
|
|
1190
|
+
...stageStepNames(this._document()),
|
|
1030
1191
|
], ...(ngDevMode ? [{ debugName: "usedNames" }] : []));
|
|
1031
1192
|
/** Gli archi derivati dal documento, Start incluso. */
|
|
1032
1193
|
edges = computed(() => {
|
|
@@ -1418,10 +1579,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
|
|
|
1418
1579
|
/**
|
|
1419
1580
|
* Cache dei dizionari e dei cataloghi — FRONTEND.md §6.4.
|
|
1420
1581
|
*
|
|
1421
|
-
* I dizionari sono statici: si caricano una volta all'avvio dell'editor e si tengono
|
|
1422
|
-
* cache
|
|
1423
|
-
*
|
|
1424
|
-
*
|
|
1582
|
+
* I dizionari sono **quasi** statici: si caricano una volta all'avvio dell'editor e si tengono
|
|
1583
|
+
* in cache, con un'eccezione — `globalVariables` dipende dal `processType` con cui li si e'
|
|
1584
|
+
* chiesti, perche' `$Record` non esiste in uno screen flow (§4.1). Qui la cache e' quindi per
|
|
1585
|
+
* tipo di flow: cambiare `processType` nell'editor ricarica le globali, non tutto il resto
|
|
1586
|
+
* dell'esperienza.
|
|
1587
|
+
*
|
|
1588
|
+
* I cataloghi (oggetti, campi, action, form, script, eventi) cambiano raramente: sono
|
|
1589
|
+
* memoizzati per chiave, in modo che aprire dieci volte lo stesso inspector non produca dieci
|
|
1590
|
+
* richieste.
|
|
1425
1591
|
*
|
|
1426
1592
|
* Nessun elenco di enum e' cablato: se il backend aggiunge un operatore, appare nelle
|
|
1427
1593
|
* tendine senza toccare il frontend (§13.11).
|
|
@@ -1430,24 +1596,41 @@ class FlowDictionaryStore {
|
|
|
1430
1596
|
api = inject(FlowBuilderApi);
|
|
1431
1597
|
_dictionaries = signal({}, ...(ngDevMode ? [{ debugName: "_dictionaries" }] : []));
|
|
1432
1598
|
_isLoaded = signal(false, ...(ngDevMode ? [{ debugName: "_isLoaded" }] : []));
|
|
1433
|
-
|
|
1599
|
+
_processType = signal(undefined, ...(ngDevMode ? [{ debugName: "_processType" }] : []));
|
|
1600
|
+
/** Una copia per tipo di flow: le globali dipendono dal `processType` (§4.1, §6.4). */
|
|
1601
|
+
cache = new Map();
|
|
1602
|
+
/** Cresce a ogni `load`: scarta la risposta di un caricamento superato. */
|
|
1603
|
+
sequence = 0;
|
|
1434
1604
|
dictionaries = this._dictionaries.asReadonly();
|
|
1435
1605
|
isLoaded = this._isLoaded.asReadonly();
|
|
1436
|
-
/**
|
|
1437
|
-
|
|
1438
|
-
|
|
1606
|
+
/** Il `processType` dei dizionari attualmente in uso. */
|
|
1607
|
+
processType = this._processType.asReadonly();
|
|
1608
|
+
/**
|
|
1609
|
+
* Idempotente: chiamabile da ogni componente che ne ha bisogno.
|
|
1610
|
+
* Con un `processType` diverso da quello in uso ricarica — dalla cache se c'e' già —
|
|
1611
|
+
* perche' cambiare tipo di flow cambia quali globali sono proponibili.
|
|
1612
|
+
*/
|
|
1613
|
+
async load(processType) {
|
|
1614
|
+
if (this._isLoaded() && processType === this._processType()) {
|
|
1439
1615
|
return;
|
|
1440
1616
|
}
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
this.
|
|
1446
|
-
|
|
1447
|
-
.
|
|
1448
|
-
this.
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1617
|
+
const key = processType ?? '';
|
|
1618
|
+
const token = ++this.sequence;
|
|
1619
|
+
let entry = this.cache.get(key);
|
|
1620
|
+
if (!entry) {
|
|
1621
|
+
entry = this.api.getDictionaries(processType).then((dictionaries) => dictionaries ?? {});
|
|
1622
|
+
// Un errore non va memoizzato: al prossimo tentativo si riprova.
|
|
1623
|
+
entry.catch(() => this.cache.delete(key));
|
|
1624
|
+
this.cache.set(key, entry);
|
|
1625
|
+
}
|
|
1626
|
+
const dictionaries = await entry;
|
|
1627
|
+
if (token !== this.sequence) {
|
|
1628
|
+
// Un caricamento piu' recente ha già applicato un altro tipo: questo e' superato.
|
|
1629
|
+
return;
|
|
1630
|
+
}
|
|
1631
|
+
this._dictionaries.set(dictionaries);
|
|
1632
|
+
this._processType.set(processType);
|
|
1633
|
+
this._isLoaded.set(true);
|
|
1451
1634
|
}
|
|
1452
1635
|
// -------------------------------------------------------------------------
|
|
1453
1636
|
// Accessori tipizzati
|
|
@@ -1468,6 +1651,8 @@ class FlowDictionaryStore {
|
|
|
1468
1651
|
transformTypes = computed(() => this._dictionaries().transformTypes ?? [], ...(ngDevMode ? [{ debugName: "transformTypes" }] : []));
|
|
1469
1652
|
transactionModels = computed(() => this._dictionaries().transactionModels ?? [], ...(ngDevMode ? [{ debugName: "transactionModels" }] : []));
|
|
1470
1653
|
waitEventTypes = computed(() => this._dictionaries().waitEventTypes ?? [], ...(ngDevMode ? [{ debugName: "waitEventTypes" }] : []));
|
|
1654
|
+
stageStepTypes = computed(() => this._dictionaries().stageStepTypes ?? [], ...(ngDevMode ? [{ debugName: "stageStepTypes" }] : []));
|
|
1655
|
+
assigneeTypes = computed(() => this._dictionaries().assigneeTypes ?? [], ...(ngDevMode ? [{ debugName: "assigneeTypes" }] : []));
|
|
1471
1656
|
conditionLogicModes = computed(() => this._dictionaries().conditionLogicModes ?? [], ...(ngDevMode ? [{ debugName: "conditionLogicModes" }] : []));
|
|
1472
1657
|
elementTypes = computed(() => this._dictionaries().elementTypes ?? [], ...(ngDevMode ? [{ debugName: "elementTypes" }] : []));
|
|
1473
1658
|
/**
|
|
@@ -1551,6 +1736,50 @@ class FlowDictionaryStore {
|
|
|
1551
1736
|
}
|
|
1552
1737
|
return operators.filter((entry) => !entry.appliesTo || entry.appliesTo.length === 0 || entry.appliesTo.includes(dataType));
|
|
1553
1738
|
}
|
|
1739
|
+
/** La voce di `globalVariables` di uno scope: `$User`, `$Flow`, … (§4.1). */
|
|
1740
|
+
globalScope(scope) {
|
|
1741
|
+
if (!scope) {
|
|
1742
|
+
return undefined;
|
|
1743
|
+
}
|
|
1744
|
+
return this.globalVariables().find((entry) => entry.scope === scope || entry.value === scope);
|
|
1745
|
+
}
|
|
1746
|
+
/**
|
|
1747
|
+
* §4.1 — la verificabilita' e' **per scope**: se lo scope dichiara almeno un percorso, uno
|
|
1748
|
+
* che non c'e' e' `GLOBAL_UNKNOWN`; se non ne dichiara nessuno, resta non verificabile, che
|
|
1749
|
+
* significa "non lo so", non "non esiste".
|
|
1750
|
+
*/
|
|
1751
|
+
isGlobalScopeVerifiable(scope) {
|
|
1752
|
+
return (this.globalScope(scope)?.paths?.length ?? 0) > 0;
|
|
1753
|
+
}
|
|
1754
|
+
/** I percorsi noti di uno scope, già prefissati: `$User.Email`. */
|
|
1755
|
+
globalPathsOf(scope) {
|
|
1756
|
+
const entry = this.globalScope(scope);
|
|
1757
|
+
if (!entry) {
|
|
1758
|
+
return [];
|
|
1759
|
+
}
|
|
1760
|
+
const prefix = entry.scope ?? entry.value;
|
|
1761
|
+
return (entry.paths ?? []).map((path) => `${prefix}.${path}`);
|
|
1762
|
+
}
|
|
1763
|
+
/** §5.13 — la voce di `stageStepTypes` di un `actionType`. */
|
|
1764
|
+
stageStepType(value) {
|
|
1765
|
+
if (!value) {
|
|
1766
|
+
return undefined;
|
|
1767
|
+
}
|
|
1768
|
+
return this.stageStepTypes().find((entry) => entry.value === value);
|
|
1769
|
+
}
|
|
1770
|
+
/** `stepBackground` vuole `actionName`; il fallback serve se il dizionario non lo dichiara. */
|
|
1771
|
+
stageStepRequiresActionName(actionType) {
|
|
1772
|
+
const entry = this.stageStepType(actionType);
|
|
1773
|
+
return entry?.requiresActionName ?? actionType === 'stepBackground';
|
|
1774
|
+
}
|
|
1775
|
+
/** `stepInteractive` e `stepApproval` vogliono gli assegnatari (§5.13). */
|
|
1776
|
+
stageStepRequiresAssignees(actionType) {
|
|
1777
|
+
const entry = this.stageStepType(actionType);
|
|
1778
|
+
if (entry?.requiresAssignees !== undefined) {
|
|
1779
|
+
return entry.requiresAssignees;
|
|
1780
|
+
}
|
|
1781
|
+
return actionType === 'stepInteractive' || actionType === 'stepApproval';
|
|
1782
|
+
}
|
|
1554
1783
|
dataType(value) {
|
|
1555
1784
|
return this.dataTypes().find((entry) => entry.value === value);
|
|
1556
1785
|
}
|
|
@@ -2512,6 +2741,11 @@ class FlowCanvasComponent {
|
|
|
2512
2741
|
}
|
|
2513
2742
|
case 'Transform':
|
|
2514
2743
|
return node['objectType'] || null;
|
|
2744
|
+
case 'OrchestratedStage': {
|
|
2745
|
+
// Gli step non sono una sequenza: si conta quanti sono, non fino a dove si e' arrivati.
|
|
2746
|
+
const steps = node['stageSteps']?.length ?? 0;
|
|
2747
|
+
return steps ? `${steps} step` : null;
|
|
2748
|
+
}
|
|
2515
2749
|
case 'CustomError': {
|
|
2516
2750
|
const messages = node['customErrorMessages']?.length ?? 0;
|
|
2517
2751
|
return messages ? `${messages} ${messages === 1 ? 'messaggio' : 'messaggi'}` : null;
|
|
@@ -2659,11 +2893,11 @@ class FlowCanvasComponent {
|
|
|
2659
2893
|
return 'cat-other';
|
|
2660
2894
|
}
|
|
2661
2895
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: FlowCanvasComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2662
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: FlowCanvasComponent, isStandalone: true, selector: "fb-flow-canvas", inputs: { selectedName: { classPropertyName: "selectedName", publicName: "selectedName", isSignal: true, isRequired: false, transformFunction: null }, outline: { classPropertyName: "outline", publicName: "outline", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", nodeOpened: "nodeOpened", nodeRemoveRequested: "nodeRemoveRequested", nodeDuplicateRequested: "nodeDuplicateRequested", elementDropped: "elementDropped" }, ngImport: i0, template: "<!--\n Gerarchia obbligatoria: f-flow > f-canvas > fNode / f-connection.\n I `@for` sono direttamente dentro <f-canvas>: nessun wrapper, quindi non serve\n `ngProjectAs` (che sarebbe indispensabile con blocchi annidati).\n-->\n<f-flow\n fDraggable\n (fCreateConnection)=\"onCreateConnection($event)\"\n (fReassignConnection)=\"onReassignConnection($event)\"\n (fMoveNodes)=\"onMoveNodes($event)\"\n (fSelectionChange)=\"onSelectionChange($event)\"\n (fDeleteSelected)=\"onDeleteSelected($event)\"\n (fCreateNode)=\"onCreateNode($event)\"\n>\n <f-canvas fZoom>\n <f-background>\n <f-circle-pattern />\n </f-background>\n\n @for (edge of edges(); track edge.id) {\n <f-connection\n [fConnectionId]=\"edge.id\"\n [fSourceId]=\"edge.sourceId\"\n [fTargetId]=\"edge.targetId\"\n fBehavior=\"floating\"\n [fType]=\"edge.isGoTo ? 'segment' : 'bezier'\"\n [class]=\"'fb-edge fb-edge--' + edge.kind + (edge.isGoTo ? ' fb-edge--goto' : '')\"\n >\n <f-connection-marker-arrow [type]=\"markerEnd\" />\n @if (edge.label) {\n <div fConnectionContent class=\"fb-edge-label\">{{ edge.label }}</div>\n }\n </f-connection>\n }\n\n @for (node of nodes(); track node.id) {\n <div\n fNode\n fDragHandle\n [fNodeId]=\"node.id\"\n [fNodePosition]=\"node.position\"\n [class]=\"'fb-node ' + categoryClass(node) + ' ' + node.widthClass\"\n [class.fb-node--start]=\"node.isStart\"\n [class.fb-node--selected]=\"isSelected(node)\"\n [class.fb-node--unreachable]=\"!node.isReachable\"\n [class.fb-node--error]=\"node.severity === 'Error'\"\n [class.fb-node--warning]=\"node.severity === 'Warning'\"\n (dblclick)=\"onNodeDoubleClick(node.name)\"\n >\n <!--\n Lo Start non ha ingresso: e' il punto di partenza (\u00A73.4).\n `fConnectorConnectableSide` e' cio' che fa entrare l'arco dall'alto: senza, foblex\n calcola il lato e un arco che scende dal node sopra potrebbe agganciarsi di fianco.\n -->\n @if (!node.isStart) {\n <div\n fConnector\n fConnectorType=\"target\"\n [fConnectorId]=\"targetIdOf(node)\"\n [fConnectorConnectableSide]=\"sides.TOP\"\n fConnectorMultiple=\"true\"\n class=\"fb-connector fb-connector--in\"\n title=\"Ingresso\"\n ></div>\n }\n\n <div class=\"fb-node__head\">\n <span class=\"fb-node__icon\" aria-hidden=\"true\">{{ node.icon }}</span>\n <div class=\"fb-node__text\">\n <span class=\"fb-node__title\" [title]=\"node.description || node.label\">{{ node.label }}</span>\n <span class=\"fb-node__sub\">\n {{ node.typeLabel }}\n @if (node.subtitle) {\n <span class=\"fb-node__sub-dot\">\u00B7</span>{{ node.subtitle }}\n }\n </span>\n </div>\n @if (node.hasAutomaticOutput) {\n <!-- L'elemento espone il proprio risultato sotto il proprio nome (\u00A74.5). -->\n <span class=\"fb-node__auto\" title=\"Espone un output automatico referenziabile come \u00AB{{ node.name }}\u00BB\">\n \u0192\n </span>\n }\n <!--\n `fDragBlocker` impedisce che il pointerdown sul bottone diventi un trascinamento\n del node: senza, aprire il dettaglio sposterebbe l'elemento di qualche pixel.\n -->\n <button\n type=\"button\"\n fDragBlocker\n class=\"fb-node__edit\"\n [attr.aria-label]=\"'Apri il dettaglio di ' + node.label\"\n title=\"Apri il dettaglio\"\n (click)=\"onEditClick($event, node.name)\"\n >\n \u270E\n </button>\n </div>\n\n <div class=\"fb-node__meta\">\n @if (!node.isStart) {\n <span class=\"fb-node__name\" [title]=\"'Nome tecnico: ' + node.name\">{{ node.name }}</span>\n }\n @if (!node.isReachable) {\n <span class=\"fb-badge fb-badge--unreachable\" title=\"Nessun percorso raggiunge questo elemento dallo Start\">\n scollegato\n </span>\n }\n @if (node.issueCount > 0) {\n <span\n class=\"fb-badge\"\n [class.fb-badge--error]=\"node.severity === 'Error'\"\n [class.fb-badge--warning]=\"node.severity === 'Warning'\"\n [class.fb-badge--info]=\"node.severity === 'Info'\"\n [title]=\"node.issueCount + ' rilievi di validazione'\"\n >\n {{ node.issueCount }}\n </span>\n }\n @if (node.danglingOutlets.length > 0) {\n <span\n class=\"fb-badge fb-badge--dangling\"\n [title]=\"'Rami dichiarati senza destinazione: ' + danglingLabels(node)\"\n >\n ramo incompleto\n </span>\n }\n </div>\n\n <!--\n Le uscite stanno sul bordo **inferiore**, una per ramo, nell'ordine in cui il modello\n le dichiara: per una Decision e' l'ordine di valutazione delle regole, che e'\n semantico (\u00A75.3), e da sinistra a destra si legge come la lista nell'inspector.\n L'etichetta si mostra solo quando i rami sono piu' di uno: su un `next` unico\n direbbe soltanto \u00ABSuccessivo\u00BB.\n -->\n <div class=\"fb-node__outlets\" [class.fb-node__outlets--labelled]=\"node.showsOutletLabels\">\n @for (outlet of node.outlets; track outlet.key) {\n <div class=\"fb-outlet\">\n @if (node.showsOutletLabels) {\n <span class=\"fb-outlet__label\" [title]=\"outlet.label\">{{ outlet.label }}</span>\n }\n <div\n fConnector\n fConnectorType=\"source\"\n [fConnectorId]=\"connectorIdOf(node, outlet.key)\"\n [fConnectorConnectableSide]=\"sides.BOTTOM\"\n [class]=\"'fb-connector fb-connector--out fb-connector--' + outlet.kind\"\n [title]=\"outlet.label\"\n ></div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Anteprima dell'arco durante il trascinamento. -->\n <f-connection-for-create fBehavior=\"floating\" fType=\"bezier\" class=\"fb-edge fb-edge--creating\">\n <f-connection-marker-arrow [type]=\"markerEnd\" />\n </f-connection-for-create>\n\n <f-selection-area />\n </f-canvas>\n\n <f-minimap [fMinSize]=\"1200\" class=\"fb-minimap\" />\n</f-flow>\n", styles: [":host{display:block;position:relative;width:100%;height:100%;overflow:hidden;background:var(--fb-canvas-bg, #f4f5f7)}f-flow{display:block;width:100%;height:100%}.fb-minimap{position:absolute;right:14px;bottom:14px;width:190px;height:130px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-md, 0 6px 18px rgb(16 24 40 / 10%));overflow:hidden}.fb-node{position:absolute;display:flex;flex-direction:column;box-sizing:border-box;width:240px;padding:0;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-lg, 12px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));font:inherit;cursor:grab;-webkit-user-select:none;user-select:none;transition:box-shadow .12s ease,border-color .12s ease}.fb-node--outlets-3{width:304px}.fb-node--outlets-4{width:380px}.fb-node--outlets-5{width:456px}.fb-node--outlets-6{width:520px}.fb-node:hover{box-shadow:var(--fb-shadow-md, 0 6px 18px rgb(16 24 40 / 10%))}.fb-node--selected{border-color:var(--fb-accent, #4f6ef7);box-shadow:0 0 0 3px color-mix(in srgb,var(--fb-accent, #4f6ef7) 22%,transparent)}.fb-node--unreachable{border-style:dashed;opacity:.8}.fb-node--error{border-color:var(--fb-error, #c9372c)}.fb-node--warning{border-color:var(--fb-warning, #b7791f)}.fb-node__head{display:flex;align-items:center;gap:8px;padding:10px 10px 6px 12px}.fb-node__icon{display:grid;place-items:center;flex:0 0 auto;width:28px;height:28px;border-radius:var(--fb-radius-sm, 8px);background:var(--fb-node-accent, #667085);color:#fff;font-size:14px;line-height:1}.cat-start{--fb-node-accent: #22a06b}.cat-screen{--fb-node-accent: #3b82f6}.cat-logic{--fb-node-accent: #8b5cf6}.cat-data{--fb-node-accent: #06b6d4}.cat-action{--fb-node-accent: #f59e0b}.cat-flow{--fb-node-accent: #14b8a6}.cat-other{--fb-node-accent: #667085}.fb-node__text{flex:1;min-width:0}.fb-node__title{display:block;font-size:13px;font-weight:600;line-height:17px;color:var(--fb-text, #1a1c23);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-node__sub{display:block;margin-top:1px;font-size:11px;line-height:14px;color:var(--fb-text-muted, #6b7086);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-node__sub-dot{margin:0 4px;color:var(--fb-text-subtle, #98a2b3)}.fb-node__auto{flex:0 0 auto;font-size:12px;font-weight:700;color:var(--fb-accent, #4f6ef7);cursor:help}.fb-node__edit{display:grid;place-items:center;flex:0 0 auto;width:22px;height:22px;padding:0;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-text-subtle, #98a2b3);font:inherit;font-size:12px;cursor:pointer;opacity:0;transition:opacity .12s ease,background .12s ease}.fb-node:hover .fb-node__edit,.fb-node--selected .fb-node__edit,.fb-node__edit:focus-visible{opacity:1}.fb-node__edit:hover{background:var(--fb-surface-alt, #f7f8fa);color:var(--fb-text, #1a1c23)}.fb-node__meta{display:flex;flex-wrap:wrap;align-items:center;gap:4px;min-height:14px;padding:0 12px 6px}.fb-node__name{flex:0 1 auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;color:var(--fb-text-subtle, #98a2b3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-badge{padding:1px 6px;border-radius:10px;background:var(--fb-badge-bg, #eef0f4);font-size:10px;font-weight:600;color:var(--fb-text-muted, #6b7086);white-space:nowrap;cursor:help}.fb-badge--error{background:color-mix(in srgb,var(--fb-error, #c9372c) 14%,transparent);color:var(--fb-error, #c9372c)}.fb-badge--warning{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-badge--info{background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 12%,transparent);color:var(--fb-accent, #4f6ef7)}.fb-badge--unreachable,.fb-badge--dangling{background:color-mix(in srgb,var(--fb-warning, #b7791f) 12%,transparent);color:var(--fb-warning, #b7791f)}.fb-node__outlets{display:flex;align-items:flex-end;justify-content:space-evenly;gap:4px;padding:0 8px 4px}.fb-node__outlets--labelled{padding-top:5px;border-top:1px solid var(--fb-border-subtle, #eef0f4)}.fb-outlet{display:flex;flex:1 1 0;flex-direction:column;align-items:center;gap:2px;min-width:0}.fb-outlet__label{max-width:100%;font-size:10px;line-height:13px;color:var(--fb-text-muted, #6b7086);text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-connector{box-sizing:border-box;width:12px;height:12px;flex:0 0 auto;border:2px solid var(--fb-surface, #fff);border-radius:50%;background:var(--fb-connector, #98a2b3);cursor:crosshair;transition:transform .12s ease,box-shadow .12s ease}f-flow .fb-connector--out{position:relative;inset:auto;margin-bottom:-12px}.fb-connector--out:hover{transform:scale(1.2)}f-flow .fb-connector--in{position:absolute;inset:-2px auto auto 50%;width:24px;height:4px;border:0;border-radius:2px;transform:translate(-50%);background:var(--fb-border-strong, #cfd4de)}.fb-connector--out{--ff-connector-connected-color: var(--fb-connector, #98a2b3)}.fb-connector--Next,.fb-connector--Start,.fb-connector--LoopNext{--fb-connector: var(--fb-edge-next, #98a2b3)}.fb-connector--Rule,.fb-connector--WaitEvent{--fb-connector: var(--fb-edge-rule, #8b5cf6)}.fb-connector--Default,.fb-connector--LoopEnd{--fb-connector: var(--fb-edge-default, #06b6d4)}.fb-connector--Fault{--fb-connector: var(--fb-edge-fault, #dc2626)}.fb-connector--Timeout,.fb-connector--ScheduledPath{--fb-connector: var(--fb-edge-timeout, #f59e0b)}.fb-connector.f-connector-connectable{box-shadow:0 0 0 4px color-mix(in srgb,var(--fb-accent, #4f6ef7) 28%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: FFlowModule }, { kind: "component", type: i1.FFlowComponent, selector: "f-flow", inputs: ["fFlowId", "fCache"], outputs: ["fNodesRendered", "fFullRendered", "fLoaded"] }, { kind: "component", type: i1.FCanvasComponent, selector: "f-canvas", inputs: ["position", "scale", "debounceTime", "fLayers"], outputs: ["fCanvasChange"] }, { kind: "component", type: i1.FBackgroundComponent, selector: "f-background" }, { kind: "component", type: i1.FCirclePatternComponent, selector: "f-circle-pattern", inputs: ["id", "color", "radius"] }, { kind: "directive", type: i1.FZoomDirective, selector: "f-canvas[fZoom]", inputs: ["fZoom", "fWheelTrigger", "fDblClickTrigger", "fZoomMinimum", "fZoomMaximum", "fZoomStep", "fPinchStep", "fZoomDblClickStep"] }, { kind: "component", type: i1.FSelectionArea, selector: "f-selection-area", inputs: ["fTrigger"] }, { kind: "directive", type: i1.FConnectionContent, selector: "[fConnectionContent]", inputs: ["position", "offset", "align"] }, { kind: "component", type: i1.FConnectionMarkerArrow, selector: "f-connection-marker-arrow", inputs: ["type"] }, { kind: "component", type: i1.FConnectionComponent, selector: "f-connection", inputs: ["fConnectionId", "fSourceId", "fTargetId", "fOutputId", "fInputId", "fRadius", "fOffset", "fBehavior", "fType", "fSelectionDisabled", "fReassignableStart", "fReassignDisabled", "fSourceSide", "fTargetSide", "fInputSide", "fOutputSide"], exportAs: ["fComponent"] }, { kind: "component", type: i1.FConnectionForCreateComponent, selector: "f-connection-for-create", inputs: ["fRadius", "fOffset", "fBehavior", "fType", "fInputSide", "fOutputSide"] }, { kind: "directive", type: i1.FConnectorDirective, selector: "[fConnector]", inputs: ["fConnectorId", "fConnectorType", "fConnectorDisabled", "fConnectorMultiple", "fConnectorCategory", "fConnectorConnectableSide", "fConnectorSelfConnectable", "fCanBeConnectedTo", "fConnectionFromOutlet"], exportAs: ["fConnector"] }, { kind: "component", type: i1.FMinimapComponent, selector: "f-minimap", inputs: ["fMinSize", "fNodeRenderLimit"], exportAs: ["fComponent"] }, { kind: "directive", type: i1.FNodeDirective, selector: "[fNode]", inputs: ["fNodeId", "fNodeParentId", "fNodePosition", "fNodeSize", "fNodeRotate", "fConnectOnNode", "fMinimapClass", "fNodeDraggingDisabled", "fNodeSelectionDisabled", "fIncludePadding", "fAutoExpandOnChildHit", "fAutoSizeToFitChildren"], outputs: ["fNodePositionChange", "fNodeSizeChange", "fNodeRotateChange"], exportAs: ["fComponent"] }, { kind: "directive", type: i1.FDragHandleDirective, selector: "[fDragHandle]" }, { kind: "directive", type: i1.FDragBlockerDirective, selector: "[fDragBlocker]" }, { kind: "directive", type: i1.FDraggableDirective, selector: "f-flow[fDraggable]", inputs: ["fDraggableDisabled", "fDropToGroup", "fMultiSelectTrigger", "fReassignConnectionTrigger", "fCreateConnectionTrigger", "fConnectionWaypointsTrigger", "fMoveControlPointTrigger", "fNodeResizeTrigger", "fNodeRotateTrigger", "fNodeMoveTrigger", "fCanvasMoveTrigger", "fExternalItemTrigger", "fEmitOnNodeIntersect", "vCellSize", "hCellSize", "fCellSizeWhileDragging"], outputs: ["fSelectionChange", "fDeleteSelected", "fNodeIntersectedWithConnections", "fNodeConnectionsIntersection", "fCreateNode", "fMoveNodes", "fReassignConnection", "fCreateConnection", "fConnectionWaypointsChanged", "fDropToGroup", "fDragStarted", "fDragEnded"], exportAs: ["fDraggable"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2896
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: FlowCanvasComponent, isStandalone: true, selector: "fb-flow-canvas", inputs: { selectedName: { classPropertyName: "selectedName", publicName: "selectedName", isSignal: true, isRequired: false, transformFunction: null }, outline: { classPropertyName: "outline", publicName: "outline", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", nodeOpened: "nodeOpened", nodeRemoveRequested: "nodeRemoveRequested", nodeDuplicateRequested: "nodeDuplicateRequested", elementDropped: "elementDropped" }, ngImport: i0, template: "<!--\r\n Gerarchia obbligatoria: f-flow > f-canvas > fNode / f-connection.\r\n I `@for` sono direttamente dentro <f-canvas>: nessun wrapper, quindi non serve\r\n `ngProjectAs` (che sarebbe indispensabile con blocchi annidati).\r\n-->\r\n<f-flow\r\n fDraggable\r\n (fCreateConnection)=\"onCreateConnection($event)\"\r\n (fReassignConnection)=\"onReassignConnection($event)\"\r\n (fMoveNodes)=\"onMoveNodes($event)\"\r\n (fSelectionChange)=\"onSelectionChange($event)\"\r\n (fDeleteSelected)=\"onDeleteSelected($event)\"\r\n (fCreateNode)=\"onCreateNode($event)\"\r\n>\r\n <f-canvas fZoom>\r\n <f-background>\r\n <f-circle-pattern />\r\n </f-background>\r\n\r\n @for (edge of edges(); track edge.id) {\r\n <f-connection\r\n [fConnectionId]=\"edge.id\"\r\n [fSourceId]=\"edge.sourceId\"\r\n [fTargetId]=\"edge.targetId\"\r\n fBehavior=\"floating\"\r\n [fType]=\"edge.isGoTo ? 'segment' : 'bezier'\"\r\n [class]=\"'fb-edge fb-edge--' + edge.kind + (edge.isGoTo ? ' fb-edge--goto' : '')\"\r\n >\r\n <f-connection-marker-arrow [type]=\"markerEnd\" />\r\n @if (edge.label) {\r\n <div fConnectionContent class=\"fb-edge-label\">{{ edge.label }}</div>\r\n }\r\n </f-connection>\r\n }\r\n\r\n @for (node of nodes(); track node.id) {\r\n <div\r\n fNode\r\n fDragHandle\r\n [fNodeId]=\"node.id\"\r\n [fNodePosition]=\"node.position\"\r\n [class]=\"'fb-node ' + categoryClass(node) + ' ' + node.widthClass\"\r\n [class.fb-node--start]=\"node.isStart\"\r\n [class.fb-node--selected]=\"isSelected(node)\"\r\n [class.fb-node--unreachable]=\"!node.isReachable\"\r\n [class.fb-node--error]=\"node.severity === 'Error'\"\r\n [class.fb-node--warning]=\"node.severity === 'Warning'\"\r\n (dblclick)=\"onNodeDoubleClick(node.name)\"\r\n >\r\n <!--\r\n Lo Start non ha ingresso: e' il punto di partenza (\u00A73.4).\r\n `fConnectorConnectableSide` e' cio' che fa entrare l'arco dall'alto: senza, foblex\r\n calcola il lato e un arco che scende dal node sopra potrebbe agganciarsi di fianco.\r\n -->\r\n @if (!node.isStart) {\r\n <div\r\n fConnector\r\n fConnectorType=\"target\"\r\n [fConnectorId]=\"targetIdOf(node)\"\r\n [fConnectorConnectableSide]=\"sides.TOP\"\r\n fConnectorMultiple=\"true\"\r\n class=\"fb-connector fb-connector--in\"\r\n title=\"Ingresso\"\r\n ></div>\r\n }\r\n\r\n <div class=\"fb-node__head\">\r\n <span class=\"fb-node__icon\" aria-hidden=\"true\">{{ node.icon }}</span>\r\n <div class=\"fb-node__text\">\r\n <span class=\"fb-node__title\" [title]=\"node.description || node.label\">{{ node.label }}</span>\r\n <span class=\"fb-node__sub\">\r\n {{ node.typeLabel }}\r\n @if (node.subtitle) {\r\n <span class=\"fb-node__sub-dot\">\u00B7</span>{{ node.subtitle }}\r\n }\r\n </span>\r\n </div>\r\n @if (node.hasAutomaticOutput) {\r\n <!-- L'elemento espone il proprio risultato sotto il proprio nome (\u00A74.5). -->\r\n <span class=\"fb-node__auto\" title=\"Espone un output automatico referenziabile come \u00AB{{ node.name }}\u00BB\">\r\n \u0192\r\n </span>\r\n }\r\n <!--\r\n `fDragBlocker` impedisce che il pointerdown sul bottone diventi un trascinamento\r\n del node: senza, aprire il dettaglio sposterebbe l'elemento di qualche pixel.\r\n -->\r\n <button\r\n type=\"button\"\r\n fDragBlocker\r\n class=\"fb-node__edit\"\r\n [attr.aria-label]=\"'Apri il dettaglio di ' + node.label\"\r\n title=\"Apri il dettaglio\"\r\n (click)=\"onEditClick($event, node.name)\"\r\n >\r\n \u270E\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-node__meta\">\r\n @if (!node.isStart) {\r\n <span class=\"fb-node__name\" [title]=\"'Nome tecnico: ' + node.name\">{{ node.name }}</span>\r\n }\r\n @if (!node.isReachable) {\r\n <span class=\"fb-badge fb-badge--unreachable\" title=\"Nessun percorso raggiunge questo elemento dallo Start\">\r\n scollegato\r\n </span>\r\n }\r\n @if (node.issueCount > 0) {\r\n <span\r\n class=\"fb-badge\"\r\n [class.fb-badge--error]=\"node.severity === 'Error'\"\r\n [class.fb-badge--warning]=\"node.severity === 'Warning'\"\r\n [class.fb-badge--info]=\"node.severity === 'Info'\"\r\n [title]=\"node.issueCount + ' rilievi di validazione'\"\r\n >\r\n {{ node.issueCount }}\r\n </span>\r\n }\r\n @if (node.danglingOutlets.length > 0) {\r\n <span\r\n class=\"fb-badge fb-badge--dangling\"\r\n [title]=\"'Rami dichiarati senza destinazione: ' + danglingLabels(node)\"\r\n >\r\n ramo incompleto\r\n </span>\r\n }\r\n </div>\r\n\r\n <!--\r\n Le uscite stanno sul bordo **inferiore**, una per ramo, nell'ordine in cui il modello\r\n le dichiara: per una Decision e' l'ordine di valutazione delle regole, che e'\r\n semantico (\u00A75.3), e da sinistra a destra si legge come la lista nell'inspector.\r\n L'etichetta si mostra solo quando i rami sono piu' di uno: su un `next` unico\r\n direbbe soltanto \u00ABSuccessivo\u00BB.\r\n -->\r\n <div class=\"fb-node__outlets\" [class.fb-node__outlets--labelled]=\"node.showsOutletLabels\">\r\n @for (outlet of node.outlets; track outlet.key) {\r\n <div class=\"fb-outlet\">\r\n @if (node.showsOutletLabels) {\r\n <span class=\"fb-outlet__label\" [title]=\"outlet.label\">{{ outlet.label }}</span>\r\n }\r\n <div\r\n fConnector\r\n fConnectorType=\"source\"\r\n [fConnectorId]=\"connectorIdOf(node, outlet.key)\"\r\n [fConnectorConnectableSide]=\"sides.BOTTOM\"\r\n [class]=\"'fb-connector fb-connector--out fb-connector--' + outlet.kind\"\r\n [title]=\"outlet.label\"\r\n ></div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Anteprima dell'arco durante il trascinamento. -->\r\n <f-connection-for-create fBehavior=\"floating\" fType=\"bezier\" class=\"fb-edge fb-edge--creating\">\r\n <f-connection-marker-arrow [type]=\"markerEnd\" />\r\n </f-connection-for-create>\r\n\r\n <f-selection-area />\r\n </f-canvas>\r\n\r\n <f-minimap [fMinSize]=\"1200\" class=\"fb-minimap\" />\r\n</f-flow>\r\n", styles: [":host{display:block;position:relative;width:100%;height:100%;overflow:hidden;background:var(--fb-canvas-bg, #f4f5f7)}f-flow{display:block;width:100%;height:100%}.fb-minimap{position:absolute;right:14px;bottom:14px;width:190px;height:130px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-md, 0 6px 18px rgb(16 24 40 / 10%));overflow:hidden}.fb-node{position:absolute;display:flex;flex-direction:column;box-sizing:border-box;width:240px;padding:0;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-lg, 12px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));font:inherit;cursor:grab;-webkit-user-select:none;user-select:none;transition:box-shadow .12s ease,border-color .12s ease}.fb-node--outlets-3{width:304px}.fb-node--outlets-4{width:380px}.fb-node--outlets-5{width:456px}.fb-node--outlets-6{width:520px}.fb-node:hover{box-shadow:var(--fb-shadow-md, 0 6px 18px rgb(16 24 40 / 10%))}.fb-node--selected{border-color:var(--fb-accent, #4f6ef7);box-shadow:0 0 0 3px color-mix(in srgb,var(--fb-accent, #4f6ef7) 22%,transparent)}.fb-node--unreachable{border-style:dashed;opacity:.8}.fb-node--error{border-color:var(--fb-error, #c9372c)}.fb-node--warning{border-color:var(--fb-warning, #b7791f)}.fb-node__head{display:flex;align-items:center;gap:8px;padding:10px 10px 6px 12px}.fb-node__icon{display:grid;place-items:center;flex:0 0 auto;width:28px;height:28px;border-radius:var(--fb-radius-sm, 8px);background:var(--fb-node-accent, #667085);color:#fff;font-size:14px;line-height:1}.cat-start{--fb-node-accent: #22a06b}.cat-screen{--fb-node-accent: #3b82f6}.cat-logic{--fb-node-accent: #8b5cf6}.cat-data{--fb-node-accent: #06b6d4}.cat-action{--fb-node-accent: #f59e0b}.cat-flow{--fb-node-accent: #14b8a6}.cat-other{--fb-node-accent: #667085}.fb-node__text{flex:1;min-width:0}.fb-node__title{display:block;font-size:13px;font-weight:600;line-height:17px;color:var(--fb-text, #1a1c23);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-node__sub{display:block;margin-top:1px;font-size:11px;line-height:14px;color:var(--fb-text-muted, #6b7086);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-node__sub-dot{margin:0 4px;color:var(--fb-text-subtle, #98a2b3)}.fb-node__auto{flex:0 0 auto;font-size:12px;font-weight:700;color:var(--fb-accent, #4f6ef7);cursor:help}.fb-node__edit{display:grid;place-items:center;flex:0 0 auto;width:22px;height:22px;padding:0;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-text-subtle, #98a2b3);font:inherit;font-size:12px;cursor:pointer;opacity:0;transition:opacity .12s ease,background .12s ease}.fb-node:hover .fb-node__edit,.fb-node--selected .fb-node__edit,.fb-node__edit:focus-visible{opacity:1}.fb-node__edit:hover{background:var(--fb-surface-alt, #f7f8fa);color:var(--fb-text, #1a1c23)}.fb-node__meta{display:flex;flex-wrap:wrap;align-items:center;gap:4px;min-height:14px;padding:0 12px 6px}.fb-node__name{flex:0 1 auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;color:var(--fb-text-subtle, #98a2b3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-badge{padding:1px 6px;border-radius:10px;background:var(--fb-badge-bg, #eef0f4);font-size:10px;font-weight:600;color:var(--fb-text-muted, #6b7086);white-space:nowrap;cursor:help}.fb-badge--error{background:color-mix(in srgb,var(--fb-error, #c9372c) 14%,transparent);color:var(--fb-error, #c9372c)}.fb-badge--warning{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-badge--info{background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 12%,transparent);color:var(--fb-accent, #4f6ef7)}.fb-badge--unreachable,.fb-badge--dangling{background:color-mix(in srgb,var(--fb-warning, #b7791f) 12%,transparent);color:var(--fb-warning, #b7791f)}.fb-node__outlets{display:flex;align-items:flex-end;justify-content:space-evenly;gap:4px;padding:0 8px 4px}.fb-node__outlets--labelled{padding-top:5px;border-top:1px solid var(--fb-border-subtle, #eef0f4)}.fb-outlet{display:flex;flex:1 1 0;flex-direction:column;align-items:center;gap:2px;min-width:0}.fb-outlet__label{max-width:100%;font-size:10px;line-height:13px;color:var(--fb-text-muted, #6b7086);text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-connector{box-sizing:border-box;width:12px;height:12px;flex:0 0 auto;border:2px solid var(--fb-surface, #fff);border-radius:50%;background:var(--fb-connector, #98a2b3);cursor:crosshair;transition:transform .12s ease,box-shadow .12s ease}f-flow .fb-connector--out{position:relative;inset:auto;margin-bottom:-12px}.fb-connector--out:hover{transform:scale(1.2)}f-flow .fb-connector--in{position:absolute;inset:-2px auto auto 50%;width:24px;height:4px;border:0;border-radius:2px;transform:translate(-50%);background:var(--fb-border-strong, #cfd4de)}.fb-connector--out{--ff-connector-connected-color: var(--fb-connector, #98a2b3)}.fb-connector--Next,.fb-connector--Start,.fb-connector--LoopNext{--fb-connector: var(--fb-edge-next, #98a2b3)}.fb-connector--Rule,.fb-connector--WaitEvent{--fb-connector: var(--fb-edge-rule, #8b5cf6)}.fb-connector--Default,.fb-connector--LoopEnd{--fb-connector: var(--fb-edge-default, #06b6d4)}.fb-connector--Fault{--fb-connector: var(--fb-edge-fault, #dc2626)}.fb-connector--Timeout,.fb-connector--ScheduledPath{--fb-connector: var(--fb-edge-timeout, #f59e0b)}.fb-connector.f-connector-connectable{box-shadow:0 0 0 4px color-mix(in srgb,var(--fb-accent, #4f6ef7) 28%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: FFlowModule }, { kind: "component", type: i1.FFlowComponent, selector: "f-flow", inputs: ["fFlowId", "fCache"], outputs: ["fNodesRendered", "fFullRendered", "fLoaded"] }, { kind: "component", type: i1.FCanvasComponent, selector: "f-canvas", inputs: ["position", "scale", "debounceTime", "fLayers"], outputs: ["fCanvasChange"] }, { kind: "component", type: i1.FBackgroundComponent, selector: "f-background" }, { kind: "component", type: i1.FCirclePatternComponent, selector: "f-circle-pattern", inputs: ["id", "color", "radius"] }, { kind: "directive", type: i1.FZoomDirective, selector: "f-canvas[fZoom]", inputs: ["fZoom", "fWheelTrigger", "fDblClickTrigger", "fZoomMinimum", "fZoomMaximum", "fZoomStep", "fPinchStep", "fZoomDblClickStep"] }, { kind: "component", type: i1.FSelectionArea, selector: "f-selection-area", inputs: ["fTrigger"] }, { kind: "directive", type: i1.FConnectionContent, selector: "[fConnectionContent]", inputs: ["position", "offset", "align"] }, { kind: "component", type: i1.FConnectionMarkerArrow, selector: "f-connection-marker-arrow", inputs: ["type"] }, { kind: "component", type: i1.FConnectionComponent, selector: "f-connection", inputs: ["fConnectionId", "fSourceId", "fTargetId", "fOutputId", "fInputId", "fRadius", "fOffset", "fBehavior", "fType", "fSelectionDisabled", "fReassignableStart", "fReassignDisabled", "fSourceSide", "fTargetSide", "fInputSide", "fOutputSide"], exportAs: ["fComponent"] }, { kind: "component", type: i1.FConnectionForCreateComponent, selector: "f-connection-for-create", inputs: ["fRadius", "fOffset", "fBehavior", "fType", "fInputSide", "fOutputSide"] }, { kind: "directive", type: i1.FConnectorDirective, selector: "[fConnector]", inputs: ["fConnectorId", "fConnectorType", "fConnectorDisabled", "fConnectorMultiple", "fConnectorCategory", "fConnectorConnectableSide", "fConnectorSelfConnectable", "fCanBeConnectedTo", "fConnectionFromOutlet"], exportAs: ["fConnector"] }, { kind: "component", type: i1.FMinimapComponent, selector: "f-minimap", inputs: ["fMinSize", "fNodeRenderLimit"], exportAs: ["fComponent"] }, { kind: "directive", type: i1.FNodeDirective, selector: "[fNode]", inputs: ["fNodeId", "fNodeParentId", "fNodePosition", "fNodeSize", "fNodeRotate", "fConnectOnNode", "fMinimapClass", "fNodeDraggingDisabled", "fNodeSelectionDisabled", "fIncludePadding", "fAutoExpandOnChildHit", "fAutoSizeToFitChildren"], outputs: ["fNodePositionChange", "fNodeSizeChange", "fNodeRotateChange"], exportAs: ["fComponent"] }, { kind: "directive", type: i1.FDragHandleDirective, selector: "[fDragHandle]" }, { kind: "directive", type: i1.FDragBlockerDirective, selector: "[fDragBlocker]" }, { kind: "directive", type: i1.FDraggableDirective, selector: "f-flow[fDraggable]", inputs: ["fDraggableDisabled", "fDropToGroup", "fMultiSelectTrigger", "fReassignConnectionTrigger", "fCreateConnectionTrigger", "fConnectionWaypointsTrigger", "fMoveControlPointTrigger", "fNodeResizeTrigger", "fNodeRotateTrigger", "fNodeMoveTrigger", "fCanvasMoveTrigger", "fExternalItemTrigger", "fEmitOnNodeIntersect", "vCellSize", "hCellSize", "fCellSizeWhileDragging"], outputs: ["fSelectionChange", "fDeleteSelected", "fNodeIntersectedWithConnections", "fNodeConnectionsIntersection", "fCreateNode", "fMoveNodes", "fReassignConnection", "fCreateConnection", "fConnectionWaypointsChanged", "fDropToGroup", "fDragStarted", "fDragEnded"], exportAs: ["fDraggable"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2663
2897
|
}
|
|
2664
2898
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: FlowCanvasComponent, decorators: [{
|
|
2665
2899
|
type: Component,
|
|
2666
|
-
args: [{ selector: 'fb-flow-canvas', standalone: true, imports: [FFlowModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\n Gerarchia obbligatoria: f-flow > f-canvas > fNode / f-connection.\n I `@for` sono direttamente dentro <f-canvas>: nessun wrapper, quindi non serve\n `ngProjectAs` (che sarebbe indispensabile con blocchi annidati).\n-->\n<f-flow\n fDraggable\n (fCreateConnection)=\"onCreateConnection($event)\"\n (fReassignConnection)=\"onReassignConnection($event)\"\n (fMoveNodes)=\"onMoveNodes($event)\"\n (fSelectionChange)=\"onSelectionChange($event)\"\n (fDeleteSelected)=\"onDeleteSelected($event)\"\n (fCreateNode)=\"onCreateNode($event)\"\n>\n <f-canvas fZoom>\n <f-background>\n <f-circle-pattern />\n </f-background>\n\n @for (edge of edges(); track edge.id) {\n <f-connection\n [fConnectionId]=\"edge.id\"\n [fSourceId]=\"edge.sourceId\"\n [fTargetId]=\"edge.targetId\"\n fBehavior=\"floating\"\n [fType]=\"edge.isGoTo ? 'segment' : 'bezier'\"\n [class]=\"'fb-edge fb-edge--' + edge.kind + (edge.isGoTo ? ' fb-edge--goto' : '')\"\n >\n <f-connection-marker-arrow [type]=\"markerEnd\" />\n @if (edge.label) {\n <div fConnectionContent class=\"fb-edge-label\">{{ edge.label }}</div>\n }\n </f-connection>\n }\n\n @for (node of nodes(); track node.id) {\n <div\n fNode\n fDragHandle\n [fNodeId]=\"node.id\"\n [fNodePosition]=\"node.position\"\n [class]=\"'fb-node ' + categoryClass(node) + ' ' + node.widthClass\"\n [class.fb-node--start]=\"node.isStart\"\n [class.fb-node--selected]=\"isSelected(node)\"\n [class.fb-node--unreachable]=\"!node.isReachable\"\n [class.fb-node--error]=\"node.severity === 'Error'\"\n [class.fb-node--warning]=\"node.severity === 'Warning'\"\n (dblclick)=\"onNodeDoubleClick(node.name)\"\n >\n <!--\n Lo Start non ha ingresso: e' il punto di partenza (\u00A73.4).\n `fConnectorConnectableSide` e' cio' che fa entrare l'arco dall'alto: senza, foblex\n calcola il lato e un arco che scende dal node sopra potrebbe agganciarsi di fianco.\n -->\n @if (!node.isStart) {\n <div\n fConnector\n fConnectorType=\"target\"\n [fConnectorId]=\"targetIdOf(node)\"\n [fConnectorConnectableSide]=\"sides.TOP\"\n fConnectorMultiple=\"true\"\n class=\"fb-connector fb-connector--in\"\n title=\"Ingresso\"\n ></div>\n }\n\n <div class=\"fb-node__head\">\n <span class=\"fb-node__icon\" aria-hidden=\"true\">{{ node.icon }}</span>\n <div class=\"fb-node__text\">\n <span class=\"fb-node__title\" [title]=\"node.description || node.label\">{{ node.label }}</span>\n <span class=\"fb-node__sub\">\n {{ node.typeLabel }}\n @if (node.subtitle) {\n <span class=\"fb-node__sub-dot\">\u00B7</span>{{ node.subtitle }}\n }\n </span>\n </div>\n @if (node.hasAutomaticOutput) {\n <!-- L'elemento espone il proprio risultato sotto il proprio nome (\u00A74.5). -->\n <span class=\"fb-node__auto\" title=\"Espone un output automatico referenziabile come \u00AB{{ node.name }}\u00BB\">\n \u0192\n </span>\n }\n <!--\n `fDragBlocker` impedisce che il pointerdown sul bottone diventi un trascinamento\n del node: senza, aprire il dettaglio sposterebbe l'elemento di qualche pixel.\n -->\n <button\n type=\"button\"\n fDragBlocker\n class=\"fb-node__edit\"\n [attr.aria-label]=\"'Apri il dettaglio di ' + node.label\"\n title=\"Apri il dettaglio\"\n (click)=\"onEditClick($event, node.name)\"\n >\n \u270E\n </button>\n </div>\n\n <div class=\"fb-node__meta\">\n @if (!node.isStart) {\n <span class=\"fb-node__name\" [title]=\"'Nome tecnico: ' + node.name\">{{ node.name }}</span>\n }\n @if (!node.isReachable) {\n <span class=\"fb-badge fb-badge--unreachable\" title=\"Nessun percorso raggiunge questo elemento dallo Start\">\n scollegato\n </span>\n }\n @if (node.issueCount > 0) {\n <span\n class=\"fb-badge\"\n [class.fb-badge--error]=\"node.severity === 'Error'\"\n [class.fb-badge--warning]=\"node.severity === 'Warning'\"\n [class.fb-badge--info]=\"node.severity === 'Info'\"\n [title]=\"node.issueCount + ' rilievi di validazione'\"\n >\n {{ node.issueCount }}\n </span>\n }\n @if (node.danglingOutlets.length > 0) {\n <span\n class=\"fb-badge fb-badge--dangling\"\n [title]=\"'Rami dichiarati senza destinazione: ' + danglingLabels(node)\"\n >\n ramo incompleto\n </span>\n }\n </div>\n\n <!--\n Le uscite stanno sul bordo **inferiore**, una per ramo, nell'ordine in cui il modello\n le dichiara: per una Decision e' l'ordine di valutazione delle regole, che e'\n semantico (\u00A75.3), e da sinistra a destra si legge come la lista nell'inspector.\n L'etichetta si mostra solo quando i rami sono piu' di uno: su un `next` unico\n direbbe soltanto \u00ABSuccessivo\u00BB.\n -->\n <div class=\"fb-node__outlets\" [class.fb-node__outlets--labelled]=\"node.showsOutletLabels\">\n @for (outlet of node.outlets; track outlet.key) {\n <div class=\"fb-outlet\">\n @if (node.showsOutletLabels) {\n <span class=\"fb-outlet__label\" [title]=\"outlet.label\">{{ outlet.label }}</span>\n }\n <div\n fConnector\n fConnectorType=\"source\"\n [fConnectorId]=\"connectorIdOf(node, outlet.key)\"\n [fConnectorConnectableSide]=\"sides.BOTTOM\"\n [class]=\"'fb-connector fb-connector--out fb-connector--' + outlet.kind\"\n [title]=\"outlet.label\"\n ></div>\n </div>\n }\n </div>\n </div>\n }\n\n <!-- Anteprima dell'arco durante il trascinamento. -->\n <f-connection-for-create fBehavior=\"floating\" fType=\"bezier\" class=\"fb-edge fb-edge--creating\">\n <f-connection-marker-arrow [type]=\"markerEnd\" />\n </f-connection-for-create>\n\n <f-selection-area />\n </f-canvas>\n\n <f-minimap [fMinSize]=\"1200\" class=\"fb-minimap\" />\n</f-flow>\n", styles: [":host{display:block;position:relative;width:100%;height:100%;overflow:hidden;background:var(--fb-canvas-bg, #f4f5f7)}f-flow{display:block;width:100%;height:100%}.fb-minimap{position:absolute;right:14px;bottom:14px;width:190px;height:130px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-md, 0 6px 18px rgb(16 24 40 / 10%));overflow:hidden}.fb-node{position:absolute;display:flex;flex-direction:column;box-sizing:border-box;width:240px;padding:0;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-lg, 12px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));font:inherit;cursor:grab;-webkit-user-select:none;user-select:none;transition:box-shadow .12s ease,border-color .12s ease}.fb-node--outlets-3{width:304px}.fb-node--outlets-4{width:380px}.fb-node--outlets-5{width:456px}.fb-node--outlets-6{width:520px}.fb-node:hover{box-shadow:var(--fb-shadow-md, 0 6px 18px rgb(16 24 40 / 10%))}.fb-node--selected{border-color:var(--fb-accent, #4f6ef7);box-shadow:0 0 0 3px color-mix(in srgb,var(--fb-accent, #4f6ef7) 22%,transparent)}.fb-node--unreachable{border-style:dashed;opacity:.8}.fb-node--error{border-color:var(--fb-error, #c9372c)}.fb-node--warning{border-color:var(--fb-warning, #b7791f)}.fb-node__head{display:flex;align-items:center;gap:8px;padding:10px 10px 6px 12px}.fb-node__icon{display:grid;place-items:center;flex:0 0 auto;width:28px;height:28px;border-radius:var(--fb-radius-sm, 8px);background:var(--fb-node-accent, #667085);color:#fff;font-size:14px;line-height:1}.cat-start{--fb-node-accent: #22a06b}.cat-screen{--fb-node-accent: #3b82f6}.cat-logic{--fb-node-accent: #8b5cf6}.cat-data{--fb-node-accent: #06b6d4}.cat-action{--fb-node-accent: #f59e0b}.cat-flow{--fb-node-accent: #14b8a6}.cat-other{--fb-node-accent: #667085}.fb-node__text{flex:1;min-width:0}.fb-node__title{display:block;font-size:13px;font-weight:600;line-height:17px;color:var(--fb-text, #1a1c23);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-node__sub{display:block;margin-top:1px;font-size:11px;line-height:14px;color:var(--fb-text-muted, #6b7086);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-node__sub-dot{margin:0 4px;color:var(--fb-text-subtle, #98a2b3)}.fb-node__auto{flex:0 0 auto;font-size:12px;font-weight:700;color:var(--fb-accent, #4f6ef7);cursor:help}.fb-node__edit{display:grid;place-items:center;flex:0 0 auto;width:22px;height:22px;padding:0;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-text-subtle, #98a2b3);font:inherit;font-size:12px;cursor:pointer;opacity:0;transition:opacity .12s ease,background .12s ease}.fb-node:hover .fb-node__edit,.fb-node--selected .fb-node__edit,.fb-node__edit:focus-visible{opacity:1}.fb-node__edit:hover{background:var(--fb-surface-alt, #f7f8fa);color:var(--fb-text, #1a1c23)}.fb-node__meta{display:flex;flex-wrap:wrap;align-items:center;gap:4px;min-height:14px;padding:0 12px 6px}.fb-node__name{flex:0 1 auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;color:var(--fb-text-subtle, #98a2b3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-badge{padding:1px 6px;border-radius:10px;background:var(--fb-badge-bg, #eef0f4);font-size:10px;font-weight:600;color:var(--fb-text-muted, #6b7086);white-space:nowrap;cursor:help}.fb-badge--error{background:color-mix(in srgb,var(--fb-error, #c9372c) 14%,transparent);color:var(--fb-error, #c9372c)}.fb-badge--warning{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-badge--info{background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 12%,transparent);color:var(--fb-accent, #4f6ef7)}.fb-badge--unreachable,.fb-badge--dangling{background:color-mix(in srgb,var(--fb-warning, #b7791f) 12%,transparent);color:var(--fb-warning, #b7791f)}.fb-node__outlets{display:flex;align-items:flex-end;justify-content:space-evenly;gap:4px;padding:0 8px 4px}.fb-node__outlets--labelled{padding-top:5px;border-top:1px solid var(--fb-border-subtle, #eef0f4)}.fb-outlet{display:flex;flex:1 1 0;flex-direction:column;align-items:center;gap:2px;min-width:0}.fb-outlet__label{max-width:100%;font-size:10px;line-height:13px;color:var(--fb-text-muted, #6b7086);text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-connector{box-sizing:border-box;width:12px;height:12px;flex:0 0 auto;border:2px solid var(--fb-surface, #fff);border-radius:50%;background:var(--fb-connector, #98a2b3);cursor:crosshair;transition:transform .12s ease,box-shadow .12s ease}f-flow .fb-connector--out{position:relative;inset:auto;margin-bottom:-12px}.fb-connector--out:hover{transform:scale(1.2)}f-flow .fb-connector--in{position:absolute;inset:-2px auto auto 50%;width:24px;height:4px;border:0;border-radius:2px;transform:translate(-50%);background:var(--fb-border-strong, #cfd4de)}.fb-connector--out{--ff-connector-connected-color: var(--fb-connector, #98a2b3)}.fb-connector--Next,.fb-connector--Start,.fb-connector--LoopNext{--fb-connector: var(--fb-edge-next, #98a2b3)}.fb-connector--Rule,.fb-connector--WaitEvent{--fb-connector: var(--fb-edge-rule, #8b5cf6)}.fb-connector--Default,.fb-connector--LoopEnd{--fb-connector: var(--fb-edge-default, #06b6d4)}.fb-connector--Fault{--fb-connector: var(--fb-edge-fault, #dc2626)}.fb-connector--Timeout,.fb-connector--ScheduledPath{--fb-connector: var(--fb-edge-timeout, #f59e0b)}.fb-connector.f-connector-connectable{box-shadow:0 0 0 4px color-mix(in srgb,var(--fb-accent, #4f6ef7) 28%,transparent)}\n"] }]
|
|
2900
|
+
args: [{ selector: 'fb-flow-canvas', standalone: true, imports: [FFlowModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\r\n Gerarchia obbligatoria: f-flow > f-canvas > fNode / f-connection.\r\n I `@for` sono direttamente dentro <f-canvas>: nessun wrapper, quindi non serve\r\n `ngProjectAs` (che sarebbe indispensabile con blocchi annidati).\r\n-->\r\n<f-flow\r\n fDraggable\r\n (fCreateConnection)=\"onCreateConnection($event)\"\r\n (fReassignConnection)=\"onReassignConnection($event)\"\r\n (fMoveNodes)=\"onMoveNodes($event)\"\r\n (fSelectionChange)=\"onSelectionChange($event)\"\r\n (fDeleteSelected)=\"onDeleteSelected($event)\"\r\n (fCreateNode)=\"onCreateNode($event)\"\r\n>\r\n <f-canvas fZoom>\r\n <f-background>\r\n <f-circle-pattern />\r\n </f-background>\r\n\r\n @for (edge of edges(); track edge.id) {\r\n <f-connection\r\n [fConnectionId]=\"edge.id\"\r\n [fSourceId]=\"edge.sourceId\"\r\n [fTargetId]=\"edge.targetId\"\r\n fBehavior=\"floating\"\r\n [fType]=\"edge.isGoTo ? 'segment' : 'bezier'\"\r\n [class]=\"'fb-edge fb-edge--' + edge.kind + (edge.isGoTo ? ' fb-edge--goto' : '')\"\r\n >\r\n <f-connection-marker-arrow [type]=\"markerEnd\" />\r\n @if (edge.label) {\r\n <div fConnectionContent class=\"fb-edge-label\">{{ edge.label }}</div>\r\n }\r\n </f-connection>\r\n }\r\n\r\n @for (node of nodes(); track node.id) {\r\n <div\r\n fNode\r\n fDragHandle\r\n [fNodeId]=\"node.id\"\r\n [fNodePosition]=\"node.position\"\r\n [class]=\"'fb-node ' + categoryClass(node) + ' ' + node.widthClass\"\r\n [class.fb-node--start]=\"node.isStart\"\r\n [class.fb-node--selected]=\"isSelected(node)\"\r\n [class.fb-node--unreachable]=\"!node.isReachable\"\r\n [class.fb-node--error]=\"node.severity === 'Error'\"\r\n [class.fb-node--warning]=\"node.severity === 'Warning'\"\r\n (dblclick)=\"onNodeDoubleClick(node.name)\"\r\n >\r\n <!--\r\n Lo Start non ha ingresso: e' il punto di partenza (\u00A73.4).\r\n `fConnectorConnectableSide` e' cio' che fa entrare l'arco dall'alto: senza, foblex\r\n calcola il lato e un arco che scende dal node sopra potrebbe agganciarsi di fianco.\r\n -->\r\n @if (!node.isStart) {\r\n <div\r\n fConnector\r\n fConnectorType=\"target\"\r\n [fConnectorId]=\"targetIdOf(node)\"\r\n [fConnectorConnectableSide]=\"sides.TOP\"\r\n fConnectorMultiple=\"true\"\r\n class=\"fb-connector fb-connector--in\"\r\n title=\"Ingresso\"\r\n ></div>\r\n }\r\n\r\n <div class=\"fb-node__head\">\r\n <span class=\"fb-node__icon\" aria-hidden=\"true\">{{ node.icon }}</span>\r\n <div class=\"fb-node__text\">\r\n <span class=\"fb-node__title\" [title]=\"node.description || node.label\">{{ node.label }}</span>\r\n <span class=\"fb-node__sub\">\r\n {{ node.typeLabel }}\r\n @if (node.subtitle) {\r\n <span class=\"fb-node__sub-dot\">\u00B7</span>{{ node.subtitle }}\r\n }\r\n </span>\r\n </div>\r\n @if (node.hasAutomaticOutput) {\r\n <!-- L'elemento espone il proprio risultato sotto il proprio nome (\u00A74.5). -->\r\n <span class=\"fb-node__auto\" title=\"Espone un output automatico referenziabile come \u00AB{{ node.name }}\u00BB\">\r\n \u0192\r\n </span>\r\n }\r\n <!--\r\n `fDragBlocker` impedisce che il pointerdown sul bottone diventi un trascinamento\r\n del node: senza, aprire il dettaglio sposterebbe l'elemento di qualche pixel.\r\n -->\r\n <button\r\n type=\"button\"\r\n fDragBlocker\r\n class=\"fb-node__edit\"\r\n [attr.aria-label]=\"'Apri il dettaglio di ' + node.label\"\r\n title=\"Apri il dettaglio\"\r\n (click)=\"onEditClick($event, node.name)\"\r\n >\r\n \u270E\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-node__meta\">\r\n @if (!node.isStart) {\r\n <span class=\"fb-node__name\" [title]=\"'Nome tecnico: ' + node.name\">{{ node.name }}</span>\r\n }\r\n @if (!node.isReachable) {\r\n <span class=\"fb-badge fb-badge--unreachable\" title=\"Nessun percorso raggiunge questo elemento dallo Start\">\r\n scollegato\r\n </span>\r\n }\r\n @if (node.issueCount > 0) {\r\n <span\r\n class=\"fb-badge\"\r\n [class.fb-badge--error]=\"node.severity === 'Error'\"\r\n [class.fb-badge--warning]=\"node.severity === 'Warning'\"\r\n [class.fb-badge--info]=\"node.severity === 'Info'\"\r\n [title]=\"node.issueCount + ' rilievi di validazione'\"\r\n >\r\n {{ node.issueCount }}\r\n </span>\r\n }\r\n @if (node.danglingOutlets.length > 0) {\r\n <span\r\n class=\"fb-badge fb-badge--dangling\"\r\n [title]=\"'Rami dichiarati senza destinazione: ' + danglingLabels(node)\"\r\n >\r\n ramo incompleto\r\n </span>\r\n }\r\n </div>\r\n\r\n <!--\r\n Le uscite stanno sul bordo **inferiore**, una per ramo, nell'ordine in cui il modello\r\n le dichiara: per una Decision e' l'ordine di valutazione delle regole, che e'\r\n semantico (\u00A75.3), e da sinistra a destra si legge come la lista nell'inspector.\r\n L'etichetta si mostra solo quando i rami sono piu' di uno: su un `next` unico\r\n direbbe soltanto \u00ABSuccessivo\u00BB.\r\n -->\r\n <div class=\"fb-node__outlets\" [class.fb-node__outlets--labelled]=\"node.showsOutletLabels\">\r\n @for (outlet of node.outlets; track outlet.key) {\r\n <div class=\"fb-outlet\">\r\n @if (node.showsOutletLabels) {\r\n <span class=\"fb-outlet__label\" [title]=\"outlet.label\">{{ outlet.label }}</span>\r\n }\r\n <div\r\n fConnector\r\n fConnectorType=\"source\"\r\n [fConnectorId]=\"connectorIdOf(node, outlet.key)\"\r\n [fConnectorConnectableSide]=\"sides.BOTTOM\"\r\n [class]=\"'fb-connector fb-connector--out fb-connector--' + outlet.kind\"\r\n [title]=\"outlet.label\"\r\n ></div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Anteprima dell'arco durante il trascinamento. -->\r\n <f-connection-for-create fBehavior=\"floating\" fType=\"bezier\" class=\"fb-edge fb-edge--creating\">\r\n <f-connection-marker-arrow [type]=\"markerEnd\" />\r\n </f-connection-for-create>\r\n\r\n <f-selection-area />\r\n </f-canvas>\r\n\r\n <f-minimap [fMinSize]=\"1200\" class=\"fb-minimap\" />\r\n</f-flow>\r\n", styles: [":host{display:block;position:relative;width:100%;height:100%;overflow:hidden;background:var(--fb-canvas-bg, #f4f5f7)}f-flow{display:block;width:100%;height:100%}.fb-minimap{position:absolute;right:14px;bottom:14px;width:190px;height:130px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-md, 0 6px 18px rgb(16 24 40 / 10%));overflow:hidden}.fb-node{position:absolute;display:flex;flex-direction:column;box-sizing:border-box;width:240px;padding:0;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-lg, 12px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));font:inherit;cursor:grab;-webkit-user-select:none;user-select:none;transition:box-shadow .12s ease,border-color .12s ease}.fb-node--outlets-3{width:304px}.fb-node--outlets-4{width:380px}.fb-node--outlets-5{width:456px}.fb-node--outlets-6{width:520px}.fb-node:hover{box-shadow:var(--fb-shadow-md, 0 6px 18px rgb(16 24 40 / 10%))}.fb-node--selected{border-color:var(--fb-accent, #4f6ef7);box-shadow:0 0 0 3px color-mix(in srgb,var(--fb-accent, #4f6ef7) 22%,transparent)}.fb-node--unreachable{border-style:dashed;opacity:.8}.fb-node--error{border-color:var(--fb-error, #c9372c)}.fb-node--warning{border-color:var(--fb-warning, #b7791f)}.fb-node__head{display:flex;align-items:center;gap:8px;padding:10px 10px 6px 12px}.fb-node__icon{display:grid;place-items:center;flex:0 0 auto;width:28px;height:28px;border-radius:var(--fb-radius-sm, 8px);background:var(--fb-node-accent, #667085);color:#fff;font-size:14px;line-height:1}.cat-start{--fb-node-accent: #22a06b}.cat-screen{--fb-node-accent: #3b82f6}.cat-logic{--fb-node-accent: #8b5cf6}.cat-data{--fb-node-accent: #06b6d4}.cat-action{--fb-node-accent: #f59e0b}.cat-flow{--fb-node-accent: #14b8a6}.cat-other{--fb-node-accent: #667085}.fb-node__text{flex:1;min-width:0}.fb-node__title{display:block;font-size:13px;font-weight:600;line-height:17px;color:var(--fb-text, #1a1c23);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-node__sub{display:block;margin-top:1px;font-size:11px;line-height:14px;color:var(--fb-text-muted, #6b7086);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-node__sub-dot{margin:0 4px;color:var(--fb-text-subtle, #98a2b3)}.fb-node__auto{flex:0 0 auto;font-size:12px;font-weight:700;color:var(--fb-accent, #4f6ef7);cursor:help}.fb-node__edit{display:grid;place-items:center;flex:0 0 auto;width:22px;height:22px;padding:0;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-text-subtle, #98a2b3);font:inherit;font-size:12px;cursor:pointer;opacity:0;transition:opacity .12s ease,background .12s ease}.fb-node:hover .fb-node__edit,.fb-node--selected .fb-node__edit,.fb-node__edit:focus-visible{opacity:1}.fb-node__edit:hover{background:var(--fb-surface-alt, #f7f8fa);color:var(--fb-text, #1a1c23)}.fb-node__meta{display:flex;flex-wrap:wrap;align-items:center;gap:4px;min-height:14px;padding:0 12px 6px}.fb-node__name{flex:0 1 auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;color:var(--fb-text-subtle, #98a2b3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-badge{padding:1px 6px;border-radius:10px;background:var(--fb-badge-bg, #eef0f4);font-size:10px;font-weight:600;color:var(--fb-text-muted, #6b7086);white-space:nowrap;cursor:help}.fb-badge--error{background:color-mix(in srgb,var(--fb-error, #c9372c) 14%,transparent);color:var(--fb-error, #c9372c)}.fb-badge--warning{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-badge--info{background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 12%,transparent);color:var(--fb-accent, #4f6ef7)}.fb-badge--unreachable,.fb-badge--dangling{background:color-mix(in srgb,var(--fb-warning, #b7791f) 12%,transparent);color:var(--fb-warning, #b7791f)}.fb-node__outlets{display:flex;align-items:flex-end;justify-content:space-evenly;gap:4px;padding:0 8px 4px}.fb-node__outlets--labelled{padding-top:5px;border-top:1px solid var(--fb-border-subtle, #eef0f4)}.fb-outlet{display:flex;flex:1 1 0;flex-direction:column;align-items:center;gap:2px;min-width:0}.fb-outlet__label{max-width:100%;font-size:10px;line-height:13px;color:var(--fb-text-muted, #6b7086);text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-connector{box-sizing:border-box;width:12px;height:12px;flex:0 0 auto;border:2px solid var(--fb-surface, #fff);border-radius:50%;background:var(--fb-connector, #98a2b3);cursor:crosshair;transition:transform .12s ease,box-shadow .12s ease}f-flow .fb-connector--out{position:relative;inset:auto;margin-bottom:-12px}.fb-connector--out:hover{transform:scale(1.2)}f-flow .fb-connector--in{position:absolute;inset:-2px auto auto 50%;width:24px;height:4px;border:0;border-radius:2px;transform:translate(-50%);background:var(--fb-border-strong, #cfd4de)}.fb-connector--out{--ff-connector-connected-color: var(--fb-connector, #98a2b3)}.fb-connector--Next,.fb-connector--Start,.fb-connector--LoopNext{--fb-connector: var(--fb-edge-next, #98a2b3)}.fb-connector--Rule,.fb-connector--WaitEvent{--fb-connector: var(--fb-edge-rule, #8b5cf6)}.fb-connector--Default,.fb-connector--LoopEnd{--fb-connector: var(--fb-edge-default, #06b6d4)}.fb-connector--Fault{--fb-connector: var(--fb-edge-fault, #dc2626)}.fb-connector--Timeout,.fb-connector--ScheduledPath{--fb-connector: var(--fb-edge-timeout, #f59e0b)}.fb-connector.f-connector-connectable{box-shadow:0 0 0 4px color-mix(in srgb,var(--fb-accent, #4f6ef7) 28%,transparent)}\n"] }]
|
|
2667
2901
|
}], propDecorators: { selectedName: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedName", required: false }] }], outline: [{ type: i0.Input, args: [{ isSignal: true, alias: "outline", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], nodeOpened: [{ type: i0.Output, args: ["nodeOpened"] }], nodeRemoveRequested: [{ type: i0.Output, args: ["nodeRemoveRequested"] }], nodeDuplicateRequested: [{ type: i0.Output, args: ["nodeDuplicateRequested"] }], elementDropped: [{ type: i0.Output, args: ["elementDropped"] }] } });
|
|
2668
2902
|
|
|
2669
2903
|
/**
|
|
@@ -2724,6 +2958,18 @@ class ElementPaletteComponent {
|
|
|
2724
2958
|
iconOf(entry) {
|
|
2725
2959
|
return elementIcon(entry.value, entry.label);
|
|
2726
2960
|
}
|
|
2961
|
+
/**
|
|
2962
|
+
* L'etichetta del ramo di fault, presa dalla mappa delle uscite invece di scrivere «ramo di
|
|
2963
|
+
* errore» per tutti: su uno stage di orchestrazione quel ramo **non** e' un guasto, e' lo step
|
|
2964
|
+
* rifiutato (§5.13). Un tipo nuovo eredita l'etichetta giusta senza toccare la palette.
|
|
2965
|
+
*/
|
|
2966
|
+
faultLabel(entry) {
|
|
2967
|
+
if (!entry.hasFaultConnector) {
|
|
2968
|
+
return null;
|
|
2969
|
+
}
|
|
2970
|
+
const outlet = outletsOf(entry.value, {}).find((candidate) => candidate.kind === 'Fault');
|
|
2971
|
+
return outlet ? `ramo «${outlet.label.toLowerCase()}»` : 'ramo di errore';
|
|
2972
|
+
}
|
|
2727
2973
|
categoryClass(category) {
|
|
2728
2974
|
const normalized = category.toLowerCase();
|
|
2729
2975
|
if (normalized.startsWith('inter')) {
|
|
@@ -2744,11 +2990,11 @@ class ElementPaletteComponent {
|
|
|
2744
2990
|
return 'cat-other';
|
|
2745
2991
|
}
|
|
2746
2992
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ElementPaletteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2747
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ElementPaletteComponent, isStandalone: true, selector: "fb-element-palette", inputs: { processType: { classPropertyName: "processType", publicName: "processType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementPicked: "elementPicked" }, ngImport: i0, template: "<div class=\"fb-palette__search\">\n <input\n type=\"search\"\n placeholder=\"Cerca un elemento\"\n aria-label=\"Cerca un elemento\"\n (input)=\"onFilter($any($event.target).value)\"\n />\n</div>\n\n@if (isEmpty()) {\n <p class=\"fb-palette__empty\">\n Il dizionario degli elementi non e\u2019 ancora disponibile.\n </p>\n}\n\n<div class=\"fb-palette__groups\">\n @for (group of groups(); track group.category) {\n <section class=\"fb-palette__group\">\n <h3 class=\"fb-palette__category\">{{ group.category }}</h3>\n @for (entry of group.entries; track entry.value) {\n <!--\n `fExternalItem` rende la voce trascinabile sul canvas: il rilascio emette\n `fCreateNode` con questo `fData` e la posizione, che diventa locationX/locationY.\n -->\n <button\n type=\"button\"\n class=\"fb-palette__item\"\n fExternalItem\n [fExternalItemId]=\"entry.value\"\n [fData]=\"entry.value\"\n [class.fb-palette__item--warn]=\"isIncompatible(entry)\"\n [title]=\"incompatibleHint(entry) || entry.description || entry.label\"\n (click)=\"pick(entry)\"\n >\n <span class=\"fb-palette__icon\" [class]=\"'fb-palette__icon ' + categoryClass(group.category)\">\n {{ iconOf(entry) }}\n </span>\n <span class=\"fb-palette__text\">\n <span class=\"fb-palette__label\">{{ entry.label }}</span>\n @if (entry.hasAutomaticOutput) {\n <span class=\"fb-palette__flag\" title=\"Espone un output automatico sotto il nome dell\u2019elemento\">\n output automatico\n </span>\n }\n @if (entry
|
|
2993
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ElementPaletteComponent, isStandalone: true, selector: "fb-element-palette", inputs: { processType: { classPropertyName: "processType", publicName: "processType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementPicked: "elementPicked" }, ngImport: i0, template: "<div class=\"fb-palette__search\">\r\n <input\r\n type=\"search\"\r\n placeholder=\"Cerca un elemento\"\r\n aria-label=\"Cerca un elemento\"\r\n (input)=\"onFilter($any($event.target).value)\"\r\n />\r\n</div>\r\n\r\n@if (isEmpty()) {\r\n <p class=\"fb-palette__empty\">\r\n Il dizionario degli elementi non e\u2019 ancora disponibile.\r\n </p>\r\n}\r\n\r\n<div class=\"fb-palette__groups\">\r\n @for (group of groups(); track group.category) {\r\n <section class=\"fb-palette__group\">\r\n <h3 class=\"fb-palette__category\">{{ group.category }}</h3>\r\n @for (entry of group.entries; track entry.value) {\r\n <!--\r\n `fExternalItem` rende la voce trascinabile sul canvas: il rilascio emette\r\n `fCreateNode` con questo `fData` e la posizione, che diventa locationX/locationY.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-palette__item\"\r\n fExternalItem\r\n [fExternalItemId]=\"entry.value\"\r\n [fData]=\"entry.value\"\r\n [class.fb-palette__item--warn]=\"isIncompatible(entry)\"\r\n [title]=\"incompatibleHint(entry) || entry.description || entry.label\"\r\n (click)=\"pick(entry)\"\r\n >\r\n <span class=\"fb-palette__icon\" [class]=\"'fb-palette__icon ' + categoryClass(group.category)\">\r\n {{ iconOf(entry) }}\r\n </span>\r\n <span class=\"fb-palette__text\">\r\n <span class=\"fb-palette__label\">{{ entry.label }}</span>\r\n @if (entry.hasAutomaticOutput) {\r\n <span class=\"fb-palette__flag\" title=\"Espone un output automatico sotto il nome dell\u2019elemento\">\r\n output automatico\r\n </span>\r\n }\r\n @if (faultLabel(entry)) {\r\n <span class=\"fb-palette__flag\" title=\"Ha un ramo che l\u2019autore puo\u2019 prevedere e disegnare\">\r\n {{ faultLabel(entry) }}\r\n </span>\r\n }\r\n </span>\r\n @if (isIncompatible(entry)) {\r\n <span class=\"fb-palette__warn\" aria-hidden=\"true\">!</span>\r\n }\r\n </button>\r\n }\r\n </section>\r\n }\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff);border-right:1px solid var(--fb-border, #d6dae1)}.fb-palette__search{padding:8px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-palette__search input{box-sizing:border-box;width:100%;padding:5px 8px;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);color:var(--fb-text, #1d2939);font:inherit;font-size:12px}.fb-palette__search input:focus-visible{outline:2px solid var(--fb-accent, #2f6feb);outline-offset:-1px}.fb-palette__groups{flex:1;min-height:0;overflow-y:auto;padding:4px 0 12px}.fb-palette__empty{margin:12px 10px;font-size:12px;color:var(--fb-text-muted, #667085)}.fb-palette__category{margin:10px 10px 4px;font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-palette__item{display:flex;align-items:center;gap:8px;box-sizing:border-box;width:calc(100% - 12px);margin:1px 6px;padding:5px 8px;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-text, #1a1c23);font:inherit;text-align:left;cursor:grab;transition:background .12s ease}.fb-palette__item:hover{background:var(--fb-surface-alt, #f7f8fa)}.fb-palette__item:focus-visible{outline:2px solid var(--fb-accent, #2f6feb);outline-offset:-2px}.fb-palette__icon{display:grid;place-items:center;flex:0 0 auto;width:24px;height:24px;border-radius:var(--fb-radius-xs, 6px);background:var(--fb-icon-bg, #98a2b3);color:#fff;font-size:11px;font-weight:700}.cat-screen{--fb-icon-bg: #3b82f6}.cat-logic{--fb-icon-bg: #8b5cf6}.cat-data{--fb-icon-bg: #06b6d4}.cat-action{--fb-icon-bg: #f59e0b}.cat-flow{--fb-icon-bg: #14b8a6}.fb-palette__text{display:flex;flex-direction:column;min-width:0}.fb-palette__label{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-palette__flag{font-size:9px;color:var(--fb-text-subtle, #98a2b3)}.fb-palette__item--warn .fb-palette__label{color:var(--fb-warning, #b7791f)}.fb-palette__warn{margin-left:auto;color:var(--fb-warning, #b7791f);font-weight:700}:host ::ng-deep .f-external-item-preview{padding:4px 8px;border:1px solid var(--fb-accent, #2f6feb);border-radius:6px;background:var(--fb-surface, #fff);box-shadow:0 4px 12px #1018282e;opacity:.95}\n"], dependencies: [{ kind: "ngmodule", type: FFlowModule }, { kind: "directive", type: i1.FExternalItem, selector: "[fExternalItem]", inputs: ["fExternalItemId", "fData", "fDisabled", "fPreview", "fPreviewMatchSize", "fPlaceholder"], outputs: ["fPreviewChange", "fPlaceholderChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2748
2994
|
}
|
|
2749
2995
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ElementPaletteComponent, decorators: [{
|
|
2750
2996
|
type: Component,
|
|
2751
|
-
args: [{ selector: 'fb-element-palette', standalone: true, imports: [FFlowModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-palette__search\">\n <input\n type=\"search\"\n placeholder=\"Cerca un elemento\"\n aria-label=\"Cerca un elemento\"\n (input)=\"onFilter($any($event.target).value)\"\n />\n</div>\n\n@if (isEmpty()) {\n <p class=\"fb-palette__empty\">\n Il dizionario degli elementi non e\u2019 ancora disponibile.\n </p>\n}\n\n<div class=\"fb-palette__groups\">\n @for (group of groups(); track group.category) {\n <section class=\"fb-palette__group\">\n <h3 class=\"fb-palette__category\">{{ group.category }}</h3>\n @for (entry of group.entries; track entry.value) {\n <!--\n `fExternalItem` rende la voce trascinabile sul canvas: il rilascio emette\n `fCreateNode` con questo `fData` e la posizione, che diventa locationX/locationY.\n -->\n <button\n type=\"button\"\n class=\"fb-palette__item\"\n fExternalItem\n [fExternalItemId]=\"entry.value\"\n [fData]=\"entry.value\"\n [class.fb-palette__item--warn]=\"isIncompatible(entry)\"\n [title]=\"incompatibleHint(entry) || entry.description || entry.label\"\n (click)=\"pick(entry)\"\n >\n <span class=\"fb-palette__icon\" [class]=\"'fb-palette__icon ' + categoryClass(group.category)\">\n {{ iconOf(entry) }}\n </span>\n <span class=\"fb-palette__text\">\n <span class=\"fb-palette__label\">{{ entry.label }}</span>\n @if (entry.hasAutomaticOutput) {\n <span class=\"fb-palette__flag\" title=\"Espone un output automatico sotto il nome dell\u2019elemento\">\n output automatico\n </span>\n }\n @if (entry
|
|
2997
|
+
args: [{ selector: 'fb-element-palette', standalone: true, imports: [FFlowModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-palette__search\">\r\n <input\r\n type=\"search\"\r\n placeholder=\"Cerca un elemento\"\r\n aria-label=\"Cerca un elemento\"\r\n (input)=\"onFilter($any($event.target).value)\"\r\n />\r\n</div>\r\n\r\n@if (isEmpty()) {\r\n <p class=\"fb-palette__empty\">\r\n Il dizionario degli elementi non e\u2019 ancora disponibile.\r\n </p>\r\n}\r\n\r\n<div class=\"fb-palette__groups\">\r\n @for (group of groups(); track group.category) {\r\n <section class=\"fb-palette__group\">\r\n <h3 class=\"fb-palette__category\">{{ group.category }}</h3>\r\n @for (entry of group.entries; track entry.value) {\r\n <!--\r\n `fExternalItem` rende la voce trascinabile sul canvas: il rilascio emette\r\n `fCreateNode` con questo `fData` e la posizione, che diventa locationX/locationY.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-palette__item\"\r\n fExternalItem\r\n [fExternalItemId]=\"entry.value\"\r\n [fData]=\"entry.value\"\r\n [class.fb-palette__item--warn]=\"isIncompatible(entry)\"\r\n [title]=\"incompatibleHint(entry) || entry.description || entry.label\"\r\n (click)=\"pick(entry)\"\r\n >\r\n <span class=\"fb-palette__icon\" [class]=\"'fb-palette__icon ' + categoryClass(group.category)\">\r\n {{ iconOf(entry) }}\r\n </span>\r\n <span class=\"fb-palette__text\">\r\n <span class=\"fb-palette__label\">{{ entry.label }}</span>\r\n @if (entry.hasAutomaticOutput) {\r\n <span class=\"fb-palette__flag\" title=\"Espone un output automatico sotto il nome dell\u2019elemento\">\r\n output automatico\r\n </span>\r\n }\r\n @if (faultLabel(entry)) {\r\n <span class=\"fb-palette__flag\" title=\"Ha un ramo che l\u2019autore puo\u2019 prevedere e disegnare\">\r\n {{ faultLabel(entry) }}\r\n </span>\r\n }\r\n </span>\r\n @if (isIncompatible(entry)) {\r\n <span class=\"fb-palette__warn\" aria-hidden=\"true\">!</span>\r\n }\r\n </button>\r\n }\r\n </section>\r\n }\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff);border-right:1px solid var(--fb-border, #d6dae1)}.fb-palette__search{padding:8px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-palette__search input{box-sizing:border-box;width:100%;padding:5px 8px;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);color:var(--fb-text, #1d2939);font:inherit;font-size:12px}.fb-palette__search input:focus-visible{outline:2px solid var(--fb-accent, #2f6feb);outline-offset:-1px}.fb-palette__groups{flex:1;min-height:0;overflow-y:auto;padding:4px 0 12px}.fb-palette__empty{margin:12px 10px;font-size:12px;color:var(--fb-text-muted, #667085)}.fb-palette__category{margin:10px 10px 4px;font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-palette__item{display:flex;align-items:center;gap:8px;box-sizing:border-box;width:calc(100% - 12px);margin:1px 6px;padding:5px 8px;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-text, #1a1c23);font:inherit;text-align:left;cursor:grab;transition:background .12s ease}.fb-palette__item:hover{background:var(--fb-surface-alt, #f7f8fa)}.fb-palette__item:focus-visible{outline:2px solid var(--fb-accent, #2f6feb);outline-offset:-2px}.fb-palette__icon{display:grid;place-items:center;flex:0 0 auto;width:24px;height:24px;border-radius:var(--fb-radius-xs, 6px);background:var(--fb-icon-bg, #98a2b3);color:#fff;font-size:11px;font-weight:700}.cat-screen{--fb-icon-bg: #3b82f6}.cat-logic{--fb-icon-bg: #8b5cf6}.cat-data{--fb-icon-bg: #06b6d4}.cat-action{--fb-icon-bg: #f59e0b}.cat-flow{--fb-icon-bg: #14b8a6}.fb-palette__text{display:flex;flex-direction:column;min-width:0}.fb-palette__label{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-palette__flag{font-size:9px;color:var(--fb-text-subtle, #98a2b3)}.fb-palette__item--warn .fb-palette__label{color:var(--fb-warning, #b7791f)}.fb-palette__warn{margin-left:auto;color:var(--fb-warning, #b7791f);font-weight:700}:host ::ng-deep .f-external-item-preview{padding:4px 8px;border:1px solid var(--fb-accent, #2f6feb);border-radius:6px;background:var(--fb-surface, #fff);box-shadow:0 4px 12px #1018282e;opacity:.95}\n"] }]
|
|
2752
2998
|
}], propDecorators: { processType: [{ type: i0.Input, args: [{ isSignal: true, alias: "processType", required: false }] }], elementPicked: [{ type: i0.Output, args: ["elementPicked"] }] } });
|
|
2753
2999
|
|
|
2754
3000
|
/**
|
|
@@ -2763,8 +3009,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
|
|
|
2763
3009
|
* pur non essendo dichiarati in nessuna collection di risorse: la primitiva li restituisce
|
|
2764
3010
|
* già, ed e' il motivo per cui non si ricostruisce l'elenco lato client.
|
|
2765
3011
|
*
|
|
2766
|
-
* Resta possibile scrivere a mano: i percorsi di relazione e i campi di un record non
|
|
2767
|
-
*
|
|
3012
|
+
* Resta possibile scrivere a mano: i percorsi di relazione e i campi di un record non sono
|
|
3013
|
+
* enumerabili. Gli scope del sistema ospite (`$User.X`), invece, sono verificabili **quando
|
|
3014
|
+
* l'host li dichiara**: se `globalVariables` porta almeno un percorso di quello scope, un
|
|
3015
|
+
* percorso che non c'e' e' `GLOBAL_UNKNOWN`; se non ne porta nessuno, lo scope resta non
|
|
3016
|
+
* verificabile — che significa "non lo so", non "non esiste" (§4.1).
|
|
2768
3017
|
*/
|
|
2769
3018
|
class ReferencePickerComponent {
|
|
2770
3019
|
api = inject(FlowBuilderApi);
|
|
@@ -2783,11 +3032,6 @@ class ReferencePickerComponent {
|
|
|
2783
3032
|
* formula e' `TARGET_NOT_WRITABLE` (§4.6).
|
|
2784
3033
|
*/
|
|
2785
3034
|
writableOnly = input(false, ...(ngDevMode ? [{ debugName: "writableOnly" }] : []));
|
|
2786
|
-
/**
|
|
2787
|
-
* `true` → aggiunge `$Flow.CurrentStage` e `$Flow.ActiveStages` alle destinazioni.
|
|
2788
|
-
* Sono le sole variabili globali scrivibili, e solo se il flow dichiara stage (§5.2).
|
|
2789
|
-
*/
|
|
2790
|
-
allowStageTargets = input(false, ...(ngDevMode ? [{ debugName: "allowStageTargets" }] : []));
|
|
2791
3035
|
/**
|
|
2792
3036
|
* `true` → a sinistra ci va il nome di un **node**, non di una risorsa: e' il caso di
|
|
2793
3037
|
* `WasVisited` e `HasError` (§4.3).
|
|
@@ -2819,7 +3063,18 @@ class ReferencePickerComponent {
|
|
|
2819
3063
|
})));
|
|
2820
3064
|
return;
|
|
2821
3065
|
}
|
|
2822
|
-
|
|
3066
|
+
/**
|
|
3067
|
+
* `?? undefined` non e' cosmetico: nei template il safe navigation di Angular
|
|
3068
|
+
* (`describe(x)?.isCollection`) produce **null**, non `undefined`. Un `isCollection: null`
|
|
3069
|
+
* che arriva alla primitiva viene letto come "filtra per valore singolo" e svuota
|
|
3070
|
+
* l'elenco: un campo senza filtro deve mandare il campo **assente**.
|
|
3071
|
+
*/
|
|
3072
|
+
const query = {
|
|
3073
|
+
definition,
|
|
3074
|
+
dataType: dataType ?? undefined,
|
|
3075
|
+
isCollection: isCollection ?? undefined,
|
|
3076
|
+
objectType: objectType ?? undefined,
|
|
3077
|
+
};
|
|
2823
3078
|
this.isLoading.set(true);
|
|
2824
3079
|
this.loadError.set(null);
|
|
2825
3080
|
const request = writable ? this.api.getWritableReferences(query) : this.api.getReferences(query);
|
|
@@ -2833,30 +3088,12 @@ class ReferencePickerComponent {
|
|
|
2833
3088
|
.finally(() => this.isLoading.set(false));
|
|
2834
3089
|
});
|
|
2835
3090
|
}
|
|
2836
|
-
/** Le due globali di stage, aggiunte alle destinazioni quando il flow dichiara stage. */
|
|
2837
|
-
stageTargets = computed(() => {
|
|
2838
|
-
if (!this.allowStageTargets() || !(this.store.document().stages?.length ?? 0)) {
|
|
2839
|
-
return [];
|
|
2840
|
-
}
|
|
2841
|
-
return [
|
|
2842
|
-
{
|
|
2843
|
-
name: '$Flow.CurrentStage',
|
|
2844
|
-
kind: 'Global',
|
|
2845
|
-
isWritable: true,
|
|
2846
|
-
description: 'Lo stage corrente: si fa avanzare con un Assignment.',
|
|
2847
|
-
},
|
|
2848
|
-
{
|
|
2849
|
-
name: '$Flow.ActiveStages',
|
|
2850
|
-
kind: 'Global',
|
|
2851
|
-
isCollection: true,
|
|
2852
|
-
isWritable: true,
|
|
2853
|
-
description: 'La collection degli stage attivi.',
|
|
2854
|
-
},
|
|
2855
|
-
];
|
|
2856
|
-
}, ...(ngDevMode ? [{ debugName: "stageTargets" }] : []));
|
|
2857
3091
|
options = computed(() => {
|
|
2858
3092
|
const needle = this.query().trim().toLowerCase();
|
|
2859
|
-
|
|
3093
|
+
// Le globali assegnabili — `$Flow.CurrentStage`, `$Flow.ActiveStages` e quelle che l'host
|
|
3094
|
+
// dichiara scrivibili — le comprende già `POST /flows/references/writable`: aggiungerle
|
|
3095
|
+
// qui le duplicherebbe (§5.2, §6.4).
|
|
3096
|
+
const all = this.references();
|
|
2860
3097
|
if (!needle) {
|
|
2861
3098
|
return all;
|
|
2862
3099
|
}
|
|
@@ -2908,35 +3145,34 @@ class ReferencePickerComponent {
|
|
|
2908
3145
|
* - `navigated`: la radice e' nota ma c'e' un percorso dopo il punto (campo di record,
|
|
2909
3146
|
* output automatico navigato): la validazione non verifica i percorsi con il punto,
|
|
2910
3147
|
* quindi si accetta senza segnalare;
|
|
2911
|
-
* - `host`: scope
|
|
2912
|
-
* - `unknown`: nessuna corrispondenza: si avvisa, senza bloccare.
|
|
3148
|
+
* - `host`: scope del sistema ospite che **non dichiara percorsi**: non verificabile (§4.1);
|
|
3149
|
+
* - `unknown`: nessuna corrispondenza: si avvisa, senza bloccare. Ci finisce anche il
|
|
3150
|
+
* percorso inesistente di uno scope che i percorsi li dichiara, perche' lì il backend
|
|
3151
|
+
* risponderebbe `GLOBAL_UNKNOWN`.
|
|
2913
3152
|
*/
|
|
2914
3153
|
valueState = computed(() => {
|
|
2915
3154
|
const value = (this.value() ?? '').trim();
|
|
2916
3155
|
if (!value) {
|
|
2917
3156
|
return 'empty';
|
|
2918
3157
|
}
|
|
2919
|
-
const all =
|
|
3158
|
+
const all = this.references();
|
|
2920
3159
|
if (all.some((reference) => reference.name === value)) {
|
|
2921
3160
|
return 'known';
|
|
2922
3161
|
}
|
|
2923
3162
|
const root = referenceRoot(value);
|
|
2924
|
-
|
|
2925
|
-
.globalVariables()
|
|
2926
|
-
.find((entry) => entry.scope === root || entry.value === root);
|
|
2927
|
-
if (global?.isResolvedByHost) {
|
|
3163
|
+
if (this.dictionaries.globalScope(root) && !this.dictionaries.isGlobalScopeVerifiable(root)) {
|
|
2928
3164
|
return 'host';
|
|
2929
3165
|
}
|
|
2930
3166
|
if (all.some((reference) => reference.name === root)) {
|
|
2931
3167
|
return 'navigated';
|
|
2932
3168
|
}
|
|
2933
3169
|
// Se l'elenco non e' arrivato, non si accusa nessuno.
|
|
2934
|
-
return
|
|
3170
|
+
return all.length === 0 && this.isLoading() ? 'empty' : 'unknown';
|
|
2935
3171
|
}, ...(ngDevMode ? [{ debugName: "valueState" }] : []));
|
|
2936
3172
|
hint = computed(() => {
|
|
2937
3173
|
switch (this.valueState()) {
|
|
2938
3174
|
case 'host':
|
|
2939
|
-
return 'Scope risolto dal sistema ospite: il backend non puo’
|
|
3175
|
+
return 'Scope risolto dal sistema ospite, che non dichiara i suoi percorsi: il backend non puo’ verificarlo.';
|
|
2940
3176
|
case 'navigated':
|
|
2941
3177
|
return 'Percorso su un riferimento noto: la validazione non verifica i campi dopo il punto.';
|
|
2942
3178
|
case 'unknown':
|
|
@@ -2987,12 +3223,12 @@ class ReferencePickerComponent {
|
|
|
2987
3223
|
return parts.join(' · ');
|
|
2988
3224
|
}
|
|
2989
3225
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ReferencePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2990
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ReferencePickerComponent, isStandalone: true, selector: "fb-reference-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, dataType: { classPropertyName: "dataType", publicName: "dataType", isSignal: true, isRequired: false, transformFunction: null }, isCollection: { classPropertyName: "isCollection", publicName: "isCollection", isSignal: true, isRequired: false, transformFunction: null }, objectType: { classPropertyName: "objectType", publicName: "objectType", isSignal: true, isRequired: false, transformFunction: null }, writableOnly: { classPropertyName: "writableOnly", publicName: "writableOnly", isSignal: true, isRequired: false, transformFunction: null },
|
|
3226
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ReferencePickerComponent, isStandalone: true, selector: "fb-reference-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, dataType: { classPropertyName: "dataType", publicName: "dataType", isSignal: true, isRequired: false, transformFunction: null }, isCollection: { classPropertyName: "isCollection", publicName: "isCollection", isSignal: true, isRequired: false, transformFunction: null }, objectType: { classPropertyName: "objectType", publicName: "objectType", isSignal: true, isRequired: false, transformFunction: null }, writableOnly: { classPropertyName: "writableOnly", publicName: "writableOnly", isSignal: true, isRequired: false, transformFunction: null }, elementsOnly: { classPropertyName: "elementsOnly", publicName: "elementsOnly", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div class=\"fb-ref\" [class.fb-ref--open]=\"isOpen()\">\r\n <div class=\"fb-ref__control\">\r\n <input\r\n class=\"fb-ref__input\"\r\n type=\"text\"\r\n [value]=\"value() || ''\"\r\n [placeholder]=\"placeholder()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"label()\"\r\n (input)=\"onManualInput($any($event.target).value)\"\r\n (focus)=\"open()\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__toggle\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isOpen()\"\r\n aria-label=\"Mostra i riferimenti disponibili\"\r\n (click)=\"toggle()\"\r\n >\r\n \u25BE\r\n </button>\r\n @if (value()) {\r\n <button type=\"button\" class=\"fb-ref__clear\" aria-label=\"Svuota\" (click)=\"clear()\">\u00D7</button>\r\n }\r\n </div>\r\n\r\n @if (hint()) {\r\n <p class=\"fb-ref__hint\" [class.fb-ref__hint--warn]=\"valueState() === 'unknown'\">{{ hint() }}</p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"fb-ref__hint fb-ref__hint--warn\">\r\n Elenco dei riferimenti non disponibile: puoi scrivere il nome a mano.\r\n </p>\r\n }\r\n\r\n @if (isOpen()) {\r\n <div class=\"fb-ref__panel\" role=\"listbox\">\r\n <input\r\n class=\"fb-ref__search\"\r\n type=\"search\"\r\n placeholder=\"Filtra\"\r\n aria-label=\"Filtra i riferimenti\"\r\n (input)=\"onQuery($any($event.target).value)\"\r\n />\r\n @if (groups().length === 0) {\r\n <p class=\"fb-ref__empty\">Nessun riferimento compatibile.</p>\r\n }\r\n @for (group of groups(); track group.kind) {\r\n <div class=\"fb-ref__group\">\r\n <span class=\"fb-ref__group-label\">{{ group.label }}</span>\r\n @for (item of group.items; track item.name) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__option\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"item.name === value()\"\r\n (click)=\"choose(item)\"\r\n >\r\n <span class=\"fb-ref__name\">{{ item.name }}</span>\r\n <span class=\"fb-ref__meta\">{{ describe(item) }}</span>\r\n </button>\r\n }\r\n </div>\r\n }\r\n <button type=\"button\" class=\"fb-ref__close\" (click)=\"close()\">Chiudi</button>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block}.fb-ref{position:relative}.fb-ref__control{display:flex;align-items:stretch;gap:0;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);overflow:hidden}.fb-ref--open .fb-ref__control{border-color:var(--fb-accent, #2f6feb)}.fb-ref__input{flex:1;min-width:0;padding:5px 7px;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-ref__input:focus-visible{outline:none}.fb-ref__toggle,.fb-ref__clear{flex:0 0 auto;padding:0 7px;border:0;border-left:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:12px;cursor:pointer}.fb-ref__toggle:hover,.fb-ref__clear:hover{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__hint{margin:3px 0 0;font-size:10px;line-height:1.35;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__hint--warn{color:var(--fb-warning, #b7791f)}.fb-ref__panel{position:absolute;z-index:30;top:calc(100% + 3px);left:0;right:0;max-height:260px;overflow-y:auto;padding:6px;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);box-shadow:0 6px 18px #10182829}.fb-ref__search{box-sizing:border-box;width:100%;margin-bottom:6px;padding:4px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:5px;font:inherit;font-size:12px}.fb-ref__group{margin-bottom:6px}.fb-ref__group-label{display:block;padding:2px 4px;font-size:9px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__option{display:flex;flex-direction:column;width:100%;padding:4px 6px;border:0;border-radius:4px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-ref__option:hover,.fb-ref__option[aria-selected=true]{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__name{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.fb-ref__meta{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-ref__empty{margin:4px;font-size:11px;color:var(--fb-text-muted, #667085)}.fb-ref__close{width:100%;margin-top:4px;padding:4px;border:0;border-top:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2991
3227
|
}
|
|
2992
3228
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ReferencePickerComponent, decorators: [{
|
|
2993
3229
|
type: Component,
|
|
2994
|
-
args: [{ selector: 'fb-reference-picker', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-ref\" [class.fb-ref--open]=\"isOpen()\">\n <div class=\"fb-ref__control\">\n <input\n class=\"fb-ref__input\"\n type=\"text\"\n [value]=\"value() || ''\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"label()\"\n (input)=\"onManualInput($any($event.target).value)\"\n (focus)=\"open()\"\n />\n <button\n type=\"button\"\n class=\"fb-ref__toggle\"\n [disabled]=\"disabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n aria-label=\"Mostra i riferimenti disponibili\"\n (click)=\"toggle()\"\n >\n \u25BE\n </button>\n @if (value()) {\n <button type=\"button\" class=\"fb-ref__clear\" aria-label=\"Svuota\" (click)=\"clear()\">\u00D7</button>\n }\n </div>\n\n @if (hint()) {\n <p class=\"fb-ref__hint\" [class.fb-ref__hint--warn]=\"valueState() === 'unknown'\">{{ hint() }}</p>\n }\n @if (errorMessage()) {\n <p class=\"fb-ref__hint fb-ref__hint--warn\">\n Elenco dei riferimenti non disponibile: puoi scrivere il nome a mano.\n </p>\n }\n\n @if (isOpen()) {\n <div class=\"fb-ref__panel\" role=\"listbox\">\n <input\n class=\"fb-ref__search\"\n type=\"search\"\n placeholder=\"Filtra\"\n aria-label=\"Filtra i riferimenti\"\n (input)=\"onQuery($any($event.target).value)\"\n />\n @if (groups().length === 0) {\n <p class=\"fb-ref__empty\">Nessun riferimento compatibile.</p>\n }\n @for (group of groups(); track group.kind) {\n <div class=\"fb-ref__group\">\n <span class=\"fb-ref__group-label\">{{ group.label }}</span>\n @for (item of group.items; track item.name) {\n <button\n type=\"button\"\n class=\"fb-ref__option\"\n role=\"option\"\n [attr.aria-selected]=\"item.name === value()\"\n (click)=\"choose(item)\"\n >\n <span class=\"fb-ref__name\">{{ item.name }}</span>\n <span class=\"fb-ref__meta\">{{ describe(item) }}</span>\n </button>\n }\n </div>\n }\n <button type=\"button\" class=\"fb-ref__close\" (click)=\"close()\">Chiudi</button>\n </div>\n }\n</div>\n", styles: [":host{display:block}.fb-ref{position:relative}.fb-ref__control{display:flex;align-items:stretch;gap:0;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);overflow:hidden}.fb-ref--open .fb-ref__control{border-color:var(--fb-accent, #2f6feb)}.fb-ref__input{flex:1;min-width:0;padding:5px 7px;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-ref__input:focus-visible{outline:none}.fb-ref__toggle,.fb-ref__clear{flex:0 0 auto;padding:0 7px;border:0;border-left:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:12px;cursor:pointer}.fb-ref__toggle:hover,.fb-ref__clear:hover{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__hint{margin:3px 0 0;font-size:10px;line-height:1.35;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__hint--warn{color:var(--fb-warning, #b7791f)}.fb-ref__panel{position:absolute;z-index:30;top:calc(100% + 3px);left:0;right:0;max-height:260px;overflow-y:auto;padding:6px;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);box-shadow:0 6px 18px #10182829}.fb-ref__search{box-sizing:border-box;width:100%;margin-bottom:6px;padding:4px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:5px;font:inherit;font-size:12px}.fb-ref__group{margin-bottom:6px}.fb-ref__group-label{display:block;padding:2px 4px;font-size:9px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__option{display:flex;flex-direction:column;width:100%;padding:4px 6px;border:0;border-radius:4px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-ref__option:hover,.fb-ref__option[aria-selected=true]{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__name{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.fb-ref__meta{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-ref__empty{margin:4px;font-size:11px;color:var(--fb-text-muted, #667085)}.fb-ref__close{width:100%;margin-top:4px;padding:4px;border:0;border-top:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}\n"] }]
|
|
2995
|
-
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], dataType: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataType", required: false }] }], isCollection: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCollection", required: false }] }], objectType: [{ type: i0.Input, args: [{ isSignal: true, alias: "objectType", required: false }] }], writableOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "writableOnly", required: false }] }],
|
|
3230
|
+
args: [{ selector: 'fb-reference-picker', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-ref\" [class.fb-ref--open]=\"isOpen()\">\r\n <div class=\"fb-ref__control\">\r\n <input\r\n class=\"fb-ref__input\"\r\n type=\"text\"\r\n [value]=\"value() || ''\"\r\n [placeholder]=\"placeholder()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"label()\"\r\n (input)=\"onManualInput($any($event.target).value)\"\r\n (focus)=\"open()\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__toggle\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isOpen()\"\r\n aria-label=\"Mostra i riferimenti disponibili\"\r\n (click)=\"toggle()\"\r\n >\r\n \u25BE\r\n </button>\r\n @if (value()) {\r\n <button type=\"button\" class=\"fb-ref__clear\" aria-label=\"Svuota\" (click)=\"clear()\">\u00D7</button>\r\n }\r\n </div>\r\n\r\n @if (hint()) {\r\n <p class=\"fb-ref__hint\" [class.fb-ref__hint--warn]=\"valueState() === 'unknown'\">{{ hint() }}</p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"fb-ref__hint fb-ref__hint--warn\">\r\n Elenco dei riferimenti non disponibile: puoi scrivere il nome a mano.\r\n </p>\r\n }\r\n\r\n @if (isOpen()) {\r\n <div class=\"fb-ref__panel\" role=\"listbox\">\r\n <input\r\n class=\"fb-ref__search\"\r\n type=\"search\"\r\n placeholder=\"Filtra\"\r\n aria-label=\"Filtra i riferimenti\"\r\n (input)=\"onQuery($any($event.target).value)\"\r\n />\r\n @if (groups().length === 0) {\r\n <p class=\"fb-ref__empty\">Nessun riferimento compatibile.</p>\r\n }\r\n @for (group of groups(); track group.kind) {\r\n <div class=\"fb-ref__group\">\r\n <span class=\"fb-ref__group-label\">{{ group.label }}</span>\r\n @for (item of group.items; track item.name) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__option\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"item.name === value()\"\r\n (click)=\"choose(item)\"\r\n >\r\n <span class=\"fb-ref__name\">{{ item.name }}</span>\r\n <span class=\"fb-ref__meta\">{{ describe(item) }}</span>\r\n </button>\r\n }\r\n </div>\r\n }\r\n <button type=\"button\" class=\"fb-ref__close\" (click)=\"close()\">Chiudi</button>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block}.fb-ref{position:relative}.fb-ref__control{display:flex;align-items:stretch;gap:0;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);overflow:hidden}.fb-ref--open .fb-ref__control{border-color:var(--fb-accent, #2f6feb)}.fb-ref__input{flex:1;min-width:0;padding:5px 7px;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-ref__input:focus-visible{outline:none}.fb-ref__toggle,.fb-ref__clear{flex:0 0 auto;padding:0 7px;border:0;border-left:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:12px;cursor:pointer}.fb-ref__toggle:hover,.fb-ref__clear:hover{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__hint{margin:3px 0 0;font-size:10px;line-height:1.35;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__hint--warn{color:var(--fb-warning, #b7791f)}.fb-ref__panel{position:absolute;z-index:30;top:calc(100% + 3px);left:0;right:0;max-height:260px;overflow-y:auto;padding:6px;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);box-shadow:0 6px 18px #10182829}.fb-ref__search{box-sizing:border-box;width:100%;margin-bottom:6px;padding:4px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:5px;font:inherit;font-size:12px}.fb-ref__group{margin-bottom:6px}.fb-ref__group-label{display:block;padding:2px 4px;font-size:9px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__option{display:flex;flex-direction:column;width:100%;padding:4px 6px;border:0;border-radius:4px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-ref__option:hover,.fb-ref__option[aria-selected=true]{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__name{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.fb-ref__meta{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-ref__empty{margin:4px;font-size:11px;color:var(--fb-text-muted, #667085)}.fb-ref__close{width:100%;margin-top:4px;padding:4px;border:0;border-top:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}\n"] }]
|
|
3231
|
+
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], dataType: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataType", required: false }] }], isCollection: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCollection", required: false }] }], objectType: [{ type: i0.Input, args: [{ isSignal: true, alias: "objectType", required: false }] }], writableOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "writableOnly", required: false }] }], elementsOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "elementsOnly", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
|
|
2996
3232
|
|
|
2997
3233
|
/**
|
|
2998
3234
|
* `[fbValue]` su un `<select>`.
|
|
@@ -3042,6 +3278,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
|
|
|
3042
3278
|
*
|
|
3043
3279
|
* Il tipo del letterale deve corrispondere al tipo della destinazione: quando il tipo e'
|
|
3044
3280
|
* noto, l'editor mostra il controllo giusto e propone quella modalita' per default.
|
|
3281
|
+
*
|
|
3282
|
+
* Due dettagli di formato che il contratto tratta come sostanza, non come presentazione:
|
|
3283
|
+
*
|
|
3284
|
+
* - i numeri viaggiano in **cultura invariante** (§4.3): il separatore decimale e' il punto, e
|
|
3285
|
+
* `1234,50` viene tradotto in `1234.50` invece di essere troncato in silenzio;
|
|
3286
|
+
* - un valore data **senza fuso** significa "ora locale dell'applicazione", non "UTC"
|
|
3287
|
+
* (§4.2, §13.15): sono due istanti diversi, quindi il fuso e' una scelta esplicita
|
|
3288
|
+
* dell'utente e non un effetto collaterale del datepicker.
|
|
3045
3289
|
*/
|
|
3046
3290
|
class ValueEditorComponent {
|
|
3047
3291
|
dictionaries = inject(FlowDictionaryStore);
|
|
@@ -3147,6 +3391,12 @@ class ValueEditorComponent {
|
|
|
3147
3391
|
return '';
|
|
3148
3392
|
}
|
|
3149
3393
|
const field = this.literalField();
|
|
3394
|
+
if (field === 'dateValue' && value.dateValue !== undefined) {
|
|
3395
|
+
// `datetime-local` rifiuta un valore col fuso e resterebbe **vuoto** pur avendo un
|
|
3396
|
+
// valore: il suffisso si toglie qui e si riscrive in uscita. Se il documento porta un
|
|
3397
|
+
// campo diverso da quello atteso si passa al fallback qui sotto, che lo mostra comunque.
|
|
3398
|
+
return ValueEditorComponent.stripZone(value.dateValue);
|
|
3399
|
+
}
|
|
3150
3400
|
const raw = value[field];
|
|
3151
3401
|
if (raw === undefined || raw === null) {
|
|
3152
3402
|
// Se il documento porta un tipo diverso da quello atteso, mostralo comunque:
|
|
@@ -3161,6 +3411,15 @@ class ValueEditorComponent {
|
|
|
3161
3411
|
return String(raw);
|
|
3162
3412
|
}, ...(ngDevMode ? [{ debugName: "literalText" }] : []));
|
|
3163
3413
|
booleanValue = computed(() => this.value()?.booleanValue === true, ...(ngDevMode ? [{ debugName: "booleanValue" }] : []));
|
|
3414
|
+
/** Il fuso dichiarato nel valore data: `Z`, un offset, oppure niente = ora locale (§4.2). */
|
|
3415
|
+
dateIsUtc = computed(() => ValueEditorComponent.hasZone(this.value()?.dateValue), ...(ngDevMode ? [{ debugName: "dateIsUtc" }] : []));
|
|
3416
|
+
static ZONE_PATTERN = /(Z|[+-]\d{2}:?\d{2})$/;
|
|
3417
|
+
static hasZone(value) {
|
|
3418
|
+
return !!value && ValueEditorComponent.ZONE_PATTERN.test(value);
|
|
3419
|
+
}
|
|
3420
|
+
static stripZone(value) {
|
|
3421
|
+
return (value ?? '').replace(ValueEditorComponent.ZONE_PATTERN, '');
|
|
3422
|
+
}
|
|
3164
3423
|
globalConstants = computed(() => {
|
|
3165
3424
|
const entry = this.dictionaries
|
|
3166
3425
|
.globalVariables()
|
|
@@ -3169,7 +3428,17 @@ class ValueEditorComponent {
|
|
|
3169
3428
|
// fanno digitare (§4.1).
|
|
3170
3429
|
return (entry?.paths ?? []).map((path) => `$GlobalConstant.${path}`);
|
|
3171
3430
|
}, ...(ngDevMode ? [{ debugName: "globalConstants" }] : []));
|
|
3172
|
-
|
|
3431
|
+
numericHint = computed(() => {
|
|
3432
|
+
switch (this.dataType()) {
|
|
3433
|
+
case 'Number':
|
|
3434
|
+
// Il punto decimale non e' una preferenza di formato: la virgola non e' accettata (§4.3).
|
|
3435
|
+
return 'Separatore decimale: il punto. Usa Number per importi e quantita’: Integer troncherebbe i decimali.';
|
|
3436
|
+
case 'Integer':
|
|
3437
|
+
return 'Numero intero, senza separatore delle migliaia.';
|
|
3438
|
+
default:
|
|
3439
|
+
return null;
|
|
3440
|
+
}
|
|
3441
|
+
}, ...(ngDevMode ? [{ debugName: "numericHint" }] : []));
|
|
3173
3442
|
setMode(mode) {
|
|
3174
3443
|
switch (mode) {
|
|
3175
3444
|
case 'reference':
|
|
@@ -3201,19 +3470,21 @@ class ValueEditorComponent {
|
|
|
3201
3470
|
}
|
|
3202
3471
|
switch (field) {
|
|
3203
3472
|
case 'integerValue': {
|
|
3204
|
-
|
|
3205
|
-
|
|
3473
|
+
// Cultura invariante anche sugli interi: `1.234` non e' milleduecentotrentaquattro.
|
|
3474
|
+
const parsed = parseInvariantNumber(raw);
|
|
3475
|
+
this.emit(parsed === undefined ? undefined : { integerValue: Math.trunc(parsed) });
|
|
3206
3476
|
return;
|
|
3207
3477
|
}
|
|
3208
3478
|
case 'numberValue': {
|
|
3209
|
-
const parsed =
|
|
3210
|
-
this.emit(
|
|
3479
|
+
const parsed = parseInvariantNumber(raw);
|
|
3480
|
+
this.emit(parsed === undefined ? undefined : { numberValue: parsed });
|
|
3211
3481
|
return;
|
|
3212
3482
|
}
|
|
3213
3483
|
case 'dateValue':
|
|
3214
|
-
//
|
|
3215
|
-
//
|
|
3216
|
-
|
|
3484
|
+
// L'input `datetime-local` produce `2026-08-15T00:00` senza fuso: si completano i
|
|
3485
|
+
// secondi e si riscrive il fuso scelto, perche' senza `Z` il valore significa
|
|
3486
|
+
// "ora locale" e il motore lo converte prima di confrontarlo (§4.2).
|
|
3487
|
+
this.emit({ dateValue: this.withDateZone(raw.length === 16 ? `${raw}:00` : raw) });
|
|
3217
3488
|
return;
|
|
3218
3489
|
case 'enumValue':
|
|
3219
3490
|
this.emit({ enumValue: raw });
|
|
@@ -3225,6 +3496,21 @@ class ValueEditorComponent {
|
|
|
3225
3496
|
onBooleanChange(checked) {
|
|
3226
3497
|
this.emit({ booleanValue: checked });
|
|
3227
3498
|
}
|
|
3499
|
+
withDateZone(local, utc = this.dateIsUtc()) {
|
|
3500
|
+
return utc ? `${ValueEditorComponent.stripZone(local)}Z` : ValueEditorComponent.stripZone(local);
|
|
3501
|
+
}
|
|
3502
|
+
/**
|
|
3503
|
+
* Cambia il fuso **dichiarato**, non l'istante: `09:00Z` e `09:00` sono le nove in due fusi
|
|
3504
|
+
* diversi, e l'editor non converte al posto dell'utente. Riscrivere lo stesso orario con
|
|
3505
|
+
* l'altro fuso e' esattamente cio' che serve quando il valore e' stato inserito sbagliato.
|
|
3506
|
+
*/
|
|
3507
|
+
setDateZone(utc) {
|
|
3508
|
+
const current = this.value()?.dateValue;
|
|
3509
|
+
if (!current) {
|
|
3510
|
+
return;
|
|
3511
|
+
}
|
|
3512
|
+
this.emit({ dateValue: this.withDateZone(current, utc) });
|
|
3513
|
+
}
|
|
3228
3514
|
onFormulaChange(expression) {
|
|
3229
3515
|
this.emit({
|
|
3230
3516
|
formulaExpression: expression,
|
|
@@ -3268,17 +3554,17 @@ class ValueEditorComponent {
|
|
|
3268
3554
|
}
|
|
3269
3555
|
dataTypeOptions = computed(() => this.dictionaries.dataTypes(), ...(ngDevMode ? [{ debugName: "dataTypeOptions" }] : []));
|
|
3270
3556
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ValueEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3271
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ValueEditorComponent, isStandalone: true, selector: "fb-value-editor", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, dataType: { classPropertyName: "dataType", publicName: "dataType", isSignal: true, isRequired: false, transformFunction: null }, objectType: { classPropertyName: "objectType", publicName: "objectType", isSignal: true, isRequired: false, transformFunction: null }, isCollection: { classPropertyName: "isCollection", publicName: "isCollection", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, allowFormula: { classPropertyName: "allowFormula", publicName: "allowFormula", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div class=\"fb-value\">\r\n <div class=\"fb-value__modes\" role=\"group\" [attr.aria-label]=\"label() + ': modalita\u2019'\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'reference'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Riferimento a una risorsa o all\u2019output di un elemento\"\r\n (click)=\"setMode('reference')\"\r\n >\r\n Riferimento\r\n </button>\r\n @if (literalAllowed()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'literal'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Valore letterale del tipo della destinazione\"\r\n (click)=\"setMode('literal')\"\r\n >\r\n Valore\r\n </button>\r\n }\r\n @if (allowFormula()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'formula'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Espressione calcolata dal motore di regole\"\r\n (click)=\"setMode('formula')\"\r\n >\r\n Formula\r\n </button>\r\n }\r\n @if (globalConstants().length) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'globalConstant'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Costante globale\"\r\n (click)=\"setMode('globalConstant')\"\r\n >\r\n Costante globale\r\n </button>\r\n }\r\n @if (mode() !== 'empty') {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode fb-value__mode--clear\"\r\n [disabled]=\"disabled()\"\r\n title=\"Nessun valore\"\r\n (click)=\"setMode('empty')\"\r\n >\r\n \u00D7\r\n </button>\r\n }\r\n </div>\r\n\r\n @if (isAmbiguous()) {\r\n <!-- Piu' campi di valore insieme: il comportamento a runtime dipende dall'ordine di lettura. -->\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questo valore ha {{ filledFieldCount() }} campi valorizzati insieme: a runtime conta l\u2019ordine di lettura.\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"normalize()\">\r\n Tieni solo \u00AB{{ mode() === 'formula' ? 'formula' : mode() === 'literal' ? 'valore' : 'riferimento' }}\u00BB\r\n </button>\r\n </p>\r\n }\r\n\r\n @switch (mode()) {\r\n @case ('reference') {\r\n <fb-reference-picker\r\n [value]=\"value()?.elementReference\"\r\n [label]=\"label()\"\r\n [dataType]=\"dataType()\"\r\n [isCollection]=\"isCollection()\"\r\n [objectType]=\"objectType()\"\r\n [disabled]=\"disabled()\"\r\n (valueChange)=\"onReferenceChange($event)\"\r\n />\r\n }\r\n\r\n @case ('globalConstant') {\r\n <select\r\n class=\"fb-select\"\r\n [disabled]=\"disabled()\"\r\n [fbValue]=\"value()?.elementReference || ''\"\r\n (change)=\"onGlobalConstantChange($any($event.target).value)\"\r\n >\r\n @for (constant of globalConstants(); track constant) {\r\n <option [value]=\"constant\">{{ constant }}</option>\r\n }\r\n </select>\r\n }\r\n\r\n @case ('literal') {\r\n @if (dataType() === 'Boolean') {\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"booleanValue()\"\r\n [disabled]=\"disabled()\"\r\n (change)=\"onBooleanChange($any($event.target).checked)\"\r\n />\r\n {{ booleanValue() ? 'vero' : 'falso' }}\r\n </label>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [type]=\"literalInputType()\"\r\n [value]=\"literalText()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"label()\"\r\n [placeholder]=\"dataType() === 'Enum' ? 'Nome del valore di enum' : ''\"\r\n (input)=\"onLiteralChange($any($event.target).value)\"\r\n />\r\n @if (
|
|
3557
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ValueEditorComponent, isStandalone: true, selector: "fb-value-editor", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, dataType: { classPropertyName: "dataType", publicName: "dataType", isSignal: true, isRequired: false, transformFunction: null }, objectType: { classPropertyName: "objectType", publicName: "objectType", isSignal: true, isRequired: false, transformFunction: null }, isCollection: { classPropertyName: "isCollection", publicName: "isCollection", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, allowFormula: { classPropertyName: "allowFormula", publicName: "allowFormula", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div class=\"fb-value\">\r\n <div class=\"fb-value__modes\" role=\"group\" [attr.aria-label]=\"label() + ': modalita\u2019'\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'reference'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Riferimento a una risorsa o all\u2019output di un elemento\"\r\n (click)=\"setMode('reference')\"\r\n >\r\n Riferimento\r\n </button>\r\n @if (literalAllowed()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'literal'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Valore letterale del tipo della destinazione\"\r\n (click)=\"setMode('literal')\"\r\n >\r\n Valore\r\n </button>\r\n }\r\n @if (allowFormula()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'formula'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Espressione calcolata dal motore di regole\"\r\n (click)=\"setMode('formula')\"\r\n >\r\n Formula\r\n </button>\r\n }\r\n @if (globalConstants().length) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'globalConstant'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Costante globale\"\r\n (click)=\"setMode('globalConstant')\"\r\n >\r\n Costante globale\r\n </button>\r\n }\r\n @if (mode() !== 'empty') {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode fb-value__mode--clear\"\r\n [disabled]=\"disabled()\"\r\n title=\"Nessun valore\"\r\n (click)=\"setMode('empty')\"\r\n >\r\n \u00D7\r\n </button>\r\n }\r\n </div>\r\n\r\n @if (isAmbiguous()) {\r\n <!-- Piu' campi di valore insieme: il comportamento a runtime dipende dall'ordine di lettura. -->\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questo valore ha {{ filledFieldCount() }} campi valorizzati insieme: a runtime conta l\u2019ordine di lettura.\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"normalize()\">\r\n Tieni solo \u00AB{{ mode() === 'formula' ? 'formula' : mode() === 'literal' ? 'valore' : 'riferimento' }}\u00BB\r\n </button>\r\n </p>\r\n }\r\n\r\n @switch (mode()) {\r\n @case ('reference') {\r\n <fb-reference-picker\r\n [value]=\"value()?.elementReference\"\r\n [label]=\"label()\"\r\n [dataType]=\"dataType()\"\r\n [isCollection]=\"isCollection()\"\r\n [objectType]=\"objectType()\"\r\n [disabled]=\"disabled()\"\r\n (valueChange)=\"onReferenceChange($event)\"\r\n />\r\n }\r\n\r\n @case ('globalConstant') {\r\n <select\r\n class=\"fb-select\"\r\n [disabled]=\"disabled()\"\r\n [fbValue]=\"value()?.elementReference || ''\"\r\n (change)=\"onGlobalConstantChange($any($event.target).value)\"\r\n >\r\n @for (constant of globalConstants(); track constant) {\r\n <option [value]=\"constant\">{{ constant }}</option>\r\n }\r\n </select>\r\n }\r\n\r\n @case ('literal') {\r\n @if (dataType() === 'Boolean') {\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"booleanValue()\"\r\n [disabled]=\"disabled()\"\r\n (change)=\"onBooleanChange($any($event.target).checked)\"\r\n />\r\n {{ booleanValue() ? 'vero' : 'falso' }}\r\n </label>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [type]=\"literalInputType()\"\r\n [value]=\"literalText()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"label()\"\r\n [placeholder]=\"dataType() === 'Enum' ? 'Nome del valore di enum' : ''\"\r\n (input)=\"onLiteralChange($any($event.target).value)\"\r\n />\r\n @if (numericHint()) {\r\n <p class=\"fb-field__hint\">{{ numericHint() }}</p>\r\n }\r\n @if (dataType() === 'Date') {\r\n <!--\r\n Il fuso e' una scelta, non un dettaglio: `09:00Z` e `09:00` sono due istanti\r\n diversi, e il motore converte in UTC prima di ogni confronto (\u00A74.2).\r\n -->\r\n <div class=\"fb-value__modes\" role=\"group\" aria-label=\"Fuso del valore data\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"!dateIsUtc()\"\r\n [disabled]=\"disabled()\"\r\n title=\"Interpretato nel fuso dell\u2019applicazione\"\r\n (click)=\"setDateZone(false)\"\r\n >\r\n Ora locale\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"dateIsUtc()\"\r\n [disabled]=\"disabled()\"\r\n title=\"Scrive il suffisso Z: l\u2019orario e\u2019 in UTC\"\r\n (click)=\"setDateZone(true)\"\r\n >\r\n UTC (Z)\r\n </button>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Data e ora insieme.\r\n {{\r\n dateIsUtc()\r\n ? 'Con \u00ABUTC\u00BB l\u2019orario e\u2019 assoluto.'\r\n : 'Senza fuso l\u2019orario e\u2019 interpretato nel fuso dell\u2019applicazione, non in UTC.'\r\n }}\r\n Cambiare fuso riscrive l\u2019orario, non lo converte.\r\n </p>\r\n }\r\n }\r\n }\r\n\r\n @case ('formula') {\r\n <textarea\r\n class=\"fb-textarea fb-input--mono\"\r\n [value]=\"value()?.formulaExpression || ''\"\r\n [disabled]=\"disabled()\"\r\n placeholder=\"Importo * 1.22\"\r\n [attr.aria-label]=\"label() + ': espressione'\"\r\n (input)=\"onFormulaChange($any($event.target).value)\"\r\n ></textarea>\r\n <div class=\"fb-field__row\">\r\n <label class=\"fb-field__hint\">Tipo del risultato</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"value()?.formulaDataType || ''\"\r\n [disabled]=\"disabled()\"\r\n (change)=\"onFormulaTypeChange($any($event.target).value)\"\r\n >\r\n @for (type of dataTypeOptions(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n L\u2019espressione va al motore di regole: il backend non ne verifica la sintassi.\r\n </p>\r\n }\r\n\r\n @case ('empty') {\r\n <p class=\"fb-field__hint\">Nessun valore.</p>\r\n }\r\n }\r\n</div>\r\n", styles: [":host{display:block}.fb-value{display:flex;flex-direction:column;gap:4px}.fb-value__modes{display:flex;flex-wrap:wrap;gap:2px}.fb-value__mode{padding:2px 7px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:10px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:10px;cursor:pointer}.fb-value__mode:hover:not(:disabled){background:var(--fb-surface-alt, #f8f9fb)}.fb-value__mode--active{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent);color:var(--fb-accent, #2f6feb);font-weight:600}.fb-value__mode--clear{margin-left:auto}.fb-value__mode:disabled{opacity:.5;cursor:not-allowed}\n"], dependencies: [{ kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3272
3558
|
}
|
|
3273
3559
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ValueEditorComponent, decorators: [{
|
|
3274
3560
|
type: Component,
|
|
3275
|
-
args: [{ selector: 'fb-value-editor', standalone: true, imports: [ReferencePickerComponent, SelectValueDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-value\">\r\n <div class=\"fb-value__modes\" role=\"group\" [attr.aria-label]=\"label() + ': modalita\u2019'\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'reference'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Riferimento a una risorsa o all\u2019output di un elemento\"\r\n (click)=\"setMode('reference')\"\r\n >\r\n Riferimento\r\n </button>\r\n @if (literalAllowed()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'literal'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Valore letterale del tipo della destinazione\"\r\n (click)=\"setMode('literal')\"\r\n >\r\n Valore\r\n </button>\r\n }\r\n @if (allowFormula()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'formula'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Espressione calcolata dal motore di regole\"\r\n (click)=\"setMode('formula')\"\r\n >\r\n Formula\r\n </button>\r\n }\r\n @if (globalConstants().length) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'globalConstant'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Costante globale\"\r\n (click)=\"setMode('globalConstant')\"\r\n >\r\n Costante globale\r\n </button>\r\n }\r\n @if (mode() !== 'empty') {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode fb-value__mode--clear\"\r\n [disabled]=\"disabled()\"\r\n title=\"Nessun valore\"\r\n (click)=\"setMode('empty')\"\r\n >\r\n \u00D7\r\n </button>\r\n }\r\n </div>\r\n\r\n @if (isAmbiguous()) {\r\n <!-- Piu' campi di valore insieme: il comportamento a runtime dipende dall'ordine di lettura. -->\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questo valore ha {{ filledFieldCount() }} campi valorizzati insieme: a runtime conta l\u2019ordine di lettura.\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"normalize()\">\r\n Tieni solo \u00AB{{ mode() === 'formula' ? 'formula' : mode() === 'literal' ? 'valore' : 'riferimento' }}\u00BB\r\n </button>\r\n </p>\r\n }\r\n\r\n @switch (mode()) {\r\n @case ('reference') {\r\n <fb-reference-picker\r\n [value]=\"value()?.elementReference\"\r\n [label]=\"label()\"\r\n [dataType]=\"dataType()\"\r\n [isCollection]=\"isCollection()\"\r\n [objectType]=\"objectType()\"\r\n [disabled]=\"disabled()\"\r\n (valueChange)=\"onReferenceChange($event)\"\r\n />\r\n }\r\n\r\n @case ('globalConstant') {\r\n <select\r\n class=\"fb-select\"\r\n [disabled]=\"disabled()\"\r\n [fbValue]=\"value()?.elementReference || ''\"\r\n (change)=\"onGlobalConstantChange($any($event.target).value)\"\r\n >\r\n @for (constant of globalConstants(); track constant) {\r\n <option [value]=\"constant\">{{ constant }}</option>\r\n }\r\n </select>\r\n }\r\n\r\n @case ('literal') {\r\n @if (dataType() === 'Boolean') {\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"booleanValue()\"\r\n [disabled]=\"disabled()\"\r\n (change)=\"onBooleanChange($any($event.target).checked)\"\r\n />\r\n {{ booleanValue() ? 'vero' : 'falso' }}\r\n </label>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [type]=\"literalInputType()\"\r\n [value]=\"literalText()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"label()\"\r\n [placeholder]=\"dataType() === 'Enum' ? 'Nome del valore di enum' : ''\"\r\n (input)=\"onLiteralChange($any($event.target).value)\"\r\n />\r\n @if (
|
|
3561
|
+
args: [{ selector: 'fb-value-editor', standalone: true, imports: [ReferencePickerComponent, SelectValueDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-value\">\r\n <div class=\"fb-value__modes\" role=\"group\" [attr.aria-label]=\"label() + ': modalita\u2019'\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'reference'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Riferimento a una risorsa o all\u2019output di un elemento\"\r\n (click)=\"setMode('reference')\"\r\n >\r\n Riferimento\r\n </button>\r\n @if (literalAllowed()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'literal'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Valore letterale del tipo della destinazione\"\r\n (click)=\"setMode('literal')\"\r\n >\r\n Valore\r\n </button>\r\n }\r\n @if (allowFormula()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'formula'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Espressione calcolata dal motore di regole\"\r\n (click)=\"setMode('formula')\"\r\n >\r\n Formula\r\n </button>\r\n }\r\n @if (globalConstants().length) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"mode() === 'globalConstant'\"\r\n [disabled]=\"disabled()\"\r\n title=\"Costante globale\"\r\n (click)=\"setMode('globalConstant')\"\r\n >\r\n Costante globale\r\n </button>\r\n }\r\n @if (mode() !== 'empty') {\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode fb-value__mode--clear\"\r\n [disabled]=\"disabled()\"\r\n title=\"Nessun valore\"\r\n (click)=\"setMode('empty')\"\r\n >\r\n \u00D7\r\n </button>\r\n }\r\n </div>\r\n\r\n @if (isAmbiguous()) {\r\n <!-- Piu' campi di valore insieme: il comportamento a runtime dipende dall'ordine di lettura. -->\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questo valore ha {{ filledFieldCount() }} campi valorizzati insieme: a runtime conta l\u2019ordine di lettura.\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"normalize()\">\r\n Tieni solo \u00AB{{ mode() === 'formula' ? 'formula' : mode() === 'literal' ? 'valore' : 'riferimento' }}\u00BB\r\n </button>\r\n </p>\r\n }\r\n\r\n @switch (mode()) {\r\n @case ('reference') {\r\n <fb-reference-picker\r\n [value]=\"value()?.elementReference\"\r\n [label]=\"label()\"\r\n [dataType]=\"dataType()\"\r\n [isCollection]=\"isCollection()\"\r\n [objectType]=\"objectType()\"\r\n [disabled]=\"disabled()\"\r\n (valueChange)=\"onReferenceChange($event)\"\r\n />\r\n }\r\n\r\n @case ('globalConstant') {\r\n <select\r\n class=\"fb-select\"\r\n [disabled]=\"disabled()\"\r\n [fbValue]=\"value()?.elementReference || ''\"\r\n (change)=\"onGlobalConstantChange($any($event.target).value)\"\r\n >\r\n @for (constant of globalConstants(); track constant) {\r\n <option [value]=\"constant\">{{ constant }}</option>\r\n }\r\n </select>\r\n }\r\n\r\n @case ('literal') {\r\n @if (dataType() === 'Boolean') {\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"booleanValue()\"\r\n [disabled]=\"disabled()\"\r\n (change)=\"onBooleanChange($any($event.target).checked)\"\r\n />\r\n {{ booleanValue() ? 'vero' : 'falso' }}\r\n </label>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [type]=\"literalInputType()\"\r\n [value]=\"literalText()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"label()\"\r\n [placeholder]=\"dataType() === 'Enum' ? 'Nome del valore di enum' : ''\"\r\n (input)=\"onLiteralChange($any($event.target).value)\"\r\n />\r\n @if (numericHint()) {\r\n <p class=\"fb-field__hint\">{{ numericHint() }}</p>\r\n }\r\n @if (dataType() === 'Date') {\r\n <!--\r\n Il fuso e' una scelta, non un dettaglio: `09:00Z` e `09:00` sono due istanti\r\n diversi, e il motore converte in UTC prima di ogni confronto (\u00A74.2).\r\n -->\r\n <div class=\"fb-value__modes\" role=\"group\" aria-label=\"Fuso del valore data\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"!dateIsUtc()\"\r\n [disabled]=\"disabled()\"\r\n title=\"Interpretato nel fuso dell\u2019applicazione\"\r\n (click)=\"setDateZone(false)\"\r\n >\r\n Ora locale\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-value__mode\"\r\n [class.fb-value__mode--active]=\"dateIsUtc()\"\r\n [disabled]=\"disabled()\"\r\n title=\"Scrive il suffisso Z: l\u2019orario e\u2019 in UTC\"\r\n (click)=\"setDateZone(true)\"\r\n >\r\n UTC (Z)\r\n </button>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Data e ora insieme.\r\n {{\r\n dateIsUtc()\r\n ? 'Con \u00ABUTC\u00BB l\u2019orario e\u2019 assoluto.'\r\n : 'Senza fuso l\u2019orario e\u2019 interpretato nel fuso dell\u2019applicazione, non in UTC.'\r\n }}\r\n Cambiare fuso riscrive l\u2019orario, non lo converte.\r\n </p>\r\n }\r\n }\r\n }\r\n\r\n @case ('formula') {\r\n <textarea\r\n class=\"fb-textarea fb-input--mono\"\r\n [value]=\"value()?.formulaExpression || ''\"\r\n [disabled]=\"disabled()\"\r\n placeholder=\"Importo * 1.22\"\r\n [attr.aria-label]=\"label() + ': espressione'\"\r\n (input)=\"onFormulaChange($any($event.target).value)\"\r\n ></textarea>\r\n <div class=\"fb-field__row\">\r\n <label class=\"fb-field__hint\">Tipo del risultato</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"value()?.formulaDataType || ''\"\r\n [disabled]=\"disabled()\"\r\n (change)=\"onFormulaTypeChange($any($event.target).value)\"\r\n >\r\n @for (type of dataTypeOptions(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n L\u2019espressione va al motore di regole: il backend non ne verifica la sintassi.\r\n </p>\r\n }\r\n\r\n @case ('empty') {\r\n <p class=\"fb-field__hint\">Nessun valore.</p>\r\n }\r\n }\r\n</div>\r\n", styles: [":host{display:block}.fb-value{display:flex;flex-direction:column;gap:4px}.fb-value__modes{display:flex;flex-wrap:wrap;gap:2px}.fb-value__mode{padding:2px 7px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:10px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:10px;cursor:pointer}.fb-value__mode:hover:not(:disabled){background:var(--fb-surface-alt, #f8f9fb)}.fb-value__mode--active{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent);color:var(--fb-accent, #2f6feb);font-weight:600}.fb-value__mode--clear{margin-left:auto}.fb-value__mode:disabled{opacity:.5;cursor:not-allowed}\n"] }]
|
|
3276
3562
|
}], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], dataType: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataType", required: false }] }], objectType: [{ type: i0.Input, args: [{ isSignal: true, alias: "objectType", required: false }] }], isCollection: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCollection", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], allowFormula: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowFormula", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
|
|
3277
3563
|
|
|
3278
3564
|
/**
|
|
3279
|
-
* Editor delle condizioni — FRONTEND.md §4.3 e trappole §13.1, §13.4.
|
|
3565
|
+
* Editor delle condizioni — FRONTEND.md §4.3 e trappole §13.1, §13.4, §13.13, §13.14.
|
|
3280
3566
|
*
|
|
3281
|
-
*
|
|
3567
|
+
* Quattro cose che questo componente fa deliberatamente, perche' un editor che non le fa
|
|
3282
3568
|
* produce condizioni che fanno il contrario di quello che l'utente crede:
|
|
3283
3569
|
*
|
|
3284
3570
|
* 1. **Operatori unari.** Sette operatori non confrontano due valori: per loro
|
|
@@ -3290,21 +3576,117 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
|
|
|
3290
3576
|
* perche' gli indici sono 1-based e scalano. La riscrittura sta in
|
|
3291
3577
|
* {@link removeCondition} / {@link moveCondition}.
|
|
3292
3578
|
*
|
|
3579
|
+
* 3. **Testo e numero non si confrontano** (`CONDITION_TYPE_MISMATCH`, errore che blocca
|
|
3580
|
+
* l'attivazione). Il tipo del lato sinistro arriva da `POST /flows/references` e guida il
|
|
3581
|
+
* secondo operando: il letterale finisce nel campo giusto e una risorsa incompatibile e'
|
|
3582
|
+
* segnalata. Il backend segnala solo quando conosce **entrambi** i tipi, e su un campo di
|
|
3583
|
+
* un record non li conosce: fermare qui e' il solo modo di fermare in tempo.
|
|
3584
|
+
*
|
|
3585
|
+
* 4. **`None` non e' un operatore, e' un "da completare"**: la bozza si salva, l'attivazione
|
|
3586
|
+
* no. La condizione e' evidenziata come incompleta, non presentata come valida.
|
|
3587
|
+
*
|
|
3293
3588
|
* Inoltre: `WasVisited` e `HasError` vogliono a sinistra il nome di un **node**, non di una
|
|
3294
3589
|
* risorsa (`appliesToElements`), e il selettore cambia di conseguenza.
|
|
3295
3590
|
*/
|
|
3296
3591
|
class ConditionEditorComponent {
|
|
3297
3592
|
dictionaries = inject(FlowDictionaryStore);
|
|
3593
|
+
api = inject(FlowBuilderApi);
|
|
3594
|
+
store = inject(FlowDocumentStore);
|
|
3298
3595
|
/** Il contenitore: porta `conditions`, `conditionLogic` e, se serve, `formula`. */
|
|
3299
3596
|
holder = input.required(...(ngDevMode ? [{ debugName: "holder" }] : []));
|
|
3300
3597
|
title = input('Condizioni', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
3301
3598
|
/** `false` dove il modello non prevede la modalita' formula sull'elemento. */
|
|
3302
3599
|
allowFormula = input(true, ...(ngDevMode ? [{ debugName: "allowFormula" }] : []));
|
|
3600
|
+
/**
|
|
3601
|
+
* `false` dove il modello porta **solo** la lista di condizioni, senza un campo per la
|
|
3602
|
+
* logica: gli `entryConditions` / `exitConditions` di uno step di orchestrazione (§5.13).
|
|
3603
|
+
* Mostrare i pulsanti della logica lì scriverebbe un campo che il contratto non prevede.
|
|
3604
|
+
*/
|
|
3605
|
+
allowLogic = input(true, ...(ngDevMode ? [{ debugName: "allowLogic" }] : []));
|
|
3303
3606
|
/** Path per ancorare i rilievi di validazione, es. `rules[Approvato]`. */
|
|
3304
3607
|
issuePath = input('', ...(ngDevMode ? [{ debugName: "issuePath" }] : []));
|
|
3305
3608
|
/** Emesso a ogni modifica: il chiamante applica la mutazione allo store. */
|
|
3306
3609
|
changed = output();
|
|
3307
3610
|
conditions = computed(() => this.holder().conditions ?? [], ...(ngDevMode ? [{ debugName: "conditions" }] : []));
|
|
3611
|
+
/**
|
|
3612
|
+
* I riferimenti del documento, per conoscere il tipo del lato sinistro. Non e' un doppione
|
|
3613
|
+
* del picker: serve **il tipo**, che e' l'unica cosa che permette di impedire il confronto
|
|
3614
|
+
* fra testo e numero prima che lo dica la validazione (§4.3).
|
|
3615
|
+
*/
|
|
3616
|
+
references = signal([], ...(ngDevMode ? [{ debugName: "references" }] : []));
|
|
3617
|
+
constructor() {
|
|
3618
|
+
effect(() => {
|
|
3619
|
+
const definition = this.store.document();
|
|
3620
|
+
// Senza condizioni non serve conoscere nessun tipo: in un form con molti blocchi di
|
|
3621
|
+
// condizioni vuoti (uno stage con dieci step) risparmia altrettante richieste.
|
|
3622
|
+
if (!this.conditions().length) {
|
|
3623
|
+
return;
|
|
3624
|
+
}
|
|
3625
|
+
void this.api
|
|
3626
|
+
.getReferences({ definition })
|
|
3627
|
+
.then((list) => this.references.set(list ?? []))
|
|
3628
|
+
// Senza l'elenco non si segnala nulla: non sapere non e' sapere che e' sbagliato.
|
|
3629
|
+
.catch(() => this.references.set([]));
|
|
3630
|
+
});
|
|
3631
|
+
}
|
|
3632
|
+
/** Il tipo di un riferimento, `undefined` se navigato o ignoto: lì non si segnala (§4.3). */
|
|
3633
|
+
typeOfReference(reference) {
|
|
3634
|
+
if (!reference) {
|
|
3635
|
+
return undefined;
|
|
3636
|
+
}
|
|
3637
|
+
return this.references().find((entry) => entry.name === reference)?.dataType ?? undefined;
|
|
3638
|
+
}
|
|
3639
|
+
/** Il tipo del lato sinistro: guida il secondo operando. */
|
|
3640
|
+
leftDataType(condition) {
|
|
3641
|
+
return this.typeOfReference(condition.leftValueReference);
|
|
3642
|
+
}
|
|
3643
|
+
/** Il tipo del lato destro, dedotto dal campo valorizzato o dal riferimento scelto. */
|
|
3644
|
+
rightDataType(condition) {
|
|
3645
|
+
const value = condition.rightValue;
|
|
3646
|
+
if (!value) {
|
|
3647
|
+
return undefined;
|
|
3648
|
+
}
|
|
3649
|
+
if (value.formulaExpression !== undefined) {
|
|
3650
|
+
return value.formulaDataType;
|
|
3651
|
+
}
|
|
3652
|
+
if (value.elementReference !== undefined) {
|
|
3653
|
+
return this.typeOfReference(value.elementReference);
|
|
3654
|
+
}
|
|
3655
|
+
if (value.stringValue !== undefined) {
|
|
3656
|
+
return 'String';
|
|
3657
|
+
}
|
|
3658
|
+
if (value.integerValue !== undefined) {
|
|
3659
|
+
return 'Integer';
|
|
3660
|
+
}
|
|
3661
|
+
if (value.numberValue !== undefined) {
|
|
3662
|
+
return 'Number';
|
|
3663
|
+
}
|
|
3664
|
+
if (value.dateValue !== undefined) {
|
|
3665
|
+
return 'Date';
|
|
3666
|
+
}
|
|
3667
|
+
if (value.booleanValue !== undefined) {
|
|
3668
|
+
return 'Boolean';
|
|
3669
|
+
}
|
|
3670
|
+
if (value.enumValue !== undefined) {
|
|
3671
|
+
return 'Enum';
|
|
3672
|
+
}
|
|
3673
|
+
return undefined;
|
|
3674
|
+
}
|
|
3675
|
+
/**
|
|
3676
|
+
* `true` quando i due lati sono incompatibili: e' `CONDITION_TYPE_MISMATCH`, un errore che
|
|
3677
|
+
* blocca l'attivazione. L'unica coppia vietata e' testo con numero (§4.3).
|
|
3678
|
+
*/
|
|
3679
|
+
hasTypeMismatch(condition) {
|
|
3680
|
+
if (!isTypeCheckedOperator(condition.operator, this.isUnary(condition))) {
|
|
3681
|
+
return false;
|
|
3682
|
+
}
|
|
3683
|
+
return !areTypesComparable(this.leftDataType(condition), this.rightDataType(condition));
|
|
3684
|
+
}
|
|
3685
|
+
typeMismatchMessage(condition) {
|
|
3686
|
+
const left = this.leftDataType(condition) ?? '?';
|
|
3687
|
+
const right = this.rightDataType(condition) ?? '?';
|
|
3688
|
+
return `Un valore ${left} non si confronta con un valore ${right}: e’ CONDITION_TYPE_MISMATCH e blocca l’attivazione.`;
|
|
3689
|
+
}
|
|
3308
3690
|
logicMode = computed(() => {
|
|
3309
3691
|
const logic = this.holder().conditionLogic;
|
|
3310
3692
|
if (!logic) {
|
|
@@ -3331,7 +3713,19 @@ class ConditionEditorComponent {
|
|
|
3331
3713
|
}, ...(ngDevMode ? [{ debugName: "customLogicError" }] : []));
|
|
3332
3714
|
/** Con `Formula` il campo `conditions` viene **ignorato** dal motore (§4.3). */
|
|
3333
3715
|
conditionsIgnored = computed(() => this.logicMode() === 'formula', ...(ngDevMode ? [{ debugName: "conditionsIgnored" }] : []));
|
|
3334
|
-
|
|
3716
|
+
/**
|
|
3717
|
+
* Gli operatori applicabili al tipo del lato sinistro: `appliesTo` del dizionario, vuoto =
|
|
3718
|
+
* qualunque tipo (§4.3). L'operatore già scritto si tiene comunque nell'elenco, altrimenti
|
|
3719
|
+
* il `select` resterebbe vuoto pur avendo un valore.
|
|
3720
|
+
*/
|
|
3721
|
+
operatorsFor(condition) {
|
|
3722
|
+
const applicable = this.dictionaries.operatorsFor(this.leftDataType(condition));
|
|
3723
|
+
if (!condition.operator || applicable.some((entry) => entry.value === condition.operator)) {
|
|
3724
|
+
return applicable;
|
|
3725
|
+
}
|
|
3726
|
+
const current = this.dictionaries.operator(condition.operator);
|
|
3727
|
+
return current ? [...applicable, current] : applicable;
|
|
3728
|
+
}
|
|
3335
3729
|
isUnary(condition) {
|
|
3336
3730
|
return this.dictionaries.isUnaryOperator(condition.operator);
|
|
3337
3731
|
}
|
|
@@ -3360,10 +3754,15 @@ class ConditionEditorComponent {
|
|
|
3360
3754
|
operatorDescription(operator) {
|
|
3361
3755
|
return this.dictionaries.operator(operator)?.description ?? null;
|
|
3362
3756
|
}
|
|
3363
|
-
/**
|
|
3757
|
+
/**
|
|
3758
|
+
* `None` e' uno stato dell'editor, non un operatore: la **bozza si salva, l'attivazione no**
|
|
3759
|
+
* (`CONDITION_INCOMPLETE`, errore). A runtime vale sempre falso (§4.3, §13.14).
|
|
3760
|
+
*/
|
|
3364
3761
|
isPlaceholderOperator(condition) {
|
|
3365
3762
|
return condition.operator === 'None';
|
|
3366
3763
|
}
|
|
3764
|
+
/** Quante condizioni sono da completare: si dice in testa, non solo riga per riga. */
|
|
3765
|
+
incompleteCount = computed(() => this.conditions().filter((condition) => condition.operator === 'None').length, ...(ngDevMode ? [{ debugName: "incompleteCount" }] : []));
|
|
3367
3766
|
// -------------------------------------------------------------------------
|
|
3368
3767
|
// Mutazioni
|
|
3369
3768
|
// -------------------------------------------------------------------------
|
|
@@ -3466,12 +3865,12 @@ class ConditionEditorComponent {
|
|
|
3466
3865
|
});
|
|
3467
3866
|
}
|
|
3468
3867
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ConditionEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3469
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ConditionEditorComponent, isStandalone: true, selector: "fb-condition-editor", inputs: { holder: { classPropertyName: "holder", publicName: "holder", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, allowFormula: { classPropertyName: "allowFormula", publicName: "allowFormula", isSignal: true, isRequired: false, transformFunction: null }, issuePath: { classPropertyName: "issuePath", publicName: "issuePath", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, ngImport: i0, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">{{ title() }}</legend>\r\n\r\n <div class=\"fb-cond__logic\">\r\n <label class=\"fb-field__label\">Come si combinano</label>\r\n <div class=\"fb-cond__modes\" role=\"group\" aria-label=\"Logica delle condizioni\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'and'\"\r\n title=\"Tutte le condizioni devono essere vere\"\r\n (click)=\"setLogicMode('and')\"\r\n >\r\n Tutte (AND)\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'or'\"\r\n title=\"Almeno una condizione deve essere vera\"\r\n (click)=\"setLogicMode('or')\"\r\n >\r\n Almeno una (OR)\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'custom'\"\r\n title=\"Espressione sugli indici delle condizioni, es. 1 AND (2 OR 3)\"\r\n (click)=\"setLogicMode('custom')\"\r\n >\r\n Espressione\r\n </button>\r\n @if (allowFormula()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'formula'\"\r\n title=\"L\u2019esito lo determina una formula: le condizioni vengono ignorate\"\r\n (click)=\"setLogicMode('formula')\"\r\n >\r\n Formula\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (logicMode() === 'custom') {\r\n <div class=\"fb-field\">\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [class.fb-input--invalid]=\"!!customLogicError()\"\r\n [value]=\"customLogic()\"\r\n placeholder=\"1 AND (2 OR 3)\"\r\n aria-label=\"Espressione sugli indici delle condizioni\"\r\n (input)=\"setCustomLogic($any($event.target).value)\"\r\n />\r\n @if (customLogicError()) {\r\n <p class=\"fb-field__error\">{{ customLogicError() }}</p>\r\n } @else {\r\n <p class=\"fb-field__hint\">\r\n Gli indici sono 1-based e si riferiscono all\u2019ordine sotto. Cancellare una condizione riscrive\r\n l\u2019espressione automaticamente.\r\n </p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (logicMode() === 'formula') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Formula</label>\r\n <textarea\r\n class=\"fb-textarea fb-input--mono\"\r\n [value]=\"holder().formula || ''\"\r\n placeholder=\"AND(Esito = 'KO', Importo > 1000)\"\r\n (input)=\"setFormula($any($event.target).value)\"\r\n ></textarea>\r\n <p class=\"fb-field__hint\">\r\n Con la modalita\u2019 Formula le condizioni sotto vengono ignorate dal motore.\r\n </p>\r\n </div>\r\n }\r\n\r\n @if (conditionsIgnored() && conditions().length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Ci sono {{ conditions().length }} condizioni ma la logica e\u2019 \u00ABFormula\u00BB: il motore le ignora.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (condition of conditions(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <!-- L'indice e' 1-based perche' e' quello che l'espressione referenzia. -->\r\n <span class=\"fb-list__index\" [title]=\"'Indice ' + ($index + 1) + ' nell\u2019espressione'\">\r\n {{ $index + 1 }}\r\n </span>\r\n @if (isPlaceholderOperator(condition)) {\r\n <span class=\"fb-cond__placeholder\" title=\"A runtime vale sempre falso: e\u2019 un segnaposto\">\r\n incompleta\r\n </span>\r\n }\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta su\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveCondition($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta giu\u2019\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveCondition($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi la condizione\"\r\n (click)=\"removeCondition($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">\r\n {{ appliesToElements(condition) ? 'Elemento' : 'Risorsa' }}\r\n </label>\r\n <fb-reference-picker\r\n [value]=\"condition.leftValueReference\"\r\n [elementsOnly]=\"appliesToElements(condition)\"\r\n [placeholder]=\"appliesToElements(condition) ? 'Scegli un elemento del flow' : 'Scegli una risorsa'\"\r\n (valueChange)=\"setLeft($index, $event)\"\r\n />\r\n @if (appliesToElements(condition)) {\r\n <p class=\"fb-field__hint\">\r\n Questo operatore si applica a un elemento del flow, non a una risorsa.\r\n </p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Operatore</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"condition.operator || ''\"\r\n (change)=\"setOperator($index, $any($event.target).value)\"\r\n >\r\n @for (operator of operators(); track operator.value) {\r\n <option [value]=\"operator.value\">{{ operator.label }}</option>\r\n }\r\n </select>\r\n @if (operatorDescription(condition.operator)) {\r\n <p class=\"fb-field__hint\">{{ operatorDescription(condition.operator) }}</p>\r\n }\r\n </div>\r\n\r\n @if (isUnary(condition)) {\r\n <!--\r\n Trappola numero uno: per gli operatori unari `rightValue` non e' il termine di\r\n confronto ma l'esito atteso. Qui non c'e' un campo \"valore da confrontare\":\r\n c'e' un selettore che dice quale delle due cose si sta chiedendo.\r\n -->\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Esito atteso</label>\r\n <div class=\"fb-cond__unary\" role=\"group\" aria-label=\"Esito atteso\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"unaryExpectation(condition)\"\r\n (click)=\"setUnaryExpectation($index, true)\"\r\n >\r\n {{ operatorLabel(condition.operator) }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"!unaryExpectation(condition)\"\r\n (click)=\"setUnaryExpectation($index, false)\"\r\n >\r\n NON {{ operatorLabel(condition.operator) }}\r\n </button>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Questa condizione e\u2019 vera quando: <strong>{{ unarySummary(condition) }}</strong>.\r\n </p>\r\n </div>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Confronta con</label>\r\n <fb-value-editor\r\n [value]=\"condition.rightValue\"\r\n label=\"Valore di confronto\"\r\n (valueChange)=\"setRightValue($index, $event)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessuna condizione.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addCondition()\">Aggiungi condizione</button>\r\n</fieldset>\r\n", styles: [":host{display:block}.fb-cond__logic{margin-bottom:8px}.fb-cond__modes,.fb-cond__unary{display:flex;flex-wrap:wrap;gap:3px;margin-top:3px}.fb-cond__mode{padding:3px 8px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:12px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}.fb-cond__mode:hover{background:var(--fb-surface-alt, #f8f9fb)}.fb-cond__mode--active{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent);color:var(--fb-accent, #2f6feb);font-weight:600}.fb-cond__placeholder{padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--fb-warning, #b7791f) 14%,transparent);font-size:10px;font-weight:600;color:var(--fb-warning, #b7791f)}\n"], dependencies: [{ kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "allowStageTargets", "elementsOnly"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3868
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ConditionEditorComponent, isStandalone: true, selector: "fb-condition-editor", inputs: { holder: { classPropertyName: "holder", publicName: "holder", isSignal: true, isRequired: true, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, allowFormula: { classPropertyName: "allowFormula", publicName: "allowFormula", isSignal: true, isRequired: false, transformFunction: null }, allowLogic: { classPropertyName: "allowLogic", publicName: "allowLogic", isSignal: true, isRequired: false, transformFunction: null }, issuePath: { classPropertyName: "issuePath", publicName: "issuePath", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, ngImport: i0, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">{{ title() }}</legend>\r\n\r\n @if (allowLogic()) {\r\n <div class=\"fb-cond__logic\">\r\n <label class=\"fb-field__label\">Come si combinano</label>\r\n <div class=\"fb-cond__modes\" role=\"group\" aria-label=\"Logica delle condizioni\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'and'\"\r\n title=\"Tutte le condizioni devono essere vere\"\r\n (click)=\"setLogicMode('and')\"\r\n >\r\n Tutte (AND)\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'or'\"\r\n title=\"Almeno una condizione deve essere vera\"\r\n (click)=\"setLogicMode('or')\"\r\n >\r\n Almeno una (OR)\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'custom'\"\r\n title=\"Espressione sugli indici delle condizioni, es. 1 AND (2 OR 3)\"\r\n (click)=\"setLogicMode('custom')\"\r\n >\r\n Espressione\r\n </button>\r\n @if (allowFormula()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'formula'\"\r\n title=\"L\u2019esito lo determina una formula: le condizioni vengono ignorate\"\r\n (click)=\"setLogicMode('formula')\"\r\n >\r\n Formula\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <p class=\"fb-field__hint\">\r\n Devono essere vere <strong>tutte</strong>: qui il modello non prevede una logica separata.\r\n </p>\r\n }\r\n\r\n @if (logicMode() === 'custom') {\r\n <div class=\"fb-field\">\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [class.fb-input--invalid]=\"!!customLogicError()\"\r\n [value]=\"customLogic()\"\r\n placeholder=\"1 AND (2 OR 3)\"\r\n aria-label=\"Espressione sugli indici delle condizioni\"\r\n (input)=\"setCustomLogic($any($event.target).value)\"\r\n />\r\n @if (customLogicError()) {\r\n <p class=\"fb-field__error\">{{ customLogicError() }}</p>\r\n } @else {\r\n <p class=\"fb-field__hint\">\r\n Gli indici sono 1-based e si riferiscono all\u2019ordine sotto. Cancellare una condizione riscrive\r\n l\u2019espressione automaticamente.\r\n </p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (logicMode() === 'formula') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Formula</label>\r\n <textarea\r\n class=\"fb-textarea fb-input--mono\"\r\n [value]=\"holder().formula || ''\"\r\n placeholder=\"AND(Esito = 'KO', Importo > 1000)\"\r\n (input)=\"setFormula($any($event.target).value)\"\r\n ></textarea>\r\n <p class=\"fb-field__hint\">\r\n Con la modalita\u2019 Formula le condizioni sotto vengono ignorate dal motore.\r\n </p>\r\n </div>\r\n }\r\n\r\n @if (conditionsIgnored() && conditions().length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Ci sono {{ conditions().length }} condizioni ma la logica e\u2019 \u00ABFormula\u00BB: il motore le ignora.\r\n </p>\r\n }\r\n\r\n @if (incompleteCount()) {\r\n <!-- `None` blocca l'attivazione: la bozza si salva, la versione attiva no (\u00A713.14). -->\r\n <p class=\"fb-callout fb-callout--error\">\r\n {{ incompleteCount() === 1 ? 'Una condizione e\u2019' : incompleteCount() + ' condizioni sono' }} da\r\n completare: la bozza si salva, l\u2019attivazione no (CONDITION_INCOMPLETE).\r\n </p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (condition of conditions(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <!-- L'indice e' 1-based perche' e' quello che l'espressione referenzia. -->\r\n <span class=\"fb-list__index\" [title]=\"'Indice ' + ($index + 1) + ' nell\u2019espressione'\">\r\n {{ $index + 1 }}\r\n </span>\r\n @if (isPlaceholderOperator(condition)) {\r\n <span\r\n class=\"fb-cond__placeholder\"\r\n title=\"A runtime vale sempre falso, e l\u2019attivazione la rifiuta: va completata\"\r\n >\r\n da completare\r\n </span>\r\n }\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta su\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveCondition($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta giu\u2019\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveCondition($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi la condizione\"\r\n (click)=\"removeCondition($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">\r\n {{ appliesToElements(condition) ? 'Elemento' : 'Risorsa' }}\r\n </label>\r\n <fb-reference-picker\r\n [value]=\"condition.leftValueReference\"\r\n [elementsOnly]=\"appliesToElements(condition)\"\r\n [placeholder]=\"appliesToElements(condition) ? 'Scegli un elemento del flow' : 'Scegli una risorsa'\"\r\n (valueChange)=\"setLeft($index, $event)\"\r\n />\r\n @if (appliesToElements(condition)) {\r\n <p class=\"fb-field__hint\">\r\n Questo operatore si applica a un elemento del flow, non a una risorsa.\r\n </p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Operatore</label>\r\n <select\r\n class=\"fb-select\"\r\n [class.fb-input--invalid]=\"isPlaceholderOperator(condition)\"\r\n [fbValue]=\"condition.operator || ''\"\r\n (change)=\"setOperator($index, $any($event.target).value)\"\r\n >\r\n <!-- Filtrati per il tipo del lato sinistro: `appliesTo` del dizionario (\u00A74.3). -->\r\n @for (operator of operatorsFor(condition); track operator.value) {\r\n <option [value]=\"operator.value\">{{ operator.label }}</option>\r\n }\r\n </select>\r\n @if (isPlaceholderOperator(condition)) {\r\n <p class=\"fb-field__error\">\r\n Segnaposto: a runtime vale sempre falso e l\u2019attivazione lo rifiuta\r\n (CONDITION_INCOMPLETE). Scegli un operatore.\r\n </p>\r\n } @else if (operatorDescription(condition.operator)) {\r\n <p class=\"fb-field__hint\">{{ operatorDescription(condition.operator) }}</p>\r\n }\r\n </div>\r\n\r\n @if (isUnary(condition)) {\r\n <!--\r\n Trappola numero uno: per gli operatori unari `rightValue` non e' il termine di\r\n confronto ma l'esito atteso. Qui non c'e' un campo \"valore da confrontare\":\r\n c'e' un selettore che dice quale delle due cose si sta chiedendo.\r\n -->\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Esito atteso</label>\r\n <div class=\"fb-cond__unary\" role=\"group\" aria-label=\"Esito atteso\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"unaryExpectation(condition)\"\r\n (click)=\"setUnaryExpectation($index, true)\"\r\n >\r\n {{ operatorLabel(condition.operator) }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"!unaryExpectation(condition)\"\r\n (click)=\"setUnaryExpectation($index, false)\"\r\n >\r\n NON {{ operatorLabel(condition.operator) }}\r\n </button>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Questa condizione e\u2019 vera quando: <strong>{{ unarySummary(condition) }}</strong>.\r\n </p>\r\n </div>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Confronta con</label>\r\n <!--\r\n Il tipo del lato sinistro guida il secondo operando: il letterale finisce nel\r\n campo giusto e le risorse proposte sono quelle compatibili. Testo con numero e'\r\n CONDITION_TYPE_MISMATCH e blocca l'attivazione (\u00A74.3).\r\n -->\r\n <fb-value-editor\r\n [value]=\"condition.rightValue\"\r\n label=\"Valore di confronto\"\r\n [dataType]=\"leftDataType(condition)\"\r\n (valueChange)=\"setRightValue($index, $event)\"\r\n />\r\n @if (hasTypeMismatch(condition)) {\r\n <p class=\"fb-field__error\">{{ typeMismatchMessage(condition) }}</p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessuna condizione.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addCondition()\">Aggiungi condizione</button>\r\n</fieldset>\r\n", styles: [":host{display:block}.fb-cond__logic{margin-bottom:8px}.fb-cond__modes,.fb-cond__unary{display:flex;flex-wrap:wrap;gap:3px;margin-top:3px}.fb-cond__mode{padding:3px 8px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:12px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}.fb-cond__mode:hover{background:var(--fb-surface-alt, #f8f9fb)}.fb-cond__mode--active{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent);color:var(--fb-accent, #2f6feb);font-weight:600}.fb-cond__placeholder{padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--fb-warning, #b7791f) 14%,transparent);font-size:10px;font-weight:600;color:var(--fb-warning, #b7791f)}\n"], dependencies: [{ kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3470
3869
|
}
|
|
3471
3870
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ConditionEditorComponent, decorators: [{
|
|
3472
3871
|
type: Component,
|
|
3473
|
-
args: [{ selector: 'fb-condition-editor', standalone: true, imports: [ReferencePickerComponent, ValueEditorComponent, SelectValueDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">{{ title() }}</legend>\r\n\r\n <div class=\"fb-cond__logic\">\r\n <label class=\"fb-field__label\">Come si combinano</label>\r\n <div class=\"fb-cond__modes\" role=\"group\" aria-label=\"Logica delle condizioni\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'and'\"\r\n title=\"Tutte le condizioni devono essere vere\"\r\n (click)=\"setLogicMode('and')\"\r\n >\r\n Tutte (AND)\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'or'\"\r\n title=\"Almeno una condizione deve essere vera\"\r\n (click)=\"setLogicMode('or')\"\r\n >\r\n Almeno una (OR)\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'custom'\"\r\n title=\"Espressione sugli indici delle condizioni, es. 1 AND (2 OR 3)\"\r\n (click)=\"setLogicMode('custom')\"\r\n >\r\n Espressione\r\n </button>\r\n @if (allowFormula()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'formula'\"\r\n title=\"L\u2019esito lo determina una formula: le condizioni vengono ignorate\"\r\n (click)=\"setLogicMode('formula')\"\r\n >\r\n Formula\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (logicMode() === 'custom') {\r\n <div class=\"fb-field\">\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [class.fb-input--invalid]=\"!!customLogicError()\"\r\n [value]=\"customLogic()\"\r\n placeholder=\"1 AND (2 OR 3)\"\r\n aria-label=\"Espressione sugli indici delle condizioni\"\r\n (input)=\"setCustomLogic($any($event.target).value)\"\r\n />\r\n @if (customLogicError()) {\r\n <p class=\"fb-field__error\">{{ customLogicError() }}</p>\r\n } @else {\r\n <p class=\"fb-field__hint\">\r\n Gli indici sono 1-based e si riferiscono all\u2019ordine sotto. Cancellare una condizione riscrive\r\n l\u2019espressione automaticamente.\r\n </p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (logicMode() === 'formula') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Formula</label>\r\n <textarea\r\n class=\"fb-textarea fb-input--mono\"\r\n [value]=\"holder().formula || ''\"\r\n placeholder=\"AND(Esito = 'KO', Importo > 1000)\"\r\n (input)=\"setFormula($any($event.target).value)\"\r\n ></textarea>\r\n <p class=\"fb-field__hint\">\r\n Con la modalita\u2019 Formula le condizioni sotto vengono ignorate dal motore.\r\n </p>\r\n </div>\r\n }\r\n\r\n @if (conditionsIgnored() && conditions().length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Ci sono {{ conditions().length }} condizioni ma la logica e\u2019 \u00ABFormula\u00BB: il motore le ignora.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (condition of conditions(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <!-- L'indice e' 1-based perche' e' quello che l'espressione referenzia. -->\r\n <span class=\"fb-list__index\" [title]=\"'Indice ' + ($index + 1) + ' nell\u2019espressione'\">\r\n {{ $index + 1 }}\r\n </span>\r\n @if (isPlaceholderOperator(condition)) {\r\n <span class=\"fb-cond__placeholder\" title=\"A runtime vale sempre falso: e\u2019 un segnaposto\">\r\n incompleta\r\n </span>\r\n }\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta su\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveCondition($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta giu\u2019\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveCondition($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi la condizione\"\r\n (click)=\"removeCondition($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">\r\n {{ appliesToElements(condition) ? 'Elemento' : 'Risorsa' }}\r\n </label>\r\n <fb-reference-picker\r\n [value]=\"condition.leftValueReference\"\r\n [elementsOnly]=\"appliesToElements(condition)\"\r\n [placeholder]=\"appliesToElements(condition) ? 'Scegli un elemento del flow' : 'Scegli una risorsa'\"\r\n (valueChange)=\"setLeft($index, $event)\"\r\n />\r\n @if (appliesToElements(condition)) {\r\n <p class=\"fb-field__hint\">\r\n Questo operatore si applica a un elemento del flow, non a una risorsa.\r\n </p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Operatore</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"condition.operator || ''\"\r\n (change)=\"setOperator($index, $any($event.target).value)\"\r\n >\r\n @for (operator of operators(); track operator.value) {\r\n <option [value]=\"operator.value\">{{ operator.label }}</option>\r\n }\r\n </select>\r\n @if (operatorDescription(condition.operator)) {\r\n <p class=\"fb-field__hint\">{{ operatorDescription(condition.operator) }}</p>\r\n }\r\n </div>\r\n\r\n @if (isUnary(condition)) {\r\n <!--\r\n Trappola numero uno: per gli operatori unari `rightValue` non e' il termine di\r\n confronto ma l'esito atteso. Qui non c'e' un campo \"valore da confrontare\":\r\n c'e' un selettore che dice quale delle due cose si sta chiedendo.\r\n -->\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Esito atteso</label>\r\n <div class=\"fb-cond__unary\" role=\"group\" aria-label=\"Esito atteso\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"unaryExpectation(condition)\"\r\n (click)=\"setUnaryExpectation($index, true)\"\r\n >\r\n {{ operatorLabel(condition.operator) }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"!unaryExpectation(condition)\"\r\n (click)=\"setUnaryExpectation($index, false)\"\r\n >\r\n NON {{ operatorLabel(condition.operator) }}\r\n </button>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Questa condizione e\u2019 vera quando: <strong>{{ unarySummary(condition) }}</strong>.\r\n </p>\r\n </div>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Confronta con</label>\r\n <fb-value-editor\r\n [value]=\"condition.rightValue\"\r\n label=\"Valore di confronto\"\r\n (valueChange)=\"setRightValue($index, $event)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessuna condizione.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addCondition()\">Aggiungi condizione</button>\r\n</fieldset>\r\n", styles: [":host{display:block}.fb-cond__logic{margin-bottom:8px}.fb-cond__modes,.fb-cond__unary{display:flex;flex-wrap:wrap;gap:3px;margin-top:3px}.fb-cond__mode{padding:3px 8px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:12px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}.fb-cond__mode:hover{background:var(--fb-surface-alt, #f8f9fb)}.fb-cond__mode--active{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent);color:var(--fb-accent, #2f6feb);font-weight:600}.fb-cond__placeholder{padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--fb-warning, #b7791f) 14%,transparent);font-size:10px;font-weight:600;color:var(--fb-warning, #b7791f)}\n"] }]
|
|
3474
|
-
}], propDecorators: { holder: [{ type: i0.Input, args: [{ isSignal: true, alias: "holder", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], allowFormula: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowFormula", required: false }] }], issuePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "issuePath", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
|
|
3872
|
+
args: [{ selector: 'fb-condition-editor', standalone: true, imports: [ReferencePickerComponent, ValueEditorComponent, SelectValueDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">{{ title() }}</legend>\r\n\r\n @if (allowLogic()) {\r\n <div class=\"fb-cond__logic\">\r\n <label class=\"fb-field__label\">Come si combinano</label>\r\n <div class=\"fb-cond__modes\" role=\"group\" aria-label=\"Logica delle condizioni\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'and'\"\r\n title=\"Tutte le condizioni devono essere vere\"\r\n (click)=\"setLogicMode('and')\"\r\n >\r\n Tutte (AND)\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'or'\"\r\n title=\"Almeno una condizione deve essere vera\"\r\n (click)=\"setLogicMode('or')\"\r\n >\r\n Almeno una (OR)\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'custom'\"\r\n title=\"Espressione sugli indici delle condizioni, es. 1 AND (2 OR 3)\"\r\n (click)=\"setLogicMode('custom')\"\r\n >\r\n Espressione\r\n </button>\r\n @if (allowFormula()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"logicMode() === 'formula'\"\r\n title=\"L\u2019esito lo determina una formula: le condizioni vengono ignorate\"\r\n (click)=\"setLogicMode('formula')\"\r\n >\r\n Formula\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <p class=\"fb-field__hint\">\r\n Devono essere vere <strong>tutte</strong>: qui il modello non prevede una logica separata.\r\n </p>\r\n }\r\n\r\n @if (logicMode() === 'custom') {\r\n <div class=\"fb-field\">\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [class.fb-input--invalid]=\"!!customLogicError()\"\r\n [value]=\"customLogic()\"\r\n placeholder=\"1 AND (2 OR 3)\"\r\n aria-label=\"Espressione sugli indici delle condizioni\"\r\n (input)=\"setCustomLogic($any($event.target).value)\"\r\n />\r\n @if (customLogicError()) {\r\n <p class=\"fb-field__error\">{{ customLogicError() }}</p>\r\n } @else {\r\n <p class=\"fb-field__hint\">\r\n Gli indici sono 1-based e si riferiscono all\u2019ordine sotto. Cancellare una condizione riscrive\r\n l\u2019espressione automaticamente.\r\n </p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (logicMode() === 'formula') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Formula</label>\r\n <textarea\r\n class=\"fb-textarea fb-input--mono\"\r\n [value]=\"holder().formula || ''\"\r\n placeholder=\"AND(Esito = 'KO', Importo > 1000)\"\r\n (input)=\"setFormula($any($event.target).value)\"\r\n ></textarea>\r\n <p class=\"fb-field__hint\">\r\n Con la modalita\u2019 Formula le condizioni sotto vengono ignorate dal motore.\r\n </p>\r\n </div>\r\n }\r\n\r\n @if (conditionsIgnored() && conditions().length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Ci sono {{ conditions().length }} condizioni ma la logica e\u2019 \u00ABFormula\u00BB: il motore le ignora.\r\n </p>\r\n }\r\n\r\n @if (incompleteCount()) {\r\n <!-- `None` blocca l'attivazione: la bozza si salva, la versione attiva no (\u00A713.14). -->\r\n <p class=\"fb-callout fb-callout--error\">\r\n {{ incompleteCount() === 1 ? 'Una condizione e\u2019' : incompleteCount() + ' condizioni sono' }} da\r\n completare: la bozza si salva, l\u2019attivazione no (CONDITION_INCOMPLETE).\r\n </p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (condition of conditions(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <!-- L'indice e' 1-based perche' e' quello che l'espressione referenzia. -->\r\n <span class=\"fb-list__index\" [title]=\"'Indice ' + ($index + 1) + ' nell\u2019espressione'\">\r\n {{ $index + 1 }}\r\n </span>\r\n @if (isPlaceholderOperator(condition)) {\r\n <span\r\n class=\"fb-cond__placeholder\"\r\n title=\"A runtime vale sempre falso, e l\u2019attivazione la rifiuta: va completata\"\r\n >\r\n da completare\r\n </span>\r\n }\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta su\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveCondition($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta giu\u2019\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveCondition($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi la condizione\"\r\n (click)=\"removeCondition($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">\r\n {{ appliesToElements(condition) ? 'Elemento' : 'Risorsa' }}\r\n </label>\r\n <fb-reference-picker\r\n [value]=\"condition.leftValueReference\"\r\n [elementsOnly]=\"appliesToElements(condition)\"\r\n [placeholder]=\"appliesToElements(condition) ? 'Scegli un elemento del flow' : 'Scegli una risorsa'\"\r\n (valueChange)=\"setLeft($index, $event)\"\r\n />\r\n @if (appliesToElements(condition)) {\r\n <p class=\"fb-field__hint\">\r\n Questo operatore si applica a un elemento del flow, non a una risorsa.\r\n </p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Operatore</label>\r\n <select\r\n class=\"fb-select\"\r\n [class.fb-input--invalid]=\"isPlaceholderOperator(condition)\"\r\n [fbValue]=\"condition.operator || ''\"\r\n (change)=\"setOperator($index, $any($event.target).value)\"\r\n >\r\n <!-- Filtrati per il tipo del lato sinistro: `appliesTo` del dizionario (\u00A74.3). -->\r\n @for (operator of operatorsFor(condition); track operator.value) {\r\n <option [value]=\"operator.value\">{{ operator.label }}</option>\r\n }\r\n </select>\r\n @if (isPlaceholderOperator(condition)) {\r\n <p class=\"fb-field__error\">\r\n Segnaposto: a runtime vale sempre falso e l\u2019attivazione lo rifiuta\r\n (CONDITION_INCOMPLETE). Scegli un operatore.\r\n </p>\r\n } @else if (operatorDescription(condition.operator)) {\r\n <p class=\"fb-field__hint\">{{ operatorDescription(condition.operator) }}</p>\r\n }\r\n </div>\r\n\r\n @if (isUnary(condition)) {\r\n <!--\r\n Trappola numero uno: per gli operatori unari `rightValue` non e' il termine di\r\n confronto ma l'esito atteso. Qui non c'e' un campo \"valore da confrontare\":\r\n c'e' un selettore che dice quale delle due cose si sta chiedendo.\r\n -->\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Esito atteso</label>\r\n <div class=\"fb-cond__unary\" role=\"group\" aria-label=\"Esito atteso\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"unaryExpectation(condition)\"\r\n (click)=\"setUnaryExpectation($index, true)\"\r\n >\r\n {{ operatorLabel(condition.operator) }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-cond__mode\"\r\n [class.fb-cond__mode--active]=\"!unaryExpectation(condition)\"\r\n (click)=\"setUnaryExpectation($index, false)\"\r\n >\r\n NON {{ operatorLabel(condition.operator) }}\r\n </button>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Questa condizione e\u2019 vera quando: <strong>{{ unarySummary(condition) }}</strong>.\r\n </p>\r\n </div>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Confronta con</label>\r\n <!--\r\n Il tipo del lato sinistro guida il secondo operando: il letterale finisce nel\r\n campo giusto e le risorse proposte sono quelle compatibili. Testo con numero e'\r\n CONDITION_TYPE_MISMATCH e blocca l'attivazione (\u00A74.3).\r\n -->\r\n <fb-value-editor\r\n [value]=\"condition.rightValue\"\r\n label=\"Valore di confronto\"\r\n [dataType]=\"leftDataType(condition)\"\r\n (valueChange)=\"setRightValue($index, $event)\"\r\n />\r\n @if (hasTypeMismatch(condition)) {\r\n <p class=\"fb-field__error\">{{ typeMismatchMessage(condition) }}</p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessuna condizione.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addCondition()\">Aggiungi condizione</button>\r\n</fieldset>\r\n", styles: [":host{display:block}.fb-cond__logic{margin-bottom:8px}.fb-cond__modes,.fb-cond__unary{display:flex;flex-wrap:wrap;gap:3px;margin-top:3px}.fb-cond__mode{padding:3px 8px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:12px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}.fb-cond__mode:hover{background:var(--fb-surface-alt, #f8f9fb)}.fb-cond__mode--active{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent);color:var(--fb-accent, #2f6feb);font-weight:600}.fb-cond__placeholder{padding:1px 6px;border-radius:8px;background:color-mix(in srgb,var(--fb-warning, #b7791f) 14%,transparent);font-size:10px;font-weight:600;color:var(--fb-warning, #b7791f)}\n"] }]
|
|
3873
|
+
}], ctorParameters: () => [], propDecorators: { holder: [{ type: i0.Input, args: [{ isSignal: true, alias: "holder", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], allowFormula: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowFormula", required: false }] }], allowLogic: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowLogic", required: false }] }], issuePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "issuePath", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
|
|
3475
3874
|
|
|
3476
3875
|
/**
|
|
3477
3876
|
* Editor dei filtri sui record — FRONTEND.md §4.4.
|
|
@@ -3776,7 +4175,7 @@ class ParameterEditorComponent {
|
|
|
3776
4175
|
});
|
|
3777
4176
|
}
|
|
3778
4177
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ParameterEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3779
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ParameterEditorComponent, isStandalone: true, selector: "fb-parameter-editor", inputs: { holder: { classPropertyName: "holder", publicName: "holder", isSignal: true, isRequired: true, transformFunction: null }, catalogParameters: { classPropertyName: "catalogParameters", publicName: "catalogParameters", isSignal: true, isRequired: false, transformFunction: null }, inputTitle: { classPropertyName: "inputTitle", publicName: "inputTitle", isSignal: true, isRequired: false, transformFunction: null }, outputTitle: { classPropertyName: "outputTitle", publicName: "outputTitle", isSignal: true, isRequired: false, transformFunction: null }, showInputs: { classPropertyName: "showInputs", publicName: "showInputs", isSignal: true, isRequired: false, transformFunction: null }, showOutputs: { classPropertyName: "showOutputs", publicName: "showOutputs", isSignal: true, isRequired: false, transformFunction: null }, outputsDisabledReason: { classPropertyName: "outputsDisabledReason", publicName: "outputsDisabledReason", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, ngImport: i0, template: "@if (showInputs()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">{{ inputTitle() }}</legend>\r\n\r\n @if (missingRequired().length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Parametri obbligatori non ancora impostati:\r\n @for (parameter of missingRequired(); track parameter.name) {\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"addInput(parameter.name)\">\r\n + {{ parameter.name }}\r\n </button>\r\n }\r\n </p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (parameter of inputs(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n @if (hasCatalog()) {\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"parameter.name || ''\"\r\n aria-label=\"Nome del parametro\"\r\n (change)=\"setInputName($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (candidate of inputCatalog(); track candidate.name) {\r\n <option [value]=\"candidate.name\">\r\n {{ candidate.label || candidate.name }}{{ candidate.isRequired ? ' *' : '' }}\r\n </option>\r\n }\r\n @if (unknownInput(parameter)) {\r\n <option [value]=\"parameter.name\">{{ parameter.name }} (non nel catalogo)</option>\r\n }\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"parameter.name || ''\"\r\n placeholder=\"Nome del parametro\"\r\n aria-label=\"Nome del parametro\"\r\n (input)=\"setInputName($index, $any($event.target).value)\"\r\n />\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi il parametro\"\r\n (click)=\"removeInput($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n @if (unknownInput(parameter)) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Il catalogo non dichiara questo parametro: la validazione lo segnalerebbe come errore.\r\n </p>\r\n }\r\n @if (describe(parameter.name)?.description) {\r\n <p class=\"fb-field__hint\">{{ describe(parameter.name)?.description }}</p>\r\n }\r\n\r\n <fb-value-editor\r\n [value]=\"parameter.value\"\r\n [dataType]=\"describe(parameter.name)?.dataType\"\r\n [objectType]=\"describe(parameter.name)?.objectType || undefined\"\r\n [isCollection]=\"describe(parameter.name)?.isCollection\"\r\n label=\"Valore del parametro\"\r\n (valueChange)=\"setInputValue($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun parametro di ingresso.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addInput()\">Aggiungi parametro</button>\r\n </fieldset>\r\n}\r\n\r\n@if (showOutputs()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">{{ outputTitle() }}</legend>\r\n\r\n @if (outputsDisabledReason()) {\r\n <p class=\"fb-callout\">{{ outputsDisabledReason() }}</p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (parameter of outputs(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n @if (hasCatalog()) {\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"parameter.name || ''\"\r\n aria-label=\"Nome del parametro di uscita\"\r\n (change)=\"setOutputName($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (candidate of outputCatalog(); track candidate.name) {\r\n <option [value]=\"candidate.name\">{{ candidate.label || candidate.name }}</option>\r\n }\r\n @if (unknownOutput(parameter)) {\r\n <option [value]=\"parameter.name\">{{ parameter.name }} (non nel catalogo)</option>\r\n }\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"parameter.name || ''\"\r\n placeholder=\"Nome del parametro\"\r\n aria-label=\"Nome del parametro di uscita\"\r\n (input)=\"setOutputName($index, $any($event.target).value)\"\r\n />\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi il parametro\"\r\n (click)=\"removeOutput($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n @if (unknownOutput(parameter)) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Il catalogo non dichiara questo parametro di uscita.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Assegna a</label>\r\n <!-- Solo variabili: assegnare a una costante o a una formula e' un errore. -->\r\n <fb-reference-picker\r\n [value]=\"parameter.assignToReference\"\r\n [writableOnly]=\"true\"\r\n [dataType]=\"describe(parameter.name)?.dataType\"\r\n [isCollection]=\"describe(parameter.name)?.isCollection\"\r\n placeholder=\"Scegli una variabile\"\r\n (valueChange)=\"setOutputTarget($index, $event)\"\r\n />\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun parametro di uscita.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addOutput()\">Aggiungi parametro</button>\r\n </fieldset>\r\n}\r\n", styles: [":host{display:block}.fb-list__header .fb-select,.fb-list__header .fb-input{flex:1;min-width:0}\n"], dependencies: [{ kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "
|
|
4178
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ParameterEditorComponent, isStandalone: true, selector: "fb-parameter-editor", inputs: { holder: { classPropertyName: "holder", publicName: "holder", isSignal: true, isRequired: true, transformFunction: null }, catalogParameters: { classPropertyName: "catalogParameters", publicName: "catalogParameters", isSignal: true, isRequired: false, transformFunction: null }, inputTitle: { classPropertyName: "inputTitle", publicName: "inputTitle", isSignal: true, isRequired: false, transformFunction: null }, outputTitle: { classPropertyName: "outputTitle", publicName: "outputTitle", isSignal: true, isRequired: false, transformFunction: null }, showInputs: { classPropertyName: "showInputs", publicName: "showInputs", isSignal: true, isRequired: false, transformFunction: null }, showOutputs: { classPropertyName: "showOutputs", publicName: "showOutputs", isSignal: true, isRequired: false, transformFunction: null }, outputsDisabledReason: { classPropertyName: "outputsDisabledReason", publicName: "outputsDisabledReason", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, ngImport: i0, template: "@if (showInputs()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">{{ inputTitle() }}</legend>\r\n\r\n @if (missingRequired().length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Parametri obbligatori non ancora impostati:\r\n @for (parameter of missingRequired(); track parameter.name) {\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"addInput(parameter.name)\">\r\n + {{ parameter.name }}\r\n </button>\r\n }\r\n </p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (parameter of inputs(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n @if (hasCatalog()) {\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"parameter.name || ''\"\r\n aria-label=\"Nome del parametro\"\r\n (change)=\"setInputName($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (candidate of inputCatalog(); track candidate.name) {\r\n <option [value]=\"candidate.name\">\r\n {{ candidate.label || candidate.name }}{{ candidate.isRequired ? ' *' : '' }}\r\n </option>\r\n }\r\n @if (unknownInput(parameter)) {\r\n <option [value]=\"parameter.name\">{{ parameter.name }} (non nel catalogo)</option>\r\n }\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"parameter.name || ''\"\r\n placeholder=\"Nome del parametro\"\r\n aria-label=\"Nome del parametro\"\r\n (input)=\"setInputName($index, $any($event.target).value)\"\r\n />\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi il parametro\"\r\n (click)=\"removeInput($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n @if (unknownInput(parameter)) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Il catalogo non dichiara questo parametro: la validazione lo segnalerebbe come errore.\r\n </p>\r\n }\r\n @if (describe(parameter.name)?.description) {\r\n <p class=\"fb-field__hint\">{{ describe(parameter.name)?.description }}</p>\r\n }\r\n\r\n <fb-value-editor\r\n [value]=\"parameter.value\"\r\n [dataType]=\"describe(parameter.name)?.dataType\"\r\n [objectType]=\"describe(parameter.name)?.objectType || undefined\"\r\n [isCollection]=\"describe(parameter.name)?.isCollection\"\r\n label=\"Valore del parametro\"\r\n (valueChange)=\"setInputValue($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun parametro di ingresso.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addInput()\">Aggiungi parametro</button>\r\n </fieldset>\r\n}\r\n\r\n@if (showOutputs()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">{{ outputTitle() }}</legend>\r\n\r\n @if (outputsDisabledReason()) {\r\n <p class=\"fb-callout\">{{ outputsDisabledReason() }}</p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (parameter of outputs(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n @if (hasCatalog()) {\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"parameter.name || ''\"\r\n aria-label=\"Nome del parametro di uscita\"\r\n (change)=\"setOutputName($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (candidate of outputCatalog(); track candidate.name) {\r\n <option [value]=\"candidate.name\">{{ candidate.label || candidate.name }}</option>\r\n }\r\n @if (unknownOutput(parameter)) {\r\n <option [value]=\"parameter.name\">{{ parameter.name }} (non nel catalogo)</option>\r\n }\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"parameter.name || ''\"\r\n placeholder=\"Nome del parametro\"\r\n aria-label=\"Nome del parametro di uscita\"\r\n (input)=\"setOutputName($index, $any($event.target).value)\"\r\n />\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi il parametro\"\r\n (click)=\"removeOutput($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n @if (unknownOutput(parameter)) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Il catalogo non dichiara questo parametro di uscita.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Assegna a</label>\r\n <!-- Solo variabili: assegnare a una costante o a una formula e' un errore. -->\r\n <fb-reference-picker\r\n [value]=\"parameter.assignToReference\"\r\n [writableOnly]=\"true\"\r\n [dataType]=\"describe(parameter.name)?.dataType\"\r\n [isCollection]=\"describe(parameter.name)?.isCollection\"\r\n placeholder=\"Scegli una variabile\"\r\n (valueChange)=\"setOutputTarget($index, $event)\"\r\n />\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun parametro di uscita.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addOutput()\">Aggiungi parametro</button>\r\n </fieldset>\r\n}\r\n", styles: [":host{display:block}.fb-list__header .fb-select,.fb-list__header .fb-input{flex:1;min-width:0}\n"], dependencies: [{ kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3780
4179
|
}
|
|
3781
4180
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ParameterEditorComponent, decorators: [{
|
|
3782
4181
|
type: Component,
|
|
@@ -3863,11 +4262,11 @@ class FieldAssignmentEditorComponent {
|
|
|
3863
4262
|
return !this.fields().some((field) => field.name === assignment.field);
|
|
3864
4263
|
}
|
|
3865
4264
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: FieldAssignmentEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3866
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: FieldAssignmentEditorComponent, isStandalone: true, selector: "fb-field-assignment-editor", inputs: { holder: { classPropertyName: "holder", publicName: "holder", isSignal: true, isRequired: true, transformFunction: null }, object: { classPropertyName: "object", publicName: "object", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, disabledReason: { classPropertyName: "disabledReason", publicName: "disabledReason", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, ngImport: i0, template: "<fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">{{ title() }}</legend>\n\n @if (disabledReason()) {\n <p class=\"fb-callout\">{{ disabledReason() }}</p>\n }\n @if (!object()) {\n <p class=\"fb-field__hint\">Scegli prima un oggetto per poterne valorizzare i campi.</p>\n }\n @if (missingRequired().length) {\n <p class=\"fb-callout fb-callout--warn\">\n Campi obbligatori non valorizzati:\n @for (field of missingRequired(); track field.name) {\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"add(field.name)\">\n + {{ field.label || field.name }}\n </button>\n }\n </p>\n }\n\n <div class=\"fb-list\">\n @for (assignment of assignments(); track $index) {\n <div class=\"fb-list__item\">\n <div class=\"fb-list__header\">\n @if (hasCatalog()) {\n <input\n class=\"fb-input\"\n [attr.list]=\"'fb-updateable-' + object()\"\n [value]=\"assignment.field || ''\"\n placeholder=\"Nome del campo\"\n aria-label=\"Campo\"\n (input)=\"setField($index, $any($event.target).value)\"\n />\n <datalist id=\"fb-updateable-{{ object() }}\">\n @for (field of fieldOptions(); track field.name) {\n <option [value]=\"field.name\">{{ field.label || field.name }}</option>\n }\n </datalist>\n } @else {\n <input\n class=\"fb-input\"\n [value]=\"assignment.field || ''\"\n placeholder=\"Nome del campo\"\n aria-label=\"Campo\"\n (input)=\"setField($index, $any($event.target).value)\"\n />\n }\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\n aria-label=\"Rimuovi\"\n (click)=\"remove($index)\"\n >\n \u00D7\n </button>\n </div>\n\n @if (isUnknown(assignment)) {\n <p class=\"fb-field__hint fb-field__hint--warn\">\n Questo campo non e\u2019 fra quelli aggiornabili dell\u2019oggetto.\n </p>\n }\n\n <fb-value-editor\n [value]=\"assignment.value\"\n [dataType]=\"describe(assignment.field)?.dataType\"\n [objectType]=\"describe(assignment.field)?.objectType || undefined\"\n label=\"Valore del campo\"\n (valueChange)=\"setValue($index, $event)\"\n />\n </div>\n } @empty {\n <p class=\"fb-empty\">Nessun campo valorizzato.</p>\n }\n </div>\n\n <button type=\"button\" class=\"fb-btn\" (click)=\"add()\">Aggiungi campo</button>\n</fieldset>\n", styles: [":host{display:block}.fb-list__header .fb-input{flex:1;min-width:0}\n"], dependencies: [{ kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "disabled", "allowFormula"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4265
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: FieldAssignmentEditorComponent, isStandalone: true, selector: "fb-field-assignment-editor", inputs: { holder: { classPropertyName: "holder", publicName: "holder", isSignal: true, isRequired: true, transformFunction: null }, object: { classPropertyName: "object", publicName: "object", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, disabledReason: { classPropertyName: "disabledReason", publicName: "disabledReason", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, ngImport: i0, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">{{ title() }}</legend>\r\n\r\n @if (disabledReason()) {\r\n <p class=\"fb-callout\">{{ disabledReason() }}</p>\r\n }\r\n @if (!object()) {\r\n <p class=\"fb-field__hint\">Scegli prima un oggetto per poterne valorizzare i campi.</p>\r\n }\r\n @if (missingRequired().length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Campi obbligatori non valorizzati:\r\n @for (field of missingRequired(); track field.name) {\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"add(field.name)\">\r\n + {{ field.label || field.name }}\r\n </button>\r\n }\r\n </p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (assignment of assignments(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n @if (hasCatalog()) {\r\n <input\r\n class=\"fb-input\"\r\n [attr.list]=\"'fb-updateable-' + object()\"\r\n [value]=\"assignment.field || ''\"\r\n placeholder=\"Nome del campo\"\r\n aria-label=\"Campo\"\r\n (input)=\"setField($index, $any($event.target).value)\"\r\n />\r\n <datalist id=\"fb-updateable-{{ object() }}\">\r\n @for (field of fieldOptions(); track field.name) {\r\n <option [value]=\"field.name\">{{ field.label || field.name }}</option>\r\n }\r\n </datalist>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"assignment.field || ''\"\r\n placeholder=\"Nome del campo\"\r\n aria-label=\"Campo\"\r\n (input)=\"setField($index, $any($event.target).value)\"\r\n />\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"remove($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n @if (isUnknown(assignment)) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Questo campo non e\u2019 fra quelli aggiornabili dell\u2019oggetto.\r\n </p>\r\n }\r\n\r\n <fb-value-editor\r\n [value]=\"assignment.value\"\r\n [dataType]=\"describe(assignment.field)?.dataType\"\r\n [objectType]=\"describe(assignment.field)?.objectType || undefined\"\r\n label=\"Valore del campo\"\r\n (valueChange)=\"setValue($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun campo valorizzato.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"add()\">Aggiungi campo</button>\r\n</fieldset>\r\n", styles: [":host{display:block}.fb-list__header .fb-input{flex:1;min-width:0}\n"], dependencies: [{ kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "disabled", "allowFormula"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3867
4266
|
}
|
|
3868
4267
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: FieldAssignmentEditorComponent, decorators: [{
|
|
3869
4268
|
type: Component,
|
|
3870
|
-
args: [{ selector: 'fb-field-assignment-editor', standalone: true, imports: [ValueEditorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">{{ title() }}</legend>\n\n @if (disabledReason()) {\n <p class=\"fb-callout\">{{ disabledReason() }}</p>\n }\n @if (!object()) {\n <p class=\"fb-field__hint\">Scegli prima un oggetto per poterne valorizzare i campi.</p>\n }\n @if (missingRequired().length) {\n <p class=\"fb-callout fb-callout--warn\">\n Campi obbligatori non valorizzati:\n @for (field of missingRequired(); track field.name) {\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"add(field.name)\">\n + {{ field.label || field.name }}\n </button>\n }\n </p>\n }\n\n <div class=\"fb-list\">\n @for (assignment of assignments(); track $index) {\n <div class=\"fb-list__item\">\n <div class=\"fb-list__header\">\n @if (hasCatalog()) {\n <input\n class=\"fb-input\"\n [attr.list]=\"'fb-updateable-' + object()\"\n [value]=\"assignment.field || ''\"\n placeholder=\"Nome del campo\"\n aria-label=\"Campo\"\n (input)=\"setField($index, $any($event.target).value)\"\n />\n <datalist id=\"fb-updateable-{{ object() }}\">\n @for (field of fieldOptions(); track field.name) {\n <option [value]=\"field.name\">{{ field.label || field.name }}</option>\n }\n </datalist>\n } @else {\n <input\n class=\"fb-input\"\n [value]=\"assignment.field || ''\"\n placeholder=\"Nome del campo\"\n aria-label=\"Campo\"\n (input)=\"setField($index, $any($event.target).value)\"\n />\n }\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\n aria-label=\"Rimuovi\"\n (click)=\"remove($index)\"\n >\n \u00D7\n </button>\n </div>\n\n @if (isUnknown(assignment)) {\n <p class=\"fb-field__hint fb-field__hint--warn\">\n Questo campo non e\u2019 fra quelli aggiornabili dell\u2019oggetto.\n </p>\n }\n\n <fb-value-editor\n [value]=\"assignment.value\"\n [dataType]=\"describe(assignment.field)?.dataType\"\n [objectType]=\"describe(assignment.field)?.objectType || undefined\"\n label=\"Valore del campo\"\n (valueChange)=\"setValue($index, $event)\"\n />\n </div>\n } @empty {\n <p class=\"fb-empty\">Nessun campo valorizzato.</p>\n }\n </div>\n\n <button type=\"button\" class=\"fb-btn\" (click)=\"add()\">Aggiungi campo</button>\n</fieldset>\n", styles: [":host{display:block}.fb-list__header .fb-input{flex:1;min-width:0}\n"] }]
|
|
4269
|
+
args: [{ selector: 'fb-field-assignment-editor', standalone: true, imports: [ValueEditorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">{{ title() }}</legend>\r\n\r\n @if (disabledReason()) {\r\n <p class=\"fb-callout\">{{ disabledReason() }}</p>\r\n }\r\n @if (!object()) {\r\n <p class=\"fb-field__hint\">Scegli prima un oggetto per poterne valorizzare i campi.</p>\r\n }\r\n @if (missingRequired().length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Campi obbligatori non valorizzati:\r\n @for (field of missingRequired(); track field.name) {\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"add(field.name)\">\r\n + {{ field.label || field.name }}\r\n </button>\r\n }\r\n </p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (assignment of assignments(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n @if (hasCatalog()) {\r\n <input\r\n class=\"fb-input\"\r\n [attr.list]=\"'fb-updateable-' + object()\"\r\n [value]=\"assignment.field || ''\"\r\n placeholder=\"Nome del campo\"\r\n aria-label=\"Campo\"\r\n (input)=\"setField($index, $any($event.target).value)\"\r\n />\r\n <datalist id=\"fb-updateable-{{ object() }}\">\r\n @for (field of fieldOptions(); track field.name) {\r\n <option [value]=\"field.name\">{{ field.label || field.name }}</option>\r\n }\r\n </datalist>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"assignment.field || ''\"\r\n placeholder=\"Nome del campo\"\r\n aria-label=\"Campo\"\r\n (input)=\"setField($index, $any($event.target).value)\"\r\n />\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"remove($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n @if (isUnknown(assignment)) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Questo campo non e\u2019 fra quelli aggiornabili dell\u2019oggetto.\r\n </p>\r\n }\r\n\r\n <fb-value-editor\r\n [value]=\"assignment.value\"\r\n [dataType]=\"describe(assignment.field)?.dataType\"\r\n [objectType]=\"describe(assignment.field)?.objectType || undefined\"\r\n label=\"Valore del campo\"\r\n (valueChange)=\"setValue($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun campo valorizzato.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"add()\">Aggiungi campo</button>\r\n</fieldset>\r\n", styles: [":host{display:block}.fb-list__header .fb-input{flex:1;min-width:0}\n"] }]
|
|
3871
4270
|
}], ctorParameters: () => [], propDecorators: { holder: [{ type: i0.Input, args: [{ isSignal: true, alias: "holder", required: true }] }], object: [{ type: i0.Input, args: [{ isSignal: true, alias: "object", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], disabledReason: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledReason", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
|
|
3872
4271
|
|
|
3873
4272
|
/**
|
|
@@ -4170,8 +4569,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
|
|
|
4170
4569
|
* 1. **Le operazioni sono eseguite nell'ordine dichiarato**, quindi devono essere
|
|
4171
4570
|
* riordinabili: un'interfaccia che le presenta come un insieme nasconde la semantica.
|
|
4172
4571
|
* 2. **Cosa puo' stare in `assignToReference`**: una variabile, un campo di una variabile
|
|
4173
|
-
* record, un campo di `$Record` e
|
|
4174
|
-
* `$Flow.
|
|
4572
|
+
* record, un campo di `$Record` e, fra le globali, `$Flow.CurrentStage`,
|
|
4573
|
+
* `$Flow.ActiveStages` e quelle che il sistema ospite dichiara scrivibili — le propone
|
|
4574
|
+
* già `POST /flows/references/writable`. Tutto il resto e' di sola lettura.
|
|
4175
4575
|
* 3. Gli operatori marcati `expectsCollection` hanno senso **solo** su destinazioni
|
|
4176
4576
|
* collection: su una variabile singola non falliscono, non fanno nulla.
|
|
4177
4577
|
*/
|
|
@@ -4180,8 +4580,6 @@ class AssignmentInspectorComponent extends NodeInspectorBase {
|
|
|
4180
4580
|
assignment = computed(() => this.node(), ...(ngDevMode ? [{ debugName: "assignment" }] : []));
|
|
4181
4581
|
items = computed(() => this.assignment().assignmentItems ?? [], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
4182
4582
|
operators = computed(() => this.dictionaries.assignmentOperators(), ...(ngDevMode ? [{ debugName: "operators" }] : []));
|
|
4183
|
-
/** Il flow dichiara stage: solo allora le due globali di stage sono proponibili (§5.2). */
|
|
4184
|
-
hasStages = computed(() => (this.store.document().stages?.length ?? 0) > 0, ...(ngDevMode ? [{ debugName: "hasStages" }] : []));
|
|
4185
4583
|
operatorLabel(value) {
|
|
4186
4584
|
if (!value) {
|
|
4187
4585
|
return '';
|
|
@@ -4265,11 +4663,11 @@ class AssignmentInspectorComponent extends NodeInspectorBase {
|
|
|
4265
4663
|
return !operator.startsWith('Remove') || operator === 'RemovePosition' || operator === 'RemoveUncommon';
|
|
4266
4664
|
}
|
|
4267
4665
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: AssignmentInspectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
4268
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: AssignmentInspectorComponent, isStandalone: true, selector: "fb-assignment-inspector", usesInheritance: true, ngImport: i0, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Operazioni</legend>\r\n <p class=\"fb-section__note\">\r\n Le operazioni sono eseguite <strong>nell\u2019ordine in cui compaiono</strong>: spostarne una cambia il\r\n risultato.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (item of items(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta su\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveItem($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta giu\u2019\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveItem($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi l\u2019operazione\"\r\n (click)=\"removeItem($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Destinazione</label>\r\n <!--\r\n Solo destinazioni scrivibili: una costante o una formula produrrebbero\r\n TARGET_NOT_WRITABLE. Le
|
|
4666
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: AssignmentInspectorComponent, isStandalone: true, selector: "fb-assignment-inspector", usesInheritance: true, ngImport: i0, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Operazioni</legend>\r\n <p class=\"fb-section__note\">\r\n Le operazioni sono eseguite <strong>nell\u2019ordine in cui compaiono</strong>: spostarne una cambia il\r\n risultato.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (item of items(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta su\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveItem($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta giu\u2019\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveItem($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi l\u2019operazione\"\r\n (click)=\"removeItem($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Destinazione</label>\r\n <!--\r\n Solo destinazioni scrivibili: una costante o una formula produrrebbero\r\n TARGET_NOT_WRITABLE. Le globali assegnabili \u2014 `$Flow.CurrentStage`,\r\n `$Flow.ActiveStages` e quelle dichiarate scrivibili dall'host \u2014 arrivano gi\u00E0\r\n dalla primitiva, non si aggiungono qui.\r\n -->\r\n <fb-reference-picker\r\n [value]=\"item.assignToReference\"\r\n [writableOnly]=\"true\"\r\n placeholder=\"Scegli una variabile\"\r\n (valueChange)=\"setTarget($index, $event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Puoi scrivere anche un campo di un record: <code>Cliente.Email</code>, <code>$Record.Stato</code>.\r\n </p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Operazione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"item.operator || ''\"\r\n (change)=\"setOperator($index, $any($event.target).value)\"\r\n >\r\n @for (operator of operators(); track operator.value) {\r\n <option [value]=\"operator.value\">{{ operator.label }}</option>\r\n }\r\n </select>\r\n @if (operatorDescription(item.operator)) {\r\n <p class=\"fb-field__hint\">{{ operatorDescription(item.operator) }}</p>\r\n }\r\n @if (addSemanticsHint(item)) {\r\n <p class=\"fb-field__hint\">{{ addSemanticsHint(item) }}</p>\r\n }\r\n @if (expectsCollection(item)) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Questa operazione ha senso solo su una destinazione collection: su una variabile singola non\r\n fallisce, semplicemente non fa nulla.\r\n </p>\r\n }\r\n </div>\r\n\r\n @if (needsValue(item)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\r\n <fb-value-editor [value]=\"item.value\" label=\"Valore\" (valueChange)=\"setValue($index, $event)\" />\r\n </div>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Nessuna operazione: un Assignment senza operazioni non fa nulla (ASSIGNMENT_WITHOUT_ITEMS).\r\n </p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addItem()\">Aggiungi operazione</button>\r\n</fieldset>\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4269
4667
|
}
|
|
4270
4668
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: AssignmentInspectorComponent, decorators: [{
|
|
4271
4669
|
type: Component,
|
|
4272
|
-
args: [{ selector: 'fb-assignment-inspector', standalone: true, imports: [ConnectorEditorComponent, ReferencePickerComponent, ValueEditorComponent, SelectValueDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Operazioni</legend>\r\n <p class=\"fb-section__note\">\r\n Le operazioni sono eseguite <strong>nell\u2019ordine in cui compaiono</strong>: spostarne una cambia il\r\n risultato.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (item of items(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta su\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveItem($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta giu\u2019\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveItem($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi l\u2019operazione\"\r\n (click)=\"removeItem($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Destinazione</label>\r\n <!--\r\n Solo destinazioni scrivibili: una costante o una formula produrrebbero\r\n TARGET_NOT_WRITABLE. Le
|
|
4670
|
+
args: [{ selector: 'fb-assignment-inspector', standalone: true, imports: [ConnectorEditorComponent, ReferencePickerComponent, ValueEditorComponent, SelectValueDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Operazioni</legend>\r\n <p class=\"fb-section__note\">\r\n Le operazioni sono eseguite <strong>nell\u2019ordine in cui compaiono</strong>: spostarne una cambia il\r\n risultato.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (item of items(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta su\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveItem($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta giu\u2019\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveItem($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi l\u2019operazione\"\r\n (click)=\"removeItem($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Destinazione</label>\r\n <!--\r\n Solo destinazioni scrivibili: una costante o una formula produrrebbero\r\n TARGET_NOT_WRITABLE. Le globali assegnabili \u2014 `$Flow.CurrentStage`,\r\n `$Flow.ActiveStages` e quelle dichiarate scrivibili dall'host \u2014 arrivano gi\u00E0\r\n dalla primitiva, non si aggiungono qui.\r\n -->\r\n <fb-reference-picker\r\n [value]=\"item.assignToReference\"\r\n [writableOnly]=\"true\"\r\n placeholder=\"Scegli una variabile\"\r\n (valueChange)=\"setTarget($index, $event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Puoi scrivere anche un campo di un record: <code>Cliente.Email</code>, <code>$Record.Stato</code>.\r\n </p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Operazione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"item.operator || ''\"\r\n (change)=\"setOperator($index, $any($event.target).value)\"\r\n >\r\n @for (operator of operators(); track operator.value) {\r\n <option [value]=\"operator.value\">{{ operator.label }}</option>\r\n }\r\n </select>\r\n @if (operatorDescription(item.operator)) {\r\n <p class=\"fb-field__hint\">{{ operatorDescription(item.operator) }}</p>\r\n }\r\n @if (addSemanticsHint(item)) {\r\n <p class=\"fb-field__hint\">{{ addSemanticsHint(item) }}</p>\r\n }\r\n @if (expectsCollection(item)) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Questa operazione ha senso solo su una destinazione collection: su una variabile singola non\r\n fallisce, semplicemente non fa nulla.\r\n </p>\r\n }\r\n </div>\r\n\r\n @if (needsValue(item)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\r\n <fb-value-editor [value]=\"item.value\" label=\"Valore\" (valueChange)=\"setValue($index, $event)\" />\r\n </div>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Nessuna operazione: un Assignment senza operazioni non fa nulla (ASSIGNMENT_WITHOUT_ITEMS).\r\n </p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addItem()\">Aggiungi operazione</button>\r\n</fieldset>\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n" }]
|
|
4273
4671
|
}] });
|
|
4274
4672
|
|
|
4275
4673
|
/**
|
|
@@ -4386,7 +4784,7 @@ class CollectionProcessorInspectorComponent extends NodeInspectorBase {
|
|
|
4386
4784
|
this.patch((node) => mutate(node));
|
|
4387
4785
|
}
|
|
4388
4786
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: CollectionProcessorInspectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
4389
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: CollectionProcessorInspectorComponent, isStandalone: true, selector: "fb-collection-processor-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Cosa fa</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"processor().collectionProcessorType || ''\"\r\n (change)=\"setKind($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (kind of kinds(); track kind.value) {\r\n <option [value]=\"kind.value\">{{ kind.label }}</option>\r\n }\r\n </select>\r\n @if (!hasKind()) {\r\n <p class=\"fb-field__error\">Senza questo valore l\u2019elemento non e\u2019 eseguibile (PROCESSOR_TYPE_MISSING).</p>\r\n }\r\n</div>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Collection di partenza</label>\r\n <fb-reference-picker\r\n [value]=\"processor().collectionReference\"\r\n [isCollection]=\"true\"\r\n placeholder=\"Scegli una collection\"\r\n (valueChange)=\"setCollection($event)\"\r\n />\r\n</div>\r\n\r\n<p class=\"fb-callout\">\r\n Il risultato non si assegna a una variabile: e\u2019 l\u2019<strong>output automatico</strong> dell\u2019elemento, e si\r\n referenzia col suo nome \u2014 <code>{{ name() }}</code>.\r\n</p>\r\n\r\n@if (isSort()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Ordinamento</legend>\r\n <div class=\"fb-list\">\r\n @for (option of sortOptions(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta su\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveSortOption($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta giu\u2019\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveSortOption($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeSortOption($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"option.sortField || ''\"\r\n placeholder=\"Nome del campo degli elementi\"\r\n (input)=\"setSortField($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Direzione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"option.sortOrder || ''\"\r\n (change)=\"setSortOrder($index, $any($event.target).value)\"\r\n >\r\n @for (order of sortOrders(); track order.value) {\r\n <option [value]=\"order.value\">{{ order.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"option.doesPutEmptyStringAndNullFirst === true\"\r\n (change)=\"setEmptyFirst($index, $any($event.target).checked)\"\r\n />\r\n Metti prima i valori vuoti e nulli\r\n </label>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Un Sort senza criteri di ordinamento e\u2019 un errore (SORT_OPTIONS_MISSING).</p>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addSortOption()\">Aggiungi criterio</button>\r\n </fieldset>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Numero massimo di elementi</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"processor().limit ?? ''\"\r\n (input)=\"setLimit($any($event.target).value)\"\r\n />\r\n </div>\r\n}\r\n\r\n@if (isFilter()) {\r\n <div class=\"fb-field\">\r\n <!--\r\n Trappola: questo NON e' dove finisce il risultato. \u00C8 la variabile che espone alle\r\n condizioni l'elemento che si sta esaminando, esattamente come nel Loop.\r\n -->\r\n <label class=\"fb-field__label fb-field__label--required\">Elemento in esame</label>\r\n <fb-reference-picker\r\n [value]=\"processor().assignNextValueToReference\"\r\n [writableOnly]=\"true\"\r\n [dataType]=\"elementDataType()\"\r\n [objectType]=\"elementObjectType()\"\r\n [isCollection]=\"false\"\r\n placeholder=\"Variabile che espone l\u2019elemento alle condizioni\"\r\n (valueChange)=\"setCurrentElementVariable($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Questa variabile serve <strong>a scrivere le condizioni</strong> qui sotto: non e\u2019 la destinazione del\r\n risultato.\r\n </p>\r\n </div>\r\n\r\n <fb-condition-editor\r\n [holder]=\"processor()\"\r\n title=\"Tieni gli elementi per cui\"\r\n (changed)=\"onConditionsChanged($event)\"\r\n />\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConditionEditorComponent, selector: "fb-condition-editor", inputs: ["holder", "title", "allowFormula", "issuePath"], outputs: ["changed"] }, { kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "
|
|
4787
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: CollectionProcessorInspectorComponent, isStandalone: true, selector: "fb-collection-processor-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Cosa fa</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"processor().collectionProcessorType || ''\"\r\n (change)=\"setKind($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (kind of kinds(); track kind.value) {\r\n <option [value]=\"kind.value\">{{ kind.label }}</option>\r\n }\r\n </select>\r\n @if (!hasKind()) {\r\n <p class=\"fb-field__error\">Senza questo valore l\u2019elemento non e\u2019 eseguibile (PROCESSOR_TYPE_MISSING).</p>\r\n }\r\n</div>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Collection di partenza</label>\r\n <fb-reference-picker\r\n [value]=\"processor().collectionReference\"\r\n [isCollection]=\"true\"\r\n placeholder=\"Scegli una collection\"\r\n (valueChange)=\"setCollection($event)\"\r\n />\r\n</div>\r\n\r\n<p class=\"fb-callout\">\r\n Il risultato non si assegna a una variabile: e\u2019 l\u2019<strong>output automatico</strong> dell\u2019elemento, e si\r\n referenzia col suo nome \u2014 <code>{{ name() }}</code>.\r\n</p>\r\n\r\n@if (isSort()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Ordinamento</legend>\r\n <div class=\"fb-list\">\r\n @for (option of sortOptions(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta su\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveSortOption($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta giu\u2019\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveSortOption($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeSortOption($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"option.sortField || ''\"\r\n placeholder=\"Nome del campo degli elementi\"\r\n (input)=\"setSortField($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Direzione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"option.sortOrder || ''\"\r\n (change)=\"setSortOrder($index, $any($event.target).value)\"\r\n >\r\n @for (order of sortOrders(); track order.value) {\r\n <option [value]=\"order.value\">{{ order.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"option.doesPutEmptyStringAndNullFirst === true\"\r\n (change)=\"setEmptyFirst($index, $any($event.target).checked)\"\r\n />\r\n Metti prima i valori vuoti e nulli\r\n </label>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Un Sort senza criteri di ordinamento e\u2019 un errore (SORT_OPTIONS_MISSING).</p>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addSortOption()\">Aggiungi criterio</button>\r\n </fieldset>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Numero massimo di elementi</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"processor().limit ?? ''\"\r\n (input)=\"setLimit($any($event.target).value)\"\r\n />\r\n </div>\r\n}\r\n\r\n@if (isFilter()) {\r\n <div class=\"fb-field\">\r\n <!--\r\n Trappola: questo NON e' dove finisce il risultato. \u00C8 la variabile che espone alle\r\n condizioni l'elemento che si sta esaminando, esattamente come nel Loop.\r\n -->\r\n <label class=\"fb-field__label fb-field__label--required\">Elemento in esame</label>\r\n <fb-reference-picker\r\n [value]=\"processor().assignNextValueToReference\"\r\n [writableOnly]=\"true\"\r\n [dataType]=\"elementDataType()\"\r\n [objectType]=\"elementObjectType()\"\r\n [isCollection]=\"false\"\r\n placeholder=\"Variabile che espone l\u2019elemento alle condizioni\"\r\n (valueChange)=\"setCurrentElementVariable($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Questa variabile serve <strong>a scrivere le condizioni</strong> qui sotto: non e\u2019 la destinazione del\r\n risultato.\r\n </p>\r\n </div>\r\n\r\n <fb-condition-editor\r\n [holder]=\"processor()\"\r\n title=\"Tieni gli elementi per cui\"\r\n (changed)=\"onConditionsChanged($event)\"\r\n />\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConditionEditorComponent, selector: "fb-condition-editor", inputs: ["holder", "title", "allowFormula", "allowLogic", "issuePath"], outputs: ["changed"] }, { kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4390
4788
|
}
|
|
4391
4789
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: CollectionProcessorInspectorComponent, decorators: [{
|
|
4392
4790
|
type: Component,
|
|
@@ -4453,11 +4851,11 @@ class CustomErrorInspectorComponent extends NodeInspectorBase {
|
|
|
4453
4851
|
});
|
|
4454
4852
|
}
|
|
4455
4853
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: CustomErrorInspectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
4456
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: CustomErrorInspectorComponent, isStandalone: true, selector: "fb-custom-error-inspector", usesInheritance: true, ngImport: i0, template: "<p class=\"fb-callout\">\n Questo elemento <strong>interrompe</strong> l\u2019esecuzione e restituisce i messaggi al chiamante. Non ha\n uscite: quello che c\u2019e\u2019 dopo non verra\u2019 eseguito.\n</p>\n\n<div class=\"fb-list\">\n @for (message of messages(); track $index) {\n <div class=\"fb-list__item\">\n <div class=\"fb-list__header\">\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\n <span class=\"fb-list__spacer\"></span>\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\n aria-label=\"Rimuovi il messaggio\"\n (click)=\"removeMessage($index)\"\n >\n \u00D7\n </button>\n </div>\n\n <div class=\"fb-field\">\n <label class=\"fb-field__label fb-field__label--required\">Messaggio</label>\n <textarea\n class=\"fb-textarea\"\n [value]=\"message.errorMessage || ''\"\n placeholder=\"L\u2019importo supera il limite consentito.\"\n (input)=\"setMessage($index, $any($event.target).value)\"\n ></textarea>\n </div>\n\n <label class=\"fb-check\">\n <input\n type=\"checkbox\"\n [checked]=\"message.isFieldError === true\"\n (change)=\"setIsFieldError($index, $any($event.target).checked)\"\n />\n Mostra accanto a un campo\n </label>\n\n @if (message.isFieldError) {\n <div class=\"fb-field\">\n <label class=\"fb-field__label fb-field__label--required\">Campo</label>\n <input\n class=\"fb-input\"\n [value]=\"message.fieldSelection || ''\"\n placeholder=\"Importo\"\n (input)=\"setFieldSelection($index, $any($event.target).value)\"\n />\n </div>\n }\n </div>\n } @empty {\n <p class=\"fb-empty\">\n Almeno un messaggio e\u2019 obbligatorio: sono il prodotto di questo elemento\n (CUSTOM_ERROR_WITHOUT_MESSAGES).\n </p>\n }\n</div>\n\n<button type=\"button\" class=\"fb-btn\" (click)=\"addMessage()\">Aggiungi messaggio</button>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4854
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: CustomErrorInspectorComponent, isStandalone: true, selector: "fb-custom-error-inspector", usesInheritance: true, ngImport: i0, template: "<p class=\"fb-callout\">\r\n Questo elemento <strong>interrompe</strong> l\u2019esecuzione e restituisce i messaggi al chiamante. Non ha\r\n uscite: quello che c\u2019e\u2019 dopo non verra\u2019 eseguito.\r\n</p>\r\n\r\n<div class=\"fb-list\">\r\n @for (message of messages(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi il messaggio\"\r\n (click)=\"removeMessage($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Messaggio</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"message.errorMessage || ''\"\r\n placeholder=\"L\u2019importo supera il limite consentito.\"\r\n (input)=\"setMessage($index, $any($event.target).value)\"\r\n ></textarea>\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"message.isFieldError === true\"\r\n (change)=\"setIsFieldError($index, $any($event.target).checked)\"\r\n />\r\n Mostra accanto a un campo\r\n </label>\r\n\r\n @if (message.isFieldError) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"message.fieldSelection || ''\"\r\n placeholder=\"Importo\"\r\n (input)=\"setFieldSelection($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Almeno un messaggio e\u2019 obbligatorio: sono il prodotto di questo elemento\r\n (CUSTOM_ERROR_WITHOUT_MESSAGES).\r\n </p>\r\n }\r\n</div>\r\n\r\n<button type=\"button\" class=\"fb-btn\" (click)=\"addMessage()\">Aggiungi messaggio</button>\r\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4457
4855
|
}
|
|
4458
4856
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: CustomErrorInspectorComponent, decorators: [{
|
|
4459
4857
|
type: Component,
|
|
4460
|
-
args: [{ selector: 'fb-custom-error-inspector', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<p class=\"fb-callout\">\n Questo elemento <strong>interrompe</strong> l\u2019esecuzione e restituisce i messaggi al chiamante. Non ha\n uscite: quello che c\u2019e\u2019 dopo non verra\u2019 eseguito.\n</p>\n\n<div class=\"fb-list\">\n @for (message of messages(); track $index) {\n <div class=\"fb-list__item\">\n <div class=\"fb-list__header\">\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\n <span class=\"fb-list__spacer\"></span>\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\n aria-label=\"Rimuovi il messaggio\"\n (click)=\"removeMessage($index)\"\n >\n \u00D7\n </button>\n </div>\n\n <div class=\"fb-field\">\n <label class=\"fb-field__label fb-field__label--required\">Messaggio</label>\n <textarea\n class=\"fb-textarea\"\n [value]=\"message.errorMessage || ''\"\n placeholder=\"L\u2019importo supera il limite consentito.\"\n (input)=\"setMessage($index, $any($event.target).value)\"\n ></textarea>\n </div>\n\n <label class=\"fb-check\">\n <input\n type=\"checkbox\"\n [checked]=\"message.isFieldError === true\"\n (change)=\"setIsFieldError($index, $any($event.target).checked)\"\n />\n Mostra accanto a un campo\n </label>\n\n @if (message.isFieldError) {\n <div class=\"fb-field\">\n <label class=\"fb-field__label fb-field__label--required\">Campo</label>\n <input\n class=\"fb-input\"\n [value]=\"message.fieldSelection || ''\"\n placeholder=\"Importo\"\n (input)=\"setFieldSelection($index, $any($event.target).value)\"\n />\n </div>\n }\n </div>\n } @empty {\n <p class=\"fb-empty\">\n Almeno un messaggio e\u2019 obbligatorio: sono il prodotto di questo elemento\n (CUSTOM_ERROR_WITHOUT_MESSAGES).\n </p>\n }\n</div>\n\n<button type=\"button\" class=\"fb-btn\" (click)=\"addMessage()\">Aggiungi messaggio</button>\n" }]
|
|
4858
|
+
args: [{ selector: 'fb-custom-error-inspector', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<p class=\"fb-callout\">\r\n Questo elemento <strong>interrompe</strong> l\u2019esecuzione e restituisce i messaggi al chiamante. Non ha\r\n uscite: quello che c\u2019e\u2019 dopo non verra\u2019 eseguito.\r\n</p>\r\n\r\n<div class=\"fb-list\">\r\n @for (message of messages(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi il messaggio\"\r\n (click)=\"removeMessage($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Messaggio</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"message.errorMessage || ''\"\r\n placeholder=\"L\u2019importo supera il limite consentito.\"\r\n (input)=\"setMessage($index, $any($event.target).value)\"\r\n ></textarea>\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"message.isFieldError === true\"\r\n (change)=\"setIsFieldError($index, $any($event.target).checked)\"\r\n />\r\n Mostra accanto a un campo\r\n </label>\r\n\r\n @if (message.isFieldError) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"message.fieldSelection || ''\"\r\n placeholder=\"Importo\"\r\n (input)=\"setFieldSelection($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Almeno un messaggio e\u2019 obbligatorio: sono il prodotto di questo elemento\r\n (CUSTOM_ERROR_WITHOUT_MESSAGES).\r\n </p>\r\n }\r\n</div>\r\n\r\n<button type=\"button\" class=\"fb-btn\" (click)=\"addMessage()\">Aggiungi messaggio</button>\r\n" }]
|
|
4461
4859
|
}] });
|
|
4462
4860
|
|
|
4463
4861
|
/**
|
|
@@ -4562,11 +4960,11 @@ class DecisionInspectorComponent extends NodeInspectorBase {
|
|
|
4562
4960
|
this.setField('defaultConnectorLabel', label);
|
|
4563
4961
|
}
|
|
4564
4962
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: DecisionInspectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
4565
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: DecisionInspectorComponent, isStandalone: true, selector: "fb-decision-inspector", usesInheritance: true, ngImport: i0, template: "<p class=\"fb-callout\">\n Le regole sono valutate <strong>dall\u2019alto verso il basso</strong> e si ferma alla prima vera. L\u2019ordine e\u2019\n parte del significato del flow: usa le frecce per cambiarlo.\n</p>\n\n<div class=\"fb-list\">\n @for (rule of rules(); track $index) {\n <div class=\"fb-list__item\">\n <div class=\"fb-list__header\">\n <span class=\"fb-list__index\" [title]=\"'Valutata per ' + ($index + 1) + '\u00AA'\">{{ $index + 1 }}</span>\n <span class=\"fb-list__spacer\"></span>\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\n aria-label=\"Valuta prima\"\n [disabled]=\"$first\"\n (click)=\"moveRule($index, -1)\"\n >\n \u2191\n </button>\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\n aria-label=\"Valuta dopo\"\n [disabled]=\"$last\"\n (click)=\"moveRule($index, 1)\"\n >\n \u2193\n </button>\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\n aria-label=\"Rimuovi la regola\"\n (click)=\"removeRule($index)\"\n >\n \u00D7\n </button>\n </div>\n\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">Etichetta del ramo</label>\n <input\n class=\"fb-input\"\n [value]=\"rule.label || ''\"\n placeholder=\"Approvato\"\n (input)=\"setRuleLabel($index, $any($event.target).value)\"\n />\n @if (!rule.label) {\n <p class=\"fb-field__hint\">Senza etichetta l\u2019arco resta senza nome sul canvas.</p>\n }\n </div>\n\n <div class=\"fb-field\">\n <label class=\"fb-field__label fb-field__label--required\">Nome tecnico</label>\n <input\n class=\"fb-input fb-input--mono\"\n [class.fb-input--invalid]=\"!!ruleNameError($index)\"\n [value]=\"rule.name || ''\"\n (input)=\"setRuleName($index, $any($event.target).value)\"\n />\n @if (ruleNameError($index)) {\n <p class=\"fb-field__error\">{{ ruleNameError($index) }}</p>\n }\n </div>\n\n <fb-condition-editor\n [holder]=\"rule\"\n title=\"Quando prendere questo ramo\"\n [issuePath]=\"'rules[' + (rule.name || $index) + ']'\"\n (changed)=\"onRuleConditionsChanged($index, $event)\"\n />\n </div>\n } @empty {\n <p class=\"fb-empty\">\n Nessuna regola: una Decision senza regole prende sempre il ramo di default\n (DECISION_WITHOUT_RULES).\n </p>\n }\n</div>\n\n<button type=\"button\" class=\"fb-btn\" (click)=\"addRule()\">Aggiungi regola</button>\n\n<fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">Se nessuna regola e\u2019 vera</legend>\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">Etichetta del ramo di default</label>\n <input\n class=\"fb-input\"\n [value]=\"defaultLabel()\"\n placeholder=\"Rifiutato\"\n (input)=\"setDefaultLabel($any($event.target).value)\"\n />\n </div>\n @if (!hasDefaultTarget()) {\n <p class=\"fb-field__hint\">\n Nessuna destinazione di default: se nessuna regola e\u2019 vera l\u2019esecuzione finisce qui.\n </p>\n }\n</fieldset>\n\n<fb-connector-editor\n [nodeName]=\"name()\"\n [node]=\"node()\"\n [outlets]=\"outlets()\"\n title=\"Rami\"\n (connectorChanged)=\"onConnectorChanged($event)\"\n/>\n", dependencies: [{ kind: "component", type: ConditionEditorComponent, selector: "fb-condition-editor", inputs: ["holder", "title", "allowFormula", "issuePath"], outputs: ["changed"] }, { kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4963
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: DecisionInspectorComponent, isStandalone: true, selector: "fb-decision-inspector", usesInheritance: true, ngImport: i0, template: "<p class=\"fb-callout\">\r\n Le regole sono valutate <strong>dall\u2019alto verso il basso</strong> e si ferma alla prima vera. L\u2019ordine e\u2019\r\n parte del significato del flow: usa le frecce per cambiarlo.\r\n</p>\r\n\r\n<div class=\"fb-list\">\r\n @for (rule of rules(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\" [title]=\"'Valutata per ' + ($index + 1) + '\u00AA'\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Valuta prima\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveRule($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Valuta dopo\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveRule($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi la regola\"\r\n (click)=\"removeRule($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta del ramo</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"rule.label || ''\"\r\n placeholder=\"Approvato\"\r\n (input)=\"setRuleLabel($index, $any($event.target).value)\"\r\n />\r\n @if (!rule.label) {\r\n <p class=\"fb-field__hint\">Senza etichetta l\u2019arco resta senza nome sul canvas.</p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Nome tecnico</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [class.fb-input--invalid]=\"!!ruleNameError($index)\"\r\n [value]=\"rule.name || ''\"\r\n (input)=\"setRuleName($index, $any($event.target).value)\"\r\n />\r\n @if (ruleNameError($index)) {\r\n <p class=\"fb-field__error\">{{ ruleNameError($index) }}</p>\r\n }\r\n </div>\r\n\r\n <fb-condition-editor\r\n [holder]=\"rule\"\r\n title=\"Quando prendere questo ramo\"\r\n [issuePath]=\"'rules[' + (rule.name || $index) + ']'\"\r\n (changed)=\"onRuleConditionsChanged($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Nessuna regola: una Decision senza regole prende sempre il ramo di default\r\n (DECISION_WITHOUT_RULES).\r\n </p>\r\n }\r\n</div>\r\n\r\n<button type=\"button\" class=\"fb-btn\" (click)=\"addRule()\">Aggiungi regola</button>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Se nessuna regola e\u2019 vera</legend>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta del ramo di default</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"defaultLabel()\"\r\n placeholder=\"Rifiutato\"\r\n (input)=\"setDefaultLabel($any($event.target).value)\"\r\n />\r\n </div>\r\n @if (!hasDefaultTarget()) {\r\n <p class=\"fb-field__hint\">\r\n Nessuna destinazione di default: se nessuna regola e\u2019 vera l\u2019esecuzione finisce qui.\r\n </p>\r\n }\r\n</fieldset>\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Rami\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConditionEditorComponent, selector: "fb-condition-editor", inputs: ["holder", "title", "allowFormula", "allowLogic", "issuePath"], outputs: ["changed"] }, { kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4566
4964
|
}
|
|
4567
4965
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: DecisionInspectorComponent, decorators: [{
|
|
4568
4966
|
type: Component,
|
|
4569
|
-
args: [{ selector: 'fb-decision-inspector', standalone: true, imports: [ConditionEditorComponent, ConnectorEditorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<p class=\"fb-callout\">\n Le regole sono valutate <strong>dall\u2019alto verso il basso</strong> e si ferma alla prima vera. L\u2019ordine e\u2019\n parte del significato del flow: usa le frecce per cambiarlo.\n</p>\n\n<div class=\"fb-list\">\n @for (rule of rules(); track $index) {\n <div class=\"fb-list__item\">\n <div class=\"fb-list__header\">\n <span class=\"fb-list__index\" [title]=\"'Valutata per ' + ($index + 1) + '\u00AA'\">{{ $index + 1 }}</span>\n <span class=\"fb-list__spacer\"></span>\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\n aria-label=\"Valuta prima\"\n [disabled]=\"$first\"\n (click)=\"moveRule($index, -1)\"\n >\n \u2191\n </button>\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\n aria-label=\"Valuta dopo\"\n [disabled]=\"$last\"\n (click)=\"moveRule($index, 1)\"\n >\n \u2193\n </button>\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\n aria-label=\"Rimuovi la regola\"\n (click)=\"removeRule($index)\"\n >\n \u00D7\n </button>\n </div>\n\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">Etichetta del ramo</label>\n <input\n class=\"fb-input\"\n [value]=\"rule.label || ''\"\n placeholder=\"Approvato\"\n (input)=\"setRuleLabel($index, $any($event.target).value)\"\n />\n @if (!rule.label) {\n <p class=\"fb-field__hint\">Senza etichetta l\u2019arco resta senza nome sul canvas.</p>\n }\n </div>\n\n <div class=\"fb-field\">\n <label class=\"fb-field__label fb-field__label--required\">Nome tecnico</label>\n <input\n class=\"fb-input fb-input--mono\"\n [class.fb-input--invalid]=\"!!ruleNameError($index)\"\n [value]=\"rule.name || ''\"\n (input)=\"setRuleName($index, $any($event.target).value)\"\n />\n @if (ruleNameError($index)) {\n <p class=\"fb-field__error\">{{ ruleNameError($index) }}</p>\n }\n </div>\n\n <fb-condition-editor\n [holder]=\"rule\"\n title=\"Quando prendere questo ramo\"\n [issuePath]=\"'rules[' + (rule.name || $index) + ']'\"\n (changed)=\"onRuleConditionsChanged($index, $event)\"\n />\n </div>\n } @empty {\n <p class=\"fb-empty\">\n Nessuna regola: una Decision senza regole prende sempre il ramo di default\n (DECISION_WITHOUT_RULES).\n </p>\n }\n</div>\n\n<button type=\"button\" class=\"fb-btn\" (click)=\"addRule()\">Aggiungi regola</button>\n\n<fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">Se nessuna regola e\u2019 vera</legend>\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">Etichetta del ramo di default</label>\n <input\n class=\"fb-input\"\n [value]=\"defaultLabel()\"\n placeholder=\"Rifiutato\"\n (input)=\"setDefaultLabel($any($event.target).value)\"\n />\n </div>\n @if (!hasDefaultTarget()) {\n <p class=\"fb-field__hint\">\n Nessuna destinazione di default: se nessuna regola e\u2019 vera l\u2019esecuzione finisce qui.\n </p>\n }\n</fieldset>\n\n<fb-connector-editor\n [nodeName]=\"name()\"\n [node]=\"node()\"\n [outlets]=\"outlets()\"\n title=\"Rami\"\n (connectorChanged)=\"onConnectorChanged($event)\"\n/>\n" }]
|
|
4967
|
+
args: [{ selector: 'fb-decision-inspector', standalone: true, imports: [ConditionEditorComponent, ConnectorEditorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<p class=\"fb-callout\">\r\n Le regole sono valutate <strong>dall\u2019alto verso il basso</strong> e si ferma alla prima vera. L\u2019ordine e\u2019\r\n parte del significato del flow: usa le frecce per cambiarlo.\r\n</p>\r\n\r\n<div class=\"fb-list\">\r\n @for (rule of rules(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\" [title]=\"'Valutata per ' + ($index + 1) + '\u00AA'\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Valuta prima\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveRule($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Valuta dopo\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveRule($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi la regola\"\r\n (click)=\"removeRule($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta del ramo</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"rule.label || ''\"\r\n placeholder=\"Approvato\"\r\n (input)=\"setRuleLabel($index, $any($event.target).value)\"\r\n />\r\n @if (!rule.label) {\r\n <p class=\"fb-field__hint\">Senza etichetta l\u2019arco resta senza nome sul canvas.</p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Nome tecnico</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [class.fb-input--invalid]=\"!!ruleNameError($index)\"\r\n [value]=\"rule.name || ''\"\r\n (input)=\"setRuleName($index, $any($event.target).value)\"\r\n />\r\n @if (ruleNameError($index)) {\r\n <p class=\"fb-field__error\">{{ ruleNameError($index) }}</p>\r\n }\r\n </div>\r\n\r\n <fb-condition-editor\r\n [holder]=\"rule\"\r\n title=\"Quando prendere questo ramo\"\r\n [issuePath]=\"'rules[' + (rule.name || $index) + ']'\"\r\n (changed)=\"onRuleConditionsChanged($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Nessuna regola: una Decision senza regole prende sempre il ramo di default\r\n (DECISION_WITHOUT_RULES).\r\n </p>\r\n }\r\n</div>\r\n\r\n<button type=\"button\" class=\"fb-btn\" (click)=\"addRule()\">Aggiungi regola</button>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Se nessuna regola e\u2019 vera</legend>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta del ramo di default</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"defaultLabel()\"\r\n placeholder=\"Rifiutato\"\r\n (input)=\"setDefaultLabel($any($event.target).value)\"\r\n />\r\n </div>\r\n @if (!hasDefaultTarget()) {\r\n <p class=\"fb-field__hint\">\r\n Nessuna destinazione di default: se nessuna regola e\u2019 vera l\u2019esecuzione finisce qui.\r\n </p>\r\n }\r\n</fieldset>\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Rami\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n" }]
|
|
4570
4968
|
}] });
|
|
4571
4969
|
|
|
4572
4970
|
/**
|
|
@@ -4640,13 +5038,357 @@ class LoopInspectorComponent extends NodeInspectorBase {
|
|
|
4640
5038
|
this.setField('iterationOrder', order);
|
|
4641
5039
|
}
|
|
4642
5040
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: LoopInspectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
4643
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: LoopInspectorComponent, isStandalone: true, selector: "fb-loop-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Collection da iterare</label>\r\n <!-- Solo collection: iterare una variabile singola e' un errore (LOOP_COLLECTION_MISSING). -->\r\n <fb-reference-picker\r\n [value]=\"loop().collectionReference\"\r\n [isCollection]=\"true\"\r\n placeholder=\"Scegli una collection\"\r\n (valueChange)=\"setCollection($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Anche l\u2019output automatico di un Get Records senza \u00ABsolo il primo record\u00BB e\u2019 iterabile.\r\n </p>\r\n</div>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Elemento corrente</label>\r\n <fb-reference-picker\r\n [value]=\"loop().assignNextValueToReference\"\r\n [writableOnly]=\"true\"\r\n [dataType]=\"collectionType()\"\r\n [objectType]=\"collectionObjectType()\"\r\n [isCollection]=\"false\"\r\n placeholder=\"Variabile che riceve l\u2019elemento\"\r\n (valueChange)=\"setCurrentValueVariable($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Deve essere una variabile <strong>singola</strong> dello stesso tipo degli elementi: senza, il corpo del\r\n ciclo non ha modo di leggere l\u2019elemento corrente.\r\n </p>\r\n</div>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Ordine di iterazione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"loop().iterationOrder || ''\"\r\n (change)=\"setIterationOrder($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 predefinito \u2014</option>\r\n @for (order of sortOrders(); track order.value) {\r\n <option [value]=\"order.value\">{{ order.label }}</option>\r\n }\r\n </select>\r\n</div>\r\n\r\n@if (hasBody() && !bodyReturnsToLoop()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il corpo del ciclo non torna sul Loop: nessun percorso dal ramo \u00ABper ogni valore\u00BB rientra qui, quindi\r\n verrebbe eseguita una sola iterazione. Collega l\u2019ultimo elemento del corpo di nuovo al Loop, marcando\r\n l\u2019arco come salto indietro.\r\n </p>\r\n}\r\n@if (!hasBody()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Il ramo \u00ABper ogni valore\u00BB non ha destinazione: il ciclo non ha corpo.\r\n </p>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Rami del ciclo\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n\r\n<p class=\"fb-field__hint\">\r\n Il cursore si azzera all\u2019uscita: rientrare nello stesso Loop ricomincia da capo.\r\n</p>\r\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "
|
|
5041
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: LoopInspectorComponent, isStandalone: true, selector: "fb-loop-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Collection da iterare</label>\r\n <!-- Solo collection: iterare una variabile singola e' un errore (LOOP_COLLECTION_MISSING). -->\r\n <fb-reference-picker\r\n [value]=\"loop().collectionReference\"\r\n [isCollection]=\"true\"\r\n placeholder=\"Scegli una collection\"\r\n (valueChange)=\"setCollection($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Anche l\u2019output automatico di un Get Records senza \u00ABsolo il primo record\u00BB e\u2019 iterabile.\r\n </p>\r\n</div>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Elemento corrente</label>\r\n <fb-reference-picker\r\n [value]=\"loop().assignNextValueToReference\"\r\n [writableOnly]=\"true\"\r\n [dataType]=\"collectionType()\"\r\n [objectType]=\"collectionObjectType()\"\r\n [isCollection]=\"false\"\r\n placeholder=\"Variabile che riceve l\u2019elemento\"\r\n (valueChange)=\"setCurrentValueVariable($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Deve essere una variabile <strong>singola</strong> dello stesso tipo degli elementi: senza, il corpo del\r\n ciclo non ha modo di leggere l\u2019elemento corrente.\r\n </p>\r\n</div>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Ordine di iterazione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"loop().iterationOrder || ''\"\r\n (change)=\"setIterationOrder($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 predefinito \u2014</option>\r\n @for (order of sortOrders(); track order.value) {\r\n <option [value]=\"order.value\">{{ order.label }}</option>\r\n }\r\n </select>\r\n</div>\r\n\r\n@if (hasBody() && !bodyReturnsToLoop()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il corpo del ciclo non torna sul Loop: nessun percorso dal ramo \u00ABper ogni valore\u00BB rientra qui, quindi\r\n verrebbe eseguita una sola iterazione. Collega l\u2019ultimo elemento del corpo di nuovo al Loop, marcando\r\n l\u2019arco come salto indietro.\r\n </p>\r\n}\r\n@if (!hasBody()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Il ramo \u00ABper ogni valore\u00BB non ha destinazione: il ciclo non ha corpo.\r\n </p>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Rami del ciclo\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n\r\n<p class=\"fb-field__hint\">\r\n Il cursore si azzera all\u2019uscita: rientrare nello stesso Loop ricomincia da capo.\r\n</p>\r\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4644
5042
|
}
|
|
4645
5043
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: LoopInspectorComponent, decorators: [{
|
|
4646
5044
|
type: Component,
|
|
4647
5045
|
args: [{ selector: 'fb-loop-inspector', standalone: true, imports: [ConnectorEditorComponent, ReferencePickerComponent, SelectValueDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Collection da iterare</label>\r\n <!-- Solo collection: iterare una variabile singola e' un errore (LOOP_COLLECTION_MISSING). -->\r\n <fb-reference-picker\r\n [value]=\"loop().collectionReference\"\r\n [isCollection]=\"true\"\r\n placeholder=\"Scegli una collection\"\r\n (valueChange)=\"setCollection($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Anche l\u2019output automatico di un Get Records senza \u00ABsolo il primo record\u00BB e\u2019 iterabile.\r\n </p>\r\n</div>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Elemento corrente</label>\r\n <fb-reference-picker\r\n [value]=\"loop().assignNextValueToReference\"\r\n [writableOnly]=\"true\"\r\n [dataType]=\"collectionType()\"\r\n [objectType]=\"collectionObjectType()\"\r\n [isCollection]=\"false\"\r\n placeholder=\"Variabile che riceve l\u2019elemento\"\r\n (valueChange)=\"setCurrentValueVariable($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Deve essere una variabile <strong>singola</strong> dello stesso tipo degli elementi: senza, il corpo del\r\n ciclo non ha modo di leggere l\u2019elemento corrente.\r\n </p>\r\n</div>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Ordine di iterazione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"loop().iterationOrder || ''\"\r\n (change)=\"setIterationOrder($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 predefinito \u2014</option>\r\n @for (order of sortOrders(); track order.value) {\r\n <option [value]=\"order.value\">{{ order.label }}</option>\r\n }\r\n </select>\r\n</div>\r\n\r\n@if (hasBody() && !bodyReturnsToLoop()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il corpo del ciclo non torna sul Loop: nessun percorso dal ramo \u00ABper ogni valore\u00BB rientra qui, quindi\r\n verrebbe eseguita una sola iterazione. Collega l\u2019ultimo elemento del corpo di nuovo al Loop, marcando\r\n l\u2019arco come salto indietro.\r\n </p>\r\n}\r\n@if (!hasBody()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Il ramo \u00ABper ogni valore\u00BB non ha destinazione: il ciclo non ha corpo.\r\n </p>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Rami del ciclo\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n\r\n<p class=\"fb-field__hint\">\r\n Il cursore si azzera all\u2019uscita: rientrare nello stesso Loop ricomincia da capo.\r\n</p>\r\n" }]
|
|
4648
5046
|
}] });
|
|
4649
5047
|
|
|
5048
|
+
/**
|
|
5049
|
+
* Orchestrated Stage — FRONTEND.md §5.13.
|
|
5050
|
+
*
|
|
5051
|
+
* Un gruppo di step, alcuni affidati a una persona. Quello che questo form fa di diverso da un
|
|
5052
|
+
* elenco di sotto-elementi, e che il modello impone:
|
|
5053
|
+
*
|
|
5054
|
+
* 1. **Gli step non sono una sequenza.** L'ordine nell'array e' solo l'ordine d'esame: uno
|
|
5055
|
+
* step parte appena le sue `entryConditions` sono vere. Non sono numerati come passi, e le
|
|
5056
|
+
* frecce dicono di riordinare l'*esame*, non l'esecuzione.
|
|
5057
|
+
* 2. **Il `name` di uno step sta nello stesso spazio dei nomi** di node e risorse (§3.3): un
|
|
5058
|
+
* omonimo di una variabile e' `NAME_DUPLICATED`, e il controllo e' lo stesso dell'inspector.
|
|
5059
|
+
* 3. **Una condizione non puo' referenziare l'output di un altro step**: finche' quello step
|
|
5060
|
+
* non ha girato il riferimento e' irrisolvibile, e a runtime un riferimento irrisolvibile
|
|
5061
|
+
* e' un errore. Qui e' segnalato con la via d'uscita: scrivere il risultato in una
|
|
5062
|
+
* variabile e condizionare su quella.
|
|
5063
|
+
* 4. **`entryConditions` e `exitConditions` non sono simmetriche**: se le prime non si
|
|
5064
|
+
* avverano lo step viene saltato, se le seconde restano false lo stage va in **stallo** e
|
|
5065
|
+
* l'esecuzione fallisce. Sono due cose diverse che si assomigliano, quindi e' scritto.
|
|
5066
|
+
* 5. **`faultConnector` e' il ramo dello step rifiutato**, non un ramo di guasto: senza, un
|
|
5067
|
+
* rifiuto fa fallire l'interview. Per un flow di approvazione va quasi sempre disegnato.
|
|
5068
|
+
*
|
|
5069
|
+
* `runAsUser` viene ignorato dal runtime e `canAssigneeEdit` / `shouldLock` /
|
|
5070
|
+
* `requiresAsyncProcessing` sono riservati: non sono esposti.
|
|
5071
|
+
*/
|
|
5072
|
+
class OrchestratedStageInspectorComponent extends NodeInspectorBase {
|
|
5073
|
+
api = inject(FlowBuilderApi);
|
|
5074
|
+
elementType = 'OrchestratedStage';
|
|
5075
|
+
stage = computed(() => this.node(), ...(ngDevMode ? [{ debugName: "stage" }] : []));
|
|
5076
|
+
steps = computed(() => stepsOf(this.stage()), ...(ngDevMode ? [{ debugName: "steps" }] : []));
|
|
5077
|
+
/** I tre tipi di step: `stageStepTypes` e' l'elenco autoritativo (§6.4). */
|
|
5078
|
+
stepTypes = computed(() => this.dictionaries.stageStepTypes(), ...(ngDevMode ? [{ debugName: "stepTypes" }] : []));
|
|
5079
|
+
assigneeTypes = computed(() => this.dictionaries.assigneeTypes(), ...(ngDevMode ? [{ debugName: "assigneeTypes" }] : []));
|
|
5080
|
+
/** L'output che il runtime legge da un evaluation flow di condizione. */
|
|
5081
|
+
conditionOutputName = ORCHESTRATION_CONDITION_OUTPUT;
|
|
5082
|
+
/**
|
|
5083
|
+
* I flow proponibili come step in background o come evaluation flow. Una lista vuota
|
|
5084
|
+
* significa "non lo so": in quel caso il campo resta scrivibile a mano (§5.9, §7).
|
|
5085
|
+
*/
|
|
5086
|
+
flowCandidates = signal([], ...(ngDevMode ? [{ debugName: "flowCandidates" }] : []));
|
|
5087
|
+
constructor() {
|
|
5088
|
+
super();
|
|
5089
|
+
void this.api
|
|
5090
|
+
.listSubflowCandidates(this.store.document().fullName ?? undefined)
|
|
5091
|
+
.then((list) => this.flowCandidates.set(list ?? []))
|
|
5092
|
+
.catch(() => this.flowCandidates.set([]));
|
|
5093
|
+
}
|
|
5094
|
+
candidates = computed(() => this.flowCandidates(), ...(ngDevMode ? [{ debugName: "candidates" }] : []));
|
|
5095
|
+
/** L'id del `datalist`: dipende dall'elemento, per non collidere con un altro stage. */
|
|
5096
|
+
flowListId = computed(() => `fb-stage-flows-${this.name()}`, ...(ngDevMode ? [{ debugName: "flowListId" }] : []));
|
|
5097
|
+
/**
|
|
5098
|
+
* I contenitori di condizioni, uno per step, calcolati **una volta** per documento: costruirli
|
|
5099
|
+
* nel template creerebbe un oggetto nuovo a ogni ciclo di change detection.
|
|
5100
|
+
*/
|
|
5101
|
+
conditionHolders = computed(() => this.steps().map((step) => ({
|
|
5102
|
+
entry: { conditions: step.entryConditions ?? [] },
|
|
5103
|
+
exit: { conditions: step.exitConditions ?? [] },
|
|
5104
|
+
})), ...(ngDevMode ? [{ debugName: "conditionHolders" }] : []));
|
|
5105
|
+
// -------------------------------------------------------------------------
|
|
5106
|
+
// Diagnostica locale
|
|
5107
|
+
// -------------------------------------------------------------------------
|
|
5108
|
+
requiresActionName(step) {
|
|
5109
|
+
return this.dictionaries.stageStepRequiresActionName(step.actionType);
|
|
5110
|
+
}
|
|
5111
|
+
requiresAssignees(step) {
|
|
5112
|
+
return this.dictionaries.stageStepRequiresAssignees(step.actionType);
|
|
5113
|
+
}
|
|
5114
|
+
/** Il rifiuto e' un esito previsto solo per l'approvazione: e' lì che serve il ramo. */
|
|
5115
|
+
supportsRejection(step) {
|
|
5116
|
+
const entry = this.dictionaries.stageStepType(step.actionType);
|
|
5117
|
+
return entry?.supportsRejection ?? step.actionType === 'stepApproval';
|
|
5118
|
+
}
|
|
5119
|
+
stepTypeDescription(step) {
|
|
5120
|
+
return this.dictionaries.stageStepType(step.actionType)?.description ?? null;
|
|
5121
|
+
}
|
|
5122
|
+
/** Un `actionType` che il dizionario non conosce: sarebbe `STAGE_STEP_TYPE_UNKNOWN`. */
|
|
5123
|
+
isUnknownStepType(step) {
|
|
5124
|
+
if (!step.actionType || !this.stepTypes().length) {
|
|
5125
|
+
return false;
|
|
5126
|
+
}
|
|
5127
|
+
return !this.dictionaries.stageStepType(step.actionType);
|
|
5128
|
+
}
|
|
5129
|
+
/**
|
|
5130
|
+
* Il nome dello step: stessa regola dei node, sullo spazio dei nomi comune (§3.3).
|
|
5131
|
+
* L'unicita' si conta sulle occorrenze in `usedNames`, che gli step li comprende già: una
|
|
5132
|
+
* sola occorrenza e' questo step, due sono un omonimo.
|
|
5133
|
+
*/
|
|
5134
|
+
stepNameError(step) {
|
|
5135
|
+
const check = checkFlowName(step.name, [], step.name);
|
|
5136
|
+
if (!check.isValid) {
|
|
5137
|
+
return check.message ?? 'Nome non valido.';
|
|
5138
|
+
}
|
|
5139
|
+
const key = (step.name ?? '').toLowerCase();
|
|
5140
|
+
const occurrences = this.store.usedNames().filter((name) => name.toLowerCase() === key).length;
|
|
5141
|
+
return occurrences > 1
|
|
5142
|
+
? 'Questo nome e’ già usato da un elemento, una risorsa o un altro step (NAME_DUPLICATED).'
|
|
5143
|
+
: null;
|
|
5144
|
+
}
|
|
5145
|
+
/**
|
|
5146
|
+
* Il nome dello step il cui output una condizione sta leggendo: e' irrisolvibile finche'
|
|
5147
|
+
* quello step non ha girato (§5.13, punto 4). `undefined` quando va tutto bene.
|
|
5148
|
+
*/
|
|
5149
|
+
stepOutputInConditions(step) {
|
|
5150
|
+
const conditions = [...(step.entryConditions ?? []), ...(step.exitConditions ?? [])];
|
|
5151
|
+
for (const condition of conditions) {
|
|
5152
|
+
const referenced = stageStepOutputReferenced(condition.leftValueReference, this.steps()) ??
|
|
5153
|
+
stageStepOutputReferenced(condition.rightValue?.elementReference, this.steps());
|
|
5154
|
+
if (referenced) {
|
|
5155
|
+
return referenced;
|
|
5156
|
+
}
|
|
5157
|
+
}
|
|
5158
|
+
return undefined;
|
|
5159
|
+
}
|
|
5160
|
+
/** Lo step tiene un output senza destinazione: e' lecito, ma vale la pena dirlo. */
|
|
5161
|
+
hasSimulatedOutputs(step) {
|
|
5162
|
+
return step.debugSimulateStep === true;
|
|
5163
|
+
}
|
|
5164
|
+
// -------------------------------------------------------------------------
|
|
5165
|
+
// Step
|
|
5166
|
+
// -------------------------------------------------------------------------
|
|
5167
|
+
addStep() {
|
|
5168
|
+
const name = uniqueFlowName('Step', this.store.usedNames());
|
|
5169
|
+
this.patch((node) => {
|
|
5170
|
+
const stage = node;
|
|
5171
|
+
stage.stageSteps ??= [];
|
|
5172
|
+
stage.stageSteps.push({
|
|
5173
|
+
name,
|
|
5174
|
+
label: `Step ${stage.stageSteps.length + 1}`,
|
|
5175
|
+
// Il tipo lo scelga l'utente: senza, e' `STAGE_STEP_TYPE_MISSING` e si vede subito.
|
|
5176
|
+
});
|
|
5177
|
+
});
|
|
5178
|
+
}
|
|
5179
|
+
removeStep(index) {
|
|
5180
|
+
this.patch((node) => {
|
|
5181
|
+
const stage = node;
|
|
5182
|
+
stage.stageSteps?.splice(index, 1);
|
|
5183
|
+
if (stage.stageSteps?.length === 0) {
|
|
5184
|
+
delete stage.stageSteps;
|
|
5185
|
+
}
|
|
5186
|
+
});
|
|
5187
|
+
}
|
|
5188
|
+
/** Sposta lo step nell'ordine d'**esame**: non e' un ordine di esecuzione (§5.13). */
|
|
5189
|
+
moveStep(index, direction) {
|
|
5190
|
+
const target = index + direction;
|
|
5191
|
+
if (target < 0 || target >= this.steps().length) {
|
|
5192
|
+
return;
|
|
5193
|
+
}
|
|
5194
|
+
this.patch((node) => {
|
|
5195
|
+
const steps = node.stageSteps;
|
|
5196
|
+
if (!steps) {
|
|
5197
|
+
return;
|
|
5198
|
+
}
|
|
5199
|
+
const [moved] = steps.splice(index, 1);
|
|
5200
|
+
steps.splice(target, 0, moved);
|
|
5201
|
+
});
|
|
5202
|
+
}
|
|
5203
|
+
patchStep(index, mutate) {
|
|
5204
|
+
this.patch((node) => {
|
|
5205
|
+
const step = node.stageSteps?.[index];
|
|
5206
|
+
if (step) {
|
|
5207
|
+
mutate(step);
|
|
5208
|
+
}
|
|
5209
|
+
});
|
|
5210
|
+
}
|
|
5211
|
+
setStepLabel(index, label) {
|
|
5212
|
+
this.patchStep(index, (step) => {
|
|
5213
|
+
step.label = label || undefined;
|
|
5214
|
+
if (!step.name && label) {
|
|
5215
|
+
step.name = slugifyFlowName(label);
|
|
5216
|
+
}
|
|
5217
|
+
});
|
|
5218
|
+
}
|
|
5219
|
+
setStepName(index, name) {
|
|
5220
|
+
this.patchStep(index, (step) => {
|
|
5221
|
+
step.name = name || undefined;
|
|
5222
|
+
});
|
|
5223
|
+
}
|
|
5224
|
+
setStepDescription(index, description) {
|
|
5225
|
+
this.patchStep(index, (step) => {
|
|
5226
|
+
step.description = description || undefined;
|
|
5227
|
+
});
|
|
5228
|
+
}
|
|
5229
|
+
/**
|
|
5230
|
+
* Cambiare tipo cambia cosa lo step pretende: gli assegnatari non hanno senso su uno step in
|
|
5231
|
+
* background, e `actionName` non ne ha su uno assegnato. I campi che il nuovo tipo non
|
|
5232
|
+
* prevede si rimuovono, invece di restare nel documento a dire una cosa che non vale piu'.
|
|
5233
|
+
*/
|
|
5234
|
+
setStepType(index, actionType) {
|
|
5235
|
+
const requiresActionName = this.dictionaries.stageStepRequiresActionName(actionType);
|
|
5236
|
+
const requiresAssignees = this.dictionaries.stageStepRequiresAssignees(actionType);
|
|
5237
|
+
this.patchStep(index, (step) => {
|
|
5238
|
+
step.actionType = actionType || undefined;
|
|
5239
|
+
if (!requiresActionName) {
|
|
5240
|
+
delete step.actionName;
|
|
5241
|
+
}
|
|
5242
|
+
if (!requiresAssignees) {
|
|
5243
|
+
delete step.assignees;
|
|
5244
|
+
delete step.requiresMultiMemberApproval;
|
|
5245
|
+
}
|
|
5246
|
+
else {
|
|
5247
|
+
step.assignees ??= [{}];
|
|
5248
|
+
}
|
|
5249
|
+
});
|
|
5250
|
+
}
|
|
5251
|
+
setStepActionName(index, actionName) {
|
|
5252
|
+
this.patchStep(index, (step) => {
|
|
5253
|
+
step.actionName = actionName || undefined;
|
|
5254
|
+
});
|
|
5255
|
+
}
|
|
5256
|
+
setMultiMemberApproval(index, required) {
|
|
5257
|
+
this.patchStep(index, (step) => {
|
|
5258
|
+
// Il modello lo porta come stringa: `"1"` oppure `"0"` (§5.13).
|
|
5259
|
+
step.requiresMultiMemberApproval = required ? '1' : '0';
|
|
5260
|
+
});
|
|
5261
|
+
}
|
|
5262
|
+
isMultiMemberApproval(step) {
|
|
5263
|
+
return step.requiresMultiMemberApproval === '1';
|
|
5264
|
+
}
|
|
5265
|
+
setSimulateStep(index, simulate) {
|
|
5266
|
+
this.patchStep(index, (step) => {
|
|
5267
|
+
if (simulate) {
|
|
5268
|
+
step.debugSimulateStep = true;
|
|
5269
|
+
}
|
|
5270
|
+
else {
|
|
5271
|
+
delete step.debugSimulateStep;
|
|
5272
|
+
delete step.outputConfigParams;
|
|
5273
|
+
}
|
|
5274
|
+
});
|
|
5275
|
+
}
|
|
5276
|
+
// -------------------------------------------------------------------------
|
|
5277
|
+
// Assegnatari
|
|
5278
|
+
// -------------------------------------------------------------------------
|
|
5279
|
+
assigneesOf(step) {
|
|
5280
|
+
return step.assignees ?? [];
|
|
5281
|
+
}
|
|
5282
|
+
addAssignee(index) {
|
|
5283
|
+
this.patchStep(index, (step) => {
|
|
5284
|
+
step.assignees ??= [];
|
|
5285
|
+
step.assignees.push({});
|
|
5286
|
+
});
|
|
5287
|
+
}
|
|
5288
|
+
removeAssignee(stepIndex, assigneeIndex) {
|
|
5289
|
+
this.patchStep(stepIndex, (step) => {
|
|
5290
|
+
step.assignees?.splice(assigneeIndex, 1);
|
|
5291
|
+
if (step.assignees?.length === 0) {
|
|
5292
|
+
delete step.assignees;
|
|
5293
|
+
}
|
|
5294
|
+
});
|
|
5295
|
+
}
|
|
5296
|
+
setAssigneeType(stepIndex, assigneeIndex, assigneeType) {
|
|
5297
|
+
this.patchStep(stepIndex, (step) => {
|
|
5298
|
+
const assignee = step.assignees?.[assigneeIndex];
|
|
5299
|
+
if (assignee) {
|
|
5300
|
+
assignee.assigneeType = assigneeType || undefined;
|
|
5301
|
+
}
|
|
5302
|
+
});
|
|
5303
|
+
}
|
|
5304
|
+
setAssigneeValue(stepIndex, assigneeIndex, value) {
|
|
5305
|
+
this.patchStep(stepIndex, (step) => {
|
|
5306
|
+
const assignee = step.assignees?.[assigneeIndex];
|
|
5307
|
+
if (assignee) {
|
|
5308
|
+
assignee.assignee = value;
|
|
5309
|
+
}
|
|
5310
|
+
});
|
|
5311
|
+
}
|
|
5312
|
+
/** Assegnatario senza tipo o senza valore: e' `STAGE_STEP_ASSIGNEE_INVALID`. */
|
|
5313
|
+
isAssigneeIncomplete(assignee) {
|
|
5314
|
+
return !assignee.assigneeType || !assignee.assignee;
|
|
5315
|
+
}
|
|
5316
|
+
// -------------------------------------------------------------------------
|
|
5317
|
+
// Condizioni ed evaluation flow
|
|
5318
|
+
// -------------------------------------------------------------------------
|
|
5319
|
+
/**
|
|
5320
|
+
* Le condizioni di uno step sono condizioni come le altre (§4.3), ma il modello porta solo
|
|
5321
|
+
* la lista: `conditionLogic` e `formula` non esistono e non vanno scritti.
|
|
5322
|
+
*/
|
|
5323
|
+
onEntryConditionsChanged(index, mutate) {
|
|
5324
|
+
this.applyConditions(index, 'entryConditions', mutate);
|
|
5325
|
+
}
|
|
5326
|
+
onExitConditionsChanged(index, mutate) {
|
|
5327
|
+
this.applyConditions(index, 'exitConditions', mutate);
|
|
5328
|
+
}
|
|
5329
|
+
applyConditions(index, field, mutate) {
|
|
5330
|
+
this.patchStep(index, (step) => {
|
|
5331
|
+
const holder = { conditions: step[field] ?? [] };
|
|
5332
|
+
mutate(holder);
|
|
5333
|
+
const conditions = holder.conditions ?? [];
|
|
5334
|
+
if (conditions.length) {
|
|
5335
|
+
step[field] = conditions;
|
|
5336
|
+
}
|
|
5337
|
+
else {
|
|
5338
|
+
// Lista vuota omessa, non scritta come `[]` (§2).
|
|
5339
|
+
delete step[field];
|
|
5340
|
+
}
|
|
5341
|
+
});
|
|
5342
|
+
}
|
|
5343
|
+
setEntryActionName(index, actionName) {
|
|
5344
|
+
this.patchStep(index, (step) => {
|
|
5345
|
+
if (actionName) {
|
|
5346
|
+
step.entryActionName = actionName;
|
|
5347
|
+
// Il tipo e' implicito: la condizione la decide un evaluation flow (§5.13).
|
|
5348
|
+
step.entryActionType = 'EvaluationFlow';
|
|
5349
|
+
}
|
|
5350
|
+
else {
|
|
5351
|
+
delete step.entryActionName;
|
|
5352
|
+
delete step.entryActionType;
|
|
5353
|
+
}
|
|
5354
|
+
});
|
|
5355
|
+
}
|
|
5356
|
+
setExitActionName(index, actionName) {
|
|
5357
|
+
this.patchStep(index, (step) => {
|
|
5358
|
+
if (actionName) {
|
|
5359
|
+
step.exitActionName = actionName;
|
|
5360
|
+
step.exitActionType = 'EvaluationFlow';
|
|
5361
|
+
}
|
|
5362
|
+
else {
|
|
5363
|
+
delete step.exitActionName;
|
|
5364
|
+
delete step.exitActionType;
|
|
5365
|
+
}
|
|
5366
|
+
});
|
|
5367
|
+
}
|
|
5368
|
+
// -------------------------------------------------------------------------
|
|
5369
|
+
// Parametri
|
|
5370
|
+
// -------------------------------------------------------------------------
|
|
5371
|
+
onParametersChanged(index, mutate) {
|
|
5372
|
+
this.patchStep(index, (step) => mutate(step));
|
|
5373
|
+
}
|
|
5374
|
+
/** Il ramo del rifiuto e' disegnato: senza, un rifiuto fa fallire l'interview (§5.13). */
|
|
5375
|
+
hasRejectionBranch = computed(() => !!this.stage().faultConnector, ...(ngDevMode ? [{ debugName: "hasRejectionBranch" }] : []));
|
|
5376
|
+
/** C'e' almeno uno step il cui rifiuto e' un esito previsto. */
|
|
5377
|
+
hasApprovalStep = computed(() => this.steps().some((step) => this.supportsRejection(step)), ...(ngDevMode ? [{ debugName: "hasApprovalStep" }] : []));
|
|
5378
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: OrchestratedStageInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5379
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: OrchestratedStageInspectorComponent, isStandalone: true, selector: "fb-orchestrated-stage-inspector", usesInheritance: true, ngImport: i0, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Step dello stage</legend>\r\n <p class=\"fb-section__note\">\r\n Gli step <strong>non sono una sequenza</strong>: parte quello le cui condizioni d\u2019ingresso sono vere, e\r\n l\u2019ordine qui sotto e\u2019 solo l\u2019ordine in cui vengono esaminati.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n <!-- `stepIndex` esplicito: dentro l'elenco degli assegnatari `$index` e' quello dell'assegnatario. -->\r\n @for (step of steps(); track $index; let stepIndex = $index, isFirst = $first, isLast = $last) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <!-- Titolo, non indice: gli step non sono numerati perche' non sono una sequenza. -->\r\n <span class=\"fb-list__title\">{{ step.label || step.name || '\u2014' }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Esamina prima\"\r\n title=\"Cambia l\u2019ordine d\u2019esame, non l\u2019ordine di esecuzione\"\r\n [disabled]=\"isFirst\"\r\n (click)=\"moveStep(stepIndex, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Esamina dopo\"\r\n title=\"Cambia l\u2019ordine d\u2019esame, non l\u2019ordine di esecuzione\"\r\n [disabled]=\"isLast\"\r\n (click)=\"moveStep(stepIndex, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi lo step\"\r\n (click)=\"removeStep(stepIndex)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Etichetta</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"step.label || ''\"\r\n placeholder=\"Approva la pratica\"\r\n (input)=\"setStepLabel(stepIndex, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Nome tecnico</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [class.fb-input--invalid]=\"!!stepNameError(step)\"\r\n [value]=\"step.name || ''\"\r\n (input)=\"setStepName(stepIndex, $any($event.target).value)\"\r\n />\r\n @if (stepNameError(step)) {\r\n <p class=\"fb-field__error\">{{ stepNameError(step) }}</p>\r\n } @else {\r\n <p class=\"fb-field__hint\">\r\n Sta nello stesso spazio dei nomi di elementi e risorse. Gli output dello step sono\r\n referenziabili come <code>{{ step.name || 'NomeStep' }}.NomeOutput</code>.\r\n </p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo di step</label>\r\n <select\r\n class=\"fb-select\"\r\n [class.fb-input--invalid]=\"!step.actionType || isUnknownStepType(step)\"\r\n [fbValue]=\"step.actionType || ''\"\r\n (change)=\"setStepType(stepIndex, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (type of stepTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n @if (!step.actionType) {\r\n <p class=\"fb-field__error\">Senza tipo lo step non e\u2019 valido (STAGE_STEP_TYPE_MISSING).</p>\r\n } @else if (isUnknownStepType(step)) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ step.actionType }}\u00BB non e\u2019 un tipo di step di questo sistema (STAGE_STEP_TYPE_UNKNOWN).\r\n </p>\r\n } @else if (stepTypeDescription(step)) {\r\n <p class=\"fb-field__hint\">{{ stepTypeDescription(step) }}</p>\r\n }\r\n </div>\r\n\r\n @if (requiresActionName(step)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Flow da eseguire</label>\r\n <!--\r\n Una lista di candidati vuota significa \"non lo so\", non \"nessuno\": il campo resta\r\n scrivibile a mano invece di bloccare l'utente (\u00A77).\r\n -->\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [class.fb-input--invalid]=\"!step.actionName\"\r\n [value]=\"step.actionName || ''\"\r\n [attr.list]=\"flowListId()\"\r\n placeholder=\"Preparazione_Pratica\"\r\n (input)=\"setStepActionName(stepIndex, $any($event.target).value)\"\r\n />\r\n @if (!step.actionName) {\r\n <p class=\"fb-field__error\">\r\n Uno step in background esegue un flow: senza, e\u2019 STAGE_STEP_FLOW_MISSING.\r\n </p>\r\n } @else {\r\n <p class=\"fb-field__hint\">Il motore lo esegue subito, senza coinvolgere nessuno.</p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (requiresAssignees(step)) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Assegnatari</legend>\r\n <p class=\"fb-section__note\">\r\n Su questo step l\u2019interview si <strong>sospende</strong>: resta aperto un work item finche\u2019\r\n una persona non lo conclude.\r\n </p>\r\n <div class=\"fb-list\">\r\n @for (assignee of assigneesOf(step); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi l\u2019assegnatario\"\r\n (click)=\"removeAssignee(stepIndex, $index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"assignee.assigneeType || ''\"\r\n (change)=\"setAssigneeType(stepIndex, $index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (type of assigneeTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Chi</label>\r\n <fb-value-editor\r\n [value]=\"assignee.assignee\"\r\n label=\"Assegnatario\"\r\n dataType=\"String\"\r\n (valueChange)=\"setAssigneeValue(stepIndex, $index, $event)\"\r\n />\r\n </div>\r\n @if (isAssigneeIncomplete(assignee)) {\r\n <p class=\"fb-field__error\">Servono tipo e destinatario (STAGE_STEP_ASSIGNEE_INVALID).</p>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Senza assegnatari questo step non e\u2019 valido (STAGE_STEP_ASSIGNEES_MISSING).\r\n </p>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addAssignee(stepIndex)\">\r\n Aggiungi assegnatario\r\n </button>\r\n\r\n @if (supportsRejection(step)) {\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"isMultiMemberApproval(step)\"\r\n (change)=\"setMultiMemberApproval(stepIndex, $any($event.target).checked)\"\r\n />\r\n Serve l\u2019approvazione di tutti i membri\r\n </label>\r\n }\r\n </fieldset>\r\n }\r\n\r\n <!--\r\n Ingresso e uscita non sono simmetriche: se l'ingresso non si avvera lo step viene\r\n saltato, se l'uscita resta falsa lo stage va in stallo e l'esecuzione fallisce (\u00A75.13).\r\n -->\r\n <fb-condition-editor\r\n [holder]=\"conditionHolders()[stepIndex].entry\"\r\n title=\"Condizioni d\u2019ingresso (se lo step si applica)\"\r\n [allowLogic]=\"false\"\r\n [allowFormula]=\"false\"\r\n (changed)=\"onEntryConditionsChanged(stepIndex, $event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Se non si avverano, lo step viene <strong>saltato</strong> e lo stage prosegue.\r\n </p>\r\n\r\n <fb-condition-editor\r\n [holder]=\"conditionHolders()[stepIndex].exit\"\r\n title=\"Condizioni d\u2019uscita (quando lo step libera lo stage)\"\r\n [allowLogic]=\"false\"\r\n [allowFormula]=\"false\"\r\n (changed)=\"onExitConditionsChanged(stepIndex, $event)\"\r\n />\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Se restano false quando non c\u2019e\u2019 piu\u2019 niente in esecuzione, lo stage e\u2019 in stallo e\r\n l\u2019esecuzione <strong>fallisce</strong>.\r\n </p>\r\n\r\n @if (stepOutputInConditions(step)) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Una condizione referenzia l\u2019output dello step \u00AB{{ stepOutputInConditions(step) }}\u00BB: finche\u2019\r\n quello step non ha girato il riferimento e\u2019 irrisolvibile, e a runtime e\u2019 un errore. Fai\r\n scrivere quel risultato in una variabile (parametro di uscita \u2192 destinazione) e condiziona su\r\n quella.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Evaluation flow per l\u2019ingresso</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"step.entryActionName || ''\"\r\n [attr.list]=\"flowListId()\"\r\n placeholder=\"Valuta_Ingresso\"\r\n (input)=\"setEntryActionName(stepIndex, $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Deve restituire l\u2019output booleano <code>{{ conditionOutputName }}</code>: e\u2019 l\u2019unico che il\r\n runtime legge, dichiararne altri e\u2019 STAGE_ACTION_INVALID.\r\n </p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Evaluation flow per l\u2019uscita</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"step.exitActionName || ''\"\r\n [attr.list]=\"flowListId()\"\r\n placeholder=\"Valuta_Uscita\"\r\n (input)=\"setExitActionName(stepIndex, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <fb-parameter-editor\r\n [holder]=\"step\"\r\n inputTitle=\"Parametri dello step\"\r\n [showOutputs]=\"true\"\r\n outputTitle=\"Valori prodotti dallo step\"\r\n (changed)=\"onParametersChanged(stepIndex, $event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n La destinazione e\u2019 <strong>facoltativa</strong>: l\u2019output e\u2019 gi\u00E0 referenziabile come\r\n <code>{{ step.name || 'NomeStep' }}.NomeOutput</code>. Serve una variabile solo se un altro step\r\n deve condizionare su quel risultato.\r\n </p>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"hasSimulatedOutputs(step)\"\r\n (change)=\"setSimulateStep(stepIndex, $any($event.target).checked)\"\r\n />\r\n Simula lo step nella prova\r\n </label>\r\n @if (hasSimulatedOutputs(step)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Con la simulazione lo step non viene eseguito ne\u2019 assegnato: si usano gli output finti di\r\n <code>outputConfigParams</code>. Non memorizzarci dati personali.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Descrizione</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"step.description || ''\"\r\n (input)=\"setStepDescription(stepIndex, $any($event.target).value)\"\r\n ></textarea>\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Uno stage senza step non fa nulla ed e\u2019 un errore di validazione (STAGE_WITHOUT_STEPS).\r\n </p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addStep()\">Aggiungi step</button>\r\n\r\n <!-- I candidati proposti a ogni campo che vuole il nome di un flow. -->\r\n <datalist [id]=\"flowListId()\">\r\n @for (candidate of candidates(); track candidate.flowName) {\r\n <option [value]=\"candidate.flowName\">{{ candidate.label || candidate.flowName }}</option>\r\n }\r\n </datalist>\r\n</fieldset>\r\n\r\n@if (hasApprovalStep() && !hasRejectionBranch()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n C\u2019e\u2019 uno step di approvazione ma il ramo \u00ABStep rifiutato\u00BB non e\u2019 disegnato: senza, un rifiuto fa\r\n <strong>fallire</strong> l\u2019interview. Non e\u2019 un ramo di guasto, e\u2019 l\u2019esito previsto del rifiuto.\r\n </p>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Rami\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConditionEditorComponent, selector: "fb-condition-editor", inputs: ["holder", "title", "allowFormula", "allowLogic", "issuePath"], outputs: ["changed"] }, { kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason"], outputs: ["changed"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5380
|
+
}
|
|
5381
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: OrchestratedStageInspectorComponent, decorators: [{
|
|
5382
|
+
type: Component,
|
|
5383
|
+
args: [{ selector: 'fb-orchestrated-stage-inspector', standalone: true, imports: [
|
|
5384
|
+
ConditionEditorComponent,
|
|
5385
|
+
ConnectorEditorComponent,
|
|
5386
|
+
ParameterEditorComponent,
|
|
5387
|
+
ValueEditorComponent,
|
|
5388
|
+
SelectValueDirective,
|
|
5389
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Step dello stage</legend>\r\n <p class=\"fb-section__note\">\r\n Gli step <strong>non sono una sequenza</strong>: parte quello le cui condizioni d\u2019ingresso sono vere, e\r\n l\u2019ordine qui sotto e\u2019 solo l\u2019ordine in cui vengono esaminati.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n <!-- `stepIndex` esplicito: dentro l'elenco degli assegnatari `$index` e' quello dell'assegnatario. -->\r\n @for (step of steps(); track $index; let stepIndex = $index, isFirst = $first, isLast = $last) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <!-- Titolo, non indice: gli step non sono numerati perche' non sono una sequenza. -->\r\n <span class=\"fb-list__title\">{{ step.label || step.name || '\u2014' }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Esamina prima\"\r\n title=\"Cambia l\u2019ordine d\u2019esame, non l\u2019ordine di esecuzione\"\r\n [disabled]=\"isFirst\"\r\n (click)=\"moveStep(stepIndex, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Esamina dopo\"\r\n title=\"Cambia l\u2019ordine d\u2019esame, non l\u2019ordine di esecuzione\"\r\n [disabled]=\"isLast\"\r\n (click)=\"moveStep(stepIndex, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi lo step\"\r\n (click)=\"removeStep(stepIndex)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Etichetta</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"step.label || ''\"\r\n placeholder=\"Approva la pratica\"\r\n (input)=\"setStepLabel(stepIndex, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Nome tecnico</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [class.fb-input--invalid]=\"!!stepNameError(step)\"\r\n [value]=\"step.name || ''\"\r\n (input)=\"setStepName(stepIndex, $any($event.target).value)\"\r\n />\r\n @if (stepNameError(step)) {\r\n <p class=\"fb-field__error\">{{ stepNameError(step) }}</p>\r\n } @else {\r\n <p class=\"fb-field__hint\">\r\n Sta nello stesso spazio dei nomi di elementi e risorse. Gli output dello step sono\r\n referenziabili come <code>{{ step.name || 'NomeStep' }}.NomeOutput</code>.\r\n </p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo di step</label>\r\n <select\r\n class=\"fb-select\"\r\n [class.fb-input--invalid]=\"!step.actionType || isUnknownStepType(step)\"\r\n [fbValue]=\"step.actionType || ''\"\r\n (change)=\"setStepType(stepIndex, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (type of stepTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n @if (!step.actionType) {\r\n <p class=\"fb-field__error\">Senza tipo lo step non e\u2019 valido (STAGE_STEP_TYPE_MISSING).</p>\r\n } @else if (isUnknownStepType(step)) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ step.actionType }}\u00BB non e\u2019 un tipo di step di questo sistema (STAGE_STEP_TYPE_UNKNOWN).\r\n </p>\r\n } @else if (stepTypeDescription(step)) {\r\n <p class=\"fb-field__hint\">{{ stepTypeDescription(step) }}</p>\r\n }\r\n </div>\r\n\r\n @if (requiresActionName(step)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Flow da eseguire</label>\r\n <!--\r\n Una lista di candidati vuota significa \"non lo so\", non \"nessuno\": il campo resta\r\n scrivibile a mano invece di bloccare l'utente (\u00A77).\r\n -->\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [class.fb-input--invalid]=\"!step.actionName\"\r\n [value]=\"step.actionName || ''\"\r\n [attr.list]=\"flowListId()\"\r\n placeholder=\"Preparazione_Pratica\"\r\n (input)=\"setStepActionName(stepIndex, $any($event.target).value)\"\r\n />\r\n @if (!step.actionName) {\r\n <p class=\"fb-field__error\">\r\n Uno step in background esegue un flow: senza, e\u2019 STAGE_STEP_FLOW_MISSING.\r\n </p>\r\n } @else {\r\n <p class=\"fb-field__hint\">Il motore lo esegue subito, senza coinvolgere nessuno.</p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (requiresAssignees(step)) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Assegnatari</legend>\r\n <p class=\"fb-section__note\">\r\n Su questo step l\u2019interview si <strong>sospende</strong>: resta aperto un work item finche\u2019\r\n una persona non lo conclude.\r\n </p>\r\n <div class=\"fb-list\">\r\n @for (assignee of assigneesOf(step); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi l\u2019assegnatario\"\r\n (click)=\"removeAssignee(stepIndex, $index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"assignee.assigneeType || ''\"\r\n (change)=\"setAssigneeType(stepIndex, $index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (type of assigneeTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Chi</label>\r\n <fb-value-editor\r\n [value]=\"assignee.assignee\"\r\n label=\"Assegnatario\"\r\n dataType=\"String\"\r\n (valueChange)=\"setAssigneeValue(stepIndex, $index, $event)\"\r\n />\r\n </div>\r\n @if (isAssigneeIncomplete(assignee)) {\r\n <p class=\"fb-field__error\">Servono tipo e destinatario (STAGE_STEP_ASSIGNEE_INVALID).</p>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Senza assegnatari questo step non e\u2019 valido (STAGE_STEP_ASSIGNEES_MISSING).\r\n </p>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addAssignee(stepIndex)\">\r\n Aggiungi assegnatario\r\n </button>\r\n\r\n @if (supportsRejection(step)) {\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"isMultiMemberApproval(step)\"\r\n (change)=\"setMultiMemberApproval(stepIndex, $any($event.target).checked)\"\r\n />\r\n Serve l\u2019approvazione di tutti i membri\r\n </label>\r\n }\r\n </fieldset>\r\n }\r\n\r\n <!--\r\n Ingresso e uscita non sono simmetriche: se l'ingresso non si avvera lo step viene\r\n saltato, se l'uscita resta falsa lo stage va in stallo e l'esecuzione fallisce (\u00A75.13).\r\n -->\r\n <fb-condition-editor\r\n [holder]=\"conditionHolders()[stepIndex].entry\"\r\n title=\"Condizioni d\u2019ingresso (se lo step si applica)\"\r\n [allowLogic]=\"false\"\r\n [allowFormula]=\"false\"\r\n (changed)=\"onEntryConditionsChanged(stepIndex, $event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Se non si avverano, lo step viene <strong>saltato</strong> e lo stage prosegue.\r\n </p>\r\n\r\n <fb-condition-editor\r\n [holder]=\"conditionHolders()[stepIndex].exit\"\r\n title=\"Condizioni d\u2019uscita (quando lo step libera lo stage)\"\r\n [allowLogic]=\"false\"\r\n [allowFormula]=\"false\"\r\n (changed)=\"onExitConditionsChanged(stepIndex, $event)\"\r\n />\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Se restano false quando non c\u2019e\u2019 piu\u2019 niente in esecuzione, lo stage e\u2019 in stallo e\r\n l\u2019esecuzione <strong>fallisce</strong>.\r\n </p>\r\n\r\n @if (stepOutputInConditions(step)) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Una condizione referenzia l\u2019output dello step \u00AB{{ stepOutputInConditions(step) }}\u00BB: finche\u2019\r\n quello step non ha girato il riferimento e\u2019 irrisolvibile, e a runtime e\u2019 un errore. Fai\r\n scrivere quel risultato in una variabile (parametro di uscita \u2192 destinazione) e condiziona su\r\n quella.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Evaluation flow per l\u2019ingresso</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"step.entryActionName || ''\"\r\n [attr.list]=\"flowListId()\"\r\n placeholder=\"Valuta_Ingresso\"\r\n (input)=\"setEntryActionName(stepIndex, $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Deve restituire l\u2019output booleano <code>{{ conditionOutputName }}</code>: e\u2019 l\u2019unico che il\r\n runtime legge, dichiararne altri e\u2019 STAGE_ACTION_INVALID.\r\n </p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Evaluation flow per l\u2019uscita</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"step.exitActionName || ''\"\r\n [attr.list]=\"flowListId()\"\r\n placeholder=\"Valuta_Uscita\"\r\n (input)=\"setExitActionName(stepIndex, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <fb-parameter-editor\r\n [holder]=\"step\"\r\n inputTitle=\"Parametri dello step\"\r\n [showOutputs]=\"true\"\r\n outputTitle=\"Valori prodotti dallo step\"\r\n (changed)=\"onParametersChanged(stepIndex, $event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n La destinazione e\u2019 <strong>facoltativa</strong>: l\u2019output e\u2019 gi\u00E0 referenziabile come\r\n <code>{{ step.name || 'NomeStep' }}.NomeOutput</code>. Serve una variabile solo se un altro step\r\n deve condizionare su quel risultato.\r\n </p>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"hasSimulatedOutputs(step)\"\r\n (change)=\"setSimulateStep(stepIndex, $any($event.target).checked)\"\r\n />\r\n Simula lo step nella prova\r\n </label>\r\n @if (hasSimulatedOutputs(step)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Con la simulazione lo step non viene eseguito ne\u2019 assegnato: si usano gli output finti di\r\n <code>outputConfigParams</code>. Non memorizzarci dati personali.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Descrizione</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"step.description || ''\"\r\n (input)=\"setStepDescription(stepIndex, $any($event.target).value)\"\r\n ></textarea>\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Uno stage senza step non fa nulla ed e\u2019 un errore di validazione (STAGE_WITHOUT_STEPS).\r\n </p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addStep()\">Aggiungi step</button>\r\n\r\n <!-- I candidati proposti a ogni campo che vuole il nome di un flow. -->\r\n <datalist [id]=\"flowListId()\">\r\n @for (candidate of candidates(); track candidate.flowName) {\r\n <option [value]=\"candidate.flowName\">{{ candidate.label || candidate.flowName }}</option>\r\n }\r\n </datalist>\r\n</fieldset>\r\n\r\n@if (hasApprovalStep() && !hasRejectionBranch()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n C\u2019e\u2019 uno step di approvazione ma il ramo \u00ABStep rifiutato\u00BB non e\u2019 disegnato: senza, un rifiuto fa\r\n <strong>fallire</strong> l\u2019interview. Non e\u2019 un ramo di guasto, e\u2019 l\u2019esito previsto del rifiuto.\r\n </p>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Rami\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n" }]
|
|
5390
|
+
}], ctorParameters: () => [] });
|
|
5391
|
+
|
|
4650
5392
|
/**
|
|
4651
5393
|
* Get Records — FRONTEND.md §5.6.
|
|
4652
5394
|
*
|
|
@@ -4835,7 +5577,7 @@ class RecordLookupInspectorComponent extends NodeInspectorBase {
|
|
|
4835
5577
|
/** `relatedRecords` e' modellato ma non tradotto in query: se c'e', si avvisa (§5.6). */
|
|
4836
5578
|
hasRelatedRecords = computed(() => (this.lookup().relatedRecords?.length ?? 0) > 0, ...(ngDevMode ? [{ debugName: "hasRelatedRecords" }] : []));
|
|
4837
5579
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: RecordLookupInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4838
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: RecordLookupInspectorComponent, isStandalone: true, selector: "fb-record-lookup-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Oggetto</label>\r\n @if (hasObjectCatalog()) {\r\n <select class=\"fb-select\" [fbValue]=\"lookup().object || ''\" (change)=\"setObject($any($event.target).value)\">\r\n <option value=\"\">\u2014 scegli un oggetto \u2014</option>\r\n @for (object of objectOptions(); track object.name) {\r\n <option [value]=\"object.name\">{{ object.label || object.name }}</option>\r\n }\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"lookup().object || ''\"\r\n placeholder=\"Nome dell\u2019entita\u2019\"\r\n (input)=\"setObject($any($event.target).value)\"\r\n />\r\n }\r\n</div>\r\n\r\n<fb-record-filter-editor\r\n [holder]=\"lookup()\"\r\n [object]=\"lookup().object\"\r\n title=\"Quali record leggere\"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"true\"\r\n [supportsFormula]=\"true\"\r\n emptyWarning=\"Senza filtri legge tutti i record dell\u2019oggetto.\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n/>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Quanti e in che ordine</legend>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"lookup().getFirstRecordOnly === true\"\r\n (change)=\"setFirstOnly($any($event.target).checked)\"\r\n />\r\n Solo il primo record\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n @if (returnsCollection()) {\r\n Il risultato e\u2019 una <strong>collection</strong>: puo\u2019 essere iterata da un Loop.\r\n } @else {\r\n Il risultato e\u2019 un <strong>record singolo</strong>: non e\u2019 iterabile da un Loop.\r\n }\r\n </p>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Ordina per</label>\r\n <select class=\"fb-select\" [fbValue]=\"lookup().sortField || ''\" (change)=\"setSortField($any($event.target).value)\">\r\n <option value=\"\">\u2014 nessun ordinamento \u2014</option>\r\n @for (field of sortableOptions(); track field.name) {\r\n <option [value]=\"field.name\">{{ field.label || field.name }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n @if (lookup().sortField) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Direzione</label>\r\n <select class=\"fb-select\" [fbValue]=\"lookup().sortOrder || ''\" (change)=\"setSortOrder($any($event.target).value)\">\r\n @for (order of sortOrders(); track order.value) {\r\n <option [value]=\"order.value\">{{ order.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n }\r\n\r\n @if (returnsCollection()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Numero massimo di record</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"lookup().limit ?? ''\"\r\n (input)=\"setLimit($any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n</fieldset>\r\n\r\n@if (fieldOptions().length) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Campi da leggere</legend>\r\n <p class=\"fb-section__note\">Nessuna selezione = tutti i campi disponibili.</p>\r\n <div class=\"fb-fields-grid\">\r\n @for (field of fieldOptions(); track field.name) {\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"isQueried(field.name)\"\r\n (change)=\"toggleQueriedField(field.name, $any($event.target).checked)\"\r\n />\r\n {{ field.label || field.name }}\r\n </label>\r\n }\r\n </div>\r\n </fieldset>\r\n}\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Dove finisce il risultato</legend>\r\n\r\n @if (hasOutputConflict()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Sono dichiarati insieme l\u2019output automatico e una destinazione esplicita: e\u2019 un conflitto\r\n (OUTPUT_CONFIGURATION_CONFLICT). Scegli una sola modalita\u2019 qui sotto.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"radio\"\r\n name=\"output-mode\"\r\n [checked]=\"outputMode() === 'automatic'\"\r\n (change)=\"setOutputMode('automatic')\"\r\n />\r\n Output automatico <em>(consigliato)</em>\r\n </label>\r\n @if (outputMode() === 'automatic') {\r\n <p class=\"fb-field__hint\">\r\n Il risultato si referenzia con il nome dell\u2019elemento: <code>{{ name() }}</code>,\r\n <code>{{ name() }}.Campo</code>. Non serve dichiarare nessuna variabile.\r\n </p>\r\n }\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"radio\"\r\n name=\"output-mode\"\r\n [checked]=\"outputMode() === 'variable'\"\r\n (change)=\"setOutputMode('variable')\"\r\n />\r\n In una variabile\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"radio\"\r\n name=\"output-mode\"\r\n [checked]=\"outputMode() === 'assignments'\"\r\n (change)=\"setOutputMode('assignments')\"\r\n />\r\n Campo per campo\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"radio\"\r\n name=\"output-mode\"\r\n [checked]=\"outputMode() === 'discard'\"\r\n (change)=\"setOutputMode('discard')\"\r\n />\r\n Scarta il risultato\r\n </label>\r\n </div>\r\n\r\n @if (outputMode() === 'variable') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Variabile di destinazione</label>\r\n <fb-reference-picker\r\n [value]=\"lookup().outputReference\"\r\n [writableOnly]=\"true\"\r\n [isCollection]=\"returnsCollection()\"\r\n [objectType]=\"lookup().object\"\r\n placeholder=\"Scegli una variabile\"\r\n (valueChange)=\"setOutputReference($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (outputMode() === 'assignments') {\r\n <div class=\"fb-list\">\r\n @for (assignment of outputAssignments(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeOutputAssignment($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo del record</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"assignment.field || ''\"\r\n (change)=\"setOutputAssignmentField($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (field of fieldOptions(); track field.name) {\r\n <option [value]=\"field.name\">{{ field.label || field.name }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Assegna a</label>\r\n <fb-reference-picker\r\n [value]=\"assignment.assignToReference\"\r\n [writableOnly]=\"true\"\r\n placeholder=\"Scegli una variabile\"\r\n (valueChange)=\"setOutputAssignmentTarget($index, $event)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addOutputAssignment()\">Aggiungi campo</button>\r\n }\r\n\r\n @if (outputMode() === 'discard') {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n L\u2019elemento interroga il database e butta via il risultato (LOOKUP_RESULT_DISCARDED).\r\n </p>\r\n }\r\n</fieldset>\r\n\r\n@if (hasRelatedRecords()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questo elemento dichiara <code>relatedRecords</code>: il campo e\u2019 modellato ma non viene tradotto in\r\n query, quindi non ha effetto.\r\n </p>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: RecordFilterEditorComponent, selector: "fb-record-filter-editor", inputs: ["holder", "object", "title", "usage", "supportsLogic", "supportsFormula", "emptyWarning", "emptyWarningSeverity"], outputs: ["changed"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "
|
|
5580
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: RecordLookupInspectorComponent, isStandalone: true, selector: "fb-record-lookup-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Oggetto</label>\r\n @if (hasObjectCatalog()) {\r\n <select class=\"fb-select\" [fbValue]=\"lookup().object || ''\" (change)=\"setObject($any($event.target).value)\">\r\n <option value=\"\">\u2014 scegli un oggetto \u2014</option>\r\n @for (object of objectOptions(); track object.name) {\r\n <option [value]=\"object.name\">{{ object.label || object.name }}</option>\r\n }\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"lookup().object || ''\"\r\n placeholder=\"Nome dell\u2019entita\u2019\"\r\n (input)=\"setObject($any($event.target).value)\"\r\n />\r\n }\r\n</div>\r\n\r\n<fb-record-filter-editor\r\n [holder]=\"lookup()\"\r\n [object]=\"lookup().object\"\r\n title=\"Quali record leggere\"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"true\"\r\n [supportsFormula]=\"true\"\r\n emptyWarning=\"Senza filtri legge tutti i record dell\u2019oggetto.\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n/>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Quanti e in che ordine</legend>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"lookup().getFirstRecordOnly === true\"\r\n (change)=\"setFirstOnly($any($event.target).checked)\"\r\n />\r\n Solo il primo record\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n @if (returnsCollection()) {\r\n Il risultato e\u2019 una <strong>collection</strong>: puo\u2019 essere iterata da un Loop.\r\n } @else {\r\n Il risultato e\u2019 un <strong>record singolo</strong>: non e\u2019 iterabile da un Loop.\r\n }\r\n </p>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Ordina per</label>\r\n <select class=\"fb-select\" [fbValue]=\"lookup().sortField || ''\" (change)=\"setSortField($any($event.target).value)\">\r\n <option value=\"\">\u2014 nessun ordinamento \u2014</option>\r\n @for (field of sortableOptions(); track field.name) {\r\n <option [value]=\"field.name\">{{ field.label || field.name }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n @if (lookup().sortField) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Direzione</label>\r\n <select class=\"fb-select\" [fbValue]=\"lookup().sortOrder || ''\" (change)=\"setSortOrder($any($event.target).value)\">\r\n @for (order of sortOrders(); track order.value) {\r\n <option [value]=\"order.value\">{{ order.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n }\r\n\r\n @if (returnsCollection()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Numero massimo di record</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"lookup().limit ?? ''\"\r\n (input)=\"setLimit($any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n</fieldset>\r\n\r\n@if (fieldOptions().length) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Campi da leggere</legend>\r\n <p class=\"fb-section__note\">Nessuna selezione = tutti i campi disponibili.</p>\r\n <div class=\"fb-fields-grid\">\r\n @for (field of fieldOptions(); track field.name) {\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"isQueried(field.name)\"\r\n (change)=\"toggleQueriedField(field.name, $any($event.target).checked)\"\r\n />\r\n {{ field.label || field.name }}\r\n </label>\r\n }\r\n </div>\r\n </fieldset>\r\n}\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Dove finisce il risultato</legend>\r\n\r\n @if (hasOutputConflict()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Sono dichiarati insieme l\u2019output automatico e una destinazione esplicita: e\u2019 un conflitto\r\n (OUTPUT_CONFIGURATION_CONFLICT). Scegli una sola modalita\u2019 qui sotto.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"radio\"\r\n name=\"output-mode\"\r\n [checked]=\"outputMode() === 'automatic'\"\r\n (change)=\"setOutputMode('automatic')\"\r\n />\r\n Output automatico <em>(consigliato)</em>\r\n </label>\r\n @if (outputMode() === 'automatic') {\r\n <p class=\"fb-field__hint\">\r\n Il risultato si referenzia con il nome dell\u2019elemento: <code>{{ name() }}</code>,\r\n <code>{{ name() }}.Campo</code>. Non serve dichiarare nessuna variabile.\r\n </p>\r\n }\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"radio\"\r\n name=\"output-mode\"\r\n [checked]=\"outputMode() === 'variable'\"\r\n (change)=\"setOutputMode('variable')\"\r\n />\r\n In una variabile\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"radio\"\r\n name=\"output-mode\"\r\n [checked]=\"outputMode() === 'assignments'\"\r\n (change)=\"setOutputMode('assignments')\"\r\n />\r\n Campo per campo\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"radio\"\r\n name=\"output-mode\"\r\n [checked]=\"outputMode() === 'discard'\"\r\n (change)=\"setOutputMode('discard')\"\r\n />\r\n Scarta il risultato\r\n </label>\r\n </div>\r\n\r\n @if (outputMode() === 'variable') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Variabile di destinazione</label>\r\n <fb-reference-picker\r\n [value]=\"lookup().outputReference\"\r\n [writableOnly]=\"true\"\r\n [isCollection]=\"returnsCollection()\"\r\n [objectType]=\"lookup().object\"\r\n placeholder=\"Scegli una variabile\"\r\n (valueChange)=\"setOutputReference($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (outputMode() === 'assignments') {\r\n <div class=\"fb-list\">\r\n @for (assignment of outputAssignments(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeOutputAssignment($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo del record</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"assignment.field || ''\"\r\n (change)=\"setOutputAssignmentField($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (field of fieldOptions(); track field.name) {\r\n <option [value]=\"field.name\">{{ field.label || field.name }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Assegna a</label>\r\n <fb-reference-picker\r\n [value]=\"assignment.assignToReference\"\r\n [writableOnly]=\"true\"\r\n placeholder=\"Scegli una variabile\"\r\n (valueChange)=\"setOutputAssignmentTarget($index, $event)\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addOutputAssignment()\">Aggiungi campo</button>\r\n }\r\n\r\n @if (outputMode() === 'discard') {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n L\u2019elemento interroga il database e butta via il risultato (LOOKUP_RESULT_DISCARDED).\r\n </p>\r\n }\r\n</fieldset>\r\n\r\n@if (hasRelatedRecords()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questo elemento dichiara <code>relatedRecords</code>: il campo e\u2019 modellato ma non viene tradotto in\r\n query, quindi non ha effetto.\r\n </p>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: RecordFilterEditorComponent, selector: "fb-record-filter-editor", inputs: ["holder", "object", "title", "usage", "supportsLogic", "supportsFormula", "emptyWarning", "emptyWarningSeverity"], outputs: ["changed"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4839
5581
|
}
|
|
4840
5582
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: RecordLookupInspectorComponent, decorators: [{
|
|
4841
5583
|
type: Component,
|
|
@@ -4854,11 +5596,11 @@ class RecordRollbackInspectorComponent extends NodeInspectorBase {
|
|
|
4854
5596
|
/** Fuori da uno screen flow non c'e' una transazione aperta da annullare. */
|
|
4855
5597
|
isScreenFlow = computed(() => this.store.document().processType === 'Screen', ...(ngDevMode ? [{ debugName: "isScreenFlow" }] : []));
|
|
4856
5598
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: RecordRollbackInspectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
4857
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: RecordRollbackInspectorComponent, isStandalone: true, selector: "fb-record-rollback-inspector", usesInheritance: true, ngImport: i0, template: "<p class=\"fb-callout\">\n Annulla le modifiche ai record ancora pendenti. Non ha altri campi da configurare.\n</p>\n\n@if (!isScreenFlow()) {\n <p class=\"fb-callout fb-callout--warn\">\n Questo elemento ha senso in uno screen flow, dove esiste una transazione aperta fra due schermate. In un\n flow \u00AB{{ store.document().processType }}\u00BB non c\u2019e\u2019 nulla da annullare.\n </p>\n}\n\n<fb-connector-editor\n [nodeName]=\"name()\"\n [node]=\"node()\"\n [outlets]=\"outlets()\"\n (connectorChanged)=\"onConnectorChanged($event)\"\n/>\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5599
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: RecordRollbackInspectorComponent, isStandalone: true, selector: "fb-record-rollback-inspector", usesInheritance: true, ngImport: i0, template: "<p class=\"fb-callout\">\r\n Annulla le modifiche ai record ancora pendenti. Non ha altri campi da configurare.\r\n</p>\r\n\r\n@if (!isScreenFlow()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questo elemento ha senso in uno screen flow, dove esiste una transazione aperta fra due schermate. In un\r\n flow \u00AB{{ store.document().processType }}\u00BB non c\u2019e\u2019 nulla da annullare.\r\n </p>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4858
5600
|
}
|
|
4859
5601
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: RecordRollbackInspectorComponent, decorators: [{
|
|
4860
5602
|
type: Component,
|
|
4861
|
-
args: [{ selector: 'fb-record-rollback-inspector', standalone: true, imports: [ConnectorEditorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<p class=\"fb-callout\">\n Annulla le modifiche ai record ancora pendenti. Non ha altri campi da configurare.\n</p>\n\n@if (!isScreenFlow()) {\n <p class=\"fb-callout fb-callout--warn\">\n Questo elemento ha senso in uno screen flow, dove esiste una transazione aperta fra due schermate. In un\n flow \u00AB{{ store.document().processType }}\u00BB non c\u2019e\u2019 nulla da annullare.\n </p>\n}\n\n<fb-connector-editor\n [nodeName]=\"name()\"\n [node]=\"node()\"\n [outlets]=\"outlets()\"\n (connectorChanged)=\"onConnectorChanged($event)\"\n/>\n" }]
|
|
5603
|
+
args: [{ selector: 'fb-record-rollback-inspector', standalone: true, imports: [ConnectorEditorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<p class=\"fb-callout\">\r\n Annulla le modifiche ai record ancora pendenti. Non ha altri campi da configurare.\r\n</p>\r\n\r\n@if (!isScreenFlow()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questo elemento ha senso in uno screen flow, dove esiste una transazione aperta fra due schermate. In un\r\n flow \u00AB{{ store.document().processType }}\u00BB non c\u2019e\u2019 nulla da annullare.\r\n </p>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n" }]
|
|
4862
5604
|
}] });
|
|
4863
5605
|
|
|
4864
5606
|
/**
|
|
@@ -5038,7 +5780,7 @@ class RecordWriteInspectorComponent extends NodeInspectorBase {
|
|
|
5038
5780
|
this.patch((node) => mutate(node));
|
|
5039
5781
|
}
|
|
5040
5782
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: RecordWriteInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5041
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: RecordWriteInspectorComponent, isStandalone: true, selector: "fb-record-write-inspector", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Come indicare i {{ title() }}</legend>\r\n <label class=\"fb-check\">\r\n <input type=\"radio\" name=\"write-mode\" [checked]=\"mode() === 'object'\" (change)=\"setMode('object')\" />\r\n Per oggetto{{ needsFilters() ? ' e filtri' : ' e valori' }}\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"radio\" name=\"write-mode\" [checked]=\"mode() === 'reference'\" (change)=\"setMode('reference')\" />\r\n Un record gi\u00E0 in memoria\r\n </label>\r\n</fieldset>\r\n\r\n@if (mode() === 'reference') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Record</label>\r\n <fb-reference-picker\r\n [value]=\"record().inputReference\"\r\n dataType=\"Object\"\r\n placeholder=\"Variabile di tipo record\"\r\n (valueChange)=\"setInputReference($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Il record porta con se\u2019 i propri valori: non serve indicare oggetto ne\u2019 campi.\r\n </p>\r\n </div>\r\n} @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Oggetto</label>\r\n @if (hasObjectCatalog()) {\r\n <select class=\"fb-select\" [fbValue]=\"record().object || ''\" (change)=\"setObject($any($event.target).value)\">\r\n <option value=\"\">\u2014 scegli un oggetto \u2014</option>\r\n @for (object of objectOptions(); track object.name) {\r\n <option [value]=\"object.name\">{{ object.label || object.name }}</option>\r\n }\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"record().object || ''\"\r\n placeholder=\"Nome dell\u2019entita\u2019\"\r\n (input)=\"setObject($any($event.target).value)\"\r\n />\r\n }\r\n </div>\r\n\r\n @if (needsFilters()) {\r\n <fb-record-filter-editor\r\n [holder]=\"$any(record())\"\r\n [object]=\"record().object\"\r\n [title]=\"isDelete() ? 'Quali record cancellare' : 'Quali record aggiornare'\"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"supportsFilterLogic()\"\r\n [emptyWarning]=\"emptyFilterWarning()\"\r\n [emptyWarningSeverity]=\"emptyFilterSeverity()\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n />\r\n\r\n @if (showsBulkConfirm()) {\r\n <label class=\"fb-check fb-confirm\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"bulkUpdateConfirmed()\"\r\n (change)=\"confirmBulkUpdate($any($event.target).checked)\"\r\n />\r\n Confermo di voler aggiornare <strong>tutti</strong> i record di \u00AB{{ record().object || 'questo oggetto' }}\u00BB\r\n </label>\r\n }\r\n }\r\n\r\n @if (!isDelete()) {\r\n <fb-field-assignment-editor\r\n [holder]=\"$any(record())\"\r\n [object]=\"record().object\"\r\n [title]=\"isCreate() ? 'Valori del nuovo record' : 'Valori da scrivere'\"\r\n (changed)=\"onAssignmentsChanged($event)\"\r\n />\r\n }\r\n}\r\n\r\n@if (isCreate()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Upsert</legend>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"record().doesUpsert === true\"\r\n (change)=\"setDoesUpsert($any($event.target).checked)\"\r\n />\r\n Aggiorna il record se esiste gi\u00E0\r\n </label>\r\n\r\n @if (record().doesUpsert) {\r\n @if (hasUpsertConflict()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Sono indicati insieme il campo di id esterno e quello standard: va scelto uno solo\r\n (UPSERT_CONFIGURATION_INVALID).\r\n </p>\r\n }\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"radio\"\r\n name=\"upsert-mode\"\r\n [checked]=\"upsertMode() === 'external'\"\r\n (change)=\"setUpsertMode('external')\"\r\n />\r\n Riconosci il record da un id esterno\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"radio\"\r\n name=\"upsert-mode\"\r\n [checked]=\"upsertMode() === 'standard'\"\r\n (change)=\"setUpsertMode('standard')\"\r\n />\r\n Riconosci il record dall\u2019id standard\r\n </label>\r\n\r\n @if (upsertMode() === 'external') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo id esterno</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"record().upsertExternalIdField || ''\"\r\n (input)=\"setUpsertExternalField($any($event.target).value)\"\r\n />\r\n </div>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo id standard</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"record().upsertStandardIdField || ''\"\r\n (input)=\"setUpsertStandardField($any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n }\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Identificativo creato</legend>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"record().storeOutputAutomatically === true\"\r\n (change)=\"setStoreOutputAutomatically($any($event.target).checked)\"\r\n />\r\n Output automatico\r\n </label>\r\n @if (record().storeOutputAutomatically) {\r\n <p class=\"fb-field__hint\">\r\n L\u2019identificativo creato si referenzia col nome dell\u2019elemento: <code>{{ name() }}</code>.\r\n </p>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Assegna l\u2019identificativo a</label>\r\n <fb-reference-picker\r\n [value]=\"record().assignRecordIdToReference\"\r\n [writableOnly]=\"true\"\r\n placeholder=\"Scegli una variabile\"\r\n (valueChange)=\"setAssignRecordId($event)\"\r\n />\r\n </div>\r\n }\r\n </fieldset>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: FieldAssignmentEditorComponent, selector: "fb-field-assignment-editor", inputs: ["holder", "object", "title", "disabledReason"], outputs: ["changed"] }, { kind: "component", type: RecordFilterEditorComponent, selector: "fb-record-filter-editor", inputs: ["holder", "object", "title", "usage", "supportsLogic", "supportsFormula", "emptyWarning", "emptyWarningSeverity"], outputs: ["changed"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "
|
|
5783
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: RecordWriteInspectorComponent, isStandalone: true, selector: "fb-record-write-inspector", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Come indicare i {{ title() }}</legend>\r\n <label class=\"fb-check\">\r\n <input type=\"radio\" name=\"write-mode\" [checked]=\"mode() === 'object'\" (change)=\"setMode('object')\" />\r\n Per oggetto{{ needsFilters() ? ' e filtri' : ' e valori' }}\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"radio\" name=\"write-mode\" [checked]=\"mode() === 'reference'\" (change)=\"setMode('reference')\" />\r\n Un record gi\u00E0 in memoria\r\n </label>\r\n</fieldset>\r\n\r\n@if (mode() === 'reference') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Record</label>\r\n <fb-reference-picker\r\n [value]=\"record().inputReference\"\r\n dataType=\"Object\"\r\n placeholder=\"Variabile di tipo record\"\r\n (valueChange)=\"setInputReference($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Il record porta con se\u2019 i propri valori: non serve indicare oggetto ne\u2019 campi.\r\n </p>\r\n </div>\r\n} @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Oggetto</label>\r\n @if (hasObjectCatalog()) {\r\n <select class=\"fb-select\" [fbValue]=\"record().object || ''\" (change)=\"setObject($any($event.target).value)\">\r\n <option value=\"\">\u2014 scegli un oggetto \u2014</option>\r\n @for (object of objectOptions(); track object.name) {\r\n <option [value]=\"object.name\">{{ object.label || object.name }}</option>\r\n }\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"record().object || ''\"\r\n placeholder=\"Nome dell\u2019entita\u2019\"\r\n (input)=\"setObject($any($event.target).value)\"\r\n />\r\n }\r\n </div>\r\n\r\n @if (needsFilters()) {\r\n <fb-record-filter-editor\r\n [holder]=\"$any(record())\"\r\n [object]=\"record().object\"\r\n [title]=\"isDelete() ? 'Quali record cancellare' : 'Quali record aggiornare'\"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"supportsFilterLogic()\"\r\n [emptyWarning]=\"emptyFilterWarning()\"\r\n [emptyWarningSeverity]=\"emptyFilterSeverity()\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n />\r\n\r\n @if (showsBulkConfirm()) {\r\n <label class=\"fb-check fb-confirm\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"bulkUpdateConfirmed()\"\r\n (change)=\"confirmBulkUpdate($any($event.target).checked)\"\r\n />\r\n Confermo di voler aggiornare <strong>tutti</strong> i record di \u00AB{{ record().object || 'questo oggetto' }}\u00BB\r\n </label>\r\n }\r\n }\r\n\r\n @if (!isDelete()) {\r\n <fb-field-assignment-editor\r\n [holder]=\"$any(record())\"\r\n [object]=\"record().object\"\r\n [title]=\"isCreate() ? 'Valori del nuovo record' : 'Valori da scrivere'\"\r\n (changed)=\"onAssignmentsChanged($event)\"\r\n />\r\n }\r\n}\r\n\r\n@if (isCreate()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Upsert</legend>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"record().doesUpsert === true\"\r\n (change)=\"setDoesUpsert($any($event.target).checked)\"\r\n />\r\n Aggiorna il record se esiste gi\u00E0\r\n </label>\r\n\r\n @if (record().doesUpsert) {\r\n @if (hasUpsertConflict()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Sono indicati insieme il campo di id esterno e quello standard: va scelto uno solo\r\n (UPSERT_CONFIGURATION_INVALID).\r\n </p>\r\n }\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"radio\"\r\n name=\"upsert-mode\"\r\n [checked]=\"upsertMode() === 'external'\"\r\n (change)=\"setUpsertMode('external')\"\r\n />\r\n Riconosci il record da un id esterno\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"radio\"\r\n name=\"upsert-mode\"\r\n [checked]=\"upsertMode() === 'standard'\"\r\n (change)=\"setUpsertMode('standard')\"\r\n />\r\n Riconosci il record dall\u2019id standard\r\n </label>\r\n\r\n @if (upsertMode() === 'external') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo id esterno</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"record().upsertExternalIdField || ''\"\r\n (input)=\"setUpsertExternalField($any($event.target).value)\"\r\n />\r\n </div>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo id standard</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"record().upsertStandardIdField || ''\"\r\n (input)=\"setUpsertStandardField($any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n }\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Identificativo creato</legend>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"record().storeOutputAutomatically === true\"\r\n (change)=\"setStoreOutputAutomatically($any($event.target).checked)\"\r\n />\r\n Output automatico\r\n </label>\r\n @if (record().storeOutputAutomatically) {\r\n <p class=\"fb-field__hint\">\r\n L\u2019identificativo creato si referenzia col nome dell\u2019elemento: <code>{{ name() }}</code>.\r\n </p>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Assegna l\u2019identificativo a</label>\r\n <fb-reference-picker\r\n [value]=\"record().assignRecordIdToReference\"\r\n [writableOnly]=\"true\"\r\n placeholder=\"Scegli una variabile\"\r\n (valueChange)=\"setAssignRecordId($event)\"\r\n />\r\n </div>\r\n }\r\n </fieldset>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: FieldAssignmentEditorComponent, selector: "fb-field-assignment-editor", inputs: ["holder", "object", "title", "disabledReason"], outputs: ["changed"] }, { kind: "component", type: RecordFilterEditorComponent, selector: "fb-record-filter-editor", inputs: ["holder", "object", "title", "usage", "supportsLogic", "supportsFormula", "emptyWarning", "emptyWarningSeverity"], outputs: ["changed"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5042
5784
|
}
|
|
5043
5785
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: RecordWriteInspectorComponent, decorators: [{
|
|
5044
5786
|
type: Component,
|
|
@@ -5528,7 +6270,7 @@ class SubflowInspectorComponent extends NodeInspectorBase {
|
|
|
5528
6270
|
});
|
|
5529
6271
|
}
|
|
5530
6272
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: SubflowInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5531
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: SubflowInspectorComponent, isStandalone: true, selector: "fb-subflow-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Flow da invocare</label>\r\n @if (hasCandidates()) {\r\n <select\r\n class=\"fb-select\"\r\n [class.fb-select--invalid]=\"isRecursive()\"\r\n [fbValue]=\"subflow().flowName || ''\"\r\n (change)=\"setFlowName($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (candidate of candidateOptions(); track candidate.flowName) {\r\n <option [value]=\"candidate.flowName\">{{ candidate.label || candidate.flowName }}</option>\r\n }\r\n </select>\r\n <p class=\"fb-field__hint\">Solo i flow con una versione attiva possono essere invocati.</p>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"subflow().flowName || ''\"\r\n placeholder=\"API name del flow\"\r\n (input)=\"setFlowName($any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Nessun flow attivo disponibile come subflow: attivane uno, oppure scrivi il nome a mano.\r\n </p>\r\n }\r\n @if (isRecursive()) {\r\n <p class=\"fb-field__error\">Un flow non puo\u2019 invocare se stesso (SUBFLOW_RECURSIVE).</p>\r\n }\r\n</div>\r\n\r\n@if (couldNotLoadTarget()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Non e\u2019 stato possibile leggere la definizione del flow invocato: i nomi di input e output non vengono\r\n proposti, ma puoi scriverli a mano.\r\n </p>\r\n}\r\n\r\n<p class=\"fb-callout\">\r\n Un subflow che si sospende \u2014 cioe\u2019 che contiene screen o Wait \u2014 non e\u2019 supportato dal motore.\r\n</p>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Valori passati al subflow</legend>\r\n @if (inputVariables().length) {\r\n <p class=\"fb-section__note\">\r\n Sono le variabili di input del flow invocato: {{ inputVariables().length }} disponibili.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (assignment of inputAssignments(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n @if (inputVariables().length) {\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"assignment.name || ''\"\r\n aria-label=\"Variabile del subflow\"\r\n (change)=\"setInputName($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (variable of inputVariables(); track variable.name) {\r\n <option [value]=\"variable.name\">{{ variable.name }}</option>\r\n }\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"assignment.name || ''\"\r\n placeholder=\"Nome della variabile di input\"\r\n aria-label=\"Variabile del subflow\"\r\n (input)=\"setInputName($index, $any($event.target).value)\"\r\n />\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeInput($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n <fb-value-editor\r\n [value]=\"assignment.value\"\r\n [dataType]=\"variableOf(assignment.name)?.dataType\"\r\n [objectType]=\"variableOf(assignment.name)?.objectType\"\r\n [isCollection]=\"variableOf(assignment.name)?.isCollection\"\r\n label=\"Valore\"\r\n (valueChange)=\"setInputValue($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun valore passato.</p>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addInput()\">Aggiungi valore</button>\r\n</fieldset>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Valori restituiti</legend>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"storeOutputAutomatically()\"\r\n (change)=\"setStoreOutputAutomatically($any($event.target).checked)\"\r\n />\r\n Output automatico\r\n </label>\r\n @if (storeOutputAutomatically()) {\r\n <p class=\"fb-field__hint\">\r\n Le variabili di output del subflow si referenziano col nome dell\u2019elemento:\r\n <code>{{ name() }}.NomeVariabile</code>.\r\n </p>\r\n } @else {\r\n <div class=\"fb-list\">\r\n @for (assignment of outputAssignments(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n @if (outputVariables().length) {\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"assignment.name || ''\"\r\n aria-label=\"Variabile di output del subflow\"\r\n (change)=\"setOutputName($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (variable of outputVariables(); track variable.name) {\r\n <option [value]=\"variable.name\">{{ variable.name }}</option>\r\n }\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"assignment.name || ''\"\r\n placeholder=\"Nome della variabile di output\"\r\n aria-label=\"Variabile di output del subflow\"\r\n (input)=\"setOutputName($index, $any($event.target).value)\"\r\n />\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeOutput($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Assegna a</label>\r\n <fb-reference-picker\r\n [value]=\"assignment.assignToReference\"\r\n [writableOnly]=\"true\"\r\n [dataType]=\"variableOf(assignment.name)?.dataType\"\r\n [isCollection]=\"variableOf(assignment.name)?.isCollection\"\r\n placeholder=\"Scegli una variabile\"\r\n (valueChange)=\"setOutputTarget($index, $event)\"\r\n />\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun valore raccolto.</p>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addOutput()\">Aggiungi valore</button>\r\n }\r\n</fieldset>\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "
|
|
6273
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: SubflowInspectorComponent, isStandalone: true, selector: "fb-subflow-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Flow da invocare</label>\r\n @if (hasCandidates()) {\r\n <select\r\n class=\"fb-select\"\r\n [class.fb-select--invalid]=\"isRecursive()\"\r\n [fbValue]=\"subflow().flowName || ''\"\r\n (change)=\"setFlowName($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (candidate of candidateOptions(); track candidate.flowName) {\r\n <option [value]=\"candidate.flowName\">{{ candidate.label || candidate.flowName }}</option>\r\n }\r\n </select>\r\n <p class=\"fb-field__hint\">Solo i flow con una versione attiva possono essere invocati.</p>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"subflow().flowName || ''\"\r\n placeholder=\"API name del flow\"\r\n (input)=\"setFlowName($any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Nessun flow attivo disponibile come subflow: attivane uno, oppure scrivi il nome a mano.\r\n </p>\r\n }\r\n @if (isRecursive()) {\r\n <p class=\"fb-field__error\">Un flow non puo\u2019 invocare se stesso (SUBFLOW_RECURSIVE).</p>\r\n }\r\n</div>\r\n\r\n@if (couldNotLoadTarget()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Non e\u2019 stato possibile leggere la definizione del flow invocato: i nomi di input e output non vengono\r\n proposti, ma puoi scriverli a mano.\r\n </p>\r\n}\r\n\r\n<p class=\"fb-callout\">\r\n Un subflow che si sospende \u2014 cioe\u2019 che contiene screen o Wait \u2014 non e\u2019 supportato dal motore.\r\n</p>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Valori passati al subflow</legend>\r\n @if (inputVariables().length) {\r\n <p class=\"fb-section__note\">\r\n Sono le variabili di input del flow invocato: {{ inputVariables().length }} disponibili.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (assignment of inputAssignments(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n @if (inputVariables().length) {\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"assignment.name || ''\"\r\n aria-label=\"Variabile del subflow\"\r\n (change)=\"setInputName($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (variable of inputVariables(); track variable.name) {\r\n <option [value]=\"variable.name\">{{ variable.name }}</option>\r\n }\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"assignment.name || ''\"\r\n placeholder=\"Nome della variabile di input\"\r\n aria-label=\"Variabile del subflow\"\r\n (input)=\"setInputName($index, $any($event.target).value)\"\r\n />\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeInput($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n <fb-value-editor\r\n [value]=\"assignment.value\"\r\n [dataType]=\"variableOf(assignment.name)?.dataType\"\r\n [objectType]=\"variableOf(assignment.name)?.objectType\"\r\n [isCollection]=\"variableOf(assignment.name)?.isCollection\"\r\n label=\"Valore\"\r\n (valueChange)=\"setInputValue($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun valore passato.</p>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addInput()\">Aggiungi valore</button>\r\n</fieldset>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Valori restituiti</legend>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"storeOutputAutomatically()\"\r\n (change)=\"setStoreOutputAutomatically($any($event.target).checked)\"\r\n />\r\n Output automatico\r\n </label>\r\n @if (storeOutputAutomatically()) {\r\n <p class=\"fb-field__hint\">\r\n Le variabili di output del subflow si referenziano col nome dell\u2019elemento:\r\n <code>{{ name() }}.NomeVariabile</code>.\r\n </p>\r\n } @else {\r\n <div class=\"fb-list\">\r\n @for (assignment of outputAssignments(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n @if (outputVariables().length) {\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"assignment.name || ''\"\r\n aria-label=\"Variabile di output del subflow\"\r\n (change)=\"setOutputName($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (variable of outputVariables(); track variable.name) {\r\n <option [value]=\"variable.name\">{{ variable.name }}</option>\r\n }\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"assignment.name || ''\"\r\n placeholder=\"Nome della variabile di output\"\r\n aria-label=\"Variabile di output del subflow\"\r\n (input)=\"setOutputName($index, $any($event.target).value)\"\r\n />\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeOutput($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Assegna a</label>\r\n <fb-reference-picker\r\n [value]=\"assignment.assignToReference\"\r\n [writableOnly]=\"true\"\r\n [dataType]=\"variableOf(assignment.name)?.dataType\"\r\n [isCollection]=\"variableOf(assignment.name)?.isCollection\"\r\n placeholder=\"Scegli una variabile\"\r\n (valueChange)=\"setOutputTarget($index, $event)\"\r\n />\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun valore raccolto.</p>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addOutput()\">Aggiungi valore</button>\r\n }\r\n</fieldset>\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5532
6274
|
}
|
|
5533
6275
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: SubflowInspectorComponent, decorators: [{
|
|
5534
6276
|
type: Component,
|
|
@@ -5693,7 +6435,7 @@ class TransformInspectorComponent extends NodeInspectorBase {
|
|
|
5693
6435
|
return action.transformType === 'Sum' || action.transformType === 'Count';
|
|
5694
6436
|
}
|
|
5695
6437
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: TransformInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5696
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: TransformInspectorComponent, isStandalone: true, selector: "fb-transform-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo del risultato</label>\r\n <select class=\"fb-select\" [fbValue]=\"transform().dataType || ''\" (change)=\"setDataType($any($event.target).value)\">\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (type of dataTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n @if (!transform().dataType) {\r\n <p class=\"fb-field__error\">Obbligatorio (TRANSFORM_DATA_TYPE_MISSING).</p>\r\n }\r\n</div>\r\n\r\n@if (requiresObjectType()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo dell\u2019oggetto</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"transform().objectType || ''\"\r\n (change)=\"setObjectType($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @if (transform().dataType === 'Enum') {\r\n @for (entry of enumOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n } @else {\r\n @for (object of objectOptions(); track object.name) {\r\n <option [value]=\"object.name\">{{ object.label || object.name }}</option>\r\n }\r\n }\r\n </select>\r\n </div>\r\n}\r\n\r\n<label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"transform().isCollection === true\"\r\n (change)=\"setIsCollection($any($event.target).checked)\"\r\n />\r\n Il risultato e\u2019 una collection\r\n</label>\r\n\r\n<p class=\"fb-callout\">\r\n Il risultato e\u2019 l\u2019<strong>output automatico</strong> dell\u2019elemento: si referenzia con\r\n <code>{{ name() }}</code>.\r\n</p>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Trasformazioni</legend>\r\n\r\n <div class=\"fb-list\">\r\n @for (action of actions(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeAction($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Operazione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"action.transformType || 'Map'\"\r\n (change)=\"setActionType($index, $any($event.target).value)\"\r\n >\r\n @for (type of transformTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo di destinazione</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"action.outputFieldApiName || ''\"\r\n placeholder=\"Totale\"\r\n (input)=\"setOutputField($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n @if (isMap(action)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\r\n <fb-value-editor\r\n [value]=\"action.value\"\r\n label=\"Valore\"\r\n (valueChange)=\"setMapValue($index, $event)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (needsAggregationValues(action)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Collection su cui aggregare</label>\r\n <fb-reference-picker\r\n [value]=\"aggregationCollection(action)\"\r\n [isCollection]=\"true\"\r\n placeholder=\"Scegli una collection\"\r\n (valueChange)=\"setAggregationCollection($index, $event)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (needsAggregationField(action)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo da sommare</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"aggregationField(action)\"\r\n placeholder=\"Importo\"\r\n (input)=\"setAggregationField($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessuna trasformazione: l\u2019elemento non produce nulla (TRANSFORM_WITHOUT_VALUES).</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addAction()\">Aggiungi trasformazione</button>\r\n</fieldset>\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "
|
|
6438
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: TransformInspectorComponent, isStandalone: true, selector: "fb-transform-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo del risultato</label>\r\n <select class=\"fb-select\" [fbValue]=\"transform().dataType || ''\" (change)=\"setDataType($any($event.target).value)\">\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (type of dataTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n @if (!transform().dataType) {\r\n <p class=\"fb-field__error\">Obbligatorio (TRANSFORM_DATA_TYPE_MISSING).</p>\r\n }\r\n</div>\r\n\r\n@if (requiresObjectType()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo dell\u2019oggetto</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"transform().objectType || ''\"\r\n (change)=\"setObjectType($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @if (transform().dataType === 'Enum') {\r\n @for (entry of enumOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n } @else {\r\n @for (object of objectOptions(); track object.name) {\r\n <option [value]=\"object.name\">{{ object.label || object.name }}</option>\r\n }\r\n }\r\n </select>\r\n </div>\r\n}\r\n\r\n<label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"transform().isCollection === true\"\r\n (change)=\"setIsCollection($any($event.target).checked)\"\r\n />\r\n Il risultato e\u2019 una collection\r\n</label>\r\n\r\n<p class=\"fb-callout\">\r\n Il risultato e\u2019 l\u2019<strong>output automatico</strong> dell\u2019elemento: si referenzia con\r\n <code>{{ name() }}</code>.\r\n</p>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Trasformazioni</legend>\r\n\r\n <div class=\"fb-list\">\r\n @for (action of actions(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeAction($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Operazione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"action.transformType || 'Map'\"\r\n (change)=\"setActionType($index, $any($event.target).value)\"\r\n >\r\n @for (type of transformTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo di destinazione</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"action.outputFieldApiName || ''\"\r\n placeholder=\"Totale\"\r\n (input)=\"setOutputField($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n @if (isMap(action)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\r\n <fb-value-editor\r\n [value]=\"action.value\"\r\n label=\"Valore\"\r\n (valueChange)=\"setMapValue($index, $event)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (needsAggregationValues(action)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Collection su cui aggregare</label>\r\n <fb-reference-picker\r\n [value]=\"aggregationCollection(action)\"\r\n [isCollection]=\"true\"\r\n placeholder=\"Scegli una collection\"\r\n (valueChange)=\"setAggregationCollection($index, $event)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (needsAggregationField(action)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo da sommare</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"aggregationField(action)\"\r\n placeholder=\"Importo\"\r\n (input)=\"setAggregationField($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessuna trasformazione: l\u2019elemento non produce nulla (TRANSFORM_WITHOUT_VALUES).</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addAction()\">Aggiungi trasformazione</button>\r\n</fieldset>\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5697
6439
|
}
|
|
5698
6440
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: TransformInspectorComponent, decorators: [{
|
|
5699
6441
|
type: Component,
|
|
@@ -5808,7 +6550,7 @@ class WaitInspectorComponent extends NodeInspectorBase {
|
|
|
5808
6550
|
this.setField('defaultConnectorLabel', label);
|
|
5809
6551
|
}
|
|
5810
6552
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: WaitInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5811
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: WaitInspectorComponent, isStandalone: true, selector: "fb-wait-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-list\">\r\n @for (event of events(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta su\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveEvent($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta giu\u2019\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveEvent($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi l\u2019evento\"\r\n (click)=\"removeEvent($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Etichetta del ramo</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"event.label || ''\"\r\n placeholder=\"Alla scadenza\"\r\n (input)=\"setEventLabel($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Nome tecnico</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"event.name || ''\"\r\n (input)=\"setEventName($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo di evento</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"event.eventType || ''\"\r\n (change)=\"setEventType($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (type of eventTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n @for (entry of catalogEventOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n </select>\r\n @if (!event.eventType) {\r\n <p class=\"fb-field__error\">Senza tipo l\u2019evento non e\u2019 valido (WAIT_EVENT_TYPE_MISSING).</p>\r\n }\r\n </div>\r\n\r\n <fb-parameter-editor\r\n [holder]=\"event\"\r\n inputTitle=\"Parametri dell\u2019evento\"\r\n [showOutputs]=\"true\"\r\n outputTitle=\"Valori prodotti dall\u2019evento\"\r\n (changed)=\"onEventParametersChanged($index, $event)\"\r\n />\r\n\r\n <fb-condition-editor\r\n [holder]=\"event\"\r\n title=\"Condizioni dell\u2019evento\"\r\n (changed)=\"onEventConditionsChanged($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Almeno un evento e\u2019 obbligatorio: un Wait senza eventi non e\u2019 eseguibile (WAIT_WITHOUT_EVENTS).\r\n </p>\r\n }\r\n</div>\r\n\r\n<button type=\"button\" class=\"fb-btn\" (click)=\"addEvent()\">Aggiungi evento</button>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Se nessun evento si verifica</legend>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta del ramo di default</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"wait().defaultConnectorLabel || ''\"\r\n (input)=\"setDefaultLabel($any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n \u00C8 il ramo percorso quando le condizioni di <strong>tutti</strong> gli eventi sono false.\r\n </p>\r\n </div>\r\n</fieldset>\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Rami\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConditionEditorComponent, selector: "fb-condition-editor", inputs: ["holder", "title", "allowFormula", "issuePath"], outputs: ["changed"] }, { kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason"], outputs: ["changed"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6553
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: WaitInspectorComponent, isStandalone: true, selector: "fb-wait-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-list\">\r\n @for (event of events(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta su\"\r\n [disabled]=\"$first\"\r\n (click)=\"moveEvent($index, -1)\"\r\n >\r\n \u2191\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Sposta giu\u2019\"\r\n [disabled]=\"$last\"\r\n (click)=\"moveEvent($index, 1)\"\r\n >\r\n \u2193\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi l\u2019evento\"\r\n (click)=\"removeEvent($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Etichetta del ramo</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"event.label || ''\"\r\n placeholder=\"Alla scadenza\"\r\n (input)=\"setEventLabel($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Nome tecnico</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"event.name || ''\"\r\n (input)=\"setEventName($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo di evento</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"event.eventType || ''\"\r\n (change)=\"setEventType($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (type of eventTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n @for (entry of catalogEventOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n </select>\r\n @if (!event.eventType) {\r\n <p class=\"fb-field__error\">Senza tipo l\u2019evento non e\u2019 valido (WAIT_EVENT_TYPE_MISSING).</p>\r\n }\r\n </div>\r\n\r\n <fb-parameter-editor\r\n [holder]=\"event\"\r\n inputTitle=\"Parametri dell\u2019evento\"\r\n [showOutputs]=\"true\"\r\n outputTitle=\"Valori prodotti dall\u2019evento\"\r\n (changed)=\"onEventParametersChanged($index, $event)\"\r\n />\r\n\r\n <fb-condition-editor\r\n [holder]=\"event\"\r\n title=\"Condizioni dell\u2019evento\"\r\n (changed)=\"onEventConditionsChanged($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Almeno un evento e\u2019 obbligatorio: un Wait senza eventi non e\u2019 eseguibile (WAIT_WITHOUT_EVENTS).\r\n </p>\r\n }\r\n</div>\r\n\r\n<button type=\"button\" class=\"fb-btn\" (click)=\"addEvent()\">Aggiungi evento</button>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Se nessun evento si verifica</legend>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta del ramo di default</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"wait().defaultConnectorLabel || ''\"\r\n (input)=\"setDefaultLabel($any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n \u00C8 il ramo percorso quando le condizioni di <strong>tutti</strong> gli eventi sono false.\r\n </p>\r\n </div>\r\n</fieldset>\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Rami\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n", dependencies: [{ kind: "component", type: ConditionEditorComponent, selector: "fb-condition-editor", inputs: ["holder", "title", "allowFormula", "allowLogic", "issuePath"], outputs: ["changed"] }, { kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason"], outputs: ["changed"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5812
6554
|
}
|
|
5813
6555
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: WaitInspectorComponent, decorators: [{
|
|
5814
6556
|
type: Component,
|
|
@@ -5824,9 +6566,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
|
|
|
5824
6566
|
* `FlowDocumentStore.renameNode`, e il form dice quanti riferimenti verranno riscritti prima
|
|
5825
6567
|
* di farlo.
|
|
5826
6568
|
*
|
|
5827
|
-
* Il corpo e' scelto per tipo. I tipi non supportati (`Step`, `Experiment
|
|
5828
|
-
*
|
|
5829
|
-
*
|
|
6569
|
+
* Il corpo e' scelto per tipo. I tipi non supportati (`Step`, `Experiment`) non sono creabili
|
|
6570
|
+
* dalla palette, ma possono arrivare da un documento importato: in quel caso l'inspector li
|
|
6571
|
+
* mostra in sola lettura, dicendo perche'.
|
|
5830
6572
|
*/
|
|
5831
6573
|
class ElementInspectorComponent {
|
|
5832
6574
|
store = inject(FlowDocumentStore);
|
|
@@ -5964,7 +6706,7 @@ class ElementInspectorComponent {
|
|
|
5964
6706
|
return { x: node?.locationX ?? 0, y: node?.locationY ?? 0 };
|
|
5965
6707
|
}, ...(ngDevMode ? [{ debugName: "position" }] : []));
|
|
5966
6708
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ElementInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5967
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ElementInspectorComponent, isStandalone: true, selector: "fb-element-inspector", inputs: { selectedName: { classPropertyName: "selectedName", publicName: "selectedName", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", removeRequested: "removeRequested", duplicateRequested: "duplicateRequested" }, ngImport: i0, template: "@if (!selectedName()) {\n <p class=\"fb-inspector__empty\">\n Seleziona un elemento sul canvas per modificarlo, oppure trascina un elemento dalla palette.\n </p>\n} @else {\n @if (showHeader()) {\n <header class=\"fb-inspector__header\">\n <div>\n <span class=\"fb-inspector__type\">{{ typeLabel() }}</span>\n <h2 class=\"fb-inspector__title\">\n {{ isStart() ? 'Avvio del flow' : node()?.label || selectedName() }}\n </h2>\n </div>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\n \u00D7\n </button>\n </header>\n }\n\n <div class=\"fb-inspector__body\">\n @if (issues().length) {\n <ul class=\"fb-inspector__issues\">\n <!-- `$index`: due rilievi con lo stesso codice e lo stesso path sono possibili. -->\n @for (issue of issues(); track $index) {\n <li\n class=\"fb-inspector__issue\"\n [class.fb-inspector__issue--error]=\"issue.severity === 'Error'\"\n [class.fb-inspector__issue--warning]=\"issue.severity === 'Warning'\"\n >\n <span class=\"fb-inspector__issue-code\">{{ issue.code }}</span>\n {{ issue.message }}\n @if (issue.path) {\n <span class=\"fb-inspector__issue-path\">{{ issue.path }}</span>\n }\n </li>\n }\n </ul>\n }\n\n @if (isUnsupported()) {\n <p class=\"fb-callout fb-callout--error\">\n Questo tipo di elemento non e\u2019 supportato dal motore: il flow che lo contiene non parte\n (ELEMENT_NOT_SUPPORTED). Non e\u2019 creabile dalla palette; se e\u2019 arrivato da un documento importato,\n va rimosso.\n </p>\n }\n\n @if (!isStart()) {\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">Etichetta</label>\n <input\n class=\"fb-input\"\n [value]=\"$any(node()?.label) || ''\"\n placeholder=\"Nome mostrato sul canvas\"\n (input)=\"setLabel($any($event.target).value)\"\n />\n </div>\n\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">Nome tecnico</label>\n @if (pendingName() === null) {\n <div class=\"fb-field__row\">\n <input class=\"fb-input fb-input--mono\" [value]=\"selectedName() || ''\" readonly />\n <button type=\"button\" class=\"fb-btn\" (click)=\"startRename()\">Rinomina</button>\n </div>\n <p class=\"fb-field__hint\">\n \u00C8 l\u2019identificatore con cui i riferimenti raggiungono questo elemento.\n @if (referenceCount() > 1) {\n Compare {{ referenceCount() }} volte nel documento.\n }\n </p>\n } @else {\n <input\n class=\"fb-input fb-input--mono\"\n [class.fb-input--invalid]=\"!!nameError()\"\n [value]=\"pendingName() || ''\"\n (input)=\"onPendingNameInput($any($event.target).value)\"\n />\n @if (nameError()) {\n <p class=\"fb-field__error\">{{ nameError() }}</p>\n } @else {\n <p class=\"fb-field__hint fb-field__hint--warn\">\n La rinomina riscrive tutti i riferimenti che puntano a questo elemento\n ({{ referenceCount() }} occorrenze): nessuna primitiva del backend lo fa, lo fa l\u2019editor.\n </p>\n }\n <div class=\"fb-field__row\">\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"!canRename()\" (click)=\"applyRename()\">\n Applica\n </button>\n <button type=\"button\" class=\"fb-btn\" (click)=\"suggestNameFromLabel()\">Genera dalla label</button>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost\" (click)=\"cancelRename()\">Annulla</button>\n </div>\n }\n </div>\n\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">Descrizione</label>\n <textarea\n class=\"fb-textarea\"\n [value]=\"$any(node()?.description) || ''\"\n (input)=\"setDescription($any($event.target).value)\"\n ></textarea>\n </div>\n }\n\n <p class=\"fb-inspector__position\">\n Posizione sul canvas: {{ position().x }}, {{ position().y }}\n </p>\n\n <hr class=\"fb-inspector__divider\" />\n\n @if (isStart()) {\n <fb-start-inspector />\n } @else if (node()) {\n @switch (type()) {\n @case ('Screen') {\n <fb-screen-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('Assignment') {\n <fb-assignment-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('Decision') {\n <fb-decision-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('Loop') {\n <fb-loop-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('CollectionProcessor') {\n <fb-collection-processor-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('CustomError') {\n <fb-custom-error-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('Wait') {\n <fb-wait-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('RecordLookup') {\n <fb-record-lookup-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('RecordCreate') {\n <fb-record-write-inspector [name]=\"selectedName()!\" [node]=\"node()!\" type=\"RecordCreate\" />\n }\n @case ('RecordUpdate') {\n <fb-record-write-inspector [name]=\"selectedName()!\" [node]=\"node()!\" type=\"RecordUpdate\" />\n }\n @case ('RecordDelete') {\n <fb-record-write-inspector [name]=\"selectedName()!\" [node]=\"node()!\" type=\"RecordDelete\" />\n }\n @case ('RecordRollback') {\n <fb-record-rollback-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('ActionCall') {\n <fb-action-call-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('ScriptCall') {\n <fb-script-call-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('Subflow') {\n <fb-subflow-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('Transform') {\n <fb-transform-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @default {\n <p class=\"fb-callout fb-callout--warn\">\n Nessun form specifico per il tipo \u00AB{{ type() }}\u00BB: i campi comuni sono modificabili qui sopra.\n </p>\n }\n }\n }\n\n @if (!isStart()) {\n <hr class=\"fb-inspector__divider\" />\n <div class=\"fb-field__row\">\n <button type=\"button\" class=\"fb-btn\" (click)=\"requestDuplicate()\">Duplica</button>\n <button type=\"button\" class=\"fb-btn fb-btn--danger\" (click)=\"requestRemove()\">Elimina</button>\n </div>\n }\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-inspector__empty{margin:16px 12px;font-size:12px;line-height:1.5;color:var(--fb-text-muted, #667085)}.fb-inspector__header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;padding:10px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-inspector__type{font-size:10px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-inspector__title{margin:2px 0 0;font-size:14px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-inspector__body{flex:1;min-height:0;overflow-y:auto;padding:14px}.fb-inspector__issues{margin:0 0 12px;padding:0;list-style:none}.fb-inspector__issue{margin-bottom:4px;padding:6px 8px;border-left:3px solid var(--fb-text-subtle, #98a2b3);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:11px;line-height:1.4;color:var(--fb-text, #1d2939)}.fb-inspector__issue--error{border-left-color:var(--fb-error, #c9372c)}.fb-inspector__issue--warning{border-left-color:var(--fb-warning, #b7791f)}.fb-inspector__issue-code{display:block;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-subtle, #98a2b3)}.fb-inspector__issue-path{display:block;margin-top:2px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-muted, #667085)}.fb-inspector__position{margin:0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-inspector__divider{margin:12px 0;border:0;border-top:1px solid var(--fb-border-subtle, #e6e9ee)}\n"], dependencies: [{ kind: "component", type: ActionCallInspectorComponent, selector: "fb-action-call-inspector" }, { kind: "component", type: AssignmentInspectorComponent, selector: "fb-assignment-inspector" }, { kind: "component", type: CollectionProcessorInspectorComponent, selector: "fb-collection-processor-inspector" }, { kind: "component", type: CustomErrorInspectorComponent, selector: "fb-custom-error-inspector" }, { kind: "component", type: DecisionInspectorComponent, selector: "fb-decision-inspector" }, { kind: "component", type: LoopInspectorComponent, selector: "fb-loop-inspector" }, { kind: "component", type: RecordLookupInspectorComponent, selector: "fb-record-lookup-inspector" }, { kind: "component", type: RecordRollbackInspectorComponent, selector: "fb-record-rollback-inspector" }, { kind: "component", type: RecordWriteInspectorComponent, selector: "fb-record-write-inspector", inputs: ["type"] }, { kind: "component", type: ScreenInspectorComponent, selector: "fb-screen-inspector" }, { kind: "component", type: ScriptCallInspectorComponent, selector: "fb-script-call-inspector" }, { kind: "component", type: StartInspectorComponent, selector: "fb-start-inspector" }, { kind: "component", type: SubflowInspectorComponent, selector: "fb-subflow-inspector" }, { kind: "component", type: TransformInspectorComponent, selector: "fb-transform-inspector" }, { kind: "component", type: WaitInspectorComponent, selector: "fb-wait-inspector" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6709
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ElementInspectorComponent, isStandalone: true, selector: "fb-element-inspector", inputs: { selectedName: { classPropertyName: "selectedName", publicName: "selectedName", isSignal: true, isRequired: false, transformFunction: null }, showHeader: { classPropertyName: "showHeader", publicName: "showHeader", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", removeRequested: "removeRequested", duplicateRequested: "duplicateRequested" }, ngImport: i0, template: "@if (!selectedName()) {\r\n <p class=\"fb-inspector__empty\">\r\n Seleziona un elemento sul canvas per modificarlo, oppure trascina un elemento dalla palette.\r\n </p>\r\n} @else {\r\n @if (showHeader()) {\r\n <header class=\"fb-inspector__header\">\r\n <div>\r\n <span class=\"fb-inspector__type\">{{ typeLabel() }}</span>\r\n <h2 class=\"fb-inspector__title\">\r\n {{ isStart() ? 'Avvio del flow' : node()?.label || selectedName() }}\r\n </h2>\r\n </div>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\r\n \u00D7\r\n </button>\r\n </header>\r\n }\r\n\r\n <div class=\"fb-inspector__body\">\r\n @if (issues().length) {\r\n <ul class=\"fb-inspector__issues\">\r\n <!-- `$index`: due rilievi con lo stesso codice e lo stesso path sono possibili. -->\r\n @for (issue of issues(); track $index) {\r\n <li\r\n class=\"fb-inspector__issue\"\r\n [class.fb-inspector__issue--error]=\"issue.severity === 'Error'\"\r\n [class.fb-inspector__issue--warning]=\"issue.severity === 'Warning'\"\r\n >\r\n <span class=\"fb-inspector__issue-code\">{{ issue.code }}</span>\r\n {{ issue.message }}\r\n @if (issue.path) {\r\n <span class=\"fb-inspector__issue-path\">{{ issue.path }}</span>\r\n }\r\n </li>\r\n }\r\n </ul>\r\n }\r\n\r\n @if (isUnsupported()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Questo tipo di elemento non e\u2019 supportato dal motore: il flow che lo contiene non parte\r\n (ELEMENT_NOT_SUPPORTED). Non e\u2019 creabile dalla palette; se e\u2019 arrivato da un documento importato,\r\n va rimosso.\r\n </p>\r\n }\r\n\r\n @if (!isStart()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"$any(node()?.label) || ''\"\r\n placeholder=\"Nome mostrato sul canvas\"\r\n (input)=\"setLabel($any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Nome tecnico</label>\r\n @if (pendingName() === null) {\r\n <div class=\"fb-field__row\">\r\n <input class=\"fb-input fb-input--mono\" [value]=\"selectedName() || ''\" readonly />\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"startRename()\">Rinomina</button>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n \u00C8 l\u2019identificatore con cui i riferimenti raggiungono questo elemento.\r\n @if (referenceCount() > 1) {\r\n Compare {{ referenceCount() }} volte nel documento.\r\n }\r\n </p>\r\n } @else {\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [class.fb-input--invalid]=\"!!nameError()\"\r\n [value]=\"pendingName() || ''\"\r\n (input)=\"onPendingNameInput($any($event.target).value)\"\r\n />\r\n @if (nameError()) {\r\n <p class=\"fb-field__error\">{{ nameError() }}</p>\r\n } @else {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n La rinomina riscrive tutti i riferimenti che puntano a questo elemento\r\n ({{ referenceCount() }} occorrenze): nessuna primitiva del backend lo fa, lo fa l\u2019editor.\r\n </p>\r\n }\r\n <div class=\"fb-field__row\">\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"!canRename()\" (click)=\"applyRename()\">\r\n Applica\r\n </button>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"suggestNameFromLabel()\">Genera dalla label</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost\" (click)=\"cancelRename()\">Annulla</button>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Descrizione</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"$any(node()?.description) || ''\"\r\n (input)=\"setDescription($any($event.target).value)\"\r\n ></textarea>\r\n </div>\r\n }\r\n\r\n <p class=\"fb-inspector__position\">\r\n Posizione sul canvas: {{ position().x }}, {{ position().y }}\r\n </p>\r\n\r\n <hr class=\"fb-inspector__divider\" />\r\n\r\n @if (isStart()) {\r\n <fb-start-inspector />\r\n } @else if (node()) {\r\n @switch (type()) {\r\n @case ('Screen') {\r\n <fb-screen-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('Assignment') {\r\n <fb-assignment-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('Decision') {\r\n <fb-decision-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('Loop') {\r\n <fb-loop-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('CollectionProcessor') {\r\n <fb-collection-processor-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('CustomError') {\r\n <fb-custom-error-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('Wait') {\r\n <fb-wait-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('RecordLookup') {\r\n <fb-record-lookup-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('RecordCreate') {\r\n <fb-record-write-inspector [name]=\"selectedName()!\" [node]=\"node()!\" type=\"RecordCreate\" />\r\n }\r\n @case ('RecordUpdate') {\r\n <fb-record-write-inspector [name]=\"selectedName()!\" [node]=\"node()!\" type=\"RecordUpdate\" />\r\n }\r\n @case ('RecordDelete') {\r\n <fb-record-write-inspector [name]=\"selectedName()!\" [node]=\"node()!\" type=\"RecordDelete\" />\r\n }\r\n @case ('RecordRollback') {\r\n <fb-record-rollback-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('ActionCall') {\r\n <fb-action-call-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('ScriptCall') {\r\n <fb-script-call-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('Subflow') {\r\n <fb-subflow-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('Transform') {\r\n <fb-transform-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('OrchestratedStage') {\r\n <fb-orchestrated-stage-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @default {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Nessun form specifico per il tipo \u00AB{{ type() }}\u00BB: i campi comuni sono modificabili qui sopra.\r\n </p>\r\n }\r\n }\r\n }\r\n\r\n @if (!isStart()) {\r\n <hr class=\"fb-inspector__divider\" />\r\n <div class=\"fb-field__row\">\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"requestDuplicate()\">Duplica</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--danger\" (click)=\"requestRemove()\">Elimina</button>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-inspector__empty{margin:16px 12px;font-size:12px;line-height:1.5;color:var(--fb-text-muted, #667085)}.fb-inspector__header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;padding:10px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-inspector__type{font-size:10px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-inspector__title{margin:2px 0 0;font-size:14px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-inspector__body{flex:1;min-height:0;overflow-y:auto;padding:14px}.fb-inspector__issues{margin:0 0 12px;padding:0;list-style:none}.fb-inspector__issue{margin-bottom:4px;padding:6px 8px;border-left:3px solid var(--fb-text-subtle, #98a2b3);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:11px;line-height:1.4;color:var(--fb-text, #1d2939)}.fb-inspector__issue--error{border-left-color:var(--fb-error, #c9372c)}.fb-inspector__issue--warning{border-left-color:var(--fb-warning, #b7791f)}.fb-inspector__issue-code{display:block;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-subtle, #98a2b3)}.fb-inspector__issue-path{display:block;margin-top:2px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-muted, #667085)}.fb-inspector__position{margin:0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-inspector__divider{margin:12px 0;border:0;border-top:1px solid var(--fb-border-subtle, #e6e9ee)}\n"], dependencies: [{ kind: "component", type: ActionCallInspectorComponent, selector: "fb-action-call-inspector" }, { kind: "component", type: AssignmentInspectorComponent, selector: "fb-assignment-inspector" }, { kind: "component", type: CollectionProcessorInspectorComponent, selector: "fb-collection-processor-inspector" }, { kind: "component", type: CustomErrorInspectorComponent, selector: "fb-custom-error-inspector" }, { kind: "component", type: DecisionInspectorComponent, selector: "fb-decision-inspector" }, { kind: "component", type: LoopInspectorComponent, selector: "fb-loop-inspector" }, { kind: "component", type: OrchestratedStageInspectorComponent, selector: "fb-orchestrated-stage-inspector" }, { kind: "component", type: RecordLookupInspectorComponent, selector: "fb-record-lookup-inspector" }, { kind: "component", type: RecordRollbackInspectorComponent, selector: "fb-record-rollback-inspector" }, { kind: "component", type: RecordWriteInspectorComponent, selector: "fb-record-write-inspector", inputs: ["type"] }, { kind: "component", type: ScreenInspectorComponent, selector: "fb-screen-inspector" }, { kind: "component", type: ScriptCallInspectorComponent, selector: "fb-script-call-inspector" }, { kind: "component", type: StartInspectorComponent, selector: "fb-start-inspector" }, { kind: "component", type: SubflowInspectorComponent, selector: "fb-subflow-inspector" }, { kind: "component", type: TransformInspectorComponent, selector: "fb-transform-inspector" }, { kind: "component", type: WaitInspectorComponent, selector: "fb-wait-inspector" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
5968
6710
|
}
|
|
5969
6711
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ElementInspectorComponent, decorators: [{
|
|
5970
6712
|
type: Component,
|
|
@@ -5975,6 +6717,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
|
|
|
5975
6717
|
CustomErrorInspectorComponent,
|
|
5976
6718
|
DecisionInspectorComponent,
|
|
5977
6719
|
LoopInspectorComponent,
|
|
6720
|
+
OrchestratedStageInspectorComponent,
|
|
5978
6721
|
RecordLookupInspectorComponent,
|
|
5979
6722
|
RecordRollbackInspectorComponent,
|
|
5980
6723
|
RecordWriteInspectorComponent,
|
|
@@ -5984,7 +6727,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
|
|
|
5984
6727
|
SubflowInspectorComponent,
|
|
5985
6728
|
TransformInspectorComponent,
|
|
5986
6729
|
WaitInspectorComponent,
|
|
5987
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!selectedName()) {\n <p class=\"fb-inspector__empty\">\n Seleziona un elemento sul canvas per modificarlo, oppure trascina un elemento dalla palette.\n </p>\n} @else {\n @if (showHeader()) {\n <header class=\"fb-inspector__header\">\n <div>\n <span class=\"fb-inspector__type\">{{ typeLabel() }}</span>\n <h2 class=\"fb-inspector__title\">\n {{ isStart() ? 'Avvio del flow' : node()?.label || selectedName() }}\n </h2>\n </div>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\n \u00D7\n </button>\n </header>\n }\n\n <div class=\"fb-inspector__body\">\n @if (issues().length) {\n <ul class=\"fb-inspector__issues\">\n <!-- `$index`: due rilievi con lo stesso codice e lo stesso path sono possibili. -->\n @for (issue of issues(); track $index) {\n <li\n class=\"fb-inspector__issue\"\n [class.fb-inspector__issue--error]=\"issue.severity === 'Error'\"\n [class.fb-inspector__issue--warning]=\"issue.severity === 'Warning'\"\n >\n <span class=\"fb-inspector__issue-code\">{{ issue.code }}</span>\n {{ issue.message }}\n @if (issue.path) {\n <span class=\"fb-inspector__issue-path\">{{ issue.path }}</span>\n }\n </li>\n }\n </ul>\n }\n\n @if (isUnsupported()) {\n <p class=\"fb-callout fb-callout--error\">\n Questo tipo di elemento non e\u2019 supportato dal motore: il flow che lo contiene non parte\n (ELEMENT_NOT_SUPPORTED). Non e\u2019 creabile dalla palette; se e\u2019 arrivato da un documento importato,\n va rimosso.\n </p>\n }\n\n @if (!isStart()) {\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">Etichetta</label>\n <input\n class=\"fb-input\"\n [value]=\"$any(node()?.label) || ''\"\n placeholder=\"Nome mostrato sul canvas\"\n (input)=\"setLabel($any($event.target).value)\"\n />\n </div>\n\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">Nome tecnico</label>\n @if (pendingName() === null) {\n <div class=\"fb-field__row\">\n <input class=\"fb-input fb-input--mono\" [value]=\"selectedName() || ''\" readonly />\n <button type=\"button\" class=\"fb-btn\" (click)=\"startRename()\">Rinomina</button>\n </div>\n <p class=\"fb-field__hint\">\n \u00C8 l\u2019identificatore con cui i riferimenti raggiungono questo elemento.\n @if (referenceCount() > 1) {\n Compare {{ referenceCount() }} volte nel documento.\n }\n </p>\n } @else {\n <input\n class=\"fb-input fb-input--mono\"\n [class.fb-input--invalid]=\"!!nameError()\"\n [value]=\"pendingName() || ''\"\n (input)=\"onPendingNameInput($any($event.target).value)\"\n />\n @if (nameError()) {\n <p class=\"fb-field__error\">{{ nameError() }}</p>\n } @else {\n <p class=\"fb-field__hint fb-field__hint--warn\">\n La rinomina riscrive tutti i riferimenti che puntano a questo elemento\n ({{ referenceCount() }} occorrenze): nessuna primitiva del backend lo fa, lo fa l\u2019editor.\n </p>\n }\n <div class=\"fb-field__row\">\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"!canRename()\" (click)=\"applyRename()\">\n Applica\n </button>\n <button type=\"button\" class=\"fb-btn\" (click)=\"suggestNameFromLabel()\">Genera dalla label</button>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost\" (click)=\"cancelRename()\">Annulla</button>\n </div>\n }\n </div>\n\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">Descrizione</label>\n <textarea\n class=\"fb-textarea\"\n [value]=\"$any(node()?.description) || ''\"\n (input)=\"setDescription($any($event.target).value)\"\n ></textarea>\n </div>\n }\n\n <p class=\"fb-inspector__position\">\n Posizione sul canvas: {{ position().x }}, {{ position().y }}\n </p>\n\n <hr class=\"fb-inspector__divider\" />\n\n @if (isStart()) {\n <fb-start-inspector />\n } @else if (node()) {\n @switch (type()) {\n @case ('Screen') {\n <fb-screen-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('Assignment') {\n <fb-assignment-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('Decision') {\n <fb-decision-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('Loop') {\n <fb-loop-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('CollectionProcessor') {\n <fb-collection-processor-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('CustomError') {\n <fb-custom-error-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('Wait') {\n <fb-wait-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('RecordLookup') {\n <fb-record-lookup-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('RecordCreate') {\n <fb-record-write-inspector [name]=\"selectedName()!\" [node]=\"node()!\" type=\"RecordCreate\" />\n }\n @case ('RecordUpdate') {\n <fb-record-write-inspector [name]=\"selectedName()!\" [node]=\"node()!\" type=\"RecordUpdate\" />\n }\n @case ('RecordDelete') {\n <fb-record-write-inspector [name]=\"selectedName()!\" [node]=\"node()!\" type=\"RecordDelete\" />\n }\n @case ('RecordRollback') {\n <fb-record-rollback-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('ActionCall') {\n <fb-action-call-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('ScriptCall') {\n <fb-script-call-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('Subflow') {\n <fb-subflow-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @case ('Transform') {\n <fb-transform-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\n }\n @default {\n <p class=\"fb-callout fb-callout--warn\">\n Nessun form specifico per il tipo \u00AB{{ type() }}\u00BB: i campi comuni sono modificabili qui sopra.\n </p>\n }\n }\n }\n\n @if (!isStart()) {\n <hr class=\"fb-inspector__divider\" />\n <div class=\"fb-field__row\">\n <button type=\"button\" class=\"fb-btn\" (click)=\"requestDuplicate()\">Duplica</button>\n <button type=\"button\" class=\"fb-btn fb-btn--danger\" (click)=\"requestRemove()\">Elimina</button>\n </div>\n }\n </div>\n}\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-inspector__empty{margin:16px 12px;font-size:12px;line-height:1.5;color:var(--fb-text-muted, #667085)}.fb-inspector__header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;padding:10px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-inspector__type{font-size:10px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-inspector__title{margin:2px 0 0;font-size:14px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-inspector__body{flex:1;min-height:0;overflow-y:auto;padding:14px}.fb-inspector__issues{margin:0 0 12px;padding:0;list-style:none}.fb-inspector__issue{margin-bottom:4px;padding:6px 8px;border-left:3px solid var(--fb-text-subtle, #98a2b3);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:11px;line-height:1.4;color:var(--fb-text, #1d2939)}.fb-inspector__issue--error{border-left-color:var(--fb-error, #c9372c)}.fb-inspector__issue--warning{border-left-color:var(--fb-warning, #b7791f)}.fb-inspector__issue-code{display:block;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-subtle, #98a2b3)}.fb-inspector__issue-path{display:block;margin-top:2px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-muted, #667085)}.fb-inspector__position{margin:0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-inspector__divider{margin:12px 0;border:0;border-top:1px solid var(--fb-border-subtle, #e6e9ee)}\n"] }]
|
|
6730
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!selectedName()) {\r\n <p class=\"fb-inspector__empty\">\r\n Seleziona un elemento sul canvas per modificarlo, oppure trascina un elemento dalla palette.\r\n </p>\r\n} @else {\r\n @if (showHeader()) {\r\n <header class=\"fb-inspector__header\">\r\n <div>\r\n <span class=\"fb-inspector__type\">{{ typeLabel() }}</span>\r\n <h2 class=\"fb-inspector__title\">\r\n {{ isStart() ? 'Avvio del flow' : node()?.label || selectedName() }}\r\n </h2>\r\n </div>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\r\n \u00D7\r\n </button>\r\n </header>\r\n }\r\n\r\n <div class=\"fb-inspector__body\">\r\n @if (issues().length) {\r\n <ul class=\"fb-inspector__issues\">\r\n <!-- `$index`: due rilievi con lo stesso codice e lo stesso path sono possibili. -->\r\n @for (issue of issues(); track $index) {\r\n <li\r\n class=\"fb-inspector__issue\"\r\n [class.fb-inspector__issue--error]=\"issue.severity === 'Error'\"\r\n [class.fb-inspector__issue--warning]=\"issue.severity === 'Warning'\"\r\n >\r\n <span class=\"fb-inspector__issue-code\">{{ issue.code }}</span>\r\n {{ issue.message }}\r\n @if (issue.path) {\r\n <span class=\"fb-inspector__issue-path\">{{ issue.path }}</span>\r\n }\r\n </li>\r\n }\r\n </ul>\r\n }\r\n\r\n @if (isUnsupported()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Questo tipo di elemento non e\u2019 supportato dal motore: il flow che lo contiene non parte\r\n (ELEMENT_NOT_SUPPORTED). Non e\u2019 creabile dalla palette; se e\u2019 arrivato da un documento importato,\r\n va rimosso.\r\n </p>\r\n }\r\n\r\n @if (!isStart()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"$any(node()?.label) || ''\"\r\n placeholder=\"Nome mostrato sul canvas\"\r\n (input)=\"setLabel($any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Nome tecnico</label>\r\n @if (pendingName() === null) {\r\n <div class=\"fb-field__row\">\r\n <input class=\"fb-input fb-input--mono\" [value]=\"selectedName() || ''\" readonly />\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"startRename()\">Rinomina</button>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n \u00C8 l\u2019identificatore con cui i riferimenti raggiungono questo elemento.\r\n @if (referenceCount() > 1) {\r\n Compare {{ referenceCount() }} volte nel documento.\r\n }\r\n </p>\r\n } @else {\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [class.fb-input--invalid]=\"!!nameError()\"\r\n [value]=\"pendingName() || ''\"\r\n (input)=\"onPendingNameInput($any($event.target).value)\"\r\n />\r\n @if (nameError()) {\r\n <p class=\"fb-field__error\">{{ nameError() }}</p>\r\n } @else {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n La rinomina riscrive tutti i riferimenti che puntano a questo elemento\r\n ({{ referenceCount() }} occorrenze): nessuna primitiva del backend lo fa, lo fa l\u2019editor.\r\n </p>\r\n }\r\n <div class=\"fb-field__row\">\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"!canRename()\" (click)=\"applyRename()\">\r\n Applica\r\n </button>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"suggestNameFromLabel()\">Genera dalla label</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost\" (click)=\"cancelRename()\">Annulla</button>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Descrizione</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"$any(node()?.description) || ''\"\r\n (input)=\"setDescription($any($event.target).value)\"\r\n ></textarea>\r\n </div>\r\n }\r\n\r\n <p class=\"fb-inspector__position\">\r\n Posizione sul canvas: {{ position().x }}, {{ position().y }}\r\n </p>\r\n\r\n <hr class=\"fb-inspector__divider\" />\r\n\r\n @if (isStart()) {\r\n <fb-start-inspector />\r\n } @else if (node()) {\r\n @switch (type()) {\r\n @case ('Screen') {\r\n <fb-screen-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('Assignment') {\r\n <fb-assignment-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('Decision') {\r\n <fb-decision-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('Loop') {\r\n <fb-loop-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('CollectionProcessor') {\r\n <fb-collection-processor-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('CustomError') {\r\n <fb-custom-error-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('Wait') {\r\n <fb-wait-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('RecordLookup') {\r\n <fb-record-lookup-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('RecordCreate') {\r\n <fb-record-write-inspector [name]=\"selectedName()!\" [node]=\"node()!\" type=\"RecordCreate\" />\r\n }\r\n @case ('RecordUpdate') {\r\n <fb-record-write-inspector [name]=\"selectedName()!\" [node]=\"node()!\" type=\"RecordUpdate\" />\r\n }\r\n @case ('RecordDelete') {\r\n <fb-record-write-inspector [name]=\"selectedName()!\" [node]=\"node()!\" type=\"RecordDelete\" />\r\n }\r\n @case ('RecordRollback') {\r\n <fb-record-rollback-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('ActionCall') {\r\n <fb-action-call-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('ScriptCall') {\r\n <fb-script-call-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('Subflow') {\r\n <fb-subflow-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('Transform') {\r\n <fb-transform-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @case ('OrchestratedStage') {\r\n <fb-orchestrated-stage-inspector [name]=\"selectedName()!\" [node]=\"node()!\" />\r\n }\r\n @default {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Nessun form specifico per il tipo \u00AB{{ type() }}\u00BB: i campi comuni sono modificabili qui sopra.\r\n </p>\r\n }\r\n }\r\n }\r\n\r\n @if (!isStart()) {\r\n <hr class=\"fb-inspector__divider\" />\r\n <div class=\"fb-field__row\">\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"requestDuplicate()\">Duplica</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--danger\" (click)=\"requestRemove()\">Elimina</button>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-inspector__empty{margin:16px 12px;font-size:12px;line-height:1.5;color:var(--fb-text-muted, #667085)}.fb-inspector__header{display:flex;align-items:flex-start;justify-content:space-between;gap:8px;padding:10px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-inspector__type{font-size:10px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-inspector__title{margin:2px 0 0;font-size:14px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-inspector__body{flex:1;min-height:0;overflow-y:auto;padding:14px}.fb-inspector__issues{margin:0 0 12px;padding:0;list-style:none}.fb-inspector__issue{margin-bottom:4px;padding:6px 8px;border-left:3px solid var(--fb-text-subtle, #98a2b3);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:11px;line-height:1.4;color:var(--fb-text, #1d2939)}.fb-inspector__issue--error{border-left-color:var(--fb-error, #c9372c)}.fb-inspector__issue--warning{border-left-color:var(--fb-warning, #b7791f)}.fb-inspector__issue-code{display:block;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-subtle, #98a2b3)}.fb-inspector__issue-path{display:block;margin-top:2px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-muted, #667085)}.fb-inspector__position{margin:0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-inspector__divider{margin:12px 0;border:0;border-top:1px solid var(--fb-border-subtle, #e6e9ee)}\n"] }]
|
|
5988
6731
|
}], propDecorators: { selectedName: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedName", required: false }] }], showHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHeader", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], removeRequested: [{ type: i0.Output, args: ["removeRequested"] }], duplicateRequested: [{ type: i0.Output, args: ["duplicateRequested"] }] } });
|
|
5989
6732
|
|
|
5990
6733
|
/**
|
|
@@ -6048,11 +6791,11 @@ class ElementDialogComponent {
|
|
|
6048
6791
|
this.duplicateRequested.emit(name);
|
|
6049
6792
|
}
|
|
6050
6793
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ElementDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6051
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.27", type: ElementDialogComponent, isStandalone: true, selector: "fb-element-dialog", inputs: { selectedName: { classPropertyName: "selectedName", publicName: "selectedName", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", removeRequested: "removeRequested", duplicateRequested: "duplicateRequested" }, viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: "<!--\n Il backdrop chiude: e' il gesto che tutti si aspettano. Il pannello ferma la propagazione\n del click, altrimenti configurare un campo chiuderebbe la dialog.\n-->\n<div class=\"fb-dialog__backdrop\" (click)=\"close()\"></div>\n\n<div\n #panel\n class=\"fb-dialog__panel\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"typeLabel() + ': ' + title()\"\n tabindex=\"-1\"\n (click)=\"$event.stopPropagation()\"\n (keydown.escape)=\"close()\"\n>\n <header class=\"fb-dialog__head\">\n <div class=\"fb-dialog__identity\">\n <span class=\"fb-dialog__type\">{{ typeLabel() }}</span>\n <h2 class=\"fb-dialog__title\">{{ title() }}</h2>\n </div>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\n </header>\n\n <div class=\"fb-dialog__body\">\n <!-- L'intestazione dell'inspector qui e' quella della dialog: non si ripete. -->\n <fb-element-inspector\n [selectedName]=\"selectedName()\"\n [showHeader]=\"false\"\n (removeRequested)=\"onRemoveRequested($event)\"\n (duplicateRequested)=\"onDuplicateRequested($event)\"\n (closed)=\"close()\"\n />\n </div>\n\n <footer class=\"fb-dialog__foot\">\n <span class=\"fb-dialog__note\">\n Le modifiche sono gi\u00E0 nel documento: per tornare indietro c\u2019\u00E8 l\u2019annulla dell\u2019editor.\n </span>\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" (click)=\"close()\">Fatto</button>\n </footer>\n</div>\n", styles: [":host{position:absolute;inset:0;z-index:30;display:grid;place-items:center;padding:24px}.fb-dialog__backdrop{position:absolute;inset:0;background:#10182852;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}.fb-dialog__panel{position:relative;display:flex;flex-direction:column;width:min(760px,100%);max-height:100%;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-lg, 12px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-lg, 0 18px 44px rgb(16 24 40 / 18%));outline:none;overflow:hidden}.fb-dialog__head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4)}.fb-dialog__identity{min-width:0}.fb-dialog__type{display:block;font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-dialog__title{margin:1px 0 0;font-size:15px;font-weight:600;color:var(--fb-text, #1a1c23);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-dialog__body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain}.fb-dialog__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 14px;border-top:1px solid var(--fb-border-subtle, #eef0f4);background:var(--fb-surface-alt, #f7f8fa)}.fb-dialog__note{font-size:11px;color:var(--fb-text-muted, #6b7086)}@media(max-height:620px){:host{padding:10px}}\n"], dependencies: [{ kind: "component", type: ElementInspectorComponent, selector: "fb-element-inspector", inputs: ["selectedName", "showHeader"], outputs: ["closed", "removeRequested", "duplicateRequested"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6794
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.27", type: ElementDialogComponent, isStandalone: true, selector: "fb-element-dialog", inputs: { selectedName: { classPropertyName: "selectedName", publicName: "selectedName", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", removeRequested: "removeRequested", duplicateRequested: "duplicateRequested" }, viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: "<!--\r\n Il backdrop chiude: e' il gesto che tutti si aspettano. Il pannello ferma la propagazione\r\n del click, altrimenti configurare un campo chiuderebbe la dialog.\r\n-->\r\n<div class=\"fb-dialog__backdrop\" (click)=\"close()\"></div>\r\n\r\n<div\r\n #panel\r\n class=\"fb-dialog__panel\"\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n [attr.aria-label]=\"typeLabel() + ': ' + title()\"\r\n tabindex=\"-1\"\r\n (click)=\"$event.stopPropagation()\"\r\n (keydown.escape)=\"close()\"\r\n>\r\n <header class=\"fb-dialog__head\">\r\n <div class=\"fb-dialog__identity\">\r\n <span class=\"fb-dialog__type\">{{ typeLabel() }}</span>\r\n <h2 class=\"fb-dialog__title\">{{ title() }}</h2>\r\n </div>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\r\n </header>\r\n\r\n <div class=\"fb-dialog__body\">\r\n <!-- L'intestazione dell'inspector qui e' quella della dialog: non si ripete. -->\r\n <fb-element-inspector\r\n [selectedName]=\"selectedName()\"\r\n [showHeader]=\"false\"\r\n (removeRequested)=\"onRemoveRequested($event)\"\r\n (duplicateRequested)=\"onDuplicateRequested($event)\"\r\n (closed)=\"close()\"\r\n />\r\n </div>\r\n\r\n <footer class=\"fb-dialog__foot\">\r\n <span class=\"fb-dialog__note\">\r\n Le modifiche sono gi\u00E0 nel documento: per tornare indietro c\u2019\u00E8 l\u2019annulla dell\u2019editor.\r\n </span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" (click)=\"close()\">Fatto</button>\r\n </footer>\r\n</div>\r\n", styles: [":host{position:absolute;inset:0;z-index:30;display:grid;place-items:center;padding:24px}.fb-dialog__backdrop{position:absolute;inset:0;background:#10182852;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}.fb-dialog__panel{position:relative;display:flex;flex-direction:column;width:min(760px,100%);max-height:100%;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-lg, 12px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-lg, 0 18px 44px rgb(16 24 40 / 18%));outline:none;overflow:hidden}.fb-dialog__head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4)}.fb-dialog__identity{min-width:0}.fb-dialog__type{display:block;font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-dialog__title{margin:1px 0 0;font-size:15px;font-weight:600;color:var(--fb-text, #1a1c23);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-dialog__body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain}.fb-dialog__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 14px;border-top:1px solid var(--fb-border-subtle, #eef0f4);background:var(--fb-surface-alt, #f7f8fa)}.fb-dialog__note{font-size:11px;color:var(--fb-text-muted, #6b7086)}@media(max-height:620px){:host{padding:10px}}\n"], dependencies: [{ kind: "component", type: ElementInspectorComponent, selector: "fb-element-inspector", inputs: ["selectedName", "showHeader"], outputs: ["closed", "removeRequested", "duplicateRequested"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6052
6795
|
}
|
|
6053
6796
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ElementDialogComponent, decorators: [{
|
|
6054
6797
|
type: Component,
|
|
6055
|
-
args: [{ selector: 'fb-element-dialog', standalone: true, imports: [ElementInspectorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\n Il backdrop chiude: e' il gesto che tutti si aspettano. Il pannello ferma la propagazione\n del click, altrimenti configurare un campo chiuderebbe la dialog.\n-->\n<div class=\"fb-dialog__backdrop\" (click)=\"close()\"></div>\n\n<div\n #panel\n class=\"fb-dialog__panel\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"typeLabel() + ': ' + title()\"\n tabindex=\"-1\"\n (click)=\"$event.stopPropagation()\"\n (keydown.escape)=\"close()\"\n>\n <header class=\"fb-dialog__head\">\n <div class=\"fb-dialog__identity\">\n <span class=\"fb-dialog__type\">{{ typeLabel() }}</span>\n <h2 class=\"fb-dialog__title\">{{ title() }}</h2>\n </div>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\n </header>\n\n <div class=\"fb-dialog__body\">\n <!-- L'intestazione dell'inspector qui e' quella della dialog: non si ripete. -->\n <fb-element-inspector\n [selectedName]=\"selectedName()\"\n [showHeader]=\"false\"\n (removeRequested)=\"onRemoveRequested($event)\"\n (duplicateRequested)=\"onDuplicateRequested($event)\"\n (closed)=\"close()\"\n />\n </div>\n\n <footer class=\"fb-dialog__foot\">\n <span class=\"fb-dialog__note\">\n Le modifiche sono gi\u00E0 nel documento: per tornare indietro c\u2019\u00E8 l\u2019annulla dell\u2019editor.\n </span>\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" (click)=\"close()\">Fatto</button>\n </footer>\n</div>\n", styles: [":host{position:absolute;inset:0;z-index:30;display:grid;place-items:center;padding:24px}.fb-dialog__backdrop{position:absolute;inset:0;background:#10182852;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}.fb-dialog__panel{position:relative;display:flex;flex-direction:column;width:min(760px,100%);max-height:100%;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-lg, 12px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-lg, 0 18px 44px rgb(16 24 40 / 18%));outline:none;overflow:hidden}.fb-dialog__head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4)}.fb-dialog__identity{min-width:0}.fb-dialog__type{display:block;font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-dialog__title{margin:1px 0 0;font-size:15px;font-weight:600;color:var(--fb-text, #1a1c23);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-dialog__body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain}.fb-dialog__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 14px;border-top:1px solid var(--fb-border-subtle, #eef0f4);background:var(--fb-surface-alt, #f7f8fa)}.fb-dialog__note{font-size:11px;color:var(--fb-text-muted, #6b7086)}@media(max-height:620px){:host{padding:10px}}\n"] }]
|
|
6798
|
+
args: [{ selector: 'fb-element-dialog', standalone: true, imports: [ElementInspectorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\r\n Il backdrop chiude: e' il gesto che tutti si aspettano. Il pannello ferma la propagazione\r\n del click, altrimenti configurare un campo chiuderebbe la dialog.\r\n-->\r\n<div class=\"fb-dialog__backdrop\" (click)=\"close()\"></div>\r\n\r\n<div\r\n #panel\r\n class=\"fb-dialog__panel\"\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n [attr.aria-label]=\"typeLabel() + ': ' + title()\"\r\n tabindex=\"-1\"\r\n (click)=\"$event.stopPropagation()\"\r\n (keydown.escape)=\"close()\"\r\n>\r\n <header class=\"fb-dialog__head\">\r\n <div class=\"fb-dialog__identity\">\r\n <span class=\"fb-dialog__type\">{{ typeLabel() }}</span>\r\n <h2 class=\"fb-dialog__title\">{{ title() }}</h2>\r\n </div>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\r\n </header>\r\n\r\n <div class=\"fb-dialog__body\">\r\n <!-- L'intestazione dell'inspector qui e' quella della dialog: non si ripete. -->\r\n <fb-element-inspector\r\n [selectedName]=\"selectedName()\"\r\n [showHeader]=\"false\"\r\n (removeRequested)=\"onRemoveRequested($event)\"\r\n (duplicateRequested)=\"onDuplicateRequested($event)\"\r\n (closed)=\"close()\"\r\n />\r\n </div>\r\n\r\n <footer class=\"fb-dialog__foot\">\r\n <span class=\"fb-dialog__note\">\r\n Le modifiche sono gi\u00E0 nel documento: per tornare indietro c\u2019\u00E8 l\u2019annulla dell\u2019editor.\r\n </span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" (click)=\"close()\">Fatto</button>\r\n </footer>\r\n</div>\r\n", styles: [":host{position:absolute;inset:0;z-index:30;display:grid;place-items:center;padding:24px}.fb-dialog__backdrop{position:absolute;inset:0;background:#10182852;-webkit-backdrop-filter:blur(1px);backdrop-filter:blur(1px)}.fb-dialog__panel{position:relative;display:flex;flex-direction:column;width:min(760px,100%);max-height:100%;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-lg, 12px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-lg, 0 18px 44px rgb(16 24 40 / 18%));outline:none;overflow:hidden}.fb-dialog__head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4)}.fb-dialog__identity{min-width:0}.fb-dialog__type{display:block;font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-dialog__title{margin:1px 0 0;font-size:15px;font-weight:600;color:var(--fb-text, #1a1c23);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-dialog__body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain}.fb-dialog__foot{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 14px;border-top:1px solid var(--fb-border-subtle, #eef0f4);background:var(--fb-surface-alt, #f7f8fa)}.fb-dialog__note{font-size:11px;color:var(--fb-text-muted, #6b7086)}@media(max-height:620px){:host{padding:10px}}\n"] }]
|
|
6056
6799
|
}], ctorParameters: () => [], propDecorators: { selectedName: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedName", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], removeRequested: [{ type: i0.Output, args: ["removeRequested"] }], duplicateRequested: [{ type: i0.Output, args: ["duplicateRequested"] }], panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }] } });
|
|
6057
6800
|
|
|
6058
6801
|
/**
|
|
@@ -6337,11 +7080,11 @@ class ProblemsPanelComponent {
|
|
|
6337
7080
|
this.closed.emit();
|
|
6338
7081
|
}
|
|
6339
7082
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ProblemsPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6340
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ProblemsPanelComponent, isStandalone: true, selector: "fb-problems-panel", outputs: { elementFocused: "elementFocused", closed: "closed" }, ngImport: i0, template: "<header class=\"fb-prob__header\">\n <h2 class=\"fb-prob__title\">\n Problemi\n @if (isRunning()) {\n <span class=\"fb-prob__running\">validazione in corso\u2026</span>\n }\n </h2>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\n</header>\n\n<nav class=\"fb-prob__filters\" aria-label=\"Filtra per gravita\u2019\">\n <button\n type=\"button\"\n class=\"fb-prob__filter\"\n [class.fb-prob__filter--active]=\"filter() === 'all'\"\n (click)=\"setFilter('all')\"\n >\n Tutti\n </button>\n <button\n type=\"button\"\n class=\"fb-prob__filter fb-prob__filter--error\"\n [class.fb-prob__filter--active]=\"filter() === 'Error'\"\n (click)=\"setFilter('Error')\"\n >\n Errori <span class=\"fb-prob__count\">{{ errorCount() }}</span>\n </button>\n <button\n type=\"button\"\n class=\"fb-prob__filter fb-prob__filter--warning\"\n [class.fb-prob__filter--active]=\"filter() === 'Warning'\"\n (click)=\"setFilter('Warning')\"\n >\n Avvisi <span class=\"fb-prob__count\">{{ warningCount() }}</span>\n </button>\n <button\n type=\"button\"\n class=\"fb-prob__filter\"\n [class.fb-prob__filter--active]=\"filter() === 'Info'\"\n (click)=\"setFilter('Info')\"\n >\n Note <span class=\"fb-prob__count\">{{ infoCount() }}</span>\n </button>\n</nav>\n\n<div class=\"fb-prob__body\">\n @if (lastError()) {\n <p class=\"fb-callout fb-callout--warn\">\n Non e\u2019 stato possibile validare: {{ lastError() }}\n </p>\n }\n\n @if (!hasResult() && !isRunning()) {\n <p class=\"fb-empty\">La validazione non e\u2019 ancora stata eseguita.</p>\n }\n\n @if (isClean()) {\n <p class=\"fb-empty\">\n Nessun rilievo. Attenzione: non e\u2019 una garanzia di correttezza \u2014 la validazione non verifica i percorsi\n di relazione nei campi, la sintassi delle formule, ne\u2019 action, form e parametri quando il catalogo\n corrispondente non e\u2019 popolato.\n </p>\n }\n\n <ul class=\"fb-prob__list\">\n <!-- `$index`: due rilievi possono avere codice, elemento e path identici (due condizioni\n incomplete nella stessa regola), e una chiave duplicata e' un errore di Angular. -->\n @for (issue of issues(); track $index) {\n <li\n class=\"fb-prob__item\"\n [class.fb-prob__item--error]=\"issue.severity === 'Error'\"\n [class.fb-prob__item--warning]=\"issue.severity === 'Warning'\"\n >\n <button type=\"button\" class=\"fb-prob__link\" (click)=\"focus(issue)\">\n <span class=\"fb-prob__message\">{{ issue.message }}</span>\n <span class=\"fb-prob__meta\">\n <code>{{ issue.code }}</code>\n @if (issue.elementName) {\n \u00B7 {{ issue.elementName }}\n }\n @if (issue.path) {\n \u00B7 {{ issue.path }}\n }\n </span>\n </button>\n </li>\n }\n </ul>\n\n @if (errorCount() > 0) {\n <p class=\"fb-prob__note\">\n Gli errori bloccano l\u2019<strong>attivazione</strong>, non il salvataggio: puoi interrompere il lavoro a\n met\u00E0 e riprenderlo.\n </p>\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff);border-top:1px solid var(--fb-border, #d6dae1)}.fb-prob__header{display:flex;align-items:center;justify-content:space-between;padding:6px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-prob__title{display:flex;align-items:baseline;gap:8px;margin:0;font-size:13px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-prob__running{font-size:10px;font-weight:400;color:var(--fb-text-subtle, #98a2b3)}.fb-prob__filters{display:flex;gap:3px;padding:5px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-prob__filter{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:12px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}.fb-prob__filter--active{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent);color:var(--fb-accent, #2f6feb);font-weight:600}.fb-prob__filter--error.fb-prob__filter--active{border-color:var(--fb-error, #c9372c);background:color-mix(in srgb,var(--fb-error, #c9372c) 10%,transparent);color:var(--fb-error, #c9372c)}.fb-prob__filter--warning.fb-prob__filter--active{border-color:var(--fb-warning, #b7791f);background:color-mix(in srgb,var(--fb-warning, #b7791f) 12%,transparent);color:var(--fb-warning, #b7791f)}.fb-prob__count{padding:0 4px;border-radius:6px;background:var(--fb-border, #d6dae1);font-size:9px;color:var(--fb-text, #1d2939)}.fb-prob__body{flex:1;min-height:0;overflow-y:auto;padding:8px 12px}.fb-prob__list{margin:0;padding:0;list-style:none}.fb-prob__item{border-left:3px solid var(--fb-text-subtle, #98a2b3);margin-bottom:3px;border-radius:3px;background:var(--fb-surface-alt, #f8f9fb)}.fb-prob__item--error{border-left-color:var(--fb-error, #c9372c)}.fb-prob__item--warning{border-left-color:var(--fb-warning, #b7791f)}.fb-prob__link{display:flex;flex-direction:column;width:100%;padding:5px 8px;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-prob__link:hover{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 6%,transparent)}.fb-prob__message{font-size:12px;line-height:1.4}.fb-prob__meta{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-prob__note{margin:8px 0 0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7083
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ProblemsPanelComponent, isStandalone: true, selector: "fb-problems-panel", outputs: { elementFocused: "elementFocused", closed: "closed" }, ngImport: i0, template: "<header class=\"fb-prob__header\">\r\n <h2 class=\"fb-prob__title\">\r\n Problemi\r\n @if (isRunning()) {\r\n <span class=\"fb-prob__running\">validazione in corso\u2026</span>\r\n }\r\n </h2>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\r\n</header>\r\n\r\n<nav class=\"fb-prob__filters\" aria-label=\"Filtra per gravita\u2019\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-prob__filter\"\r\n [class.fb-prob__filter--active]=\"filter() === 'all'\"\r\n (click)=\"setFilter('all')\"\r\n >\r\n Tutti\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-prob__filter fb-prob__filter--error\"\r\n [class.fb-prob__filter--active]=\"filter() === 'Error'\"\r\n (click)=\"setFilter('Error')\"\r\n >\r\n Errori <span class=\"fb-prob__count\">{{ errorCount() }}</span>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-prob__filter fb-prob__filter--warning\"\r\n [class.fb-prob__filter--active]=\"filter() === 'Warning'\"\r\n (click)=\"setFilter('Warning')\"\r\n >\r\n Avvisi <span class=\"fb-prob__count\">{{ warningCount() }}</span>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-prob__filter\"\r\n [class.fb-prob__filter--active]=\"filter() === 'Info'\"\r\n (click)=\"setFilter('Info')\"\r\n >\r\n Note <span class=\"fb-prob__count\">{{ infoCount() }}</span>\r\n </button>\r\n</nav>\r\n\r\n<div class=\"fb-prob__body\">\r\n @if (lastError()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Non e\u2019 stato possibile validare: {{ lastError() }}\r\n </p>\r\n }\r\n\r\n @if (!hasResult() && !isRunning()) {\r\n <p class=\"fb-empty\">La validazione non e\u2019 ancora stata eseguita.</p>\r\n }\r\n\r\n @if (isClean()) {\r\n <p class=\"fb-empty\">\r\n Nessun rilievo. Attenzione: non e\u2019 una garanzia di correttezza \u2014 la validazione non verifica i percorsi\r\n di relazione nei campi, la sintassi delle formule, ne\u2019 action, form e parametri quando il catalogo\r\n corrispondente non e\u2019 popolato.\r\n </p>\r\n }\r\n\r\n <ul class=\"fb-prob__list\">\r\n <!-- `$index`: due rilievi possono avere codice, elemento e path identici (due condizioni\r\n incomplete nella stessa regola), e una chiave duplicata e' un errore di Angular. -->\r\n @for (issue of issues(); track $index) {\r\n <li\r\n class=\"fb-prob__item\"\r\n [class.fb-prob__item--error]=\"issue.severity === 'Error'\"\r\n [class.fb-prob__item--warning]=\"issue.severity === 'Warning'\"\r\n >\r\n <button type=\"button\" class=\"fb-prob__link\" (click)=\"focus(issue)\">\r\n <span class=\"fb-prob__message\">{{ issue.message }}</span>\r\n <span class=\"fb-prob__meta\">\r\n <code>{{ issue.code }}</code>\r\n @if (issue.elementName) {\r\n \u00B7 {{ issue.elementName }}\r\n }\r\n @if (issue.path) {\r\n \u00B7 {{ issue.path }}\r\n }\r\n </span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n\r\n @if (errorCount() > 0) {\r\n <p class=\"fb-prob__note\">\r\n Gli errori bloccano l\u2019<strong>attivazione</strong>, non il salvataggio: puoi interrompere il lavoro a\r\n met\u00E0 e riprenderlo.\r\n </p>\r\n }\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff);border-top:1px solid var(--fb-border, #d6dae1)}.fb-prob__header{display:flex;align-items:center;justify-content:space-between;padding:6px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-prob__title{display:flex;align-items:baseline;gap:8px;margin:0;font-size:13px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-prob__running{font-size:10px;font-weight:400;color:var(--fb-text-subtle, #98a2b3)}.fb-prob__filters{display:flex;gap:3px;padding:5px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-prob__filter{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:12px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}.fb-prob__filter--active{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent);color:var(--fb-accent, #2f6feb);font-weight:600}.fb-prob__filter--error.fb-prob__filter--active{border-color:var(--fb-error, #c9372c);background:color-mix(in srgb,var(--fb-error, #c9372c) 10%,transparent);color:var(--fb-error, #c9372c)}.fb-prob__filter--warning.fb-prob__filter--active{border-color:var(--fb-warning, #b7791f);background:color-mix(in srgb,var(--fb-warning, #b7791f) 12%,transparent);color:var(--fb-warning, #b7791f)}.fb-prob__count{padding:0 4px;border-radius:6px;background:var(--fb-border, #d6dae1);font-size:9px;color:var(--fb-text, #1d2939)}.fb-prob__body{flex:1;min-height:0;overflow-y:auto;padding:8px 12px}.fb-prob__list{margin:0;padding:0;list-style:none}.fb-prob__item{border-left:3px solid var(--fb-text-subtle, #98a2b3);margin-bottom:3px;border-radius:3px;background:var(--fb-surface-alt, #f8f9fb)}.fb-prob__item--error{border-left-color:var(--fb-error, #c9372c)}.fb-prob__item--warning{border-left-color:var(--fb-warning, #b7791f)}.fb-prob__link{display:flex;flex-direction:column;width:100%;padding:5px 8px;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-prob__link:hover{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 6%,transparent)}.fb-prob__message{font-size:12px;line-height:1.4}.fb-prob__meta{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-prob__note{margin:8px 0 0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6341
7084
|
}
|
|
6342
7085
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ProblemsPanelComponent, decorators: [{
|
|
6343
7086
|
type: Component,
|
|
6344
|
-
args: [{ selector: 'fb-problems-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<header class=\"fb-prob__header\">\n <h2 class=\"fb-prob__title\">\n Problemi\n @if (isRunning()) {\n <span class=\"fb-prob__running\">validazione in corso\u2026</span>\n }\n </h2>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\n</header>\n\n<nav class=\"fb-prob__filters\" aria-label=\"Filtra per gravita\u2019\">\n <button\n type=\"button\"\n class=\"fb-prob__filter\"\n [class.fb-prob__filter--active]=\"filter() === 'all'\"\n (click)=\"setFilter('all')\"\n >\n Tutti\n </button>\n <button\n type=\"button\"\n class=\"fb-prob__filter fb-prob__filter--error\"\n [class.fb-prob__filter--active]=\"filter() === 'Error'\"\n (click)=\"setFilter('Error')\"\n >\n Errori <span class=\"fb-prob__count\">{{ errorCount() }}</span>\n </button>\n <button\n type=\"button\"\n class=\"fb-prob__filter fb-prob__filter--warning\"\n [class.fb-prob__filter--active]=\"filter() === 'Warning'\"\n (click)=\"setFilter('Warning')\"\n >\n Avvisi <span class=\"fb-prob__count\">{{ warningCount() }}</span>\n </button>\n <button\n type=\"button\"\n class=\"fb-prob__filter\"\n [class.fb-prob__filter--active]=\"filter() === 'Info'\"\n (click)=\"setFilter('Info')\"\n >\n Note <span class=\"fb-prob__count\">{{ infoCount() }}</span>\n </button>\n</nav>\n\n<div class=\"fb-prob__body\">\n @if (lastError()) {\n <p class=\"fb-callout fb-callout--warn\">\n Non e\u2019 stato possibile validare: {{ lastError() }}\n </p>\n }\n\n @if (!hasResult() && !isRunning()) {\n <p class=\"fb-empty\">La validazione non e\u2019 ancora stata eseguita.</p>\n }\n\n @if (isClean()) {\n <p class=\"fb-empty\">\n Nessun rilievo. Attenzione: non e\u2019 una garanzia di correttezza \u2014 la validazione non verifica i percorsi\n di relazione nei campi, la sintassi delle formule, ne\u2019 action, form e parametri quando il catalogo\n corrispondente non e\u2019 popolato.\n </p>\n }\n\n <ul class=\"fb-prob__list\">\n <!-- `$index`: due rilievi possono avere codice, elemento e path identici (due condizioni\n incomplete nella stessa regola), e una chiave duplicata e' un errore di Angular. -->\n @for (issue of issues(); track $index) {\n <li\n class=\"fb-prob__item\"\n [class.fb-prob__item--error]=\"issue.severity === 'Error'\"\n [class.fb-prob__item--warning]=\"issue.severity === 'Warning'\"\n >\n <button type=\"button\" class=\"fb-prob__link\" (click)=\"focus(issue)\">\n <span class=\"fb-prob__message\">{{ issue.message }}</span>\n <span class=\"fb-prob__meta\">\n <code>{{ issue.code }}</code>\n @if (issue.elementName) {\n \u00B7 {{ issue.elementName }}\n }\n @if (issue.path) {\n \u00B7 {{ issue.path }}\n }\n </span>\n </button>\n </li>\n }\n </ul>\n\n @if (errorCount() > 0) {\n <p class=\"fb-prob__note\">\n Gli errori bloccano l\u2019<strong>attivazione</strong>, non il salvataggio: puoi interrompere il lavoro a\n met\u00E0 e riprenderlo.\n </p>\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff);border-top:1px solid var(--fb-border, #d6dae1)}.fb-prob__header{display:flex;align-items:center;justify-content:space-between;padding:6px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-prob__title{display:flex;align-items:baseline;gap:8px;margin:0;font-size:13px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-prob__running{font-size:10px;font-weight:400;color:var(--fb-text-subtle, #98a2b3)}.fb-prob__filters{display:flex;gap:3px;padding:5px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-prob__filter{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:12px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}.fb-prob__filter--active{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent);color:var(--fb-accent, #2f6feb);font-weight:600}.fb-prob__filter--error.fb-prob__filter--active{border-color:var(--fb-error, #c9372c);background:color-mix(in srgb,var(--fb-error, #c9372c) 10%,transparent);color:var(--fb-error, #c9372c)}.fb-prob__filter--warning.fb-prob__filter--active{border-color:var(--fb-warning, #b7791f);background:color-mix(in srgb,var(--fb-warning, #b7791f) 12%,transparent);color:var(--fb-warning, #b7791f)}.fb-prob__count{padding:0 4px;border-radius:6px;background:var(--fb-border, #d6dae1);font-size:9px;color:var(--fb-text, #1d2939)}.fb-prob__body{flex:1;min-height:0;overflow-y:auto;padding:8px 12px}.fb-prob__list{margin:0;padding:0;list-style:none}.fb-prob__item{border-left:3px solid var(--fb-text-subtle, #98a2b3);margin-bottom:3px;border-radius:3px;background:var(--fb-surface-alt, #f8f9fb)}.fb-prob__item--error{border-left-color:var(--fb-error, #c9372c)}.fb-prob__item--warning{border-left-color:var(--fb-warning, #b7791f)}.fb-prob__link{display:flex;flex-direction:column;width:100%;padding:5px 8px;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-prob__link:hover{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 6%,transparent)}.fb-prob__message{font-size:12px;line-height:1.4}.fb-prob__meta{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-prob__note{margin:8px 0 0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}\n"] }]
|
|
7087
|
+
args: [{ selector: 'fb-problems-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<header class=\"fb-prob__header\">\r\n <h2 class=\"fb-prob__title\">\r\n Problemi\r\n @if (isRunning()) {\r\n <span class=\"fb-prob__running\">validazione in corso\u2026</span>\r\n }\r\n </h2>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\r\n</header>\r\n\r\n<nav class=\"fb-prob__filters\" aria-label=\"Filtra per gravita\u2019\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-prob__filter\"\r\n [class.fb-prob__filter--active]=\"filter() === 'all'\"\r\n (click)=\"setFilter('all')\"\r\n >\r\n Tutti\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-prob__filter fb-prob__filter--error\"\r\n [class.fb-prob__filter--active]=\"filter() === 'Error'\"\r\n (click)=\"setFilter('Error')\"\r\n >\r\n Errori <span class=\"fb-prob__count\">{{ errorCount() }}</span>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-prob__filter fb-prob__filter--warning\"\r\n [class.fb-prob__filter--active]=\"filter() === 'Warning'\"\r\n (click)=\"setFilter('Warning')\"\r\n >\r\n Avvisi <span class=\"fb-prob__count\">{{ warningCount() }}</span>\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-prob__filter\"\r\n [class.fb-prob__filter--active]=\"filter() === 'Info'\"\r\n (click)=\"setFilter('Info')\"\r\n >\r\n Note <span class=\"fb-prob__count\">{{ infoCount() }}</span>\r\n </button>\r\n</nav>\r\n\r\n<div class=\"fb-prob__body\">\r\n @if (lastError()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Non e\u2019 stato possibile validare: {{ lastError() }}\r\n </p>\r\n }\r\n\r\n @if (!hasResult() && !isRunning()) {\r\n <p class=\"fb-empty\">La validazione non e\u2019 ancora stata eseguita.</p>\r\n }\r\n\r\n @if (isClean()) {\r\n <p class=\"fb-empty\">\r\n Nessun rilievo. Attenzione: non e\u2019 una garanzia di correttezza \u2014 la validazione non verifica i percorsi\r\n di relazione nei campi, la sintassi delle formule, ne\u2019 action, form e parametri quando il catalogo\r\n corrispondente non e\u2019 popolato.\r\n </p>\r\n }\r\n\r\n <ul class=\"fb-prob__list\">\r\n <!-- `$index`: due rilievi possono avere codice, elemento e path identici (due condizioni\r\n incomplete nella stessa regola), e una chiave duplicata e' un errore di Angular. -->\r\n @for (issue of issues(); track $index) {\r\n <li\r\n class=\"fb-prob__item\"\r\n [class.fb-prob__item--error]=\"issue.severity === 'Error'\"\r\n [class.fb-prob__item--warning]=\"issue.severity === 'Warning'\"\r\n >\r\n <button type=\"button\" class=\"fb-prob__link\" (click)=\"focus(issue)\">\r\n <span class=\"fb-prob__message\">{{ issue.message }}</span>\r\n <span class=\"fb-prob__meta\">\r\n <code>{{ issue.code }}</code>\r\n @if (issue.elementName) {\r\n \u00B7 {{ issue.elementName }}\r\n }\r\n @if (issue.path) {\r\n \u00B7 {{ issue.path }}\r\n }\r\n </span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n\r\n @if (errorCount() > 0) {\r\n <p class=\"fb-prob__note\">\r\n Gli errori bloccano l\u2019<strong>attivazione</strong>, non il salvataggio: puoi interrompere il lavoro a\r\n met\u00E0 e riprenderlo.\r\n </p>\r\n }\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff);border-top:1px solid var(--fb-border, #d6dae1)}.fb-prob__header{display:flex;align-items:center;justify-content:space-between;padding:6px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-prob__title{display:flex;align-items:baseline;gap:8px;margin:0;font-size:13px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-prob__running{font-size:10px;font-weight:400;color:var(--fb-text-subtle, #98a2b3)}.fb-prob__filters{display:flex;gap:3px;padding:5px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-prob__filter{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:12px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}.fb-prob__filter--active{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent);color:var(--fb-accent, #2f6feb);font-weight:600}.fb-prob__filter--error.fb-prob__filter--active{border-color:var(--fb-error, #c9372c);background:color-mix(in srgb,var(--fb-error, #c9372c) 10%,transparent);color:var(--fb-error, #c9372c)}.fb-prob__filter--warning.fb-prob__filter--active{border-color:var(--fb-warning, #b7791f);background:color-mix(in srgb,var(--fb-warning, #b7791f) 12%,transparent);color:var(--fb-warning, #b7791f)}.fb-prob__count{padding:0 4px;border-radius:6px;background:var(--fb-border, #d6dae1);font-size:9px;color:var(--fb-text, #1d2939)}.fb-prob__body{flex:1;min-height:0;overflow-y:auto;padding:8px 12px}.fb-prob__list{margin:0;padding:0;list-style:none}.fb-prob__item{border-left:3px solid var(--fb-text-subtle, #98a2b3);margin-bottom:3px;border-radius:3px;background:var(--fb-surface-alt, #f8f9fb)}.fb-prob__item--error{border-left-color:var(--fb-error, #c9372c)}.fb-prob__item--warning{border-left-color:var(--fb-warning, #b7791f)}.fb-prob__link{display:flex;flex-direction:column;width:100%;padding:5px 8px;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-prob__link:hover{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 6%,transparent)}.fb-prob__message{font-size:12px;line-height:1.4}.fb-prob__meta{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-prob__note{margin:8px 0 0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}\n"] }]
|
|
6345
7088
|
}], propDecorators: { elementFocused: [{ type: i0.Output, args: ["elementFocused"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
|
|
6346
7089
|
|
|
6347
7090
|
/**
|
|
@@ -6457,17 +7200,17 @@ class VersionPanelComponent {
|
|
|
6457
7200
|
this.closed.emit();
|
|
6458
7201
|
}
|
|
6459
7202
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: VersionPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6460
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: VersionPanelComponent, isStandalone: true, selector: "fb-version-panel", outputs: { closed: "closed", versionOpened: "versionOpened", notice: "notice" }, ngImport: i0, template: "<header class=\"fb-ver__header\">\n <h2 class=\"fb-ver__title\">Versioni</h2>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\n</header>\n\n<div class=\"fb-ver__body\">\n <div class=\"fb-field__row\">\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"isBusy()\" (click)=\"createNewVersion()\">\n Nuova versione dalla corrente\n </button>\n @if (hasActiveVersion()) {\n <button type=\"button\" class=\"fb-btn fb-btn--danger\" [disabled]=\"isBusy()\" (click)=\"deactivate()\">\n Disattiva\n </button>\n }\n </div>\n\n <ul class=\"fb-ver__list\">\n @for (version of versions(); track version.version) {\n <li class=\"fb-ver__item\" [class.fb-ver__item--current]=\"isCurrent(version)\">\n <div class=\"fb-ver__row\">\n <button type=\"button\" class=\"fb-ver__open\" (click)=\"open(version)\">\n <span class=\"fb-ver__number\">v{{ version.version }}</span>\n <span\n class=\"fb-ver__status\"\n [class.fb-ver__status--active]=\"version.isActive\"\n [class.fb-ver__status--invalid]=\"version.status === 'InvalidDraft'\"\n >\n {{ statusLabel(version) }}\n </span>\n @if (isCurrent(version)) {\n <span class=\"fb-ver__badge\">aperta</span>\n }\n </button>\n </div>\n\n <p class=\"fb-ver__meta\">\n @if (version.updatedAt) {\n aggiornata {{ version.updatedAt }}\n }\n @if (version.updatedBy) {\n da {{ version.updatedBy }}\n }\n </p>\n\n <div class=\"fb-ver__actions\">\n @if (version.isEditable) {\n <span class=\"fb-ver__hint\">Modificabile</span>\n } @else {\n <!-- Salvare su una versione Active o Obsolete verrebbe rifiutato con NotEditable. -->\n <span class=\"fb-ver__hint\">Sola lettura: per modificarla, creane una nuova</span>\n }\n\n @if (!version.isActive && isCurrent(version)) {\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--primary fb-btn--icon\"\n [disabled]=\"isBusy() || !canActivate()\"\n [title]=\"canActivate() ? 'Attiva questa versione' : 'Ci sono errori da correggere prima di attivare'\"\n (click)=\"activate(version)\"\n >\n Attiva\n </button>\n }\n\n @if (!version.isActive) {\n @if (pendingDelete() === version.version) {\n <span class=\"fb-ver__confirm\">\n Le esecuzioni sospese nate su questo numero riprenderebbero su una definizione diversa.\n <button type=\"button\" class=\"fb-btn fb-btn--danger fb-btn--icon\" (click)=\"confirmDelete(version.version)\">\n Elimina comunque\n </button>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"cancelDelete()\">\n Annulla\n </button>\n </span>\n } @else {\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\n [disabled]=\"isBusy()\"\n (click)=\"requestDelete(version)\"\n >\n Elimina\n </button>\n }\n }\n </div>\n </li>\n } @empty {\n <li class=\"fb-empty\">Nessuna versione: il flow non e\u2019 ancora stato salvato.</li>\n }\n </ul>\n\n <p class=\"fb-ver__note\">\n Una sola versione e\u2019 attiva: attivarne una rende superata la precedente, senza doverla disattivare prima.\n Le versioni superate costano poco \u2014 lo stato \u00ABSuperata\u00BB esiste per questo.\n </p>\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-ver__header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-ver__title{margin:0;font-size:14px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-ver__body{flex:1;min-height:0;overflow-y:auto;padding:10px 12px}.fb-ver__list{margin:12px 0 0;padding:0;list-style:none}.fb-ver__item{margin-bottom:6px;padding:8px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:6px;background:var(--fb-surface-alt, #f8f9fb)}.fb-ver__item--current{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 5%,transparent)}.fb-ver__open{display:flex;align-items:center;gap:6px;width:100%;padding:0;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-ver__number{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;font-weight:700}.fb-ver__status{padding:1px 6px;border-radius:8px;background:var(--fb-border, #d6dae1);font-size:10px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-ver__status--active{background:color-mix(in srgb,var(--fb-success, #3f8f5f) 18%,transparent);color:var(--fb-success, #3f8f5f)}.fb-ver__status--invalid{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-ver__badge{font-size:9px;color:var(--fb-accent, #2f6feb);text-transform:uppercase;letter-spacing:.05em}.fb-ver__meta{margin:3px 0 0;font-size:10px;color:var(--fb-text-muted, #667085)}.fb-ver__actions{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:6px}.fb-ver__hint{font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-ver__confirm{display:flex;flex-wrap:wrap;align-items:center;gap:4px;padding:5px 7px;border-radius:5px;background:color-mix(in srgb,var(--fb-error, #c9372c) 8%,transparent);font-size:10px;color:var(--fb-error, #c9372c)}.fb-ver__note{margin:12px 0 0;font-size:10px;line-height:1.45;color:var(--fb-text-subtle, #98a2b3)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7203
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: VersionPanelComponent, isStandalone: true, selector: "fb-version-panel", outputs: { closed: "closed", versionOpened: "versionOpened", notice: "notice" }, ngImport: i0, template: "<header class=\"fb-ver__header\">\r\n <h2 class=\"fb-ver__title\">Versioni</h2>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\r\n</header>\r\n\r\n<div class=\"fb-ver__body\">\r\n <div class=\"fb-field__row\">\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"isBusy()\" (click)=\"createNewVersion()\">\r\n Nuova versione dalla corrente\r\n </button>\r\n @if (hasActiveVersion()) {\r\n <button type=\"button\" class=\"fb-btn fb-btn--danger\" [disabled]=\"isBusy()\" (click)=\"deactivate()\">\r\n Disattiva\r\n </button>\r\n }\r\n </div>\r\n\r\n <ul class=\"fb-ver__list\">\r\n @for (version of versions(); track version.version) {\r\n <li class=\"fb-ver__item\" [class.fb-ver__item--current]=\"isCurrent(version)\">\r\n <div class=\"fb-ver__row\">\r\n <button type=\"button\" class=\"fb-ver__open\" (click)=\"open(version)\">\r\n <span class=\"fb-ver__number\">v{{ version.version }}</span>\r\n <span\r\n class=\"fb-ver__status\"\r\n [class.fb-ver__status--active]=\"version.isActive\"\r\n [class.fb-ver__status--invalid]=\"version.status === 'InvalidDraft'\"\r\n >\r\n {{ statusLabel(version) }}\r\n </span>\r\n @if (isCurrent(version)) {\r\n <span class=\"fb-ver__badge\">aperta</span>\r\n }\r\n </button>\r\n </div>\r\n\r\n <p class=\"fb-ver__meta\">\r\n @if (version.updatedAt) {\r\n aggiornata {{ version.updatedAt }}\r\n }\r\n @if (version.updatedBy) {\r\n da {{ version.updatedBy }}\r\n }\r\n </p>\r\n\r\n <div class=\"fb-ver__actions\">\r\n @if (version.isEditable) {\r\n <span class=\"fb-ver__hint\">Modificabile</span>\r\n } @else {\r\n <!-- Salvare su una versione Active o Obsolete verrebbe rifiutato con NotEditable. -->\r\n <span class=\"fb-ver__hint\">Sola lettura: per modificarla, creane una nuova</span>\r\n }\r\n\r\n @if (!version.isActive && isCurrent(version)) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--primary fb-btn--icon\"\r\n [disabled]=\"isBusy() || !canActivate()\"\r\n [title]=\"canActivate() ? 'Attiva questa versione' : 'Ci sono errori da correggere prima di attivare'\"\r\n (click)=\"activate(version)\"\r\n >\r\n Attiva\r\n </button>\r\n }\r\n\r\n @if (!version.isActive) {\r\n @if (pendingDelete() === version.version) {\r\n <span class=\"fb-ver__confirm\">\r\n Le esecuzioni sospese nate su questo numero riprenderebbero su una definizione diversa.\r\n <button type=\"button\" class=\"fb-btn fb-btn--danger fb-btn--icon\" (click)=\"confirmDelete(version.version)\">\r\n Elimina comunque\r\n </button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"cancelDelete()\">\r\n Annulla\r\n </button>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n [disabled]=\"isBusy()\"\r\n (click)=\"requestDelete(version)\"\r\n >\r\n Elimina\r\n </button>\r\n }\r\n }\r\n </div>\r\n </li>\r\n } @empty {\r\n <li class=\"fb-empty\">Nessuna versione: il flow non e\u2019 ancora stato salvato.</li>\r\n }\r\n </ul>\r\n\r\n <p class=\"fb-ver__note\">\r\n Una sola versione e\u2019 attiva: attivarne una rende superata la precedente, senza doverla disattivare prima.\r\n Le versioni superate costano poco \u2014 lo stato \u00ABSuperata\u00BB esiste per questo.\r\n </p>\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-ver__header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-ver__title{margin:0;font-size:14px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-ver__body{flex:1;min-height:0;overflow-y:auto;padding:10px 12px}.fb-ver__list{margin:12px 0 0;padding:0;list-style:none}.fb-ver__item{margin-bottom:6px;padding:8px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:6px;background:var(--fb-surface-alt, #f8f9fb)}.fb-ver__item--current{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 5%,transparent)}.fb-ver__open{display:flex;align-items:center;gap:6px;width:100%;padding:0;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-ver__number{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;font-weight:700}.fb-ver__status{padding:1px 6px;border-radius:8px;background:var(--fb-border, #d6dae1);font-size:10px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-ver__status--active{background:color-mix(in srgb,var(--fb-success, #3f8f5f) 18%,transparent);color:var(--fb-success, #3f8f5f)}.fb-ver__status--invalid{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-ver__badge{font-size:9px;color:var(--fb-accent, #2f6feb);text-transform:uppercase;letter-spacing:.05em}.fb-ver__meta{margin:3px 0 0;font-size:10px;color:var(--fb-text-muted, #667085)}.fb-ver__actions{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:6px}.fb-ver__hint{font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-ver__confirm{display:flex;flex-wrap:wrap;align-items:center;gap:4px;padding:5px 7px;border-radius:5px;background:color-mix(in srgb,var(--fb-error, #c9372c) 8%,transparent);font-size:10px;color:var(--fb-error, #c9372c)}.fb-ver__note{margin:12px 0 0;font-size:10px;line-height:1.45;color:var(--fb-text-subtle, #98a2b3)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6461
7204
|
}
|
|
6462
7205
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: VersionPanelComponent, decorators: [{
|
|
6463
7206
|
type: Component,
|
|
6464
|
-
args: [{ selector: 'fb-version-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<header class=\"fb-ver__header\">\n <h2 class=\"fb-ver__title\">Versioni</h2>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\n</header>\n\n<div class=\"fb-ver__body\">\n <div class=\"fb-field__row\">\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"isBusy()\" (click)=\"createNewVersion()\">\n Nuova versione dalla corrente\n </button>\n @if (hasActiveVersion()) {\n <button type=\"button\" class=\"fb-btn fb-btn--danger\" [disabled]=\"isBusy()\" (click)=\"deactivate()\">\n Disattiva\n </button>\n }\n </div>\n\n <ul class=\"fb-ver__list\">\n @for (version of versions(); track version.version) {\n <li class=\"fb-ver__item\" [class.fb-ver__item--current]=\"isCurrent(version)\">\n <div class=\"fb-ver__row\">\n <button type=\"button\" class=\"fb-ver__open\" (click)=\"open(version)\">\n <span class=\"fb-ver__number\">v{{ version.version }}</span>\n <span\n class=\"fb-ver__status\"\n [class.fb-ver__status--active]=\"version.isActive\"\n [class.fb-ver__status--invalid]=\"version.status === 'InvalidDraft'\"\n >\n {{ statusLabel(version) }}\n </span>\n @if (isCurrent(version)) {\n <span class=\"fb-ver__badge\">aperta</span>\n }\n </button>\n </div>\n\n <p class=\"fb-ver__meta\">\n @if (version.updatedAt) {\n aggiornata {{ version.updatedAt }}\n }\n @if (version.updatedBy) {\n da {{ version.updatedBy }}\n }\n </p>\n\n <div class=\"fb-ver__actions\">\n @if (version.isEditable) {\n <span class=\"fb-ver__hint\">Modificabile</span>\n } @else {\n <!-- Salvare su una versione Active o Obsolete verrebbe rifiutato con NotEditable. -->\n <span class=\"fb-ver__hint\">Sola lettura: per modificarla, creane una nuova</span>\n }\n\n @if (!version.isActive && isCurrent(version)) {\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--primary fb-btn--icon\"\n [disabled]=\"isBusy() || !canActivate()\"\n [title]=\"canActivate() ? 'Attiva questa versione' : 'Ci sono errori da correggere prima di attivare'\"\n (click)=\"activate(version)\"\n >\n Attiva\n </button>\n }\n\n @if (!version.isActive) {\n @if (pendingDelete() === version.version) {\n <span class=\"fb-ver__confirm\">\n Le esecuzioni sospese nate su questo numero riprenderebbero su una definizione diversa.\n <button type=\"button\" class=\"fb-btn fb-btn--danger fb-btn--icon\" (click)=\"confirmDelete(version.version)\">\n Elimina comunque\n </button>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"cancelDelete()\">\n Annulla\n </button>\n </span>\n } @else {\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\n [disabled]=\"isBusy()\"\n (click)=\"requestDelete(version)\"\n >\n Elimina\n </button>\n }\n }\n </div>\n </li>\n } @empty {\n <li class=\"fb-empty\">Nessuna versione: il flow non e\u2019 ancora stato salvato.</li>\n }\n </ul>\n\n <p class=\"fb-ver__note\">\n Una sola versione e\u2019 attiva: attivarne una rende superata la precedente, senza doverla disattivare prima.\n Le versioni superate costano poco \u2014 lo stato \u00ABSuperata\u00BB esiste per questo.\n </p>\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-ver__header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-ver__title{margin:0;font-size:14px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-ver__body{flex:1;min-height:0;overflow-y:auto;padding:10px 12px}.fb-ver__list{margin:12px 0 0;padding:0;list-style:none}.fb-ver__item{margin-bottom:6px;padding:8px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:6px;background:var(--fb-surface-alt, #f8f9fb)}.fb-ver__item--current{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 5%,transparent)}.fb-ver__open{display:flex;align-items:center;gap:6px;width:100%;padding:0;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-ver__number{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;font-weight:700}.fb-ver__status{padding:1px 6px;border-radius:8px;background:var(--fb-border, #d6dae1);font-size:10px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-ver__status--active{background:color-mix(in srgb,var(--fb-success, #3f8f5f) 18%,transparent);color:var(--fb-success, #3f8f5f)}.fb-ver__status--invalid{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-ver__badge{font-size:9px;color:var(--fb-accent, #2f6feb);text-transform:uppercase;letter-spacing:.05em}.fb-ver__meta{margin:3px 0 0;font-size:10px;color:var(--fb-text-muted, #667085)}.fb-ver__actions{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:6px}.fb-ver__hint{font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-ver__confirm{display:flex;flex-wrap:wrap;align-items:center;gap:4px;padding:5px 7px;border-radius:5px;background:color-mix(in srgb,var(--fb-error, #c9372c) 8%,transparent);font-size:10px;color:var(--fb-error, #c9372c)}.fb-ver__note{margin:12px 0 0;font-size:10px;line-height:1.45;color:var(--fb-text-subtle, #98a2b3)}\n"] }]
|
|
7207
|
+
args: [{ selector: 'fb-version-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<header class=\"fb-ver__header\">\r\n <h2 class=\"fb-ver__title\">Versioni</h2>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\r\n</header>\r\n\r\n<div class=\"fb-ver__body\">\r\n <div class=\"fb-field__row\">\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"isBusy()\" (click)=\"createNewVersion()\">\r\n Nuova versione dalla corrente\r\n </button>\r\n @if (hasActiveVersion()) {\r\n <button type=\"button\" class=\"fb-btn fb-btn--danger\" [disabled]=\"isBusy()\" (click)=\"deactivate()\">\r\n Disattiva\r\n </button>\r\n }\r\n </div>\r\n\r\n <ul class=\"fb-ver__list\">\r\n @for (version of versions(); track version.version) {\r\n <li class=\"fb-ver__item\" [class.fb-ver__item--current]=\"isCurrent(version)\">\r\n <div class=\"fb-ver__row\">\r\n <button type=\"button\" class=\"fb-ver__open\" (click)=\"open(version)\">\r\n <span class=\"fb-ver__number\">v{{ version.version }}</span>\r\n <span\r\n class=\"fb-ver__status\"\r\n [class.fb-ver__status--active]=\"version.isActive\"\r\n [class.fb-ver__status--invalid]=\"version.status === 'InvalidDraft'\"\r\n >\r\n {{ statusLabel(version) }}\r\n </span>\r\n @if (isCurrent(version)) {\r\n <span class=\"fb-ver__badge\">aperta</span>\r\n }\r\n </button>\r\n </div>\r\n\r\n <p class=\"fb-ver__meta\">\r\n @if (version.updatedAt) {\r\n aggiornata {{ version.updatedAt }}\r\n }\r\n @if (version.updatedBy) {\r\n da {{ version.updatedBy }}\r\n }\r\n </p>\r\n\r\n <div class=\"fb-ver__actions\">\r\n @if (version.isEditable) {\r\n <span class=\"fb-ver__hint\">Modificabile</span>\r\n } @else {\r\n <!-- Salvare su una versione Active o Obsolete verrebbe rifiutato con NotEditable. -->\r\n <span class=\"fb-ver__hint\">Sola lettura: per modificarla, creane una nuova</span>\r\n }\r\n\r\n @if (!version.isActive && isCurrent(version)) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--primary fb-btn--icon\"\r\n [disabled]=\"isBusy() || !canActivate()\"\r\n [title]=\"canActivate() ? 'Attiva questa versione' : 'Ci sono errori da correggere prima di attivare'\"\r\n (click)=\"activate(version)\"\r\n >\r\n Attiva\r\n </button>\r\n }\r\n\r\n @if (!version.isActive) {\r\n @if (pendingDelete() === version.version) {\r\n <span class=\"fb-ver__confirm\">\r\n Le esecuzioni sospese nate su questo numero riprenderebbero su una definizione diversa.\r\n <button type=\"button\" class=\"fb-btn fb-btn--danger fb-btn--icon\" (click)=\"confirmDelete(version.version)\">\r\n Elimina comunque\r\n </button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"cancelDelete()\">\r\n Annulla\r\n </button>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n [disabled]=\"isBusy()\"\r\n (click)=\"requestDelete(version)\"\r\n >\r\n Elimina\r\n </button>\r\n }\r\n }\r\n </div>\r\n </li>\r\n } @empty {\r\n <li class=\"fb-empty\">Nessuna versione: il flow non e\u2019 ancora stato salvato.</li>\r\n }\r\n </ul>\r\n\r\n <p class=\"fb-ver__note\">\r\n Una sola versione e\u2019 attiva: attivarne una rende superata la precedente, senza doverla disattivare prima.\r\n Le versioni superate costano poco \u2014 lo stato \u00ABSuperata\u00BB esiste per questo.\r\n </p>\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-ver__header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-ver__title{margin:0;font-size:14px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-ver__body{flex:1;min-height:0;overflow-y:auto;padding:10px 12px}.fb-ver__list{margin:12px 0 0;padding:0;list-style:none}.fb-ver__item{margin-bottom:6px;padding:8px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:6px;background:var(--fb-surface-alt, #f8f9fb)}.fb-ver__item--current{border-color:var(--fb-accent, #2f6feb);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 5%,transparent)}.fb-ver__open{display:flex;align-items:center;gap:6px;width:100%;padding:0;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-ver__number{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;font-weight:700}.fb-ver__status{padding:1px 6px;border-radius:8px;background:var(--fb-border, #d6dae1);font-size:10px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-ver__status--active{background:color-mix(in srgb,var(--fb-success, #3f8f5f) 18%,transparent);color:var(--fb-success, #3f8f5f)}.fb-ver__status--invalid{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-ver__badge{font-size:9px;color:var(--fb-accent, #2f6feb);text-transform:uppercase;letter-spacing:.05em}.fb-ver__meta{margin:3px 0 0;font-size:10px;color:var(--fb-text-muted, #667085)}.fb-ver__actions{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:6px}.fb-ver__hint{font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-ver__confirm{display:flex;flex-wrap:wrap;align-items:center;gap:4px;padding:5px 7px;border-radius:5px;background:color-mix(in srgb,var(--fb-error, #c9372c) 8%,transparent);font-size:10px;color:var(--fb-error, #c9372c)}.fb-ver__note{margin:12px 0 0;font-size:10px;line-height:1.45;color:var(--fb-text-subtle, #98a2b3)}\n"] }]
|
|
6465
7208
|
}], propDecorators: { closed: [{ type: i0.Output, args: ["closed"] }], versionOpened: [{ type: i0.Output, args: ["versionOpened"] }], notice: [{ type: i0.Output, args: ["notice"] }] } });
|
|
6466
7209
|
|
|
6467
7210
|
/**
|
|
6468
7211
|
* Provare un flow dall'editor — FRONTEND.md §6.5, §11 ("Provare").
|
|
6469
7212
|
*
|
|
6470
|
-
*
|
|
7213
|
+
* Sei cose che questo pannello tratta come dette:
|
|
6471
7214
|
* 1. `status: 'Failed'` **non** e' un errore di trasporto: la richiesta e' riuscita, il flow
|
|
6472
7215
|
* e' fallito. E `NotStarted` significa che i criteri dello Start non erano soddisfatti,
|
|
6473
7216
|
* che non e' un errore.
|
|
@@ -6479,6 +7222,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
|
|
|
6479
7222
|
* sono definitivi, e il pannello lo dice.
|
|
6480
7223
|
* 5. `debug: true` popola `trace` e `resources` — **e riporta anche i dati personali**:
|
|
6481
7224
|
* l'avviso e' in chiaro, non nascosto in una tooltip.
|
|
7225
|
+
* 6. `Suspended` copre due attese diverse — un evento e uno step di orchestrazione — e le
|
|
7226
|
+
* distinguono `isWaitingForEvent` / `isWaitingForStageStep`. Nel secondo caso si puo'
|
|
7227
|
+
* concludere lo step da qui, e la risposta puo' portare una `interviewKey` **nuova**: la
|
|
7228
|
+
* vecchia non e' piu' valida, quindi si sostituisce invece di conservarla (§5.13).
|
|
6482
7229
|
*/
|
|
6483
7230
|
class DebugPanelComponent {
|
|
6484
7231
|
api = inject(FlowBuilderApi);
|
|
@@ -6501,6 +7248,13 @@ class DebugPanelComponent {
|
|
|
6501
7248
|
status = computed(() => this.result()?.status ?? null, ...(ngDevMode ? [{ debugName: "status" }] : []));
|
|
6502
7249
|
pendingScreen = computed(() => this.result()?.pendingScreen ?? null, ...(ngDevMode ? [{ debugName: "pendingScreen" }] : []));
|
|
6503
7250
|
isWaitingForScreen = computed(() => this.status() === 'WaitingForScreen', ...(ngDevMode ? [{ debugName: "isWaitingForScreen" }] : []));
|
|
7251
|
+
/** §5.13 — l'attesa e' su uno step assegnato a una persona, non su un evento. */
|
|
7252
|
+
isWaitingForStageStep = computed(() => this.result()?.isWaitingForStageStep === true, ...(ngDevMode ? [{ debugName: "isWaitingForStageStep" }] : []));
|
|
7253
|
+
stageSteps = computed(() => this.result()?.stageSteps ?? [], ...(ngDevMode ? [{ debugName: "stageSteps" }] : []));
|
|
7254
|
+
/** Lo step su cui c'e' un work item aperto: e' quello che si puo' concludere. */
|
|
7255
|
+
waitingStageSteps = computed(() => this.stageSteps().filter((step) => step.isWaiting), ...(ngDevMode ? [{ debugName: "waitingStageSteps" }] : []));
|
|
7256
|
+
/** I valori con cui si conclude uno step, per nome di output. */
|
|
7257
|
+
stepOutputs = signal({}, ...(ngDevMode ? [{ debugName: "stepOutputs" }] : []));
|
|
6504
7258
|
trace = computed(() => this.result()?.trace ?? [], ...(ngDevMode ? [{ debugName: "trace" }] : []));
|
|
6505
7259
|
/** Le risorse come righe ordinate: il tipo dichiarato vince in lettura (§6.5). */
|
|
6506
7260
|
resourceRows = computed(() => {
|
|
@@ -6648,6 +7402,53 @@ class DebugPanelComponent {
|
|
|
6648
7402
|
this.isRunning.set(false);
|
|
6649
7403
|
}
|
|
6650
7404
|
}
|
|
7405
|
+
setStepOutput(name, value) {
|
|
7406
|
+
this.stepOutputs.update((values) => ({ ...values, [name]: value }));
|
|
7407
|
+
}
|
|
7408
|
+
/** Gli output dichiarati dallo step, per generare i campi da compilare. */
|
|
7409
|
+
stepOutputNames(stepName) {
|
|
7410
|
+
if (!stepName) {
|
|
7411
|
+
return [];
|
|
7412
|
+
}
|
|
7413
|
+
for (const stage of this.store.document().orchestratedStages ?? []) {
|
|
7414
|
+
const step = stage.stageSteps?.find((candidate) => candidate.name === stepName);
|
|
7415
|
+
if (step) {
|
|
7416
|
+
return (step.outputParameters ?? []).map((parameter) => parameter.name ?? '').filter(Boolean);
|
|
7417
|
+
}
|
|
7418
|
+
}
|
|
7419
|
+
return [];
|
|
7420
|
+
}
|
|
7421
|
+
/**
|
|
7422
|
+
* Conclude uno step come farebbe l'assegnatario. `Rejected` non e' un errore: e' l'esito che
|
|
7423
|
+
* prende il ramo «Step rifiutato» dello stage — e se quel ramo non c'e', l'interview fallisce.
|
|
7424
|
+
*/
|
|
7425
|
+
async completeStep(stepName, status) {
|
|
7426
|
+
const key = this.result()?.interviewKey;
|
|
7427
|
+
if (!key || !stepName) {
|
|
7428
|
+
return;
|
|
7429
|
+
}
|
|
7430
|
+
this.isRunning.set(true);
|
|
7431
|
+
this.errorMessage.set(null);
|
|
7432
|
+
try {
|
|
7433
|
+
const result = await this.api.completeStageStep({
|
|
7434
|
+
interviewKey: key,
|
|
7435
|
+
stepName,
|
|
7436
|
+
status,
|
|
7437
|
+
stepOutputs: this.stepOutputs(),
|
|
7438
|
+
debug: this.debugEnabled(),
|
|
7439
|
+
});
|
|
7440
|
+
this.stepOutputs.set({});
|
|
7441
|
+
// La risposta puo' portare una chiave nuova: `apply` sostituisce il risultato intero,
|
|
7442
|
+
// quindi la vecchia chiave non resta in giro.
|
|
7443
|
+
this.apply(result);
|
|
7444
|
+
}
|
|
7445
|
+
catch (error) {
|
|
7446
|
+
this.handleError(error);
|
|
7447
|
+
}
|
|
7448
|
+
finally {
|
|
7449
|
+
this.isRunning.set(false);
|
|
7450
|
+
}
|
|
7451
|
+
}
|
|
6651
7452
|
apply(result) {
|
|
6652
7453
|
this.result.set(result);
|
|
6653
7454
|
if (result.currentElementName) {
|
|
@@ -6666,6 +7467,7 @@ class DebugPanelComponent {
|
|
|
6666
7467
|
this.result.set(null);
|
|
6667
7468
|
this.errorMessage.set(null);
|
|
6668
7469
|
this.screenOutputs.set({});
|
|
7470
|
+
this.stepOutputs.set({});
|
|
6669
7471
|
}
|
|
6670
7472
|
close() {
|
|
6671
7473
|
this.closed.emit();
|
|
@@ -6696,8 +7498,15 @@ class DebugPanelComponent {
|
|
|
6696
7498
|
case 'NotStarted':
|
|
6697
7499
|
return 'I criteri dello Start non erano soddisfatti: non e’ un errore.';
|
|
6698
7500
|
case 'Paused':
|
|
7501
|
+
return 'L’esecuzione e’ in pausa: puo’ essere ripresa dalla sua chiave.';
|
|
6699
7502
|
case 'Suspended':
|
|
6700
|
-
|
|
7503
|
+
// Due attese diverse sotto lo stesso stato: dirlo evita di cercare l'evento sbagliato.
|
|
7504
|
+
if (this.isWaitingForStageStep()) {
|
|
7505
|
+
return 'Sospesa su uno step di orchestrazione: aspetta che un assegnatario lo concluda.';
|
|
7506
|
+
}
|
|
7507
|
+
return this.result()?.isWaitingForEvent
|
|
7508
|
+
? 'Sospesa in attesa di un evento: puo’ essere ripresa dalla sua chiave.'
|
|
7509
|
+
: 'L’esecuzione e’ sospesa: puo’ essere ripresa dalla sua chiave.';
|
|
6701
7510
|
default:
|
|
6702
7511
|
return null;
|
|
6703
7512
|
}
|
|
@@ -6712,11 +7521,11 @@ class DebugPanelComponent {
|
|
|
6712
7521
|
return this.pendingScreen()?.canPause === true;
|
|
6713
7522
|
}
|
|
6714
7523
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: DebugPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6715
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: DebugPanelComponent, isStandalone: true, selector: "fb-debug-panel", outputs: { closed: "closed", elementFocused: "elementFocused" }, ngImport: i0, template: "<header class=\"fb-dbg__header\">\n <h2 class=\"fb-dbg__title\">Prova</h2>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\n</header>\n\n<div class=\"fb-dbg__body\">\n @if (errorMessage()) {\n <p class=\"fb-callout fb-callout--error\">{{ errorMessage() }}</p>\n }\n\n @if (!result()) {\n <fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">Valori iniziali</legend>\n @if (inputVariables().length) {\n @for (variable of inputVariables(); track variable.name) {\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">\n {{ variable.name }}\n <span class=\"fb-dbg__type\">{{ variable.dataType }}{{ variable.isCollection ? '[]' : '' }}</span>\n </label>\n @if (variable.dataType === 'Boolean') {\n <select class=\"fb-select\" (change)=\"setInputValue(variable.name!, $any($event.target).value)\">\n <option value=\"\">\u2014</option>\n <option value=\"true\">vero</option>\n <option value=\"false\">falso</option>\n </select>\n } @else {\n <input\n class=\"fb-input\"\n [type]=\"variable.dataType === 'Number' || variable.dataType === 'Integer' ? 'number' : 'text'\"\n (input)=\"setInputValue(variable.name!, $any($event.target).value)\"\n />\n }\n </div>\n }\n } @else {\n <p class=\"fb-field__hint\">Il flow non dichiara variabili di input.</p>\n }\n </fieldset>\n\n <label class=\"fb-check\">\n <input\n type=\"checkbox\"\n [checked]=\"debugEnabled()\"\n (change)=\"setDebugEnabled($any($event.target).checked)\"\n />\n Traccia di debug\n </label>\n @if (debugEnabled()) {\n <p class=\"fb-callout fb-callout--warn\">\n La traccia riporta i valori di <strong>tutte</strong> le risorse, dati personali compresi: non usarla\n su dati reali.\n </p>\n }\n\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"!canRun()\" (click)=\"start()\">\n Avvia\n </button>\n @if (!canRun() && !isRunning()) {\n <p class=\"fb-field__hint\">Salva il flow prima di provarlo.</p>\n }\n }\n\n @if (result()) {\n <div class=\"fb-dbg__status\">\n <span\n class=\"fb-dbg__badge\"\n [class.fb-dbg__badge--ok]=\"status() === 'Completed'\"\n [class.fb-dbg__badge--fail]=\"status() === 'Failed'\"\n [class.fb-dbg__badge--wait]=\"isWaitingForScreen()\"\n >\n {{ statusLabel() }}\n </span>\n @if (result()?.currentElementName) {\n <span class=\"fb-dbg__current\">su {{ result()?.currentElementName }}</span>\n }\n <span class=\"fb-dbg__steps\">{{ result()?.steps || 0 }} passi</span>\n <span class=\"fb-list__spacer\"></span>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"reset()\">Riavvia</button>\n </div>\n\n @if (statusNote()) {\n <p class=\"fb-callout\">{{ statusNote() }}</p>\n }\n\n @if (result()?.fault) {\n <p class=\"fb-callout fb-callout--error\">{{ result()?.fault }}</p>\n }\n @for (message of result()?.errors || []; track message) {\n <p class=\"fb-callout fb-callout--error\">{{ message }}</p>\n }\n\n @if (isWaitingForScreen() && pendingScreen()) {\n <fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">\n Form \u00AB{{ pendingScreen()?.formName }}\u00BB\n </legend>\n <p class=\"fb-section__note\">\n Nell\u2019editor basta un form generico: qui vedi i valori che il form riceve e puoi compilare quelli\n che dichiara di restituire.\n </p>\n\n @if (pendingScreen()?.label) {\n <p class=\"fb-dbg__screen-label\">{{ pendingScreen()?.label }}</p>\n }\n @if (pendingScreen()?.helpText) {\n <p class=\"fb-field__hint\">{{ pendingScreen()?.helpText }}</p>\n }\n\n @if (screenInputRows().length) {\n <table class=\"fb-dbg__table\">\n <caption>\n Valori in ingresso\n </caption>\n <tbody>\n @for (row of screenInputRows(); track row.name) {\n <tr>\n <th scope=\"row\">{{ row.name }}</th>\n <td class=\"fb-dbg__type\">{{ row.type }}</td>\n <td>{{ row.value }}</td>\n </tr>\n }\n </tbody>\n </table>\n }\n\n @for (output of screenOutputNames(); track output) {\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">{{ output }}</label>\n <input class=\"fb-input\" (input)=\"setScreenOutput(output, $any($event.target).value)\" />\n </div>\n }\n @if (!screenOutputNames().length) {\n <p class=\"fb-field__hint\">Lo screen non dichiara parametri di uscita.</p>\n }\n\n <div class=\"fb-field__row\">\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--primary\"\n [disabled]=\"isRunning()\"\n (click)=\"respond('Next')\"\n >\n Avanti\n </button>\n <!-- canGoBack/canFinish/canPause sono la verita', piu' precisa dei flag del metadata. -->\n <button\n type=\"button\"\n class=\"fb-btn\"\n [disabled]=\"isRunning() || !canGoBack()\"\n title=\"Con \u00ABindietro\u00BB gli output non vengono memorizzati\"\n (click)=\"respond('Previous')\"\n >\n Indietro\n </button>\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"isRunning() || !canFinish()\" (click)=\"respond('Finish')\">\n Fine\n </button>\n <button\n type=\"button\"\n class=\"fb-btn\"\n [disabled]=\"isRunning() || !canPause()\"\n title=\"Con \u00ABpausa\u00BB gli output non vengono memorizzati\"\n (click)=\"respond('Pause')\"\n >\n Pausa\n </button>\n </div>\n <p class=\"fb-field__hint\">\n Con \u00ABindietro\u00BB e \u00ABpausa\u00BB i valori inseriti <strong>non</strong> vengono memorizzati.\n </p>\n </fieldset>\n }\n\n @if (outputRows().length) {\n <fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">Output del flow</legend>\n <table class=\"fb-dbg__table\">\n <tbody>\n @for (row of outputRows(); track row.name) {\n <tr>\n <th scope=\"row\">{{ row.name }}</th>\n <td class=\"fb-dbg__type\">{{ row.type }}</td>\n <td>{{ row.value }}</td>\n </tr>\n }\n </tbody>\n </table>\n </fieldset>\n }\n\n @if (trace().length) {\n <fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">Traccia</legend>\n <ol class=\"fb-dbg__trace\">\n @for (entry of trace(); track entry.sequence) {\n <li class=\"fb-dbg__trace-item\">\n <span class=\"fb-dbg__trace-seq\">{{ entry.sequence }}</span>\n @if (entry.elementName) {\n <button type=\"button\" class=\"fb-dbg__trace-el\" (click)=\"elementFocused.emit(entry.elementName!)\">\n {{ entry.elementName }}\n </button>\n }\n <span class=\"fb-dbg__trace-msg\">{{ entry.message }}</span>\n </li>\n }\n </ol>\n </fieldset>\n }\n\n @if (resourceRows().length) {\n <fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">Risorse</legend>\n <table class=\"fb-dbg__table\">\n <tbody>\n @for (row of resourceRows(); track row.name) {\n <tr>\n <th scope=\"row\">{{ row.name }}</th>\n <td class=\"fb-dbg__type\">{{ row.type }}</td>\n <td>{{ row.value }}</td>\n </tr>\n }\n </tbody>\n </table>\n </fieldset>\n }\n\n @if (result()?.interviewKey) {\n <p class=\"fb-field__hint\">\n Chiave dell\u2019esecuzione sospesa: <code>{{ result()?.interviewKey }}</code>\n </p>\n }\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-dbg__header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-dbg__title{margin:0;font-size:14px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__body{flex:1;min-height:0;overflow-y:auto;padding:10px 12px}.fb-dbg__status{display:flex;align-items:center;gap:8px;margin-bottom:10px}.fb-dbg__badge{padding:2px 8px;border-radius:10px;background:var(--fb-border, #d6dae1);font-size:11px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__badge--ok{background:color-mix(in srgb,var(--fb-success, #3f8f5f) 18%,transparent);color:var(--fb-success, #3f8f5f)}.fb-dbg__badge--fail{background:color-mix(in srgb,var(--fb-error, #c9372c) 14%,transparent);color:var(--fb-error, #c9372c)}.fb-dbg__badge--wait{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 12%,transparent);color:var(--fb-accent, #2f6feb)}.fb-dbg__current,.fb-dbg__steps{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-dbg__type{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-subtle, #98a2b3)}.fb-dbg__screen-label{margin:0 0 4px;font-size:12px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__table{width:100%;border-collapse:collapse;font-size:11px}.fb-dbg__table caption{padding-bottom:3px;font-size:10px;color:var(--fb-text-subtle, #98a2b3);text-align:left}.fb-dbg__table th,.fb-dbg__table td{padding:3px 5px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee);text-align:left;vertical-align:top}.fb-dbg__table th{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__table td{color:var(--fb-text-muted, #667085);word-break:break-word}.fb-dbg__trace{margin:0;padding:0;list-style:none}.fb-dbg__trace-item{display:flex;gap:6px;padding:3px 0;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee);font-size:11px}.fb-dbg__trace-seq{flex:0 0 auto;width:18px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-subtle, #98a2b3);text-align:right}.fb-dbg__trace-el{flex:0 0 auto;padding:0;border:0;background:transparent;color:var(--fb-accent, #2f6feb);font:inherit;font-size:10px;cursor:pointer;text-decoration:underline}.fb-dbg__trace-msg{color:var(--fb-text-muted, #667085);line-height:1.35}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7524
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: DebugPanelComponent, isStandalone: true, selector: "fb-debug-panel", outputs: { closed: "closed", elementFocused: "elementFocused" }, ngImport: i0, template: "<header class=\"fb-dbg__header\">\r\n <h2 class=\"fb-dbg__title\">Prova</h2>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\r\n</header>\r\n\r\n<div class=\"fb-dbg__body\">\r\n @if (errorMessage()) {\r\n <p class=\"fb-callout fb-callout--error\">{{ errorMessage() }}</p>\r\n }\r\n\r\n @if (!result()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Valori iniziali</legend>\r\n @if (inputVariables().length) {\r\n @for (variable of inputVariables(); track variable.name) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">\r\n {{ variable.name }}\r\n <span class=\"fb-dbg__type\">{{ variable.dataType }}{{ variable.isCollection ? '[]' : '' }}</span>\r\n </label>\r\n @if (variable.dataType === 'Boolean') {\r\n <select class=\"fb-select\" (change)=\"setInputValue(variable.name!, $any($event.target).value)\">\r\n <option value=\"\">\u2014</option>\r\n <option value=\"true\">vero</option>\r\n <option value=\"false\">falso</option>\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [type]=\"variable.dataType === 'Number' || variable.dataType === 'Integer' ? 'number' : 'text'\"\r\n (input)=\"setInputValue(variable.name!, $any($event.target).value)\"\r\n />\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <p class=\"fb-field__hint\">Il flow non dichiara variabili di input.</p>\r\n }\r\n </fieldset>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"debugEnabled()\"\r\n (change)=\"setDebugEnabled($any($event.target).checked)\"\r\n />\r\n Traccia di debug\r\n </label>\r\n @if (debugEnabled()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n La traccia riporta i valori di <strong>tutte</strong> le risorse, dati personali compresi: non usarla\r\n su dati reali.\r\n </p>\r\n }\r\n\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"!canRun()\" (click)=\"start()\">\r\n Avvia\r\n </button>\r\n @if (!canRun() && !isRunning()) {\r\n <p class=\"fb-field__hint\">Salva il flow prima di provarlo.</p>\r\n }\r\n }\r\n\r\n @if (result()) {\r\n <div class=\"fb-dbg__status\">\r\n <span\r\n class=\"fb-dbg__badge\"\r\n [class.fb-dbg__badge--ok]=\"status() === 'Completed'\"\r\n [class.fb-dbg__badge--fail]=\"status() === 'Failed'\"\r\n [class.fb-dbg__badge--wait]=\"isWaitingForScreen()\"\r\n >\r\n {{ statusLabel() }}\r\n </span>\r\n @if (result()?.currentElementName) {\r\n <span class=\"fb-dbg__current\">su {{ result()?.currentElementName }}</span>\r\n }\r\n <span class=\"fb-dbg__steps\">{{ result()?.steps || 0 }} passi</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"reset()\">Riavvia</button>\r\n </div>\r\n\r\n @if (statusNote()) {\r\n <p class=\"fb-callout\">{{ statusNote() }}</p>\r\n }\r\n\r\n @if (result()?.fault) {\r\n <p class=\"fb-callout fb-callout--error\">{{ result()?.fault }}</p>\r\n }\r\n @for (message of result()?.errors || []; track message) {\r\n <p class=\"fb-callout fb-callout--error\">{{ message }}</p>\r\n }\r\n\r\n @if (isWaitingForScreen() && pendingScreen()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">\r\n Form \u00AB{{ pendingScreen()?.formName }}\u00BB\r\n </legend>\r\n <p class=\"fb-section__note\">\r\n Nell\u2019editor basta un form generico: qui vedi i valori che il form riceve e puoi compilare quelli\r\n che dichiara di restituire.\r\n </p>\r\n\r\n @if (pendingScreen()?.label) {\r\n <p class=\"fb-dbg__screen-label\">{{ pendingScreen()?.label }}</p>\r\n }\r\n @if (pendingScreen()?.helpText) {\r\n <p class=\"fb-field__hint\">{{ pendingScreen()?.helpText }}</p>\r\n }\r\n\r\n @if (screenInputRows().length) {\r\n <table class=\"fb-dbg__table\">\r\n <caption>\r\n Valori in ingresso\r\n </caption>\r\n <tbody>\r\n @for (row of screenInputRows(); track row.name) {\r\n <tr>\r\n <th scope=\"row\">{{ row.name }}</th>\r\n <td class=\"fb-dbg__type\">{{ row.type }}</td>\r\n <td>{{ row.value }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n @for (output of screenOutputNames(); track output) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">{{ output }}</label>\r\n <input class=\"fb-input\" (input)=\"setScreenOutput(output, $any($event.target).value)\" />\r\n </div>\r\n }\r\n @if (!screenOutputNames().length) {\r\n <p class=\"fb-field__hint\">Lo screen non dichiara parametri di uscita.</p>\r\n }\r\n\r\n <div class=\"fb-field__row\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--primary\"\r\n [disabled]=\"isRunning()\"\r\n (click)=\"respond('Next')\"\r\n >\r\n Avanti\r\n </button>\r\n <!-- canGoBack/canFinish/canPause sono la verita', piu' precisa dei flag del metadata. -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"isRunning() || !canGoBack()\"\r\n title=\"Con \u00ABindietro\u00BB gli output non vengono memorizzati\"\r\n (click)=\"respond('Previous')\"\r\n >\r\n Indietro\r\n </button>\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"isRunning() || !canFinish()\" (click)=\"respond('Finish')\">\r\n Fine\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"isRunning() || !canPause()\"\r\n title=\"Con \u00ABpausa\u00BB gli output non vengono memorizzati\"\r\n (click)=\"respond('Pause')\"\r\n >\r\n Pausa\r\n </button>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Con \u00ABindietro\u00BB e \u00ABpausa\u00BB i valori inseriti <strong>non</strong> vengono memorizzati.\r\n </p>\r\n </fieldset>\r\n }\r\n\r\n @if (isWaitingForStageStep()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Step di orchestrazione</legend>\r\n <p class=\"fb-section__note\">\r\n L\u2019interview e\u2019 sospesa su uno step assegnato: qui si conclude al posto dell\u2019assegnatario.\r\n Concludere puo\u2019 far <strong>sospendere di nuovo</strong> lo stage, con una chiave nuova.\r\n </p>\r\n\r\n <table class=\"fb-dbg__table\">\r\n <tbody>\r\n @for (step of stageSteps(); track step.stepName) {\r\n <tr>\r\n <th scope=\"row\">{{ step.label || step.stepName }}</th>\r\n <td class=\"fb-dbg__type\">{{ step.actionType }}</td>\r\n <td>{{ step.isWaiting ? 'in attesa' : step.status }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n @for (step of waitingStageSteps(); track step.stepName) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__title\">{{ step.label || step.stepName }}</span>\r\n </div>\r\n @for (output of stepOutputNames(step.stepName); track output) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">{{ output }}</label>\r\n <input class=\"fb-input\" (input)=\"setStepOutput(output, $any($event.target).value)\" />\r\n </div>\r\n }\r\n <div class=\"fb-field__row\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--primary\"\r\n [disabled]=\"isRunning()\"\r\n (click)=\"completeStep(step.stepName, 'Completed')\"\r\n >\r\n Concludi\r\n </button>\r\n <!-- Il rifiuto non e' un errore: prende il ramo \u00ABStep rifiutato\u00BB dello stage. -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"isRunning()\"\r\n title=\"Prende il ramo \u00ABStep rifiutato\u00BB; senza quel ramo l\u2019interview fallisce\"\r\n (click)=\"completeStep(step.stepName, 'Rejected')\"\r\n >\r\n Rifiuta\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost\"\r\n [disabled]=\"isRunning()\"\r\n (click)=\"completeStep(step.stepName, 'Cancelled')\"\r\n >\r\n Annulla lo step\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n </fieldset>\r\n }\r\n\r\n @if (outputRows().length) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Output del flow</legend>\r\n <table class=\"fb-dbg__table\">\r\n <tbody>\r\n @for (row of outputRows(); track row.name) {\r\n <tr>\r\n <th scope=\"row\">{{ row.name }}</th>\r\n <td class=\"fb-dbg__type\">{{ row.type }}</td>\r\n <td>{{ row.value }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </fieldset>\r\n }\r\n\r\n @if (trace().length) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Traccia</legend>\r\n <ol class=\"fb-dbg__trace\">\r\n @for (entry of trace(); track entry.sequence) {\r\n <li class=\"fb-dbg__trace-item\">\r\n <span class=\"fb-dbg__trace-seq\">{{ entry.sequence }}</span>\r\n @if (entry.elementName) {\r\n <button type=\"button\" class=\"fb-dbg__trace-el\" (click)=\"elementFocused.emit(entry.elementName!)\">\r\n {{ entry.elementName }}\r\n </button>\r\n }\r\n <span class=\"fb-dbg__trace-msg\">{{ entry.message }}</span>\r\n </li>\r\n }\r\n </ol>\r\n </fieldset>\r\n }\r\n\r\n @if (resourceRows().length) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Risorse</legend>\r\n <table class=\"fb-dbg__table\">\r\n <tbody>\r\n @for (row of resourceRows(); track row.name) {\r\n <tr>\r\n <th scope=\"row\">{{ row.name }}</th>\r\n <td class=\"fb-dbg__type\">{{ row.type }}</td>\r\n <td>{{ row.value }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </fieldset>\r\n }\r\n\r\n @if (result()?.interviewKey) {\r\n <p class=\"fb-field__hint\">\r\n Chiave dell\u2019esecuzione sospesa: <code>{{ result()?.interviewKey }}</code>\r\n </p>\r\n }\r\n }\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-dbg__header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-dbg__title{margin:0;font-size:14px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__body{flex:1;min-height:0;overflow-y:auto;padding:10px 12px}.fb-dbg__status{display:flex;align-items:center;gap:8px;margin-bottom:10px}.fb-dbg__badge{padding:2px 8px;border-radius:10px;background:var(--fb-border, #d6dae1);font-size:11px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__badge--ok{background:color-mix(in srgb,var(--fb-success, #3f8f5f) 18%,transparent);color:var(--fb-success, #3f8f5f)}.fb-dbg__badge--fail{background:color-mix(in srgb,var(--fb-error, #c9372c) 14%,transparent);color:var(--fb-error, #c9372c)}.fb-dbg__badge--wait{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 12%,transparent);color:var(--fb-accent, #2f6feb)}.fb-dbg__current,.fb-dbg__steps{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-dbg__type{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-subtle, #98a2b3)}.fb-dbg__screen-label{margin:0 0 4px;font-size:12px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__table{width:100%;border-collapse:collapse;font-size:11px}.fb-dbg__table caption{padding-bottom:3px;font-size:10px;color:var(--fb-text-subtle, #98a2b3);text-align:left}.fb-dbg__table th,.fb-dbg__table td{padding:3px 5px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee);text-align:left;vertical-align:top}.fb-dbg__table th{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__table td{color:var(--fb-text-muted, #667085);word-break:break-word}.fb-dbg__trace{margin:0;padding:0;list-style:none}.fb-dbg__trace-item{display:flex;gap:6px;padding:3px 0;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee);font-size:11px}.fb-dbg__trace-seq{flex:0 0 auto;width:18px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-subtle, #98a2b3);text-align:right}.fb-dbg__trace-el{flex:0 0 auto;padding:0;border:0;background:transparent;color:var(--fb-accent, #2f6feb);font:inherit;font-size:10px;cursor:pointer;text-decoration:underline}.fb-dbg__trace-msg{color:var(--fb-text-muted, #667085);line-height:1.35}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6716
7525
|
}
|
|
6717
7526
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: DebugPanelComponent, decorators: [{
|
|
6718
7527
|
type: Component,
|
|
6719
|
-
args: [{ selector: 'fb-debug-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<header class=\"fb-dbg__header\">\n <h2 class=\"fb-dbg__title\">Prova</h2>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\n</header>\n\n<div class=\"fb-dbg__body\">\n @if (errorMessage()) {\n <p class=\"fb-callout fb-callout--error\">{{ errorMessage() }}</p>\n }\n\n @if (!result()) {\n <fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">Valori iniziali</legend>\n @if (inputVariables().length) {\n @for (variable of inputVariables(); track variable.name) {\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">\n {{ variable.name }}\n <span class=\"fb-dbg__type\">{{ variable.dataType }}{{ variable.isCollection ? '[]' : '' }}</span>\n </label>\n @if (variable.dataType === 'Boolean') {\n <select class=\"fb-select\" (change)=\"setInputValue(variable.name!, $any($event.target).value)\">\n <option value=\"\">\u2014</option>\n <option value=\"true\">vero</option>\n <option value=\"false\">falso</option>\n </select>\n } @else {\n <input\n class=\"fb-input\"\n [type]=\"variable.dataType === 'Number' || variable.dataType === 'Integer' ? 'number' : 'text'\"\n (input)=\"setInputValue(variable.name!, $any($event.target).value)\"\n />\n }\n </div>\n }\n } @else {\n <p class=\"fb-field__hint\">Il flow non dichiara variabili di input.</p>\n }\n </fieldset>\n\n <label class=\"fb-check\">\n <input\n type=\"checkbox\"\n [checked]=\"debugEnabled()\"\n (change)=\"setDebugEnabled($any($event.target).checked)\"\n />\n Traccia di debug\n </label>\n @if (debugEnabled()) {\n <p class=\"fb-callout fb-callout--warn\">\n La traccia riporta i valori di <strong>tutte</strong> le risorse, dati personali compresi: non usarla\n su dati reali.\n </p>\n }\n\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"!canRun()\" (click)=\"start()\">\n Avvia\n </button>\n @if (!canRun() && !isRunning()) {\n <p class=\"fb-field__hint\">Salva il flow prima di provarlo.</p>\n }\n }\n\n @if (result()) {\n <div class=\"fb-dbg__status\">\n <span\n class=\"fb-dbg__badge\"\n [class.fb-dbg__badge--ok]=\"status() === 'Completed'\"\n [class.fb-dbg__badge--fail]=\"status() === 'Failed'\"\n [class.fb-dbg__badge--wait]=\"isWaitingForScreen()\"\n >\n {{ statusLabel() }}\n </span>\n @if (result()?.currentElementName) {\n <span class=\"fb-dbg__current\">su {{ result()?.currentElementName }}</span>\n }\n <span class=\"fb-dbg__steps\">{{ result()?.steps || 0 }} passi</span>\n <span class=\"fb-list__spacer\"></span>\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"reset()\">Riavvia</button>\n </div>\n\n @if (statusNote()) {\n <p class=\"fb-callout\">{{ statusNote() }}</p>\n }\n\n @if (result()?.fault) {\n <p class=\"fb-callout fb-callout--error\">{{ result()?.fault }}</p>\n }\n @for (message of result()?.errors || []; track message) {\n <p class=\"fb-callout fb-callout--error\">{{ message }}</p>\n }\n\n @if (isWaitingForScreen() && pendingScreen()) {\n <fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">\n Form \u00AB{{ pendingScreen()?.formName }}\u00BB\n </legend>\n <p class=\"fb-section__note\">\n Nell\u2019editor basta un form generico: qui vedi i valori che il form riceve e puoi compilare quelli\n che dichiara di restituire.\n </p>\n\n @if (pendingScreen()?.label) {\n <p class=\"fb-dbg__screen-label\">{{ pendingScreen()?.label }}</p>\n }\n @if (pendingScreen()?.helpText) {\n <p class=\"fb-field__hint\">{{ pendingScreen()?.helpText }}</p>\n }\n\n @if (screenInputRows().length) {\n <table class=\"fb-dbg__table\">\n <caption>\n Valori in ingresso\n </caption>\n <tbody>\n @for (row of screenInputRows(); track row.name) {\n <tr>\n <th scope=\"row\">{{ row.name }}</th>\n <td class=\"fb-dbg__type\">{{ row.type }}</td>\n <td>{{ row.value }}</td>\n </tr>\n }\n </tbody>\n </table>\n }\n\n @for (output of screenOutputNames(); track output) {\n <div class=\"fb-field\">\n <label class=\"fb-field__label\">{{ output }}</label>\n <input class=\"fb-input\" (input)=\"setScreenOutput(output, $any($event.target).value)\" />\n </div>\n }\n @if (!screenOutputNames().length) {\n <p class=\"fb-field__hint\">Lo screen non dichiara parametri di uscita.</p>\n }\n\n <div class=\"fb-field__row\">\n <button\n type=\"button\"\n class=\"fb-btn fb-btn--primary\"\n [disabled]=\"isRunning()\"\n (click)=\"respond('Next')\"\n >\n Avanti\n </button>\n <!-- canGoBack/canFinish/canPause sono la verita', piu' precisa dei flag del metadata. -->\n <button\n type=\"button\"\n class=\"fb-btn\"\n [disabled]=\"isRunning() || !canGoBack()\"\n title=\"Con \u00ABindietro\u00BB gli output non vengono memorizzati\"\n (click)=\"respond('Previous')\"\n >\n Indietro\n </button>\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"isRunning() || !canFinish()\" (click)=\"respond('Finish')\">\n Fine\n </button>\n <button\n type=\"button\"\n class=\"fb-btn\"\n [disabled]=\"isRunning() || !canPause()\"\n title=\"Con \u00ABpausa\u00BB gli output non vengono memorizzati\"\n (click)=\"respond('Pause')\"\n >\n Pausa\n </button>\n </div>\n <p class=\"fb-field__hint\">\n Con \u00ABindietro\u00BB e \u00ABpausa\u00BB i valori inseriti <strong>non</strong> vengono memorizzati.\n </p>\n </fieldset>\n }\n\n @if (outputRows().length) {\n <fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">Output del flow</legend>\n <table class=\"fb-dbg__table\">\n <tbody>\n @for (row of outputRows(); track row.name) {\n <tr>\n <th scope=\"row\">{{ row.name }}</th>\n <td class=\"fb-dbg__type\">{{ row.type }}</td>\n <td>{{ row.value }}</td>\n </tr>\n }\n </tbody>\n </table>\n </fieldset>\n }\n\n @if (trace().length) {\n <fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">Traccia</legend>\n <ol class=\"fb-dbg__trace\">\n @for (entry of trace(); track entry.sequence) {\n <li class=\"fb-dbg__trace-item\">\n <span class=\"fb-dbg__trace-seq\">{{ entry.sequence }}</span>\n @if (entry.elementName) {\n <button type=\"button\" class=\"fb-dbg__trace-el\" (click)=\"elementFocused.emit(entry.elementName!)\">\n {{ entry.elementName }}\n </button>\n }\n <span class=\"fb-dbg__trace-msg\">{{ entry.message }}</span>\n </li>\n }\n </ol>\n </fieldset>\n }\n\n @if (resourceRows().length) {\n <fieldset class=\"fb-section\">\n <legend class=\"fb-section__title\">Risorse</legend>\n <table class=\"fb-dbg__table\">\n <tbody>\n @for (row of resourceRows(); track row.name) {\n <tr>\n <th scope=\"row\">{{ row.name }}</th>\n <td class=\"fb-dbg__type\">{{ row.type }}</td>\n <td>{{ row.value }}</td>\n </tr>\n }\n </tbody>\n </table>\n </fieldset>\n }\n\n @if (result()?.interviewKey) {\n <p class=\"fb-field__hint\">\n Chiave dell\u2019esecuzione sospesa: <code>{{ result()?.interviewKey }}</code>\n </p>\n }\n }\n</div>\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-dbg__header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-dbg__title{margin:0;font-size:14px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__body{flex:1;min-height:0;overflow-y:auto;padding:10px 12px}.fb-dbg__status{display:flex;align-items:center;gap:8px;margin-bottom:10px}.fb-dbg__badge{padding:2px 8px;border-radius:10px;background:var(--fb-border, #d6dae1);font-size:11px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__badge--ok{background:color-mix(in srgb,var(--fb-success, #3f8f5f) 18%,transparent);color:var(--fb-success, #3f8f5f)}.fb-dbg__badge--fail{background:color-mix(in srgb,var(--fb-error, #c9372c) 14%,transparent);color:var(--fb-error, #c9372c)}.fb-dbg__badge--wait{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 12%,transparent);color:var(--fb-accent, #2f6feb)}.fb-dbg__current,.fb-dbg__steps{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-dbg__type{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-subtle, #98a2b3)}.fb-dbg__screen-label{margin:0 0 4px;font-size:12px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__table{width:100%;border-collapse:collapse;font-size:11px}.fb-dbg__table caption{padding-bottom:3px;font-size:10px;color:var(--fb-text-subtle, #98a2b3);text-align:left}.fb-dbg__table th,.fb-dbg__table td{padding:3px 5px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee);text-align:left;vertical-align:top}.fb-dbg__table th{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__table td{color:var(--fb-text-muted, #667085);word-break:break-word}.fb-dbg__trace{margin:0;padding:0;list-style:none}.fb-dbg__trace-item{display:flex;gap:6px;padding:3px 0;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee);font-size:11px}.fb-dbg__trace-seq{flex:0 0 auto;width:18px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-subtle, #98a2b3);text-align:right}.fb-dbg__trace-el{flex:0 0 auto;padding:0;border:0;background:transparent;color:var(--fb-accent, #2f6feb);font:inherit;font-size:10px;cursor:pointer;text-decoration:underline}.fb-dbg__trace-msg{color:var(--fb-text-muted, #667085);line-height:1.35}\n"] }]
|
|
7528
|
+
args: [{ selector: 'fb-debug-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<header class=\"fb-dbg__header\">\r\n <h2 class=\"fb-dbg__title\">Prova</h2>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"close()\">\u00D7</button>\r\n</header>\r\n\r\n<div class=\"fb-dbg__body\">\r\n @if (errorMessage()) {\r\n <p class=\"fb-callout fb-callout--error\">{{ errorMessage() }}</p>\r\n }\r\n\r\n @if (!result()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Valori iniziali</legend>\r\n @if (inputVariables().length) {\r\n @for (variable of inputVariables(); track variable.name) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">\r\n {{ variable.name }}\r\n <span class=\"fb-dbg__type\">{{ variable.dataType }}{{ variable.isCollection ? '[]' : '' }}</span>\r\n </label>\r\n @if (variable.dataType === 'Boolean') {\r\n <select class=\"fb-select\" (change)=\"setInputValue(variable.name!, $any($event.target).value)\">\r\n <option value=\"\">\u2014</option>\r\n <option value=\"true\">vero</option>\r\n <option value=\"false\">falso</option>\r\n </select>\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [type]=\"variable.dataType === 'Number' || variable.dataType === 'Integer' ? 'number' : 'text'\"\r\n (input)=\"setInputValue(variable.name!, $any($event.target).value)\"\r\n />\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <p class=\"fb-field__hint\">Il flow non dichiara variabili di input.</p>\r\n }\r\n </fieldset>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"debugEnabled()\"\r\n (change)=\"setDebugEnabled($any($event.target).checked)\"\r\n />\r\n Traccia di debug\r\n </label>\r\n @if (debugEnabled()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n La traccia riporta i valori di <strong>tutte</strong> le risorse, dati personali compresi: non usarla\r\n su dati reali.\r\n </p>\r\n }\r\n\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"!canRun()\" (click)=\"start()\">\r\n Avvia\r\n </button>\r\n @if (!canRun() && !isRunning()) {\r\n <p class=\"fb-field__hint\">Salva il flow prima di provarlo.</p>\r\n }\r\n }\r\n\r\n @if (result()) {\r\n <div class=\"fb-dbg__status\">\r\n <span\r\n class=\"fb-dbg__badge\"\r\n [class.fb-dbg__badge--ok]=\"status() === 'Completed'\"\r\n [class.fb-dbg__badge--fail]=\"status() === 'Failed'\"\r\n [class.fb-dbg__badge--wait]=\"isWaitingForScreen()\"\r\n >\r\n {{ statusLabel() }}\r\n </span>\r\n @if (result()?.currentElementName) {\r\n <span class=\"fb-dbg__current\">su {{ result()?.currentElementName }}</span>\r\n }\r\n <span class=\"fb-dbg__steps\">{{ result()?.steps || 0 }} passi</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"reset()\">Riavvia</button>\r\n </div>\r\n\r\n @if (statusNote()) {\r\n <p class=\"fb-callout\">{{ statusNote() }}</p>\r\n }\r\n\r\n @if (result()?.fault) {\r\n <p class=\"fb-callout fb-callout--error\">{{ result()?.fault }}</p>\r\n }\r\n @for (message of result()?.errors || []; track message) {\r\n <p class=\"fb-callout fb-callout--error\">{{ message }}</p>\r\n }\r\n\r\n @if (isWaitingForScreen() && pendingScreen()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">\r\n Form \u00AB{{ pendingScreen()?.formName }}\u00BB\r\n </legend>\r\n <p class=\"fb-section__note\">\r\n Nell\u2019editor basta un form generico: qui vedi i valori che il form riceve e puoi compilare quelli\r\n che dichiara di restituire.\r\n </p>\r\n\r\n @if (pendingScreen()?.label) {\r\n <p class=\"fb-dbg__screen-label\">{{ pendingScreen()?.label }}</p>\r\n }\r\n @if (pendingScreen()?.helpText) {\r\n <p class=\"fb-field__hint\">{{ pendingScreen()?.helpText }}</p>\r\n }\r\n\r\n @if (screenInputRows().length) {\r\n <table class=\"fb-dbg__table\">\r\n <caption>\r\n Valori in ingresso\r\n </caption>\r\n <tbody>\r\n @for (row of screenInputRows(); track row.name) {\r\n <tr>\r\n <th scope=\"row\">{{ row.name }}</th>\r\n <td class=\"fb-dbg__type\">{{ row.type }}</td>\r\n <td>{{ row.value }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n @for (output of screenOutputNames(); track output) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">{{ output }}</label>\r\n <input class=\"fb-input\" (input)=\"setScreenOutput(output, $any($event.target).value)\" />\r\n </div>\r\n }\r\n @if (!screenOutputNames().length) {\r\n <p class=\"fb-field__hint\">Lo screen non dichiara parametri di uscita.</p>\r\n }\r\n\r\n <div class=\"fb-field__row\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--primary\"\r\n [disabled]=\"isRunning()\"\r\n (click)=\"respond('Next')\"\r\n >\r\n Avanti\r\n </button>\r\n <!-- canGoBack/canFinish/canPause sono la verita', piu' precisa dei flag del metadata. -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"isRunning() || !canGoBack()\"\r\n title=\"Con \u00ABindietro\u00BB gli output non vengono memorizzati\"\r\n (click)=\"respond('Previous')\"\r\n >\r\n Indietro\r\n </button>\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"isRunning() || !canFinish()\" (click)=\"respond('Finish')\">\r\n Fine\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"isRunning() || !canPause()\"\r\n title=\"Con \u00ABpausa\u00BB gli output non vengono memorizzati\"\r\n (click)=\"respond('Pause')\"\r\n >\r\n Pausa\r\n </button>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Con \u00ABindietro\u00BB e \u00ABpausa\u00BB i valori inseriti <strong>non</strong> vengono memorizzati.\r\n </p>\r\n </fieldset>\r\n }\r\n\r\n @if (isWaitingForStageStep()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Step di orchestrazione</legend>\r\n <p class=\"fb-section__note\">\r\n L\u2019interview e\u2019 sospesa su uno step assegnato: qui si conclude al posto dell\u2019assegnatario.\r\n Concludere puo\u2019 far <strong>sospendere di nuovo</strong> lo stage, con una chiave nuova.\r\n </p>\r\n\r\n <table class=\"fb-dbg__table\">\r\n <tbody>\r\n @for (step of stageSteps(); track step.stepName) {\r\n <tr>\r\n <th scope=\"row\">{{ step.label || step.stepName }}</th>\r\n <td class=\"fb-dbg__type\">{{ step.actionType }}</td>\r\n <td>{{ step.isWaiting ? 'in attesa' : step.status }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n\r\n @for (step of waitingStageSteps(); track step.stepName) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__title\">{{ step.label || step.stepName }}</span>\r\n </div>\r\n @for (output of stepOutputNames(step.stepName); track output) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">{{ output }}</label>\r\n <input class=\"fb-input\" (input)=\"setStepOutput(output, $any($event.target).value)\" />\r\n </div>\r\n }\r\n <div class=\"fb-field__row\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--primary\"\r\n [disabled]=\"isRunning()\"\r\n (click)=\"completeStep(step.stepName, 'Completed')\"\r\n >\r\n Concludi\r\n </button>\r\n <!-- Il rifiuto non e' un errore: prende il ramo \u00ABStep rifiutato\u00BB dello stage. -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"isRunning()\"\r\n title=\"Prende il ramo \u00ABStep rifiutato\u00BB; senza quel ramo l\u2019interview fallisce\"\r\n (click)=\"completeStep(step.stepName, 'Rejected')\"\r\n >\r\n Rifiuta\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost\"\r\n [disabled]=\"isRunning()\"\r\n (click)=\"completeStep(step.stepName, 'Cancelled')\"\r\n >\r\n Annulla lo step\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n </fieldset>\r\n }\r\n\r\n @if (outputRows().length) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Output del flow</legend>\r\n <table class=\"fb-dbg__table\">\r\n <tbody>\r\n @for (row of outputRows(); track row.name) {\r\n <tr>\r\n <th scope=\"row\">{{ row.name }}</th>\r\n <td class=\"fb-dbg__type\">{{ row.type }}</td>\r\n <td>{{ row.value }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </fieldset>\r\n }\r\n\r\n @if (trace().length) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Traccia</legend>\r\n <ol class=\"fb-dbg__trace\">\r\n @for (entry of trace(); track entry.sequence) {\r\n <li class=\"fb-dbg__trace-item\">\r\n <span class=\"fb-dbg__trace-seq\">{{ entry.sequence }}</span>\r\n @if (entry.elementName) {\r\n <button type=\"button\" class=\"fb-dbg__trace-el\" (click)=\"elementFocused.emit(entry.elementName!)\">\r\n {{ entry.elementName }}\r\n </button>\r\n }\r\n <span class=\"fb-dbg__trace-msg\">{{ entry.message }}</span>\r\n </li>\r\n }\r\n </ol>\r\n </fieldset>\r\n }\r\n\r\n @if (resourceRows().length) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Risorse</legend>\r\n <table class=\"fb-dbg__table\">\r\n <tbody>\r\n @for (row of resourceRows(); track row.name) {\r\n <tr>\r\n <th scope=\"row\">{{ row.name }}</th>\r\n <td class=\"fb-dbg__type\">{{ row.type }}</td>\r\n <td>{{ row.value }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n </fieldset>\r\n }\r\n\r\n @if (result()?.interviewKey) {\r\n <p class=\"fb-field__hint\">\r\n Chiave dell\u2019esecuzione sospesa: <code>{{ result()?.interviewKey }}</code>\r\n </p>\r\n }\r\n }\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-dbg__header{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee)}.fb-dbg__title{margin:0;font-size:14px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__body{flex:1;min-height:0;overflow-y:auto;padding:10px 12px}.fb-dbg__status{display:flex;align-items:center;gap:8px;margin-bottom:10px}.fb-dbg__badge{padding:2px 8px;border-radius:10px;background:var(--fb-border, #d6dae1);font-size:11px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__badge--ok{background:color-mix(in srgb,var(--fb-success, #3f8f5f) 18%,transparent);color:var(--fb-success, #3f8f5f)}.fb-dbg__badge--fail{background:color-mix(in srgb,var(--fb-error, #c9372c) 14%,transparent);color:var(--fb-error, #c9372c)}.fb-dbg__badge--wait{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 12%,transparent);color:var(--fb-accent, #2f6feb)}.fb-dbg__current,.fb-dbg__steps{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-dbg__type{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-subtle, #98a2b3)}.fb-dbg__screen-label{margin:0 0 4px;font-size:12px;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__table{width:100%;border-collapse:collapse;font-size:11px}.fb-dbg__table caption{padding-bottom:3px;font-size:10px;color:var(--fb-text-subtle, #98a2b3);text-align:left}.fb-dbg__table th,.fb-dbg__table td{padding:3px 5px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee);text-align:left;vertical-align:top}.fb-dbg__table th{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:600;color:var(--fb-text, #1d2939)}.fb-dbg__table td{color:var(--fb-text-muted, #667085);word-break:break-word}.fb-dbg__trace{margin:0;padding:0;list-style:none}.fb-dbg__trace-item{display:flex;gap:6px;padding:3px 0;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee);font-size:11px}.fb-dbg__trace-seq{flex:0 0 auto;width:18px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--fb-text-subtle, #98a2b3);text-align:right}.fb-dbg__trace-el{flex:0 0 auto;padding:0;border:0;background:transparent;color:var(--fb-accent, #2f6feb);font:inherit;font-size:10px;cursor:pointer;text-decoration:underline}.fb-dbg__trace-msg{color:var(--fb-text-muted, #667085);line-height:1.35}\n"] }]
|
|
6720
7529
|
}], propDecorators: { closed: [{ type: i0.Output, args: ["closed"] }], elementFocused: [{ type: i0.Output, args: ["elementFocused"] }] } });
|
|
6721
7530
|
|
|
6722
7531
|
/**
|
|
@@ -6821,8 +7630,15 @@ class FlowBuilderComponent {
|
|
|
6821
7630
|
}
|
|
6822
7631
|
}, ...(ngDevMode ? [{ debugName: "statusLabel" }] : []));
|
|
6823
7632
|
constructor() {
|
|
6824
|
-
|
|
6825
|
-
|
|
7633
|
+
/**
|
|
7634
|
+
* I dizionari si caricano una volta e si tengono in cache, **per `processType`**: le
|
|
7635
|
+
* globali dipendono dal tipo di flow — `$Record` non esiste in uno screen flow — e
|
|
7636
|
+
* cambiare tipo cambia quali sono proponibili (§4.1, §6.4). Lo store memoizza per tipo,
|
|
7637
|
+
* quindi tornare a un tipo già visto non produce una richiesta.
|
|
7638
|
+
*/
|
|
7639
|
+
effect(() => {
|
|
7640
|
+
void this.dictionaries.load(this.store.document().processType);
|
|
7641
|
+
});
|
|
6826
7642
|
effect(() => {
|
|
6827
7643
|
this.session.setAuthor(this.author());
|
|
6828
7644
|
});
|
|
@@ -6925,8 +7741,14 @@ class FlowBuilderComponent {
|
|
|
6925
7741
|
(this.store.document().screens?.length ?? 0) > 0, ...(ngDevMode ? [{ debugName: "hasScreensInAutoLaunched" }] : []));
|
|
6926
7742
|
/** Un flow `Screen` senza screen e' `SCREEN_FLOW_WITHOUT_SCREENS`. */
|
|
6927
7743
|
hasNoScreensInScreenFlow = computed(() => this.store.document().processType === 'Screen' && (this.store.document().screens?.length ?? 0) === 0, ...(ngDevMode ? [{ debugName: "hasNoScreensInScreenFlow" }] : []));
|
|
6928
|
-
/**
|
|
6929
|
-
|
|
7744
|
+
/**
|
|
7745
|
+
* Un flow `Orchestration` senza stage di orchestrazione e' un **avviso**
|
|
7746
|
+
* (`ORCHESTRATION_WITHOUT_STAGES`): il tipo dichiara un'orchestrazione che non c'e' (§3.1).
|
|
7747
|
+
*/
|
|
7748
|
+
isOrchestrationWithoutStages = computed(() => {
|
|
7749
|
+
const document = this.store.document();
|
|
7750
|
+
return document.processType === 'Orchestration' && (document.orchestratedStages?.length ?? 0) === 0;
|
|
7751
|
+
}, ...(ngDevMode ? [{ debugName: "isOrchestrationWithoutStages" }] : []));
|
|
6930
7752
|
// -------------------------------------------------------------------------
|
|
6931
7753
|
// Canvas
|
|
6932
7754
|
// -------------------------------------------------------------------------
|
|
@@ -7019,6 +7841,13 @@ class FlowBuilderComponent {
|
|
|
7019
7841
|
if (type === 'Wait') {
|
|
7020
7842
|
node['waitEvents'] = [{ name: 'Evento', label: 'Evento 1' }];
|
|
7021
7843
|
}
|
|
7844
|
+
if (type === 'OrchestratedStage') {
|
|
7845
|
+
// Lo step nasce senza `actionType`: e' l'utente a scegliere se e' in background,
|
|
7846
|
+
// interattivo o di approvazione, e il form lo segnala finche' manca (§5.13).
|
|
7847
|
+
node['stageSteps'] = [
|
|
7848
|
+
{ name: uniqueFlowName('Step', [...this.store.usedNames(), name]), label: 'Step 1' },
|
|
7849
|
+
];
|
|
7850
|
+
}
|
|
7022
7851
|
this.store.addNode(collection, node);
|
|
7023
7852
|
// Un elemento appena creato e' vuoto: il posto giusto in cui finire e' il suo form.
|
|
7024
7853
|
this.openElement(name);
|
|
@@ -7241,7 +8070,7 @@ class FlowBuilderComponent {
|
|
|
7241
8070
|
FlowValidationStore,
|
|
7242
8071
|
FlowEditorSession,
|
|
7243
8072
|
FlowLayoutService,
|
|
7244
|
-
], ngImport: i0, template: "<div class=\"fb-builder\" [attr.data-fb-theme]=\"null\">\r\n <header class=\"fb-top\">\r\n <div class=\"fb-top__identity\">\r\n <input\r\n class=\"fb-top__label\"\r\n [value]=\"document().label || ''\"\r\n placeholder=\"Nome del flow\"\r\n aria-label=\"Nome del flow\"\r\n [disabled]=\"!isEditable()\"\r\n (input)=\"setLabel($any($event.target).value)\"\r\n />\r\n <div class=\"fb-top__meta\">\r\n <input\r\n class=\"fb-top__name\"\r\n [value]=\"document().fullName || ''\"\r\n placeholder=\"NomeTecnico\"\r\n aria-label=\"Nome tecnico del flow\"\r\n [disabled]=\"!isEditable()\"\r\n (input)=\"setFullName($any($event.target).value)\"\r\n />\r\n <select\r\n class=\"fb-top__process\"\r\n [fbValue]=\"document().processType || ''\"\r\n aria-label=\"Tipo di flow\"\r\n [disabled]=\"!isEditable()\"\r\n (change)=\"setProcessType($any($event.target).value)\"\r\n >\r\n @for (type of processTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n <span class=\"fb-top__status\">{{ statusLabel() }}</span>\r\n @if (session.version() !== null) {\r\n <span class=\"fb-top__version\">v{{ session.version() }}</span>\r\n }\r\n @if (isDirty()) {\r\n <span class=\"fb-top__dirty\" title=\"Ci sono modifiche non salvate\">modificato</span>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"fb-top__actions\">\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"!canUndo()\" aria-label=\"Annulla\" (click)=\"undo()\">\u21B6</button>\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"!canRedo()\" aria-label=\"Ripeti\" (click)=\"redo()\">\u21B7</button>\r\n <button type=\"button\" class=\"fb-btn\" title=\"Ricalcola le posizioni\" (click)=\"autoLayout()\">Riordina</button>\r\n @if (isDialogMode()) {\r\n <!-- Il doppio click sul node fa la stessa cosa, ma non si vede: questo comando s\u00EC. -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"!selectedName()\"\r\n title=\"Apri il dettaglio dell\u2019elemento selezionato\"\r\n (click)=\"openSelectedElement()\"\r\n >\r\n Dettaglio\r\n </button>\r\n }\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"isBusy()\" (click)=\"validateNow()\">Valida</button>\r\n\r\n @switch (primaryCommand()) {\r\n @case ('newVersion') {\r\n <!-- Su una versione non modificabile il comando primario e' \"Nuova versione\" (\u00A78.1). -->\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"isBusy()\" (click)=\"createNewVersion()\">\r\n Nuova versione\r\n </button>\r\n }\r\n @case ('create') {\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"isBusy()\" (click)=\"save()\">\r\n Crea\r\n </button>\r\n }\r\n @default {\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"isBusy()\" (click)=\"save()\">\r\n Salva\r\n </button>\r\n }\r\n }\r\n\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"isBusy() || !canActivate()\"\r\n [title]=\"\r\n canActivate()\r\n ? 'Attiva questa versione'\r\n : 'L\u2019attivazione esige zero errori: correggili nel pannello dei problemi'\r\n \"\r\n (click)=\"activate()\"\r\n >\r\n Attiva\r\n </button>\r\n </div>\r\n </header>\r\n\r\n @if (conflict()) {\r\n <!-- \u00A79.3: qualcun altro ha salvato. Due strade, entrambe offerte. -->\r\n <div class=\"fb-banner fb-banner--warn\" role=\"alert\">\r\n <span>\r\n {{ conflict()?.message }}\r\n @if (conflict()?.conflictingAuthor) {\r\n Ha salvato {{ conflict()?.conflictingAuthor }}.\r\n }\r\n </span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--icon\" (click)=\"reloadAfterConflict()\">Ricarica</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--icon\" (click)=\"saveAsNewVersionAfterConflict()\">\r\n Salva come nuova versione\r\n </button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"dismissConflict()\">\u00D7</button>\r\n </div>\r\n }\r\n\r\n @if (notice()) {\r\n <div\r\n class=\"fb-banner\"\r\n [class.fb-banner--error]=\"notice()?.kind === 'error'\"\r\n role=\"status\"\r\n >\r\n <span>{{ notice()?.message }}</span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"dismissNotice()\">\r\n \u00D7\r\n </button>\r\n </div>\r\n }\r\n\r\n @if (hasScreensInAutoLaunched()) {\r\n <div class=\"fb-banner fb-banner--error\">\r\n Un flow AutoLaunched che contiene screen e\u2019 un errore di validazione: non c\u2019e\u2019 nessuno a cui mostrarli.\r\n </div>\r\n }\r\n @if (isOrchestration()) {\r\n <div class=\"fb-banner fb-banner--warn\">Un flow Orchestration non e\u2019 eseguibile dal motore.</div>\r\n }\r\n @if (hasNoScreensInScreenFlow()) {\r\n <div class=\"fb-banner fb-banner--warn\">\r\n Un flow di tipo Screen senza nessuno screen viene segnalato dalla validazione.\r\n </div>\r\n }\r\n @if (!isEditable()) {\r\n <div class=\"fb-banner\">\r\n Questa versione e\u2019 in sola lettura: per modificarla creane una nuova.\r\n </div>\r\n }\r\n\r\n <div class=\"fb-main\">\r\n <aside class=\"fb-main__palette\">\r\n <fb-element-palette [processType]=\"document().processType\" (elementPicked)=\"onElementPicked($event)\" />\r\n </aside>\r\n\r\n <div class=\"fb-main__center\">\r\n <fb-flow-canvas\r\n class=\"fb-main__canvas\"\r\n [selectedName]=\"selectedName()\"\r\n [outline]=\"outline()\"\r\n (selectionChange)=\"onSelectionChange($event)\"\r\n (nodeOpened)=\"onNodeOpened($event)\"\r\n (nodeRemoveRequested)=\"onRemoveNode($event)\"\r\n (nodeDuplicateRequested)=\"onDuplicateNode($event)\"\r\n (elementDropped)=\"onElementDropped($event)\"\r\n />\r\n\r\n @if (showProblems()) {\r\n <fb-problems-panel\r\n class=\"fb-main__problems\"\r\n (elementFocused)=\"focusElement($event)\"\r\n (closed)=\"toggleProblems()\"\r\n />\r\n } @else {\r\n <button type=\"button\" class=\"fb-main__problems-toggle\" (click)=\"toggleProblems()\">\r\n Problemi\r\n @if (errorCount()) {\r\n <span class=\"fb-main__count fb-main__count--error\">{{ errorCount() }}</span>\r\n }\r\n @if (warningCount()) {\r\n <span class=\"fb-main__count fb-main__count--warn\">{{ warningCount() }}</span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <aside class=\"fb-main__side\">\r\n <nav class=\"fb-side__tabs\" aria-label=\"Pannelli\">\r\n @if (!isDialogMode()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'inspector'\"\r\n (click)=\"setPanel('inspector')\"\r\n >\r\n Elemento\r\n </button>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'resources'\"\r\n (click)=\"setPanel('resources')\"\r\n >\r\n Risorse\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'versions'\"\r\n (click)=\"setPanel('versions')\"\r\n >\r\n Versioni\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'debug'\"\r\n (click)=\"setPanel('debug')\"\r\n >\r\n Prova\r\n </button>\r\n </nav>\r\n\r\n <div class=\"fb-side__content\">\r\n @switch (sidePanel()) {\r\n @case ('inspector') {\r\n <fb-element-inspector\r\n [selectedName]=\"selectedName()\"\r\n (removeRequested)=\"onRemoveNode($event)\"\r\n (duplicateRequested)=\"onDuplicateNode($event)\"\r\n (closed)=\"setPanel('resources')\"\r\n />\r\n }\r\n @case ('resources') {\r\n <fb-resource-panel (closed)=\"setPanel('inspector')\" />\r\n }\r\n @case ('versions') {\r\n <fb-version-panel\r\n (versionOpened)=\"openVersion($event)\"\r\n (notice)=\"showNotice($event)\"\r\n (closed)=\"setPanel('inspector')\"\r\n />\r\n }\r\n @case ('debug') {\r\n <!-- Evidenzia sul canvas senza rubare il pannello: l'interview e\u2019 in corso. -->\r\n <fb-debug-panel (elementFocused)=\"highlightElement($event)\" (closed)=\"setPanel('inspector')\" />\r\n }\r\n }\r\n </div>\r\n\r\n <footer class=\"fb-side__footer\">\r\n <label class=\"fb-btn fb-btn--icon\">\r\n Importa JSON\r\n <input type=\"file\" accept=\"application/json,.json\" hidden (change)=\"onFileSelected($event)\" />\r\n </label>\r\n </footer>\r\n </aside>\r\n </div>\r\n\r\n @if (isDialogMode() && isDialogOpen() && selectedName()) {\r\n <!-- La dialog sta dentro il builder, non nel body: la libreria e\u2019 innestabile. -->\r\n <fb-element-dialog\r\n [selectedName]=\"selectedName()\"\r\n (closed)=\"closeDialog()\"\r\n (removeRequested)=\"onRemoveNode($event)\"\r\n (duplicateRequested)=\"onDuplicateNode($event)\"\r\n />\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:100%;height:100%;min-height:0;font:inherit;color:var(--fb-text, #1d2939)}.fb-builder{position:relative;display:flex;flex-direction:column;width:100%;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-top{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-bottom:1px solid var(--fb-border, #e2e5eb);background:var(--fb-surface, #fff)}.fb-top__identity{min-width:0}.fb-top__label{width:100%;max-width:420px;padding:2px 4px;border:1px solid transparent;border-radius:4px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:15px;font-weight:600}.fb-top__label:hover:not(:disabled),.fb-top__label:focus-visible{border-color:var(--fb-border, #d6dae1);background:var(--fb-surface, #fff)}.fb-top__meta{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:2px}.fb-top__name{width:180px;padding:1px 4px;border:1px solid transparent;border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}.fb-top__name:hover:not(:disabled),.fb-top__name:focus-visible{border-color:var(--fb-border, #d6dae1)}.fb-top__process{padding:1px 4px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px}.fb-top__status,.fb-top__version,.fb-top__dirty{padding:2px 7px;border-radius:999px;background:var(--fb-surface-sunken, #eef0f4);color:var(--fb-text-muted, #6b7086);font-size:10px;font-weight:600}.fb-top__version{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-top__dirty{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-top__actions{display:flex;flex-wrap:wrap;gap:4px}.fb-banner{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:6px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 7%,transparent);font-size:11px}.fb-banner--warn{background:color-mix(in srgb,var(--fb-warning, #b7791f) 12%,transparent);color:var(--fb-warning, #b7791f)}.fb-banner--error{background:color-mix(in srgb,var(--fb-error, #c9372c) 10%,transparent);color:var(--fb-error, #c9372c)}.fb-banner>span{flex:1;min-width:200px}.fb-main{display:flex;flex:1;min-height:0}.fb-main__palette{flex:0 0 190px;min-width:0}.fb-main__center{display:flex;flex:1;flex-direction:column;min-width:0;min-height:0}.fb-main__canvas{flex:1;min-height:0}.fb-main__problems{flex:0 0 auto;height:220px}.fb-main__problems-toggle{display:flex;align-items:center;gap:6px;padding:4px 12px;border:0;border-top:1px solid var(--fb-border, #d6dae1);background:var(--fb-surface-alt, #f8f9fb);color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}.fb-main__count{padding:0 5px;border-radius:8px;background:var(--fb-border, #d6dae1);font-size:9px;font-weight:700}.fb-main__count--error{background:color-mix(in srgb,var(--fb-error, #c9372c) 16%,transparent);color:var(--fb-error, #c9372c)}.fb-main__count--warn{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-main__side{display:flex;flex-direction:column;flex:0 0 340px;min-width:0;min-height:0;border-left:1px solid var(--fb-border, #d6dae1);background:var(--fb-surface, #fff)}.fb-side__tabs{display:flex;gap:2px;margin:8px 10px;padding:3px;border-radius:var(--fb-radius, 10px);background:var(--fb-surface-sunken, #eef0f4)}.fb-side__tab{flex:1;padding:5px 8px;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-text-muted, #6b7086);font:inherit;font-size:11px;cursor:pointer;transition:background .12s ease,color .12s ease}.fb-side__tab:hover:not(.fb-side__tab--active){color:var(--fb-text, #1a1c23)}.fb-side__tab--active{background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));color:var(--fb-text, #1a1c23);font-weight:600}.fb-side__content{flex:1;min-height:0;border-top:1px solid var(--fb-border-subtle, #eef0f4)}.fb-side__content>*{height:100%}.fb-side__footer{display:flex;gap:6px;padding:6px 8px;border-top:1px solid var(--fb-border-subtle, #e6e9ee)}@media(max-width:1200px){.fb-main__palette{flex-basis:150px}.fb-main__side{flex-basis:290px}}\n"], dependencies: [{ kind: "component", type: DebugPanelComponent, selector: "fb-debug-panel", outputs: ["closed", "elementFocused"] }, { kind: "component", type: ElementDialogComponent, selector: "fb-element-dialog", inputs: ["selectedName"], outputs: ["closed", "removeRequested", "duplicateRequested"] }, { kind: "component", type: ElementInspectorComponent, selector: "fb-element-inspector", inputs: ["selectedName", "showHeader"], outputs: ["closed", "removeRequested", "duplicateRequested"] }, { kind: "component", type: ElementPaletteComponent, selector: "fb-element-palette", inputs: ["processType"], outputs: ["elementPicked"] }, { kind: "component", type: FlowCanvasComponent, selector: "fb-flow-canvas", inputs: ["selectedName", "outline"], outputs: ["selectionChange", "nodeOpened", "nodeRemoveRequested", "nodeDuplicateRequested", "elementDropped"] }, { kind: "component", type: ProblemsPanelComponent, selector: "fb-problems-panel", outputs: ["elementFocused", "closed"] }, { kind: "component", type: ResourcePanelComponent, selector: "fb-resource-panel", outputs: ["closed"] }, { kind: "component", type: VersionPanelComponent, selector: "fb-version-panel", outputs: ["closed", "versionOpened", "notice"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8073
|
+
], ngImport: i0, template: "<div class=\"fb-builder\" [attr.data-fb-theme]=\"null\">\r\n <header class=\"fb-top\">\r\n <div class=\"fb-top__identity\">\r\n <input\r\n class=\"fb-top__label\"\r\n [value]=\"document().label || ''\"\r\n placeholder=\"Nome del flow\"\r\n aria-label=\"Nome del flow\"\r\n [disabled]=\"!isEditable()\"\r\n (input)=\"setLabel($any($event.target).value)\"\r\n />\r\n <div class=\"fb-top__meta\">\r\n <input\r\n class=\"fb-top__name\"\r\n [value]=\"document().fullName || ''\"\r\n placeholder=\"NomeTecnico\"\r\n aria-label=\"Nome tecnico del flow\"\r\n [disabled]=\"!isEditable()\"\r\n (input)=\"setFullName($any($event.target).value)\"\r\n />\r\n <select\r\n class=\"fb-top__process\"\r\n [fbValue]=\"document().processType || ''\"\r\n aria-label=\"Tipo di flow\"\r\n [disabled]=\"!isEditable()\"\r\n (change)=\"setProcessType($any($event.target).value)\"\r\n >\r\n @for (type of processTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n <span class=\"fb-top__status\">{{ statusLabel() }}</span>\r\n @if (session.version() !== null) {\r\n <span class=\"fb-top__version\">v{{ session.version() }}</span>\r\n }\r\n @if (isDirty()) {\r\n <span class=\"fb-top__dirty\" title=\"Ci sono modifiche non salvate\">modificato</span>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"fb-top__actions\">\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"!canUndo()\" aria-label=\"Annulla\" (click)=\"undo()\">\u21B6</button>\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"!canRedo()\" aria-label=\"Ripeti\" (click)=\"redo()\">\u21B7</button>\r\n <button type=\"button\" class=\"fb-btn\" title=\"Ricalcola le posizioni\" (click)=\"autoLayout()\">Riordina</button>\r\n @if (isDialogMode()) {\r\n <!-- Il doppio click sul node fa la stessa cosa, ma non si vede: questo comando s\u00EC. -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"!selectedName()\"\r\n title=\"Apri il dettaglio dell\u2019elemento selezionato\"\r\n (click)=\"openSelectedElement()\"\r\n >\r\n Dettaglio\r\n </button>\r\n }\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"isBusy()\" (click)=\"validateNow()\">Valida</button>\r\n\r\n @switch (primaryCommand()) {\r\n @case ('newVersion') {\r\n <!-- Su una versione non modificabile il comando primario e' \"Nuova versione\" (\u00A78.1). -->\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"isBusy()\" (click)=\"createNewVersion()\">\r\n Nuova versione\r\n </button>\r\n }\r\n @case ('create') {\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"isBusy()\" (click)=\"save()\">\r\n Crea\r\n </button>\r\n }\r\n @default {\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"isBusy()\" (click)=\"save()\">\r\n Salva\r\n </button>\r\n }\r\n }\r\n\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"isBusy() || !canActivate()\"\r\n [title]=\"\r\n canActivate()\r\n ? 'Attiva questa versione'\r\n : 'L\u2019attivazione esige zero errori: correggili nel pannello dei problemi'\r\n \"\r\n (click)=\"activate()\"\r\n >\r\n Attiva\r\n </button>\r\n </div>\r\n </header>\r\n\r\n @if (conflict()) {\r\n <!-- \u00A79.3: qualcun altro ha salvato. Due strade, entrambe offerte. -->\r\n <div class=\"fb-banner fb-banner--warn\" role=\"alert\">\r\n <span>\r\n {{ conflict()?.message }}\r\n @if (conflict()?.conflictingAuthor) {\r\n Ha salvato {{ conflict()?.conflictingAuthor }}.\r\n }\r\n </span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--icon\" (click)=\"reloadAfterConflict()\">Ricarica</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--icon\" (click)=\"saveAsNewVersionAfterConflict()\">\r\n Salva come nuova versione\r\n </button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"dismissConflict()\">\u00D7</button>\r\n </div>\r\n }\r\n\r\n @if (notice()) {\r\n <div\r\n class=\"fb-banner\"\r\n [class.fb-banner--error]=\"notice()?.kind === 'error'\"\r\n role=\"status\"\r\n >\r\n <span>{{ notice()?.message }}</span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"dismissNotice()\">\r\n \u00D7\r\n </button>\r\n </div>\r\n }\r\n\r\n @if (hasScreensInAutoLaunched()) {\r\n <div class=\"fb-banner fb-banner--error\">\r\n Un flow AutoLaunched che contiene screen e\u2019 un errore di validazione: non c\u2019e\u2019 nessuno a cui mostrarli.\r\n </div>\r\n }\r\n @if (isOrchestrationWithoutStages()) {\r\n <div class=\"fb-banner fb-banner--warn\">\r\n Un flow Orchestration senza stage di orchestrazione viene segnalato dalla validazione\r\n (ORCHESTRATION_WITHOUT_STAGES).\r\n </div>\r\n }\r\n @if (hasNoScreensInScreenFlow()) {\r\n <div class=\"fb-banner fb-banner--warn\">\r\n Un flow di tipo Screen senza nessuno screen viene segnalato dalla validazione.\r\n </div>\r\n }\r\n @if (!isEditable()) {\r\n <div class=\"fb-banner\">\r\n Questa versione e\u2019 in sola lettura: per modificarla creane una nuova.\r\n </div>\r\n }\r\n\r\n <div class=\"fb-main\">\r\n <aside class=\"fb-main__palette\">\r\n <fb-element-palette [processType]=\"document().processType\" (elementPicked)=\"onElementPicked($event)\" />\r\n </aside>\r\n\r\n <div class=\"fb-main__center\">\r\n <fb-flow-canvas\r\n class=\"fb-main__canvas\"\r\n [selectedName]=\"selectedName()\"\r\n [outline]=\"outline()\"\r\n (selectionChange)=\"onSelectionChange($event)\"\r\n (nodeOpened)=\"onNodeOpened($event)\"\r\n (nodeRemoveRequested)=\"onRemoveNode($event)\"\r\n (nodeDuplicateRequested)=\"onDuplicateNode($event)\"\r\n (elementDropped)=\"onElementDropped($event)\"\r\n />\r\n\r\n @if (showProblems()) {\r\n <fb-problems-panel\r\n class=\"fb-main__problems\"\r\n (elementFocused)=\"focusElement($event)\"\r\n (closed)=\"toggleProblems()\"\r\n />\r\n } @else {\r\n <button type=\"button\" class=\"fb-main__problems-toggle\" (click)=\"toggleProblems()\">\r\n Problemi\r\n @if (errorCount()) {\r\n <span class=\"fb-main__count fb-main__count--error\">{{ errorCount() }}</span>\r\n }\r\n @if (warningCount()) {\r\n <span class=\"fb-main__count fb-main__count--warn\">{{ warningCount() }}</span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <aside class=\"fb-main__side\">\r\n <nav class=\"fb-side__tabs\" aria-label=\"Pannelli\">\r\n @if (!isDialogMode()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'inspector'\"\r\n (click)=\"setPanel('inspector')\"\r\n >\r\n Elemento\r\n </button>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'resources'\"\r\n (click)=\"setPanel('resources')\"\r\n >\r\n Risorse\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'versions'\"\r\n (click)=\"setPanel('versions')\"\r\n >\r\n Versioni\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'debug'\"\r\n (click)=\"setPanel('debug')\"\r\n >\r\n Prova\r\n </button>\r\n </nav>\r\n\r\n <div class=\"fb-side__content\">\r\n @switch (sidePanel()) {\r\n @case ('inspector') {\r\n <fb-element-inspector\r\n [selectedName]=\"selectedName()\"\r\n (removeRequested)=\"onRemoveNode($event)\"\r\n (duplicateRequested)=\"onDuplicateNode($event)\"\r\n (closed)=\"setPanel('resources')\"\r\n />\r\n }\r\n @case ('resources') {\r\n <fb-resource-panel (closed)=\"setPanel('inspector')\" />\r\n }\r\n @case ('versions') {\r\n <fb-version-panel\r\n (versionOpened)=\"openVersion($event)\"\r\n (notice)=\"showNotice($event)\"\r\n (closed)=\"setPanel('inspector')\"\r\n />\r\n }\r\n @case ('debug') {\r\n <!-- Evidenzia sul canvas senza rubare il pannello: l'interview e\u2019 in corso. -->\r\n <fb-debug-panel (elementFocused)=\"highlightElement($event)\" (closed)=\"setPanel('inspector')\" />\r\n }\r\n }\r\n </div>\r\n\r\n <footer class=\"fb-side__footer\">\r\n <label class=\"fb-btn fb-btn--icon\">\r\n Importa JSON\r\n <input type=\"file\" accept=\"application/json,.json\" hidden (change)=\"onFileSelected($event)\" />\r\n </label>\r\n </footer>\r\n </aside>\r\n </div>\r\n\r\n @if (isDialogMode() && isDialogOpen() && selectedName()) {\r\n <!-- La dialog sta dentro il builder, non nel body: la libreria e\u2019 innestabile. -->\r\n <fb-element-dialog\r\n [selectedName]=\"selectedName()\"\r\n (closed)=\"closeDialog()\"\r\n (removeRequested)=\"onRemoveNode($event)\"\r\n (duplicateRequested)=\"onDuplicateNode($event)\"\r\n />\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:100%;height:100%;min-height:0;font:inherit;color:var(--fb-text, #1d2939)}.fb-builder{position:relative;display:flex;flex-direction:column;width:100%;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-top{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-bottom:1px solid var(--fb-border, #e2e5eb);background:var(--fb-surface, #fff)}.fb-top__identity{min-width:0}.fb-top__label{width:100%;max-width:420px;padding:2px 4px;border:1px solid transparent;border-radius:4px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:15px;font-weight:600}.fb-top__label:hover:not(:disabled),.fb-top__label:focus-visible{border-color:var(--fb-border, #d6dae1);background:var(--fb-surface, #fff)}.fb-top__meta{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:2px}.fb-top__name{width:180px;padding:1px 4px;border:1px solid transparent;border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}.fb-top__name:hover:not(:disabled),.fb-top__name:focus-visible{border-color:var(--fb-border, #d6dae1)}.fb-top__process{padding:1px 4px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px}.fb-top__status,.fb-top__version,.fb-top__dirty{padding:2px 7px;border-radius:999px;background:var(--fb-surface-sunken, #eef0f4);color:var(--fb-text-muted, #6b7086);font-size:10px;font-weight:600}.fb-top__version{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-top__dirty{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-top__actions{display:flex;flex-wrap:wrap;gap:4px}.fb-banner{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:6px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 7%,transparent);font-size:11px}.fb-banner--warn{background:color-mix(in srgb,var(--fb-warning, #b7791f) 12%,transparent);color:var(--fb-warning, #b7791f)}.fb-banner--error{background:color-mix(in srgb,var(--fb-error, #c9372c) 10%,transparent);color:var(--fb-error, #c9372c)}.fb-banner>span{flex:1;min-width:200px}.fb-main{display:flex;flex:1;min-height:0}.fb-main__palette{flex:0 0 190px;min-width:0}.fb-main__center{display:flex;flex:1;flex-direction:column;min-width:0;min-height:0}.fb-main__canvas{flex:1;min-height:0}.fb-main__problems{flex:0 0 auto;height:220px}.fb-main__problems-toggle{display:flex;align-items:center;gap:6px;padding:4px 12px;border:0;border-top:1px solid var(--fb-border, #d6dae1);background:var(--fb-surface-alt, #f8f9fb);color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}.fb-main__count{padding:0 5px;border-radius:8px;background:var(--fb-border, #d6dae1);font-size:9px;font-weight:700}.fb-main__count--error{background:color-mix(in srgb,var(--fb-error, #c9372c) 16%,transparent);color:var(--fb-error, #c9372c)}.fb-main__count--warn{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-main__side{display:flex;flex-direction:column;flex:0 0 340px;min-width:0;min-height:0;border-left:1px solid var(--fb-border, #d6dae1);background:var(--fb-surface, #fff)}.fb-side__tabs{display:flex;gap:2px;margin:8px 10px;padding:3px;border-radius:var(--fb-radius, 10px);background:var(--fb-surface-sunken, #eef0f4)}.fb-side__tab{flex:1;padding:5px 8px;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-text-muted, #6b7086);font:inherit;font-size:11px;cursor:pointer;transition:background .12s ease,color .12s ease}.fb-side__tab:hover:not(.fb-side__tab--active){color:var(--fb-text, #1a1c23)}.fb-side__tab--active{background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));color:var(--fb-text, #1a1c23);font-weight:600}.fb-side__content{flex:1;min-height:0;border-top:1px solid var(--fb-border-subtle, #eef0f4)}.fb-side__content>*{height:100%}.fb-side__footer{display:flex;gap:6px;padding:6px 8px;border-top:1px solid var(--fb-border-subtle, #e6e9ee)}@media(max-width:1200px){.fb-main__palette{flex-basis:150px}.fb-main__side{flex-basis:290px}}\n"], dependencies: [{ kind: "component", type: DebugPanelComponent, selector: "fb-debug-panel", outputs: ["closed", "elementFocused"] }, { kind: "component", type: ElementDialogComponent, selector: "fb-element-dialog", inputs: ["selectedName"], outputs: ["closed", "removeRequested", "duplicateRequested"] }, { kind: "component", type: ElementInspectorComponent, selector: "fb-element-inspector", inputs: ["selectedName", "showHeader"], outputs: ["closed", "removeRequested", "duplicateRequested"] }, { kind: "component", type: ElementPaletteComponent, selector: "fb-element-palette", inputs: ["processType"], outputs: ["elementPicked"] }, { kind: "component", type: FlowCanvasComponent, selector: "fb-flow-canvas", inputs: ["selectedName", "outline"], outputs: ["selectionChange", "nodeOpened", "nodeRemoveRequested", "nodeDuplicateRequested", "elementDropped"] }, { kind: "component", type: ProblemsPanelComponent, selector: "fb-problems-panel", outputs: ["elementFocused", "closed"] }, { kind: "component", type: ResourcePanelComponent, selector: "fb-resource-panel", outputs: ["closed"] }, { kind: "component", type: VersionPanelComponent, selector: "fb-version-panel", outputs: ["closed", "versionOpened", "notice"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7245
8074
|
}
|
|
7246
8075
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: FlowBuilderComponent, decorators: [{
|
|
7247
8076
|
type: Component,
|
|
@@ -7259,12 +8088,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
|
|
|
7259
8088
|
FlowValidationStore,
|
|
7260
8089
|
FlowEditorSession,
|
|
7261
8090
|
FlowLayoutService,
|
|
7262
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-builder\" [attr.data-fb-theme]=\"null\">\r\n <header class=\"fb-top\">\r\n <div class=\"fb-top__identity\">\r\n <input\r\n class=\"fb-top__label\"\r\n [value]=\"document().label || ''\"\r\n placeholder=\"Nome del flow\"\r\n aria-label=\"Nome del flow\"\r\n [disabled]=\"!isEditable()\"\r\n (input)=\"setLabel($any($event.target).value)\"\r\n />\r\n <div class=\"fb-top__meta\">\r\n <input\r\n class=\"fb-top__name\"\r\n [value]=\"document().fullName || ''\"\r\n placeholder=\"NomeTecnico\"\r\n aria-label=\"Nome tecnico del flow\"\r\n [disabled]=\"!isEditable()\"\r\n (input)=\"setFullName($any($event.target).value)\"\r\n />\r\n <select\r\n class=\"fb-top__process\"\r\n [fbValue]=\"document().processType || ''\"\r\n aria-label=\"Tipo di flow\"\r\n [disabled]=\"!isEditable()\"\r\n (change)=\"setProcessType($any($event.target).value)\"\r\n >\r\n @for (type of processTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n <span class=\"fb-top__status\">{{ statusLabel() }}</span>\r\n @if (session.version() !== null) {\r\n <span class=\"fb-top__version\">v{{ session.version() }}</span>\r\n }\r\n @if (isDirty()) {\r\n <span class=\"fb-top__dirty\" title=\"Ci sono modifiche non salvate\">modificato</span>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"fb-top__actions\">\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"!canUndo()\" aria-label=\"Annulla\" (click)=\"undo()\">\u21B6</button>\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"!canRedo()\" aria-label=\"Ripeti\" (click)=\"redo()\">\u21B7</button>\r\n <button type=\"button\" class=\"fb-btn\" title=\"Ricalcola le posizioni\" (click)=\"autoLayout()\">Riordina</button>\r\n @if (isDialogMode()) {\r\n <!-- Il doppio click sul node fa la stessa cosa, ma non si vede: questo comando s\u00EC. -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"!selectedName()\"\r\n title=\"Apri il dettaglio dell\u2019elemento selezionato\"\r\n (click)=\"openSelectedElement()\"\r\n >\r\n Dettaglio\r\n </button>\r\n }\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"isBusy()\" (click)=\"validateNow()\">Valida</button>\r\n\r\n @switch (primaryCommand()) {\r\n @case ('newVersion') {\r\n <!-- Su una versione non modificabile il comando primario e' \"Nuova versione\" (\u00A78.1). -->\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"isBusy()\" (click)=\"createNewVersion()\">\r\n Nuova versione\r\n </button>\r\n }\r\n @case ('create') {\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"isBusy()\" (click)=\"save()\">\r\n Crea\r\n </button>\r\n }\r\n @default {\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"isBusy()\" (click)=\"save()\">\r\n Salva\r\n </button>\r\n }\r\n }\r\n\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"isBusy() || !canActivate()\"\r\n [title]=\"\r\n canActivate()\r\n ? 'Attiva questa versione'\r\n : 'L\u2019attivazione esige zero errori: correggili nel pannello dei problemi'\r\n \"\r\n (click)=\"activate()\"\r\n >\r\n Attiva\r\n </button>\r\n </div>\r\n </header>\r\n\r\n @if (conflict()) {\r\n <!-- \u00A79.3: qualcun altro ha salvato. Due strade, entrambe offerte. -->\r\n <div class=\"fb-banner fb-banner--warn\" role=\"alert\">\r\n <span>\r\n {{ conflict()?.message }}\r\n @if (conflict()?.conflictingAuthor) {\r\n Ha salvato {{ conflict()?.conflictingAuthor }}.\r\n }\r\n </span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--icon\" (click)=\"reloadAfterConflict()\">Ricarica</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--icon\" (click)=\"saveAsNewVersionAfterConflict()\">\r\n Salva come nuova versione\r\n </button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"dismissConflict()\">\u00D7</button>\r\n </div>\r\n }\r\n\r\n @if (notice()) {\r\n <div\r\n class=\"fb-banner\"\r\n [class.fb-banner--error]=\"notice()?.kind === 'error'\"\r\n role=\"status\"\r\n >\r\n <span>{{ notice()?.message }}</span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"dismissNotice()\">\r\n \u00D7\r\n </button>\r\n </div>\r\n }\r\n\r\n @if (hasScreensInAutoLaunched()) {\r\n <div class=\"fb-banner fb-banner--error\">\r\n Un flow AutoLaunched che contiene screen e\u2019 un errore di validazione: non c\u2019e\u2019 nessuno a cui mostrarli.\r\n </div>\r\n }\r\n @if (isOrchestration()) {\r\n <div class=\"fb-banner fb-banner--warn\">Un flow Orchestration non e\u2019 eseguibile dal motore.</div>\r\n }\r\n @if (hasNoScreensInScreenFlow()) {\r\n <div class=\"fb-banner fb-banner--warn\">\r\n Un flow di tipo Screen senza nessuno screen viene segnalato dalla validazione.\r\n </div>\r\n }\r\n @if (!isEditable()) {\r\n <div class=\"fb-banner\">\r\n Questa versione e\u2019 in sola lettura: per modificarla creane una nuova.\r\n </div>\r\n }\r\n\r\n <div class=\"fb-main\">\r\n <aside class=\"fb-main__palette\">\r\n <fb-element-palette [processType]=\"document().processType\" (elementPicked)=\"onElementPicked($event)\" />\r\n </aside>\r\n\r\n <div class=\"fb-main__center\">\r\n <fb-flow-canvas\r\n class=\"fb-main__canvas\"\r\n [selectedName]=\"selectedName()\"\r\n [outline]=\"outline()\"\r\n (selectionChange)=\"onSelectionChange($event)\"\r\n (nodeOpened)=\"onNodeOpened($event)\"\r\n (nodeRemoveRequested)=\"onRemoveNode($event)\"\r\n (nodeDuplicateRequested)=\"onDuplicateNode($event)\"\r\n (elementDropped)=\"onElementDropped($event)\"\r\n />\r\n\r\n @if (showProblems()) {\r\n <fb-problems-panel\r\n class=\"fb-main__problems\"\r\n (elementFocused)=\"focusElement($event)\"\r\n (closed)=\"toggleProblems()\"\r\n />\r\n } @else {\r\n <button type=\"button\" class=\"fb-main__problems-toggle\" (click)=\"toggleProblems()\">\r\n Problemi\r\n @if (errorCount()) {\r\n <span class=\"fb-main__count fb-main__count--error\">{{ errorCount() }}</span>\r\n }\r\n @if (warningCount()) {\r\n <span class=\"fb-main__count fb-main__count--warn\">{{ warningCount() }}</span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <aside class=\"fb-main__side\">\r\n <nav class=\"fb-side__tabs\" aria-label=\"Pannelli\">\r\n @if (!isDialogMode()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'inspector'\"\r\n (click)=\"setPanel('inspector')\"\r\n >\r\n Elemento\r\n </button>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'resources'\"\r\n (click)=\"setPanel('resources')\"\r\n >\r\n Risorse\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'versions'\"\r\n (click)=\"setPanel('versions')\"\r\n >\r\n Versioni\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'debug'\"\r\n (click)=\"setPanel('debug')\"\r\n >\r\n Prova\r\n </button>\r\n </nav>\r\n\r\n <div class=\"fb-side__content\">\r\n @switch (sidePanel()) {\r\n @case ('inspector') {\r\n <fb-element-inspector\r\n [selectedName]=\"selectedName()\"\r\n (removeRequested)=\"onRemoveNode($event)\"\r\n (duplicateRequested)=\"onDuplicateNode($event)\"\r\n (closed)=\"setPanel('resources')\"\r\n />\r\n }\r\n @case ('resources') {\r\n <fb-resource-panel (closed)=\"setPanel('inspector')\" />\r\n }\r\n @case ('versions') {\r\n <fb-version-panel\r\n (versionOpened)=\"openVersion($event)\"\r\n (notice)=\"showNotice($event)\"\r\n (closed)=\"setPanel('inspector')\"\r\n />\r\n }\r\n @case ('debug') {\r\n <!-- Evidenzia sul canvas senza rubare il pannello: l'interview e\u2019 in corso. -->\r\n <fb-debug-panel (elementFocused)=\"highlightElement($event)\" (closed)=\"setPanel('inspector')\" />\r\n }\r\n }\r\n </div>\r\n\r\n <footer class=\"fb-side__footer\">\r\n <label class=\"fb-btn fb-btn--icon\">\r\n Importa JSON\r\n <input type=\"file\" accept=\"application/json,.json\" hidden (change)=\"onFileSelected($event)\" />\r\n </label>\r\n </footer>\r\n </aside>\r\n </div>\r\n\r\n @if (isDialogMode() && isDialogOpen() && selectedName()) {\r\n <!-- La dialog sta dentro il builder, non nel body: la libreria e\u2019 innestabile. -->\r\n <fb-element-dialog\r\n [selectedName]=\"selectedName()\"\r\n (closed)=\"closeDialog()\"\r\n (removeRequested)=\"onRemoveNode($event)\"\r\n (duplicateRequested)=\"onDuplicateNode($event)\"\r\n />\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:100%;height:100%;min-height:0;font:inherit;color:var(--fb-text, #1d2939)}.fb-builder{position:relative;display:flex;flex-direction:column;width:100%;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-top{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-bottom:1px solid var(--fb-border, #e2e5eb);background:var(--fb-surface, #fff)}.fb-top__identity{min-width:0}.fb-top__label{width:100%;max-width:420px;padding:2px 4px;border:1px solid transparent;border-radius:4px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:15px;font-weight:600}.fb-top__label:hover:not(:disabled),.fb-top__label:focus-visible{border-color:var(--fb-border, #d6dae1);background:var(--fb-surface, #fff)}.fb-top__meta{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:2px}.fb-top__name{width:180px;padding:1px 4px;border:1px solid transparent;border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}.fb-top__name:hover:not(:disabled),.fb-top__name:focus-visible{border-color:var(--fb-border, #d6dae1)}.fb-top__process{padding:1px 4px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px}.fb-top__status,.fb-top__version,.fb-top__dirty{padding:2px 7px;border-radius:999px;background:var(--fb-surface-sunken, #eef0f4);color:var(--fb-text-muted, #6b7086);font-size:10px;font-weight:600}.fb-top__version{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-top__dirty{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-top__actions{display:flex;flex-wrap:wrap;gap:4px}.fb-banner{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:6px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 7%,transparent);font-size:11px}.fb-banner--warn{background:color-mix(in srgb,var(--fb-warning, #b7791f) 12%,transparent);color:var(--fb-warning, #b7791f)}.fb-banner--error{background:color-mix(in srgb,var(--fb-error, #c9372c) 10%,transparent);color:var(--fb-error, #c9372c)}.fb-banner>span{flex:1;min-width:200px}.fb-main{display:flex;flex:1;min-height:0}.fb-main__palette{flex:0 0 190px;min-width:0}.fb-main__center{display:flex;flex:1;flex-direction:column;min-width:0;min-height:0}.fb-main__canvas{flex:1;min-height:0}.fb-main__problems{flex:0 0 auto;height:220px}.fb-main__problems-toggle{display:flex;align-items:center;gap:6px;padding:4px 12px;border:0;border-top:1px solid var(--fb-border, #d6dae1);background:var(--fb-surface-alt, #f8f9fb);color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}.fb-main__count{padding:0 5px;border-radius:8px;background:var(--fb-border, #d6dae1);font-size:9px;font-weight:700}.fb-main__count--error{background:color-mix(in srgb,var(--fb-error, #c9372c) 16%,transparent);color:var(--fb-error, #c9372c)}.fb-main__count--warn{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-main__side{display:flex;flex-direction:column;flex:0 0 340px;min-width:0;min-height:0;border-left:1px solid var(--fb-border, #d6dae1);background:var(--fb-surface, #fff)}.fb-side__tabs{display:flex;gap:2px;margin:8px 10px;padding:3px;border-radius:var(--fb-radius, 10px);background:var(--fb-surface-sunken, #eef0f4)}.fb-side__tab{flex:1;padding:5px 8px;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-text-muted, #6b7086);font:inherit;font-size:11px;cursor:pointer;transition:background .12s ease,color .12s ease}.fb-side__tab:hover:not(.fb-side__tab--active){color:var(--fb-text, #1a1c23)}.fb-side__tab--active{background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));color:var(--fb-text, #1a1c23);font-weight:600}.fb-side__content{flex:1;min-height:0;border-top:1px solid var(--fb-border-subtle, #eef0f4)}.fb-side__content>*{height:100%}.fb-side__footer{display:flex;gap:6px;padding:6px 8px;border-top:1px solid var(--fb-border-subtle, #e6e9ee)}@media(max-width:1200px){.fb-main__palette{flex-basis:150px}.fb-main__side{flex-basis:290px}}\n"] }]
|
|
8091
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-builder\" [attr.data-fb-theme]=\"null\">\r\n <header class=\"fb-top\">\r\n <div class=\"fb-top__identity\">\r\n <input\r\n class=\"fb-top__label\"\r\n [value]=\"document().label || ''\"\r\n placeholder=\"Nome del flow\"\r\n aria-label=\"Nome del flow\"\r\n [disabled]=\"!isEditable()\"\r\n (input)=\"setLabel($any($event.target).value)\"\r\n />\r\n <div class=\"fb-top__meta\">\r\n <input\r\n class=\"fb-top__name\"\r\n [value]=\"document().fullName || ''\"\r\n placeholder=\"NomeTecnico\"\r\n aria-label=\"Nome tecnico del flow\"\r\n [disabled]=\"!isEditable()\"\r\n (input)=\"setFullName($any($event.target).value)\"\r\n />\r\n <select\r\n class=\"fb-top__process\"\r\n [fbValue]=\"document().processType || ''\"\r\n aria-label=\"Tipo di flow\"\r\n [disabled]=\"!isEditable()\"\r\n (change)=\"setProcessType($any($event.target).value)\"\r\n >\r\n @for (type of processTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n <span class=\"fb-top__status\">{{ statusLabel() }}</span>\r\n @if (session.version() !== null) {\r\n <span class=\"fb-top__version\">v{{ session.version() }}</span>\r\n }\r\n @if (isDirty()) {\r\n <span class=\"fb-top__dirty\" title=\"Ci sono modifiche non salvate\">modificato</span>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"fb-top__actions\">\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"!canUndo()\" aria-label=\"Annulla\" (click)=\"undo()\">\u21B6</button>\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"!canRedo()\" aria-label=\"Ripeti\" (click)=\"redo()\">\u21B7</button>\r\n <button type=\"button\" class=\"fb-btn\" title=\"Ricalcola le posizioni\" (click)=\"autoLayout()\">Riordina</button>\r\n @if (isDialogMode()) {\r\n <!-- Il doppio click sul node fa la stessa cosa, ma non si vede: questo comando s\u00EC. -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"!selectedName()\"\r\n title=\"Apri il dettaglio dell\u2019elemento selezionato\"\r\n (click)=\"openSelectedElement()\"\r\n >\r\n Dettaglio\r\n </button>\r\n }\r\n <button type=\"button\" class=\"fb-btn\" [disabled]=\"isBusy()\" (click)=\"validateNow()\">Valida</button>\r\n\r\n @switch (primaryCommand()) {\r\n @case ('newVersion') {\r\n <!-- Su una versione non modificabile il comando primario e' \"Nuova versione\" (\u00A78.1). -->\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"isBusy()\" (click)=\"createNewVersion()\">\r\n Nuova versione\r\n </button>\r\n }\r\n @case ('create') {\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"isBusy()\" (click)=\"save()\">\r\n Crea\r\n </button>\r\n }\r\n @default {\r\n <button type=\"button\" class=\"fb-btn fb-btn--primary\" [disabled]=\"isBusy()\" (click)=\"save()\">\r\n Salva\r\n </button>\r\n }\r\n }\r\n\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn\"\r\n [disabled]=\"isBusy() || !canActivate()\"\r\n [title]=\"\r\n canActivate()\r\n ? 'Attiva questa versione'\r\n : 'L\u2019attivazione esige zero errori: correggili nel pannello dei problemi'\r\n \"\r\n (click)=\"activate()\"\r\n >\r\n Attiva\r\n </button>\r\n </div>\r\n </header>\r\n\r\n @if (conflict()) {\r\n <!-- \u00A79.3: qualcun altro ha salvato. Due strade, entrambe offerte. -->\r\n <div class=\"fb-banner fb-banner--warn\" role=\"alert\">\r\n <span>\r\n {{ conflict()?.message }}\r\n @if (conflict()?.conflictingAuthor) {\r\n Ha salvato {{ conflict()?.conflictingAuthor }}.\r\n }\r\n </span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--icon\" (click)=\"reloadAfterConflict()\">Ricarica</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--icon\" (click)=\"saveAsNewVersionAfterConflict()\">\r\n Salva come nuova versione\r\n </button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"dismissConflict()\">\u00D7</button>\r\n </div>\r\n }\r\n\r\n @if (notice()) {\r\n <div\r\n class=\"fb-banner\"\r\n [class.fb-banner--error]=\"notice()?.kind === 'error'\"\r\n role=\"status\"\r\n >\r\n <span>{{ notice()?.message }}</span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" aria-label=\"Chiudi\" (click)=\"dismissNotice()\">\r\n \u00D7\r\n </button>\r\n </div>\r\n }\r\n\r\n @if (hasScreensInAutoLaunched()) {\r\n <div class=\"fb-banner fb-banner--error\">\r\n Un flow AutoLaunched che contiene screen e\u2019 un errore di validazione: non c\u2019e\u2019 nessuno a cui mostrarli.\r\n </div>\r\n }\r\n @if (isOrchestrationWithoutStages()) {\r\n <div class=\"fb-banner fb-banner--warn\">\r\n Un flow Orchestration senza stage di orchestrazione viene segnalato dalla validazione\r\n (ORCHESTRATION_WITHOUT_STAGES).\r\n </div>\r\n }\r\n @if (hasNoScreensInScreenFlow()) {\r\n <div class=\"fb-banner fb-banner--warn\">\r\n Un flow di tipo Screen senza nessuno screen viene segnalato dalla validazione.\r\n </div>\r\n }\r\n @if (!isEditable()) {\r\n <div class=\"fb-banner\">\r\n Questa versione e\u2019 in sola lettura: per modificarla creane una nuova.\r\n </div>\r\n }\r\n\r\n <div class=\"fb-main\">\r\n <aside class=\"fb-main__palette\">\r\n <fb-element-palette [processType]=\"document().processType\" (elementPicked)=\"onElementPicked($event)\" />\r\n </aside>\r\n\r\n <div class=\"fb-main__center\">\r\n <fb-flow-canvas\r\n class=\"fb-main__canvas\"\r\n [selectedName]=\"selectedName()\"\r\n [outline]=\"outline()\"\r\n (selectionChange)=\"onSelectionChange($event)\"\r\n (nodeOpened)=\"onNodeOpened($event)\"\r\n (nodeRemoveRequested)=\"onRemoveNode($event)\"\r\n (nodeDuplicateRequested)=\"onDuplicateNode($event)\"\r\n (elementDropped)=\"onElementDropped($event)\"\r\n />\r\n\r\n @if (showProblems()) {\r\n <fb-problems-panel\r\n class=\"fb-main__problems\"\r\n (elementFocused)=\"focusElement($event)\"\r\n (closed)=\"toggleProblems()\"\r\n />\r\n } @else {\r\n <button type=\"button\" class=\"fb-main__problems-toggle\" (click)=\"toggleProblems()\">\r\n Problemi\r\n @if (errorCount()) {\r\n <span class=\"fb-main__count fb-main__count--error\">{{ errorCount() }}</span>\r\n }\r\n @if (warningCount()) {\r\n <span class=\"fb-main__count fb-main__count--warn\">{{ warningCount() }}</span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n\r\n <aside class=\"fb-main__side\">\r\n <nav class=\"fb-side__tabs\" aria-label=\"Pannelli\">\r\n @if (!isDialogMode()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'inspector'\"\r\n (click)=\"setPanel('inspector')\"\r\n >\r\n Elemento\r\n </button>\r\n }\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'resources'\"\r\n (click)=\"setPanel('resources')\"\r\n >\r\n Risorse\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'versions'\"\r\n (click)=\"setPanel('versions')\"\r\n >\r\n Versioni\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-side__tab\"\r\n [class.fb-side__tab--active]=\"sidePanel() === 'debug'\"\r\n (click)=\"setPanel('debug')\"\r\n >\r\n Prova\r\n </button>\r\n </nav>\r\n\r\n <div class=\"fb-side__content\">\r\n @switch (sidePanel()) {\r\n @case ('inspector') {\r\n <fb-element-inspector\r\n [selectedName]=\"selectedName()\"\r\n (removeRequested)=\"onRemoveNode($event)\"\r\n (duplicateRequested)=\"onDuplicateNode($event)\"\r\n (closed)=\"setPanel('resources')\"\r\n />\r\n }\r\n @case ('resources') {\r\n <fb-resource-panel (closed)=\"setPanel('inspector')\" />\r\n }\r\n @case ('versions') {\r\n <fb-version-panel\r\n (versionOpened)=\"openVersion($event)\"\r\n (notice)=\"showNotice($event)\"\r\n (closed)=\"setPanel('inspector')\"\r\n />\r\n }\r\n @case ('debug') {\r\n <!-- Evidenzia sul canvas senza rubare il pannello: l'interview e\u2019 in corso. -->\r\n <fb-debug-panel (elementFocused)=\"highlightElement($event)\" (closed)=\"setPanel('inspector')\" />\r\n }\r\n }\r\n </div>\r\n\r\n <footer class=\"fb-side__footer\">\r\n <label class=\"fb-btn fb-btn--icon\">\r\n Importa JSON\r\n <input type=\"file\" accept=\"application/json,.json\" hidden (change)=\"onFileSelected($event)\" />\r\n </label>\r\n </footer>\r\n </aside>\r\n </div>\r\n\r\n @if (isDialogMode() && isDialogOpen() && selectedName()) {\r\n <!-- La dialog sta dentro il builder, non nel body: la libreria e\u2019 innestabile. -->\r\n <fb-element-dialog\r\n [selectedName]=\"selectedName()\"\r\n (closed)=\"closeDialog()\"\r\n (removeRequested)=\"onRemoveNode($event)\"\r\n (duplicateRequested)=\"onDuplicateNode($event)\"\r\n />\r\n }\r\n</div>\r\n", styles: [":host{display:block;width:100%;height:100%;min-height:0;font:inherit;color:var(--fb-text, #1d2939)}.fb-builder{position:relative;display:flex;flex-direction:column;width:100%;height:100%;min-height:0;background:var(--fb-surface, #fff)}.fb-top{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 14px;border-bottom:1px solid var(--fb-border, #e2e5eb);background:var(--fb-surface, #fff)}.fb-top__identity{min-width:0}.fb-top__label{width:100%;max-width:420px;padding:2px 4px;border:1px solid transparent;border-radius:4px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:15px;font-weight:600}.fb-top__label:hover:not(:disabled),.fb-top__label:focus-visible{border-color:var(--fb-border, #d6dae1);background:var(--fb-surface, #fff)}.fb-top__meta{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:2px}.fb-top__name{width:180px;padding:1px 4px;border:1px solid transparent;border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}.fb-top__name:hover:not(:disabled),.fb-top__name:focus-visible{border-color:var(--fb-border, #d6dae1)}.fb-top__process{padding:1px 4px;border:1px solid var(--fb-border-subtle, #e6e9ee);border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px}.fb-top__status,.fb-top__version,.fb-top__dirty{padding:2px 7px;border-radius:999px;background:var(--fb-surface-sunken, #eef0f4);color:var(--fb-text-muted, #6b7086);font-size:10px;font-weight:600}.fb-top__version{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-top__dirty{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-top__actions{display:flex;flex-wrap:wrap;gap:4px}.fb-banner{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:6px 12px;border-bottom:1px solid var(--fb-border-subtle, #e6e9ee);background:color-mix(in srgb,var(--fb-accent, #2f6feb) 7%,transparent);font-size:11px}.fb-banner--warn{background:color-mix(in srgb,var(--fb-warning, #b7791f) 12%,transparent);color:var(--fb-warning, #b7791f)}.fb-banner--error{background:color-mix(in srgb,var(--fb-error, #c9372c) 10%,transparent);color:var(--fb-error, #c9372c)}.fb-banner>span{flex:1;min-width:200px}.fb-main{display:flex;flex:1;min-height:0}.fb-main__palette{flex:0 0 190px;min-width:0}.fb-main__center{display:flex;flex:1;flex-direction:column;min-width:0;min-height:0}.fb-main__canvas{flex:1;min-height:0}.fb-main__problems{flex:0 0 auto;height:220px}.fb-main__problems-toggle{display:flex;align-items:center;gap:6px;padding:4px 12px;border:0;border-top:1px solid var(--fb-border, #d6dae1);background:var(--fb-surface-alt, #f8f9fb);color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}.fb-main__count{padding:0 5px;border-radius:8px;background:var(--fb-border, #d6dae1);font-size:9px;font-weight:700}.fb-main__count--error{background:color-mix(in srgb,var(--fb-error, #c9372c) 16%,transparent);color:var(--fb-error, #c9372c)}.fb-main__count--warn{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-main__side{display:flex;flex-direction:column;flex:0 0 340px;min-width:0;min-height:0;border-left:1px solid var(--fb-border, #d6dae1);background:var(--fb-surface, #fff)}.fb-side__tabs{display:flex;gap:2px;margin:8px 10px;padding:3px;border-radius:var(--fb-radius, 10px);background:var(--fb-surface-sunken, #eef0f4)}.fb-side__tab{flex:1;padding:5px 8px;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-text-muted, #6b7086);font:inherit;font-size:11px;cursor:pointer;transition:background .12s ease,color .12s ease}.fb-side__tab:hover:not(.fb-side__tab--active){color:var(--fb-text, #1a1c23)}.fb-side__tab--active{background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));color:var(--fb-text, #1a1c23);font-weight:600}.fb-side__content{flex:1;min-height:0;border-top:1px solid var(--fb-border-subtle, #eef0f4)}.fb-side__content>*{height:100%}.fb-side__footer{display:flex;gap:6px;padding:6px 8px;border-top:1px solid var(--fb-border-subtle, #e6e9ee)}@media(max-width:1200px){.fb-main__palette{flex-basis:150px}.fb-main__side{flex-basis:290px}}\n"] }]
|
|
7263
8092
|
}], ctorParameters: () => [], propDecorators: { flowName: [{ type: i0.Input, args: [{ isSignal: true, alias: "flowName", required: false }] }], version: [{ type: i0.Input, args: [{ isSignal: true, alias: "version", required: false }] }], author: [{ type: i0.Input, args: [{ isSignal: true, alias: "author", required: false }] }], defaultProcessType: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultProcessType", required: false }] }], inspectorMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "inspectorMode", required: false }] }], saved: [{ type: i0.Output, args: ["saved"] }], activated: [{ type: i0.Output, args: ["activated"] }], closeRequested: [{ type: i0.Output, args: ["closeRequested"] }] } });
|
|
7264
8093
|
|
|
7265
8094
|
/**
|
|
7266
8095
|
* Generated bundle index. Do not edit.
|
|
7267
8096
|
*/
|
|
7268
8097
|
|
|
7269
|
-
export { ConditionEditorComponent, ConnectorEditorComponent, DebugPanelComponent, ElementDialogComponent, ElementInspectorComponent, ElementPaletteComponent, FALLBACK_COLLECTION_BY_TYPE, FALLBACK_TYPE_LABEL, FLOW_BUILDER_HTTP_CONFIG, FLOW_ELEMENT_ICONS, FLOW_ERROR_FALLBACK_MESSAGE, FLOW_ERROR_HTTP_STATUS, FLOW_NAME_PATTERN, FLOW_NODE_COLLECTIONS, FLOW_NODE_HEIGHT, FLOW_NODE_WIDTH, FLOW_RESOURCE_COLLECTIONS, FieldAssignmentEditorComponent, FlowApiError, FlowBuilderApi, FlowBuilderComponent, FlowCanvasComponent, FlowCatalogStore, FlowDictionaryStore, FlowDocumentStore, FlowEditorSession, FlowLayoutService, FlowValidationStore, HttpFlowBuilderApi, NodeInspectorBase, ParameterEditorComponent, ProblemsPanelComponent, RecordFilterEditorComponent, ReferencePickerComponent, ResourcePanelComponent, START_NODE_NAME, SelectValueDirective, StartInspectorComponent, TYPES_WITH_AUTOMATIC_OUTPUT, TYPE_BY_COLLECTION, UNSUPPORTED_TYPES, ValueEditorComponent, VersionPanelComponent, canvasNodeId, checkConditionLogic, checkFlowName, elementIcon, emptyFlowDefinition, flowNodeWidth, flowNodeWidthClass, isCustomConditionLogic, isGlobalReference, isValidFlowName, moveCondition, outletByKey, outletsOf, parseCanvasNodeId, parseSourceConnectorId, parseTargetConnectorId, referenceRoot, remapConditionLogic, removeCondition, slugifyFlowName, sourceConnectorId, targetConnectorId, uniqueFlowName };
|
|
8098
|
+
export { ConditionEditorComponent, ConnectorEditorComponent, DebugPanelComponent, ElementDialogComponent, ElementInspectorComponent, ElementPaletteComponent, FALLBACK_COLLECTION_BY_TYPE, FALLBACK_TYPE_LABEL, FLOW_BUILDER_HTTP_CONFIG, FLOW_ELEMENT_ICONS, FLOW_ERROR_FALLBACK_MESSAGE, FLOW_ERROR_HTTP_STATUS, FLOW_NAME_PATTERN, FLOW_NODE_COLLECTIONS, FLOW_NODE_HEIGHT, FLOW_NODE_WIDTH, FLOW_RESOURCE_COLLECTIONS, FieldAssignmentEditorComponent, FlowApiError, FlowBuilderApi, FlowBuilderComponent, FlowCanvasComponent, FlowCatalogStore, FlowDictionaryStore, FlowDocumentStore, FlowEditorSession, FlowLayoutService, FlowValidationStore, HttpFlowBuilderApi, NodeInspectorBase, ORCHESTRATION_CONDITION_OUTPUT, OrchestratedStageInspectorComponent, ParameterEditorComponent, ProblemsPanelComponent, RecordFilterEditorComponent, ReferencePickerComponent, ResourcePanelComponent, START_NODE_NAME, SelectValueDirective, StartInspectorComponent, TYPES_WITH_AUTOMATIC_OUTPUT, TYPE_BY_COLLECTION, UNSUPPORTED_TYPES, ValueEditorComponent, VersionPanelComponent, areTypesComparable, canvasNodeId, checkConditionLogic, checkFlowName, elementIcon, emptyFlowDefinition, flowNodeWidth, flowNodeWidthClass, isCustomConditionLogic, isGlobalReference, isNumericType, isTypeCheckedOperator, isValidFlowName, moveCondition, outletByKey, outletsOf, parseCanvasNodeId, parseInvariantNumber, parseSourceConnectorId, parseTargetConnectorId, referenceRoot, remapConditionLogic, removeCondition, slugifyFlowName, sourceConnectorId, stageStepNames, stageStepOutputReferenced, stepsOf, targetConnectorId, uniqueFlowName };
|
|
7270
8099
|
//# sourceMappingURL=esfaenza-flow-builder.mjs.map
|