@esfaenza/flow-builder 20.3.23 → 20.3.25

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 CHANGED
@@ -142,7 +142,8 @@ sono opzionali e rifiutano con `MissingService` se non sovrascritti.
142
142
  | `listScripts` / `listScriptParameters` | astratti |
143
143
  | `listForms(kind?)` / `listFormParameters` | astratti — **un catalogo, due ruoli** (§5.1, §5.2): le schermate intere di uno Screen (`formName`) e i componenti di uno screen dinamico (`extensionName`) stanno nello stesso elenco e si distinguono per `formKind`. `kind` vale `Form`, `Component` o assente per tutto; una voce **senza** `formKind` vale `Any` e resta proponibile in entrambi i posti, perche' un catalogo che il ruolo non lo dichiara non deve vietare tutto. Usare l'uno al posto dell'altro e' `FORM_KIND_MISMATCH`, che e' un errore **diverso** da «il nome non esiste». I parametri si chiedono per nome, uguali per i due ruoli |
144
144
  | `listEnumTypes`, `listEvents`, `listSubflowCandidates` | astratti |
145
- | `describeObject`, `listFieldValues` | opzionali |
145
+ | `describeObject` | opzionale |
146
+ | `listFieldValues(object, field)` | opzionale — i valori ammessi di un campo a **scelta chiusa** (`hasClosedValueSet`, §6.4), cioe' l'altra meta' degli insiemi chiusi: quelli di un `Enum` sono del **tipo** (`listEnumValues`), questi della **colonna** — `Ordine.Stato` e `Attivita.Stato` possono ammettere valori diversi pur essendo due `String`, ed e' perche' serve la coppia. Lista vuota = "non lo so": il valore si scrive a mano |
146
147
  | `listEnumValues(enumType)` | opzionale — i **valori** di un tipo di enumerazione, cioe' i nomi scrivibili in `enumValue` (§4.2, §4.6). `listEnumTypes` e' l'altra meta' e non basta: quella dice quali tipi esistono, questa quali valori ha un tipo. `enumType` e' esattamente l'`objectType` della risorsa, del parametro o del **membro** di una classe (§4.7.1): la risposta e' del tipo, non del punto di uso, e la cache e' per nome del tipo. Lista vuota = "non lo so" — il valore si scrive a mano, e un tipo sconosciuto risponde vuoto, non 404 |
147
148
  | `listStructures`, `describeStructure(className)` | opzionali — le classi e i loro membri per le risorse `Structure` (§4.7). `listStructures` e' l'**elenco delle classi** senza membri; `describeStructure` restituisce la **descrizione** di una classe (`className`, `label`, `members`), non un array nudo (§4.7.1). Senza, le classi non sono verificabili e il nome si scrive a mano: "non lo so", non "non esiste". I tre esiti sono distinti: `members` popolato = elenco autorevole, `members: []` = membri non dichiarati (si digita, nessuna accusa), rifiuto `StructureNotFound` = classe non registrata (si segnala la **classe**) |
148
149
 
