@esfaenza/flow-builder 20.3.9 → 20.3.11

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
@@ -133,7 +133,7 @@ sono opzionali e rifiutano con `MissingService` se non sovrascritti.
133
133
  | §6.4 Dizionari e cataloghi | |
134
134
  |---|---|
135
135
  | `getDictionaries(processType?)` | astratto — `processType` filtra le globali (§4.1) |
136
- | `getReferences(query)` / `getWritableReferences(query)` | astratti |
136
+ | `getReferences(definition)` / `getWritableReferences(definition)` | astratti — prendono il **documento nudo** e restituiscono **tutti** i riferimenti: nel body non c'e' nessun filtro di tipo, e la compatibilita' col campo la decide l'editor (§6.4, §13.17) |
137
137
  | `getConnectorTargets(definition, excluding?)` | astratto |
138
138
  | `getOutline(definition)` | astratto |
139
139
  | `listObjects()`, `listFields(object, usage?)` | astratti |
@@ -254,6 +254,32 @@ Restano fuori i percorsi radicati sul risultato **automatico** di un elemento
254
254
  (`Leggi_Contatti.Owner.Name`): la validazione non li verifica, e l'editor non accusa cio' che il
255
255
  backend non verifica.
256
256
 
257
+ Il filtro di tipo di un campo (§6.4) lo applica **l'editor**: la primitiva prende il documento nudo
258
+ e restituisce tutti i riferimenti, così la stessa risposta serve tutte le tendine di una schermata
259
+ (§13.17). La regola sta in `core/reference-filter.util.ts`, ed e' la stessa per le radici e per i
260
+ segmenti di un percorso. Il filtro guarda il tipo della **radice**, e quindi non basta: in un
261
+ parametro `String` una variabile `Structure` non e' compatibile, ma `Richiesta.Ragione` sì. Per
262
+ questo `<fb-reference-picker>` tiene l'elenco **completo** accanto a quello filtrato, e ne ricava
263
+ due cose: i contenitori compaiono come righe in cui si **entra** — cliccarle apre il percorso
264
+ invece di scegliere un valore del tipo sbagliato — e le radici si riconoscono tutte, così un
265
+ `Leggi_Ordine.Numero` già scritto in un campo `String` non viene accusato di non esistere. Nelle
266
+ proposte non entra comunque nessun valore del tipo sbagliato: i segmenti li filtra la stessa
267
+ regola, tenendo solo quelli da cui si scende. In un campo di **destinazione** le due liste sono due
268
+ richieste — `getWritableReferences` per le proposte, `getReferences` per le radici — perche' la
269
+ scrivibilita' e' del **percorso** e non della radice: un `$User.Anagrafica.Citta` scritto a mano e'
270
+ `TARGET_NOT_WRITABLE`, non un nome che non esiste.
271
+
272
+ **Le globali si navigano come le risorse.** Un percorso dichiarato dall'host puo' portare un
273
+ contenitore, e allora `objectType` dice di che tipo: `$User.Anagrafica.Citta` si propone e si
274
+ verifica come `Richiesta.Ragione`. La regola da non sbagliare e' che vince il **prefisso dichiarato
275
+ piu' lungo** — non tutto cio' che segue lo scope — perche' altrimenti un percorso giusto viene
276
+ segnalato come rotto (§4.1). Dove il catalogo dichiara il contenitore ma non il tipo il rilievo e'
277
+ `PATH_NOT_VERIFIABLE`, e la correzione sta nel catalogo dell'host; navigare uno scalare
278
+ (`$User.Email.Dominio`) e' invece `GLOBAL_UNKNOWN`. Sulle **destinazioni** non cambia niente da
279
+ sapere: le globali sono di sola lettura, membri compresi — le assegnabili sono `$Flow.CurrentStage`,
280
+ `$Flow.ActiveStages` e i campi di `$Record` — e il picker lo dice con `TARGET_NOT_WRITABLE` invece
281
+ di far sembrare il nome inesistente (§5.2).
282
+
257
283
  Su una destinazione la colonna che decide non e' la stessa nei due mondi: un membro porta il proprio
258
284
  `isWritable`, un campo no. Fuori da un Create o da un Update il contesto non c'e' — un Assignment su
259
285
  `Cliente.Codice` non sa se quel record verra' creato o aggiornato — quindi lì basta `isCreateable`
@@ -430,6 +456,8 @@ distribuire e nessuna dipendenza da un font di icone dell'applicazione ospite.
430
456
  | 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** |
431
457
  | 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 |
432
458
  | 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) |
