@esfaenza/flow-builder 20.3.2 → 20.3.4

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,6 +142,7 @@ sono opzionali e rifiutano con `MissingService` se non sovrascritti.
142
142
  | `listForms` / `listFormParameters` | astratti |
143
143
  | `listEnumTypes`, `listEvents`, `listSubflowCandidates` | astratti |
144
144
  | `describeObject`, `listFieldValues` | opzionali |
145
+ | `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**) |
145
146
 
146
147
  | §6.5 Esecuzione | |
147
148
  |---|---|
@@ -202,6 +203,15 @@ qualsiasi.
202
203
  dalla mappa delle uscite invece di essere «ramo di errore» per tutti: su uno stage di
203
204
  orchestrazione quel ramo e' lo **step rifiutato**, non un guasto.
204
205
 
206
+ Un tipo con un **discriminatore** compare come piu' voci, una per valore: il Collection
207
+ Processor e' «Ordina» e «Filtra», non «ordina o filtra». Sono due gesti diversi — un `Sort`
208
+ vuole `sortOptions`, un `Filter` vuole condizioni (§5.5) — e sceglierli dalla palette evita di
209
+ sceglierli dopo, dentro il form. L'elemento nasce con il discriminatore già scritto, con la
210
+ label della variante (da cui viene anche il nome tecnico) e con il glifo della variante, lo
211
+ stesso che avra' sul canvas. `core/element-variants.ts` tiene la mappa tipo → campo del
212
+ discriminatore; i valori restano nel dizionario del backend (`collectionProcessorTypes`), e
213
+ senza quel dizionario il tipo torna a essere una voce sola.
214
+
205
215
  **Inspector.** Un form per ogni tipo supportato: Start, Screen, Assignment, Decision, Loop,
206
216
  Collection Processor, Get / Create / Update / Delete / Rollback Records, Action, Script,
207
217
  Subflow, Wait, Custom Error, Transform, Orchestrated Stage. Più l'intestazione comune con la
@@ -215,8 +225,29 @@ fa fallire l'interview. Una condizione che referenzia l'output di un altro step
215
225
  con la via d'uscita: scrivere quel risultato in una variabile.
216
226
 
217
227
  **Risorse.** I sette tipi, con i vincoli visibili: `dataType` obbligatorio, `objectType` per
218
- `Object` / `Enum`, `scale` solo sui numerici, costanti che non possono referenziare risorse,
219
- `stageOrder` distinti.
228
+ `Object` / `Enum` / `Structure`, `scale` solo sui numerici, costanti che non possono referenziare
229
+ risorse, `stageOrder` distinti.
230
+
231
+ **Classi (`Structure`).** L'ottavo tipo di dato non e' un doppione di `Object` (§4.7): di
232
+ un'istanza di classe il flow legge e scrive i **membri**. Cambia quindi il form: la classe si
233
+ scoglie con `<fb-structure-picker>` e la sua assenza e' un **errore** — senza classe il runtime
234
+ non ha nulla da istanziare — mentre il campo «valore iniziale» non c'e' affatto, perche' non
235
+ esiste un `structureValue` e la variabile parte con un'istanza vuota. I membri si scelgono con
236
+ `<fb-structure-member-picker>`, e nelle destinazioni si propongono **solo** quelli scrivibili: un
237
+ membro calcolato si legge in una condizione ma assegnarlo e' `TARGET_NOT_WRITABLE`. Lo stesso
238
+ vale dentro `<fb-reference-picker>`, dove i membri di una variabile `Structure` sono l'unica
239
+ eccezione ai percorsi non verificati: `Richiesta.Ragione` si propone e il **primo** segmento si
240
+ verifica (`STRUCTURE_MEMBER_UNKNOWN`), oltre quello si torna a "non lo so" — la descrizione della
241
+ classe e' piatta, e i membri di una classe annidata sono una seconda chiamata (§4.7.1). Un
242
+ Transform con target `Structure` compone l'istanza intera in un elemento solo: lì
243
+ `outputFieldApiName` e' il nome di un membro, e il form lo dice invece di far indovinare (§5.12).
244
+
245
+ Dei tre esiti di `describeStructure` il picker mostra tre messaggi diversi, perche' portano a
246
+ gesti opposti: con l'elenco autorevole un nome fuori elenco e' un errore; con `members: []` la
247
+ classe e' valida ma i membri non sono dichiarati e il nome si **digita**, senza accuse; con un
248
+ 404 (`StructureNotFound`) e' la **classe** a essere sbagliata, e il messaggio manda a correggere
249
+ quella invece del membro. L'intestazione dell'elenco usa la `label` della classe, che e' la
250
+ ragione per cui la risposta ha un involucro invece di essere un array.
220
251
 
221
252
  **Oggetti e campi.** Ogni punto che chiede un'entita' o un suo campo usa lo stesso controllo:
222
253
  `<fb-object-picker>` e `<fb-field-picker>`, una casella con autocomplete che filtra il catalogo
@@ -226,18 +257,31 @@ campo di testo cieco. La scrittura libera e' voluta — i percorsi di relazione
226
257
  (`Cliente.Citta`) non sono enumerabili e il catalogo dell'host puo' essere incompleto — ma un
227
258
  nome fuori catalogo viene segnalato subito, prima che il backend risponda `OBJECT_UNKNOWN` o
228
259
  `FIELD_UNKNOWN`. Il campo si chiede sempre con l'uso giusto (`filterable`, `sortable`,
229
- `updateable`), che decide sia l'elenco sia il testo dell'avviso: "non filtrabile" e "non
230
- aggiornabile" sono errori diversi. Restano `<select>` i dizionari chiusi tipi di dato,
231
- operatori, enumerazioni dove non c'e' niente da scrivere a mano.
232
-
233
- Lo stesso controllo, nella variante `<fb-name-picker>`, vale per i nomi che dipendono dal
234
- contesto e non da un catalogo di schema: il flow di uno step in background e dei suoi
235
- evaluation flow, il flow invocato da un Subflow, le variabili di input e output **del flow
236
- invocato**. Qui l'elenco arriva da chi ospita il picker (`listSubflowCandidates`, le variabili
237
- della definizione caricata), e un elenco vuoto resta "non lo so": il campo si scrive a mano e
238
- non si accusa nessun nome. Con l'elenco popolato, invece, un nome che non c'e' e' segnalato —
239
- ed e' la differenza rispetto al `datalist` che questi campi usavano prima, che accettava
240
- qualunque cosa in silenzio.
260
+ `updateable`, `createable`), che decide sia l'elenco sia il testo dell'avviso: "non filtrabile",
261
+ "non aggiornabile" e "non valorizzabile alla creazione" sono errori diversi. In particolare
262
+ `createable` e `updateable` **non** sono sinonimi (§5.7): un Create propone i primi, un Update i
263
+ secondi, e il validatore usa il codice giusto per l'elemento (`FIELD_NOT_CREATEABLE` /
264
+ `FIELD_NOT_UPDATEABLE`). Per lo stesso motivo l'editor non da' per scontato che `Id` sia
265
+ filtrabile: su una chiave composta porta la forma canonica della chiave e non e' filtrabile,
266
+ quindi l'editor dice di filtrare per le colonne della chiave invece di far cercare un campo che
267
+ nell'elenco non c'e'. Restano `<select>` i dizionari chiusi tipi di dato, operatori,
268
+ enumerazioni dove non c'e' niente da scrivere a mano.
269
+
270
+ Lo stesso controllo, nella variante `<fb-name-picker>`, vale per **ogni altro nome che il flow
271
+ prende da fuori**: tipo di action e action, script, form, i nomi dei loro parametri di ingresso
272
+ e di uscita, il flow di uno step in background e dei suoi evaluation flow, il flow invocato da
273
+ un Subflow e le variabili di input e output **del flow invocato**. Qui l'elenco arriva da chi
274
+ ospita il picker — il catalogo già caricato per altri motivi, `listSubflowCandidates`, le
275
+ variabili della definizione caricata — perche' dipende dal contesto: le action dipendono dal
276
+ tipo scelto, i parametri dall'action, le variabili dal subflow.
277
+
278
+ Un elenco vuoto resta "non lo so": il campo si scrive a mano e non si accusa nessun nome. Con
279
+ l'elenco popolato, un nome che non c'e' e' segnalato, e con la **gravita' giusta**: un'action,
280
+ un form, uno script o un parametro inesistenti sono errori che bloccano l'attivazione
281
+ (`ACTION_UNKNOWN`, `FORM_UNKNOWN`, `PARAMETER_UNKNOWN`) e si mostrano in rosso; un flow senza
282
+ versione attiva e' un avviso. Prima questi campi erano `<select>` con un'opzione sintetica
283
+ «(non nel catalogo)» per non perdere il valore, oppure un `datalist` che accettava qualunque
284
+ cosa in silenzio: il primo non si poteva cercare, il secondo non diceva niente.
241
285
 
242
286
  **Problemi.** Pannello con filtro per gravita', navigazione all'elemento con un clic,
243
287
  validazione su pausa di digitazione (debounce 400 ms) e l'avvertenza che l'assenza di rilievi
@@ -367,6 +411,7 @@ distribuire e nessuna dipendenza da un font di icone dell'applicazione ospite.
367
411
  | 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 |
368
412
  | 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** |
369
413
  | 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 |
414
+ | 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 primo segmento; 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) |
370
415
 
371
416
  Altre regole del contratto rispettate: liste vuote omesse invece di scritte come `[]` (§2),
372
417
  `filterLogic` mostrato **solo** dove il modello lo prevede (§4.4), `fullName` / `status` mai