@@ -163,7 +164,7 @@ throw new FlowApiError('VersionConflict', 'Ha salvato mrossi.', undefined, 'mros
163
164
  ```
164
165
 
165
166
  Un'implementazione completa e commentata sta in
166
- [`projects/demo/src/app/backend/in-memory-flow-builder-api.ts`](../demo/src/app/backend/in-memory-flow-builder-api.ts):
167
+ [`projects/flow-builder-example/src/app/backend/in-memory-flow-builder-api.ts`](../flow-builder-example/src/app/backend/in-memory-flow-builder-api.ts):
167
168
  copre tutte le primitive, il ciclo di vita, la concorrenza ottimistica e un esecutore finto,
168
169
  senza una sola richiesta di rete.
169
170
 
@@ -324,6 +325,19 @@ con la via d'uscita: scrivere quel risultato in una variabile.
324
325
  `Object` / `Enum` / `Structure`, `scale` solo sui numerici, costanti che non possono referenziare
325
326
  risorse, `stageOrder` distinti.
326
327
 
328
+ **Dynamic choice set.** Le sorgenti sono **tre e si escludono a vicenda** (§5.2): una collection
329
+ del flow, una query su un'entita', i valori di un **tipo enum**. Nel form sono tre pulsanti e non
330
+ tre campi da riempire a caso: sceglierne una cancella le altre — dichiararne due e'
331
+ `CHOICE_SET_SOURCE_AMBIGUOUS` — e cancella anche i campi citati, perche' `Label` non e' un campo
332
+ di un'entita' e `Ragione_Sociale` non e' una proprieta' di un valore di enum. Sulla sorgente enum
333
+ cambiano due cose: il tipo si sceglie da `listEnumTypes` e fuori catalogo e' un **errore**
334
+ (`ENUM_TYPE_UNKNOWN`, l'elenco qui e' autorevole quando non e' vuoto), e i campi citabili sono le
335
+ tre proprieta' di un valore — `Name`, `Label`, `NumericValue` — che arrivano dal dizionario
336
+ (`enumChoiceSetFields`) e non da un catalogo di campi. Le sa `core/enum-choice-set.util.ts`,
337
+ compreso il **tipo** di ciascuna: senza, il valore di un filtro su `NumericValue` sarebbe una
338
+ casella di testo. `displayField` e `valueField` hanno un default (`Label` e `Name`) e il form li
339
+ mostra come tali, cosi' non finiscono nel documento senza motivo.
340
+
327
341
  **Classi (`Structure`).** L'ottavo tipo di dato non e' un doppione di `Object` (§4.7): di
328
342
  un'istanza di classe il flow legge e scrive i **membri**. Cambia quindi il form: la classe si
329
343
  scoglie con `<fb-structure-picker>` e la sua assenza e' un **errore** — senza classe il runtime
@@ -428,6 +442,18 @@ vuoto resta "non lo so" — primitiva non esposta, tipo senza valori dichiarati,
428
442
  da scegliere — e allora il valore si digita; con l'elenco popolato un valore fuori elenco e' un
429
443
  **avviso**, perche' nessun codice della §7 lo blocca ed e' l'editor ad accorgersene prima del runtime.
430
444
 
445
+ **Valori di un campo a scelta chiusa.** È lo stesso problema degli enum sull'altra meta' dello
446
+ schema: un campo che dichiara `hasClosedValueSet` ammette pochi valori e nessun tipo li porta con
447
+ se', quindi si chiedono con `listFieldValues(object, field)` (§4.4, §6.4). Li propone
448
+ `<fb-field-value-picker>`, che il `<fb-value-editor>` monta al posto della casella di testo quando
449
+ chi lo usa gli passa `[valueSet]`: oggi lo fa il **filtro sui record**, dove il campo e la sua
450
+ entita' si sanno — anche in fondo a un percorso di relazione, perche' il tipo dell'ultimo segmento lo
451
+ naviga `core/reference-path` e con lui arriva l'insieme chiuso. Nel documento va il **valore**, non
452
+ l'etichetta: «Da approvare» aiuta a riconoscere `DaApprovare` ma non e' cio' che il motore confronta.
453
+ Elenco vuoto = "non lo so" (primitiva non esposta, campo senza insieme dichiarato) e valore fuori
454
+ elenco = **avviso**, come per gli enum: la §7 non ha un codice per questo, e un filtro con un valore
455
+ inesistente non trova nessun record senza che niente lo segnali.
456
+
431
457
  **Formule.** L'espressione va al motore di regole e la sua sintassi resta del motore: la libreria
432
458
  non ha nessun parser. Cio' che ha e' il **controllo**, `validateFormula` (`POST /flows/validate-formula`,
433
459
  §6.3), chiesto con debounce mentre si digita: risponde lo stesso motore, e i suoi rilievi portano la
@@ -525,7 +551,7 @@ questo pannello non ci sarebbe **nessun** posto in cui vedere cosa e' successo.
525
551
  dati personali compresi: l'avviso e' in chiaro. Il pannello non conduce niente: guarda, e basta.
526
552
 
527
553
  Come si implementa l'altra metà si vede nella demo
528
- (`projects/demo/src/app/runner`), e la scelta interessante e' **quando** aprire una finestra: un
554
+ (`projects/flow-builder-example/src/app/runner`), e la scelta interessante e' **quando** aprire una finestra: un
529
555
  flow che non ha niente da chiedere finisce da solo e l'esito torna subito all'editor, mentre uno
530
556
  interattivo apre il runner e restituisce l'ultimo risultato alla chiusura — così la traccia resta
531
557
  comunque lì dove si stava lavorando. Il runner guida l'interview con le primitive della §6.5,
@@ -655,7 +681,7 @@ distribuire e nessuna dipendenza da un font di icone dell'applicazione ospite.
655
681
  | 9 | `Step` ed `Experiment` non sono supportati; `OrchestratedStage` lo e' | I due non supportati sono filtrati dalla palette via `isSupported` e, se arrivano da un import, l'inspector li mostra in sola lettura spiegando perche'. Lo stage ha il suo form: step non presentati come sequenza, e la condizione che referenzia l'output di un altro step segnalata con la via d'uscita |
656
682
  | 10 | Un `Delete` senza filtri e' un **errore**, un `Update` senza filtri un **avviso** | `RecordWriteInspectorComponent`: severita' diverse, e l'update di massa chiede una conferma esplicita |
657
683
  | 11 | Non cablare enum e operatori | Ogni tendina legge da `getDictionaries()`; le mappe locali intervengono solo come fallback quando il dizionario non e' disponibile |
658
- | 12 | Il **token di continuazione e' opaco** | Non lo tocca nessuno nella libreria: l'editor non esegue, quindi il token nasce e muore nel runner dell'ospite. Quello della demo (`projects/demo/src/app/runner/interview-runner.component.ts`) lo rimanda tale e quale, non lo legge e non lo mette in nessun URL |
684
+ | 12 | Il **token di continuazione e' opaco** | Non lo tocca nessuno nella libreria: l'editor non esegue, quindi il token nasce e muore nel runner dell'ospite. Quello della demo (`projects/flow-builder-example/src/app/runner/interview-runner.component.ts`) lo rimanda tale e quale, non lo legge e non lo mette in nessun URL |
659
685
  | 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 |
660
686
  | 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** |
661
687
  | 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 |