459
+ | 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` |
460
+ | 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 |
433
461
 
434
462
  Altre regole del contratto rispettate: liste vuote omesse invece di scritte come `[]` (§2),
435
463
  `filterLogic` mostrato **solo** dove il modello lo prevede (§4.4), `fullName` / `status` mai
@@ -410,6 +410,12 @@ class HttpFlowBuilderApi extends FlowBuilderApi {
410
410
  return this.del(`/flows/editor/${HttpFlowBuilderApi.segment(flowName)}`);
411
411
  }
412
412
  // ---------------------------------------------------------------- §6.3
413
+ /**
414
+ * Documento nudo alla radice: le primitive che **analizzano** il documento non usano
415
+ * l'involucro `{definition, flowName, …}` della §6.2, che serve solo a chi deve sapere dove
416
+ * riporlo (§6.4, §13.17). Sbagliare involucro qui non produce nessun errore: si otterrebbe la
417
+ * validazione di un flow vuoto, cioe' «manca lo Start».
418
+ */
413
419
  validateDefinition(definition) {
414
420
  return this.post(`/flows/editor/validate`, definition);
415
421
  }
@@ -421,11 +427,17 @@ class HttpFlowBuilderApi extends FlowBuilderApi {
421
427
  // `processType` filtra le globali: `$Record` non esiste in uno screen flow (§4.1).
422
428
  return this.get('/flows/editor/dictionaries', HttpFlowBuilderApi.params({ processType }));
423
429
  }
424
- getReferences(query) {
425
- return this.post('/flows/editor/references', query);
430
+ /**
431
+ * Il body e' il documento **nudo**, come per validate/parse/outline/connector-targets (§6.4,
432
+ * §13.17): avvolgerlo (`{definition: …}`) o aggiungergli campi di filtro non da' nessun errore
433
+ * — il backend deserializza un `Flow` in cui non riconosce nessuna proprieta', risponde `200` e
434
+ * l'elenco contiene le sole globali. Se le tendine sembrano vuote, si guarda qui prima di tutto.
435
+ */
436
+ getReferences(definition) {
437
+ return this.post('/flows/editor/references', definition);
426
438
  }
427
- getWritableReferences(query) {
428
- return this.post('/flows/editor/writable-references', query);
439
+ getWritableReferences(definition) {
440
+ return this.post('/flows/editor/writable-references', definition);
429
441
  }
430
442
  getConnectorTargets(definition, excluding) {
431
443
  return this.post('/flows/editor/connector-targets', definition, HttpFlowBuilderApi.params({ excluding }));
@@ -1601,6 +1613,45 @@ function navigatePath(catalog, request) {
1601
1613
  return { resolution: resolution.asReadonly(), isPending: isPending.asReadonly() };
1602
1614
  }
1603
1615
 
1616
+ /**
1617
+ * Filtro di compatibilita' dei riferimenti — FRONTEND.md §6.4.
1618
+ *
1619
+ * `POST /flows/references` e `POST /flows/references/writable` prendono il **documento nudo** e
1620
+ * restituiscono **tutti** i riferimenti, ognuno col proprio `dataType`, `isCollection` e
1621
+ * `isWritable`: nel body non c'e' nessun campo di filtro. Chi sceglie cosa e' compatibile col
1622
+ * campo che l'utente sta compilando e' quindi l'editor, ed e' deliberato — la stessa risposta
1623
+ * serve tutte le tendine di una schermata, quindi si chiede una volta e si filtra n volte.
1624
+ *
1625
+ * Il filtro guarda **la radice**, non il percorso: una radice scartata si porta via anche cio'
1626
+ * che sta sotto, e chi propone i segmenti navigati applica la stessa regola separatamente
1627
+ * (`reference-picker`).
1628
+ */
1629
+ /** `true` se il campo non pone nessun vincolo: lì filtrare e' inutile. */
1630
+ function isEmptyReferenceFilter(filter) {
1631
+ return !filter || (!filter.dataType && filter.isCollection == null && !filter.objectType);
1632
+ }
1633
+ function matchesReferenceFilter(entry, filter) {
1634
+ // Un riferimento di tipo ignoto non si scarta: sarebbe peggio nasconderlo.
1635
+ if (filter.dataType && entry.dataType && entry.dataType !== filter.dataType) {
1636
+ return false;
1637
+ }
1638
+ // `!= null`, non `!== undefined`: nei template il safe navigation di Angular produce **null**,
1639
+ // e trattarlo come "voglio i valori singoli" svuoterebbe l'elenco.
1640
+ if (filter.isCollection != null && entry.isCollection != null && !!entry.isCollection !== filter.isCollection) {
1641
+ return false;
1642
+ }
1643
+ if (filter.objectType && entry.objectType && entry.objectType !== filter.objectType) {
1644
+ return false;
1645
+ }
1646
+ return true;
1647
+ }
1648
+ function filterReferences(references, filter) {
1649
+ if (isEmptyReferenceFilter(filter)) {
1650
+ return [...references];
1651
+ }
1652
+ return references.filter((entry) => matchesReferenceFilter(entry, filter));
1653
+ }
1654
+
1604
1655
  /**
1605
1656
  * Lo store del documento in lavorazione.
1606
1657
  *
@@ -3702,6 +3753,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
3702
3753
  * pur non essendo dichiarati in nessuna collection di risorse: la primitiva li restituisce
3703
3754
  * già, ed e' il motivo per cui non si ricostruisce l'elenco lato client.
3704
3755
  *
3756
+ * La primitiva prende il **documento nudo** e restituisce **tutti** i riferimenti: il filtro di
3757
+ * tipo del campo lo applica l'editor, con `core/reference-filter.util` (§6.4, §13.17). L'elenco
3758
+ * completo resta comunque a portata di mano, e serve — il filtro guarda la **radice**, e una radice
3759
+ * scartata si porta via cio' che sta sotto: in un parametro `String` una variabile `Structure` non
3760
+ * e' compatibile, ma `Richiesta.Ragione` sì.
3761
+ *
3705
3762
  * I **percorsi navigati** non sono piu' tutti uguali. Quando la radice e' una risorsa dichiarata
3706
3763
  * di cui si conosce la forma — una `Structure` con la sua classe, un record con la sua entita' — il
3707
3764
  * percorso si naviga **fino in fondo** (§4.4, §4.7.1): i segmenti si propongono un livello alla
@@ -3738,7 +3795,41 @@ class ReferencePickerComponent {
3738
3795
  */
3739
3796
  elementsOnly = input(false, ...(ngDevMode ? [{ debugName: "elementsOnly" }] : []));
3740
3797
  valueChange = output();
3741
- references = signal([], ...(ngDevMode ? [{ debugName: "references" }] : []));
3798
+ /**
3799
+ * L'elenco come arriva dalla primitiva, **senza** il filtro di tipo.
3800
+ *
3801
+ * Serve a due cose oltre che a produrre le proposte: riconoscere le radici dei percorsi e
3802
+ * mostrare i contenitori come righe in cui si entra. Il filtro (§6.4) guarda il tipo della
3803
+ * **radice**, e una radice scartata si porta via anche cio' che sta sotto: in un parametro
3804
+ * `String` una variabile `Structure` non e' compatibile, ma `Richiesta.Ragione` lo e', e
3805
+ * `Leggi_Ordine` non e' un `String` mentre `Leggi_Ordine.Numero` lo e'. Senza questo elenco il
3806
+ * primo membro non si puo' proporre e il secondo viene accusato di non esistere pur essendo un
3807
+ * riferimento valido (§4.5).
3808
+ */
3809
+ unfiltered = signal([], ...(ngDevMode ? [{ debugName: "unfiltered" }] : []));
3810
+ /**
3811
+ * L'insieme da cui si pesca prima del filtro di tipo: in un campo di destinazione e' la
3812
+ * risposta di `getWritableReferences`, altrove {@link unfiltered} stesso.
3813
+ */
3814
+ available = signal([], ...(ngDevMode ? [{ debugName: "available" }] : []));
3815
+ /**
3816
+ * Le proposte compatibili col campo. Il filtro e' **locale**: la primitiva prende il documento
3817
+ * nudo e restituisce tutto (§6.4, §13.17), cosi' la stessa risposta serve tutte le tendine di
3818
+ * una schermata.
3819
+ */
3820
+ references = computed(() => filterReferences(this.available(), {
3821
+ /**
3822
+ * `?? undefined` non e' cosmetico: nei template il safe navigation di Angular
3823
+ * (`describe(x)?.isCollection`) produce **null**, non `undefined`. Un `isCollection: null`
3824
+ * letto come "filtra per valore singolo" svuoterebbe l'elenco: un campo senza filtro non
3825
+ * deve porre nessun vincolo.
3826
+ */
3827
+ dataType: this.dataType() ?? undefined,
3828
+ isCollection: this.isCollection() ?? undefined,
3829
+ objectType: this.objectType() ?? undefined,
3830
+ }), ...(ngDevMode ? [{ debugName: "references" }] : []));
3831
+ /** Tutto cio' che puo' essere la radice di un percorso, filtrato o no. */
3832
+ roots = computed(() => this.unfiltered(), ...(ngDevMode ? [{ debugName: "roots" }] : []));
3742
3833
  isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
3743
3834
  loadError = signal(null, ...(ngDevMode ? [{ debugName: "loadError" }] : []));
3744
3835
  isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
@@ -3749,45 +3840,90 @@ class ReferencePickerComponent {
3749
3840
  effect(() => {
3750
3841
  const definition = this.store.document();
3751
3842
  const writable = this.writableOnly();
3752
- const dataType = this.dataType();
3753
- const isCollection = this.isCollection();
3754
- const objectType = this.objectType();
3755
3843
  if (this.elementsOnly()) {
3756
3844
  // I node li conosce già il documento: nessuna richiesta necessaria.
3757
- this.references.set(this.store.nodes().map((reference) => ({
3845
+ const nodes = this.store.nodes().map((reference) => ({
3758
3846
  name: reference.name,
3759
3847
  label: reference.node.label ?? null,
3760
3848
  kind: 'ElementOutput',
3761
3849
  description: this.dictionaries.labelOf(reference.type),
3762
3850
  isWritable: false,
3763
- })));
3851
+ }));
3852
+ this.unfiltered.set(nodes);
3853
+ this.available.set(nodes);
3764
3854
  return;
3765
3855
  }
3766
- /**
3767
- * `?? undefined` non e' cosmetico: nei template il safe navigation di Angular
3768
- * (`describe(x)?.isCollection`) produce **null**, non `undefined`. Un `isCollection: null`
3769
- * che arriva alla primitiva viene letto come "filtra per valore singolo" e svuota
3770
- * l'elenco: un campo senza filtro deve mandare il campo **assente**.
3771
- */
3772
- const query = {
3773
- definition,
3774
- dataType: dataType ?? undefined,
3775
- isCollection: isCollection ?? undefined,
3776
- objectType: objectType ?? undefined,
3777
- };
3778
3856
  this.isLoading.set(true);
3779
3857
  this.loadError.set(null);
3780
- const request = writable ? this.api.getWritableReferences(query) : this.api.getReferences(query);
3781
- void request
3782
- .then((list) => this.references.set(list ?? []))
3858
+ /**
3859
+ * Una sola richiesta dove non c'e' vincolo di scrittura: il body e' il documento nudo e la
3860
+ * risposta e' completa, quindi l'elenco delle radici e quello da cui si pesca sono lo stesso
3861
+ * (§6.4, §13.17). Il filtro di tipo lo applica {@link references}.
3862
+ */
3863
+ void this.api
3864
+ .getReferences(definition)
3865
+ .then((list) => {
3866
+ this.unfiltered.set(list ?? []);
3867
+ if (!writable) {
3868
+ this.available.set(list ?? []);
3869
+ }
3870
+ })
3783
3871
  .catch((error) => {
3784
3872
  // Senza l'elenco il campo resta scrivibile a mano: e' meglio di un campo bloccato.
3785
3873
  this.loadError.set(error instanceof Error ? error.message : String(error));
3786
- this.references.set([]);
3874
+ this.unfiltered.set([]);
3875
+ if (!writable) {
3876
+ this.available.set([]);
3877
+ }
3878
+ })
3879
+ .finally(() => {
3880
+ if (!writable) {
3881
+ this.isLoading.set(false);
3882
+ }
3883
+ });
3884
+ if (!writable) {
3885
+ return;
3886
+ }
3887
+ /**
3888
+ * In un campo di destinazione le proposte sono un elenco a parte, ma le **radici** restano
3889
+ * quelle di `getReferences`: la scrivibilita' e' del **percorso**, non della radice, e le
3890
+ * radici escluse sono quelle che servono per dire la cosa giusta — un `$User.Anagrafica.Citta`
3891
+ * scritto a mano e' `TARGET_NOT_WRITABLE`, non un nome che non esiste.
3892
+ */
3893
+ void this.api
3894
+ .getWritableReferences(definition)
3895
+ .then((list) => this.available.set(list ?? []))
3896
+ .catch((error) => {
3897
+ this.loadError.set(error instanceof Error ? error.message : String(error));
3898
+ this.available.set([]);
3787
3899
  })
3788
3900
  .finally(() => this.isLoading.set(false));
3789
3901
  });
3790
3902
  }
3903
+ /**
3904
+ * Il riferimento dichiarato piu' **lungo** che sia un prefisso del valore, sui confini del punto.
3905
+ *
3906
+ * Non basta il primo segmento: un nome dichiarato puo' contenere il punto. Le globali sono il caso
3907
+ * per cui la regola esiste — di `$User.Anagrafica.Citta` il dizionario dichiara `$User.Anagrafica`,
3908
+ * e cercare la corrispondenza esatta di tutto cio' che segue lo scope segnalerebbe come rotto un
3909
+ * percorso giusto (§4.1: vince il prefisso dichiarato piu' lungo).
3910
+ */
3911
+ declaredPrefix = computed(() => {
3912
+ const value = (this.value() ?? '')?.trim();
3913
+ if (!value) {
3914
+ return undefined;
3915
+ }
3916
+ let best;
3917
+ for (const candidate of this.roots()) {
3918
+ if (value !== candidate.name && !value.startsWith(`${candidate.name}.`)) {
3919
+ continue;
3920
+ }
3921
+ if (!best || candidate.name.length > best.name.length) {
3922
+ best = candidate;
3923
+ }
3924
+ }
3925
+ return best;
3926
+ }, ...(ngDevMode ? [{ debugName: "declaredPrefix" }] : []));
3791
3927
  /**
3792
3928
  * La risorsa da cui il valore corrente sta navigando, quando la sua forma e' **dichiarata**: una
3793
3929
  * `Structure` con la classe, un record con l'entita'. È cio' che rende il percorso verificabile.
@@ -3797,11 +3933,9 @@ class ReferencePickerComponent {
3797
3933
  * l'editor non deve accusare cio' che il backend non verifica.
3798
3934
  */
3799
3935
  navigableRoot = computed(() => {
3800
- const root = referenceRoot((this.value() ?? '')?.trim());
3801
- if (!root) {
3802
- return undefined;
3803
- }
3804
- const reference = this.references().find((candidate) => candidate.name === root);
3936
+ // Fra tutte le radici: quella di `Richiesta.Ragione` in un campo `String` sta solo nell'elenco
3937
+ // non filtrato.
3938
+ const reference = this.declaredPrefix();
3805
3939
  if (!reference || reference.kind === 'ElementOutput' || !reference.objectType || reference.isCollection) {
3806
3940
  return undefined;
3807
3941
  }
@@ -3830,6 +3964,16 @@ class ReferencePickerComponent {
3830
3964
  * segmento di sola lettura non si propone in un campo di destinazione, a meno che da lì il
3831
3965
  * percorso continui: `Richiesta.Cliente` non si assegna, ma `Richiesta.Cliente.Email` sì (§5.7).
3832
3966
  */
3967
+ /**
3968
+ * §5.2 — dentro una globale dell'host **niente** e' scrivibile, per quanto il membro si dichiari
3969
+ * tale: le globali le risolve un componente che non ha modo di scriverle, e proporle come
3970
+ * destinazione farebbe attivare un flow che poi fallisce davanti all'utente. L'eccezione sono i
3971
+ * campi del record che innesca, che si assegnano (§4.1).
3972
+ */
3973
+ isReadOnlyPath = computed(() => {
3974
+ const name = this.navigableRoot()?.reference.name;
3975
+ return !!name && isGlobalReference(name) && referenceRoot(name) !== '$Record';
3976
+ }, ...(ngDevMode ? [{ debugName: "isReadOnlyPath" }] : []));
3833
3977
  pathReferences = computed(() => {
3834
3978
  const root = this.navigableRoot();
3835
3979
  const tail = this.tail();
@@ -3839,7 +3983,9 @@ class ReferencePickerComponent {
3839
3983
  const prefix = tail.prefix ? `${root.reference.name}.${tail.prefix}` : root.reference.name;
3840
3984
  const kind = tail.level.container.kind === 'object' ? 'RecordField' : 'StructureMember';
3841
3985
  return tail.level.entries
3986
+ .map((entry) => (this.isReadOnlyPath() ? { ...entry, isWritable: false } : entry))
3842
3987
  .filter((entry) => !this.writableOnly() || entry.isWritable || !!entry.next)
3988
+ .filter((entry) => this.matchesTarget(entry))
3843
3989
  .map((entry) => ({
3844
3990
  name: `${prefix}.${entry.name}`,
3845
3991
  label: entry.label ?? null,
@@ -3851,12 +3997,47 @@ class ReferencePickerComponent {
3851
3997
  description: entry.isWritable ? (entry.description ?? null) : 'sola lettura',
3852
3998
  }));
3853
3999
  }, ...(ngDevMode ? [{ debugName: "pathReferences" }] : []));
4000
+ /**
4001
+ * Lo stesso filtro delle radici (§6.4), applicato ai segmenti di un percorso: in un parametro
4002
+ * `String` non si propone un membro `Date`. Un segmento da cui si scende resta comunque proposto
4003
+ * anche se il suo tipo non combacia — e' la strada per arrivare al membro che combacia.
4004
+ */
4005
+ matchesTarget(entry) {
4006
+ if (entry.next) {
4007
+ return true;
4008
+ }
4009
+ return matchesReferenceFilter(entry, {
4010
+ dataType: this.dataType() ?? undefined,
4011
+ isCollection: this.isCollection() ?? undefined,
4012
+ objectType: this.objectType() ?? undefined,
4013
+ });
4014
+ }
4015
+ /**
4016
+ * I contenitori che il filtro di tipo ha scartato: si mostrano per **entrarci**, non per
4017
+ * scegliersi. Quelli che il filtro ha tenuto stanno già fra le proposte normali.
4018
+ */
4019
+ containerOptions = computed(() => {
4020
+ const proposed = new Set(this.references().map((reference) => reference.name));
4021
+ return this.unfiltered().filter((candidate) => {
4022
+ if (proposed.has(candidate.name) || !this.canDescend(candidate)) {
4023
+ return false;
4024
+ }
4025
+ // In un campo di destinazione una globale dell'host non porta a niente di assegnabile (§5.2):
4026
+ // proporre di entrarci sarebbe un vicolo cieco. Resta nelle radici, per il messaggio giusto.
4027
+ return !(this.writableOnly() &&
4028
+ isGlobalReference(candidate.name) &&
4029
+ referenceRoot(candidate.name) !== '$Record');
4030
+ });
4031
+ }, ...(ngDevMode ? [{ debugName: "containerOptions" }] : []));
4032
+ /** `true` → questa riga apre il percorso e non e' un valore valido per il campo. */
4033
+ isContainerOnly(reference) {
4034
+ return this.containerOptions().some((candidate) => candidate.name === reference.name);
4035
+ }
3854
4036
  options = computed(() => {
3855
4037
  const needle = this.query()?.trim().toLowerCase();
3856
- // Le globali assegnabili — `$Flow.CurrentStage`, `$Flow.ActiveStages` e quelle che l'host
3857
- // dichiara scrivibili — le comprende già `POST /flows/references/writable`: aggiungerle
3858
- // qui le duplicherebbe (§5.2, §6.4).
3859
- const all = [...this.references(), ...this.pathReferences()];
4038
+ // Le due globali assegnabili — `$Flow.CurrentStage` e `$Flow.ActiveStages` le comprende già
4039
+ // `POST /flows/references/writable`: aggiungerle qui le duplicherebbe (§5.2, §6.4).
4040
+ const all = [...this.references(), ...this.containerOptions(), ...this.pathReferences()];
3860
4041
  if (!needle) {
3861
4042
  return all;
3862
4043
  }
@@ -3913,11 +4094,16 @@ class ReferencePickerComponent {
3913
4094
  * elemento): il percorso resta fuori dalla validazione, quindi si accetta senza segnalare;
3914
4095
  * - `host`: scope del sistema ospite che **non dichiara percorsi**: non verificabile (§4.1);
3915
4096
  * - `member`: percorso dentro una forma dichiarata, verificato fino in fondo (§4.4, §4.7.1);
4097
+ * - `containerRoot`: il contenitore da solo in un campo che vuole un altro tipo: il valore e' un
4098
+ * suo membro, non lui;
3916
4099
  * - `memberUnknown`: un segmento non esiste nella sua tappa: `STRUCTURE_MEMBER_UNKNOWN` su una
3917
4100
  * classe, `FIELD_UNKNOWN` su un'entita', e a differenza di prima si sa per certo;
3918
4101
  * - `memberNotWritable`: il segmento esiste, non e' scrivibile, e questo campo vuole una
3919
4102
  * destinazione: `TARGET_NOT_WRITABLE`;
3920
4103
  * - `pathUnverified`: la catena si interrompe (`PATH_NOT_VERIFIABLE`): avviso, non errore;
4104
+ * - `globalPathUntyped`: percorso globale che porta un contenitore senza dichiararne il tipo:
4105
+ * `PATH_NOT_VERIFIABLE`, e la correzione sta nel catalogo dell'host, non nel flow (§4.1);
4106
+ * - `globalPathInvalid`: si naviga un percorso globale scalare o una collection: `GLOBAL_UNKNOWN`;
3921
4107
  * - `unknown`: nessuna corrispondenza: si avvisa, senza bloccare. Ci finisce anche il
3922
4108
  * percorso inesistente di uno scope che i percorsi li dichiara, perche' lì il backend
3923
4109
  * risponderebbe `GLOBAL_UNKNOWN`.
@@ -3937,6 +4123,11 @@ class ReferencePickerComponent {
3937
4123
  }
3938
4124
  // Dentro una forma dichiarata il percorso e' verificabile: dirlo "non verificato" sarebbe falso.
3939
4125
  if (this.navigableRoot()) {
4126
+ // Il contenitore da solo: non e' fra le proposte (lo avrebbe intercettato `known`), quindi il
4127
+ // filtro del campo lo ha scartato — e il valore giusto e' un suo membro, non lui.
4128
+ if (!this.navigatedPath()) {
4129
+ return 'containerRoot';
4130
+ }
3940
4131
  const resolution = this.resolution();
3941
4132
  switch (resolution?.status) {
3942
4133
  case 'unknown':
@@ -3944,13 +4135,30 @@ class ReferencePickerComponent {
3944
4135
  case 'unverifiable':
3945
4136
  return 'pathUnverified';
3946
4137
  case 'resolved':
3947
- return this.writableOnly() && !resolution.last?.isWritable ? 'memberNotWritable' : 'member';
4138
+ return this.writableOnly() && (this.isReadOnlyPath() || !resolution.last?.isWritable)
4139
+ ? 'memberNotWritable'
4140
+ : 'member';
3948
4141
  default:
3949
4142
  // Percorso ancora aperto (`Richiesta.`) o risposta non arrivata: non si accusa nessuno.
3950
4143
  return 'empty';
3951
4144
  }
3952
4145
  }
3953
- if (all.some((reference) => reference.name === root)) {
4146
+ /**
4147
+ * §4.1 — un percorso globale dichiarato che non porta a un contenitore. I due esiti sono
4148
+ * diversi e vanno detti diversi: senza `objectType` si sa che c'e' un contenitore ma non di che
4149
+ * tipo (`PATH_NOT_VERIFIABLE`, avviso), mentre su uno scalare o una collection non c'e'
4150
+ * proprio niente da navigare (`GLOBAL_UNKNOWN`, errore).
4151
+ */
4152
+ const prefix = this.declaredPrefix();
4153
+ if (prefix && prefix.name !== value && isGlobalReference(prefix.name)) {
4154
+ const isContainer = this.dictionaries.isStructure(prefix.dataType) || prefix.dataType === 'Object';
4155
+ return isContainer && !prefix.objectType && !prefix.isCollection
4156
+ ? 'globalPathUntyped'
4157
+ : 'globalPathInvalid';
4158
+ }
4159
+ // Fra **tutte** le radici: `Leggi_Ordine` non e' un `String`, ma `Leggi_Ordine.Numero` sì, e
4160
+ // accusarlo di non esistere sarebbe falso (§4.5).
4161
+ if (this.roots().some((reference) => reference.name === root)) {
3954
4162
  return 'navigated';
3955
4163
  }
3956
4164
  // Se l'elenco non e' arrivato, non si accusa nessuno.
@@ -3976,6 +4184,10 @@ class ReferencePickerComponent {
3976
4184
  const what = this.tailIsObject() ? 'Campo' : 'Membro';
3977
4185
  return `${what} di ${this.tailContainer()}: il percorso e’ verificato fino in fondo.`;
3978
4186
  }
4187
+ case 'containerRoot':
4188
+ return this.tailIsObject()
4189
+ ? 'Questo e’ il record intero, e il campo vuole un altro tipo: scegli un suo campo.'
4190
+ : 'Questa e’ l’istanza di classe, e il campo vuole un altro tipo: scegli un suo membro.';
3979
4191
  case 'memberUnknown': {
3980
4192
  if (!resolution) {
3981
4193
  return null;
@@ -3988,19 +4200,29 @@ class ReferencePickerComponent {
3988
4200
  return names ? `${head} Disponibili: ${names}.` : head;
3989
4201
  }
3990
4202
  case 'memberNotWritable':
4203
+ // Il motivo cambia la correzione: dentro una globale non c'e' niente da rendere scrivibile.
4204
+ if (this.isReadOnlyPath()) {
4205
+ return 'Le variabili globali sono di sola lettura, membri compresi: assegnarlo e’ TARGET_NOT_WRITABLE.';
4206
+ }
3991
4207
  return this.tailIsObject()
3992
4208
  ? 'Questo campo non si scrive ne’ creando ne’ aggiornando un record: assegnarlo e’ TARGET_NOT_WRITABLE.'
3993
4209
  : 'Questo membro e’ calcolato: si legge, ma assegnarlo e’ TARGET_NOT_WRITABLE.';
3994
4210
  case 'pathUnverified':
3995
4211
  return resolution ? pathNotVerifiableMessage(resolution) : null;
4212
+ case 'globalPathUntyped':
4213
+ return `«${this.declaredPrefix()?.name}» porta un contenitore, ma il catalogo non ne dichiara il tipo: il percorso non e’ verificabile (PATH_NOT_VERIFIABLE).`;
4214
+ case 'globalPathInvalid':
4215
+ return `«${this.declaredPrefix()?.name}» e’ un valore, non un contenitore: dopo il punto non c’e’ niente da navigare (GLOBAL_UNKNOWN).`;
3996
4216
  case 'unknown':
3997
4217
  return 'Questo nome non e’ fra i riferimenti disponibili: la validazione lo segnalerebbe.';
3998
4218
  default:
3999
4219
  return null;
4000
4220
  }
4001
4221
  }, ...(ngDevMode ? [{ debugName: "hint" }] : []));
4002
- /** I due stati che sono errori e non avvisi: il colore deve dirlo. */
4003
- isHintError = computed(() => this.valueState() === 'memberUnknown' || this.valueState() === 'memberNotWritable', ...(ngDevMode ? [{ debugName: "isHintError" }] : []));
4222
+ /** Gli stati che sono avvisi: «non lo so», o un valore da correggere che non blocca. */
4223
+ isHintWarning = computed(() => ['unknown', 'containerRoot', 'globalPathUntyped'].includes(this.valueState()), ...(ngDevMode ? [{ debugName: "isHintWarning" }] : []));
4224
+ /** Gli stati che sono errori e non avvisi: il colore deve dirlo. */
4225
+ isHintError = computed(() => ['memberUnknown', 'memberNotWritable', 'globalPathInvalid'].includes(this.valueState()), ...(ngDevMode ? [{ debugName: "isHintError" }] : []));
4004
4226
  errorMessage = computed(() => this.loadError(), ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
4005
4227
  open() {
4006
4228
  if (this.disabled()) {
@@ -4019,6 +4241,11 @@ class ReferencePickerComponent {
4019
4241
  this.query.set(value);
4020
4242
  }
4021
4243
  choose(reference) {
4244
+ // Un contenitore fuori tipo non e' un valore: cliccarlo vuol dire entrarci.
4245
+ if (this.isContainerOnly(reference)) {
4246
+ this.descend(reference);
4247
+ return;
4248
+ }
4022
4249
  this.valueChange.emit(reference.name);
4023
4250
  this.close();
4024
4251
  }
@@ -4056,14 +4283,18 @@ class ReferencePickerComponent {
4056
4283
  if (reference.description) {
4057
4284
  parts.push(reference.description);
4058
4285
  }
4286
+ if (this.isContainerOnly(reference)) {
4287
+ // Dirlo: la riga c'e' ma il valore non e' quello, e senza spiegazione sembra un errore.
4288
+ parts.push(reference.dataType === 'Object' ? 'entra e scegli un campo' : 'entra e scegli un membro');
4289
+ }
4059
4290
  return parts.join(' · ');
4060
4291
  }
4061
4292
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ReferencePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4062
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ReferencePickerComponent, isStandalone: true, selector: "fb-reference-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, dataType: { classPropertyName: "dataType", publicName: "dataType", isSignal: true, isRequired: false, transformFunction: null }, isCollection: { classPropertyName: "isCollection", publicName: "isCollection", isSignal: true, isRequired: false, transformFunction: null }, objectType: { classPropertyName: "objectType", publicName: "objectType", isSignal: true, isRequired: false, transformFunction: null }, writableOnly: { classPropertyName: "writableOnly", publicName: "writableOnly", isSignal: true, isRequired: false, transformFunction: null }, elementsOnly: { classPropertyName: "elementsOnly", publicName: "elementsOnly", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div class=\"fb-ref\" [class.fb-ref--open]=\"isOpen()\">\r\n <div class=\"fb-ref__control\">\r\n <input\r\n class=\"fb-ref__input\"\r\n type=\"text\"\r\n [value]=\"value() || ''\"\r\n [placeholder]=\"placeholder()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"label()\"\r\n (input)=\"onManualInput($any($event.target).value)\"\r\n (focus)=\"open()\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__toggle\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isOpen()\"\r\n aria-label=\"Mostra i riferimenti disponibili\"\r\n (click)=\"toggle()\"\r\n >\r\n \u25BE\r\n </button>\r\n @if (value()) {\r\n <button type=\"button\" class=\"fb-ref__clear\" aria-label=\"Svuota\" (click)=\"clear()\">\u00D7</button>\r\n }\r\n </div>\r\n\r\n @if (hint()) {\r\n <!-- Un membro inesistente o non scrivibile e' un **errore**: mostrarlo come avviso direbbe il falso. -->\r\n <p\r\n class=\"fb-ref__hint\"\r\n [class.fb-ref__hint--warn]=\"valueState() === 'unknown'\"\r\n [class.fb-ref__hint--error]=\"isHintError()\"\r\n >\r\n {{ hint() }}\r\n </p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"fb-ref__hint fb-ref__hint--warn\">\r\n Elenco dei riferimenti non disponibile: puoi scrivere il nome a mano.\r\n </p>\r\n }\r\n\r\n @if (isOpen()) {\r\n <div class=\"fb-ref__panel\" role=\"listbox\">\r\n <input\r\n class=\"fb-ref__search\"\r\n type=\"search\"\r\n placeholder=\"Filtra\"\r\n aria-label=\"Filtra i riferimenti\"\r\n (input)=\"onQuery($any($event.target).value)\"\r\n />\r\n @if (groups().length === 0) {\r\n <p class=\"fb-ref__empty\">Nessun riferimento compatibile.</p>\r\n }\r\n @for (group of groups(); track group.kind) {\r\n <div class=\"fb-ref__group\">\r\n <span class=\"fb-ref__group-label\">{{ group.label }}</span>\r\n @for (item of group.items; track item.name) {\r\n <!-- Due bottoni dove il percorso continua: scegliere il riferimento e scendere di un\r\n livello sono cose diverse, e su una Structure o un record servono entrambe. -->\r\n <div class=\"fb-ref__row\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__option\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"item.name === value()\"\r\n (click)=\"choose(item)\"\r\n >\r\n <span class=\"fb-ref__name\">{{ item.name }}</span>\r\n <span class=\"fb-ref__meta\">{{ describe(item) }}</span>\r\n </button>\r\n @if (canDescend(item)) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__into\"\r\n [attr.aria-label]=\"'Entra in ' + item.name\"\r\n title=\"Entra e proponi i segmenti\"\r\n (click)=\"descend(item)\"\r\n >\r\n \u203A\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n <button type=\"button\" class=\"fb-ref__close\" (click)=\"close()\">Chiudi</button>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block}.fb-ref{position:relative}.fb-ref__control{display:flex;align-items:stretch;gap:0;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);overflow:hidden}.fb-ref--open .fb-ref__control{border-color:var(--fb-accent, #2f6feb)}.fb-ref__input{flex:1;min-width:0;padding:5px 7px;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-ref__input:focus-visible{outline:none}.fb-ref__toggle,.fb-ref__clear{flex:0 0 auto;padding:0 7px;border:0;border-left:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:12px;cursor:pointer}.fb-ref__toggle:hover,.fb-ref__clear:hover{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__hint{margin:3px 0 0;font-size:10px;line-height:1.35;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__hint--warn{color:var(--fb-warning, #b7791f)}.fb-ref__hint--error{color:var(--fb-error, #c9372c)}.fb-ref__panel{position:absolute;z-index:30;top:calc(100% + 3px);left:0;right:0;max-height:260px;overflow-y:auto;padding:6px;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);box-shadow:0 6px 18px #10182829}.fb-ref__search{box-sizing:border-box;width:100%;margin-bottom:6px;padding:4px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:5px;font:inherit;font-size:12px}.fb-ref__group{margin-bottom:6px}.fb-ref__group-label{display:block;padding:2px 4px;font-size:9px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__row{display:flex;align-items:stretch;gap:2px}.fb-ref__into{flex:0 0 auto;padding:0 7px;border:0;border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:13px;cursor:pointer}.fb-ref__into:hover{background:var(--fb-surface-alt, #f8f9fb);color:var(--fb-accent, #2f6feb)}.fb-ref__option{display:flex;flex:1;flex-direction:column;min-width:0;width:100%;padding:4px 6px;border:0;border-radius:4px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-ref__option:hover,.fb-ref__option[aria-selected=true]{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__name{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.fb-ref__meta{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-ref__empty{margin:4px;font-size:11px;color:var(--fb-text-muted, #667085)}.fb-ref__close{width:100%;margin-top:4px;padding:4px;border:0;border-top:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4293
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.27", type: ReferencePickerComponent, isStandalone: true, selector: "fb-reference-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, dataType: { classPropertyName: "dataType", publicName: "dataType", isSignal: true, isRequired: false, transformFunction: null }, isCollection: { classPropertyName: "isCollection", publicName: "isCollection", isSignal: true, isRequired: false, transformFunction: null }, objectType: { classPropertyName: "objectType", publicName: "objectType", isSignal: true, isRequired: false, transformFunction: null }, writableOnly: { classPropertyName: "writableOnly", publicName: "writableOnly", isSignal: true, isRequired: false, transformFunction: null }, elementsOnly: { classPropertyName: "elementsOnly", publicName: "elementsOnly", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, ngImport: i0, template: "<div class=\"fb-ref\" [class.fb-ref--open]=\"isOpen()\">\r\n <div class=\"fb-ref__control\">\r\n <input\r\n class=\"fb-ref__input\"\r\n type=\"text\"\r\n [value]=\"value() || ''\"\r\n [placeholder]=\"placeholder()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"label()\"\r\n (input)=\"onManualInput($any($event.target).value)\"\r\n (focus)=\"open()\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__toggle\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isOpen()\"\r\n aria-label=\"Mostra i riferimenti disponibili\"\r\n (click)=\"toggle()\"\r\n >\r\n \u25BE\r\n </button>\r\n @if (value()) {\r\n <button type=\"button\" class=\"fb-ref__clear\" aria-label=\"Svuota\" (click)=\"clear()\">\u00D7</button>\r\n }\r\n </div>\r\n\r\n @if (hint()) {\r\n <!-- Un membro inesistente o non scrivibile e' un **errore**: mostrarlo come avviso direbbe il falso. -->\r\n <p\r\n class=\"fb-ref__hint\"\r\n [class.fb-ref__hint--warn]=\"isHintWarning()\"\r\n [class.fb-ref__hint--error]=\"isHintError()\"\r\n >\r\n {{ hint() }}\r\n </p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"fb-ref__hint fb-ref__hint--warn\">\r\n Elenco dei riferimenti non disponibile: puoi scrivere il nome a mano.\r\n </p>\r\n }\r\n\r\n @if (isOpen()) {\r\n <div class=\"fb-ref__panel\" role=\"listbox\">\r\n <input\r\n class=\"fb-ref__search\"\r\n type=\"search\"\r\n placeholder=\"Filtra\"\r\n aria-label=\"Filtra i riferimenti\"\r\n (input)=\"onQuery($any($event.target).value)\"\r\n />\r\n @if (groups().length === 0) {\r\n <p class=\"fb-ref__empty\">Nessun riferimento compatibile.</p>\r\n }\r\n @for (group of groups(); track group.kind) {\r\n <div class=\"fb-ref__group\">\r\n <span class=\"fb-ref__group-label\">{{ group.label }}</span>\r\n @for (item of group.items; track item.name) {\r\n <!-- Due bottoni dove il percorso continua: scegliere il riferimento e scendere di un\r\n livello sono cose diverse, e su una Structure o un record servono entrambe. -->\r\n <div class=\"fb-ref__row\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__option\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"item.name === value()\"\r\n [title]=\"isContainerOnly(item) ? 'Il tipo non e\u2019 quello del campo: entra e scegli dentro' : ''\"\r\n (click)=\"choose(item)\"\r\n >\r\n <span class=\"fb-ref__name\">{{ item.name }}</span>\r\n <span class=\"fb-ref__meta\">{{ describe(item) }}</span>\r\n </button>\r\n @if (canDescend(item)) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__into\"\r\n [attr.aria-label]=\"'Entra in ' + item.name\"\r\n title=\"Entra e proponi i segmenti\"\r\n (click)=\"descend(item)\"\r\n >\r\n \u203A\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n <button type=\"button\" class=\"fb-ref__close\" (click)=\"close()\">Chiudi</button>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block}.fb-ref{position:relative}.fb-ref__control{display:flex;align-items:stretch;gap:0;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);overflow:hidden}.fb-ref--open .fb-ref__control{border-color:var(--fb-accent, #2f6feb)}.fb-ref__input{flex:1;min-width:0;padding:5px 7px;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-ref__input:focus-visible{outline:none}.fb-ref__toggle,.fb-ref__clear{flex:0 0 auto;padding:0 7px;border:0;border-left:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:12px;cursor:pointer}.fb-ref__toggle:hover,.fb-ref__clear:hover{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__hint{margin:3px 0 0;font-size:10px;line-height:1.35;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__hint--warn{color:var(--fb-warning, #b7791f)}.fb-ref__hint--error{color:var(--fb-error, #c9372c)}.fb-ref__panel{position:absolute;z-index:30;top:calc(100% + 3px);left:0;right:0;max-height:260px;overflow-y:auto;padding:6px;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);box-shadow:0 6px 18px #10182829}.fb-ref__search{box-sizing:border-box;width:100%;margin-bottom:6px;padding:4px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:5px;font:inherit;font-size:12px}.fb-ref__group{margin-bottom:6px}.fb-ref__group-label{display:block;padding:2px 4px;font-size:9px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__row{display:flex;align-items:stretch;gap:2px}.fb-ref__into{flex:0 0 auto;padding:0 7px;border:0;border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:13px;cursor:pointer}.fb-ref__into:hover{background:var(--fb-surface-alt, #f8f9fb);color:var(--fb-accent, #2f6feb)}.fb-ref__option{display:flex;flex:1;flex-direction:column;min-width:0;width:100%;padding:4px 6px;border:0;border-radius:4px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-ref__option:hover,.fb-ref__option[aria-selected=true]{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__name{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.fb-ref__meta{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-ref__empty{margin:4px;font-size:11px;color:var(--fb-text-muted, #667085)}.fb-ref__close{width:100%;margin-top:4px;padding:4px;border:0;border-top:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4063
4294
  }
4064
4295
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImport: i0, type: ReferencePickerComponent, decorators: [{
4065
4296
  type: Component,
4066
- args: [{ selector: 'fb-reference-picker', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-ref\" [class.fb-ref--open]=\"isOpen()\">\r\n <div class=\"fb-ref__control\">\r\n <input\r\n class=\"fb-ref__input\"\r\n type=\"text\"\r\n [value]=\"value() || ''\"\r\n [placeholder]=\"placeholder()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"label()\"\r\n (input)=\"onManualInput($any($event.target).value)\"\r\n (focus)=\"open()\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__toggle\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isOpen()\"\r\n aria-label=\"Mostra i riferimenti disponibili\"\r\n (click)=\"toggle()\"\r\n >\r\n \u25BE\r\n </button>\r\n @if (value()) {\r\n <button type=\"button\" class=\"fb-ref__clear\" aria-label=\"Svuota\" (click)=\"clear()\">\u00D7</button>\r\n }\r\n </div>\r\n\r\n @if (hint()) {\r\n <!-- Un membro inesistente o non scrivibile e' un **errore**: mostrarlo come avviso direbbe il falso. -->\r\n <p\r\n class=\"fb-ref__hint\"\r\n [class.fb-ref__hint--warn]=\"valueState() === 'unknown'\"\r\n [class.fb-ref__hint--error]=\"isHintError()\"\r\n >\r\n {{ hint() }}\r\n </p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"fb-ref__hint fb-ref__hint--warn\">\r\n Elenco dei riferimenti non disponibile: puoi scrivere il nome a mano.\r\n </p>\r\n }\r\n\r\n @if (isOpen()) {\r\n <div class=\"fb-ref__panel\" role=\"listbox\">\r\n <input\r\n class=\"fb-ref__search\"\r\n type=\"search\"\r\n placeholder=\"Filtra\"\r\n aria-label=\"Filtra i riferimenti\"\r\n (input)=\"onQuery($any($event.target).value)\"\r\n />\r\n @if (groups().length === 0) {\r\n <p class=\"fb-ref__empty\">Nessun riferimento compatibile.</p>\r\n }\r\n @for (group of groups(); track group.kind) {\r\n <div class=\"fb-ref__group\">\r\n <span class=\"fb-ref__group-label\">{{ group.label }}</span>\r\n @for (item of group.items; track item.name) {\r\n <!-- Due bottoni dove il percorso continua: scegliere il riferimento e scendere di un\r\n livello sono cose diverse, e su una Structure o un record servono entrambe. -->\r\n <div class=\"fb-ref__row\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__option\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"item.name === value()\"\r\n (click)=\"choose(item)\"\r\n >\r\n <span class=\"fb-ref__name\">{{ item.name }}</span>\r\n <span class=\"fb-ref__meta\">{{ describe(item) }}</span>\r\n </button>\r\n @if (canDescend(item)) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__into\"\r\n [attr.aria-label]=\"'Entra in ' + item.name\"\r\n title=\"Entra e proponi i segmenti\"\r\n (click)=\"descend(item)\"\r\n >\r\n \u203A\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n <button type=\"button\" class=\"fb-ref__close\" (click)=\"close()\">Chiudi</button>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block}.fb-ref{position:relative}.fb-ref__control{display:flex;align-items:stretch;gap:0;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);overflow:hidden}.fb-ref--open .fb-ref__control{border-color:var(--fb-accent, #2f6feb)}.fb-ref__input{flex:1;min-width:0;padding:5px 7px;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-ref__input:focus-visible{outline:none}.fb-ref__toggle,.fb-ref__clear{flex:0 0 auto;padding:0 7px;border:0;border-left:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:12px;cursor:pointer}.fb-ref__toggle:hover,.fb-ref__clear:hover{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__hint{margin:3px 0 0;font-size:10px;line-height:1.35;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__hint--warn{color:var(--fb-warning, #b7791f)}.fb-ref__hint--error{color:var(--fb-error, #c9372c)}.fb-ref__panel{position:absolute;z-index:30;top:calc(100% + 3px);left:0;right:0;max-height:260px;overflow-y:auto;padding:6px;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);box-shadow:0 6px 18px #10182829}.fb-ref__search{box-sizing:border-box;width:100%;margin-bottom:6px;padding:4px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:5px;font:inherit;font-size:12px}.fb-ref__group{margin-bottom:6px}.fb-ref__group-label{display:block;padding:2px 4px;font-size:9px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__row{display:flex;align-items:stretch;gap:2px}.fb-ref__into{flex:0 0 auto;padding:0 7px;border:0;border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:13px;cursor:pointer}.fb-ref__into:hover{background:var(--fb-surface-alt, #f8f9fb);color:var(--fb-accent, #2f6feb)}.fb-ref__option{display:flex;flex:1;flex-direction:column;min-width:0;width:100%;padding:4px 6px;border:0;border-radius:4px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-ref__option:hover,.fb-ref__option[aria-selected=true]{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__name{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.fb-ref__meta{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-ref__empty{margin:4px;font-size:11px;color:var(--fb-text-muted, #667085)}.fb-ref__close{width:100%;margin-top:4px;padding:4px;border:0;border-top:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}\n"] }]
4297
+ args: [{ selector: 'fb-reference-picker', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"fb-ref\" [class.fb-ref--open]=\"isOpen()\">\r\n <div class=\"fb-ref__control\">\r\n <input\r\n class=\"fb-ref__input\"\r\n type=\"text\"\r\n [value]=\"value() || ''\"\r\n [placeholder]=\"placeholder()\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-label]=\"label()\"\r\n (input)=\"onManualInput($any($event.target).value)\"\r\n (focus)=\"open()\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__toggle\"\r\n [disabled]=\"disabled()\"\r\n [attr.aria-expanded]=\"isOpen()\"\r\n aria-label=\"Mostra i riferimenti disponibili\"\r\n (click)=\"toggle()\"\r\n >\r\n \u25BE\r\n </button>\r\n @if (value()) {\r\n <button type=\"button\" class=\"fb-ref__clear\" aria-label=\"Svuota\" (click)=\"clear()\">\u00D7</button>\r\n }\r\n </div>\r\n\r\n @if (hint()) {\r\n <!-- Un membro inesistente o non scrivibile e' un **errore**: mostrarlo come avviso direbbe il falso. -->\r\n <p\r\n class=\"fb-ref__hint\"\r\n [class.fb-ref__hint--warn]=\"isHintWarning()\"\r\n [class.fb-ref__hint--error]=\"isHintError()\"\r\n >\r\n {{ hint() }}\r\n </p>\r\n }\r\n @if (errorMessage()) {\r\n <p class=\"fb-ref__hint fb-ref__hint--warn\">\r\n Elenco dei riferimenti non disponibile: puoi scrivere il nome a mano.\r\n </p>\r\n }\r\n\r\n @if (isOpen()) {\r\n <div class=\"fb-ref__panel\" role=\"listbox\">\r\n <input\r\n class=\"fb-ref__search\"\r\n type=\"search\"\r\n placeholder=\"Filtra\"\r\n aria-label=\"Filtra i riferimenti\"\r\n (input)=\"onQuery($any($event.target).value)\"\r\n />\r\n @if (groups().length === 0) {\r\n <p class=\"fb-ref__empty\">Nessun riferimento compatibile.</p>\r\n }\r\n @for (group of groups(); track group.kind) {\r\n <div class=\"fb-ref__group\">\r\n <span class=\"fb-ref__group-label\">{{ group.label }}</span>\r\n @for (item of group.items; track item.name) {\r\n <!-- Due bottoni dove il percorso continua: scegliere il riferimento e scendere di un\r\n livello sono cose diverse, e su una Structure o un record servono entrambe. -->\r\n <div class=\"fb-ref__row\">\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__option\"\r\n role=\"option\"\r\n [attr.aria-selected]=\"item.name === value()\"\r\n [title]=\"isContainerOnly(item) ? 'Il tipo non e\u2019 quello del campo: entra e scegli dentro' : ''\"\r\n (click)=\"choose(item)\"\r\n >\r\n <span class=\"fb-ref__name\">{{ item.name }}</span>\r\n <span class=\"fb-ref__meta\">{{ describe(item) }}</span>\r\n </button>\r\n @if (canDescend(item)) {\r\n <button\r\n type=\"button\"\r\n class=\"fb-ref__into\"\r\n [attr.aria-label]=\"'Entra in ' + item.name\"\r\n title=\"Entra e proponi i segmenti\"\r\n (click)=\"descend(item)\"\r\n >\r\n \u203A\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n <button type=\"button\" class=\"fb-ref__close\" (click)=\"close()\">Chiudi</button>\r\n </div>\r\n }\r\n</div>\r\n", styles: [":host{display:block}.fb-ref{position:relative}.fb-ref__control{display:flex;align-items:stretch;gap:0;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);overflow:hidden}.fb-ref--open .fb-ref__control{border-color:var(--fb-accent, #2f6feb)}.fb-ref__input{flex:1;min-width:0;padding:5px 7px;border:0;background:transparent;color:var(--fb-text, #1d2939);font:inherit;font-size:12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.fb-ref__input:focus-visible{outline:none}.fb-ref__toggle,.fb-ref__clear{flex:0 0 auto;padding:0 7px;border:0;border-left:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:12px;cursor:pointer}.fb-ref__toggle:hover,.fb-ref__clear:hover{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__hint{margin:3px 0 0;font-size:10px;line-height:1.35;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__hint--warn{color:var(--fb-warning, #b7791f)}.fb-ref__hint--error{color:var(--fb-error, #c9372c)}.fb-ref__panel{position:absolute;z-index:30;top:calc(100% + 3px);left:0;right:0;max-height:260px;overflow-y:auto;padding:6px;border:1px solid var(--fb-border, #d6dae1);border-radius:6px;background:var(--fb-surface, #fff);box-shadow:0 6px 18px #10182829}.fb-ref__search{box-sizing:border-box;width:100%;margin-bottom:6px;padding:4px 6px;border:1px solid var(--fb-border, #d6dae1);border-radius:5px;font:inherit;font-size:12px}.fb-ref__group{margin-bottom:6px}.fb-ref__group-label{display:block;padding:2px 4px;font-size:9px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--fb-text-subtle, #98a2b3)}.fb-ref__row{display:flex;align-items:stretch;gap:2px}.fb-ref__into{flex:0 0 auto;padding:0 7px;border:0;border-radius:4px;background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:13px;cursor:pointer}.fb-ref__into:hover{background:var(--fb-surface-alt, #f8f9fb);color:var(--fb-accent, #2f6feb)}.fb-ref__option{display:flex;flex:1;flex-direction:column;min-width:0;width:100%;padding:4px 6px;border:0;border-radius:4px;background:transparent;color:var(--fb-text, #1d2939);font:inherit;text-align:left;cursor:pointer}.fb-ref__option:hover,.fb-ref__option[aria-selected=true]{background:var(--fb-surface-alt, #f8f9fb)}.fb-ref__name{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.fb-ref__meta{font-size:10px;color:var(--fb-text-muted, #667085)}.fb-ref__empty{margin:4px;font-size:11px;color:var(--fb-text-muted, #667085)}.fb-ref__close{width:100%;margin-top:4px;padding:4px;border:0;border-top:1px solid var(--fb-border-subtle, #e6e9ee);background:transparent;color:var(--fb-text-muted, #667085);font:inherit;font-size:11px;cursor:pointer}\n"] }]
4067
4298
  }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], dataType: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataType", required: false }] }], isCollection: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCollection", required: false }] }], objectType: [{ type: i0.Input, args: [{ isSignal: true, alias: "objectType", required: false }] }], writableOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "writableOnly", required: false }] }], elementsOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "elementsOnly", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }] } });
4068
4299
 
4069
4300
  /**
@@ -5140,7 +5371,7 @@ class ConditionEditorComponent {
5140
5371
  return;
5141
5372
  }
5142
5373
  void this.api
5143
- .getReferences({ definition })
5374
+ .getReferences(definition)
5144
5375
  .then((list) => this.references.set(list ?? []))
5145
5376
  // Senza l'elenco non si segnala nulla: non sapere non e' sapere che e' sbagliato.
5146
5377
  .catch(() => this.references.set([]));
@@ -6118,9 +6349,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
6118
6349
  * 1. **Le operazioni sono eseguite nell'ordine dichiarato**, quindi devono essere
6119
6350
  * riordinabili: un'interfaccia che le presenta come un insieme nasconde la semantica.
6120
6351
  * 2. **Cosa puo' stare in `assignToReference`**: una variabile, un campo di una variabile
6121
- * record, un campo di `$Record` e, fra le globali, `$Flow.CurrentStage`,
6122
- * `$Flow.ActiveStages` e quelle che il sistema ospite dichiara scrivibili le propone
6123
- * già `POST /flows/references/writable`. Tutto il resto e' di sola lettura.
6352
+ * record, un campo di `$Record` e, fra le globali, soltanto `$Flow.CurrentStage` e
6353
+ * `$Flow.ActiveStages` le propone già `POST /flows/references/writable`. Tutto il resto e'
6354
+ * di sola lettura, comprese le globali dell'host e i loro membri (§5.2).
6124
6355
  * 3. Gli operatori marcati `expectsCollection` hanno senso **solo** su destinazioni
6125
6356
  * collection: su una variabile singola non falliscono, non fanno nulla.
6126
6357
  */
@@ -9836,5 +10067,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.27", ngImpo
9836
10067
  * Generated bundle index. Do not edit.
9837
10068
  */
9838
10069
 
9839
- export { ConditionEditorComponent, ConnectorEditorComponent, DebugPanelComponent, ElementDialogComponent, ElementInspectorComponent, ElementPaletteComponent, FALLBACK_COLLECTION_BY_TYPE, FALLBACK_TYPE_LABEL, FLOW_BUILDER_HTTP_CONFIG, FLOW_ELEMENT_ICONS, FLOW_ELEMENT_VARIANT_FIELDS, FLOW_ELEMENT_VARIANT_ICONS, FLOW_ERROR_FALLBACK_MESSAGE, FLOW_ERROR_HTTP_STATUS, FLOW_NAME_PATTERN, FLOW_NODE_COLLECTIONS, FLOW_NODE_HEIGHT, FLOW_NODE_WIDTH, FLOW_RESOURCE_COLLECTIONS, FieldAssignmentEditorComponent, FieldPickerComponent, FlowApiError, FlowBuilderApi, FlowBuilderComponent, FlowCanvasComponent, FlowCatalogStore, FlowDictionaryStore, FlowDocumentStore, FlowEditorSession, FlowLayoutService, FlowValidationStore, HttpFlowBuilderApi, NamePickerComponent, NodeInspectorBase, ORCHESTRATION_CONDITION_OUTPUT, ObjectPickerComponent, OrchestratedStageInspectorComponent, ParameterEditorComponent, ProblemsPanelComponent, RecordFilterEditorComponent, ReferencePickerComponent, ResourcePanelComponent, SEVERITY_BUCKETS, SEVERITY_ICON, SEVERITY_LABEL, START_NODE_NAME, SelectValueDirective, StartInspectorComponent, StructureMemberPickerComponent, StructurePickerComponent, TYPES_WITH_AUTOMATIC_OUTPUT, TYPE_BY_COLLECTION, UNSUPPORTED_TYPES, ValueEditorComponent, VersionPanelComponent, areTypesComparable, canvasNodeId, checkConditionLogic, checkFlowName, describePathEntry, elementIcon, emptyFlowDefinition, flowNodeWidth, flowNodeWidthClass, isCustomConditionLogic, isGlobalReference, isNumericType, isTypeCheckedOperator, isValidFlowName, loadPathLevel, moveCondition, navigatePath, outletByKey, outletsOf, parseCanvasNodeId, parseInvariantNumber, parseSourceConnectorId, parseTargetConnectorId, pathAvailableNames, pathContainerLabel, pathNotVerifiableMessage, referenceRoot, remapConditionLogic, removeCondition, resolvePath, severityBucket, slugifyFlowName, sourceConnectorId, stageStepNames, stageStepOutputReferenced, stepsOf, targetConnectorId, uniqueFlowName, variantFieldOf, variantOf, variantPresetOf };
10070
+ export { ConditionEditorComponent, ConnectorEditorComponent, DebugPanelComponent, ElementDialogComponent, ElementInspectorComponent, ElementPaletteComponent, FALLBACK_COLLECTION_BY_TYPE, FALLBACK_TYPE_LABEL, FLOW_BUILDER_HTTP_CONFIG, FLOW_ELEMENT_ICONS, FLOW_ELEMENT_VARIANT_FIELDS, FLOW_ELEMENT_VARIANT_ICONS, FLOW_ERROR_FALLBACK_MESSAGE, FLOW_ERROR_HTTP_STATUS, FLOW_NAME_PATTERN, FLOW_NODE_COLLECTIONS, FLOW_NODE_HEIGHT, FLOW_NODE_WIDTH, FLOW_RESOURCE_COLLECTIONS, FieldAssignmentEditorComponent, FieldPickerComponent, FlowApiError, FlowBuilderApi, FlowBuilderComponent, FlowCanvasComponent, FlowCatalogStore, FlowDictionaryStore, FlowDocumentStore, FlowEditorSession, FlowLayoutService, FlowValidationStore, HttpFlowBuilderApi, NamePickerComponent, NodeInspectorBase, ORCHESTRATION_CONDITION_OUTPUT, ObjectPickerComponent, OrchestratedStageInspectorComponent, ParameterEditorComponent, ProblemsPanelComponent, RecordFilterEditorComponent, ReferencePickerComponent, ResourcePanelComponent, SEVERITY_BUCKETS, SEVERITY_ICON, SEVERITY_LABEL, START_NODE_NAME, SelectValueDirective, StartInspectorComponent, StructureMemberPickerComponent, StructurePickerComponent, TYPES_WITH_AUTOMATIC_OUTPUT, TYPE_BY_COLLECTION, UNSUPPORTED_TYPES, ValueEditorComponent, VersionPanelComponent, areTypesComparable, canvasNodeId, checkConditionLogic, checkFlowName, describePathEntry, elementIcon, emptyFlowDefinition, filterReferences, flowNodeWidth, flowNodeWidthClass, isCustomConditionLogic, isEmptyReferenceFilter, isGlobalReference, isNumericType, isTypeCheckedOperator, isValidFlowName, loadPathLevel, matchesReferenceFilter, moveCondition, navigatePath, outletByKey, outletsOf, parseCanvasNodeId, parseInvariantNumber, parseSourceConnectorId, parseTargetConnectorId, pathAvailableNames, pathContainerLabel, pathNotVerifiableMessage, referenceRoot, remapConditionLogic, removeCondition, resolvePath, severityBucket, slugifyFlowName, sourceConnectorId, stageStepNames, stageStepOutputReferenced, stepsOf, targetConnectorId, uniqueFlowName, variantFieldOf, variantOf, variantPresetOf };
9840
10071
  //# sourceMappingURL=esfaenza-flow-builder.mjs.map