@esfaenza/flow-builder 20.3.17 → 20.3.19

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
@@ -94,7 +94,7 @@ l'attributo di scope di Angular, quindi un CSS incapsulato non li raggiunge.
94
94
 
95
95
  | Output | Quando |
96
96
  |---|---|
97
- | `saved` | dopo un salvataggio riuscito, con `FlowSaveResult` |
97
+ | `saved` | dopo un salvataggio riuscito, con `FlowSaveResult`. Lo emette anche «Duplica», e in quel caso `flowName` e' quello della **copia**: la sessione si e' spostata su di essa, quindi l'host che tiene il nome da parte deve adottarlo |
98
98
  | `activated` | dopo un'attivazione riuscita |
99
99
 
100
100
  Il componente vuole un'altezza: `<fb-flow-builder style="height: 100vh">`, oppure un
@@ -123,7 +123,7 @@ sono opzionali e rifiutano con `MissingService` se non sovrascritti.
123
123
  | `createVersion(flowName, request?)` | astratto |
124
124
  | `activateVersion(flowName, version)` | astratto |
125
125
  | `deactivateFlow(flowName)` | astratto |
126
- | `cloneFlow`, `deleteVersion`, `deleteFlow` | opzionali |
126
+ | `cloneFlow`, `deleteVersion`, `deleteFlow` | opzionali — senza `cloneFlow` «Duplica» resta disponibile e ripiega su `createFlow` |
127
127
 
128
128
  | §6.3 Validazione | |
129
129
  |---|---|
@@ -149,7 +149,7 @@ sono opzionali e rifiutano con `MissingService` se non sovrascritti.
149
149
  | §6.5 Esecuzione | |
150
150
  |---|---|
151
151
  | `startInterview`, `respondToScreen`, `resumeInterview`, `inspectInterview`, `abandonInterview` | opzionali — senza, il pannello «Prova» segnala che la funzione non c'e' |
152
- | `completeStageStep(request)` | opzionale — conclude uno step di orchestrazione (§5.13) |
152
+ | `completeStageStep(request)` | opzionale — conclude uno step di orchestrazione (§5.14) |
153
153
 
154
154
  **Errori.** Ogni metodo, in caso di rifiuto, deve fallire con un `FlowApiError`
155
155
  categorizzato (§10). L'editor si comporta in base alla `category`, mai leggendo il
@@ -215,7 +215,7 @@ orchestrazione ne resta fuori: la §7 non lo comprende.
215
215
 
216
216
  Un tipo con un **discriminatore** compare come piu' voci, una per valore: il Collection
217
217
  Processor e' «Ordina» e «Filtra», non «ordina o filtra». Sono due gesti diversi — un `Sort`
218
- vuole `sortOptions`, un `Filter` vuole condizioni (§5.5) — e sceglierli dalla palette evita di
218
+ vuole `sortOptions`, un `Filter` vuole condizioni (§5.6) — e sceglierli dalla palette evita di
219
219
  sceglierli dopo, dentro il form. L'elemento nasce con il discriminatore già scritto, con la
220
220
  label della variante (da cui viene anche il nome tecnico) e con il glifo della variante, lo
221
221
  stesso che avra' sul canvas. `core/element-variants.ts` tiene la mappa tipo → campo del
@@ -254,6 +254,38 @@ Tre cose che il modello non mostra e il form dice:
254
254
  Il riordino e l'annidamento si fanno trascinando (`@angular/cdk/drag-drop`, senza drop list: il
255
255
  bersaglio si calcola dal DOM) oppure con i comandi «su / giu' / porta fuori».
256
256
 
