@esfaenza/flow-builder 20.3.39 → 20.3.40
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 +24 -1
- package/fesm2022/esfaenza-flow-builder.mjs +362 -9
- package/fesm2022/esfaenza-flow-builder.mjs.map +1 -1
- package/index.d.ts +118 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -489,6 +489,16 @@ sapere: le globali sono di sola lettura, membri compresi — le assegnabili sono
|
|
|
489
489
|
`$Flow.ActiveStages` e i campi di `$Record` — e il picker lo dice con `TARGET_NOT_WRITABLE` invece
|
|
490
490
|
di far sembrare il nome inesistente (§5.2).
|
|
491
491
|
|
|
492
|
+
**Uno scope puo' nominarsi da solo.** `$Profile` senza percorso e' un riferimento valido se — e solo
|
|
493
|
+
se — l'host lo dichiara così, con una voce **senza punto** che porta il suo `dataType` e il suo
|
|
494
|
+
`objectType` (§4.1): e' come un host espone l'utente corrente come un'unica istanza invece di
|
|
495
|
+
elencarne i campi, e da lì la navigazione riparte, quindi `$Profile.Livello` si verifica sui membri
|
|
496
|
+
della classe senza che il catalogo dichiari un percorso per ognuno. Il prefisso dichiarato piu' lungo
|
|
497
|
+
e' la stessa regola di prima: la voce senza punto e' il prefisso **vuoto**, cioe' quello che vince
|
|
498
|
+
solo quando nessun altro corrisponde. Dove lo scope dichiara percorsi ma non la voce senza punto,
|
|
499
|
+
`$Profile` da solo resta `GLOBAL_UNKNOWN`: nella demo e' la differenza fra `$Profile` (dichiarato
|
|
500
|
+
così) e `$User` (che dichiara i suoi campi).
|
|
501
|
+
|
|
492
502
|
Su una destinazione la colonna che decide non e' la stessa nei due mondi: un membro porta il proprio
|
|
493
503
|
`isWritable`, un campo no. Fuori da un Create o da un Update il contesto non c'e' — un Assignment su
|
|
494
504
|
`Cliente.Codice` non sa se quel record verra' creato o aggiornato — quindi lì basta `isCreateable`
|
|
@@ -575,6 +585,19 @@ aggiunte. Tre esiti restano distinti e nessuno dei tre e' «formula valida»: pr
|
|
|
575
585
|
stata controllata), `isValid` (verificata davvero, ed e' l'unico caso con la spunta verde) — una
|
|
576
586
|
spunta su un'espressione mai controllata e' peggio di nessuna spunta.
|
|
577
587
|
|
|
588
|
+
**Testo con merge field (§5.12).** Il messaggio di un Custom Error non e' una casella di testo
|
|
589
|
+
qualunque: supporta i segnaposto `{!...}` come il testo di un text template e le scritte di uno screen
|
|
590
|
+
dinamico, e lì servono piu' che altrove — *«L'ordine e' già stato evaso»* senza il numero dell'ordine e'
|
|
591
|
+
meta' messaggio. Lo monta `<fb-merge-text-editor>`, ed e' un componente diverso dall'editor di formule
|
|
592
|
+
perche' il contenuto e' diverso: qui c'e' una **frase**, con dentro delle isole. Tre conseguenze. Offre
|
|
593
|
+
l'**inserimento** di un riferimento (un bottone con l'elenco, piu' i suggerimenti mentre si scrive dentro
|
|
594
|
+
un `{!` aperto), e scrive l'isola intera, graffe comprese: la sintassi non deve stare a memoria. Manda il
|
|
595
|
+
testo al motore **solo se contiene `{!`**, perche' una frase in italiano mandata a un motore di
|
|
596
|
+
espressioni si farebbe accusare parola per parola. E gli esiti restano i tre delle formule, con la stessa
|
|
597
|
+
regola: nessuna spunta su un testo che nessuno ha guardato. Lo stesso controllo avviene nella validazione
|
|
598
|
+
del documento, con `usage: "Text"` e il rilievo sul path `customErrorMessages[n].errorMessage`: un refuso
|
|
599
|
+
dentro una graffa non si scopre davanti a chi sta usando il flow.
|
|
600
|
+
|
|
578
601
|
**Un campo a `null` e' assente.** Il valore ha un campo per tipo e va valorizzato **uno e un solo**
|
|
579
602
|
campo (§4.2); la §2 dice che cio' che non c'e' si omette, ma un backend che serializza tutte le
|
|
580
603
|
proprieta' — `System.Text.Json` senza `IgnoreNullValues` lo fa di default — manda
|
|
@@ -849,7 +872,7 @@ distribuire e nessuna dipendenza da un font di icone dell'applicazione ospite.
|
|
|
849
872
|
| 13 | **Testo e numero non si confrontano** (`CONDITION_TYPE_MISMATCH`) | `ConditionEditorComponent` conosce il tipo del lato sinistro da `POST /flows/references`: filtra gli operatori applicabili, guida il campo del letterale del secondo operando e segnala la coppia vietata. La regola sta in `core/condition-types.util.ts`, che salta gli operatori con semantica propria (`Contains`, `In`, …). I numeri si scrivono in cultura invariante: `1234,50` viene tradotto in `1234.50`, non troncato |
|
|
850
873
|
| 14 | **`None` non e' un operatore, e' un "da completare"** | Condizione evidenziata come incompleta, con il conteggio in testa alla sezione e la frase «la bozza si salva, l'attivazione no»; il validatore della demo lo emette come **errore** |
|
|
851
874
|
| 15 | **Un valore data senza `Z` significa ora locale** | `ValueEditorComponent` ha un selettore «Ora locale / UTC (Z)», dice che cambiare fuso riscrive l'orario e non lo converte, e toglie il suffisso solo per il controllo `datetime-local`, che con il fuso resterebbe vuoto |
|
|
852
|
-
| 16 | **`Structure` e `Object` non sono intercambiabili** | `StructurePickerComponent` per la classe (fuori catalogo = **errore**, `STRUCTURE_TYPE_UNKNOWN`) e `StructureMemberPickerComponent` per i membri, filtrati su `isWritable` dove serve una destinazione. Il pannello risorse mostra la classe come obbligatoria con severita' di errore e **non** mostra il valore iniziale, perche' un `structureValue` non esiste; `ReferencePickerComponent` propone `Variabile.Membro` e verifica il percorso **fino in fondo** con `core/path-navigation.ts`, con `PATH_NOT_VERIFIABLE` dove la catena si interrompe; il Transform con target classe chiede un membro invece di un campo. `FlowDictionaryStore.isStructure` legge il flag dal dizionario, non dal nome del tipo. La risposta dei membri e' la **descrizione della classe** (`{className, label, members}`), e i suoi tre esiti restano distinti fino alla UI: `FlowCatalogStore.describeStructure` li traduce in `declared` / `undeclared` / `unknown-class` / `unknown-catalog`, e solo `declared` autorizza a dire che un membro non esiste (§4.7.1) |
|
|
875
|
+
| 16 | **`Structure` e `Object` non sono intercambiabili** | `StructurePickerComponent` per la classe (fuori catalogo = **errore**, `STRUCTURE_TYPE_UNKNOWN`) e `StructureMemberPickerComponent` per i membri, filtrati su `isWritable` **soltanto** con `usage="writable"`, cioe' dove serve una destinazione: un membro calcolato si legge — in una condizione, in una formula, in un valore — e filtrarlo ovunque renderebbe invisibili proprio i membri derivati (§13.16). Il pannello risorse mostra la classe come obbligatoria con severita' di errore e **non** mostra il valore iniziale, perche' un `structureValue` non esiste; `ReferencePickerComponent` propone `Variabile.Membro` e verifica il percorso **fino in fondo** con `core/path-navigation.ts`, con `PATH_NOT_VERIFIABLE` dove la catena si interrompe; il Transform con target classe chiede un membro invece di un campo. `FlowDictionaryStore.isStructure` legge il flag dal dizionario, non dal nome del tipo. La risposta dei membri e' la **descrizione della classe** (`{className, label, members}`), e i suoi tre esiti restano distinti fino alla UI: `FlowCatalogStore.describeStructure` li traduce in `declared` / `undeclared` / `unknown-class` / `unknown-catalog`, e solo `declared` autorizza a dire che un membro non esiste (§4.7.1) |
|
|
853
876
|
| 17 | **Due body diversi per due famiglie di primitive** | `HttpFlowBuilderApi`: le primitive che **analizzano** il documento — `validate`, `parse`, `references`, `references/writable`, `connector-targets`, `outline` — lo mandano **nudo alla radice**; l'involucro `{definition, flowName, …}` resta alle sole primitive di scrittura della §6.2. Sbagliare involucro non da' nessun errore: il backend legge un flow vuoto e risponde `200`. Per lo stesso motivo `getReferences`/`getWritableReferences` prendono la `FlowDefinition` e non un oggetto query: non c'e' nessun campo di filtro nel body, e il filtro di tipo lo applica l'editor con `core/reference-filter.util.ts` |
|
|
854
877
|
| 18 | **Gli enum si scrivono come stringhe** | Il modello e' fatto di unioni di stringhe letterali (`FlowDataType`, `FlowVersionStatus`, …) e non di enum numerici: `JSON.stringify` non ha modo di produrre un ordinale. Conta perche' `"status": 3` non e' `Draft` ma `InvalidDraft` e `"dataType": 0` e' `String`, non "non specificato" — nessun errore lo segnalerebbe. Chi scrive un'altra implementazione di `FlowBuilderApi` non traduca i valori in numeri |
|
|
855
878
|
| 19 | **Un campo di screen dinamico e' una risorsa, ma di sola lettura** | Lo restituisce `POST /flows/references` con `kind: "ScreenField"`, e il reference picker lo propone in un gruppo suo; nei selettori di **destinazione** non compare, perche' `references/writable` lo esclude. L'unica eccezione e' l'`assignToReference` di una **screen action**, dove il campo di *quella* schermata e' una destinazione e l'elenco lo passa il chiamante (`extraReferences`). Il nome entra in `FlowDocumentStore.usedNames`, quindi un campo omonimo di una variabile e' `NAME_DUPLICATED`, e `renameScreenField` riscrive i riferimenti come `renameNode` |
|
|
@@ -3821,14 +3821,21 @@ class FlowDictionaryStore {
|
|
|
3821
3821
|
isGlobalScopeVerifiable(scope) {
|
|
3822
3822
|
return (this.globalScope(scope)?.paths?.length ?? 0) > 0;
|
|
3823
3823
|
}
|
|
3824
|
-
/**
|
|
3824
|
+
/**
|
|
3825
|
+
* I percorsi noti di uno scope, già prefissati: `$User.Email`.
|
|
3826
|
+
*
|
|
3827
|
+
* Il percorso **vuoto** e' lo scope stesso (§4.1): un host puo' dichiarare `$Profile` senza
|
|
3828
|
+
* punto — un'unica istanza invece dell'elenco dei suoi campi — e lì il riferimento e' il nome
|
|
3829
|
+
* dello scope. Concatenare comunque il punto produrrebbe `$Profile.`, che non e' un
|
|
3830
|
+
* riferimento di niente.
|
|
3831
|
+
*/
|
|
3825
3832
|
globalPathsOf(scope) {
|
|
3826
3833
|
const entry = this.globalScope(scope);
|
|
3827
3834
|
if (!entry) {
|
|
3828
3835
|
return [];
|
|
3829
3836
|
}
|
|
3830
3837
|
const prefix = entry.scope ?? entry.value;
|
|
3831
|
-
return (entry.paths ?? []).map((path) => `${prefix}.${path}`);
|
|
3838
|
+
return (entry.paths ?? []).map((path) => (path ? `${prefix}.${path}` : prefix));
|
|
3832
3839
|
}
|
|
3833
3840
|
/** §5.14 — la voce di `stageStepTypes` di un `actionType`. */
|
|
3834
3841
|
stageStepType(value) {
|
|
@@ -4081,7 +4088,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
4081
4088
|
* `code` e' stabile e si usa per decidere il comportamento; `message` e' testo per
|
|
4082
4089
|
* l'utente e non va interpretato (§7).
|
|
4083
4090
|
*/
|
|
4084
|
-
const DEBOUNCE_MS$
|
|
4091
|
+
const DEBOUNCE_MS$2 = 400;
|
|
4085
4092
|
class FlowValidationStore {
|
|
4086
4093
|
api = inject(FlowBuilderApi);
|
|
4087
4094
|
destroyRef = inject(DestroyRef);
|
|
@@ -4161,7 +4168,7 @@ class FlowValidationStore {
|
|
|
4161
4168
|
this.timer = setTimeout(() => {
|
|
4162
4169
|
this.timer = undefined;
|
|
4163
4170
|
void this.run(definition);
|
|
4164
|
-
}, DEBOUNCE_MS$
|
|
4171
|
+
}, DEBOUNCE_MS$2);
|
|
4165
4172
|
}
|
|
4166
4173
|
/** Valida subito, saltando il debounce: prima di attivare, o su richiesta esplicita. */
|
|
4167
4174
|
async run(definition) {
|
|
@@ -8222,7 +8229,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
8222
8229
|
* di «la primitiva non c'e'», che e' l'unica cosa condivisa fra i campi.
|
|
8223
8230
|
*/
|
|
8224
8231
|
/** §11.4 — la stessa pausa di digitazione della validazione del documento. */
|
|
8225
|
-
const DEBOUNCE_MS = 400;
|
|
8232
|
+
const DEBOUNCE_MS$1 = 400;
|
|
8226
8233
|
class FormulaEditorComponent {
|
|
8227
8234
|
store = inject(FlowDocumentStore);
|
|
8228
8235
|
api = inject(FlowBuilderApi);
|
|
@@ -8576,7 +8583,7 @@ class FormulaEditorComponent {
|
|
|
8576
8583
|
this.timer = setTimeout(() => {
|
|
8577
8584
|
this.timer = undefined;
|
|
8578
8585
|
void this.run(expression);
|
|
8579
|
-
}, DEBOUNCE_MS);
|
|
8586
|
+
}, DEBOUNCE_MS$1);
|
|
8580
8587
|
}
|
|
8581
8588
|
async run(expression) {
|
|
8582
8589
|
const token = ++this.sequence;
|
|
@@ -9900,6 +9907,346 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
9900
9907
|
args: [{ selector: 'fb-connector-editor', standalone: true, imports: [SelectValueDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fieldset class=\"fb-section\">\r\n <legend class=\"fb-section__title\">{{ title() }}</legend>\r\n\r\n @for (outlet of outlets(); track outlet.key) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label\" [class.fb-field__label--required]=\"outlet.isStructural\">\r\n {{ outlet.label }}\r\n <span class=\"fb-conn__kind\" [attr.data-kind]=\"outlet.kind\">{{ outlet.kind }}</span>\r\n </label>\r\n\r\n <div class=\"fb-field__row\">\r\n <select\r\n class=\"fb-select\"\r\n [fbValue]=\"currentTarget(outlet)\"\r\n [attr.aria-label]=\"'Destinazione di ' + outlet.label\"\r\n (change)=\"setTarget(outlet, $any($event.target).value)\"\r\n >\r\n <option value=\"\">\u2014 nessuna destinazione \u2014</option>\r\n @for (target of targetOptions(); track target.name) {\r\n <option [value]=\"target.name\">{{ target.label || target.name }}</option>\r\n }\r\n </select>\r\n @if (!isTerminal(outlet)) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi il ramo\"\r\n title=\"Rimuove il ramo: il percorso finira\u2019 qui\"\r\n (click)=\"clear(outlet)\"\r\n >\r\n \u00D7\r\n </button>\r\n }\r\n </div>\r\n\r\n @if (currentTarget(outlet)) {\r\n <label class=\"fb-check\">\r\n <input type=\"checkbox\" [checked]=\"isGoTo(outlet)\" (change)=\"setGoTo(outlet, $any($event.target).checked)\" />\r\n Disegna come salto indietro (isGoTo)\r\n </label>\r\n }\r\n\r\n @if (hintFor(outlet)) {\r\n <p\r\n class=\"fb-field__hint\"\r\n [class.fb-field__hint--warn]=\"isDangling(outlet) || (isTerminal(outlet) && outlet.isStructural)\"\r\n >\r\n {{ hintFor(outlet) }}\r\n </p>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-field__hint\">Questo elemento non ha uscite: interrompe l\u2019esecuzione.</p>\r\n }\r\n</fieldset>\r\n", styles: [":host{display:block}.fb-conn__kind{margin-left:5px;padding:0 5px;border-radius:8px;background:var(--fb-badge-bg, #eef1f5);font-size:9px;font-weight:600;text-transform:none;color:var(--fb-text-subtle, #98a2b3)}.fb-conn__kind[data-kind=Fault]{background:color-mix(in srgb,var(--fb-error, #c9372c) 14%,transparent);color:var(--fb-error, #c9372c)}.fb-conn__kind[data-kind=Timeout],.fb-conn__kind[data-kind=ScheduledPath]{background:color-mix(in srgb,var(--fb-warning, #b7791f) 14%,transparent);color:var(--fb-warning, #b7791f)}.fb-conn__kind[data-kind=Rule],.fb-conn__kind[data-kind=WaitEvent]{background:color-mix(in srgb,var(--fb-edge-rule, #7c5cd6) 14%,transparent);color:var(--fb-edge-rule, #7c5cd6)}.fb-field__row .fb-select{flex:1;min-width:0}\n"] }]
|
|
9901
9908
|
}], ctorParameters: () => [], propDecorators: { nodeName: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodeName", required: true }] }], node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: true }] }], outlets: [{ type: i0.Input, args: [{ isSignal: true, alias: "outlets", required: true }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], connectorChanged: [{ type: i0.Output, args: ["connectorChanged"] }] } });
|
|
9902
9909
|
|
|
9910
|
+
/**
|
|
9911
|
+
* Un testo con **merge field** — FRONTEND.md §5.12, §5.2.
|
|
9912
|
+
*
|
|
9913
|
+
* Non e' un editor di formule, ed e' la distinzione che regge tutto il componente: qui il
|
|
9914
|
+
* contenuto e' testo — una frase che l'utente legge — con dentro delle isole `{!...}` che il
|
|
9915
|
+
* runtime sostituisce quando l'elemento scatta. Trattarlo come un'espressione accuserebbe ogni
|
|
9916
|
+
* parola scritta in italiano; ignorarlo del tutto lascerebbe scoprire un refuso dentro una
|
|
9917
|
+
* graffa davanti a chi sta usando il flow.
|
|
9918
|
+
*
|
|
9919
|
+
* Tre regole, e vengono tutte dal contratto:
|
|
9920
|
+
*
|
|
9921
|
+
* - **si offre l'inserimento di un riferimento.** E' il posto in cui serve di piu' — «L'ordine
|
|
9922
|
+
* e' già stato evaso» senza il numero dell'ordine e' meta' messaggio — e i nomi sono quelli di
|
|
9923
|
+
* `POST /flows/references`, la stessa fonte del reference picker e dell'autocompletamento
|
|
9924
|
+
* delle formule (output automatici compresi, §4.5).
|
|
9925
|
+
* - **si verifica solo se contiene `{!`.** Un testo senza segnaposto non viene mandato a
|
|
9926
|
+
* nessuno: non c'e' niente da verificare, e la risposta di un motore di espressioni su una
|
|
9927
|
+
* frase sarebbe un rilievo per parola.
|
|
9928
|
+
* - **l'esito non e' mai una spunta inventata.** Come per le formule (§6.3) gli esiti sono tre e
|
|
9929
|
+
* restano distinti: primitiva assente (silenzio, e il servizio la spegne per la sessione),
|
|
9930
|
+
* `isVerified: false` (motore non configurato — si dice), `isValid` (l'unico con la spunta).
|
|
9931
|
+
*
|
|
9932
|
+
* Il codice del rilievo e' **del motore**, non della §7: si mostra e non si interpreta. La
|
|
9933
|
+
* `position` e' riferita al testo intero — anche quando il difetto sta dentro un'isola — perche'
|
|
9934
|
+
* e' lì che il bottone del rilievo va a selezionare.
|
|
9935
|
+
*/
|
|
9936
|
+
/** §11.4 — la stessa pausa di digitazione della validazione del documento. */
|
|
9937
|
+
const DEBOUNCE_MS = 400;
|
|
9938
|
+
/** L'apertura di un'isola. Sta qui perche' la usano il rilevamento e l'inserimento. */
|
|
9939
|
+
const OPEN = '{!';
|
|
9940
|
+
class MergeTextEditorComponent {
|
|
9941
|
+
store = inject(FlowDocumentStore);
|
|
9942
|
+
api = inject(FlowBuilderApi);
|
|
9943
|
+
service = inject(FormulaValidationService);
|
|
9944
|
+
destroyRef = inject(DestroyRef);
|
|
9945
|
+
text = input('', ...(ngDevMode ? [{ debugName: "text" }] : []));
|
|
9946
|
+
/**
|
|
9947
|
+
* Dove comparira'. Resta un input perche' un motore puo' distinguere il messaggio di un errore
|
|
9948
|
+
* dalla scritta di un campo, ma il valore giusto e' quasi sempre quello predefinito.
|
|
9949
|
+
*/
|
|
9950
|
+
usage = input('Text', ...(ngDevMode ? [{ debugName: "usage" }] : []));
|
|
9951
|
+
placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
|
|
9952
|
+
ariaLabel = input('Testo', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
|
|
9953
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
|
|
9954
|
+
rows = input(3, ...(ngDevMode ? [{ debugName: "rows" }] : []));
|
|
9955
|
+
/** Come nel formula editor: `change` dove mutare il documento ridisegna mezza schermata. */
|
|
9956
|
+
commitOn = input('input', ...(ngDevMode ? [{ debugName: "commitOn" }] : []));
|
|
9957
|
+
textChange = output();
|
|
9958
|
+
area = viewChild('area', ...(ngDevMode ? [{ debugName: "area" }] : []));
|
|
9959
|
+
/**
|
|
9960
|
+
* Il testo che si sta scrivendo. Non e' legato al DOM — la casella tiene il suo valore e la
|
|
9961
|
+
* `[value]` resta quella del documento — perche' riscrivere l'attributo a ogni tasto sposta il
|
|
9962
|
+
* cursore quando si corregge in mezzo alla frase.
|
|
9963
|
+
*/
|
|
9964
|
+
draft = signal('', ...(ngDevMode ? [{ debugName: "draft" }] : []));
|
|
9965
|
+
_result = signal(null, ...(ngDevMode ? [{ debugName: "_result" }] : []));
|
|
9966
|
+
_isChecking = signal(false, ...(ngDevMode ? [{ debugName: "_isChecking" }] : []));
|
|
9967
|
+
timer;
|
|
9968
|
+
/** Cresce a ogni richiesta: scarta le risposte di verifiche già superate. */
|
|
9969
|
+
sequence = 0;
|
|
9970
|
+
result = this._result.asReadonly();
|
|
9971
|
+
isChecking = this._isChecking.asReadonly();
|
|
9972
|
+
// -------------------------------------------------------------------------
|
|
9973
|
+
// I nomi inseribili
|
|
9974
|
+
// -------------------------------------------------------------------------
|
|
9975
|
+
references = signal([], ...(ngDevMode ? [{ debugName: "references" }] : []));
|
|
9976
|
+
/** Il documento per cui l'elenco e' stato chiesto: evita una richiesta a ogni apertura. */
|
|
9977
|
+
loadedFor = null;
|
|
9978
|
+
isPickerOpen = signal(false, ...(ngDevMode ? [{ debugName: "isPickerOpen" }] : []));
|
|
9979
|
+
filter = signal('', ...(ngDevMode ? [{ debugName: "filter" }] : []));
|
|
9980
|
+
/**
|
|
9981
|
+
* Cio' che si sta scrivendo **dentro** un'isola aperta, se il cursore ci sta dentro: e' la
|
|
9982
|
+
* seconda strada per inserire un nome, e la piu' rapida — chi ha scritto `{!Ord` non va a
|
|
9983
|
+
* cercare un bottone.
|
|
9984
|
+
*/
|
|
9985
|
+
token = signal(null, ...(ngDevMode ? [{ debugName: "token" }] : []));
|
|
9986
|
+
highlighted = signal(0, ...(ngDevMode ? [{ debugName: "highlighted" }] : []));
|
|
9987
|
+
suggestions = computed(() => {
|
|
9988
|
+
const token = this.token();
|
|
9989
|
+
if (!token) {
|
|
9990
|
+
return [];
|
|
9991
|
+
}
|
|
9992
|
+
const needle = token.text.toLowerCase();
|
|
9993
|
+
const matches = this.references().filter((reference) => reference.name.toLowerCase().startsWith(needle));
|
|
9994
|
+
if (matches.length === 1 && matches[0].name.toLowerCase() === needle) {
|
|
9995
|
+
return [];
|
|
9996
|
+
}
|
|
9997
|
+
return matches.slice(0, 8);
|
|
9998
|
+
}, ...(ngDevMode ? [{ debugName: "suggestions" }] : []));
|
|
9999
|
+
/** L'elenco del bottone: tutti i nomi, filtrati dalla ricerca. */
|
|
10000
|
+
pickerOptions = computed(() => {
|
|
10001
|
+
const needle = this.filter().trim().toLowerCase();
|
|
10002
|
+
const all = this.references();
|
|
10003
|
+
return (needle ? all.filter((entry) => entry.name.toLowerCase().includes(needle)) : all).slice(0, 60);
|
|
10004
|
+
}, ...(ngDevMode ? [{ debugName: "pickerOptions" }] : []));
|
|
10005
|
+
// -------------------------------------------------------------------------
|
|
10006
|
+
// Esito della verifica
|
|
10007
|
+
// -------------------------------------------------------------------------
|
|
10008
|
+
/** Un testo senza segnaposto non si manda: non c'e' niente da verificare (§5.12). */
|
|
10009
|
+
hasMergeFields = computed(() => this.draft().includes(OPEN), ...(ngDevMode ? [{ debugName: "hasMergeFields" }] : []));
|
|
10010
|
+
issues = computed(() => this._result()?.issues ?? [], ...(ngDevMode ? [{ debugName: "issues" }] : []));
|
|
10011
|
+
hasErrors = computed(() => this.issues().some((issue) => severityBucket(issue.severity) === 'Error'), ...(ngDevMode ? [{ debugName: "hasErrors" }] : []));
|
|
10012
|
+
isConfirmed = computed(() => {
|
|
10013
|
+
const result = this._result();
|
|
10014
|
+
return !!result && result.isVerified && result.isValid && !this.issues().length;
|
|
10015
|
+
}, ...(ngDevMode ? [{ debugName: "isConfirmed" }] : []));
|
|
10016
|
+
/** Il motore c'e' come primitiva ma non come motore: si dice, non si tace (§6.3). */
|
|
10017
|
+
isUnverified = computed(() => {
|
|
10018
|
+
const result = this._result();
|
|
10019
|
+
return !!result && !result.isVerified;
|
|
10020
|
+
}, ...(ngDevMode ? [{ debugName: "isUnverified" }] : []));
|
|
10021
|
+
constructor() {
|
|
10022
|
+
effect(() => {
|
|
10023
|
+
const text = this.text();
|
|
10024
|
+
this.usage();
|
|
10025
|
+
untracked(() => {
|
|
10026
|
+
this.draft.set(text);
|
|
10027
|
+
this.schedule(text);
|
|
10028
|
+
});
|
|
10029
|
+
});
|
|
10030
|
+
this.destroyRef.onDestroy(() => this.cancel());
|
|
10031
|
+
}
|
|
10032
|
+
onInput(value) {
|
|
10033
|
+
this.draft.set(value);
|
|
10034
|
+
this.schedule(value);
|
|
10035
|
+
this.refreshToken();
|
|
10036
|
+
if (this.commitOn() === 'input') {
|
|
10037
|
+
this.textChange.emit(value);
|
|
10038
|
+
}
|
|
10039
|
+
}
|
|
10040
|
+
onCommit(value) {
|
|
10041
|
+
if (this.commitOn() === 'change') {
|
|
10042
|
+
this.textChange.emit(value);
|
|
10043
|
+
}
|
|
10044
|
+
}
|
|
10045
|
+
onFocus() {
|
|
10046
|
+
void this.loadReferences();
|
|
10047
|
+
this.refreshToken();
|
|
10048
|
+
}
|
|
10049
|
+
onCaretMove() {
|
|
10050
|
+
this.refreshToken();
|
|
10051
|
+
}
|
|
10052
|
+
onBlur() {
|
|
10053
|
+
this.token.set(null);
|
|
10054
|
+
}
|
|
10055
|
+
/**
|
|
10056
|
+
* Le frecce scorrono i suggerimenti e Invio inserisce — ma **solo** quando ce ne sono: in un
|
|
10057
|
+
* testo Invio deve restare Invio, che qui e' un a capo dentro il messaggio.
|
|
10058
|
+
*/
|
|
10059
|
+
onKeyDown(event) {
|
|
10060
|
+
const options = this.suggestions();
|
|
10061
|
+
if (!options.length) {
|
|
10062
|
+
return;
|
|
10063
|
+
}
|
|
10064
|
+
if (event.key === 'Escape') {
|
|
10065
|
+
this.token.set(null);
|
|
10066
|
+
event.stopPropagation();
|
|
10067
|
+
return;
|
|
10068
|
+
}
|
|
10069
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
10070
|
+
const step = event.key === 'ArrowDown' ? 1 : -1;
|
|
10071
|
+
this.highlighted.update((index) => (index + step + options.length) % options.length);
|
|
10072
|
+
event.preventDefault();
|
|
10073
|
+
return;
|
|
10074
|
+
}
|
|
10075
|
+
if (event.key === 'Enter' || event.key === 'Tab') {
|
|
10076
|
+
this.complete(options[this.highlighted()]?.name ?? '');
|
|
10077
|
+
event.preventDefault();
|
|
10078
|
+
}
|
|
10079
|
+
}
|
|
10080
|
+
togglePicker() {
|
|
10081
|
+
const open = !this.isPickerOpen();
|
|
10082
|
+
this.isPickerOpen.set(open);
|
|
10083
|
+
if (open) {
|
|
10084
|
+
void this.loadReferences();
|
|
10085
|
+
}
|
|
10086
|
+
}
|
|
10087
|
+
/**
|
|
10088
|
+
* Il bottone: scrive un'isola **intera** al punto del cursore, graffe comprese. Inserire il
|
|
10089
|
+
* solo nome lascerebbe all'utente il compito di ricordarsi la sintassi, che e' esattamente
|
|
10090
|
+
* cio' che il comando esiste per evitare.
|
|
10091
|
+
*/
|
|
10092
|
+
insertReference(name) {
|
|
10093
|
+
const element = this.area()?.nativeElement;
|
|
10094
|
+
if (!element || !name || this.disabled()) {
|
|
10095
|
+
return;
|
|
10096
|
+
}
|
|
10097
|
+
const snippet = `${OPEN}${name}}`;
|
|
10098
|
+
const start = element.selectionStart ?? element.value.length;
|
|
10099
|
+
const end = element.selectionEnd ?? start;
|
|
10100
|
+
const next = element.value.slice(0, start) + snippet + element.value.slice(end);
|
|
10101
|
+
const caret = start + snippet.length;
|
|
10102
|
+
this.write(next, caret);
|
|
10103
|
+
this.isPickerOpen.set(false);
|
|
10104
|
+
}
|
|
10105
|
+
/**
|
|
10106
|
+
* Il suggerimento dentro un'isola aperta: **completa** il nome e chiude la graffa.
|
|
10107
|
+
*
|
|
10108
|
+
* Non e' {@link insertReference}, ed e' la distinzione da non perdere: lì si scrive un'isola
|
|
10109
|
+
* nuova al punto del cursore, qui si sta già scrivendo dentro una — passare per l'altra strada
|
|
10110
|
+
* produce `{!IdOr{!IdOrdine}`, cioe' due aperture e un segnaposto che non si risolve.
|
|
10111
|
+
*/
|
|
10112
|
+
complete(name) {
|
|
10113
|
+
const element = this.area()?.nativeElement;
|
|
10114
|
+
const token = this.token();
|
|
10115
|
+
if (!element || !name || !token) {
|
|
10116
|
+
return;
|
|
10117
|
+
}
|
|
10118
|
+
const after = element.value.slice(token.end);
|
|
10119
|
+
// Se la graffa c'e' già — si sta correggendo un'isola scritta prima — non se ne aggiunge una
|
|
10120
|
+
// seconda: `{!Ordine}}` non e' un segnaposto.
|
|
10121
|
+
const closing = after.startsWith('}') ? '' : '}';
|
|
10122
|
+
const next = element.value.slice(0, token.start) + name + closing + after;
|
|
10123
|
+
this.write(next, token.start + name.length + closing.length);
|
|
10124
|
+
}
|
|
10125
|
+
/** Scrive nella casella e propaga: la casella e' la sorgente del testo mentre si digita. */
|
|
10126
|
+
write(next, caret) {
|
|
10127
|
+
const element = this.area()?.nativeElement;
|
|
10128
|
+
if (!element) {
|
|
10129
|
+
return;
|
|
10130
|
+
}
|
|
10131
|
+
element.value = next;
|
|
10132
|
+
element.setSelectionRange(caret, caret);
|
|
10133
|
+
element.focus();
|
|
10134
|
+
this.token.set(null);
|
|
10135
|
+
this.onInput(next);
|
|
10136
|
+
// Con `commitOn="change"` il `change` del DOM non scatta su una scrittura da codice.
|
|
10137
|
+
this.onCommit(next);
|
|
10138
|
+
}
|
|
10139
|
+
async loadReferences() {
|
|
10140
|
+
const document = this.store.document();
|
|
10141
|
+
if (this.loadedFor === document) {
|
|
10142
|
+
return;
|
|
10143
|
+
}
|
|
10144
|
+
this.loadedFor = document;
|
|
10145
|
+
try {
|
|
10146
|
+
this.references.set(await this.api.getReferences(document));
|
|
10147
|
+
}
|
|
10148
|
+
catch {
|
|
10149
|
+
// Elenco non disponibile: nessuna proposta, nessuna accusa. Il segnaposto si scrive lo
|
|
10150
|
+
// stesso — l'inserimento e' un aiuto, non un vincolo.
|
|
10151
|
+
this.references.set([]);
|
|
10152
|
+
}
|
|
10153
|
+
}
|
|
10154
|
+
/**
|
|
10155
|
+
* La parola sotto il cursore, **solo dentro un'isola aperta**: fuori dalle graffe si sta
|
|
10156
|
+
* scrivendo una frase, e proporre nomi di variabili a ogni parola sarebbe rumore.
|
|
10157
|
+
*/
|
|
10158
|
+
refreshToken() {
|
|
10159
|
+
const element = this.area()?.nativeElement;
|
|
10160
|
+
if (!element) {
|
|
10161
|
+
return;
|
|
10162
|
+
}
|
|
10163
|
+
const caret = element.selectionStart ?? 0;
|
|
10164
|
+
const before = element.value.slice(0, caret);
|
|
10165
|
+
const open = before.lastIndexOf(OPEN);
|
|
10166
|
+
// Un'isola già chiusa prima del cursore non conta: il `}` termina il segnaposto.
|
|
10167
|
+
if (open < 0 || before.indexOf('}', open) >= 0) {
|
|
10168
|
+
this.token.set(null);
|
|
10169
|
+
return;
|
|
10170
|
+
}
|
|
10171
|
+
const text = before.slice(open + OPEN.length);
|
|
10172
|
+
if (/[^A-Za-z0-9_.$]/.test(text)) {
|
|
10173
|
+
this.token.set(null);
|
|
10174
|
+
return;
|
|
10175
|
+
}
|
|
10176
|
+
this.token.set({ text, start: caret - text.length, end: caret });
|
|
10177
|
+
this.highlighted.set(0);
|
|
10178
|
+
}
|
|
10179
|
+
severityOf(issue) {
|
|
10180
|
+
return severityBucket(issue.severity);
|
|
10181
|
+
}
|
|
10182
|
+
hasPosition(issue) {
|
|
10183
|
+
return typeof issue.position === 'number' && issue.position >= 0;
|
|
10184
|
+
}
|
|
10185
|
+
/** Il tratto citato dal rilievo, così il messaggio dice *dove* anche senza il salto. */
|
|
10186
|
+
excerptOf(issue) {
|
|
10187
|
+
if (!this.hasPosition(issue)) {
|
|
10188
|
+
return '';
|
|
10189
|
+
}
|
|
10190
|
+
const start = issue.position;
|
|
10191
|
+
const length = typeof issue.length === 'number' && issue.length > 0 ? issue.length : 1;
|
|
10192
|
+
return this.draft().slice(start, start + length);
|
|
10193
|
+
}
|
|
10194
|
+
/** Porta il cursore sul tratto segnalato: e' il payoff di `position`. */
|
|
10195
|
+
goToIssue(issue) {
|
|
10196
|
+
if (!this.hasPosition(issue) || this.disabled()) {
|
|
10197
|
+
return;
|
|
10198
|
+
}
|
|
10199
|
+
const element = this.area()?.nativeElement;
|
|
10200
|
+
if (!element) {
|
|
10201
|
+
return;
|
|
10202
|
+
}
|
|
10203
|
+
const start = issue.position;
|
|
10204
|
+
const length = typeof issue.length === 'number' && issue.length > 0 ? issue.length : 1;
|
|
10205
|
+
element.focus();
|
|
10206
|
+
element.setSelectionRange(Math.min(start, element.value.length), Math.min(start + length, element.value.length));
|
|
10207
|
+
}
|
|
10208
|
+
schedule(text) {
|
|
10209
|
+
this.cancel();
|
|
10210
|
+
// Senza segnaposto non si chiama nessuno, e non si mostra nessun esito: non c'e' niente da
|
|
10211
|
+
// verificare, e una spunta su una frase direbbe che qualcuno l'ha guardata.
|
|
10212
|
+
if (!text.includes(OPEN) || !this.service.isSupported()) {
|
|
10213
|
+
this.sequence += 1;
|
|
10214
|
+
this._result.set(null);
|
|
10215
|
+
this._isChecking.set(false);
|
|
10216
|
+
return;
|
|
10217
|
+
}
|
|
10218
|
+
this._isChecking.set(true);
|
|
10219
|
+
this.timer = setTimeout(() => void this.check(text), DEBOUNCE_MS);
|
|
10220
|
+
}
|
|
10221
|
+
cancel() {
|
|
10222
|
+
if (this.timer) {
|
|
10223
|
+
clearTimeout(this.timer);
|
|
10224
|
+
this.timer = undefined;
|
|
10225
|
+
}
|
|
10226
|
+
}
|
|
10227
|
+
async check(text) {
|
|
10228
|
+
const token = ++this.sequence;
|
|
10229
|
+
// Il documento si manda **in lavorazione**: un messaggio cita le variabili appena aggiunte,
|
|
10230
|
+
// e verificarlo contro il salvato le direbbe inesistenti (§6.3).
|
|
10231
|
+
const result = await this.service.validate({
|
|
10232
|
+
flow: this.store.document(),
|
|
10233
|
+
expression: text,
|
|
10234
|
+
usage: this.usage(),
|
|
10235
|
+
});
|
|
10236
|
+
if (token !== this.sequence) {
|
|
10237
|
+
return;
|
|
10238
|
+
}
|
|
10239
|
+
this._isChecking.set(false);
|
|
10240
|
+
this._result.set(result);
|
|
10241
|
+
}
|
|
10242
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: MergeTextEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
10243
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: MergeTextEditorComponent, isStandalone: true, selector: "fb-merge-text-editor", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: false, transformFunction: null }, usage: { classPropertyName: "usage", publicName: "usage", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, commitOn: { classPropertyName: "commitOn", publicName: "commitOn", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { textChange: "textChange" }, viewQueries: [{ propertyName: "area", first: true, predicate: ["area"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"fb-merge__bar\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-merge__toggle\"\r\n [class.fb-merge__toggle--on]=\"isPickerOpen()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isPickerOpen()\"\r\n title=\"Inserisci un riferimento nel testo\"\r\n (click)=\"togglePicker()\"\r\n >\r\n {!} Inserisci riferimento\r\n </button>\r\n</div>\r\n\r\n<textarea\r\n #area\r\n class=\"fb-textarea\"\r\n [class.fb-input--invalid]=\"hasErrors()\"\r\n [value]=\"text()\"\r\n [rows]=\"rows()\"\r\n [disabled]=\"disabled()\"\r\n [placeholder]=\"placeholder()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n (input)=\"onInput($any($event.target).value)\"\r\n (change)=\"onCommit($any($event.target).value)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (keyup)=\"onCaretMove()\"\r\n (click)=\"onCaretMove()\"\r\n></textarea>\r\n\r\n@if (suggestions().length) {\r\n <!--\r\n I nomi proposti mentre si scrive **dentro** un segnaposto aperto: qui si **completa** il nome\r\n e si chiude la graffa, non si inserisce un\u2019isola nuova \u2014 quella e\u2019 l\u2019altra strada, il bottone.\r\n `mousedown` va fermato: il blur della casella arriverebbe prima del click e chiuderebbe\r\n l\u2019elenco.\r\n -->\r\n <ul class=\"fb-merge__hints\" role=\"listbox\" aria-label=\"Riferimenti disponibili\">\r\n @for (reference of suggestions(); track reference.name) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-merge__hint\"\r\n [class.fb-merge__hint--on]=\"$index === highlighted()\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"$index === highlighted()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"complete(reference.name)\"\r\n >\r\n <code>{{ reference.name }}</code>\r\n @if (reference.dataType) {\r\n <span class=\"fb-merge__hint-type\">\r\n {{ reference.dataType }}{{ reference.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n}\r\n\r\n@if (isPickerOpen()) {\r\n <div class=\"fb-merge__picker\">\r\n <input\r\n type=\"search\"\r\n class=\"fb-input fb-merge__search\"\r\n placeholder=\"Cerca un riferimento\u2026\"\r\n aria-label=\"Cerca un riferimento\"\r\n [value]=\"filter()\"\r\n (input)=\"filter.set($any($event.target).value)\"\r\n />\r\n @for (reference of pickerOptions(); track reference.name) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-merge__option\"\r\n [disabled]=\"disabled()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insertReference(reference.name)\"\r\n >\r\n <code>{{ reference.name }}</code>\r\n @if (reference.dataType) {\r\n <span class=\"fb-merge__hint-type\">\r\n {{ reference.dataType }}{{ reference.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n </button>\r\n } @empty {\r\n <p class=\"fb-field__hint\">Nessun riferimento corrisponde alla ricerca.</p>\r\n }\r\n </div>\r\n}\r\n\r\n@if (isChecking()) {\r\n <p class=\"fb-field__hint\">Verifica dei segnaposto\u2026</p>\r\n} @else if (issues().length) {\r\n <ul class=\"fb-merge__issues\">\r\n @for (issue of issues(); track $index) {\r\n <li class=\"fb-merge__issue\" [class]=\"'fb-merge__issue--' + severityOf(issue)\">\r\n @if (hasPosition(issue)) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-merge__jump\"\r\n [disabled]=\"disabled()\"\r\n title=\"Seleziona il tratto segnalato\"\r\n (click)=\"goToIssue(issue)\"\r\n >\r\n @if (excerptOf(issue)) {\r\n <code>{{ excerptOf(issue) }}</code>\r\n } @else {\r\n car. {{ issue.position! + 1 }}\r\n }\r\n </button>\r\n }\r\n <span class=\"fb-merge__message\">{{ issue.message }}</span>\r\n <!-- Codice del motore, non della \u00A77: si mostra e non si interpreta. -->\r\n <code class=\"fb-merge__code\">{{ issue.code }}</code>\r\n </li>\r\n }\r\n </ul>\r\n} @else if (isConfirmed()) {\r\n <p class=\"fb-merge__ok\">\u2713 Segnaposto verificati dal motore.</p>\r\n} @else if (isUnverified()) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Nessun motore di validazione delle formule e\u2019 configurato: i segnaposto non sono stati\r\n controllati.\r\n </p>\r\n}\r\n\r\n<ng-content />\r\n", styles: [":host{display:flex;flex-direction:column;gap:4px}.fb-merge__bar{display:flex;justify-content:flex-end}.fb-merge__toggle{padding:1px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface, #fff);color:var(--fb-text-muted, #667085);font:inherit;font-size:10px;cursor:pointer}.fb-merge__toggle--on{border-color:var(--fb-accent, #2f6feb);color:var(--fb-accent, #2f6feb)}.fb-merge__toggle:disabled{opacity:.5;cursor:not-allowed}.fb-merge__hints,.fb-merge__picker{display:flex;flex-direction:column;gap:1px;max-height:180px;margin:0;padding:2px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface, #fff);list-style:none}.fb-merge__picker{gap:2px;padding:4px;background:var(--fb-surface-alt, #f8f9fb)}.fb-merge__search{font-size:10px}.fb-merge__hint,.fb-merge__option{display:flex;gap:6px;align-items:baseline;width:100%;padding:2px 5px;border:0;border-radius:3px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-merge__option{background:var(--fb-surface, #fff)}.fb-merge__hint:hover,.fb-merge__hint--on,.fb-merge__option:hover{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-merge__hint code,.fb-merge__option code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-merge__hint-type{margin-left:auto;color:var(--fb-text-subtle, #98a2b3)}.fb-merge__option:disabled{opacity:.5;cursor:not-allowed}.fb-merge__issues{display:flex;flex-direction:column;gap:3px;margin:0;padding:0;list-style:none}.fb-merge__issue{display:flex;flex-wrap:wrap;gap:5px;align-items:baseline;padding:3px 6px;border-left:3px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:10px;line-height:1.45}.fb-merge__issue--Error{border-left-color:var(--fb-error, #c9372c);color:var(--fb-error, #c9372c)}.fb-merge__issue--Warning{border-left-color:var(--fb-warning, #b7791f);color:var(--fb-warning, #b7791f)}.fb-merge__issue--Info{border-left-color:var(--fb-accent, #2f6feb);color:var(--fb-text-muted, #667085)}.fb-merge__message{flex:1 1 auto;min-width:0}.fb-merge__jump{padding:0 4px;border:1px solid currentcolor;border-radius:3px;background:transparent;color:inherit;font:inherit;font-size:10px;cursor:pointer}.fb-merge__jump:disabled{opacity:.5;cursor:not-allowed}.fb-merge__jump code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-merge__code{color:var(--fb-text-subtle, #98a2b3);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px}.fb-merge__ok{margin:0;font-size:10px;color:var(--fb-success, #22a06b)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10244
|
+
}
|
|
10245
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: MergeTextEditorComponent, decorators: [{
|
|
10246
|
+
type: Component,
|
|
10247
|
+
args: [{ selector: 'fb-merge-text-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-merge__bar\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-merge__toggle\"\r\n [class.fb-merge__toggle--on]=\"isPickerOpen()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isPickerOpen()\"\r\n title=\"Inserisci un riferimento nel testo\"\r\n (click)=\"togglePicker()\"\r\n >\r\n {!} Inserisci riferimento\r\n </button>\r\n</div>\r\n\r\n<textarea\r\n #area\r\n class=\"fb-textarea\"\r\n [class.fb-input--invalid]=\"hasErrors()\"\r\n [value]=\"text()\"\r\n [rows]=\"rows()\"\r\n [disabled]=\"disabled()\"\r\n [placeholder]=\"placeholder()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n (input)=\"onInput($any($event.target).value)\"\r\n (change)=\"onCommit($any($event.target).value)\"\r\n (focus)=\"onFocus()\"\r\n (blur)=\"onBlur()\"\r\n (keydown)=\"onKeyDown($event)\"\r\n (keyup)=\"onCaretMove()\"\r\n (click)=\"onCaretMove()\"\r\n></textarea>\r\n\r\n@if (suggestions().length) {\r\n <!--\r\n I nomi proposti mentre si scrive **dentro** un segnaposto aperto: qui si **completa** il nome\r\n e si chiude la graffa, non si inserisce un\u2019isola nuova \u2014 quella e\u2019 l\u2019altra strada, il bottone.\r\n `mousedown` va fermato: il blur della casella arriverebbe prima del click e chiuderebbe\r\n l\u2019elenco.\r\n -->\r\n <ul class=\"fb-merge__hints\" role=\"listbox\" aria-label=\"Riferimenti disponibili\">\r\n @for (reference of suggestions(); track reference.name) {\r\n <li>\r\n <button\r\n type=\"button\"\r\n class=\"fb-merge__hint\"\r\n [class.fb-merge__hint--on]=\"$index === highlighted()\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"$index === highlighted()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"complete(reference.name)\"\r\n >\r\n <code>{{ reference.name }}</code>\r\n @if (reference.dataType) {\r\n <span class=\"fb-merge__hint-type\">\r\n {{ reference.dataType }}{{ reference.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n </button>\r\n </li>\r\n }\r\n </ul>\r\n}\r\n\r\n@if (isPickerOpen()) {\r\n <div class=\"fb-merge__picker\">\r\n <input\r\n type=\"search\"\r\n class=\"fb-input fb-merge__search\"\r\n placeholder=\"Cerca un riferimento\u2026\"\r\n aria-label=\"Cerca un riferimento\"\r\n [value]=\"filter()\"\r\n (input)=\"filter.set($any($event.target).value)\"\r\n />\r\n @for (reference of pickerOptions(); track reference.name) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-merge__option\"\r\n [disabled]=\"disabled()\"\r\n (mousedown)=\"$event.preventDefault()\"\r\n (click)=\"insertReference(reference.name)\"\r\n >\r\n <code>{{ reference.name }}</code>\r\n @if (reference.dataType) {\r\n <span class=\"fb-merge__hint-type\">\r\n {{ reference.dataType }}{{ reference.isCollection ? '[]' : '' }}\r\n </span>\r\n }\r\n </button>\r\n } @empty {\r\n <p class=\"fb-field__hint\">Nessun riferimento corrisponde alla ricerca.</p>\r\n }\r\n </div>\r\n}\r\n\r\n@if (isChecking()) {\r\n <p class=\"fb-field__hint\">Verifica dei segnaposto\u2026</p>\r\n} @else if (issues().length) {\r\n <ul class=\"fb-merge__issues\">\r\n @for (issue of issues(); track $index) {\r\n <li class=\"fb-merge__issue\" [class]=\"'fb-merge__issue--' + severityOf(issue)\">\r\n @if (hasPosition(issue)) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-merge__jump\"\r\n [disabled]=\"disabled()\"\r\n title=\"Seleziona il tratto segnalato\"\r\n (click)=\"goToIssue(issue)\"\r\n >\r\n @if (excerptOf(issue)) {\r\n <code>{{ excerptOf(issue) }}</code>\r\n } @else {\r\n car. {{ issue.position! + 1 }}\r\n }\r\n </button>\r\n }\r\n <span class=\"fb-merge__message\">{{ issue.message }}</span>\r\n <!-- Codice del motore, non della \u00A77: si mostra e non si interpreta. -->\r\n <code class=\"fb-merge__code\">{{ issue.code }}</code>\r\n </li>\r\n }\r\n </ul>\r\n} @else if (isConfirmed()) {\r\n <p class=\"fb-merge__ok\">\u2713 Segnaposto verificati dal motore.</p>\r\n} @else if (isUnverified()) {\r\n <p class=\"fb-field__hint fb-field__hint--warn\">\r\n Nessun motore di validazione delle formule e\u2019 configurato: i segnaposto non sono stati\r\n controllati.\r\n </p>\r\n}\r\n\r\n<ng-content />\r\n", styles: [":host{display:flex;flex-direction:column;gap:4px}.fb-merge__bar{display:flex;justify-content:flex-end}.fb-merge__toggle{padding:1px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface, #fff);color:var(--fb-text-muted, #667085);font:inherit;font-size:10px;cursor:pointer}.fb-merge__toggle--on{border-color:var(--fb-accent, #2f6feb);color:var(--fb-accent, #2f6feb)}.fb-merge__toggle:disabled{opacity:.5;cursor:not-allowed}.fb-merge__hints,.fb-merge__picker{display:flex;flex-direction:column;gap:1px;max-height:180px;margin:0;padding:2px;overflow-y:auto;border:1px solid var(--fb-border, #d6dae1);border-radius:4px;background:var(--fb-surface, #fff);list-style:none}.fb-merge__picker{gap:2px;padding:4px;background:var(--fb-surface-alt, #f8f9fb)}.fb-merge__search{font-size:10px}.fb-merge__hint,.fb-merge__option{display:flex;gap:6px;align-items:baseline;width:100%;padding:2px 5px;border:0;border-radius:3px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:10px;text-align:left;cursor:pointer}.fb-merge__option{background:var(--fb-surface, #fff)}.fb-merge__hint:hover,.fb-merge__hint--on,.fb-merge__option:hover{background:color-mix(in srgb,var(--fb-accent, #2f6feb) 10%,transparent)}.fb-merge__hint code,.fb-merge__option code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-merge__hint-type{margin-left:auto;color:var(--fb-text-subtle, #98a2b3)}.fb-merge__option:disabled{opacity:.5;cursor:not-allowed}.fb-merge__issues{display:flex;flex-direction:column;gap:3px;margin:0;padding:0;list-style:none}.fb-merge__issue{display:flex;flex-wrap:wrap;gap:5px;align-items:baseline;padding:3px 6px;border-left:3px solid var(--fb-border, #d6dae1);border-radius:3px;background:var(--fb-surface-alt, #f8f9fb);font-size:10px;line-height:1.45}.fb-merge__issue--Error{border-left-color:var(--fb-error, #c9372c);color:var(--fb-error, #c9372c)}.fb-merge__issue--Warning{border-left-color:var(--fb-warning, #b7791f);color:var(--fb-warning, #b7791f)}.fb-merge__issue--Info{border-left-color:var(--fb-accent, #2f6feb);color:var(--fb-text-muted, #667085)}.fb-merge__message{flex:1 1 auto;min-width:0}.fb-merge__jump{padding:0 4px;border:1px solid currentcolor;border-radius:3px;background:transparent;color:inherit;font:inherit;font-size:10px;cursor:pointer}.fb-merge__jump:disabled{opacity:.5;cursor:not-allowed}.fb-merge__jump code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-merge__code{color:var(--fb-text-subtle, #98a2b3);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px}.fb-merge__ok{margin:0;font-size:10px;color:var(--fb-success, #22a06b)}\n"] }]
|
|
10248
|
+
}], ctorParameters: () => [], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], usage: [{ type: i0.Input, args: [{ isSignal: true, alias: "usage", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], commitOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "commitOn", required: false }] }], textChange: [{ type: i0.Output, args: ["textChange"] }], area: [{ type: i0.ViewChild, args: ['area', { isSignal: true }] }] } });
|
|
10249
|
+
|
|
9903
10250
|
/**
|
|
9904
10251
|
* Base comune degli inspector.
|
|
9905
10252
|
*
|
|
@@ -10399,6 +10746,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
10399
10746
|
* Il Custom Error **interrompe** l'esecuzione e restituisce i messaggi al chiamante: sono il
|
|
10400
10747
|
* suo prodotto principale, e almeno uno e' obbligatorio (`CUSTOM_ERROR_WITHOUT_MESSAGES`).
|
|
10401
10748
|
* Non ha uscite: per questo il form non mostra nessun connector.
|
|
10749
|
+
*
|
|
10750
|
+
* Il messaggio non e' una casella di testo qualunque: supporta i **merge field** `{!...}`, e qui
|
|
10751
|
+
* servono piu' che altrove — «L'ordine e' già stato evaso» senza il numero dell'ordine e' meta'
|
|
10752
|
+
* messaggio. Per questo ci va `fb-merge-text-editor`, che offre l'inserimento di un riferimento e
|
|
10753
|
+
* fa verificare i segnaposto dal motore di formule mentre si scrive; un testo senza `{!` non
|
|
10754
|
+
* viene mandato a nessuno.
|
|
10402
10755
|
*/
|
|
10403
10756
|
class CustomErrorInspectorComponent extends NodeInspectorBase {
|
|
10404
10757
|
elementType = 'CustomError';
|
|
@@ -10453,11 +10806,11 @@ class CustomErrorInspectorComponent extends NodeInspectorBase {
|
|
|
10453
10806
|
});
|
|
10454
10807
|
}
|
|
10455
10808
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: CustomErrorInspectorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
10456
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: CustomErrorInspectorComponent, isStandalone: true, selector: "fb-custom-error-inspector", usesInheritance: true, ngImport: i0, template: "<p class=\"fb-callout\">\r\n Questo elemento <strong>interrompe</strong> l\u2019esecuzione e restituisce i messaggi al chiamante. Non ha\r\n uscite: quello che c\u2019e\u2019 dopo non verra\u2019 eseguito.\r\n</p>\r\n\r\n<div class=\"fb-list\">\r\n @for (message of messages(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi il messaggio\"\r\n (click)=\"removeMessage($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Messaggio</label>\r\n
|
|
10809
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.28", type: CustomErrorInspectorComponent, isStandalone: true, selector: "fb-custom-error-inspector", usesInheritance: true, ngImport: i0, template: "<p class=\"fb-callout\">\r\n Questo elemento <strong>interrompe</strong> l\u2019esecuzione e restituisce i messaggi al chiamante. Non ha\r\n uscite: quello che c\u2019e\u2019 dopo non verra\u2019 eseguito.\r\n</p>\r\n\r\n<div class=\"fb-list\">\r\n @for (message of messages(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi il messaggio\"\r\n (click)=\"removeMessage($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Messaggio</label>\r\n <!--\r\n \u00A75.12 \u2014 il messaggio supporta i merge field: l\u2019editor offre l\u2019inserimento di un\r\n riferimento e li fa verificare dal motore mentre si scrive.\r\n -->\r\n <fb-merge-text-editor\r\n [text]=\"message.errorMessage || ''\"\r\n placeholder=\"L\u2019ordine {{ '{' }}!Ordine.Numero} e\u2019 gi\u00E0 stato evaso.\"\r\n ariaLabel=\"Messaggio d\u2019errore\"\r\n [rows]=\"2\"\r\n (textChange)=\"setMessage($index, $event)\"\r\n >\r\n <p class=\"fb-field__hint\">\r\n Fra <code>{!</code> e <code>}</code> ci va un riferimento: il runtime lo\r\n sostituisce quando l\u2019errore scatta.\r\n </p>\r\n </fb-merge-text-editor>\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"message.isFieldError === true\"\r\n (change)=\"setIsFieldError($index, $any($event.target).checked)\"\r\n />\r\n Mostra accanto a un campo\r\n </label>\r\n\r\n @if (message.isFieldError) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"message.fieldSelection || ''\"\r\n placeholder=\"Importo\"\r\n (input)=\"setFieldSelection($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Almeno un messaggio e\u2019 obbligatorio: sono il prodotto di questo elemento\r\n (CUSTOM_ERROR_WITHOUT_MESSAGES).\r\n </p>\r\n }\r\n</div>\r\n\r\n<button type=\"button\" class=\"fb-btn\" (click)=\"addMessage()\">Aggiungi messaggio</button>\r\n", dependencies: [{ kind: "component", type: MergeTextEditorComponent, selector: "fb-merge-text-editor", inputs: ["text", "usage", "placeholder", "ariaLabel", "disabled", "rows", "commitOn"], outputs: ["textChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
10457
10810
|
}
|
|
10458
10811
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImport: i0, type: CustomErrorInspectorComponent, decorators: [{
|
|
10459
10812
|
type: Component,
|
|
10460
|
-
args: [{ selector: 'fb-custom-error-inspector', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<p class=\"fb-callout\">\r\n Questo elemento <strong>interrompe</strong> l\u2019esecuzione e restituisce i messaggi al chiamante. Non ha\r\n uscite: quello che c\u2019e\u2019 dopo non verra\u2019 eseguito.\r\n</p>\r\n\r\n<div class=\"fb-list\">\r\n @for (message of messages(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi il messaggio\"\r\n (click)=\"removeMessage($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Messaggio</label>\r\n
|
|
10813
|
+
args: [{ selector: 'fb-custom-error-inspector', standalone: true, imports: [MergeTextEditorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<p class=\"fb-callout\">\r\n Questo elemento <strong>interrompe</strong> l\u2019esecuzione e restituisce i messaggi al chiamante. Non ha\r\n uscite: quello che c\u2019e\u2019 dopo non verra\u2019 eseguito.\r\n</p>\r\n\r\n<div class=\"fb-list\">\r\n @for (message of messages(); track $index) {\r\n <div class=\"fb-list__item\">\r\n <div class=\"fb-list__header\">\r\n <span class=\"fb-list__index\">{{ $index + 1 }}</span>\r\n <span class=\"fb-list__spacer\"></span>\r\n <button\r\n type=\"button\"\r\n class=\"fb-btn fb-btn--ghost fb-btn--icon\"\r\n aria-label=\"Rimuovi il messaggio\"\r\n (click)=\"removeMessage($index)\"\r\n >\r\n \u00D7\r\n </button>\r\n </div>\r\n\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Messaggio</label>\r\n <!--\r\n \u00A75.12 \u2014 il messaggio supporta i merge field: l\u2019editor offre l\u2019inserimento di un\r\n riferimento e li fa verificare dal motore mentre si scrive.\r\n -->\r\n <fb-merge-text-editor\r\n [text]=\"message.errorMessage || ''\"\r\n placeholder=\"L\u2019ordine {{ '{' }}!Ordine.Numero} e\u2019 gi\u00E0 stato evaso.\"\r\n ariaLabel=\"Messaggio d\u2019errore\"\r\n [rows]=\"2\"\r\n (textChange)=\"setMessage($index, $event)\"\r\n >\r\n <p class=\"fb-field__hint\">\r\n Fra <code>{!</code> e <code>}</code> ci va un riferimento: il runtime lo\r\n sostituisce quando l\u2019errore scatta.\r\n </p>\r\n </fb-merge-text-editor>\r\n </div>\r\n\r\n <label class=\"fb-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"message.isFieldError === true\"\r\n (change)=\"setIsFieldError($index, $any($event.target).checked)\"\r\n />\r\n Mostra accanto a un campo\r\n </label>\r\n\r\n @if (message.isFieldError) {\r\n <div class=\"fb-field\">\r\n <label class=\"fb-field__label fb-field__label--required\">Campo</label>\r\n <input\r\n class=\"fb-input\"\r\n [value]=\"message.fieldSelection || ''\"\r\n placeholder=\"Importo\"\r\n (input)=\"setFieldSelection($index, $any($event.target).value)\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n } @empty {\r\n <p class=\"fb-empty\">\r\n Almeno un messaggio e\u2019 obbligatorio: sono il prodotto di questo elemento\r\n (CUSTOM_ERROR_WITHOUT_MESSAGES).\r\n </p>\r\n }\r\n</div>\r\n\r\n<button type=\"button\" class=\"fb-btn\" (click)=\"addMessage()\">Aggiungi messaggio</button>\r\n" }]
|
|
10461
10814
|
}] });
|
|
10462
10815
|
|
|
10463
10816
|
/**
|
|
@@ -17487,5 +17840,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.28", ngImpo
|
|
|
17487
17840
|
* Generated bundle index. Do not edit.
|
|
17488
17841
|
*/
|
|
17489
17842
|
|
|
17490
|
-
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, NamePickerComponent, NodeInspectorBase, ORCHESTRATION_CONDITION_OUTPUT, ObjectPickerComponent, OrchestratedStageInspectorComponent, ParameterEditorComponent, PasteDialogComponent, ProblemsPanelComponent, RecordFilterEditorComponent, ReferencePickerComponent, ResourceDialogComponent, ResourceFormComponent, ResourcePanelComponent, RunDialogComponent, SEVERITY_BUCKETS, SEVERITY_ICON, SEVERITY_LABEL, START_NODE_NAME, SelectValueDirective, StartInspectorComponent, StructureMemberPickerComponent, StructurePickerComponent, TYPES_WITH_AUTOMATIC_OUTPUT, TYPE_BY_COLLECTION, UNSUPPORTED_TYPES, ValueEditorComponent, VersionPanelComponent, allFieldsOf, applyPaste, areTypesComparable, boundsAround, buildClipboardPayload, canvasFoldId, canvasGroupId, canvasNodeId, checkConditionLogic, checkFlowName, choiceSetSourceOf, declaredChoiceSetSources, describeFieldPath, describePathEntry, duplicateField, elementIcon, emptyFlowDefinition, enumChoiceSetFieldType, fieldAt, filterReferences, flattenFields, flowNodeWidth, flowNodeWidthClass, foldSourceConnectorId, foldTargetConnectorId, groupColorClass, groupRect, hasAutoSize, innerNamesOf, insertField, isClipboardPayload, isCustomConditionLogic, isEmptyReferenceFilter, isFieldResource, isFoldReference, isGlobalReference, isNumericType, isPathInside, isTypeCheckedOperator, isUnknownEnumChoiceSetField, isValidFlowName, isValued, loadPathLevel, matchesReferenceFilter, membersInside, moveCondition, moveField, navigatePath, otherSourceFieldsOf, outletByKey, outletsOf, parseCanvasFoldId, parseCanvasGroupId, parseCanvasNodeId, parseFieldPath, parseInvariantNumber, parseSourceConnectorId, parseTargetConnectorId, pathAvailableNames, pathContainerLabel, pathKey, pathNotVerifiableMessage, planPaste, recomputeMembers, referenceRoot, referencedRootsOf, remapConditionLogic, removeCondition, removeField, resolvePath, rewriteReferences, sameMembers, samePath, screenActionNames, screenFieldNames, severityBucket, slugifyFlowName, sourceConnectorId, stageStepNames, stageStepOutputReferenced, stepsOf, targetConnectorId, typeOfCollection, uniqueFlowName, valuedFieldOf, valuedFieldsOf, variantFieldOf, variantOf, variantPresetOf };
|
|
17843
|
+
export { ConditionEditorComponent, ConnectorEditorComponent, DebugPanelComponent, DynamicScreenInspectorComponent, ENUM_CHOICE_SET_DEFAULT_DISPLAY_FIELD, ENUM_CHOICE_SET_DEFAULT_VALUE_FIELD, ENUM_CHOICE_SET_FIELDS, ElementDialogComponent, ElementInspectorComponent, ElementPaletteComponent, EnumValuePickerComponent, FALLBACK_COLLECTION_BY_TYPE, FALLBACK_TYPE_LABEL, FLOW_BUILDER_HTTP_CONFIG, FLOW_CLIPBOARD_KIND, FLOW_CLIPBOARD_VERSION, FLOW_ELEMENT_ICONS, FLOW_ELEMENT_VARIANT_FIELDS, FLOW_ELEMENT_VARIANT_ICONS, FLOW_ERROR_FALLBACK_MESSAGE, FLOW_ERROR_HTTP_STATUS, FLOW_FOLD_HEIGHT, FLOW_FOLD_WIDTH, FLOW_GROUP_COLORS, FLOW_NAME_PATTERN, FLOW_NODE_COLLECTIONS, FLOW_NODE_HEIGHT, FLOW_NODE_WIDTH, FLOW_REFERENCE_FIELDS, FLOW_RESOURCE_COLLECTIONS, FLOW_VALUE_FIELDS, FLOW_VALUE_LITERAL_FIELDS, FieldAssignmentEditorComponent, FieldPickerComponent, FieldValuePickerComponent, FlowApiError, FlowBuilderApi, FlowBuilderComponent, FlowCanvasComponent, FlowCatalogStore, FlowClipboardService, FlowDictionaryStore, FlowDocumentStore, FlowEditorSession, FlowLayoutService, FlowValidationStore, FormulaEditorComponent, FormulaValidationService, GROUP_HEADER_HEIGHT, GROUP_MIN_HEIGHT, GROUP_MIN_WIDTH, GROUP_PADDING, GroupPanelComponent, HttpFlowBuilderApi, MergeTextEditorComponent, NamePickerComponent, NodeInspectorBase, ORCHESTRATION_CONDITION_OUTPUT, ObjectPickerComponent, OrchestratedStageInspectorComponent, ParameterEditorComponent, PasteDialogComponent, ProblemsPanelComponent, RecordFilterEditorComponent, ReferencePickerComponent, ResourceDialogComponent, ResourceFormComponent, ResourcePanelComponent, RunDialogComponent, SEVERITY_BUCKETS, SEVERITY_ICON, SEVERITY_LABEL, START_NODE_NAME, SelectValueDirective, StartInspectorComponent, StructureMemberPickerComponent, StructurePickerComponent, TYPES_WITH_AUTOMATIC_OUTPUT, TYPE_BY_COLLECTION, UNSUPPORTED_TYPES, ValueEditorComponent, VersionPanelComponent, allFieldsOf, applyPaste, areTypesComparable, boundsAround, buildClipboardPayload, canvasFoldId, canvasGroupId, canvasNodeId, checkConditionLogic, checkFlowName, choiceSetSourceOf, declaredChoiceSetSources, describeFieldPath, describePathEntry, duplicateField, elementIcon, emptyFlowDefinition, enumChoiceSetFieldType, fieldAt, filterReferences, flattenFields, flowNodeWidth, flowNodeWidthClass, foldSourceConnectorId, foldTargetConnectorId, groupColorClass, groupRect, hasAutoSize, innerNamesOf, insertField, isClipboardPayload, isCustomConditionLogic, isEmptyReferenceFilter, isFieldResource, isFoldReference, isGlobalReference, isNumericType, isPathInside, isTypeCheckedOperator, isUnknownEnumChoiceSetField, isValidFlowName, isValued, loadPathLevel, matchesReferenceFilter, membersInside, moveCondition, moveField, navigatePath, otherSourceFieldsOf, outletByKey, outletsOf, parseCanvasFoldId, parseCanvasGroupId, parseCanvasNodeId, parseFieldPath, parseInvariantNumber, parseSourceConnectorId, parseTargetConnectorId, pathAvailableNames, pathContainerLabel, pathKey, pathNotVerifiableMessage, planPaste, recomputeMembers, referenceRoot, referencedRootsOf, remapConditionLogic, removeCondition, removeField, resolvePath, rewriteReferences, sameMembers, samePath, screenActionNames, screenFieldNames, severityBucket, slugifyFlowName, sourceConnectorId, stageStepNames, stageStepOutputReferenced, stepsOf, targetConnectorId, typeOfCollection, uniqueFlowName, valuedFieldOf, valuedFieldsOf, variantFieldOf, variantOf, variantPresetOf };
|
|
17491
17844
|
//# sourceMappingURL=esfaenza-flow-builder.mjs.map
|