@esfaenza/flow-builder 20.3.52 → 20.3.54
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 +62 -3
- package/fesm2022/esfaenza-flow-builder.mjs +443 -21
- package/fesm2022/esfaenza-flow-builder.mjs.map +1 -1
- package/index.d.ts +306 -17
- package/package.json +1 -1
|
@@ -965,6 +965,143 @@ function variantPresetOf(type, variant) {
|
|
|
965
965
|
return { [field]: variant };
|
|
966
966
|
}
|
|
967
967
|
|
|
968
|
+
/**
|
|
969
|
+
* Il trigger su record, e i **valori precedenti** — FRONTEND.md §3.4, §4.1, §7.
|
|
970
|
+
*
|
|
971
|
+
* Due domande che sembrano una sola e non lo sono. La prima: questo flow parte da un record? La
|
|
972
|
+
* seconda: i **valori di prima** del record ci sono? Non discende dal momento (`triggerType`) ma
|
|
973
|
+
* dall'**operazione** (`recordTriggerType`), ed e' l'unica cosa che decide quanto costa scrivere un
|
|
974
|
+
* `IsChanged` o un `$Record__Prior` — perche' ci sono **sempre** (aggiornamento), **a volte**
|
|
975
|
+
* (creazione e aggiornamento: sulla creazione no) o **mai** (creazione, eliminazione).
|
|
976
|
+
*
|
|
977
|
+
* Da lì le tre gravita' di `PRIOR_VALUES_NOT_AVAILABLE`, che la §7 dichiara e che quindi non si
|
|
978
|
+
* indovinano: dove i valori non ci sono mai l'interview **fallisce** davanti a chi stava salvando —
|
|
979
|
+
* errore; dove ci sono a volte il flow funziona a meta' — avviso; dove ci sono sempre non c'e'
|
|
980
|
+
* niente da dire. La regola sta qui, in un posto solo, e la applicano tutti e due i capi: l'editor,
|
|
981
|
+
* che lo dice mentre si scrive la condizione, e il validatore, che emette il rilievo. Due copie
|
|
982
|
+
* divergono, e la si scopre quando l'editor tace su cio' che il backend rifiuta.
|
|
983
|
+
*
|
|
984
|
+
* L'eccezione e' `doesRequireRecordChangedToMeetCriteria`: il runtime lo **ignora** invece di
|
|
985
|
+
* fallire, quindi non e' mai un errore, e sull'operazione «a volte» non e' nemmeno un rilievo —
|
|
986
|
+
* ignorarlo sulla creazione e' il comportamento giusto, non un difetto.
|
|
987
|
+
*
|
|
988
|
+
* Restano fuori le **formule**: un'espressione che cita `$Record__Prior` non e' analizzabile qui,
|
|
989
|
+
* perche' la sintassi la conosce solo il motore (§6.3).
|
|
990
|
+
*/
|
|
991
|
+
/**
|
|
992
|
+
* I trigger che lavorano su un record, cioe' quelli che rendono disponibile `$Record` (§4.1).
|
|
993
|
+
* Il contratto li nomina uno per uno (§3.4): non e' un dizionario da leggere, e' la tabella dei sei
|
|
994
|
+
* tipi di flow.
|
|
995
|
+
*/
|
|
996
|
+
const RECORD_TRIGGERS = new Set([
|
|
997
|
+
'RecordBeforeSave',
|
|
998
|
+
'RecordAfterSave',
|
|
999
|
+
'RecordBeforeDelete',
|
|
1000
|
+
]);
|
|
1001
|
+
/** L'operatore che legge i valori precedenti. Lo nomina la §7: non c'e' un flag di dizionario. */
|
|
1002
|
+
const PRIOR_VALUES_OPERATOR = 'IsChanged';
|
|
1003
|
+
/** Lo scope che **e'** i valori precedenti (§4.1). */
|
|
1004
|
+
const PRIOR_VALUES_SCOPE = '$Record__Prior';
|
|
1005
|
+
function isRecordTrigger(triggerType) {
|
|
1006
|
+
return RECORD_TRIGGERS.has(triggerType ?? '');
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* §3.4, §7 — la domanda si pone all'**operazione**, non al momento, e le quattro operazioni le
|
|
1010
|
+
* nomina il contratto. Dove l'operazione manca la risposta la da' il trigger, com'e' scritto nella
|
|
1011
|
+
* §3.4: su un trigger di salvataggio l'assenza vale `CreateAndUpdate`, e con `RecordBeforeDelete`
|
|
1012
|
+
* l'operazione la dice il trigger — cioe' un'eliminazione, che un «prima» non ce l'ha.
|
|
1013
|
+
*/
|
|
1014
|
+
function priorValuesAvailability(triggerType, operation) {
|
|
1015
|
+
if (!isRecordTrigger(triggerType)) {
|
|
1016
|
+
return 'unknown';
|
|
1017
|
+
}
|
|
1018
|
+
switch (operation) {
|
|
1019
|
+
case 'Update':
|
|
1020
|
+
return 'always';
|
|
1021
|
+
case 'CreateAndUpdate':
|
|
1022
|
+
return 'sometimes';
|
|
1023
|
+
case 'Create':
|
|
1024
|
+
case 'Delete':
|
|
1025
|
+
return 'never';
|
|
1026
|
+
}
|
|
1027
|
+
if (!operation) {
|
|
1028
|
+
return triggerType === 'RecordBeforeDelete' ? 'never' : 'sometimes';
|
|
1029
|
+
}
|
|
1030
|
+
// Un'operazione che il contratto non nomina: non si sa, e non sapere non e' sapere che e'
|
|
1031
|
+
// sbagliato — resta l'avviso, mai l'errore.
|
|
1032
|
+
return 'unknown';
|
|
1033
|
+
}
|
|
1034
|
+
/** La stessa domanda con in mano il documento: la coppia sta in un posto solo, lo Start (§3.4). */
|
|
1035
|
+
function priorValuesOfDefinition(definition) {
|
|
1036
|
+
const start = definition?.start?.[0];
|
|
1037
|
+
return priorValuesAvailability(start?.triggerType, start?.recordTriggerType);
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* §7 — quanto costa **leggere** i valori precedenti: `IsChanged`, o un riferimento radicato su
|
|
1041
|
+
* `$Record__Prior`. Mai ci sono = a runtime l'interview fallisce, quindi errore; a volte = il flow
|
|
1042
|
+
* funziona a meta', quindi avviso.
|
|
1043
|
+
*/
|
|
1044
|
+
function priorValuesSeverity(availability) {
|
|
1045
|
+
switch (availability) {
|
|
1046
|
+
case 'always':
|
|
1047
|
+
return 'none';
|
|
1048
|
+
case 'never':
|
|
1049
|
+
return 'error';
|
|
1050
|
+
default:
|
|
1051
|
+
return 'warning';
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* §7 — l'eccezione: `doesRequireRecordChangedToMeetCriteria` il runtime lo **ignora** invece di
|
|
1056
|
+
* fallire, quindi non e' mai un errore; e su `CreateAndUpdate` non e' nemmeno un rilievo, perche'
|
|
1057
|
+
* ignorarlo sulla creazione e' cio' che deve accadere.
|
|
1058
|
+
*/
|
|
1059
|
+
function priorCriteriaSeverity(availability) {
|
|
1060
|
+
return availability === 'never' ? 'warning' : 'none';
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* §6.3 — se ha senso **proporre** cio' che legge i valori precedenti: una funzione di formula
|
|
1064
|
+
* marcata `requiresPriorValues`, in una palette.
|
|
1065
|
+
*
|
|
1066
|
+
* Non e' {@link priorValuesSeverity} con altro nome, e la differenza sta tutta nel caso «non lo
|
|
1067
|
+
* so»: un flow che non e' innescato da un record lì e' un **avviso** — i valori puo' passarli chi
|
|
1068
|
+
* avvia l'interview, accusarlo sarebbe un falso positivo — mentre qui e' un motivo per non mettere
|
|
1069
|
+
* la voce in elenco, perche' proporre `PRIORVALUE` dove non c'e' nessun record che innesca e'
|
|
1070
|
+
* proporre una funzione che non ha su cosa lavorare. Su «creazione e aggiornamento» si propone: la
|
|
1071
|
+
* meta' aggiornamento la usa.
|
|
1072
|
+
*
|
|
1073
|
+
* Resta una **proposta**: chi la scrive a mano non viene accusato da qui, ma da `validateFormula`.
|
|
1074
|
+
*/
|
|
1075
|
+
function priorValuesProposable(availability) {
|
|
1076
|
+
return availability === 'always' || availability === 'sometimes';
|
|
1077
|
+
}
|
|
1078
|
+
/** `true` se il riferimento e' radicato sui valori precedenti: e' la **radice** che conta (§4.1). */
|
|
1079
|
+
function readsPriorValues(reference) {
|
|
1080
|
+
const trimmed = (reference ?? '').trim();
|
|
1081
|
+
if (!trimmed) {
|
|
1082
|
+
return false;
|
|
1083
|
+
}
|
|
1084
|
+
const dot = trimmed.indexOf('.');
|
|
1085
|
+
const root = dot < 0 ? trimmed : trimmed.slice(0, dot);
|
|
1086
|
+
return root.toLowerCase() === PRIOR_VALUES_SCOPE.toLowerCase();
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Perche' i valori precedenti mancano, in una frase — la stessa da tutte e due le parti, cosi' chi
|
|
1090
|
+
* la legge nell'editor e chi la rilegge nel pannello dei problemi non trova due spiegazioni diverse.
|
|
1091
|
+
*/
|
|
1092
|
+
function describePriorValues(availability) {
|
|
1093
|
+
switch (availability) {
|
|
1094
|
+
case 'never':
|
|
1095
|
+
return 'con questa operazione il record di prima non esiste';
|
|
1096
|
+
case 'sometimes':
|
|
1097
|
+
return 'sulla creazione il record di prima non esiste, e li’ la condizione non e’ valutabile';
|
|
1098
|
+
case 'unknown':
|
|
1099
|
+
return 'questo flow non e’ innescato da un record: i valori precedenti li passa chi avvia l’interview';
|
|
1100
|
+
default:
|
|
1101
|
+
return '';
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
968
1105
|
/**
|
|
969
1106
|
* Nomi — FRONTEND.md §3.3, §13.5.
|
|
970
1107
|
*
|
|
@@ -3885,6 +4022,7 @@ class FlowDictionaryStore {
|
|
|
3885
4022
|
globalVariables = computed(() => this._dictionaries().globalVariables ?? [], ...(ngDevMode ? [{ debugName: "globalVariables" }] : []));
|
|
3886
4023
|
processTypes = computed(() => this._dictionaries().processTypes ?? [], ...(ngDevMode ? [{ debugName: "processTypes" }] : []));
|
|
3887
4024
|
triggerTypes = computed(() => this._dictionaries().triggerTypes ?? [], ...(ngDevMode ? [{ debugName: "triggerTypes" }] : []));
|
|
4025
|
+
/** §3.4 — le quattro operazioni che innescano un flow da un record, coi momenti che ammettono. */
|
|
3888
4026
|
recordTriggerTypes = computed(() => this._dictionaries().recordTriggerTypes ?? [], ...(ngDevMode ? [{ debugName: "recordTriggerTypes" }] : []));
|
|
3889
4027
|
// -------------------------------------------------------------------------
|
|
3890
4028
|
// §3.4 — il tipo di flow
|
|
@@ -3924,6 +4062,73 @@ class FlowDictionaryStore {
|
|
|
3924
4062
|
flowTypeOfDefinition(definition) {
|
|
3925
4063
|
return this.flowTypeOf(definition?.processType, definition?.start?.[0]?.triggerType);
|
|
3926
4064
|
}
|
|
4065
|
+
// -------------------------------------------------------------------------
|
|
4066
|
+
// §3.4 — l'operazione e il momento di un trigger su record
|
|
4067
|
+
// -------------------------------------------------------------------------
|
|
4068
|
+
/**
|
|
4069
|
+
* La voce di un'operazione (`recordTriggerType`). Voce assente = nessun flag, cioe' «non lo so»:
|
|
4070
|
+
* chi legge torna a proporre i momenti del tipo di flow invece di togliere opzioni.
|
|
4071
|
+
*/
|
|
4072
|
+
recordTriggerType(value) {
|
|
4073
|
+
return value ? this.recordTriggerTypes().find((entry) => entry.value === value) : undefined;
|
|
4074
|
+
}
|
|
4075
|
+
/**
|
|
4076
|
+
* §3.4 — i **momenti** che un'operazione ammette, ed e' l'unico elenco da cui proporli: quello di
|
|
4077
|
+
* primo livello proporrebbe coppie che la validazione rifiuta (`START_TRIGGER_MISMATCH`).
|
|
4078
|
+
*
|
|
4079
|
+
* Qui sta la normalizzazione delle due forme in cui le voci arrivano — il solo valore oppure la
|
|
4080
|
+
* voce intera — perche' un host puo' serializzarle in entrambi i modi e riconoscerne una sola
|
|
4081
|
+
* significa funzionare con meta' dei dizionari senza che nulla lo dica. Dove arriva il solo
|
|
4082
|
+
* valore, etichetta e descrizione si ripescano dal dizionario `triggerTypes`, che e' dove stanno
|
|
4083
|
+
* comunque; dove non c'e' nemmeno quello resta il valore grezzo, che e' meglio di una riga vuota.
|
|
4084
|
+
*
|
|
4085
|
+
* Elenco vuoto = il dizionario non li dichiara, **non** «nessun momento ammesso».
|
|
4086
|
+
*/
|
|
4087
|
+
recordTriggerTimings(value) {
|
|
4088
|
+
const declared = this.recordTriggerType(value)?.triggerTypes ?? [];
|
|
4089
|
+
return declared.map((timing) => {
|
|
4090
|
+
if (typeof timing !== 'string') {
|
|
4091
|
+
return timing;
|
|
4092
|
+
}
|
|
4093
|
+
const known = this.triggerTypes().find((entry) => entry.value === timing);
|
|
4094
|
+
return known ?? { value: timing, label: timing };
|
|
4095
|
+
});
|
|
4096
|
+
}
|
|
4097
|
+
/**
|
|
4098
|
+
* Il momento da scrivere quando non si sceglie — l'eliminazione — o quando quello in mano non e'
|
|
4099
|
+
* ammesso dall'operazione appena scelta. Ripiega sul primo dichiarato: `defaultTriggerType` e'
|
|
4100
|
+
* facoltativo, e un'operazione con un momento solo non ha bisogno di dichiararlo due volte.
|
|
4101
|
+
*/
|
|
4102
|
+
defaultTimingOf(value) {
|
|
4103
|
+
const entry = this.recordTriggerType(value);
|
|
4104
|
+
return entry?.defaultTriggerType ?? this.recordTriggerTimings(value)[0]?.value;
|
|
4105
|
+
}
|
|
4106
|
+
/**
|
|
4107
|
+
* La domanda all'incontrario: quali operazioni ammettono questo momento. Serve dove il momento si
|
|
4108
|
+
* sceglie per primo — cioe' solo nel ripiego, su un documento il cui tipo di flow non si
|
|
4109
|
+
* riconosce — per rimettere a posto l'operazione invece di lasciare una coppia impossibile.
|
|
4110
|
+
*/
|
|
4111
|
+
recordTriggerTypesFor(trigger) {
|
|
4112
|
+
if (!trigger) {
|
|
4113
|
+
return [];
|
|
4114
|
+
}
|
|
4115
|
+
return this.recordTriggerTypes().filter((entry) => this.recordTriggerTimings(entry.value).some((timing) => timing.value === trigger));
|
|
4116
|
+
}
|
|
4117
|
+
/**
|
|
4118
|
+
* §3.4 — se la coppia operazione + momento e' una delle sei.
|
|
4119
|
+
*
|
|
4120
|
+
* `unknown` e' il caso normale su un dizionario che non dichiara i momenti, e non e' un difetto:
|
|
4121
|
+
* accusare una coppia senza avere la tabella con cui giudicarla e' peggio che tacere. Un editor
|
|
4122
|
+
* che rende la sequenza — l'operazione prima, il momento dopo — `mismatch` non lo produce mai: lo
|
|
4123
|
+
* incontra solo su un documento scritto altrove.
|
|
4124
|
+
*/
|
|
4125
|
+
recordTriggerPair(operation, trigger) {
|
|
4126
|
+
const timings = this.recordTriggerTimings(operation);
|
|
4127
|
+
if (!operation || !trigger || !timings.length) {
|
|
4128
|
+
return 'unknown';
|
|
4129
|
+
}
|
|
4130
|
+
return timings.some((timing) => timing.value === trigger) ? 'ok' : 'mismatch';
|
|
4131
|
+
}
|
|
3927
4132
|
startFrequencies = computed(() => this._dictionaries().startFrequencies ?? [], ...(ngDevMode ? [{ debugName: "startFrequencies" }] : []));
|
|
3928
4133
|
offsetUnits = computed(() => this._dictionaries().offsetUnits ?? [], ...(ngDevMode ? [{ debugName: "offsetUnits" }] : []));
|
|
3929
4134
|
sortOrders = computed(() => this._dictionaries().sortOrders ?? [], ...(ngDevMode ? [{ debugName: "sortOrders" }] : []));
|
|
@@ -4276,9 +4481,21 @@ class FlowCatalogStore {
|
|
|
4276
4481
|
*
|
|
4277
4482
|
* La primitiva e' opzionale e l'errore diventa lista vuota — che qui significa «il motore non
|
|
4278
4483
|
* le dichiara»: nessuna palette e nessuna accusa a una funzione fuori elenco (§4.6, §6.3).
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4484
|
+
*
|
|
4485
|
+
* `availability` toglie le funzioni che leggono i **valori precedenti** del record dove un
|
|
4486
|
+
* «prima» non c'e' (§6.3). Il filtro sta **dopo** la cache di proposito: la risposta del motore
|
|
4487
|
+
* e' la stessa per tutto il documento, e cio' che cambia e' l'operazione dello Start — rifetchare
|
|
4488
|
+
* a ogni cambio sarebbe una richiesta per niente, e mettere l'operazione nella chiave terrebbe in
|
|
4489
|
+
* memoria quattro copie dello stesso elenco. Assente = non si filtra: e' «non lo so», la regola
|
|
4490
|
+
* dei cataloghi. Dove il backend ha già filtrato questo non toglie niente — la regola e' la
|
|
4491
|
+
* stessa, applicata ai due capi.
|
|
4492
|
+
*/
|
|
4493
|
+
listFormulaFunctions(usage, availability) {
|
|
4494
|
+
return this.formulaFunctionsCache
|
|
4495
|
+
.get(usage ?? '', () => this.api.listFormulaFunctions(usage).then((list) => list ?? []).catch(() => []))
|
|
4496
|
+
.then((list) => !availability || priorValuesProposable(availability)
|
|
4497
|
+
? list
|
|
4498
|
+
: list.filter((entry) => !entry.requiresPriorValues));
|
|
4282
4499
|
}
|
|
4283
4500
|
listEnumTypes() {
|
|
4284
4501
|
return this.entriesCache.get('enum-types', () => this.api.listEnumTypes().then((list) => list ?? []));
|
|
@@ -7491,6 +7708,11 @@ class ReferencePickerComponent {
|
|
|
7491
7708
|
* - `globalPathUntyped`: percorso globale che porta un contenitore senza dichiararne il tipo:
|
|
7492
7709
|
* `PATH_NOT_VERIFIABLE`, e la correzione sta nel catalogo dell'host, non nel flow (§4.1);
|
|
7493
7710
|
* - `globalPathInvalid`: si naviga un percorso globale scalare o una collection: `GLOBAL_UNKNOWN`;
|
|
7711
|
+
* - `priorValuesMissing`: il valore e' radicato su `$Record__Prior` e i valori precedenti non
|
|
7712
|
+
* ci sono, o non ci sono sempre: `PRIOR_VALUES_NOT_AVAILABLE`, errore o avviso secondo
|
|
7713
|
+
* l'operazione che innesca il flow (§7). Si guarda **prima** di tutto il resto, perche' un
|
|
7714
|
+
* host che smette di proporre quello scope lo farebbe cadere in «questo nome non esiste», che
|
|
7715
|
+
* manda a cercare un nome sbagliato invece di dire che manca il record di prima;
|
|
7494
7716
|
* - `unknown`: nessuna corrispondenza: si avvisa, senza bloccare. Ci finisce anche il
|
|
7495
7717
|
* percorso inesistente di uno scope che i percorsi li dichiara, perche' lì il backend
|
|
7496
7718
|
* risponderebbe `GLOBAL_UNKNOWN`.
|
|
@@ -7500,6 +7722,9 @@ class ReferencePickerComponent {
|
|
|
7500
7722
|
if (!value) {
|
|
7501
7723
|
return 'empty';
|
|
7502
7724
|
}
|
|
7725
|
+
if (readsPriorValues(value) && this.priorValuesSeverity() !== 'none') {
|
|
7726
|
+
return 'priorValuesMissing';
|
|
7727
|
+
}
|
|
7503
7728
|
const all = this.references();
|
|
7504
7729
|
if (all.some((reference) => reference.name === value)) {
|
|
7505
7730
|
return 'known';
|
|
@@ -7600,16 +7825,42 @@ class ReferencePickerComponent {
|
|
|
7600
7825
|
return `«${this.declaredPrefix()?.name}» porta un contenitore, ma il catalogo non ne dichiara il tipo: il percorso non e’ verificabile (PATH_NOT_VERIFIABLE).`;
|
|
7601
7826
|
case 'globalPathInvalid':
|
|
7602
7827
|
return `«${this.declaredPrefix()?.name}» e’ un valore, non un contenitore: dopo il punto non c’e’ niente da navigare (GLOBAL_UNKNOWN).`;
|
|
7828
|
+
case 'priorValuesMissing': {
|
|
7829
|
+
const availability = priorValuesOfDefinition(this.store.document());
|
|
7830
|
+
const consequence = availability === 'never'
|
|
7831
|
+
? ': a runtime l’interview fallisce'
|
|
7832
|
+
: availability === 'sometimes'
|
|
7833
|
+
? ': il flow funziona a meta’'
|
|
7834
|
+
: '';
|
|
7835
|
+
return `Questo e’ il record prima del salvataggio, ma ${describePriorValues(availability)}${consequence} (PRIOR_VALUES_NOT_AVAILABLE).`;
|
|
7836
|
+
}
|
|
7603
7837
|
case 'unknown':
|
|
7604
7838
|
return 'Questo nome non e’ fra i riferimenti disponibili: la validazione lo segnalerebbe.';
|
|
7605
7839
|
default:
|
|
7606
7840
|
return null;
|
|
7607
7841
|
}
|
|
7608
7842
|
}, ...(ngDevMode ? [{ debugName: "hint" }] : []));
|
|
7843
|
+
/**
|
|
7844
|
+
* §7 — la gravita' di leggere i valori precedenti in **questo** documento: la decide l'operazione
|
|
7845
|
+
* che innesca il flow, non lo stato del picker, ed e' l'unico stato con due colori possibili.
|
|
7846
|
+
*/
|
|
7847
|
+
priorValuesSeverity = computed(() => priorValuesSeverity(priorValuesOfDefinition(this.store.document())), ...(ngDevMode ? [{ debugName: "priorValuesSeverity" }] : []));
|
|
7609
7848
|
/** Gli stati che sono avvisi: «non lo so», o un valore da correggere che non blocca. */
|
|
7610
|
-
isHintWarning = computed(() =>
|
|
7849
|
+
isHintWarning = computed(() => {
|
|
7850
|
+
const state = this.valueState();
|
|
7851
|
+
if (state === 'priorValuesMissing') {
|
|
7852
|
+
return this.priorValuesSeverity() === 'warning';
|
|
7853
|
+
}
|
|
7854
|
+
return ['unknown', 'containerRoot', 'globalPathUntyped'].includes(state);
|
|
7855
|
+
}, ...(ngDevMode ? [{ debugName: "isHintWarning" }] : []));
|
|
7611
7856
|
/** Gli stati che sono errori e non avvisi: il colore deve dirlo. */
|
|
7612
|
-
isHintError = computed(() =>
|
|
7857
|
+
isHintError = computed(() => {
|
|
7858
|
+
const state = this.valueState();
|
|
7859
|
+
if (state === 'priorValuesMissing') {
|
|
7860
|
+
return this.priorValuesSeverity() === 'error';
|
|
7861
|
+
}
|
|
7862
|
+
return ['memberUnknown', 'memberNotWritable', 'globalPathInvalid'].includes(state);
|
|
7863
|
+
}, ...(ngDevMode ? [{ debugName: "isHintError" }] : []));
|
|
7613
7864
|
errorMessage = computed(() => this.loadError(), ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
|
|
7614
7865
|
open() {
|
|
7615
7866
|
if (this.disabled()) {
|
|
@@ -8849,10 +9100,17 @@ class FormulaEditorComponent {
|
|
|
8849
9100
|
// Con `commitOn="change"` il `change` del DOM non scatta su una scrittura da codice.
|
|
8850
9101
|
this.onCommit(next);
|
|
8851
9102
|
}
|
|
8852
|
-
|
|
9103
|
+
/**
|
|
9104
|
+
* §6.3 — quando ci sono i **valori precedenti** del record: da qui dipende se la palette propone
|
|
9105
|
+
* `PRIORVALUE` e simili. E' un `computed` e non una lettura dentro l'effetto perche' il documento
|
|
9106
|
+
* cambia a ogni battuta mentre questa risposta cambia quasi mai: cosi' la palette si ricarica
|
|
9107
|
+
* quando cambia l'**operazione**, non quando si scrive.
|
|
9108
|
+
*/
|
|
9109
|
+
priorValues = computed(() => priorValuesOfDefinition(this.store.document()), ...(ngDevMode ? [{ debugName: "priorValues" }] : []));
|
|
9110
|
+
async loadFunctions(usage, availability) {
|
|
8853
9111
|
// La primitiva e' opzionale: in errore lo store risponde lista vuota, cioe' «non dichiarate».
|
|
8854
|
-
const list = await this.catalog.listFormulaFunctions(usage);
|
|
8855
|
-
if (this.usage() === usage) {
|
|
9112
|
+
const list = await this.catalog.listFormulaFunctions(usage, availability);
|
|
9113
|
+
if (this.usage() === usage && this.priorValues() === availability) {
|
|
8856
9114
|
this.functions.set(list);
|
|
8857
9115
|
}
|
|
8858
9116
|
}
|
|
@@ -8895,7 +9153,8 @@ class FormulaEditorComponent {
|
|
|
8895
9153
|
// montati insieme non fanno piu' di una chiamata per uso.
|
|
8896
9154
|
effect(() => {
|
|
8897
9155
|
const usage = this.usage();
|
|
8898
|
-
|
|
9156
|
+
const availability = this.priorValues();
|
|
9157
|
+
untracked(() => void this.loadFunctions(usage, availability));
|
|
8899
9158
|
});
|
|
8900
9159
|
effect(() => {
|
|
8901
9160
|
const expression = this.expression();
|
|
@@ -9501,6 +9760,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
9501
9760
|
*
|
|
9502
9761
|
* Inoltre: `WasVisited` e `HasError` vogliono a sinistra il nome di un **node**, non di una
|
|
9503
9762
|
* risorsa (`appliesToElements`), e il selettore cambia di conseguenza.
|
|
9763
|
+
*
|
|
9764
|
+
* E **i valori precedenti del record non ci sono sempre** (§7). Una condizione che li legge —
|
|
9765
|
+
* `IsChanged`, o un riferimento radicato su `$Record__Prior` — vale quanto l'operazione che innesca
|
|
9766
|
+
* il flow: sull'aggiornamento non c'e' niente da dire, su «creazione e aggiornamento» il flow
|
|
9767
|
+
* funziona a meta' (avviso), sulla creazione e sull'eliminazione a runtime l'interview **fallisce**
|
|
9768
|
+
* davanti a chi stava salvando (errore). La regola sta in `core/record-trigger.ts`, ed e' la stessa
|
|
9769
|
+
* che applica il validatore: qui si dice mentre si scrive la condizione, che e' mezz'ora prima.
|
|
9504
9770
|
*/
|
|
9505
9771
|
class ConditionEditorComponent {
|
|
9506
9772
|
dictionaries = inject(FlowDictionaryStore);
|
|
@@ -9620,6 +9886,37 @@ class ConditionEditorComponent {
|
|
|
9620
9886
|
}
|
|
9621
9887
|
return !areTypesComparable(this.leftDataType(condition), this.rightDataType(condition));
|
|
9622
9888
|
}
|
|
9889
|
+
/**
|
|
9890
|
+
* §3.4, §7 — quando ci sono i valori precedenti del record in **questo** documento: dipende
|
|
9891
|
+
* dall'operazione che innesca il flow, che sta nello Start.
|
|
9892
|
+
*/
|
|
9893
|
+
priorValues = computed(() => priorValuesOfDefinition(this.store.document()), ...(ngDevMode ? [{ debugName: "priorValues" }] : []));
|
|
9894
|
+
/**
|
|
9895
|
+
* La condizione legge i valori precedenti? Tre modi di farlo, e vanno guardati tutti e tre:
|
|
9896
|
+
* l'operatore `IsChanged`, il riferimento di sinistra e quello di confronto. Le **formule**
|
|
9897
|
+
* restano fuori di proposito: la sintassi la conosce solo il motore (§6.3).
|
|
9898
|
+
*/
|
|
9899
|
+
readsPriorValues(condition) {
|
|
9900
|
+
return (condition.operator === PRIOR_VALUES_OPERATOR ||
|
|
9901
|
+
readsPriorValues(condition.leftValueReference) ||
|
|
9902
|
+
readsPriorValues(condition.rightValue?.elementReference));
|
|
9903
|
+
}
|
|
9904
|
+
/** `none` dove non c'e' niente da dire: e' il caso dell'aggiornamento, e di chi non li legge. */
|
|
9905
|
+
priorValuesSeverityOf(condition) {
|
|
9906
|
+
return this.readsPriorValues(condition) ? priorValuesSeverity(this.priorValues()) : 'none';
|
|
9907
|
+
}
|
|
9908
|
+
priorValuesMessage(condition) {
|
|
9909
|
+
const availability = this.priorValues();
|
|
9910
|
+
const consequence = availability === 'never'
|
|
9911
|
+
? ': a runtime l’interview fallisce'
|
|
9912
|
+
: availability === 'sometimes'
|
|
9913
|
+
? ': il flow funziona a meta’'
|
|
9914
|
+
: '';
|
|
9915
|
+
const what = condition.operator === PRIOR_VALUES_OPERATOR
|
|
9916
|
+
? `L’operatore «${this.operatorLabel(condition.operator)}» legge i valori precedenti del record`
|
|
9917
|
+
: 'Questa condizione legge i valori precedenti del record';
|
|
9918
|
+
return `${what}, ma ${describePriorValues(availability)}${consequence} (PRIOR_VALUES_NOT_AVAILABLE).`;
|
|
9919
|
+
}
|
|
9623
9920
|
typeMismatchMessage(condition) {
|
|
9624
9921
|
const left = this.leftDataType(condition) ?? '?';
|
|
9625
9922
|
const right = this.rightDataType(condition) ?? '?';
|
|
@@ -9803,11 +10100,11 @@ class ConditionEditorComponent {
|
|
|
9803
10100
|
});
|
|
9804
10101
|
}
|
|
9805
10102
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: ConditionEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
9806
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", 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 });
|
|
10103
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", 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 <!--\r\n \u00A77 \u2014 i valori precedenti del record non ci sono sempre, e quanto costa leggerli lo\r\n decide l'**operazione** che innesca il flow: mai = l'interview fallisce (errore), a\r\n volte = funziona a meta' (avviso). Dirlo qui e' dirlo prima che lo dica il runtime.\r\n -->\r\n @if (priorValuesSeverityOf(condition) === 'error') {\r\n <p class=\"fb-field__error\">{{ priorValuesMessage(condition) }}</p>\r\n } @else if (priorValuesSeverityOf(condition) === 'warning') {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">{{ priorValuesMessage(condition) }}</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 });
|
|
9807
10104
|
}
|
|
9808
10105
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: ConditionEditorComponent, decorators: [{
|
|
9809
10106
|
type: Component,
|
|
9810
|
-
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"] }]
|
|
10107
|
+
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 <!--\r\n \u00A77 \u2014 i valori precedenti del record non ci sono sempre, e quanto costa leggerli lo\r\n decide l'**operazione** che innesca il flow: mai = l'interview fallisce (errore), a\r\n volte = funziona a meta' (avviso). Dirlo qui e' dirlo prima che lo dica il runtime.\r\n -->\r\n @if (priorValuesSeverityOf(condition) === 'error') {\r\n <p class=\"fb-field__error\">{{ priorValuesMessage(condition) }}</p>\r\n } @else if (priorValuesSeverityOf(condition) === 'warning') {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">{{ priorValuesMessage(condition) }}</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"] }]
|
|
9811
10108
|
}], 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"] }] } });
|
|
9812
10109
|
|
|
9813
10110
|
/**
|
|
@@ -9850,6 +10147,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
9850
10147
|
class RecordFilterEditorComponent {
|
|
9851
10148
|
catalog = inject(FlowCatalogStore);
|
|
9852
10149
|
dictionaries = inject(FlowDictionaryStore);
|
|
10150
|
+
/**
|
|
10151
|
+
* §7 — serve per una domanda sola: i **valori precedenti** del record ci sono? Dipende
|
|
10152
|
+
* dall'operazione che innesca il flow, che sta nello Start, e vale per i criteri di ingresso come
|
|
10153
|
+
* per una condizione — un filtro `IsChanged`, o un valore che cita `$Record__Prior`, su un flow
|
|
10154
|
+
* che parte alla creazione non ha niente da confrontare.
|
|
10155
|
+
*/
|
|
10156
|
+
documents = inject(FlowDocumentStore);
|
|
9853
10157
|
holder = input.required(...(ngDevMode ? [{ debugName: "holder" }] : []));
|
|
9854
10158
|
object = input(undefined, ...(ngDevMode ? [{ debugName: "object" }] : []));
|
|
9855
10159
|
title = input('Filtri', ...(ngDevMode ? [{ debugName: "title" }] : []));
|
|
@@ -9970,6 +10274,24 @@ class RecordFilterEditorComponent {
|
|
|
9970
10274
|
return checkConditionLogic(logic, this.filters().length, 'filtro');
|
|
9971
10275
|
}, ...(ngDevMode ? [{ debugName: "customLogicError" }] : []));
|
|
9972
10276
|
showEmptyWarning = computed(() => !!this.emptyWarning() && this.filters().length === 0, ...(ngDevMode ? [{ debugName: "showEmptyWarning" }] : []));
|
|
10277
|
+
/**
|
|
10278
|
+
* §7 — la gravita' di leggere i valori precedenti in questo filtro: `none` dove non li legge o
|
|
10279
|
+
* dove ci sono sempre. La regola e' quella di `core/record-trigger.ts`, la stessa del condition
|
|
10280
|
+
* editor e del validatore: scriverla due volte significa scriverla due volte diversa.
|
|
10281
|
+
*/
|
|
10282
|
+
priorValuesSeverityOf(filter) {
|
|
10283
|
+
const reads = filter.operator === PRIOR_VALUES_OPERATOR || readsPriorValues(filter.value?.elementReference);
|
|
10284
|
+
return reads ? priorValuesSeverity(priorValuesOfDefinition(this.documents.document())) : 'none';
|
|
10285
|
+
}
|
|
10286
|
+
priorValuesMessage() {
|
|
10287
|
+
const availability = priorValuesOfDefinition(this.documents.document());
|
|
10288
|
+
const consequence = availability === 'never'
|
|
10289
|
+
? ': a runtime l’interview fallisce'
|
|
10290
|
+
: availability === 'sometimes'
|
|
10291
|
+
? ': il flow funziona a meta’'
|
|
10292
|
+
: '';
|
|
10293
|
+
return `Questo filtro legge i valori precedenti del record, ma ${describePriorValues(availability)}${consequence} (PRIOR_VALUES_NOT_AVAILABLE).`;
|
|
10294
|
+
}
|
|
9973
10295
|
addFilter() {
|
|
9974
10296
|
this.changed.emit((holder) => {
|
|
9975
10297
|
holder.filters ??= [];
|
|
@@ -10115,11 +10437,11 @@ class RecordFilterEditorComponent {
|
|
|
10115
10437
|
return this.types.valueSetOf(filter.field);
|
|
10116
10438
|
}
|
|
10117
10439
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: RecordFilterEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10118
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", 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 });
|
|
10440
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", 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 <!--\r\n \u00A77 \u2014 un filtro che legge i valori di prima del record vale quanto l'operazione che\r\n innesca il flow: mai = l'interview fallisce, a volte = funziona a meta'.\r\n -->\r\n @if (priorValuesSeverityOf(filter) === 'error') {\r\n <p class=\"fb-field__error\">{{ priorValuesMessage() }}</p>\r\n } @else if (priorValuesSeverityOf(filter) === 'warning') {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">{{ priorValuesMessage() }}</p>\r\n }\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 });
|
|
10119
10441
|
}
|
|
10120
10442
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: RecordFilterEditorComponent, decorators: [{
|
|
10121
10443
|
type: Component,
|
|
10122
|
-
args: [{ selector: 'fb-record-filter-editor', standalone: true, imports: [FieldPickerComponent, FormulaEditorComponent, ValueEditorComponent, SelectValueDirective], changeDetection: ChangeDetectionStrategy.OnPush, 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"] }]
|
|
10444
|
+
args: [{ selector: 'fb-record-filter-editor', standalone: true, imports: [FieldPickerComponent, FormulaEditorComponent, ValueEditorComponent, SelectValueDirective], changeDetection: ChangeDetectionStrategy.OnPush, 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 <!--\r\n \u00A77 \u2014 un filtro che legge i valori di prima del record vale quanto l'operazione che\r\n innesca il flow: mai = l'interview fallisce, a volte = funziona a meta'.\r\n -->\r\n @if (priorValuesSeverityOf(filter) === 'error') {\r\n <p class=\"fb-field__error\">{{ priorValuesMessage() }}</p>\r\n } @else if (priorValuesSeverityOf(filter) === 'warning') {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">{{ priorValuesMessage() }}</p>\r\n }\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"] }]
|
|
10123
10445
|
}], ctorParameters: () => [], propDecorators: { holder: [{ type: i0.Input, args: [{ isSignal: true, alias: "holder", required: true }] }], object: [{ type: i0.Input, args: [{ isSignal: true, alias: "object", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], usage: [{ type: i0.Input, args: [{ isSignal: true, alias: "usage", required: false }] }], fieldOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldOptions", required: false }] }], supportsLogic: [{ type: i0.Input, args: [{ isSignal: true, alias: "supportsLogic", required: false }] }], supportsFormula: [{ type: i0.Input, args: [{ isSignal: true, alias: "supportsFormula", required: false }] }], emptyWarning: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyWarning", required: false }] }], emptyWarningSeverity: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyWarningSeverity", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
|
|
10124
10446
|
|
|
10125
10447
|
/**
|
|
@@ -14256,9 +14578,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
14256
14578
|
* Con un trigger su record il flow espone `$Record` e `$Record__Prior`; senza, quei
|
|
14257
14579
|
* riferimenti non sono disponibili e la validazione lo segnala. Il form lo dice, perche' e'
|
|
14258
14580
|
* la differenza fra un riferimento che funziona e uno che no.
|
|
14581
|
+
*
|
|
14582
|
+
* **Su un trigger da record il «quando parte» non e' una tendina, e' una sequenza** (§3.4). I campi
|
|
14583
|
+
* sono due — `recordTriggerType` e' l'**operazione**, `triggerType` il **momento** rispetto alla
|
|
14584
|
+
* scrittura — ma non sono due assi liberi: l'eliminazione ha un momento solo, e le coppie che
|
|
14585
|
+
* significano qualcosa sono sei. Due tendine indipendenti lascerebbero dichiarare «prima
|
|
14586
|
+
* dell'eliminazione» insieme a «alla creazione»: il runtime la legge come un'eliminazione — con
|
|
14587
|
+
* `RecordBeforeDelete` l'operazione la dice il trigger e `recordTriggerType` non viene guardato —
|
|
14588
|
+
* cioe' il flow parte su qualcosa che nessuno ha scelto. Quindi si chiede l'oggetto, poi
|
|
14589
|
+
* l'operazione, poi i criteri, poi il momento **fra quelli che l'operazione ammette**, e da quella
|
|
14590
|
+
* sequenza la coppia impossibile non e' esprimibile (`START_TRIGGER_MISMATCH` non si incontra mai,
|
|
14591
|
+
* se non aprendo un documento scritto altrove). I momenti li dichiara la voce dell'operazione nei
|
|
14592
|
+
* dizionari, non un elenco cablato: proporre i `triggerTypes` di primo livello significa proporre
|
|
14593
|
+
* coppie che la validazione rifiuta.
|
|
14259
14594
|
*/
|
|
14260
|
-
/** I trigger che lavorano su un record e abilitano `$Record`. */
|
|
14261
|
-
const RECORD_TRIGGERS = new Set(['RecordBeforeSave', 'RecordAfterSave', 'RecordBeforeDelete']);
|
|
14262
14595
|
class StartInspectorComponent {
|
|
14263
14596
|
store = inject(FlowDocumentStore);
|
|
14264
14597
|
dictionaries = inject(FlowDictionaryStore);
|
|
@@ -14303,6 +14636,51 @@ class StartInspectorComponent {
|
|
|
14303
14636
|
: '';
|
|
14304
14637
|
}, ...(ngDevMode ? [{ debugName: "registrationLabel" }] : []));
|
|
14305
14638
|
recordTriggerTypes = computed(() => this.dictionaries.recordTriggerTypes(), ...(ngDevMode ? [{ debugName: "recordTriggerTypes" }] : []));
|
|
14639
|
+
/**
|
|
14640
|
+
* §3.4 — dove il tipo di flow **e'** innescato da un record, la tendina «quando parte» sparisce:
|
|
14641
|
+
* i suoi tre valori sono il *momento*, e il momento si sceglie per ultimo e fra quelli che
|
|
14642
|
+
* l'operazione ammette. Il ripiego — un documento il cui tipo non si riconosce, dove i trigger
|
|
14643
|
+
* proponibili sono tutti e sei — tiene la tendina e chiede l'operazione accanto: togliere la
|
|
14644
|
+
* scelta a chi ha in mano una coppia fuori dalle sei lo bloccherebbe sul valore che ha.
|
|
14645
|
+
*/
|
|
14646
|
+
isRecordFlowType = computed(() => {
|
|
14647
|
+
const proposable = this.triggerTypes();
|
|
14648
|
+
return proposable.length > 0 && proposable.every((entry) => RECORD_TRIGGERS.has(entry.value));
|
|
14649
|
+
}, ...(ngDevMode ? [{ debugName: "isRecordFlowType" }] : []));
|
|
14650
|
+
/** La voce dell'operazione dichiarata dal documento, coi suoi flag (§6.4). */
|
|
14651
|
+
recordOperation = computed(() => this.dictionaries.recordTriggerType(this.start().recordTriggerType), ...(ngDevMode ? [{ debugName: "recordOperation" }] : []));
|
|
14652
|
+
/**
|
|
14653
|
+
* I momenti proponibili: quelli **dell'operazione scelta**. Dove il dizionario non li dichiara —
|
|
14654
|
+
* o l'operazione non e' ancora scelta — si torna ai trigger su record del tipo di flow, che e' il
|
|
14655
|
+
* comportamento di prima: elenco vuoto significa «non lo so», non «nessun momento ammesso».
|
|
14656
|
+
*/
|
|
14657
|
+
timingOptions = computed(() => {
|
|
14658
|
+
const declared = this.dictionaries.recordTriggerTimings(this.start().recordTriggerType);
|
|
14659
|
+
return declared.length
|
|
14660
|
+
? declared
|
|
14661
|
+
: this.triggerTypes().filter((entry) => RECORD_TRIGGERS.has(entry.value));
|
|
14662
|
+
}, ...(ngDevMode ? [{ debugName: "timingOptions" }] : []));
|
|
14663
|
+
/**
|
|
14664
|
+
* Dove l'operazione ammette un momento solo — l'eliminazione — **la domanda non si pone affatto**
|
|
14665
|
+
* e il momento si scrive comunque: il contratto chiede entrambi i campi anche lì. Il controllo
|
|
14666
|
+
* `allowsTimingChoice !== false` e' la cintura: un dizionario che non lo dichiara decide sul
|
|
14667
|
+
* numero di opzioni, che e' la stessa risposta.
|
|
14668
|
+
*/
|
|
14669
|
+
showTimingChoice = computed(() => this.recordOperation()?.allowsTimingChoice !== false && this.timingOptions().length > 1, ...(ngDevMode ? [{ debugName: "showTimingChoice" }] : []));
|
|
14670
|
+
/** La voce del momento in mano, per mostrarne l'etichetta dove non c'e' niente da scegliere. */
|
|
14671
|
+
currentTiming = computed(() => this.timingOptions().find((entry) => entry.value === this.triggerType()), ...(ngDevMode ? [{ debugName: "currentTiming" }] : []));
|
|
14672
|
+
/**
|
|
14673
|
+
* §3.4 — `doesRequireRecordChangedToMeetCriteria` ha senso solo dove c'e' un «prima» da
|
|
14674
|
+
* confrontare: alla creazione e all'eliminazione il flag resta inerte, e con esso `IsChanged` non
|
|
14675
|
+
* decide nulla. Flag non dichiarato = lo si mostra: e' il ripiego di sempre.
|
|
14676
|
+
*/
|
|
14677
|
+
showRequireChanged = computed(() => this.recordOperation()?.usesPriorRecord !== false, ...(ngDevMode ? [{ debugName: "showRequireChanged" }] : []));
|
|
14678
|
+
/**
|
|
14679
|
+
* La coppia che il documento dichiara non e' una delle sei. Dalla sequenza non e' esprimibile,
|
|
14680
|
+
* quindi arriva da un documento scritto altrove: si **dice**, e la correzione e' un comando.
|
|
14681
|
+
*/
|
|
14682
|
+
hasTriggerMismatch = computed(() => this.dictionaries.recordTriggerPair(this.start().recordTriggerType, this.triggerType()) ===
|
|
14683
|
+
'mismatch', ...(ngDevMode ? [{ debugName: "hasTriggerMismatch" }] : []));
|
|
14306
14684
|
frequencies = computed(() => this.dictionaries.startFrequencies(), ...(ngDevMode ? [{ debugName: "frequencies" }] : []));
|
|
14307
14685
|
offsetUnits = computed(() => this.dictionaries.offsetUnits(), ...(ngDevMode ? [{ debugName: "offsetUnits" }] : []));
|
|
14308
14686
|
triggerType = computed(() => this.start().triggerType ?? 'None', ...(ngDevMode ? [{ debugName: "triggerType" }] : []));
|
|
@@ -14316,7 +14694,20 @@ class StartInspectorComponent {
|
|
|
14316
14694
|
setTriggerType(value) {
|
|
14317
14695
|
this.store.updateStart((start) => {
|
|
14318
14696
|
start.triggerType = value === 'None' ? undefined : value;
|
|
14319
|
-
if (
|
|
14697
|
+
if (RECORD_TRIGGERS.has(value)) {
|
|
14698
|
+
/*
|
|
14699
|
+
* §3.4 — operazione e momento non sono due assi liberi. Qui il momento si sceglie per primo
|
|
14700
|
+
* (e' il ripiego: dalla sequenza si passa da `setRecordOperation`), quindi se l'operazione
|
|
14701
|
+
* in mano non ammette questo momento va rimessa a posto — all'unica che lo ammette dove ce
|
|
14702
|
+
* n'e' una sola (l'eliminazione), altrimenti tolta. Lasciarla sarebbe la coppia che il
|
|
14703
|
+
* runtime legge al contrario di come e' scritta.
|
|
14704
|
+
*/
|
|
14705
|
+
const allowed = this.dictionaries.recordTriggerTypesFor(value);
|
|
14706
|
+
if (allowed.length && !allowed.some((entry) => entry.value === start.recordTriggerType)) {
|
|
14707
|
+
start.recordTriggerType = allowed.length === 1 ? allowed[0].value : undefined;
|
|
14708
|
+
}
|
|
14709
|
+
}
|
|
14710
|
+
else {
|
|
14320
14711
|
// Campi che appartengono ai **soli** trigger su record: tenerli sarebbe rumore che il
|
|
14321
14712
|
// motore ignora e che sporca il diff.
|
|
14322
14713
|
delete start.recordTriggerType;
|
|
@@ -14363,11 +14754,42 @@ class StartInspectorComponent {
|
|
|
14363
14754
|
delete start.filters;
|
|
14364
14755
|
});
|
|
14365
14756
|
}
|
|
14366
|
-
|
|
14757
|
+
/**
|
|
14758
|
+
* §3.4 — l'operazione, che e' la domanda **prima** del momento, e scrive tutti e due i campi in
|
|
14759
|
+
* **una** mutazione: con due, l'annulla riporterebbe indietro il momento lasciando l'operazione
|
|
14760
|
+
* nuova, cioe' una coppia che non e' nessuna delle sei. Il momento si tocca solo se quello in
|
|
14761
|
+
* mano non e' ammesso — cambiare operazione non deve buttare via una scelta ancora valida.
|
|
14762
|
+
*/
|
|
14763
|
+
setRecordOperation(value) {
|
|
14367
14764
|
this.store.updateStart((start) => {
|
|
14368
|
-
|
|
14765
|
+
if (!value) {
|
|
14766
|
+
delete start.recordTriggerType;
|
|
14767
|
+
return;
|
|
14768
|
+
}
|
|
14769
|
+
start.recordTriggerType = value;
|
|
14770
|
+
const timings = this.dictionaries.recordTriggerTimings(value).map((entry) => entry.value);
|
|
14771
|
+
const fallback = this.dictionaries.defaultTimingOf(value);
|
|
14772
|
+
if (timings.length && !timings.includes(start.triggerType ?? '') && fallback) {
|
|
14773
|
+
start.triggerType = fallback;
|
|
14774
|
+
}
|
|
14775
|
+
// Il flag del «prima» e' inerte dove l'operazione non ha un prima: tenerlo sarebbe una
|
|
14776
|
+
// condizione scritta che il motore non guarda.
|
|
14777
|
+
if (this.dictionaries.recordTriggerType(value)?.usesPriorRecord === false) {
|
|
14778
|
+
delete start.doesRequireRecordChangedToMeetCriteria;
|
|
14779
|
+
}
|
|
14369
14780
|
});
|
|
14370
14781
|
}
|
|
14782
|
+
/**
|
|
14783
|
+
* Rimette il momento fra quelli che l'operazione ammette. E' un **comando** e non una correzione
|
|
14784
|
+
* automatica: su un documento scritto altrove non si sa quale meta' della coppia sia quella
|
|
14785
|
+
* voluta, e cambiarne una di soppiatto e' una modifica che nessuno ha chiesto.
|
|
14786
|
+
*/
|
|
14787
|
+
useDefaultTiming() {
|
|
14788
|
+
const timing = this.dictionaries.defaultTimingOf(this.start().recordTriggerType);
|
|
14789
|
+
if (timing) {
|
|
14790
|
+
this.setTriggerType(timing);
|
|
14791
|
+
}
|
|
14792
|
+
}
|
|
14371
14793
|
setRequireChanged(value) {
|
|
14372
14794
|
this.store.updateStart((start) => {
|
|
14373
14795
|
if (value) {
|
|
@@ -14445,7 +14867,7 @@ class StartInspectorComponent {
|
|
|
14445
14867
|
this.store.setConnector('$start', event.outletKey, event.target, event.isGoTo);
|
|
14446
14868
|
}
|
|
14447
14869
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: StartInspectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
14448
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", type: StartInspectorComponent, isStandalone: true, selector: "fb-start-inspector", ngImport: i0, template: "@if (!hasEntryPoint()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Lo Start non punta a nessun elemento: il flow non ha un punto di ingresso e non e\u2019 eseguibile\r\n (START_NO_ENTRY_POINT).\r\n </p>\r\n}\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Quando parte</label>\r\n <!--\r\n \u00A73.4 \u2014 i trigger sono quelli del **tipo di flow** scelto alla creazione, non tutti: la coppia\r\n `processType` + `triggerType` **e'** il tipo, e cambiarla qui vorrebbe dire cambiarlo.\r\n -->\r\n <select class=\"fb-select\" [fbValue]=\"triggerType()\" (change)=\"setTriggerType($any($event.target).value)\">\r\n @for (trigger of triggerTypes(); track trigger.value) {\r\n <option [value]=\"trigger.value\">{{ trigger.label }}</option>\r\n }\r\n </select>\r\n @if (flowType(); as type) {\r\n <p class=\"fb-field__hint\">\r\n Tipo di flow: <strong>{{ type.label }}</strong\r\n >{{ type.description ? ' \u2014 ' + type.description : '' }}\r\n </p>\r\n }\r\n @if (requiresRegistration()) {\r\n <!--\r\n \u00A78 \u2014 l'unico caso in cui una definizione **valida** puo' non essere attivabile: il flow non\r\n parte da solo, e l'infrastruttura dell'ospite deve prenderlo in carico. Dirlo qui, dove si\r\n sceglie il trigger, e' dirlo prima che l'attivazione fallisca.\r\n -->\r\n <p class=\"fb-callout\">\r\n Questo flow non parte da solo: attivandolo,\r\n {{ registrationLabel() ? 'il servizio \u00AB' + registrationLabel() + '\u00BB' : 'l\u2019infrastruttura dell\u2019ambiente' }}\r\n deve <strong>prenderlo in carico</strong>. Se non c\u2019e\u2019 chi lo faccia, l\u2019attivazione non riesce\r\n anche con la definizione a posto.\r\n </p>\r\n }\r\n</div>\r\n\r\n@if (isRecordTrigger()) {\r\n <p class=\"fb-callout\">\r\n Con un trigger su record il flow espone <code>$Record</code> e <code>$Record__Prior</code>.\r\n </p>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Oggetto che innesca</label>\r\n <fb-object-picker\r\n [value]=\"start().object\"\r\n label=\"Oggetto che innesca\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setObject($event ?? '')\"\r\n />\r\n @if (!start().object) {\r\n <p class=\"fb-field__error\">Obbligatorio con i trigger su record (START_OBJECT_MISSING).</p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Su quale operazione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"start().recordTriggerType || ''\"\r\n (change)=\"setRecordTriggerType($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (type of recordTriggerTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n <fb-record-filter-editor\r\n [holder]=\"$any(start())\"\r\n [object]=\"start().object\"\r\n title=\"Criteri di ingresso\"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"true\"\r\n [supportsFormula]=\"true\"\r\n emptyWarning=\"Senza criteri il flow parte su ogni record.\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n />\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"start().doesRequireRecordChangedToMeetCriteria === true\"\r\n (change)=\"setRequireChanged($any($event.target).checked)\"\r\n />\r\n Solo se il record <em>non</em> soddisfaceva i criteri prima del salvataggio\r\n </label>\r\n}\r\n\r\n@if (isScheduled()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Pianificazione</legend>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Frequenza</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"start().schedule?.frequency || ''\"\r\n (change)=\"setFrequency($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (frequency of frequencies(); track frequency.value) {\r\n <option [value]=\"frequency.value\">{{ frequency.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Data di inizio</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"date\"\r\n [value]=\"startDateValue()\"\r\n (input)=\"setStartDate($any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Ora</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"time\"\r\n [value]=\"startTimeValue()\"\r\n (input)=\"setStartTime($any($event.target).value)\"\r\n />\r\n </div>\r\n </div>\r\n @if (!start().schedule?.frequency) {\r\n <p class=\"fb-field__error\">La pianificazione e\u2019 obbligatoria con questo trigger (START_SCHEDULE_MISSING).</p>\r\n }\r\n </fieldset>\r\n\r\n <!--\r\n \u00A73.4 \u2014 su uno schedulato l'oggetto e' **facoltativo** e vuol dire un'altra cosa che sui trigger\r\n su record: non \u00ABl'entita' che innesca\u00BB ma \u00ABun'esecuzione per ogni record che soddisfa i filtri\u00BB.\r\n Senza, il flow gira una volta sola.\r\n -->\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Un\u2019esecuzione per record</legend>\r\n <p class=\"fb-section__note\">\r\n Facoltativo. Indicando un\u2019entita\u2019, il flow gira <strong>una volta per ogni record</strong> che\r\n soddisfa i filtri invece di una volta sola.\r\n </p>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Entita\u2019</label>\r\n <fb-object-picker\r\n [value]=\"start().object\"\r\n label=\"Entita\u2019\"\r\n placeholder=\"Nessuna: una sola esecuzione\"\r\n (valueChange)=\"setObject($event ?? '')\"\r\n />\r\n </div>\r\n @if (start().object) {\r\n <fb-record-filter-editor\r\n [holder]=\"$any(start())\"\r\n [object]=\"start().object\"\r\n title=\"Quali record\"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"true\"\r\n [supportsFormula]=\"true\"\r\n emptyWarning=\"Senza criteri il flow gira su ogni record dell\u2019entita\u2019.\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n />\r\n }\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Percorsi differiti</legend>\r\n <p class=\"fb-section__note\">\r\n Ogni percorso e\u2019 un ramo che parte dopo un intervallo, calcolato da un istante di riferimento.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (path of scheduledPaths(); 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 percorso\"\r\n (click)=\"removeScheduledPath($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</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"path.label || ''\"\r\n (input)=\"setPathField($index, '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\">Nome tecnico</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"path.name || ''\"\r\n (input)=\"setPathField($index, 'name', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Dopo</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n [value]=\"path.offsetNumber ?? ''\"\r\n (input)=\"setPathOffsetNumber($index, $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]=\"path.offsetUnit || ''\"\r\n (change)=\"setPathField($index, 'offsetUnit', $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 <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Istante di riferimento</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"path.timeSource || ''\"\r\n placeholder=\"Es. RecordTriggerEvent\"\r\n (input)=\"setPathField($index, 'timeSource', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo data del record</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"path.recordField || ''\"\r\n (input)=\"setPathField($index, 'recordField', $any($event.target).value)\"\r\n />\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun percorso differito.</p>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addScheduledPath()\">Aggiungi percorso</button>\r\n </fieldset>\r\n}\r\n\r\n@if (triggerType() === 'None') {\r\n <p class=\"fb-field__hint\">\r\n Il flow parte solo su richiesta. I valori iniziali si passano nelle variabili di input.\r\n </p>\r\n}\r\n\r\n@if (isEvent()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Evento</legend>\r\n <p class=\"fb-section__note\">\r\n Il flow parte alla ricezione di un evento: e\u2019 a questo che l\u2019host si sottoscrive quando la\r\n versione viene attivata (\u00A78).\r\n </p>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo di evento</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"start().eventType || ''\"\r\n placeholder=\"Es. OrdineEvaso\"\r\n (input)=\"setEventField('eventType', $any($event.target).value)\"\r\n />\r\n @if (!start().eventType) {\r\n <p class=\"fb-field__error\">Obbligatorio con questo trigger (START_EVENT_MISSING).</p>\r\n }\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Nome dell\u2019evento</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"start().eventName || ''\"\r\n (input)=\"setEventField('eventName', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">Facoltativo: serve dove il tipo da solo non identifica l\u2019evento.</p>\r\n </div>\r\n </fieldset>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"'$start'\"\r\n [node]=\"startNode()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Da dove comincia\"\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: 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: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
14870
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", type: StartInspectorComponent, isStandalone: true, selector: "fb-start-inspector", ngImport: i0, template: "@if (!hasEntryPoint()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Lo Start non punta a nessun elemento: il flow non ha un punto di ingresso e non e\u2019 eseguibile\r\n (START_NO_ENTRY_POINT).\r\n </p>\r\n}\r\n\r\n<!--\r\n \u00A73.4 \u2014 su un flow innescato da un record la tendina non c'e': i suoi tre valori sono il *momento*,\r\n e il momento e' l'ultima domanda della sequenza qui sotto, posta fra i soli momenti che\r\n l'operazione scelta ammette. Altrove i trigger sono quelli del **tipo di flow** scelto alla\r\n creazione, non tutti: la coppia `processType` + `triggerType` **e'** il tipo, e cambiarla qui\r\n vorrebbe dire cambiarlo.\r\n-->\r\n@if (!isRecordFlowType()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Quando parte</label>\r\n <select class=\"fb-select\" [fbValue]=\"triggerType()\" (change)=\"setTriggerType($any($event.target).value)\">\r\n @for (trigger of triggerTypes(); track trigger.value) {\r\n <option [value]=\"trigger.value\">{{ trigger.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n}\r\n\r\n@if (flowType(); as type) {\r\n <p class=\"fb-field__hint\">\r\n Tipo di flow: <strong>{{ type.label }}</strong\r\n >{{ type.description ? ' \u2014 ' + type.description : '' }}\r\n </p>\r\n}\r\n@if (requiresRegistration()) {\r\n <!--\r\n \u00A78 \u2014 l'unico caso in cui una definizione **valida** puo' non essere attivabile: il flow non\r\n parte da solo, e l'infrastruttura dell'ospite deve prenderlo in carico. Dirlo qui, dove si\r\n sceglie il trigger, e' dirlo prima che l'attivazione fallisca.\r\n -->\r\n <p class=\"fb-callout\">\r\n Questo flow non parte da solo: attivandolo,\r\n {{ registrationLabel() ? 'il servizio \u00AB' + registrationLabel() + '\u00BB' : 'l\u2019infrastruttura dell\u2019ambiente' }}\r\n deve <strong>prenderlo in carico</strong>. Se non c\u2019e\u2019 chi lo faccia, l\u2019attivazione non riesce\r\n anche con la definizione a posto.\r\n </p>\r\n}\r\n\r\n@if (isRecordTrigger()) {\r\n <p class=\"fb-callout\">\r\n Con un trigger su record il flow espone <code>$Record</code> e <code>$Record__Prior</code>.\r\n </p>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Oggetto che innesca</label>\r\n <fb-object-picker\r\n [value]=\"start().object\"\r\n label=\"Oggetto che innesca\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setObject($event ?? '')\"\r\n />\r\n @if (!start().object) {\r\n <p class=\"fb-field__error\">Obbligatorio con i trigger su record (START_OBJECT_MISSING).</p>\r\n }\r\n </div>\r\n\r\n <!--\r\n \u00A73.4 \u2014 **l'operazione prima, il momento dopo**: sono due campi ma non due assi liberi, e da due\r\n tendine indipendenti si dichiara \u00ABprima dell'eliminazione\u00BB insieme a \u00ABalla creazione\u00BB, che il\r\n runtime legge come un'eliminazione. Qui quella coppia non e' esprimibile.\r\n -->\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Su quale operazione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"start().recordTriggerType || ''\"\r\n (change)=\"setRecordOperation($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (type of recordTriggerTypes(); track type.value) {\r\n <option [value]=\"type.value\" [title]=\"type.description || type.label\">{{ type.label }}</option>\r\n }\r\n </select>\r\n @if (recordOperation()?.description; as description) {\r\n <p class=\"fb-field__hint\">{{ description }}</p>\r\n }\r\n @if (!start().recordTriggerType) {\r\n <!-- Avviso e non errore: il motore lo legge come \u00ABogni salvataggio\u00BB (\u00A73.4). -->\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Senza operazione il flow parte su <strong>ogni</strong> salvataggio, creazioni e\r\n aggiornamenti (START_RECORD_TRIGGER_MISSING).\r\n </p>\r\n }\r\n </div>\r\n\r\n <fb-record-filter-editor\r\n [holder]=\"$any(start())\"\r\n [object]=\"start().object\"\r\n title=\"Criteri di ingresso\"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"true\"\r\n [supportsFormula]=\"true\"\r\n emptyWarning=\"Senza criteri il flow parte su ogni record.\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n />\r\n\r\n @if (showRequireChanged()) {\r\n <!--\r\n \u00A73.4 \u2014 il \u00ABprima\u00BB da confrontare c'e' solo dove l'operazione lo porta (`usesPriorRecord`):\r\n alla creazione e all'eliminazione questo flag \u2014 e con lui l'operatore `IsChanged` \u2014 non decide\r\n nulla, quindi la domanda non si pone.\r\n -->\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"start().doesRequireRecordChangedToMeetCriteria === true\"\r\n (change)=\"setRequireChanged($any($event.target).checked)\"\r\n />\r\n Solo se il record <em>non</em> soddisfaceva i criteri prima del salvataggio\r\n </label>\r\n } @else if (start().doesRequireRecordChangedToMeetCriteria === true) {\r\n <!--\r\n Il flag c'e' ma l'operazione non ha un \u00ABprima\u00BB: arriva da un documento scritto altrove, o da\r\n un'operazione cambiata prima di questa versione dell'editor. Nasconderlo e basta lo\r\n toglierebbe dalla vista lasciandolo scritto \u2014 si dice, e la ripulitura e' un comando.\r\n E' un **avviso** e non un errore, a differenza di una condizione che legge i valori\r\n precedenti: questo il runtime lo ignora invece di fallire (\u00A77).\r\n -->\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il documento chiede che il record <strong>non</strong> soddisfacesse i criteri prima del\r\n salvataggio, ma con questa operazione non c\u2019e\u2019 un \u00ABprima\u00BB da confrontare: il motore lo ignora\r\n (PRIOR_VALUES_NOT_AVAILABLE).\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost\" (click)=\"setRequireChanged(false)\">\r\n Togli la condizione\r\n </button>\r\n </p>\r\n }\r\n\r\n <!--\r\n Il momento e' l'**ultima** domanda, e sta qui solo dove la tendina in cima non c'e': nel ripiego\r\n il `triggerType` lo governa quella, e due controlli sullo stesso campo si contraddicono a vista.\r\n -->\r\n @if (isRecordFlowType()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">In che momento</label>\r\n @if (showTimingChoice()) {\r\n <select class=\"fb-select\" [fbValue]=\"triggerType()\" (change)=\"setTriggerType($any($event.target).value)\">\r\n @for (timing of timingOptions(); track timing.value) {\r\n <option [value]=\"timing.value\" [title]=\"timing.description || timing.label\">{{ timing.label }}</option>\r\n }\r\n </select>\r\n @if (currentTiming()?.description; as description) {\r\n <p class=\"fb-field__hint\">{{ description }}</p>\r\n }\r\n } @else {\r\n <!--\r\n Momento unico (`allowsTimingChoice: false`, l'eliminazione): la domanda non si pone, ma il\r\n campo si scrive lo stesso \u2014 il contratto chiede **entrambi**.\r\n -->\r\n <p class=\"fb-field__hint\">\r\n <strong>{{ currentTiming()?.label || triggerType() }}</strong> \u2014 con questa operazione e\u2019\r\n l\u2019unico momento possibile, e viene scritto comunque nel documento.\r\n </p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (hasTriggerMismatch()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n L\u2019operazione e il momento scritti nel documento non stanno insieme (START_TRIGGER_MISMATCH):\r\n il flow parte su un\u2019operazione diversa da quella scelta, e l\u2019attivazione non riesce.\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost\" (click)=\"useDefaultTiming()\">\r\n Riporta il momento fra quelli ammessi\r\n </button>\r\n </p>\r\n }\r\n}\r\n\r\n@if (isScheduled()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Pianificazione</legend>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Frequenza</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"start().schedule?.frequency || ''\"\r\n (change)=\"setFrequency($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (frequency of frequencies(); track frequency.value) {\r\n <option [value]=\"frequency.value\">{{ frequency.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Data di inizio</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"date\"\r\n [value]=\"startDateValue()\"\r\n (input)=\"setStartDate($any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Ora</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"time\"\r\n [value]=\"startTimeValue()\"\r\n (input)=\"setStartTime($any($event.target).value)\"\r\n />\r\n </div>\r\n </div>\r\n @if (!start().schedule?.frequency) {\r\n <p class=\"fb-field__error\">La pianificazione e\u2019 obbligatoria con questo trigger (START_SCHEDULE_MISSING).</p>\r\n }\r\n </fieldset>\r\n\r\n <!--\r\n \u00A73.4 \u2014 su uno schedulato l'oggetto e' **facoltativo** e vuol dire un'altra cosa che sui trigger\r\n su record: non \u00ABl'entita' che innesca\u00BB ma \u00ABun'esecuzione per ogni record che soddisfa i filtri\u00BB.\r\n Senza, il flow gira una volta sola.\r\n -->\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Un\u2019esecuzione per record</legend>\r\n <p class=\"fb-section__note\">\r\n Facoltativo. Indicando un\u2019entita\u2019, il flow gira <strong>una volta per ogni record</strong> che\r\n soddisfa i filtri invece di una volta sola.\r\n </p>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Entita\u2019</label>\r\n <fb-object-picker\r\n [value]=\"start().object\"\r\n label=\"Entita\u2019\"\r\n placeholder=\"Nessuna: una sola esecuzione\"\r\n (valueChange)=\"setObject($event ?? '')\"\r\n />\r\n </div>\r\n @if (start().object) {\r\n <fb-record-filter-editor\r\n [holder]=\"$any(start())\"\r\n [object]=\"start().object\"\r\n title=\"Quali record\"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"true\"\r\n [supportsFormula]=\"true\"\r\n emptyWarning=\"Senza criteri il flow gira su ogni record dell\u2019entita\u2019.\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n />\r\n }\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Percorsi differiti</legend>\r\n <p class=\"fb-section__note\">\r\n Ogni percorso e\u2019 un ramo che parte dopo un intervallo, calcolato da un istante di riferimento.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (path of scheduledPaths(); 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 percorso\"\r\n (click)=\"removeScheduledPath($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</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"path.label || ''\"\r\n (input)=\"setPathField($index, '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\">Nome tecnico</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"path.name || ''\"\r\n (input)=\"setPathField($index, 'name', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Dopo</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n [value]=\"path.offsetNumber ?? ''\"\r\n (input)=\"setPathOffsetNumber($index, $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]=\"path.offsetUnit || ''\"\r\n (change)=\"setPathField($index, 'offsetUnit', $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 <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Istante di riferimento</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"path.timeSource || ''\"\r\n placeholder=\"Es. RecordTriggerEvent\"\r\n (input)=\"setPathField($index, 'timeSource', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo data del record</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"path.recordField || ''\"\r\n (input)=\"setPathField($index, 'recordField', $any($event.target).value)\"\r\n />\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun percorso differito.</p>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addScheduledPath()\">Aggiungi percorso</button>\r\n </fieldset>\r\n}\r\n\r\n@if (triggerType() === 'None') {\r\n <p class=\"fb-field__hint\">\r\n Il flow parte solo su richiesta. I valori iniziali si passano nelle variabili di input.\r\n </p>\r\n}\r\n\r\n@if (isEvent()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Evento</legend>\r\n <p class=\"fb-section__note\">\r\n Il flow parte alla ricezione di un evento: e\u2019 a questo che l\u2019host si sottoscrive quando la\r\n versione viene attivata (\u00A78).\r\n </p>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo di evento</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"start().eventType || ''\"\r\n placeholder=\"Es. OrdineEvaso\"\r\n (input)=\"setEventField('eventType', $any($event.target).value)\"\r\n />\r\n @if (!start().eventType) {\r\n <p class=\"fb-field__error\">Obbligatorio con questo trigger (START_EVENT_MISSING).</p>\r\n }\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Nome dell\u2019evento</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"start().eventName || ''\"\r\n (input)=\"setEventField('eventName', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">Facoltativo: serve dove il tipo da solo non identifica l\u2019evento.</p>\r\n </div>\r\n </fieldset>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"'$start'\"\r\n [node]=\"startNode()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Da dove comincia\"\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: 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: "directive", type: SelectValueDirective, selector: "select[fbValue]", inputs: ["fbValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
14449
14871
|
}
|
|
14450
14872
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: StartInspectorComponent, decorators: [{
|
|
14451
14873
|
type: Component,
|
|
@@ -14454,7 +14876,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
14454
14876
|
ObjectPickerComponent,
|
|
14455
14877
|
RecordFilterEditorComponent,
|
|
14456
14878
|
SelectValueDirective,
|
|
14457
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!hasEntryPoint()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Lo Start non punta a nessun elemento: il flow non ha un punto di ingresso e non e\u2019 eseguibile\r\n (START_NO_ENTRY_POINT).\r\n </p>\r\n}\r\n\r\n<div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Quando parte</label>\r\n <!--\r\n \u00A73.4 \u2014 i trigger sono quelli del **tipo di flow** scelto alla creazione, non tutti: la coppia\r\n `processType` + `triggerType` **e'** il tipo, e cambiarla qui vorrebbe dire cambiarlo.\r\n -->\r\n <select class=\"fb-select\" [fbValue]=\"triggerType()\" (change)=\"setTriggerType($any($event.target).value)\">\r\n @for (trigger of triggerTypes(); track trigger.value) {\r\n <option [value]=\"trigger.value\">{{ trigger.label }}</option>\r\n }\r\n </select>\r\n @if (flowType(); as type) {\r\n <p class=\"fb-field__hint\">\r\n Tipo di flow: <strong>{{ type.label }}</strong\r\n >{{ type.description ? ' \u2014 ' + type.description : '' }}\r\n </p>\r\n }\r\n @if (requiresRegistration()) {\r\n <!--\r\n \u00A78 \u2014 l'unico caso in cui una definizione **valida** puo' non essere attivabile: il flow non\r\n parte da solo, e l'infrastruttura dell'ospite deve prenderlo in carico. Dirlo qui, dove si\r\n sceglie il trigger, e' dirlo prima che l'attivazione fallisca.\r\n -->\r\n <p class=\"fb-callout\">\r\n Questo flow non parte da solo: attivandolo,\r\n {{ registrationLabel() ? 'il servizio \u00AB' + registrationLabel() + '\u00BB' : 'l\u2019infrastruttura dell\u2019ambiente' }}\r\n deve <strong>prenderlo in carico</strong>. Se non c\u2019e\u2019 chi lo faccia, l\u2019attivazione non riesce\r\n anche con la definizione a posto.\r\n </p>\r\n }\r\n</div>\r\n\r\n@if (isRecordTrigger()) {\r\n <p class=\"fb-callout\">\r\n Con un trigger su record il flow espone <code>$Record</code> e <code>$Record__Prior</code>.\r\n </p>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Oggetto che innesca</label>\r\n <fb-object-picker\r\n [value]=\"start().object\"\r\n label=\"Oggetto che innesca\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setObject($event ?? '')\"\r\n />\r\n @if (!start().object) {\r\n <p class=\"fb-field__error\">Obbligatorio con i trigger su record (START_OBJECT_MISSING).</p>\r\n }\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Su quale operazione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"start().recordTriggerType || ''\"\r\n (change)=\"setRecordTriggerType($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (type of recordTriggerTypes(); track type.value) {\r\n <option [value]=\"type.value\">{{ type.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n <fb-record-filter-editor\r\n [holder]=\"$any(start())\"\r\n [object]=\"start().object\"\r\n title=\"Criteri di ingresso\"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"true\"\r\n [supportsFormula]=\"true\"\r\n emptyWarning=\"Senza criteri il flow parte su ogni record.\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n />\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"start().doesRequireRecordChangedToMeetCriteria === true\"\r\n (change)=\"setRequireChanged($any($event.target).checked)\"\r\n />\r\n Solo se il record <em>non</em> soddisfaceva i criteri prima del salvataggio\r\n </label>\r\n}\r\n\r\n@if (isScheduled()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Pianificazione</legend>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Frequenza</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"start().schedule?.frequency || ''\"\r\n (change)=\"setFrequency($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (frequency of frequencies(); track frequency.value) {\r\n <option [value]=\"frequency.value\">{{ frequency.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Data di inizio</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"date\"\r\n [value]=\"startDateValue()\"\r\n (input)=\"setStartDate($any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Ora</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"time\"\r\n [value]=\"startTimeValue()\"\r\n (input)=\"setStartTime($any($event.target).value)\"\r\n />\r\n </div>\r\n </div>\r\n @if (!start().schedule?.frequency) {\r\n <p class=\"fb-field__error\">La pianificazione e\u2019 obbligatoria con questo trigger (START_SCHEDULE_MISSING).</p>\r\n }\r\n </fieldset>\r\n\r\n <!--\r\n \u00A73.4 \u2014 su uno schedulato l'oggetto e' **facoltativo** e vuol dire un'altra cosa che sui trigger\r\n su record: non \u00ABl'entita' che innesca\u00BB ma \u00ABun'esecuzione per ogni record che soddisfa i filtri\u00BB.\r\n Senza, il flow gira una volta sola.\r\n -->\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Un\u2019esecuzione per record</legend>\r\n <p class=\"fb-section__note\">\r\n Facoltativo. Indicando un\u2019entita\u2019, il flow gira <strong>una volta per ogni record</strong> che\r\n soddisfa i filtri invece di una volta sola.\r\n </p>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Entita\u2019</label>\r\n <fb-object-picker\r\n [value]=\"start().object\"\r\n label=\"Entita\u2019\"\r\n placeholder=\"Nessuna: una sola esecuzione\"\r\n (valueChange)=\"setObject($event ?? '')\"\r\n />\r\n </div>\r\n @if (start().object) {\r\n <fb-record-filter-editor\r\n [holder]=\"$any(start())\"\r\n [object]=\"start().object\"\r\n title=\"Quali record\"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"true\"\r\n [supportsFormula]=\"true\"\r\n emptyWarning=\"Senza criteri il flow gira su ogni record dell\u2019entita\u2019.\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n />\r\n }\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Percorsi differiti</legend>\r\n <p class=\"fb-section__note\">\r\n Ogni percorso e\u2019 un ramo che parte dopo un intervallo, calcolato da un istante di riferimento.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (path of scheduledPaths(); 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 percorso\"\r\n (click)=\"removeScheduledPath($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</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"path.label || ''\"\r\n (input)=\"setPathField($index, '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\">Nome tecnico</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"path.name || ''\"\r\n (input)=\"setPathField($index, 'name', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Dopo</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n [value]=\"path.offsetNumber ?? ''\"\r\n (input)=\"setPathOffsetNumber($index, $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]=\"path.offsetUnit || ''\"\r\n (change)=\"setPathField($index, 'offsetUnit', $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 <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Istante di riferimento</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"path.timeSource || ''\"\r\n placeholder=\"Es. RecordTriggerEvent\"\r\n (input)=\"setPathField($index, 'timeSource', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo data del record</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"path.recordField || ''\"\r\n (input)=\"setPathField($index, 'recordField', $any($event.target).value)\"\r\n />\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun percorso differito.</p>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addScheduledPath()\">Aggiungi percorso</button>\r\n </fieldset>\r\n}\r\n\r\n@if (triggerType() === 'None') {\r\n <p class=\"fb-field__hint\">\r\n Il flow parte solo su richiesta. I valori iniziali si passano nelle variabili di input.\r\n </p>\r\n}\r\n\r\n@if (isEvent()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Evento</legend>\r\n <p class=\"fb-section__note\">\r\n Il flow parte alla ricezione di un evento: e\u2019 a questo che l\u2019host si sottoscrive quando la\r\n versione viene attivata (\u00A78).\r\n </p>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo di evento</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"start().eventType || ''\"\r\n placeholder=\"Es. OrdineEvaso\"\r\n (input)=\"setEventField('eventType', $any($event.target).value)\"\r\n />\r\n @if (!start().eventType) {\r\n <p class=\"fb-field__error\">Obbligatorio con questo trigger (START_EVENT_MISSING).</p>\r\n }\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Nome dell\u2019evento</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"start().eventName || ''\"\r\n (input)=\"setEventField('eventName', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">Facoltativo: serve dove il tipo da solo non identifica l\u2019evento.</p>\r\n </div>\r\n </fieldset>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"'$start'\"\r\n [node]=\"startNode()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Da dove comincia\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n" }]
|
|
14879
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!hasEntryPoint()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n Lo Start non punta a nessun elemento: il flow non ha un punto di ingresso e non e\u2019 eseguibile\r\n (START_NO_ENTRY_POINT).\r\n </p>\r\n}\r\n\r\n<!--\r\n \u00A73.4 \u2014 su un flow innescato da un record la tendina non c'e': i suoi tre valori sono il *momento*,\r\n e il momento e' l'ultima domanda della sequenza qui sotto, posta fra i soli momenti che\r\n l'operazione scelta ammette. Altrove i trigger sono quelli del **tipo di flow** scelto alla\r\n creazione, non tutti: la coppia `processType` + `triggerType` **e'** il tipo, e cambiarla qui\r\n vorrebbe dire cambiarlo.\r\n-->\r\n@if (!isRecordFlowType()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Quando parte</label>\r\n <select class=\"fb-select\" [fbValue]=\"triggerType()\" (change)=\"setTriggerType($any($event.target).value)\">\r\n @for (trigger of triggerTypes(); track trigger.value) {\r\n <option [value]=\"trigger.value\">{{ trigger.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n}\r\n\r\n@if (flowType(); as type) {\r\n <p class=\"fb-field__hint\">\r\n Tipo di flow: <strong>{{ type.label }}</strong\r\n >{{ type.description ? ' \u2014 ' + type.description : '' }}\r\n </p>\r\n}\r\n@if (requiresRegistration()) {\r\n <!--\r\n \u00A78 \u2014 l'unico caso in cui una definizione **valida** puo' non essere attivabile: il flow non\r\n parte da solo, e l'infrastruttura dell'ospite deve prenderlo in carico. Dirlo qui, dove si\r\n sceglie il trigger, e' dirlo prima che l'attivazione fallisca.\r\n -->\r\n <p class=\"fb-callout\">\r\n Questo flow non parte da solo: attivandolo,\r\n {{ registrationLabel() ? 'il servizio \u00AB' + registrationLabel() + '\u00BB' : 'l\u2019infrastruttura dell\u2019ambiente' }}\r\n deve <strong>prenderlo in carico</strong>. Se non c\u2019e\u2019 chi lo faccia, l\u2019attivazione non riesce\r\n anche con la definizione a posto.\r\n </p>\r\n}\r\n\r\n@if (isRecordTrigger()) {\r\n <p class=\"fb-callout\">\r\n Con un trigger su record il flow espone <code>$Record</code> e <code>$Record__Prior</code>.\r\n </p>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Oggetto che innesca</label>\r\n <fb-object-picker\r\n [value]=\"start().object\"\r\n label=\"Oggetto che innesca\"\r\n placeholder=\"Scrivi o scegli un oggetto\"\r\n (valueChange)=\"setObject($event ?? '')\"\r\n />\r\n @if (!start().object) {\r\n <p class=\"fb-field__error\">Obbligatorio con i trigger su record (START_OBJECT_MISSING).</p>\r\n }\r\n </div>\r\n\r\n <!--\r\n \u00A73.4 \u2014 **l'operazione prima, il momento dopo**: sono due campi ma non due assi liberi, e da due\r\n tendine indipendenti si dichiara \u00ABprima dell'eliminazione\u00BB insieme a \u00ABalla creazione\u00BB, che il\r\n runtime legge come un'eliminazione. Qui quella coppia non e' esprimibile.\r\n -->\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Su quale operazione</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"start().recordTriggerType || ''\"\r\n (change)=\"setRecordOperation($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (type of recordTriggerTypes(); track type.value) {\r\n <option [value]=\"type.value\" [title]=\"type.description || type.label\">{{ type.label }}</option>\r\n }\r\n </select>\r\n @if (recordOperation()?.description; as description) {\r\n <p class=\"fb-field__hint\">{{ description }}</p>\r\n }\r\n @if (!start().recordTriggerType) {\r\n <!-- Avviso e non errore: il motore lo legge come \u00ABogni salvataggio\u00BB (\u00A73.4). -->\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Senza operazione il flow parte su <strong>ogni</strong> salvataggio, creazioni e\r\n aggiornamenti (START_RECORD_TRIGGER_MISSING).\r\n </p>\r\n }\r\n </div>\r\n\r\n <fb-record-filter-editor\r\n [holder]=\"$any(start())\"\r\n [object]=\"start().object\"\r\n title=\"Criteri di ingresso\"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"true\"\r\n [supportsFormula]=\"true\"\r\n emptyWarning=\"Senza criteri il flow parte su ogni record.\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n />\r\n\r\n @if (showRequireChanged()) {\r\n <!--\r\n \u00A73.4 \u2014 il \u00ABprima\u00BB da confrontare c'e' solo dove l'operazione lo porta (`usesPriorRecord`):\r\n alla creazione e all'eliminazione questo flag \u2014 e con lui l'operatore `IsChanged` \u2014 non decide\r\n nulla, quindi la domanda non si pone.\r\n -->\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"start().doesRequireRecordChangedToMeetCriteria === true\"\r\n (change)=\"setRequireChanged($any($event.target).checked)\"\r\n />\r\n Solo se il record <em>non</em> soddisfaceva i criteri prima del salvataggio\r\n </label>\r\n } @else if (start().doesRequireRecordChangedToMeetCriteria === true) {\r\n <!--\r\n Il flag c'e' ma l'operazione non ha un \u00ABprima\u00BB: arriva da un documento scritto altrove, o da\r\n un'operazione cambiata prima di questa versione dell'editor. Nasconderlo e basta lo\r\n toglierebbe dalla vista lasciandolo scritto \u2014 si dice, e la ripulitura e' un comando.\r\n E' un **avviso** e non un errore, a differenza di una condizione che legge i valori\r\n precedenti: questo il runtime lo ignora invece di fallire (\u00A77).\r\n -->\r\n <p class=\"fb-callout fb-callout--warn\">\r\n Il documento chiede che il record <strong>non</strong> soddisfacesse i criteri prima del\r\n salvataggio, ma con questa operazione non c\u2019e\u2019 un \u00ABprima\u00BB da confrontare: il motore lo ignora\r\n (PRIOR_VALUES_NOT_AVAILABLE).\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost\" (click)=\"setRequireChanged(false)\">\r\n Togli la condizione\r\n </button>\r\n </p>\r\n }\r\n\r\n <!--\r\n Il momento e' l'**ultima** domanda, e sta qui solo dove la tendina in cima non c'e': nel ripiego\r\n il `triggerType` lo governa quella, e due controlli sullo stesso campo si contraddicono a vista.\r\n -->\r\n @if (isRecordFlowType()) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">In che momento</label>\r\n @if (showTimingChoice()) {\r\n <select class=\"fb-select\" [fbValue]=\"triggerType()\" (change)=\"setTriggerType($any($event.target).value)\">\r\n @for (timing of timingOptions(); track timing.value) {\r\n <option [value]=\"timing.value\" [title]=\"timing.description || timing.label\">{{ timing.label }}</option>\r\n }\r\n </select>\r\n @if (currentTiming()?.description; as description) {\r\n <p class=\"fb-field__hint\">{{ description }}</p>\r\n }\r\n } @else {\r\n <!--\r\n Momento unico (`allowsTimingChoice: false`, l'eliminazione): la domanda non si pone, ma il\r\n campo si scrive lo stesso \u2014 il contratto chiede **entrambi**.\r\n -->\r\n <p class=\"fb-field__hint\">\r\n <strong>{{ currentTiming()?.label || triggerType() }}</strong> \u2014 con questa operazione e\u2019\r\n l\u2019unico momento possibile, e viene scritto comunque nel documento.\r\n </p>\r\n }\r\n </div>\r\n }\r\n\r\n @if (hasTriggerMismatch()) {\r\n <p class=\"fb-callout fb-callout--error\">\r\n L\u2019operazione e il momento scritti nel documento non stanno insieme (START_TRIGGER_MISMATCH):\r\n il flow parte su un\u2019operazione diversa da quella scelta, e l\u2019attivazione non riesce.\r\n <button type=\"button\" class=\"fb-btn fb-btn--ghost\" (click)=\"useDefaultTiming()\">\r\n Riporta il momento fra quelli ammessi\r\n </button>\r\n </p>\r\n }\r\n}\r\n\r\n@if (isScheduled()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Pianificazione</legend>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Frequenza</label>\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"start().schedule?.frequency || ''\"\r\n (change)=\"setFrequency($any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 scegli \u2014</option>\r\n @for (frequency of frequencies(); track frequency.value) {\r\n <option [value]=\"frequency.value\">{{ frequency.label }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Data di inizio</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"date\"\r\n [value]=\"startDateValue()\"\r\n (input)=\"setStartDate($any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Ora</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"time\"\r\n [value]=\"startTimeValue()\"\r\n (input)=\"setStartTime($any($event.target).value)\"\r\n />\r\n </div>\r\n </div>\r\n @if (!start().schedule?.frequency) {\r\n <p class=\"fb-field__error\">La pianificazione e\u2019 obbligatoria con questo trigger (START_SCHEDULE_MISSING).</p>\r\n }\r\n </fieldset>\r\n\r\n <!--\r\n \u00A73.4 \u2014 su uno schedulato l'oggetto e' **facoltativo** e vuol dire un'altra cosa che sui trigger\r\n su record: non \u00ABl'entita' che innesca\u00BB ma \u00ABun'esecuzione per ogni record che soddisfa i filtri\u00BB.\r\n Senza, il flow gira una volta sola.\r\n -->\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Un\u2019esecuzione per record</legend>\r\n <p class=\"fb-section__note\">\r\n Facoltativo. Indicando un\u2019entita\u2019, il flow gira <strong>una volta per ogni record</strong> che\r\n soddisfa i filtri invece di una volta sola.\r\n </p>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Entita\u2019</label>\r\n <fb-object-picker\r\n [value]=\"start().object\"\r\n label=\"Entita\u2019\"\r\n placeholder=\"Nessuna: una sola esecuzione\"\r\n (valueChange)=\"setObject($event ?? '')\"\r\n />\r\n </div>\r\n @if (start().object) {\r\n <fb-record-filter-editor\r\n [holder]=\"$any(start())\"\r\n [object]=\"start().object\"\r\n title=\"Quali record\"\r\n usage=\"filterable\"\r\n [supportsLogic]=\"true\"\r\n [supportsFormula]=\"true\"\r\n emptyWarning=\"Senza criteri il flow gira su ogni record dell\u2019entita\u2019.\"\r\n (changed)=\"onFiltersChanged($event)\"\r\n />\r\n }\r\n </fieldset>\r\n\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Percorsi differiti</legend>\r\n <p class=\"fb-section__note\">\r\n Ogni percorso e\u2019 un ramo che parte dopo un intervallo, calcolato da un istante di riferimento.\r\n </p>\r\n\r\n <div class=\"fb-list\">\r\n @for (path of scheduledPaths(); 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 percorso\"\r\n (click)=\"removeScheduledPath($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</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"path.label || ''\"\r\n (input)=\"setPathField($index, '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\">Nome tecnico</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"path.name || ''\"\r\n (input)=\"setPathField($index, 'name', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field__row\">\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Dopo</label>\r\n <input\r\n class=\"fb-input\"\r\n type=\"number\"\r\n [value]=\"path.offsetNumber ?? ''\"\r\n (input)=\"setPathOffsetNumber($index, $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]=\"path.offsetUnit || ''\"\r\n (change)=\"setPathField($index, 'offsetUnit', $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 <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Istante di riferimento</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"path.timeSource || ''\"\r\n placeholder=\"Es. RecordTriggerEvent\"\r\n (input)=\"setPathField($index, 'timeSource', $any($event.target).value)\"\r\n />\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Campo data del record</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"path.recordField || ''\"\r\n (input)=\"setPathField($index, 'recordField', $any($event.target).value)\"\r\n />\r\n </div>\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">Nessun percorso differito.</p>\r\n }\r\n </div>\r\n <button type=\"button\" class=\"fb-btn\" (click)=\"addScheduledPath()\">Aggiungi percorso</button>\r\n </fieldset>\r\n}\r\n\r\n@if (triggerType() === 'None') {\r\n <p class=\"fb-field__hint\">\r\n Il flow parte solo su richiesta. I valori iniziali si passano nelle variabili di input.\r\n </p>\r\n}\r\n\r\n@if (isEvent()) {\r\n <fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">Evento</legend>\r\n <p class=\"fb-section__note\">\r\n Il flow parte alla ricezione di un evento: e\u2019 a questo che l\u2019host si sottoscrive quando la\r\n versione viene attivata (\u00A78).\r\n </p>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Tipo di evento</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"start().eventType || ''\"\r\n placeholder=\"Es. OrdineEvaso\"\r\n (input)=\"setEventField('eventType', $any($event.target).value)\"\r\n />\r\n @if (!start().eventType) {\r\n <p class=\"fb-field__error\">Obbligatorio con questo trigger (START_EVENT_MISSING).</p>\r\n }\r\n </div>\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\">Nome dell\u2019evento</label>\r\n <input\r\n class=\"fb-input fb-input--mono\"\r\n [value]=\"start().eventName || ''\"\r\n (input)=\"setEventField('eventName', $any($event.target).value)\"\r\n />\r\n <p class=\"fb-field__hint\">Facoltativo: serve dove il tipo da solo non identifica l\u2019evento.</p>\r\n </div>\r\n </fieldset>\r\n}\r\n\r\n<fb-connector-editor\r\n [nodeName]=\"'$start'\"\r\n [node]=\"startNode()\"\r\n [outlets]=\"outlets()\"\r\n title=\"Da dove comincia\"\r\n (connectorChanged)=\"onConnectorChanged($event)\"\r\n/>\r\n" }]
|
|
14458
14880
|
}] });
|
|
14459
14881
|
|
|
14460
14882
|
/**
|
|
@@ -19529,5 +19951,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
19529
19951
|
* Generated bundle index. Do not edit.
|
|
19530
19952
|
*/
|
|
19531
19953
|
|
|
19532
|
-
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, describeActivationError, 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, isRegistrationError, isTypeCheckedOperator, isUnknownEnumChoiceSetField, isValidFlowName, isValued, isVersionActive, 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 };
|
|
19954
|
+
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, PRIOR_VALUES_OPERATOR, PRIOR_VALUES_SCOPE, ParameterEditorComponent, PasteDialogComponent, ProblemsPanelComponent, RECORD_TRIGGERS, 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, describeActivationError, describeFieldPath, describePathEntry, describePriorValues, duplicateField, elementIcon, emptyFlowDefinition, enumChoiceSetFieldType, fieldAt, filterReferences, flattenFields, flowNodeWidth, flowNodeWidthClass, foldSourceConnectorId, foldTargetConnectorId, groupColorClass, groupRect, hasAutoSize, innerNamesOf, insertField, isClipboardPayload, isCustomConditionLogic, isEmptyReferenceFilter, isFieldResource, isFoldReference, isGlobalReference, isNumericType, isPathInside, isRecordTrigger, isRegistrationError, isTypeCheckedOperator, isUnknownEnumChoiceSetField, isValidFlowName, isValued, isVersionActive, loadPathLevel, matchesReferenceFilter, membersInside, moveCondition, moveField, navigatePath, otherSourceFieldsOf, outletByKey, outletsOf, parseCanvasFoldId, parseCanvasGroupId, parseCanvasNodeId, parseFieldPath, parseInvariantNumber, parseSourceConnectorId, parseTargetConnectorId, pathAvailableNames, pathContainerLabel, pathKey, pathNotVerifiableMessage, planPaste, priorCriteriaSeverity, priorValuesAvailability, priorValuesOfDefinition, priorValuesProposable, priorValuesSeverity, readsPriorValues, 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 };
|
|
19533
19955
|
//# sourceMappingURL=esfaenza-flow-builder.mjs.map
|