257
+ **Screen action (§5.2).** Un campo che l'utente compila puo' **innescare un'action** i cui risultati
258
+ finiscono negli altri campi della stessa schermata: e' il caso «scrivi il codice fiscale e nome e
259
+ cognome compaiono da soli», e senza di essa lo si farebbe spezzando lo screen in due con un elemento
260
+ Action in mezzo. Si modellano nelle proprieta' della **schermata** (cliccare l'anteprima fuori dai
261
+ campi), in **due** elenchi che il contratto tiene separati — `actions` e `triggers` — perche' piu'
262
+ trigger possono invocare la stessa action. Identificazione e parametri sono quelli di un elemento
263
+ Action, `ACTION_UNKNOWN` e `PARAMETER_UNKNOWN` compresi.
264
+
265
+ Le tre cose che riguardano l'editor, e non il runtime:
266
+
267
+ - **il picker della destinazione e' allargato qui e solo qui.** L'`assignToReference` di un output
268
+ accetta anche i **campi di questa schermata**, che ovunque altrove sono di sola lettura:
269
+ `POST /flows/references/writable` continua a escluderli — e giustamente, un Assignment che ci
270
+ scrive resta `TARGET_NOT_WRITABLE`. L'allargamento e' quindi un parametro del chiamante
271
+ (`<fb-reference-picker [extraReferences]>`), non un comportamento del picker;
272
+ - **il nome dell'action sta nello spazio dei nomi del flow** (§3.3): con l'output automatico e' la
273
+ radice di `Cerca.nome`, quindi un'omonimia con una variabile — o con una `Structure` chiamata come
274
+ lei — renderebbe ambiguo quel riferimento. `usedNames` lo comprende, e il form lo dice con
275
+ `NAME_DUPLICATED` come per il nome di uno step;
276
+ - **un'action senza output e' un avviso** (`SCREEN_ACTION_WITHOUT_OUTPUTS`): viene invocata e il suo
277
+ risultato si perde. L'output automatico non e' la cura per tutti i casi — rende il risultato
278
+ leggibile come `Cerca.nome` ma **non scrive in nessun campo**: e' la forma per una condizione, non
279
+ per precompilare;
280
+ - **un trigger senza campo e senza `initBehavior` non scattera' mai**
281
+ (`SCREEN_TRIGGER_WITHOUT_CAUSE`), e l'unico `initBehavior` ammesso e' `runOnLoad` — il
282
+ `runOnRevisit` della specifica Salesforce e' `SCREEN_TRIGGER_INIT_BEHAVIOR_UNKNOWN`, e vale la
283
+ pena saperlo perche' chi arriva da quella specifica lo scrive per abitudine.
284
+
285
+ Le action si aprono **una alla volta**: i cataloghi delle action e dei loro parametri dipendono da
286
+ `actionType`/`actionName`, e tenerne N in volo sarebbe N volte la corsa fra risposte che l'inspector
287
+ dell'Action risolve scartando quelle superate.
288
+
257
289
  Sullo stage di orchestrazione il form dice le tre cose che il modello non mostra: gli step
258
290
  **non sono una sequenza** (le frecce riordinano l'esame, non l'esecuzione), ingresso e uscita
259
291
  non sono simmetriche (ingresso falso = step saltato, uscita falsa = stage in **stallo**), e
@@ -275,7 +307,7 @@ membro calcolato si legge in una condizione ma assegnarlo e' `TARGET_NOT_WRITABL
275
307
  vale dentro `<fb-reference-picker>`, dove `Richiesta.Ragione` si propone e si verifica
276
308
  (`STRUCTURE_MEMBER_UNKNOWN`). Un Transform con target `Structure` compone l'istanza intera in un
277
309
  elemento solo: lì `outputFieldApiName` e' il nome di un membro, e il form lo dice invece di far
278
- indovinare (§5.12).
310
+ indovinare (§5.13).
279
311
 
280
312
  **Percorsi annidati.** I percorsi con il punto non sono piu' un buco nero: la validazione li segue,
281
313
  e quindi li segue l'editor. `core/path-navigation.ts` naviga la catena una tappa alla volta —
@@ -306,6 +338,13 @@ richieste — `getWritableReferences` per le proposte, `getReferences` per le ra
306
338
  scrivibilita' e' del **percorso** e non della radice: un `$User.Anagrafica.Citta` scritto a mano e'
307
339
  `TARGET_NOT_WRITABLE`, non un nome che non esiste.
