@eqproject/eqp-dynamic-module 2.10.99 → 2.10.101

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.
Files changed (61) hide show
  1. package/README.md +887 -876
  2. package/esm2020/lib/components/exported/eqp-dynamic-module-configurator/eqp-dynamic-module-configurator.component.mjs +25 -25
  3. package/esm2020/lib/components/private/action-button-creator/action-button-creator.component.mjs +3 -3
  4. package/esm2020/lib/components/private/add-form-field/add-form-field.component.mjs +14 -14
  5. package/esm2020/lib/components/private/add-formula-field/add-formula-field.component.mjs +7 -7
  6. package/esm2020/lib/components/private/dbg-templates/list-value-dbg-template/list-value-dbg-template.component.mjs +3 -3
  7. package/esm2020/lib/components/private/dbgetter/dbgetter.component.mjs +5 -5
  8. package/esm2020/lib/components/private/dynamic-module-field-extra-fix/dynamic-module-field-extra-fix.component.mjs +5 -5
  9. package/esm2020/lib/components/private/field-templates/action-button-field-template/action-button-field-template.component.mjs +5 -5
  10. package/esm2020/lib/components/private/field-templates/attachment-field-template/attachment-field-template.component.mjs +10 -10
  11. package/esm2020/lib/components/private/field-templates/date-field-template/date-field-template.component.mjs +2 -2
  12. package/esm2020/lib/components/private/field-templates/list-value-field-template/list-value-field-template.component.mjs +3 -3
  13. package/esm2020/lib/components/private/field-templates/numeric-field-template/numeric-field-template.component.mjs +16 -9
  14. package/esm2020/lib/components/private/field-templates/text-field-template/text-field-template.component.mjs +6 -6
  15. package/esm2020/lib/components/private/field-templates/textarea-field-template/textarea-field-template.component.mjs +6 -6
  16. package/esm2020/lib/components/private/form-records/add-form-record/add-form-record.component.mjs +5 -5
  17. package/esm2020/lib/components/private/form-records/hlist-form-record/hlist-form-record.component.mjs +5 -5
  18. package/esm2020/lib/components/private/form-records/list-form-record/list-form-record.component.mjs +10 -10
  19. package/esm2020/lib/components/private/form-records/list-view-form-record/list-view-form-record.component.mjs +10 -10
  20. package/esm2020/lib/components/private/form-statistics/filter-form-statistic/filter-form-statistic.component.mjs +32 -9
  21. package/esm2020/lib/components/private/form-statistics/filter-templates/boolean-filter-template/boolean-filter-template.component.mjs +7 -7
  22. package/esm2020/lib/components/private/form-statistics/filter-templates/date-filter-template/date-filter-template.component.mjs +8 -8
  23. package/esm2020/lib/components/private/form-statistics/filter-templates/image-selector-filter-template/image-selector-filter-template.component.mjs +3 -3
  24. package/esm2020/lib/components/private/form-statistics/filter-templates/list-value-filter-template/list-value-filter-template.component.mjs +6 -6
  25. package/esm2020/lib/components/private/form-statistics/filter-templates/numeric-filter-template/numeric-filter-template.component.mjs +17 -10
  26. package/esm2020/lib/components/private/form-statistics/filter-templates/text-filter-template/text-filter-template.component.mjs +7 -7
  27. package/esm2020/lib/components/private/form-statistics/filter-templates/textarea-filter-template/textarea-filter-template.component.mjs +7 -7
  28. package/esm2020/lib/components/private/graphs/graphs.component.mjs +3 -3
  29. package/esm2020/lib/components/private/tmw-image-drawer/tmw-image-drawer.component.mjs +5 -5
  30. package/esm2020/lib/components/private/tmw-image-marker/tmw-image-marker.component.mjs +6 -6
  31. package/esm2020/lib/components/private/trigger-creator/trigger-creator.component.mjs +8 -10
  32. package/esm2020/lib/components/private/trigger-creator/trigger-templates/boolean-trigger-template/boolean-trigger-template.component.mjs +3 -3
  33. package/esm2020/lib/components/private/trigger-creator/trigger-templates/date-trigger-template/date-trigger-template.component.mjs +4 -4
  34. package/esm2020/lib/components/private/trigger-creator/trigger-templates/list-value-trigger-template/list-value-trigger-template.component.mjs +3 -3
  35. package/esm2020/lib/components/private/trigger-creator/trigger-templates/numeric-trigger-template/numeric-trigger-template.component.mjs +13 -6
  36. package/esm2020/lib/components/private/trigger-creator/trigger-templates/text-trigger-template/text-trigger-template.component.mjs +7 -7
  37. package/esm2020/lib/components/private/trigger-creator/trigger-templates/textarea-trigger-template/textarea-trigger-template.component.mjs +7 -7
  38. package/esm2020/lib/eqp-dynamic-module.module.mjs +18 -40
  39. package/esm2020/lib/models/dynAttachment.mjs +1 -1
  40. package/esm2020/lib/utils/google-fonts-injector.mjs +1 -1
  41. package/fesm2015/eqproject-eqp-dynamic-module.mjs +227 -205
  42. package/fesm2015/eqproject-eqp-dynamic-module.mjs.map +1 -1
  43. package/fesm2020/eqproject-eqp-dynamic-module.mjs +226 -205
  44. package/fesm2020/eqproject-eqp-dynamic-module.mjs.map +1 -1
  45. package/lib/components/exported/eqp-dynamic-module-configurator/eqp-dynamic-module-configurator.component.d.ts +8 -8
  46. package/lib/components/private/add-form-field/add-form-field.component.d.ts +9 -9
  47. package/lib/components/private/field-templates/attachment-field-template/attachment-field-template.component.d.ts +2 -2
  48. package/lib/components/private/field-templates/date-field-template/date-field-template.component.d.ts +1 -1
  49. package/lib/components/private/field-templates/numeric-field-template/numeric-field-template.component.d.ts +2 -2
  50. package/lib/components/private/form-records/hlist-form-record/hlist-form-record.component.d.ts +2 -2
  51. package/lib/components/private/form-records/list-form-record/list-form-record.component.d.ts +2 -2
  52. package/lib/components/private/form-records/list-view-form-record/list-view-form-record.component.d.ts +2 -2
  53. package/lib/components/private/form-statistics/filter-form-statistic/filter-form-statistic.component.d.ts +4 -3
  54. package/lib/components/private/form-statistics/filter-templates/date-filter-template/date-filter-template.component.d.ts +1 -1
  55. package/lib/components/private/form-statistics/filter-templates/numeric-filter-template/numeric-filter-template.component.d.ts +2 -2
  56. package/lib/components/private/trigger-creator/trigger-creator.component.d.ts +0 -2
  57. package/lib/components/private/trigger-creator/trigger-templates/date-trigger-template/date-trigger-template.component.d.ts +1 -1
  58. package/lib/components/private/trigger-creator/trigger-templates/numeric-trigger-template/numeric-trigger-template.component.d.ts +2 -2
  59. package/lib/eqp-dynamic-module.module.d.ts +8 -25
  60. package/lib/models/dynAttachment.d.ts +2 -2
  61. package/package.json +6 -13
