@esfaenza/flow-builder 20.3.38 → 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 +36 -1
- package/fesm2022/esfaenza-flow-builder.mjs +773 -194
- package/fesm2022/esfaenza-flow-builder.mjs.map +1 -1
- package/index.d.ts +270 -88
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -235,6 +235,14 @@ il trascinamento sul canvas vuoto disegna il rettangolo di selezione invece di s
|
|
|
235
235
|
un elemento, il canvas lo dice e dice **cosa farne**: «trascinane uno per spostarli tutti». Un
|
|
236
236
|
gesto che nessuno annuncia non esiste.
|
|
237
237
|
|
|
238
|
+
**Risorse.** Il pannello «Risorse» e' un **elenco**: nome, tipo, quante volte e' usata, i rilievi
|
|
239
|
+
della riga. Aggiungerne una o cliccarne il nome apre una **finestra** dedicata con il form dentro,
|
|
240
|
+
come per il dettaglio di un elemento — e per la stessa ragione: il form di un dynamic choice set
|
|
241
|
+
(sorgente, due campi, ordinamento, limite, filtri) dentro la colonna laterale spingeva l'elenco
|
|
242
|
+
fuori dallo schermo, cioe' faceva sparire il contesto per cui l'elenco esiste. La finestra si
|
|
243
|
+
sposta prendendola per l'intestazione, non ha «Annulla» — le modifiche sono già nel documento, e
|
|
244
|
+
a tornare indietro e' l'annulla dell'editor — e si chiude da se' se la risorsa viene rimossa.
|
|
245
|
+
|
|
238
246
|
*Quante volte e' usata.* Ogni risorsa porta il numero dei suoi usi, formule comprese; a zero
|
|
239
247
|
occorrenze lo dice, ed e' l'unico modo di sapere quali delle venti variabili sono morte.
|
|
240
248
|
Rimuovere una risorsa **usata** chiede conferma e dice quanti riferimenti resterebbero orfani:
|
|
@@ -481,6 +489,16 @@ sapere: le globali sono di sola lettura, membri compresi — le assegnabili sono
|
|
|
481
489
|
`$Flow.ActiveStages` e i campi di `$Record` — e il picker lo dice con `TARGET_NOT_WRITABLE` invece
|
|
482
490
|
di far sembrare il nome inesistente (§5.2).
|
|
483
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
|
+
|
|
484
502
|
Su una destinazione la colonna che decide non e' la stessa nei due mondi: un membro porta il proprio
|
|
485
503
|
`isWritable`, un campo no. Fuori da un Create o da un Update il contesto non c'e' — un Assignment su
|
|
486
504
|
`Cliente.Codice` non sa se quel record verra' creato o aggiornato — quindi lì basta `isCreateable`
|
|
@@ -567,6 +585,19 @@ aggiunte. Tre esiti restano distinti e nessuno dei tre e' «formula valida»: pr
|
|
|
567
585
|
stata controllata), `isValid` (verificata davvero, ed e' l'unico caso con la spunta verde) — una
|
|
568
586
|
spunta su un'espressione mai controllata e' peggio di nessuna spunta.
|
|
569
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
|
+
|
|
570
601
|
**Un campo a `null` e' assente.** Il valore ha un campo per tipo e va valorizzato **uno e un solo**
|
|
571
602
|
campo (§4.2); la §2 dice che cio' che non c'e' si omette, ma un backend che serializza tutte le
|
|
572
603
|
proprieta' — `System.Text.Json` senza `IgnoreNullValues` lo fa di default — manda
|
|
@@ -800,6 +831,10 @@ due misure sono token: `--fb-dialog-width` (1400px) e `--fb-dialog-height` (860p
|
|
|
800
831
|
limitate allo spazio disponibile. La larghezza e' quella che serve al compositore dello screen
|
|
801
832
|
dinamico, che e' a due pannelli.
|
|
802
833
|
|
|
834
|
+
La finestra di una **risorsa** ha una misura sua — `--fb-resource-dialog-width` (760px) e
|
|
835
|
+
`--fb-resource-dialog-height` (720px) — perche' dentro c'e' una colonna sola di campi: la misura
|
|
836
|
+
del compositore lascerebbe due terzi di bianco.
|
|
837
|
+
|
|
803
838
|
Nota sugli archi: il colore si imposta valorizzando le custom properties del tema di
|
|
804
839
|
@foblex/flow (`--ff-connection-color`, `--ff-marker-color`) invece di sovrascrivere le sue
|
|
805
840
|
regole, perche' i selettori hanno la stessa specificita' e chi vince dipenderebbe dall'ordine
|
|
@@ -837,7 +872,7 @@ distribuire e nessuna dipendenza da un font di icone dell'applicazione ospite.
|
|
|
837
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 |
|
|
838
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** |
|
|
839
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 |
|
|
840
|
-
| 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) |
|
|
841
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` |
|
|
842
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 |
|
|
843
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` |
|