308
340
 
341
+ C'e' **un** posto in cui alle proposte si aggiunge qualcosa che la primitiva non restituisce, e
342
+ `extraReferences` esiste solo per quello: l'output di una **screen action**, che si assegna a un campo
343
+ della schermata che si sta modificando (§5.2). Non e' una scorciatoia per riferimenti che il backend
344
+ non conosce — quei campi restano esclusi da `references/writable`, e altrove assegnarli e'
345
+ `TARGET_NOT_WRITABLE`: e' l'unico punto in cui la regola del contratto e' diversa, e per questo
346
+ l'elenco lo passa il chiamante.
347
+
309
348
  **Le globali si navigano come le risorse.** Un percorso dichiarato dall'host puo' portare un
310
349
  contenitore, e allora `objectType` dice di che tipo: `$User.Anagrafica.Citta` si propone e si
311
350
  verifica come `Richiesta.Ragione`. La regola da non sbagliare e' che vince il **prefisso dichiarato
@@ -321,7 +360,7 @@ Su una destinazione la colonna che decide non e' la stessa nei due mondi: un mem
321
360
  `isWritable`, un campo no. Fuori da un Create o da un Update il contesto non c'e' — un Assignment su
322
361
  `Cliente.Codice` non sa se quel record verra' creato o aggiornato — quindi lì basta `isCreateable`
323
362
  **oppure** `isUpdateable`, e un campo che non e' ne' l'uno ne' l'altro e' `TARGET_NOT_WRITABLE` in
324
- qualunque contesto (§5.7).
363
+ qualunque contesto (§5.8).
325
364
 
326
365
  Dei tre esiti di `describeStructure` il picker mostra tre messaggi diversi, perche' portano a
327
366
  gesti opposti: con l'elenco autorevole un nome fuori elenco e' un errore; con `members: []` la
@@ -340,7 +379,7 @@ ma un nome fuori catalogo viene segnalato subito, prima che il backend risponda
340
379
  dell'oggetto referenziato e l'ultimo segmento si verifica con l'uso richiesto (§4.4). Il campo si chiede sempre con l'uso giusto (`filterable`, `sortable`,
341
380
  `updateable`, `createable`), che decide sia l'elenco sia il testo dell'avviso: "non filtrabile",
342
381
  "non aggiornabile" e "non valorizzabile alla creazione" sono errori diversi. In particolare
343
- `createable` e `updateable` **non** sono sinonimi (§5.7): un Create propone i primi, un Update i
382
+ `createable` e `updateable` **non** sono sinonimi (§5.8): un Create propone i primi, un Update i
344
383
  secondi, e il validatore usa il codice giusto per l'elemento (`FIELD_NOT_CREATEABLE` /
345
384
  `FIELD_NOT_UPDATEABLE`). Per lo stesso motivo l'editor non da' per scontato che `Id` sia
346
385
  filtrabile: su una chiave composta porta la forma canonica della chiave e non e' filtrabile,
@@ -431,6 +470,15 @@ non e' una garanzia di correttezza.
431
470
  attivazione bloccata finche' ci sono errori, eliminazione dietro una conferma esplicita che
432
471
  spiega il rischio per le esecuzioni sospese.
433
472
 
