@esfaenza/flow-builder 20.3.39 → 20.3.41
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 +32 -3
- package/fesm2022/esfaenza-flow-builder.mjs +395 -11
- package/fesm2022/esfaenza-flow-builder.mjs.map +1 -1
- package/index.d.ts +138 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -349,7 +349,11 @@ Tre cose che il modello non mostra e il form dice:
|
|
|
349
349
|
- le regole di visibilita' si rivalutano **sui valori appena inviati**, i campi nascosti vengono
|
|
350
350
|
**azzerati** e solo i visibili vengono validati;
|
|
351
351
|
- `choiceReferences` accetta **solo** `Choice` e `DynamicChoiceSet`, e gli output automatici di un
|
|
352
|
-
`ComponentInstance` sono esclusivi con i suoi `outputParameters
|
|
352
|
+
`ComponentInstance` sono esclusivi con i suoi `outputParameters`;
|
|
353
|
+
- `autoSelectSingleChoice` fa prendere al campo l'**unica** opzione risolta, quando e' una sola: e'
|
|
354
|
+
la tendina che dipende da un'altra tendina — i CAP di un comune — dove chiedere di scegliere non
|
|
355
|
+
decide niente. La spunta compare solo dove il tipo `acceptsChoices`, e altrove e'
|
|
356
|
+
`SCREEN_FIELD_CONFIGURATION_INVALID` (avviso).
|
|
353
357
|
|
|
354
358
|
Il riordino e l'annidamento si fanno trascinando (`@angular/cdk/drag-drop`, senza drop list: il
|
|
355
359
|
bersaglio si calcola dal DOM) oppure con i comandi «su / giu' / porta fuori».
|
|
@@ -400,7 +404,9 @@ Le tre cose che riguardano l'editor, e non il runtime:
|
|
|
400
404
|
- **un trigger senza campo e senza `initBehavior` non scattera' mai**
|
|
401
405
|
(`SCREEN_TRIGGER_WITHOUT_CAUSE`), e l'unico `initBehavior` ammesso e' `runOnLoad` — il
|
|
402
406
|
`runOnRevisit` della specifica Salesforce e' `SCREEN_TRIGGER_INIT_BEHAVIOR_UNKNOWN`, e vale la
|
|
403
|
-
pena saperlo perche' chi arriva da quella specifica lo scrive per abitudine.
|
|
407
|
+
pena saperlo perche' chi arriva da quella specifica lo scrive per abitudine. Dove il campo
|
|
408
|
+
osservato ha un `defaultValue` il form dice che `runOnLoad` **non serve**: un campo precompilato
|
|
409
|
+
dal flow conta come un campo che ha preso un valore, e l'action gira comunque all'arrivo.
|
|
404
410
|
|
|
405
411
|
Le action si aprono **una alla volta**: i cataloghi delle action e dei loro parametri dipendono da
|
|
406
412
|
`actionType`/`actionName`, e tenerne N in volo sarebbe N volte la corsa fra risposte che l'inspector
|
|
@@ -489,6 +495,16 @@ sapere: le globali sono di sola lettura, membri compresi — le assegnabili sono
|
|
|
489
495
|
`$Flow.ActiveStages` e i campi di `$Record` — e il picker lo dice con `TARGET_NOT_WRITABLE` invece
|
|
490
496
|
di far sembrare il nome inesistente (§5.2).
|
|
491
497
|
|
|
498
|
+
**Uno scope puo' nominarsi da solo.** `$Profile` senza percorso e' un riferimento valido se — e solo
|
|
499
|
+
se — l'host lo dichiara così, con una voce **senza punto** che porta il suo `dataType` e il suo
|
|
500
|
+
`objectType` (§4.1): e' come un host espone l'utente corrente come un'unica istanza invece di
|
|
501
|
+
elencarne i campi, e da lì la navigazione riparte, quindi `$Profile.Livello` si verifica sui membri
|
|
502
|
+
della classe senza che il catalogo dichiari un percorso per ognuno. Il prefisso dichiarato piu' lungo
|
|
503
|
+
e' la stessa regola di prima: la voce senza punto e' il prefisso **vuoto**, cioe' quello che vince
|
|
504
|
+
solo quando nessun altro corrisponde. Dove lo scope dichiara percorsi ma non la voce senza punto,
|
|
505
|
+
`$Profile` da solo resta `GLOBAL_UNKNOWN`: nella demo e' la differenza fra `$Profile` (dichiarato
|
|
506
|
+
così) e `$User` (che dichiara i suoi campi).
|
|
507
|
+
|
|
492
508
|
Su una destinazione la colonna che decide non e' la stessa nei due mondi: un membro porta il proprio
|
|
493
509
|
`isWritable`, un campo no. Fuori da un Create o da un Update il contesto non c'e' — un Assignment su
|
|
494
510
|
`Cliente.Codice` non sa se quel record verra' creato o aggiornato — quindi lì basta `isCreateable`
|
|
@@ -575,6 +591,19 @@ aggiunte. Tre esiti restano distinti e nessuno dei tre e' «formula valida»: pr
|
|
|
575
591
|
stata controllata), `isValid` (verificata davvero, ed e' l'unico caso con la spunta verde) — una
|
|
576
592
|
spunta su un'espressione mai controllata e' peggio di nessuna spunta.
|
|
577
593
|
|
|
594
|
+
**Testo con merge field (§5.12).** Il messaggio di un Custom Error non e' una casella di testo
|
|
595
|
+
qualunque: supporta i segnaposto `{!...}` come il testo di un text template e le scritte di uno screen
|
|
596
|
+
dinamico, e lì servono piu' che altrove — *«L'ordine e' già stato evaso»* senza il numero dell'ordine e'
|
|
597
|
+
meta' messaggio. Lo monta `<fb-merge-text-editor>`, ed e' un componente diverso dall'editor di formule
|
|
598
|
+
perche' il contenuto e' diverso: qui c'e' una **frase**, con dentro delle isole. Tre conseguenze. Offre
|
|
599
|
+
l'**inserimento** di un riferimento (un bottone con l'elenco, piu' i suggerimenti mentre si scrive dentro
|
|
600
|
+
un `{!` aperto), e scrive l'isola intera, graffe comprese: la sintassi non deve stare a memoria. Manda il
|
|
601
|
+
testo al motore **solo se contiene `{!`**, perche' una frase in italiano mandata a un motore di
|
|
602
|
+
espressioni si farebbe accusare parola per parola. E gli esiti restano i tre delle formule, con la stessa
|
|
603
|
+
regola: nessuna spunta su un testo che nessuno ha guardato. Lo stesso controllo avviene nella validazione
|
|
604
|
+
del documento, con `usage: "Text"` e il rilievo sul path `customErrorMessages[n].errorMessage`: un refuso
|
|
605
|
+
dentro una graffa non si scopre davanti a chi sta usando il flow.
|
|
606
|
+
|
|
578
607
|
**Un campo a `null` e' assente.** Il valore ha un campo per tipo e va valorizzato **uno e un solo**
|
|
579
608
|
campo (§4.2); la §2 dice che cio' che non c'e' si omette, ma un backend che serializza tutte le
|
|
580
609
|
proprieta' — `System.Text.Json` senza `IgnoreNullValues` lo fa di default — manda
|
|
@@ -849,7 +878,7 @@ distribuire e nessuna dipendenza da un font di icone dell'applicazione ospite.
|
|
|
849
878
|
| 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
879
|
| 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
880
|
| 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) |
|
|
881
|
+
| 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
882
|
| 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
883
|
| 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
884
|
| 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` |
|