@esfaenza/flow-builder 20.3.44 → 20.3.45
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 +39 -3
- package/fesm2022/esfaenza-flow-builder.mjs +361 -39
- package/fesm2022/esfaenza-flow-builder.mjs.map +1 -1
- package/index.d.ts +232 -16
- package/package.json +1 -1
|
@@ -1416,6 +1416,12 @@ const ORCHESTRATION_CONDITION_OUTPUT = 'isOrchestrationConditionMet';
|
|
|
1416
1416
|
* del flow** (§5.2). I loro nomi vivono nello stesso spazio dei nomi di node e risorse (§3.3),
|
|
1417
1417
|
* quindi `usedNames` dello store deve comprenderli — un campo omonimo di una variabile e'
|
|
1418
1418
|
* `NAME_DUPLICATED`, non una stranezza tollerata.
|
|
1419
|
+
*
|
|
1420
|
+
* L'unica eccezione a quest'ultima e' la `RepeatingSection`, e le due meta' vanno tenute distinte perche'
|
|
1421
|
+
* e' facile appiattirle: i campi **dentro** una riga non sono risorse (il loro nome non individua alcun
|
|
1422
|
+
* valore, perche' la riga esiste una volta per elemento della collection) ma un nome unico ce l'hanno
|
|
1423
|
+
* comunque. Quindi `screenFieldNames` li comprende — `NAME_DUPLICATED` vale — mentre
|
|
1424
|
+
* {@link resourceFieldsOf} no: proporli fra i riferimenti e' `SCREEN_FIELD_IN_REPEATER`.
|
|
1419
1425
|
*/
|
|
1420
1426
|
/** Uguaglianza fra percorsi: due array diversi con gli stessi indici sono lo stesso campo. */
|
|
1421
1427
|
function samePath(a, b) {
|
|
@@ -1483,7 +1489,9 @@ function allFieldsOf(screen) {
|
|
|
1483
1489
|
*
|
|
1484
1490
|
* Contenitori compresi: un `Region` non e' una risorsa — non raccoglie un valore — ma il suo
|
|
1485
1491
|
* nome resta un nome, e due campi omonimi nella stessa schermata sono comunque un problema.
|
|
1486
|
-
*
|
|
1492
|
+
* Ci sono anche i campi **dentro una riga** di una sezione ripetibile, che risorse non sono ma un nome
|
|
1493
|
+
* ce l'hanno lo stesso: e' l'indirizzo con cui il frontend rende il campo, e due omonimi lo renderebbero
|
|
1494
|
+
* ambiguo (§5.2). Chi vuole i **soli** riferimenti proponibili usa {@link resourceFieldsOf}.
|
|
1487
1495
|
*/
|
|
1488
1496
|
function screenFieldNames(definition) {
|
|
1489
1497
|
const names = [];
|
|
@@ -1526,11 +1534,80 @@ function screenActionNames(definition) {
|
|
|
1526
1534
|
* i suoi output. Il flag `storesValue` arriva dal dizionario, che e' l'unica fonte autoritativa:
|
|
1527
1535
|
* senza la voce del dizionario si risponde `false`, cioe' "non lo so" — proporre un riferimento
|
|
1528
1536
|
* che il backend non conosce e' peggio che non proporlo.
|
|
1537
|
+
*
|
|
1538
|
+
* Guarda il **solo campo**, e non basta: un campo dentro una `RepeatingSection` raccoglie un valore ma
|
|
1539
|
+
* non e' una risorsa, perche' esiste in una riga per ogni elemento della collection. Quella domanda ha
|
|
1540
|
+
* bisogno del contesto, e la risponde {@link resourceFieldsOf}.
|
|
1529
1541
|
*/
|
|
1530
1542
|
function isFieldResource(field, entry) {
|
|
1531
1543
|
return !!field?.name && entry?.storesValue === true;
|
|
1532
1544
|
}
|
|
1533
1545
|
// ---------------------------------------------------------------------------
|
|
1546
|
+
// §5.2 — sezioni ripetibili: cosa cambia dentro una riga
|
|
1547
|
+
// ---------------------------------------------------------------------------
|
|
1548
|
+
/**
|
|
1549
|
+
* §5.2 — i campi dichiarati dentro una `RepeatingSection` sono il **modello di una riga**, e la riga
|
|
1550
|
+
* esiste una volta per elemento della collection: il loro nome non individua alcun valore.
|
|
1551
|
+
*
|
|
1552
|
+
* Da qui discende tutto cio' che l'editor fa di diverso lì dentro. Non sono risorse del flow, non si
|
|
1553
|
+
* propongono fra i riferimenti, non innescano screen action e non sono destinazioni: nominarli e'
|
|
1554
|
+
* `SCREEN_FIELD_IN_REPEATER`. Dentro una riga si nomina il **cursore** (`itemReference`), che e' una
|
|
1555
|
+
* variabile vera — `PuntoCorrente.PodId`, mai `Luce_POD`.
|
|
1556
|
+
*
|
|
1557
|
+
* Cio' che invece **non** cambia: il nome resta unico, perche' e' l'indirizzo con cui il frontend rende
|
|
1558
|
+
* il campo, quindi un omonimo di una variabile e' `NAME_DUPLICATED` come sempre e `screenFieldNames` li
|
|
1559
|
+
* comprende tutti.
|
|
1560
|
+
*/
|
|
1561
|
+
function repeatedFieldNames(definition, typeOf) {
|
|
1562
|
+
const names = new Set();
|
|
1563
|
+
for (const screen of definition?.dynamicScreens ?? []) {
|
|
1564
|
+
walkInside(screen.fields, typeOf, false, (field, inside) => {
|
|
1565
|
+
if (inside && field.name) {
|
|
1566
|
+
names.add(field.name);
|
|
1567
|
+
}
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
return names;
|
|
1571
|
+
}
|
|
1572
|
+
/**
|
|
1573
|
+
* I campi di una schermata che sono **risorse del flow**: raccolgono un valore e non stanno dentro una
|
|
1574
|
+
* riga. Sono gli unici da proporre come riferimento, come innesco di una screen action e come
|
|
1575
|
+
* destinazione dei suoi output.
|
|
1576
|
+
*/
|
|
1577
|
+
function resourceFieldsOf(screen, typeOf) {
|
|
1578
|
+
const fields = [];
|
|
1579
|
+
walkInside(screen?.fields, typeOf, false, (field, inside) => {
|
|
1580
|
+
if (!inside && isFieldResource(field, typeOf(field))) {
|
|
1581
|
+
fields.push(field);
|
|
1582
|
+
}
|
|
1583
|
+
});
|
|
1584
|
+
return fields;
|
|
1585
|
+
}
|
|
1586
|
+
/**
|
|
1587
|
+
* La sezione ripetibile che **contiene** il campo a un percorso, se c'e'. Un antenato stretto: la
|
|
1588
|
+
* sezione stessa non sta dentro se stessa, ed e' la differenza fra «configuro la sezione» e «configuro
|
|
1589
|
+
* un campo di una riga», che sono due pannelli diversi.
|
|
1590
|
+
*/
|
|
1591
|
+
function repeatingSectionOf(screen, path, typeOf) {
|
|
1592
|
+
if (!screen || !path?.length) {
|
|
1593
|
+
return undefined;
|
|
1594
|
+
}
|
|
1595
|
+
for (let depth = 1; depth < path.length; depth++) {
|
|
1596
|
+
const ancestor = fieldAt(screen.fields, path.slice(0, depth));
|
|
1597
|
+
if (ancestor && typeOf(ancestor)?.isRepeatingSection === true) {
|
|
1598
|
+
return ancestor;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
return undefined;
|
|
1602
|
+
}
|
|
1603
|
+
/** Cammina l'albero portandosi dietro «sto dentro una riga»: le sezioni **non si annidano** (§5.2). */
|
|
1604
|
+
function walkInside(fields, typeOf, inside, visit) {
|
|
1605
|
+
for (const field of fields ?? []) {
|
|
1606
|
+
visit(field, inside);
|
|
1607
|
+
walkInside(field.fields, typeOf, inside || typeOf(field)?.isRepeatingSection === true, visit);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
// ---------------------------------------------------------------------------
|
|
1534
1611
|
// Mutazioni (lavorano sulla copia di lavoro dello store)
|
|
1535
1612
|
// ---------------------------------------------------------------------------
|
|
1536
1613
|
/** Inserisce un campo dentro `parentPath` alla posizione indicata (in fondo se assente). */
|
|
@@ -2444,6 +2521,12 @@ const FLOW_REFERENCE_FIELDS = new Set([
|
|
|
2444
2521
|
'defaultSelectedChoiceReference',
|
|
2445
2522
|
'screenActionName',
|
|
2446
2523
|
'triggerFieldName',
|
|
2524
|
+
// §5.2 — il **cursore** di una sezione ripetibile: e' una variabile del flow come le altre, ed e'
|
|
2525
|
+
// il nome che i campi della riga citano (`PuntoCorrente.PodId`). Fuori da qui, rinominare quella
|
|
2526
|
+
// variabile lascerebbe la sezione puntata a un nome che non esiste e ogni riferimento dentro la
|
|
2527
|
+
// riga rotto — senza che il conteggio degli usi lo avesse annunciato. La `collectionReference`
|
|
2528
|
+
// sta già nell'elenco, perche' la usano anche Loop e dynamic choice set.
|
|
2529
|
+
'itemReference',
|
|
2447
2530
|
]);
|
|
2448
2531
|
/**
|
|
2449
2532
|
* Riscrive ogni occorrenza di un nome nei campi che contengono riferimenti **e nei merge field**.
|
|
@@ -3825,6 +3908,15 @@ class FlowDictionaryStore {
|
|
|
3825
3908
|
screenFieldIsContainer(value) {
|
|
3826
3909
|
return this.screenFieldType(value)?.isContainer ?? false;
|
|
3827
3910
|
}
|
|
3911
|
+
/**
|
|
3912
|
+
* §5.2 — sezione **ripetibile**. Distinto da {@link screenFieldIsContainer} di proposito: contiene
|
|
3913
|
+
* campi, ma quelli che contiene sono il modello di una riga e i loro nomi **non** sono riferimenti
|
|
3914
|
+
* proponibili (`SCREEN_FIELD_IN_REPEATER`). E' il flag su cui si accende tutto cio' che l'editor fa di
|
|
3915
|
+
* diverso dentro una riga.
|
|
3916
|
+
*/
|
|
3917
|
+
screenFieldIsRepeatingSection(value) {
|
|
3918
|
+
return this.screenFieldType(value)?.isRepeatingSection ?? false;
|
|
3919
|
+
}
|
|
3828
3920
|
/** §5.2 — il campo si configura con `choiceReferences`. */
|
|
3829
3921
|
screenFieldAcceptsChoices(value) {
|
|
3830
3922
|
return this.screenFieldType(value)?.acceptsChoices ?? false;
|
|
@@ -6856,6 +6948,16 @@ class ReferencePickerComponent {
|
|
|
6856
6948
|
* verrebbe accusato di non esistere.
|
|
6857
6949
|
*/
|
|
6858
6950
|
extraReferences = input([], ...(ngDevMode ? [{ debugName: "extraReferences" }] : []));
|
|
6951
|
+
/**
|
|
6952
|
+
* Le radici da proporre **per prime**. Oggi c'e' un chiamante solo: dentro una riga di sezione
|
|
6953
|
+
* ripetibile la strada normale e' il **cursore** (`PuntoCorrente.PodId`), e i campi della riga —
|
|
6954
|
+
* che sono cio' che uno cerca istintivamente — non sono nemmeno riferimenti validi (§5.2).
|
|
6955
|
+
*
|
|
6956
|
+
* Non aggiunge e non toglie niente: riordina. L'elenco resta quello della primitiva, e un
|
|
6957
|
+
* riferimento preferito che non c'e' semplicemente non compare — proporre un nome che il backend
|
|
6958
|
+
* non conosce sarebbe peggio che non metterlo in cima.
|
|
6959
|
+
*/
|
|
6960
|
+
preferredRoots = input([], ...(ngDevMode ? [{ debugName: "preferredRoots" }] : []));
|
|
6859
6961
|
valueChange = output();
|
|
6860
6962
|
/**
|
|
6861
6963
|
* L'elenco come arriva dalla primitiva, **senza** il filtro di tipo.
|
|
@@ -7104,7 +7206,11 @@ class ReferencePickerComponent {
|
|
|
7104
7206
|
* fondo alla tendina i campi finivano sotto la piega — «ho cliccato la freccia e non mi da'
|
|
7105
7207
|
* l'elenco dei campi». L'ordine dei gruppi e' quello di prima apparizione, quindi basta questo.
|
|
7106
7208
|
*/
|
|
7107
|
-
const all =
|
|
7209
|
+
const all = this.preferFirst([
|
|
7210
|
+
...this.pathReferences(),
|
|
7211
|
+
...this.references(),
|
|
7212
|
+
...this.containerOptions(),
|
|
7213
|
+
]);
|
|
7108
7214
|
if (!needle) {
|
|
7109
7215
|
return all;
|
|
7110
7216
|
}
|
|
@@ -7112,6 +7218,22 @@ class ReferencePickerComponent {
|
|
|
7112
7218
|
.toLowerCase()
|
|
7113
7219
|
.includes(needle));
|
|
7114
7220
|
}, ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
7221
|
+
/**
|
|
7222
|
+
* Porta in testa le radici preferite, **senza** cambiare l'ordine relativo del resto. I gruppi si
|
|
7223
|
+
* costruiscono per ordine di prima apparizione, quindi bastano questi due passaggi perche' il
|
|
7224
|
+
* gruppo giusto risulti il primo della tendina.
|
|
7225
|
+
*/
|
|
7226
|
+
preferFirst(references) {
|
|
7227
|
+
const preferred = this.preferredRoots()
|
|
7228
|
+
.map((name) => name.trim().toLowerCase())
|
|
7229
|
+
.filter(Boolean);
|
|
7230
|
+
if (!preferred.length) {
|
|
7231
|
+
return references;
|
|
7232
|
+
}
|
|
7233
|
+
const wanted = (reference) => preferred.includes(reference.name.toLowerCase());
|
|
7234
|
+
const first = references.filter(wanted);
|
|
7235
|
+
return first.length ? [...first, ...references.filter((entry) => !wanted(entry))] : references;
|
|
7236
|
+
}
|
|
7115
7237
|
/** Le opzioni raggruppate per `kind`, così gli output automatici si distinguono. */
|
|
7116
7238
|
groups = computed(() => {
|
|
7117
7239
|
const groups = [];
|
|
@@ -7380,12 +7502,12 @@ class ReferencePickerComponent {
|
|
|
7380
7502
|
return parts.join(' · ');
|
|
7381
7503
|
}
|
|
7382
7504
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ReferencePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7383
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 }, extraReferences: { classPropertyName: "extraReferences", publicName: "extraReferences", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true, isSignal: true }], 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 <!-- Un membro inesistente o non scrivibile e' un **errore**: mostrarlo come avviso direbbe il falso. -->\r\n <p\r\n class=\"fb-ref__hint\"\r\n [class.fb-ref__hint--warn]=\"isHintWarning()\"\r\n [class.fb-ref__hint--error]=\"isHintError()\"\r\n >\r\n {{ hint() }}\r\n </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 #panel 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 <!-- Due bottoni dove il percorso continua: scegliere il riferimento e scendere di un\r\n livello sono cose diverse, e su una Structure o un record servono entrambe. -->\r\n <div class=\"fb-ref__row\">\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 [title]=\"isContainerOnly(item) ? 'Il tipo non e\u2019 quello del campo: entra e scegli dentro' : ''\"\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 @if (canDescend(item)) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__into\"\r\n [attr.aria-label]=\"'Entra in ' + item.name\"\r\n title=\"Entra e proponi i segmenti\"\r\n (click)=\"descend(item)\"\r\n >\r\n \u203A\r\n </button>\r\n }\r\n </div>\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__hint--error{color:var(--fb-error, #c9372c)}.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__row{display:flex;align-items:stretch;gap:2px}.fb-ref__into{flex:0 0 auto;padding:0 7px;border:0;border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:13px;cursor:pointer}.fb-ref__into:hover{background:var(--fb-surface-alt, #f8f9fb);color:var(--fb-accent, #2f6feb)}.fb-ref__option{display:flex;flex:1;flex-direction:column;min-width:0;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 });
|
|
7505
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 }, extraReferences: { classPropertyName: "extraReferences", publicName: "extraReferences", isSignal: true, isRequired: false, transformFunction: null }, preferredRoots: { classPropertyName: "preferredRoots", publicName: "preferredRoots", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true, isSignal: true }], 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 <!-- Un membro inesistente o non scrivibile e' un **errore**: mostrarlo come avviso direbbe il falso. -->\r\n <p\r\n class=\"fb-ref__hint\"\r\n [class.fb-ref__hint--warn]=\"isHintWarning()\"\r\n [class.fb-ref__hint--error]=\"isHintError()\"\r\n >\r\n {{ hint() }}\r\n </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 #panel 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 <!-- Due bottoni dove il percorso continua: scegliere il riferimento e scendere di un\r\n livello sono cose diverse, e su una Structure o un record servono entrambe. -->\r\n <div class=\"fb-ref__row\">\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 [title]=\"isContainerOnly(item) ? 'Il tipo non e\u2019 quello del campo: entra e scegli dentro' : ''\"\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 @if (canDescend(item)) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__into\"\r\n [attr.aria-label]=\"'Entra in ' + item.name\"\r\n title=\"Entra e proponi i segmenti\"\r\n (click)=\"descend(item)\"\r\n >\r\n \u203A\r\n </button>\r\n }\r\n </div>\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__hint--error{color:var(--fb-error, #c9372c)}.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__row{display:flex;align-items:stretch;gap:2px}.fb-ref__into{flex:0 0 auto;padding:0 7px;border:0;border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:13px;cursor:pointer}.fb-ref__into:hover{background:var(--fb-surface-alt, #f8f9fb);color:var(--fb-accent, #2f6feb)}.fb-ref__option{display:flex;flex:1;flex-direction:column;min-width:0;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 });
|
|
7384
7506
|
}
|
|
7385
7507
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ReferencePickerComponent, decorators: [{
|
|
7386
7508
|
type: Component,
|
|
7387
7509
|
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 <!-- Un membro inesistente o non scrivibile e' un **errore**: mostrarlo come avviso direbbe il falso. -->\r\n <p\r\n class=\"fb-ref__hint\"\r\n [class.fb-ref__hint--warn]=\"isHintWarning()\"\r\n [class.fb-ref__hint--error]=\"isHintError()\"\r\n >\r\n {{ hint() }}\r\n </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 #panel 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 <!-- Due bottoni dove il percorso continua: scegliere il riferimento e scendere di un\r\n livello sono cose diverse, e su una Structure o un record servono entrambe. -->\r\n <div class=\"fb-ref__row\">\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 [title]=\"isContainerOnly(item) ? 'Il tipo non e\u2019 quello del campo: entra e scegli dentro' : ''\"\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 @if (canDescend(item)) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__into\"\r\n [attr.aria-label]=\"'Entra in ' + item.name\"\r\n title=\"Entra e proponi i segmenti\"\r\n (click)=\"descend(item)\"\r\n >\r\n \u203A\r\n </button>\r\n }\r\n </div>\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__hint--error{color:var(--fb-error, #c9372c)}.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__row{display:flex;align-items:stretch;gap:2px}.fb-ref__into{flex:0 0 auto;padding:0 7px;border:0;border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:13px;cursor:pointer}.fb-ref__into:hover{background:var(--fb-surface-alt, #f8f9fb);color:var(--fb-accent, #2f6feb)}.fb-ref__option{display:flex;flex:1;flex-direction:column;min-width:0;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"] }]
|
|
7388
|
-
}], 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 }] }], extraReferences: [{ type: i0.Input, args: [{ isSignal: true, alias: "extraReferences", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }] } });
|
|
7510
|
+
}], 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 }] }], extraReferences: [{ type: i0.Input, args: [{ isSignal: true, alias: "extraReferences", required: false }] }], preferredRoots: [{ type: i0.Input, args: [{ isSignal: true, alias: "preferredRoots", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }] } });
|
|
7389
7511
|
|
|
7390
7512
|
/**
|
|
7391
7513
|
* Selettore di oggetto (entita') — FRONTEND.md §4.2.
|
|
@@ -8388,6 +8510,12 @@ class FormulaEditorComponent {
|
|
|
8388
8510
|
ariaLabel = input('Espressione', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
8389
8511
|
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
8390
8512
|
rows = input(3, ...(ngDevMode ? [{ debugName: "rows" }] : []));
|
|
8513
|
+
/**
|
|
8514
|
+
* I nomi da suggerire **per primi** (§5.2). Lo passa un chiamante solo: la regola di validazione
|
|
8515
|
+
* di un campo dentro una riga di sezione ripetibile, dove la strada normale e' il cursore. Non
|
|
8516
|
+
* aggiunge nomi all'elenco di `POST /flows/references`: riordina i suggerimenti.
|
|
8517
|
+
*/
|
|
8518
|
+
preferredRoots = input([], ...(ngDevMode ? [{ debugName: "preferredRoots" }] : []));
|
|
8391
8519
|
/**
|
|
8392
8520
|
* Quando propagare al documento. `input` a ogni tasto, `change` all'uscita dal campo: la
|
|
8393
8521
|
* seconda serve dove mutare il documento ridisegna mezza schermata — l'anteprima dello screen
|
|
@@ -8429,7 +8557,12 @@ class FormulaEditorComponent {
|
|
|
8429
8557
|
return [];
|
|
8430
8558
|
}
|
|
8431
8559
|
const needle = token.text.toLowerCase();
|
|
8432
|
-
const
|
|
8560
|
+
const preferred = this.preferredRoots().map((name) => name.trim().toLowerCase());
|
|
8561
|
+
const matches = this.references()
|
|
8562
|
+
.filter((reference) => reference.name.toLowerCase().startsWith(needle))
|
|
8563
|
+
// Stabile: cambia solo chi viene prima, non chi c'e'.
|
|
8564
|
+
.sort((left, right) => Number(preferred.includes(right.name.toLowerCase())) -
|
|
8565
|
+
Number(preferred.includes(left.name.toLowerCase())));
|
|
8433
8566
|
// Un solo suggerimento uguale a cio' che si e' già scritto non aiuta: e' solo un pannello che
|
|
8434
8567
|
// copre il testo.
|
|
8435
8568
|
if (matches.length === 1 && matches[0].name.toLowerCase() === needle) {
|
|
@@ -8750,12 +8883,12 @@ class FormulaEditorComponent {
|
|
|
8750
8883
|
}
|
|
8751
8884
|
}
|
|
8752
8885
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FormulaEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8753
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: FormulaEditorComponent, isStandalone: true, selector: "fb-formula-editor", inputs: { expression: { classPropertyName: "expression", publicName: "expression", isSignal: true, isRequired: false, transformFunction: null }, usage: { classPropertyName: "usage", publicName: "usage", isSignal: true, isRequired: false, transformFunction: null }, expectedDataType: { classPropertyName: "expectedDataType", publicName: "expectedDataType", isSignal: true, isRequired: false, transformFunction: null }, scale: { classPropertyName: "scale", publicName: "scale", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, commitOn: { classPropertyName: "commitOn", publicName: "commitOn", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expressionChange: "expressionChange" }, viewQueries: [{ propertyName: "area", first: true, predicate: ["area"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (hasPalette()) {\r\n <!--\r\n La palette compare **solo** se il motore dichiara delle funzioni (\u00A76.3): elenco vuoto\r\n significa \u00ABnon le dichiara\u00BB, e un pannello vuoto farebbe credere che non ce ne siano.\r\n -->\r\n <div class=\"fb-formula__bar\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__toggle\"\r\n [class.fb-formula__toggle--on]=\"isPaletteOpen()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isPaletteOpen()\"\r\n title=\"Funzioni disponibili nel motore\"\r\n (click)=\"togglePalette()\"\r\n >\r\n <em>f</em>(x) Funzioni\r\n </button>\r\n </div>\r\n}\r\n\r\n<textarea\r\n #area\r\n class=\"fb-textarea fb-input--mono\"\r\n [class.fb-input--invalid]=\"hasErrors()\"\r\n [value]=\"expression()\"\r\n [rows]=\"rows()\"\r\n [disabled]=\"disabled()\"\r\n [placeholder]=\"placeholder()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n (input)=\"onInput($any($event.target).value)\"\r\n (change)=\"onCommit($any($event.target).value)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (keyup)=\"onCaretMove()\"\r\n (click)=\"onCaretMove()\"\r\n></textarea>\r\n\r\n@if (suggestions().length) {\r\n <!--\r\n L'elenco dei riferimenti disponibili come autocompletamento (\u00A76.3): stessa fonte del\r\n reference picker, `POST /flows/references`, output automatici compresi. `mousedown` va\r\n fermato \u2014 il blur della casella arriverebbe prima del click e chiuderebbe l'elenco.\r\n -->\r\n <ul class=\"fb-formula__hints\" role=\"listbox\" aria-label=\"Riferimenti disponibili\">\r\n @for (reference of suggestions(); track reference.name) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__hint\"\r\n [class.fb-formula__hint--on]=\"$index === highlighted()\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"$index === highlighted()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insert(reference.name)\"\r\n >\r\n <code>{{ reference.name }}</code>\r\n @if (reference.dataType) {\r\n <span class=\"fb-formula__hint-type\">\r\n {{ reference.dataType }}{{ reference.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n}\r\n\r\n@if (hasPalette() && isPaletteOpen()) {\r\n <div class=\"fb-formula__palette\">\r\n <input\r\n type=\"search\"\r\n class=\"fb-input fb-formula__search\"\r\n placeholder=\"Cerca una funzione\u2026\"\r\n aria-label=\"Cerca una funzione\"\r\n [value]=\"paletteFilter()\"\r\n (input)=\"paletteFilter.set($any($event.target).value)\"\r\n />\r\n @if (paletteGroups().length) {\r\n @for (group of paletteGroups(); track $index) {\r\n <div class=\"fb-formula__group\">\r\n @if (group.category) {\r\n <h5 class=\"fb-formula__group-title\">{{ group.category }}</h5>\r\n }\r\n @for (entry of group.items; track entry.name) {\r\n <!--\r\n `mousedown` fermato come nei suggerimenti: il blur della casella arriverebbe prima\r\n del click. `signature` e `description` si mostrano e non si parsano \u2014 la grammatica\r\n resta del motore (\u00A76.3).\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__fn\"\r\n [disabled]=\"disabled()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insertFunction(entry)\"\r\n >\r\n <code class=\"fb-formula__fn-sig\">{{ signatureOf(entry) }}</code>\r\n @if (entry.resultDataType) {\r\n <span class=\"fb-formula__fn-type\">\r\n {{ entry.resultDataType }}{{ entry.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n @if (entry.description) {\r\n <span class=\"fb-formula__fn-desc\">{{ entry.description }}</span>\r\n }\r\n @if (entry.example) {\r\n <code class=\"fb-formula__fn-example\">{{ entry.example }}</code>\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <p class=\"fb-field__hint\">Nessuna funzione corrisponde alla ricerca.</p>\r\n }\r\n <!--\r\n L'elenco non e\u2019 autoritativo: un motore puo\u2019 supportare piu\u2019 di quanto dichiara, quindi una\r\n funzione che non c\u2019e\u2019 non e\u2019 un errore (\u00A76.3).\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Elenco dichiarato dal motore: puo\u2019 non essere completo. A verificare l\u2019espressione resta il\r\n motore stesso.\r\n </p>\r\n </div>\r\n}\r\n\r\n@if (isChecking()) {\r\n <p class=\"fb-field__hint\">Verifica in corso\u2026</p>\r\n} @else if (issues().length) {\r\n <ul class=\"fb-formula__issues\">\r\n @for (issue of issues(); track $index) {\r\n <li class=\"fb-formula__issue\" [class]=\"'fb-formula__issue--' + severityOf(issue)\">\r\n @if (hasPosition(issue)) {\r\n <!--\r\n Il salto e' il senso di `position`: un indice di carattere che l'utente dovrebbe\r\n contare a mano non porta da nessuna parte.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__jump\"\r\n [disabled]=\"disabled()\"\r\n title=\"Seleziona il tratto segnalato\"\r\n (click)=\"goToIssue(issue)\"\r\n >\r\n @if (excerptOf(issue)) {\r\n <code>{{ excerptOf(issue) }}</code>\r\n } @else {\r\n car. {{ issue.position! + 1 }}\r\n }\r\n </button>\r\n }\r\n <span class=\"fb-formula__message\">{{ issue.message }}</span>\r\n <!-- Codice del motore, non della \u00A77: si mostra e non si interpreta. -->\r\n <code class=\"fb-formula__code\">{{ issue.code }}</code>\r\n </li>\r\n }\r\n </ul>\r\n} @else if (isConfirmed()) {\r\n <p class=\"fb-formula__ok\">\u2713 Espressione verificata dal motore.</p>\r\n} @else if (isUnverified()) {\r\n <!--\r\n Primitiva s\u00EC, motore no: nessun rilievo **e** nessuna conferma. Dirlo e' l'unico modo di\r\n non far leggere il silenzio come un via libera (\u00A76.3).\r\n -->\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Nessun motore di validazione delle formule e\u2019 configurato: l\u2019espressione non e\u2019 stata\r\n controllata.\r\n </p>\r\n}\r\n\r\n@if (typeMismatch(); as mismatch) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n L\u2019espressione produce {{ mismatch.produced }}, ma qui serve {{ mismatch.expected }}.\r\n </p>\r\n}\r\n\r\n<ng-content />\r\n", styles: [":host{display:flex;flex-direction:column;gap:4px}.fb-formula__issues{display:flex;flex-direction:column;gap:3px;margin:0;padding:0;list-style:none}.fb-formula__issue{display:flex;flex-wrap:wrap;gap:5px;align-items:baseline;padding:3px 6px;border-left:3px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:10px;line-height:1.45}.fb-formula__issue--Error{border-left-color:var(--fb-error, #c9372c);color:var(--fb-error, #c9372c)}.fb-formula__issue--Warning{border-left-color:var(--fb-warning, #b7791f);color:var(--fb-warning, #b7791f)}.fb-formula__issue--Info{border-left-color:var(--fb-accent, #2f6feb);color:var(--fb-text-muted, #667085)}.fb-formula__message{flex:1 1 auto;min-width:0}.fb-formula__jump{padding:0 4px;border:1px solid currentcolor;border-radius:3px;background:transparent;color:inherit;font:inherit;font-size:10px;cursor:pointer}.fb-formula__jump:disabled{opacity:.5;cursor:not-allowed}.fb-formula__jump code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__code{color:var(--fb-text-subtle, #98a2b3);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px}.fb-formula__ok{margin:0;font-size:10px;color:var(--fb-success, #22a06b)}.fb-formula__hints{display:flex;flex-direction:column;gap:1px;max-height:160px;margin:0;padding:2px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface, #fff);list-style:none}.fb-formula__hint{display:flex;gap:6px;align-items:baseline;width:100%;padding:2px 5px;border:0;border-radius:3px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-formula__hint:hover,.fb-formula__hint--on{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-formula__hint code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__hint-type{margin-left:auto;color:var(--fb-text-subtle, #98a2b3)}.fb-formula__bar{display:flex;justify-content:flex-end}.fb-formula__toggle{padding:1px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface, #fff);color:var(--fb-text-muted, #667085);font:inherit;font-size:10px;cursor:pointer}.fb-formula__toggle em{font-family:ui-serif,Georgia,serif}.fb-formula__toggle--on{border-color:var(--fb-accent, #2f6feb);color:var(--fb-accent, #2f6feb)}.fb-formula__toggle:disabled{opacity:.5;cursor:not-allowed}.fb-formula__palette{display:flex;flex-direction:column;gap:4px;max-height:220px;padding:4px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface-alt, #f8f9fb)}.fb-formula__search{font-size:10px}.fb-formula__group{display:flex;flex-direction:column;gap:2px}.fb-formula__group-title{margin:2px 0 0;color:var(--fb-text-subtle, #98a2b3);font-size:9px;font-weight:600;text-transform:uppercase;letter-spacing:.04em}.fb-formula__fn{display:grid;grid-template-columns:1fr auto;gap:0 6px;padding:3px 5px;border:0;border-radius:3px;background:var(--fb-surface, #fff);color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-formula__fn:hover{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-formula__fn:disabled{opacity:.5;cursor:not-allowed}.fb-formula__fn-sig{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__fn-type{color:var(--fb-text-subtle, #98a2b3)}.fb-formula__fn-desc,.fb-formula__fn-example{grid-column:1 / -1;color:var(--fb-text-muted, #667085);font-size:9px;line-height:1.4}.fb-formula__fn-example{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--fb-text-subtle, #98a2b3)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8886
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: FormulaEditorComponent, isStandalone: true, selector: "fb-formula-editor", inputs: { expression: { classPropertyName: "expression", publicName: "expression", isSignal: true, isRequired: false, transformFunction: null }, usage: { classPropertyName: "usage", publicName: "usage", isSignal: true, isRequired: false, transformFunction: null }, expectedDataType: { classPropertyName: "expectedDataType", publicName: "expectedDataType", isSignal: true, isRequired: false, transformFunction: null }, scale: { classPropertyName: "scale", publicName: "scale", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, preferredRoots: { classPropertyName: "preferredRoots", publicName: "preferredRoots", isSignal: true, isRequired: false, transformFunction: null }, commitOn: { classPropertyName: "commitOn", publicName: "commitOn", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expressionChange: "expressionChange" }, viewQueries: [{ propertyName: "area", first: true, predicate: ["area"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (hasPalette()) {\r\n <!--\r\n La palette compare **solo** se il motore dichiara delle funzioni (\u00A76.3): elenco vuoto\r\n significa \u00ABnon le dichiara\u00BB, e un pannello vuoto farebbe credere che non ce ne siano.\r\n -->\r\n <div class=\"fb-formula__bar\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__toggle\"\r\n [class.fb-formula__toggle--on]=\"isPaletteOpen()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isPaletteOpen()\"\r\n title=\"Funzioni disponibili nel motore\"\r\n (click)=\"togglePalette()\"\r\n >\r\n <em>f</em>(x) Funzioni\r\n </button>\r\n </div>\r\n}\r\n\r\n<textarea\r\n #area\r\n class=\"fb-textarea fb-input--mono\"\r\n [class.fb-input--invalid]=\"hasErrors()\"\r\n [value]=\"expression()\"\r\n [rows]=\"rows()\"\r\n [disabled]=\"disabled()\"\r\n [placeholder]=\"placeholder()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n (input)=\"onInput($any($event.target).value)\"\r\n (change)=\"onCommit($any($event.target).value)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (keyup)=\"onCaretMove()\"\r\n (click)=\"onCaretMove()\"\r\n></textarea>\r\n\r\n@if (suggestions().length) {\r\n <!--\r\n L'elenco dei riferimenti disponibili come autocompletamento (\u00A76.3): stessa fonte del\r\n reference picker, `POST /flows/references`, output automatici compresi. `mousedown` va\r\n fermato \u2014 il blur della casella arriverebbe prima del click e chiuderebbe l'elenco.\r\n -->\r\n <ul class=\"fb-formula__hints\" role=\"listbox\" aria-label=\"Riferimenti disponibili\">\r\n @for (reference of suggestions(); track reference.name) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__hint\"\r\n [class.fb-formula__hint--on]=\"$index === highlighted()\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"$index === highlighted()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insert(reference.name)\"\r\n >\r\n <code>{{ reference.name }}</code>\r\n @if (reference.dataType) {\r\n <span class=\"fb-formula__hint-type\">\r\n {{ reference.dataType }}{{ reference.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n}\r\n\r\n@if (hasPalette() && isPaletteOpen()) {\r\n <div class=\"fb-formula__palette\">\r\n <input\r\n type=\"search\"\r\n class=\"fb-input fb-formula__search\"\r\n placeholder=\"Cerca una funzione\u2026\"\r\n aria-label=\"Cerca una funzione\"\r\n [value]=\"paletteFilter()\"\r\n (input)=\"paletteFilter.set($any($event.target).value)\"\r\n />\r\n @if (paletteGroups().length) {\r\n @for (group of paletteGroups(); track $index) {\r\n <div class=\"fb-formula__group\">\r\n @if (group.category) {\r\n <h5 class=\"fb-formula__group-title\">{{ group.category }}</h5>\r\n }\r\n @for (entry of group.items; track entry.name) {\r\n <!--\r\n `mousedown` fermato come nei suggerimenti: il blur della casella arriverebbe prima\r\n del click. `signature` e `description` si mostrano e non si parsano \u2014 la grammatica\r\n resta del motore (\u00A76.3).\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__fn\"\r\n [disabled]=\"disabled()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insertFunction(entry)\"\r\n >\r\n <code class=\"fb-formula__fn-sig\">{{ signatureOf(entry) }}</code>\r\n @if (entry.resultDataType) {\r\n <span class=\"fb-formula__fn-type\">\r\n {{ entry.resultDataType }}{{ entry.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n @if (entry.description) {\r\n <span class=\"fb-formula__fn-desc\">{{ entry.description }}</span>\r\n }\r\n @if (entry.example) {\r\n <code class=\"fb-formula__fn-example\">{{ entry.example }}</code>\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <p class=\"fb-field__hint\">Nessuna funzione corrisponde alla ricerca.</p>\r\n }\r\n <!--\r\n L'elenco non e\u2019 autoritativo: un motore puo\u2019 supportare piu\u2019 di quanto dichiara, quindi una\r\n funzione che non c\u2019e\u2019 non e\u2019 un errore (\u00A76.3).\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Elenco dichiarato dal motore: puo\u2019 non essere completo. A verificare l\u2019espressione resta il\r\n motore stesso.\r\n </p>\r\n </div>\r\n}\r\n\r\n@if (isChecking()) {\r\n <p class=\"fb-field__hint\">Verifica in corso\u2026</p>\r\n} @else if (issues().length) {\r\n <ul class=\"fb-formula__issues\">\r\n @for (issue of issues(); track $index) {\r\n <li class=\"fb-formula__issue\" [class]=\"'fb-formula__issue--' + severityOf(issue)\">\r\n @if (hasPosition(issue)) {\r\n <!--\r\n Il salto e' il senso di `position`: un indice di carattere che l'utente dovrebbe\r\n contare a mano non porta da nessuna parte.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__jump\"\r\n [disabled]=\"disabled()\"\r\n title=\"Seleziona il tratto segnalato\"\r\n (click)=\"goToIssue(issue)\"\r\n >\r\n @if (excerptOf(issue)) {\r\n <code>{{ excerptOf(issue) }}</code>\r\n } @else {\r\n car. {{ issue.position! + 1 }}\r\n }\r\n </button>\r\n }\r\n <span class=\"fb-formula__message\">{{ issue.message }}</span>\r\n <!-- Codice del motore, non della \u00A77: si mostra e non si interpreta. -->\r\n <code class=\"fb-formula__code\">{{ issue.code }}</code>\r\n </li>\r\n }\r\n </ul>\r\n} @else if (isConfirmed()) {\r\n <p class=\"fb-formula__ok\">\u2713 Espressione verificata dal motore.</p>\r\n} @else if (isUnverified()) {\r\n <!--\r\n Primitiva s\u00EC, motore no: nessun rilievo **e** nessuna conferma. Dirlo e' l'unico modo di\r\n non far leggere il silenzio come un via libera (\u00A76.3).\r\n -->\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Nessun motore di validazione delle formule e\u2019 configurato: l\u2019espressione non e\u2019 stata\r\n controllata.\r\n </p>\r\n}\r\n\r\n@if (typeMismatch(); as mismatch) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n L\u2019espressione produce {{ mismatch.produced }}, ma qui serve {{ mismatch.expected }}.\r\n </p>\r\n}\r\n\r\n<ng-content />\r\n", styles: [":host{display:flex;flex-direction:column;gap:4px}.fb-formula__issues{display:flex;flex-direction:column;gap:3px;margin:0;padding:0;list-style:none}.fb-formula__issue{display:flex;flex-wrap:wrap;gap:5px;align-items:baseline;padding:3px 6px;border-left:3px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:10px;line-height:1.45}.fb-formula__issue--Error{border-left-color:var(--fb-error, #c9372c);color:var(--fb-error, #c9372c)}.fb-formula__issue--Warning{border-left-color:var(--fb-warning, #b7791f);color:var(--fb-warning, #b7791f)}.fb-formula__issue--Info{border-left-color:var(--fb-accent, #2f6feb);color:var(--fb-text-muted, #667085)}.fb-formula__message{flex:1 1 auto;min-width:0}.fb-formula__jump{padding:0 4px;border:1px solid currentcolor;border-radius:3px;background:transparent;color:inherit;font:inherit;font-size:10px;cursor:pointer}.fb-formula__jump:disabled{opacity:.5;cursor:not-allowed}.fb-formula__jump code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__code{color:var(--fb-text-subtle, #98a2b3);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px}.fb-formula__ok{margin:0;font-size:10px;color:var(--fb-success, #22a06b)}.fb-formula__hints{display:flex;flex-direction:column;gap:1px;max-height:160px;margin:0;padding:2px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface, #fff);list-style:none}.fb-formula__hint{display:flex;gap:6px;align-items:baseline;width:100%;padding:2px 5px;border:0;border-radius:3px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-formula__hint:hover,.fb-formula__hint--on{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-formula__hint code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__hint-type{margin-left:auto;color:var(--fb-text-subtle, #98a2b3)}.fb-formula__bar{display:flex;justify-content:flex-end}.fb-formula__toggle{padding:1px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface, #fff);color:var(--fb-text-muted, #667085);font:inherit;font-size:10px;cursor:pointer}.fb-formula__toggle em{font-family:ui-serif,Georgia,serif}.fb-formula__toggle--on{border-color:var(--fb-accent, #2f6feb);color:var(--fb-accent, #2f6feb)}.fb-formula__toggle:disabled{opacity:.5;cursor:not-allowed}.fb-formula__palette{display:flex;flex-direction:column;gap:4px;max-height:220px;padding:4px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface-alt, #f8f9fb)}.fb-formula__search{font-size:10px}.fb-formula__group{display:flex;flex-direction:column;gap:2px}.fb-formula__group-title{margin:2px 0 0;color:var(--fb-text-subtle, #98a2b3);font-size:9px;font-weight:600;text-transform:uppercase;letter-spacing:.04em}.fb-formula__fn{display:grid;grid-template-columns:1fr auto;gap:0 6px;padding:3px 5px;border:0;border-radius:3px;background:var(--fb-surface, #fff);color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-formula__fn:hover{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-formula__fn:disabled{opacity:.5;cursor:not-allowed}.fb-formula__fn-sig{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__fn-type{color:var(--fb-text-subtle, #98a2b3)}.fb-formula__fn-desc,.fb-formula__fn-example{grid-column:1 / -1;color:var(--fb-text-muted, #667085);font-size:9px;line-height:1.4}.fb-formula__fn-example{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--fb-text-subtle, #98a2b3)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
8754
8887
|
}
|
|
8755
8888
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FormulaEditorComponent, decorators: [{
|
|
8756
8889
|
type: Component,
|
|
8757
8890
|
args: [{ selector: 'fb-formula-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (hasPalette()) {\r\n <!--\r\n La palette compare **solo** se il motore dichiara delle funzioni (\u00A76.3): elenco vuoto\r\n significa \u00ABnon le dichiara\u00BB, e un pannello vuoto farebbe credere che non ce ne siano.\r\n -->\r\n <div class=\"fb-formula__bar\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__toggle\"\r\n [class.fb-formula__toggle--on]=\"isPaletteOpen()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isPaletteOpen()\"\r\n title=\"Funzioni disponibili nel motore\"\r\n (click)=\"togglePalette()\"\r\n >\r\n <em>f</em>(x) Funzioni\r\n </button>\r\n </div>\r\n}\r\n\r\n<textarea\r\n #area\r\n class=\"fb-textarea fb-input--mono\"\r\n [class.fb-input--invalid]=\"hasErrors()\"\r\n [value]=\"expression()\"\r\n [rows]=\"rows()\"\r\n [disabled]=\"disabled()\"\r\n [placeholder]=\"placeholder()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n (input)=\"onInput($any($event.target).value)\"\r\n (change)=\"onCommit($any($event.target).value)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (keyup)=\"onCaretMove()\"\r\n (click)=\"onCaretMove()\"\r\n></textarea>\r\n\r\n@if (suggestions().length) {\r\n <!--\r\n L'elenco dei riferimenti disponibili come autocompletamento (\u00A76.3): stessa fonte del\r\n reference picker, `POST /flows/references`, output automatici compresi. `mousedown` va\r\n fermato \u2014 il blur della casella arriverebbe prima del click e chiuderebbe l'elenco.\r\n -->\r\n <ul class=\"fb-formula__hints\" role=\"listbox\" aria-label=\"Riferimenti disponibili\">\r\n @for (reference of suggestions(); track reference.name) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__hint\"\r\n [class.fb-formula__hint--on]=\"$index === highlighted()\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"$index === highlighted()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insert(reference.name)\"\r\n >\r\n <code>{{ reference.name }}</code>\r\n @if (reference.dataType) {\r\n <span class=\"fb-formula__hint-type\">\r\n {{ reference.dataType }}{{ reference.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n}\r\n\r\n@if (hasPalette() && isPaletteOpen()) {\r\n <div class=\"fb-formula__palette\">\r\n <input\r\n type=\"search\"\r\n class=\"fb-input fb-formula__search\"\r\n placeholder=\"Cerca una funzione\u2026\"\r\n aria-label=\"Cerca una funzione\"\r\n [value]=\"paletteFilter()\"\r\n (input)=\"paletteFilter.set($any($event.target).value)\"\r\n />\r\n @if (paletteGroups().length) {\r\n @for (group of paletteGroups(); track $index) {\r\n <div class=\"fb-formula__group\">\r\n @if (group.category) {\r\n <h5 class=\"fb-formula__group-title\">{{ group.category }}</h5>\r\n }\r\n @for (entry of group.items; track entry.name) {\r\n <!--\r\n `mousedown` fermato come nei suggerimenti: il blur della casella arriverebbe prima\r\n del click. `signature` e `description` si mostrano e non si parsano \u2014 la grammatica\r\n resta del motore (\u00A76.3).\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__fn\"\r\n [disabled]=\"disabled()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insertFunction(entry)\"\r\n >\r\n <code class=\"fb-formula__fn-sig\">{{ signatureOf(entry) }}</code>\r\n @if (entry.resultDataType) {\r\n <span class=\"fb-formula__fn-type\">\r\n {{ entry.resultDataType }}{{ entry.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n @if (entry.description) {\r\n <span class=\"fb-formula__fn-desc\">{{ entry.description }}</span>\r\n }\r\n @if (entry.example) {\r\n <code class=\"fb-formula__fn-example\">{{ entry.example }}</code>\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <p class=\"fb-field__hint\">Nessuna funzione corrisponde alla ricerca.</p>\r\n }\r\n <!--\r\n L'elenco non e\u2019 autoritativo: un motore puo\u2019 supportare piu\u2019 di quanto dichiara, quindi una\r\n funzione che non c\u2019e\u2019 non e\u2019 un errore (\u00A76.3).\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Elenco dichiarato dal motore: puo\u2019 non essere completo. A verificare l\u2019espressione resta il\r\n motore stesso.\r\n </p>\r\n </div>\r\n}\r\n\r\n@if (isChecking()) {\r\n <p class=\"fb-field__hint\">Verifica in corso\u2026</p>\r\n} @else if (issues().length) {\r\n <ul class=\"fb-formula__issues\">\r\n @for (issue of issues(); track $index) {\r\n <li class=\"fb-formula__issue\" [class]=\"'fb-formula__issue--' + severityOf(issue)\">\r\n @if (hasPosition(issue)) {\r\n <!--\r\n Il salto e' il senso di `position`: un indice di carattere che l'utente dovrebbe\r\n contare a mano non porta da nessuna parte.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-formula__jump\"\r\n [disabled]=\"disabled()\"\r\n title=\"Seleziona il tratto segnalato\"\r\n (click)=\"goToIssue(issue)\"\r\n >\r\n @if (excerptOf(issue)) {\r\n <code>{{ excerptOf(issue) }}</code>\r\n } @else {\r\n car. {{ issue.position! + 1 }}\r\n }\r\n </button>\r\n }\r\n <span class=\"fb-formula__message\">{{ issue.message }}</span>\r\n <!-- Codice del motore, non della \u00A77: si mostra e non si interpreta. -->\r\n <code class=\"fb-formula__code\">{{ issue.code }}</code>\r\n </li>\r\n }\r\n </ul>\r\n} @else if (isConfirmed()) {\r\n <p class=\"fb-formula__ok\">\u2713 Espressione verificata dal motore.</p>\r\n} @else if (isUnverified()) {\r\n <!--\r\n Primitiva s\u00EC, motore no: nessun rilievo **e** nessuna conferma. Dirlo e' l'unico modo di\r\n non far leggere il silenzio come un via libera (\u00A76.3).\r\n -->\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Nessun motore di validazione delle formule e\u2019 configurato: l\u2019espressione non e\u2019 stata\r\n controllata.\r\n </p>\r\n}\r\n\r\n@if (typeMismatch(); as mismatch) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n L\u2019espressione produce {{ mismatch.produced }}, ma qui serve {{ mismatch.expected }}.\r\n </p>\r\n}\r\n\r\n<ng-content />\r\n", styles: [":host{display:flex;flex-direction:column;gap:4px}.fb-formula__issues{display:flex;flex-direction:column;gap:3px;margin:0;padding:0;list-style:none}.fb-formula__issue{display:flex;flex-wrap:wrap;gap:5px;align-items:baseline;padding:3px 6px;border-left:3px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:10px;line-height:1.45}.fb-formula__issue--Error{border-left-color:var(--fb-error, #c9372c);color:var(--fb-error, #c9372c)}.fb-formula__issue--Warning{border-left-color:var(--fb-warning, #b7791f);color:var(--fb-warning, #b7791f)}.fb-formula__issue--Info{border-left-color:var(--fb-accent, #2f6feb);color:var(--fb-text-muted, #667085)}.fb-formula__message{flex:1 1 auto;min-width:0}.fb-formula__jump{padding:0 4px;border:1px solid currentcolor;border-radius:3px;background:transparent;color:inherit;font:inherit;font-size:10px;cursor:pointer}.fb-formula__jump:disabled{opacity:.5;cursor:not-allowed}.fb-formula__jump code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__code{color:var(--fb-text-subtle, #98a2b3);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px}.fb-formula__ok{margin:0;font-size:10px;color:var(--fb-success, #22a06b)}.fb-formula__hints{display:flex;flex-direction:column;gap:1px;max-height:160px;margin:0;padding:2px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface, #fff);list-style:none}.fb-formula__hint{display:flex;gap:6px;align-items:baseline;width:100%;padding:2px 5px;border:0;border-radius:3px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-formula__hint:hover,.fb-formula__hint--on{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-formula__hint code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__hint-type{margin-left:auto;color:var(--fb-text-subtle, #98a2b3)}.fb-formula__bar{display:flex;justify-content:flex-end}.fb-formula__toggle{padding:1px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface, #fff);color:var(--fb-text-muted, #667085);font:inherit;font-size:10px;cursor:pointer}.fb-formula__toggle em{font-family:ui-serif,Georgia,serif}.fb-formula__toggle--on{border-color:var(--fb-accent, #2f6feb);color:var(--fb-accent, #2f6feb)}.fb-formula__toggle:disabled{opacity:.5;cursor:not-allowed}.fb-formula__palette{display:flex;flex-direction:column;gap:4px;max-height:220px;padding:4px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface-alt, #f8f9fb)}.fb-formula__search{font-size:10px}.fb-formula__group{display:flex;flex-direction:column;gap:2px}.fb-formula__group-title{margin:2px 0 0;color:var(--fb-text-subtle, #98a2b3);font-size:9px;font-weight:600;text-transform:uppercase;letter-spacing:.04em}.fb-formula__fn{display:grid;grid-template-columns:1fr auto;gap:0 6px;padding:3px 5px;border:0;border-radius:3px;background:var(--fb-surface, #fff);color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-formula__fn:hover{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-formula__fn:disabled{opacity:.5;cursor:not-allowed}.fb-formula__fn-sig{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-formula__fn-type{color:var(--fb-text-subtle, #98a2b3)}.fb-formula__fn-desc,.fb-formula__fn-example{grid-column:1 / -1;color:var(--fb-text-muted, #667085);font-size:9px;line-height:1.4}.fb-formula__fn-example{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--fb-text-subtle, #98a2b3)}\n"] }]
|
|
8758
|
-
}], ctorParameters: () => [], propDecorators: { expression: [{ type: i0.Input, args: [{ isSignal: true, alias: "expression", required: false }] }], usage: [{ type: i0.Input, args: [{ isSignal: true, alias: "usage", required: false }] }], expectedDataType: [{ type: i0.Input, args: [{ isSignal: true, alias: "expectedDataType", required: false }] }], scale: [{ type: i0.Input, args: [{ isSignal: true, alias: "scale", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], commitOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "commitOn", required: false }] }], expressionChange: [{ type: i0.Output, args: ["expressionChange"] }], area: [{ type: i0.ViewChild, args: ['area', { isSignal: true }] }] } });
|
|
8891
|
+
}], ctorParameters: () => [], propDecorators: { expression: [{ type: i0.Input, args: [{ isSignal: true, alias: "expression", required: false }] }], usage: [{ type: i0.Input, args: [{ isSignal: true, alias: "usage", required: false }] }], expectedDataType: [{ type: i0.Input, args: [{ isSignal: true, alias: "expectedDataType", required: false }] }], scale: [{ type: i0.Input, args: [{ isSignal: true, alias: "scale", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], preferredRoots: [{ type: i0.Input, args: [{ isSignal: true, alias: "preferredRoots", required: false }] }], commitOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "commitOn", required: false }] }], expressionChange: [{ type: i0.Output, args: ["expressionChange"] }], area: [{ type: i0.ViewChild, args: ['area', { isSignal: true }] }] } });
|
|
8759
8892
|
|
|
8760
8893
|
/**
|
|
8761
8894
|
* `[fbValue]` su un `<select>`.
|
|
@@ -8831,6 +8964,12 @@ class ValueEditorComponent {
|
|
|
8831
8964
|
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
8832
8965
|
/** Nasconde la modalita' formula dove il modello non la prevede. */
|
|
8833
8966
|
allowFormula = input(true, ...(ngDevMode ? [{ debugName: "allowFormula" }] : []));
|
|
8967
|
+
/**
|
|
8968
|
+
* Le radici da proporre **per prime** nel reference picker (§5.2). Oggi lo passa un chiamante
|
|
8969
|
+
* solo: dentro una riga di sezione ripetibile la strada normale e' il **cursore**, e i campi
|
|
8970
|
+
* della riga non sono nemmeno riferimenti validi. Non aggiunge niente all'elenco: riordina.
|
|
8971
|
+
*/
|
|
8972
|
+
preferredRoots = input([], ...(ngDevMode ? [{ debugName: "preferredRoots" }] : []));
|
|
8834
8973
|
valueChange = output();
|
|
8835
8974
|
/** La modalita' dedotta dal campo effettivamente valorizzato. */
|
|
8836
8975
|
mode = computed(() => {
|
|
@@ -9122,7 +9261,7 @@ class ValueEditorComponent {
|
|
|
9122
9261
|
}
|
|
9123
9262
|
dataTypeOptions = computed(() => this.dictionaries.dataTypes(), ...(ngDevMode ? [{ debugName: "dataTypeOptions" }] : []));
|
|
9124
9263
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ValueEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9125
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 }, valueSet: { classPropertyName: "valueSet", publicName: "valueSet", 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 @if (isStructureTarget()) {\r\n <p class=\"fb-field__hint\">\r\n Un\u2019istanza di classe si passa per riferimento: non esiste un valore letterale con cui scriverla.\r\n </p>\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 <!--\r\n Tre stati, non due: **assente**, `false` e `true`. Una casella di spunta ne rappresenta\r\n due, e quella non spuntata finiva per dire \u00ABfalso\u00BB su un valore che nel documento non\r\n c'era \u2014 chi non la toccava leggeva una scelta che nessuno aveva fatto e che al backend non\r\n arrivava. `false` e' un valore e si scrive; \u00ABnon impostato\u00BB e' l'assenza del campo (\u00A72,\r\n \u00A74.2), ed e' l'unica cosa che una spunta non sa dire. Stesso controllo del form di\r\n \u00ABEsegui\u00BB, dove il problema era gi\u00E0 stato risolto cos\u00EC.\r\n -->\r\n <select\r\n class=\"fb-select\"\r\n [disabled]=\"disabled()\"\r\n [fbValue]=\"booleanText()\"\r\n (change)=\"onBooleanTextChange($any($event.target).value)\"\r\n >\r\n <option value=\"\">non impostato</option>\r\n <option value=\"true\">vero</option>\r\n <option value=\"false\">falso</option>\r\n </select>\r\n @if (!booleanText()) {\r\n <p class=\"fb-field__hint\">\r\n Nessun valore nel documento: \u00ABfalso\u00BB e\u2019 una scelta e va detta, perche\u2019 un campo assente\r\n non e\u2019 <code>false</code>.\r\n </p>\r\n }\r\n } @else if (dataType() === 'Enum') {\r\n <!--\r\n Un enum si scrive **per nome** su un insieme chiuso: i nomi ammessi sono quelli del tipo\r\n (\u00A74.2, \u00A74.6), e farli digitare e' il modo piu' facile di scriverne uno che il runtime non\r\n riconosce. Senza `objectType` \u2014 o senza la primitiva \u2014 il picker resta una casella di\r\n testo, che e' l'unica cosa onesta quando i valori non si sanno.\r\n -->\r\n <fb-enum-value-picker\r\n [value]=\"value()?.enumValue\"\r\n [enumType]=\"objectType()\"\r\n [label]=\"label()\"\r\n [disabled]=\"disabled()\"\r\n placeholder=\"Nome del valore di enum\"\r\n (valueChange)=\"onEnumChange($event)\"\r\n />\r\n } @else if (hasValueSet()) {\r\n <!--\r\n Campo a scelta chiusa (\u00A74.4): i valori ammessi sono della **colonna** e si chiedono con\r\n `listFieldValues`, non si deducono dal tipo. Farli digitare su un insieme di quattro e' il\r\n modo piu' facile di scrivere un valore che nessun record ha \u2014 e il filtro non troverebbe\r\n niente senza nessun errore da nessuna parte.\r\n -->\r\n <fb-field-value-picker\r\n [value]=\"literalText()\"\r\n [valueSet]=\"valueSet()\"\r\n [label]=\"label()\"\r\n [disabled]=\"disabled()\"\r\n (valueChange)=\"onClosedValueChange($event)\"\r\n />\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 (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 <!--\r\n Il tipo atteso e' quello **dichiarato sulla formula** (`formulaDataType`), non quello del\r\n campo: e' cio' che il documento porta, ed e' su quello che il motore va misurato (\u00A76.3).\r\n -->\r\n <fb-formula-editor\r\n [expression]=\"value()?.formulaExpression || ''\"\r\n usage=\"Value\"\r\n [expectedDataType]=\"$any(value()?.formulaDataType) || dataType()\"\r\n [disabled]=\"disabled()\"\r\n placeholder=\"Importo * 1.22\"\r\n [ariaLabel]=\"label() + ': espressione'\"\r\n (expressionChange)=\"onFormulaChange($event)\"\r\n />\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: la sintassi delle funzioni e\u2019 del motore.\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:6px}\n"], dependencies: [{ kind: "component", type: EnumValuePickerComponent, selector: "fb-enum-value-picker", inputs: ["value", "enumType", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: FieldValuePickerComponent, selector: "fb-field-value-picker", inputs: ["value", "valueSet", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: FormulaEditorComponent, selector: "fb-formula-editor", inputs: ["expression", "usage", "expectedDataType", "scale", "placeholder", "ariaLabel", "disabled", "rows", "commitOn"], outputs: ["expressionChange"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9264
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 }, valueSet: { classPropertyName: "valueSet", publicName: "valueSet", 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 }, preferredRoots: { classPropertyName: "preferredRoots", publicName: "preferredRoots", 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 [preferredRoots]=\"preferredRoots()\"\r\n [disabled]=\"disabled()\"\r\n (valueChange)=\"onReferenceChange($event)\"\r\n />\r\n @if (isStructureTarget()) {\r\n <p class=\"fb-field__hint\">\r\n Un\u2019istanza di classe si passa per riferimento: non esiste un valore letterale con cui scriverla.\r\n </p>\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 <!--\r\n Tre stati, non due: **assente**, `false` e `true`. Una casella di spunta ne rappresenta\r\n due, e quella non spuntata finiva per dire \u00ABfalso\u00BB su un valore che nel documento non\r\n c'era \u2014 chi non la toccava leggeva una scelta che nessuno aveva fatto e che al backend non\r\n arrivava. `false` e' un valore e si scrive; \u00ABnon impostato\u00BB e' l'assenza del campo (\u00A72,\r\n \u00A74.2), ed e' l'unica cosa che una spunta non sa dire. Stesso controllo del form di\r\n \u00ABEsegui\u00BB, dove il problema era gi\u00E0 stato risolto cos\u00EC.\r\n -->\r\n <select\r\n class=\"fb-select\"\r\n [disabled]=\"disabled()\"\r\n [fbValue]=\"booleanText()\"\r\n (change)=\"onBooleanTextChange($any($event.target).value)\"\r\n >\r\n <option value=\"\">non impostato</option>\r\n <option value=\"true\">vero</option>\r\n <option value=\"false\">falso</option>\r\n </select>\r\n @if (!booleanText()) {\r\n <p class=\"fb-field__hint\">\r\n Nessun valore nel documento: \u00ABfalso\u00BB e\u2019 una scelta e va detta, perche\u2019 un campo assente\r\n non e\u2019 <code>false</code>.\r\n </p>\r\n }\r\n } @else if (dataType() === 'Enum') {\r\n <!--\r\n Un enum si scrive **per nome** su un insieme chiuso: i nomi ammessi sono quelli del tipo\r\n (\u00A74.2, \u00A74.6), e farli digitare e' il modo piu' facile di scriverne uno che il runtime non\r\n riconosce. Senza `objectType` \u2014 o senza la primitiva \u2014 il picker resta una casella di\r\n testo, che e' l'unica cosa onesta quando i valori non si sanno.\r\n -->\r\n <fb-enum-value-picker\r\n [value]=\"value()?.enumValue\"\r\n [enumType]=\"objectType()\"\r\n [label]=\"label()\"\r\n [disabled]=\"disabled()\"\r\n placeholder=\"Nome del valore di enum\"\r\n (valueChange)=\"onEnumChange($event)\"\r\n />\r\n } @else if (hasValueSet()) {\r\n <!--\r\n Campo a scelta chiusa (\u00A74.4): i valori ammessi sono della **colonna** e si chiedono con\r\n `listFieldValues`, non si deducono dal tipo. Farli digitare su un insieme di quattro e' il\r\n modo piu' facile di scrivere un valore che nessun record ha \u2014 e il filtro non troverebbe\r\n niente senza nessun errore da nessuna parte.\r\n -->\r\n <fb-field-value-picker\r\n [value]=\"literalText()\"\r\n [valueSet]=\"valueSet()\"\r\n [label]=\"label()\"\r\n [disabled]=\"disabled()\"\r\n (valueChange)=\"onClosedValueChange($event)\"\r\n />\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 (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 <!--\r\n Il tipo atteso e' quello **dichiarato sulla formula** (`formulaDataType`), non quello del\r\n campo: e' cio' che il documento porta, ed e' su quello che il motore va misurato (\u00A76.3).\r\n -->\r\n <fb-formula-editor\r\n [expression]=\"value()?.formulaExpression || ''\"\r\n usage=\"Value\"\r\n [expectedDataType]=\"$any(value()?.formulaDataType) || dataType()\"\r\n [disabled]=\"disabled()\"\r\n placeholder=\"Importo * 1.22\"\r\n [ariaLabel]=\"label() + ': espressione'\"\r\n (expressionChange)=\"onFormulaChange($event)\"\r\n />\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: la sintassi delle funzioni e\u2019 del motore.\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:6px}\n"], dependencies: [{ kind: "component", type: EnumValuePickerComponent, selector: "fb-enum-value-picker", inputs: ["value", "enumType", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: FieldValuePickerComponent, selector: "fb-field-value-picker", inputs: ["value", "valueSet", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: FormulaEditorComponent, selector: "fb-formula-editor", inputs: ["expression", "usage", "expectedDataType", "scale", "placeholder", "ariaLabel", "disabled", "rows", "preferredRoots", "commitOn"], outputs: ["expressionChange"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences", "preferredRoots"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9126
9265
|
}
|
|
9127
9266
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ValueEditorComponent, decorators: [{
|
|
9128
9267
|
type: Component,
|
|
@@ -9132,8 +9271,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
9132
9271
|
FormulaEditorComponent,
|
|
9133
9272
|
ReferencePickerComponent,
|
|
9134
9273
|
SelectValueDirective,
|
|
9135
|
-
], 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 @if (isStructureTarget()) {\r\n <p class=\"fb-field__hint\">\r\n Un\u2019istanza di classe si passa per riferimento: non esiste un valore letterale con cui scriverla.\r\n </p>\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 <!--\r\n Tre stati, non due: **assente**, `false` e `true`. Una casella di spunta ne rappresenta\r\n due, e quella non spuntata finiva per dire \u00ABfalso\u00BB su un valore che nel documento non\r\n c'era \u2014 chi non la toccava leggeva una scelta che nessuno aveva fatto e che al backend non\r\n arrivava. `false` e' un valore e si scrive; \u00ABnon impostato\u00BB e' l'assenza del campo (\u00A72,\r\n \u00A74.2), ed e' l'unica cosa che una spunta non sa dire. Stesso controllo del form di\r\n \u00ABEsegui\u00BB, dove il problema era gi\u00E0 stato risolto cos\u00EC.\r\n -->\r\n <select\r\n class=\"fb-select\"\r\n [disabled]=\"disabled()\"\r\n [fbValue]=\"booleanText()\"\r\n (change)=\"onBooleanTextChange($any($event.target).value)\"\r\n >\r\n <option value=\"\">non impostato</option>\r\n <option value=\"true\">vero</option>\r\n <option value=\"false\">falso</option>\r\n </select>\r\n @if (!booleanText()) {\r\n <p class=\"fb-field__hint\">\r\n Nessun valore nel documento: \u00ABfalso\u00BB e\u2019 una scelta e va detta, perche\u2019 un campo assente\r\n non e\u2019 <code>false</code>.\r\n </p>\r\n }\r\n } @else if (dataType() === 'Enum') {\r\n <!--\r\n Un enum si scrive **per nome** su un insieme chiuso: i nomi ammessi sono quelli del tipo\r\n (\u00A74.2, \u00A74.6), e farli digitare e' il modo piu' facile di scriverne uno che il runtime non\r\n riconosce. Senza `objectType` \u2014 o senza la primitiva \u2014 il picker resta una casella di\r\n testo, che e' l'unica cosa onesta quando i valori non si sanno.\r\n -->\r\n <fb-enum-value-picker\r\n [value]=\"value()?.enumValue\"\r\n [enumType]=\"objectType()\"\r\n [label]=\"label()\"\r\n [disabled]=\"disabled()\"\r\n placeholder=\"Nome del valore di enum\"\r\n (valueChange)=\"onEnumChange($event)\"\r\n />\r\n } @else if (hasValueSet()) {\r\n <!--\r\n Campo a scelta chiusa (\u00A74.4): i valori ammessi sono della **colonna** e si chiedono con\r\n `listFieldValues`, non si deducono dal tipo. Farli digitare su un insieme di quattro e' il\r\n modo piu' facile di scrivere un valore che nessun record ha \u2014 e il filtro non troverebbe\r\n niente senza nessun errore da nessuna parte.\r\n -->\r\n <fb-field-value-picker\r\n [value]=\"literalText()\"\r\n [valueSet]=\"valueSet()\"\r\n [label]=\"label()\"\r\n [disabled]=\"disabled()\"\r\n (valueChange)=\"onClosedValueChange($event)\"\r\n />\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 (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 <!--\r\n Il tipo atteso e' quello **dichiarato sulla formula** (`formulaDataType`), non quello del\r\n campo: e' cio' che il documento porta, ed e' su quello che il motore va misurato (\u00A76.3).\r\n -->\r\n <fb-formula-editor\r\n [expression]=\"value()?.formulaExpression || ''\"\r\n usage=\"Value\"\r\n [expectedDataType]=\"$any(value()?.formulaDataType) || dataType()\"\r\n [disabled]=\"disabled()\"\r\n placeholder=\"Importo * 1.22\"\r\n [ariaLabel]=\"label() + ': espressione'\"\r\n (expressionChange)=\"onFormulaChange($event)\"\r\n />\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: la sintassi delle funzioni e\u2019 del motore.\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:6px}\n"] }]
|
|
9136
|
-
}], 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 }] }], valueSet: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueSet", 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"] }] } });
|
|
9274
|
+
], 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 [preferredRoots]=\"preferredRoots()\"\r\n [disabled]=\"disabled()\"\r\n (valueChange)=\"onReferenceChange($event)\"\r\n />\r\n @if (isStructureTarget()) {\r\n <p class=\"fb-field__hint\">\r\n Un\u2019istanza di classe si passa per riferimento: non esiste un valore letterale con cui scriverla.\r\n </p>\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 <!--\r\n Tre stati, non due: **assente**, `false` e `true`. Una casella di spunta ne rappresenta\r\n due, e quella non spuntata finiva per dire \u00ABfalso\u00BB su un valore che nel documento non\r\n c'era \u2014 chi non la toccava leggeva una scelta che nessuno aveva fatto e che al backend non\r\n arrivava. `false` e' un valore e si scrive; \u00ABnon impostato\u00BB e' l'assenza del campo (\u00A72,\r\n \u00A74.2), ed e' l'unica cosa che una spunta non sa dire. Stesso controllo del form di\r\n \u00ABEsegui\u00BB, dove il problema era gi\u00E0 stato risolto cos\u00EC.\r\n -->\r\n <select\r\n class=\"fb-select\"\r\n [disabled]=\"disabled()\"\r\n [fbValue]=\"booleanText()\"\r\n (change)=\"onBooleanTextChange($any($event.target).value)\"\r\n >\r\n <option value=\"\">non impostato</option>\r\n <option value=\"true\">vero</option>\r\n <option value=\"false\">falso</option>\r\n </select>\r\n @if (!booleanText()) {\r\n <p class=\"fb-field__hint\">\r\n Nessun valore nel documento: \u00ABfalso\u00BB e\u2019 una scelta e va detta, perche\u2019 un campo assente\r\n non e\u2019 <code>false</code>.\r\n </p>\r\n }\r\n } @else if (dataType() === 'Enum') {\r\n <!--\r\n Un enum si scrive **per nome** su un insieme chiuso: i nomi ammessi sono quelli del tipo\r\n (\u00A74.2, \u00A74.6), e farli digitare e' il modo piu' facile di scriverne uno che il runtime non\r\n riconosce. Senza `objectType` \u2014 o senza la primitiva \u2014 il picker resta una casella di\r\n testo, che e' l'unica cosa onesta quando i valori non si sanno.\r\n -->\r\n <fb-enum-value-picker\r\n [value]=\"value()?.enumValue\"\r\n [enumType]=\"objectType()\"\r\n [label]=\"label()\"\r\n [disabled]=\"disabled()\"\r\n placeholder=\"Nome del valore di enum\"\r\n (valueChange)=\"onEnumChange($event)\"\r\n />\r\n } @else if (hasValueSet()) {\r\n <!--\r\n Campo a scelta chiusa (\u00A74.4): i valori ammessi sono della **colonna** e si chiedono con\r\n `listFieldValues`, non si deducono dal tipo. Farli digitare su un insieme di quattro e' il\r\n modo piu' facile di scrivere un valore che nessun record ha \u2014 e il filtro non troverebbe\r\n niente senza nessun errore da nessuna parte.\r\n -->\r\n <fb-field-value-picker\r\n [value]=\"literalText()\"\r\n [valueSet]=\"valueSet()\"\r\n [label]=\"label()\"\r\n [disabled]=\"disabled()\"\r\n (valueChange)=\"onClosedValueChange($event)\"\r\n />\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 (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 <!--\r\n Il tipo atteso e' quello **dichiarato sulla formula** (`formulaDataType`), non quello del\r\n campo: e' cio' che il documento porta, ed e' su quello che il motore va misurato (\u00A76.3).\r\n -->\r\n <fb-formula-editor\r\n [expression]=\"value()?.formulaExpression || ''\"\r\n usage=\"Value\"\r\n [expectedDataType]=\"$any(value()?.formulaDataType) || dataType()\"\r\n [disabled]=\"disabled()\"\r\n placeholder=\"Importo * 1.22\"\r\n [ariaLabel]=\"label() + ': espressione'\"\r\n (expressionChange)=\"onFormulaChange($event)\"\r\n />\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: la sintassi delle funzioni e\u2019 del motore.\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:6px}\n"] }]
|
|
9275
|
+
}], 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 }] }], valueSet: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueSet", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], allowFormula: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowFormula", required: false }] }], preferredRoots: [{ type: i0.Input, args: [{ isSignal: true, alias: "preferredRoots", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
|
|
9137
9276
|
|
|
9138
9277
|
/**
|
|
9139
9278
|
* Editor delle condizioni — FRONTEND.md §4.3 e trappole §13.1, §13.4, §13.13, §13.14.
|
|
@@ -9172,6 +9311,12 @@ class ConditionEditorComponent {
|
|
|
9172
9311
|
title = input('Condizioni', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
9173
9312
|
/** `false` dove il modello non prevede la modalita' formula sull'elemento. */
|
|
9174
9313
|
allowFormula = input(true, ...(ngDevMode ? [{ debugName: "allowFormula" }] : []));
|
|
9314
|
+
/**
|
|
9315
|
+
* Le radici da proporre **per prime** nel reference picker (§5.2). Oggi lo passa un chiamante
|
|
9316
|
+
* solo: dentro una riga di sezione ripetibile la strada normale e' il **cursore**, e i campi
|
|
9317
|
+
* della riga non sono nemmeno riferimenti validi. Non aggiunge niente all'elenco: riordina.
|
|
9318
|
+
*/
|
|
9319
|
+
preferredRoots = input([], ...(ngDevMode ? [{ debugName: "preferredRoots" }] : []));
|
|
9175
9320
|
/**
|
|
9176
9321
|
* `false` dove il modello porta **solo** la lista di condizioni, senza un campo per la
|
|
9177
9322
|
* logica: gli `entryConditions` / `exitConditions` di uno step di orchestrazione (§5.14).
|
|
@@ -9457,12 +9602,12 @@ class ConditionEditorComponent {
|
|
|
9457
9602
|
});
|
|
9458
9603
|
}
|
|
9459
9604
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ConditionEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9460
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 <!-- Una condizione deve produrre un booleano: mandarlo e' cio' che fa dire al motore\r\n \u00ABqui serve un booleano\u00BB invece di accettare un'espressione che fallira' (\u00A76.3). -->\r\n <fb-formula-editor\r\n [expression]=\"holder().formula || ''\"\r\n usage=\"Condition\"\r\n expectedDataType=\"Boolean\"\r\n placeholder=\"AND(Esito = 'KO', Importo > 1000)\"\r\n ariaLabel=\"Formula della condizione\"\r\n (expressionChange)=\"setFormula($event)\"\r\n >\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 </fb-formula-editor>\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 <!-- I tre termini del confronto sono una frase sola: si leggono in riga. -->\r\n <div class=\"fb-fields-row\">\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 fb-field--compact\">\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 [objectType]=\"leftObjectType(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 </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{margin-top:3px}.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: FormulaEditorComponent, selector: "fb-formula-editor", inputs: ["expression", "usage", "expectedDataType", "scale", "placeholder", "ariaLabel", "disabled", "rows", "commitOn"], outputs: ["expressionChange"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9605
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 }, preferredRoots: { classPropertyName: "preferredRoots", publicName: "preferredRoots", 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 <!-- Una condizione deve produrre un booleano: mandarlo e' cio' che fa dire al motore\r\n \u00ABqui serve un booleano\u00BB invece di accettare un'espressione che fallira' (\u00A76.3). -->\r\n <fb-formula-editor\r\n [expression]=\"holder().formula || ''\"\r\n usage=\"Condition\"\r\n expectedDataType=\"Boolean\"\r\n placeholder=\"AND(Esito = 'KO', Importo > 1000)\"\r\n ariaLabel=\"Formula della condizione\"\r\n (expressionChange)=\"setFormula($event)\"\r\n >\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 </fb-formula-editor>\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 <!-- I tre termini del confronto sono una frase sola: si leggono in riga. -->\r\n <div class=\"fb-fields-row\">\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 [preferredRoots]=\"preferredRoots()\"\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 fb-field--compact\">\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 [objectType]=\"leftObjectType(condition)\"\r\n [preferredRoots]=\"preferredRoots()\"\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 </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{margin-top:3px}.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: FormulaEditorComponent, selector: "fb-formula-editor", inputs: ["expression", "usage", "expectedDataType", "scale", "placeholder", "ariaLabel", "disabled", "rows", "preferredRoots", "commitOn"], outputs: ["expressionChange"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences", "preferredRoots"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula", "preferredRoots"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9461
9606
|
}
|
|
9462
9607
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ConditionEditorComponent, decorators: [{
|
|
9463
9608
|
type: Component,
|
|
9464
|
-
args: [{ selector: 'fb-condition-editor', standalone: true, imports: [FormulaEditorComponent, 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 <!-- Una condizione deve produrre un booleano: mandarlo e' cio' che fa dire al motore\r\n \u00ABqui serve un booleano\u00BB invece di accettare un'espressione che fallira' (\u00A76.3). -->\r\n <fb-formula-editor\r\n [expression]=\"holder().formula || ''\"\r\n usage=\"Condition\"\r\n expectedDataType=\"Boolean\"\r\n placeholder=\"AND(Esito = 'KO', Importo > 1000)\"\r\n ariaLabel=\"Formula della condizione\"\r\n (expressionChange)=\"setFormula($event)\"\r\n >\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 </fb-formula-editor>\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 <!-- I tre termini del confronto sono una frase sola: si leggono in riga. -->\r\n <div class=\"fb-fields-row\">\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 fb-field--compact\">\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 [objectType]=\"leftObjectType(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 </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{margin-top:3px}.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"] }]
|
|
9465
|
-
}], 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"] }] } });
|
|
9609
|
+
args: [{ selector: 'fb-condition-editor', standalone: true, imports: [FormulaEditorComponent, 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 <!-- Una condizione deve produrre un booleano: mandarlo e' cio' che fa dire al motore\r\n \u00ABqui serve un booleano\u00BB invece di accettare un'espressione che fallira' (\u00A76.3). -->\r\n <fb-formula-editor\r\n [expression]=\"holder().formula || ''\"\r\n usage=\"Condition\"\r\n expectedDataType=\"Boolean\"\r\n placeholder=\"AND(Esito = 'KO', Importo > 1000)\"\r\n ariaLabel=\"Formula della condizione\"\r\n (expressionChange)=\"setFormula($event)\"\r\n >\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 </fb-formula-editor>\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 <!-- I tre termini del confronto sono una frase sola: si leggono in riga. -->\r\n <div class=\"fb-fields-row\">\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 [preferredRoots]=\"preferredRoots()\"\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 fb-field--compact\">\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 [objectType]=\"leftObjectType(condition)\"\r\n [preferredRoots]=\"preferredRoots()\"\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 </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{margin-top:3px}.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"] }]
|
|
9610
|
+
}], 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 }] }], preferredRoots: [{ type: i0.Input, args: [{ isSignal: true, alias: "preferredRoots", 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"] }] } });
|
|
9466
9611
|
|
|
9467
9612
|
/**
|
|
9468
9613
|
* Editor dei filtri sui record — FRONTEND.md §4.4.
|
|
@@ -9769,7 +9914,7 @@ class RecordFilterEditorComponent {
|
|
|
9769
9914
|
return this.types.valueSetOf(filter.field);
|
|
9770
9915
|
}
|
|
9771
9916
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: RecordFilterEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9772
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: RecordFilterEditorComponent, isStandalone: true, selector: "fb-record-filter-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 }, usage: { classPropertyName: "usage", publicName: "usage", isSignal: true, isRequired: false, transformFunction: null }, fieldOptions: { classPropertyName: "fieldOptions", publicName: "fieldOptions", isSignal: true, isRequired: false, transformFunction: null }, supportsLogic: { classPropertyName: "supportsLogic", publicName: "supportsLogic", isSignal: true, isRequired: false, transformFunction: null }, supportsFormula: { classPropertyName: "supportsFormula", publicName: "supportsFormula", isSignal: true, isRequired: false, transformFunction: null }, emptyWarning: { classPropertyName: "emptyWarning", publicName: "emptyWarning", isSignal: true, isRequired: false, transformFunction: null }, emptyWarningSeverity: { classPropertyName: "emptyWarningSeverity", publicName: "emptyWarningSeverity", 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 (!object() && !fieldOptions().length) {\r\n <p class=\"fb-field__hint\">Scegli prima un oggetto per poter filtrare sui suoi campi.</p>\r\n }\r\n\r\n @if (supportsLogic()) {\r\n <div class=\"fb-filter__modes\" role=\"group\" aria-label=\"Logica dei filtri\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"logicMode() === 'and'\"\r\n (click)=\"setLogicMode('and')\"\r\n >\r\n Tutti (AND)\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"logicMode() === 'or'\"\r\n (click)=\"setLogicMode('or')\"\r\n >\r\n Almeno uno (OR)\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"logicMode() === 'custom'\"\r\n (click)=\"setLogicMode('custom')\"\r\n >\r\n Espressione\r\n </button>\r\n @if (supportsFormula()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"logicMode() === 'formula'\"\r\n (click)=\"setLogicMode('formula')\"\r\n >\r\n Formula\r\n </button>\r\n }\r\n </div>\r\n } @else {\r\n <!-- Qui il modello non ha `filterLogic`: mostrarlo lo farebbe perdere al salvataggio. -->\r\n <p class=\"fb-field__hint\">Su questo elemento i filtri sono sempre combinati in AND.</p>\r\n }\r\n\r\n @if (supportsLogic() && 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 dei filtri\"\r\n (input)=\"setCustomLogic($any($event.target).value)\"\r\n />\r\n <!--\r\n Gli indici sono quelli numerati nell\u2019elenco qui sotto, e sono 1-based. Un indice\r\n inesistente e\u2019 `CONDITION_LOGIC_INVALID`, che e\u2019 un **errore**: blocca l\u2019attivazione,\r\n quindi conviene dirlo mentre si scrive e non alla validazione.\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 ai filtri numerati sotto. Cancellare un filtro\r\n riscrive l\u2019espressione automaticamente.\r\n </p>\r\n }\r\n </div>\r\n }\r\n\r\n <!--\r\n `filterLogic: \"Formula\"` non e\u2019 supportato da nessun elemento (\u00A74.4): non lo scrive nessun\r\n gesto di questo editor, ma un flow scritto altrove puo\u2019 portarcelo. Si dice invece di\r\n correggerlo di soppiatto \u2014 e\u2019 l\u2019unico indizio di cosa quel flow voleva fare.\r\n -->\r\n @if (unsupportedFormulaLogic()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n <code>filterLogic: \"Formula\"</code> non e\u2019 un valore supportato: sui choice set e\u2019 un errore\r\n di validazione, altrove fa fallire l\u2019esecuzione. I filtri qui sotto si combinano in AND.\r\n @if (supportsFormula()) {\r\n Per una formula usa la modalita\u2019 \u00ABFormula\u00BB, che scrive <code>filterFormula</code>.\r\n }\r\n </p>\r\n }\r\n\r\n @if (supportsFormula() && logicMode() === 'formula') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Formula di filtro</label>\r\n <fb-formula-editor\r\n [expression]=\"holder().filterFormula || ''\"\r\n usage=\"Condition\"\r\n expectedDataType=\"Boolean\"\r\n ariaLabel=\"Formula di filtro\"\r\n (expressionChange)=\"setFormula($event)\"\r\n >\r\n <p class=\"fb-field__hint\">\r\n Valutata dal motore di regole, <strong>in alternativa</strong> ai filtri: sta nel campo\r\n <code>filterFormula</code>, e la logica dei filtri non si applica.\r\n </p>\r\n </fb-formula-editor>\r\n </div>\r\n }\r\n\r\n @if (identifierNotFilterable()) {\r\n <p class=\"fb-field__hint\">\r\n Su questo oggetto l\u2019identificativo non e\u2019 filtrabile: la chiave e\u2019 composta e porta la propria\r\n forma canonica. Filtra per le colonne della chiave, una per colonna.\r\n </p>\r\n }\r\n\r\n @if (showEmptyWarning()) {\r\n <p\r\n class=\"fb-callout\"\r\n [class.fb-callout--warn]=\"emptyWarningSeverity() === 'warn'\"\r\n [class.fb-callout--error]=\"emptyWarningSeverity() === 'error'\"\r\n >\r\n {{ emptyWarning() }}\r\n </p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (filter of filters(); 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 filtro\"\r\n (click)=\"removeFilter($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <!-- Campo, operatore e valore sono una frase sola: si leggono in riga. -->\r\n <div class=\"fb-fields-row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo</label>\r\n @if (fieldOptions().length) {\r\n <!-- Insieme chiuso: qui non c'e' un catalogo incompleto da compensare. -->\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"filter.field || ''\"\r\n aria-label=\"Campo del filtro\"\r\n (change)=\"setField($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (option of fieldOptions(); track option.value) {\r\n <option [value]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n @if (unknownFixedField(filter)) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ filter.field }}\u00BB non e\u2019 fra i campi citabili qui (FIELD_UNKNOWN).\r\n </p>\r\n }\r\n } @else {\r\n <fb-field-picker\r\n [value]=\"filter.field\"\r\n [object]=\"object()\"\r\n [usage]=\"usage()\"\r\n placeholder=\"Scrivi o scegli un campo\"\r\n (valueChange)=\"setField($index, $event ?? '')\"\r\n />\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field fb-field--compact\">\r\n <label class=\"fb-field__label\">Operatore</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"filter.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 </div>\r\n\r\n @if (isNullOperator(filter)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Esito atteso</label>\r\n <div class=\"fb-filter__modes\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"nullExpectation(filter)\"\r\n (click)=\"setNullExpectation($index, true)\"\r\n >\r\n \u00E8 vuoto\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"!nullExpectation(filter)\"\r\n (click)=\"setNullExpectation($index, false)\"\r\n >\r\n non \u00E8 vuoto\r\n </button>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\r\n <fb-value-editor\r\n [value]=\"filter.value\"\r\n [dataType]=\"fieldDataType(filter)\"\r\n [objectType]=\"fieldObjectType(filter)\"\r\n [valueSet]=\"fieldValueSet(filter)\"\r\n label=\"Valore del filtro\"\r\n [allowFormula]=\"false\"\r\n (valueChange)=\"setValue($index, $event)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun filtro.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addFilter()\">Aggiungi filtro</button>\r\n</fieldset>\r\n", styles: [":host{display:block}.fb-filter__modes{margin-bottom:8px}.fb-field .fb-filter__modes{margin-bottom:0}\n"], dependencies: [{ kind: "component", type: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: FormulaEditorComponent, selector: "fb-formula-editor", inputs: ["expression", "usage", "expectedDataType", "scale", "placeholder", "ariaLabel", "disabled", "rows", "commitOn"], outputs: ["expressionChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9917
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: RecordFilterEditorComponent, isStandalone: true, selector: "fb-record-filter-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 }, usage: { classPropertyName: "usage", publicName: "usage", isSignal: true, isRequired: false, transformFunction: null }, fieldOptions: { classPropertyName: "fieldOptions", publicName: "fieldOptions", isSignal: true, isRequired: false, transformFunction: null }, supportsLogic: { classPropertyName: "supportsLogic", publicName: "supportsLogic", isSignal: true, isRequired: false, transformFunction: null }, supportsFormula: { classPropertyName: "supportsFormula", publicName: "supportsFormula", isSignal: true, isRequired: false, transformFunction: null }, emptyWarning: { classPropertyName: "emptyWarning", publicName: "emptyWarning", isSignal: true, isRequired: false, transformFunction: null }, emptyWarningSeverity: { classPropertyName: "emptyWarningSeverity", publicName: "emptyWarningSeverity", 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 (!object() && !fieldOptions().length) {\r\n <p class=\"fb-field__hint\">Scegli prima un oggetto per poter filtrare sui suoi campi.</p>\r\n }\r\n\r\n @if (supportsLogic()) {\r\n <div class=\"fb-filter__modes\" role=\"group\" aria-label=\"Logica dei filtri\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"logicMode() === 'and'\"\r\n (click)=\"setLogicMode('and')\"\r\n >\r\n Tutti (AND)\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"logicMode() === 'or'\"\r\n (click)=\"setLogicMode('or')\"\r\n >\r\n Almeno uno (OR)\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"logicMode() === 'custom'\"\r\n (click)=\"setLogicMode('custom')\"\r\n >\r\n Espressione\r\n </button>\r\n @if (supportsFormula()) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"logicMode() === 'formula'\"\r\n (click)=\"setLogicMode('formula')\"\r\n >\r\n Formula\r\n </button>\r\n }\r\n </div>\r\n } @else {\r\n <!-- Qui il modello non ha `filterLogic`: mostrarlo lo farebbe perdere al salvataggio. -->\r\n <p class=\"fb-field__hint\">Su questo elemento i filtri sono sempre combinati in AND.</p>\r\n }\r\n\r\n @if (supportsLogic() && 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 dei filtri\"\r\n (input)=\"setCustomLogic($any($event.target).value)\"\r\n />\r\n <!--\r\n Gli indici sono quelli numerati nell\u2019elenco qui sotto, e sono 1-based. Un indice\r\n inesistente e\u2019 `CONDITION_LOGIC_INVALID`, che e\u2019 un **errore**: blocca l\u2019attivazione,\r\n quindi conviene dirlo mentre si scrive e non alla validazione.\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 ai filtri numerati sotto. Cancellare un filtro\r\n riscrive l\u2019espressione automaticamente.\r\n </p>\r\n }\r\n </div>\r\n }\r\n\r\n <!--\r\n `filterLogic: \"Formula\"` non e\u2019 supportato da nessun elemento (\u00A74.4): non lo scrive nessun\r\n gesto di questo editor, ma un flow scritto altrove puo\u2019 portarcelo. Si dice invece di\r\n correggerlo di soppiatto \u2014 e\u2019 l\u2019unico indizio di cosa quel flow voleva fare.\r\n -->\r\n @if (unsupportedFormulaLogic()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n <code>filterLogic: \"Formula\"</code> non e\u2019 un valore supportato: sui choice set e\u2019 un errore\r\n di validazione, altrove fa fallire l\u2019esecuzione. I filtri qui sotto si combinano in AND.\r\n @if (supportsFormula()) {\r\n Per una formula usa la modalita\u2019 \u00ABFormula\u00BB, che scrive <code>filterFormula</code>.\r\n }\r\n </p>\r\n }\r\n\r\n @if (supportsFormula() && logicMode() === 'formula') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Formula di filtro</label>\r\n <fb-formula-editor\r\n [expression]=\"holder().filterFormula || ''\"\r\n usage=\"Condition\"\r\n expectedDataType=\"Boolean\"\r\n ariaLabel=\"Formula di filtro\"\r\n (expressionChange)=\"setFormula($event)\"\r\n >\r\n <p class=\"fb-field__hint\">\r\n Valutata dal motore di regole, <strong>in alternativa</strong> ai filtri: sta nel campo\r\n <code>filterFormula</code>, e la logica dei filtri non si applica.\r\n </p>\r\n </fb-formula-editor>\r\n </div>\r\n }\r\n\r\n @if (identifierNotFilterable()) {\r\n <p class=\"fb-field__hint\">\r\n Su questo oggetto l\u2019identificativo non e\u2019 filtrabile: la chiave e\u2019 composta e porta la propria\r\n forma canonica. Filtra per le colonne della chiave, una per colonna.\r\n </p>\r\n }\r\n\r\n @if (showEmptyWarning()) {\r\n <p\r\n class=\"fb-callout\"\r\n [class.fb-callout--warn]=\"emptyWarningSeverity() === 'warn'\"\r\n [class.fb-callout--error]=\"emptyWarningSeverity() === 'error'\"\r\n >\r\n {{ emptyWarning() }}\r\n </p>\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (filter of filters(); 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 filtro\"\r\n (click)=\"removeFilter($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <!-- Campo, operatore e valore sono una frase sola: si leggono in riga. -->\r\n <div class=\"fb-fields-row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo</label>\r\n @if (fieldOptions().length) {\r\n <!-- Insieme chiuso: qui non c'e' un catalogo incompleto da compensare. -->\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"filter.field || ''\"\r\n aria-label=\"Campo del filtro\"\r\n (change)=\"setField($index, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (option of fieldOptions(); track option.value) {\r\n <option [value]=\"option.value\">{{ option.label }}</option>\r\n }\r\n </select>\r\n @if (unknownFixedField(filter)) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ filter.field }}\u00BB non e\u2019 fra i campi citabili qui (FIELD_UNKNOWN).\r\n </p>\r\n }\r\n } @else {\r\n <fb-field-picker\r\n [value]=\"filter.field\"\r\n [object]=\"object()\"\r\n [usage]=\"usage()\"\r\n placeholder=\"Scrivi o scegli un campo\"\r\n (valueChange)=\"setField($index, $event ?? '')\"\r\n />\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field fb-field--compact\">\r\n <label class=\"fb-field__label\">Operatore</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"filter.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 </div>\r\n\r\n @if (isNullOperator(filter)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Esito atteso</label>\r\n <div class=\"fb-filter__modes\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"nullExpectation(filter)\"\r\n (click)=\"setNullExpectation($index, true)\"\r\n >\r\n \u00E8 vuoto\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"!nullExpectation(filter)\"\r\n (click)=\"setNullExpectation($index, false)\"\r\n >\r\n non \u00E8 vuoto\r\n </button>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\r\n <fb-value-editor\r\n [value]=\"filter.value\"\r\n [dataType]=\"fieldDataType(filter)\"\r\n [objectType]=\"fieldObjectType(filter)\"\r\n [valueSet]=\"fieldValueSet(filter)\"\r\n label=\"Valore del filtro\"\r\n [allowFormula]=\"false\"\r\n (valueChange)=\"setValue($index, $event)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun filtro.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addFilter()\">Aggiungi filtro</button>\r\n</fieldset>\r\n", styles: [":host{display:block}.fb-filter__modes{margin-bottom:8px}.fb-field .fb-filter__modes{margin-bottom:0}\n"], dependencies: [{ kind: "component", type: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: FormulaEditorComponent, selector: "fb-formula-editor", inputs: ["expression", "usage", "expectedDataType", "scale", "placeholder", "ariaLabel", "disabled", "rows", "preferredRoots", "commitOn"], outputs: ["expressionChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula", "preferredRoots"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9773
9918
|
}
|
|
9774
9919
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: RecordFilterEditorComponent, decorators: [{
|
|
9775
9920
|
type: Component,
|
|
@@ -9823,6 +9968,12 @@ class ParameterEditorComponent {
|
|
|
9823
9968
|
* quei campi sono una destinazione, e per questo non e' un default ma un parametro del chiamante.
|
|
9824
9969
|
*/
|
|
9825
9970
|
extraTargets = input([], ...(ngDevMode ? [{ debugName: "extraTargets" }] : []));
|
|
9971
|
+
/**
|
|
9972
|
+
* Le radici da proporre **per prime**, in ingresso e in uscita (§5.2). Dentro una riga di sezione
|
|
9973
|
+
* ripetibile e' il cursore: e' lì che vanno letti gli input di un componente e assegnati i suoi
|
|
9974
|
+
* output, perche' una riga ha un cursore e i campi della riga non sono riferimenti.
|
|
9975
|
+
*/
|
|
9976
|
+
preferredRoots = input([], ...(ngDevMode ? [{ debugName: "preferredRoots" }] : []));
|
|
9826
9977
|
changed = output();
|
|
9827
9978
|
inputs = computed(() => this.holder().inputParameters ?? [], ...(ngDevMode ? [{ debugName: "inputs" }] : []));
|
|
9828
9979
|
outputs = computed(() => this.holder().outputParameters ?? [], ...(ngDevMode ? [{ debugName: "outputs" }] : []));
|
|
@@ -9921,12 +10072,12 @@ class ParameterEditorComponent {
|
|
|
9921
10072
|
});
|
|
9922
10073
|
}
|
|
9923
10074
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ParameterEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9924
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 }, extraTargets: { classPropertyName: "extraTargets", publicName: "extraTargets", 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 <!-- Nome e valore sono una coppia: in colonna raddoppiavano l\u2019altezza dell\u2019elenco. -->\r\n <div class=\"fb-fields-row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Parametro</label>\r\n <fb-name-picker\r\n [value]=\"parameter.name\"\r\n [options]=\"inputOptions()\"\r\n label=\"Nome del parametro\"\r\n placeholder=\"Scrivi o scegli un parametro\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Il catalogo non dichiara questo parametro: la validazione lo segnalerebbe come errore.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Parametri dichiarati non disponibili: scrivi il nome a mano.\"\r\n (valueChange)=\"setInputName($index, $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\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\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon fb-fields-row__action\"\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 </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-fields-row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Parametro</label>\r\n <fb-name-picker\r\n [value]=\"parameter.name\"\r\n [options]=\"outputOptions()\"\r\n label=\"Nome del parametro di uscita\"\r\n placeholder=\"Scrivi o scegli un parametro\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Il catalogo non dichiara questo parametro di uscita.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Parametri di uscita dichiarati non disponibili: scrivi il nome a mano.\"\r\n (valueChange)=\"setOutputName($index, $event ?? '')\"\r\n />\r\n </div>\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 [extraReferences]=\"extraTargets()\"\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\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon fb-fields-row__action\"\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 </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}\n"], dependencies: [{ kind: "component", type: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10075
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 }, extraTargets: { classPropertyName: "extraTargets", publicName: "extraTargets", isSignal: true, isRequired: false, transformFunction: null }, preferredRoots: { classPropertyName: "preferredRoots", publicName: "preferredRoots", 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 <!-- Nome e valore sono una coppia: in colonna raddoppiavano l\u2019altezza dell\u2019elenco. -->\r\n <div class=\"fb-fields-row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Parametro</label>\r\n <fb-name-picker\r\n [value]=\"parameter.name\"\r\n [options]=\"inputOptions()\"\r\n label=\"Nome del parametro\"\r\n placeholder=\"Scrivi o scegli un parametro\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Il catalogo non dichiara questo parametro: la validazione lo segnalerebbe come errore.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Parametri dichiarati non disponibili: scrivi il nome a mano.\"\r\n (valueChange)=\"setInputName($index, $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\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 [preferredRoots]=\"preferredRoots()\"\r\n label=\"Valore del parametro\"\r\n (valueChange)=\"setInputValue($index, $event)\"\r\n />\r\n </div>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon fb-fields-row__action\"\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 </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-fields-row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Parametro</label>\r\n <fb-name-picker\r\n [value]=\"parameter.name\"\r\n [options]=\"outputOptions()\"\r\n label=\"Nome del parametro di uscita\"\r\n placeholder=\"Scrivi o scegli un parametro\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Il catalogo non dichiara questo parametro di uscita.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Parametri di uscita dichiarati non disponibili: scrivi il nome a mano.\"\r\n (valueChange)=\"setOutputName($index, $event ?? '')\"\r\n />\r\n </div>\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 [extraReferences]=\"extraTargets()\"\r\n [preferredRoots]=\"preferredRoots()\"\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\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon fb-fields-row__action\"\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 </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}\n"], dependencies: [{ kind: "component", type: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences", "preferredRoots"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula", "preferredRoots"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
9925
10076
|
}
|
|
9926
10077
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ParameterEditorComponent, decorators: [{
|
|
9927
10078
|
type: Component,
|
|
9928
|
-
args: [{ selector: 'fb-parameter-editor', standalone: true, imports: [NamePickerComponent, ReferencePickerComponent, ValueEditorComponent], changeDetection: ChangeDetectionStrategy.OnPush, 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 <!-- Nome e valore sono una coppia: in colonna raddoppiavano l\u2019altezza dell\u2019elenco. -->\r\n <div class=\"fb-fields-row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Parametro</label>\r\n <fb-name-picker\r\n [value]=\"parameter.name\"\r\n [options]=\"inputOptions()\"\r\n label=\"Nome del parametro\"\r\n placeholder=\"Scrivi o scegli un parametro\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Il catalogo non dichiara questo parametro: la validazione lo segnalerebbe come errore.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Parametri dichiarati non disponibili: scrivi il nome a mano.\"\r\n (valueChange)=\"setInputName($index, $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\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\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon fb-fields-row__action\"\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 </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-fields-row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Parametro</label>\r\n <fb-name-picker\r\n [value]=\"parameter.name\"\r\n [options]=\"outputOptions()\"\r\n label=\"Nome del parametro di uscita\"\r\n placeholder=\"Scrivi o scegli un parametro\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Il catalogo non dichiara questo parametro di uscita.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Parametri di uscita dichiarati non disponibili: scrivi il nome a mano.\"\r\n (valueChange)=\"setOutputName($index, $event ?? '')\"\r\n />\r\n </div>\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 [extraReferences]=\"extraTargets()\"\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\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon fb-fields-row__action\"\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 </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}\n"] }]
|
|
9929
|
-
}], propDecorators: { holder: [{ type: i0.Input, args: [{ isSignal: true, alias: "holder", required: true }] }], catalogParameters: [{ type: i0.Input, args: [{ isSignal: true, alias: "catalogParameters", required: false }] }], inputTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputTitle", required: false }] }], outputTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "outputTitle", required: false }] }], showInputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "showInputs", required: false }] }], showOutputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOutputs", required: false }] }], outputsDisabledReason: [{ type: i0.Input, args: [{ isSignal: true, alias: "outputsDisabledReason", required: false }] }], extraTargets: [{ type: i0.Input, args: [{ isSignal: true, alias: "extraTargets", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
|
|
10079
|
+
args: [{ selector: 'fb-parameter-editor', standalone: true, imports: [NamePickerComponent, ReferencePickerComponent, ValueEditorComponent], changeDetection: ChangeDetectionStrategy.OnPush, 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 <!-- Nome e valore sono una coppia: in colonna raddoppiavano l\u2019altezza dell\u2019elenco. -->\r\n <div class=\"fb-fields-row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Parametro</label>\r\n <fb-name-picker\r\n [value]=\"parameter.name\"\r\n [options]=\"inputOptions()\"\r\n label=\"Nome del parametro\"\r\n placeholder=\"Scrivi o scegli un parametro\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Il catalogo non dichiara questo parametro: la validazione lo segnalerebbe come errore.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Parametri dichiarati non disponibili: scrivi il nome a mano.\"\r\n (valueChange)=\"setInputName($index, $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\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 [preferredRoots]=\"preferredRoots()\"\r\n label=\"Valore del parametro\"\r\n (valueChange)=\"setInputValue($index, $event)\"\r\n />\r\n </div>\r\n\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon fb-fields-row__action\"\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 </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-fields-row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Parametro</label>\r\n <fb-name-picker\r\n [value]=\"parameter.name\"\r\n [options]=\"outputOptions()\"\r\n label=\"Nome del parametro di uscita\"\r\n placeholder=\"Scrivi o scegli un parametro\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Il catalogo non dichiara questo parametro di uscita.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Parametri di uscita dichiarati non disponibili: scrivi il nome a mano.\"\r\n (valueChange)=\"setOutputName($index, $event ?? '')\"\r\n />\r\n </div>\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 [extraReferences]=\"extraTargets()\"\r\n [preferredRoots]=\"preferredRoots()\"\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\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon fb-fields-row__action\"\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 </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}\n"] }]
|
|
10080
|
+
}], propDecorators: { holder: [{ type: i0.Input, args: [{ isSignal: true, alias: "holder", required: true }] }], catalogParameters: [{ type: i0.Input, args: [{ isSignal: true, alias: "catalogParameters", required: false }] }], inputTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputTitle", required: false }] }], outputTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "outputTitle", required: false }] }], showInputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "showInputs", required: false }] }], showOutputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "showOutputs", required: false }] }], outputsDisabledReason: [{ type: i0.Input, args: [{ isSignal: true, alias: "outputsDisabledReason", required: false }] }], extraTargets: [{ type: i0.Input, args: [{ isSignal: true, alias: "extraTargets", required: false }] }], preferredRoots: [{ type: i0.Input, args: [{ isSignal: true, alias: "preferredRoots", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
|
|
9930
10081
|
|
|
9931
10082
|
/**
|
|
9932
10083
|
* Editor di `inputAssignments` — FRONTEND.md §5.8.
|
|
@@ -10010,7 +10161,7 @@ class FieldAssignmentEditorComponent {
|
|
|
10010
10161
|
return this.fields().find((field) => field.name === name);
|
|
10011
10162
|
}
|
|
10012
10163
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FieldAssignmentEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10013
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 }, usage: { classPropertyName: "usage", publicName: "usage", 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 <!-- Campo e valore sono una coppia: in colonna raddoppiavano l\u2019altezza dell\u2019elenco. -->\r\n <div class=\"fb-fields-row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo</label>\r\n <fb-field-picker\r\n [value]=\"assignment.field\"\r\n [object]=\"object()\"\r\n [usage]=\"usage()\"\r\n placeholder=\"Scrivi o scegli un campo\"\r\n (valueChange)=\"setField($index, $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\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\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon fb-fields-row__action\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"remove($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\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}\n"], dependencies: [{ kind: "component", type: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10164
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 }, usage: { classPropertyName: "usage", publicName: "usage", 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 <!-- Campo e valore sono una coppia: in colonna raddoppiavano l\u2019altezza dell\u2019elenco. -->\r\n <div class=\"fb-fields-row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo</label>\r\n <fb-field-picker\r\n [value]=\"assignment.field\"\r\n [object]=\"object()\"\r\n [usage]=\"usage()\"\r\n placeholder=\"Scrivi o scegli un campo\"\r\n (valueChange)=\"setField($index, $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\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\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon fb-fields-row__action\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"remove($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\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}\n"], dependencies: [{ kind: "component", type: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula", "preferredRoots"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10014
10165
|
}
|
|
10015
10166
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: FieldAssignmentEditorComponent, decorators: [{
|
|
10016
10167
|
type: Component,
|
|
@@ -10798,7 +10949,7 @@ class ActionCallInspectorComponent extends NodeInspectorBase {
|
|
|
10798
10949
|
this.patch((node) => mutate(node));
|
|
10799
10950
|
}
|
|
10800
10951
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ActionCallInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10801
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: ActionCallInspectorComponent, isStandalone: true, selector: "fb-action-call-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo di action</label>\r\n <fb-name-picker\r\n [value]=\"action().actionType\"\r\n [options]=\"actionTypeOptions()\"\r\n label=\"Tipo di action\"\r\n placeholder=\"Scrivi o scegli un tipo\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo tipo di action non e\u2019 fra quelli dichiarati dal sistema ospite.\"\r\n emptyMessage=\"Catalogo dei tipi di action non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setActionType($event ?? '')\"\r\n />\r\n</div>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Action</label>\r\n <fb-name-picker\r\n [value]=\"action().actionName\"\r\n [options]=\"actionOptions()\"\r\n label=\"Action\"\r\n placeholder=\"Scrivi o scegli un\u2019action\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questa action non esiste nel catalogo del tipo scelto: la validazione la segnala come errore.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Scegli prima il tipo di action, oppure scrivi il nome a mano.\"\r\n (valueChange)=\"setActionName($event ?? '')\"\r\n />\r\n</div>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Esecuzione</legend>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Modello transazionale</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"action().flowTransactionModel || ''\"\r\n (change)=\"setTransactionModel($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 predefinito \u2014</option>\r\n @for (model of transactionModels(); track model.value) {\r\n <option [value]=\"model.value\">{{ model.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]=\"action().isWaitUntilCompleted === true\"\r\n (change)=\"setWaitUntilCompleted($any($event.target).checked)\"\r\n />\r\n Attendi il completamento\r\n </label>\r\n\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Attesa</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"0\"\r\n [value]=\"action().offset ?? ''\"\r\n (input)=\"setOffset($any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Unita\u2019</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"action().offsetUnit || ''\"\r\n (change)=\"setOffsetUnit($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014</option>\r\n @for (unit of offsetUnits(); track unit.value) {\r\n <option [value]=\"unit.value\">{{ unit.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n </div>\r\n <p class=\"fb-field__hint\">Definiscono l\u2019attesa di un\u2019action asincrona.</p>\r\n</fieldset>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Ramo di timeout</legend>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"timeoutEnabled()\"\r\n (change)=\"setTimeoutEnabled($any($event.target).checked)\"\r\n />\r\n Abilita il ramo di timeout\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n Il ramo esiste solo con questo flag: qui il flag e la destinazione sono legati, cos\u00EC non possono\r\n contraddirsi.\r\n </p>\r\n @if (timeoutMismatch()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il flag e il ramo di timeout non sono coerenti fra loro.\r\n </p>\r\n }\r\n</fieldset>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Output</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 Gli output dell\u2019action si referenziano col nome dell\u2019elemento: <code>{{ name() }}.NomeOutput</code>.\r\n </p>\r\n }\r\n</fieldset>\r\n\r\n<fb-parameter-editor\r\n [holder]=\"action()\"\r\n [catalogParameters]=\"parameterCatalog()\"\r\n [showOutputs]=\"!storeOutputAutomatically()\"\r\n [outputsDisabledReason]=\"\r\n storeOutputAutomatically() ? 'Con l\u2019output automatico i parametri di uscita non servono.' : null\r\n \"\r\n (changed)=\"onParametersChanged($event)\"\r\n/>\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Le tre uscite\"\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: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason", "extraTargets"], outputs: ["changed"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10952
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: ActionCallInspectorComponent, isStandalone: true, selector: "fb-action-call-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo di action</label>\r\n <fb-name-picker\r\n [value]=\"action().actionType\"\r\n [options]=\"actionTypeOptions()\"\r\n label=\"Tipo di action\"\r\n placeholder=\"Scrivi o scegli un tipo\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo tipo di action non e\u2019 fra quelli dichiarati dal sistema ospite.\"\r\n emptyMessage=\"Catalogo dei tipi di action non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setActionType($event ?? '')\"\r\n />\r\n</div>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Action</label>\r\n <fb-name-picker\r\n [value]=\"action().actionName\"\r\n [options]=\"actionOptions()\"\r\n label=\"Action\"\r\n placeholder=\"Scrivi o scegli un\u2019action\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questa action non esiste nel catalogo del tipo scelto: la validazione la segnala come errore.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Scegli prima il tipo di action, oppure scrivi il nome a mano.\"\r\n (valueChange)=\"setActionName($event ?? '')\"\r\n />\r\n</div>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Esecuzione</legend>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Modello transazionale</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"action().flowTransactionModel || ''\"\r\n (change)=\"setTransactionModel($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 predefinito \u2014</option>\r\n @for (model of transactionModels(); track model.value) {\r\n <option [value]=\"model.value\">{{ model.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]=\"action().isWaitUntilCompleted === true\"\r\n (change)=\"setWaitUntilCompleted($any($event.target).checked)\"\r\n />\r\n Attendi il completamento\r\n </label>\r\n\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Attesa</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"0\"\r\n [value]=\"action().offset ?? ''\"\r\n (input)=\"setOffset($any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Unita\u2019</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"action().offsetUnit || ''\"\r\n (change)=\"setOffsetUnit($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014</option>\r\n @for (unit of offsetUnits(); track unit.value) {\r\n <option [value]=\"unit.value\">{{ unit.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n </div>\r\n <p class=\"fb-field__hint\">Definiscono l\u2019attesa di un\u2019action asincrona.</p>\r\n</fieldset>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Ramo di timeout</legend>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"timeoutEnabled()\"\r\n (change)=\"setTimeoutEnabled($any($event.target).checked)\"\r\n />\r\n Abilita il ramo di timeout\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n Il ramo esiste solo con questo flag: qui il flag e la destinazione sono legati, cos\u00EC non possono\r\n contraddirsi.\r\n </p>\r\n @if (timeoutMismatch()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il flag e il ramo di timeout non sono coerenti fra loro.\r\n </p>\r\n }\r\n</fieldset>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Output</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 Gli output dell\u2019action si referenziano col nome dell\u2019elemento: <code>{{ name() }}.NomeOutput</code>.\r\n </p>\r\n }\r\n</fieldset>\r\n\r\n<fb-parameter-editor\r\n [holder]=\"action()\"\r\n [catalogParameters]=\"parameterCatalog()\"\r\n [showOutputs]=\"!storeOutputAutomatically()\"\r\n [outputsDisabledReason]=\"\r\n storeOutputAutomatically() ? 'Con l\u2019output automatico i parametri di uscita non servono.' : null\r\n \"\r\n (changed)=\"onParametersChanged($event)\"\r\n/>\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"name()\"\r\n [node]=\"node()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Le tre uscite\"\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: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason", "extraTargets", "preferredRoots"], outputs: ["changed"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10802
10953
|
}
|
|
10803
10954
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ActionCallInspectorComponent, decorators: [{
|
|
10804
10955
|
type: Component,
|
|
@@ -10948,7 +11099,7 @@ class AssignmentInspectorComponent extends NodeInspectorBase {
|
|
|
10948
11099
|
return !operator.startsWith('Remove') || operator === 'RemovePosition' || operator === 'RemoveUncommon';
|
|
10949
11100
|
}
|
|
10950
11101
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: AssignmentInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10951
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 <!-- Destinazione, operazione e valore sono una frase sola: si leggono in riga. -->\r\n <div class=\"fb-fields-row\">\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 fb-field--compact\">\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 <!--\r\n Il tipo della destinazione guida il controllo: su un Enum i valori proponibili sono\r\n quelli del suo tipo, e farli digitare e' il modo piu' facile di scriverne uno che il\r\n runtime non riconosce (\u00A74.6). Vale anche dentro una classe \u2014 \u00ABRichiesta.Stato\u00BB \u2014 perche'\r\n il tipo si ricava navigando i membri (\u00A74.7.1). Ignoto il tipo, il campo resta generico.\r\n -->\r\n <fb-value-editor\r\n [value]=\"item.value\"\r\n label=\"Valore\"\r\n [dataType]=\"targetDataType(item)\"\r\n [objectType]=\"targetObjectType(item)\"\r\n (valueChange)=\"setValue($index, $event)\"\r\n />\r\n </div>\r\n }\r\n </div>\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", "extraReferences"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11102
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 <!-- Destinazione, operazione e valore sono una frase sola: si leggono in riga. -->\r\n <div class=\"fb-fields-row\">\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 fb-field--compact\">\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 <!--\r\n Il tipo della destinazione guida il controllo: su un Enum i valori proponibili sono\r\n quelli del suo tipo, e farli digitare e' il modo piu' facile di scriverne uno che il\r\n runtime non riconosce (\u00A74.6). Vale anche dentro una classe \u2014 \u00ABRichiesta.Stato\u00BB \u2014 perche'\r\n il tipo si ricava navigando i membri (\u00A74.7.1). Ignoto il tipo, il campo resta generico.\r\n -->\r\n <fb-value-editor\r\n [value]=\"item.value\"\r\n label=\"Valore\"\r\n [dataType]=\"targetDataType(item)\"\r\n [objectType]=\"targetObjectType(item)\"\r\n (valueChange)=\"setValue($index, $event)\"\r\n />\r\n </div>\r\n }\r\n </div>\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", "extraReferences", "preferredRoots"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula", "preferredRoots"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10952
11103
|
}
|
|
10953
11104
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: AssignmentInspectorComponent, decorators: [{
|
|
10954
11105
|
type: Component,
|
|
@@ -11069,7 +11220,7 @@ class CollectionProcessorInspectorComponent extends NodeInspectorBase {
|
|
|
11069
11220
|
this.patch((node) => mutate(node));
|
|
11070
11221
|
}
|
|
11071
11222
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: CollectionProcessorInspectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
11072
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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", "extraReferences"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11223
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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", "preferredRoots", "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", "extraReferences", "preferredRoots"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11073
11224
|
}
|
|
11074
11225
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: CollectionProcessorInspectorComponent, decorators: [{
|
|
11075
11226
|
type: Component,
|
|
@@ -11251,7 +11402,7 @@ class DecisionInspectorComponent extends NodeInspectorBase {
|
|
|
11251
11402
|
this.setField('defaultConnectorLabel', label);
|
|
11252
11403
|
}
|
|
11253
11404
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: DecisionInspectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
11254
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 });
|
|
11405
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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", "preferredRoots", "allowLogic", "issuePath"], outputs: ["changed"] }, { kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
11255
11406
|
}
|
|
11256
11407
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: DecisionInspectorComponent, decorators: [{
|
|
11257
11408
|
type: Component,
|
|
@@ -11317,6 +11468,7 @@ const FIELD_ICONS = {
|
|
|
11317
11468
|
ComponentInstance: '⬡',
|
|
11318
11469
|
Region: '▯',
|
|
11319
11470
|
RegionContainer: '▣',
|
|
11471
|
+
RepeatingSection: '⧉',
|
|
11320
11472
|
ObjectProvided: '⌗',
|
|
11321
11473
|
};
|
|
11322
11474
|
class DynamicScreenInspectorComponent extends NodeInspectorBase {
|
|
@@ -11546,6 +11698,18 @@ class DynamicScreenInspectorComponent extends NodeInspectorBase {
|
|
|
11546
11698
|
isContainer(field) {
|
|
11547
11699
|
return this.dictionary.screenFieldIsContainer(field?.fieldType);
|
|
11548
11700
|
}
|
|
11701
|
+
isRepeatingSection(field) {
|
|
11702
|
+
return this.dictionary.screenFieldIsRepeatingSection(field?.fieldType);
|
|
11703
|
+
}
|
|
11704
|
+
/**
|
|
11705
|
+
* §5.2 — il campo ha dei `fields` dentro, quale che sia il loro significato: e' la domanda che
|
|
11706
|
+
* serve al rilascio e al comando «aggiungi qui». I due flag restano distinti — cio' che sta in una
|
|
11707
|
+
* sezione ripetibile e' il **modello di una riga**, non campi della schermata — ma per decidere
|
|
11708
|
+
* *dove* finisce un campo trascinato la differenza non conta.
|
|
11709
|
+
*/
|
|
11710
|
+
holdsFields(field) {
|
|
11711
|
+
return this.isContainer(field) || this.isRepeatingSection(field);
|
|
11712
|
+
}
|
|
11549
11713
|
/** `true` sulla sezione, che dispone i figli **in riga**: le colonne stanno una accanto all'altra. */
|
|
11550
11714
|
isSection(field) {
|
|
11551
11715
|
return field?.fieldType === 'RegionContainer';
|
|
@@ -11849,7 +12013,7 @@ class DynamicScreenInspectorComponent extends NodeInspectorBase {
|
|
|
11849
12013
|
if (!path) {
|
|
11850
12014
|
return { parent: [], index: this.screen().fields?.length ?? 0 };
|
|
11851
12015
|
}
|
|
11852
|
-
if (this.
|
|
12016
|
+
if (this.holdsFields(this.selectedField())) {
|
|
11853
12017
|
return { parent: path, index: fieldAt(this.screen().fields, path)?.fields?.length ?? 0 };
|
|
11854
12018
|
}
|
|
11855
12019
|
return { parent: path.slice(0, -1), index: path[path.length - 1] + 1 };
|
|
@@ -11857,6 +12021,17 @@ class DynamicScreenInspectorComponent extends NodeInspectorBase {
|
|
|
11857
12021
|
addComponentAtSelection(type) {
|
|
11858
12022
|
this.addComponent(type, this.clickTarget());
|
|
11859
12023
|
}
|
|
12024
|
+
/** Se il tipo puo' finire dove il clic lo metterebbe: e' cio' che disabilita il chip della palette. */
|
|
12025
|
+
canAddAtSelection(type) {
|
|
12026
|
+
return this.canPlaceAt(type, this.clickTarget());
|
|
12027
|
+
}
|
|
12028
|
+
/** §5.2 — l'unico divieto di collocazione: una sezione ripetibile dentro un'altra. */
|
|
12029
|
+
canPlaceAt(type, target) {
|
|
12030
|
+
if (!this.dictionary.screenFieldIsRepeatingSection(type)) {
|
|
12031
|
+
return true;
|
|
12032
|
+
}
|
|
12033
|
+
return (repeatingSectionOf(this.screen(), [...target.parent, target.index], this.typeOfField) === undefined);
|
|
12034
|
+
}
|
|
11860
12035
|
addObjectFieldAtSelection(field) {
|
|
11861
12036
|
this.addObjectField(field, this.clickTarget());
|
|
11862
12037
|
}
|
|
@@ -11866,6 +12041,12 @@ class DynamicScreenInspectorComponent extends NodeInspectorBase {
|
|
|
11866
12041
|
* primo gesto sarebbe sempre lo stesso.
|
|
11867
12042
|
*/
|
|
11868
12043
|
addComponent(type, target) {
|
|
12044
|
+
// §5.2 — le sezioni ripetibili **non si annidano**: il cursore e' una variabile sola per sezione,
|
|
12045
|
+
// e due sezioni annidate ne vorrebbero due vive contemporaneamente. La tendina dei tipi la
|
|
12046
|
+
// esclude già, ma il trascinamento dalla palette da lì non passa.
|
|
12047
|
+
if (!this.canPlaceAt(type, target)) {
|
|
12048
|
+
return;
|
|
12049
|
+
}
|
|
11869
12050
|
const label = this.dictionary.screenFieldType(type)?.label ?? type;
|
|
11870
12051
|
const used = [...this.store.usedNames()];
|
|
11871
12052
|
const field = { name: uniqueFlowName(label, used), fieldType: type };
|
|
@@ -12048,6 +12229,107 @@ class DynamicScreenInspectorComponent extends NodeInspectorBase {
|
|
|
12048
12229
|
return dot < 0 ? '' : reference.slice(dot + 1);
|
|
12049
12230
|
}, ...(ngDevMode ? [{ debugName: "providedField" }] : []));
|
|
12050
12231
|
// -------------------------------------------------------------------------
|
|
12232
|
+
// §5.2 — sezioni ripetibili: cosa cambia quando si sta dentro una riga
|
|
12233
|
+
// -------------------------------------------------------------------------
|
|
12234
|
+
/** Come si legge la voce di dizionario di un campo: il flag e' del dizionario, non del codice. */
|
|
12235
|
+
typeOfField = (field) => this.dictionary.screenFieldType(field.fieldType);
|
|
12236
|
+
selectedIsRepeatingSection = computed(() => this.selectedType()?.isRepeatingSection === true, ...(ngDevMode ? [{ debugName: "selectedIsRepeatingSection" }] : []));
|
|
12237
|
+
/**
|
|
12238
|
+
* La sezione ripetibile che **contiene** il campo selezionato, se c'e'. Antenato stretto: sulla
|
|
12239
|
+
* sezione stessa e' `undefined`, perche' configurare la sezione e configurare un campo di una riga
|
|
12240
|
+
* sono due pannelli diversi.
|
|
12241
|
+
*/
|
|
12242
|
+
selectedRepeater = computed(() => repeatingSectionOf(this.screen(), this.selectedPath(), this.typeOfField), ...(ngDevMode ? [{ debugName: "selectedRepeater" }] : []));
|
|
12243
|
+
isInsideRepeater = computed(() => this.selectedRepeater() !== undefined, ...(ngDevMode ? [{ debugName: "isInsideRepeater" }] : []));
|
|
12244
|
+
/**
|
|
12245
|
+
* Il **cursore** della riga in cui si sta: e' cio' che si nomina lì dentro (§5.2). Scrivere il nome
|
|
12246
|
+
* del campo — `Luce_POD` — e' `SCREEN_FIELD_IN_REPEATER`, perche' quel campo esiste in una riga per
|
|
12247
|
+
* elemento della collection e il riferimento non ne individua nessuna.
|
|
12248
|
+
*/
|
|
12249
|
+
rowCursor = computed(() => this.selectedRepeater()?.itemReference ?? '', ...(ngDevMode ? [{ debugName: "rowCursor" }] : []));
|
|
12250
|
+
/**
|
|
12251
|
+
* Cosa proporre **per primo** nei selettori di riferimento del campo selezionato. Dentro una riga
|
|
12252
|
+
* e' il cursore: e' la strada normale, e i campi della riga — che sono cio' che uno cerca per
|
|
12253
|
+
* istinto — non compaiono affatto, perche' non sono riferimenti validi. Fuori e' vuoto, cioe'
|
|
12254
|
+
* l'ordine di sempre.
|
|
12255
|
+
*/
|
|
12256
|
+
preferredRoots = computed(() => {
|
|
12257
|
+
const cursor = this.rowCursor();
|
|
12258
|
+
return cursor ? [cursor] : [];
|
|
12259
|
+
}, ...(ngDevMode ? [{ debugName: "preferredRoots" }] : []));
|
|
12260
|
+
/**
|
|
12261
|
+
* I tipi proponibili per il campo selezionato. Dentro una riga manca la sezione ripetibile: **non si
|
|
12262
|
+
* annidano** — il cursore e' una variabile sola per sezione, e due sezioni annidate ne vorrebbero due
|
|
12263
|
+
* vive contemporaneamente. La validazione lo rifiuta comunque, ma un editor che lascia comporre e poi
|
|
12264
|
+
* accusa fa perdere tempo due volte.
|
|
12265
|
+
*/
|
|
12266
|
+
fieldTypeOptions = computed(() => {
|
|
12267
|
+
const all = this.dictionary.screenFieldTypes();
|
|
12268
|
+
return this.isInsideRepeater() ? all.filter((entry) => entry.isRepeatingSection !== true) : all;
|
|
12269
|
+
}, ...(ngDevMode ? [{ debugName: "fieldTypeOptions" }] : []));
|
|
12270
|
+
/**
|
|
12271
|
+
* La classe delle righe: l'`objectType` della **variabile** in `collectionReference` (§5.2). Si
|
|
12272
|
+
* legge dal documento e non da `getReferences` perche' i due riferimenti di una sezione sono
|
|
12273
|
+
* variabili per forza — ci scrive il runtime — e la risposta serve sincrona, dentro il template.
|
|
12274
|
+
*/
|
|
12275
|
+
rowClassOf(section) {
|
|
12276
|
+
return this.variableTypeOf(section?.collectionReference)?.objectType;
|
|
12277
|
+
}
|
|
12278
|
+
/** La classe con cui si popolano le tendine dei membri: quella della sezione, dentro o fuori. */
|
|
12279
|
+
rowClass = computed(() => this.rowClassOf(this.selectedIsRepeatingSection() ? this.selectedField() : this.selectedRepeater()), ...(ngDevMode ? [{ debugName: "rowClass" }] : []));
|
|
12280
|
+
/**
|
|
12281
|
+
* §5.2 — le incoerenze dei due riferimenti sono tutte `REPEATING_SECTION_INVALID`, e si dicono qui
|
|
12282
|
+
* invece di aspettare la validazione: riferimento mancante, costante al posto di una variabile,
|
|
12283
|
+
* collection scambiata col cursore, due classi diverse.
|
|
12284
|
+
*/
|
|
12285
|
+
repeaterIssue = computed(() => {
|
|
12286
|
+
const section = this.selectedField();
|
|
12287
|
+
if (!this.selectedIsRepeatingSection() || !section) {
|
|
12288
|
+
return null;
|
|
12289
|
+
}
|
|
12290
|
+
const collection = section.collectionReference;
|
|
12291
|
+
const item = section.itemReference;
|
|
12292
|
+
if (!collection || !item) {
|
|
12293
|
+
return 'Servono entrambi i riferimenti: la collection in cui vivono le righe e il cursore su cui il runtime appoggia la riga corrente.';
|
|
12294
|
+
}
|
|
12295
|
+
const collectionType = this.variableTypeOf(collection);
|
|
12296
|
+
const itemType = this.variableTypeOf(item);
|
|
12297
|
+
if (!collectionType) {
|
|
12298
|
+
return `«${collection}» non e’ una variabile del flow: le righe le scrive il runtime, quindi dev’essere una variabile.`;
|
|
12299
|
+
}
|
|
12300
|
+
if (!itemType) {
|
|
12301
|
+
return `«${item}» non e’ una variabile del flow: il cursore lo scrive il runtime.`;
|
|
12302
|
+
}
|
|
12303
|
+
if (collectionType.dataType !== 'Structure' || itemType.dataType !== 'Structure') {
|
|
12304
|
+
return 'Entrambi i riferimenti devono essere di tipo Structure: la riga e’ un’istanza di classe.';
|
|
12305
|
+
}
|
|
12306
|
+
if (!collectionType.isCollection) {
|
|
12307
|
+
return `«${collection}» non e’ una collection: e’ lì che vivono le righe.`;
|
|
12308
|
+
}
|
|
12309
|
+
if (itemType.isCollection) {
|
|
12310
|
+
return `«${item}» e’ una collection: il cursore tiene **una** riga per volta, come l’assignNextValueToReference di un Loop.`;
|
|
12311
|
+
}
|
|
12312
|
+
if (collectionType.objectType !== itemType.objectType) {
|
|
12313
|
+
return `Le due variabili dichiarano classi diverse (${collectionType.objectType ?? '—'} e ${itemType.objectType ?? '—'}): il cursore deve essere della stessa classe delle righe.`;
|
|
12314
|
+
}
|
|
12315
|
+
return null;
|
|
12316
|
+
}, ...(ngDevMode ? [{ debugName: "repeaterIssue" }] : []));
|
|
12317
|
+
/** §5.2 — il massimo mancante e' un **avviso**: senza, l'utente puo' aggiungere righe all'infinito. */
|
|
12318
|
+
repeaterHasNoLimit = computed(() => this.selectedIsRepeatingSection() && this.selectedField()?.maxInstances === undefined, ...(ngDevMode ? [{ debugName: "repeaterHasNoLimit" }] : []));
|
|
12319
|
+
/**
|
|
12320
|
+
* La variabile del documento con quel nome, se e' una variabile. Non un riferimento qualunque: una
|
|
12321
|
+
* costante o una formula qui e' `REPEATING_SECTION_INVALID`, e distinguerle e' il punto.
|
|
12322
|
+
*/
|
|
12323
|
+
variableTypeOf(name) {
|
|
12324
|
+
if (!name) {
|
|
12325
|
+
return undefined;
|
|
12326
|
+
}
|
|
12327
|
+
const match = this.store
|
|
12328
|
+
.resources()
|
|
12329
|
+
.find((entry) => entry.collection === 'variables' && entry.name === name);
|
|
12330
|
+
return match?.resource;
|
|
12331
|
+
}
|
|
12332
|
+
// -------------------------------------------------------------------------
|
|
12051
12333
|
// Mutazioni sul campo selezionato
|
|
12052
12334
|
// -------------------------------------------------------------------------
|
|
12053
12335
|
/** Scrive una proprieta' del campo selezionato; valore vuoto → chiave omessa (§2). */
|
|
@@ -12110,10 +12392,25 @@ class DynamicScreenInspectorComponent extends NodeInspectorBase {
|
|
|
12110
12392
|
delete field.defaultSelectedChoiceReference;
|
|
12111
12393
|
delete field.autoSelectSingleChoice;
|
|
12112
12394
|
}
|
|
12113
|
-
|
|
12395
|
+
// I `fields` di una sezione ripetibile sono il **modello della riga**: `isContainer` e' falso —
|
|
12396
|
+
// quei campi non sono campi della schermata — ma cancellarli butterebbe via la riga (§5.2).
|
|
12397
|
+
if (!entry?.isContainer && entry?.isRepeatingSection !== true) {
|
|
12114
12398
|
delete field.fields;
|
|
12399
|
+
}
|
|
12400
|
+
if (!entry?.isContainer) {
|
|
12115
12401
|
delete field.regionContainerType;
|
|
12116
12402
|
}
|
|
12403
|
+
if (entry?.isRepeatingSection !== true) {
|
|
12404
|
+
delete field.collectionReference;
|
|
12405
|
+
delete field.itemReference;
|
|
12406
|
+
delete field.minInstances;
|
|
12407
|
+
delete field.maxInstances;
|
|
12408
|
+
delete field.allowAdd;
|
|
12409
|
+
delete field.allowRemove;
|
|
12410
|
+
delete field.addButtonLabel;
|
|
12411
|
+
delete field.removeButtonLabel;
|
|
12412
|
+
delete field.itemLabel;
|
|
12413
|
+
}
|
|
12117
12414
|
if (type !== 'ComponentInstance') {
|
|
12118
12415
|
delete field.extensionName;
|
|
12119
12416
|
delete field.inputParameters;
|
|
@@ -12134,6 +12431,20 @@ class DynamicScreenInspectorComponent extends NodeInspectorBase {
|
|
|
12134
12431
|
const parsed = Number(raw);
|
|
12135
12432
|
this.setFieldProperty(property, raw === '' || Number.isNaN(parsed) ? undefined : parsed);
|
|
12136
12433
|
}
|
|
12434
|
+
/**
|
|
12435
|
+
* §5.2 — `allowAdd` e `allowRemove` hanno default `true`: si scrive solo il `false`, che e' la
|
|
12436
|
+
* scelta significativa. È la stessa regola dei flag del node (§2), non quella di un `FlowValue`.
|
|
12437
|
+
*/
|
|
12438
|
+
setRepeaterFlag(property, value) {
|
|
12439
|
+
this.patchField((field) => {
|
|
12440
|
+
if (value) {
|
|
12441
|
+
delete field[property];
|
|
12442
|
+
}
|
|
12443
|
+
else {
|
|
12444
|
+
field[property] = false;
|
|
12445
|
+
}
|
|
12446
|
+
});
|
|
12447
|
+
}
|
|
12137
12448
|
/** `isRequired` si scrive solo quando e' vero: il default e' facoltativo. */
|
|
12138
12449
|
setRequired(value) {
|
|
12139
12450
|
this.patchField((field) => {
|
|
@@ -12298,9 +12609,17 @@ class DynamicScreenInspectorComponent extends NodeInspectorBase {
|
|
|
12298
12609
|
isWritable: true,
|
|
12299
12610
|
description: 'campo di questa schermata',
|
|
12300
12611
|
})), ...(ngDevMode ? [{ debugName: "screenFieldTargets" }] : []));
|
|
12301
|
-
/**
|
|
12612
|
+
/**
|
|
12613
|
+
* I campi che raccolgono un valore: gli unici che un'action possa riempire, e gli unici che
|
|
12614
|
+
* innescano.
|
|
12615
|
+
*
|
|
12616
|
+
* **Senza quelli dentro una riga**, che raccolgono un valore ma non sono risorse: un trigger nomina
|
|
12617
|
+
* un campo, e il campo di una riga non ne ha uno solo — sarebbe da dichiarare *quale* riga osserva.
|
|
12618
|
+
* Un `triggerFieldName` che punta lì e' `SCREEN_FIELD_IN_REPEATER`, e lo stesso vale per
|
|
12619
|
+
* l'`assignToReference` di un output (§5.2).
|
|
12620
|
+
*/
|
|
12302
12621
|
valueFieldsOfScreen() {
|
|
12303
|
-
return
|
|
12622
|
+
return resourceFieldsOf(this.screen(), this.typeOfField);
|
|
12304
12623
|
}
|
|
12305
12624
|
/**
|
|
12306
12625
|
* I campi proponibili come innesco. Sono **i campi di questa schermata**, non i riferimenti in
|
|
@@ -12569,7 +12888,7 @@ class DynamicScreenInspectorComponent extends NodeInspectorBase {
|
|
|
12569
12888
|
});
|
|
12570
12889
|
}
|
|
12571
12890
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: DynamicScreenInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
12572
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: DynamicScreenInspectorComponent, isStandalone: true, selector: "fb-dynamic-screen-inspector", inputs: { initialSelection: { classPropertyName: "initialSelection", publicName: "initialSelection", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "composer", first: true, predicate: ["composer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"fb-scr\" #composer>\r\n <!-- ============================================================ sinistra -->\r\n <aside class=\"fb-scr__side\" aria-label=\"Componenti e campi\">\r\n <div class=\"fb-scr__tabs\" role=\"tablist\">\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"fb-scr__tab\"\r\n [class.fb-scr__tab--active]=\"paletteTab() === 'components'\"\r\n [attr.aria-selected]=\"paletteTab() === 'components'\"\r\n (click)=\"setPaletteTab('components')\"\r\n >\r\n Componenti\r\n </button>\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"fb-scr__tab\"\r\n [class.fb-scr__tab--active]=\"paletteTab() === 'fields'\"\r\n [attr.aria-selected]=\"paletteTab() === 'fields'\"\r\n (click)=\"setPaletteTab('fields')\"\r\n >\r\n Campi\r\n </button>\r\n </div>\r\n\r\n @if (paletteTab() === 'components') {\r\n @if (!dictionary.screenFieldTypes().length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il dizionario <code>screenFieldTypes</code> non e\u2019 disponibile: senza i suoi flag l\u2019editor non\r\n sa quali campi ammette ciascun tipo, e non li inventa.\r\n </p>\r\n }\r\n <p class=\"fb-scr__side-hint\">Trascina sulla schermata, oppure clicca per aggiungere.</p>\r\n <ul class=\"fb-scr__palette\">\r\n @for (entry of dictionary.screenFieldTypes(); track entry.value) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-scr__chip\"\r\n cdkDrag\r\n [title]=\"entry.description || entry.label\"\r\n (cdkDragMoved)=\"onPaletteDragMoved($event)\"\r\n (cdkDragEnded)=\"onComponentDragEnded($event, entry.value)\"\r\n (click)=\"addComponentAtSelection(entry.value)\"\r\n >\r\n <span class=\"fb-scr__chip-icon\" aria-hidden=\"true\">{{ iconOf(entry.value) }}</span>\r\n <span class=\"fb-scr__chip-label\">{{ entry.label }}</span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n } @else {\r\n <p class=\"fb-scr__side-hint\">\r\n Un campo dell\u2019entita\u2019 porta con se\u2019 tipo, etichetta, obbligatorieta\u2019 e opzioni: arrivano dallo\r\n schema dati, qui non si ridichiarano.\r\n </p>\r\n <!-- Il catalogo non e' un dizionario chiuso: si sceglie o si scrive, come ovunque si\r\n indichi un'entita' (vedi `object-picker`). -->\r\n <fb-object-picker\r\n [value]=\"fieldsObject()\"\r\n label=\"Entita\u2019\"\r\n placeholder=\"Scrivi o scegli un\u2019entita\u2019\"\r\n (valueChange)=\"setFieldsObject($event)\"\r\n />\r\n @if (fieldsObject() && !fieldsOfObject().length) {\r\n <p class=\"fb-scr__side-empty\">\r\n Nessun campo dichiarato per questa entita\u2019: il catalogo non li espone, non significa che non\r\n ci siano.\r\n </p>\r\n }\r\n <ul class=\"fb-scr__palette\">\r\n @for (field of fieldsOfObject(); track $index) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-scr__chip\"\r\n cdkDrag\r\n [title]=\"field.name + (field.dataType ? ' \u00B7 ' + field.dataType : '')\"\r\n (cdkDragMoved)=\"onPaletteDragMoved($event)\"\r\n (cdkDragEnded)=\"onObjectFieldDragEnded($event, field)\"\r\n (click)=\"addObjectFieldAtSelection(field)\"\r\n >\r\n <span class=\"fb-scr__chip-icon\" aria-hidden=\"true\">\u2317</span>\r\n <span class=\"fb-scr__chip-label\">\r\n {{ field.label || field.name }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n <small>{{ field.dataType }}</small>\r\n </span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n </aside>\r\n\r\n <!-- ============================================================== centro -->\r\n <!-- Cliccare fuori da un campo riporta a destra le proprieta' della schermata. -->\r\n <section class=\"fb-scr__canvas\" aria-label=\"Anteprima della schermata\" (click)=\"selectScreen()\">\r\n <div class=\"fb-scr__frame\">\r\n @if (showHeader()) {\r\n <header class=\"fb-scr__frame-head\">\r\n {{ $any(node()).label || name() }}\r\n @if (screen().helpText) {\r\n <span class=\"fb-scr__help\" [title]=\"screen().helpText || ''\">?</span>\r\n }\r\n </header>\r\n }\r\n\r\n <div\r\n class=\"fb-scr__body\"\r\n [attr.data-drop]=\"''\"\r\n data-axis=\"column\"\r\n [class.fb-scr__body--empty]=\"isEmpty()\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: screen().fields || [], parent: [], axis: 'column' }\"\r\n />\r\n </div>\r\n\r\n <!--\r\n La barra di inserimento e' un **velo** sopra l'anteprima, non un figlio del contenitore di\r\n rilascio: dentro la griglia occupava una riga intera e spostava in basso proprio la sezione\r\n che si stava puntando, che allora usciva da sotto il puntatore e il bersaglio oscillava.\r\n -->\r\n @if (dropMarker(); as bar) {\r\n <div\r\n class=\"fb-scr__marker\"\r\n [style.left.px]=\"bar.left\"\r\n [style.top.px]=\"bar.top\"\r\n [style.width.px]=\"bar.width\"\r\n [style.height.px]=\"bar.height\"\r\n ></div>\r\n }\r\n\r\n @if (showFooter()) {\r\n <footer class=\"fb-scr__frame-foot\">\r\n @if (allowPause()) {\r\n <span class=\"fb-scr__btn fb-scr__btn--ghost\">{{ screen().pauseButtonLabel || 'Pausa' }}</span>\r\n }\r\n <span class=\"fb-scr__spacer\"></span>\r\n @if (allowBack()) {\r\n <span class=\"fb-scr__btn fb-scr__btn--ghost\">{{ screen().backButtonLabel || 'Indietro' }}</span>\r\n }\r\n <span class=\"fb-scr__btn fb-scr__btn--primary\">\r\n {{ screen().nextOrFinishButtonLabel || (allowFinish() ? 'Fine' : 'Avanti') }}\r\n </span>\r\n </footer>\r\n }\r\n </div>\r\n\r\n @if (isEmpty()) {\r\n <p class=\"fb-callout fb-callout--warn fb-scr__canvas-note\">\r\n La schermata non ha campi: non c\u2019e\u2019 niente da mostrare all\u2019utente (SCREEN_WITHOUT_FIELDS).\r\n </p>\r\n }\r\n </section>\r\n\r\n <!-- ============================================================== destra -->\r\n <aside class=\"fb-scr__props\" aria-label=\"Proprieta\u2019\">\r\n @if (!selectedField()) {\r\n <!-- ------------------------------------------------ proprieta' della schermata -->\r\n <header class=\"fb-scr__props-head\">\r\n <h3 class=\"fb-scr__props-title\">Schermata</h3>\r\n </header>\r\n <p class=\"fb-scr__side-hint\">Seleziona un campo nell\u2019anteprima per configurarlo.</p>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo di aiuto</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"screen().helpText || ''\"\r\n (input)=\"setScreenText('helpText', $any($event.target).value)\"\r\n ></textarea>\r\n </div>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Navigazione</legend>\r\n <p class=\"fb-section__note\">\r\n Questi flag sono un\u2019intenzione, non la verita\u2019 finale: a runtime il motore comunica\r\n <code>canGoBack</code>, <code>canFinish</code> e <code>canPause</code> nella richiesta della\r\n schermata.\r\n </p>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowBack()\" (change)=\"setScreenFlag('allowBack', $any($event.target).checked)\" />\r\n Consenti \u00ABindietro\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowFinish()\" (change)=\"setScreenFlag('allowFinish', $any($event.target).checked)\" />\r\n Consenti \u00ABfine\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowPause()\" (change)=\"setScreenFlag('allowPause', $any($event.target).checked)\" />\r\n Consenti \u00ABpausa\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"showHeader()\" (change)=\"setScreenFlag('showHeader', $any($event.target).checked)\" />\r\n Mostra l\u2019intestazione\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"showFooter()\" (change)=\"setScreenFlag('showFooter', $any($event.target).checked)\" />\r\n Mostra il piede\r\n </label>\r\n\r\n @if (allowPause()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo mostrato alla pausa</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().pausedText || ''\"\r\n (input)=\"setScreenText('pausedText', $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (isDeadEnd()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Questa schermata non ha una destinazione e non consente \u00ABfine\u00BB: e\u2019 un vicolo cieco, e\r\n l\u2019utente resterebbe bloccato (SCREEN_DEAD_END).\r\n </p>\r\n }\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Pulsanti</legend>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta \u00ABindietro\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().backButtonLabel || ''\"\r\n (input)=\"setScreenText('backButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta \u00ABavanti / fine\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().nextOrFinishButtonLabel || ''\"\r\n (input)=\"setScreenText('nextOrFinishButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta \u00ABpausa\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().pauseButtonLabel || ''\"\r\n (input)=\"setScreenText('pauseButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n </fieldset>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Stage mostrato nell\u2019avanzamento</label>\r\n <fb-name-picker\r\n [value]=\"screen().stageReference\"\r\n [options]=\"stageOptions()\"\r\n label=\"Stage\"\r\n placeholder=\"Scegli uno stage\"\r\n unknownMessage=\"Questo stage non e\u2019 dichiarato dal flow.\"\r\n emptyMessage=\"Il flow non dichiara stage: creali nel pannello delle risorse.\"\r\n (valueChange)=\"setScreenText('stageReference', $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <!--\r\n Screen action (\u00A75.2). Due elenchi e non uno perche' il contratto li separa: piu' trigger\r\n possono invocare la stessa action, quindi \u00ABchi la chiama\u00BB non e' una sua proprieta'. Le\r\n action si aprono una alla volta: i cataloghi dipendono da tipo e nome, e tenerne N in volo\r\n sarebbe N volte la corsa fra risposte.\r\n -->\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Azioni della schermata</legend>\r\n <p class=\"fb-section__note\">\r\n Un campo che l\u2019utente compila puo\u2019 innescare un\u2019action i cui risultati finiscono negli\r\n <strong>altri campi di questa schermata</strong>: e\u2019 il caso \u00ABscrivi il codice fiscale e nome\r\n e cognome compaiono da soli\u00BB. L\u2019alternativa sarebbe spezzare la schermata in due con un\r\n elemento Action in mezzo.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (action of screenActions(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost\"\r\n [attr.aria-expanded]=\"selectedActionIndex() === $index\"\r\n (click)=\"selectAction(selectedActionIndex() === $index ? null : $index)\"\r\n >\r\n {{ selectedActionIndex() === $index ? '\u25BE' : '\u25B8' }}\r\n {{ action.name || '(senza nome)' }}\r\n </button>\r\n <span class=\"fb-list__spacer\"></span>\r\n <span class=\"fb-scr__side-hint\">{{ action.actionName || 'action non scelta' }}</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\u2019action\"\r\n (click)=\"removeScreenAction($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n @if (actionLosesResult(action)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questa action viene invocata ma il suo risultato si perde: aggiungi un parametro di\r\n uscita, oppure accendi l\u2019output automatico (SCREEN_ACTION_WITHOUT_OUTPUTS).\r\n </p>\r\n }\r\n @if (actionHasNoTrigger(action)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Nessun trigger la invoca: senza, non girera\u2019 mai.\r\n </p>\r\n }\r\n\r\n @if (selectedActionIndex() === $index) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Nome</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"action.name || ''\"\r\n (change)=\"setActionName($index, $any($event.target).value)\"\r\n />\r\n @if (actionNameError(action); as error) {\r\n <p class=\"fb-field__error\">{{ error }}</p>\r\n }\r\n <p class=\"fb-field__hint\">\r\n E\u2019 il nome con cui la citano i trigger, e vive nello spazio dei nomi del flow. Con\r\n l\u2019output automatico e\u2019 anche la radice del riferimento:\r\n <code>{{ action.name || 'Cerca' }}.NomeOutput</code>.\r\n </p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Tipo di action</label>\r\n <fb-name-picker\r\n [value]=\"action.actionType\"\r\n [options]=\"actionTypeOptions()\"\r\n label=\"Tipo di action\"\r\n placeholder=\"Scrivi o scegli un tipo\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo tipo di action non e\u2019 fra quelli dichiarati dal sistema ospite.\"\r\n emptyMessage=\"Catalogo dei tipi di action non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setActionType($index, $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Action</label>\r\n <fb-name-picker\r\n [value]=\"action.actionName\"\r\n [options]=\"actionOptions()\"\r\n label=\"Action\"\r\n placeholder=\"Scrivi o scegli un\u2019action\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questa action non esiste nel catalogo del tipo scelto: e\u2019 ACTION_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Scegli prima il tipo di action, oppure scrivi il nome a mano.\"\r\n (valueChange)=\"setActionTarget($index, $event ?? '')\"\r\n />\r\n @if (!action.actionName) {\r\n <p class=\"fb-field__error\">Obbligatoria: senza, ACTION_NAME_MISSING.</p>\r\n }\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"action.storeOutputAutomatically === true\"\r\n (change)=\"setActionStoreOutput($index, $any($event.target).checked)\"\r\n />\r\n Output automatico\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n L\u2019output automatico rende il risultato leggibile come\r\n <code>{{ action.name || 'Cerca' }}.NomeOutput</code>, ma\r\n <strong>non scrive in nessun campo</strong>: e\u2019 la forma da usare quando il risultato\r\n serve a una condizione, non a precompilare.\r\n </p>\r\n\r\n <!--\r\n L'unico posto in cui un campo di schermata e' una destinazione (\u00A75.2):\r\n `POST /flows/references/writable` continua a escluderlo, e un Assignment che ci\r\n scrive resta TARGET_NOT_WRITABLE.\r\n -->\r\n <fb-parameter-editor\r\n [holder]=\"action\"\r\n [catalogParameters]=\"actionParameterCatalog()\"\r\n [showOutputs]=\"action.storeOutputAutomatically !== true\"\r\n outputTitle=\"Campi da riempire\"\r\n [extraTargets]=\"screenFieldTargets()\"\r\n [outputsDisabledReason]=\"\r\n action.storeOutputAutomatically === true\r\n ? 'Con l\u2019output automatico il risultato non viene scritto nei campi.'\r\n : null\r\n \"\r\n (changed)=\"onActionParametersChanged($index, $event)\"\r\n />\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessuna action: i campi di questa schermata li compila solo l\u2019utente.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addScreenAction()\">Aggiungi action</button>\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Trigger</legend>\r\n <p class=\"fb-section__note\">\r\n Quale campo invoca quale action. Senza condizioni l\u2019action gira a ogni cambio del campo.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (trigger of screenTriggers(); 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 trigger\"\r\n (click)=\"removeScreenTrigger($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\">Action da invocare</label>\r\n <fb-name-picker\r\n [value]=\"trigger.screenActionName\"\r\n [options]=\"screenActionOptions()\"\r\n label=\"Action della schermata\"\r\n placeholder=\"Scegli un\u2019action\"\r\n unknownMessage=\"Questa schermata non dichiara un\u2019action con questo nome: e\u2019 SCREEN_ACTION_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Aggiungi prima un\u2019action qui sopra.\"\r\n (valueChange)=\"setTriggerProperty($index, 'screenActionName', $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo che la innesca</label>\r\n <!-- I campi di **questa** schermata, non i riferimenti in generale (\u00A75.2). -->\r\n <fb-name-picker\r\n [value]=\"trigger.triggerFieldName\"\r\n [options]=\"triggerFieldOptions()\"\r\n label=\"Campo della schermata\"\r\n placeholder=\"Scegli un campo\"\r\n unknownMessage=\"Questo non e\u2019 un campo di questa schermata: e\u2019 SCREEN_TRIGGER_FIELD_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"La schermata non ha ancora campi che raccolgono un valore.\"\r\n (valueChange)=\"setTriggerProperty($index, 'triggerFieldName', $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">All\u2019arrivo sulla schermata</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"trigger.initBehavior || ''\"\r\n (change)=\"setTriggerProperty($index, 'initBehavior', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 non invocare \u2014</option>\r\n <option value=\"runOnLoad\">Invoca al caricamento (runOnLoad)</option>\r\n </select>\r\n @if (triggerInitIsUnknown(trigger)) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ trigger.initBehavior }}\u00BB non e\u2019 ammesso: l\u2019unico valore e\u2019 <code>runOnLoad</code>\r\n (SCREEN_TRIGGER_INIT_BEHAVIOR_UNKNOWN).\r\n </p>\r\n }\r\n @if (triggerFiresOnLoadByDefault(trigger)) {\r\n <p class=\"fb-field__hint\">\r\n Non serve: \u00AB{{ trigger.triggerFieldName }}\u00BB ha un valore di default, e un campo\r\n precompilato dal flow innesca l\u2019action gi\u00E0 all\u2019arrivo sulla schermata.\r\n </p>\r\n }\r\n </div>\r\n\r\n @if (triggerHasNoCause(trigger)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Senza un campo che la innesca e senza l\u2019invocazione al caricamento, questo trigger non\r\n scattera\u2019 mai (SCREEN_TRIGGER_WITHOUT_CAUSE).\r\n </p>\r\n }\r\n\r\n <fb-condition-editor\r\n [holder]=\"triggerConditions(trigger)\"\r\n title=\"Invoca l\u2019action quando\"\r\n [allowFormula]=\"false\"\r\n [issuePath]=\"'triggers[' + $index + ']'\"\r\n (changed)=\"onTriggerConditionsChanged($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun trigger: le action dichiarate non verranno invocate.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addScreenTrigger()\">Aggiungi trigger</button>\r\n </fieldset>\r\n } @else {\r\n <!-- ---------------------------------------------------- proprieta' del campo -->\r\n <header class=\"fb-scr__props-head\">\r\n <h3 class=\"fb-scr__props-title\">{{ captionOf(selectedField()!) }}</h3>\r\n <div class=\"fb-scr__props-actions\">\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" title=\"Sposta su\" (click)=\"moveSelected(-1)\">\u2191</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" title=\"Sposta giu\u2019\" (click)=\"moveSelected(1)\">\u2193</button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--sm\"\r\n title=\"Porta fuori dal contenitore\"\r\n [disabled]=\"!canOutdent()\"\r\n (click)=\"outdentSelected()\"\r\n >\r\n \u21E4\r\n </button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" title=\"Duplica\" (click)=\"duplicateSelected()\">\u29C9</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--danger fb-btn--sm\" title=\"Elimina\" (click)=\"removeSelected()\">\r\n \u00D7\r\n </button>\r\n </div>\r\n </header>\r\n\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]=\"selectedField()!.fieldType || ''\"\r\n (change)=\"setFieldType($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of dictionary.screenFieldTypes(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.label }}</option>\r\n }\r\n </select>\r\n @if (!selectedField()!.fieldType) {\r\n <p class=\"fb-field__error\">Il tipo e\u2019 obbligatorio: senza, SCREEN_FIELD_TYPE_MISSING.</p>\r\n } @else if (isUnknownType(selectedField())) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Questo tipo non e\u2019 nel dizionario: l\u2019editor non sa quali campi ammetta e mostra solo i comuni.\r\n </p>\r\n } @else if (selectedType()?.description) {\r\n <p class=\"fb-field__hint\">{{ selectedType()?.description }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Nome</label>\r\n <!-- Sul `change` e non sull\u2019`input`: la rinomina riscrive i riferimenti nel documento,\r\n e farlo a ogni tasto significherebbe riscriverlo per ogni lettera. -->\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"selectedField()!.name || ''\"\r\n (change)=\"setFieldName($any($event.target).value)\"\r\n />\r\n @if (selectedIsResource()) {\r\n <p class=\"fb-field__hint\">\r\n Questo campo e\u2019 una <strong>risorsa</strong>: lo referenzi come\r\n <code>{{ selectedField()!.name || 'Nome' }}</code> in condizioni, formule e parametri. \u00C8 di\r\n sola lettura per il flow \u2014 un Assignment che ci scrive e\u2019 TARGET_NOT_WRITABLE.\r\n </p>\r\n }\r\n </div>\r\n\r\n @if (!selectedType()?.isContainer) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">\r\n {{ selectedField()!.fieldType === 'DisplayText' ? 'Testo' : 'Etichetta' }}\r\n </label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"selectedField()!.fieldText || ''\"\r\n (input)=\"setFieldProperty('fieldText', $any($event.target).value)\"\r\n ></textarea>\r\n <p class=\"fb-field__hint\">\r\n Supporta i merge field <code>{!Riferimento}</code>.\r\n @if (selectedField()!.fieldType === 'ComponentInstance') {\r\n <!--\r\n \u00A75.2 \u2014 su un componente l\u2019etichetta e\u2019 **ammessa** e viene consegnata al frontend\r\n in `label`, ma la sua assenza non e\u2019 un rilievo: un componente di solito disegna\r\n la propria intestazione. Nasconderla, come faceva prima l\u2019editor, toglieva un\r\n campo che il contratto prevede.\r\n -->\r\n Facoltativa: un componente di solito disegna la propria intestazione.\r\n }\r\n </p>\r\n </div>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Intestazione</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"selectedField()!.fieldText || ''\"\r\n (input)=\"setFieldProperty('fieldText', $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo di aiuto</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"selectedField()!.helpText || ''\"\r\n (input)=\"setFieldProperty('helpText', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Larghezza</label>\r\n <div class=\"fb-scr__width\">\r\n <input\r\n type=\"range\"\r\n min=\"1\"\r\n max=\"12\"\r\n step=\"1\"\r\n [value]=\"widthOf(selectedField()!)\"\r\n (input)=\"setNumberProperty('width', $any($event.target).value)\"\r\n />\r\n <span class=\"fb-scr__width-value\">{{ widthOf(selectedField()!) }}/12</span>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Colonne della griglia della schermata. \u00C8 un\u2019indicazione: il frontend puo\u2019 ignorarla.\r\n </p>\r\n </div>\r\n\r\n @if (selectedField()!.fieldType === 'ComponentInstance') {\r\n <!--\r\n \u00A75.2 \u2014 perche\u2019 qui non c\u2019e\u2019 \u00ABobbligatorio\u00BB. La domanda arriva sempre, e la risposta non\r\n si indovina guardando l\u2019interfaccia: un componente non ha un valore proprio, ce l\u2019hanno\r\n i suoi output, che vanno in **variabili** scelte dall\u2019autore. \u00ABObbligatorio\u00BB dovrebbe\r\n dire *quale output* deve essere valorizzato, e il metadata non ha modo di dirlo \u2014\r\n dichiararlo qui sarebbe `SCREEN_FIELD_CONFIGURATION_INVALID` e il runtime lo\r\n ignorerebbe. Le due strade vere stanno nel contratto e sono queste.\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Un componente non raccoglie un valore \u2014 lo fanno i suoi output \u2014 quindi obbligatorieta\u2019, valore\r\n predefinito e regola di validazione non si applicano: dichiararli e\u2019\r\n <code>SCREEN_FIELD_CONFIGURATION_INVALID</code> e il runtime li ignora. Per pretendere una\r\n compilazione: la validazione la fa il componente stesso, oppure si controlla la variabile di\r\n destinazione con una Decision dopo la schermata.\r\n </p>\r\n }\r\n\r\n <!-- ------------------------------------------------ campi che raccolgono un valore -->\r\n @if (selectedType()?.storesValue) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Valore</legend>\r\n\r\n @if (selectedField()!.fieldType !== 'ObjectProvided') {\r\n <div class=\"fb-field\">\r\n <label\r\n class=\"fb-field__label\"\r\n [class.fb-field__label--required]=\"!!selectedType()?.requiresDataType\"\r\n >\r\n Tipo di dato\r\n </label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.dataType || ''\"\r\n (change)=\"setFieldProperty('dataType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of dictionary.dataTypes(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.label }}</option>\r\n }\r\n </select>\r\n @if (selectedType()?.requiresDataType && !selectedField()!.dataType) {\r\n <p class=\"fb-field__error\">Obbligatorio per questo tipo di campo (DATA_TYPE_MISSING).</p>\r\n }\r\n @if (selectedType()?.isCollection) {\r\n <p class=\"fb-field__hint\">\r\n Il valore raccolto e\u2019 una <strong>collection</strong>, non una stringa con i valori\r\n separati: nelle condizioni si usano gli operatori di collection.\r\n </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\" [class.fb-field__label--required]=\"objectTypeIsStructure()\">\r\n {{\r\n objectTypeIsStructure()\r\n ? 'Classe'\r\n : selectedField()!.dataType === 'Enum'\r\n ? 'Tipo di enumerazione'\r\n : 'Oggetto'\r\n }}\r\n </label>\r\n @if (selectedField()!.dataType === 'Enum') {\r\n <!-- Dizionario chiuso: si sceglie, non si scrive. -->\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.objectType || ''\"\r\n (change)=\"setFieldProperty('objectType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of enumOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n </select>\r\n @if (!selectedField()!.objectType) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Senza il tipo concreto l\u2019editor non puo\u2019 proporre i valori dell\u2019enumerazione.\r\n </p>\r\n }\r\n } @else if (objectTypeIsStructure()) {\r\n <fb-structure-picker\r\n [value]=\"selectedField()!.objectType\"\r\n label=\"Classe\"\r\n (valueChange)=\"setFieldProperty('objectType', $event ?? '')\"\r\n />\r\n @if (!selectedField()!.objectType) {\r\n <p class=\"fb-field__error\">\r\n La classe e\u2019 obbligatoria: senza, il runtime non ha nulla da istanziare\r\n (OBJECT_TYPE_MISSING).\r\n </p>\r\n }\r\n } @else {\r\n <fb-object-picker\r\n [value]=\"selectedField()!.objectType\"\r\n label=\"Oggetto\"\r\n (valueChange)=\"setFieldProperty('objectType', $event ?? '')\"\r\n />\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo dell\u2019entita\u2019</label>\r\n <p class=\"fb-field__hint\">\r\n Tipo, label, obbligatorieta\u2019, scala e \u2014 se il campo e\u2019 una picklist \u2014 le opzioni arrivano\r\n dallo schema dati: qui non si ridichiarano.\r\n </p>\r\n <fb-object-picker\r\n [value]=\"providedObject() || undefined\"\r\n label=\"Oggetto\"\r\n (valueChange)=\"setProvidedObject($event)\"\r\n />\r\n <fb-field-picker\r\n [value]=\"providedField() || undefined\"\r\n [object]=\"providedObject() || undefined\"\r\n label=\"Campo\"\r\n (valueChange)=\"setProvidedField($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedIsRequired()\"\r\n (change)=\"setRequired($any($event.target).checked)\"\r\n />\r\n Obbligatorio\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedIsEditable()\"\r\n (change)=\"setEditable($any($event.target).checked)\"\r\n />\r\n Modificabile\r\n </label>\r\n @if (!selectedIsEditable()) {\r\n <p class=\"fb-field__hint\">\r\n A <code>false</code> il runtime <strong>ignora</strong> cio\u2019 che il client rimanda indietro:\r\n e\u2019 l\u2019unico modo di rendere un campo davvero di sola lettura.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore di default</label>\r\n <fb-value-editor\r\n [value]=\"selectedField()!.defaultValue\"\r\n [dataType]=\"selectedField()!.dataType\"\r\n [objectType]=\"selectedField()!.objectType\"\r\n [isCollection]=\"selectedType()?.isCollection\"\r\n label=\"Valore di default\"\r\n (valueChange)=\"setDefaultValue($event)\"\r\n />\r\n </div>\r\n\r\n @if (scaleApplies()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Decimali</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"0\"\r\n [value]=\"selectedField()!.scale ?? ''\"\r\n (change)=\"setNumberProperty('scale', $any($event.target).value)\"\r\n />\r\n </div>\r\n } @else if (selectedField()!.scale !== undefined) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n <code>scale</code> su un campo non numerico e\u2019 SCALE_NOT_APPLICABLE.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Lunghezza massima</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"selectedField()!.maxLength ?? ''\"\r\n (change)=\"setNumberProperty('maxLength', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">Verificata anche dal runtime (TOO_LONG).</p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Tornando sulla schermata</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.inputsOnNextNavToAssocScrn || ''\"\r\n (change)=\"setFieldProperty('inputsOnNextNavToAssocScrn', $any($event.target).value)\"\r\n >\r\n <option value=\"\">Predefinito (mantieni i valori)</option>\r\n @for (entry of dictionary.screenFieldInputsRevisited(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.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\">Regola di validazione</label>\r\n <!--\r\n `commitOn=\"change\"`: qui mutare il documento ridisegna l'anteprima, e riscriverla a\r\n ogni tasto costa. La verifica parte lo stesso mentre si digita (\u00A76.3).\r\n -->\r\n <fb-formula-editor\r\n [expression]=\"selectedField()!.validationRule?.formulaExpression || ''\"\r\n usage=\"ValidationRule\"\r\n expectedDataType=\"Boolean\"\r\n commitOn=\"change\"\r\n [rows]=\"2\"\r\n placeholder=\"Espressione, es. LEN(Nome) > 3\"\r\n ariaLabel=\"Regola di validazione\"\r\n (expressionChange)=\"setValidationRule('formulaExpression', $event)\"\r\n />\r\n <input\r\n class=\"fb-input\"\r\n placeholder=\"Messaggio mostrato quando l\u2019espressione e\u2019 falsa\"\r\n [value]=\"selectedField()!.validationRule?.errorMessage || ''\"\r\n (change)=\"setValidationRule('errorMessage', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n L\u2019espressione la valuta il motore di regole: il backend non la interpreta, la fa\r\n verificare al motore.\r\n </p>\r\n </div>\r\n </fieldset>\r\n }\r\n\r\n <!-- --------------------------------------------------------------- choice -->\r\n @if (selectedType()?.acceptsChoices) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Opzioni</legend>\r\n <p class=\"fb-section__note\">\r\n Accetta <strong>Choice</strong> e <strong>Dynamic choice set</strong>, nell\u2019ordine in cui le\r\n opzioni compaiono. Puntare a una variabile e\u2019 SCREEN_FIELD_CHOICE_UNKNOWN.\r\n </p>\r\n\r\n @if (!selectedField()!.choiceReferences?.length) {\r\n @if (selectedField()!.fieldType === 'ObjectProvided') {\r\n <!-- Le opzioni di una picklist arrivano dallo schema: qui si aggiungono solo se\r\n si vuole sostituirle, e non dichiararne nessuna e' il caso normale. -->\r\n <p class=\"fb-field__hint\">\r\n Se il campo dello schema e\u2019 una picklist, le opzioni arrivano da l\u00EC: dichiararle qui\r\n serve solo a sostituirle.\r\n </p>\r\n } @else {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Nessuna opzione: il campo non ha niente da mostrare (SCREEN_FIELD_CHOICES_MISSING).\r\n </p>\r\n }\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (choice of selectedField()!.choiceReferences || []; 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__title\">{{ choice }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" (click)=\"moveChoice($index, -1)\">\u2191</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" (click)=\"moveChoice($index, 1)\">\u2193</button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--sm\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeChoice($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Aggiungi un\u2019opzione</label>\r\n <!--\r\n `commitOn=\"enter\"`: qui ogni emissione e\u2019 una riga in piu\u2019, non un campo che cambia\r\n valore \u2014 a tasto, scrivere \u00ABAlta\u00BB aggiungeva \u00ABA\u00BB, \u00ABAl\u00BB, \u00ABAlt\u00BB e \u00ABAlta\u00BB.\r\n -->\r\n <fb-name-picker\r\n [options]=\"choiceOptions()\"\r\n label=\"Choice\"\r\n commitOn=\"enter\"\r\n placeholder=\"Scegli una choice o un choice set\"\r\n unknownMessage=\"Questo nome non e\u2019 una choice ne\u2019 un choice set: e\u2019 SCREEN_FIELD_CHOICE_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Il flow non dichiara nessuna choice: creale nel pannello delle risorse.\"\r\n (valueChange)=\"addChoice($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Scegli dall\u2019elenco, oppure scrivi il nome e premi Invio.\r\n </p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Opzione selezionata all\u2019apertura</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.defaultSelectedChoiceReference || ''\"\r\n (change)=\"setFieldProperty('defaultSelectedChoiceReference', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 nessuna \u2014</option>\r\n @for (choice of selectedField()!.choiceReferences || []; track $index) {\r\n <option [value]=\"choice\">{{ choice }}</option>\r\n }\r\n </select>\r\n @if (defaultChoiceIsForeign()) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n \u00AB{{ selectedField()!.defaultSelectedChoiceReference }}\u00BB non e\u2019 fra le opzioni elencate qui\r\n sopra.\r\n </p>\r\n }\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedAutoSelectsSingleChoice()\"\r\n (change)=\"setAutoSelectSingleChoice($any($event.target).checked)\"\r\n />\r\n Scegli da sola l\u2019unica opzione\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n Quando le opzioni risolte sono <strong>esattamente una</strong>, il campo la prende da se\u2019.\r\n Serve alle tendine che dipendono da un\u2019altra tendina \u2014 i CAP di un comune \u2014 dove chiedere\r\n di scegliere l\u2019unica voce non decide niente.\r\n </p>\r\n </fieldset>\r\n }\r\n\r\n <!-- ------------------------------------------------------- contenitori -->\r\n @if (selectedType()?.isContainer) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Contenitore</legend>\r\n @if (selectedField()!.fieldType === 'RegionContainer') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Tipo di sezione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.regionContainerType || ''\"\r\n (change)=\"setFieldProperty('regionContainerType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 predefinito \u2014</option>\r\n @for (entry of dictionary.regionContainerTypes(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n }\r\n @if (!selectedField()!.fields?.length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il contenitore e\u2019 vuoto: non produce niente sulla schermata (SCREEN_CONTAINER_EMPTY).\r\n </p>\r\n }\r\n </fieldset>\r\n }\r\n\r\n <!-- --------------------------------------------------- ComponentInstance -->\r\n @if (selectedField()!.fieldType === 'ComponentInstance') {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Componente</legend>\r\n <p class=\"fb-section__note\">\r\n Componenti e form sono la stessa domanda al frontend \u2014 cosa sa rendere, e con quali parametri\r\n \u2014 e passano dallo stesso catalogo. Un <code>ComponentInstance</code> non ha un valore proprio:\r\n lo hanno i suoi output.\r\n </p>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Componente</label>\r\n <fb-name-picker\r\n [value]=\"selectedField()!.extensionName\"\r\n [options]=\"componentOptions()\"\r\n [unusableOptions]=\"unusableComponents()\"\r\n label=\"Componente\"\r\n placeholder=\"Scrivi o scegli un componente\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo componente non esiste nel catalogo: e\u2019 SCREEN_COMPONENT_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n unusableMessage=\"Questo nome e\u2019 una schermata intera, non un componente montabile qui (FORM_KIND_MISMATCH).\"\r\n emptyMessage=\"Il catalogo dei componenti non e\u2019 popolato: il nome non viene verificato.\"\r\n (valueChange)=\"setFieldProperty('extensionName', $event ?? '')\"\r\n />\r\n @if (!selectedField()!.extensionName) {\r\n <p class=\"fb-field__error\">Obbligatorio: senza, SCREEN_COMPONENT_MISSING.</p>\r\n }\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedField()!.storeOutputAutomatically === true\"\r\n (change)=\"setStoreOutputAutomatically($any($event.target).checked)\"\r\n />\r\n Rendi gli output referenziabili automaticamente\r\n </label>\r\n @if (selectedField()!.storeOutputAutomatically) {\r\n <p class=\"fb-field__hint\">\r\n Gli output si referenziano come\r\n <code>{{ selectedField()!.name || 'Campo' }}.nomeOutput</code>, senza dichiarare variabili.\r\n </p>\r\n }\r\n @if (hasOutputConflict()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Output automatici <strong>e</strong> parametri di uscita insieme:\r\n OUTPUT_CONFIGURATION_CONFLICT.\r\n </p>\r\n }\r\n\r\n <fb-parameter-editor\r\n [holder]=\"$any(selectedField())\"\r\n [catalogParameters]=\"componentParameterList()\"\r\n inputTitle=\"Valori passati al componente\"\r\n outputTitle=\"Valori raccolti dal componente\"\r\n [showOutputs]=\"!selectedField()!.storeOutputAutomatically\"\r\n outputsDisabledReason=\"Gli output sono automatici: disattivalo per assegnarli a variabili.\"\r\n (changed)=\"onComponentParametersChanged($event)\"\r\n />\r\n </fieldset>\r\n }\r\n\r\n <!-- ------------------------------------------------------- visibilita' -->\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Visibilita\u2019</legend>\r\n <p class=\"fb-section__note\">\r\n Le regole si rivalutano <strong>sui valori appena inviati</strong>: e\u2019 cos\u00EC che un campo compare\r\n in funzione di un altro campo della stessa schermata. Un campo risultato nascosto viene\r\n <strong>azzerato</strong> e non viene validato.\r\n </p>\r\n <fb-condition-editor\r\n [holder]=\"visibilityRule()\"\r\n title=\"Mostra il campo quando\"\r\n [allowFormula]=\"false\"\r\n [issuePath]=\"'fields[' + (selectedField()!.name || '') + '].visibilityRule'\"\r\n (changed)=\"onVisibilityChanged($event)\"\r\n />\r\n </fieldset>\r\n }\r\n </aside>\r\n</div>\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\r\n<!--\r\n ============================================================== l'anteprima\r\n Due template ricorsivi. `listTpl` disegna i figli di un contenitore, e nient'altro: `data-item`\r\n marca cio' che conta come fratello nel calcolo del punto di rilascio, e il segnaposto del\r\n contenitore vuoto ne resta fuori. La barra di inserimento non e' qui \u2014 sta sopra l'anteprima,\r\n vedi il velo nel frame.\r\n-->\r\n<ng-template #listTpl let-fields let-parent=\"parent\" let-axis=\"axis\">\r\n @for (child of fields; track $index) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"fieldTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: child, path: childPath(parent, $index), axis: axis }\"\r\n />\r\n }\r\n @if (!fields.length) {\r\n <p class=\"fb-scr__drop-hint\">Trascina qui un componente</p>\r\n }\r\n</ng-template>\r\n\r\n<ng-template #fieldTpl let-field let-path=\"path\" let-axis=\"axis\">\r\n <div\r\n class=\"fb-scr__item\"\r\n data-item=\"\"\r\n cdkDrag\r\n [style.grid-column]=\"'span ' + widthOf(field)\"\r\n [class.fb-scr__item--selected]=\"isSelected(path)\"\r\n [class.fb-scr__item--dragging]=\"isDragging(path)\"\r\n [class.fb-scr__item--container]=\"isContainer(field)\"\r\n (cdkDragStarted)=\"onFieldDragStarted(path)\"\r\n (cdkDragMoved)=\"onFieldDragMoved($event)\"\r\n (cdkDragEnded)=\"onFieldDragEnded($event, path)\"\r\n (click)=\"select(path); $event.stopPropagation()\"\r\n >\r\n <span class=\"fb-scr__grip\" cdkDragHandle title=\"Trascina per spostare\" aria-hidden=\"true\">\u283F</span>\r\n @if (field.visibilityRule?.conditions?.length) {\r\n <span class=\"fb-scr__flag\" title=\"Ha una regola di visibilita\u2019\">\u25D0</span>\r\n }\r\n\r\n @switch (field.fieldType) {\r\n @case ('RegionContainer') {\r\n <div class=\"fb-scr__section\">\r\n @if (field.regionContainerType !== 'SectionWithoutHeader') {\r\n <header class=\"fb-scr__section-head\">{{ field.fieldText || field.name }}</header>\r\n }\r\n <div class=\"fb-scr__cols\" [attr.data-drop]=\"dropId(path)\" data-axis=\"row\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: field.fields || [], parent: path, axis: 'row' }\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case ('Region') {\r\n <div class=\"fb-scr__region\">\r\n <span class=\"fb-scr__region-tag\">{{ field.name }} \u00B7 {{ widthOf(field) }}/12</span>\r\n <div class=\"fb-scr__region-body\" [attr.data-drop]=\"dropId(path)\" data-axis=\"column\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: field.fields || [], parent: path, axis: 'column' }\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case ('DisplayText') {\r\n <p class=\"fb-scr__display\">{{ field.fieldText || '(testo vuoto)' }}</p>\r\n }\r\n @case ('LargeTextArea') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control fb-scr__control--area\">{{ placeholderOf(field) }}</div>\r\n }\r\n @case ('PasswordField') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control\">\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022</div>\r\n }\r\n @case ('DropdownBox') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control fb-scr__control--select\">\r\n <span>{{ field.defaultSelectedChoiceReference || choiceLabelsOf(field)[0] || '\u2014 scegli \u2014' }}</span>\r\n <span aria-hidden=\"true\">\u25BE</span>\r\n </div>\r\n }\r\n @case ('MultiSelectPicklist') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control fb-scr__control--select\">\r\n <span>{{ choiceLabelsOf(field).join(', ') || '\u2014 scegli \u2014' }}</span>\r\n <span aria-hidden=\"true\">\u2261</span>\r\n </div>\r\n }\r\n @case ('RadioButtons') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__options\">\r\n @for (option of choiceLabelsOf(field); track $index) {\r\n <span class=\"fb-scr__option\">\u25EF {{ option }}</span>\r\n }\r\n @if (!choiceLabelsOf(field).length) {\r\n <span class=\"fb-scr__option fb-scr__option--missing\">Nessuna opzione</span>\r\n }\r\n </div>\r\n }\r\n @case ('MultiSelectCheckboxes') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__options\">\r\n @for (option of choiceLabelsOf(field); track $index) {\r\n <span class=\"fb-scr__option\">\u2610 {{ option }}</span>\r\n }\r\n @if (!choiceLabelsOf(field).length) {\r\n <span class=\"fb-scr__option fb-scr__option--missing\">Nessuna opzione</span>\r\n }\r\n </div>\r\n }\r\n @case ('ComponentInstance') {\r\n <!--\r\n L\u2019etichetta si disegna se c\u2019e\u2019: il runtime la consegna in `label` come per gli altri\r\n campi (\u00A75.2). Nessun asterisco: un componente non raccoglie un valore, quindi\r\n \u00ABobbligatorio\u00BB non ha niente su cui applicarsi.\r\n -->\r\n @if (field.fieldText) {\r\n <label class=\"fb-scr__label\">{{ field.fieldText }}</label>\r\n }\r\n <div class=\"fb-scr__component\">\r\n <span aria-hidden=\"true\">\u2B21</span>\r\n {{ field.extensionName || 'Componente non indicato' }}\r\n </div>\r\n }\r\n @case ('ObjectProvided') {\r\n <label class=\"fb-scr__label\">\r\n {{ field.fieldText || field.objectFieldReference || field.name }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control\">{{ placeholderOf(field) }}</div>\r\n <span class=\"fb-scr__tag\">{{ field.objectFieldReference || 'campo non indicato' }}</span>\r\n }\r\n @default {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control\">{{ placeholderOf(field) }}</div>\r\n @if (isUnknownType(field)) {\r\n <span class=\"fb-scr__tag fb-scr__tag--warn\">{{ field.fieldType }}: tipo non nel dizionario</span>\r\n }\r\n }\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: [".fb-scr{display:grid;grid-template-columns:220px minmax(0,1fr) 340px;gap:12px;align-items:start;margin-bottom:14px}@media(max-width:1100px){.fb-scr{grid-template-columns:minmax(0,1fr)}}.fb-scr__side,.fb-scr__props{min-width:0;padding:10px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__tabs{display:flex;gap:4px;margin-bottom:8px}.fb-scr__tab{flex:1;padding:5px 8px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text-muted, #6b7086);font:inherit;font-size:11px;font-weight:600;cursor:pointer}.fb-scr__tab--active{border-color:var(--fb-accent, #4f6ef7);background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 10%,transparent);color:var(--fb-accent-strong, #3d59e0)}.fb-scr__side-hint,.fb-scr__side-empty{margin:6px 0;font-size:11px;color:var(--fb-text-muted, #6b7086)}.fb-scr__palette{display:flex;flex-direction:column;gap:4px;margin:8px 0 0;padding:0;max-height:320px;overflow-y:auto;overscroll-behavior:contain;list-style:none}.fb-scr__chip{display:flex;align-items:center;gap:8px;width:100%;padding:6px 8px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text, #1a1c23);font:inherit;font-size:12px;text-align:left;cursor:grab}.fb-scr__chip:hover{border-color:var(--fb-accent, #4f6ef7)}.fb-scr__chip-icon{flex:none;width:20px;text-align:center;color:var(--fb-text-muted, #6b7086)}.fb-scr__chip-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-scr__chip-label small{margin-left:4px;color:var(--fb-text-subtle, #98a2b3);font-size:10px}.fb-scr__canvas{min-width:0;padding:14px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-canvas-bg, #f4f5f7);max-height:60vh;overflow-y:auto}.fb-scr__frame{position:relative;display:flex;flex-direction:column;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-sm, 8px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));overflow:hidden}.fb-scr__frame-head{display:flex;align-items:center;gap:6px;padding:8px 12px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4);font-size:13px;font-weight:600}.fb-scr__help{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;border-radius:50%;background:var(--fb-surface-sunken, #eef0f4);color:var(--fb-text-muted, #6b7086);font-size:10px}.fb-scr__body,.fb-scr__region-body{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));align-content:start;gap:8px 0;padding:12px;min-height:90px}.fb-scr__region-body{padding:8px;min-height:60px}.fb-scr__cols{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));align-items:stretch;gap:0;padding:8px;min-height:60px}.fb-scr__cols>.fb-scr__item{display:flex;align-self:stretch}.fb-scr__cols>.fb-scr__item>.fb-scr__region{flex:1;min-width:0}.fb-scr__drop-hint{grid-column:1 / -1;margin:0;padding:10px;border:1px dashed var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);color:var(--fb-text-subtle, #98a2b3);font-size:11px;text-align:center}.fb-scr__marker{position:absolute;z-index:2;border-radius:2px;background:var(--fb-accent, #4f6ef7);pointer-events:none}.fb-scr__item{position:relative;box-sizing:border-box;padding:6px 8px;border:1px solid transparent;border-radius:var(--fb-radius-xs, 6px);cursor:pointer}.fb-scr__item:hover{border-color:var(--fb-border-strong, #cfd4de);background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 4%,transparent)}.fb-scr__item--selected{border-color:var(--fb-accent, #4f6ef7);box-shadow:inset 0 0 0 1px var(--fb-accent, #4f6ef7)}.fb-scr__item--dragging{opacity:.45;pointer-events:none}.fb-scr__grip{position:absolute;top:2px;left:-2px;padding:0 3px;color:var(--fb-text-subtle, #98a2b3);font-size:11px;line-height:1;opacity:0;cursor:grab}.fb-scr__item:hover>.fb-scr__grip,.fb-scr__item--selected>.fb-scr__grip{opacity:1}.fb-scr__flag{position:absolute;top:2px;right:4px;color:var(--fb-text-muted, #6b7086);font-size:11px}.fb-scr__label{display:block;margin-bottom:3px;font-size:11px;font-weight:600;color:var(--fb-text, #1a1c23)}.fb-scr__req{color:var(--fb-error, #dc2626)}.fb-scr__control{display:flex;align-items:center;justify-content:space-between;gap:6px;min-height:26px;padding:4px 8px;border:1px solid var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text-subtle, #98a2b3);font-size:12px;pointer-events:none}.fb-scr__control--area{min-height:54px;align-items:flex-start}.fb-scr__display{margin:0;font-size:12px;color:var(--fb-text, #1a1c23)}.fb-scr__options{display:flex;flex-direction:column;gap:2px;pointer-events:none}.fb-scr__option{font-size:12px;color:var(--fb-text-muted, #6b7086)}.fb-scr__option--missing{color:var(--fb-warning, #b7791f)}.fb-scr__component{display:flex;align-items:center;gap:6px;padding:10px;border:1px dashed var(--fb-accent, #4f6ef7);border-radius:var(--fb-radius-xs, 6px);background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 5%,transparent);font-size:12px;color:var(--fb-text-muted, #6b7086)}.fb-scr__tag{display:inline-block;margin-top:3px;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-scr__tag--warn{color:var(--fb-warning, #b7791f)}.fb-scr__section{border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__section-head{padding:5px 10px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--fb-text-muted, #6b7086)}.fb-scr__region{border:1px dashed var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff)}.fb-scr__region-tag{display:block;padding:3px 6px 0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-scr__frame-foot{display:flex;align-items:center;gap:6px;padding:8px 12px;border-top:1px solid var(--fb-border-subtle, #eef0f4);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__spacer{flex:1}.fb-scr__btn{padding:3px 10px;border:1px solid var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);font-size:11px;color:var(--fb-text-muted, #6b7086)}.fb-scr__btn--primary{border-color:var(--fb-accent, #4f6ef7);background:var(--fb-accent, #4f6ef7);color:var(--fb-accent-contrast, #fff)}.fb-scr__canvas-note{margin-top:10px}.fb-scr__props{background:var(--fb-surface, #fff)}.fb-scr__props-head{display:flex;align-items:center;gap:8px;margin-bottom:8px}.fb-scr__props-title{flex:1;min-width:0;margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--fb-text-muted, #6b7086)}.fb-scr__props-actions{display:flex;flex-wrap:wrap;gap:3px}.fb-btn--sm{padding:3px 7px;font-size:11px}.fb-scr__width{display:flex;align-items:center;gap:8px}.fb-scr__width input[type=range]{flex:1;min-width:0}.fb-scr__width-value{font-size:11px;color:var(--fb-text-muted, #6b7086)}\n"], dependencies: [{ kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { 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: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: FormulaEditorComponent, selector: "fb-formula-editor", inputs: ["expression", "usage", "expectedDataType", "scale", "placeholder", "ariaLabel", "disabled", "rows", "commitOn"], outputs: ["expressionChange"] }, { kind: "component", type: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ObjectPickerComponent, selector: "fb-object-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason", "extraTargets"], outputs: ["changed"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }, { kind: "component", type: StructurePickerComponent, selector: "fb-structure-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
12891
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: DynamicScreenInspectorComponent, isStandalone: true, selector: "fb-dynamic-screen-inspector", inputs: { initialSelection: { classPropertyName: "initialSelection", publicName: "initialSelection", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "composer", first: true, predicate: ["composer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"fb-scr\" #composer>\r\n <!-- ============================================================ sinistra -->\r\n <aside class=\"fb-scr__side\" aria-label=\"Componenti e campi\">\r\n <div class=\"fb-scr__tabs\" role=\"tablist\">\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"fb-scr__tab\"\r\n [class.fb-scr__tab--active]=\"paletteTab() === 'components'\"\r\n [attr.aria-selected]=\"paletteTab() === 'components'\"\r\n (click)=\"setPaletteTab('components')\"\r\n >\r\n Componenti\r\n </button>\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"fb-scr__tab\"\r\n [class.fb-scr__tab--active]=\"paletteTab() === 'fields'\"\r\n [attr.aria-selected]=\"paletteTab() === 'fields'\"\r\n (click)=\"setPaletteTab('fields')\"\r\n >\r\n Campi\r\n </button>\r\n </div>\r\n\r\n @if (paletteTab() === 'components') {\r\n @if (!dictionary.screenFieldTypes().length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il dizionario <code>screenFieldTypes</code> non e\u2019 disponibile: senza i suoi flag l\u2019editor non\r\n sa quali campi ammette ciascun tipo, e non li inventa.\r\n </p>\r\n }\r\n <p class=\"fb-scr__side-hint\">Trascina sulla schermata, oppure clicca per aggiungere.</p>\r\n <ul class=\"fb-scr__palette\">\r\n @for (entry of dictionary.screenFieldTypes(); track entry.value) {\r\n <li>\r\n <!--\r\n \u00A75.2 \u2014 l'unico chip che si spegne: una sezione ripetibile dentro un'altra. Non si\r\n annidano, e il cursore e' una variabile sola per sezione.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-scr__chip\"\r\n cdkDrag\r\n [disabled]=\"!canAddAtSelection(entry.value)\"\r\n [title]=\"\r\n canAddAtSelection(entry.value)\r\n ? entry.description || entry.label\r\n : 'Le sezioni ripetibili non si annidano: seleziona un punto fuori dalla riga.'\r\n \"\r\n (cdkDragMoved)=\"onPaletteDragMoved($event)\"\r\n (cdkDragEnded)=\"onComponentDragEnded($event, entry.value)\"\r\n (click)=\"addComponentAtSelection(entry.value)\"\r\n >\r\n <span class=\"fb-scr__chip-icon\" aria-hidden=\"true\">{{ iconOf(entry.value) }}</span>\r\n <span class=\"fb-scr__chip-label\">{{ entry.label }}</span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n } @else {\r\n <p class=\"fb-scr__side-hint\">\r\n Un campo dell\u2019entita\u2019 porta con se\u2019 tipo, etichetta, obbligatorieta\u2019 e opzioni: arrivano dallo\r\n schema dati, qui non si ridichiarano.\r\n </p>\r\n <!-- Il catalogo non e' un dizionario chiuso: si sceglie o si scrive, come ovunque si\r\n indichi un'entita' (vedi `object-picker`). -->\r\n <fb-object-picker\r\n [value]=\"fieldsObject()\"\r\n label=\"Entita\u2019\"\r\n placeholder=\"Scrivi o scegli un\u2019entita\u2019\"\r\n (valueChange)=\"setFieldsObject($event)\"\r\n />\r\n @if (fieldsObject() && !fieldsOfObject().length) {\r\n <p class=\"fb-scr__side-empty\">\r\n Nessun campo dichiarato per questa entita\u2019: il catalogo non li espone, non significa che non\r\n ci siano.\r\n </p>\r\n }\r\n <ul class=\"fb-scr__palette\">\r\n @for (field of fieldsOfObject(); track $index) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-scr__chip\"\r\n cdkDrag\r\n [title]=\"field.name + (field.dataType ? ' \u00B7 ' + field.dataType : '')\"\r\n (cdkDragMoved)=\"onPaletteDragMoved($event)\"\r\n (cdkDragEnded)=\"onObjectFieldDragEnded($event, field)\"\r\n (click)=\"addObjectFieldAtSelection(field)\"\r\n >\r\n <span class=\"fb-scr__chip-icon\" aria-hidden=\"true\">\u2317</span>\r\n <span class=\"fb-scr__chip-label\">\r\n {{ field.label || field.name }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n <small>{{ field.dataType }}</small>\r\n </span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n </aside>\r\n\r\n <!-- ============================================================== centro -->\r\n <!-- Cliccare fuori da un campo riporta a destra le proprieta' della schermata. -->\r\n <section class=\"fb-scr__canvas\" aria-label=\"Anteprima della schermata\" (click)=\"selectScreen()\">\r\n <div class=\"fb-scr__frame\">\r\n @if (showHeader()) {\r\n <header class=\"fb-scr__frame-head\">\r\n {{ $any(node()).label || name() }}\r\n @if (screen().helpText) {\r\n <span class=\"fb-scr__help\" [title]=\"screen().helpText || ''\">?</span>\r\n }\r\n </header>\r\n }\r\n\r\n <div\r\n class=\"fb-scr__body\"\r\n [attr.data-drop]=\"''\"\r\n data-axis=\"column\"\r\n [class.fb-scr__body--empty]=\"isEmpty()\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: screen().fields || [], parent: [], axis: 'column' }\"\r\n />\r\n </div>\r\n\r\n <!--\r\n La barra di inserimento e' un **velo** sopra l'anteprima, non un figlio del contenitore di\r\n rilascio: dentro la griglia occupava una riga intera e spostava in basso proprio la sezione\r\n che si stava puntando, che allora usciva da sotto il puntatore e il bersaglio oscillava.\r\n -->\r\n @if (dropMarker(); as bar) {\r\n <div\r\n class=\"fb-scr__marker\"\r\n [style.left.px]=\"bar.left\"\r\n [style.top.px]=\"bar.top\"\r\n [style.width.px]=\"bar.width\"\r\n [style.height.px]=\"bar.height\"\r\n ></div>\r\n }\r\n\r\n @if (showFooter()) {\r\n <footer class=\"fb-scr__frame-foot\">\r\n @if (allowPause()) {\r\n <span class=\"fb-scr__btn fb-scr__btn--ghost\">{{ screen().pauseButtonLabel || 'Pausa' }}</span>\r\n }\r\n <span class=\"fb-scr__spacer\"></span>\r\n @if (allowBack()) {\r\n <span class=\"fb-scr__btn fb-scr__btn--ghost\">{{ screen().backButtonLabel || 'Indietro' }}</span>\r\n }\r\n <span class=\"fb-scr__btn fb-scr__btn--primary\">\r\n {{ screen().nextOrFinishButtonLabel || (allowFinish() ? 'Fine' : 'Avanti') }}\r\n </span>\r\n </footer>\r\n }\r\n </div>\r\n\r\n @if (isEmpty()) {\r\n <p class=\"fb-callout fb-callout--warn fb-scr__canvas-note\">\r\n La schermata non ha campi: non c\u2019e\u2019 niente da mostrare all\u2019utente (SCREEN_WITHOUT_FIELDS).\r\n </p>\r\n }\r\n </section>\r\n\r\n <!-- ============================================================== destra -->\r\n <aside class=\"fb-scr__props\" aria-label=\"Proprieta\u2019\">\r\n @if (!selectedField()) {\r\n <!-- ------------------------------------------------ proprieta' della schermata -->\r\n <header class=\"fb-scr__props-head\">\r\n <h3 class=\"fb-scr__props-title\">Schermata</h3>\r\n </header>\r\n <p class=\"fb-scr__side-hint\">Seleziona un campo nell\u2019anteprima per configurarlo.</p>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo di aiuto</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"screen().helpText || ''\"\r\n (input)=\"setScreenText('helpText', $any($event.target).value)\"\r\n ></textarea>\r\n </div>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Navigazione</legend>\r\n <p class=\"fb-section__note\">\r\n Questi flag sono un\u2019intenzione, non la verita\u2019 finale: a runtime il motore comunica\r\n <code>canGoBack</code>, <code>canFinish</code> e <code>canPause</code> nella richiesta della\r\n schermata.\r\n </p>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowBack()\" (change)=\"setScreenFlag('allowBack', $any($event.target).checked)\" />\r\n Consenti \u00ABindietro\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowFinish()\" (change)=\"setScreenFlag('allowFinish', $any($event.target).checked)\" />\r\n Consenti \u00ABfine\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowPause()\" (change)=\"setScreenFlag('allowPause', $any($event.target).checked)\" />\r\n Consenti \u00ABpausa\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"showHeader()\" (change)=\"setScreenFlag('showHeader', $any($event.target).checked)\" />\r\n Mostra l\u2019intestazione\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"showFooter()\" (change)=\"setScreenFlag('showFooter', $any($event.target).checked)\" />\r\n Mostra il piede\r\n </label>\r\n\r\n @if (allowPause()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo mostrato alla pausa</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().pausedText || ''\"\r\n (input)=\"setScreenText('pausedText', $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (isDeadEnd()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Questa schermata non ha una destinazione e non consente \u00ABfine\u00BB: e\u2019 un vicolo cieco, e\r\n l\u2019utente resterebbe bloccato (SCREEN_DEAD_END).\r\n </p>\r\n }\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Pulsanti</legend>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta \u00ABindietro\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().backButtonLabel || ''\"\r\n (input)=\"setScreenText('backButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta \u00ABavanti / fine\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().nextOrFinishButtonLabel || ''\"\r\n (input)=\"setScreenText('nextOrFinishButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta \u00ABpausa\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().pauseButtonLabel || ''\"\r\n (input)=\"setScreenText('pauseButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n </fieldset>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Stage mostrato nell\u2019avanzamento</label>\r\n <fb-name-picker\r\n [value]=\"screen().stageReference\"\r\n [options]=\"stageOptions()\"\r\n label=\"Stage\"\r\n placeholder=\"Scegli uno stage\"\r\n unknownMessage=\"Questo stage non e\u2019 dichiarato dal flow.\"\r\n emptyMessage=\"Il flow non dichiara stage: creali nel pannello delle risorse.\"\r\n (valueChange)=\"setScreenText('stageReference', $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <!--\r\n Screen action (\u00A75.2). Due elenchi e non uno perche' il contratto li separa: piu' trigger\r\n possono invocare la stessa action, quindi \u00ABchi la chiama\u00BB non e' una sua proprieta'. Le\r\n action si aprono una alla volta: i cataloghi dipendono da tipo e nome, e tenerne N in volo\r\n sarebbe N volte la corsa fra risposte.\r\n -->\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Azioni della schermata</legend>\r\n <p class=\"fb-section__note\">\r\n Un campo che l\u2019utente compila puo\u2019 innescare un\u2019action i cui risultati finiscono negli\r\n <strong>altri campi di questa schermata</strong>: e\u2019 il caso \u00ABscrivi il codice fiscale e nome\r\n e cognome compaiono da soli\u00BB. L\u2019alternativa sarebbe spezzare la schermata in due con un\r\n elemento Action in mezzo.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (action of screenActions(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost\"\r\n [attr.aria-expanded]=\"selectedActionIndex() === $index\"\r\n (click)=\"selectAction(selectedActionIndex() === $index ? null : $index)\"\r\n >\r\n {{ selectedActionIndex() === $index ? '\u25BE' : '\u25B8' }}\r\n {{ action.name || '(senza nome)' }}\r\n </button>\r\n <span class=\"fb-list__spacer\"></span>\r\n <span class=\"fb-scr__side-hint\">{{ action.actionName || 'action non scelta' }}</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\u2019action\"\r\n (click)=\"removeScreenAction($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n @if (actionLosesResult(action)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questa action viene invocata ma il suo risultato si perde: aggiungi un parametro di\r\n uscita, oppure accendi l\u2019output automatico (SCREEN_ACTION_WITHOUT_OUTPUTS).\r\n </p>\r\n }\r\n @if (actionHasNoTrigger(action)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Nessun trigger la invoca: senza, non girera\u2019 mai.\r\n </p>\r\n }\r\n\r\n @if (selectedActionIndex() === $index) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Nome</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"action.name || ''\"\r\n (change)=\"setActionName($index, $any($event.target).value)\"\r\n />\r\n @if (actionNameError(action); as error) {\r\n <p class=\"fb-field__error\">{{ error }}</p>\r\n }\r\n <p class=\"fb-field__hint\">\r\n E\u2019 il nome con cui la citano i trigger, e vive nello spazio dei nomi del flow. Con\r\n l\u2019output automatico e\u2019 anche la radice del riferimento:\r\n <code>{{ action.name || 'Cerca' }}.NomeOutput</code>.\r\n </p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Tipo di action</label>\r\n <fb-name-picker\r\n [value]=\"action.actionType\"\r\n [options]=\"actionTypeOptions()\"\r\n label=\"Tipo di action\"\r\n placeholder=\"Scrivi o scegli un tipo\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo tipo di action non e\u2019 fra quelli dichiarati dal sistema ospite.\"\r\n emptyMessage=\"Catalogo dei tipi di action non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setActionType($index, $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Action</label>\r\n <fb-name-picker\r\n [value]=\"action.actionName\"\r\n [options]=\"actionOptions()\"\r\n label=\"Action\"\r\n placeholder=\"Scrivi o scegli un\u2019action\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questa action non esiste nel catalogo del tipo scelto: e\u2019 ACTION_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Scegli prima il tipo di action, oppure scrivi il nome a mano.\"\r\n (valueChange)=\"setActionTarget($index, $event ?? '')\"\r\n />\r\n @if (!action.actionName) {\r\n <p class=\"fb-field__error\">Obbligatoria: senza, ACTION_NAME_MISSING.</p>\r\n }\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"action.storeOutputAutomatically === true\"\r\n (change)=\"setActionStoreOutput($index, $any($event.target).checked)\"\r\n />\r\n Output automatico\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n L\u2019output automatico rende il risultato leggibile come\r\n <code>{{ action.name || 'Cerca' }}.NomeOutput</code>, ma\r\n <strong>non scrive in nessun campo</strong>: e\u2019 la forma da usare quando il risultato\r\n serve a una condizione, non a precompilare.\r\n </p>\r\n\r\n <!--\r\n L'unico posto in cui un campo di schermata e' una destinazione (\u00A75.2):\r\n `POST /flows/references/writable` continua a escluderlo, e un Assignment che ci\r\n scrive resta TARGET_NOT_WRITABLE.\r\n -->\r\n <fb-parameter-editor\r\n [holder]=\"action\"\r\n [catalogParameters]=\"actionParameterCatalog()\"\r\n [showOutputs]=\"action.storeOutputAutomatically !== true\"\r\n outputTitle=\"Campi da riempire\"\r\n [extraTargets]=\"screenFieldTargets()\"\r\n [outputsDisabledReason]=\"\r\n action.storeOutputAutomatically === true\r\n ? 'Con l\u2019output automatico il risultato non viene scritto nei campi.'\r\n : null\r\n \"\r\n (changed)=\"onActionParametersChanged($index, $event)\"\r\n />\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessuna action: i campi di questa schermata li compila solo l\u2019utente.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addScreenAction()\">Aggiungi action</button>\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Trigger</legend>\r\n <p class=\"fb-section__note\">\r\n Quale campo invoca quale action. Senza condizioni l\u2019action gira a ogni cambio del campo.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (trigger of screenTriggers(); 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 trigger\"\r\n (click)=\"removeScreenTrigger($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\">Action da invocare</label>\r\n <fb-name-picker\r\n [value]=\"trigger.screenActionName\"\r\n [options]=\"screenActionOptions()\"\r\n label=\"Action della schermata\"\r\n placeholder=\"Scegli un\u2019action\"\r\n unknownMessage=\"Questa schermata non dichiara un\u2019action con questo nome: e\u2019 SCREEN_ACTION_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Aggiungi prima un\u2019action qui sopra.\"\r\n (valueChange)=\"setTriggerProperty($index, 'screenActionName', $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo che la innesca</label>\r\n <!-- I campi di **questa** schermata, non i riferimenti in generale (\u00A75.2). -->\r\n <fb-name-picker\r\n [value]=\"trigger.triggerFieldName\"\r\n [options]=\"triggerFieldOptions()\"\r\n label=\"Campo della schermata\"\r\n placeholder=\"Scegli un campo\"\r\n unknownMessage=\"Questo non e\u2019 un campo di questa schermata: e\u2019 SCREEN_TRIGGER_FIELD_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"La schermata non ha ancora campi che raccolgono un valore.\"\r\n (valueChange)=\"setTriggerProperty($index, 'triggerFieldName', $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">All\u2019arrivo sulla schermata</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"trigger.initBehavior || ''\"\r\n (change)=\"setTriggerProperty($index, 'initBehavior', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 non invocare \u2014</option>\r\n <option value=\"runOnLoad\">Invoca al caricamento (runOnLoad)</option>\r\n </select>\r\n @if (triggerInitIsUnknown(trigger)) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ trigger.initBehavior }}\u00BB non e\u2019 ammesso: l\u2019unico valore e\u2019 <code>runOnLoad</code>\r\n (SCREEN_TRIGGER_INIT_BEHAVIOR_UNKNOWN).\r\n </p>\r\n }\r\n @if (triggerFiresOnLoadByDefault(trigger)) {\r\n <p class=\"fb-field__hint\">\r\n Non serve: \u00AB{{ trigger.triggerFieldName }}\u00BB ha un valore di default, e un campo\r\n precompilato dal flow innesca l\u2019action gi\u00E0 all\u2019arrivo sulla schermata.\r\n </p>\r\n }\r\n </div>\r\n\r\n @if (triggerHasNoCause(trigger)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Senza un campo che la innesca e senza l\u2019invocazione al caricamento, questo trigger non\r\n scattera\u2019 mai (SCREEN_TRIGGER_WITHOUT_CAUSE).\r\n </p>\r\n }\r\n\r\n <fb-condition-editor\r\n [holder]=\"triggerConditions(trigger)\"\r\n title=\"Invoca l\u2019action quando\"\r\n [allowFormula]=\"false\"\r\n [issuePath]=\"'triggers[' + $index + ']'\"\r\n (changed)=\"onTriggerConditionsChanged($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun trigger: le action dichiarate non verranno invocate.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addScreenTrigger()\">Aggiungi trigger</button>\r\n </fieldset>\r\n } @else {\r\n <!-- ---------------------------------------------------- proprieta' del campo -->\r\n <header class=\"fb-scr__props-head\">\r\n <h3 class=\"fb-scr__props-title\">{{ captionOf(selectedField()!) }}</h3>\r\n <div class=\"fb-scr__props-actions\">\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" title=\"Sposta su\" (click)=\"moveSelected(-1)\">\u2191</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" title=\"Sposta giu\u2019\" (click)=\"moveSelected(1)\">\u2193</button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--sm\"\r\n title=\"Porta fuori dal contenitore\"\r\n [disabled]=\"!canOutdent()\"\r\n (click)=\"outdentSelected()\"\r\n >\r\n \u21E4\r\n </button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" title=\"Duplica\" (click)=\"duplicateSelected()\">\u29C9</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--danger fb-btn--sm\" title=\"Elimina\" (click)=\"removeSelected()\">\r\n \u00D7\r\n </button>\r\n </div>\r\n </header>\r\n\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]=\"selectedField()!.fieldType || ''\"\r\n (change)=\"setFieldType($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n <!--\r\n \u00A75.2 \u2014 dentro una riga la sezione ripetibile non c'e': **non si annidano**, perche' il\r\n cursore e' una variabile sola per sezione. La validazione lo rifiuterebbe comunque, ma\r\n lasciar comporre e poi accusare fa perdere tempo due volte.\r\n -->\r\n @for (entry of fieldTypeOptions(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.label }}</option>\r\n }\r\n </select>\r\n @if (isInsideRepeater()) {\r\n <p class=\"fb-field__hint\">\r\n Questo campo sta dentro la riga di <code>{{ selectedRepeater()!.name }}</code>: esiste una\r\n volta per ogni elemento della collection, quindi\r\n <strong>non e\u2019 una risorsa del flow</strong> e non si nomina per nome. Dentro una riga si\r\n nomina il cursore \u2014\r\n <code>{{ rowCursor() || 'itemReference' }}.<membro></code> \u2014 e scrivere\r\n <code>{{ selectedField()!.name }}</code> in una condizione, in una formula o in un parametro\r\n e\u2019 <code>SCREEN_FIELD_IN_REPEATER</code>.\r\n </p>\r\n }\r\n @if (!selectedField()!.fieldType) {\r\n <p class=\"fb-field__error\">Il tipo e\u2019 obbligatorio: senza, SCREEN_FIELD_TYPE_MISSING.</p>\r\n } @else if (isUnknownType(selectedField())) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Questo tipo non e\u2019 nel dizionario: l\u2019editor non sa quali campi ammetta e mostra solo i comuni.\r\n </p>\r\n } @else if (selectedType()?.description) {\r\n <p class=\"fb-field__hint\">{{ selectedType()?.description }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Nome</label>\r\n <!-- Sul `change` e non sull\u2019`input`: la rinomina riscrive i riferimenti nel documento,\r\n e farlo a ogni tasto significherebbe riscriverlo per ogni lettera. -->\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"selectedField()!.name || ''\"\r\n (change)=\"setFieldName($any($event.target).value)\"\r\n />\r\n @if (selectedIsResource() && !isInsideRepeater()) {\r\n <p class=\"fb-field__hint\">\r\n Questo campo e\u2019 una <strong>risorsa</strong>: lo referenzi come\r\n <code>{{ selectedField()!.name || 'Nome' }}</code> in condizioni, formule e parametri. \u00C8 di\r\n sola lettura per il flow \u2014 un Assignment che ci scrive e\u2019 TARGET_NOT_WRITABLE.\r\n </p>\r\n } @else if (isInsideRepeater()) {\r\n <p class=\"fb-field__hint\">\r\n Il nome resta comunque <strong>unico</strong>: e\u2019 l\u2019indirizzo con cui il frontend rende il\r\n campo, e un omonimo di una variabile e\u2019 <code>NAME_DUPLICATED</code> come sempre.\r\n </p>\r\n }\r\n </div>\r\n\r\n <!--\r\n \u00A75.2 \u2014 `memberName` e il riferimento con cui gli altri campi lo nominano sono la **stessa\r\n domanda posta due volte**: `memberName: \"PodId\"` e `PuntoCorrente.PodId` sono lo stesso\r\n membro, e la classe da cui vengono e' l'`objectType` della variabile in `collectionReference`.\r\n -->\r\n @if (isInsideRepeater() && selectedType()?.storesValue) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Membro della riga</label>\r\n @if (rowClass()) {\r\n <fb-structure-member-picker\r\n [value]=\"selectedField()!.memberName\"\r\n [className]=\"rowClass()\"\r\n usage=\"writable\"\r\n label=\"Membro della riga\"\r\n (valueChange)=\"setFieldProperty('memberName', $event ?? '')\"\r\n />\r\n } @else {\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"selectedField()!.memberName || ''\"\r\n (change)=\"setFieldProperty('memberName', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n La classe delle righe non e\u2019 nota: la sezione non dichiara una <code>collectionReference</code>\r\n valida, quindi i membri non si possono proporre.\r\n </p>\r\n }\r\n <p class=\"fb-field__hint\">\r\n Il membro della riga in cui finisce il valore. Senza, vale il nome del campo. Dentro una\r\n riga lo si legge come\r\n <code>{{ rowCursor() || 'itemReference' }}.{{ selectedField()!.memberName || selectedField()!.name }}</code>.\r\n </p>\r\n </div>\r\n }\r\n\r\n <!--\r\n Il ramo dei contenitori vale anche per una sezione ripetibile: l\u00EC `fieldText` e'\r\n l'intestazione del blocco, non l'etichetta di un valore \u2014 l'etichetta della **riga** e'\r\n `itemLabel`, ed e' un campo suo, piu' sotto (\u00A75.2).\r\n -->\r\n @if (!holdsFields(selectedField())) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">\r\n {{ selectedField()!.fieldType === 'DisplayText' ? 'Testo' : 'Etichetta' }}\r\n </label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"selectedField()!.fieldText || ''\"\r\n (input)=\"setFieldProperty('fieldText', $any($event.target).value)\"\r\n ></textarea>\r\n <p class=\"fb-field__hint\">\r\n Supporta i merge field <code>{!Riferimento}</code>.\r\n @if (selectedField()!.fieldType === 'ComponentInstance') {\r\n <!--\r\n \u00A75.2 \u2014 su un componente l\u2019etichetta e\u2019 **ammessa** e viene consegnata al frontend\r\n in `label`, ma la sua assenza non e\u2019 un rilievo: un componente di solito disegna\r\n la propria intestazione. Nasconderla, come faceva prima l\u2019editor, toglieva un\r\n campo che il contratto prevede.\r\n -->\r\n Facoltativa: un componente di solito disegna la propria intestazione.\r\n }\r\n </p>\r\n </div>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Intestazione</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"selectedField()!.fieldText || ''\"\r\n (input)=\"setFieldProperty('fieldText', $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo di aiuto</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"selectedField()!.helpText || ''\"\r\n (input)=\"setFieldProperty('helpText', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Larghezza</label>\r\n <div class=\"fb-scr__width\">\r\n <input\r\n type=\"range\"\r\n min=\"1\"\r\n max=\"12\"\r\n step=\"1\"\r\n [value]=\"widthOf(selectedField()!)\"\r\n (input)=\"setNumberProperty('width', $any($event.target).value)\"\r\n />\r\n <span class=\"fb-scr__width-value\">{{ widthOf(selectedField()!) }}/12</span>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Colonne della griglia della schermata. \u00C8 un\u2019indicazione: il frontend puo\u2019 ignorarla.\r\n </p>\r\n </div>\r\n\r\n @if (selectedField()!.fieldType === 'ComponentInstance') {\r\n <!--\r\n \u00A75.2 \u2014 perche\u2019 qui non c\u2019e\u2019 \u00ABobbligatorio\u00BB. La domanda arriva sempre, e la risposta non\r\n si indovina guardando l\u2019interfaccia: un componente non ha un valore proprio, ce l\u2019hanno\r\n i suoi output, che vanno in **variabili** scelte dall\u2019autore. \u00ABObbligatorio\u00BB dovrebbe\r\n dire *quale output* deve essere valorizzato, e il metadata non ha modo di dirlo \u2014\r\n dichiararlo qui sarebbe `SCREEN_FIELD_CONFIGURATION_INVALID` e il runtime lo\r\n ignorerebbe. Le due strade vere stanno nel contratto e sono queste.\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Un componente non raccoglie un valore \u2014 lo fanno i suoi output \u2014 quindi obbligatorieta\u2019, valore\r\n predefinito e regola di validazione non si applicano: dichiararli e\u2019\r\n <code>SCREEN_FIELD_CONFIGURATION_INVALID</code> e il runtime li ignora. Per pretendere una\r\n compilazione: la validazione la fa il componente stesso, oppure si controlla la variabile di\r\n destinazione con una Decision dopo la schermata.\r\n </p>\r\n }\r\n\r\n <!-- ------------------------------------------------ campi che raccolgono un valore -->\r\n @if (selectedType()?.storesValue) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Valore</legend>\r\n\r\n @if (selectedField()!.fieldType !== 'ObjectProvided') {\r\n <div class=\"fb-field\">\r\n <label\r\n class=\"fb-field__label\"\r\n [class.fb-field__label--required]=\"!!selectedType()?.requiresDataType\"\r\n >\r\n Tipo di dato\r\n </label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.dataType || ''\"\r\n (change)=\"setFieldProperty('dataType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of dictionary.dataTypes(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.label }}</option>\r\n }\r\n </select>\r\n @if (selectedType()?.requiresDataType && !selectedField()!.dataType) {\r\n <p class=\"fb-field__error\">Obbligatorio per questo tipo di campo (DATA_TYPE_MISSING).</p>\r\n }\r\n @if (selectedType()?.isCollection) {\r\n <p class=\"fb-field__hint\">\r\n Il valore raccolto e\u2019 una <strong>collection</strong>, non una stringa con i valori\r\n separati: nelle condizioni si usano gli operatori di collection.\r\n </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\" [class.fb-field__label--required]=\"objectTypeIsStructure()\">\r\n {{\r\n objectTypeIsStructure()\r\n ? 'Classe'\r\n : selectedField()!.dataType === 'Enum'\r\n ? 'Tipo di enumerazione'\r\n : 'Oggetto'\r\n }}\r\n </label>\r\n @if (selectedField()!.dataType === 'Enum') {\r\n <!-- Dizionario chiuso: si sceglie, non si scrive. -->\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.objectType || ''\"\r\n (change)=\"setFieldProperty('objectType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of enumOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n </select>\r\n @if (!selectedField()!.objectType) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Senza il tipo concreto l\u2019editor non puo\u2019 proporre i valori dell\u2019enumerazione.\r\n </p>\r\n }\r\n } @else if (objectTypeIsStructure()) {\r\n <fb-structure-picker\r\n [value]=\"selectedField()!.objectType\"\r\n label=\"Classe\"\r\n (valueChange)=\"setFieldProperty('objectType', $event ?? '')\"\r\n />\r\n @if (!selectedField()!.objectType) {\r\n <p class=\"fb-field__error\">\r\n La classe e\u2019 obbligatoria: senza, il runtime non ha nulla da istanziare\r\n (OBJECT_TYPE_MISSING).\r\n </p>\r\n }\r\n } @else {\r\n <fb-object-picker\r\n [value]=\"selectedField()!.objectType\"\r\n label=\"Oggetto\"\r\n (valueChange)=\"setFieldProperty('objectType', $event ?? '')\"\r\n />\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo dell\u2019entita\u2019</label>\r\n <p class=\"fb-field__hint\">\r\n Tipo, label, obbligatorieta\u2019, scala e \u2014 se il campo e\u2019 una picklist \u2014 le opzioni arrivano\r\n dallo schema dati: qui non si ridichiarano.\r\n </p>\r\n <fb-object-picker\r\n [value]=\"providedObject() || undefined\"\r\n label=\"Oggetto\"\r\n (valueChange)=\"setProvidedObject($event)\"\r\n />\r\n <fb-field-picker\r\n [value]=\"providedField() || undefined\"\r\n [object]=\"providedObject() || undefined\"\r\n label=\"Campo\"\r\n (valueChange)=\"setProvidedField($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedIsRequired()\"\r\n (change)=\"setRequired($any($event.target).checked)\"\r\n />\r\n Obbligatorio\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedIsEditable()\"\r\n (change)=\"setEditable($any($event.target).checked)\"\r\n />\r\n Modificabile\r\n </label>\r\n @if (!selectedIsEditable()) {\r\n <p class=\"fb-field__hint\">\r\n A <code>false</code> il runtime <strong>ignora</strong> cio\u2019 che il client rimanda indietro:\r\n e\u2019 l\u2019unico modo di rendere un campo davvero di sola lettura.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore di default</label>\r\n <fb-value-editor\r\n [value]=\"selectedField()!.defaultValue\"\r\n [dataType]=\"selectedField()!.dataType\"\r\n [objectType]=\"selectedField()!.objectType\"\r\n [isCollection]=\"selectedType()?.isCollection\"\r\n [preferredRoots]=\"preferredRoots()\"\r\n label=\"Valore di default\"\r\n (valueChange)=\"setDefaultValue($event)\"\r\n />\r\n </div>\r\n\r\n @if (scaleApplies()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Decimali</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"0\"\r\n [value]=\"selectedField()!.scale ?? ''\"\r\n (change)=\"setNumberProperty('scale', $any($event.target).value)\"\r\n />\r\n </div>\r\n } @else if (selectedField()!.scale !== undefined) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n <code>scale</code> su un campo non numerico e\u2019 SCALE_NOT_APPLICABLE.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Lunghezza massima</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"selectedField()!.maxLength ?? ''\"\r\n (change)=\"setNumberProperty('maxLength', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">Verificata anche dal runtime (TOO_LONG).</p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Tornando sulla schermata</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.inputsOnNextNavToAssocScrn || ''\"\r\n (change)=\"setFieldProperty('inputsOnNextNavToAssocScrn', $any($event.target).value)\"\r\n >\r\n <option value=\"\">Predefinito (mantieni i valori)</option>\r\n @for (entry of dictionary.screenFieldInputsRevisited(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.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\">Regola di validazione</label>\r\n <!--\r\n `commitOn=\"change\"`: qui mutare il documento ridisegna l'anteprima, e riscriverla a\r\n ogni tasto costa. La verifica parte lo stesso mentre si digita (\u00A76.3).\r\n -->\r\n <fb-formula-editor\r\n [expression]=\"selectedField()!.validationRule?.formulaExpression || ''\"\r\n usage=\"ValidationRule\"\r\n expectedDataType=\"Boolean\"\r\n commitOn=\"change\"\r\n [preferredRoots]=\"preferredRoots()\"\r\n [rows]=\"2\"\r\n placeholder=\"Espressione, es. LEN(Nome) > 3\"\r\n ariaLabel=\"Regola di validazione\"\r\n (expressionChange)=\"setValidationRule('formulaExpression', $event)\"\r\n />\r\n <input\r\n class=\"fb-input\"\r\n placeholder=\"Messaggio mostrato quando l\u2019espressione e\u2019 falsa\"\r\n [value]=\"selectedField()!.validationRule?.errorMessage || ''\"\r\n (change)=\"setValidationRule('errorMessage', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n L\u2019espressione la valuta il motore di regole: il backend non la interpreta, la fa\r\n verificare al motore.\r\n </p>\r\n </div>\r\n </fieldset>\r\n }\r\n\r\n <!-- --------------------------------------------------------------- choice -->\r\n @if (selectedType()?.acceptsChoices) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Opzioni</legend>\r\n <p class=\"fb-section__note\">\r\n Accetta <strong>Choice</strong> e <strong>Dynamic choice set</strong>, nell\u2019ordine in cui le\r\n opzioni compaiono. Puntare a una variabile e\u2019 SCREEN_FIELD_CHOICE_UNKNOWN.\r\n </p>\r\n\r\n @if (!selectedField()!.choiceReferences?.length) {\r\n @if (selectedField()!.fieldType === 'ObjectProvided') {\r\n <!-- Le opzioni di una picklist arrivano dallo schema: qui si aggiungono solo se\r\n si vuole sostituirle, e non dichiararne nessuna e' il caso normale. -->\r\n <p class=\"fb-field__hint\">\r\n Se il campo dello schema e\u2019 una picklist, le opzioni arrivano da l\u00EC: dichiararle qui\r\n serve solo a sostituirle.\r\n </p>\r\n } @else {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Nessuna opzione: il campo non ha niente da mostrare (SCREEN_FIELD_CHOICES_MISSING).\r\n </p>\r\n }\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (choice of selectedField()!.choiceReferences || []; 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__title\">{{ choice }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" (click)=\"moveChoice($index, -1)\">\u2191</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" (click)=\"moveChoice($index, 1)\">\u2193</button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--sm\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeChoice($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Aggiungi un\u2019opzione</label>\r\n <!--\r\n `commitOn=\"enter\"`: qui ogni emissione e\u2019 una riga in piu\u2019, non un campo che cambia\r\n valore \u2014 a tasto, scrivere \u00ABAlta\u00BB aggiungeva \u00ABA\u00BB, \u00ABAl\u00BB, \u00ABAlt\u00BB e \u00ABAlta\u00BB.\r\n -->\r\n <fb-name-picker\r\n [options]=\"choiceOptions()\"\r\n label=\"Choice\"\r\n commitOn=\"enter\"\r\n placeholder=\"Scegli una choice o un choice set\"\r\n unknownMessage=\"Questo nome non e\u2019 una choice ne\u2019 un choice set: e\u2019 SCREEN_FIELD_CHOICE_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Il flow non dichiara nessuna choice: creale nel pannello delle risorse.\"\r\n (valueChange)=\"addChoice($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Scegli dall\u2019elenco, oppure scrivi il nome e premi Invio.\r\n </p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Opzione selezionata all\u2019apertura</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.defaultSelectedChoiceReference || ''\"\r\n (change)=\"setFieldProperty('defaultSelectedChoiceReference', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 nessuna \u2014</option>\r\n @for (choice of selectedField()!.choiceReferences || []; track $index) {\r\n <option [value]=\"choice\">{{ choice }}</option>\r\n }\r\n </select>\r\n @if (defaultChoiceIsForeign()) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n \u00AB{{ selectedField()!.defaultSelectedChoiceReference }}\u00BB non e\u2019 fra le opzioni elencate qui\r\n sopra.\r\n </p>\r\n }\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedAutoSelectsSingleChoice()\"\r\n (change)=\"setAutoSelectSingleChoice($any($event.target).checked)\"\r\n />\r\n Scegli da sola l\u2019unica opzione\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n Quando le opzioni risolte sono <strong>esattamente una</strong>, il campo la prende da se\u2019.\r\n Serve alle tendine che dipendono da un\u2019altra tendina \u2014 i CAP di un comune \u2014 dove chiedere\r\n di scegliere l\u2019unica voce non decide niente.\r\n </p>\r\n </fieldset>\r\n }\r\n\r\n <!-- ------------------------------------------------------- contenitori -->\r\n @if (selectedType()?.isContainer) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Contenitore</legend>\r\n @if (selectedField()!.fieldType === 'RegionContainer') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Tipo di sezione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.regionContainerType || ''\"\r\n (change)=\"setFieldProperty('regionContainerType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 predefinito \u2014</option>\r\n @for (entry of dictionary.regionContainerTypes(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n }\r\n @if (!selectedField()!.fields?.length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il contenitore e\u2019 vuoto: non produce niente sulla schermata (SCREEN_CONTAINER_EMPTY).\r\n </p>\r\n }\r\n </fieldset>\r\n }\r\n\r\n <!-- ------------------------------------------------ sezione ripetibile (\u00A75.2) -->\r\n @if (selectedIsRepeatingSection()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Righe</legend>\r\n <p class=\"fb-section__note\">\r\n I campi qui dentro sono il <strong>modello di una riga</strong>: la schermata ne rende una\r\n copia per ogni elemento della collection, e l\u2019utente decide quante con un tasto. I due\r\n riferimenti vanno pensati insieme \u2014 la <strong>collection</strong> e\u2019 dove le righe vivono,\r\n il <strong>cursore</strong> e\u2019 la riga corrente, come\r\n l\u2019<code>assignNextValueToReference</code> di un Loop.\r\n </p>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Collection delle righe</label>\r\n <fb-reference-picker\r\n [value]=\"selectedField()!.collectionReference\"\r\n dataType=\"Structure\"\r\n [isCollection]=\"true\"\r\n [writableOnly]=\"true\"\r\n label=\"Collection delle righe\"\r\n placeholder=\"Una variabile collection di tipo Structure\"\r\n (valueChange)=\"setFieldProperty('collectionReference', $event ?? '')\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n \u00C8 quella che il resto del flow attraversa con un Loop: la sezione non introduce un posto\r\n nuovo in cui i dati stanno. Se la riga e\u2019 il DTO che poi finisce in una action, conviene\r\n che sia una collection <strong>di quel DTO</strong>.\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\">Cursore della riga</label>\r\n <fb-reference-picker\r\n [value]=\"selectedField()!.itemReference\"\r\n dataType=\"Structure\"\r\n [isCollection]=\"false\"\r\n [objectType]=\"rowClass()\"\r\n [writableOnly]=\"true\"\r\n label=\"Cursore della riga\"\r\n placeholder=\"Una variabile Structure della stessa classe\"\r\n (valueChange)=\"setFieldProperty('itemReference', $event ?? '')\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n \u00C8 il nome che si scrive <strong>dentro</strong> la riga: visibilita\u2019, regole di\r\n validazione, filtri delle tendine, parametri dei componenti e\r\n <code>itemLabel</code> nominano\r\n <code>{{ selectedField()!.itemReference || 'Cursore' }}.<membro></code>, mai il nome\r\n di un campo della riga.\r\n </p>\r\n </div>\r\n\r\n @if (repeaterIssue(); as issue) {\r\n <p class=\"fb-callout fb-callout--error\">{{ issue }} (REPEATING_SECTION_INVALID)</p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Righe minime</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"0\"\r\n [value]=\"selectedField()!.minInstances ?? ''\"\r\n (change)=\"setNumberProperty('minInstances', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Righe massime</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"selectedField()!.maxInstances ?? ''\"\r\n (change)=\"setNumberProperty('maxInstances', $any($event.target).value)\"\r\n />\r\n @if (repeaterHasNoLimit()) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Senza un massimo l\u2019utente puo\u2019 aggiungere righe all\u2019infinito\r\n (REPEATING_SECTION_WITHOUT_LIMIT).\r\n </p>\r\n }\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedField()!.allowAdd !== false\"\r\n (change)=\"setRepeaterFlag('allowAdd', $any($event.target).checked)\"\r\n />\r\n L\u2019utente puo\u2019 aggiungere righe\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedField()!.allowRemove !== false\"\r\n (change)=\"setRepeaterFlag('allowRemove', $any($event.target).checked)\"\r\n />\r\n L\u2019utente puo\u2019 togliere righe\r\n </label>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Scritta del comando \u00ABaggiungi\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"selectedField()!.addButtonLabel || ''\"\r\n (input)=\"setFieldProperty('addButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Scritta del comando \u00ABtogli\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"selectedField()!.removeButtonLabel || ''\"\r\n (input)=\"setFieldProperty('removeButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Intestazione della singola riga</label>\r\n <!-- `commitOn=\"change\"`: mutare il documento ridisegna l'anteprima. -->\r\n <fb-merge-text-editor\r\n [text]=\"selectedField()!.itemLabel || ''\"\r\n [rows]=\"2\"\r\n commitOn=\"change\"\r\n placeholder=\"Punto {{ '{' }}!Cursore.PodId}\"\r\n ariaLabel=\"Intestazione della riga\"\r\n (textChange)=\"setFieldProperty('itemLabel', $event)\"\r\n >\r\n <p class=\"fb-field__hint\">\r\n Risolta <strong>sulla riga</strong>: i merge field qui nominano il cursore\r\n (<code>{!{{ selectedField()!.itemReference || 'Cursore' }}.Membro}</code>), non\r\n un campo della riga.\r\n </p>\r\n </fb-merge-text-editor>\r\n </div>\r\n\r\n @if (!selectedField()!.fields?.length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il modello della riga e\u2019 vuoto: la sezione non mostra niente (SCREEN_CONTAINER_EMPTY).\r\n </p>\r\n }\r\n </fieldset>\r\n }\r\n\r\n <!-- --------------------------------------------------- ComponentInstance -->\r\n @if (selectedField()!.fieldType === 'ComponentInstance') {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Componente</legend>\r\n <p class=\"fb-section__note\">\r\n Componenti e form sono la stessa domanda al frontend \u2014 cosa sa rendere, e con quali parametri\r\n \u2014 e passano dallo stesso catalogo. Un <code>ComponentInstance</code> non ha un valore proprio:\r\n lo hanno i suoi output.\r\n </p>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Componente</label>\r\n <fb-name-picker\r\n [value]=\"selectedField()!.extensionName\"\r\n [options]=\"componentOptions()\"\r\n [unusableOptions]=\"unusableComponents()\"\r\n label=\"Componente\"\r\n placeholder=\"Scrivi o scegli un componente\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo componente non esiste nel catalogo: e\u2019 SCREEN_COMPONENT_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n unusableMessage=\"Questo nome e\u2019 una schermata intera, non un componente montabile qui (FORM_KIND_MISMATCH).\"\r\n emptyMessage=\"Il catalogo dei componenti non e\u2019 popolato: il nome non viene verificato.\"\r\n (valueChange)=\"setFieldProperty('extensionName', $event ?? '')\"\r\n />\r\n @if (!selectedField()!.extensionName) {\r\n <p class=\"fb-field__error\">Obbligatorio: senza, SCREEN_COMPONENT_MISSING.</p>\r\n }\r\n </div>\r\n\r\n <!--\r\n \u00A75.2 \u2014 dentro una riga la spunta **non c'e'**: gli output automatici si espongono come\r\n `<NomeCampo>.<NomeOutput>`, che sarebbe **una risorsa sola per tutte le righe** \u2014 l'ultima\r\n che ha girato. \u00C8 `REPEATING_SECTION_INVALID`, e la strada giusta e' `assignToReference` su\r\n un membro del cursore, che una riga ce l'ha per davvero.\r\n -->\r\n @if (!isInsideRepeater()) {\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedField()!.storeOutputAutomatically === true\"\r\n (change)=\"setStoreOutputAutomatically($any($event.target).checked)\"\r\n />\r\n Rendi gli output referenziabili automaticamente\r\n </label>\r\n @if (selectedField()!.storeOutputAutomatically) {\r\n <p class=\"fb-field__hint\">\r\n Gli output si referenziano come\r\n <code>{{ selectedField()!.name || 'Campo' }}.nomeOutput</code>, senza dichiarare\r\n variabili.\r\n </p>\r\n }\r\n @if (hasOutputConflict()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Output automatici <strong>e</strong> parametri di uscita insieme:\r\n OUTPUT_CONFIGURATION_CONFLICT.\r\n </p>\r\n }\r\n } @else {\r\n <p class=\"fb-field__hint\">\r\n Gli output automatici qui non si possono usare: si esporrebbero come\r\n <code>{{ selectedField()!.name || 'Campo' }}.nomeOutput</code>, cioe\u2019 una risorsa sola per\r\n tutte le righe \u2014 l\u2019ultima che ha girato (REPEATING_SECTION_INVALID). Assegnali con\r\n <strong>assignToReference</strong> a un membro di\r\n <code>{{ rowCursor() || 'Cursore' }}</code>.\r\n </p>\r\n @if (selectedField()!.storeOutputAutomatically) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Questo componente dichiara gli output automatici e sta dentro una riga:\r\n REPEATING_SECTION_INVALID.\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" (click)=\"setStoreOutputAutomatically(false)\">\r\n Togli\r\n </button>\r\n </p>\r\n }\r\n }\r\n\r\n <fb-parameter-editor\r\n [holder]=\"$any(selectedField())\"\r\n [catalogParameters]=\"componentParameterList()\"\r\n [preferredRoots]=\"preferredRoots()\"\r\n inputTitle=\"Valori passati al componente\"\r\n outputTitle=\"Valori raccolti dal componente\"\r\n [showOutputs]=\"!selectedField()!.storeOutputAutomatically\"\r\n outputsDisabledReason=\"Gli output sono automatici: disattivalo per assegnarli a variabili.\"\r\n (changed)=\"onComponentParametersChanged($event)\"\r\n />\r\n </fieldset>\r\n }\r\n\r\n <!-- ------------------------------------------------------- visibilita' -->\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Visibilita\u2019</legend>\r\n <p class=\"fb-section__note\">\r\n Le regole si rivalutano <strong>sui valori appena inviati</strong>: e\u2019 cos\u00EC che un campo compare\r\n in funzione di un altro campo della stessa schermata. Un campo risultato nascosto viene\r\n <strong>azzerato</strong> e non viene validato.\r\n </p>\r\n <fb-condition-editor\r\n [holder]=\"visibilityRule()\"\r\n title=\"Mostra il campo quando\"\r\n [allowFormula]=\"false\"\r\n [preferredRoots]=\"preferredRoots()\"\r\n [issuePath]=\"'fields[' + (selectedField()!.name || '') + '].visibilityRule'\"\r\n (changed)=\"onVisibilityChanged($event)\"\r\n />\r\n </fieldset>\r\n }\r\n </aside>\r\n</div>\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\r\n<!--\r\n ============================================================== l'anteprima\r\n Due template ricorsivi. `listTpl` disegna i figli di un contenitore, e nient'altro: `data-item`\r\n marca cio' che conta come fratello nel calcolo del punto di rilascio, e il segnaposto del\r\n contenitore vuoto ne resta fuori. La barra di inserimento non e' qui \u2014 sta sopra l'anteprima,\r\n vedi il velo nel frame.\r\n-->\r\n<ng-template #listTpl let-fields let-parent=\"parent\" let-axis=\"axis\">\r\n @for (child of fields; track $index) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"fieldTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: child, path: childPath(parent, $index), axis: axis }\"\r\n />\r\n }\r\n @if (!fields.length) {\r\n <p class=\"fb-scr__drop-hint\">Trascina qui un componente</p>\r\n }\r\n</ng-template>\r\n\r\n<ng-template #fieldTpl let-field let-path=\"path\" let-axis=\"axis\">\r\n <div\r\n class=\"fb-scr__item\"\r\n data-item=\"\"\r\n cdkDrag\r\n [style.grid-column]=\"'span ' + widthOf(field)\"\r\n [class.fb-scr__item--selected]=\"isSelected(path)\"\r\n [class.fb-scr__item--dragging]=\"isDragging(path)\"\r\n [class.fb-scr__item--container]=\"holdsFields(field)\"\r\n (cdkDragStarted)=\"onFieldDragStarted(path)\"\r\n (cdkDragMoved)=\"onFieldDragMoved($event)\"\r\n (cdkDragEnded)=\"onFieldDragEnded($event, path)\"\r\n (click)=\"select(path); $event.stopPropagation()\"\r\n >\r\n <span class=\"fb-scr__grip\" cdkDragHandle title=\"Trascina per spostare\" aria-hidden=\"true\">\u283F</span>\r\n @if (field.visibilityRule?.conditions?.length) {\r\n <span class=\"fb-scr__flag\" title=\"Ha una regola di visibilita\u2019\">\u25D0</span>\r\n }\r\n\r\n @switch (field.fieldType) {\r\n @case ('RegionContainer') {\r\n <div class=\"fb-scr__section\">\r\n @if (field.regionContainerType !== 'SectionWithoutHeader') {\r\n <header class=\"fb-scr__section-head\">{{ field.fieldText || field.name }}</header>\r\n }\r\n <div class=\"fb-scr__cols\" [attr.data-drop]=\"dropId(path)\" data-axis=\"row\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: field.fields || [], parent: path, axis: 'row' }\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case ('Region') {\r\n <div class=\"fb-scr__region\">\r\n <span class=\"fb-scr__region-tag\">{{ field.name }} \u00B7 {{ widthOf(field) }}/12</span>\r\n <div class=\"fb-scr__region-body\" [attr.data-drop]=\"dropId(path)\" data-axis=\"column\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: field.fields || [], parent: path, axis: 'column' }\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case ('RepeatingSection') {\r\n <!--\r\n \u00A75.2 \u2014 si disegna **una** riga, ed e' il modello: a runtime la schermata ne rende una copia\r\n per elemento della collection. Disegnarne due sarebbe finto \u2014 quante siano lo decide chi\r\n compila \u2014 e disegnarla senza cornice farebbe credere che i campi siano della schermata.\r\n -->\r\n <div class=\"fb-scr__repeat\">\r\n <header class=\"fb-scr__repeat-head\">\r\n <span>{{ field.fieldText || field.name }}</span>\r\n <span class=\"fb-scr__repeat-meta\">\r\n {{ field.collectionReference || 'collection non indicata' }}\r\n @if (field.minInstances !== undefined || field.maxInstances !== undefined) {\r\n \u00B7 {{ field.minInstances ?? 0 }}\u2013{{ field.maxInstances ?? '\u221E' }}\r\n }\r\n </span>\r\n </header>\r\n <div class=\"fb-scr__repeat-row\">\r\n <span class=\"fb-scr__repeat-tag\">\r\n {{ field.itemLabel || 'Riga 1' }}\r\n @if (field.allowRemove !== false) {\r\n <span class=\"fb-scr__repeat-x\" aria-hidden=\"true\">\u00D7</span>\r\n }\r\n </span>\r\n <div class=\"fb-scr__repeat-body\" [attr.data-drop]=\"dropId(path)\" data-axis=\"column\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: field.fields || [], parent: path, axis: 'column' }\"\r\n />\r\n </div>\r\n </div>\r\n @if (field.allowAdd !== false) {\r\n <span class=\"fb-scr__repeat-add\">+ {{ field.addButtonLabel || 'Aggiungi' }}</span>\r\n }\r\n </div>\r\n }\r\n @case ('DisplayText') {\r\n <p class=\"fb-scr__display\">{{ field.fieldText || '(testo vuoto)' }}</p>\r\n }\r\n @case ('LargeTextArea') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control fb-scr__control--area\">{{ placeholderOf(field) }}</div>\r\n }\r\n @case ('PasswordField') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control\">\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022</div>\r\n }\r\n @case ('DropdownBox') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control fb-scr__control--select\">\r\n <span>{{ field.defaultSelectedChoiceReference || choiceLabelsOf(field)[0] || '\u2014 scegli \u2014' }}</span>\r\n <span aria-hidden=\"true\">\u25BE</span>\r\n </div>\r\n }\r\n @case ('MultiSelectPicklist') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control fb-scr__control--select\">\r\n <span>{{ choiceLabelsOf(field).join(', ') || '\u2014 scegli \u2014' }}</span>\r\n <span aria-hidden=\"true\">\u2261</span>\r\n </div>\r\n }\r\n @case ('RadioButtons') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__options\">\r\n @for (option of choiceLabelsOf(field); track $index) {\r\n <span class=\"fb-scr__option\">\u25EF {{ option }}</span>\r\n }\r\n @if (!choiceLabelsOf(field).length) {\r\n <span class=\"fb-scr__option fb-scr__option--missing\">Nessuna opzione</span>\r\n }\r\n </div>\r\n }\r\n @case ('MultiSelectCheckboxes') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__options\">\r\n @for (option of choiceLabelsOf(field); track $index) {\r\n <span class=\"fb-scr__option\">\u2610 {{ option }}</span>\r\n }\r\n @if (!choiceLabelsOf(field).length) {\r\n <span class=\"fb-scr__option fb-scr__option--missing\">Nessuna opzione</span>\r\n }\r\n </div>\r\n }\r\n @case ('ComponentInstance') {\r\n <!--\r\n L\u2019etichetta si disegna se c\u2019e\u2019: il runtime la consegna in `label` come per gli altri\r\n campi (\u00A75.2). Nessun asterisco: un componente non raccoglie un valore, quindi\r\n \u00ABobbligatorio\u00BB non ha niente su cui applicarsi.\r\n -->\r\n @if (field.fieldText) {\r\n <label class=\"fb-scr__label\">{{ field.fieldText }}</label>\r\n }\r\n <div class=\"fb-scr__component\">\r\n <span aria-hidden=\"true\">\u2B21</span>\r\n {{ field.extensionName || 'Componente non indicato' }}\r\n </div>\r\n }\r\n @case ('ObjectProvided') {\r\n <label class=\"fb-scr__label\">\r\n {{ field.fieldText || field.objectFieldReference || field.name }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control\">{{ placeholderOf(field) }}</div>\r\n <span class=\"fb-scr__tag\">{{ field.objectFieldReference || 'campo non indicato' }}</span>\r\n }\r\n @default {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control\">{{ placeholderOf(field) }}</div>\r\n @if (isUnknownType(field)) {\r\n <span class=\"fb-scr__tag fb-scr__tag--warn\">{{ field.fieldType }}: tipo non nel dizionario</span>\r\n }\r\n }\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: [".fb-scr{display:grid;grid-template-columns:220px minmax(0,1fr) 340px;gap:12px;align-items:start;margin-bottom:14px}@media(max-width:1100px){.fb-scr{grid-template-columns:minmax(0,1fr)}}.fb-scr__side,.fb-scr__props{min-width:0;padding:10px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__tabs{display:flex;gap:4px;margin-bottom:8px}.fb-scr__tab{flex:1;padding:5px 8px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text-muted, #6b7086);font:inherit;font-size:11px;font-weight:600;cursor:pointer}.fb-scr__tab--active{border-color:var(--fb-accent, #4f6ef7);background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 10%,transparent);color:var(--fb-accent-strong, #3d59e0)}.fb-scr__side-hint,.fb-scr__side-empty{margin:6px 0;font-size:11px;color:var(--fb-text-muted, #6b7086)}.fb-scr__palette{display:flex;flex-direction:column;gap:4px;margin:8px 0 0;padding:0;max-height:320px;overflow-y:auto;overscroll-behavior:contain;list-style:none}.fb-scr__chip{display:flex;align-items:center;gap:8px;width:100%;padding:6px 8px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text, #1a1c23);font:inherit;font-size:12px;text-align:left;cursor:grab}.fb-scr__chip:hover{border-color:var(--fb-accent, #4f6ef7)}.fb-scr__chip-icon{flex:none;width:20px;text-align:center;color:var(--fb-text-muted, #6b7086)}.fb-scr__chip-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-scr__chip-label small{margin-left:4px;color:var(--fb-text-subtle, #98a2b3);font-size:10px}.fb-scr__canvas{min-width:0;padding:14px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-canvas-bg, #f4f5f7);max-height:60vh;overflow-y:auto}.fb-scr__frame{position:relative;display:flex;flex-direction:column;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-sm, 8px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));overflow:hidden}.fb-scr__frame-head{display:flex;align-items:center;gap:6px;padding:8px 12px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4);font-size:13px;font-weight:600}.fb-scr__help{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;border-radius:50%;background:var(--fb-surface-sunken, #eef0f4);color:var(--fb-text-muted, #6b7086);font-size:10px}.fb-scr__body,.fb-scr__region-body{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));align-content:start;gap:8px 0;padding:12px;min-height:90px}.fb-scr__region-body{padding:8px;min-height:60px}.fb-scr__cols{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));align-items:stretch;gap:0;padding:8px;min-height:60px}.fb-scr__cols>.fb-scr__item{display:flex;align-self:stretch}.fb-scr__cols>.fb-scr__item>.fb-scr__region{flex:1;min-width:0}.fb-scr__drop-hint{grid-column:1 / -1;margin:0;padding:10px;border:1px dashed var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);color:var(--fb-text-subtle, #98a2b3);font-size:11px;text-align:center}.fb-scr__marker{position:absolute;z-index:2;border-radius:2px;background:var(--fb-accent, #4f6ef7);pointer-events:none}.fb-scr__item{position:relative;box-sizing:border-box;padding:6px 8px;border:1px solid transparent;border-radius:var(--fb-radius-xs, 6px);cursor:pointer}.fb-scr__item:hover{border-color:var(--fb-border-strong, #cfd4de);background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 4%,transparent)}.fb-scr__item--selected{border-color:var(--fb-accent, #4f6ef7);box-shadow:inset 0 0 0 1px var(--fb-accent, #4f6ef7)}.fb-scr__item--dragging{opacity:.45;pointer-events:none}.fb-scr__grip{position:absolute;top:2px;left:-2px;padding:0 3px;color:var(--fb-text-subtle, #98a2b3);font-size:11px;line-height:1;opacity:0;cursor:grab}.fb-scr__item:hover>.fb-scr__grip,.fb-scr__item--selected>.fb-scr__grip{opacity:1}.fb-scr__flag{position:absolute;top:2px;right:4px;color:var(--fb-text-muted, #6b7086);font-size:11px}.fb-scr__label{display:block;margin-bottom:3px;font-size:11px;font-weight:600;color:var(--fb-text, #1a1c23)}.fb-scr__req{color:var(--fb-error, #dc2626)}.fb-scr__control{display:flex;align-items:center;justify-content:space-between;gap:6px;min-height:26px;padding:4px 8px;border:1px solid var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text-subtle, #98a2b3);font-size:12px;pointer-events:none}.fb-scr__control--area{min-height:54px;align-items:flex-start}.fb-scr__display{margin:0;font-size:12px;color:var(--fb-text, #1a1c23)}.fb-scr__options{display:flex;flex-direction:column;gap:2px;pointer-events:none}.fb-scr__option{font-size:12px;color:var(--fb-text-muted, #6b7086)}.fb-scr__option--missing{color:var(--fb-warning, #b7791f)}.fb-scr__component{display:flex;align-items:center;gap:6px;padding:10px;border:1px dashed var(--fb-accent, #4f6ef7);border-radius:var(--fb-radius-xs, 6px);background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 5%,transparent);font-size:12px;color:var(--fb-text-muted, #6b7086)}.fb-scr__tag{display:inline-block;margin-top:3px;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-scr__tag--warn{color:var(--fb-warning, #b7791f)}.fb-scr__section{border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__section-head{padding:5px 10px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--fb-text-muted, #6b7086)}.fb-scr__region{border:1px dashed var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff)}.fb-scr__region-tag{display:block;padding:3px 6px 0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-scr__repeat{border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__repeat-head{display:flex;align-items:baseline;gap:8px;padding:5px 10px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--fb-text-muted, #6b7086)}.fb-scr__repeat-meta{margin-left:auto;font-size:10px;font-weight:400;text-transform:none;letter-spacing:0;color:var(--fb-text-subtle, #98a2b3)}.fb-scr__repeat-row{margin:8px;border:1px dashed var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff)}.fb-scr__repeat-tag{display:flex;align-items:center;gap:6px;padding:3px 6px 0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-scr__repeat-x{margin-left:auto}.fb-scr__repeat-body{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));align-content:start;gap:8px 0;padding:8px;min-height:60px}.fb-scr__repeat-add{display:inline-block;margin:0 8px 8px;padding:3px 10px;border:1px dashed var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);font-size:11px;color:var(--fb-text-muted, #6b7086)}.fb-scr__frame-foot{display:flex;align-items:center;gap:6px;padding:8px 12px;border-top:1px solid var(--fb-border-subtle, #eef0f4);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__spacer{flex:1}.fb-scr__btn{padding:3px 10px;border:1px solid var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);font-size:11px;color:var(--fb-text-muted, #6b7086)}.fb-scr__btn--primary{border-color:var(--fb-accent, #4f6ef7);background:var(--fb-accent, #4f6ef7);color:var(--fb-accent-contrast, #fff)}.fb-scr__canvas-note{margin-top:10px}.fb-scr__props{background:var(--fb-surface, #fff)}.fb-scr__props-head{display:flex;align-items:center;gap:8px;margin-bottom:8px}.fb-scr__props-title{flex:1;min-width:0;margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--fb-text-muted, #6b7086)}.fb-scr__props-actions{display:flex;flex-wrap:wrap;gap:3px}.fb-btn--sm{padding:3px 7px;font-size:11px}.fb-scr__width{display:flex;align-items:center;gap:8px}.fb-scr__width input[type=range]{flex:1;min-width:0}.fb-scr__width-value{font-size:11px;color:var(--fb-text-muted, #6b7086)}\n"], dependencies: [{ kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: ConditionEditorComponent, selector: "fb-condition-editor", inputs: ["holder", "title", "allowFormula", "preferredRoots", "allowLogic", "issuePath"], outputs: ["changed"] }, { kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: FormulaEditorComponent, selector: "fb-formula-editor", inputs: ["expression", "usage", "expectedDataType", "scale", "placeholder", "ariaLabel", "disabled", "rows", "preferredRoots", "commitOn"], outputs: ["expressionChange"] }, { kind: "component", type: MergeTextEditorComponent, selector: "fb-merge-text-editor", inputs: ["text", "usage", "placeholder", "ariaLabel", "disabled", "rows", "commitOn"], outputs: ["textChange"] }, { kind: "component", type: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ObjectPickerComponent, selector: "fb-object-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason", "extraTargets", "preferredRoots"], outputs: ["changed"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences", "preferredRoots"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }, { kind: "component", type: StructureMemberPickerComponent, selector: "fb-structure-member-picker", inputs: ["value", "className", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: StructurePickerComponent, selector: "fb-structure-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula", "preferredRoots"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
12573
12892
|
}
|
|
12574
12893
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: DynamicScreenInspectorComponent, decorators: [{
|
|
12575
12894
|
type: Component,
|
|
@@ -12580,14 +12899,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
12580
12899
|
ConnectorEditorComponent,
|
|
12581
12900
|
FieldPickerComponent,
|
|
12582
12901
|
FormulaEditorComponent,
|
|
12902
|
+
MergeTextEditorComponent,
|
|
12583
12903
|
NamePickerComponent,
|
|
12584
12904
|
NgTemplateOutlet,
|
|
12585
12905
|
ObjectPickerComponent,
|
|
12586
12906
|
ParameterEditorComponent,
|
|
12907
|
+
ReferencePickerComponent,
|
|
12587
12908
|
SelectValueDirective,
|
|
12909
|
+
StructureMemberPickerComponent,
|
|
12588
12910
|
StructurePickerComponent,
|
|
12589
12911
|
ValueEditorComponent,
|
|
12590
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-scr\" #composer>\r\n <!-- ============================================================ sinistra -->\r\n <aside class=\"fb-scr__side\" aria-label=\"Componenti e campi\">\r\n <div class=\"fb-scr__tabs\" role=\"tablist\">\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"fb-scr__tab\"\r\n [class.fb-scr__tab--active]=\"paletteTab() === 'components'\"\r\n [attr.aria-selected]=\"paletteTab() === 'components'\"\r\n (click)=\"setPaletteTab('components')\"\r\n >\r\n Componenti\r\n </button>\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"fb-scr__tab\"\r\n [class.fb-scr__tab--active]=\"paletteTab() === 'fields'\"\r\n [attr.aria-selected]=\"paletteTab() === 'fields'\"\r\n (click)=\"setPaletteTab('fields')\"\r\n >\r\n Campi\r\n </button>\r\n </div>\r\n\r\n @if (paletteTab() === 'components') {\r\n @if (!dictionary.screenFieldTypes().length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il dizionario <code>screenFieldTypes</code> non e\u2019 disponibile: senza i suoi flag l\u2019editor non\r\n sa quali campi ammette ciascun tipo, e non li inventa.\r\n </p>\r\n }\r\n <p class=\"fb-scr__side-hint\">Trascina sulla schermata, oppure clicca per aggiungere.</p>\r\n <ul class=\"fb-scr__palette\">\r\n @for (entry of dictionary.screenFieldTypes(); track entry.value) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-scr__chip\"\r\n cdkDrag\r\n [title]=\"entry.description || entry.label\"\r\n (cdkDragMoved)=\"onPaletteDragMoved($event)\"\r\n (cdkDragEnded)=\"onComponentDragEnded($event, entry.value)\"\r\n (click)=\"addComponentAtSelection(entry.value)\"\r\n >\r\n <span class=\"fb-scr__chip-icon\" aria-hidden=\"true\">{{ iconOf(entry.value) }}</span>\r\n <span class=\"fb-scr__chip-label\">{{ entry.label }}</span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n } @else {\r\n <p class=\"fb-scr__side-hint\">\r\n Un campo dell\u2019entita\u2019 porta con se\u2019 tipo, etichetta, obbligatorieta\u2019 e opzioni: arrivano dallo\r\n schema dati, qui non si ridichiarano.\r\n </p>\r\n <!-- Il catalogo non e' un dizionario chiuso: si sceglie o si scrive, come ovunque si\r\n indichi un'entita' (vedi `object-picker`). -->\r\n <fb-object-picker\r\n [value]=\"fieldsObject()\"\r\n label=\"Entita\u2019\"\r\n placeholder=\"Scrivi o scegli un\u2019entita\u2019\"\r\n (valueChange)=\"setFieldsObject($event)\"\r\n />\r\n @if (fieldsObject() && !fieldsOfObject().length) {\r\n <p class=\"fb-scr__side-empty\">\r\n Nessun campo dichiarato per questa entita\u2019: il catalogo non li espone, non significa che non\r\n ci siano.\r\n </p>\r\n }\r\n <ul class=\"fb-scr__palette\">\r\n @for (field of fieldsOfObject(); track $index) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-scr__chip\"\r\n cdkDrag\r\n [title]=\"field.name + (field.dataType ? ' \u00B7 ' + field.dataType : '')\"\r\n (cdkDragMoved)=\"onPaletteDragMoved($event)\"\r\n (cdkDragEnded)=\"onObjectFieldDragEnded($event, field)\"\r\n (click)=\"addObjectFieldAtSelection(field)\"\r\n >\r\n <span class=\"fb-scr__chip-icon\" aria-hidden=\"true\">\u2317</span>\r\n <span class=\"fb-scr__chip-label\">\r\n {{ field.label || field.name }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n <small>{{ field.dataType }}</small>\r\n </span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n </aside>\r\n\r\n <!-- ============================================================== centro -->\r\n <!-- Cliccare fuori da un campo riporta a destra le proprieta' della schermata. -->\r\n <section class=\"fb-scr__canvas\" aria-label=\"Anteprima della schermata\" (click)=\"selectScreen()\">\r\n <div class=\"fb-scr__frame\">\r\n @if (showHeader()) {\r\n <header class=\"fb-scr__frame-head\">\r\n {{ $any(node()).label || name() }}\r\n @if (screen().helpText) {\r\n <span class=\"fb-scr__help\" [title]=\"screen().helpText || ''\">?</span>\r\n }\r\n </header>\r\n }\r\n\r\n <div\r\n class=\"fb-scr__body\"\r\n [attr.data-drop]=\"''\"\r\n data-axis=\"column\"\r\n [class.fb-scr__body--empty]=\"isEmpty()\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: screen().fields || [], parent: [], axis: 'column' }\"\r\n />\r\n </div>\r\n\r\n <!--\r\n La barra di inserimento e' un **velo** sopra l'anteprima, non un figlio del contenitore di\r\n rilascio: dentro la griglia occupava una riga intera e spostava in basso proprio la sezione\r\n che si stava puntando, che allora usciva da sotto il puntatore e il bersaglio oscillava.\r\n -->\r\n @if (dropMarker(); as bar) {\r\n <div\r\n class=\"fb-scr__marker\"\r\n [style.left.px]=\"bar.left\"\r\n [style.top.px]=\"bar.top\"\r\n [style.width.px]=\"bar.width\"\r\n [style.height.px]=\"bar.height\"\r\n ></div>\r\n }\r\n\r\n @if (showFooter()) {\r\n <footer class=\"fb-scr__frame-foot\">\r\n @if (allowPause()) {\r\n <span class=\"fb-scr__btn fb-scr__btn--ghost\">{{ screen().pauseButtonLabel || 'Pausa' }}</span>\r\n }\r\n <span class=\"fb-scr__spacer\"></span>\r\n @if (allowBack()) {\r\n <span class=\"fb-scr__btn fb-scr__btn--ghost\">{{ screen().backButtonLabel || 'Indietro' }}</span>\r\n }\r\n <span class=\"fb-scr__btn fb-scr__btn--primary\">\r\n {{ screen().nextOrFinishButtonLabel || (allowFinish() ? 'Fine' : 'Avanti') }}\r\n </span>\r\n </footer>\r\n }\r\n </div>\r\n\r\n @if (isEmpty()) {\r\n <p class=\"fb-callout fb-callout--warn fb-scr__canvas-note\">\r\n La schermata non ha campi: non c\u2019e\u2019 niente da mostrare all\u2019utente (SCREEN_WITHOUT_FIELDS).\r\n </p>\r\n }\r\n </section>\r\n\r\n <!-- ============================================================== destra -->\r\n <aside class=\"fb-scr__props\" aria-label=\"Proprieta\u2019\">\r\n @if (!selectedField()) {\r\n <!-- ------------------------------------------------ proprieta' della schermata -->\r\n <header class=\"fb-scr__props-head\">\r\n <h3 class=\"fb-scr__props-title\">Schermata</h3>\r\n </header>\r\n <p class=\"fb-scr__side-hint\">Seleziona un campo nell\u2019anteprima per configurarlo.</p>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo di aiuto</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"screen().helpText || ''\"\r\n (input)=\"setScreenText('helpText', $any($event.target).value)\"\r\n ></textarea>\r\n </div>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Navigazione</legend>\r\n <p class=\"fb-section__note\">\r\n Questi flag sono un\u2019intenzione, non la verita\u2019 finale: a runtime il motore comunica\r\n <code>canGoBack</code>, <code>canFinish</code> e <code>canPause</code> nella richiesta della\r\n schermata.\r\n </p>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowBack()\" (change)=\"setScreenFlag('allowBack', $any($event.target).checked)\" />\r\n Consenti \u00ABindietro\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowFinish()\" (change)=\"setScreenFlag('allowFinish', $any($event.target).checked)\" />\r\n Consenti \u00ABfine\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowPause()\" (change)=\"setScreenFlag('allowPause', $any($event.target).checked)\" />\r\n Consenti \u00ABpausa\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"showHeader()\" (change)=\"setScreenFlag('showHeader', $any($event.target).checked)\" />\r\n Mostra l\u2019intestazione\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"showFooter()\" (change)=\"setScreenFlag('showFooter', $any($event.target).checked)\" />\r\n Mostra il piede\r\n </label>\r\n\r\n @if (allowPause()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo mostrato alla pausa</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().pausedText || ''\"\r\n (input)=\"setScreenText('pausedText', $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (isDeadEnd()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Questa schermata non ha una destinazione e non consente \u00ABfine\u00BB: e\u2019 un vicolo cieco, e\r\n l\u2019utente resterebbe bloccato (SCREEN_DEAD_END).\r\n </p>\r\n }\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Pulsanti</legend>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta \u00ABindietro\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().backButtonLabel || ''\"\r\n (input)=\"setScreenText('backButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta \u00ABavanti / fine\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().nextOrFinishButtonLabel || ''\"\r\n (input)=\"setScreenText('nextOrFinishButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta \u00ABpausa\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().pauseButtonLabel || ''\"\r\n (input)=\"setScreenText('pauseButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n </fieldset>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Stage mostrato nell\u2019avanzamento</label>\r\n <fb-name-picker\r\n [value]=\"screen().stageReference\"\r\n [options]=\"stageOptions()\"\r\n label=\"Stage\"\r\n placeholder=\"Scegli uno stage\"\r\n unknownMessage=\"Questo stage non e\u2019 dichiarato dal flow.\"\r\n emptyMessage=\"Il flow non dichiara stage: creali nel pannello delle risorse.\"\r\n (valueChange)=\"setScreenText('stageReference', $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <!--\r\n Screen action (\u00A75.2). Due elenchi e non uno perche' il contratto li separa: piu' trigger\r\n possono invocare la stessa action, quindi \u00ABchi la chiama\u00BB non e' una sua proprieta'. Le\r\n action si aprono una alla volta: i cataloghi dipendono da tipo e nome, e tenerne N in volo\r\n sarebbe N volte la corsa fra risposte.\r\n -->\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Azioni della schermata</legend>\r\n <p class=\"fb-section__note\">\r\n Un campo che l\u2019utente compila puo\u2019 innescare un\u2019action i cui risultati finiscono negli\r\n <strong>altri campi di questa schermata</strong>: e\u2019 il caso \u00ABscrivi il codice fiscale e nome\r\n e cognome compaiono da soli\u00BB. L\u2019alternativa sarebbe spezzare la schermata in due con un\r\n elemento Action in mezzo.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (action of screenActions(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost\"\r\n [attr.aria-expanded]=\"selectedActionIndex() === $index\"\r\n (click)=\"selectAction(selectedActionIndex() === $index ? null : $index)\"\r\n >\r\n {{ selectedActionIndex() === $index ? '\u25BE' : '\u25B8' }}\r\n {{ action.name || '(senza nome)' }}\r\n </button>\r\n <span class=\"fb-list__spacer\"></span>\r\n <span class=\"fb-scr__side-hint\">{{ action.actionName || 'action non scelta' }}</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\u2019action\"\r\n (click)=\"removeScreenAction($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n @if (actionLosesResult(action)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questa action viene invocata ma il suo risultato si perde: aggiungi un parametro di\r\n uscita, oppure accendi l\u2019output automatico (SCREEN_ACTION_WITHOUT_OUTPUTS).\r\n </p>\r\n }\r\n @if (actionHasNoTrigger(action)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Nessun trigger la invoca: senza, non girera\u2019 mai.\r\n </p>\r\n }\r\n\r\n @if (selectedActionIndex() === $index) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Nome</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"action.name || ''\"\r\n (change)=\"setActionName($index, $any($event.target).value)\"\r\n />\r\n @if (actionNameError(action); as error) {\r\n <p class=\"fb-field__error\">{{ error }}</p>\r\n }\r\n <p class=\"fb-field__hint\">\r\n E\u2019 il nome con cui la citano i trigger, e vive nello spazio dei nomi del flow. Con\r\n l\u2019output automatico e\u2019 anche la radice del riferimento:\r\n <code>{{ action.name || 'Cerca' }}.NomeOutput</code>.\r\n </p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Tipo di action</label>\r\n <fb-name-picker\r\n [value]=\"action.actionType\"\r\n [options]=\"actionTypeOptions()\"\r\n label=\"Tipo di action\"\r\n placeholder=\"Scrivi o scegli un tipo\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo tipo di action non e\u2019 fra quelli dichiarati dal sistema ospite.\"\r\n emptyMessage=\"Catalogo dei tipi di action non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setActionType($index, $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Action</label>\r\n <fb-name-picker\r\n [value]=\"action.actionName\"\r\n [options]=\"actionOptions()\"\r\n label=\"Action\"\r\n placeholder=\"Scrivi o scegli un\u2019action\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questa action non esiste nel catalogo del tipo scelto: e\u2019 ACTION_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Scegli prima il tipo di action, oppure scrivi il nome a mano.\"\r\n (valueChange)=\"setActionTarget($index, $event ?? '')\"\r\n />\r\n @if (!action.actionName) {\r\n <p class=\"fb-field__error\">Obbligatoria: senza, ACTION_NAME_MISSING.</p>\r\n }\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"action.storeOutputAutomatically === true\"\r\n (change)=\"setActionStoreOutput($index, $any($event.target).checked)\"\r\n />\r\n Output automatico\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n L\u2019output automatico rende il risultato leggibile come\r\n <code>{{ action.name || 'Cerca' }}.NomeOutput</code>, ma\r\n <strong>non scrive in nessun campo</strong>: e\u2019 la forma da usare quando il risultato\r\n serve a una condizione, non a precompilare.\r\n </p>\r\n\r\n <!--\r\n L'unico posto in cui un campo di schermata e' una destinazione (\u00A75.2):\r\n `POST /flows/references/writable` continua a escluderlo, e un Assignment che ci\r\n scrive resta TARGET_NOT_WRITABLE.\r\n -->\r\n <fb-parameter-editor\r\n [holder]=\"action\"\r\n [catalogParameters]=\"actionParameterCatalog()\"\r\n [showOutputs]=\"action.storeOutputAutomatically !== true\"\r\n outputTitle=\"Campi da riempire\"\r\n [extraTargets]=\"screenFieldTargets()\"\r\n [outputsDisabledReason]=\"\r\n action.storeOutputAutomatically === true\r\n ? 'Con l\u2019output automatico il risultato non viene scritto nei campi.'\r\n : null\r\n \"\r\n (changed)=\"onActionParametersChanged($index, $event)\"\r\n />\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessuna action: i campi di questa schermata li compila solo l\u2019utente.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addScreenAction()\">Aggiungi action</button>\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Trigger</legend>\r\n <p class=\"fb-section__note\">\r\n Quale campo invoca quale action. Senza condizioni l\u2019action gira a ogni cambio del campo.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (trigger of screenTriggers(); 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 trigger\"\r\n (click)=\"removeScreenTrigger($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\">Action da invocare</label>\r\n <fb-name-picker\r\n [value]=\"trigger.screenActionName\"\r\n [options]=\"screenActionOptions()\"\r\n label=\"Action della schermata\"\r\n placeholder=\"Scegli un\u2019action\"\r\n unknownMessage=\"Questa schermata non dichiara un\u2019action con questo nome: e\u2019 SCREEN_ACTION_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Aggiungi prima un\u2019action qui sopra.\"\r\n (valueChange)=\"setTriggerProperty($index, 'screenActionName', $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo che la innesca</label>\r\n <!-- I campi di **questa** schermata, non i riferimenti in generale (\u00A75.2). -->\r\n <fb-name-picker\r\n [value]=\"trigger.triggerFieldName\"\r\n [options]=\"triggerFieldOptions()\"\r\n label=\"Campo della schermata\"\r\n placeholder=\"Scegli un campo\"\r\n unknownMessage=\"Questo non e\u2019 un campo di questa schermata: e\u2019 SCREEN_TRIGGER_FIELD_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"La schermata non ha ancora campi che raccolgono un valore.\"\r\n (valueChange)=\"setTriggerProperty($index, 'triggerFieldName', $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">All\u2019arrivo sulla schermata</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"trigger.initBehavior || ''\"\r\n (change)=\"setTriggerProperty($index, 'initBehavior', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 non invocare \u2014</option>\r\n <option value=\"runOnLoad\">Invoca al caricamento (runOnLoad)</option>\r\n </select>\r\n @if (triggerInitIsUnknown(trigger)) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ trigger.initBehavior }}\u00BB non e\u2019 ammesso: l\u2019unico valore e\u2019 <code>runOnLoad</code>\r\n (SCREEN_TRIGGER_INIT_BEHAVIOR_UNKNOWN).\r\n </p>\r\n }\r\n @if (triggerFiresOnLoadByDefault(trigger)) {\r\n <p class=\"fb-field__hint\">\r\n Non serve: \u00AB{{ trigger.triggerFieldName }}\u00BB ha un valore di default, e un campo\r\n precompilato dal flow innesca l\u2019action gi\u00E0 all\u2019arrivo sulla schermata.\r\n </p>\r\n }\r\n </div>\r\n\r\n @if (triggerHasNoCause(trigger)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Senza un campo che la innesca e senza l\u2019invocazione al caricamento, questo trigger non\r\n scattera\u2019 mai (SCREEN_TRIGGER_WITHOUT_CAUSE).\r\n </p>\r\n }\r\n\r\n <fb-condition-editor\r\n [holder]=\"triggerConditions(trigger)\"\r\n title=\"Invoca l\u2019action quando\"\r\n [allowFormula]=\"false\"\r\n [issuePath]=\"'triggers[' + $index + ']'\"\r\n (changed)=\"onTriggerConditionsChanged($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun trigger: le action dichiarate non verranno invocate.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addScreenTrigger()\">Aggiungi trigger</button>\r\n </fieldset>\r\n } @else {\r\n <!-- ---------------------------------------------------- proprieta' del campo -->\r\n <header class=\"fb-scr__props-head\">\r\n <h3 class=\"fb-scr__props-title\">{{ captionOf(selectedField()!) }}</h3>\r\n <div class=\"fb-scr__props-actions\">\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" title=\"Sposta su\" (click)=\"moveSelected(-1)\">\u2191</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" title=\"Sposta giu\u2019\" (click)=\"moveSelected(1)\">\u2193</button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--sm\"\r\n title=\"Porta fuori dal contenitore\"\r\n [disabled]=\"!canOutdent()\"\r\n (click)=\"outdentSelected()\"\r\n >\r\n \u21E4\r\n </button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" title=\"Duplica\" (click)=\"duplicateSelected()\">\u29C9</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--danger fb-btn--sm\" title=\"Elimina\" (click)=\"removeSelected()\">\r\n \u00D7\r\n </button>\r\n </div>\r\n </header>\r\n\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]=\"selectedField()!.fieldType || ''\"\r\n (change)=\"setFieldType($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of dictionary.screenFieldTypes(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.label }}</option>\r\n }\r\n </select>\r\n @if (!selectedField()!.fieldType) {\r\n <p class=\"fb-field__error\">Il tipo e\u2019 obbligatorio: senza, SCREEN_FIELD_TYPE_MISSING.</p>\r\n } @else if (isUnknownType(selectedField())) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Questo tipo non e\u2019 nel dizionario: l\u2019editor non sa quali campi ammetta e mostra solo i comuni.\r\n </p>\r\n } @else if (selectedType()?.description) {\r\n <p class=\"fb-field__hint\">{{ selectedType()?.description }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Nome</label>\r\n <!-- Sul `change` e non sull\u2019`input`: la rinomina riscrive i riferimenti nel documento,\r\n e farlo a ogni tasto significherebbe riscriverlo per ogni lettera. -->\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"selectedField()!.name || ''\"\r\n (change)=\"setFieldName($any($event.target).value)\"\r\n />\r\n @if (selectedIsResource()) {\r\n <p class=\"fb-field__hint\">\r\n Questo campo e\u2019 una <strong>risorsa</strong>: lo referenzi come\r\n <code>{{ selectedField()!.name || 'Nome' }}</code> in condizioni, formule e parametri. \u00C8 di\r\n sola lettura per il flow \u2014 un Assignment che ci scrive e\u2019 TARGET_NOT_WRITABLE.\r\n </p>\r\n }\r\n </div>\r\n\r\n @if (!selectedType()?.isContainer) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">\r\n {{ selectedField()!.fieldType === 'DisplayText' ? 'Testo' : 'Etichetta' }}\r\n </label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"selectedField()!.fieldText || ''\"\r\n (input)=\"setFieldProperty('fieldText', $any($event.target).value)\"\r\n ></textarea>\r\n <p class=\"fb-field__hint\">\r\n Supporta i merge field <code>{!Riferimento}</code>.\r\n @if (selectedField()!.fieldType === 'ComponentInstance') {\r\n <!--\r\n \u00A75.2 \u2014 su un componente l\u2019etichetta e\u2019 **ammessa** e viene consegnata al frontend\r\n in `label`, ma la sua assenza non e\u2019 un rilievo: un componente di solito disegna\r\n la propria intestazione. Nasconderla, come faceva prima l\u2019editor, toglieva un\r\n campo che il contratto prevede.\r\n -->\r\n Facoltativa: un componente di solito disegna la propria intestazione.\r\n }\r\n </p>\r\n </div>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Intestazione</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"selectedField()!.fieldText || ''\"\r\n (input)=\"setFieldProperty('fieldText', $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo di aiuto</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"selectedField()!.helpText || ''\"\r\n (input)=\"setFieldProperty('helpText', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Larghezza</label>\r\n <div class=\"fb-scr__width\">\r\n <input\r\n type=\"range\"\r\n min=\"1\"\r\n max=\"12\"\r\n step=\"1\"\r\n [value]=\"widthOf(selectedField()!)\"\r\n (input)=\"setNumberProperty('width', $any($event.target).value)\"\r\n />\r\n <span class=\"fb-scr__width-value\">{{ widthOf(selectedField()!) }}/12</span>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Colonne della griglia della schermata. \u00C8 un\u2019indicazione: il frontend puo\u2019 ignorarla.\r\n </p>\r\n </div>\r\n\r\n @if (selectedField()!.fieldType === 'ComponentInstance') {\r\n <!--\r\n \u00A75.2 \u2014 perche\u2019 qui non c\u2019e\u2019 \u00ABobbligatorio\u00BB. La domanda arriva sempre, e la risposta non\r\n si indovina guardando l\u2019interfaccia: un componente non ha un valore proprio, ce l\u2019hanno\r\n i suoi output, che vanno in **variabili** scelte dall\u2019autore. \u00ABObbligatorio\u00BB dovrebbe\r\n dire *quale output* deve essere valorizzato, e il metadata non ha modo di dirlo \u2014\r\n dichiararlo qui sarebbe `SCREEN_FIELD_CONFIGURATION_INVALID` e il runtime lo\r\n ignorerebbe. Le due strade vere stanno nel contratto e sono queste.\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Un componente non raccoglie un valore \u2014 lo fanno i suoi output \u2014 quindi obbligatorieta\u2019, valore\r\n predefinito e regola di validazione non si applicano: dichiararli e\u2019\r\n <code>SCREEN_FIELD_CONFIGURATION_INVALID</code> e il runtime li ignora. Per pretendere una\r\n compilazione: la validazione la fa il componente stesso, oppure si controlla la variabile di\r\n destinazione con una Decision dopo la schermata.\r\n </p>\r\n }\r\n\r\n <!-- ------------------------------------------------ campi che raccolgono un valore -->\r\n @if (selectedType()?.storesValue) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Valore</legend>\r\n\r\n @if (selectedField()!.fieldType !== 'ObjectProvided') {\r\n <div class=\"fb-field\">\r\n <label\r\n class=\"fb-field__label\"\r\n [class.fb-field__label--required]=\"!!selectedType()?.requiresDataType\"\r\n >\r\n Tipo di dato\r\n </label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.dataType || ''\"\r\n (change)=\"setFieldProperty('dataType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of dictionary.dataTypes(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.label }}</option>\r\n }\r\n </select>\r\n @if (selectedType()?.requiresDataType && !selectedField()!.dataType) {\r\n <p class=\"fb-field__error\">Obbligatorio per questo tipo di campo (DATA_TYPE_MISSING).</p>\r\n }\r\n @if (selectedType()?.isCollection) {\r\n <p class=\"fb-field__hint\">\r\n Il valore raccolto e\u2019 una <strong>collection</strong>, non una stringa con i valori\r\n separati: nelle condizioni si usano gli operatori di collection.\r\n </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\" [class.fb-field__label--required]=\"objectTypeIsStructure()\">\r\n {{\r\n objectTypeIsStructure()\r\n ? 'Classe'\r\n : selectedField()!.dataType === 'Enum'\r\n ? 'Tipo di enumerazione'\r\n : 'Oggetto'\r\n }}\r\n </label>\r\n @if (selectedField()!.dataType === 'Enum') {\r\n <!-- Dizionario chiuso: si sceglie, non si scrive. -->\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.objectType || ''\"\r\n (change)=\"setFieldProperty('objectType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of enumOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n </select>\r\n @if (!selectedField()!.objectType) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Senza il tipo concreto l\u2019editor non puo\u2019 proporre i valori dell\u2019enumerazione.\r\n </p>\r\n }\r\n } @else if (objectTypeIsStructure()) {\r\n <fb-structure-picker\r\n [value]=\"selectedField()!.objectType\"\r\n label=\"Classe\"\r\n (valueChange)=\"setFieldProperty('objectType', $event ?? '')\"\r\n />\r\n @if (!selectedField()!.objectType) {\r\n <p class=\"fb-field__error\">\r\n La classe e\u2019 obbligatoria: senza, il runtime non ha nulla da istanziare\r\n (OBJECT_TYPE_MISSING).\r\n </p>\r\n }\r\n } @else {\r\n <fb-object-picker\r\n [value]=\"selectedField()!.objectType\"\r\n label=\"Oggetto\"\r\n (valueChange)=\"setFieldProperty('objectType', $event ?? '')\"\r\n />\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo dell\u2019entita\u2019</label>\r\n <p class=\"fb-field__hint\">\r\n Tipo, label, obbligatorieta\u2019, scala e \u2014 se il campo e\u2019 una picklist \u2014 le opzioni arrivano\r\n dallo schema dati: qui non si ridichiarano.\r\n </p>\r\n <fb-object-picker\r\n [value]=\"providedObject() || undefined\"\r\n label=\"Oggetto\"\r\n (valueChange)=\"setProvidedObject($event)\"\r\n />\r\n <fb-field-picker\r\n [value]=\"providedField() || undefined\"\r\n [object]=\"providedObject() || undefined\"\r\n label=\"Campo\"\r\n (valueChange)=\"setProvidedField($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedIsRequired()\"\r\n (change)=\"setRequired($any($event.target).checked)\"\r\n />\r\n Obbligatorio\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedIsEditable()\"\r\n (change)=\"setEditable($any($event.target).checked)\"\r\n />\r\n Modificabile\r\n </label>\r\n @if (!selectedIsEditable()) {\r\n <p class=\"fb-field__hint\">\r\n A <code>false</code> il runtime <strong>ignora</strong> cio\u2019 che il client rimanda indietro:\r\n e\u2019 l\u2019unico modo di rendere un campo davvero di sola lettura.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore di default</label>\r\n <fb-value-editor\r\n [value]=\"selectedField()!.defaultValue\"\r\n [dataType]=\"selectedField()!.dataType\"\r\n [objectType]=\"selectedField()!.objectType\"\r\n [isCollection]=\"selectedType()?.isCollection\"\r\n label=\"Valore di default\"\r\n (valueChange)=\"setDefaultValue($event)\"\r\n />\r\n </div>\r\n\r\n @if (scaleApplies()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Decimali</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"0\"\r\n [value]=\"selectedField()!.scale ?? ''\"\r\n (change)=\"setNumberProperty('scale', $any($event.target).value)\"\r\n />\r\n </div>\r\n } @else if (selectedField()!.scale !== undefined) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n <code>scale</code> su un campo non numerico e\u2019 SCALE_NOT_APPLICABLE.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Lunghezza massima</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"selectedField()!.maxLength ?? ''\"\r\n (change)=\"setNumberProperty('maxLength', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">Verificata anche dal runtime (TOO_LONG).</p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Tornando sulla schermata</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.inputsOnNextNavToAssocScrn || ''\"\r\n (change)=\"setFieldProperty('inputsOnNextNavToAssocScrn', $any($event.target).value)\"\r\n >\r\n <option value=\"\">Predefinito (mantieni i valori)</option>\r\n @for (entry of dictionary.screenFieldInputsRevisited(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.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\">Regola di validazione</label>\r\n <!--\r\n `commitOn=\"change\"`: qui mutare il documento ridisegna l'anteprima, e riscriverla a\r\n ogni tasto costa. La verifica parte lo stesso mentre si digita (\u00A76.3).\r\n -->\r\n <fb-formula-editor\r\n [expression]=\"selectedField()!.validationRule?.formulaExpression || ''\"\r\n usage=\"ValidationRule\"\r\n expectedDataType=\"Boolean\"\r\n commitOn=\"change\"\r\n [rows]=\"2\"\r\n placeholder=\"Espressione, es. LEN(Nome) > 3\"\r\n ariaLabel=\"Regola di validazione\"\r\n (expressionChange)=\"setValidationRule('formulaExpression', $event)\"\r\n />\r\n <input\r\n class=\"fb-input\"\r\n placeholder=\"Messaggio mostrato quando l\u2019espressione e\u2019 falsa\"\r\n [value]=\"selectedField()!.validationRule?.errorMessage || ''\"\r\n (change)=\"setValidationRule('errorMessage', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n L\u2019espressione la valuta il motore di regole: il backend non la interpreta, la fa\r\n verificare al motore.\r\n </p>\r\n </div>\r\n </fieldset>\r\n }\r\n\r\n <!-- --------------------------------------------------------------- choice -->\r\n @if (selectedType()?.acceptsChoices) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Opzioni</legend>\r\n <p class=\"fb-section__note\">\r\n Accetta <strong>Choice</strong> e <strong>Dynamic choice set</strong>, nell\u2019ordine in cui le\r\n opzioni compaiono. Puntare a una variabile e\u2019 SCREEN_FIELD_CHOICE_UNKNOWN.\r\n </p>\r\n\r\n @if (!selectedField()!.choiceReferences?.length) {\r\n @if (selectedField()!.fieldType === 'ObjectProvided') {\r\n <!-- Le opzioni di una picklist arrivano dallo schema: qui si aggiungono solo se\r\n si vuole sostituirle, e non dichiararne nessuna e' il caso normale. -->\r\n <p class=\"fb-field__hint\">\r\n Se il campo dello schema e\u2019 una picklist, le opzioni arrivano da l\u00EC: dichiararle qui\r\n serve solo a sostituirle.\r\n </p>\r\n } @else {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Nessuna opzione: il campo non ha niente da mostrare (SCREEN_FIELD_CHOICES_MISSING).\r\n </p>\r\n }\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (choice of selectedField()!.choiceReferences || []; 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__title\">{{ choice }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" (click)=\"moveChoice($index, -1)\">\u2191</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" (click)=\"moveChoice($index, 1)\">\u2193</button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--sm\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeChoice($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Aggiungi un\u2019opzione</label>\r\n <!--\r\n `commitOn=\"enter\"`: qui ogni emissione e\u2019 una riga in piu\u2019, non un campo che cambia\r\n valore \u2014 a tasto, scrivere \u00ABAlta\u00BB aggiungeva \u00ABA\u00BB, \u00ABAl\u00BB, \u00ABAlt\u00BB e \u00ABAlta\u00BB.\r\n -->\r\n <fb-name-picker\r\n [options]=\"choiceOptions()\"\r\n label=\"Choice\"\r\n commitOn=\"enter\"\r\n placeholder=\"Scegli una choice o un choice set\"\r\n unknownMessage=\"Questo nome non e\u2019 una choice ne\u2019 un choice set: e\u2019 SCREEN_FIELD_CHOICE_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Il flow non dichiara nessuna choice: creale nel pannello delle risorse.\"\r\n (valueChange)=\"addChoice($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Scegli dall\u2019elenco, oppure scrivi il nome e premi Invio.\r\n </p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Opzione selezionata all\u2019apertura</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.defaultSelectedChoiceReference || ''\"\r\n (change)=\"setFieldProperty('defaultSelectedChoiceReference', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 nessuna \u2014</option>\r\n @for (choice of selectedField()!.choiceReferences || []; track $index) {\r\n <option [value]=\"choice\">{{ choice }}</option>\r\n }\r\n </select>\r\n @if (defaultChoiceIsForeign()) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n \u00AB{{ selectedField()!.defaultSelectedChoiceReference }}\u00BB non e\u2019 fra le opzioni elencate qui\r\n sopra.\r\n </p>\r\n }\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedAutoSelectsSingleChoice()\"\r\n (change)=\"setAutoSelectSingleChoice($any($event.target).checked)\"\r\n />\r\n Scegli da sola l\u2019unica opzione\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n Quando le opzioni risolte sono <strong>esattamente una</strong>, il campo la prende da se\u2019.\r\n Serve alle tendine che dipendono da un\u2019altra tendina \u2014 i CAP di un comune \u2014 dove chiedere\r\n di scegliere l\u2019unica voce non decide niente.\r\n </p>\r\n </fieldset>\r\n }\r\n\r\n <!-- ------------------------------------------------------- contenitori -->\r\n @if (selectedType()?.isContainer) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Contenitore</legend>\r\n @if (selectedField()!.fieldType === 'RegionContainer') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Tipo di sezione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.regionContainerType || ''\"\r\n (change)=\"setFieldProperty('regionContainerType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 predefinito \u2014</option>\r\n @for (entry of dictionary.regionContainerTypes(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n }\r\n @if (!selectedField()!.fields?.length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il contenitore e\u2019 vuoto: non produce niente sulla schermata (SCREEN_CONTAINER_EMPTY).\r\n </p>\r\n }\r\n </fieldset>\r\n }\r\n\r\n <!-- --------------------------------------------------- ComponentInstance -->\r\n @if (selectedField()!.fieldType === 'ComponentInstance') {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Componente</legend>\r\n <p class=\"fb-section__note\">\r\n Componenti e form sono la stessa domanda al frontend \u2014 cosa sa rendere, e con quali parametri\r\n \u2014 e passano dallo stesso catalogo. Un <code>ComponentInstance</code> non ha un valore proprio:\r\n lo hanno i suoi output.\r\n </p>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Componente</label>\r\n <fb-name-picker\r\n [value]=\"selectedField()!.extensionName\"\r\n [options]=\"componentOptions()\"\r\n [unusableOptions]=\"unusableComponents()\"\r\n label=\"Componente\"\r\n placeholder=\"Scrivi o scegli un componente\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo componente non esiste nel catalogo: e\u2019 SCREEN_COMPONENT_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n unusableMessage=\"Questo nome e\u2019 una schermata intera, non un componente montabile qui (FORM_KIND_MISMATCH).\"\r\n emptyMessage=\"Il catalogo dei componenti non e\u2019 popolato: il nome non viene verificato.\"\r\n (valueChange)=\"setFieldProperty('extensionName', $event ?? '')\"\r\n />\r\n @if (!selectedField()!.extensionName) {\r\n <p class=\"fb-field__error\">Obbligatorio: senza, SCREEN_COMPONENT_MISSING.</p>\r\n }\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedField()!.storeOutputAutomatically === true\"\r\n (change)=\"setStoreOutputAutomatically($any($event.target).checked)\"\r\n />\r\n Rendi gli output referenziabili automaticamente\r\n </label>\r\n @if (selectedField()!.storeOutputAutomatically) {\r\n <p class=\"fb-field__hint\">\r\n Gli output si referenziano come\r\n <code>{{ selectedField()!.name || 'Campo' }}.nomeOutput</code>, senza dichiarare variabili.\r\n </p>\r\n }\r\n @if (hasOutputConflict()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Output automatici <strong>e</strong> parametri di uscita insieme:\r\n OUTPUT_CONFIGURATION_CONFLICT.\r\n </p>\r\n }\r\n\r\n <fb-parameter-editor\r\n [holder]=\"$any(selectedField())\"\r\n [catalogParameters]=\"componentParameterList()\"\r\n inputTitle=\"Valori passati al componente\"\r\n outputTitle=\"Valori raccolti dal componente\"\r\n [showOutputs]=\"!selectedField()!.storeOutputAutomatically\"\r\n outputsDisabledReason=\"Gli output sono automatici: disattivalo per assegnarli a variabili.\"\r\n (changed)=\"onComponentParametersChanged($event)\"\r\n />\r\n </fieldset>\r\n }\r\n\r\n <!-- ------------------------------------------------------- visibilita' -->\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Visibilita\u2019</legend>\r\n <p class=\"fb-section__note\">\r\n Le regole si rivalutano <strong>sui valori appena inviati</strong>: e\u2019 cos\u00EC che un campo compare\r\n in funzione di un altro campo della stessa schermata. Un campo risultato nascosto viene\r\n <strong>azzerato</strong> e non viene validato.\r\n </p>\r\n <fb-condition-editor\r\n [holder]=\"visibilityRule()\"\r\n title=\"Mostra il campo quando\"\r\n [allowFormula]=\"false\"\r\n [issuePath]=\"'fields[' + (selectedField()!.name || '') + '].visibilityRule'\"\r\n (changed)=\"onVisibilityChanged($event)\"\r\n />\r\n </fieldset>\r\n }\r\n </aside>\r\n</div>\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\r\n<!--\r\n ============================================================== l'anteprima\r\n Due template ricorsivi. `listTpl` disegna i figli di un contenitore, e nient'altro: `data-item`\r\n marca cio' che conta come fratello nel calcolo del punto di rilascio, e il segnaposto del\r\n contenitore vuoto ne resta fuori. La barra di inserimento non e' qui \u2014 sta sopra l'anteprima,\r\n vedi il velo nel frame.\r\n-->\r\n<ng-template #listTpl let-fields let-parent=\"parent\" let-axis=\"axis\">\r\n @for (child of fields; track $index) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"fieldTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: child, path: childPath(parent, $index), axis: axis }\"\r\n />\r\n }\r\n @if (!fields.length) {\r\n <p class=\"fb-scr__drop-hint\">Trascina qui un componente</p>\r\n }\r\n</ng-template>\r\n\r\n<ng-template #fieldTpl let-field let-path=\"path\" let-axis=\"axis\">\r\n <div\r\n class=\"fb-scr__item\"\r\n data-item=\"\"\r\n cdkDrag\r\n [style.grid-column]=\"'span ' + widthOf(field)\"\r\n [class.fb-scr__item--selected]=\"isSelected(path)\"\r\n [class.fb-scr__item--dragging]=\"isDragging(path)\"\r\n [class.fb-scr__item--container]=\"isContainer(field)\"\r\n (cdkDragStarted)=\"onFieldDragStarted(path)\"\r\n (cdkDragMoved)=\"onFieldDragMoved($event)\"\r\n (cdkDragEnded)=\"onFieldDragEnded($event, path)\"\r\n (click)=\"select(path); $event.stopPropagation()\"\r\n >\r\n <span class=\"fb-scr__grip\" cdkDragHandle title=\"Trascina per spostare\" aria-hidden=\"true\">\u283F</span>\r\n @if (field.visibilityRule?.conditions?.length) {\r\n <span class=\"fb-scr__flag\" title=\"Ha una regola di visibilita\u2019\">\u25D0</span>\r\n }\r\n\r\n @switch (field.fieldType) {\r\n @case ('RegionContainer') {\r\n <div class=\"fb-scr__section\">\r\n @if (field.regionContainerType !== 'SectionWithoutHeader') {\r\n <header class=\"fb-scr__section-head\">{{ field.fieldText || field.name }}</header>\r\n }\r\n <div class=\"fb-scr__cols\" [attr.data-drop]=\"dropId(path)\" data-axis=\"row\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: field.fields || [], parent: path, axis: 'row' }\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case ('Region') {\r\n <div class=\"fb-scr__region\">\r\n <span class=\"fb-scr__region-tag\">{{ field.name }} \u00B7 {{ widthOf(field) }}/12</span>\r\n <div class=\"fb-scr__region-body\" [attr.data-drop]=\"dropId(path)\" data-axis=\"column\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: field.fields || [], parent: path, axis: 'column' }\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case ('DisplayText') {\r\n <p class=\"fb-scr__display\">{{ field.fieldText || '(testo vuoto)' }}</p>\r\n }\r\n @case ('LargeTextArea') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control fb-scr__control--area\">{{ placeholderOf(field) }}</div>\r\n }\r\n @case ('PasswordField') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control\">\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022</div>\r\n }\r\n @case ('DropdownBox') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control fb-scr__control--select\">\r\n <span>{{ field.defaultSelectedChoiceReference || choiceLabelsOf(field)[0] || '\u2014 scegli \u2014' }}</span>\r\n <span aria-hidden=\"true\">\u25BE</span>\r\n </div>\r\n }\r\n @case ('MultiSelectPicklist') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control fb-scr__control--select\">\r\n <span>{{ choiceLabelsOf(field).join(', ') || '\u2014 scegli \u2014' }}</span>\r\n <span aria-hidden=\"true\">\u2261</span>\r\n </div>\r\n }\r\n @case ('RadioButtons') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__options\">\r\n @for (option of choiceLabelsOf(field); track $index) {\r\n <span class=\"fb-scr__option\">\u25EF {{ option }}</span>\r\n }\r\n @if (!choiceLabelsOf(field).length) {\r\n <span class=\"fb-scr__option fb-scr__option--missing\">Nessuna opzione</span>\r\n }\r\n </div>\r\n }\r\n @case ('MultiSelectCheckboxes') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__options\">\r\n @for (option of choiceLabelsOf(field); track $index) {\r\n <span class=\"fb-scr__option\">\u2610 {{ option }}</span>\r\n }\r\n @if (!choiceLabelsOf(field).length) {\r\n <span class=\"fb-scr__option fb-scr__option--missing\">Nessuna opzione</span>\r\n }\r\n </div>\r\n }\r\n @case ('ComponentInstance') {\r\n <!--\r\n L\u2019etichetta si disegna se c\u2019e\u2019: il runtime la consegna in `label` come per gli altri\r\n campi (\u00A75.2). Nessun asterisco: un componente non raccoglie un valore, quindi\r\n \u00ABobbligatorio\u00BB non ha niente su cui applicarsi.\r\n -->\r\n @if (field.fieldText) {\r\n <label class=\"fb-scr__label\">{{ field.fieldText }}</label>\r\n }\r\n <div class=\"fb-scr__component\">\r\n <span aria-hidden=\"true\">\u2B21</span>\r\n {{ field.extensionName || 'Componente non indicato' }}\r\n </div>\r\n }\r\n @case ('ObjectProvided') {\r\n <label class=\"fb-scr__label\">\r\n {{ field.fieldText || field.objectFieldReference || field.name }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control\">{{ placeholderOf(field) }}</div>\r\n <span class=\"fb-scr__tag\">{{ field.objectFieldReference || 'campo non indicato' }}</span>\r\n }\r\n @default {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control\">{{ placeholderOf(field) }}</div>\r\n @if (isUnknownType(field)) {\r\n <span class=\"fb-scr__tag fb-scr__tag--warn\">{{ field.fieldType }}: tipo non nel dizionario</span>\r\n }\r\n }\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: [".fb-scr{display:grid;grid-template-columns:220px minmax(0,1fr) 340px;gap:12px;align-items:start;margin-bottom:14px}@media(max-width:1100px){.fb-scr{grid-template-columns:minmax(0,1fr)}}.fb-scr__side,.fb-scr__props{min-width:0;padding:10px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__tabs{display:flex;gap:4px;margin-bottom:8px}.fb-scr__tab{flex:1;padding:5px 8px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text-muted, #6b7086);font:inherit;font-size:11px;font-weight:600;cursor:pointer}.fb-scr__tab--active{border-color:var(--fb-accent, #4f6ef7);background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 10%,transparent);color:var(--fb-accent-strong, #3d59e0)}.fb-scr__side-hint,.fb-scr__side-empty{margin:6px 0;font-size:11px;color:var(--fb-text-muted, #6b7086)}.fb-scr__palette{display:flex;flex-direction:column;gap:4px;margin:8px 0 0;padding:0;max-height:320px;overflow-y:auto;overscroll-behavior:contain;list-style:none}.fb-scr__chip{display:flex;align-items:center;gap:8px;width:100%;padding:6px 8px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text, #1a1c23);font:inherit;font-size:12px;text-align:left;cursor:grab}.fb-scr__chip:hover{border-color:var(--fb-accent, #4f6ef7)}.fb-scr__chip-icon{flex:none;width:20px;text-align:center;color:var(--fb-text-muted, #6b7086)}.fb-scr__chip-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-scr__chip-label small{margin-left:4px;color:var(--fb-text-subtle, #98a2b3);font-size:10px}.fb-scr__canvas{min-width:0;padding:14px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-canvas-bg, #f4f5f7);max-height:60vh;overflow-y:auto}.fb-scr__frame{position:relative;display:flex;flex-direction:column;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-sm, 8px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));overflow:hidden}.fb-scr__frame-head{display:flex;align-items:center;gap:6px;padding:8px 12px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4);font-size:13px;font-weight:600}.fb-scr__help{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;border-radius:50%;background:var(--fb-surface-sunken, #eef0f4);color:var(--fb-text-muted, #6b7086);font-size:10px}.fb-scr__body,.fb-scr__region-body{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));align-content:start;gap:8px 0;padding:12px;min-height:90px}.fb-scr__region-body{padding:8px;min-height:60px}.fb-scr__cols{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));align-items:stretch;gap:0;padding:8px;min-height:60px}.fb-scr__cols>.fb-scr__item{display:flex;align-self:stretch}.fb-scr__cols>.fb-scr__item>.fb-scr__region{flex:1;min-width:0}.fb-scr__drop-hint{grid-column:1 / -1;margin:0;padding:10px;border:1px dashed var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);color:var(--fb-text-subtle, #98a2b3);font-size:11px;text-align:center}.fb-scr__marker{position:absolute;z-index:2;border-radius:2px;background:var(--fb-accent, #4f6ef7);pointer-events:none}.fb-scr__item{position:relative;box-sizing:border-box;padding:6px 8px;border:1px solid transparent;border-radius:var(--fb-radius-xs, 6px);cursor:pointer}.fb-scr__item:hover{border-color:var(--fb-border-strong, #cfd4de);background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 4%,transparent)}.fb-scr__item--selected{border-color:var(--fb-accent, #4f6ef7);box-shadow:inset 0 0 0 1px var(--fb-accent, #4f6ef7)}.fb-scr__item--dragging{opacity:.45;pointer-events:none}.fb-scr__grip{position:absolute;top:2px;left:-2px;padding:0 3px;color:var(--fb-text-subtle, #98a2b3);font-size:11px;line-height:1;opacity:0;cursor:grab}.fb-scr__item:hover>.fb-scr__grip,.fb-scr__item--selected>.fb-scr__grip{opacity:1}.fb-scr__flag{position:absolute;top:2px;right:4px;color:var(--fb-text-muted, #6b7086);font-size:11px}.fb-scr__label{display:block;margin-bottom:3px;font-size:11px;font-weight:600;color:var(--fb-text, #1a1c23)}.fb-scr__req{color:var(--fb-error, #dc2626)}.fb-scr__control{display:flex;align-items:center;justify-content:space-between;gap:6px;min-height:26px;padding:4px 8px;border:1px solid var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text-subtle, #98a2b3);font-size:12px;pointer-events:none}.fb-scr__control--area{min-height:54px;align-items:flex-start}.fb-scr__display{margin:0;font-size:12px;color:var(--fb-text, #1a1c23)}.fb-scr__options{display:flex;flex-direction:column;gap:2px;pointer-events:none}.fb-scr__option{font-size:12px;color:var(--fb-text-muted, #6b7086)}.fb-scr__option--missing{color:var(--fb-warning, #b7791f)}.fb-scr__component{display:flex;align-items:center;gap:6px;padding:10px;border:1px dashed var(--fb-accent, #4f6ef7);border-radius:var(--fb-radius-xs, 6px);background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 5%,transparent);font-size:12px;color:var(--fb-text-muted, #6b7086)}.fb-scr__tag{display:inline-block;margin-top:3px;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-scr__tag--warn{color:var(--fb-warning, #b7791f)}.fb-scr__section{border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__section-head{padding:5px 10px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--fb-text-muted, #6b7086)}.fb-scr__region{border:1px dashed var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff)}.fb-scr__region-tag{display:block;padding:3px 6px 0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-scr__frame-foot{display:flex;align-items:center;gap:6px;padding:8px 12px;border-top:1px solid var(--fb-border-subtle, #eef0f4);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__spacer{flex:1}.fb-scr__btn{padding:3px 10px;border:1px solid var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);font-size:11px;color:var(--fb-text-muted, #6b7086)}.fb-scr__btn--primary{border-color:var(--fb-accent, #4f6ef7);background:var(--fb-accent, #4f6ef7);color:var(--fb-accent-contrast, #fff)}.fb-scr__canvas-note{margin-top:10px}.fb-scr__props{background:var(--fb-surface, #fff)}.fb-scr__props-head{display:flex;align-items:center;gap:8px;margin-bottom:8px}.fb-scr__props-title{flex:1;min-width:0;margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--fb-text-muted, #6b7086)}.fb-scr__props-actions{display:flex;flex-wrap:wrap;gap:3px}.fb-btn--sm{padding:3px 7px;font-size:11px}.fb-scr__width{display:flex;align-items:center;gap:8px}.fb-scr__width input[type=range]{flex:1;min-width:0}.fb-scr__width-value{font-size:11px;color:var(--fb-text-muted, #6b7086)}\n"] }]
|
|
12912
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-scr\" #composer>\r\n <!-- ============================================================ sinistra -->\r\n <aside class=\"fb-scr__side\" aria-label=\"Componenti e campi\">\r\n <div class=\"fb-scr__tabs\" role=\"tablist\">\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"fb-scr__tab\"\r\n [class.fb-scr__tab--active]=\"paletteTab() === 'components'\"\r\n [attr.aria-selected]=\"paletteTab() === 'components'\"\r\n (click)=\"setPaletteTab('components')\"\r\n >\r\n Componenti\r\n </button>\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"fb-scr__tab\"\r\n [class.fb-scr__tab--active]=\"paletteTab() === 'fields'\"\r\n [attr.aria-selected]=\"paletteTab() === 'fields'\"\r\n (click)=\"setPaletteTab('fields')\"\r\n >\r\n Campi\r\n </button>\r\n </div>\r\n\r\n @if (paletteTab() === 'components') {\r\n @if (!dictionary.screenFieldTypes().length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il dizionario <code>screenFieldTypes</code> non e\u2019 disponibile: senza i suoi flag l\u2019editor non\r\n sa quali campi ammette ciascun tipo, e non li inventa.\r\n </p>\r\n }\r\n <p class=\"fb-scr__side-hint\">Trascina sulla schermata, oppure clicca per aggiungere.</p>\r\n <ul class=\"fb-scr__palette\">\r\n @for (entry of dictionary.screenFieldTypes(); track entry.value) {\r\n <li>\r\n <!--\r\n \u00A75.2 \u2014 l'unico chip che si spegne: una sezione ripetibile dentro un'altra. Non si\r\n annidano, e il cursore e' una variabile sola per sezione.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-scr__chip\"\r\n cdkDrag\r\n [disabled]=\"!canAddAtSelection(entry.value)\"\r\n [title]=\"\r\n canAddAtSelection(entry.value)\r\n ? entry.description || entry.label\r\n : 'Le sezioni ripetibili non si annidano: seleziona un punto fuori dalla riga.'\r\n \"\r\n (cdkDragMoved)=\"onPaletteDragMoved($event)\"\r\n (cdkDragEnded)=\"onComponentDragEnded($event, entry.value)\"\r\n (click)=\"addComponentAtSelection(entry.value)\"\r\n >\r\n <span class=\"fb-scr__chip-icon\" aria-hidden=\"true\">{{ iconOf(entry.value) }}</span>\r\n <span class=\"fb-scr__chip-label\">{{ entry.label }}</span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n } @else {\r\n <p class=\"fb-scr__side-hint\">\r\n Un campo dell\u2019entita\u2019 porta con se\u2019 tipo, etichetta, obbligatorieta\u2019 e opzioni: arrivano dallo\r\n schema dati, qui non si ridichiarano.\r\n </p>\r\n <!-- Il catalogo non e' un dizionario chiuso: si sceglie o si scrive, come ovunque si\r\n indichi un'entita' (vedi `object-picker`). -->\r\n <fb-object-picker\r\n [value]=\"fieldsObject()\"\r\n label=\"Entita\u2019\"\r\n placeholder=\"Scrivi o scegli un\u2019entita\u2019\"\r\n (valueChange)=\"setFieldsObject($event)\"\r\n />\r\n @if (fieldsObject() && !fieldsOfObject().length) {\r\n <p class=\"fb-scr__side-empty\">\r\n Nessun campo dichiarato per questa entita\u2019: il catalogo non li espone, non significa che non\r\n ci siano.\r\n </p>\r\n }\r\n <ul class=\"fb-scr__palette\">\r\n @for (field of fieldsOfObject(); track $index) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-scr__chip\"\r\n cdkDrag\r\n [title]=\"field.name + (field.dataType ? ' \u00B7 ' + field.dataType : '')\"\r\n (cdkDragMoved)=\"onPaletteDragMoved($event)\"\r\n (cdkDragEnded)=\"onObjectFieldDragEnded($event, field)\"\r\n (click)=\"addObjectFieldAtSelection(field)\"\r\n >\r\n <span class=\"fb-scr__chip-icon\" aria-hidden=\"true\">\u2317</span>\r\n <span class=\"fb-scr__chip-label\">\r\n {{ field.label || field.name }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n <small>{{ field.dataType }}</small>\r\n </span>\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n }\r\n </aside>\r\n\r\n <!-- ============================================================== centro -->\r\n <!-- Cliccare fuori da un campo riporta a destra le proprieta' della schermata. -->\r\n <section class=\"fb-scr__canvas\" aria-label=\"Anteprima della schermata\" (click)=\"selectScreen()\">\r\n <div class=\"fb-scr__frame\">\r\n @if (showHeader()) {\r\n <header class=\"fb-scr__frame-head\">\r\n {{ $any(node()).label || name() }}\r\n @if (screen().helpText) {\r\n <span class=\"fb-scr__help\" [title]=\"screen().helpText || ''\">?</span>\r\n }\r\n </header>\r\n }\r\n\r\n <div\r\n class=\"fb-scr__body\"\r\n [attr.data-drop]=\"''\"\r\n data-axis=\"column\"\r\n [class.fb-scr__body--empty]=\"isEmpty()\"\r\n >\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: screen().fields || [], parent: [], axis: 'column' }\"\r\n />\r\n </div>\r\n\r\n <!--\r\n La barra di inserimento e' un **velo** sopra l'anteprima, non un figlio del contenitore di\r\n rilascio: dentro la griglia occupava una riga intera e spostava in basso proprio la sezione\r\n che si stava puntando, che allora usciva da sotto il puntatore e il bersaglio oscillava.\r\n -->\r\n @if (dropMarker(); as bar) {\r\n <div\r\n class=\"fb-scr__marker\"\r\n [style.left.px]=\"bar.left\"\r\n [style.top.px]=\"bar.top\"\r\n [style.width.px]=\"bar.width\"\r\n [style.height.px]=\"bar.height\"\r\n ></div>\r\n }\r\n\r\n @if (showFooter()) {\r\n <footer class=\"fb-scr__frame-foot\">\r\n @if (allowPause()) {\r\n <span class=\"fb-scr__btn fb-scr__btn--ghost\">{{ screen().pauseButtonLabel || 'Pausa' }}</span>\r\n }\r\n <span class=\"fb-scr__spacer\"></span>\r\n @if (allowBack()) {\r\n <span class=\"fb-scr__btn fb-scr__btn--ghost\">{{ screen().backButtonLabel || 'Indietro' }}</span>\r\n }\r\n <span class=\"fb-scr__btn fb-scr__btn--primary\">\r\n {{ screen().nextOrFinishButtonLabel || (allowFinish() ? 'Fine' : 'Avanti') }}\r\n </span>\r\n </footer>\r\n }\r\n </div>\r\n\r\n @if (isEmpty()) {\r\n <p class=\"fb-callout fb-callout--warn fb-scr__canvas-note\">\r\n La schermata non ha campi: non c\u2019e\u2019 niente da mostrare all\u2019utente (SCREEN_WITHOUT_FIELDS).\r\n </p>\r\n }\r\n </section>\r\n\r\n <!-- ============================================================== destra -->\r\n <aside class=\"fb-scr__props\" aria-label=\"Proprieta\u2019\">\r\n @if (!selectedField()) {\r\n <!-- ------------------------------------------------ proprieta' della schermata -->\r\n <header class=\"fb-scr__props-head\">\r\n <h3 class=\"fb-scr__props-title\">Schermata</h3>\r\n </header>\r\n <p class=\"fb-scr__side-hint\">Seleziona un campo nell\u2019anteprima per configurarlo.</p>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo di aiuto</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"screen().helpText || ''\"\r\n (input)=\"setScreenText('helpText', $any($event.target).value)\"\r\n ></textarea>\r\n </div>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Navigazione</legend>\r\n <p class=\"fb-section__note\">\r\n Questi flag sono un\u2019intenzione, non la verita\u2019 finale: a runtime il motore comunica\r\n <code>canGoBack</code>, <code>canFinish</code> e <code>canPause</code> nella richiesta della\r\n schermata.\r\n </p>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowBack()\" (change)=\"setScreenFlag('allowBack', $any($event.target).checked)\" />\r\n Consenti \u00ABindietro\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowFinish()\" (change)=\"setScreenFlag('allowFinish', $any($event.target).checked)\" />\r\n Consenti \u00ABfine\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowPause()\" (change)=\"setScreenFlag('allowPause', $any($event.target).checked)\" />\r\n Consenti \u00ABpausa\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"showHeader()\" (change)=\"setScreenFlag('showHeader', $any($event.target).checked)\" />\r\n Mostra l\u2019intestazione\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"showFooter()\" (change)=\"setScreenFlag('showFooter', $any($event.target).checked)\" />\r\n Mostra il piede\r\n </label>\r\n\r\n @if (allowPause()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo mostrato alla pausa</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().pausedText || ''\"\r\n (input)=\"setScreenText('pausedText', $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (isDeadEnd()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Questa schermata non ha una destinazione e non consente \u00ABfine\u00BB: e\u2019 un vicolo cieco, e\r\n l\u2019utente resterebbe bloccato (SCREEN_DEAD_END).\r\n </p>\r\n }\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Pulsanti</legend>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta \u00ABindietro\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().backButtonLabel || ''\"\r\n (input)=\"setScreenText('backButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta \u00ABavanti / fine\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().nextOrFinishButtonLabel || ''\"\r\n (input)=\"setScreenText('nextOrFinishButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Etichetta \u00ABpausa\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().pauseButtonLabel || ''\"\r\n (input)=\"setScreenText('pauseButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n </fieldset>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Stage mostrato nell\u2019avanzamento</label>\r\n <fb-name-picker\r\n [value]=\"screen().stageReference\"\r\n [options]=\"stageOptions()\"\r\n label=\"Stage\"\r\n placeholder=\"Scegli uno stage\"\r\n unknownMessage=\"Questo stage non e\u2019 dichiarato dal flow.\"\r\n emptyMessage=\"Il flow non dichiara stage: creali nel pannello delle risorse.\"\r\n (valueChange)=\"setScreenText('stageReference', $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <!--\r\n Screen action (\u00A75.2). Due elenchi e non uno perche' il contratto li separa: piu' trigger\r\n possono invocare la stessa action, quindi \u00ABchi la chiama\u00BB non e' una sua proprieta'. Le\r\n action si aprono una alla volta: i cataloghi dipendono da tipo e nome, e tenerne N in volo\r\n sarebbe N volte la corsa fra risposte.\r\n -->\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Azioni della schermata</legend>\r\n <p class=\"fb-section__note\">\r\n Un campo che l\u2019utente compila puo\u2019 innescare un\u2019action i cui risultati finiscono negli\r\n <strong>altri campi di questa schermata</strong>: e\u2019 il caso \u00ABscrivi il codice fiscale e nome\r\n e cognome compaiono da soli\u00BB. L\u2019alternativa sarebbe spezzare la schermata in due con un\r\n elemento Action in mezzo.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (action of screenActions(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost\"\r\n [attr.aria-expanded]=\"selectedActionIndex() === $index\"\r\n (click)=\"selectAction(selectedActionIndex() === $index ? null : $index)\"\r\n >\r\n {{ selectedActionIndex() === $index ? '\u25BE' : '\u25B8' }}\r\n {{ action.name || '(senza nome)' }}\r\n </button>\r\n <span class=\"fb-list__spacer\"></span>\r\n <span class=\"fb-scr__side-hint\">{{ action.actionName || 'action non scelta' }}</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\u2019action\"\r\n (click)=\"removeScreenAction($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n @if (actionLosesResult(action)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questa action viene invocata ma il suo risultato si perde: aggiungi un parametro di\r\n uscita, oppure accendi l\u2019output automatico (SCREEN_ACTION_WITHOUT_OUTPUTS).\r\n </p>\r\n }\r\n @if (actionHasNoTrigger(action)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Nessun trigger la invoca: senza, non girera\u2019 mai.\r\n </p>\r\n }\r\n\r\n @if (selectedActionIndex() === $index) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Nome</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"action.name || ''\"\r\n (change)=\"setActionName($index, $any($event.target).value)\"\r\n />\r\n @if (actionNameError(action); as error) {\r\n <p class=\"fb-field__error\">{{ error }}</p>\r\n }\r\n <p class=\"fb-field__hint\">\r\n E\u2019 il nome con cui la citano i trigger, e vive nello spazio dei nomi del flow. Con\r\n l\u2019output automatico e\u2019 anche la radice del riferimento:\r\n <code>{{ action.name || 'Cerca' }}.NomeOutput</code>.\r\n </p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Tipo di action</label>\r\n <fb-name-picker\r\n [value]=\"action.actionType\"\r\n [options]=\"actionTypeOptions()\"\r\n label=\"Tipo di action\"\r\n placeholder=\"Scrivi o scegli un tipo\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo tipo di action non e\u2019 fra quelli dichiarati dal sistema ospite.\"\r\n emptyMessage=\"Catalogo dei tipi di action non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setActionType($index, $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Action</label>\r\n <fb-name-picker\r\n [value]=\"action.actionName\"\r\n [options]=\"actionOptions()\"\r\n label=\"Action\"\r\n placeholder=\"Scrivi o scegli un\u2019action\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questa action non esiste nel catalogo del tipo scelto: e\u2019 ACTION_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Scegli prima il tipo di action, oppure scrivi il nome a mano.\"\r\n (valueChange)=\"setActionTarget($index, $event ?? '')\"\r\n />\r\n @if (!action.actionName) {\r\n <p class=\"fb-field__error\">Obbligatoria: senza, ACTION_NAME_MISSING.</p>\r\n }\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"action.storeOutputAutomatically === true\"\r\n (change)=\"setActionStoreOutput($index, $any($event.target).checked)\"\r\n />\r\n Output automatico\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n L\u2019output automatico rende il risultato leggibile come\r\n <code>{{ action.name || 'Cerca' }}.NomeOutput</code>, ma\r\n <strong>non scrive in nessun campo</strong>: e\u2019 la forma da usare quando il risultato\r\n serve a una condizione, non a precompilare.\r\n </p>\r\n\r\n <!--\r\n L'unico posto in cui un campo di schermata e' una destinazione (\u00A75.2):\r\n `POST /flows/references/writable` continua a escluderlo, e un Assignment che ci\r\n scrive resta TARGET_NOT_WRITABLE.\r\n -->\r\n <fb-parameter-editor\r\n [holder]=\"action\"\r\n [catalogParameters]=\"actionParameterCatalog()\"\r\n [showOutputs]=\"action.storeOutputAutomatically !== true\"\r\n outputTitle=\"Campi da riempire\"\r\n [extraTargets]=\"screenFieldTargets()\"\r\n [outputsDisabledReason]=\"\r\n action.storeOutputAutomatically === true\r\n ? 'Con l\u2019output automatico il risultato non viene scritto nei campi.'\r\n : null\r\n \"\r\n (changed)=\"onActionParametersChanged($index, $event)\"\r\n />\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessuna action: i campi di questa schermata li compila solo l\u2019utente.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addScreenAction()\">Aggiungi action</button>\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Trigger</legend>\r\n <p class=\"fb-section__note\">\r\n Quale campo invoca quale action. Senza condizioni l\u2019action gira a ogni cambio del campo.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (trigger of screenTriggers(); 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 trigger\"\r\n (click)=\"removeScreenTrigger($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\">Action da invocare</label>\r\n <fb-name-picker\r\n [value]=\"trigger.screenActionName\"\r\n [options]=\"screenActionOptions()\"\r\n label=\"Action della schermata\"\r\n placeholder=\"Scegli un\u2019action\"\r\n unknownMessage=\"Questa schermata non dichiara un\u2019action con questo nome: e\u2019 SCREEN_ACTION_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Aggiungi prima un\u2019action qui sopra.\"\r\n (valueChange)=\"setTriggerProperty($index, 'screenActionName', $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo che la innesca</label>\r\n <!-- I campi di **questa** schermata, non i riferimenti in generale (\u00A75.2). -->\r\n <fb-name-picker\r\n [value]=\"trigger.triggerFieldName\"\r\n [options]=\"triggerFieldOptions()\"\r\n label=\"Campo della schermata\"\r\n placeholder=\"Scegli un campo\"\r\n unknownMessage=\"Questo non e\u2019 un campo di questa schermata: e\u2019 SCREEN_TRIGGER_FIELD_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"La schermata non ha ancora campi che raccolgono un valore.\"\r\n (valueChange)=\"setTriggerProperty($index, 'triggerFieldName', $event ?? '')\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">All\u2019arrivo sulla schermata</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"trigger.initBehavior || ''\"\r\n (change)=\"setTriggerProperty($index, 'initBehavior', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 non invocare \u2014</option>\r\n <option value=\"runOnLoad\">Invoca al caricamento (runOnLoad)</option>\r\n </select>\r\n @if (triggerInitIsUnknown(trigger)) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ trigger.initBehavior }}\u00BB non e\u2019 ammesso: l\u2019unico valore e\u2019 <code>runOnLoad</code>\r\n (SCREEN_TRIGGER_INIT_BEHAVIOR_UNKNOWN).\r\n </p>\r\n }\r\n @if (triggerFiresOnLoadByDefault(trigger)) {\r\n <p class=\"fb-field__hint\">\r\n Non serve: \u00AB{{ trigger.triggerFieldName }}\u00BB ha un valore di default, e un campo\r\n precompilato dal flow innesca l\u2019action gi\u00E0 all\u2019arrivo sulla schermata.\r\n </p>\r\n }\r\n </div>\r\n\r\n @if (triggerHasNoCause(trigger)) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Senza un campo che la innesca e senza l\u2019invocazione al caricamento, questo trigger non\r\n scattera\u2019 mai (SCREEN_TRIGGER_WITHOUT_CAUSE).\r\n </p>\r\n }\r\n\r\n <fb-condition-editor\r\n [holder]=\"triggerConditions(trigger)\"\r\n title=\"Invoca l\u2019action quando\"\r\n [allowFormula]=\"false\"\r\n [issuePath]=\"'triggers[' + $index + ']'\"\r\n (changed)=\"onTriggerConditionsChanged($index, $event)\"\r\n />\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun trigger: le action dichiarate non verranno invocate.</p>\r\n }\r\n </div>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addScreenTrigger()\">Aggiungi trigger</button>\r\n </fieldset>\r\n } @else {\r\n <!-- ---------------------------------------------------- proprieta' del campo -->\r\n <header class=\"fb-scr__props-head\">\r\n <h3 class=\"fb-scr__props-title\">{{ captionOf(selectedField()!) }}</h3>\r\n <div class=\"fb-scr__props-actions\">\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" title=\"Sposta su\" (click)=\"moveSelected(-1)\">\u2191</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" title=\"Sposta giu\u2019\" (click)=\"moveSelected(1)\">\u2193</button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--sm\"\r\n title=\"Porta fuori dal contenitore\"\r\n [disabled]=\"!canOutdent()\"\r\n (click)=\"outdentSelected()\"\r\n >\r\n \u21E4\r\n </button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" title=\"Duplica\" (click)=\"duplicateSelected()\">\u29C9</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--danger fb-btn--sm\" title=\"Elimina\" (click)=\"removeSelected()\">\r\n \u00D7\r\n </button>\r\n </div>\r\n </header>\r\n\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]=\"selectedField()!.fieldType || ''\"\r\n (change)=\"setFieldType($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n <!--\r\n \u00A75.2 \u2014 dentro una riga la sezione ripetibile non c'e': **non si annidano**, perche' il\r\n cursore e' una variabile sola per sezione. La validazione lo rifiuterebbe comunque, ma\r\n lasciar comporre e poi accusare fa perdere tempo due volte.\r\n -->\r\n @for (entry of fieldTypeOptions(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.label }}</option>\r\n }\r\n </select>\r\n @if (isInsideRepeater()) {\r\n <p class=\"fb-field__hint\">\r\n Questo campo sta dentro la riga di <code>{{ selectedRepeater()!.name }}</code>: esiste una\r\n volta per ogni elemento della collection, quindi\r\n <strong>non e\u2019 una risorsa del flow</strong> e non si nomina per nome. Dentro una riga si\r\n nomina il cursore \u2014\r\n <code>{{ rowCursor() || 'itemReference' }}.<membro></code> \u2014 e scrivere\r\n <code>{{ selectedField()!.name }}</code> in una condizione, in una formula o in un parametro\r\n e\u2019 <code>SCREEN_FIELD_IN_REPEATER</code>.\r\n </p>\r\n }\r\n @if (!selectedField()!.fieldType) {\r\n <p class=\"fb-field__error\">Il tipo e\u2019 obbligatorio: senza, SCREEN_FIELD_TYPE_MISSING.</p>\r\n } @else if (isUnknownType(selectedField())) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Questo tipo non e\u2019 nel dizionario: l\u2019editor non sa quali campi ammetta e mostra solo i comuni.\r\n </p>\r\n } @else if (selectedType()?.description) {\r\n <p class=\"fb-field__hint\">{{ selectedType()?.description }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Nome</label>\r\n <!-- Sul `change` e non sull\u2019`input`: la rinomina riscrive i riferimenti nel documento,\r\n e farlo a ogni tasto significherebbe riscriverlo per ogni lettera. -->\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"selectedField()!.name || ''\"\r\n (change)=\"setFieldName($any($event.target).value)\"\r\n />\r\n @if (selectedIsResource() && !isInsideRepeater()) {\r\n <p class=\"fb-field__hint\">\r\n Questo campo e\u2019 una <strong>risorsa</strong>: lo referenzi come\r\n <code>{{ selectedField()!.name || 'Nome' }}</code> in condizioni, formule e parametri. \u00C8 di\r\n sola lettura per il flow \u2014 un Assignment che ci scrive e\u2019 TARGET_NOT_WRITABLE.\r\n </p>\r\n } @else if (isInsideRepeater()) {\r\n <p class=\"fb-field__hint\">\r\n Il nome resta comunque <strong>unico</strong>: e\u2019 l\u2019indirizzo con cui il frontend rende il\r\n campo, e un omonimo di una variabile e\u2019 <code>NAME_DUPLICATED</code> come sempre.\r\n </p>\r\n }\r\n </div>\r\n\r\n <!--\r\n \u00A75.2 \u2014 `memberName` e il riferimento con cui gli altri campi lo nominano sono la **stessa\r\n domanda posta due volte**: `memberName: \"PodId\"` e `PuntoCorrente.PodId` sono lo stesso\r\n membro, e la classe da cui vengono e' l'`objectType` della variabile in `collectionReference`.\r\n -->\r\n @if (isInsideRepeater() && selectedType()?.storesValue) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Membro della riga</label>\r\n @if (rowClass()) {\r\n <fb-structure-member-picker\r\n [value]=\"selectedField()!.memberName\"\r\n [className]=\"rowClass()\"\r\n usage=\"writable\"\r\n label=\"Membro della riga\"\r\n (valueChange)=\"setFieldProperty('memberName', $event ?? '')\"\r\n />\r\n } @else {\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"selectedField()!.memberName || ''\"\r\n (change)=\"setFieldProperty('memberName', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n La classe delle righe non e\u2019 nota: la sezione non dichiara una <code>collectionReference</code>\r\n valida, quindi i membri non si possono proporre.\r\n </p>\r\n }\r\n <p class=\"fb-field__hint\">\r\n Il membro della riga in cui finisce il valore. Senza, vale il nome del campo. Dentro una\r\n riga lo si legge come\r\n <code>{{ rowCursor() || 'itemReference' }}.{{ selectedField()!.memberName || selectedField()!.name }}</code>.\r\n </p>\r\n </div>\r\n }\r\n\r\n <!--\r\n Il ramo dei contenitori vale anche per una sezione ripetibile: l\u00EC `fieldText` e'\r\n l'intestazione del blocco, non l'etichetta di un valore \u2014 l'etichetta della **riga** e'\r\n `itemLabel`, ed e' un campo suo, piu' sotto (\u00A75.2).\r\n -->\r\n @if (!holdsFields(selectedField())) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">\r\n {{ selectedField()!.fieldType === 'DisplayText' ? 'Testo' : 'Etichetta' }}\r\n </label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"selectedField()!.fieldText || ''\"\r\n (input)=\"setFieldProperty('fieldText', $any($event.target).value)\"\r\n ></textarea>\r\n <p class=\"fb-field__hint\">\r\n Supporta i merge field <code>{!Riferimento}</code>.\r\n @if (selectedField()!.fieldType === 'ComponentInstance') {\r\n <!--\r\n \u00A75.2 \u2014 su un componente l\u2019etichetta e\u2019 **ammessa** e viene consegnata al frontend\r\n in `label`, ma la sua assenza non e\u2019 un rilievo: un componente di solito disegna\r\n la propria intestazione. Nasconderla, come faceva prima l\u2019editor, toglieva un\r\n campo che il contratto prevede.\r\n -->\r\n Facoltativa: un componente di solito disegna la propria intestazione.\r\n }\r\n </p>\r\n </div>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Intestazione</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"selectedField()!.fieldText || ''\"\r\n (input)=\"setFieldProperty('fieldText', $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo di aiuto</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"selectedField()!.helpText || ''\"\r\n (input)=\"setFieldProperty('helpText', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Larghezza</label>\r\n <div class=\"fb-scr__width\">\r\n <input\r\n type=\"range\"\r\n min=\"1\"\r\n max=\"12\"\r\n step=\"1\"\r\n [value]=\"widthOf(selectedField()!)\"\r\n (input)=\"setNumberProperty('width', $any($event.target).value)\"\r\n />\r\n <span class=\"fb-scr__width-value\">{{ widthOf(selectedField()!) }}/12</span>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Colonne della griglia della schermata. \u00C8 un\u2019indicazione: il frontend puo\u2019 ignorarla.\r\n </p>\r\n </div>\r\n\r\n @if (selectedField()!.fieldType === 'ComponentInstance') {\r\n <!--\r\n \u00A75.2 \u2014 perche\u2019 qui non c\u2019e\u2019 \u00ABobbligatorio\u00BB. La domanda arriva sempre, e la risposta non\r\n si indovina guardando l\u2019interfaccia: un componente non ha un valore proprio, ce l\u2019hanno\r\n i suoi output, che vanno in **variabili** scelte dall\u2019autore. \u00ABObbligatorio\u00BB dovrebbe\r\n dire *quale output* deve essere valorizzato, e il metadata non ha modo di dirlo \u2014\r\n dichiararlo qui sarebbe `SCREEN_FIELD_CONFIGURATION_INVALID` e il runtime lo\r\n ignorerebbe. Le due strade vere stanno nel contratto e sono queste.\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Un componente non raccoglie un valore \u2014 lo fanno i suoi output \u2014 quindi obbligatorieta\u2019, valore\r\n predefinito e regola di validazione non si applicano: dichiararli e\u2019\r\n <code>SCREEN_FIELD_CONFIGURATION_INVALID</code> e il runtime li ignora. Per pretendere una\r\n compilazione: la validazione la fa il componente stesso, oppure si controlla la variabile di\r\n destinazione con una Decision dopo la schermata.\r\n </p>\r\n }\r\n\r\n <!-- ------------------------------------------------ campi che raccolgono un valore -->\r\n @if (selectedType()?.storesValue) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Valore</legend>\r\n\r\n @if (selectedField()!.fieldType !== 'ObjectProvided') {\r\n <div class=\"fb-field\">\r\n <label\r\n class=\"fb-field__label\"\r\n [class.fb-field__label--required]=\"!!selectedType()?.requiresDataType\"\r\n >\r\n Tipo di dato\r\n </label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.dataType || ''\"\r\n (change)=\"setFieldProperty('dataType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of dictionary.dataTypes(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.label }}</option>\r\n }\r\n </select>\r\n @if (selectedType()?.requiresDataType && !selectedField()!.dataType) {\r\n <p class=\"fb-field__error\">Obbligatorio per questo tipo di campo (DATA_TYPE_MISSING).</p>\r\n }\r\n @if (selectedType()?.isCollection) {\r\n <p class=\"fb-field__hint\">\r\n Il valore raccolto e\u2019 una <strong>collection</strong>, non una stringa con i valori\r\n separati: nelle condizioni si usano gli operatori di collection.\r\n </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\" [class.fb-field__label--required]=\"objectTypeIsStructure()\">\r\n {{\r\n objectTypeIsStructure()\r\n ? 'Classe'\r\n : selectedField()!.dataType === 'Enum'\r\n ? 'Tipo di enumerazione'\r\n : 'Oggetto'\r\n }}\r\n </label>\r\n @if (selectedField()!.dataType === 'Enum') {\r\n <!-- Dizionario chiuso: si sceglie, non si scrive. -->\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.objectType || ''\"\r\n (change)=\"setFieldProperty('objectType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of enumOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n </select>\r\n @if (!selectedField()!.objectType) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Senza il tipo concreto l\u2019editor non puo\u2019 proporre i valori dell\u2019enumerazione.\r\n </p>\r\n }\r\n } @else if (objectTypeIsStructure()) {\r\n <fb-structure-picker\r\n [value]=\"selectedField()!.objectType\"\r\n label=\"Classe\"\r\n (valueChange)=\"setFieldProperty('objectType', $event ?? '')\"\r\n />\r\n @if (!selectedField()!.objectType) {\r\n <p class=\"fb-field__error\">\r\n La classe e\u2019 obbligatoria: senza, il runtime non ha nulla da istanziare\r\n (OBJECT_TYPE_MISSING).\r\n </p>\r\n }\r\n } @else {\r\n <fb-object-picker\r\n [value]=\"selectedField()!.objectType\"\r\n label=\"Oggetto\"\r\n (valueChange)=\"setFieldProperty('objectType', $event ?? '')\"\r\n />\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo dell\u2019entita\u2019</label>\r\n <p class=\"fb-field__hint\">\r\n Tipo, label, obbligatorieta\u2019, scala e \u2014 se il campo e\u2019 una picklist \u2014 le opzioni arrivano\r\n dallo schema dati: qui non si ridichiarano.\r\n </p>\r\n <fb-object-picker\r\n [value]=\"providedObject() || undefined\"\r\n label=\"Oggetto\"\r\n (valueChange)=\"setProvidedObject($event)\"\r\n />\r\n <fb-field-picker\r\n [value]=\"providedField() || undefined\"\r\n [object]=\"providedObject() || undefined\"\r\n label=\"Campo\"\r\n (valueChange)=\"setProvidedField($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedIsRequired()\"\r\n (change)=\"setRequired($any($event.target).checked)\"\r\n />\r\n Obbligatorio\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedIsEditable()\"\r\n (change)=\"setEditable($any($event.target).checked)\"\r\n />\r\n Modificabile\r\n </label>\r\n @if (!selectedIsEditable()) {\r\n <p class=\"fb-field__hint\">\r\n A <code>false</code> il runtime <strong>ignora</strong> cio\u2019 che il client rimanda indietro:\r\n e\u2019 l\u2019unico modo di rendere un campo davvero di sola lettura.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore di default</label>\r\n <fb-value-editor\r\n [value]=\"selectedField()!.defaultValue\"\r\n [dataType]=\"selectedField()!.dataType\"\r\n [objectType]=\"selectedField()!.objectType\"\r\n [isCollection]=\"selectedType()?.isCollection\"\r\n [preferredRoots]=\"preferredRoots()\"\r\n label=\"Valore di default\"\r\n (valueChange)=\"setDefaultValue($event)\"\r\n />\r\n </div>\r\n\r\n @if (scaleApplies()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Decimali</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"0\"\r\n [value]=\"selectedField()!.scale ?? ''\"\r\n (change)=\"setNumberProperty('scale', $any($event.target).value)\"\r\n />\r\n </div>\r\n } @else if (selectedField()!.scale !== undefined) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n <code>scale</code> su un campo non numerico e\u2019 SCALE_NOT_APPLICABLE.\r\n </p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Lunghezza massima</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"selectedField()!.maxLength ?? ''\"\r\n (change)=\"setNumberProperty('maxLength', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">Verificata anche dal runtime (TOO_LONG).</p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Tornando sulla schermata</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.inputsOnNextNavToAssocScrn || ''\"\r\n (change)=\"setFieldProperty('inputsOnNextNavToAssocScrn', $any($event.target).value)\"\r\n >\r\n <option value=\"\">Predefinito (mantieni i valori)</option>\r\n @for (entry of dictionary.screenFieldInputsRevisited(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.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\">Regola di validazione</label>\r\n <!--\r\n `commitOn=\"change\"`: qui mutare il documento ridisegna l'anteprima, e riscriverla a\r\n ogni tasto costa. La verifica parte lo stesso mentre si digita (\u00A76.3).\r\n -->\r\n <fb-formula-editor\r\n [expression]=\"selectedField()!.validationRule?.formulaExpression || ''\"\r\n usage=\"ValidationRule\"\r\n expectedDataType=\"Boolean\"\r\n commitOn=\"change\"\r\n [preferredRoots]=\"preferredRoots()\"\r\n [rows]=\"2\"\r\n placeholder=\"Espressione, es. LEN(Nome) > 3\"\r\n ariaLabel=\"Regola di validazione\"\r\n (expressionChange)=\"setValidationRule('formulaExpression', $event)\"\r\n />\r\n <input\r\n class=\"fb-input\"\r\n placeholder=\"Messaggio mostrato quando l\u2019espressione e\u2019 falsa\"\r\n [value]=\"selectedField()!.validationRule?.errorMessage || ''\"\r\n (change)=\"setValidationRule('errorMessage', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n L\u2019espressione la valuta il motore di regole: il backend non la interpreta, la fa\r\n verificare al motore.\r\n </p>\r\n </div>\r\n </fieldset>\r\n }\r\n\r\n <!-- --------------------------------------------------------------- choice -->\r\n @if (selectedType()?.acceptsChoices) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Opzioni</legend>\r\n <p class=\"fb-section__note\">\r\n Accetta <strong>Choice</strong> e <strong>Dynamic choice set</strong>, nell\u2019ordine in cui le\r\n opzioni compaiono. Puntare a una variabile e\u2019 SCREEN_FIELD_CHOICE_UNKNOWN.\r\n </p>\r\n\r\n @if (!selectedField()!.choiceReferences?.length) {\r\n @if (selectedField()!.fieldType === 'ObjectProvided') {\r\n <!-- Le opzioni di una picklist arrivano dallo schema: qui si aggiungono solo se\r\n si vuole sostituirle, e non dichiararne nessuna e' il caso normale. -->\r\n <p class=\"fb-field__hint\">\r\n Se il campo dello schema e\u2019 una picklist, le opzioni arrivano da l\u00EC: dichiararle qui\r\n serve solo a sostituirle.\r\n </p>\r\n } @else {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Nessuna opzione: il campo non ha niente da mostrare (SCREEN_FIELD_CHOICES_MISSING).\r\n </p>\r\n }\r\n }\r\n\r\n <div class=\"fb-list\">\r\n @for (choice of selectedField()!.choiceReferences || []; 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__title\">{{ choice }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" (click)=\"moveChoice($index, -1)\">\u2191</button>\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" (click)=\"moveChoice($index, 1)\">\u2193</button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--sm\"\r\n aria-label=\"Rimuovi\"\r\n (click)=\"removeChoice($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Aggiungi un\u2019opzione</label>\r\n <!--\r\n `commitOn=\"enter\"`: qui ogni emissione e\u2019 una riga in piu\u2019, non un campo che cambia\r\n valore \u2014 a tasto, scrivere \u00ABAlta\u00BB aggiungeva \u00ABA\u00BB, \u00ABAl\u00BB, \u00ABAlt\u00BB e \u00ABAlta\u00BB.\r\n -->\r\n <fb-name-picker\r\n [options]=\"choiceOptions()\"\r\n label=\"Choice\"\r\n commitOn=\"enter\"\r\n placeholder=\"Scegli una choice o un choice set\"\r\n unknownMessage=\"Questo nome non e\u2019 una choice ne\u2019 un choice set: e\u2019 SCREEN_FIELD_CHOICE_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Il flow non dichiara nessuna choice: creale nel pannello delle risorse.\"\r\n (valueChange)=\"addChoice($event)\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Scegli dall\u2019elenco, oppure scrivi il nome e premi Invio.\r\n </p>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Opzione selezionata all\u2019apertura</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.defaultSelectedChoiceReference || ''\"\r\n (change)=\"setFieldProperty('defaultSelectedChoiceReference', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 nessuna \u2014</option>\r\n @for (choice of selectedField()!.choiceReferences || []; track $index) {\r\n <option [value]=\"choice\">{{ choice }}</option>\r\n }\r\n </select>\r\n @if (defaultChoiceIsForeign()) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n \u00AB{{ selectedField()!.defaultSelectedChoiceReference }}\u00BB non e\u2019 fra le opzioni elencate qui\r\n sopra.\r\n </p>\r\n }\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedAutoSelectsSingleChoice()\"\r\n (change)=\"setAutoSelectSingleChoice($any($event.target).checked)\"\r\n />\r\n Scegli da sola l\u2019unica opzione\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n Quando le opzioni risolte sono <strong>esattamente una</strong>, il campo la prende da se\u2019.\r\n Serve alle tendine che dipendono da un\u2019altra tendina \u2014 i CAP di un comune \u2014 dove chiedere\r\n di scegliere l\u2019unica voce non decide niente.\r\n </p>\r\n </fieldset>\r\n }\r\n\r\n <!-- ------------------------------------------------------- contenitori -->\r\n @if (selectedType()?.isContainer) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Contenitore</legend>\r\n @if (selectedField()!.fieldType === 'RegionContainer') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Tipo di sezione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"selectedField()!.regionContainerType || ''\"\r\n (change)=\"setFieldProperty('regionContainerType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 predefinito \u2014</option>\r\n @for (entry of dictionary.regionContainerTypes(); track entry.value) {\r\n <option [value]=\"entry.value\">{{ entry.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n }\r\n @if (!selectedField()!.fields?.length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il contenitore e\u2019 vuoto: non produce niente sulla schermata (SCREEN_CONTAINER_EMPTY).\r\n </p>\r\n }\r\n </fieldset>\r\n }\r\n\r\n <!-- ------------------------------------------------ sezione ripetibile (\u00A75.2) -->\r\n @if (selectedIsRepeatingSection()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Righe</legend>\r\n <p class=\"fb-section__note\">\r\n I campi qui dentro sono il <strong>modello di una riga</strong>: la schermata ne rende una\r\n copia per ogni elemento della collection, e l\u2019utente decide quante con un tasto. I due\r\n riferimenti vanno pensati insieme \u2014 la <strong>collection</strong> e\u2019 dove le righe vivono,\r\n il <strong>cursore</strong> e\u2019 la riga corrente, come\r\n l\u2019<code>assignNextValueToReference</code> di un Loop.\r\n </p>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Collection delle righe</label>\r\n <fb-reference-picker\r\n [value]=\"selectedField()!.collectionReference\"\r\n dataType=\"Structure\"\r\n [isCollection]=\"true\"\r\n [writableOnly]=\"true\"\r\n label=\"Collection delle righe\"\r\n placeholder=\"Una variabile collection di tipo Structure\"\r\n (valueChange)=\"setFieldProperty('collectionReference', $event ?? '')\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n \u00C8 quella che il resto del flow attraversa con un Loop: la sezione non introduce un posto\r\n nuovo in cui i dati stanno. Se la riga e\u2019 il DTO che poi finisce in una action, conviene\r\n che sia una collection <strong>di quel DTO</strong>.\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\">Cursore della riga</label>\r\n <fb-reference-picker\r\n [value]=\"selectedField()!.itemReference\"\r\n dataType=\"Structure\"\r\n [isCollection]=\"false\"\r\n [objectType]=\"rowClass()\"\r\n [writableOnly]=\"true\"\r\n label=\"Cursore della riga\"\r\n placeholder=\"Una variabile Structure della stessa classe\"\r\n (valueChange)=\"setFieldProperty('itemReference', $event ?? '')\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n \u00C8 il nome che si scrive <strong>dentro</strong> la riga: visibilita\u2019, regole di\r\n validazione, filtri delle tendine, parametri dei componenti e\r\n <code>itemLabel</code> nominano\r\n <code>{{ selectedField()!.itemReference || 'Cursore' }}.<membro></code>, mai il nome\r\n di un campo della riga.\r\n </p>\r\n </div>\r\n\r\n @if (repeaterIssue(); as issue) {\r\n <p class=\"fb-callout fb-callout--error\">{{ issue }} (REPEATING_SECTION_INVALID)</p>\r\n }\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Righe minime</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"0\"\r\n [value]=\"selectedField()!.minInstances ?? ''\"\r\n (change)=\"setNumberProperty('minInstances', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Righe massime</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"selectedField()!.maxInstances ?? ''\"\r\n (change)=\"setNumberProperty('maxInstances', $any($event.target).value)\"\r\n />\r\n @if (repeaterHasNoLimit()) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Senza un massimo l\u2019utente puo\u2019 aggiungere righe all\u2019infinito\r\n (REPEATING_SECTION_WITHOUT_LIMIT).\r\n </p>\r\n }\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedField()!.allowAdd !== false\"\r\n (change)=\"setRepeaterFlag('allowAdd', $any($event.target).checked)\"\r\n />\r\n L\u2019utente puo\u2019 aggiungere righe\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedField()!.allowRemove !== false\"\r\n (change)=\"setRepeaterFlag('allowRemove', $any($event.target).checked)\"\r\n />\r\n L\u2019utente puo\u2019 togliere righe\r\n </label>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Scritta del comando \u00ABaggiungi\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"selectedField()!.addButtonLabel || ''\"\r\n (input)=\"setFieldProperty('addButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Scritta del comando \u00ABtogli\u00BB</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"selectedField()!.removeButtonLabel || ''\"\r\n (input)=\"setFieldProperty('removeButtonLabel', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Intestazione della singola riga</label>\r\n <!-- `commitOn=\"change\"`: mutare il documento ridisegna l'anteprima. -->\r\n <fb-merge-text-editor\r\n [text]=\"selectedField()!.itemLabel || ''\"\r\n [rows]=\"2\"\r\n commitOn=\"change\"\r\n placeholder=\"Punto {{ '{' }}!Cursore.PodId}\"\r\n ariaLabel=\"Intestazione della riga\"\r\n (textChange)=\"setFieldProperty('itemLabel', $event)\"\r\n >\r\n <p class=\"fb-field__hint\">\r\n Risolta <strong>sulla riga</strong>: i merge field qui nominano il cursore\r\n (<code>{!{{ selectedField()!.itemReference || 'Cursore' }}.Membro}</code>), non\r\n un campo della riga.\r\n </p>\r\n </fb-merge-text-editor>\r\n </div>\r\n\r\n @if (!selectedField()!.fields?.length) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il modello della riga e\u2019 vuoto: la sezione non mostra niente (SCREEN_CONTAINER_EMPTY).\r\n </p>\r\n }\r\n </fieldset>\r\n }\r\n\r\n <!-- --------------------------------------------------- ComponentInstance -->\r\n @if (selectedField()!.fieldType === 'ComponentInstance') {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Componente</legend>\r\n <p class=\"fb-section__note\">\r\n Componenti e form sono la stessa domanda al frontend \u2014 cosa sa rendere, e con quali parametri\r\n \u2014 e passano dallo stesso catalogo. Un <code>ComponentInstance</code> non ha un valore proprio:\r\n lo hanno i suoi output.\r\n </p>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Componente</label>\r\n <fb-name-picker\r\n [value]=\"selectedField()!.extensionName\"\r\n [options]=\"componentOptions()\"\r\n [unusableOptions]=\"unusableComponents()\"\r\n label=\"Componente\"\r\n placeholder=\"Scrivi o scegli un componente\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo componente non esiste nel catalogo: e\u2019 SCREEN_COMPONENT_UNKNOWN.\"\r\n unknownSeverity=\"error\"\r\n unusableMessage=\"Questo nome e\u2019 una schermata intera, non un componente montabile qui (FORM_KIND_MISMATCH).\"\r\n emptyMessage=\"Il catalogo dei componenti non e\u2019 popolato: il nome non viene verificato.\"\r\n (valueChange)=\"setFieldProperty('extensionName', $event ?? '')\"\r\n />\r\n @if (!selectedField()!.extensionName) {\r\n <p class=\"fb-field__error\">Obbligatorio: senza, SCREEN_COMPONENT_MISSING.</p>\r\n }\r\n </div>\r\n\r\n <!--\r\n \u00A75.2 \u2014 dentro una riga la spunta **non c'e'**: gli output automatici si espongono come\r\n `<NomeCampo>.<NomeOutput>`, che sarebbe **una risorsa sola per tutte le righe** \u2014 l'ultima\r\n che ha girato. \u00C8 `REPEATING_SECTION_INVALID`, e la strada giusta e' `assignToReference` su\r\n un membro del cursore, che una riga ce l'ha per davvero.\r\n -->\r\n @if (!isInsideRepeater()) {\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"selectedField()!.storeOutputAutomatically === true\"\r\n (change)=\"setStoreOutputAutomatically($any($event.target).checked)\"\r\n />\r\n Rendi gli output referenziabili automaticamente\r\n </label>\r\n @if (selectedField()!.storeOutputAutomatically) {\r\n <p class=\"fb-field__hint\">\r\n Gli output si referenziano come\r\n <code>{{ selectedField()!.name || 'Campo' }}.nomeOutput</code>, senza dichiarare\r\n variabili.\r\n </p>\r\n }\r\n @if (hasOutputConflict()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Output automatici <strong>e</strong> parametri di uscita insieme:\r\n OUTPUT_CONFIGURATION_CONFLICT.\r\n </p>\r\n }\r\n } @else {\r\n <p class=\"fb-field__hint\">\r\n Gli output automatici qui non si possono usare: si esporrebbero come\r\n <code>{{ selectedField()!.name || 'Campo' }}.nomeOutput</code>, cioe\u2019 una risorsa sola per\r\n tutte le righe \u2014 l\u2019ultima che ha girato (REPEATING_SECTION_INVALID). Assegnali con\r\n <strong>assignToReference</strong> a un membro di\r\n <code>{{ rowCursor() || 'Cursore' }}</code>.\r\n </p>\r\n @if (selectedField()!.storeOutputAutomatically) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Questo componente dichiara gli output automatici e sta dentro una riga:\r\n REPEATING_SECTION_INVALID.\r\n <button type=\"button\" class=\"fb-btn fb-btn--sm\" (click)=\"setStoreOutputAutomatically(false)\">\r\n Togli\r\n </button>\r\n </p>\r\n }\r\n }\r\n\r\n <fb-parameter-editor\r\n [holder]=\"$any(selectedField())\"\r\n [catalogParameters]=\"componentParameterList()\"\r\n [preferredRoots]=\"preferredRoots()\"\r\n inputTitle=\"Valori passati al componente\"\r\n outputTitle=\"Valori raccolti dal componente\"\r\n [showOutputs]=\"!selectedField()!.storeOutputAutomatically\"\r\n outputsDisabledReason=\"Gli output sono automatici: disattivalo per assegnarli a variabili.\"\r\n (changed)=\"onComponentParametersChanged($event)\"\r\n />\r\n </fieldset>\r\n }\r\n\r\n <!-- ------------------------------------------------------- visibilita' -->\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Visibilita\u2019</legend>\r\n <p class=\"fb-section__note\">\r\n Le regole si rivalutano <strong>sui valori appena inviati</strong>: e\u2019 cos\u00EC che un campo compare\r\n in funzione di un altro campo della stessa schermata. Un campo risultato nascosto viene\r\n <strong>azzerato</strong> e non viene validato.\r\n </p>\r\n <fb-condition-editor\r\n [holder]=\"visibilityRule()\"\r\n title=\"Mostra il campo quando\"\r\n [allowFormula]=\"false\"\r\n [preferredRoots]=\"preferredRoots()\"\r\n [issuePath]=\"'fields[' + (selectedField()!.name || '') + '].visibilityRule'\"\r\n (changed)=\"onVisibilityChanged($event)\"\r\n />\r\n </fieldset>\r\n }\r\n </aside>\r\n</div>\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\r\n<!--\r\n ============================================================== l'anteprima\r\n Due template ricorsivi. `listTpl` disegna i figli di un contenitore, e nient'altro: `data-item`\r\n marca cio' che conta come fratello nel calcolo del punto di rilascio, e il segnaposto del\r\n contenitore vuoto ne resta fuori. La barra di inserimento non e' qui \u2014 sta sopra l'anteprima,\r\n vedi il velo nel frame.\r\n-->\r\n<ng-template #listTpl let-fields let-parent=\"parent\" let-axis=\"axis\">\r\n @for (child of fields; track $index) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"fieldTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: child, path: childPath(parent, $index), axis: axis }\"\r\n />\r\n }\r\n @if (!fields.length) {\r\n <p class=\"fb-scr__drop-hint\">Trascina qui un componente</p>\r\n }\r\n</ng-template>\r\n\r\n<ng-template #fieldTpl let-field let-path=\"path\" let-axis=\"axis\">\r\n <div\r\n class=\"fb-scr__item\"\r\n data-item=\"\"\r\n cdkDrag\r\n [style.grid-column]=\"'span ' + widthOf(field)\"\r\n [class.fb-scr__item--selected]=\"isSelected(path)\"\r\n [class.fb-scr__item--dragging]=\"isDragging(path)\"\r\n [class.fb-scr__item--container]=\"holdsFields(field)\"\r\n (cdkDragStarted)=\"onFieldDragStarted(path)\"\r\n (cdkDragMoved)=\"onFieldDragMoved($event)\"\r\n (cdkDragEnded)=\"onFieldDragEnded($event, path)\"\r\n (click)=\"select(path); $event.stopPropagation()\"\r\n >\r\n <span class=\"fb-scr__grip\" cdkDragHandle title=\"Trascina per spostare\" aria-hidden=\"true\">\u283F</span>\r\n @if (field.visibilityRule?.conditions?.length) {\r\n <span class=\"fb-scr__flag\" title=\"Ha una regola di visibilita\u2019\">\u25D0</span>\r\n }\r\n\r\n @switch (field.fieldType) {\r\n @case ('RegionContainer') {\r\n <div class=\"fb-scr__section\">\r\n @if (field.regionContainerType !== 'SectionWithoutHeader') {\r\n <header class=\"fb-scr__section-head\">{{ field.fieldText || field.name }}</header>\r\n }\r\n <div class=\"fb-scr__cols\" [attr.data-drop]=\"dropId(path)\" data-axis=\"row\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: field.fields || [], parent: path, axis: 'row' }\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case ('Region') {\r\n <div class=\"fb-scr__region\">\r\n <span class=\"fb-scr__region-tag\">{{ field.name }} \u00B7 {{ widthOf(field) }}/12</span>\r\n <div class=\"fb-scr__region-body\" [attr.data-drop]=\"dropId(path)\" data-axis=\"column\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: field.fields || [], parent: path, axis: 'column' }\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case ('RepeatingSection') {\r\n <!--\r\n \u00A75.2 \u2014 si disegna **una** riga, ed e' il modello: a runtime la schermata ne rende una copia\r\n per elemento della collection. Disegnarne due sarebbe finto \u2014 quante siano lo decide chi\r\n compila \u2014 e disegnarla senza cornice farebbe credere che i campi siano della schermata.\r\n -->\r\n <div class=\"fb-scr__repeat\">\r\n <header class=\"fb-scr__repeat-head\">\r\n <span>{{ field.fieldText || field.name }}</span>\r\n <span class=\"fb-scr__repeat-meta\">\r\n {{ field.collectionReference || 'collection non indicata' }}\r\n @if (field.minInstances !== undefined || field.maxInstances !== undefined) {\r\n \u00B7 {{ field.minInstances ?? 0 }}\u2013{{ field.maxInstances ?? '\u221E' }}\r\n }\r\n </span>\r\n </header>\r\n <div class=\"fb-scr__repeat-row\">\r\n <span class=\"fb-scr__repeat-tag\">\r\n {{ field.itemLabel || 'Riga 1' }}\r\n @if (field.allowRemove !== false) {\r\n <span class=\"fb-scr__repeat-x\" aria-hidden=\"true\">\u00D7</span>\r\n }\r\n </span>\r\n <div class=\"fb-scr__repeat-body\" [attr.data-drop]=\"dropId(path)\" data-axis=\"column\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"listTpl\"\r\n [ngTemplateOutletContext]=\"{ $implicit: field.fields || [], parent: path, axis: 'column' }\"\r\n />\r\n </div>\r\n </div>\r\n @if (field.allowAdd !== false) {\r\n <span class=\"fb-scr__repeat-add\">+ {{ field.addButtonLabel || 'Aggiungi' }}</span>\r\n }\r\n </div>\r\n }\r\n @case ('DisplayText') {\r\n <p class=\"fb-scr__display\">{{ field.fieldText || '(testo vuoto)' }}</p>\r\n }\r\n @case ('LargeTextArea') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control fb-scr__control--area\">{{ placeholderOf(field) }}</div>\r\n }\r\n @case ('PasswordField') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control\">\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022</div>\r\n }\r\n @case ('DropdownBox') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control fb-scr__control--select\">\r\n <span>{{ field.defaultSelectedChoiceReference || choiceLabelsOf(field)[0] || '\u2014 scegli \u2014' }}</span>\r\n <span aria-hidden=\"true\">\u25BE</span>\r\n </div>\r\n }\r\n @case ('MultiSelectPicklist') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control fb-scr__control--select\">\r\n <span>{{ choiceLabelsOf(field).join(', ') || '\u2014 scegli \u2014' }}</span>\r\n <span aria-hidden=\"true\">\u2261</span>\r\n </div>\r\n }\r\n @case ('RadioButtons') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__options\">\r\n @for (option of choiceLabelsOf(field); track $index) {\r\n <span class=\"fb-scr__option\">\u25EF {{ option }}</span>\r\n }\r\n @if (!choiceLabelsOf(field).length) {\r\n <span class=\"fb-scr__option fb-scr__option--missing\">Nessuna opzione</span>\r\n }\r\n </div>\r\n }\r\n @case ('MultiSelectCheckboxes') {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__options\">\r\n @for (option of choiceLabelsOf(field); track $index) {\r\n <span class=\"fb-scr__option\">\u2610 {{ option }}</span>\r\n }\r\n @if (!choiceLabelsOf(field).length) {\r\n <span class=\"fb-scr__option fb-scr__option--missing\">Nessuna opzione</span>\r\n }\r\n </div>\r\n }\r\n @case ('ComponentInstance') {\r\n <!--\r\n L\u2019etichetta si disegna se c\u2019e\u2019: il runtime la consegna in `label` come per gli altri\r\n campi (\u00A75.2). Nessun asterisco: un componente non raccoglie un valore, quindi\r\n \u00ABobbligatorio\u00BB non ha niente su cui applicarsi.\r\n -->\r\n @if (field.fieldText) {\r\n <label class=\"fb-scr__label\">{{ field.fieldText }}</label>\r\n }\r\n <div class=\"fb-scr__component\">\r\n <span aria-hidden=\"true\">\u2B21</span>\r\n {{ field.extensionName || 'Componente non indicato' }}\r\n </div>\r\n }\r\n @case ('ObjectProvided') {\r\n <label class=\"fb-scr__label\">\r\n {{ field.fieldText || field.objectFieldReference || field.name }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control\">{{ placeholderOf(field) }}</div>\r\n <span class=\"fb-scr__tag\">{{ field.objectFieldReference || 'campo non indicato' }}</span>\r\n }\r\n @default {\r\n <label class=\"fb-scr__label\">\r\n {{ captionOf(field) }}\r\n @if (field.isRequired) {\r\n <span class=\"fb-scr__req\">*</span>\r\n }\r\n </label>\r\n <div class=\"fb-scr__control\">{{ placeholderOf(field) }}</div>\r\n @if (isUnknownType(field)) {\r\n <span class=\"fb-scr__tag fb-scr__tag--warn\">{{ field.fieldType }}: tipo non nel dizionario</span>\r\n }\r\n }\r\n }\r\n </div>\r\n</ng-template>\r\n", styles: [".fb-scr{display:grid;grid-template-columns:220px minmax(0,1fr) 340px;gap:12px;align-items:start;margin-bottom:14px}@media(max-width:1100px){.fb-scr{grid-template-columns:minmax(0,1fr)}}.fb-scr__side,.fb-scr__props{min-width:0;padding:10px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__tabs{display:flex;gap:4px;margin-bottom:8px}.fb-scr__tab{flex:1;padding:5px 8px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text-muted, #6b7086);font:inherit;font-size:11px;font-weight:600;cursor:pointer}.fb-scr__tab--active{border-color:var(--fb-accent, #4f6ef7);background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 10%,transparent);color:var(--fb-accent-strong, #3d59e0)}.fb-scr__side-hint,.fb-scr__side-empty{margin:6px 0;font-size:11px;color:var(--fb-text-muted, #6b7086)}.fb-scr__palette{display:flex;flex-direction:column;gap:4px;margin:8px 0 0;padding:0;max-height:320px;overflow-y:auto;overscroll-behavior:contain;list-style:none}.fb-scr__chip{display:flex;align-items:center;gap:8px;width:100%;padding:6px 8px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text, #1a1c23);font:inherit;font-size:12px;text-align:left;cursor:grab}.fb-scr__chip:hover{border-color:var(--fb-accent, #4f6ef7)}.fb-scr__chip-icon{flex:none;width:20px;text-align:center;color:var(--fb-text-muted, #6b7086)}.fb-scr__chip-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-scr__chip-label small{margin-left:4px;color:var(--fb-text-subtle, #98a2b3);font-size:10px}.fb-scr__canvas{min-width:0;padding:14px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-canvas-bg, #f4f5f7);max-height:60vh;overflow-y:auto}.fb-scr__frame{position:relative;display:flex;flex-direction:column;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-sm, 8px);background:var(--fb-surface, #fff);box-shadow:var(--fb-shadow-sm, 0 1px 2px rgb(16 24 40 / 6%));overflow:hidden}.fb-scr__frame-head{display:flex;align-items:center;gap:6px;padding:8px 12px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4);font-size:13px;font-weight:600}.fb-scr__help{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;border-radius:50%;background:var(--fb-surface-sunken, #eef0f4);color:var(--fb-text-muted, #6b7086);font-size:10px}.fb-scr__body,.fb-scr__region-body{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));align-content:start;gap:8px 0;padding:12px;min-height:90px}.fb-scr__region-body{padding:8px;min-height:60px}.fb-scr__cols{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));align-items:stretch;gap:0;padding:8px;min-height:60px}.fb-scr__cols>.fb-scr__item{display:flex;align-self:stretch}.fb-scr__cols>.fb-scr__item>.fb-scr__region{flex:1;min-width:0}.fb-scr__drop-hint{grid-column:1 / -1;margin:0;padding:10px;border:1px dashed var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);color:var(--fb-text-subtle, #98a2b3);font-size:11px;text-align:center}.fb-scr__marker{position:absolute;z-index:2;border-radius:2px;background:var(--fb-accent, #4f6ef7);pointer-events:none}.fb-scr__item{position:relative;box-sizing:border-box;padding:6px 8px;border:1px solid transparent;border-radius:var(--fb-radius-xs, 6px);cursor:pointer}.fb-scr__item:hover{border-color:var(--fb-border-strong, #cfd4de);background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 4%,transparent)}.fb-scr__item--selected{border-color:var(--fb-accent, #4f6ef7);box-shadow:inset 0 0 0 1px var(--fb-accent, #4f6ef7)}.fb-scr__item--dragging{opacity:.45;pointer-events:none}.fb-scr__grip{position:absolute;top:2px;left:-2px;padding:0 3px;color:var(--fb-text-subtle, #98a2b3);font-size:11px;line-height:1;opacity:0;cursor:grab}.fb-scr__item:hover>.fb-scr__grip,.fb-scr__item--selected>.fb-scr__grip{opacity:1}.fb-scr__flag{position:absolute;top:2px;right:4px;color:var(--fb-text-muted, #6b7086);font-size:11px}.fb-scr__label{display:block;margin-bottom:3px;font-size:11px;font-weight:600;color:var(--fb-text, #1a1c23)}.fb-scr__req{color:var(--fb-error, #dc2626)}.fb-scr__control{display:flex;align-items:center;justify-content:space-between;gap:6px;min-height:26px;padding:4px 8px;border:1px solid var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text-subtle, #98a2b3);font-size:12px;pointer-events:none}.fb-scr__control--area{min-height:54px;align-items:flex-start}.fb-scr__display{margin:0;font-size:12px;color:var(--fb-text, #1a1c23)}.fb-scr__options{display:flex;flex-direction:column;gap:2px;pointer-events:none}.fb-scr__option{font-size:12px;color:var(--fb-text-muted, #6b7086)}.fb-scr__option--missing{color:var(--fb-warning, #b7791f)}.fb-scr__component{display:flex;align-items:center;gap:6px;padding:10px;border:1px dashed var(--fb-accent, #4f6ef7);border-radius:var(--fb-radius-xs, 6px);background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 5%,transparent);font-size:12px;color:var(--fb-text-muted, #6b7086)}.fb-scr__tag{display:inline-block;margin-top:3px;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-scr__tag--warn{color:var(--fb-warning, #b7791f)}.fb-scr__section{border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__section-head{padding:5px 10px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--fb-text-muted, #6b7086)}.fb-scr__region{border:1px dashed var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff)}.fb-scr__region-tag{display:block;padding:3px 6px 0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-scr__repeat{border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__repeat-head{display:flex;align-items:baseline;gap:8px;padding:5px 10px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--fb-text-muted, #6b7086)}.fb-scr__repeat-meta{margin-left:auto;font-size:10px;font-weight:400;text-transform:none;letter-spacing:0;color:var(--fb-text-subtle, #98a2b3)}.fb-scr__repeat-row{margin:8px;border:1px dashed var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff)}.fb-scr__repeat-tag{display:flex;align-items:center;gap:6px;padding:3px 6px 0;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-scr__repeat-x{margin-left:auto}.fb-scr__repeat-body{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));align-content:start;gap:8px 0;padding:8px;min-height:60px}.fb-scr__repeat-add{display:inline-block;margin:0 8px 8px;padding:3px 10px;border:1px dashed var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);font-size:11px;color:var(--fb-text-muted, #6b7086)}.fb-scr__frame-foot{display:flex;align-items:center;gap:6px;padding:8px 12px;border-top:1px solid var(--fb-border-subtle, #eef0f4);background:var(--fb-surface-alt, #f7f8fa)}.fb-scr__spacer{flex:1}.fb-scr__btn{padding:3px 10px;border:1px solid var(--fb-border-strong, #cfd4de);border-radius:var(--fb-radius-xs, 6px);font-size:11px;color:var(--fb-text-muted, #6b7086)}.fb-scr__btn--primary{border-color:var(--fb-accent, #4f6ef7);background:var(--fb-accent, #4f6ef7);color:var(--fb-accent-contrast, #fff)}.fb-scr__canvas-note{margin-top:10px}.fb-scr__props{background:var(--fb-surface, #fff)}.fb-scr__props-head{display:flex;align-items:center;gap:8px;margin-bottom:8px}.fb-scr__props-title{flex:1;min-width:0;margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--fb-text-muted, #6b7086)}.fb-scr__props-actions{display:flex;flex-wrap:wrap;gap:3px}.fb-btn--sm{padding:3px 7px;font-size:11px}.fb-scr__width{display:flex;align-items:center;gap:8px}.fb-scr__width input[type=range]{flex:1;min-width:0}.fb-scr__width-value{font-size:11px;color:var(--fb-text-muted, #6b7086)}\n"] }]
|
|
12591
12913
|
}], ctorParameters: () => [], propDecorators: { initialSelection: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialSelection", required: false }] }], composer: [{ type: i0.ViewChild, args: ['composer', { isSignal: true }] }] } });
|
|
12592
12914
|
|
|
12593
12915
|
/**
|
|
@@ -12661,7 +12983,7 @@ class LoopInspectorComponent extends NodeInspectorBase {
|
|
|
12661
12983
|
this.setField('iterationOrder', order);
|
|
12662
12984
|
}
|
|
12663
12985
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: LoopInspectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
12664
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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", "extraReferences"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
12986
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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", "extraReferences", "preferredRoots"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
12665
12987
|
}
|
|
12666
12988
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: LoopInspectorComponent, decorators: [{
|
|
12667
12989
|
type: Component,
|
|
@@ -13002,7 +13324,7 @@ class OrchestratedStageInspectorComponent extends NodeInspectorBase {
|
|
|
13002
13324
|
/** C'e' almeno uno step il cui rifiuto e' un esito previsto. */
|
|
13003
13325
|
hasApprovalStep = computed(() => this.steps().some((step) => this.supportsRejection(step)), ...(ngDevMode ? [{ debugName: "hasApprovalStep" }] : []));
|
|
13004
13326
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: OrchestratedStageInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13005
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 <fb-name-picker\r\n [value]=\"step.actionName\"\r\n [options]=\"candidateOptions()\"\r\n label=\"Flow da eseguire\"\r\n placeholder=\"Preparazione_Pratica\"\r\n unknownMessage=\"Questo flow non e\u2019 fra quelli invocabili: senza una versione attiva il motore non lo trova.\"\r\n emptyMessage=\"Elenco dei flow non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setStepActionName(stepIndex, $event ?? '')\"\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.14).\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 <fb-name-picker\r\n [value]=\"step.entryActionName\"\r\n [options]=\"candidateOptions()\"\r\n label=\"Evaluation flow per l\u2019ingresso\"\r\n placeholder=\"Valuta_Ingresso\"\r\n unknownMessage=\"Questo flow non e\u2019 fra quelli invocabili: senza una versione attiva il motore non lo trova.\"\r\n emptyMessage=\"Elenco dei flow non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setEntryActionName(stepIndex, $event ?? '')\"\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 <fb-name-picker\r\n [value]=\"step.exitActionName\"\r\n [options]=\"candidateOptions()\"\r\n label=\"Evaluation flow per l\u2019uscita\"\r\n placeholder=\"Valuta_Uscita\"\r\n unknownMessage=\"Questo flow non e\u2019 fra quelli invocabili: senza una versione attiva il motore non lo trova.\"\r\n emptyMessage=\"Elenco dei flow non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setExitActionName(stepIndex, $event ?? '')\"\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</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: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason", "extraTargets"], outputs: ["changed"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13327
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 <fb-name-picker\r\n [value]=\"step.actionName\"\r\n [options]=\"candidateOptions()\"\r\n label=\"Flow da eseguire\"\r\n placeholder=\"Preparazione_Pratica\"\r\n unknownMessage=\"Questo flow non e\u2019 fra quelli invocabili: senza una versione attiva il motore non lo trova.\"\r\n emptyMessage=\"Elenco dei flow non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setStepActionName(stepIndex, $event ?? '')\"\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.14).\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 <fb-name-picker\r\n [value]=\"step.entryActionName\"\r\n [options]=\"candidateOptions()\"\r\n label=\"Evaluation flow per l\u2019ingresso\"\r\n placeholder=\"Valuta_Ingresso\"\r\n unknownMessage=\"Questo flow non e\u2019 fra quelli invocabili: senza una versione attiva il motore non lo trova.\"\r\n emptyMessage=\"Elenco dei flow non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setEntryActionName(stepIndex, $event ?? '')\"\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 <fb-name-picker\r\n [value]=\"step.exitActionName\"\r\n [options]=\"candidateOptions()\"\r\n label=\"Evaluation flow per l\u2019uscita\"\r\n placeholder=\"Valuta_Uscita\"\r\n unknownMessage=\"Questo flow non e\u2019 fra quelli invocabili: senza una versione attiva il motore non lo trova.\"\r\n emptyMessage=\"Elenco dei flow non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setExitActionName(stepIndex, $event ?? '')\"\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</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", "preferredRoots", "allowLogic", "issuePath"], outputs: ["changed"] }, { kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason", "extraTargets", "preferredRoots"], outputs: ["changed"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula", "preferredRoots"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13006
13328
|
}
|
|
13007
13329
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: OrchestratedStageInspectorComponent, decorators: [{
|
|
13008
13330
|
type: Component,
|
|
@@ -13200,7 +13522,7 @@ class RecordLookupInspectorComponent extends NodeInspectorBase {
|
|
|
13200
13522
|
/** `relatedRecords` e' modellato ma non tradotto in query: se c'e', si avvisa (§5.7). */
|
|
13201
13523
|
hasRelatedRecords = computed(() => (this.lookup().relatedRecords?.length ?? 0) > 0, ...(ngDevMode ? [{ debugName: "hasRelatedRecords" }] : []));
|
|
13202
13524
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: RecordLookupInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13203
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 <fb-object-picker\r\n [value]=\"lookup().object\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setObject($event ?? '')\"\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 <fb-field-picker\r\n [value]=\"lookup().sortField\"\r\n [object]=\"lookup().object\"\r\n usage=\"sortable\"\r\n label=\"Campo di ordinamento\"\r\n placeholder=\"Nessun ordinamento\"\r\n (valueChange)=\"setSortField($event ?? '')\"\r\n />\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 <fb-field-picker\r\n [value]=\"assignment.field\"\r\n [object]=\"lookup().object\"\r\n usage=\"any\"\r\n placeholder=\"Scrivi o scegli un campo\"\r\n (valueChange)=\"setOutputAssignmentField($index, $event ?? '')\"\r\n />\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: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ObjectPickerComponent, selector: "fb-object-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: RecordFilterEditorComponent, selector: "fb-record-filter-editor", inputs: ["holder", "object", "title", "usage", "fieldOptions", "supportsLogic", "supportsFormula", "emptyWarning", "emptyWarningSeverity"], outputs: ["changed"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13525
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 <fb-object-picker\r\n [value]=\"lookup().object\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setObject($event ?? '')\"\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 <fb-field-picker\r\n [value]=\"lookup().sortField\"\r\n [object]=\"lookup().object\"\r\n usage=\"sortable\"\r\n label=\"Campo di ordinamento\"\r\n placeholder=\"Nessun ordinamento\"\r\n (valueChange)=\"setSortField($event ?? '')\"\r\n />\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 <fb-field-picker\r\n [value]=\"assignment.field\"\r\n [object]=\"lookup().object\"\r\n usage=\"any\"\r\n placeholder=\"Scrivi o scegli un campo\"\r\n (valueChange)=\"setOutputAssignmentField($index, $event ?? '')\"\r\n />\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: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ObjectPickerComponent, selector: "fb-object-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: RecordFilterEditorComponent, selector: "fb-record-filter-editor", inputs: ["holder", "object", "title", "usage", "fieldOptions", "supportsLogic", "supportsFormula", "emptyWarning", "emptyWarningSeverity"], outputs: ["changed"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences", "preferredRoots"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13204
13526
|
}
|
|
13205
13527
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: RecordLookupInspectorComponent, decorators: [{
|
|
13206
13528
|
type: Component,
|
|
@@ -13424,7 +13746,7 @@ class RecordWriteInspectorComponent extends NodeInspectorBase {
|
|
|
13424
13746
|
this.patch((node) => mutate(node));
|
|
13425
13747
|
}
|
|
13426
13748
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: RecordWriteInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13427
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 <fb-object-picker\r\n [value]=\"record().object\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setObject($event ?? '')\"\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 <!-- I due insiemi non coincidono: `createable` su un Create, `updateable` su un Update. -->\r\n <fb-field-assignment-editor\r\n [holder]=\"$any(record())\"\r\n [object]=\"record().object\"\r\n [usage]=\"assignmentUsage()\"\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 <fb-field-picker\r\n [value]=\"record().upsertExternalIdField\"\r\n [object]=\"record().object\"\r\n usage=\"any\"\r\n label=\"Campo id esterno\"\r\n (valueChange)=\"setUpsertExternalField($event ?? '')\"\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 <fb-field-picker\r\n [value]=\"record().upsertStandardIdField\"\r\n [object]=\"record().object\"\r\n usage=\"any\"\r\n label=\"Campo id standard\"\r\n (valueChange)=\"setUpsertStandardField($event ?? '')\"\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", "usage", "title", "disabledReason"], outputs: ["changed"] }, { kind: "component", type: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ObjectPickerComponent, selector: "fb-object-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: RecordFilterEditorComponent, selector: "fb-record-filter-editor", inputs: ["holder", "object", "title", "usage", "fieldOptions", "supportsLogic", "supportsFormula", "emptyWarning", "emptyWarningSeverity"], outputs: ["changed"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13749
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 <fb-object-picker\r\n [value]=\"record().object\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setObject($event ?? '')\"\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 <!-- I due insiemi non coincidono: `createable` su un Create, `updateable` su un Update. -->\r\n <fb-field-assignment-editor\r\n [holder]=\"$any(record())\"\r\n [object]=\"record().object\"\r\n [usage]=\"assignmentUsage()\"\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 <fb-field-picker\r\n [value]=\"record().upsertExternalIdField\"\r\n [object]=\"record().object\"\r\n usage=\"any\"\r\n label=\"Campo id esterno\"\r\n (valueChange)=\"setUpsertExternalField($event ?? '')\"\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 <fb-field-picker\r\n [value]=\"record().upsertStandardIdField\"\r\n [object]=\"record().object\"\r\n usage=\"any\"\r\n label=\"Campo id standard\"\r\n (valueChange)=\"setUpsertStandardField($event ?? '')\"\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", "usage", "title", "disabledReason"], outputs: ["changed"] }, { kind: "component", type: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ObjectPickerComponent, selector: "fb-object-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: RecordFilterEditorComponent, selector: "fb-record-filter-editor", inputs: ["holder", "object", "title", "usage", "fieldOptions", "supportsLogic", "supportsFormula", "emptyWarning", "emptyWarningSeverity"], outputs: ["changed"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences", "preferredRoots"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13428
13750
|
}
|
|
13429
13751
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: RecordWriteInspectorComponent, decorators: [{
|
|
13430
13752
|
type: Component,
|
|
@@ -13536,7 +13858,7 @@ class ScreenInspectorComponent extends NodeInspectorBase {
|
|
|
13536
13858
|
this.patch((node) => mutate(node));
|
|
13537
13859
|
}
|
|
13538
13860
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ScreenInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13539
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: ScreenInspectorComponent, isStandalone: true, selector: "fb-screen-inspector", usesInheritance: true, ngImport: i0, template: "<p class=\"fb-callout\">\r\n Lo screen dichiara <strong>quale form</strong> mostrare, non i suoi campi: il form e\u2019 un componente del\r\n frontend applicativo, e qui si definisce solo il contratto di dati.\r\n</p>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Form</label>\r\n <fb-name-picker\r\n [value]=\"screen().formName\"\r\n [options]=\"formOptions()\"\r\n [unusableOptions]=\"unusableForms()\"\r\n label=\"Form\"\r\n placeholder=\"Scrivi o scegli un form\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo form non esiste nel catalogo: la validazione lo segnala come errore.\"\r\n unknownSeverity=\"error\"\r\n unusableMessage=\"Questo nome e\u2019 un componente di screen dinamico, non una schermata: qui serve un form (FORM_KIND_MISMATCH).\"\r\n emptyMessage=\"Il catalogo dei form non e\u2019 popolato: il nome non viene verificato.\"\r\n (valueChange)=\"setFormName($event ?? '')\"\r\n />\r\n</div>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo di aiuto</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"screen().helpText || ''\"\r\n (input)=\"setHelpText($any($event.target).value)\"\r\n ></textarea>\r\n</div>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Navigazione</legend>\r\n <p class=\"fb-section__note\">\r\n Questi flag sono un\u2019intenzione, non la verita\u2019 finale: a runtime il motore comunica\r\n <code>canGoBack</code>, <code>canFinish</code> e <code>canPause</code> nella richiesta del form \u2014\r\n per esempio \u00ABindietro\u00BB conta solo se esiste uno screen precedente nel percorso.\r\n </p>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowBack()\" (change)=\"setFlag('allowBack', $any($event.target).checked)\" />\r\n Consenti \u00ABindietro\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowFinish()\" (change)=\"setFlag('allowFinish', $any($event.target).checked)\" />\r\n Consenti \u00ABfine\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowPause()\" (change)=\"setFlag('allowPause', $any($event.target).checked)\" />\r\n Consenti \u00ABpausa\u00BB\r\n </label>\r\n\r\n @if (allowPause()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo mostrato alla pausa</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().pausedText || ''\"\r\n (input)=\"setPausedText($any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (isDeadEnd()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Questo screen non ha una destinazione e non consente \u00ABfine\u00BB: e\u2019 un vicolo cieco, e l\u2019utente resterebbe\r\n bloccato.\r\n </p>\r\n }\r\n</fieldset>\r\n\r\n<fb-parameter-editor\r\n [holder]=\"screen()\"\r\n [catalogParameters]=\"parameters()\"\r\n inputTitle=\"Valori passati al form\"\r\n outputTitle=\"Valori raccolti dal form\"\r\n (changed)=\"onParametersChanged($event)\"\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: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason", "extraTargets"], outputs: ["changed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13861
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: ScreenInspectorComponent, isStandalone: true, selector: "fb-screen-inspector", usesInheritance: true, ngImport: i0, template: "<p class=\"fb-callout\">\r\n Lo screen dichiara <strong>quale form</strong> mostrare, non i suoi campi: il form e\u2019 un componente del\r\n frontend applicativo, e qui si definisce solo il contratto di dati.\r\n</p>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Form</label>\r\n <fb-name-picker\r\n [value]=\"screen().formName\"\r\n [options]=\"formOptions()\"\r\n [unusableOptions]=\"unusableForms()\"\r\n label=\"Form\"\r\n placeholder=\"Scrivi o scegli un form\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo form non esiste nel catalogo: la validazione lo segnala come errore.\"\r\n unknownSeverity=\"error\"\r\n unusableMessage=\"Questo nome e\u2019 un componente di screen dinamico, non una schermata: qui serve un form (FORM_KIND_MISMATCH).\"\r\n emptyMessage=\"Il catalogo dei form non e\u2019 popolato: il nome non viene verificato.\"\r\n (valueChange)=\"setFormName($event ?? '')\"\r\n />\r\n</div>\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo di aiuto</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"screen().helpText || ''\"\r\n (input)=\"setHelpText($any($event.target).value)\"\r\n ></textarea>\r\n</div>\r\n\r\n<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Navigazione</legend>\r\n <p class=\"fb-section__note\">\r\n Questi flag sono un\u2019intenzione, non la verita\u2019 finale: a runtime il motore comunica\r\n <code>canGoBack</code>, <code>canFinish</code> e <code>canPause</code> nella richiesta del form \u2014\r\n per esempio \u00ABindietro\u00BB conta solo se esiste uno screen precedente nel percorso.\r\n </p>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowBack()\" (change)=\"setFlag('allowBack', $any($event.target).checked)\" />\r\n Consenti \u00ABindietro\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowFinish()\" (change)=\"setFlag('allowFinish', $any($event.target).checked)\" />\r\n Consenti \u00ABfine\u00BB\r\n </label>\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"allowPause()\" (change)=\"setFlag('allowPause', $any($event.target).checked)\" />\r\n Consenti \u00ABpausa\u00BB\r\n </label>\r\n\r\n @if (allowPause()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Testo mostrato alla pausa</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"screen().pausedText || ''\"\r\n (input)=\"setPausedText($any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (isDeadEnd()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Questo screen non ha una destinazione e non consente \u00ABfine\u00BB: e\u2019 un vicolo cieco, e l\u2019utente resterebbe\r\n bloccato.\r\n </p>\r\n }\r\n</fieldset>\r\n\r\n<fb-parameter-editor\r\n [holder]=\"screen()\"\r\n [catalogParameters]=\"parameters()\"\r\n inputTitle=\"Valori passati al form\"\r\n outputTitle=\"Valori raccolti dal form\"\r\n (changed)=\"onParametersChanged($event)\"\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: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason", "extraTargets", "preferredRoots"], outputs: ["changed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13540
13862
|
}
|
|
13541
13863
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ScreenInspectorComponent, decorators: [{
|
|
13542
13864
|
type: Component,
|
|
@@ -13603,7 +13925,7 @@ class ScriptCallInspectorComponent extends NodeInspectorBase {
|
|
|
13603
13925
|
this.patch((node) => mutate(node));
|
|
13604
13926
|
}
|
|
13605
13927
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ScriptCallInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13606
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.28", type: ScriptCallInspectorComponent, isStandalone: true, selector: "fb-script-call-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Script</label>\r\n <fb-name-picker\r\n [value]=\"script().scriptName\"\r\n [options]=\"scriptOptions()\"\r\n label=\"Script\"\r\n placeholder=\"Scrivi o scegli uno script\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo script non esiste nel catalogo: la validazione lo segnala come errore.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Catalogo degli script non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setScriptName($event ?? '')\"\r\n />\r\n</div>\r\n\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\r\n<fb-parameter-editor\r\n [holder]=\"script()\"\r\n [catalogParameters]=\"parameterCatalog()\"\r\n [showOutputs]=\"!storeOutputAutomatically()\"\r\n (changed)=\"onParametersChanged($event)\"\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: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason", "extraTargets"], outputs: ["changed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13928
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.28", type: ScriptCallInspectorComponent, isStandalone: true, selector: "fb-script-call-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Script</label>\r\n <fb-name-picker\r\n [value]=\"script().scriptName\"\r\n [options]=\"scriptOptions()\"\r\n label=\"Script\"\r\n placeholder=\"Scrivi o scegli uno script\"\r\n [isMono]=\"false\"\r\n unknownMessage=\"Questo script non esiste nel catalogo: la validazione lo segnala come errore.\"\r\n unknownSeverity=\"error\"\r\n emptyMessage=\"Catalogo degli script non disponibile: puoi scrivere il nome a mano.\"\r\n (valueChange)=\"setScriptName($event ?? '')\"\r\n />\r\n</div>\r\n\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\r\n<fb-parameter-editor\r\n [holder]=\"script()\"\r\n [catalogParameters]=\"parameterCatalog()\"\r\n [showOutputs]=\"!storeOutputAutomatically()\"\r\n (changed)=\"onParametersChanged($event)\"\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: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "component", type: ParameterEditorComponent, selector: "fb-parameter-editor", inputs: ["holder", "catalogParameters", "inputTitle", "outputTitle", "showInputs", "showOutputs", "outputsDisabledReason", "extraTargets", "preferredRoots"], outputs: ["changed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13607
13929
|
}
|
|
13608
13930
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ScriptCallInspectorComponent, decorators: [{
|
|
13609
13931
|
type: Component,
|
|
@@ -13938,7 +14260,7 @@ class SubflowInspectorComponent extends NodeInspectorBase {
|
|
|
13938
14260
|
});
|
|
13939
14261
|
}
|
|
13940
14262
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: SubflowInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
13941
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 <fb-name-picker\r\n [value]=\"subflow().flowName\"\r\n [options]=\"candidates()\"\r\n label=\"Flow da invocare\"\r\n placeholder=\"API name del flow\"\r\n unknownMessage=\"Questo flow non e\u2019 fra quelli invocabili: solo i flow con una versione attiva lo sono.\"\r\n emptyMessage=\"Nessun flow attivo disponibile come subflow: attivane uno, oppure scrivi il nome a mano.\"\r\n (valueChange)=\"setFlowName($event ?? '')\"\r\n />\r\n @if (hasCandidates()) {\r\n <p class=\"fb-field__hint\">Solo i flow con una versione attiva possono essere invocati.</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 <fb-name-picker\r\n [value]=\"assignment.name\"\r\n [options]=\"inputOptions()\"\r\n label=\"Variabile del subflow\"\r\n placeholder=\"Nome della variabile di input\"\r\n unknownMessage=\"Questa variabile non e\u2019 fra gli input del flow invocato.\"\r\n emptyMessage=\"Input del flow invocato non disponibili: scrivi il nome a mano.\"\r\n (valueChange)=\"setInputName($index, $event ?? '')\"\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 <fb-name-picker\r\n [value]=\"assignment.name\"\r\n [options]=\"outputOptions()\"\r\n label=\"Variabile di output del subflow\"\r\n placeholder=\"Nome della variabile di output\"\r\n unknownMessage=\"Questa variabile non e\u2019 fra gli output del flow invocato.\"\r\n emptyMessage=\"Output del flow invocato non disponibili: scrivi il nome a mano.\"\r\n (valueChange)=\"setOutputName($index, $event ?? '')\"\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: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
14263
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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 <fb-name-picker\r\n [value]=\"subflow().flowName\"\r\n [options]=\"candidates()\"\r\n label=\"Flow da invocare\"\r\n placeholder=\"API name del flow\"\r\n unknownMessage=\"Questo flow non e\u2019 fra quelli invocabili: solo i flow con una versione attiva lo sono.\"\r\n emptyMessage=\"Nessun flow attivo disponibile come subflow: attivane uno, oppure scrivi il nome a mano.\"\r\n (valueChange)=\"setFlowName($event ?? '')\"\r\n />\r\n @if (hasCandidates()) {\r\n <p class=\"fb-field__hint\">Solo i flow con una versione attiva possono essere invocati.</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 <fb-name-picker\r\n [value]=\"assignment.name\"\r\n [options]=\"inputOptions()\"\r\n label=\"Variabile del subflow\"\r\n placeholder=\"Nome della variabile di input\"\r\n unknownMessage=\"Questa variabile non e\u2019 fra gli input del flow invocato.\"\r\n emptyMessage=\"Input del flow invocato non disponibili: scrivi il nome a mano.\"\r\n (valueChange)=\"setInputName($index, $event ?? '')\"\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 <fb-name-picker\r\n [value]=\"assignment.name\"\r\n [options]=\"outputOptions()\"\r\n label=\"Variabile di output del subflow\"\r\n placeholder=\"Nome della variabile di output\"\r\n unknownMessage=\"Questa variabile non e\u2019 fra gli output del flow invocato.\"\r\n emptyMessage=\"Output del flow invocato non disponibili: scrivi il nome a mano.\"\r\n (valueChange)=\"setOutputName($index, $event ?? '')\"\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: NamePickerComponent, selector: "fb-name-picker", inputs: ["value", "options", "label", "placeholder", "disabled", "unknownMessage", "unknownSeverity", "unusableOptions", "unusableMessage", "emptyMessage", "isMono", "commitOn"], outputs: ["valueChange"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences", "preferredRoots"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula", "preferredRoots"], outputs: ["valueChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
13942
14264
|
}
|
|
13943
14265
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: SubflowInspectorComponent, decorators: [{
|
|
13944
14266
|
type: Component,
|
|
@@ -14602,7 +14924,7 @@ class TransformInspectorComponent extends NodeInspectorBase {
|
|
|
14602
14924
|
return null;
|
|
14603
14925
|
}
|
|
14604
14926
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: TransformInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
14605
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: TransformInspectorComponent, isStandalone: true, selector: "fb-transform-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-tr\">\r\n <!-- ============================================================ sorgenti -->\r\n <aside class=\"fb-tr__panel\" aria-label=\"Sorgenti\">\r\n <h3 class=\"fb-tr__panel-title\">Sorgenti</h3>\r\n\r\n <input\r\n class=\"fb-input fb-tr__search\"\r\n type=\"search\"\r\n placeholder=\"Cerca una sorgente\"\r\n aria-label=\"Cerca una sorgente\"\r\n [value]=\"sourceQuery()\"\r\n (input)=\"sourceQuery.set($any($event.target).value)\"\r\n />\r\n\r\n @if (sourceCrumbs().length) {\r\n <nav class=\"fb-tr__crumbs\" aria-label=\"Percorso della sorgente\">\r\n <button type=\"button\" class=\"fb-tr__crumb\" (click)=\"enterSource('')\">Tutte</button>\r\n @for (crumb of sourceCrumbs(); track crumb.path) {\r\n <span class=\"fb-tr__crumb-sep\" aria-hidden=\"true\">\u203A</span>\r\n <button type=\"button\" class=\"fb-tr__crumb\" (click)=\"enterSource(crumb.path)\">{{ crumb.label }}</button>\r\n }\r\n </nav>\r\n }\r\n\r\n <p class=\"fb-tr__hint\">\r\n Trascina su una destinazione, oppure clicca per mapparla su quella selezionata.\r\n </p>\r\n\r\n @if (sourceError()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n {{ sourceError() }} Le sorgenti si scrivono a mano nel dettaglio: l\u2019elenco non c\u2019e\u2019, i\r\n riferimenti s\u00EC.\r\n </p>\r\n }\r\n\r\n <ul class=\"fb-tr__list\">\r\n @for (source of sources(); track source.path) {\r\n <li class=\"fb-tr__source-row\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-tr__source\"\r\n cdkDrag\r\n [class.fb-tr__source--dragging]=\"draggingPath() === source.path\"\r\n [title]=\"source.path + (source.detail ? ' \u00B7 ' + source.detail : '')\"\r\n (cdkDragStarted)=\"onSourceDragStarted(source)\"\r\n (cdkDragMoved)=\"onSourceDragMoved($event)\"\r\n (cdkDragEnded)=\"onSourceDragEnded($event, source)\"\r\n (click)=\"mapToSelected(source)\"\r\n >\r\n <span class=\"fb-tr__source-name\">\r\n {{ source.label }}\r\n @if (source.isCollection) {\r\n <span class=\"fb-tr__badge\" aria-label=\"collection\">[ ]</span>\r\n }\r\n </span>\r\n @if (source.detail) {\r\n <span class=\"fb-tr__source-detail\">{{ source.detail }}</span>\r\n }\r\n </button>\r\n @if (source.canEnter) {\r\n <!-- Entrare e mappare sono due gesti diversi: un record intero e' una sorgente valida. -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon fb-tr__enter\"\r\n [attr.aria-label]=\"'Entra in ' + source.label\"\r\n (click)=\"enterSource(source.path)\"\r\n >\r\n \u203A\r\n </button>\r\n }\r\n </li>\r\n } @empty {\r\n @if (sourcePending()) {\r\n <li class=\"fb-tr__empty\">Caricamento\u2026</li>\r\n } @else if (sourceUndeclared()) {\r\n <li class=\"fb-tr__empty\">\r\n Il catalogo non dichiara cosa c\u2019e\u2019 qui dentro: non significa che non ci sia niente. Il\r\n percorso si scrive a mano nel dettaglio.\r\n </li>\r\n } @else {\r\n <li class=\"fb-tr__empty\">Nessuna sorgente con questo nome.</li>\r\n }\r\n }\r\n </ul>\r\n </aside>\r\n\r\n <!-- ========================================================= destinazione -->\r\n <section class=\"fb-tr__panel fb-tr__map\" aria-label=\"Destinazione\">\r\n <h3 class=\"fb-tr__panel-title\">\r\n Destinazione\r\n @if (slotCount()) {\r\n <span class=\"fb-tr__count\">{{ mappedCount() }} di {{ slotCount() }} mappate</span>\r\n } @else if (mappedCount()) {\r\n <span class=\"fb-tr__count\">{{ mappedCount() }} mappate</span>\r\n }\r\n </h3>\r\n\r\n <!-- Il tipo del risultato e' la forma della colonna: sta in cima, non in fondo. -->\r\n <div class=\"fb-tr__result\">\r\n <div class=\"fb-fields-row\">\r\n <div class=\"fb-field fb-field--compact\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo del risultato</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"transform().dataType || ''\"\r\n (change)=\"setDataType($any($event.target).value)\"\r\n >\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 </div>\r\n\r\n @if (requiresObjectType()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">\r\n {{ isStructureTarget() ? 'Classe del risultato' : 'Tipo dell\u2019oggetto' }}\r\n </label>\r\n @if (isStructureTarget()) {\r\n <!-- \u00A74.7: una classe del backend. Le destinazioni delle azioni sono i suoi membri. -->\r\n <fb-structure-picker\r\n [value]=\"transform().objectType\"\r\n label=\"Classe del risultato\"\r\n (valueChange)=\"setObjectType($event ?? '')\"\r\n />\r\n } @else if (transform().dataType === 'Enum') {\r\n <!-- Le enumerazioni sono un dizionario chiuso: non c'e' scrittura libera da concedere. -->\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 @for (entry of enumOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n </select>\r\n } @else {\r\n <fb-object-picker\r\n [value]=\"transform().objectType\"\r\n label=\"Tipo dell\u2019oggetto\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setObjectType($event ?? '')\"\r\n />\r\n }\r\n </div>\r\n }\r\n\r\n <label class=\"fb-check fb-tr__collection\">\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 Collection\r\n </label>\r\n </div>\r\n\r\n @if (!transform().dataType) {\r\n <p class=\"fb-field__error\">Obbligatorio (TRANSFORM_DATA_TYPE_MISSING).</p>\r\n }\r\n @if (missingObjectType()) {\r\n <p class=\"fb-field__error\">\r\n La classe e\u2019 obbligatoria: senza, l\u2019attivazione e\u2019 bloccata (OBJECT_TYPE_MISSING).\r\n </p>\r\n }\r\n @if (targetUndeclared()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il catalogo non dichiara i {{ isStructureTarget() ? 'membri' : 'campi' }} di\r\n <code>{{ transform().objectType }}</code>: le destinazioni si scrivono a mano, e nessuna di\r\n esse viene accusata di non esistere.\r\n </p>\r\n }\r\n </div>\r\n\r\n <ul class=\"fb-tr__list fb-tr__rows\">\r\n @for (row of targets(); track row.key) {\r\n <!--\r\n `data-fb-slot` e' cio' che il rilascio cerca: il bersaglio lo calcola `hitTest` dal DOM,\r\n non una drop list del CDK.\r\n -->\r\n <li\r\n class=\"fb-tr__row\"\r\n [attr.data-fb-slot]=\"row.key\"\r\n [class.fb-tr__row--selected]=\"isSelected(row)\"\r\n [class.fb-tr__row--drop]=\"dropKey() === row.key\"\r\n [class.fb-tr__row--empty]=\"row.index < 0\"\r\n >\r\n <button type=\"button\" class=\"fb-tr__row-main\" (click)=\"select(row.key)\">\r\n <span class=\"fb-tr__op\" [attr.title]=\"operationLabel(operationOf(row))\" aria-hidden=\"true\">\r\n {{ operationIcon(row) }}\r\n </span>\r\n <span class=\"fb-tr__row-text\">\r\n <span class=\"fb-tr__row-name\">\r\n {{ row.label }}\r\n @if (row.isCollection) {\r\n <span class=\"fb-tr__badge\" aria-label=\"collection\">[ ]</span>\r\n }\r\n @if (row.isUnknown) {\r\n <span class=\"fb-tr__badge fb-tr__badge--warn\">fuori catalogo</span>\r\n }\r\n </span>\r\n @if (row.index < 0) {\r\n <span class=\"fb-tr__row-src fb-tr__row-src--empty\">non mappata</span>\r\n } @else if (sourceSummary(row)) {\r\n <span class=\"fb-tr__row-src\">\u2190 {{ sourceSummary(row) }}</span>\r\n } @else {\r\n <span class=\"fb-tr__row-src fb-tr__row-src--empty\">sorgente da indicare</span>\r\n }\r\n </span>\r\n @if (row.dataType) {\r\n <span class=\"fb-tr__row-type\">{{ row.dataType }}</span>\r\n }\r\n @if (issuesOf(row).length) {\r\n <span class=\"fb-tr__row-issue\" [attr.title]=\"issuesOf(row)[0].message\">!</span>\r\n }\r\n </button>\r\n @if (row.index >= 0) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n [attr.aria-label]=\"'Togli la mappatura di ' + row.label\"\r\n (click)=\"removeAction(row)\"\r\n >\r\n \u00D7\r\n </button>\r\n }\r\n </li>\r\n } @empty {\r\n <li class=\"fb-empty\">\r\n Nessuna trasformazione: l\u2019elemento non produce nulla (TRANSFORM_WITHOUT_VALUES).\r\n </li>\r\n }\r\n </ul>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addAction()\">\r\n {{ hasTargetCatalog() ? 'Aggiungi una destinazione fuori catalogo' : 'Aggiungi trasformazione' }}\r\n </button>\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 </section>\r\n\r\n <!-- ============================================================ dettaglio -->\r\n <aside class=\"fb-tr__panel fb-tr__detail\" aria-label=\"Dettaglio della mappatura\">\r\n @if (selected(); as row) {\r\n <h3 class=\"fb-tr__panel-title\">{{ row.label }}</h3>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Operazione</label>\r\n <div class=\"fb-tr__modes\" role=\"group\" aria-label=\"Operazione\">\r\n @for (type of transformTypes(); track type.value) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-tr__mode\"\r\n [class.fb-tr__mode--active]=\"operationOf(row) === type.value\"\r\n (click)=\"setOperation(row, type.value)\"\r\n >\r\n {{ type.label }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">\r\n {{ isStructureTarget() ? 'Membro di destinazione' : 'Campo di destinazione' }}\r\n </label>\r\n @if (isStructureTarget()) {\r\n <!-- Solo i membri scrivibili: un membro calcolato e' TARGET_NOT_WRITABLE (\u00A74.7). -->\r\n <fb-structure-member-picker\r\n [value]=\"row.field\"\r\n [className]=\"transform().objectType\"\r\n usage=\"writable\"\r\n label=\"Membro di destinazione\"\r\n (valueChange)=\"setOutputField(row, $event ?? '')\"\r\n />\r\n } @else if (targetObject()) {\r\n <!-- Il risultato e' un record: le destinazioni sono i campi della sua entita' (\u00A74.4). -->\r\n <fb-field-picker\r\n [value]=\"row.field\"\r\n [object]=\"targetObject()\"\r\n label=\"Campo di destinazione\"\r\n (valueChange)=\"setOutputField(row, $event ?? '')\"\r\n />\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"row.field\"\r\n placeholder=\"Totale\"\r\n (input)=\"setOutputField(row, $any($event.target).value)\"\r\n />\r\n }\r\n </div>\r\n\r\n @if (isMap(row)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\r\n <!--\r\n Il tipo di cio' che si scrive guida il controllo: su un campo o un membro Enum i valori\r\n proponibili sono quelli del suo tipo (\u00A74.6).\r\n -->\r\n <fb-value-editor\r\n [value]=\"row.action?.value ?? undefined\"\r\n label=\"Valore\"\r\n [dataType]=\"mapDataType(row)\"\r\n [objectType]=\"mapObjectType(row)\"\r\n (valueChange)=\"setMapValue(row, $event)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (needsAggregationValues(row)) {\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(row.action)\"\r\n [isCollection]=\"true\"\r\n placeholder=\"Scegli una collection\"\r\n (valueChange)=\"setAggregationCollection(row, $event)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (needsAggregationField(row)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo da sommare</label>\r\n <!--\r\n Nel documento va il **nome** del campo (`stringValue`, \u00A75.13); dove il tipo della\r\n collection e' noto, il nome lo si sceglie da un elenco invece di ricordarlo.\r\n -->\r\n @if (aggregationObject(row); as object) {\r\n <fb-field-picker\r\n [value]=\"aggregationField(row.action)\"\r\n [object]=\"object\"\r\n label=\"Campo da sommare\"\r\n (valueChange)=\"setAggregationField(row, $event ?? '')\"\r\n />\r\n } @else if (aggregationClass(row); as className) {\r\n <fb-structure-member-picker\r\n [value]=\"aggregationField(row.action)\"\r\n [className]=\"className\"\r\n label=\"Membro da sommare\"\r\n (valueChange)=\"setAggregationField(row, $event ?? '')\"\r\n />\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"aggregationField(row.action)\"\r\n placeholder=\"Importo\"\r\n (input)=\"setAggregationField(row, $any($event.target).value)\"\r\n />\r\n }\r\n </div>\r\n }\r\n\r\n @for (issue of issuesOf(row); track $index) {\r\n <p class=\"fb-callout fb-callout--error\">{{ issue.message }} ({{ issue.code }})</p>\r\n }\r\n } @else {\r\n <p class=\"fb-tr__hint\">\r\n Scegli il tipo del risultato: le destinazioni compaiono da l\u00EC, e la mappatura si fa\r\n trascinando una sorgente su una di esse.\r\n </p>\r\n }\r\n </aside>\r\n</div>\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", styles: [":host{display:block;container-type:inline-size}.fb-tr{display:grid;grid-template-columns:240px minmax(0,1fr) 320px;gap:12px;align-items:start;margin-bottom:14px}@container (max-width: 1040px){.fb-tr{grid-template-columns:minmax(0,1fr)}}.fb-tr__panel{min-width:0;padding:10px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-surface-alt, #f7f8fa)}.fb-tr__map{background:var(--fb-surface, #fff)}.fb-tr__panel-title{display:flex;align-items:baseline;justify-content:space-between;gap:8px;margin:0 0 8px;font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3);overflow-wrap:anywhere}.fb-tr__count{font-size:10px;font-weight:600;letter-spacing:0;text-transform:none;color:var(--fb-text-muted, #6b7086)}.fb-tr__hint{margin:6px 0;font-size:11px;line-height:1.45;color:var(--fb-text-muted, #6b7086)}.fb-tr__search{margin-bottom:6px}.fb-tr__crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:2px;margin-bottom:6px}.fb-tr__crumb{padding:2px 4px;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-accent, #4f6ef7);font:inherit;font-size:11px;cursor:pointer}.fb-tr__crumb:hover{background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 10%,transparent)}.fb-tr__crumb-sep{color:var(--fb-text-subtle, #98a2b3);font-size:11px}.fb-tr__list{display:flex;flex-direction:column;gap:4px;margin:0;padding:0;max-height:340px;overflow-y:auto;overscroll-behavior:contain;list-style:none}.fb-tr__empty{padding:8px;border:1px dashed var(--fb-border, #d6dae1);border-radius:var(--fb-radius-xs, 6px);font-size:11px;line-height:1.45;color:var(--fb-text-muted, #667085)}.fb-tr__source-row{display:flex;align-items:stretch;gap:2px}.fb-tr__source{display:flex;flex:1;flex-direction:column;gap:1px;min-width:0;padding:5px 8px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text, #1a1c23);font:inherit;font-size:12px;text-align:left;cursor:grab}.fb-tr__source:hover{border-color:var(--fb-accent, #4f6ef7)}.fb-tr__source--dragging{opacity:.6}.fb-tr__source-name,.fb-tr__source-detail{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-tr__source-detail{font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-tr__enter{flex:none}.fb-tr__badge{margin-left:4px;padding:0 4px;border-radius:4px;background:var(--fb-surface-sunken, #eef0f4);font-size:9px;font-weight:700;color:var(--fb-text-muted, #6b7086)}.fb-tr__badge--warn{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-tr__result{margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4)}.fb-tr__collection{align-self:end;padding-bottom:6px;white-space:nowrap}.fb-tr__rows{max-height:420px;margin-bottom:8px}.fb-tr__row{display:flex;align-items:stretch;gap:2px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff)}.fb-tr__row--empty{border-style:dashed;background:var(--fb-surface-alt, #f7f8fa)}.fb-tr__row--selected{border-color:var(--fb-accent, #4f6ef7);box-shadow:0 0 0 1px var(--fb-accent, #4f6ef7) inset}.fb-tr__row--drop{border-color:var(--fb-accent, #4f6ef7);border-style:solid;background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 12%,transparent)}.fb-tr__row-main{display:flex;flex:1;align-items:center;gap:8px;min-width:0;padding:6px 8px;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-text, #1a1c23);font:inherit;text-align:left;cursor:pointer}.fb-tr__op{display:grid;flex:none;place-items:center;width:20px;height:20px;border-radius:50%;background:var(--fb-surface-sunken, #eef0f4);font-size:11px;font-weight:700;color:var(--fb-text-muted, #6b7086)}.fb-tr__row-text{display:flex;flex:1;flex-direction:column;gap:1px;min-width:0}.fb-tr__row-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:600}.fb-tr__row-src{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:10px;color:var(--fb-text-muted, #6b7086)}.fb-tr__row-src--empty{color:var(--fb-text-subtle, #98a2b3);font-style:italic}.fb-tr__row-type{flex:none;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-tr__row-issue{display:grid;flex:none;place-items:center;width:16px;height:16px;border-radius:50%;background:color-mix(in srgb,var(--fb-error, #dc2626) 14%,transparent);font-size:10px;font-weight:700;color:var(--fb-error, #dc2626)}.fb-tr__modes{margin-top:2px}\n"], dependencies: [{ kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ObjectPickerComponent, selector: "fb-object-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences"], outputs: ["valueChange"] }, { kind: "component", type: StructureMemberPickerComponent, selector: "fb-structure-member-picker", inputs: ["value", "className", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: StructurePickerComponent, selector: "fb-structure-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
14927
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: TransformInspectorComponent, isStandalone: true, selector: "fb-transform-inspector", usesInheritance: true, ngImport: i0, template: "<div class=\"fb-tr\">\r\n <!-- ============================================================ sorgenti -->\r\n <aside class=\"fb-tr__panel\" aria-label=\"Sorgenti\">\r\n <h3 class=\"fb-tr__panel-title\">Sorgenti</h3>\r\n\r\n <input\r\n class=\"fb-input fb-tr__search\"\r\n type=\"search\"\r\n placeholder=\"Cerca una sorgente\"\r\n aria-label=\"Cerca una sorgente\"\r\n [value]=\"sourceQuery()\"\r\n (input)=\"sourceQuery.set($any($event.target).value)\"\r\n />\r\n\r\n @if (sourceCrumbs().length) {\r\n <nav class=\"fb-tr__crumbs\" aria-label=\"Percorso della sorgente\">\r\n <button type=\"button\" class=\"fb-tr__crumb\" (click)=\"enterSource('')\">Tutte</button>\r\n @for (crumb of sourceCrumbs(); track crumb.path) {\r\n <span class=\"fb-tr__crumb-sep\" aria-hidden=\"true\">\u203A</span>\r\n <button type=\"button\" class=\"fb-tr__crumb\" (click)=\"enterSource(crumb.path)\">{{ crumb.label }}</button>\r\n }\r\n </nav>\r\n }\r\n\r\n <p class=\"fb-tr__hint\">\r\n Trascina su una destinazione, oppure clicca per mapparla su quella selezionata.\r\n </p>\r\n\r\n @if (sourceError()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n {{ sourceError() }} Le sorgenti si scrivono a mano nel dettaglio: l\u2019elenco non c\u2019e\u2019, i\r\n riferimenti s\u00EC.\r\n </p>\r\n }\r\n\r\n <ul class=\"fb-tr__list\">\r\n @for (source of sources(); track source.path) {\r\n <li class=\"fb-tr__source-row\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-tr__source\"\r\n cdkDrag\r\n [class.fb-tr__source--dragging]=\"draggingPath() === source.path\"\r\n [title]=\"source.path + (source.detail ? ' \u00B7 ' + source.detail : '')\"\r\n (cdkDragStarted)=\"onSourceDragStarted(source)\"\r\n (cdkDragMoved)=\"onSourceDragMoved($event)\"\r\n (cdkDragEnded)=\"onSourceDragEnded($event, source)\"\r\n (click)=\"mapToSelected(source)\"\r\n >\r\n <span class=\"fb-tr__source-name\">\r\n {{ source.label }}\r\n @if (source.isCollection) {\r\n <span class=\"fb-tr__badge\" aria-label=\"collection\">[ ]</span>\r\n }\r\n </span>\r\n @if (source.detail) {\r\n <span class=\"fb-tr__source-detail\">{{ source.detail }}</span>\r\n }\r\n </button>\r\n @if (source.canEnter) {\r\n <!-- Entrare e mappare sono due gesti diversi: un record intero e' una sorgente valida. -->\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon fb-tr__enter\"\r\n [attr.aria-label]=\"'Entra in ' + source.label\"\r\n (click)=\"enterSource(source.path)\"\r\n >\r\n \u203A\r\n </button>\r\n }\r\n </li>\r\n } @empty {\r\n @if (sourcePending()) {\r\n <li class=\"fb-tr__empty\">Caricamento\u2026</li>\r\n } @else if (sourceUndeclared()) {\r\n <li class=\"fb-tr__empty\">\r\n Il catalogo non dichiara cosa c\u2019e\u2019 qui dentro: non significa che non ci sia niente. Il\r\n percorso si scrive a mano nel dettaglio.\r\n </li>\r\n } @else {\r\n <li class=\"fb-tr__empty\">Nessuna sorgente con questo nome.</li>\r\n }\r\n }\r\n </ul>\r\n </aside>\r\n\r\n <!-- ========================================================= destinazione -->\r\n <section class=\"fb-tr__panel fb-tr__map\" aria-label=\"Destinazione\">\r\n <h3 class=\"fb-tr__panel-title\">\r\n Destinazione\r\n @if (slotCount()) {\r\n <span class=\"fb-tr__count\">{{ mappedCount() }} di {{ slotCount() }} mappate</span>\r\n } @else if (mappedCount()) {\r\n <span class=\"fb-tr__count\">{{ mappedCount() }} mappate</span>\r\n }\r\n </h3>\r\n\r\n <!-- Il tipo del risultato e' la forma della colonna: sta in cima, non in fondo. -->\r\n <div class=\"fb-tr__result\">\r\n <div class=\"fb-fields-row\">\r\n <div class=\"fb-field fb-field--compact\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo del risultato</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"transform().dataType || ''\"\r\n (change)=\"setDataType($any($event.target).value)\"\r\n >\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 </div>\r\n\r\n @if (requiresObjectType()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">\r\n {{ isStructureTarget() ? 'Classe del risultato' : 'Tipo dell\u2019oggetto' }}\r\n </label>\r\n @if (isStructureTarget()) {\r\n <!-- \u00A74.7: una classe del backend. Le destinazioni delle azioni sono i suoi membri. -->\r\n <fb-structure-picker\r\n [value]=\"transform().objectType\"\r\n label=\"Classe del risultato\"\r\n (valueChange)=\"setObjectType($event ?? '')\"\r\n />\r\n } @else if (transform().dataType === 'Enum') {\r\n <!-- Le enumerazioni sono un dizionario chiuso: non c'e' scrittura libera da concedere. -->\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 @for (entry of enumOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n </select>\r\n } @else {\r\n <fb-object-picker\r\n [value]=\"transform().objectType\"\r\n label=\"Tipo dell\u2019oggetto\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setObjectType($event ?? '')\"\r\n />\r\n }\r\n </div>\r\n }\r\n\r\n <label class=\"fb-check fb-tr__collection\">\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 Collection\r\n </label>\r\n </div>\r\n\r\n @if (!transform().dataType) {\r\n <p class=\"fb-field__error\">Obbligatorio (TRANSFORM_DATA_TYPE_MISSING).</p>\r\n }\r\n @if (missingObjectType()) {\r\n <p class=\"fb-field__error\">\r\n La classe e\u2019 obbligatoria: senza, l\u2019attivazione e\u2019 bloccata (OBJECT_TYPE_MISSING).\r\n </p>\r\n }\r\n @if (targetUndeclared()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il catalogo non dichiara i {{ isStructureTarget() ? 'membri' : 'campi' }} di\r\n <code>{{ transform().objectType }}</code>: le destinazioni si scrivono a mano, e nessuna di\r\n esse viene accusata di non esistere.\r\n </p>\r\n }\r\n </div>\r\n\r\n <ul class=\"fb-tr__list fb-tr__rows\">\r\n @for (row of targets(); track row.key) {\r\n <!--\r\n `data-fb-slot` e' cio' che il rilascio cerca: il bersaglio lo calcola `hitTest` dal DOM,\r\n non una drop list del CDK.\r\n -->\r\n <li\r\n class=\"fb-tr__row\"\r\n [attr.data-fb-slot]=\"row.key\"\r\n [class.fb-tr__row--selected]=\"isSelected(row)\"\r\n [class.fb-tr__row--drop]=\"dropKey() === row.key\"\r\n [class.fb-tr__row--empty]=\"row.index < 0\"\r\n >\r\n <button type=\"button\" class=\"fb-tr__row-main\" (click)=\"select(row.key)\">\r\n <span class=\"fb-tr__op\" [attr.title]=\"operationLabel(operationOf(row))\" aria-hidden=\"true\">\r\n {{ operationIcon(row) }}\r\n </span>\r\n <span class=\"fb-tr__row-text\">\r\n <span class=\"fb-tr__row-name\">\r\n {{ row.label }}\r\n @if (row.isCollection) {\r\n <span class=\"fb-tr__badge\" aria-label=\"collection\">[ ]</span>\r\n }\r\n @if (row.isUnknown) {\r\n <span class=\"fb-tr__badge fb-tr__badge--warn\">fuori catalogo</span>\r\n }\r\n </span>\r\n @if (row.index < 0) {\r\n <span class=\"fb-tr__row-src fb-tr__row-src--empty\">non mappata</span>\r\n } @else if (sourceSummary(row)) {\r\n <span class=\"fb-tr__row-src\">\u2190 {{ sourceSummary(row) }}</span>\r\n } @else {\r\n <span class=\"fb-tr__row-src fb-tr__row-src--empty\">sorgente da indicare</span>\r\n }\r\n </span>\r\n @if (row.dataType) {\r\n <span class=\"fb-tr__row-type\">{{ row.dataType }}</span>\r\n }\r\n @if (issuesOf(row).length) {\r\n <span class=\"fb-tr__row-issue\" [attr.title]=\"issuesOf(row)[0].message\">!</span>\r\n }\r\n </button>\r\n @if (row.index >= 0) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n [attr.aria-label]=\"'Togli la mappatura di ' + row.label\"\r\n (click)=\"removeAction(row)\"\r\n >\r\n \u00D7\r\n </button>\r\n }\r\n </li>\r\n } @empty {\r\n <li class=\"fb-empty\">\r\n Nessuna trasformazione: l\u2019elemento non produce nulla (TRANSFORM_WITHOUT_VALUES).\r\n </li>\r\n }\r\n </ul>\r\n\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addAction()\">\r\n {{ hasTargetCatalog() ? 'Aggiungi una destinazione fuori catalogo' : 'Aggiungi trasformazione' }}\r\n </button>\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 </section>\r\n\r\n <!-- ============================================================ dettaglio -->\r\n <aside class=\"fb-tr__panel fb-tr__detail\" aria-label=\"Dettaglio della mappatura\">\r\n @if (selected(); as row) {\r\n <h3 class=\"fb-tr__panel-title\">{{ row.label }}</h3>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Operazione</label>\r\n <div class=\"fb-tr__modes\" role=\"group\" aria-label=\"Operazione\">\r\n @for (type of transformTypes(); track type.value) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-tr__mode\"\r\n [class.fb-tr__mode--active]=\"operationOf(row) === type.value\"\r\n (click)=\"setOperation(row, type.value)\"\r\n >\r\n {{ type.label }}\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">\r\n {{ isStructureTarget() ? 'Membro di destinazione' : 'Campo di destinazione' }}\r\n </label>\r\n @if (isStructureTarget()) {\r\n <!-- Solo i membri scrivibili: un membro calcolato e' TARGET_NOT_WRITABLE (\u00A74.7). -->\r\n <fb-structure-member-picker\r\n [value]=\"row.field\"\r\n [className]=\"transform().objectType\"\r\n usage=\"writable\"\r\n label=\"Membro di destinazione\"\r\n (valueChange)=\"setOutputField(row, $event ?? '')\"\r\n />\r\n } @else if (targetObject()) {\r\n <!-- Il risultato e' un record: le destinazioni sono i campi della sua entita' (\u00A74.4). -->\r\n <fb-field-picker\r\n [value]=\"row.field\"\r\n [object]=\"targetObject()\"\r\n label=\"Campo di destinazione\"\r\n (valueChange)=\"setOutputField(row, $event ?? '')\"\r\n />\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"row.field\"\r\n placeholder=\"Totale\"\r\n (input)=\"setOutputField(row, $any($event.target).value)\"\r\n />\r\n }\r\n </div>\r\n\r\n @if (isMap(row)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Valore</label>\r\n <!--\r\n Il tipo di cio' che si scrive guida il controllo: su un campo o un membro Enum i valori\r\n proponibili sono quelli del suo tipo (\u00A74.6).\r\n -->\r\n <fb-value-editor\r\n [value]=\"row.action?.value ?? undefined\"\r\n label=\"Valore\"\r\n [dataType]=\"mapDataType(row)\"\r\n [objectType]=\"mapObjectType(row)\"\r\n (valueChange)=\"setMapValue(row, $event)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (needsAggregationValues(row)) {\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(row.action)\"\r\n [isCollection]=\"true\"\r\n placeholder=\"Scegli una collection\"\r\n (valueChange)=\"setAggregationCollection(row, $event)\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (needsAggregationField(row)) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo da sommare</label>\r\n <!--\r\n Nel documento va il **nome** del campo (`stringValue`, \u00A75.13); dove il tipo della\r\n collection e' noto, il nome lo si sceglie da un elenco invece di ricordarlo.\r\n -->\r\n @if (aggregationObject(row); as object) {\r\n <fb-field-picker\r\n [value]=\"aggregationField(row.action)\"\r\n [object]=\"object\"\r\n label=\"Campo da sommare\"\r\n (valueChange)=\"setAggregationField(row, $event ?? '')\"\r\n />\r\n } @else if (aggregationClass(row); as className) {\r\n <fb-structure-member-picker\r\n [value]=\"aggregationField(row.action)\"\r\n [className]=\"className\"\r\n label=\"Membro da sommare\"\r\n (valueChange)=\"setAggregationField(row, $event ?? '')\"\r\n />\r\n } @else {\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"aggregationField(row.action)\"\r\n placeholder=\"Importo\"\r\n (input)=\"setAggregationField(row, $any($event.target).value)\"\r\n />\r\n }\r\n </div>\r\n }\r\n\r\n @for (issue of issuesOf(row); track $index) {\r\n <p class=\"fb-callout fb-callout--error\">{{ issue.message }} ({{ issue.code }})</p>\r\n }\r\n } @else {\r\n <p class=\"fb-tr__hint\">\r\n Scegli il tipo del risultato: le destinazioni compaiono da l\u00EC, e la mappatura si fa\r\n trascinando una sorgente su una di esse.\r\n </p>\r\n }\r\n </aside>\r\n</div>\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", styles: [":host{display:block;container-type:inline-size}.fb-tr{display:grid;grid-template-columns:240px minmax(0,1fr) 320px;gap:12px;align-items:start;margin-bottom:14px}@container (max-width: 1040px){.fb-tr{grid-template-columns:minmax(0,1fr)}}.fb-tr__panel{min-width:0;padding:10px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius, 10px);background:var(--fb-surface-alt, #f7f8fa)}.fb-tr__map{background:var(--fb-surface, #fff)}.fb-tr__panel-title{display:flex;align-items:baseline;justify-content:space-between;gap:8px;margin:0 0 8px;font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3);overflow-wrap:anywhere}.fb-tr__count{font-size:10px;font-weight:600;letter-spacing:0;text-transform:none;color:var(--fb-text-muted, #6b7086)}.fb-tr__hint{margin:6px 0;font-size:11px;line-height:1.45;color:var(--fb-text-muted, #6b7086)}.fb-tr__search{margin-bottom:6px}.fb-tr__crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:2px;margin-bottom:6px}.fb-tr__crumb{padding:2px 4px;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-accent, #4f6ef7);font:inherit;font-size:11px;cursor:pointer}.fb-tr__crumb:hover{background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 10%,transparent)}.fb-tr__crumb-sep{color:var(--fb-text-subtle, #98a2b3);font-size:11px}.fb-tr__list{display:flex;flex-direction:column;gap:4px;margin:0;padding:0;max-height:340px;overflow-y:auto;overscroll-behavior:contain;list-style:none}.fb-tr__empty{padding:8px;border:1px dashed var(--fb-border, #d6dae1);border-radius:var(--fb-radius-xs, 6px);font-size:11px;line-height:1.45;color:var(--fb-text-muted, #667085)}.fb-tr__source-row{display:flex;align-items:stretch;gap:2px}.fb-tr__source{display:flex;flex:1;flex-direction:column;gap:1px;min-width:0;padding:5px 8px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff);color:var(--fb-text, #1a1c23);font:inherit;font-size:12px;text-align:left;cursor:grab}.fb-tr__source:hover{border-color:var(--fb-accent, #4f6ef7)}.fb-tr__source--dragging{opacity:.6}.fb-tr__source-name,.fb-tr__source-detail{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fb-tr__source-detail{font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-tr__enter{flex:none}.fb-tr__badge{margin-left:4px;padding:0 4px;border-radius:4px;background:var(--fb-surface-sunken, #eef0f4);font-size:9px;font-weight:700;color:var(--fb-text-muted, #6b7086)}.fb-tr__badge--warn{background:color-mix(in srgb,var(--fb-warning, #b7791f) 16%,transparent);color:var(--fb-warning, #b7791f)}.fb-tr__result{margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--fb-border-subtle, #eef0f4)}.fb-tr__collection{align-self:end;padding-bottom:6px;white-space:nowrap}.fb-tr__rows{max-height:420px;margin-bottom:8px}.fb-tr__row{display:flex;align-items:stretch;gap:2px;border:1px solid var(--fb-border, #e2e5eb);border-radius:var(--fb-radius-xs, 6px);background:var(--fb-surface, #fff)}.fb-tr__row--empty{border-style:dashed;background:var(--fb-surface-alt, #f7f8fa)}.fb-tr__row--selected{border-color:var(--fb-accent, #4f6ef7);box-shadow:0 0 0 1px var(--fb-accent, #4f6ef7) inset}.fb-tr__row--drop{border-color:var(--fb-accent, #4f6ef7);border-style:solid;background:color-mix(in srgb,var(--fb-accent, #4f6ef7) 12%,transparent)}.fb-tr__row-main{display:flex;flex:1;align-items:center;gap:8px;min-width:0;padding:6px 8px;border:0;border-radius:var(--fb-radius-xs, 6px);background:transparent;color:var(--fb-text, #1a1c23);font:inherit;text-align:left;cursor:pointer}.fb-tr__op{display:grid;flex:none;place-items:center;width:20px;height:20px;border-radius:50%;background:var(--fb-surface-sunken, #eef0f4);font-size:11px;font-weight:700;color:var(--fb-text-muted, #6b7086)}.fb-tr__row-text{display:flex;flex:1;flex-direction:column;gap:1px;min-width:0}.fb-tr__row-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:600}.fb-tr__row-src{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:10px;color:var(--fb-text-muted, #6b7086)}.fb-tr__row-src--empty{color:var(--fb-text-subtle, #98a2b3);font-style:italic}.fb-tr__row-type{flex:none;font-size:10px;color:var(--fb-text-subtle, #98a2b3)}.fb-tr__row-issue{display:grid;flex:none;place-items:center;width:16px;height:16px;border-radius:50%;background:color-mix(in srgb,var(--fb-error, #dc2626) 14%,transparent);font-size:10px;font-weight:700;color:var(--fb-error, #dc2626)}.fb-tr__modes{margin-top:2px}\n"], dependencies: [{ kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "component", type: ConnectorEditorComponent, selector: "fb-connector-editor", inputs: ["nodeName", "node", "outlets", "title"], outputs: ["connectorChanged"] }, { kind: "component", type: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ObjectPickerComponent, selector: "fb-object-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences", "preferredRoots"], outputs: ["valueChange"] }, { kind: "component", type: StructureMemberPickerComponent, selector: "fb-structure-member-picker", inputs: ["value", "className", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: StructurePickerComponent, selector: "fb-structure-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula", "preferredRoots"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
14606
14928
|
}
|
|
14607
14929
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: TransformInspectorComponent, decorators: [{
|
|
14608
14930
|
type: Component,
|
|
@@ -14727,7 +15049,7 @@ class WaitInspectorComponent extends NodeInspectorBase {
|
|
|
14727
15049
|
this.setField('defaultConnectorLabel', label);
|
|
14728
15050
|
}
|
|
14729
15051
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: WaitInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
14730
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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", "extraTargets"], outputs: ["changed"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
15052
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", 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", "preferredRoots", "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", "extraTargets", "preferredRoots"], outputs: ["changed"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
14731
15053
|
}
|
|
14732
15054
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: WaitInspectorComponent, decorators: [{
|
|
14733
15055
|
type: Component,
|
|
@@ -16167,7 +16489,7 @@ class ResourceFormComponent {
|
|
|
16167
16489
|
return this.resource()['value'];
|
|
16168
16490
|
}
|
|
16169
16491
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ResourceFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
16170
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: ResourceFormComponent, isStandalone: true, selector: "fb-resource-form", inputs: { reference: { classPropertyName: "reference", publicName: "reference", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<!--\r\n Il form di **una** risorsa: e' cio' che prima stava inline sotto la riga dell'elenco, e ora\r\n vive nella dialog. I rilievi locali stanno in cima e non accanto al campo che li produce\r\n perche' qui il form si apre gi\u00E0 puntato sulla risorsa: la domanda \u00ABcosa non va\u00BB viene prima\r\n di \u00ABdove\u00BB.\r\n-->\r\n@if (nameError(); as message) {\r\n <p class=\"fb-field__error\">{{ message }}</p>\r\n}\r\n@if (constantReferencesResource()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Una costante deve essere un valore fisso: non puo\u2019 referenziare altre risorse\r\n (CONSTANT_REFERENCES_RESOURCE).\r\n </p>\r\n}\r\n@if (duplicateStageOrder()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Due stage con lo stesso ordine: quale sia il corrente all\u2019avvio diventa arbitrario\r\n (STAGE_ORDER_DUPLICATED).\r\n </p>\r\n}\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Nome</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"reference().name\"\r\n (change)=\"rename($any($event.target).value)\"\r\n />\r\n <!--\r\n Le tre categorie non si comportano allo stesso modo davanti a una rinomina, e questo e' il\r\n punto in cui il gesto avviene: i riferimenti e i merge field li riscrive l\u2019editor, le\r\n espressioni delle formule no \u2014 la loro sintassi e\u2019 del motore. Dirlo altrove vorrebbe dire\r\n dirlo a chi non sta rinominando.\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Il nome vive nello stesso spazio dei nomi degli elementi. Rinominare riscrive i riferimenti e i\r\n merge field <code>{!\u2026}</code> nei testi.\r\n </p>\r\n @if (formulaUseCount()) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Attenzione: {{ formulaUseCount() }}\r\n {{ formulaUseCount() === 1 ? 'occorrenza sta' : 'occorrenze stanno' }} dentro\r\n {{ formulaUseCount() === 1 ? 'una formula' : 'delle formule' }} e\r\n <strong>non {{ formulaUseCount() === 1 ? 'viene' : 'vengono' }} riscritt{{ formulaUseCount() === 1 ? 'a' : 'e' }}</strong>:\r\n la sintassi e\u2019 del motore di regole, quindi\r\n {{ formulaUseCount() === 1 ? 'va corretta' : 'vanno corrette' }} a mano.\r\n </p>\r\n }\r\n</div>\r\n\r\n@if (collection() === 'stages') {\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]=\"string('label')\"\r\n (input)=\"setField('label', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Ordine</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"string('stageOrder')\"\r\n (input)=\"setNumberField('stageOrder', $any($event.target).value)\"\r\n />\r\n </div>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"boolean('isActive')\"\r\n (change)=\"setBooleanField('isActive', $any($event.target).checked)\"\r\n />\r\n Attivo all\u2019avvio\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n All\u2019avvio lo stage corrente e\u2019 il primo attivo per ordine. Si avanza con un Assignment su\r\n <code>$Flow.CurrentStage</code>.\r\n </p>\r\n}\r\n\r\n@if (collection() === 'textTemplates') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Testo</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"string('text')\"\r\n placeholder=\"Gentile {!Cliente.Nome},\"\r\n (input)=\"setField('text', $any($event.target).value)\"\r\n ></textarea>\r\n </div>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"boolean('isViewedAsPlainText')\"\r\n (change)=\"setBooleanField('isViewedAsPlainText', $any($event.target).checked)\"\r\n />\r\n Testo semplice\r\n </label>\r\n}\r\n\r\n@if (collection() !== 'textTemplates' && collection() !== 'stages') {\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]=\"string('dataType')\"\r\n (change)=\"setDataType($any($event.target).value)\"\r\n >\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 (collection() === 'dynamicChoiceSets') {\r\n <!--\r\n \u00A75.2 \u2014 il valore di un'opzione **generata** non lo scrive l'autore del flow: lo produce\r\n la sorgente, nel tipo in cui il sistema ospite lo tiene, e `dataType` decide il tipo in\r\n cui viaggia. La regola e' generale \u2014 vale per tutte e tre le sorgenti \u2014 e si vede su un\r\n oggetto la cui chiave e' un enum, dove nella tendina serve di norma il numero.\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Decide il tipo in cui viaggia il valore dell\u2019opzione, con qualunque sorgente:\r\n <code>String</code> il nome come testo, <code>Integer</code> o <code>Number</code> il\r\n numero sottostante, <code>Enum</code> il valore tipizzato \u2014 che e\u2019 cio\u2019 che serve in un\r\n parametro o in un membro di classe <code>Enum</code>. Una conversione impossibile non fa\r\n fallire niente: resta il valore prodotto dalla sorgente.\r\n </p>\r\n }\r\n </div>\r\n\r\n @if (requiresObjectType() && !hidesObjectType()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">\r\n @if (isEnum()) {\r\n Tipo di enumerazione\r\n } @else if (isStructure()) {\r\n Classe\r\n } @else {\r\n Oggetto\r\n }\r\n </label>\r\n @if (isEnum()) {\r\n <!-- Dizionario chiuso: qui la scrittura libera non serve. -->\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"string('objectType')\"\r\n (change)=\"setField('objectType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of enumOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n </select>\r\n } @else if (isStructure()) {\r\n <!-- \u00A74.7: una classe del backend, non un'entita' del modello dati. -->\r\n <fb-structure-picker\r\n [value]=\"string('objectType') || undefined\"\r\n label=\"Classe\"\r\n (valueChange)=\"setField('objectType', $event ?? '')\"\r\n />\r\n } @else {\r\n <fb-object-picker\r\n [value]=\"string('objectType') || undefined\"\r\n label=\"Oggetto\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setField('objectType', $event ?? '')\"\r\n />\r\n }\r\n @if (missingObjectType()) {\r\n <!-- Su una Structure non e' un avviso: senza classe non c'e' nulla da istanziare. -->\r\n <p class=\"fb-field__error\">\r\n La classe e\u2019 obbligatoria: senza, l\u2019attivazione e\u2019 bloccata (OBJECT_TYPE_MISSING).\r\n </p>\r\n } @else if (isStructure()) {\r\n <p class=\"fb-field__hint\">\r\n Il flow ne legge e scrive i <strong>membri</strong> (<code>Nome.Membro</code>): non si\r\n interroga con Get Records ne\u2019 si salva con Create/Update.\r\n </p>\r\n } @else {\r\n <p class=\"fb-field__hint\">Obbligatorio per Object ed Enum (OBJECT_TYPE_MISSING).</p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (supportsScale()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Decimali</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"0\"\r\n [value]=\"string('scale')\"\r\n (input)=\"setNumberField('scale', $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n}\r\n\r\n@if (collection() === 'variables') {\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"boolean('isCollection')\"\r\n (change)=\"setBooleanField('isCollection', $any($event.target).checked)\"\r\n />\r\n \u00C8 una collection\r\n </label>\r\n <p class=\"fb-field__hint\">Solo una collection puo\u2019 essere iterata da un Loop.</p>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"boolean('isInput')\"\r\n (change)=\"setBooleanField('isInput', $any($event.target).checked)\"\r\n />\r\n Valorizzabile all\u2019avvio (input)\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"boolean('isOutput')\"\r\n (change)=\"setBooleanField('isOutput', $any($event.target).checked)\"\r\n />\r\n Leggibile alla fine (output)\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n Input e output sono il contratto del flow verso chi lo invoca, subflow compresi.\r\n </p>\r\n}\r\n\r\n@if (collection() === 'formulas') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Espressione</label>\r\n <!--\r\n Il tipo atteso e' quello che la risorsa dichiara, e `scale` va con lui: sono cio'\r\n che permette al motore di dire che l'espressione produce altro (\u00A76.3).\r\n -->\r\n <fb-formula-editor\r\n [expression]=\"string('expression')\"\r\n usage=\"Resource\"\r\n [expectedDataType]=\"$any(resource()['dataType'])\"\r\n [scale]=\"$any(resource()['scale'])\"\r\n placeholder=\"Importo * 1.22\"\r\n ariaLabel=\"Espressione della formula\"\r\n (expressionChange)=\"setField('expression', $event)\"\r\n >\r\n <p class=\"fb-field__hint\">\r\n Passata verbatim al motore di regole: la sintassi delle funzioni e\u2019 del motore.\r\n </p>\r\n </fb-formula-editor>\r\n </div>\r\n}\r\n\r\n@if (collection() === 'choices') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Testo mostrato</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"string('choiceText')\"\r\n (input)=\"setField('choiceText', $any($event.target).value)\"\r\n />\r\n </div>\r\n}\r\n\r\n@if (collection() === 'dynamicChoiceSets') {\r\n <!--\r\n \u00A75.2 \u2014 le sorgenti sono tre e si escludono a vicenda: i pulsanti le rendono\r\n mutuamente esclusive nel documento, non solo nel form.\r\n -->\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Da dove arrivano le opzioni</label>\r\n <div class=\"fb-filter__modes\" role=\"group\" aria-label=\"Sorgente delle opzioni\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"isChoiceSetSource('collection')\"\r\n (click)=\"setChoiceSetSource('collection')\"\r\n >\r\n Collection del flow\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"isChoiceSetSource('object')\"\r\n (click)=\"setChoiceSetSource('object')\"\r\n >\r\n Query su un oggetto\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"isChoiceSetSource('enum')\"\r\n (click)=\"setChoiceSetSource('enum')\"\r\n >\r\n Valori di un enum\r\n </button>\r\n </div>\r\n </div>\r\n\r\n @if (ambiguousChoiceSetSource()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questo choice set dichiara piu\u2019 di una sorgente: il runtime ne usa una sola\r\n (CHOICE_SET_SOURCE_AMBIGUOUS). Scegli quella giusta qui sopra: le altre vengono tolte.\r\n </p>\r\n }\r\n\r\n @if (isChoiceSetSource('collection')) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Collection</label>\r\n <fb-reference-picker\r\n [value]=\"string('collectionReference')\"\r\n [isCollection]=\"true\"\r\n placeholder=\"Scegli una collection\"\r\n (valueChange)=\"setField('collectionReference', $event ?? '')\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Tipicamente il risultato di un Get Records: le opzioni sono i record che il flow ha gi\u00E0\r\n letto, <strong>nell\u2019ordine in cui ci sono</strong>. Filtri e ordinamento non si applicano\r\n qui: per sceglierne una parte, filtra la collection con un elemento Filter prima dello\r\n screen.\r\n </p>\r\n </div>\r\n }\r\n\r\n @if (isChoiceSetSource('object')) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Oggetto</label>\r\n <fb-object-picker\r\n [value]=\"string('object') || undefined\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setField('object', $event ?? '')\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (isChoiceSetSource('enum')) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo di enumerazione</label>\r\n <!-- Dizionario chiuso, e qui e' anche **autorevole**: un tipo fuori elenco e' un errore. -->\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"string('enumType')\"\r\n (change)=\"setField('enumType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of enumOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n </select>\r\n @if (unknownEnumType()) {\r\n <p class=\"fb-field__error\">\r\n Il tipo \u00AB{{ string('enumType') }}\u00BB non e\u2019 fra quelli utilizzabili\r\n (ENUM_TYPE_UNKNOWN).\r\n </p>\r\n } @else {\r\n <p class=\"fb-field__hint\">\r\n Le opzioni sono i valori dichiarati dal tipo: nessuna choice da tenere allineata a mano.\r\n </p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (isChoiceSetSource('enum')) {\r\n <!--\r\n \u00A75.2 \u2014 qui i campi citabili sono le tre proprieta' di un valore di enum, non i campi\r\n di un'entita': l'elenco viene dal dizionario, e i default rendono superfluo dichiararli.\r\n -->\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo mostrato</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"string('displayField')\"\r\n (change)=\"setField('displayField', $any($event.target).value)\"\r\n >\r\n <option value=\"\">Predefinito ({{ defaultDisplayField }})</option>\r\n @for (field of enumChoiceSetFields(); track field.value) {\r\n <option [value]=\"field.value\">{{ field.label }}</option>\r\n }\r\n </select>\r\n @if (unknownEnumChoiceSetField('displayField')) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ string('displayField') }}\u00BB non e\u2019 una proprieta\u2019 di un valore di enum\r\n (FIELD_UNKNOWN).\r\n </p>\r\n }\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo del valore</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"string('valueField')\"\r\n (change)=\"setField('valueField', $any($event.target).value)\"\r\n >\r\n <option value=\"\">Predefinito ({{ defaultValueField }})</option>\r\n @for (field of enumChoiceSetFields(); track field.value) {\r\n <option [value]=\"field.value\">{{ field.label }}</option>\r\n }\r\n </select>\r\n @if (unknownEnumChoiceSetField('valueField')) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ string('valueField') }}\u00BB non e\u2019 una proprieta\u2019 di un valore di enum\r\n (FIELD_UNKNOWN).\r\n </p>\r\n }\r\n </div>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Dichiarare <code>Integer</code> come tipo della risorsa e\u2019 la stessa cosa che scegliere qui\r\n \u00ABValore numerico\u00BB: il valore dell\u2019opzione e\u2019 il numero sottostante.\r\n </p>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo mostrato</label>\r\n <fb-field-picker\r\n [value]=\"string('displayField') || undefined\"\r\n [object]=\"string('object') || undefined\"\r\n usage=\"any\"\r\n label=\"Campo mostrato\"\r\n (valueChange)=\"setField('displayField', $event ?? '')\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo del valore</label>\r\n <fb-field-picker\r\n [value]=\"string('valueField') || undefined\"\r\n [object]=\"string('object') || undefined\"\r\n usage=\"any\"\r\n label=\"Campo del valore\"\r\n (valueChange)=\"setField('valueField', $event ?? '')\"\r\n />\r\n </div>\r\n }\r\n <!--\r\n \u00A75.2 \u2014 `filters`, `filterLogic`, `sortField` e `sortOrder` valgono sulle **sole** sorgenti\r\n `object` (dove diventano la query) ed `enumType` (valutati in memoria). Su una collection le\r\n opzioni sono i suoi elementi nell\u2019ordine in cui ci sono: mostrare i controlli l\u00EC\r\n inviterebbe a dichiarare cio\u2019 che il runtime ignora, ed e\u2019 `CHOICE_SET_FILTERS_IGNORED`.\r\n -->\r\n @if (!isChoiceSetSource('collection')) {\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Ordina per</label>\r\n @if (isChoiceSetSource('enum')) {\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"string('sortField')\"\r\n (change)=\"setField('sortField', $any($event.target).value)\"\r\n >\r\n <option value=\"\">Ordine di dichiarazione</option>\r\n @for (field of enumChoiceSetFields(); track field.value) {\r\n <option [value]=\"field.value\">{{ field.label }}</option>\r\n }\r\n </select>\r\n @if (unknownEnumChoiceSetField('sortField')) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ string('sortField') }}\u00BB non e\u2019 una proprieta\u2019 di un valore di enum\r\n (FIELD_UNKNOWN).\r\n </p>\r\n }\r\n } @else {\r\n <fb-field-picker\r\n [value]=\"string('sortField') || undefined\"\r\n [object]=\"string('object') || undefined\"\r\n usage=\"sortable\"\r\n label=\"Campo di ordinamento\"\r\n placeholder=\"Nessun ordinamento\"\r\n (valueChange)=\"setField('sortField', $event ?? '')\"\r\n />\r\n }\r\n </div>\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]=\"string('sortOrder')\"\r\n (change)=\"setField('sortOrder', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\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 </div>\r\n }\r\n\r\n <!-- `limit` e' l'unico dei quattro che vale su tutt'e tre le sorgenti (\u00A75.2). -->\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Numero massimo</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"string('limit')\"\r\n (input)=\"setNumberField('limit', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n @if (!isChoiceSetSource('collection')) {\r\n <!--\r\n `supportsLogic` a true: dalla revisione del contratto `filterLogic` **esiste** anche qui, con\r\n le stesse forme e gli stessi rilievi degli elementi che interrogano il database (\u00A74.4).\r\n Nessun `emptyWarning`: senza filtri il set legge tutti i record dell\u2019oggetto, che qui e\u2019 un\r\n uso legittimo. Su un enum i filtri li valuta il runtime **in memoria**, e i campi sono le tre\r\n proprieta\u2019 di un valore: `fieldOptions` e\u2019 cio\u2019 che sostituisce il catalogo (\u00A75.2).\r\n -->\r\n <fb-record-filter-editor\r\n [holder]=\"$any(resource())\"\r\n [object]=\"isChoiceSetSource('enum') ? undefined : string('object') || undefined\"\r\n [fieldOptions]=\"isChoiceSetSource('enum') ? enumChoiceSetFields() : []\"\r\n [title]=\"\r\n isChoiceSetSource('enum') ? 'Quali valori diventano opzioni' : 'Quali record diventano opzioni'\r\n \"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"true\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n />\r\n } @else if (ignoredChoiceSetFilters(); as ignored) {\r\n <!--\r\n Il documento dichiara cio' che su una collection il runtime ignora. E\u2019 un **avviso**, e la\r\n ripulitura e\u2019 un comando: cancellare da se\u2019 i filtri di un flow scritto altrove sarebbe una\r\n modifica che nessuno ha chiesto, e farebbe sparire l\u2019unico indizio di cosa quel flow\r\n voleva selezionare. E\u2019 la stessa scelta dei membri di un riquadro (\u00A73.6).\r\n -->\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Su una collection {{ ignored }}: le opzioni sono gli elementi della collection nell\u2019ordine in\r\n cui ci sono (CHOICE_SET_FILTERS_IGNORED).\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"clearIgnoredChoiceSetFilters()\">\r\n Togli\r\n </button>\r\n </p>\r\n }\r\n}\r\n\r\n@if (isStructure() && collection() === 'variables') {\r\n <p class=\"fb-field__hint\">\r\n Non serve un valore iniziale: la variabile parte con un\u2019istanza vuota, e il flow ne assegna i\r\n membri uno alla volta con un Assignment.\r\n </p>\r\n}\r\n\r\n@if (\r\n supportsInitialValue() &&\r\n (collection() === 'variables' || collection() === 'constants' || collection() === 'choices')\r\n) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">\r\n {{ collection() === 'variables' ? 'Valore iniziale' : 'Valore' }}\r\n </label>\r\n <fb-value-editor\r\n [value]=\"value()\"\r\n [dataType]=\"$any(resource()['dataType'])\"\r\n [objectType]=\"$any(resource()['objectType'])\"\r\n [isCollection]=\"boolean('isCollection')\"\r\n [allowFormula]=\"collection() !== 'constants'\"\r\n label=\"Valore\"\r\n (valueChange)=\"setValue($event)\"\r\n />\r\n </div>\r\n}\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Descrizione</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"string('description')\"\r\n (input)=\"setField('description', $any($event.target).value)\"\r\n />\r\n</div>\r\n", dependencies: [{ kind: "component", type: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: FormulaEditorComponent, selector: "fb-formula-editor", inputs: ["expression", "usage", "expectedDataType", "scale", "placeholder", "ariaLabel", "disabled", "rows", "commitOn"], outputs: ["expressionChange"] }, { kind: "component", type: ObjectPickerComponent, selector: "fb-object-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences"], outputs: ["valueChange"] }, { kind: "component", type: RecordFilterEditorComponent, selector: "fb-record-filter-editor", inputs: ["holder", "object", "title", "usage", "fieldOptions", "supportsLogic", "supportsFormula", "emptyWarning", "emptyWarningSeverity"], outputs: ["changed"] }, { kind: "component", type: StructurePickerComponent, selector: "fb-structure-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
16492
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: ResourceFormComponent, isStandalone: true, selector: "fb-resource-form", inputs: { reference: { classPropertyName: "reference", publicName: "reference", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<!--\r\n Il form di **una** risorsa: e' cio' che prima stava inline sotto la riga dell'elenco, e ora\r\n vive nella dialog. I rilievi locali stanno in cima e non accanto al campo che li produce\r\n perche' qui il form si apre gi\u00E0 puntato sulla risorsa: la domanda \u00ABcosa non va\u00BB viene prima\r\n di \u00ABdove\u00BB.\r\n-->\r\n@if (nameError(); as message) {\r\n <p class=\"fb-field__error\">{{ message }}</p>\r\n}\r\n@if (constantReferencesResource()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Una costante deve essere un valore fisso: non puo\u2019 referenziare altre risorse\r\n (CONSTANT_REFERENCES_RESOURCE).\r\n </p>\r\n}\r\n@if (duplicateStageOrder()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Due stage con lo stesso ordine: quale sia il corrente all\u2019avvio diventa arbitrario\r\n (STAGE_ORDER_DUPLICATED).\r\n </p>\r\n}\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Nome</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"reference().name\"\r\n (change)=\"rename($any($event.target).value)\"\r\n />\r\n <!--\r\n Le tre categorie non si comportano allo stesso modo davanti a una rinomina, e questo e' il\r\n punto in cui il gesto avviene: i riferimenti e i merge field li riscrive l\u2019editor, le\r\n espressioni delle formule no \u2014 la loro sintassi e\u2019 del motore. Dirlo altrove vorrebbe dire\r\n dirlo a chi non sta rinominando.\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Il nome vive nello stesso spazio dei nomi degli elementi. Rinominare riscrive i riferimenti e i\r\n merge field <code>{!\u2026}</code> nei testi.\r\n </p>\r\n @if (formulaUseCount()) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Attenzione: {{ formulaUseCount() }}\r\n {{ formulaUseCount() === 1 ? 'occorrenza sta' : 'occorrenze stanno' }} dentro\r\n {{ formulaUseCount() === 1 ? 'una formula' : 'delle formule' }} e\r\n <strong>non {{ formulaUseCount() === 1 ? 'viene' : 'vengono' }} riscritt{{ formulaUseCount() === 1 ? 'a' : 'e' }}</strong>:\r\n la sintassi e\u2019 del motore di regole, quindi\r\n {{ formulaUseCount() === 1 ? 'va corretta' : 'vanno corrette' }} a mano.\r\n </p>\r\n }\r\n</div>\r\n\r\n@if (collection() === 'stages') {\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]=\"string('label')\"\r\n (input)=\"setField('label', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Ordine</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"string('stageOrder')\"\r\n (input)=\"setNumberField('stageOrder', $any($event.target).value)\"\r\n />\r\n </div>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"boolean('isActive')\"\r\n (change)=\"setBooleanField('isActive', $any($event.target).checked)\"\r\n />\r\n Attivo all\u2019avvio\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n All\u2019avvio lo stage corrente e\u2019 il primo attivo per ordine. Si avanza con un Assignment su\r\n <code>$Flow.CurrentStage</code>.\r\n </p>\r\n}\r\n\r\n@if (collection() === 'textTemplates') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Testo</label>\r\n <textarea\r\n class=\"fb-textarea\"\r\n [value]=\"string('text')\"\r\n placeholder=\"Gentile {!Cliente.Nome},\"\r\n (input)=\"setField('text', $any($event.target).value)\"\r\n ></textarea>\r\n </div>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"boolean('isViewedAsPlainText')\"\r\n (change)=\"setBooleanField('isViewedAsPlainText', $any($event.target).checked)\"\r\n />\r\n Testo semplice\r\n </label>\r\n}\r\n\r\n@if (collection() !== 'textTemplates' && collection() !== 'stages') {\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]=\"string('dataType')\"\r\n (change)=\"setDataType($any($event.target).value)\"\r\n >\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 (collection() === 'dynamicChoiceSets') {\r\n <!--\r\n \u00A75.2 \u2014 il valore di un'opzione **generata** non lo scrive l'autore del flow: lo produce\r\n la sorgente, nel tipo in cui il sistema ospite lo tiene, e `dataType` decide il tipo in\r\n cui viaggia. La regola e' generale \u2014 vale per tutte e tre le sorgenti \u2014 e si vede su un\r\n oggetto la cui chiave e' un enum, dove nella tendina serve di norma il numero.\r\n -->\r\n <p class=\"fb-field__hint\">\r\n Decide il tipo in cui viaggia il valore dell\u2019opzione, con qualunque sorgente:\r\n <code>String</code> il nome come testo, <code>Integer</code> o <code>Number</code> il\r\n numero sottostante, <code>Enum</code> il valore tipizzato \u2014 che e\u2019 cio\u2019 che serve in un\r\n parametro o in un membro di classe <code>Enum</code>. Una conversione impossibile non fa\r\n fallire niente: resta il valore prodotto dalla sorgente.\r\n </p>\r\n }\r\n </div>\r\n\r\n @if (requiresObjectType() && !hidesObjectType()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">\r\n @if (isEnum()) {\r\n Tipo di enumerazione\r\n } @else if (isStructure()) {\r\n Classe\r\n } @else {\r\n Oggetto\r\n }\r\n </label>\r\n @if (isEnum()) {\r\n <!-- Dizionario chiuso: qui la scrittura libera non serve. -->\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"string('objectType')\"\r\n (change)=\"setField('objectType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of enumOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n </select>\r\n } @else if (isStructure()) {\r\n <!-- \u00A74.7: una classe del backend, non un'entita' del modello dati. -->\r\n <fb-structure-picker\r\n [value]=\"string('objectType') || undefined\"\r\n label=\"Classe\"\r\n (valueChange)=\"setField('objectType', $event ?? '')\"\r\n />\r\n } @else {\r\n <fb-object-picker\r\n [value]=\"string('objectType') || undefined\"\r\n label=\"Oggetto\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setField('objectType', $event ?? '')\"\r\n />\r\n }\r\n @if (missingObjectType()) {\r\n <!-- Su una Structure non e' un avviso: senza classe non c'e' nulla da istanziare. -->\r\n <p class=\"fb-field__error\">\r\n La classe e\u2019 obbligatoria: senza, l\u2019attivazione e\u2019 bloccata (OBJECT_TYPE_MISSING).\r\n </p>\r\n } @else if (isStructure()) {\r\n <p class=\"fb-field__hint\">\r\n Il flow ne legge e scrive i <strong>membri</strong> (<code>Nome.Membro</code>): non si\r\n interroga con Get Records ne\u2019 si salva con Create/Update.\r\n </p>\r\n } @else {\r\n <p class=\"fb-field__hint\">Obbligatorio per Object ed Enum (OBJECT_TYPE_MISSING).</p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (supportsScale()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Decimali</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"0\"\r\n [value]=\"string('scale')\"\r\n (input)=\"setNumberField('scale', $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n}\r\n\r\n@if (collection() === 'variables') {\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"boolean('isCollection')\"\r\n (change)=\"setBooleanField('isCollection', $any($event.target).checked)\"\r\n />\r\n \u00C8 una collection\r\n </label>\r\n <p class=\"fb-field__hint\">Solo una collection puo\u2019 essere iterata da un Loop.</p>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"boolean('isInput')\"\r\n (change)=\"setBooleanField('isInput', $any($event.target).checked)\"\r\n />\r\n Valorizzabile all\u2019avvio (input)\r\n </label>\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"boolean('isOutput')\"\r\n (change)=\"setBooleanField('isOutput', $any($event.target).checked)\"\r\n />\r\n Leggibile alla fine (output)\r\n </label>\r\n <p class=\"fb-field__hint\">\r\n Input e output sono il contratto del flow verso chi lo invoca, subflow compresi.\r\n </p>\r\n}\r\n\r\n@if (collection() === 'formulas') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Espressione</label>\r\n <!--\r\n Il tipo atteso e' quello che la risorsa dichiara, e `scale` va con lui: sono cio'\r\n che permette al motore di dire che l'espressione produce altro (\u00A76.3).\r\n -->\r\n <fb-formula-editor\r\n [expression]=\"string('expression')\"\r\n usage=\"Resource\"\r\n [expectedDataType]=\"$any(resource()['dataType'])\"\r\n [scale]=\"$any(resource()['scale'])\"\r\n placeholder=\"Importo * 1.22\"\r\n ariaLabel=\"Espressione della formula\"\r\n (expressionChange)=\"setField('expression', $event)\"\r\n >\r\n <p class=\"fb-field__hint\">\r\n Passata verbatim al motore di regole: la sintassi delle funzioni e\u2019 del motore.\r\n </p>\r\n </fb-formula-editor>\r\n </div>\r\n}\r\n\r\n@if (collection() === 'choices') {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Testo mostrato</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"string('choiceText')\"\r\n (input)=\"setField('choiceText', $any($event.target).value)\"\r\n />\r\n </div>\r\n}\r\n\r\n@if (collection() === 'dynamicChoiceSets') {\r\n <!--\r\n \u00A75.2 \u2014 le sorgenti sono tre e si escludono a vicenda: i pulsanti le rendono\r\n mutuamente esclusive nel documento, non solo nel form.\r\n -->\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Da dove arrivano le opzioni</label>\r\n <div class=\"fb-filter__modes\" role=\"group\" aria-label=\"Sorgente delle opzioni\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"isChoiceSetSource('collection')\"\r\n (click)=\"setChoiceSetSource('collection')\"\r\n >\r\n Collection del flow\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"isChoiceSetSource('object')\"\r\n (click)=\"setChoiceSetSource('object')\"\r\n >\r\n Query su un oggetto\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"fb-filter__mode\"\r\n [class.fb-filter__mode--active]=\"isChoiceSetSource('enum')\"\r\n (click)=\"setChoiceSetSource('enum')\"\r\n >\r\n Valori di un enum\r\n </button>\r\n </div>\r\n </div>\r\n\r\n @if (ambiguousChoiceSetSource()) {\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Questo choice set dichiara piu\u2019 di una sorgente: il runtime ne usa una sola\r\n (CHOICE_SET_SOURCE_AMBIGUOUS). Scegli quella giusta qui sopra: le altre vengono tolte.\r\n </p>\r\n }\r\n\r\n @if (isChoiceSetSource('collection')) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Collection</label>\r\n <fb-reference-picker\r\n [value]=\"string('collectionReference')\"\r\n [isCollection]=\"true\"\r\n placeholder=\"Scegli una collection\"\r\n (valueChange)=\"setField('collectionReference', $event ?? '')\"\r\n />\r\n <p class=\"fb-field__hint\">\r\n Tipicamente il risultato di un Get Records: le opzioni sono i record che il flow ha gi\u00E0\r\n letto, <strong>nell\u2019ordine in cui ci sono</strong>. Filtri e ordinamento non si applicano\r\n qui: per sceglierne una parte, filtra la collection con un elemento Filter prima dello\r\n screen.\r\n </p>\r\n </div>\r\n }\r\n\r\n @if (isChoiceSetSource('object')) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Oggetto</label>\r\n <fb-object-picker\r\n [value]=\"string('object') || undefined\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setField('object', $event ?? '')\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (isChoiceSetSource('enum')) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo di enumerazione</label>\r\n <!-- Dizionario chiuso, e qui e' anche **autorevole**: un tipo fuori elenco e' un errore. -->\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"string('enumType')\"\r\n (change)=\"setField('enumType', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (entry of enumOptions(); track entry.name) {\r\n <option [value]=\"entry.name\">{{ entry.label || entry.name }}</option>\r\n }\r\n </select>\r\n @if (unknownEnumType()) {\r\n <p class=\"fb-field__error\">\r\n Il tipo \u00AB{{ string('enumType') }}\u00BB non e\u2019 fra quelli utilizzabili\r\n (ENUM_TYPE_UNKNOWN).\r\n </p>\r\n } @else {\r\n <p class=\"fb-field__hint\">\r\n Le opzioni sono i valori dichiarati dal tipo: nessuna choice da tenere allineata a mano.\r\n </p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (isChoiceSetSource('enum')) {\r\n <!--\r\n \u00A75.2 \u2014 qui i campi citabili sono le tre proprieta' di un valore di enum, non i campi\r\n di un'entita': l'elenco viene dal dizionario, e i default rendono superfluo dichiararli.\r\n -->\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo mostrato</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"string('displayField')\"\r\n (change)=\"setField('displayField', $any($event.target).value)\"\r\n >\r\n <option value=\"\">Predefinito ({{ defaultDisplayField }})</option>\r\n @for (field of enumChoiceSetFields(); track field.value) {\r\n <option [value]=\"field.value\">{{ field.label }}</option>\r\n }\r\n </select>\r\n @if (unknownEnumChoiceSetField('displayField')) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ string('displayField') }}\u00BB non e\u2019 una proprieta\u2019 di un valore di enum\r\n (FIELD_UNKNOWN).\r\n </p>\r\n }\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo del valore</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"string('valueField')\"\r\n (change)=\"setField('valueField', $any($event.target).value)\"\r\n >\r\n <option value=\"\">Predefinito ({{ defaultValueField }})</option>\r\n @for (field of enumChoiceSetFields(); track field.value) {\r\n <option [value]=\"field.value\">{{ field.label }}</option>\r\n }\r\n </select>\r\n @if (unknownEnumChoiceSetField('valueField')) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ string('valueField') }}\u00BB non e\u2019 una proprieta\u2019 di un valore di enum\r\n (FIELD_UNKNOWN).\r\n </p>\r\n }\r\n </div>\r\n </div>\r\n <p class=\"fb-field__hint\">\r\n Dichiarare <code>Integer</code> come tipo della risorsa e\u2019 la stessa cosa che scegliere qui\r\n \u00ABValore numerico\u00BB: il valore dell\u2019opzione e\u2019 il numero sottostante.\r\n </p>\r\n } @else {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo mostrato</label>\r\n <fb-field-picker\r\n [value]=\"string('displayField') || undefined\"\r\n [object]=\"string('object') || undefined\"\r\n usage=\"any\"\r\n label=\"Campo mostrato\"\r\n (valueChange)=\"setField('displayField', $event ?? '')\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo del valore</label>\r\n <fb-field-picker\r\n [value]=\"string('valueField') || undefined\"\r\n [object]=\"string('object') || undefined\"\r\n usage=\"any\"\r\n label=\"Campo del valore\"\r\n (valueChange)=\"setField('valueField', $event ?? '')\"\r\n />\r\n </div>\r\n }\r\n <!--\r\n \u00A75.2 \u2014 `filters`, `filterLogic`, `sortField` e `sortOrder` valgono sulle **sole** sorgenti\r\n `object` (dove diventano la query) ed `enumType` (valutati in memoria). Su una collection le\r\n opzioni sono i suoi elementi nell\u2019ordine in cui ci sono: mostrare i controlli l\u00EC\r\n inviterebbe a dichiarare cio\u2019 che il runtime ignora, ed e\u2019 `CHOICE_SET_FILTERS_IGNORED`.\r\n -->\r\n @if (!isChoiceSetSource('collection')) {\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Ordina per</label>\r\n @if (isChoiceSetSource('enum')) {\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"string('sortField')\"\r\n (change)=\"setField('sortField', $any($event.target).value)\"\r\n >\r\n <option value=\"\">Ordine di dichiarazione</option>\r\n @for (field of enumChoiceSetFields(); track field.value) {\r\n <option [value]=\"field.value\">{{ field.label }}</option>\r\n }\r\n </select>\r\n @if (unknownEnumChoiceSetField('sortField')) {\r\n <p class=\"fb-field__error\">\r\n \u00AB{{ string('sortField') }}\u00BB non e\u2019 una proprieta\u2019 di un valore di enum\r\n (FIELD_UNKNOWN).\r\n </p>\r\n }\r\n } @else {\r\n <fb-field-picker\r\n [value]=\"string('sortField') || undefined\"\r\n [object]=\"string('object') || undefined\"\r\n usage=\"sortable\"\r\n label=\"Campo di ordinamento\"\r\n placeholder=\"Nessun ordinamento\"\r\n (valueChange)=\"setField('sortField', $event ?? '')\"\r\n />\r\n }\r\n </div>\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]=\"string('sortOrder')\"\r\n (change)=\"setField('sortOrder', $any($event.target).value)\"\r\n >\r\n <option value=\"\">\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 </div>\r\n }\r\n\r\n <!-- `limit` e' l'unico dei quattro che vale su tutt'e tre le sorgenti (\u00A75.2). -->\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Numero massimo</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"string('limit')\"\r\n (input)=\"setNumberField('limit', $any($event.target).value)\"\r\n />\r\n </div>\r\n\r\n @if (!isChoiceSetSource('collection')) {\r\n <!--\r\n `supportsLogic` a true: dalla revisione del contratto `filterLogic` **esiste** anche qui, con\r\n le stesse forme e gli stessi rilievi degli elementi che interrogano il database (\u00A74.4).\r\n Nessun `emptyWarning`: senza filtri il set legge tutti i record dell\u2019oggetto, che qui e\u2019 un\r\n uso legittimo. Su un enum i filtri li valuta il runtime **in memoria**, e i campi sono le tre\r\n proprieta\u2019 di un valore: `fieldOptions` e\u2019 cio\u2019 che sostituisce il catalogo (\u00A75.2).\r\n -->\r\n <fb-record-filter-editor\r\n [holder]=\"$any(resource())\"\r\n [object]=\"isChoiceSetSource('enum') ? undefined : string('object') || undefined\"\r\n [fieldOptions]=\"isChoiceSetSource('enum') ? enumChoiceSetFields() : []\"\r\n [title]=\"\r\n isChoiceSetSource('enum') ? 'Quali valori diventano opzioni' : 'Quali record diventano opzioni'\r\n \"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"true\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n />\r\n } @else if (ignoredChoiceSetFilters(); as ignored) {\r\n <!--\r\n Il documento dichiara cio' che su una collection il runtime ignora. E\u2019 un **avviso**, e la\r\n ripulitura e\u2019 un comando: cancellare da se\u2019 i filtri di un flow scritto altrove sarebbe una\r\n modifica che nessuno ha chiesto, e farebbe sparire l\u2019unico indizio di cosa quel flow\r\n voleva selezionare. E\u2019 la stessa scelta dei membri di un riquadro (\u00A73.6).\r\n -->\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Su una collection {{ ignored }}: le opzioni sono gli elementi della collection nell\u2019ordine in\r\n cui ci sono (CHOICE_SET_FILTERS_IGNORED).\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost fb-btn--icon\" (click)=\"clearIgnoredChoiceSetFilters()\">\r\n Togli\r\n </button>\r\n </p>\r\n }\r\n}\r\n\r\n@if (isStructure() && collection() === 'variables') {\r\n <p class=\"fb-field__hint\">\r\n Non serve un valore iniziale: la variabile parte con un\u2019istanza vuota, e il flow ne assegna i\r\n membri uno alla volta con un Assignment.\r\n </p>\r\n}\r\n\r\n@if (\r\n supportsInitialValue() &&\r\n (collection() === 'variables' || collection() === 'constants' || collection() === 'choices')\r\n) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">\r\n {{ collection() === 'variables' ? 'Valore iniziale' : 'Valore' }}\r\n </label>\r\n <fb-value-editor\r\n [value]=\"value()\"\r\n [dataType]=\"$any(resource()['dataType'])\"\r\n [objectType]=\"$any(resource()['objectType'])\"\r\n [isCollection]=\"boolean('isCollection')\"\r\n [allowFormula]=\"collection() !== 'constants'\"\r\n label=\"Valore\"\r\n (valueChange)=\"setValue($event)\"\r\n />\r\n </div>\r\n}\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Descrizione</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"string('description')\"\r\n (input)=\"setField('description', $any($event.target).value)\"\r\n />\r\n</div>\r\n", dependencies: [{ kind: "component", type: FieldPickerComponent, selector: "fb-field-picker", inputs: ["value", "object", "usage", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: FormulaEditorComponent, selector: "fb-formula-editor", inputs: ["expression", "usage", "expectedDataType", "scale", "placeholder", "ariaLabel", "disabled", "rows", "preferredRoots", "commitOn"], outputs: ["expressionChange"] }, { kind: "component", type: ObjectPickerComponent, selector: "fb-object-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ReferencePickerComponent, selector: "fb-reference-picker", inputs: ["value", "label", "placeholder", "disabled", "dataType", "isCollection", "objectType", "writableOnly", "elementsOnly", "extraReferences", "preferredRoots"], outputs: ["valueChange"] }, { kind: "component", type: RecordFilterEditorComponent, selector: "fb-record-filter-editor", inputs: ["holder", "object", "title", "usage", "fieldOptions", "supportsLogic", "supportsFormula", "emptyWarning", "emptyWarningSeverity"], outputs: ["changed"] }, { kind: "component", type: StructurePickerComponent, selector: "fb-structure-picker", inputs: ["value", "label", "placeholder", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: ValueEditorComponent, selector: "fb-value-editor", inputs: ["value", "label", "dataType", "objectType", "isCollection", "valueSet", "disabled", "allowFormula", "preferredRoots"], outputs: ["valueChange"] }, { kind: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
16171
16493
|
}
|
|
16172
16494
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: ResourceFormComponent, decorators: [{
|
|
16173
16495
|
type: Component,
|
|
@@ -18792,5 +19114,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
18792
19114
|
* Generated bundle index. Do not edit.
|
|
18793
19115
|
*/
|
|
18794
19116
|
|
|
18795
|
-
export { ConditionEditorComponent, ConnectorEditorComponent, DebugPanelComponent, DynamicScreenInspectorComponent, ENUM_CHOICE_SET_DEFAULT_DISPLAY_FIELD, ENUM_CHOICE_SET_DEFAULT_VALUE_FIELD, ENUM_CHOICE_SET_FIELDS, ElementDialogComponent, ElementInspectorComponent, ElementPaletteComponent, EnumValuePickerComponent, FALLBACK_COLLECTION_BY_TYPE, FALLBACK_TYPE_LABEL, FLOW_BUILDER_HTTP_CONFIG, FLOW_CLIPBOARD_KIND, FLOW_CLIPBOARD_VERSION, FLOW_ELEMENT_ICONS, FLOW_ELEMENT_VARIANT_FIELDS, FLOW_ELEMENT_VARIANT_ICONS, FLOW_ERROR_FALLBACK_MESSAGE, FLOW_ERROR_HTTP_STATUS, FLOW_FOLD_HEIGHT, FLOW_FOLD_WIDTH, FLOW_GROUP_COLORS, FLOW_NAME_PATTERN, FLOW_NODE_COLLECTIONS, FLOW_NODE_HEIGHT, FLOW_NODE_WIDTH, FLOW_REFERENCE_FIELDS, FLOW_RESOURCE_COLLECTIONS, FLOW_VALUE_FIELDS, FLOW_VALUE_LITERAL_FIELDS, FieldAssignmentEditorComponent, FieldPickerComponent, FieldValuePickerComponent, FlowApiError, FlowBuilderApi, FlowBuilderComponent, FlowCanvasComponent, FlowCatalogStore, FlowClipboardService, FlowDictionaryStore, FlowDocumentStore, FlowEditorSession, FlowLayoutService, FlowValidationStore, FormulaEditorComponent, FormulaValidationService, GROUP_HEADER_HEIGHT, GROUP_MIN_HEIGHT, GROUP_MIN_WIDTH, GROUP_PADDING, GroupPanelComponent, HttpFlowBuilderApi, MergeTextEditorComponent, NamePickerComponent, NodeInspectorBase, ORCHESTRATION_CONDITION_OUTPUT, ObjectPickerComponent, OrchestratedStageInspectorComponent, ParameterEditorComponent, PasteDialogComponent, ProblemsPanelComponent, RecordFilterEditorComponent, ReferencePickerComponent, ResourceDialogComponent, ResourceFormComponent, ResourcePanelComponent, RunDialogComponent, SEVERITY_BUCKETS, SEVERITY_ICON, SEVERITY_LABEL, START_NODE_NAME, SelectValueDirective, StartInspectorComponent, StructureMemberPickerComponent, StructurePickerComponent, TYPES_WITH_AUTOMATIC_OUTPUT, TYPE_BY_COLLECTION, UNSUPPORTED_TYPES, ValueEditorComponent, VersionPanelComponent, allFieldsOf, applyPaste, areTypesComparable, boundsAround, buildClipboardPayload, canvasFoldId, canvasGroupId, canvasNodeId, checkConditionLogic, checkFlowName, choiceSetSourceOf, declaredChoiceSetSources, describeFieldPath, describePathEntry, duplicateField, elementIcon, emptyFlowDefinition, enumChoiceSetFieldType, fieldAt, filterReferences, flattenFields, flowNodeWidth, flowNodeWidthClass, foldSourceConnectorId, foldTargetConnectorId, groupColorClass, groupRect, hasAutoSize, innerNamesOf, insertField, isClipboardPayload, isCustomConditionLogic, isEmptyReferenceFilter, isFieldResource, isFoldReference, isGlobalReference, isNumericType, isPathInside, isTypeCheckedOperator, isUnknownEnumChoiceSetField, isValidFlowName, isValued, loadPathLevel, matchesReferenceFilter, membersInside, moveCondition, moveField, navigatePath, otherSourceFieldsOf, outletByKey, outletsOf, parseCanvasFoldId, parseCanvasGroupId, parseCanvasNodeId, parseFieldPath, parseInvariantNumber, parseSourceConnectorId, parseTargetConnectorId, pathAvailableNames, pathContainerLabel, pathKey, pathNotVerifiableMessage, planPaste, recomputeMembers, referenceRoot, referencedRootsOf, remapConditionLogic, removeCondition, removeField, resolvePath, rewriteReferences, sameMembers, samePath, screenActionNames, screenFieldNames, severityBucket, slugifyFlowName, sourceConnectorId, stageStepNames, stageStepOutputReferenced, stepsOf, targetConnectorId, typeOfCollection, uniqueFlowName, valuedFieldOf, valuedFieldsOf, variantFieldOf, variantOf, variantPresetOf };
|
|
19117
|
+
export { ConditionEditorComponent, ConnectorEditorComponent, DebugPanelComponent, DynamicScreenInspectorComponent, ENUM_CHOICE_SET_DEFAULT_DISPLAY_FIELD, ENUM_CHOICE_SET_DEFAULT_VALUE_FIELD, ENUM_CHOICE_SET_FIELDS, ElementDialogComponent, ElementInspectorComponent, ElementPaletteComponent, EnumValuePickerComponent, FALLBACK_COLLECTION_BY_TYPE, FALLBACK_TYPE_LABEL, FLOW_BUILDER_HTTP_CONFIG, FLOW_CLIPBOARD_KIND, FLOW_CLIPBOARD_VERSION, FLOW_ELEMENT_ICONS, FLOW_ELEMENT_VARIANT_FIELDS, FLOW_ELEMENT_VARIANT_ICONS, FLOW_ERROR_FALLBACK_MESSAGE, FLOW_ERROR_HTTP_STATUS, FLOW_FOLD_HEIGHT, FLOW_FOLD_WIDTH, FLOW_GROUP_COLORS, FLOW_NAME_PATTERN, FLOW_NODE_COLLECTIONS, FLOW_NODE_HEIGHT, FLOW_NODE_WIDTH, FLOW_REFERENCE_FIELDS, FLOW_RESOURCE_COLLECTIONS, FLOW_VALUE_FIELDS, FLOW_VALUE_LITERAL_FIELDS, FieldAssignmentEditorComponent, FieldPickerComponent, FieldValuePickerComponent, FlowApiError, FlowBuilderApi, FlowBuilderComponent, FlowCanvasComponent, FlowCatalogStore, FlowClipboardService, FlowDictionaryStore, FlowDocumentStore, FlowEditorSession, FlowLayoutService, FlowValidationStore, FormulaEditorComponent, FormulaValidationService, GROUP_HEADER_HEIGHT, GROUP_MIN_HEIGHT, GROUP_MIN_WIDTH, GROUP_PADDING, GroupPanelComponent, HttpFlowBuilderApi, MergeTextEditorComponent, NamePickerComponent, NodeInspectorBase, ORCHESTRATION_CONDITION_OUTPUT, ObjectPickerComponent, OrchestratedStageInspectorComponent, ParameterEditorComponent, PasteDialogComponent, ProblemsPanelComponent, RecordFilterEditorComponent, ReferencePickerComponent, ResourceDialogComponent, ResourceFormComponent, ResourcePanelComponent, RunDialogComponent, SEVERITY_BUCKETS, SEVERITY_ICON, SEVERITY_LABEL, START_NODE_NAME, SelectValueDirective, StartInspectorComponent, StructureMemberPickerComponent, StructurePickerComponent, TYPES_WITH_AUTOMATIC_OUTPUT, TYPE_BY_COLLECTION, UNSUPPORTED_TYPES, ValueEditorComponent, VersionPanelComponent, allFieldsOf, applyPaste, areTypesComparable, boundsAround, buildClipboardPayload, canvasFoldId, canvasGroupId, canvasNodeId, checkConditionLogic, checkFlowName, choiceSetSourceOf, declaredChoiceSetSources, describeFieldPath, describePathEntry, duplicateField, elementIcon, emptyFlowDefinition, enumChoiceSetFieldType, fieldAt, filterReferences, flattenFields, flowNodeWidth, flowNodeWidthClass, foldSourceConnectorId, foldTargetConnectorId, groupColorClass, groupRect, hasAutoSize, innerNamesOf, insertField, isClipboardPayload, isCustomConditionLogic, isEmptyReferenceFilter, isFieldResource, isFoldReference, isGlobalReference, isNumericType, isPathInside, isTypeCheckedOperator, isUnknownEnumChoiceSetField, isValidFlowName, isValued, loadPathLevel, matchesReferenceFilter, membersInside, moveCondition, moveField, navigatePath, otherSourceFieldsOf, outletByKey, outletsOf, parseCanvasFoldId, parseCanvasGroupId, parseCanvasNodeId, parseFieldPath, parseInvariantNumber, parseSourceConnectorId, parseTargetConnectorId, pathAvailableNames, pathContainerLabel, pathKey, pathNotVerifiableMessage, planPaste, recomputeMembers, referenceRoot, referencedRootsOf, remapConditionLogic, removeCondition, removeField, repeatedFieldNames, repeatingSectionOf, resolvePath, resourceFieldsOf, rewriteReferences, sameMembers, samePath, screenActionNames, screenFieldNames, severityBucket, slugifyFlowName, sourceConnectorId, stageStepNames, stageStepOutputReferenced, stepsOf, targetConnectorId, typeOfCollection, uniqueFlowName, valuedFieldOf, valuedFieldsOf, variantFieldOf, variantOf, variantPresetOf };
|
|
18796
19118
|
//# sourceMappingURL=esfaenza-flow-builder.mjs.map
|