473
+ **Duplica.** Il flow salvato sotto un altro nome, alla versione 1 (§6.2): il comando chiede nome
474
+ tecnico e nome visibile della copia, e l'editor **continua sulla copia** — restare sull'originale
475
+ farebbe finire il salvataggio successivo nel flow sbagliato. Due strade, e la differenza conta:
476
+ su un documento pulito si usa `cloneFlow`, che copia lato backend; con modifiche non salvate la
477
+ copia si crea con `createFlow` mandando il documento in mano, perche' `cloneFlow` copierebbe la
478
+ versione **salvata** e le modifiche appena scritte spariscono senza dirlo. La stessa strada e' il
479
+ ripiego dove `cloneFlow` non c'e' (e' opzionale). Un nome già usato lo rifiuta il backend con
480
+ `AlreadyExists`, e il modulo resta aperto sul nome da correggere.
481
+
434
482
  **Prova.** Interview con form generato dalle variabili di input, form generico per gli screen
435
483
  (valori in ingresso più i campi da restituire), `canGoBack` / `canFinish` / `canPause` come
436
484
  verita' runtime, traccia navigabile e tabella delle risorse — con l'avviso in chiaro che la
@@ -550,7 +598,7 @@ distribuire e nessuna dipendenza da un font di icone dell'applicazione ospite.
550
598
  | 2 | `assignNextValueToReference` di un Collection Processor **non** e' la destinazione | `CollectionProcessorInspectorComponent`: il campo si chiama «Elemento in esame», e un callout dice che il risultato e' l'output automatico dell'elemento |
551
599
  | 3 | Gli **output automatici** sono riferimenti validi anche se non dichiarati | `ReferencePickerComponent` chiede l'elenco a `POST /flows/references`, che li include; non ricostruisce nulla lato client |
552
600
  | 4 | Cancellare una condizione richiede di **riscrivere `conditionLogic`** | `condition-logic.util.ts`: `removeCondition` e `moveCondition` rimappano gli indici 1-based; un termine rimasto orfano diventa `?` e viene segnalato |
553
- | 5 | Node e risorse condividono **un unico spazio di nomi** | `FlowDocumentStore.usedNames` unisce i due insiemi e `checkFlowName` confronta case-insensitive; pannello risorse e inspector usano lo stesso controllo |
601
+ | 5 | Node e risorse condividono **un unico spazio di nomi** | `FlowDocumentStore.usedNames` unisce **cinque** insiemi — node, risorse, step di orchestrazione, campi di screen dinamico e screen action, cioe' tutto cio' il cui nome e' la radice di un riferimento (§3.3) — e `checkFlowName` confronta case-insensitive; pannello risorse e inspector usano lo stesso controllo |
554
602
  | 6 | `processType` non e' decorativo | Banner in cima all'editor per `AutoLaunched` + screen, `Orchestration` senza stage, `Screen` senza screen; la palette segnala lo Screen incompatibile. Il `processType` viaggia anche a `getDictionaries`, perche' decide quali globali esistono |
555
603
  | 7 | Le **regole di una Decision sono ordinate** | `DecisionInspectorComponent`: regole numerate, frecce di riordino, callout «valutate dall'alto verso il basso, si ferma alla prima vera» |
556
604
  | 8 | **Rinominare non aggiorna i riferimenti** | `FlowDocumentStore.renameNode` cammina il documento e riscrive ogni campo di riferimento, incluso il caso navigato (`Vecchio.Campo` → `Nuovo.Campo`); l'inspector dice quante occorrenze verranno toccate |
@@ -564,6 +612,9 @@ distribuire e nessuna dipendenza da un font di icone dell'applicazione ospite.
564
612
  | 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) |
565
613
  | 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` |
566
614
  | 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 |
615
+ | 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` |
616
+ | 20 | **La validazione di uno screen dinamico la fa il server e non fa avanzare il flow** | Riguarda il runtime, non l'editor: `EXECUTION_FRONTEND.md` §5.5 e §6.2, e lato client `flow-execution` (`isValidationRetry`, `indexValidationErrors`). Qui l'editor fa la sua parte a monte: `validationRule` si scrive con `<fb-formula-editor>`, che la fa verificare mentre si digita (§6.3) |
617
+ | 21 | **Un campo nascosto viene azzerato all'invio** | L'inspector lo dice dove si scrive la `visibilityRule`: la regola si rivaluta sui valori appena inviati e il campo che sparisce **perde** il valore. È l'unica cosa che chi disegna il flow non puo' dedurre dal metadata, e per questo sta nel form e non solo in questa tabella |
567
618
 
568
619
  Altre regole del contratto rispettate: liste vuote omesse invece di scritte come `[]` (§2),
569
620
  `filterLogic` mostrato **solo** dove il modello lo prevede (§4.4), `fullName` / `status` mai