package/README.md CHANGED
@@ -1,876 +1,887 @@
1
- # @eqproject/eqp-dynamic-module
2
-
3
- [![npm version](https://img.shields.io/npm/v/@eqproject/eqp-dynamic-module.svg)](https://www.npmjs.com/package/@eqproject/eqp-dynamic-module)
4
- [![Angular](https://img.shields.io/badge/Angular-15-red.svg)](https://angular.io/)
5
-
6
- > Libreria Angular 15 per la creazione, visualizzazione e gestione di form dinamiche con configuratore no-code.
7
- > Angular 15 library for building, rendering and managing dynamic forms with a no-code configurator.
8
-
9
- 📖 **[Guida utente / User Guide →](./USERGUIDE.md)**
10
-
11
- ---
12
-
13
- ## Changelog
14
-
15
- ### v2.10.99
16
- - **Bugfix configurator immagine persa su campo `Immagine`/`Immagine con markers`:** `catchButtonImageChange` e `catchButtonImageWithMarkersChange` in `add-form-field` leggevano l'indice sbagliato (`attachments[1]`) dell'array emesso da `eqp-attachments`. Al primo caricamento di un'immagine su un campo nuovo l'array ha un solo elemento, quindi `field.DynAttachment` veniva sovrascritto con `undefined`: l'immagine spariva riaprendo la modale di modifica campo e non compariva mai in anteprima. Corretto leggendo `attachments[attachments.length - 1]`.
17
- - **Bugfix configurator image lost on `Image`/`Image with markers` field:** `catchButtonImageChange` and `catchButtonImageWithMarkersChange` in `add-form-field` were reading the wrong index (`attachments[1]`) from the array emitted by `eqp-attachments`. On the first image upload to a new field the array has only one element, so `field.DynAttachment` was overwritten with `undefined`: the image disappeared when reopening the field edit dialog and never showed up in the preview. Fixed to read `attachments[attachments.length - 1]`.
18
-
19
- ### v2.10.87
20
- - **Bugfix configurator sezione "Generale" assente per 5 tipi di campo:** durante il lavoro di potenziamento grafico (v2.10.68–v2.10.70), i tipi `ActionButtonField`, `ImageField`, `ImageWithMarkersField`, `ListValueField` e `ImageSelectorField` avevano ricevuto la sezione "Grafica" nel tab "Stile Compilazione" del configuratore, ma la sezione "Generale" (Larghezza campo, Visibile, VisibleIf, Tooltip, Tipo di invisibilità, Mantieni il valore) era stata rimossa per errore. Ripristinata per tutti e 5 i tipi.
21
- - **Bugfix configurator "Generale" section missing for 5 field types:** during the graphical enhancement work (v2.10.68–v2.10.70), `ActionButtonField`, `ImageField`, `ImageWithMarkersField`, `ListValueField` and `ImageSelectorField` received the "Grafica" section in the configurator's "Stile Compilazione" tab, but the "Generale" section (field width, visibility, VisibleIf, tooltip, invisibility type, maintain value) was accidentally removed. Restored for all 5 field types.
22
-
23
- ### v2.10.86
24
- - **Bugfix loop infinito `ListValueField`:** `FormControl.setValue()` notificava il callback `_onChange` del `NgModel` registrato tramite `[formControlName]` sul `mat-checkbox`, causando `ngModelChange` → `updateSelected()` → `setFormControlValue()` in ricorsione infinita. Aggiunto `{ emitModelToViewChange: false }` a `setFormControlValue()` per interrompere il ciclo. Fix correlati: `updateSelected()` ora restituisce `null` (non `[]`) per campi single-choice senza selezione, evitando instabilità Angular CD da `[] !== []`; `resetArrayData()` chiama `updateSelected(false)` per non emettere `recordChange` durante il rebuild delle opzioni; `updateField()` distingue formula-per-valore da formula-per-opzioni nei campi `DataGetterType=Formula`.
25
- - **Bugfix loop infinito `onRecordChange`:** aggiunta guardia di rientranza `_recordChanging` con `try/finally` in `add-form-record.onRecordChange()` per prevenire ricorsione da campi formula concatenati (es. campo numerico campo elenco valorizzato dalla formula del primo).
26
- - **Bugfix loop in anteprima `DynAttachment.ButtonKey` null:** nei template `image-field-template` e `image-with-markers-field-template`, la valutazione di `field.DynAttachment.ButtonKey` in `*ngIf` lanciava eccezione quando `DynAttachment` era `null` (campo senza immagine caricata), innescando un loop di Angular CD. Sostituito con `field.DynAttachment?.ButtonKey`.
27
- - **Fix posizione dialog DataGetter:** la modale del Query Editor aperta con "Modifica" nel configuratore compariva a metà pagina. Aggiunti `position: { top: '20px' }` e `maxHeight: '90vh'` per allinearla al comportamento di tutte le altre dialog.
28
- - **Bugfix infinite loop `ListValueField`:** `FormControl.setValue()` was notifying the `_onChange` callback of the `NgModel` registered via `[formControlName]` on `mat-checkbox`, causing `ngModelChange` → `updateSelected()` → `setFormControlValue()` in infinite recursion. Added `{ emitModelToViewChange: false }` to `setFormControlValue()` to break the cycle. Related fixes: `updateSelected()` now returns `null` (not `[]`) for single-choice fields with no selection, preventing Angular CD instability from `[] !== []`; `resetArrayData()` calls `updateSelected(false)` to avoid emitting `recordChange` during option rebuild; `updateField()` now distinguishes formula-for-value from formula-for-options in `DataGetterType=Formula` fields.
29
- - **Bugfix infinite loop `onRecordChange`:** added `_recordChanging` re-entrancy guard with `try/finally` in `add-form-record.onRecordChange()` to prevent recursion from chained formula fields (e.g. numeric field list field driven by the first field's formula).
30
- - **Bugfix preview loop — `DynAttachment.ButtonKey` null:** in `image-field-template` and `image-with-markers-field-template`, evaluating `field.DynAttachment.ButtonKey` in `*ngIf` threw an exception when `DynAttachment` was `null` (field with no image loaded), triggering an Angular CD loop. Replaced with `field.DynAttachment?.ButtonKey`.
31
- - **Fix DataGetter dialog position:** the Query Editor modal opened via "Modifica" in the configurator was appearing at mid-page. Added `position: { top: '20px' }` and `maxHeight: '90vh'` to align it with all other dialogs.
32
-
33
- ### v2.10.85
34
- - **Bugfix loop infinito (approccio corretto):** il loop di v2.10.84 era asincrono: `setValue` chiama `writeValue` sui ControlValueAccessor di Angular Material che emettono eventi nel tick successivo, quando la guardia di rientranza era già rilasciata. Soluzione definitiva: il validator `required` ora legge direttamente da `record[field.Name]` tramite closure (anziché da `control.value`); in `onRecordChange()` viene chiamato `updateValueAndValidity({ emitEvent: false })` — che ri-esegue i validator senza invocare `writeValue` — eliminando alla radice ogni possibilità di cascade.
35
- - **Bugfix infinite loop (correct approach):** the v2.10.84 loop was asynchronous: `setValue` calls `writeValue` on Angular Material ControlValueAccessors which emit events on the next tick, after the re-entrancy guard was already released. Definitive fix: the `required` validator now reads directly from `record[field.Name]` via closure (instead of `control.value`); `onRecordChange()` calls `updateValueAndValidity({ emitEvent: false })` — which re-runs validators without invoking `writeValue` — eliminating any cascade at the root.
36
-
37
- ### v2.10.84
38
- - **Bugfix loop infinito `onRecordChange`:** la sincronizzazione dei `FormControl` introdotta in v2.10.83 causava un loop: `setValue` invoca `writeValue` sui ControlValueAccessor (es. `mat-datepicker`), che emettono `(dateChange)/(ngModelChange)` `recordChange` `onRecordChange` di nuovo, all'infinito. Aggiunta una guardia di rientranza (`_isInRecordChange`) con `try/finally` che interrompe il ciclo. La sincronizzazione dei FormControl resta attiva e la validazione required funziona correttamente.
39
- - **Bugfix infinite loop `onRecordChange`:** the FormControl sync introduced in v2.10.83 caused an infinite loop: `setValue` calls `writeValue` on ControlValueAccessors (e.g. `mat-datepicker`), which emit `(dateChange)/(ngModelChange)` `recordChange` `onRecordChange` again, endlessly. Added a re-entrancy guard (`_isInRecordChange`) with `try/finally` that breaks the cycle. FormControl sync remains active and required validation works correctly.
40
-
41
- ### v2.10.83
42
- - **Bugfix validazione form campi obbligatori valorizzati via formula/ActionButton:** quando un campo con `required` veniva impostato tramite formula o ActionButton, il valore compariva visivamente ma il `FormControl` Angular rimaneva non aggiornato, lasciando il form invalido finché l'utente non interagiva manualmente col campo. Ora `onRecordChange()` risincronizza tutti i `FormControl` dal record dopo ogni aggiornamento formula, rendendo la validazione coerente con il valore visualizzato.
43
- - **Bugfix form validationrequired fields set via formula/ActionButton:** when a required field was populated by a formula or ActionButton, the value appeared visually but the Angular `FormControl` was never updated, keeping the form invalid until the user manually interacted with the field. `onRecordChange()` now re-syncs all `FormControl` values from the record after every formula update, making validation consistent with the displayed value.
44
-
45
- ### v2.10.81
46
- - **Bugfix configurator — `DataGetter` null dopo decode Base64:** quando il campo `DataGetterValueBase64String` decodifica in un JSON con `DataGetter: null`, viene ora creato un oggetto `DataGetter` vuoto anziché proseguire con `null`, evitando errori a runtime nel configuratore.
47
- - **Bugfix `add-form-record` `actionButtons` null:** se l'input `actionButtons` arriva `null` al componente, viene ora inizializzato a un array vuoto prima del filtraggio, prevenendo un'eccezione al caricamento del record.
48
- - **Bugfix configurator `DataGetter` null after Base64 decode:** when `DataGetterValueBase64String` decodes to a JSON with `DataGetter: null`, a new empty `DataGetter` object is now created instead of proceeding with `null`, preventing runtime errors in the configurator.
49
- - **Bugfix `add-form-record` — `actionButtons` null:** if the `actionButtons` input arrives as `null`, it is now initialized to an empty array before filtering, preventing an exception on record load.
50
-
51
- ### v2.10.79
52
- - **DataGetter V2 selezione automatica colonna singola:** quando il flusso V2 genera una sola `columnKey`, essa viene assegnata automaticamente a `DataGetterColumnForce` senza che l'utente debba selezionarla manualmente dalla dropdown.
53
- - **DataGetter V2 — single column auto-selection:** when the V2 flow produces exactly one `columnKey`, it is automatically assigned to `DataGetterColumnForce` without requiring manual selection from the dropdown.
54
-
55
- ### v2.10.77
56
- - **DataGetter V2`DataGetterColumnForce` come stringa:** `onAiDataGetterOut` ora salva `DataGetterColumnForce` come stringa chiave (non come oggetto), allineandosi al formato atteso da `eqp-select`. Il valore pre-selezionato nella dropdown compare automaticamente dopo il flusso AI.
57
- - **DataGetter V2 — `DataGetterColumnForce` as string:** `onAiDataGetterOut` now stores `DataGetterColumnForce` as a key string (not as an object), matching the format expected by `eqp-select`. The pre-selected value in the dropdown appears automatically after the AI flow.
58
-
59
- ### v2.10.76
60
- - **DataGetter V2 — `createColumnKeys` retrocompatibile:** `add-form-field` ora rileva `DataGetterCodeVersion=2` e legge `selectedFields` da `queryCommandDatabaseConfiguration.selectedFields` invece che dal livello radice; fallback su `PropertyName` se `CurrentTranslate` è assente.
61
- - **DataGetter V2 — `createColumnKeys` backward-compatible:** `add-form-field` now detects `DataGetterCodeVersion=2` and reads `selectedFields` from `queryCommandDatabaseConfiguration.selectedFields` instead of the root level; falls back to `PropertyName` when `CurrentTranslate` is missing.
62
-
63
- ### v2.10.74 / v2.10.75
64
- - **DataGetter AI — nuova modalità "Da database" (DataGetterType=3):** aggiunto campo `DataGetterSpeechText` nel modello `DataGetter`. Il configurator AI può creare campi con recupero dati da database impostando un prompt testuale: al caricamento del form, il componente QueryEditor esterno viene invocato silenziosamente, elabora il prompt via AI e popola automaticamente `DataGetterValue`, `DataGetterCardinality=1`, `DataGetterHasResetButton=true` e `DataGetterColumnForce` (se il risultato ha un solo campo selezionato).
65
- - **DataGetterCodeVersion V2 — retrocompatibilità in lettura:** il `DbgetterComponent` rileva automaticamente i campi con `DataGetterCodeVersion=2` (formato Omnisearch AI) ed esegue un unwrap trasparente della struttura `queryCommandDatabaseConfiguration` al formato V1, senza impatto sui campi legacy. Il `DataGetterCodeVersion=2` viene propagato al componente QueryEditor esterno tramite `config.DataGetterCodeVersion` per consentire al client ospitante di attivare il flusso V2 in lettura.
66
- - **AI DataGetter — new "Da database" mode (DataGetterType=3):** added `DataGetterSpeechText` field to the `DataGetter` model. The AI configurator can create database-getter fields with a natural-language prompt: on form load, the external QueryEditor component is invoked silently, processes the prompt via AI and automatically populates `DataGetterValue`, `DataGetterCardinality=1`, `DataGetterHasResetButton=true` and `DataGetterColumnForce` (if a single output field is returned).
67
- - **DataGetterCodeVersion V2 — backward-compatible read flow:** `DbgetterComponent` now auto-detects fields with `DataGetterCodeVersion=2` (Omnisearch AI format) and transparently unwraps the `queryCommandDatabaseConfiguration` structure to the V1 format, with zero impact on legacy fields. `DataGetterCodeVersion=2` is forwarded to the external QueryEditor component via `config.DataGetterCodeVersion` to enable the V2 read flow on the host application side.
68
-
69
- ### v2.10.70
70
- - **Theming configuratornuovi input:** aggiunto `[configuratorThemeCss]` che accetta direttamente il testo di un file CSS con le dichiarazioni delle variabili `--conf-*`. Permette di portare il tema dall'esterno come file statico senza hardcodare valori TypeScript. Se entrambi gli input sono presenti, `configuratorTheme` sovrascrive `configuratorThemeCss` per le chiavi in conflitto.
71
- - **Theming configurator — nuove variabili CSS:** `--conf-stepper-header-bg` (sfondo zona step superiore), `--conf-stepper-content-bg` (sfondo zona inferiore), `--conf-step-icon-edit-bg` (sfondo pallini step completati), `--conf-hint-btn-bg` / `--conf-hint-btn-hover-bg` (bottone suggerimento rapido), `--conf-btn-color` (colore testo bottoni con sfondo gradiente).
72
- - **Theming configurator — forzatura `!important`:** tutti i valori iniettati tramite tema esterno sono ora applicati con `!important`, rendendo il sistema di theming l'unico canale valido per sovrascrivere i colori.
73
- - **Theming configurator`--conf-btn-color`:** il colore del testo dei bottoni attivi (sfondo gradiente) è ora templatizzabile e forzato con `!important` per resistere a override CSS provenienti dall'applicazione ospitante.
74
- - **New theming input:** added `[configuratorThemeCss]` accepting a CSS text string with `--conf-*` variable declarations. Enables external theme files without TypeScript hardcoding. When both inputs are present, `configuratorTheme` overrides `configuratorThemeCss` for conflicting keys.
75
- - **New CSS variables:** `--conf-stepper-header-bg`, `--conf-stepper-content-bg`, `--conf-step-icon-edit-bg`, `--conf-hint-btn-bg`, `--conf-hint-btn-hover-bg`, `--conf-btn-color`.
76
- - **`!important` enforcement:** all externally-injected theme values are now set with `!important`, making the theming system the sole valid override channel.
77
-
78
- ### v2.10.65
79
- - **TextFieldicona opzionale:** aggiunta la possibilità di associare un'icona Material Icons al campo di testo. Le nuove proprietà `IconName` (stringa) e `IconPosition` (enum: `1`=Sinistra/prefix, `2`=Destra/suffix) sono opzionali e retrocompatibili (null sui form esistenti). Configurabili nel builder tramite il toggle "Icona" nella sezione Specifiche del campo.
80
- - **TextFieldoptional icon:** added support for a Material Icons icon on text fields. New properties `IconName` (string) and `IconPosition` (enum: `1`=Left/prefix, `2`=Right/suffix) are optional and backward-compatible (null on existing forms). Configurable in the builder via the "Icona" toggle in the field's Specifiche section.
81
-
82
- ### v2.10.64
83
- - **Bugfix configurator:** se il campo `Code` del form risulta `null` al momento del salvataggio (scenario: form creato con AI senza salvataggio intermedio), ora viene generato automaticamente da `Name` prima dell'invio al server.
84
-
85
- ### v2.10.63
86
- - README riscritto in formato bilingue (italiano completo + inglese completo).
87
- - Aggiunto `USERGUIDE.md` con guida pratica per scenari d'uso comuni e sezione prompt AI di esempio.
88
- - `USERGUIDE.md` incluso nel pacchetto npm tramite `ng-package.json` assets.
89
-
90
- ### v2.10.62
91
- - Migrazione da `tmw-picker` 1.0.x a 1.1.0: NgModule → standalone components, moment.js → Luxon, aggiornamento di tutti i token formato data (`DD/MM/YYYY` → `dd/MM/yyyy`).
92
- - Rimossi input inutilizzati: `answerToDuplicateId` da `eqp-dynamic-module`, `ProjectName` da `eqp-dynamic-module-configurator`.
93
- - Documentazione NPM riscritta completamente (bilingue IT/EN).
94
-
95
- ### v2.10.60
96
- - Aggiornamenti interni e correzioni bug.
97
-
98
- ---
99
-
100
- ## Versione italiana
101
-
102
- - [Panoramica](#panoramica)
103
- - [Prerequisiti](#prerequisiti)
104
- - [Installazione](#installazione)
105
- - [Configurazione del modulo](#configurazione-del-modulo)
106
- - [Componenti](#componenti)
107
- - [eqp-dynamic-module — Visualizzatore form](#eqp-dynamic-module--visualizzatore-form)
108
- - [eqp-dynamic-module-configurator — Builder form](#eqp-dynamic-module-configurator--builder-form)
109
- - [Modelli di configurazione](#modelli-di-configurazione)
110
- - [Modalità di visualizzazione](#modalità-di-visualizzazione)
111
- - [Configurazione endpoint](#configurazione-endpoint)
112
- - [Modelli dati](#modelli-dati)
113
- - [Tipi di campo](#tipi-di-campo)
114
-
115
- ---
116
-
117
- ### Panoramica
118
-
119
- `@eqproject/eqp-dynamic-module` espone **due componenti pubblici**:
120
-
121
- | Componente | Scopo |
122
- |-----------|-------|
123
- | `<eqp-dynamic-module>` | Visualizzatore, compilatore, lista, filtro e grafici a runtime |
124
- | `<eqp-dynamic-module-configurator>` | Builder no-code per creare e modificare le definizioni form |
125
-
126
- Le form sono strutture JSON salvate lato server e recuperate a runtime. La libreria gestisce rendering, validazione, recupero dati, operazioni CRUD e funzionalità avanzate come formule, trigger, action button e speech-to-text.
127
-
128
- ---
129
-
130
- ### Prerequisiti
131
-
132
- ```bash
133
- npm install @angular/cdk@^15.1.2 @angular/material@^15.1.2 @angular/material-luxon-adapter@^15.2.9 --legacy-peer-deps
134
- npm install @angular-material-components/datetime-picker@^15.0.0 @angular-material-components/moment-adapter@^15.0.0 --legacy-peer-deps
135
- npm install moment@^2.29.4 sweetalert2@^11.4.24 --legacy-peer-deps
136
- ```
137
-
138
- > Tutti i comandi `npm install` per questa libreria richiedono il flag `--legacy-peer-deps`.
139
-
140
- ---
141
-
142
- ### Installazione
143
-
144
- ```bash
145
- npm install @eqproject/eqp-dynamic-module --legacy-peer-deps
146
- ```
147
-
148
- ---
149
-
150
- ### Configurazione del modulo
151
-
152
- ```typescript
153
- import { EqpDynamicModuleModule } from '@eqproject/eqp-dynamic-module';
154
-
155
- @NgModule({
156
- imports: [
157
- EqpDynamicModuleModule
158
- ]
159
- })
160
- export class AppModule {}
161
- ```
162
-
163
- In `angular.json`, aggiungi il tema Material agli stili:
164
-
165
- ```json
166
- "styles": [
167
- "node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
168
- "src/styles.css"
169
- ]
170
- ```
171
-
172
- ---
173
-
174
- ### Componenti
175
-
176
- #### `eqp-dynamic-module` — Visualizzatore form
177
-
178
- Visualizza una form dinamica in una delle [modalità disponibili](#modalità-di-visualizzazione).
179
-
180
- **Utilizzo base**
181
-
182
- ```typescript
183
- import { DynamicModuleGeneralConfig, DynamicModuleViewModeEnum } from '@eqproject/eqp-dynamic-module';
184
-
185
- generalConfig = new DynamicModuleGeneralConfig(
186
- 'https://tua-api.esempio.it/api',
187
- this.userToken,
188
- this.context,
189
- null
190
- );
191
- ```
192
-
193
- ```html
194
- <eqp-dynamic-module
195
- [configurations]="generalConfig"
196
- [formID]="'id-del-form'"
197
- [starterViewMode]="DynamicModuleViewModeEnum.LIST"
198
- [userID]="currentUser.id"
199
- (saveRecord)="onSalvataggio($event)"
200
- (afterSaveRecord)="dopoSalvataggio($event)">
201
- </eqp-dynamic-module>
202
- ```
203
-
204
- **Input**
205
-
206
- | Input | Tipo | Default | Descrizione |
207
- |-------|------|---------|-------------|
208
- | `configurations` | `DynamicModuleGeneralConfig` | — | **Obbligatorio.** Configurazione connessione server. |
209
- | `formID` | `string` | — | **Obbligatorio.** ID del form da visualizzare. |
210
- | `starterViewMode` | `DynamicModuleViewModeEnum` | `LIST` | Modalità iniziale. |
211
- | `userID` | `string` | `"0"` | ID utente per il salvataggio record. |
212
- | `orgaID` | `string` | `"0"` | ID organizzazione. |
213
- | `showTitle` | `boolean` | `true` | Mostra/nasconde il nome del form. |
214
- | `showBackButton` | `boolean` | `true` | Mostra/nasconde il pulsante indietro. |
215
- | `showSaveButton` | `boolean` | `true` | Mostra/nasconde il pulsante salva. |
216
- | `values` | `Record[]` | `null` | Record pre-caricati per la modalità LIST. |
217
- | `FormJSON` | `string` | `""` | JSON del form per la modalità REPAIR. |
218
- | `formulaObject` | `any` | `{}` | Oggetto contesto per le formule (es. `{ role, user }`). |
219
- | `selectedRecord` | `Record \| string` | `null` | Record pre-selezionato (oggetto o ID). |
220
- | `externalButtons` | `RecordButton[]` | `[]` | Pulsanti extra nel menu azioni record. |
221
- | `actionButtons` | `ActionButton[]` | `[]` | Pulsanti azione per i campi di tipo `Bottone`. |
222
- | `defaultListActions` | `DynamicModuleListFormRecordActionsDefault` | tutti `true` | Azioni default lista: add, view, edit, duplicate, delete, graphs. |
223
- | `listViewRecordTitle` | `string[]` | `[]` | Chiavi dei campi che compongono il titolo accordion. |
224
- | `defaultListViewFunction` | `Function` | `null` | Funzione custom al caricamento della lista. |
225
- | `onSaveBackToList` | `boolean` | `false` | Torna alla LIST dopo il salvataggio. |
226
- | `onBackTo` | `DynamicModuleViewModeEnum` | `null` | Modalità di destinazione del pulsante indietro. |
227
- | `numberOfColumns` | `number` | `3` | Numero di colonne del layout. |
228
- | `showHiddenFields` | `boolean` | `true` | Mostra/nasconde i campi marcati come nascosti. |
229
- | `filterResultViewMode` | `DynamicModuleFilterResultViewModeEnum` | `INTERNAL_EQPTABLE` | Modalità visualizzazione risultati filtro. |
230
- | `additionalParams` | `any` | `null` | Parametri extra per le chiamate filtro server. |
231
- | `additionalInfo` | `any` | `null` | Dati extra per operazioni client-side. |
232
- | `prefilterParams` | `any` | `null` | Parametri pre-filtro. |
233
- | `updateInfo` | `any` | `null` | Dati per aggiornare i valori delle risposte. |
234
- | `contestualizationParams` | `any` | `null` | Parametri di contestualizzazione della lista risultati. |
235
- | `showNewSearchButton` | `boolean` | `true` | Mostra/nasconde il pulsante "nuova ricerca". |
236
- | `highlightFilter` | `any` | | Configurazione evidenziazione righe/campi. |
237
- | `isDraggableListView` | `boolean` | `true` | Abilita drag-and-drop nella lista. |
238
- | `Statistic` | `FilterStatistic` | `null` | Configurazione statistiche e filtri. |
239
- | `QueryEditorComponent` | `any` | | Componente query editor custom per i lookup. |
240
- | `debugMode` | `boolean` | `false` | Abilita log dettagliati in console. |
241
-
242
- **Output**
243
-
244
- | Output | Payload | Descrizione |
245
- |--------|---------|-------------|
246
- | `(saveRecord)` | `Record` | Emesso al salvataggio **senza** endpoint configurato. |
247
- | `(afterSaveRecord)` | `Record` | Emesso dopo la chiamata server di salvataggio. |
248
- | `(deleteRecord)` | `Record` | Emesso all'eliminazione **senza** endpoint configurato. |
249
- | `(afterDeleteRecord)` | `Record` | Emesso dopo la chiamata server di eliminazione. |
250
- | `(SaveJSON)` | `string` | Emesso all'esportazione del JSON del form. |
251
- | `(afterFilter)` | `DynRecord[]` | Emesso dopo l'applicazione di un filtro. |
252
- | `(dragStarted)` | `Record` | Emesso all'inizio di un drag. |
253
- | `(dragReleased)` | `void` | Emesso al rilascio del drag. |
254
- | `(clickDragIndicator)` | `Record` | Emesso al click sull'icona drag. |
255
- | `(out)` | `eventOut` | Output generico per comunicazione esterna. |
256
- | `(fireTrigger)` | `FireTrigger` | Emesso quando scatta un trigger. |
257
- | `(afterOutputExternalFilters)` | `FilterStatistic` | Emesso dopo filtri esterni applicati. |
258
-
259
- ---
260
-
261
- #### `eqp-dynamic-module-configurator` Builder form
262
-
263
- Designer no-code per creare e modificare definizioni form.
264
-
265
- **Modalità d'uso**
266
-
267
- ```typescript
268
- // Nuovo form
269
- const specific = new DynamicModuleConfiguratorSpecificConfig();
270
- specific.UserID = this.currentUser.id;
271
- specific.orgaID = this.currentOrga.id;
272
- const general = new DynamicModuleGeneralConfig(this.baseServerUrl, this.userToken, this.context, null);
273
- this.config = new DynamicModuleConfiguratorConfig(general, specific);
274
- ```
275
-
276
- ```html
277
- <!-- Nuovo form -->
278
- <eqp-dynamic-module-configurator
279
- *ngIf="config"
280
- [configurations]="config"
281
- (saveFormEvent)="onSalvaForm($event)">
282
- </eqp-dynamic-module-configurator>
283
-
284
- <!-- Modifica form esistente -->
285
- <eqp-dynamic-module-configurator
286
- *ngIf="config"
287
- [configurations]="config"
288
- [formID]="formID"
289
- (saveFormEvent)="onSalvaForm($event)">
290
- </eqp-dynamic-module-configurator>
291
-
292
- <!-- Esportazione -->
293
- <eqp-dynamic-module-configurator
294
- [configurations]="config"
295
- [formID]="formID"
296
- [viewMode]="'Export'"
297
- (saveFormEvent)="onSalvaForm($event)">
298
- </eqp-dynamic-module-configurator>
299
-
300
- <!-- Importazione da JSON -->
301
- <eqp-dynamic-module-configurator
302
- [configurations]="config"
303
- [formID]="null"
304
- [viewMode]="'Export'"
305
- (saveFormEvent)="onSalvaForm($event)">
306
- </eqp-dynamic-module-configurator>
307
- ```
308
-
309
- **Input**
310
-
311
- | Input | Tipo | Default | Descrizione |
312
- |-------|------|---------|-------------|
313
- | `configurations` | `DynamicModuleConfiguratorConfig` | — | **Obbligatorio.** Contenitore configurazione. |
314
- | `formID` | `string` | `null` | ID del form da modificare. `null` crea un nuovo form. |
315
- | `viewMode` | `string` | `"addOrEdit"` | `"addOrEdit"` per creare/modificare, `"Export"` per esportare/importare. |
316
- | `fieldsExtraConfig` | `FieldExtraConfig[]` | — | Configurazione extra per campi specifici. |
317
- | `triggers` | `any` | — | Definizioni trigger disponibili nell'editor. |
318
- | `actionButtons` | `any` | — | Definizioni action button disponibili. |
319
- | `contestualization` | `Contestualization[]` | — | Opzioni di contestualizzazione per lookup e filtri. |
320
- | `formulaObject` | `any` | — | Contesto per l'anteprima delle formule. |
321
- | `QueryEditorComponent` | `DynamicLoaderDirectiveData` | — | Componente query editor custom. |
322
- | `debugMode` | `boolean` | `false` | Abilita log dettagliati. |
323
- | `configuratorTheme` | `Record<string, string> \| null` | `null` | Override delle variabili CSS del tema tramite oggetto TypeScript. |
324
- | `configuratorThemeCss` | `string \| null` | `null` | Override delle variabili CSS del tema tramite stringa CSS (es. contenuto di un file `.css`). |
325
-
326
- **Output**
327
-
328
- | Output | Payload | Descrizione |
329
- |--------|---------|-------------|
330
- | `(saveFormEvent)` | `Form` | Emesso al salvataggio **senza** endpoint configurato. |
331
- | `(afterSaveFormEvent)` | `Form` | Emesso dopo la chiamata server di salvataggio. |
332
- | `(out)` | `eventOut` | Output generico per comunicazione esterna. |
333
- | `(fireTrigger)` | `FireTrigger` | Emesso quando scatta un trigger. |
334
-
335
- **Theming**
336
-
337
- Il configurator espone un sistema di temi basato su CSS custom properties. Tutti i valori iniettati tramite tema sono applicati con `!important` e non possono essere sovrascritti dall'esterno se non attraverso questi input.
338
-
339
- ```html
340
- <!-- Opzione A: oggetto TypeScript -->
341
- <eqp-dynamic-module-configurator
342
- [configurations]="config"
343
- [configuratorTheme]="{ '--conf-gradient': 'linear-gradient(to right, #1565c0, #0288d1)', '--conf-bg-page': '#f0f6fb' }">
344
- </eqp-dynamic-module-configurator>
345
-
346
- <!-- Opzione B: file CSS caricato come stringa -->
347
- <eqp-dynamic-module-configurator
348
- [configurations]="config"
349
- [configuratorThemeCss]="themeCssString">
350
- </eqp-dynamic-module-configurator>
351
- ```
352
-
353
- Formato del file CSS per `configuratorThemeCss` (nessun selettore richiesto):
354
-
355
- ```css
356
- --conf-gradient: linear-gradient(to right, #1565c0, #0288d1);
357
- --conf-bg-page: #f0f6fb;
358
- --conf-btn-color: #ffffff;
359
- ```
360
-
361
- Variabili disponibili:
362
-
363
- | Variabile | Default | Descrizione |
364
- |-----------|---------|-------------|
365
- | `--conf-gradient` | gradiente viola-blu | Sfondo bottoni e header |
366
- | `--conf-bg-page` | `#f5f5f5` | Sfondo generale pagina/stepper |
367
- | `--conf-radius` | `10px` | Border radius bottoni |
368
- | `--conf-modal-radius` | `12px` | Border radius modali |
369
- | `--conf-accent` | `#693DDA` | Colore accento (bordi, focus) |
370
- | `--conf-primary` | `#1E31EB` | Colore primario |
371
- | `--conf-step-selected` | `#643cda` | Freccia step selezionato |
372
- | `--conf-step-edit` | `#3034e7` | Freccia step completato |
373
- | `--conf-stepper-header-bg` | ereditato da `--conf-bg-page` | Sfondo zona superiore (header stepper) |
374
- | `--conf-stepper-content-bg` | ereditato da `--conf-bg-page` | Sfondo zona inferiore (form e bottoni) |
375
- | `--conf-step-icon-edit-bg` | ereditato da `--conf-step-edit` | Sfondo pallini step completati |
376
- | `--conf-btn-color` | `#ffffff` | Colore testo bottoni attivi (sfondo gradiente) |
377
- | `--conf-hint-btn-bg` | `#2563eb` | Sfondo bottone suggerimento rapido (lampadina) |
378
- | `--conf-hint-btn-hover-bg` | `#1d4ed8` | Sfondo lampadina al hover |
379
- | `--conf-table-header-bg` | variabile SCSS | Sfondo header tabella campi |
380
- | `--conf-search-bg` | variabile SCSS | Sfondo campo di ricerca |
381
- | `--conf-table-bg` | `#ffffff` | Sfondo righe tabella |
382
- | `--conf-card-bg` | `#ffffff` | Sfondo card |
383
- | `--conf-font-family` | `inherit` | Font dell'intero configurator |
384
-
385
- ---
386
-
387
- ### Modelli di configurazione
388
-
389
- #### `DynamicModuleGeneralConfig`
390
-
391
- ```typescript
392
- const general = new DynamicModuleGeneralConfig(
393
- 'https://api.esempio.it/api', // baseServerUrl
394
- userToken, // token autenticazione
395
- context, // oggetto Context
396
- null // EndPointConfiguration (null = usa default)
397
- );
398
- ```
399
-
400
- | Proprietà | Tipo | Descrizione |
401
- |-----------|------|-------------|
402
- | `baseServerUrl` | `string` | URL base API. Usato per costruire automaticamente gli endpoint se `endPointConfiguration` è `null`. |
403
- | `userToken` | `string` | Token di autenticazione inviato con ogni chiamata. |
404
- | `endPointConfiguration` | `EndPointConfiguration \| null` | Override completo degli endpoint. `null` usa le rotte standard. |
405
- | `context` | `Context` | Contesto applicativo. |
406
-
407
- #### `DynamicModuleListFormRecordActionsDefault`
408
-
409
- ```typescript
410
- const actions = new DynamicModuleListFormRecordActionsDefault();
411
- actions.add = true; // Pulsante "Aggiungi" nell'header lista
412
- actions.view = true; // Visualizza record (solo lettura)
413
- actions.edit = true; // Modifica record
414
- actions.duplicate = false; // Duplica record
415
- actions.delete = true; // Elimina record
416
- actions.graphs = false; // Grafici record
417
- ```
418
-
419
- ---
420
-
421
- ### Modalità di visualizzazione
422
-
423
- ```typescript
424
- import { DynamicModuleViewModeEnum } from '@eqproject/eqp-dynamic-module';
425
-
426
- enum DynamicModuleViewModeEnum {
427
- NONE = 0, // Nessuna visualizzazione
428
- VIEW = 1, // Sola lettura
429
- COMPILE = 2, // Compilazione / modifica
430
- LIST = 3, // Lista record
431
- REPAIR = 4, // Revisione form
432
- LISTWIEW = 5, // Lista compatta alternativa
433
- FILTER = 6, // Filtro / ricerca
434
- GRAPHS = 7, // Statistiche e grafici
435
- HLIST = 8, // Lista orizzontale
436
- EXTERNAL_FILTER = 9 // Filtro guidato dal componente padre
437
- }
438
- ```
439
-
440
- ---
441
-
442
- ### Configurazione endpoint
443
-
444
- Per default la libreria costruisce tutti gli URL dagli endpoint a partire da `baseServerUrl`. Passa un `EndPointConfiguration` custom per sovrascrivere singole rotte.
445
-
446
- ```typescript
447
- import { EndPointConfiguration, EndPointData, RequestMethodEnum, ParamTypeEnum } from '@eqproject/eqp-dynamic-module';
448
-
449
- const endPoints = new EndPointConfiguration();
450
- endPoints.Records.SaveEndPoint = new EndPointData();
451
- endPoints.Records.SaveEndPoint.Url = 'https://custom-api.esempio.it/records/save';
452
- endPoints.Records.SaveEndPoint.RequestMethod = RequestMethodEnum.POST;
453
- endPoints.Records.SaveEndPoint.Params = [{
454
- ParamName: 'orgId',
455
- ParamValue: this.orgaId,
456
- ParamType: ParamTypeEnum['Query param']
457
- }];
458
- ```
459
-
460
- **Endpoint Records disponibili:** `GetWithContextualizationByFormCodeEndPoint`, `GetByFormIDEndPoint`, `GetByFormCodeEndPoint`, `GetAllByEntAndUserIDEndPoint`, `GetByIDEndPoint`, `SaveEndPoint`, `DuplicateEndPoint`, `DeleteEndPoint`, `RepairEndPoint`, `ApplyFilter`, `GetAllAttachmentsEndPoint`.
461
-
462
- **Endpoint Forms disponibili:** `GetByIDEndPoint`, `GetAllFormEndPoint`, `GetByIDAndVersionEndPoint`, `SaveEndPoint`, `SaveAttachmentEndPoint`, `ExportByIDEndPoint`, `GetAttachmentWithBases64`, `SpeechToFormEditEndPoint`.
463
-
464
- ---
465
-
466
- ### Modelli dati
467
-
468
- #### `Record`
469
-
470
- | Proprietà | Tipo | Descrizione |
471
- |-----------|------|-------------|
472
- | `ID` | `string` | Identificatore unico. |
473
- | `EntID` | `string` | ID del form (entità) di appartenenza. |
474
- | `Version` | `number` | Versione del form al momento della compilazione. |
475
- | `userID` | `string` | ID utente che ha creato il record. |
476
- | `AnswerDate` | `string` | Data di compilazione (ISO). |
477
- | `HTMLreadableValues` | `string` | Valori in formato HTML leggibile. |
478
- | `AdditionalParams` | `any` | Parametri aggiuntivi. |
479
- | `AdditionalInfo` | `any` | Informazioni aggiuntive. |
480
-
481
- ---
482
-
483
- ### Tipi di campo
484
-
485
- | Valore | Chiave | Descrizione |
486
- |--------|--------|-------------|
487
- | `1` | `Campo di testo` | Input testo singola riga. |
488
- | `2` | `Area di testo` | Textarea multiriga. |
489
- | `3` | `Booleano` | Checkbox / toggle. |
490
- | `4` | `Data e/ora` | Selettore data e/o ora. |
491
- | `5` | `Campo numerico` | Input numerico con maschera. |
492
- | `6` | `Allegato` | Upload file. |
493
- | `7` | `Immagine` | Upload immagine con crop. |
494
- | `8` | `Elenco generico` | Dropdown / selezione multipla. |
495
- | `9` | `Lookup` | Lookup server-side con query configurabile. |
496
- | `10` | `Form di dettaglio` | Form di dettaglio annidato. |
497
- | `11` | `Elenco immagini` | Selettore lista immagini. |
498
- | `12` | `Etichetta` | Solo visualizzazione. |
499
- | `13` | `Immagine con markers` | Immagine con annotazioni interattive. |
500
- | `14` | `Bottone` | Campo pulsante azione. |
501
-
502
- ---
503
-
504
- ## English version
505
-
506
- - [Overview](#overview)
507
- - [Prerequisites](#prerequisites)
508
- - [Installation](#installation)
509
- - [Module Setup](#module-setup)
510
- - [Components](#components)
511
- - [eqp-dynamic-module Form Viewer/Filler](#eqp-dynamic-module--form-viewerfiller)
512
- - [eqp-dynamic-module-configurator Form Builder](#eqp-dynamic-module-configurator--form-builder)
513
- - [Configuration Models](#configuration-models)
514
- - [View Modes](#view-modes)
515
- - [Endpoint Configuration](#endpoint-configuration)
516
- - [Data Models](#data-models)
517
- - [Field Types Reference](#field-types-reference)
518
-
519
- ---
520
-
521
- ### Overview
522
-
523
- `@eqproject/eqp-dynamic-module` exposes **two public components**:
524
-
525
- | Component | Purpose |
526
- |-----------|---------|
527
- | `<eqp-dynamic-module>` | Runtime form viewer, filler, list, filter and graphs |
528
- | `<eqp-dynamic-module-configurator>` | No-code form builder (create, edit, import, export) |
529
-
530
- Forms are defined as JSON structures stored server-side and fetched at runtime. The library handles rendering, validation, data retrieval, CRUD operations and advanced features like formulas, triggers, action buttons and speech-to-text.
531
-
532
- ---
533
-
534
- ### Prerequisites
535
-
536
- ```bash
537
- npm install @angular/cdk@^15.1.2 @angular/material@^15.1.2 @angular/material-luxon-adapter@^15.2.9 --legacy-peer-deps
538
- npm install @angular-material-components/datetime-picker@^15.0.0 @angular-material-components/moment-adapter@^15.0.0 --legacy-peer-deps
539
- npm install moment@^2.29.4 sweetalert2@^11.4.24 --legacy-peer-deps
540
- ```
541
-
542
- > All `npm install` commands for this library require `--legacy-peer-deps`.
543
-
544
- ---
545
-
546
- ### Installation
547
-
548
- ```bash
549
- npm install @eqproject/eqp-dynamic-module --legacy-peer-deps
550
- ```
551
-
552
- ---
553
-
554
- ### Module Setup
555
-
556
- ```typescript
557
- import { EqpDynamicModuleModule } from '@eqproject/eqp-dynamic-module';
558
-
559
- @NgModule({
560
- imports: [EqpDynamicModuleModule]
561
- })
562
- export class AppModule {}
563
- ```
564
-
565
- Add Angular Material theme to `angular.json` styles:
566
-
567
- ```json
568
- "styles": [
569
- "node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
570
- "src/styles.css"
571
- ]
572
- ```
573
-
574
- ---
575
-
576
- ### Components
577
-
578
- #### `eqp-dynamic-module` — Form Viewer/Filler
579
-
580
- **Basic usage**
581
-
582
- ```typescript
583
- import { DynamicModuleGeneralConfig, DynamicModuleViewModeEnum } from '@eqproject/eqp-dynamic-module';
584
-
585
- generalConfig = new DynamicModuleGeneralConfig(
586
- 'https://your-api.example.com/api',
587
- this.userToken,
588
- this.context,
589
- null
590
- );
591
- ```
592
-
593
- ```html
594
- <eqp-dynamic-module
595
- [configurations]="generalConfig"
596
- [formID]="'your-form-id'"
597
- [starterViewMode]="DynamicModuleViewModeEnum.LIST"
598
- [userID]="currentUser.id"
599
- (saveRecord)="onSave($event)"
600
- (afterSaveRecord)="onAfterSave($event)">
601
- </eqp-dynamic-module>
602
- ```
603
-
604
- **Inputs**
605
-
606
- | Input | Type | Default | Description |
607
- |-------|------|---------|-------------|
608
- | `configurations` | `DynamicModuleGeneralConfig` | — | **Required.** Server connection configuration. |
609
- | `formID` | `string` | — | **Required.** ID of the form to display. |
610
- | `starterViewMode` | `DynamicModuleViewModeEnum` | `LIST` | Initial view mode. |
611
- | `userID` | `string` | `"0"` | User ID stamped on saved records. |
612
- | `orgaID` | `string` | `"0"` | Organization ID. |
613
- | `showTitle` | `boolean` | `true` | Show/hide the form name. |
614
- | `showBackButton` | `boolean` | `true` | Show/hide the back button. |
615
- | `showSaveButton` | `boolean` | `true` | Show/hide the save button. |
616
- | `values` | `Record[]` | `null` | Pre-loaded records for LIST mode. |
617
- | `FormJSON` | `string` | `""` | Form JSON string for REPAIR mode. |
618
- | `formulaObject` | `any` | `{}` | Context object for formula evaluation. |
619
- | `selectedRecord` | `Record \| string` | `null` | Pre-select a record by object or ID. |
620
- | `externalButtons` | `RecordButton[]` | `[]` | Extra buttons in the record action menu. |
621
- | `actionButtons` | `ActionButton[]` | `[]` | Action buttons for `Bottone` field type. |
622
- | `defaultListActions` | `DynamicModuleListFormRecordActionsDefault` | all `true` | Toggle default list actions. |
623
- | `listViewRecordTitle` | `string[]` | `[]` | Field keys composing the accordion title. |
624
- | `defaultListViewFunction` | `Function` | `null` | Custom function called on list load. |
625
- | `onSaveBackToList` | `boolean` | `false` | Return to LIST after save. |
626
- | `onBackTo` | `DynamicModuleViewModeEnum` | `null` | View mode for the back button. |
627
- | `numberOfColumns` | `number` | `3` | Number of layout columns. |
628
- | `showHiddenFields` | `boolean` | `true` | Show/hide hidden fields. |
629
- | `filterResultViewMode` | `DynamicModuleFilterResultViewModeEnum` | `INTERNAL_EQPTABLE` | Filter results display mode. |
630
- | `additionalParams` | `any` | `null` | Extra params for server filter calls. |
631
- | `additionalInfo` | `any` | `null` | Extra data for client-side operations. |
632
- | `prefilterParams` | `any` | `null` | Pre-filter parameters. |
633
- | `updateInfo` | `any` | `null` | Data to update response values after load. |
634
- | `contestualizationParams` | `any` | `null` | Contextualisation parameters. |
635
- | `showNewSearchButton` | `boolean` | `true` | Show/hide the new search button. |
636
- | `highlightFilter` | `any` | | Row/field highlighting configuration. |
637
- | `isDraggableListView` | `boolean` | `true` | Enable drag-and-drop in list view. |
638
- | `Statistic` | `FilterStatistic` | `null` | Statistics and filter configuration. |
639
- | `QueryEditorComponent` | `any` | | Custom query editor component for lookups. |
640
- | `debugMode` | `boolean` | `false` | Enable verbose console logging. |
641
-
642
- **Outputs**
643
-
644
- | Output | Payload | Description |
645
- |--------|---------|-------------|
646
- | `(saveRecord)` | `Record` | Emitted on save when **no** save endpoint is configured. |
647
- | `(afterSaveRecord)` | `Record` | Emitted after server save call completes. |
648
- | `(deleteRecord)` | `Record` | Emitted on delete when **no** delete endpoint is configured. |
649
- | `(afterDeleteRecord)` | `Record` | Emitted after server delete call completes. |
650
- | `(SaveJSON)` | `string` | Emitted when form JSON is exported. |
651
- | `(afterFilter)` | `DynRecord[]` | Emitted after filter operation with result set. |
652
- | `(dragStarted)` | `Record` | Emitted when drag starts. |
653
- | `(dragReleased)` | `void` | Emitted when drag ends. |
654
- | `(clickDragIndicator)` | `Record` | Emitted when drag handle is clicked. |
655
- | `(out)` | `eventOut` | General-purpose external output. |
656
- | `(fireTrigger)` | `FireTrigger` | Emitted when a trigger fires. |
657
- | `(afterOutputExternalFilters)` | `FilterStatistic` | Emitted after external filters applied. |
658
-
659
- ---
660
-
661
- #### `eqp-dynamic-module-configurator` Form Builder
662
-
663
- **Usage modes**
664
-
665
- ```html
666
- <!-- Create new form -->
667
- <eqp-dynamic-module-configurator
668
- *ngIf="config"
669
- [configurations]="config"
670
- (saveFormEvent)="onFormSaved($event)">
671
- </eqp-dynamic-module-configurator>
672
-
673
- <!-- Edit existing form -->
674
- <eqp-dynamic-module-configurator
675
- [configurations]="config"
676
- [formID]="formID"
677
- (saveFormEvent)="onFormSaved($event)">
678
- </eqp-dynamic-module-configurator>
679
-
680
- <!-- Export form -->
681
- <eqp-dynamic-module-configurator
682
- [configurations]="config"
683
- [formID]="formID"
684
- [viewMode]="'Export'"
685
- (saveFormEvent)="onFormSaved($event)">
686
- </eqp-dynamic-module-configurator>
687
-
688
- <!-- Import from JSON -->
689
- <eqp-dynamic-module-configurator
690
- [configurations]="config"
691
- [formID]="null"
692
- [viewMode]="'Export'"
693
- (saveFormEvent)="onFormSaved($event)">
694
- </eqp-dynamic-module-configurator>
695
- ```
696
-
697
- **Inputs**
698
-
699
- | Input | Type | Default | Description |
700
- |-------|------|---------|-------------|
701
- | `configurations` | `DynamicModuleConfiguratorConfig` | — | **Required.** Configuration container. |
702
- | `formID` | `string` | `null` | Form ID to edit. `null` creates a new form. |
703
- | `viewMode` | `string` | `"addOrEdit"` | `"addOrEdit"` or `"Export"`. |
704
- | `fieldsExtraConfig` | `FieldExtraConfig[]` | — | Extra configuration for specific fields. |
705
- | `triggers` | `any` | — | Trigger definitions for the editor. |
706
- | `actionButtons` | `any` | — | Action button definitions. |
707
- | `contestualization` | `Contestualization[]` | — | Contextualisation options. |
708
- | `formulaObject` | `any` | — | Context for formula preview. |
709
- | `QueryEditorComponent` | `DynamicLoaderDirectiveData` | — | Custom query editor component. |
710
- | `debugMode` | `boolean` | `false` | Enable verbose logging. |
711
- | `configuratorTheme` | `Record<string, string> \| null` | `null` | CSS variable overrides via TypeScript object. |
712
- | `configuratorThemeCss` | `string \| null` | `null` | CSS variable overrides via CSS text string (e.g. contents of a `.css` file). |
713
-
714
- **Outputs**
715
-
716
- | Output | Payload | Description |
717
- |--------|---------|-------------|
718
- | `(saveFormEvent)` | `Form` | Emitted on save when **no** save endpoint is configured. |
719
- | `(afterSaveFormEvent)` | `Form` | Emitted after server save call completes. |
720
- | `(out)` | `eventOut` | General-purpose external output. |
721
- | `(fireTrigger)` | `FireTrigger` | Emitted when a trigger fires. |
722
-
723
- **Theming**
724
-
725
- The configurator exposes a theming system based on CSS custom properties. All values injected via the theme inputs are applied with `!important` and cannot be overridden externally except through these inputs.
726
-
727
- ```html
728
- <!-- Option A: TypeScript object -->
729
- <eqp-dynamic-module-configurator
730
- [configurations]="config"
731
- [configuratorTheme]="{ '--conf-gradient': 'linear-gradient(to right, #1565c0, #0288d1)' }">
732
- </eqp-dynamic-module-configurator>
733
-
734
- <!-- Option B: CSS file loaded as string -->
735
- <eqp-dynamic-module-configurator
736
- [configurations]="config"
737
- [configuratorThemeCss]="themeCssString">
738
- </eqp-dynamic-module-configurator>
739
- ```
740
-
741
- CSS file format for `configuratorThemeCss` (no selector required):
742
-
743
- ```css
744
- --conf-gradient: linear-gradient(to right, #1565c0, #0288d1);
745
- --conf-bg-page: #f0f6fb;
746
- --conf-btn-color: #ffffff;
747
- ```
748
-
749
- Available variables:
750
-
751
- | Variable | Default | Description |
752
- |----------|---------|-------------|
753
- | `--conf-gradient` | purple-blue gradient | Button and header background |
754
- | `--conf-bg-page` | `#f5f5f5` | General page/stepper background |
755
- | `--conf-radius` | `10px` | Button border radius |
756
- | `--conf-modal-radius` | `12px` | Modal border radius |
757
- | `--conf-accent` | `#693DDA` | Accent colour (borders, focus) |
758
- | `--conf-primary` | `#1E31EB` | Primary colour |
759
- | `--conf-step-selected` | `#643cda` | Selected step arrow |
760
- | `--conf-step-edit` | `#3034e7` | Completed step arrow |
761
- | `--conf-stepper-header-bg` | inherited from `--conf-bg-page` | Upper zone background (stepper header) |
762
- | `--conf-stepper-content-bg` | inherited from `--conf-bg-page` | Lower zone background (form and buttons) |
763
- | `--conf-step-icon-edit-bg` | inherited from `--conf-step-edit` | Completed step icon background |
764
- | `--conf-btn-color` | `#ffffff` | Active button text colour (gradient background) |
765
- | `--conf-hint-btn-bg` | `#2563eb` | Quick-suggestion button (lightbulb) background |
766
- | `--conf-hint-btn-hover-bg` | `#1d4ed8` | Lightbulb button hover background |
767
- | `--conf-table-header-bg` | SCSS variable | Field table header background |
768
- | `--conf-search-bg` | SCSS variable | Search field background |
769
- | `--conf-table-bg` | `#ffffff` | Table row background |
770
- | `--conf-card-bg` | `#ffffff` | Card background |
771
- | `--conf-font-family` | `inherit` | Configurator-wide font family |
772
-
773
- ---
774
-
775
- ### Configuration Models
776
-
777
- #### `DynamicModuleGeneralConfig`
778
-
779
- ```typescript
780
- const general = new DynamicModuleGeneralConfig(
781
- baseServerUrl, // string e.g. "https://api.example.com/api"
782
- userToken, // string auth token
783
- context, // Context
784
- endPointConfiguration // EndPointConfiguration | null
785
- );
786
- ```
787
-
788
- #### `DynamicModuleListFormRecordActionsDefault`
789
-
790
- ```typescript
791
- const actions = new DynamicModuleListFormRecordActionsDefault();
792
- actions.add = true;
793
- actions.view = true;
794
- actions.edit = true;
795
- actions.duplicate = false;
796
- actions.delete = true;
797
- actions.graphs = false;
798
- ```
799
-
800
- ---
801
-
802
- ### View Modes
803
-
804
- ```typescript
805
- enum DynamicModuleViewModeEnum {
806
- NONE = 0,
807
- VIEW = 1,
808
- COMPILE = 2,
809
- LIST = 3,
810
- REPAIR = 4,
811
- LISTWIEW = 5,
812
- FILTER = 6,
813
- GRAPHS = 7,
814
- HLIST = 8,
815
- EXTERNAL_FILTER = 9
816
- }
817
- ```
818
-
819
- ---
820
-
821
- ### Endpoint Configuration
822
-
823
- ```typescript
824
- const endPoints = new EndPointConfiguration();
825
- endPoints.Records.SaveEndPoint = new EndPointData();
826
- endPoints.Records.SaveEndPoint.Url = 'https://custom-api.example.com/records/save';
827
- endPoints.Records.SaveEndPoint.RequestMethod = RequestMethodEnum.POST;
828
- endPoints.Records.SaveEndPoint.Params = [{
829
- ParamName: 'orgId',
830
- ParamValue: this.orgaId,
831
- ParamType: ParamTypeEnum['Query param']
832
- }];
833
- const general = new DynamicModuleGeneralConfig(baseUrl, token, context, endPoints);
834
- ```
835
-
836
- **Available Records endpoints:** `GetWithContextualizationByFormCodeEndPoint`, `GetByFormIDEndPoint`, `GetByFormCodeEndPoint`, `GetAllByEntAndUserIDEndPoint`, `GetByIDEndPoint`, `SaveEndPoint`, `DuplicateEndPoint`, `DeleteEndPoint`, `RepairEndPoint`, `ApplyFilter`, `GetAllAttachmentsEndPoint`.
837
-
838
- **Available Forms endpoints:** `GetByIDEndPoint`, `GetAllFormEndPoint`, `GetByIDAndVersionEndPoint`, `SaveEndPoint`, `SaveAttachmentEndPoint`, `ExportByIDEndPoint`, `GetAttachmentWithBases64`, `SpeechToFormEditEndPoint`.
839
-
840
- ---
841
-
842
- ### Data Models
843
-
844
- #### `Record`
845
-
846
- | Property | Type | Description |
847
- |----------|------|-------------|
848
- | `ID` | `string` | Unique record identifier. |
849
- | `EntID` | `string` | ID of the form this record belongs to. |
850
- | `Version` | `number` | Form version at compilation time. |
851
- | `userID` | `string` | ID of the user who created the record. |
852
- | `AnswerDate` | `string` | ISO date string of compilation. |
853
- | `HTMLreadableValues` | `string` | Pre-rendered HTML of field values. |
854
- | `AdditionalParams` | `any` | Extra parameters. |
855
- | `AdditionalInfo` | `any` | Extra information. |
856
-
857
- ---
858
-
859
- ### Field Types Reference
860
-
861
- | Value | Key | Description |
862
- |-------|-----|-------------|
863
- | `1` | `Campo di testo` | Single-line text input. |
864
- | `2` | `Area di testo` | Multi-line textarea. |
865
- | `3` | `Booleano` | Checkbox / boolean toggle. |
866
- | `4` | `Data e/ora` | Date and/or time picker. |
867
- | `5` | `Campo numerico` | Numeric input with mask. |
868
- | `6` | `Allegato` | File attachment upload. |
869
- | `7` | `Immagine` | Image upload with optional cropping. |
870
- | `8` | `Elenco generico` | Dropdown / multi-select list. |
871
- | `9` | `Lookup` | Server-side lookup with configurable query. |
872
- | `10` | `Form di dettaglio` | Embedded detail (inner) form. |
873
- | `11` | `Elenco immagini` | Image selector list. |
874
- | `12` | `Etichetta` | Display-only label. |
875
- | `13` | `Immagine con markers` | Image with interactive annotation markers. |
876
- | `14` | `Bottone` | Action button field. |
1
+ # @eqproject/eqp-dynamic-module
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@eqproject/eqp-dynamic-module.svg)](https://www.npmjs.com/package/@eqproject/eqp-dynamic-module)
4
+ [![Angular](https://img.shields.io/badge/Angular-15-red.svg)](https://angular.io/)
5
+
6
+ > Libreria Angular 15 per la creazione, visualizzazione e gestione di form dinamiche con configuratore no-code.
7
+ > Angular 15 library for building, rendering and managing dynamic forms with a no-code configurator.
8
+
9
+ 📖 **[Guida utente / User Guide →](./USERGUIDE.md)**
10
+
11
+ ---
12
+
13
+ ## Changelog
14
+
15
+ ### v2.10.101
16
+ - **Migrazione interna `eqp-table`/`eqp-attachments`/`eqp-numeric` `tmw-table`/`tmw-attachments`/`tmw-numeric`:** le ultime tre dipendenze `@eqproject/eqp-*` sono state sostituite dalle librerie Material-free `tmw-*` (stesso lavoro già fatto per `eqp-select`/`eqp-datetimepicker` nelle versioni precedenti). Nessun cambio di API pubblica di questa libreria: i tag `<eqp-table>`/`<eqp-attachments>` erano già privati, i modelli `ConfigColumn`/`TypeColumn`/`DynAttachment` restano gli stessi nomi/forma. Chi consuma questa libreria non deve più installare `@eqproject/eqp-table`, `@eqproject/eqp-attachments`, `@eqproject/eqp-numeric` `@eqproject/eqp-filters` (import morto, mai realmente usato).
17
+ - **Migrazione completa `<mat-icon>` `<tmw-icon>`:** tutte le icone della libreria (inclusi i pulsanti del builder, i template di campo e le colonne azione delle tabelle) sono ora renderizzate dalla nuova libreria `tmw-icons` (SVG inline, icone vendorizzate da Tabler Icons, nessuna dipendenza dal font Material Icons). **Attenzione per chi ha form esistenti con icone personalizzate**: i campi di testo libero "Icona" (`IconName` su `TextField`/`NumericField`/`TextareaField`, `Icon` su `ActionButton`) si aspettavano nomi Material Icons (es. `search`, `home`, `euro`) ora si aspettano nomi Tabler Icons (es. `search`, `user`, `currency-euro`); i nomi già salvati che non trovano corrispondenza esatta nel registro `tmw-icons` semplicemente non renderizzano l'icona (nessun errore a runtime, solo icona assente). Nessun impatto sul resto del form.
18
+ - **Pulizia dipendenze:** rimosse dalle `peerDependencies` `@angular-material-components/datetime-picker`, `@angular-material-components/moment-adapter` e `moment` (mai più necessarie dopo la migrazione a `tmw-picker`, completata in una versione precedente). Nuove dipendenze dirette: `tmw-attachments`, `tmw-icons`, `tmw-numeric`, `tmw-table`, `xlsx` (quest'ultima solo per l'export XLSX di `filter-form-statistic`, `tmw-table` non ha un formato XLSX nativo).
19
+
20
+ - **Internal migration `eqp-table`/`eqp-attachments`/`eqp-numeric` `tmw-table`/`tmw-attachments`/`tmw-numeric`:** the last three `@eqproject/eqp-*` dependencies have been replaced with the Material-free `tmw-*` libraries (same work already done for `eqp-select`/`eqp-datetimepicker` in previous versions). No public API change in this library: the `<eqp-table>`/`<eqp-attachments>` tags were already private, the `ConfigColumn`/`TypeColumn`/`DynAttachment` models keep the same names/shape. Consumers of this library no longer need to install `@eqproject/eqp-table`, `@eqproject/eqp-attachments`, `@eqproject/eqp-numeric` or `@eqproject/eqp-filters` (dead import, never actually used).
21
+ - **Complete `<mat-icon>` `<tmw-icon>` migration:** every icon in the library (including builder buttons, field templates and table action columns) is now rendered by the new `tmw-icons` library (inline SVG, icons vendored from Tabler Icons, no dependency on the Material Icons font). **Note for existing forms with custom icons**: the free-text "Icon" fields (`IconName` on `TextField`/`NumericField`/`TextareaField`, `Icon` on `ActionButton`) used to expect Material Icons names (e.g. `search`, `home`, `euro`) they now expect Tabler Icons names (e.g. `search`, `user`, `currency-euro`); previously saved names with no exact match in the `tmw-icons` registry simply don't render the icon (no runtime error, just a missing icon). No impact on the rest of the form.
22
+ - **Dependency cleanup:** removed `@angular-material-components/datetime-picker`, `@angular-material-components/moment-adapter` and `moment` from `peerDependencies` (no longer needed after the `tmw-picker` migration, completed in a previous version). New direct dependencies: `tmw-attachments`, `tmw-icons`, `tmw-numeric`, `tmw-table`, `xlsx` (the latter only for `filter-form-statistic`'s XLSX export — `tmw-table` has no native XLSX format).
23
+
24
+ ### v2.10.100
25
+ - **Cleanup rimossi import morti di `@eqproject/eqp-datetimepicker` e `@eqproject/eqp-img-drawing`:** entrambi erano registrati nell'`NgModule` (`EqpDatetimepickerModule`, `EqpImgDrawingModule`) e in `trigger-creator.component.ts` (`PickerModeEnum`) ma non più usati da nessun template sostituiti internamente da tempo da `tmw-datetimepicker` (campo Data) e da `tmw-image-drawer`/`tmw-image-marker` (campo Immagine con markers). Nessun impatto funzionale: build verificata anche con i due pacchetti fisicamente assenti da `node_modules`, per provare che non fossero più necessari. Chi consuma questa libreria non deve più installare `@eqproject/eqp-datetimepicker` né `@eqproject/eqp-img-drawing`.
26
+ - **Cleanup removed dead imports of `@eqproject/eqp-datetimepicker` and `@eqproject/eqp-img-drawing`:** both were registered in the `NgModule` (`EqpDatetimepickerModule`, `EqpImgDrawingModule`) and in `trigger-creator.component.ts` (`PickerModeEnum`) but no longer used by any template — internally superseded a while ago by `tmw-datetimepicker` (Date field) and `tmw-image-drawer`/`tmw-image-marker` (Image with markers field). No functional impact: build verified even with both packages physically absent from `node_modules`, to prove they were no longer required. Consumers of this library no longer need to install `@eqproject/eqp-datetimepicker` or `@eqproject/eqp-img-drawing`.
27
+
28
+ ### v2.10.99
29
+ - **Bugfix configurator immagine persa su campo `Immagine`/`Immagine con markers`:** `catchButtonImageChange` e `catchButtonImageWithMarkersChange` in `add-form-field` leggevano l'indice sbagliato (`attachments[1]`) dell'array emesso da `eqp-attachments`. Al primo caricamento di un'immagine su un campo nuovo l'array ha un solo elemento, quindi `field.DynAttachment` veniva sovrascritto con `undefined`: l'immagine spariva riaprendo la modale di modifica campo e non compariva mai in anteprima. Corretto leggendo `attachments[attachments.length - 1]`.
30
+ - **Bugfix configuratorimage lost on `Image`/`Image with markers` field:** `catchButtonImageChange` and `catchButtonImageWithMarkersChange` in `add-form-field` were reading the wrong index (`attachments[1]`) from the array emitted by `eqp-attachments`. On the first image upload to a new field the array has only one element, so `field.DynAttachment` was overwritten with `undefined`: the image disappeared when reopening the field edit dialog and never showed up in the preview. Fixed to read `attachments[attachments.length - 1]`.
31
+
32
+ ### v2.10.87
33
+ - **Bugfix configurator — sezione "Generale" assente per 5 tipi di campo:** durante il lavoro di potenziamento grafico (v2.10.68–v2.10.70), i tipi `ActionButtonField`, `ImageField`, `ImageWithMarkersField`, `ListValueField` e `ImageSelectorField` avevano ricevuto la sezione "Grafica" nel tab "Stile Compilazione" del configuratore, ma la sezione "Generale" (Larghezza campo, Visibile, VisibleIf, Tooltip, Tipo di invisibilità, Mantieni il valore) era stata rimossa per errore. Ripristinata per tutti e 5 i tipi.
34
+ - **Bugfix configurator "Generale" section missing for 5 field types:** during the graphical enhancement work (v2.10.68–v2.10.70), `ActionButtonField`, `ImageField`, `ImageWithMarkersField`, `ListValueField` and `ImageSelectorField` received the "Grafica" section in the configurator's "Stile Compilazione" tab, but the "Generale" section (field width, visibility, VisibleIf, tooltip, invisibility type, maintain value) was accidentally removed. Restored for all 5 field types.
35
+
36
+ ### v2.10.86
37
+ - **Bugfix loop infinito `ListValueField`:** `FormControl.setValue()` notificava il callback `_onChange` del `NgModel` registrato tramite `[formControlName]` sul `mat-checkbox`, causando `ngModelChange` → `updateSelected()` → `setFormControlValue()` in ricorsione infinita. Aggiunto `{ emitModelToViewChange: false }` a `setFormControlValue()` per interrompere il ciclo. Fix correlati: `updateSelected()` ora restituisce `null` (non `[]`) per campi single-choice senza selezione, evitando instabilità Angular CD da `[] !== []`; `resetArrayData()` chiama `updateSelected(false)` per non emettere `recordChange` durante il rebuild delle opzioni; `updateField()` distingue formula-per-valore da formula-per-opzioni nei campi `DataGetterType=Formula`.
38
+ - **Bugfix loop infinito `onRecordChange`:** aggiunta guardia di rientranza `_recordChanging` con `try/finally` in `add-form-record.onRecordChange()` per prevenire ricorsione da campi formula concatenati (es. campo numerico campo elenco valorizzato dalla formula del primo).
39
+ - **Bugfix loop in anteprima `DynAttachment.ButtonKey` null:** nei template `image-field-template` e `image-with-markers-field-template`, la valutazione di `field.DynAttachment.ButtonKey` in `*ngIf` lanciava eccezione quando `DynAttachment` era `null` (campo senza immagine caricata), innescando un loop di Angular CD. Sostituito con `field.DynAttachment?.ButtonKey`.
40
+ - **Fix posizione dialog DataGetter:** la modale del Query Editor aperta con "Modifica" nel configuratore compariva a metà pagina. Aggiunti `position: { top: '20px' }` e `maxHeight: '90vh'` per allinearla al comportamento di tutte le altre dialog.
41
+ - **Bugfix infinite loop `ListValueField`:** `FormControl.setValue()` was notifying the `_onChange` callback of the `NgModel` registered via `[formControlName]` on `mat-checkbox`, causing `ngModelChange` → `updateSelected()` → `setFormControlValue()` in infinite recursion. Added `{ emitModelToViewChange: false }` to `setFormControlValue()` to break the cycle. Related fixes: `updateSelected()` now returns `null` (not `[]`) for single-choice fields with no selection, preventing Angular CD instability from `[] !== []`; `resetArrayData()` calls `updateSelected(false)` to avoid emitting `recordChange` during option rebuild; `updateField()` now distinguishes formula-for-value from formula-for-options in `DataGetterType=Formula` fields.
42
+ - **Bugfix infinite loop `onRecordChange`:** added `_recordChanging` re-entrancy guard with `try/finally` in `add-form-record.onRecordChange()` to prevent recursion from chained formula fields (e.g. numeric field list field driven by the first field's formula).
43
+ - **Bugfix preview loop`DynAttachment.ButtonKey` null:** in `image-field-template` and `image-with-markers-field-template`, evaluating `field.DynAttachment.ButtonKey` in `*ngIf` threw an exception when `DynAttachment` was `null` (field with no image loaded), triggering an Angular CD loop. Replaced with `field.DynAttachment?.ButtonKey`.
44
+ - **Fix DataGetter dialog position:** the Query Editor modal opened via "Modifica" in the configurator was appearing at mid-page. Added `position: { top: '20px' }` and `maxHeight: '90vh'` to align it with all other dialogs.
45
+
46
+ ### v2.10.85
47
+ - **Bugfix loop infinito (approccio corretto):** il loop di v2.10.84 era asincrono: `setValue` chiama `writeValue` sui ControlValueAccessor di Angular Material che emettono eventi nel tick successivo, quando la guardia di rientranza era già rilasciata. Soluzione definitiva: il validator `required` ora legge direttamente da `record[field.Name]` tramite closure (anziché da `control.value`); in `onRecordChange()` viene chiamato `updateValueAndValidity({ emitEvent: false })` che ri-esegue i validator senza invocare `writeValue` eliminando alla radice ogni possibilità di cascade.
48
+ - **Bugfix infinite loop (correct approach):** the v2.10.84 loop was asynchronous: `setValue` calls `writeValue` on Angular Material ControlValueAccessors which emit events on the next tick, after the re-entrancy guard was already released. Definitive fix: the `required` validator now reads directly from `record[field.Name]` via closure (instead of `control.value`); `onRecordChange()` calls `updateValueAndValidity({ emitEvent: false })` which re-runs validators without invoking `writeValue` eliminating any cascade at the root.
49
+
50
+ ### v2.10.84
51
+ - **Bugfix loop infinito `onRecordChange`:** la sincronizzazione dei `FormControl` introdotta in v2.10.83 causava un loop: `setValue` invoca `writeValue` sui ControlValueAccessor (es. `mat-datepicker`), che emettono `(dateChange)/(ngModelChange)` → `recordChange` → `onRecordChange` di nuovo, all'infinito. Aggiunta una guardia di rientranza (`_isInRecordChange`) con `try/finally` che interrompe il ciclo. La sincronizzazione dei FormControl resta attiva e la validazione required funziona correttamente.
52
+ - **Bugfix infinite loop `onRecordChange`:** the FormControl sync introduced in v2.10.83 caused an infinite loop: `setValue` calls `writeValue` on ControlValueAccessors (e.g. `mat-datepicker`), which emit `(dateChange)/(ngModelChange)` → `recordChange` → `onRecordChange` again, endlessly. Added a re-entrancy guard (`_isInRecordChange`) with `try/finally` that breaks the cycle. FormControl sync remains active and required validation works correctly.
53
+
54
+ ### v2.10.83
55
+ - **Bugfix validazione form — campi obbligatori valorizzati via formula/ActionButton:** quando un campo con `required` veniva impostato tramite formula o ActionButton, il valore compariva visivamente ma il `FormControl` Angular rimaneva non aggiornato, lasciando il form invalido finché l'utente non interagiva manualmente col campo. Ora `onRecordChange()` risincronizza tutti i `FormControl` dal record dopo ogni aggiornamento formula, rendendo la validazione coerente con il valore visualizzato.
56
+ - **Bugfix form validation required fields set via formula/ActionButton:** when a required field was populated by a formula or ActionButton, the value appeared visually but the Angular `FormControl` was never updated, keeping the form invalid until the user manually interacted with the field. `onRecordChange()` now re-syncs all `FormControl` values from the record after every formula update, making validation consistent with the displayed value.
57
+
58
+ ### v2.10.81
59
+ - **Bugfix configurator — `DataGetter` null dopo decode Base64:** quando il campo `DataGetterValueBase64String` decodifica in un JSON con `DataGetter: null`, viene ora creato un oggetto `DataGetter` vuoto anziché proseguire con `null`, evitando errori a runtime nel configuratore.
60
+ - **Bugfix `add-form-record` `actionButtons` null:** se l'input `actionButtons` arriva `null` al componente, viene ora inizializzato a un array vuoto prima del filtraggio, prevenendo un'eccezione al caricamento del record.
61
+ - **Bugfix configurator — `DataGetter` null after Base64 decode:** when `DataGetterValueBase64String` decodes to a JSON with `DataGetter: null`, a new empty `DataGetter` object is now created instead of proceeding with `null`, preventing runtime errors in the configurator.
62
+ - **Bugfix `add-form-record` — `actionButtons` null:** if the `actionButtons` input arrives as `null`, it is now initialized to an empty array before filtering, preventing an exception on record load.
63
+
64
+ ### v2.10.79
65
+ - **DataGetter V2 — selezione automatica colonna singola:** quando il flusso V2 genera una sola `columnKey`, essa viene assegnata automaticamente a `DataGetterColumnForce` senza che l'utente debba selezionarla manualmente dalla dropdown.
66
+ - **DataGetter V2 single column auto-selection:** when the V2 flow produces exactly one `columnKey`, it is automatically assigned to `DataGetterColumnForce` without requiring manual selection from the dropdown.
67
+
68
+ ### v2.10.77
69
+ - **DataGetter V2 — `DataGetterColumnForce` come stringa:** `onAiDataGetterOut` ora salva `DataGetterColumnForce` come stringa chiave (non come oggetto), allineandosi al formato atteso da `eqp-select`. Il valore pre-selezionato nella dropdown compare automaticamente dopo il flusso AI.
70
+ - **DataGetter V2`DataGetterColumnForce` as string:** `onAiDataGetterOut` now stores `DataGetterColumnForce` as a key string (not as an object), matching the format expected by `eqp-select`. The pre-selected value in the dropdown appears automatically after the AI flow.
71
+
72
+ ### v2.10.76
73
+ - **DataGetter V2`createColumnKeys` retrocompatibile:** `add-form-field` ora rileva `DataGetterCodeVersion=2` e legge `selectedFields` da `queryCommandDatabaseConfiguration.selectedFields` invece che dal livello radice; fallback su `PropertyName` se `CurrentTranslate` è assente.
74
+ - **DataGetter V2 — `createColumnKeys` backward-compatible:** `add-form-field` now detects `DataGetterCodeVersion=2` and reads `selectedFields` from `queryCommandDatabaseConfiguration.selectedFields` instead of the root level; falls back to `PropertyName` when `CurrentTranslate` is missing.
75
+
76
+ ### v2.10.74 / v2.10.75
77
+ - **DataGetter AI — nuova modalità "Da database" (DataGetterType=3):** aggiunto campo `DataGetterSpeechText` nel modello `DataGetter`. Il configurator AI può creare campi con recupero dati da database impostando un prompt testuale: al caricamento del form, il componente QueryEditor esterno viene invocato silenziosamente, elabora il prompt via AI e popola automaticamente `DataGetterValue`, `DataGetterCardinality=1`, `DataGetterHasResetButton=true` e `DataGetterColumnForce` (se il risultato ha un solo campo selezionato).
78
+ - **DataGetterCodeVersion V2 — retrocompatibilità in lettura:** il `DbgetterComponent` rileva automaticamente i campi con `DataGetterCodeVersion=2` (formato Omnisearch AI) ed esegue un unwrap trasparente della struttura `queryCommandDatabaseConfiguration` al formato V1, senza impatto sui campi legacy. Il `DataGetterCodeVersion=2` viene propagato al componente QueryEditor esterno tramite `config.DataGetterCodeVersion` per consentire al client ospitante di attivare il flusso V2 in lettura.
79
+ - **AI DataGetter new "Da database" mode (DataGetterType=3):** added `DataGetterSpeechText` field to the `DataGetter` model. The AI configurator can create database-getter fields with a natural-language prompt: on form load, the external QueryEditor component is invoked silently, processes the prompt via AI and automatically populates `DataGetterValue`, `DataGetterCardinality=1`, `DataGetterHasResetButton=true` and `DataGetterColumnForce` (if a single output field is returned).
80
+ - **DataGetterCodeVersion V2 backward-compatible read flow:** `DbgetterComponent` now auto-detects fields with `DataGetterCodeVersion=2` (Omnisearch AI format) and transparently unwraps the `queryCommandDatabaseConfiguration` structure to the V1 format, with zero impact on legacy fields. `DataGetterCodeVersion=2` is forwarded to the external QueryEditor component via `config.DataGetterCodeVersion` to enable the V2 read flow on the host application side.
81
+
82
+ ### v2.10.70
83
+ - **Theming configurator nuovi input:** aggiunto `[configuratorThemeCss]` che accetta direttamente il testo di un file CSS con le dichiarazioni delle variabili `--conf-*`. Permette di portare il tema dall'esterno come file statico senza hardcodare valori TypeScript. Se entrambi gli input sono presenti, `configuratorTheme` sovrascrive `configuratorThemeCss` per le chiavi in conflitto.
84
+ - **Theming configurator — nuove variabili CSS:** `--conf-stepper-header-bg` (sfondo zona step superiore), `--conf-stepper-content-bg` (sfondo zona inferiore), `--conf-step-icon-edit-bg` (sfondo pallini step completati), `--conf-hint-btn-bg` / `--conf-hint-btn-hover-bg` (bottone suggerimento rapido), `--conf-btn-color` (colore testo bottoni con sfondo gradiente).
85
+ - **Theming configurator — forzatura `!important`:** tutti i valori iniettati tramite tema esterno sono ora applicati con `!important`, rendendo il sistema di theming l'unico canale valido per sovrascrivere i colori.
86
+ - **Theming configurator `--conf-btn-color`:** il colore del testo dei bottoni attivi (sfondo gradiente) è ora templatizzabile e forzato con `!important` per resistere a override CSS provenienti dall'applicazione ospitante.
87
+ - **New theming input:** added `[configuratorThemeCss]` accepting a CSS text string with `--conf-*` variable declarations. Enables external theme files without TypeScript hardcoding. When both inputs are present, `configuratorTheme` overrides `configuratorThemeCss` for conflicting keys.
88
+ - **New CSS variables:** `--conf-stepper-header-bg`, `--conf-stepper-content-bg`, `--conf-step-icon-edit-bg`, `--conf-hint-btn-bg`, `--conf-hint-btn-hover-bg`, `--conf-btn-color`.
89
+ - **`!important` enforcement:** all externally-injected theme values are now set with `!important`, making the theming system the sole valid override channel.
90
+
91
+ ### v2.10.65
92
+ - **TextField icona opzionale:** aggiunta la possibilità di associare un'icona Material Icons al campo di testo. Le nuove proprietà `IconName` (stringa) e `IconPosition` (enum: `1`=Sinistra/prefix, `2`=Destra/suffix) sono opzionali e retrocompatibili (null sui form esistenti). Configurabili nel builder tramite il toggle "Icona" nella sezione Specifiche del campo.
93
+ - **TextField optional icon:** added support for a Material Icons icon on text fields. New properties `IconName` (string) and `IconPosition` (enum: `1`=Left/prefix, `2`=Right/suffix) are optional and backward-compatible (null on existing forms). Configurable in the builder via the "Icona" toggle in the field's Specifiche section.
94
+
95
+ ### v2.10.64
96
+ - **Bugfix configurator:** se il campo `Code` del form risulta `null` al momento del salvataggio (scenario: form creato con AI senza salvataggio intermedio), ora viene generato automaticamente da `Name` prima dell'invio al server.
97
+
98
+ ### v2.10.63
99
+ - README riscritto in formato bilingue (italiano completo + inglese completo).
100
+ - Aggiunto `USERGUIDE.md` con guida pratica per scenari d'uso comuni e sezione prompt AI di esempio.
101
+ - `USERGUIDE.md` incluso nel pacchetto npm tramite `ng-package.json` assets.
102
+
103
+ ### v2.10.62
104
+ - Migrazione da `tmw-picker` 1.0.x a 1.1.0: NgModule → standalone components, moment.js → Luxon, aggiornamento di tutti i token formato data (`DD/MM/YYYY` → `dd/MM/yyyy`).
105
+ - Rimossi input inutilizzati: `answerToDuplicateId` da `eqp-dynamic-module`, `ProjectName` da `eqp-dynamic-module-configurator`.
106
+ - Documentazione NPM riscritta completamente (bilingue IT/EN).
107
+
108
+ ### v2.10.60
109
+ - Aggiornamenti interni e correzioni bug.
110
+
111
+ ---
112
+
113
+ ## Versione italiana
114
+
115
+ - [Panoramica](#panoramica)
116
+ - [Prerequisiti](#prerequisiti)
117
+ - [Installazione](#installazione)
118
+ - [Configurazione del modulo](#configurazione-del-modulo)
119
+ - [Componenti](#componenti)
120
+ - [eqp-dynamic-module — Visualizzatore form](#eqp-dynamic-module--visualizzatore-form)
121
+ - [eqp-dynamic-module-configurator Builder form](#eqp-dynamic-module-configurator--builder-form)
122
+ - [Modelli di configurazione](#modelli-di-configurazione)
123
+ - [Modalità di visualizzazione](#modalità-di-visualizzazione)
124
+ - [Configurazione endpoint](#configurazione-endpoint)
125
+ - [Modelli dati](#modelli-dati)
126
+ - [Tipi di campo](#tipi-di-campo)
127
+
128
+ ---
129
+
130
+ ### Panoramica
131
+
132
+ `@eqproject/eqp-dynamic-module` espone **due componenti pubblici**:
133
+
134
+ | Componente | Scopo |
135
+ |-----------|-------|
136
+ | `<eqp-dynamic-module>` | Visualizzatore, compilatore, lista, filtro e grafici a runtime |
137
+ | `<eqp-dynamic-module-configurator>` | Builder no-code per creare e modificare le definizioni form |
138
+
139
+ Le form sono strutture JSON salvate lato server e recuperate a runtime. La libreria gestisce rendering, validazione, recupero dati, operazioni CRUD e funzionalità avanzate come formule, trigger, action button e speech-to-text.
140
+
141
+ ---
142
+
143
+ ### Prerequisiti
144
+
145
+ ```bash
146
+ npm install @angular/cdk@^15.1.2 @angular/material@^15.1.2 @angular/material-luxon-adapter@^15.2.9 --legacy-peer-deps
147
+ npm install sweetalert2@^11.4.24 --legacy-peer-deps
148
+ ```
149
+
150
+ > Tutti i comandi `npm install` per questa libreria richiedono il flag `--legacy-peer-deps`.
151
+
152
+ ---
153
+
154
+ ### Installazione
155
+
156
+ ```bash
157
+ npm install @eqproject/eqp-dynamic-module --legacy-peer-deps
158
+ ```
159
+
160
+ ---
161
+
162
+ ### Configurazione del modulo
163
+
164
+ ```typescript
165
+ import { EqpDynamicModuleModule } from '@eqproject/eqp-dynamic-module';
166
+
167
+ @NgModule({
168
+ imports: [
169
+ EqpDynamicModuleModule
170
+ ]
171
+ })
172
+ export class AppModule {}
173
+ ```
174
+
175
+ In `angular.json`, aggiungi il tema Material agli stili:
176
+
177
+ ```json
178
+ "styles": [
179
+ "node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
180
+ "src/styles.css"
181
+ ]
182
+ ```
183
+
184
+ ---
185
+
186
+ ### Componenti
187
+
188
+ #### `eqp-dynamic-module` — Visualizzatore form
189
+
190
+ Visualizza una form dinamica in una delle [modalità disponibili](#modalità-di-visualizzazione).
191
+
192
+ **Utilizzo base**
193
+
194
+ ```typescript
195
+ import { DynamicModuleGeneralConfig, DynamicModuleViewModeEnum } from '@eqproject/eqp-dynamic-module';
196
+
197
+ generalConfig = new DynamicModuleGeneralConfig(
198
+ 'https://tua-api.esempio.it/api',
199
+ this.userToken,
200
+ this.context,
201
+ null
202
+ );
203
+ ```
204
+
205
+ ```html
206
+ <eqp-dynamic-module
207
+ [configurations]="generalConfig"
208
+ [formID]="'id-del-form'"
209
+ [starterViewMode]="DynamicModuleViewModeEnum.LIST"
210
+ [userID]="currentUser.id"
211
+ (saveRecord)="onSalvataggio($event)"
212
+ (afterSaveRecord)="dopoSalvataggio($event)">
213
+ </eqp-dynamic-module>
214
+ ```
215
+
216
+ **Input**
217
+
218
+ | Input | Tipo | Default | Descrizione |
219
+ |-------|------|---------|-------------|
220
+ | `configurations` | `DynamicModuleGeneralConfig` | | **Obbligatorio.** Configurazione connessione server. |
221
+ | `formID` | `string` | | **Obbligatorio.** ID del form da visualizzare. |
222
+ | `starterViewMode` | `DynamicModuleViewModeEnum` | `LIST` | Modalità iniziale. |
223
+ | `userID` | `string` | `"0"` | ID utente per il salvataggio record. |
224
+ | `orgaID` | `string` | `"0"` | ID organizzazione. |
225
+ | `showTitle` | `boolean` | `true` | Mostra/nasconde il nome del form. |
226
+ | `showBackButton` | `boolean` | `true` | Mostra/nasconde il pulsante indietro. |
227
+ | `showSaveButton` | `boolean` | `true` | Mostra/nasconde il pulsante salva. |
228
+ | `values` | `Record[]` | `null` | Record pre-caricati per la modalità LIST. |
229
+ | `FormJSON` | `string` | `""` | JSON del form per la modalità REPAIR. |
230
+ | `formulaObject` | `any` | `{}` | Oggetto contesto per le formule (es. `{ role, user }`). |
231
+ | `selectedRecord` | `Record \| string` | `null` | Record pre-selezionato (oggetto o ID). |
232
+ | `externalButtons` | `RecordButton[]` | `[]` | Pulsanti extra nel menu azioni record. |
233
+ | `actionButtons` | `ActionButton[]` | `[]` | Pulsanti azione per i campi di tipo `Bottone`. |
234
+ | `defaultListActions` | `DynamicModuleListFormRecordActionsDefault` | tutti `true` | Azioni default lista: add, view, edit, duplicate, delete, graphs. |
235
+ | `listViewRecordTitle` | `string[]` | `[]` | Chiavi dei campi che compongono il titolo accordion. |
236
+ | `defaultListViewFunction` | `Function` | `null` | Funzione custom al caricamento della lista. |
237
+ | `onSaveBackToList` | `boolean` | `false` | Torna alla LIST dopo il salvataggio. |
238
+ | `onBackTo` | `DynamicModuleViewModeEnum` | `null` | Modalità di destinazione del pulsante indietro. |
239
+ | `numberOfColumns` | `number` | `3` | Numero di colonne del layout. |
240
+ | `showHiddenFields` | `boolean` | `true` | Mostra/nasconde i campi marcati come nascosti. |
241
+ | `filterResultViewMode` | `DynamicModuleFilterResultViewModeEnum` | `INTERNAL_EQPTABLE` | Modalità visualizzazione risultati filtro. |
242
+ | `additionalParams` | `any` | `null` | Parametri extra per le chiamate filtro server. |
243
+ | `additionalInfo` | `any` | `null` | Dati extra per operazioni client-side. |
244
+ | `prefilterParams` | `any` | `null` | Parametri pre-filtro. |
245
+ | `updateInfo` | `any` | `null` | Dati per aggiornare i valori delle risposte. |
246
+ | `contestualizationParams` | `any` | `null` | Parametri di contestualizzazione della lista risultati. |
247
+ | `showNewSearchButton` | `boolean` | `true` | Mostra/nasconde il pulsante "nuova ricerca". |
248
+ | `highlightFilter` | `any` | | Configurazione evidenziazione righe/campi. |
249
+ | `isDraggableListView` | `boolean` | `true` | Abilita drag-and-drop nella lista. |
250
+ | `Statistic` | `FilterStatistic` | `null` | Configurazione statistiche e filtri. |
251
+ | `QueryEditorComponent` | `any` | | Componente query editor custom per i lookup. |
252
+ | `debugMode` | `boolean` | `false` | Abilita log dettagliati in console. |
253
+
254
+ **Output**
255
+
256
+ | Output | Payload | Descrizione |
257
+ |--------|---------|-------------|
258
+ | `(saveRecord)` | `Record` | Emesso al salvataggio **senza** endpoint configurato. |
259
+ | `(afterSaveRecord)` | `Record` | Emesso dopo la chiamata server di salvataggio. |
260
+ | `(deleteRecord)` | `Record` | Emesso all'eliminazione **senza** endpoint configurato. |
261
+ | `(afterDeleteRecord)` | `Record` | Emesso dopo la chiamata server di eliminazione. |
262
+ | `(SaveJSON)` | `string` | Emesso all'esportazione del JSON del form. |
263
+ | `(afterFilter)` | `DynRecord[]` | Emesso dopo l'applicazione di un filtro. |
264
+ | `(dragStarted)` | `Record` | Emesso all'inizio di un drag. |
265
+ | `(dragReleased)` | `void` | Emesso al rilascio del drag. |
266
+ | `(clickDragIndicator)` | `Record` | Emesso al click sull'icona drag. |
267
+ | `(out)` | `eventOut` | Output generico per comunicazione esterna. |
268
+ | `(fireTrigger)` | `FireTrigger` | Emesso quando scatta un trigger. |
269
+ | `(afterOutputExternalFilters)` | `FilterStatistic` | Emesso dopo filtri esterni applicati. |
270
+
271
+ ---
272
+
273
+ #### `eqp-dynamic-module-configurator` Builder form
274
+
275
+ Designer no-code per creare e modificare definizioni form.
276
+
277
+ **Modalità d'uso**
278
+
279
+ ```typescript
280
+ // Nuovo form
281
+ const specific = new DynamicModuleConfiguratorSpecificConfig();
282
+ specific.UserID = this.currentUser.id;
283
+ specific.orgaID = this.currentOrga.id;
284
+ const general = new DynamicModuleGeneralConfig(this.baseServerUrl, this.userToken, this.context, null);
285
+ this.config = new DynamicModuleConfiguratorConfig(general, specific);
286
+ ```
287
+
288
+ ```html
289
+ <!-- Nuovo form -->
290
+ <eqp-dynamic-module-configurator
291
+ *ngIf="config"
292
+ [configurations]="config"
293
+ (saveFormEvent)="onSalvaForm($event)">
294
+ </eqp-dynamic-module-configurator>
295
+
296
+ <!-- Modifica form esistente -->
297
+ <eqp-dynamic-module-configurator
298
+ *ngIf="config"
299
+ [configurations]="config"
300
+ [formID]="formID"
301
+ (saveFormEvent)="onSalvaForm($event)">
302
+ </eqp-dynamic-module-configurator>
303
+
304
+ <!-- Esportazione -->
305
+ <eqp-dynamic-module-configurator
306
+ [configurations]="config"
307
+ [formID]="formID"
308
+ [viewMode]="'Export'"
309
+ (saveFormEvent)="onSalvaForm($event)">
310
+ </eqp-dynamic-module-configurator>
311
+
312
+ <!-- Importazione da JSON -->
313
+ <eqp-dynamic-module-configurator
314
+ [configurations]="config"
315
+ [formID]="null"
316
+ [viewMode]="'Export'"
317
+ (saveFormEvent)="onSalvaForm($event)">
318
+ </eqp-dynamic-module-configurator>
319
+ ```
320
+
321
+ **Input**
322
+
323
+ | Input | Tipo | Default | Descrizione |
324
+ |-------|------|---------|-------------|
325
+ | `configurations` | `DynamicModuleConfiguratorConfig` | — | **Obbligatorio.** Contenitore configurazione. |
326
+ | `formID` | `string` | `null` | ID del form da modificare. `null` crea un nuovo form. |
327
+ | `viewMode` | `string` | `"addOrEdit"` | `"addOrEdit"` per creare/modificare, `"Export"` per esportare/importare. |
328
+ | `fieldsExtraConfig` | `FieldExtraConfig[]` | | Configurazione extra per campi specifici. |
329
+ | `triggers` | `any` | — | Definizioni trigger disponibili nell'editor. |
330
+ | `actionButtons` | `any` | | Definizioni action button disponibili. |
331
+ | `contestualization` | `Contestualization[]` | | Opzioni di contestualizzazione per lookup e filtri. |
332
+ | `formulaObject` | `any` | | Contesto per l'anteprima delle formule. |
333
+ | `QueryEditorComponent` | `DynamicLoaderDirectiveData` | | Componente query editor custom. |
334
+ | `debugMode` | `boolean` | `false` | Abilita log dettagliati. |
335
+ | `configuratorTheme` | `Record<string, string> \| null` | `null` | Override delle variabili CSS del tema tramite oggetto TypeScript. |
336
+ | `configuratorThemeCss` | `string \| null` | `null` | Override delle variabili CSS del tema tramite stringa CSS (es. contenuto di un file `.css`). |
337
+
338
+ **Output**
339
+
340
+ | Output | Payload | Descrizione |
341
+ |--------|---------|-------------|
342
+ | `(saveFormEvent)` | `Form` | Emesso al salvataggio **senza** endpoint configurato. |
343
+ | `(afterSaveFormEvent)` | `Form` | Emesso dopo la chiamata server di salvataggio. |
344
+ | `(out)` | `eventOut` | Output generico per comunicazione esterna. |
345
+ | `(fireTrigger)` | `FireTrigger` | Emesso quando scatta un trigger. |
346
+
347
+ **Theming**
348
+
349
+ Il configurator espone un sistema di temi basato su CSS custom properties. Tutti i valori iniettati tramite tema sono applicati con `!important` e non possono essere sovrascritti dall'esterno se non attraverso questi input.
350
+
351
+ ```html
352
+ <!-- Opzione A: oggetto TypeScript -->
353
+ <eqp-dynamic-module-configurator
354
+ [configurations]="config"
355
+ [configuratorTheme]="{ '--conf-gradient': 'linear-gradient(to right, #1565c0, #0288d1)', '--conf-bg-page': '#f0f6fb' }">
356
+ </eqp-dynamic-module-configurator>
357
+
358
+ <!-- Opzione B: file CSS caricato come stringa -->
359
+ <eqp-dynamic-module-configurator
360
+ [configurations]="config"
361
+ [configuratorThemeCss]="themeCssString">
362
+ </eqp-dynamic-module-configurator>
363
+ ```
364
+
365
+ Formato del file CSS per `configuratorThemeCss` (nessun selettore richiesto):
366
+
367
+ ```css
368
+ --conf-gradient: linear-gradient(to right, #1565c0, #0288d1);
369
+ --conf-bg-page: #f0f6fb;
370
+ --conf-btn-color: #ffffff;
371
+ ```
372
+
373
+ Variabili disponibili:
374
+
375
+ | Variabile | Default | Descrizione |
376
+ |-----------|---------|-------------|
377
+ | `--conf-gradient` | gradiente viola-blu | Sfondo bottoni e header |
378
+ | `--conf-bg-page` | `#f5f5f5` | Sfondo generale pagina/stepper |
379
+ | `--conf-radius` | `10px` | Border radius bottoni |
380
+ | `--conf-modal-radius` | `12px` | Border radius modali |
381
+ | `--conf-accent` | `#693DDA` | Colore accento (bordi, focus) |
382
+ | `--conf-primary` | `#1E31EB` | Colore primario |
383
+ | `--conf-step-selected` | `#643cda` | Freccia step selezionato |
384
+ | `--conf-step-edit` | `#3034e7` | Freccia step completato |
385
+ | `--conf-stepper-header-bg` | ereditato da `--conf-bg-page` | Sfondo zona superiore (header stepper) |
386
+ | `--conf-stepper-content-bg` | ereditato da `--conf-bg-page` | Sfondo zona inferiore (form e bottoni) |
387
+ | `--conf-step-icon-edit-bg` | ereditato da `--conf-step-edit` | Sfondo pallini step completati |
388
+ | `--conf-btn-color` | `#ffffff` | Colore testo bottoni attivi (sfondo gradiente) |
389
+ | `--conf-hint-btn-bg` | `#2563eb` | Sfondo bottone suggerimento rapido (lampadina) |
390
+ | `--conf-hint-btn-hover-bg` | `#1d4ed8` | Sfondo lampadina al hover |
391
+ | `--conf-table-header-bg` | variabile SCSS | Sfondo header tabella campi |
392
+ | `--conf-search-bg` | variabile SCSS | Sfondo campo di ricerca |
393
+ | `--conf-table-bg` | `#ffffff` | Sfondo righe tabella |
394
+ | `--conf-card-bg` | `#ffffff` | Sfondo card |
395
+ | `--conf-font-family` | `inherit` | Font dell'intero configurator |
396
+
397
+ ---
398
+
399
+ ### Modelli di configurazione
400
+
401
+ #### `DynamicModuleGeneralConfig`
402
+
403
+ ```typescript
404
+ const general = new DynamicModuleGeneralConfig(
405
+ 'https://api.esempio.it/api', // baseServerUrl
406
+ userToken, // token autenticazione
407
+ context, // oggetto Context
408
+ null // EndPointConfiguration (null = usa default)
409
+ );
410
+ ```
411
+
412
+ | Proprietà | Tipo | Descrizione |
413
+ |-----------|------|-------------|
414
+ | `baseServerUrl` | `string` | URL base API. Usato per costruire automaticamente gli endpoint se `endPointConfiguration` è `null`. |
415
+ | `userToken` | `string` | Token di autenticazione inviato con ogni chiamata. |
416
+ | `endPointConfiguration` | `EndPointConfiguration \| null` | Override completo degli endpoint. `null` usa le rotte standard. |
417
+ | `context` | `Context` | Contesto applicativo. |
418
+
419
+ #### `DynamicModuleListFormRecordActionsDefault`
420
+
421
+ ```typescript
422
+ const actions = new DynamicModuleListFormRecordActionsDefault();
423
+ actions.add = true; // Pulsante "Aggiungi" nell'header lista
424
+ actions.view = true; // Visualizza record (solo lettura)
425
+ actions.edit = true; // Modifica record
426
+ actions.duplicate = false; // Duplica record
427
+ actions.delete = true; // Elimina record
428
+ actions.graphs = false; // Grafici record
429
+ ```
430
+
431
+ ---
432
+
433
+ ### Modalità di visualizzazione
434
+
435
+ ```typescript
436
+ import { DynamicModuleViewModeEnum } from '@eqproject/eqp-dynamic-module';
437
+
438
+ enum DynamicModuleViewModeEnum {
439
+ NONE = 0, // Nessuna visualizzazione
440
+ VIEW = 1, // Sola lettura
441
+ COMPILE = 2, // Compilazione / modifica
442
+ LIST = 3, // Lista record
443
+ REPAIR = 4, // Revisione form
444
+ LISTWIEW = 5, // Lista compatta alternativa
445
+ FILTER = 6, // Filtro / ricerca
446
+ GRAPHS = 7, // Statistiche e grafici
447
+ HLIST = 8, // Lista orizzontale
448
+ EXTERNAL_FILTER = 9 // Filtro guidato dal componente padre
449
+ }
450
+ ```
451
+
452
+ ---
453
+
454
+ ### Configurazione endpoint
455
+
456
+ Per default la libreria costruisce tutti gli URL dagli endpoint a partire da `baseServerUrl`. Passa un `EndPointConfiguration` custom per sovrascrivere singole rotte.
457
+
458
+ ```typescript
459
+ import { EndPointConfiguration, EndPointData, RequestMethodEnum, ParamTypeEnum } from '@eqproject/eqp-dynamic-module';
460
+
461
+ const endPoints = new EndPointConfiguration();
462
+ endPoints.Records.SaveEndPoint = new EndPointData();
463
+ endPoints.Records.SaveEndPoint.Url = 'https://custom-api.esempio.it/records/save';
464
+ endPoints.Records.SaveEndPoint.RequestMethod = RequestMethodEnum.POST;
465
+ endPoints.Records.SaveEndPoint.Params = [{
466
+ ParamName: 'orgId',
467
+ ParamValue: this.orgaId,
468
+ ParamType: ParamTypeEnum['Query param']
469
+ }];
470
+ ```
471
+
472
+ **Endpoint Records disponibili:** `GetWithContextualizationByFormCodeEndPoint`, `GetByFormIDEndPoint`, `GetByFormCodeEndPoint`, `GetAllByEntAndUserIDEndPoint`, `GetByIDEndPoint`, `SaveEndPoint`, `DuplicateEndPoint`, `DeleteEndPoint`, `RepairEndPoint`, `ApplyFilter`, `GetAllAttachmentsEndPoint`.
473
+
474
+ **Endpoint Forms disponibili:** `GetByIDEndPoint`, `GetAllFormEndPoint`, `GetByIDAndVersionEndPoint`, `SaveEndPoint`, `SaveAttachmentEndPoint`, `ExportByIDEndPoint`, `GetAttachmentWithBases64`, `SpeechToFormEditEndPoint`.
475
+
476
+ ---
477
+
478
+ ### Modelli dati
479
+
480
+ #### `Record`
481
+
482
+ | Proprietà | Tipo | Descrizione |
483
+ |-----------|------|-------------|
484
+ | `ID` | `string` | Identificatore unico. |
485
+ | `EntID` | `string` | ID del form (entità) di appartenenza. |
486
+ | `Version` | `number` | Versione del form al momento della compilazione. |
487
+ | `userID` | `string` | ID utente che ha creato il record. |
488
+ | `AnswerDate` | `string` | Data di compilazione (ISO). |
489
+ | `HTMLreadableValues` | `string` | Valori in formato HTML leggibile. |
490
+ | `AdditionalParams` | `any` | Parametri aggiuntivi. |
491
+ | `AdditionalInfo` | `any` | Informazioni aggiuntive. |
492
+
493
+ ---
494
+
495
+ ### Tipi di campo
496
+
497
+ | Valore | Chiave | Descrizione |
498
+ |--------|--------|-------------|
499
+ | `1` | `Campo di testo` | Input testo singola riga. |
500
+ | `2` | `Area di testo` | Textarea multiriga. |
501
+ | `3` | `Booleano` | Checkbox / toggle. |
502
+ | `4` | `Data e/ora` | Selettore data e/o ora. |
503
+ | `5` | `Campo numerico` | Input numerico con maschera. |
504
+ | `6` | `Allegato` | Upload file. |
505
+ | `7` | `Immagine` | Upload immagine con crop. |
506
+ | `8` | `Elenco generico` | Dropdown / selezione multipla. |
507
+ | `9` | `Lookup` | Lookup server-side con query configurabile. |
508
+ | `10` | `Form di dettaglio` | Form di dettaglio annidato. |
509
+ | `11` | `Elenco immagini` | Selettore lista immagini. |
510
+ | `12` | `Etichetta` | Solo visualizzazione. |
511
+ | `13` | `Immagine con markers` | Immagine con annotazioni interattive. |
512
+ | `14` | `Bottone` | Campo pulsante azione. |
513
+
514
+ ---
515
+
516
+ ## English version
517
+
518
+ - [Overview](#overview)
519
+ - [Prerequisites](#prerequisites)
520
+ - [Installation](#installation)
521
+ - [Module Setup](#module-setup)
522
+ - [Components](#components)
523
+ - [eqp-dynamic-module Form Viewer/Filler](#eqp-dynamic-module--form-viewerfiller)
524
+ - [eqp-dynamic-module-configurator — Form Builder](#eqp-dynamic-module-configurator--form-builder)
525
+ - [Configuration Models](#configuration-models)
526
+ - [View Modes](#view-modes)
527
+ - [Endpoint Configuration](#endpoint-configuration)
528
+ - [Data Models](#data-models)
529
+ - [Field Types Reference](#field-types-reference)
530
+
531
+ ---
532
+
533
+ ### Overview
534
+
535
+ `@eqproject/eqp-dynamic-module` exposes **two public components**:
536
+
537
+ | Component | Purpose |
538
+ |-----------|---------|
539
+ | `<eqp-dynamic-module>` | Runtime form viewer, filler, list, filter and graphs |
540
+ | `<eqp-dynamic-module-configurator>` | No-code form builder (create, edit, import, export) |
541
+
542
+ Forms are defined as JSON structures stored server-side and fetched at runtime. The library handles rendering, validation, data retrieval, CRUD operations and advanced features like formulas, triggers, action buttons and speech-to-text.
543
+
544
+ ---
545
+
546
+ ### Prerequisites
547
+
548
+ ```bash
549
+ npm install @angular/cdk@^15.1.2 @angular/material@^15.1.2 @angular/material-luxon-adapter@^15.2.9 --legacy-peer-deps
550
+ npm install sweetalert2@^11.4.24 --legacy-peer-deps
551
+ ```
552
+
553
+ > All `npm install` commands for this library require `--legacy-peer-deps`.
554
+
555
+ ---
556
+
557
+ ### Installation
558
+
559
+ ```bash
560
+ npm install @eqproject/eqp-dynamic-module --legacy-peer-deps
561
+ ```
562
+
563
+ ---
564
+
565
+ ### Module Setup
566
+
567
+ ```typescript
568
+ import { EqpDynamicModuleModule } from '@eqproject/eqp-dynamic-module';
569
+
570
+ @NgModule({
571
+ imports: [EqpDynamicModuleModule]
572
+ })
573
+ export class AppModule {}
574
+ ```
575
+
576
+ Add Angular Material theme to `angular.json` styles:
577
+
578
+ ```json
579
+ "styles": [
580
+ "node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
581
+ "src/styles.css"
582
+ ]
583
+ ```
584
+
585
+ ---
586
+
587
+ ### Components
588
+
589
+ #### `eqp-dynamic-module` — Form Viewer/Filler
590
+
591
+ **Basic usage**
592
+
593
+ ```typescript
594
+ import { DynamicModuleGeneralConfig, DynamicModuleViewModeEnum } from '@eqproject/eqp-dynamic-module';
595
+
596
+ generalConfig = new DynamicModuleGeneralConfig(
597
+ 'https://your-api.example.com/api',
598
+ this.userToken,
599
+ this.context,
600
+ null
601
+ );
602
+ ```
603
+
604
+ ```html
605
+ <eqp-dynamic-module
606
+ [configurations]="generalConfig"
607
+ [formID]="'your-form-id'"
608
+ [starterViewMode]="DynamicModuleViewModeEnum.LIST"
609
+ [userID]="currentUser.id"
610
+ (saveRecord)="onSave($event)"
611
+ (afterSaveRecord)="onAfterSave($event)">
612
+ </eqp-dynamic-module>
613
+ ```
614
+
615
+ **Inputs**
616
+
617
+ | Input | Type | Default | Description |
618
+ |-------|------|---------|-------------|
619
+ | `configurations` | `DynamicModuleGeneralConfig` | | **Required.** Server connection configuration. |
620
+ | `formID` | `string` | | **Required.** ID of the form to display. |
621
+ | `starterViewMode` | `DynamicModuleViewModeEnum` | `LIST` | Initial view mode. |
622
+ | `userID` | `string` | `"0"` | User ID stamped on saved records. |
623
+ | `orgaID` | `string` | `"0"` | Organization ID. |
624
+ | `showTitle` | `boolean` | `true` | Show/hide the form name. |
625
+ | `showBackButton` | `boolean` | `true` | Show/hide the back button. |
626
+ | `showSaveButton` | `boolean` | `true` | Show/hide the save button. |
627
+ | `values` | `Record[]` | `null` | Pre-loaded records for LIST mode. |
628
+ | `FormJSON` | `string` | `""` | Form JSON string for REPAIR mode. |
629
+ | `formulaObject` | `any` | `{}` | Context object for formula evaluation. |
630
+ | `selectedRecord` | `Record \| string` | `null` | Pre-select a record by object or ID. |
631
+ | `externalButtons` | `RecordButton[]` | `[]` | Extra buttons in the record action menu. |
632
+ | `actionButtons` | `ActionButton[]` | `[]` | Action buttons for `Bottone` field type. |
633
+ | `defaultListActions` | `DynamicModuleListFormRecordActionsDefault` | all `true` | Toggle default list actions. |
634
+ | `listViewRecordTitle` | `string[]` | `[]` | Field keys composing the accordion title. |
635
+ | `defaultListViewFunction` | `Function` | `null` | Custom function called on list load. |
636
+ | `onSaveBackToList` | `boolean` | `false` | Return to LIST after save. |
637
+ | `onBackTo` | `DynamicModuleViewModeEnum` | `null` | View mode for the back button. |
638
+ | `numberOfColumns` | `number` | `3` | Number of layout columns. |
639
+ | `showHiddenFields` | `boolean` | `true` | Show/hide hidden fields. |
640
+ | `filterResultViewMode` | `DynamicModuleFilterResultViewModeEnum` | `INTERNAL_EQPTABLE` | Filter results display mode. |
641
+ | `additionalParams` | `any` | `null` | Extra params for server filter calls. |
642
+ | `additionalInfo` | `any` | `null` | Extra data for client-side operations. |
643
+ | `prefilterParams` | `any` | `null` | Pre-filter parameters. |
644
+ | `updateInfo` | `any` | `null` | Data to update response values after load. |
645
+ | `contestualizationParams` | `any` | `null` | Contextualisation parameters. |
646
+ | `showNewSearchButton` | `boolean` | `true` | Show/hide the new search button. |
647
+ | `highlightFilter` | `any` | | Row/field highlighting configuration. |
648
+ | `isDraggableListView` | `boolean` | `true` | Enable drag-and-drop in list view. |
649
+ | `Statistic` | `FilterStatistic` | `null` | Statistics and filter configuration. |
650
+ | `QueryEditorComponent` | `any` | | Custom query editor component for lookups. |
651
+ | `debugMode` | `boolean` | `false` | Enable verbose console logging. |
652
+
653
+ **Outputs**
654
+
655
+ | Output | Payload | Description |
656
+ |--------|---------|-------------|
657
+ | `(saveRecord)` | `Record` | Emitted on save when **no** save endpoint is configured. |
658
+ | `(afterSaveRecord)` | `Record` | Emitted after server save call completes. |
659
+ | `(deleteRecord)` | `Record` | Emitted on delete when **no** delete endpoint is configured. |
660
+ | `(afterDeleteRecord)` | `Record` | Emitted after server delete call completes. |
661
+ | `(SaveJSON)` | `string` | Emitted when form JSON is exported. |
662
+ | `(afterFilter)` | `DynRecord[]` | Emitted after filter operation with result set. |
663
+ | `(dragStarted)` | `Record` | Emitted when drag starts. |
664
+ | `(dragReleased)` | `void` | Emitted when drag ends. |
665
+ | `(clickDragIndicator)` | `Record` | Emitted when drag handle is clicked. |
666
+ | `(out)` | `eventOut` | General-purpose external output. |
667
+ | `(fireTrigger)` | `FireTrigger` | Emitted when a trigger fires. |
668
+ | `(afterOutputExternalFilters)` | `FilterStatistic` | Emitted after external filters applied. |
669
+
670
+ ---
671
+
672
+ #### `eqp-dynamic-module-configurator` — Form Builder
673
+
674
+ **Usage modes**
675
+
676
+ ```html
677
+ <!-- Create new form -->
678
+ <eqp-dynamic-module-configurator
679
+ *ngIf="config"
680
+ [configurations]="config"
681
+ (saveFormEvent)="onFormSaved($event)">
682
+ </eqp-dynamic-module-configurator>
683
+
684
+ <!-- Edit existing form -->
685
+ <eqp-dynamic-module-configurator
686
+ [configurations]="config"
687
+ [formID]="formID"
688
+ (saveFormEvent)="onFormSaved($event)">
689
+ </eqp-dynamic-module-configurator>
690
+
691
+ <!-- Export form -->
692
+ <eqp-dynamic-module-configurator
693
+ [configurations]="config"
694
+ [formID]="formID"
695
+ [viewMode]="'Export'"
696
+ (saveFormEvent)="onFormSaved($event)">
697
+ </eqp-dynamic-module-configurator>
698
+
699
+ <!-- Import from JSON -->
700
+ <eqp-dynamic-module-configurator
701
+ [configurations]="config"
702
+ [formID]="null"
703
+ [viewMode]="'Export'"
704
+ (saveFormEvent)="onFormSaved($event)">
705
+ </eqp-dynamic-module-configurator>
706
+ ```
707
+
708
+ **Inputs**
709
+
710
+ | Input | Type | Default | Description |
711
+ |-------|------|---------|-------------|
712
+ | `configurations` | `DynamicModuleConfiguratorConfig` | | **Required.** Configuration container. |
713
+ | `formID` | `string` | `null` | Form ID to edit. `null` creates a new form. |
714
+ | `viewMode` | `string` | `"addOrEdit"` | `"addOrEdit"` or `"Export"`. |
715
+ | `fieldsExtraConfig` | `FieldExtraConfig[]` | — | Extra configuration for specific fields. |
716
+ | `triggers` | `any` | | Trigger definitions for the editor. |
717
+ | `actionButtons` | `any` | — | Action button definitions. |
718
+ | `contestualization` | `Contestualization[]` | | Contextualisation options. |
719
+ | `formulaObject` | `any` | | Context for formula preview. |
720
+ | `QueryEditorComponent` | `DynamicLoaderDirectiveData` | | Custom query editor component. |
721
+ | `debugMode` | `boolean` | `false` | Enable verbose logging. |
722
+ | `configuratorTheme` | `Record<string, string> \| null` | `null` | CSS variable overrides via TypeScript object. |
723
+ | `configuratorThemeCss` | `string \| null` | `null` | CSS variable overrides via CSS text string (e.g. contents of a `.css` file). |
724
+
725
+ **Outputs**
726
+
727
+ | Output | Payload | Description |
728
+ |--------|---------|-------------|
729
+ | `(saveFormEvent)` | `Form` | Emitted on save when **no** save endpoint is configured. |
730
+ | `(afterSaveFormEvent)` | `Form` | Emitted after server save call completes. |
731
+ | `(out)` | `eventOut` | General-purpose external output. |
732
+ | `(fireTrigger)` | `FireTrigger` | Emitted when a trigger fires. |
733
+
734
+ **Theming**
735
+
736
+ The configurator exposes a theming system based on CSS custom properties. All values injected via the theme inputs are applied with `!important` and cannot be overridden externally except through these inputs.
737
+
738
+ ```html
739
+ <!-- Option A: TypeScript object -->
740
+ <eqp-dynamic-module-configurator
741
+ [configurations]="config"
742
+ [configuratorTheme]="{ '--conf-gradient': 'linear-gradient(to right, #1565c0, #0288d1)' }">
743
+ </eqp-dynamic-module-configurator>
744
+
745
+ <!-- Option B: CSS file loaded as string -->
746
+ <eqp-dynamic-module-configurator
747
+ [configurations]="config"
748
+ [configuratorThemeCss]="themeCssString">
749
+ </eqp-dynamic-module-configurator>
750
+ ```
751
+
752
+ CSS file format for `configuratorThemeCss` (no selector required):
753
+
754
+ ```css
755
+ --conf-gradient: linear-gradient(to right, #1565c0, #0288d1);
756
+ --conf-bg-page: #f0f6fb;
757
+ --conf-btn-color: #ffffff;
758
+ ```
759
+
760
+ Available variables:
761
+
762
+ | Variable | Default | Description |
763
+ |----------|---------|-------------|
764
+ | `--conf-gradient` | purple-blue gradient | Button and header background |
765
+ | `--conf-bg-page` | `#f5f5f5` | General page/stepper background |
766
+ | `--conf-radius` | `10px` | Button border radius |
767
+ | `--conf-modal-radius` | `12px` | Modal border radius |
768
+ | `--conf-accent` | `#693DDA` | Accent colour (borders, focus) |
769
+ | `--conf-primary` | `#1E31EB` | Primary colour |
770
+ | `--conf-step-selected` | `#643cda` | Selected step arrow |
771
+ | `--conf-step-edit` | `#3034e7` | Completed step arrow |
772
+ | `--conf-stepper-header-bg` | inherited from `--conf-bg-page` | Upper zone background (stepper header) |
773
+ | `--conf-stepper-content-bg` | inherited from `--conf-bg-page` | Lower zone background (form and buttons) |
774
+ | `--conf-step-icon-edit-bg` | inherited from `--conf-step-edit` | Completed step icon background |
775
+ | `--conf-btn-color` | `#ffffff` | Active button text colour (gradient background) |
776
+ | `--conf-hint-btn-bg` | `#2563eb` | Quick-suggestion button (lightbulb) background |
777
+ | `--conf-hint-btn-hover-bg` | `#1d4ed8` | Lightbulb button hover background |
778
+ | `--conf-table-header-bg` | SCSS variable | Field table header background |
779
+ | `--conf-search-bg` | SCSS variable | Search field background |
780
+ | `--conf-table-bg` | `#ffffff` | Table row background |
781
+ | `--conf-card-bg` | `#ffffff` | Card background |
782
+ | `--conf-font-family` | `inherit` | Configurator-wide font family |
783
+
784
+ ---
785
+
786
+ ### Configuration Models
787
+
788
+ #### `DynamicModuleGeneralConfig`
789
+
790
+ ```typescript
791
+ const general = new DynamicModuleGeneralConfig(
792
+ baseServerUrl, // string — e.g. "https://api.example.com/api"
793
+ userToken, // string — auth token
794
+ context, // Context
795
+ endPointConfiguration // EndPointConfiguration | null
796
+ );
797
+ ```
798
+
799
+ #### `DynamicModuleListFormRecordActionsDefault`
800
+
801
+ ```typescript
802
+ const actions = new DynamicModuleListFormRecordActionsDefault();
803
+ actions.add = true;
804
+ actions.view = true;
805
+ actions.edit = true;
806
+ actions.duplicate = false;
807
+ actions.delete = true;
808
+ actions.graphs = false;
809
+ ```
810
+
811
+ ---
812
+
813
+ ### View Modes
814
+
815
+ ```typescript
816
+ enum DynamicModuleViewModeEnum {
817
+ NONE = 0,
818
+ VIEW = 1,
819
+ COMPILE = 2,
820
+ LIST = 3,
821
+ REPAIR = 4,
822
+ LISTWIEW = 5,
823
+ FILTER = 6,
824
+ GRAPHS = 7,
825
+ HLIST = 8,
826
+ EXTERNAL_FILTER = 9
827
+ }
828
+ ```
829
+
830
+ ---
831
+
832
+ ### Endpoint Configuration
833
+
834
+ ```typescript
835
+ const endPoints = new EndPointConfiguration();
836
+ endPoints.Records.SaveEndPoint = new EndPointData();
837
+ endPoints.Records.SaveEndPoint.Url = 'https://custom-api.example.com/records/save';
838
+ endPoints.Records.SaveEndPoint.RequestMethod = RequestMethodEnum.POST;
839
+ endPoints.Records.SaveEndPoint.Params = [{
840
+ ParamName: 'orgId',
841
+ ParamValue: this.orgaId,
842
+ ParamType: ParamTypeEnum['Query param']
843
+ }];
844
+ const general = new DynamicModuleGeneralConfig(baseUrl, token, context, endPoints);
845
+ ```
846
+
847
+ **Available Records endpoints:** `GetWithContextualizationByFormCodeEndPoint`, `GetByFormIDEndPoint`, `GetByFormCodeEndPoint`, `GetAllByEntAndUserIDEndPoint`, `GetByIDEndPoint`, `SaveEndPoint`, `DuplicateEndPoint`, `DeleteEndPoint`, `RepairEndPoint`, `ApplyFilter`, `GetAllAttachmentsEndPoint`.
848
+
849
+ **Available Forms endpoints:** `GetByIDEndPoint`, `GetAllFormEndPoint`, `GetByIDAndVersionEndPoint`, `SaveEndPoint`, `SaveAttachmentEndPoint`, `ExportByIDEndPoint`, `GetAttachmentWithBases64`, `SpeechToFormEditEndPoint`.
850
+
851
+ ---
852
+
853
+ ### Data Models
854
+
855
+ #### `Record`
856
+
857
+ | Property | Type | Description |
858
+ |----------|------|-------------|
859
+ | `ID` | `string` | Unique record identifier. |
860
+ | `EntID` | `string` | ID of the form this record belongs to. |
861
+ | `Version` | `number` | Form version at compilation time. |
862
+ | `userID` | `string` | ID of the user who created the record. |
863
+ | `AnswerDate` | `string` | ISO date string of compilation. |
864
+ | `HTMLreadableValues` | `string` | Pre-rendered HTML of field values. |
865
+ | `AdditionalParams` | `any` | Extra parameters. |
866
+ | `AdditionalInfo` | `any` | Extra information. |
867
+
868
+ ---
869
+
870
+ ### Field Types Reference
871
+
872
+ | Value | Key | Description |
873
+ |-------|-----|-------------|
874
+ | `1` | `Campo di testo` | Single-line text input. |
875
+ | `2` | `Area di testo` | Multi-line textarea. |
876
+ | `3` | `Booleano` | Checkbox / boolean toggle. |
877
+ | `4` | `Data e/ora` | Date and/or time picker. |
878
+ | `5` | `Campo numerico` | Numeric input with mask. |
879
+ | `6` | `Allegato` | File attachment upload. |
880
+ | `7` | `Immagine` | Image upload with optional cropping. |
881
+ | `8` | `Elenco generico` | Dropdown / multi-select list. |
882
+ | `9` | `Lookup` | Server-side lookup with configurable query. |
883
+ | `10` | `Form di dettaglio` | Embedded detail (inner) form. |
884
+ | `11` | `Elenco immagini` | Image selector list. |
885
+ | `12` | `Etichetta` | Display-only label. |
886
+ | `13` | `Immagine con markers` | Image with interactive annotation markers. |
887
+ | `14` | `Bottone` | Action button field. |