wuic-framework-lib 1.7.0 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/{wuic-framework-lib-chart-list.component-Bl424n7x.mjs → wuic-framework-lib-chart-list.component-MeAS47VV.mjs} +4 -4
- package/fesm2022/{wuic-framework-lib-code-editor.component-N6HMl2mf.mjs → wuic-framework-lib-code-editor.component-WtZC2MZC.mjs} +6 -6
- package/fesm2022/{wuic-framework-lib-designer.component-Bd2fwl6H.mjs → wuic-framework-lib-designer.component-Dt7Yz5hn.mjs} +12 -12
- package/fesm2022/{wuic-framework-lib-first-run-wizard.component-NN6cWVHL.mjs → wuic-framework-lib-first-run-wizard.component-C8nhy5yK.mjs} +349 -33
- package/fesm2022/{wuic-framework-lib-framework-docs.component-B867JAYe.mjs → wuic-framework-lib-framework-docs.component-CGsugPCx.mjs} +1426 -979
- package/fesm2022/{wuic-framework-lib-pivot-builder.component-DWukH0L-.mjs → wuic-framework-lib-pivot-builder.component-S5zqy3vj.mjs} +164 -164
- package/fesm2022/{wuic-framework-lib-prompt-dialog-fallback-host.component-DWO1Rcgv.mjs → wuic-framework-lib-prompt-dialog-fallback-host.component-VY-gtgRW.mjs} +28 -28
- package/fesm2022/{wuic-framework-lib-report-designer.component-QcrU81m6.mjs → wuic-framework-lib-report-designer.component-QRxxueU-.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-report-scaffold-dialog.component-U-zdOoRV.mjs → wuic-framework-lib-report-scaffold-dialog.component-OGdglGPw.mjs} +246 -246
- package/fesm2022/{wuic-framework-lib-report-viewer.component-B4LhA3SL.mjs → wuic-framework-lib-report-viewer.component-CuXw3e0j.mjs} +4 -4
- package/fesm2022/{wuic-framework-lib-scene3d-designer.component-DjOfzKLo.mjs → wuic-framework-lib-scene3d-designer.component-LhC0KzWO.mjs} +20 -20
- package/fesm2022/{wuic-framework-lib-scene3d-light-baker-gpu-C96T9uIW.mjs → wuic-framework-lib-scene3d-light-baker-gpu-B5ywsrSp.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-scene3d-shader-effect-DjHyCAFK.mjs → wuic-framework-lib-scene3d-shader-effect-gBEFKNvi.mjs} +18 -18
- package/fesm2022/{wuic-framework-lib-scene3d-viewer.component-Dboz1fjl.mjs → wuic-framework-lib-scene3d-viewer.component-DiDqJO-P.mjs} +5 -5
- package/fesm2022/{wuic-framework-lib-scheduler-list.component--wY21R3o.mjs → wuic-framework-lib-scheduler-list.component-5JbxIBdp.mjs} +4 -4
- package/fesm2022/{wuic-framework-lib-spreadsheet-list-sf.component-Ek30J8v-.mjs → wuic-framework-lib-spreadsheet-list-sf.component-Dxk5d9au.mjs} +47 -47
- package/fesm2022/{wuic-framework-lib-timeline-list.component-aqCH4P0G.mjs → wuic-framework-lib-timeline-list.component-B1ro-16J.mjs} +6 -6
- package/fesm2022/{wuic-framework-lib-workflow-designer.component-DMM8BeXm.mjs → wuic-framework-lib-workflow-designer.component-D32ZMxq2.mjs} +6 -6
- package/fesm2022/{wuic-framework-lib-wuic-framework-lib-dfLTqam5.mjs → wuic-framework-lib-wuic-framework-lib-81WUtxz8.mjs} +847 -823
- package/fesm2022/wuic-framework-lib.mjs +1 -1
- package/package.json +19 -2
- package/styles/_wuic-tokens.scss +82 -82
- package/types/wuic-framework-lib.d.ts +5 -0
|
@@ -6,7 +6,7 @@ import * as i1$1 from '@angular/forms';
|
|
|
6
6
|
import { FormsModule } from '@angular/forms';
|
|
7
7
|
import * as i1 from '@angular/common/http';
|
|
8
8
|
import { HttpContext } from '@angular/common/http';
|
|
9
|
-
import { G as GlobalHandler, W as WtoolboxService, p as WUIC_SUPPRESS_GLOBAL_ERROR } from './wuic-framework-lib-wuic-framework-lib-
|
|
9
|
+
import { G as GlobalHandler, W as WtoolboxService, p as WUIC_SUPPRESS_GLOBAL_ERROR } from './wuic-framework-lib-wuic-framework-lib-81WUtxz8.mjs';
|
|
10
10
|
import { firstValueFrom } from 'rxjs';
|
|
11
11
|
import * as i8 from '@ngx-translate/core';
|
|
12
12
|
import { TranslateModule } from '@ngx-translate/core';
|
|
@@ -22,6 +22,292 @@ import * as i2 from 'primeng/dialog';
|
|
|
22
22
|
import { DialogModule } from 'primeng/dialog';
|
|
23
23
|
import * as i3 from 'primeng/api';
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Traduzioni INLINE del first-run wizard (5 lingue: it/en/fr/es/de).
|
|
27
|
+
*
|
|
28
|
+
* Perche' inline e non `_wuic_translations` (eccezione documentata alla skill
|
|
29
|
+
* ui-localization): il wizard e' l'unica pagina che gira PRIMA che il DB
|
|
30
|
+
* metadati esista — `MetaDataSQLConnection` e' ancora al placeholder
|
|
31
|
+
* `__SET_CONNECTION_STRING__` e `MetaService.GetTranslation` risponde []. Una
|
|
32
|
+
* chiave registrata in DB verrebbe mostrata grezza. Stesso motivo per cui il
|
|
33
|
+
* disclaimer GDPR del crash-reporting usa un dizionario inline nel componente.
|
|
34
|
+
*
|
|
35
|
+
* La lingua iniziale viene da `navigator.language`; cambiando "Lingua admin
|
|
36
|
+
* iniziale" nel wizard, il wizard stesso passa a quella lingua
|
|
37
|
+
* (`TranslateService.use`).
|
|
38
|
+
*
|
|
39
|
+
* I valori con markup (`*_html`) finiscono in `[innerHTML]`: usare solo
|
|
40
|
+
* <strong>, <code>, <br>.
|
|
41
|
+
*/
|
|
42
|
+
const FIRST_RUN_SUPPORTED_LANGS = ['it-IT', 'en-US', 'fr-FR', 'es-ES', 'de-DE'];
|
|
43
|
+
const FIRST_RUN_UI_BUNDLES = {
|
|
44
|
+
'it-IT': {
|
|
45
|
+
firstrun: {
|
|
46
|
+
ui: {
|
|
47
|
+
title: 'Configurazione iniziale progetto',
|
|
48
|
+
subtitle: 'Seleziona DBMS, connessione dati e nome database metadati.',
|
|
49
|
+
setup_mode: 'Modalità setup',
|
|
50
|
+
setup_mode_existing: 'DB esistente',
|
|
51
|
+
create_tutorial_if_missing: 'Crea tutorial se manca',
|
|
52
|
+
data_connection_placeholder: 'es. data source=localhost\\sqlexpress;User ID=sa;Password=...;initial catalog=WideWorldImporters',
|
|
53
|
+
test_connection: 'Test connessione e carica DB',
|
|
54
|
+
tutorial_data_db: 'Database dati tutorial',
|
|
55
|
+
data_db: 'Database dati',
|
|
56
|
+
data_db_placeholder: 'Seleziona o digita database',
|
|
57
|
+
refresh_db_list: 'Aggiorna elenco DB',
|
|
58
|
+
tutorial_meta_db: 'Nome DB metadati tutorial',
|
|
59
|
+
meta_db: 'Nome DB metadati',
|
|
60
|
+
scaffold_existing: 'Esegui scaffold automatico delle tabelle del DB selezionato',
|
|
61
|
+
scaffold_existing_hint_html: 'Popola <code>_metadati__tabelle</code> / <code>_metadati__colonne</code> al termine dell\'installazione. Operazione potenzialmente lunga su DB con molte tabelle.',
|
|
62
|
+
admin_section: 'Utente admin iniziale',
|
|
63
|
+
admin_username: 'Username admin iniziale',
|
|
64
|
+
admin_password: 'Password admin iniziale',
|
|
65
|
+
admin_password_placeholder: '(min 4 caratteri)',
|
|
66
|
+
admin_language: 'Lingua admin iniziale',
|
|
67
|
+
admin_language_hint: 'Lingua applicata all\'utente admin dopo il primo login e a questa pagina. Puoi cambiarla in seguito dal profilo utente.',
|
|
68
|
+
rag_section: 'RAG Chatbot (opzionale)',
|
|
69
|
+
rag_intro_html: 'Il RAG Chatbot è già incluso e funziona <strong>out-of-the-box</strong>: l\'engine è nativo <strong>.NET/ONNX</strong> (nessun Python, nessun server separato da installare). Al primo uso della chat scarica automaticamente i modelli (~2.3 GB) da <code>wuic-framework.com</code>. Con una GPU NVIDIA (CUDA 12.x + cuDNN 9.x) le risposte sono in ~1s; senza, fallback automatico su CPU. <strong>Nessun setup da fare qui.</strong>',
|
|
70
|
+
anthropic_key: 'Anthropic API Key (opzionale)',
|
|
71
|
+
anthropic_key_hint_html: 'Senza chiave il chatbot funziona solo in modalità retrieval (ricerca snippet). Con chiave abilita la chat con LLM (Claude) e le azioni proposte sul designer. Viene salvata in <code>appsettings.json</code>; puoi cambiarla anche dopo.',
|
|
72
|
+
error_close_aria: 'Chiudi errore',
|
|
73
|
+
error_close: 'Chiudi',
|
|
74
|
+
progress_batch: 'batch',
|
|
75
|
+
submit: 'Conferma e genera metadataDB',
|
|
76
|
+
msg_connection_required: 'Inserisci la DataSQLConnection prima del test.',
|
|
77
|
+
msg_connection_unparsable: 'DataSQLConnection non valida: impossibile derivare la connessione base.',
|
|
78
|
+
msg_connection_ok: 'Connessione valida',
|
|
79
|
+
msg_connection_ok_detail: 'Connessione riuscita. Trovati {{count}} database.',
|
|
80
|
+
msg_connection_fixed: 'Connessione corretta automaticamente',
|
|
81
|
+
msg_connection_fixed_detail: 'Applicato fix certificati SQL Server (Encrypt=False;TrustServerCertificate=True).',
|
|
82
|
+
msg_credentials_required: 'Stringa DataSQLConnection non valida: servono almeno user e password (oppure Integrated Security=true su MSSQL).',
|
|
83
|
+
msg_integrated_security_mssql_only: 'Integrated Security è supportata solo su Microsoft SQL Server: per {{dbms}} servono user e password.',
|
|
84
|
+
msg_data_source_missing: 'Stringa DataSQLConnection non valida: manca data source/server/host.',
|
|
85
|
+
msg_pick_data_db: 'Seleziona un database dati dalla lista.',
|
|
86
|
+
msg_test_connection_first: 'Testa prima la connessione dati per abilitare il database di destinazione.',
|
|
87
|
+
msg_admin_username_required: 'Inserisci un username per l\'utente admin iniziale.',
|
|
88
|
+
msg_admin_password_required: 'Inserisci una password (almeno 4 caratteri) per l\'utente admin iniziale.',
|
|
89
|
+
msg_base_connection_failed: 'Stringa DataSQLConnection non valida: impossibile derivare la connessione base senza database.',
|
|
90
|
+
confirm_recreate_title: 'Conferma ricreazione metadata DB',
|
|
91
|
+
confirm_recreate_question: 'Il database metadati \'{{db}}\' esiste già. Vuoi eliminarlo e ricrearlo?',
|
|
92
|
+
no: 'No',
|
|
93
|
+
yes: 'Sì',
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
'en-US': {
|
|
98
|
+
firstrun: {
|
|
99
|
+
ui: {
|
|
100
|
+
title: 'Initial project setup',
|
|
101
|
+
subtitle: 'Choose the DBMS, the data connection and the metadata database name.',
|
|
102
|
+
setup_mode: 'Setup mode',
|
|
103
|
+
setup_mode_existing: 'Existing database',
|
|
104
|
+
create_tutorial_if_missing: 'Create the tutorial database if missing',
|
|
105
|
+
data_connection_placeholder: 'e.g. data source=localhost\\sqlexpress;User ID=sa;Password=...;initial catalog=WideWorldImporters',
|
|
106
|
+
test_connection: 'Test connection and load databases',
|
|
107
|
+
tutorial_data_db: 'Tutorial data database',
|
|
108
|
+
data_db: 'Data database',
|
|
109
|
+
data_db_placeholder: 'Select or type a database',
|
|
110
|
+
refresh_db_list: 'Refresh database list',
|
|
111
|
+
tutorial_meta_db: 'Tutorial metadata database name',
|
|
112
|
+
meta_db: 'Metadata database name',
|
|
113
|
+
scaffold_existing: 'Scaffold the tables of the selected database automatically',
|
|
114
|
+
scaffold_existing_hint_html: 'Fills <code>_metadati__tabelle</code> / <code>_metadati__colonne</code> when the installation ends. It can take a while on databases with many tables.',
|
|
115
|
+
admin_section: 'Initial admin user',
|
|
116
|
+
admin_username: 'Initial admin username',
|
|
117
|
+
admin_password: 'Initial admin password',
|
|
118
|
+
admin_password_placeholder: '(at least 4 characters)',
|
|
119
|
+
admin_language: 'Initial admin language',
|
|
120
|
+
admin_language_hint: 'Language applied to the admin user after the first login, and to this page. You can change it later from the user profile.',
|
|
121
|
+
rag_section: 'RAG Chatbot (optional)',
|
|
122
|
+
rag_intro_html: 'The RAG Chatbot is included and works <strong>out of the box</strong>: the engine is native <strong>.NET/ONNX</strong> (no Python, no separate server to install). The first time you use the chat it downloads the models (~2.3 GB) from <code>wuic-framework.com</code>. With an NVIDIA GPU (CUDA 12.x + cuDNN 9.x) answers take about 1s; without one it falls back to CPU. <strong>Nothing to set up here.</strong>',
|
|
123
|
+
anthropic_key: 'Anthropic API key (optional)',
|
|
124
|
+
anthropic_key_hint_html: 'Without a key the chatbot only works in retrieval mode (snippet search). With a key it enables the LLM chat (Claude) and the actions it proposes in the designer. It is stored in <code>appsettings.json</code> and can be changed later.',
|
|
125
|
+
error_close_aria: 'Dismiss error',
|
|
126
|
+
error_close: 'Dismiss',
|
|
127
|
+
progress_batch: 'batch',
|
|
128
|
+
submit: 'Confirm and create the metadata database',
|
|
129
|
+
msg_connection_required: 'Enter the DataSQLConnection before testing.',
|
|
130
|
+
msg_connection_unparsable: 'Invalid DataSQLConnection: the base connection cannot be derived.',
|
|
131
|
+
msg_connection_ok: 'Connection valid',
|
|
132
|
+
msg_connection_ok_detail: 'Connected. Found {{count}} databases.',
|
|
133
|
+
msg_connection_fixed: 'Connection fixed automatically',
|
|
134
|
+
msg_connection_fixed_detail: 'Applied the SQL Server certificate fix (Encrypt=False;TrustServerCertificate=True).',
|
|
135
|
+
msg_credentials_required: 'Invalid DataSQLConnection: user and password are required (or Integrated Security=true on SQL Server).',
|
|
136
|
+
msg_integrated_security_mssql_only: 'Integrated Security is only supported on Microsoft SQL Server: {{dbms}} needs a user and a password.',
|
|
137
|
+
msg_data_source_missing: 'Invalid DataSQLConnection: data source/server/host is missing.',
|
|
138
|
+
msg_pick_data_db: 'Pick a data database from the list.',
|
|
139
|
+
msg_test_connection_first: 'Test the data connection first to enable the target database.',
|
|
140
|
+
msg_admin_username_required: 'Enter a username for the initial admin user.',
|
|
141
|
+
msg_admin_password_required: 'Enter a password (at least 4 characters) for the initial admin user.',
|
|
142
|
+
msg_base_connection_failed: 'Invalid DataSQLConnection: the base connection without a database cannot be derived.',
|
|
143
|
+
confirm_recreate_title: 'Confirm metadata database recreation',
|
|
144
|
+
confirm_recreate_question: 'The metadata database \'{{db}}\' already exists. Do you want to drop and recreate it?',
|
|
145
|
+
no: 'No',
|
|
146
|
+
yes: 'Yes',
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
'fr-FR': {
|
|
151
|
+
firstrun: {
|
|
152
|
+
ui: {
|
|
153
|
+
title: 'Configuration initiale du projet',
|
|
154
|
+
subtitle: 'Choisissez le SGBD, la connexion aux données et le nom de la base de métadonnées.',
|
|
155
|
+
setup_mode: 'Mode d\'installation',
|
|
156
|
+
setup_mode_existing: 'Base existante',
|
|
157
|
+
create_tutorial_if_missing: 'Créer la base du tutoriel si elle manque',
|
|
158
|
+
data_connection_placeholder: 'ex. data source=localhost\\sqlexpress;User ID=sa;Password=...;initial catalog=WideWorldImporters',
|
|
159
|
+
test_connection: 'Tester la connexion et charger les bases',
|
|
160
|
+
tutorial_data_db: 'Base de données du tutoriel',
|
|
161
|
+
data_db: 'Base de données',
|
|
162
|
+
data_db_placeholder: 'Sélectionnez ou saisissez une base',
|
|
163
|
+
refresh_db_list: 'Actualiser la liste des bases',
|
|
164
|
+
tutorial_meta_db: 'Nom de la base de métadonnées du tutoriel',
|
|
165
|
+
meta_db: 'Nom de la base de métadonnées',
|
|
166
|
+
scaffold_existing: 'Générer automatiquement les métadonnées des tables de la base choisie',
|
|
167
|
+
scaffold_existing_hint_html: 'Remplit <code>_metadati__tabelle</code> / <code>_metadati__colonne</code> à la fin de l\'installation. L\'opération peut être longue sur une base comptant beaucoup de tables.',
|
|
168
|
+
admin_section: 'Utilisateur administrateur initial',
|
|
169
|
+
admin_username: 'Nom d\'utilisateur administrateur',
|
|
170
|
+
admin_password: 'Mot de passe administrateur',
|
|
171
|
+
admin_password_placeholder: '(4 caractères minimum)',
|
|
172
|
+
admin_language: 'Langue de l\'administrateur',
|
|
173
|
+
admin_language_hint: 'Langue appliquée à l\'administrateur après la première connexion, ainsi qu\'à cette page. Vous pourrez la changer depuis le profil utilisateur.',
|
|
174
|
+
rag_section: 'RAG Chatbot (facultatif)',
|
|
175
|
+
rag_intro_html: 'Le RAG Chatbot est inclus et fonctionne <strong>immédiatement</strong> : le moteur est natif <strong>.NET/ONNX</strong> (pas de Python, aucun serveur séparé à installer). Au premier usage du chat, les modèles (~2,3 Go) sont téléchargés depuis <code>wuic-framework.com</code>. Avec un GPU NVIDIA (CUDA 12.x + cuDNN 9.x) les réponses arrivent en ~1 s ; sinon, repli automatique sur le CPU. <strong>Rien à configurer ici.</strong>',
|
|
176
|
+
anthropic_key: 'Clé API Anthropic (facultative)',
|
|
177
|
+
anthropic_key_hint_html: 'Sans clé, le chatbot fonctionne uniquement en mode recherche d\'extraits. Avec une clé, il active le chat LLM (Claude) et les actions proposées dans le designer. Elle est enregistrée dans <code>appsettings.json</code> et reste modifiable ensuite.',
|
|
178
|
+
error_close_aria: 'Fermer l\'erreur',
|
|
179
|
+
error_close: 'Fermer',
|
|
180
|
+
progress_batch: 'lot',
|
|
181
|
+
submit: 'Confirmer et créer la base de métadonnées',
|
|
182
|
+
msg_connection_required: 'Saisissez la DataSQLConnection avant le test.',
|
|
183
|
+
msg_connection_unparsable: 'DataSQLConnection invalide : impossible de dériver la connexion de base.',
|
|
184
|
+
msg_connection_ok: 'Connexion valide',
|
|
185
|
+
msg_connection_ok_detail: 'Connexion réussie. {{count}} bases trouvées.',
|
|
186
|
+
msg_connection_fixed: 'Connexion corrigée automatiquement',
|
|
187
|
+
msg_connection_fixed_detail: 'Correctif de certificat SQL Server appliqué (Encrypt=False;TrustServerCertificate=True).',
|
|
188
|
+
msg_credentials_required: 'DataSQLConnection invalide : utilisateur et mot de passe sont requis (ou Integrated Security=true sur SQL Server).',
|
|
189
|
+
msg_integrated_security_mssql_only: 'Integrated Security n\'est pris en charge que sur Microsoft SQL Server : {{dbms}} exige un utilisateur et un mot de passe.',
|
|
190
|
+
msg_data_source_missing: 'DataSQLConnection invalide : data source/server/host manquant.',
|
|
191
|
+
msg_pick_data_db: 'Choisissez une base de données dans la liste.',
|
|
192
|
+
msg_test_connection_first: 'Testez d\'abord la connexion aux données pour activer la base cible.',
|
|
193
|
+
msg_admin_username_required: 'Saisissez un nom d\'utilisateur pour l\'administrateur initial.',
|
|
194
|
+
msg_admin_password_required: 'Saisissez un mot de passe (4 caractères minimum) pour l\'administrateur initial.',
|
|
195
|
+
msg_base_connection_failed: 'DataSQLConnection invalide : impossible de dériver la connexion de base sans base de données.',
|
|
196
|
+
confirm_recreate_title: 'Confirmer la recréation de la base de métadonnées',
|
|
197
|
+
confirm_recreate_question: 'La base de métadonnées \'{{db}}\' existe déjà. Voulez-vous la supprimer et la recréer ?',
|
|
198
|
+
no: 'Non',
|
|
199
|
+
yes: 'Oui',
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
'es-ES': {
|
|
204
|
+
firstrun: {
|
|
205
|
+
ui: {
|
|
206
|
+
title: 'Configuración inicial del proyecto',
|
|
207
|
+
subtitle: 'Elige el SGBD, la conexión de datos y el nombre de la base de metadatos.',
|
|
208
|
+
setup_mode: 'Modo de instalación',
|
|
209
|
+
setup_mode_existing: 'Base de datos existente',
|
|
210
|
+
create_tutorial_if_missing: 'Crear la base del tutorial si falta',
|
|
211
|
+
data_connection_placeholder: 'p. ej. data source=localhost\\sqlexpress;User ID=sa;Password=...;initial catalog=WideWorldImporters',
|
|
212
|
+
test_connection: 'Probar conexión y cargar bases de datos',
|
|
213
|
+
tutorial_data_db: 'Base de datos del tutorial',
|
|
214
|
+
data_db: 'Base de datos',
|
|
215
|
+
data_db_placeholder: 'Selecciona o escribe una base de datos',
|
|
216
|
+
refresh_db_list: 'Actualizar lista de bases de datos',
|
|
217
|
+
tutorial_meta_db: 'Nombre de la base de metadatos del tutorial',
|
|
218
|
+
meta_db: 'Nombre de la base de metadatos',
|
|
219
|
+
scaffold_existing: 'Generar automáticamente los metadatos de las tablas de la base elegida',
|
|
220
|
+
scaffold_existing_hint_html: 'Rellena <code>_metadati__tabelle</code> / <code>_metadati__colonne</code> al terminar la instalación. Puede tardar en bases con muchas tablas.',
|
|
221
|
+
admin_section: 'Usuario administrador inicial',
|
|
222
|
+
admin_username: 'Usuario administrador inicial',
|
|
223
|
+
admin_password: 'Contraseña del administrador',
|
|
224
|
+
admin_password_placeholder: '(mínimo 4 caracteres)',
|
|
225
|
+
admin_language: 'Idioma del administrador',
|
|
226
|
+
admin_language_hint: 'Idioma aplicado al administrador tras el primer inicio de sesión y a esta página. Puedes cambiarlo después desde el perfil de usuario.',
|
|
227
|
+
rag_section: 'RAG Chatbot (opcional)',
|
|
228
|
+
rag_intro_html: 'El RAG Chatbot ya está incluido y funciona <strong>de inmediato</strong>: el motor es nativo <strong>.NET/ONNX</strong> (sin Python ni servidores aparte). La primera vez que uses el chat descarga los modelos (~2,3 GB) desde <code>wuic-framework.com</code>. Con una GPU NVIDIA (CUDA 12.x + cuDNN 9.x) las respuestas tardan ~1 s; sin ella, recurre automáticamente a la CPU. <strong>Aquí no hay nada que configurar.</strong>',
|
|
229
|
+
anthropic_key: 'Clave API de Anthropic (opcional)',
|
|
230
|
+
anthropic_key_hint_html: 'Sin clave el chatbot solo funciona en modo de recuperación (búsqueda de fragmentos). Con clave habilita el chat con LLM (Claude) y las acciones propuestas en el diseñador. Se guarda en <code>appsettings.json</code> y puedes cambiarla más adelante.',
|
|
231
|
+
error_close_aria: 'Cerrar el error',
|
|
232
|
+
error_close: 'Cerrar',
|
|
233
|
+
progress_batch: 'lote',
|
|
234
|
+
submit: 'Confirmar y crear la base de metadatos',
|
|
235
|
+
msg_connection_required: 'Introduce la DataSQLConnection antes de la prueba.',
|
|
236
|
+
msg_connection_unparsable: 'DataSQLConnection no válida: no se puede derivar la conexión base.',
|
|
237
|
+
msg_connection_ok: 'Conexión válida',
|
|
238
|
+
msg_connection_ok_detail: 'Conexión correcta. Se han encontrado {{count}} bases de datos.',
|
|
239
|
+
msg_connection_fixed: 'Conexión corregida automáticamente',
|
|
240
|
+
msg_connection_fixed_detail: 'Aplicada la corrección de certificados de SQL Server (Encrypt=False;TrustServerCertificate=True).',
|
|
241
|
+
msg_credentials_required: 'DataSQLConnection no válida: se necesitan usuario y contraseña (o Integrated Security=true en SQL Server).',
|
|
242
|
+
msg_integrated_security_mssql_only: 'Integrated Security solo se admite en Microsoft SQL Server: {{dbms}} necesita usuario y contraseña.',
|
|
243
|
+
msg_data_source_missing: 'DataSQLConnection no válida: falta data source/server/host.',
|
|
244
|
+
msg_pick_data_db: 'Selecciona una base de datos de la lista.',
|
|
245
|
+
msg_test_connection_first: 'Prueba primero la conexión de datos para habilitar la base de destino.',
|
|
246
|
+
msg_admin_username_required: 'Introduce un usuario para el administrador inicial.',
|
|
247
|
+
msg_admin_password_required: 'Introduce una contraseña (mínimo 4 caracteres) para el administrador inicial.',
|
|
248
|
+
msg_base_connection_failed: 'DataSQLConnection no válida: no se puede derivar la conexión base sin base de datos.',
|
|
249
|
+
confirm_recreate_title: 'Confirmar la recreación de la base de metadatos',
|
|
250
|
+
confirm_recreate_question: 'La base de metadatos \'{{db}}\' ya existe. ¿Quieres eliminarla y volver a crearla?',
|
|
251
|
+
no: 'No',
|
|
252
|
+
yes: 'Sí',
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
'de-DE': {
|
|
257
|
+
firstrun: {
|
|
258
|
+
ui: {
|
|
259
|
+
title: 'Erstkonfiguration des Projekts',
|
|
260
|
+
subtitle: 'Wähle das DBMS, die Datenverbindung und den Namen der Metadaten-Datenbank.',
|
|
261
|
+
setup_mode: 'Installationsmodus',
|
|
262
|
+
setup_mode_existing: 'Vorhandene Datenbank',
|
|
263
|
+
create_tutorial_if_missing: 'Tutorial-Datenbank anlegen, falls sie fehlt',
|
|
264
|
+
data_connection_placeholder: 'z. B. data source=localhost\\sqlexpress;User ID=sa;Password=...;initial catalog=WideWorldImporters',
|
|
265
|
+
test_connection: 'Verbindung testen und Datenbanken laden',
|
|
266
|
+
tutorial_data_db: 'Tutorial-Datenbank',
|
|
267
|
+
data_db: 'Datenbank',
|
|
268
|
+
data_db_placeholder: 'Datenbank auswählen oder eingeben',
|
|
269
|
+
refresh_db_list: 'Datenbankliste aktualisieren',
|
|
270
|
+
tutorial_meta_db: 'Name der Tutorial-Metadatenbank',
|
|
271
|
+
meta_db: 'Name der Metadaten-Datenbank',
|
|
272
|
+
scaffold_existing: 'Metadaten der Tabellen der gewählten Datenbank automatisch erzeugen',
|
|
273
|
+
scaffold_existing_hint_html: 'Füllt <code>_metadati__tabelle</code> / <code>_metadati__colonne</code> am Ende der Installation. Bei Datenbanken mit vielen Tabellen kann das dauern.',
|
|
274
|
+
admin_section: 'Erster Administrator',
|
|
275
|
+
admin_username: 'Benutzername des Administrators',
|
|
276
|
+
admin_password: 'Passwort des Administrators',
|
|
277
|
+
admin_password_placeholder: '(mindestens 4 Zeichen)',
|
|
278
|
+
admin_language: 'Sprache des Administrators',
|
|
279
|
+
admin_language_hint: 'Sprache, die nach der ersten Anmeldung für den Administrator und für diese Seite gilt. Sie lässt sich später im Benutzerprofil ändern.',
|
|
280
|
+
rag_section: 'RAG Chatbot (optional)',
|
|
281
|
+
rag_intro_html: 'Der RAG Chatbot ist enthalten und funktioniert <strong>sofort</strong>: Die Engine ist nativ <strong>.NET/ONNX</strong> (kein Python, kein separater Server). Beim ersten Chat werden die Modelle (~2,3 GB) von <code>wuic-framework.com</code> geladen. Mit einer NVIDIA-GPU (CUDA 12.x + cuDNN 9.x) dauern Antworten etwa 1 s, sonst wird automatisch die CPU verwendet. <strong>Hier ist nichts einzurichten.</strong>',
|
|
282
|
+
anthropic_key: 'Anthropic-API-Schlüssel (optional)',
|
|
283
|
+
anthropic_key_hint_html: 'Ohne Schlüssel arbeitet der Chatbot nur im Retrieval-Modus (Snippet-Suche). Mit Schlüssel sind der LLM-Chat (Claude) und die im Designer vorgeschlagenen Aktionen aktiv. Er wird in <code>appsettings.json</code> gespeichert und kann später geändert werden.',
|
|
284
|
+
error_close_aria: 'Fehler schließen',
|
|
285
|
+
error_close: 'Schließen',
|
|
286
|
+
progress_batch: 'Stapel',
|
|
287
|
+
submit: 'Bestätigen und Metadaten-Datenbank erzeugen',
|
|
288
|
+
msg_connection_required: 'Gib die DataSQLConnection vor dem Test ein.',
|
|
289
|
+
msg_connection_unparsable: 'Ungültige DataSQLConnection: Die Basisverbindung kann nicht abgeleitet werden.',
|
|
290
|
+
msg_connection_ok: 'Verbindung gültig',
|
|
291
|
+
msg_connection_ok_detail: 'Verbindung hergestellt. {{count}} Datenbanken gefunden.',
|
|
292
|
+
msg_connection_fixed: 'Verbindung automatisch korrigiert',
|
|
293
|
+
msg_connection_fixed_detail: 'SQL-Server-Zertifikatskorrektur angewendet (Encrypt=False;TrustServerCertificate=True).',
|
|
294
|
+
msg_credentials_required: 'Ungültige DataSQLConnection: Benutzer und Passwort sind erforderlich (oder Integrated Security=true auf SQL Server).',
|
|
295
|
+
msg_integrated_security_mssql_only: 'Integrated Security wird nur von Microsoft SQL Server unterstützt: {{dbms}} benötigt Benutzer und Passwort.',
|
|
296
|
+
msg_data_source_missing: 'Ungültige DataSQLConnection: data source/server/host fehlt.',
|
|
297
|
+
msg_pick_data_db: 'Wähle eine Datenbank aus der Liste.',
|
|
298
|
+
msg_test_connection_first: 'Teste zuerst die Datenverbindung, um die Zieldatenbank zu aktivieren.',
|
|
299
|
+
msg_admin_username_required: 'Gib einen Benutzernamen für den ersten Administrator ein.',
|
|
300
|
+
msg_admin_password_required: 'Gib ein Passwort (mindestens 4 Zeichen) für den ersten Administrator ein.',
|
|
301
|
+
msg_base_connection_failed: 'Ungültige DataSQLConnection: Die Basisverbindung ohne Datenbank kann nicht abgeleitet werden.',
|
|
302
|
+
confirm_recreate_title: 'Neuerstellung der Metadaten-Datenbank bestätigen',
|
|
303
|
+
confirm_recreate_question: 'Die Metadaten-Datenbank \'{{db}}\' existiert bereits. Möchtest du sie löschen und neu erstellen?',
|
|
304
|
+
no: 'Nein',
|
|
305
|
+
yes: 'Ja',
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
|
|
25
311
|
/**
|
|
26
312
|
* Componente standalone framework che incapsula l'INTERO workflow di firstRun:
|
|
27
313
|
*
|
|
@@ -101,8 +387,9 @@ class WuicFirstRunWizardComponent {
|
|
|
101
387
|
{ label: 'Español', value: 'es-ES' },
|
|
102
388
|
{ label: 'Deutsch', value: 'de-DE' }
|
|
103
389
|
];
|
|
390
|
+
/** Rebuilt on every language change: see refreshLocalizedOptions(). */
|
|
104
391
|
firstRunSetupModeOptions = [
|
|
105
|
-
{ label: '
|
|
392
|
+
{ label: FIRST_RUN_UI_BUNDLES['en-US'].firstrun.ui['setup_mode_existing'], value: 'existing' },
|
|
106
393
|
{ label: 'Tutorial WideWorldImporters', value: 'tutorial' }
|
|
107
394
|
];
|
|
108
395
|
firstRunTutorialAvailable = true;
|
|
@@ -118,7 +405,10 @@ class WuicFirstRunWizardComponent {
|
|
|
118
405
|
adminUsername: 'admin',
|
|
119
406
|
adminPassword: '',
|
|
120
407
|
adminLanguage: WuicFirstRunWizardComponent.resolveDefaultAdminLanguage(),
|
|
121
|
-
|
|
408
|
+
// On by default: whoever points the wizard at an existing database wants its tables to
|
|
409
|
+
// become routes. With this off, accepting the defaults produced an application with no
|
|
410
|
+
// routes at all (journey win-vscode-src, 2026-09-07). Tutorial mode ignores the flag.
|
|
411
|
+
scaffoldExistingDatabase: true,
|
|
122
412
|
anthropicApiKey: '',
|
|
123
413
|
// Crash reporting opt-in (skill crash-reporting Commit 8). OFF by default
|
|
124
414
|
// per GDPR: l'utente lo abilita esplicitamente in fase di first-install
|
|
@@ -349,16 +639,16 @@ class WuicFirstRunWizardComponent {
|
|
|
349
639
|
}
|
|
350
640
|
if (!dbName)
|
|
351
641
|
dbName = this.firstRunForm.metadataDbName || 'metadataDB';
|
|
352
|
-
const promptResult = await WtoolboxService.promptDialog('
|
|
642
|
+
const promptResult = await WtoolboxService.promptDialog(this.translate.instant('firstrun.ui.confirm_recreate_title'), [
|
|
353
643
|
{
|
|
354
644
|
name: 'confirmDrop',
|
|
355
|
-
caption:
|
|
645
|
+
caption: this.translate.instant('firstrun.ui.confirm_recreate_question', { db: dbName }),
|
|
356
646
|
type: 'dictionary_radio',
|
|
357
647
|
value: 'no',
|
|
358
648
|
required: true,
|
|
359
649
|
dictionaryData: [
|
|
360
|
-
{ label: '
|
|
361
|
-
{ label: '
|
|
650
|
+
{ label: this.translate.instant('firstrun.ui.no'), value: 'no' },
|
|
651
|
+
{ label: this.translate.instant('firstrun.ui.yes'), value: 'yes' }
|
|
362
652
|
]
|
|
363
653
|
}
|
|
364
654
|
], '620px', '400px');
|
|
@@ -402,7 +692,7 @@ class WuicFirstRunWizardComponent {
|
|
|
402
692
|
return 'es-ES';
|
|
403
693
|
if (raw.startsWith('de'))
|
|
404
694
|
return 'de-DE';
|
|
405
|
-
return '
|
|
695
|
+
return 'en-US'; // unknown browser language: English, not Italian
|
|
406
696
|
}
|
|
407
697
|
// ════════════════════════════════════════════════════════════════════════
|
|
408
698
|
// BOOTSTRAP / PROBE
|
|
@@ -430,7 +720,7 @@ class WuicFirstRunWizardComponent {
|
|
|
430
720
|
const tutorialFlag = settings['tutorialAvailable'] ?? settings['tutorialavailable'];
|
|
431
721
|
this.firstRunTutorialAvailable = tutorialFlag === undefined ? true : this.toBoolean(tutorialFlag);
|
|
432
722
|
if (!this.firstRunTutorialAvailable) {
|
|
433
|
-
this.firstRunSetupModeOptions = [{ label: '
|
|
723
|
+
this.firstRunSetupModeOptions = [{ label: this.translate.instant('firstrun.ui.setup_mode_existing'), value: 'existing' }];
|
|
434
724
|
this.firstRunForm.setupMode = 'existing';
|
|
435
725
|
}
|
|
436
726
|
if (!isFirstRun) {
|
|
@@ -556,12 +846,12 @@ class WuicFirstRunWizardComponent {
|
|
|
556
846
|
const dbms = this.normalizeDbms(this.firstRunForm.dbms);
|
|
557
847
|
const rawConnectionString = String(this.firstRunForm.dataConnectionString || '').trim();
|
|
558
848
|
if (!rawConnectionString) {
|
|
559
|
-
this.firstRunError = '
|
|
849
|
+
this.firstRunError = this.translate.instant('firstrun.ui.msg_connection_required');
|
|
560
850
|
return;
|
|
561
851
|
}
|
|
562
852
|
const baseConnection = this.buildConnectionWithoutDatabase(rawConnectionString, dbms);
|
|
563
853
|
if (!baseConnection) {
|
|
564
|
-
this.firstRunError = '
|
|
854
|
+
this.firstRunError = this.translate.instant('firstrun.ui.msg_connection_unparsable');
|
|
565
855
|
return;
|
|
566
856
|
}
|
|
567
857
|
this.firstRunConnectionTesting = true;
|
|
@@ -575,8 +865,8 @@ class WuicFirstRunWizardComponent {
|
|
|
575
865
|
}
|
|
576
866
|
this.messageService.add({
|
|
577
867
|
severity: 'success',
|
|
578
|
-
summary: '
|
|
579
|
-
detail:
|
|
868
|
+
summary: this.translate.instant('firstrun.ui.msg_connection_ok'),
|
|
869
|
+
detail: this.translate.instant('firstrun.ui.msg_connection_ok_detail', { count: this.firstRunDataDbOptions.length })
|
|
580
870
|
});
|
|
581
871
|
}
|
|
582
872
|
catch (error) {
|
|
@@ -596,8 +886,8 @@ class WuicFirstRunWizardComponent {
|
|
|
596
886
|
}
|
|
597
887
|
this.messageService.add({
|
|
598
888
|
severity: 'success',
|
|
599
|
-
summary: '
|
|
600
|
-
detail: '
|
|
889
|
+
summary: this.translate.instant('firstrun.ui.msg_connection_fixed'),
|
|
890
|
+
detail: this.translate.instant('firstrun.ui.msg_connection_fixed_detail')
|
|
601
891
|
});
|
|
602
892
|
return;
|
|
603
893
|
}
|
|
@@ -655,38 +945,38 @@ class WuicFirstRunWizardComponent {
|
|
|
655
945
|
? (this.firstRunForm.tutorialMetadataDbName || this.firstRunForm.metadataDbName || 'MetadataCRM')
|
|
656
946
|
: (this.firstRunForm.metadataDbName || 'metadataDB')).trim();
|
|
657
947
|
if (!conn.integratedSecurity && (!conn.userId || !conn.password)) {
|
|
658
|
-
this.firstRunError = '
|
|
948
|
+
this.firstRunError = this.translate.instant('firstrun.ui.msg_credentials_required');
|
|
659
949
|
return;
|
|
660
950
|
}
|
|
661
951
|
if (conn.integratedSecurity && dbms !== 'mssql') {
|
|
662
|
-
this.firstRunError = '
|
|
952
|
+
this.firstRunError = this.translate.instant('firstrun.ui.msg_integrated_security_mssql_only', { dbms });
|
|
663
953
|
return;
|
|
664
954
|
}
|
|
665
955
|
if (!conn.dataSource) {
|
|
666
|
-
this.firstRunError = '
|
|
956
|
+
this.firstRunError = this.translate.instant('firstrun.ui.msg_data_source_missing');
|
|
667
957
|
return;
|
|
668
958
|
}
|
|
669
959
|
if (!selectedDataDbName) {
|
|
670
|
-
this.firstRunError = '
|
|
960
|
+
this.firstRunError = this.translate.instant('firstrun.ui.msg_pick_data_db');
|
|
671
961
|
return;
|
|
672
962
|
}
|
|
673
963
|
if (!this.firstRunConnectionValid) {
|
|
674
|
-
this.firstRunError = '
|
|
964
|
+
this.firstRunError = this.translate.instant('firstrun.ui.msg_test_connection_first');
|
|
675
965
|
return;
|
|
676
966
|
}
|
|
677
967
|
const adminUsername = String(this.firstRunForm.adminUsername || '').trim();
|
|
678
968
|
const adminPassword = String(this.firstRunForm.adminPassword || '');
|
|
679
969
|
if (!adminUsername) {
|
|
680
|
-
this.firstRunError = '
|
|
970
|
+
this.firstRunError = this.translate.instant('firstrun.ui.msg_admin_username_required');
|
|
681
971
|
return;
|
|
682
972
|
}
|
|
683
973
|
if (!adminPassword || adminPassword.length < 4) {
|
|
684
|
-
this.firstRunError =
|
|
974
|
+
this.firstRunError = this.translate.instant('firstrun.ui.msg_admin_password_required');
|
|
685
975
|
return;
|
|
686
976
|
}
|
|
687
977
|
const dataBaseConnection = this.buildConnectionWithoutDatabase(this.firstRunForm.dataConnectionString || '', dbms);
|
|
688
978
|
if (!dataBaseConnection) {
|
|
689
|
-
this.firstRunError = '
|
|
979
|
+
this.firstRunError = this.translate.instant('firstrun.ui.msg_base_connection_failed');
|
|
690
980
|
return;
|
|
691
981
|
}
|
|
692
982
|
this.firstRunInstalling = true;
|
|
@@ -1282,17 +1572,43 @@ class WuicFirstRunWizardComponent {
|
|
|
1282
1572
|
for (const [lang, strings] of Object.entries(bundles)) {
|
|
1283
1573
|
this.translate.setTranslation(lang, strings, true);
|
|
1284
1574
|
}
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|| Object.keys(bundles).find(l => l.startsWith(browserLang.substring(0, 2)))
|
|
1289
|
-
|| 'it-IT';
|
|
1290
|
-
this.translate.setDefaultLang(resolvedLang);
|
|
1291
|
-
this.translate.use(resolvedLang);
|
|
1575
|
+
// Labels of the wizard itself (inline: no metadata DB yet, see first-run-wizard.i18n.ts).
|
|
1576
|
+
for (const [lang, strings] of Object.entries(FIRST_RUN_UI_BUNDLES)) {
|
|
1577
|
+
this.translate.setTranslation(lang, strings, true);
|
|
1292
1578
|
}
|
|
1579
|
+
// The wizard ALWAYS follows the browser language: it runs before any user
|
|
1580
|
+
// exists, so a default language set elsewhere at bootstrap (it-IT) must not
|
|
1581
|
+
// win here. The admin-language select then switches it (see
|
|
1582
|
+
// onFirstRunAdminLanguageChanged).
|
|
1583
|
+
const resolved = WuicFirstRunWizardComponent.resolveDefaultAdminLanguage();
|
|
1584
|
+
if (!this.translate.getDefaultLang())
|
|
1585
|
+
this.translate.setDefaultLang(resolved);
|
|
1586
|
+
this.translate.use(resolved);
|
|
1587
|
+
this.refreshLocalizedOptions();
|
|
1588
|
+
}
|
|
1589
|
+
/**
|
|
1590
|
+
* The admin-language select drives the language of the wizard itself as well:
|
|
1591
|
+
* what you pick for the admin is what you immediately read on this page
|
|
1592
|
+
* (the crash-reporting disclaimer already followed this value).
|
|
1593
|
+
*/
|
|
1594
|
+
onFirstRunAdminLanguageChanged(lang) {
|
|
1595
|
+
this.firstRunForm.adminLanguage = lang;
|
|
1596
|
+
if (!lang)
|
|
1597
|
+
return;
|
|
1598
|
+
this.translate.use(lang);
|
|
1599
|
+
this.refreshLocalizedOptions();
|
|
1600
|
+
}
|
|
1601
|
+
/**
|
|
1602
|
+
* Select options are plain strings, not template bindings: the `translate`
|
|
1603
|
+
* pipe cannot re-render them, so they are rebuilt whenever the language
|
|
1604
|
+
* changes. Product names (DBMS, "Tutorial WideWorldImporters") stay as they are.
|
|
1605
|
+
*/
|
|
1606
|
+
refreshLocalizedOptions() {
|
|
1607
|
+
const existing = this.translate.instant('firstrun.ui.setup_mode_existing');
|
|
1608
|
+
this.firstRunSetupModeOptions = this.firstRunSetupModeOptions.map(o => o.value === 'existing' ? { ...o, label: existing } : o);
|
|
1293
1609
|
}
|
|
1294
1610
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WuicFirstRunWizardComponent, deps: [{ token: i1.HttpClient }, { token: i8.TranslateService }, { token: i3.MessageService }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component });
|
|
1295
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: WuicFirstRunWizardComponent, isStandalone: true, selector: "wuic-first-run-wizard-impl", outputs: { complete: "complete" }, ngImport: i0, template: "@if (showFirstRunInstall) {\n<div class=\"first-run-overlay\">\n <div class=\"first-run-card first-run-card-wide\">\n <div class=\"first-run-title\">Configurazione iniziale progetto</div>\n <div class=\"first-run-subtitle\">Seleziona DBMS, connessione dati e nome database metadati.</div>\n\n <!-- BODY scrollabile: header (title/subtitle) e footer (progress + CTA)\n restano sempre visibili, solo questo blocco scrolla quando il form\n e' piu' alto della viewport. -->\n <div class=\"first-run-body\">\n\n <!-- Grid 2 colonne: sx = connessione + scaffold / dx = admin + RAG.\n Su viewport stretti (< 720px) il grid collassa a 1 colonna. -->\n <div class=\"first-run-grid\">\n\n <!-- \u2500\u2500 COLONNA SINISTRA: Database + Setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"first-run-col\">\n\n @if (firstRunSetupModeOptions.length > 1) {\n <div class=\"first-run-field\">\n <label for=\"first-run-mode\">Modalit\u00E0 setup</label>\n <p-select [options]=\"firstRunSetupModeOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"firstRunForm.setupMode\" (ngModelChange)=\"onFirstRunSetupModeChanged($event)\"\n [disabled]=\"firstRunInstalling\" [style]=\"{ width: '100%' }\" inputId=\"first-run-mode\"></p-select>\n </div>\n }\n\n <div class=\"first-run-field\">\n <label for=\"first-run-dbms\">DBMS</label>\n <p-select [options]=\"firstRunDbmsOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"firstRunForm.dbms\" (ngModelChange)=\"onFirstRunDbmsChanged($event)\"\n [disabled]=\"firstRunInstalling\" [style]=\"{ width: '100%' }\" inputId=\"first-run-dbms\"></p-select>\n </div>\n\n @if (firstRunForm.setupMode === 'tutorial') {\n <div class=\"first-run-field first-run-checkbox-row\">\n <label>\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.createTutorialIfMissing\"\n (ngModelChange)=\"firstRunForm.createTutorialIfMissing = !!$event\" [disabled]=\"firstRunInstalling\" />\n Crea tutorial se manca\n </label>\n </div>\n }\n\n <div class=\"first-run-field\">\n <label for=\"first-run-datasql\">DataSQLConnection</label>\n <input id=\"first-run-datasql\" class=\"first-run-input\" type=\"text\"\n [ngModel]=\"firstRunForm.dataConnectionString\" (ngModelChange)=\"onFirstRunConnectionChanged($event)\"\n [disabled]=\"firstRunInstalling\"\n placeholder=\"es. data source=localhost\\sqlexpress;User ID=sa;Password=...;initial catalog=WideWorldImporters\" />\n </div>\n\n <div class=\"first-run-field\">\n <p-button label=\"Test connessione e carica DB\" severity=\"secondary\" [outlined]=\"true\"\n [loading]=\"firstRunConnectionTesting\"\n [disabled]=\"firstRunInstalling || firstRunLoading || !firstRunForm.dataConnectionString\"\n (onClick)=\"testFirstRunConnectionAndLoadDatabases()\"></p-button>\n </div>\n\n @if (firstRunForm.setupMode === 'tutorial') {\n <div class=\"first-run-field\">\n <label for=\"first-run-datadb\">Database dati tutorial</label>\n <input id=\"first-run-datadb\" class=\"first-run-input\" type=\"text\"\n [ngModel]=\"firstRunForm.tutorialDataDbName\"\n (ngModelChange)=\"firstRunForm.tutorialDataDbName = $event; firstRunForm.dataDbName = $event\"\n [disabled]=\"firstRunInstalling || !firstRunConnectionValid\"\n placeholder=\"WideWorldImporters\" />\n </div>\n } @else {\n <div class=\"first-run-field\">\n <label for=\"first-run-datadb\">Database dati</label>\n <p-select [options]=\"firstRunDataDbOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"firstRunForm.dataDbName\" (ngModelChange)=\"firstRunForm.dataDbName = $event\"\n [disabled]=\"firstRunInstalling || firstRunDbLoading || !firstRunConnectionValid\" [filter]=\"true\"\n [editable]=\"true\" [style]=\"{ width: '100%' }\" inputId=\"first-run-datadb\"\n placeholder=\"Seleziona o digita database\"></p-select>\n <div style=\"margin-top: 0.5rem;\">\n <p-button label=\"Aggiorna elenco DB\" severity=\"secondary\" [outlined]=\"true\" size=\"small\"\n [loading]=\"firstRunDbLoading\" [disabled]=\"firstRunInstalling || !firstRunConnectionValid\"\n (onClick)=\"testFirstRunConnectionAndLoadDatabases()\"></p-button>\n </div>\n </div>\n }\n\n <div class=\"first-run-field\">\n <label for=\"first-run-metadb\">@if (firstRunForm.setupMode === 'tutorial') {Nome DB metadati tutorial} @else {Nome DB metadati}</label>\n <input id=\"first-run-metadb\" class=\"first-run-input\" type=\"text\"\n [ngModel]=\"firstRunForm.setupMode === 'tutorial' ? firstRunForm.tutorialMetadataDbName : firstRunForm.metadataDbName\"\n (ngModelChange)=\"firstRunForm.metadataDbName = $event; firstRunForm.tutorialMetadataDbName = $event\"\n [disabled]=\"firstRunInstalling\"\n placeholder=\"metadataDB\" />\n </div>\n\n @if (firstRunForm.setupMode !== 'tutorial') {\n <div class=\"first-run-field first-run-checkbox-row\">\n <label>\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.scaffoldExistingDatabase\"\n (ngModelChange)=\"firstRunForm.scaffoldExistingDatabase = !!$event\"\n [disabled]=\"firstRunInstalling\" />\n Esegui scaffold automatico delle tabelle del DB selezionato\n </label>\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\">\n Popola <code>_metadati__tabelle</code> / <code>_metadati__colonne</code> al termine dell'installazione.\n Operazione potenzialmente lunga su DB con molte tabelle.\n </small>\n </div>\n }\n </div>\n\n <!-- \u2500\u2500 COLONNA DESTRA: Admin + RAG \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"first-run-col\">\n\n <div class=\"first-run-section-title\">Utente admin iniziale</div>\n\n <div class=\"first-run-field\">\n <label for=\"first-run-admin-username\">Username admin iniziale</label>\n <input id=\"first-run-admin-username\" class=\"first-run-input\" type=\"text\"\n [ngModel]=\"firstRunForm.adminUsername\"\n (ngModelChange)=\"firstRunForm.adminUsername = $event\"\n [disabled]=\"firstRunInstalling\" autocomplete=\"off\"\n placeholder=\"admin\" />\n </div>\n\n <div class=\"first-run-field\">\n <label for=\"first-run-admin-password\">Password admin iniziale</label>\n <input id=\"first-run-admin-password\" class=\"first-run-input\" type=\"password\"\n [ngModel]=\"firstRunForm.adminPassword\"\n (ngModelChange)=\"firstRunForm.adminPassword = $event\"\n [disabled]=\"firstRunInstalling\" autocomplete=\"new-password\"\n placeholder=\"(min 4 caratteri)\" />\n </div>\n\n <div class=\"first-run-field\">\n <label for=\"first-run-admin-language\">Lingua admin iniziale</label>\n <p-select [options]=\"firstRunAdminLanguageOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"firstRunForm.adminLanguage\"\n (ngModelChange)=\"firstRunForm.adminLanguage = $event\"\n [disabled]=\"firstRunInstalling\"\n [style]=\"{ width: '100%' }\" inputId=\"first-run-admin-language\"></p-select>\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\">\n Lingua applicata all'utente admin dopo il primo login. Puoi cambiarla in seguito dal profilo utente.\n </small>\n </div>\n\n <div class=\"first-run-section-title first-run-section-title-rag\">RAG Chatbot (opzionale)</div>\n\n <div class=\"first-run-field\">\n <small style=\"display:block; margin-bottom:8px; opacity:0.8; font-size:0.85rem; line-height:1.4;\">\n Il RAG Chatbot \u00E8 gi\u00E0 incluso e funziona <strong>out-of-the-box</strong>: l'engine \u00E8 nativo\n <strong>.NET/ONNX</strong> (nessun Python, nessun server separato da installare). Al primo\n uso della chat scarica automaticamente i modelli (~2.3 GB) da <code>wuic-framework.com</code>.\n Con una GPU NVIDIA (CUDA 12.x + cuDNN 9.x) le risposte sono in ~1s; senza, fallback automatico\n su CPU. <strong>Nessun setup da fare qui.</strong>\n </small>\n <label for=\"first-run-anthropic-key\">\n Anthropic API Key (opzionale)\n <i class=\"pi pi-info-circle first-run-info-icon\"\n [pTooltip]=\"'firstrun.rag.apiKeyTooltip' | translate\"\n tooltipPosition=\"right\"\n [tooltipStyleClass]=\"'first-run-tooltip'\"\n [escape]=\"false\"></i>\n </label>\n <textarea id=\"first-run-anthropic-key\" class=\"first-run-input first-run-textarea\"\n [ngModel]=\"firstRunForm.anthropicApiKey\"\n (ngModelChange)=\"firstRunForm.anthropicApiKey = $event\"\n [disabled]=\"firstRunInstalling\"\n rows=\"2\" autocomplete=\"off\"\n placeholder=\"sk-ant-...\"></textarea>\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\">\n Senza chiave il chatbot funziona solo in modalit\u00E0 retrieval (ricerca snippet).\n Con chiave abilita la chat con LLM (Claude) e le azioni proposte sul designer.\n Viene salvata in <code>appsettings.json</code>; puoi cambiarla anche dopo.\n </small>\n </div>\n </div>\n\n <!-- Crash reporting opt-in (skill crash-reporting Commit 8). Default OFF.\n Il consenso GDPR usa labels HARDCODED in `crashReportingLabels`\n dentro il componente (NON `wuic_translation`) perche' il\n first-run gira PRIMA che il DB metadati esista \u2014 niente DB,\n niente translation table. Vedi commento esteso nel componente.\n Al check del consenso si apre il popup col disclaimer\n dettagliato; l'utente conferma li' per attivare il flag. -->\n <div class=\"first-run-section-title first-run-section-title-crash-reporting\">{{ crashReportingLabels.title }}</div>\n <div class=\"first-run-field first-run-checkbox-row\">\n <label>\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.enableCrashReporting\"\n (ngModelChange)=\"onCrashReportingToggle($event)\"\n [disabled]=\"firstRunInstalling\" />\n {{ crashReportingLabels.checkbox_accept }}\n </label>\n <small style=\"display:block; margin-top:4px; opacity:0.85; font-size:0.85rem; line-height:1.45;\">\n {{ crashReportingLabels.intro_short }}\n <a href=\"javascript:void(0)\" (click)=\"openCrashReportingDisclaimer()\"\n style=\"margin-left:6px;\">{{ crashReportingLabels.read_full }}</a>\n </small>\n </div>\n </div>\n\n <!-- Disclaimer GDPR popup (apre al check + da link \"leggi tutto\"). -->\n <p-dialog [(visible)]=\"crashReportingDisclaimerVisible\"\n [modal]=\"true\"\n [closable]=\"true\"\n [closeOnEscape]=\"true\"\n [header]=\"crashReportingLabels.title\"\n [style]=\"{ width: '600px', maxWidth: '90vw' }\"\n [contentStyle]=\"{ 'max-height': '70vh', 'overflow-y': 'auto' }\"\n [appendTo]=\"'body'\">\n <div style=\"line-height:1.55;\">\n <p>{{ crashReportingLabels.intro }}</p>\n <p><strong>{{ crashReportingLabels.what_we_send }}</strong></p>\n <ul style=\"margin:0 0 8px 18px; padding:0;\">\n <li>{{ crashReportingLabels.what_we_dont_send }}</li>\n <li>{{ crashReportingLabels.where_it_goes }}</li>\n <li>{{ crashReportingLabels.retention }}</li>\n <li>{{ crashReportingLabels.legal_basis }}</li>\n <li>{{ crashReportingLabels.how_to_disable }}</li>\n </ul>\n </div>\n <ng-template pTemplate=\"footer\">\n <p-button [label]=\"crashReportingLabels.btn_decline\"\n severity=\"secondary\"\n (onClick)=\"declineCrashReporting()\"></p-button>\n <p-button [label]=\"crashReportingLabels.btn_accept\"\n (onClick)=\"acceptCrashReporting()\"></p-button>\n </ng-template>\n </p-dialog>\n\n </div><!-- /.first-run-body -->\n\n <!-- FOOTER sticky: error (se presente) + riga progress|CTA sempre visibile. -->\n <div class=\"first-run-footer\">\n @if (firstRunError && !firstRunErrorDismissed) {\n <div class=\"first-run-error\" role=\"alert\">\n <button type=\"button\"\n class=\"first-run-error__close\"\n (click)=\"dismissFirstRunError()\"\n aria-label=\"Chiudi errore\"\n title=\"Chiudi\">\u00D7</button>\n <div class=\"first-run-error__body\">{{ firstRunError }}</div>\n </div>\n }\n\n <div class=\"first-run-footer-row\">\n @if (firstRunInstalling && firstRunProgress.active) {\n <div class=\"first-run-progress\">\n <div class=\"first-run-progress-label\">\n <strong>{{ firstRunProgress.phase }}</strong>\n @if (firstRunProgress.total > 0 && !firstRunProgress.phase.includes('.restore')) {\n <span class=\"first-run-progress-count\">\n \u2014 batch {{ firstRunProgress.current }} / {{ firstRunProgress.total }}\n </span>\n }\n @if (firstRunProgress.elapsedMs > 0) {\n <span class=\"first-run-progress-count\">\n \u00B7 {{ (firstRunProgress.elapsedMs / 1000) | number:'1.0-0' }}s\n </span>\n }\n </div>\n @if (firstRunProgress.phase.includes('.restore') && firstRunProgress.percent < 5) {\n <p-progressBar mode=\"indeterminate\" [style]=\"{'height': '1rem'}\"></p-progressBar>\n } @else {\n <p-progressBar [value]=\"firstRunProgress.percent\" [showValue]=\"true\" [style]=\"{'height': '1rem'}\"></p-progressBar>\n }\n @if (firstRunProgress.message) {\n <div class=\"first-run-progress-message\">{{ firstRunProgress.message }}</div>\n }\n </div>\n } @else {\n <div class=\"first-run-progress-placeholder\"></div>\n }\n\n <div class=\"first-run-actions\">\n <p-button label=\"Conferma e genera metadataDB\" [loading]=\"firstRunInstalling\"\n [disabled]=\"firstRunInstalling || firstRunLoading\" (onClick)=\"submitFirstRunInstall()\"></p-button>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n", styles: [".first-run-overlay{position:fixed;inset:0;z-index:900;display:flex;align-items:center;justify-content:center;padding:24px;background:linear-gradient(135deg,#081221d9,#16294acc)}.first-run-card-wide{width:min(1180px,100%)!important}.first-run-card{width:min(860px,100%);min-height:min(720px,100vh - 48px);max-height:calc(100vh - 48px);display:flex;flex-direction:column;overflow:hidden;border-radius:14px;padding:22px;background:var(--p-surface-0);box-shadow:0 18px 48px #00000059;border:1px solid var(--p-content-border-color)}.first-run-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding-right:4px;margin-right:-4px}.first-run-footer{flex:0 0 auto;margin-top:12px;padding-top:12px;border-top:1px solid var(--p-content-border-color);display:flex;flex-direction:column;gap:10px}.first-run-footer-row{display:flex;align-items:center;gap:16px}.first-run-title{font-size:1.25rem;font-weight:700}.first-run-subtitle{margin-top:6px;margin-bottom:18px;opacity:.8}.first-run-field{margin-bottom:14px}.first-run-field label{display:block;margin-bottom:6px;font-weight:600}.first-run-checkbox-row label{display:inline-flex;align-items:center;gap:.5rem;margin-bottom:0;font-weight:500}.first-run-input{width:100%;height:40px;border-radius:8px;border:1px solid var(--p-content-border-color);padding:8px 12px;font-size:.95rem;background:var(--p-surface-0);color:var(--p-text-color)}.first-run-textarea{height:auto;min-height:56px;resize:vertical;font-family:var(--p-font-family);line-height:1.4}.first-run-grid{display:grid;grid-template-columns:1fr 1fr;column-gap:28px;row-gap:0}@media(max-width:860px){.first-run-grid{grid-template-columns:1fr}}.first-run-col{display:flex;flex-direction:column;min-width:0}.first-run-section-title{margin-top:4px;margin-bottom:12px;padding-bottom:6px;font-size:.95rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;opacity:.8;border-bottom:1px solid var(--p-content-border-color)}.first-run-section-title-rag{margin-top:18px}.first-run-python-warning{margin-top:8px;padding:10px 12px;background:#fef3c7;border:1px solid #fcd34d;border-radius:6px;color:#78350f;font-size:.85rem;line-height:1.4}.first-run-python-warning strong{color:#78350f}.first-run-python-warning code{background:#00000014;padding:1px 4px;border-radius:3px;font-family:ui-monospace,Cascadia Code,Consolas,monospace;font-size:.82rem}.first-run-python-warning ol li+li{margin-top:4px}.first-run-python-warning-link{color:#92400e;text-decoration:underline;font-weight:600}.first-run-python-warning-link:hover{color:#78350f}.first-run-python-warning-link:visited{color:#92400e}.first-run-python-note{margin-top:8px;padding:10px 12px;background:#dbeafe;border:1px solid #93c5fd;border-radius:6px;color:#1e3a8a;font-size:.85rem;line-height:1.4}.first-run-python-note strong{color:#1e3a8a}.first-run-python-note code{background:#00000014;padding:1px 4px;border-radius:3px;font-family:ui-monospace,Cascadia Code,Consolas,monospace;font-size:.82rem}.first-run-info-icon{margin-left:6px;font-size:.95rem;color:var(--p-primary-color, #3b82f6);cursor:help;vertical-align:middle;opacity:.85}.first-run-info-icon:hover{opacity:1}::ng-deep .p-tooltip.first-run-tooltip{max-width:440px}::ng-deep .p-tooltip.first-run-tooltip .p-tooltip-text{white-space:pre-line;font-size:.85rem;line-height:1.45}.first-run-input:focus{outline:2px solid rgba(59,130,246,.25);border-color:#3b82f6}.first-run-error{position:relative;margin:8px 0 14px;color:#7f1d1d;background:#fee2e2;border:1px solid #fca5a5;border-radius:8px;padding:10px 36px 10px 12px}.first-run-error__body{max-height:200px;overflow-y:auto;word-break:break-word;white-space:pre-wrap;font-family:ui-monospace,Cascadia Code,Consolas,monospace;font-size:.85rem;line-height:1.4}.first-run-error__close{position:absolute;top:6px;right:8px;width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;padding:0;background:transparent;border:0;border-radius:4px;color:inherit;font-size:1.25rem;line-height:1;cursor:pointer;opacity:.75;transition:background-color .12s ease,opacity .12s ease}.first-run-error__close:hover,.first-run-error__close:focus-visible{opacity:1;background:#7f1d1d1f;outline:none}.first-run-error__close:active{background:#7f1d1d33}.first-run-actions{flex:0 0 auto;display:flex;justify-content:flex-end}.first-run-progress{flex:1 1 auto;min-width:0;padding:8px 12px;background:var(--p-surface-50);border:1px solid var(--p-content-border-color);border-radius:8px;display:flex;flex-direction:column;gap:4px}.first-run-progress-placeholder{flex:1 1 auto;min-width:0}.first-run-progress-label{font-size:.9rem}.first-run-progress-label strong{font-weight:600}.first-run-progress-label .first-run-progress-count{opacity:.7;margin-left:4px}.first-run-progress-message{font-size:.8rem;opacity:.75;font-family:ui-monospace,Cascadia Code,Consolas,monospace}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i4.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: ProgressBarModule }, { kind: "component", type: i6.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "unit", "mode", "color"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "pipe", type: i1$2.DecimalPipe, name: "number" }, { kind: "pipe", type: i8.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
1611
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: WuicFirstRunWizardComponent, isStandalone: true, selector: "wuic-first-run-wizard-impl", outputs: { complete: "complete" }, ngImport: i0, template: "@if (showFirstRunInstall) {\r\n<div class=\"first-run-overlay\">\r\n <div class=\"first-run-card first-run-card-wide\">\r\n <div class=\"first-run-title\">{{ 'firstrun.ui.title' | translate }}</div>\r\n <div class=\"first-run-subtitle\">{{ 'firstrun.ui.subtitle' | translate }}</div>\r\n\r\n <!-- BODY scrollabile: header (title/subtitle) e footer (progress + CTA)\r\n restano sempre visibili, solo questo blocco scrolla quando il form\r\n e' piu' alto della viewport. -->\r\n <div class=\"first-run-body\">\r\n\r\n <!-- Grid 2 colonne: sx = connessione + scaffold / dx = admin + RAG.\r\n Su viewport stretti (< 720px) il grid collassa a 1 colonna. -->\r\n <div class=\"first-run-grid\">\r\n\r\n <!-- \u2500\u2500 COLONNA SINISTRA: Database + Setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\r\n <div class=\"first-run-col\">\r\n\r\n @if (firstRunSetupModeOptions.length > 1) {\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-mode\">{{ 'firstrun.ui.setup_mode' | translate }}</label>\r\n <p-select [options]=\"firstRunSetupModeOptions\" optionLabel=\"label\" optionValue=\"value\"\r\n [ngModel]=\"firstRunForm.setupMode\" (ngModelChange)=\"onFirstRunSetupModeChanged($event)\"\r\n [disabled]=\"firstRunInstalling\" [style]=\"{ width: '100%' }\" inputId=\"first-run-mode\"></p-select>\r\n </div>\r\n }\r\n\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-dbms\">DBMS</label>\r\n <p-select [options]=\"firstRunDbmsOptions\" optionLabel=\"label\" optionValue=\"value\"\r\n [ngModel]=\"firstRunForm.dbms\" (ngModelChange)=\"onFirstRunDbmsChanged($event)\"\r\n [disabled]=\"firstRunInstalling\" [style]=\"{ width: '100%' }\" inputId=\"first-run-dbms\"></p-select>\r\n </div>\r\n\r\n @if (firstRunForm.setupMode === 'tutorial') {\r\n <div class=\"first-run-field first-run-checkbox-row\">\r\n <label>\r\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.createTutorialIfMissing\"\r\n (ngModelChange)=\"firstRunForm.createTutorialIfMissing = !!$event\" [disabled]=\"firstRunInstalling\" />\r\n {{ 'firstrun.ui.create_tutorial_if_missing' | translate }}\r\n </label>\r\n </div>\r\n }\r\n\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-datasql\">DataSQLConnection</label>\r\n <input id=\"first-run-datasql\" class=\"first-run-input\" type=\"text\"\r\n [ngModel]=\"firstRunForm.dataConnectionString\" (ngModelChange)=\"onFirstRunConnectionChanged($event)\"\r\n [disabled]=\"firstRunInstalling\"\r\n [placeholder]=\"'firstrun.ui.data_connection_placeholder' | translate\" />\r\n </div>\r\n\r\n <div class=\"first-run-field\">\r\n <p-button data-testid=\"first-run-test-connection\" [label]=\"'firstrun.ui.test_connection' | translate\" severity=\"secondary\" [outlined]=\"true\"\r\n [loading]=\"firstRunConnectionTesting\"\r\n [disabled]=\"firstRunInstalling || firstRunLoading || !firstRunForm.dataConnectionString\"\r\n (onClick)=\"testFirstRunConnectionAndLoadDatabases()\"></p-button>\r\n </div>\r\n\r\n @if (firstRunForm.setupMode === 'tutorial') {\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-datadb\">{{ 'firstrun.ui.tutorial_data_db' | translate }}</label>\r\n <input id=\"first-run-datadb\" class=\"first-run-input\" type=\"text\"\r\n [ngModel]=\"firstRunForm.tutorialDataDbName\"\r\n (ngModelChange)=\"firstRunForm.tutorialDataDbName = $event; firstRunForm.dataDbName = $event\"\r\n [disabled]=\"firstRunInstalling || !firstRunConnectionValid\"\r\n placeholder=\"WideWorldImporters\" />\r\n </div>\r\n } @else {\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-datadb\">{{ 'firstrun.ui.data_db' | translate }}</label>\r\n <p-select [options]=\"firstRunDataDbOptions\" optionLabel=\"label\" optionValue=\"value\"\r\n [ngModel]=\"firstRunForm.dataDbName\" (ngModelChange)=\"firstRunForm.dataDbName = $event\"\r\n [disabled]=\"firstRunInstalling || firstRunDbLoading || !firstRunConnectionValid\" [filter]=\"true\"\r\n [editable]=\"true\" [style]=\"{ width: '100%' }\" inputId=\"first-run-datadb\"\r\n [placeholder]=\"'firstrun.ui.data_db_placeholder' | translate\"></p-select>\r\n <div style=\"margin-top: 0.5rem;\">\r\n <p-button data-testid=\"first-run-refresh-dbs\" [label]=\"'firstrun.ui.refresh_db_list' | translate\" severity=\"secondary\" [outlined]=\"true\" size=\"small\"\r\n [loading]=\"firstRunDbLoading\" [disabled]=\"firstRunInstalling || !firstRunConnectionValid\"\r\n (onClick)=\"testFirstRunConnectionAndLoadDatabases()\"></p-button>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-metadb\">{{ (firstRunForm.setupMode === 'tutorial' ? 'firstrun.ui.tutorial_meta_db' : 'firstrun.ui.meta_db') | translate }}</label>\r\n <input id=\"first-run-metadb\" class=\"first-run-input\" type=\"text\"\r\n [ngModel]=\"firstRunForm.setupMode === 'tutorial' ? firstRunForm.tutorialMetadataDbName : firstRunForm.metadataDbName\"\r\n (ngModelChange)=\"firstRunForm.metadataDbName = $event; firstRunForm.tutorialMetadataDbName = $event\"\r\n [disabled]=\"firstRunInstalling\"\r\n placeholder=\"metadataDB\" />\r\n </div>\r\n\r\n @if (firstRunForm.setupMode !== 'tutorial') {\r\n <div class=\"first-run-field first-run-checkbox-row\">\r\n <label>\r\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.scaffoldExistingDatabase\"\r\n (ngModelChange)=\"firstRunForm.scaffoldExistingDatabase = !!$event\"\r\n [disabled]=\"firstRunInstalling\" />\r\n {{ 'firstrun.ui.scaffold_existing' | translate }}\r\n </label>\r\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\"\r\n [innerHTML]=\"'firstrun.ui.scaffold_existing_hint_html' | translate\"></small>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- \u2500\u2500 COLONNA DESTRA: Admin + RAG \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\r\n <div class=\"first-run-col\">\r\n\r\n <div class=\"first-run-section-title\">{{ 'firstrun.ui.admin_section' | translate }}</div>\r\n\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-admin-username\">{{ 'firstrun.ui.admin_username' | translate }}</label>\r\n <input id=\"first-run-admin-username\" class=\"first-run-input\" type=\"text\"\r\n [ngModel]=\"firstRunForm.adminUsername\"\r\n (ngModelChange)=\"firstRunForm.adminUsername = $event\"\r\n [disabled]=\"firstRunInstalling\" autocomplete=\"off\"\r\n placeholder=\"admin\" />\r\n </div>\r\n\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-admin-password\">{{ 'firstrun.ui.admin_password' | translate }}</label>\r\n <input id=\"first-run-admin-password\" class=\"first-run-input\" type=\"password\"\r\n [ngModel]=\"firstRunForm.adminPassword\"\r\n (ngModelChange)=\"firstRunForm.adminPassword = $event\"\r\n [disabled]=\"firstRunInstalling\" autocomplete=\"new-password\"\r\n [placeholder]=\"'firstrun.ui.admin_password_placeholder' | translate\" />\r\n </div>\r\n\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-admin-language\">{{ 'firstrun.ui.admin_language' | translate }}</label>\r\n <p-select [options]=\"firstRunAdminLanguageOptions\" optionLabel=\"label\" optionValue=\"value\"\r\n [ngModel]=\"firstRunForm.adminLanguage\"\r\n (ngModelChange)=\"onFirstRunAdminLanguageChanged($event)\"\r\n [disabled]=\"firstRunInstalling\"\r\n [style]=\"{ width: '100%' }\" inputId=\"first-run-admin-language\"></p-select>\r\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\">\r\n {{ 'firstrun.ui.admin_language_hint' | translate }}\r\n </small>\r\n </div>\r\n\r\n <div class=\"first-run-section-title first-run-section-title-rag\">{{ 'firstrun.ui.rag_section' | translate }}</div>\r\n\r\n <div class=\"first-run-field\">\r\n <small style=\"display:block; margin-bottom:8px; opacity:0.8; font-size:0.85rem; line-height:1.4;\"\r\n [innerHTML]=\"'firstrun.ui.rag_intro_html' | translate\"></small>\r\n <label for=\"first-run-anthropic-key\">\r\n {{ 'firstrun.ui.anthropic_key' | translate }}\r\n <i class=\"pi pi-info-circle first-run-info-icon\"\r\n [pTooltip]=\"'firstrun.rag.apiKeyTooltip' | translate\"\r\n tooltipPosition=\"right\"\r\n [tooltipStyleClass]=\"'first-run-tooltip'\"\r\n [escape]=\"false\"></i>\r\n </label>\r\n <textarea id=\"first-run-anthropic-key\" class=\"first-run-input first-run-textarea\"\r\n [ngModel]=\"firstRunForm.anthropicApiKey\"\r\n (ngModelChange)=\"firstRunForm.anthropicApiKey = $event\"\r\n [disabled]=\"firstRunInstalling\"\r\n rows=\"2\" autocomplete=\"off\"\r\n placeholder=\"sk-ant-...\"></textarea>\r\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\"\r\n [innerHTML]=\"'firstrun.ui.anthropic_key_hint_html' | translate\"></small>\r\n </div>\r\n </div>\r\n\r\n <!-- Crash reporting opt-in (skill crash-reporting Commit 8). Default OFF.\r\n Il consenso GDPR usa labels HARDCODED in `crashReportingLabels`\r\n dentro il componente (NON `wuic_translation`) perche' il\r\n first-run gira PRIMA che il DB metadati esista \u2014 niente DB,\r\n niente translation table. Vedi commento esteso nel componente.\r\n Al check del consenso si apre il popup col disclaimer\r\n dettagliato; l'utente conferma li' per attivare il flag. -->\r\n <div class=\"first-run-section-title first-run-section-title-crash-reporting\">{{ crashReportingLabels.title }}</div>\r\n <div class=\"first-run-field first-run-checkbox-row\">\r\n <label>\r\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.enableCrashReporting\"\r\n (ngModelChange)=\"onCrashReportingToggle($event)\"\r\n [disabled]=\"firstRunInstalling\" />\r\n {{ crashReportingLabels.checkbox_accept }}\r\n </label>\r\n <small style=\"display:block; margin-top:4px; opacity:0.85; font-size:0.85rem; line-height:1.45;\">\r\n {{ crashReportingLabels.intro_short }}\r\n <a href=\"javascript:void(0)\" (click)=\"openCrashReportingDisclaimer()\"\r\n style=\"margin-left:6px;\">{{ crashReportingLabels.read_full }}</a>\r\n </small>\r\n </div>\r\n </div>\r\n\r\n <!-- Disclaimer GDPR popup (apre al check + da link \"leggi tutto\"). -->\r\n <p-dialog [(visible)]=\"crashReportingDisclaimerVisible\"\r\n [modal]=\"true\"\r\n [closable]=\"true\"\r\n [closeOnEscape]=\"true\"\r\n [header]=\"crashReportingLabels.title\"\r\n [style]=\"{ width: '600px', maxWidth: '90vw' }\"\r\n [contentStyle]=\"{ 'max-height': '70vh', 'overflow-y': 'auto' }\"\r\n [appendTo]=\"'body'\">\r\n <div style=\"line-height:1.55;\">\r\n <p>{{ crashReportingLabels.intro }}</p>\r\n <p><strong>{{ crashReportingLabels.what_we_send }}</strong></p>\r\n <ul style=\"margin:0 0 8px 18px; padding:0;\">\r\n <li>{{ crashReportingLabels.what_we_dont_send }}</li>\r\n <li>{{ crashReportingLabels.where_it_goes }}</li>\r\n <li>{{ crashReportingLabels.retention }}</li>\r\n <li>{{ crashReportingLabels.legal_basis }}</li>\r\n <li>{{ crashReportingLabels.how_to_disable }}</li>\r\n </ul>\r\n </div>\r\n <ng-template pTemplate=\"footer\">\r\n <p-button [label]=\"crashReportingLabels.btn_decline\"\r\n severity=\"secondary\"\r\n (onClick)=\"declineCrashReporting()\"></p-button>\r\n <p-button [label]=\"crashReportingLabels.btn_accept\"\r\n (onClick)=\"acceptCrashReporting()\"></p-button>\r\n </ng-template>\r\n </p-dialog>\r\n\r\n </div><!-- /.first-run-body -->\r\n\r\n <!-- FOOTER sticky: error (se presente) + riga progress|CTA sempre visibile. -->\r\n <div class=\"first-run-footer\">\r\n @if (firstRunError && !firstRunErrorDismissed) {\r\n <div class=\"first-run-error\" role=\"alert\">\r\n <button type=\"button\"\r\n class=\"first-run-error__close\"\r\n (click)=\"dismissFirstRunError()\"\r\n [attr.aria-label]=\"'firstrun.ui.error_close_aria' | translate\"\r\n [title]=\"'firstrun.ui.error_close' | translate\">\u00D7</button>\r\n <div class=\"first-run-error__body\">{{ firstRunError }}</div>\r\n </div>\r\n }\r\n\r\n <div class=\"first-run-footer-row\">\r\n @if (firstRunInstalling && firstRunProgress.active) {\r\n <div class=\"first-run-progress\">\r\n <div class=\"first-run-progress-label\">\r\n <strong>{{ firstRunProgress.phase }}</strong>\r\n @if (firstRunProgress.total > 0 && !firstRunProgress.phase.includes('.restore')) {\r\n <span class=\"first-run-progress-count\">\r\n \u2014 {{ 'firstrun.ui.progress_batch' | translate }} {{ firstRunProgress.current }} / {{ firstRunProgress.total }}\r\n </span>\r\n }\r\n @if (firstRunProgress.elapsedMs > 0) {\r\n <span class=\"first-run-progress-count\">\r\n \u00B7 {{ (firstRunProgress.elapsedMs / 1000) | number:'1.0-0' }}s\r\n </span>\r\n }\r\n </div>\r\n @if (firstRunProgress.phase.includes('.restore') && firstRunProgress.percent < 5) {\r\n <p-progressBar mode=\"indeterminate\" [style]=\"{'height': '1rem'}\"></p-progressBar>\r\n } @else {\r\n <p-progressBar [value]=\"firstRunProgress.percent\" [showValue]=\"true\" [style]=\"{'height': '1rem'}\"></p-progressBar>\r\n }\r\n @if (firstRunProgress.message) {\r\n <div class=\"first-run-progress-message\">{{ firstRunProgress.message }}</div>\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"first-run-progress-placeholder\"></div>\r\n }\r\n\r\n <div class=\"first-run-actions\">\r\n <p-button data-testid=\"first-run-submit\" [label]=\"'firstrun.ui.submit' | translate\" [loading]=\"firstRunInstalling\"\r\n [disabled]=\"firstRunInstalling || firstRunLoading\" (onClick)=\"submitFirstRunInstall()\"></p-button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n}\r\n", styles: [".first-run-overlay{position:fixed;inset:0;z-index:900;display:flex;align-items:center;justify-content:center;padding:24px;background:linear-gradient(135deg,#081221d9,#16294acc)}.first-run-card-wide{width:min(1180px,100%)!important}.first-run-card{width:min(860px,100%);min-height:min(720px,100vh - 48px);max-height:calc(100vh - 48px);display:flex;flex-direction:column;overflow:hidden;border-radius:14px;padding:22px;background:var(--p-surface-0);box-shadow:0 18px 48px #00000059;border:1px solid var(--p-content-border-color)}.first-run-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding-right:4px;margin-right:-4px}.first-run-footer{flex:0 0 auto;margin-top:12px;padding-top:12px;border-top:1px solid var(--p-content-border-color);display:flex;flex-direction:column;gap:10px}.first-run-footer-row{display:flex;align-items:center;gap:16px}.first-run-title{font-size:1.25rem;font-weight:700}.first-run-subtitle{margin-top:6px;margin-bottom:18px;opacity:.8}.first-run-field{margin-bottom:14px}.first-run-field label{display:block;margin-bottom:6px;font-weight:600}.first-run-checkbox-row label{display:inline-flex;align-items:center;gap:.5rem;margin-bottom:0;font-weight:500}.first-run-input{width:100%;height:40px;border-radius:8px;border:1px solid var(--p-content-border-color);padding:8px 12px;font-size:.95rem;background:var(--p-surface-0);color:var(--p-text-color)}.first-run-textarea{height:auto;min-height:56px;resize:vertical;font-family:var(--p-font-family);line-height:1.4}.first-run-grid{display:grid;grid-template-columns:1fr 1fr;column-gap:28px;row-gap:0}@media(max-width:860px){.first-run-grid{grid-template-columns:1fr}}.first-run-col{display:flex;flex-direction:column;min-width:0}.first-run-section-title{margin-top:4px;margin-bottom:12px;padding-bottom:6px;font-size:.95rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;opacity:.8;border-bottom:1px solid var(--p-content-border-color)}.first-run-section-title-rag{margin-top:18px}.first-run-python-warning{margin-top:8px;padding:10px 12px;background:#fef3c7;border:1px solid #fcd34d;border-radius:6px;color:#78350f;font-size:.85rem;line-height:1.4}.first-run-python-warning strong{color:#78350f}.first-run-python-warning code{background:#00000014;padding:1px 4px;border-radius:3px;font-family:ui-monospace,Cascadia Code,Consolas,monospace;font-size:.82rem}.first-run-python-warning ol li+li{margin-top:4px}.first-run-python-warning-link{color:#92400e;text-decoration:underline;font-weight:600}.first-run-python-warning-link:hover{color:#78350f}.first-run-python-warning-link:visited{color:#92400e}.first-run-python-note{margin-top:8px;padding:10px 12px;background:#dbeafe;border:1px solid #93c5fd;border-radius:6px;color:#1e3a8a;font-size:.85rem;line-height:1.4}.first-run-python-note strong{color:#1e3a8a}.first-run-python-note code{background:#00000014;padding:1px 4px;border-radius:3px;font-family:ui-monospace,Cascadia Code,Consolas,monospace;font-size:.82rem}.first-run-info-icon{margin-left:6px;font-size:.95rem;color:var(--p-primary-color, #3b82f6);cursor:help;vertical-align:middle;opacity:.85}.first-run-info-icon:hover{opacity:1}::ng-deep .p-tooltip.first-run-tooltip{max-width:440px}::ng-deep .p-tooltip.first-run-tooltip .p-tooltip-text{white-space:pre-line;font-size:.85rem;line-height:1.45}.first-run-input:focus{outline:2px solid rgba(59,130,246,.25);border-color:#3b82f6}.first-run-error{position:relative;margin:8px 0 14px;color:#7f1d1d;background:#fee2e2;border:1px solid #fca5a5;border-radius:8px;padding:10px 36px 10px 12px}.first-run-error__body{max-height:200px;overflow-y:auto;word-break:break-word;white-space:pre-wrap;font-family:ui-monospace,Cascadia Code,Consolas,monospace;font-size:.85rem;line-height:1.4}.first-run-error__close{position:absolute;top:6px;right:8px;width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;padding:0;background:transparent;border:0;border-radius:4px;color:inherit;font-size:1.25rem;line-height:1;cursor:pointer;opacity:.75;transition:background-color .12s ease,opacity .12s ease}.first-run-error__close:hover,.first-run-error__close:focus-visible{opacity:1;background:#7f1d1d1f;outline:none}.first-run-error__close:active{background:#7f1d1d33}.first-run-actions{flex:0 0 auto;display:flex;justify-content:flex-end}.first-run-progress{flex:1 1 auto;min-width:0;padding:8px 12px;background:var(--p-surface-50);border:1px solid var(--p-content-border-color);border-radius:8px;display:flex;flex-direction:column;gap:4px}.first-run-progress-placeholder{flex:1 1 auto;min-width:0}.first-run-progress-label{font-size:.9rem}.first-run-progress-label strong{font-weight:600}.first-run-progress-label .first-run-progress-count{opacity:.7;margin-left:4px}.first-run-progress-message{font-size:.8rem;opacity:.75;font-family:ui-monospace,Cascadia Code,Consolas,monospace}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i4.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i5.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: ProgressBarModule }, { kind: "component", type: i6.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "unit", "mode", "color"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i7.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "pipe", type: i1$2.DecimalPipe, name: "number" }, { kind: "pipe", type: i8.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Eager });
|
|
1296
1612
|
}
|
|
1297
1613
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WuicFirstRunWizardComponent, decorators: [{
|
|
1298
1614
|
type: Component,
|
|
@@ -1305,10 +1621,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1305
1621
|
ProgressBarModule,
|
|
1306
1622
|
TooltipModule,
|
|
1307
1623
|
DialogModule
|
|
1308
|
-
], changeDetection: ChangeDetectionStrategy.Default, template: "@if (showFirstRunInstall) {\n<div class=\"first-run-overlay\">\n <div class=\"first-run-card first-run-card-wide\">\n <div class=\"first-run-title\">Configurazione iniziale progetto</div>\n <div class=\"first-run-subtitle\">Seleziona DBMS, connessione dati e nome database metadati.</div>\n\n <!-- BODY scrollabile: header (title/subtitle) e footer (progress + CTA)\n restano sempre visibili, solo questo blocco scrolla quando il form\n e' piu' alto della viewport. -->\n <div class=\"first-run-body\">\n\n <!-- Grid 2 colonne: sx = connessione + scaffold / dx = admin + RAG.\n Su viewport stretti (< 720px) il grid collassa a 1 colonna. -->\n <div class=\"first-run-grid\">\n\n <!-- \u2500\u2500 COLONNA SINISTRA: Database + Setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"first-run-col\">\n\n @if (firstRunSetupModeOptions.length > 1) {\n <div class=\"first-run-field\">\n <label for=\"first-run-mode\">Modalit\u00E0 setup</label>\n <p-select [options]=\"firstRunSetupModeOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"firstRunForm.setupMode\" (ngModelChange)=\"onFirstRunSetupModeChanged($event)\"\n [disabled]=\"firstRunInstalling\" [style]=\"{ width: '100%' }\" inputId=\"first-run-mode\"></p-select>\n </div>\n }\n\n <div class=\"first-run-field\">\n <label for=\"first-run-dbms\">DBMS</label>\n <p-select [options]=\"firstRunDbmsOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"firstRunForm.dbms\" (ngModelChange)=\"onFirstRunDbmsChanged($event)\"\n [disabled]=\"firstRunInstalling\" [style]=\"{ width: '100%' }\" inputId=\"first-run-dbms\"></p-select>\n </div>\n\n @if (firstRunForm.setupMode === 'tutorial') {\n <div class=\"first-run-field first-run-checkbox-row\">\n <label>\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.createTutorialIfMissing\"\n (ngModelChange)=\"firstRunForm.createTutorialIfMissing = !!$event\" [disabled]=\"firstRunInstalling\" />\n Crea tutorial se manca\n </label>\n </div>\n }\n\n <div class=\"first-run-field\">\n <label for=\"first-run-datasql\">DataSQLConnection</label>\n <input id=\"first-run-datasql\" class=\"first-run-input\" type=\"text\"\n [ngModel]=\"firstRunForm.dataConnectionString\" (ngModelChange)=\"onFirstRunConnectionChanged($event)\"\n [disabled]=\"firstRunInstalling\"\n placeholder=\"es. data source=localhost\\sqlexpress;User ID=sa;Password=...;initial catalog=WideWorldImporters\" />\n </div>\n\n <div class=\"first-run-field\">\n <p-button label=\"Test connessione e carica DB\" severity=\"secondary\" [outlined]=\"true\"\n [loading]=\"firstRunConnectionTesting\"\n [disabled]=\"firstRunInstalling || firstRunLoading || !firstRunForm.dataConnectionString\"\n (onClick)=\"testFirstRunConnectionAndLoadDatabases()\"></p-button>\n </div>\n\n @if (firstRunForm.setupMode === 'tutorial') {\n <div class=\"first-run-field\">\n <label for=\"first-run-datadb\">Database dati tutorial</label>\n <input id=\"first-run-datadb\" class=\"first-run-input\" type=\"text\"\n [ngModel]=\"firstRunForm.tutorialDataDbName\"\n (ngModelChange)=\"firstRunForm.tutorialDataDbName = $event; firstRunForm.dataDbName = $event\"\n [disabled]=\"firstRunInstalling || !firstRunConnectionValid\"\n placeholder=\"WideWorldImporters\" />\n </div>\n } @else {\n <div class=\"first-run-field\">\n <label for=\"first-run-datadb\">Database dati</label>\n <p-select [options]=\"firstRunDataDbOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"firstRunForm.dataDbName\" (ngModelChange)=\"firstRunForm.dataDbName = $event\"\n [disabled]=\"firstRunInstalling || firstRunDbLoading || !firstRunConnectionValid\" [filter]=\"true\"\n [editable]=\"true\" [style]=\"{ width: '100%' }\" inputId=\"first-run-datadb\"\n placeholder=\"Seleziona o digita database\"></p-select>\n <div style=\"margin-top: 0.5rem;\">\n <p-button label=\"Aggiorna elenco DB\" severity=\"secondary\" [outlined]=\"true\" size=\"small\"\n [loading]=\"firstRunDbLoading\" [disabled]=\"firstRunInstalling || !firstRunConnectionValid\"\n (onClick)=\"testFirstRunConnectionAndLoadDatabases()\"></p-button>\n </div>\n </div>\n }\n\n <div class=\"first-run-field\">\n <label for=\"first-run-metadb\">@if (firstRunForm.setupMode === 'tutorial') {Nome DB metadati tutorial} @else {Nome DB metadati}</label>\n <input id=\"first-run-metadb\" class=\"first-run-input\" type=\"text\"\n [ngModel]=\"firstRunForm.setupMode === 'tutorial' ? firstRunForm.tutorialMetadataDbName : firstRunForm.metadataDbName\"\n (ngModelChange)=\"firstRunForm.metadataDbName = $event; firstRunForm.tutorialMetadataDbName = $event\"\n [disabled]=\"firstRunInstalling\"\n placeholder=\"metadataDB\" />\n </div>\n\n @if (firstRunForm.setupMode !== 'tutorial') {\n <div class=\"first-run-field first-run-checkbox-row\">\n <label>\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.scaffoldExistingDatabase\"\n (ngModelChange)=\"firstRunForm.scaffoldExistingDatabase = !!$event\"\n [disabled]=\"firstRunInstalling\" />\n Esegui scaffold automatico delle tabelle del DB selezionato\n </label>\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\">\n Popola <code>_metadati__tabelle</code> / <code>_metadati__colonne</code> al termine dell'installazione.\n Operazione potenzialmente lunga su DB con molte tabelle.\n </small>\n </div>\n }\n </div>\n\n <!-- \u2500\u2500 COLONNA DESTRA: Admin + RAG \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"first-run-col\">\n\n <div class=\"first-run-section-title\">Utente admin iniziale</div>\n\n <div class=\"first-run-field\">\n <label for=\"first-run-admin-username\">Username admin iniziale</label>\n <input id=\"first-run-admin-username\" class=\"first-run-input\" type=\"text\"\n [ngModel]=\"firstRunForm.adminUsername\"\n (ngModelChange)=\"firstRunForm.adminUsername = $event\"\n [disabled]=\"firstRunInstalling\" autocomplete=\"off\"\n placeholder=\"admin\" />\n </div>\n\n <div class=\"first-run-field\">\n <label for=\"first-run-admin-password\">Password admin iniziale</label>\n <input id=\"first-run-admin-password\" class=\"first-run-input\" type=\"password\"\n [ngModel]=\"firstRunForm.adminPassword\"\n (ngModelChange)=\"firstRunForm.adminPassword = $event\"\n [disabled]=\"firstRunInstalling\" autocomplete=\"new-password\"\n placeholder=\"(min 4 caratteri)\" />\n </div>\n\n <div class=\"first-run-field\">\n <label for=\"first-run-admin-language\">Lingua admin iniziale</label>\n <p-select [options]=\"firstRunAdminLanguageOptions\" optionLabel=\"label\" optionValue=\"value\"\n [ngModel]=\"firstRunForm.adminLanguage\"\n (ngModelChange)=\"firstRunForm.adminLanguage = $event\"\n [disabled]=\"firstRunInstalling\"\n [style]=\"{ width: '100%' }\" inputId=\"first-run-admin-language\"></p-select>\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\">\n Lingua applicata all'utente admin dopo il primo login. Puoi cambiarla in seguito dal profilo utente.\n </small>\n </div>\n\n <div class=\"first-run-section-title first-run-section-title-rag\">RAG Chatbot (opzionale)</div>\n\n <div class=\"first-run-field\">\n <small style=\"display:block; margin-bottom:8px; opacity:0.8; font-size:0.85rem; line-height:1.4;\">\n Il RAG Chatbot \u00E8 gi\u00E0 incluso e funziona <strong>out-of-the-box</strong>: l'engine \u00E8 nativo\n <strong>.NET/ONNX</strong> (nessun Python, nessun server separato da installare). Al primo\n uso della chat scarica automaticamente i modelli (~2.3 GB) da <code>wuic-framework.com</code>.\n Con una GPU NVIDIA (CUDA 12.x + cuDNN 9.x) le risposte sono in ~1s; senza, fallback automatico\n su CPU. <strong>Nessun setup da fare qui.</strong>\n </small>\n <label for=\"first-run-anthropic-key\">\n Anthropic API Key (opzionale)\n <i class=\"pi pi-info-circle first-run-info-icon\"\n [pTooltip]=\"'firstrun.rag.apiKeyTooltip' | translate\"\n tooltipPosition=\"right\"\n [tooltipStyleClass]=\"'first-run-tooltip'\"\n [escape]=\"false\"></i>\n </label>\n <textarea id=\"first-run-anthropic-key\" class=\"first-run-input first-run-textarea\"\n [ngModel]=\"firstRunForm.anthropicApiKey\"\n (ngModelChange)=\"firstRunForm.anthropicApiKey = $event\"\n [disabled]=\"firstRunInstalling\"\n rows=\"2\" autocomplete=\"off\"\n placeholder=\"sk-ant-...\"></textarea>\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\">\n Senza chiave il chatbot funziona solo in modalit\u00E0 retrieval (ricerca snippet).\n Con chiave abilita la chat con LLM (Claude) e le azioni proposte sul designer.\n Viene salvata in <code>appsettings.json</code>; puoi cambiarla anche dopo.\n </small>\n </div>\n </div>\n\n <!-- Crash reporting opt-in (skill crash-reporting Commit 8). Default OFF.\n Il consenso GDPR usa labels HARDCODED in `crashReportingLabels`\n dentro il componente (NON `wuic_translation`) perche' il\n first-run gira PRIMA che il DB metadati esista \u2014 niente DB,\n niente translation table. Vedi commento esteso nel componente.\n Al check del consenso si apre il popup col disclaimer\n dettagliato; l'utente conferma li' per attivare il flag. -->\n <div class=\"first-run-section-title first-run-section-title-crash-reporting\">{{ crashReportingLabels.title }}</div>\n <div class=\"first-run-field first-run-checkbox-row\">\n <label>\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.enableCrashReporting\"\n (ngModelChange)=\"onCrashReportingToggle($event)\"\n [disabled]=\"firstRunInstalling\" />\n {{ crashReportingLabels.checkbox_accept }}\n </label>\n <small style=\"display:block; margin-top:4px; opacity:0.85; font-size:0.85rem; line-height:1.45;\">\n {{ crashReportingLabels.intro_short }}\n <a href=\"javascript:void(0)\" (click)=\"openCrashReportingDisclaimer()\"\n style=\"margin-left:6px;\">{{ crashReportingLabels.read_full }}</a>\n </small>\n </div>\n </div>\n\n <!-- Disclaimer GDPR popup (apre al check + da link \"leggi tutto\"). -->\n <p-dialog [(visible)]=\"crashReportingDisclaimerVisible\"\n [modal]=\"true\"\n [closable]=\"true\"\n [closeOnEscape]=\"true\"\n [header]=\"crashReportingLabels.title\"\n [style]=\"{ width: '600px', maxWidth: '90vw' }\"\n [contentStyle]=\"{ 'max-height': '70vh', 'overflow-y': 'auto' }\"\n [appendTo]=\"'body'\">\n <div style=\"line-height:1.55;\">\n <p>{{ crashReportingLabels.intro }}</p>\n <p><strong>{{ crashReportingLabels.what_we_send }}</strong></p>\n <ul style=\"margin:0 0 8px 18px; padding:0;\">\n <li>{{ crashReportingLabels.what_we_dont_send }}</li>\n <li>{{ crashReportingLabels.where_it_goes }}</li>\n <li>{{ crashReportingLabels.retention }}</li>\n <li>{{ crashReportingLabels.legal_basis }}</li>\n <li>{{ crashReportingLabels.how_to_disable }}</li>\n </ul>\n </div>\n <ng-template pTemplate=\"footer\">\n <p-button [label]=\"crashReportingLabels.btn_decline\"\n severity=\"secondary\"\n (onClick)=\"declineCrashReporting()\"></p-button>\n <p-button [label]=\"crashReportingLabels.btn_accept\"\n (onClick)=\"acceptCrashReporting()\"></p-button>\n </ng-template>\n </p-dialog>\n\n </div><!-- /.first-run-body -->\n\n <!-- FOOTER sticky: error (se presente) + riga progress|CTA sempre visibile. -->\n <div class=\"first-run-footer\">\n @if (firstRunError && !firstRunErrorDismissed) {\n <div class=\"first-run-error\" role=\"alert\">\n <button type=\"button\"\n class=\"first-run-error__close\"\n (click)=\"dismissFirstRunError()\"\n aria-label=\"Chiudi errore\"\n title=\"Chiudi\">\u00D7</button>\n <div class=\"first-run-error__body\">{{ firstRunError }}</div>\n </div>\n }\n\n <div class=\"first-run-footer-row\">\n @if (firstRunInstalling && firstRunProgress.active) {\n <div class=\"first-run-progress\">\n <div class=\"first-run-progress-label\">\n <strong>{{ firstRunProgress.phase }}</strong>\n @if (firstRunProgress.total > 0 && !firstRunProgress.phase.includes('.restore')) {\n <span class=\"first-run-progress-count\">\n \u2014 batch {{ firstRunProgress.current }} / {{ firstRunProgress.total }}\n </span>\n }\n @if (firstRunProgress.elapsedMs > 0) {\n <span class=\"first-run-progress-count\">\n \u00B7 {{ (firstRunProgress.elapsedMs / 1000) | number:'1.0-0' }}s\n </span>\n }\n </div>\n @if (firstRunProgress.phase.includes('.restore') && firstRunProgress.percent < 5) {\n <p-progressBar mode=\"indeterminate\" [style]=\"{'height': '1rem'}\"></p-progressBar>\n } @else {\n <p-progressBar [value]=\"firstRunProgress.percent\" [showValue]=\"true\" [style]=\"{'height': '1rem'}\"></p-progressBar>\n }\n @if (firstRunProgress.message) {\n <div class=\"first-run-progress-message\">{{ firstRunProgress.message }}</div>\n }\n </div>\n } @else {\n <div class=\"first-run-progress-placeholder\"></div>\n }\n\n <div class=\"first-run-actions\">\n <p-button label=\"Conferma e genera metadataDB\" [loading]=\"firstRunInstalling\"\n [disabled]=\"firstRunInstalling || firstRunLoading\" (onClick)=\"submitFirstRunInstall()\"></p-button>\n </div>\n </div>\n </div>\n </div>\n</div>\n}\n", styles: [".first-run-overlay{position:fixed;inset:0;z-index:900;display:flex;align-items:center;justify-content:center;padding:24px;background:linear-gradient(135deg,#081221d9,#16294acc)}.first-run-card-wide{width:min(1180px,100%)!important}.first-run-card{width:min(860px,100%);min-height:min(720px,100vh - 48px);max-height:calc(100vh - 48px);display:flex;flex-direction:column;overflow:hidden;border-radius:14px;padding:22px;background:var(--p-surface-0);box-shadow:0 18px 48px #00000059;border:1px solid var(--p-content-border-color)}.first-run-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding-right:4px;margin-right:-4px}.first-run-footer{flex:0 0 auto;margin-top:12px;padding-top:12px;border-top:1px solid var(--p-content-border-color);display:flex;flex-direction:column;gap:10px}.first-run-footer-row{display:flex;align-items:center;gap:16px}.first-run-title{font-size:1.25rem;font-weight:700}.first-run-subtitle{margin-top:6px;margin-bottom:18px;opacity:.8}.first-run-field{margin-bottom:14px}.first-run-field label{display:block;margin-bottom:6px;font-weight:600}.first-run-checkbox-row label{display:inline-flex;align-items:center;gap:.5rem;margin-bottom:0;font-weight:500}.first-run-input{width:100%;height:40px;border-radius:8px;border:1px solid var(--p-content-border-color);padding:8px 12px;font-size:.95rem;background:var(--p-surface-0);color:var(--p-text-color)}.first-run-textarea{height:auto;min-height:56px;resize:vertical;font-family:var(--p-font-family);line-height:1.4}.first-run-grid{display:grid;grid-template-columns:1fr 1fr;column-gap:28px;row-gap:0}@media(max-width:860px){.first-run-grid{grid-template-columns:1fr}}.first-run-col{display:flex;flex-direction:column;min-width:0}.first-run-section-title{margin-top:4px;margin-bottom:12px;padding-bottom:6px;font-size:.95rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;opacity:.8;border-bottom:1px solid var(--p-content-border-color)}.first-run-section-title-rag{margin-top:18px}.first-run-python-warning{margin-top:8px;padding:10px 12px;background:#fef3c7;border:1px solid #fcd34d;border-radius:6px;color:#78350f;font-size:.85rem;line-height:1.4}.first-run-python-warning strong{color:#78350f}.first-run-python-warning code{background:#00000014;padding:1px 4px;border-radius:3px;font-family:ui-monospace,Cascadia Code,Consolas,monospace;font-size:.82rem}.first-run-python-warning ol li+li{margin-top:4px}.first-run-python-warning-link{color:#92400e;text-decoration:underline;font-weight:600}.first-run-python-warning-link:hover{color:#78350f}.first-run-python-warning-link:visited{color:#92400e}.first-run-python-note{margin-top:8px;padding:10px 12px;background:#dbeafe;border:1px solid #93c5fd;border-radius:6px;color:#1e3a8a;font-size:.85rem;line-height:1.4}.first-run-python-note strong{color:#1e3a8a}.first-run-python-note code{background:#00000014;padding:1px 4px;border-radius:3px;font-family:ui-monospace,Cascadia Code,Consolas,monospace;font-size:.82rem}.first-run-info-icon{margin-left:6px;font-size:.95rem;color:var(--p-primary-color, #3b82f6);cursor:help;vertical-align:middle;opacity:.85}.first-run-info-icon:hover{opacity:1}::ng-deep .p-tooltip.first-run-tooltip{max-width:440px}::ng-deep .p-tooltip.first-run-tooltip .p-tooltip-text{white-space:pre-line;font-size:.85rem;line-height:1.45}.first-run-input:focus{outline:2px solid rgba(59,130,246,.25);border-color:#3b82f6}.first-run-error{position:relative;margin:8px 0 14px;color:#7f1d1d;background:#fee2e2;border:1px solid #fca5a5;border-radius:8px;padding:10px 36px 10px 12px}.first-run-error__body{max-height:200px;overflow-y:auto;word-break:break-word;white-space:pre-wrap;font-family:ui-monospace,Cascadia Code,Consolas,monospace;font-size:.85rem;line-height:1.4}.first-run-error__close{position:absolute;top:6px;right:8px;width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;padding:0;background:transparent;border:0;border-radius:4px;color:inherit;font-size:1.25rem;line-height:1;cursor:pointer;opacity:.75;transition:background-color .12s ease,opacity .12s ease}.first-run-error__close:hover,.first-run-error__close:focus-visible{opacity:1;background:#7f1d1d1f;outline:none}.first-run-error__close:active{background:#7f1d1d33}.first-run-actions{flex:0 0 auto;display:flex;justify-content:flex-end}.first-run-progress{flex:1 1 auto;min-width:0;padding:8px 12px;background:var(--p-surface-50);border:1px solid var(--p-content-border-color);border-radius:8px;display:flex;flex-direction:column;gap:4px}.first-run-progress-placeholder{flex:1 1 auto;min-width:0}.first-run-progress-label{font-size:.9rem}.first-run-progress-label strong{font-weight:600}.first-run-progress-label .first-run-progress-count{opacity:.7;margin-left:4px}.first-run-progress-message{font-size:.8rem;opacity:.75;font-family:ui-monospace,Cascadia Code,Consolas,monospace}\n"] }]
|
|
1624
|
+
], changeDetection: ChangeDetectionStrategy.Default, template: "@if (showFirstRunInstall) {\r\n<div class=\"first-run-overlay\">\r\n <div class=\"first-run-card first-run-card-wide\">\r\n <div class=\"first-run-title\">{{ 'firstrun.ui.title' | translate }}</div>\r\n <div class=\"first-run-subtitle\">{{ 'firstrun.ui.subtitle' | translate }}</div>\r\n\r\n <!-- BODY scrollabile: header (title/subtitle) e footer (progress + CTA)\r\n restano sempre visibili, solo questo blocco scrolla quando il form\r\n e' piu' alto della viewport. -->\r\n <div class=\"first-run-body\">\r\n\r\n <!-- Grid 2 colonne: sx = connessione + scaffold / dx = admin + RAG.\r\n Su viewport stretti (< 720px) il grid collassa a 1 colonna. -->\r\n <div class=\"first-run-grid\">\r\n\r\n <!-- \u2500\u2500 COLONNA SINISTRA: Database + Setup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\r\n <div class=\"first-run-col\">\r\n\r\n @if (firstRunSetupModeOptions.length > 1) {\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-mode\">{{ 'firstrun.ui.setup_mode' | translate }}</label>\r\n <p-select [options]=\"firstRunSetupModeOptions\" optionLabel=\"label\" optionValue=\"value\"\r\n [ngModel]=\"firstRunForm.setupMode\" (ngModelChange)=\"onFirstRunSetupModeChanged($event)\"\r\n [disabled]=\"firstRunInstalling\" [style]=\"{ width: '100%' }\" inputId=\"first-run-mode\"></p-select>\r\n </div>\r\n }\r\n\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-dbms\">DBMS</label>\r\n <p-select [options]=\"firstRunDbmsOptions\" optionLabel=\"label\" optionValue=\"value\"\r\n [ngModel]=\"firstRunForm.dbms\" (ngModelChange)=\"onFirstRunDbmsChanged($event)\"\r\n [disabled]=\"firstRunInstalling\" [style]=\"{ width: '100%' }\" inputId=\"first-run-dbms\"></p-select>\r\n </div>\r\n\r\n @if (firstRunForm.setupMode === 'tutorial') {\r\n <div class=\"first-run-field first-run-checkbox-row\">\r\n <label>\r\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.createTutorialIfMissing\"\r\n (ngModelChange)=\"firstRunForm.createTutorialIfMissing = !!$event\" [disabled]=\"firstRunInstalling\" />\r\n {{ 'firstrun.ui.create_tutorial_if_missing' | translate }}\r\n </label>\r\n </div>\r\n }\r\n\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-datasql\">DataSQLConnection</label>\r\n <input id=\"first-run-datasql\" class=\"first-run-input\" type=\"text\"\r\n [ngModel]=\"firstRunForm.dataConnectionString\" (ngModelChange)=\"onFirstRunConnectionChanged($event)\"\r\n [disabled]=\"firstRunInstalling\"\r\n [placeholder]=\"'firstrun.ui.data_connection_placeholder' | translate\" />\r\n </div>\r\n\r\n <div class=\"first-run-field\">\r\n <p-button data-testid=\"first-run-test-connection\" [label]=\"'firstrun.ui.test_connection' | translate\" severity=\"secondary\" [outlined]=\"true\"\r\n [loading]=\"firstRunConnectionTesting\"\r\n [disabled]=\"firstRunInstalling || firstRunLoading || !firstRunForm.dataConnectionString\"\r\n (onClick)=\"testFirstRunConnectionAndLoadDatabases()\"></p-button>\r\n </div>\r\n\r\n @if (firstRunForm.setupMode === 'tutorial') {\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-datadb\">{{ 'firstrun.ui.tutorial_data_db' | translate }}</label>\r\n <input id=\"first-run-datadb\" class=\"first-run-input\" type=\"text\"\r\n [ngModel]=\"firstRunForm.tutorialDataDbName\"\r\n (ngModelChange)=\"firstRunForm.tutorialDataDbName = $event; firstRunForm.dataDbName = $event\"\r\n [disabled]=\"firstRunInstalling || !firstRunConnectionValid\"\r\n placeholder=\"WideWorldImporters\" />\r\n </div>\r\n } @else {\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-datadb\">{{ 'firstrun.ui.data_db' | translate }}</label>\r\n <p-select [options]=\"firstRunDataDbOptions\" optionLabel=\"label\" optionValue=\"value\"\r\n [ngModel]=\"firstRunForm.dataDbName\" (ngModelChange)=\"firstRunForm.dataDbName = $event\"\r\n [disabled]=\"firstRunInstalling || firstRunDbLoading || !firstRunConnectionValid\" [filter]=\"true\"\r\n [editable]=\"true\" [style]=\"{ width: '100%' }\" inputId=\"first-run-datadb\"\r\n [placeholder]=\"'firstrun.ui.data_db_placeholder' | translate\"></p-select>\r\n <div style=\"margin-top: 0.5rem;\">\r\n <p-button data-testid=\"first-run-refresh-dbs\" [label]=\"'firstrun.ui.refresh_db_list' | translate\" severity=\"secondary\" [outlined]=\"true\" size=\"small\"\r\n [loading]=\"firstRunDbLoading\" [disabled]=\"firstRunInstalling || !firstRunConnectionValid\"\r\n (onClick)=\"testFirstRunConnectionAndLoadDatabases()\"></p-button>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-metadb\">{{ (firstRunForm.setupMode === 'tutorial' ? 'firstrun.ui.tutorial_meta_db' : 'firstrun.ui.meta_db') | translate }}</label>\r\n <input id=\"first-run-metadb\" class=\"first-run-input\" type=\"text\"\r\n [ngModel]=\"firstRunForm.setupMode === 'tutorial' ? firstRunForm.tutorialMetadataDbName : firstRunForm.metadataDbName\"\r\n (ngModelChange)=\"firstRunForm.metadataDbName = $event; firstRunForm.tutorialMetadataDbName = $event\"\r\n [disabled]=\"firstRunInstalling\"\r\n placeholder=\"metadataDB\" />\r\n </div>\r\n\r\n @if (firstRunForm.setupMode !== 'tutorial') {\r\n <div class=\"first-run-field first-run-checkbox-row\">\r\n <label>\r\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.scaffoldExistingDatabase\"\r\n (ngModelChange)=\"firstRunForm.scaffoldExistingDatabase = !!$event\"\r\n [disabled]=\"firstRunInstalling\" />\r\n {{ 'firstrun.ui.scaffold_existing' | translate }}\r\n </label>\r\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\"\r\n [innerHTML]=\"'firstrun.ui.scaffold_existing_hint_html' | translate\"></small>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- \u2500\u2500 COLONNA DESTRA: Admin + RAG \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\r\n <div class=\"first-run-col\">\r\n\r\n <div class=\"first-run-section-title\">{{ 'firstrun.ui.admin_section' | translate }}</div>\r\n\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-admin-username\">{{ 'firstrun.ui.admin_username' | translate }}</label>\r\n <input id=\"first-run-admin-username\" class=\"first-run-input\" type=\"text\"\r\n [ngModel]=\"firstRunForm.adminUsername\"\r\n (ngModelChange)=\"firstRunForm.adminUsername = $event\"\r\n [disabled]=\"firstRunInstalling\" autocomplete=\"off\"\r\n placeholder=\"admin\" />\r\n </div>\r\n\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-admin-password\">{{ 'firstrun.ui.admin_password' | translate }}</label>\r\n <input id=\"first-run-admin-password\" class=\"first-run-input\" type=\"password\"\r\n [ngModel]=\"firstRunForm.adminPassword\"\r\n (ngModelChange)=\"firstRunForm.adminPassword = $event\"\r\n [disabled]=\"firstRunInstalling\" autocomplete=\"new-password\"\r\n [placeholder]=\"'firstrun.ui.admin_password_placeholder' | translate\" />\r\n </div>\r\n\r\n <div class=\"first-run-field\">\r\n <label for=\"first-run-admin-language\">{{ 'firstrun.ui.admin_language' | translate }}</label>\r\n <p-select [options]=\"firstRunAdminLanguageOptions\" optionLabel=\"label\" optionValue=\"value\"\r\n [ngModel]=\"firstRunForm.adminLanguage\"\r\n (ngModelChange)=\"onFirstRunAdminLanguageChanged($event)\"\r\n [disabled]=\"firstRunInstalling\"\r\n [style]=\"{ width: '100%' }\" inputId=\"first-run-admin-language\"></p-select>\r\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\">\r\n {{ 'firstrun.ui.admin_language_hint' | translate }}\r\n </small>\r\n </div>\r\n\r\n <div class=\"first-run-section-title first-run-section-title-rag\">{{ 'firstrun.ui.rag_section' | translate }}</div>\r\n\r\n <div class=\"first-run-field\">\r\n <small style=\"display:block; margin-bottom:8px; opacity:0.8; font-size:0.85rem; line-height:1.4;\"\r\n [innerHTML]=\"'firstrun.ui.rag_intro_html' | translate\"></small>\r\n <label for=\"first-run-anthropic-key\">\r\n {{ 'firstrun.ui.anthropic_key' | translate }}\r\n <i class=\"pi pi-info-circle first-run-info-icon\"\r\n [pTooltip]=\"'firstrun.rag.apiKeyTooltip' | translate\"\r\n tooltipPosition=\"right\"\r\n [tooltipStyleClass]=\"'first-run-tooltip'\"\r\n [escape]=\"false\"></i>\r\n </label>\r\n <textarea id=\"first-run-anthropic-key\" class=\"first-run-input first-run-textarea\"\r\n [ngModel]=\"firstRunForm.anthropicApiKey\"\r\n (ngModelChange)=\"firstRunForm.anthropicApiKey = $event\"\r\n [disabled]=\"firstRunInstalling\"\r\n rows=\"2\" autocomplete=\"off\"\r\n placeholder=\"sk-ant-...\"></textarea>\r\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\"\r\n [innerHTML]=\"'firstrun.ui.anthropic_key_hint_html' | translate\"></small>\r\n </div>\r\n </div>\r\n\r\n <!-- Crash reporting opt-in (skill crash-reporting Commit 8). Default OFF.\r\n Il consenso GDPR usa labels HARDCODED in `crashReportingLabels`\r\n dentro il componente (NON `wuic_translation`) perche' il\r\n first-run gira PRIMA che il DB metadati esista \u2014 niente DB,\r\n niente translation table. Vedi commento esteso nel componente.\r\n Al check del consenso si apre il popup col disclaimer\r\n dettagliato; l'utente conferma li' per attivare il flag. -->\r\n <div class=\"first-run-section-title first-run-section-title-crash-reporting\">{{ crashReportingLabels.title }}</div>\r\n <div class=\"first-run-field first-run-checkbox-row\">\r\n <label>\r\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.enableCrashReporting\"\r\n (ngModelChange)=\"onCrashReportingToggle($event)\"\r\n [disabled]=\"firstRunInstalling\" />\r\n {{ crashReportingLabels.checkbox_accept }}\r\n </label>\r\n <small style=\"display:block; margin-top:4px; opacity:0.85; font-size:0.85rem; line-height:1.45;\">\r\n {{ crashReportingLabels.intro_short }}\r\n <a href=\"javascript:void(0)\" (click)=\"openCrashReportingDisclaimer()\"\r\n style=\"margin-left:6px;\">{{ crashReportingLabels.read_full }}</a>\r\n </small>\r\n </div>\r\n </div>\r\n\r\n <!-- Disclaimer GDPR popup (apre al check + da link \"leggi tutto\"). -->\r\n <p-dialog [(visible)]=\"crashReportingDisclaimerVisible\"\r\n [modal]=\"true\"\r\n [closable]=\"true\"\r\n [closeOnEscape]=\"true\"\r\n [header]=\"crashReportingLabels.title\"\r\n [style]=\"{ width: '600px', maxWidth: '90vw' }\"\r\n [contentStyle]=\"{ 'max-height': '70vh', 'overflow-y': 'auto' }\"\r\n [appendTo]=\"'body'\">\r\n <div style=\"line-height:1.55;\">\r\n <p>{{ crashReportingLabels.intro }}</p>\r\n <p><strong>{{ crashReportingLabels.what_we_send }}</strong></p>\r\n <ul style=\"margin:0 0 8px 18px; padding:0;\">\r\n <li>{{ crashReportingLabels.what_we_dont_send }}</li>\r\n <li>{{ crashReportingLabels.where_it_goes }}</li>\r\n <li>{{ crashReportingLabels.retention }}</li>\r\n <li>{{ crashReportingLabels.legal_basis }}</li>\r\n <li>{{ crashReportingLabels.how_to_disable }}</li>\r\n </ul>\r\n </div>\r\n <ng-template pTemplate=\"footer\">\r\n <p-button [label]=\"crashReportingLabels.btn_decline\"\r\n severity=\"secondary\"\r\n (onClick)=\"declineCrashReporting()\"></p-button>\r\n <p-button [label]=\"crashReportingLabels.btn_accept\"\r\n (onClick)=\"acceptCrashReporting()\"></p-button>\r\n </ng-template>\r\n </p-dialog>\r\n\r\n </div><!-- /.first-run-body -->\r\n\r\n <!-- FOOTER sticky: error (se presente) + riga progress|CTA sempre visibile. -->\r\n <div class=\"first-run-footer\">\r\n @if (firstRunError && !firstRunErrorDismissed) {\r\n <div class=\"first-run-error\" role=\"alert\">\r\n <button type=\"button\"\r\n class=\"first-run-error__close\"\r\n (click)=\"dismissFirstRunError()\"\r\n [attr.aria-label]=\"'firstrun.ui.error_close_aria' | translate\"\r\n [title]=\"'firstrun.ui.error_close' | translate\">\u00D7</button>\r\n <div class=\"first-run-error__body\">{{ firstRunError }}</div>\r\n </div>\r\n }\r\n\r\n <div class=\"first-run-footer-row\">\r\n @if (firstRunInstalling && firstRunProgress.active) {\r\n <div class=\"first-run-progress\">\r\n <div class=\"first-run-progress-label\">\r\n <strong>{{ firstRunProgress.phase }}</strong>\r\n @if (firstRunProgress.total > 0 && !firstRunProgress.phase.includes('.restore')) {\r\n <span class=\"first-run-progress-count\">\r\n \u2014 {{ 'firstrun.ui.progress_batch' | translate }} {{ firstRunProgress.current }} / {{ firstRunProgress.total }}\r\n </span>\r\n }\r\n @if (firstRunProgress.elapsedMs > 0) {\r\n <span class=\"first-run-progress-count\">\r\n \u00B7 {{ (firstRunProgress.elapsedMs / 1000) | number:'1.0-0' }}s\r\n </span>\r\n }\r\n </div>\r\n @if (firstRunProgress.phase.includes('.restore') && firstRunProgress.percent < 5) {\r\n <p-progressBar mode=\"indeterminate\" [style]=\"{'height': '1rem'}\"></p-progressBar>\r\n } @else {\r\n <p-progressBar [value]=\"firstRunProgress.percent\" [showValue]=\"true\" [style]=\"{'height': '1rem'}\"></p-progressBar>\r\n }\r\n @if (firstRunProgress.message) {\r\n <div class=\"first-run-progress-message\">{{ firstRunProgress.message }}</div>\r\n }\r\n </div>\r\n } @else {\r\n <div class=\"first-run-progress-placeholder\"></div>\r\n }\r\n\r\n <div class=\"first-run-actions\">\r\n <p-button data-testid=\"first-run-submit\" [label]=\"'firstrun.ui.submit' | translate\" [loading]=\"firstRunInstalling\"\r\n [disabled]=\"firstRunInstalling || firstRunLoading\" (onClick)=\"submitFirstRunInstall()\"></p-button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n}\r\n", styles: [".first-run-overlay{position:fixed;inset:0;z-index:900;display:flex;align-items:center;justify-content:center;padding:24px;background:linear-gradient(135deg,#081221d9,#16294acc)}.first-run-card-wide{width:min(1180px,100%)!important}.first-run-card{width:min(860px,100%);min-height:min(720px,100vh - 48px);max-height:calc(100vh - 48px);display:flex;flex-direction:column;overflow:hidden;border-radius:14px;padding:22px;background:var(--p-surface-0);box-shadow:0 18px 48px #00000059;border:1px solid var(--p-content-border-color)}.first-run-body{flex:1 1 auto;min-height:0;overflow-y:auto;padding-right:4px;margin-right:-4px}.first-run-footer{flex:0 0 auto;margin-top:12px;padding-top:12px;border-top:1px solid var(--p-content-border-color);display:flex;flex-direction:column;gap:10px}.first-run-footer-row{display:flex;align-items:center;gap:16px}.first-run-title{font-size:1.25rem;font-weight:700}.first-run-subtitle{margin-top:6px;margin-bottom:18px;opacity:.8}.first-run-field{margin-bottom:14px}.first-run-field label{display:block;margin-bottom:6px;font-weight:600}.first-run-checkbox-row label{display:inline-flex;align-items:center;gap:.5rem;margin-bottom:0;font-weight:500}.first-run-input{width:100%;height:40px;border-radius:8px;border:1px solid var(--p-content-border-color);padding:8px 12px;font-size:.95rem;background:var(--p-surface-0);color:var(--p-text-color)}.first-run-textarea{height:auto;min-height:56px;resize:vertical;font-family:var(--p-font-family);line-height:1.4}.first-run-grid{display:grid;grid-template-columns:1fr 1fr;column-gap:28px;row-gap:0}@media(max-width:860px){.first-run-grid{grid-template-columns:1fr}}.first-run-col{display:flex;flex-direction:column;min-width:0}.first-run-section-title{margin-top:4px;margin-bottom:12px;padding-bottom:6px;font-size:.95rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;opacity:.8;border-bottom:1px solid var(--p-content-border-color)}.first-run-section-title-rag{margin-top:18px}.first-run-python-warning{margin-top:8px;padding:10px 12px;background:#fef3c7;border:1px solid #fcd34d;border-radius:6px;color:#78350f;font-size:.85rem;line-height:1.4}.first-run-python-warning strong{color:#78350f}.first-run-python-warning code{background:#00000014;padding:1px 4px;border-radius:3px;font-family:ui-monospace,Cascadia Code,Consolas,monospace;font-size:.82rem}.first-run-python-warning ol li+li{margin-top:4px}.first-run-python-warning-link{color:#92400e;text-decoration:underline;font-weight:600}.first-run-python-warning-link:hover{color:#78350f}.first-run-python-warning-link:visited{color:#92400e}.first-run-python-note{margin-top:8px;padding:10px 12px;background:#dbeafe;border:1px solid #93c5fd;border-radius:6px;color:#1e3a8a;font-size:.85rem;line-height:1.4}.first-run-python-note strong{color:#1e3a8a}.first-run-python-note code{background:#00000014;padding:1px 4px;border-radius:3px;font-family:ui-monospace,Cascadia Code,Consolas,monospace;font-size:.82rem}.first-run-info-icon{margin-left:6px;font-size:.95rem;color:var(--p-primary-color, #3b82f6);cursor:help;vertical-align:middle;opacity:.85}.first-run-info-icon:hover{opacity:1}::ng-deep .p-tooltip.first-run-tooltip{max-width:440px}::ng-deep .p-tooltip.first-run-tooltip .p-tooltip-text{white-space:pre-line;font-size:.85rem;line-height:1.45}.first-run-input:focus{outline:2px solid rgba(59,130,246,.25);border-color:#3b82f6}.first-run-error{position:relative;margin:8px 0 14px;color:#7f1d1d;background:#fee2e2;border:1px solid #fca5a5;border-radius:8px;padding:10px 36px 10px 12px}.first-run-error__body{max-height:200px;overflow-y:auto;word-break:break-word;white-space:pre-wrap;font-family:ui-monospace,Cascadia Code,Consolas,monospace;font-size:.85rem;line-height:1.4}.first-run-error__close{position:absolute;top:6px;right:8px;width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;padding:0;background:transparent;border:0;border-radius:4px;color:inherit;font-size:1.25rem;line-height:1;cursor:pointer;opacity:.75;transition:background-color .12s ease,opacity .12s ease}.first-run-error__close:hover,.first-run-error__close:focus-visible{opacity:1;background:#7f1d1d1f;outline:none}.first-run-error__close:active{background:#7f1d1d33}.first-run-actions{flex:0 0 auto;display:flex;justify-content:flex-end}.first-run-progress{flex:1 1 auto;min-width:0;padding:8px 12px;background:var(--p-surface-50);border:1px solid var(--p-content-border-color);border-radius:8px;display:flex;flex-direction:column;gap:4px}.first-run-progress-placeholder{flex:1 1 auto;min-width:0}.first-run-progress-label{font-size:.9rem}.first-run-progress-label strong{font-weight:600}.first-run-progress-label .first-run-progress-count{opacity:.7;margin-left:4px}.first-run-progress-message{font-size:.8rem;opacity:.75;font-family:ui-monospace,Cascadia Code,Consolas,monospace}\n"] }]
|
|
1309
1625
|
}], ctorParameters: () => [{ type: i1.HttpClient }, { type: i8.TranslateService }, { type: i3.MessageService }, { type: i0.Injector }], propDecorators: { complete: [{
|
|
1310
1626
|
type: Output
|
|
1311
1627
|
}] } });
|
|
1312
1628
|
|
|
1313
1629
|
export { WuicFirstRunWizardComponent };
|
|
1314
|
-
//# sourceMappingURL=wuic-framework-lib-first-run-wizard.component-
|
|
1630
|
+
//# sourceMappingURL=wuic-framework-lib-first-run-wizard.component-C8nhy5yK.mjs.map
|