wuic-framework-lib 1.2.0 → 1.3.0
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-B1V8Q-Qq.mjs → wuic-framework-lib-chart-list.component-C02jeFGy.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-code-editor.component-4N95qt3D.mjs → wuic-framework-lib-code-editor.component-BZNLr0Jj.mjs} +59 -2
- package/fesm2022/{wuic-framework-lib-designer.component-pW1YK-oY.mjs → wuic-framework-lib-designer.component-N_CfbGnr.mjs} +986 -17
- package/fesm2022/{wuic-framework-lib-first-run-wizard.component-CaGePYLi.mjs → wuic-framework-lib-first-run-wizard.component-lW7-xMm3.mjs} +7 -61
- package/fesm2022/{wuic-framework-lib-framework-docs.component-m0IlS0Sl.mjs → wuic-framework-lib-framework-docs.component-CGQbmSkv.mjs} +3716 -347
- package/fesm2022/{wuic-framework-lib-pivot-builder.component-VIs0CIH_.mjs → wuic-framework-lib-pivot-builder.component-0gJz9RWr.mjs} +5 -5
- package/fesm2022/{wuic-framework-lib-prompt-dialog-fallback-host.component-Dm9GTZ07.mjs → wuic-framework-lib-prompt-dialog-fallback-host.component-C9LvmFsL.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-report-designer.component-FiAwNkPM.mjs → wuic-framework-lib-report-designer.component-DcpdzFjh.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-report-viewer.component-DY0dGMrt.mjs → wuic-framework-lib-report-viewer.component-BHpbGpp9.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-scheduler-list.component-3E5m-9Qd.mjs → wuic-framework-lib-scheduler-list.component-DHoukjf-.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-spreadsheet-list-sf.component-D9P9WbDl.mjs → wuic-framework-lib-spreadsheet-list-sf.component-VsaXepUC.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-workflow-designer.component-4RC2EkGA.mjs → wuic-framework-lib-workflow-designer.component-epj3oKq3.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-wuic-framework-lib-BSyGhpM1.mjs → wuic-framework-lib-wuic-framework-lib-Deudd4MY.mjs} +2186 -144
- package/fesm2022/wuic-framework-lib.mjs +1 -1
- package/package.json +1 -1
- package/types/wuic-framework-lib.d.ts +829 -11
|
@@ -17,7 +17,7 @@ import * as i6$1 from 'primeng/tooltip';
|
|
|
17
17
|
import { TooltipModule } from 'primeng/tooltip';
|
|
18
18
|
import * as i2 from 'primeng/dialog';
|
|
19
19
|
import { DialogModule } from 'primeng/dialog';
|
|
20
|
-
import { G as GlobalHandler,
|
|
20
|
+
import { G as GlobalHandler, W as WtoolboxService } from './wuic-framework-lib-wuic-framework-lib-Deudd4MY.mjs';
|
|
21
21
|
import * as i1 from '@angular/common/http';
|
|
22
22
|
import * as i3 from 'primeng/api';
|
|
23
23
|
|
|
@@ -25,7 +25,7 @@ import * as i3 from 'primeng/api';
|
|
|
25
25
|
* Componente standalone framework che incapsula l'INTERO workflow di firstRun:
|
|
26
26
|
*
|
|
27
27
|
* 1. probe `GET /api/Meta/FirstRunStatus` al boot per decidere visibilita';
|
|
28
|
-
* 2. rendering del form wizard (DBMS, connection string, admin, RAG
|
|
28
|
+
* 2. rendering del form wizard (DBMS, connection string, admin, RAG API key);
|
|
29
29
|
* 3. test connessione + caricamento elenco DB (`MetaService.get_database_names`);
|
|
30
30
|
* 4. submit `MetaService.configure_wuic` con tutti i parametri raccolti;
|
|
31
31
|
* 5. polling progress (`GET /api/Meta/FirstRunProgress`) durante l'install;
|
|
@@ -34,9 +34,7 @@ import * as i3 from 'primeng/api';
|
|
|
34
34
|
* 7. clear lato client (cookies + sessionStorage + localStorage + indexedDB)
|
|
35
35
|
* al termine dell'install e wait `waitForBackendReady` prima del redirect;
|
|
36
36
|
* 8. registrazione bundle traduzioni `firstrun.*` (5 lingue) PRIMA che il
|
|
37
|
-
* template risolva i pipe `| translate
|
|
38
|
-
* 9. hook post-login per `MetaService.resumeRagSetupIfPending` (consume del
|
|
39
|
-
* flag `logs/rag-setup-pending.json` settato dal wizard).
|
|
37
|
+
* template risolva i pipe `| translate`.
|
|
40
38
|
*
|
|
41
39
|
* **Auto-control**: il componente decide da se' se mostrarsi (firstRun=true) o
|
|
42
40
|
* essere invisibile (firstRun=false). Il consumer si limita a montarlo nel
|
|
@@ -47,8 +45,7 @@ import * as i3 from 'primeng/api';
|
|
|
47
45
|
* **Self-contained**: tutti gli helper (parseConnectionString, normalizeDbms,
|
|
48
46
|
* extractErrorMessage, ecc.) sono incapsulati qui dentro. Niente dipendenza
|
|
49
47
|
* dal consumer oltre ai servizi WUIC standard (HttpClient, TranslateService,
|
|
50
|
-
* WtoolboxService per promptDialog + appSettings
|
|
51
|
-
* l'aggancio post-login, UserInfoService per l'id utente del RAG resume).
|
|
48
|
+
* WtoolboxService per promptDialog + appSettings).
|
|
52
49
|
*/
|
|
53
50
|
class WuicFirstRunWizardComponent {
|
|
54
51
|
http;
|
|
@@ -108,9 +105,6 @@ class WuicFirstRunWizardComponent {
|
|
|
108
105
|
{ label: 'Tutorial WideWorldImporters', value: 'tutorial' }
|
|
109
106
|
];
|
|
110
107
|
firstRunTutorialAvailable = true;
|
|
111
|
-
firstRunPythonInstalled = true;
|
|
112
|
-
firstRunPythonSupported = true;
|
|
113
|
-
firstRunPythonVersion = '';
|
|
114
108
|
firstRunForm = {
|
|
115
109
|
setupMode: 'existing',
|
|
116
110
|
createTutorialIfMissing: true,
|
|
@@ -124,8 +118,6 @@ class WuicFirstRunWizardComponent {
|
|
|
124
118
|
adminPassword: '',
|
|
125
119
|
adminLanguage: WuicFirstRunWizardComponent.resolveDefaultAdminLanguage(),
|
|
126
120
|
scaffoldExistingDatabase: false,
|
|
127
|
-
installRag: false,
|
|
128
|
-
useCuda: false,
|
|
129
121
|
anthropicApiKey: '',
|
|
130
122
|
// Crash reporting opt-in (skill crash-reporting Commit 8). OFF by default
|
|
131
123
|
// per GDPR: l'utente lo abilita esplicitamente in fase di first-install
|
|
@@ -295,8 +287,6 @@ class WuicFirstRunWizardComponent {
|
|
|
295
287
|
error: null
|
|
296
288
|
};
|
|
297
289
|
firstRunProgressTimer = null;
|
|
298
|
-
authStateSubscription = null;
|
|
299
|
-
ragResumeChecked = false;
|
|
300
290
|
constructor(http, translate, messageService, injector) {
|
|
301
291
|
this.http = http;
|
|
302
292
|
this.translate = translate;
|
|
@@ -331,22 +321,11 @@ class WuicFirstRunWizardComponent {
|
|
|
331
321
|
return true;
|
|
332
322
|
}, { priority: 100 });
|
|
333
323
|
// Hook post-login per consumare `logs/rag-setup-pending.json`.
|
|
334
|
-
const authSession = this.injector.get(AuthSessionService, null);
|
|
335
|
-
if (authSession) {
|
|
336
|
-
this.authStateSubscription = authSession.state$.subscribe((state) => {
|
|
337
|
-
const isAuth = state?.authenticated === true || state?.legacyAuthenticated === true;
|
|
338
|
-
if (!this.ragResumeChecked && isAuth) {
|
|
339
|
-
this.ragResumeChecked = true;
|
|
340
|
-
this.triggerRagSetupResumeIfPending();
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
324
|
// Probe FirstRunStatus + bootstrap form.
|
|
345
325
|
void this.bootstrapFirstRun();
|
|
346
326
|
}
|
|
347
327
|
ngOnDestroy() {
|
|
348
328
|
this.stopFirstRunProgressPolling();
|
|
349
|
-
this.authStateSubscription?.unsubscribe();
|
|
350
329
|
this.metadataDbExistsDelegateDisposer?.();
|
|
351
330
|
}
|
|
352
331
|
/** Mostra il prompt di conferma drop+recreate del metadata DB e, se
|
|
@@ -454,16 +433,6 @@ class WuicFirstRunWizardComponent {
|
|
|
454
433
|
this.firstRunSetupModeOptions = [{ label: 'DB esistente', value: 'existing' }];
|
|
455
434
|
this.firstRunForm.setupMode = 'existing';
|
|
456
435
|
}
|
|
457
|
-
const pythonFlag = settings['pythonInstalled'] ?? settings['pythoninstalled'];
|
|
458
|
-
this.firstRunPythonInstalled = pythonFlag === undefined ? true : this.toBoolean(pythonFlag);
|
|
459
|
-
const pythonSupportedFlag = settings['pythonSupported'] ?? settings['pythonsupported'];
|
|
460
|
-
this.firstRunPythonSupported = pythonSupportedFlag === undefined
|
|
461
|
-
? this.firstRunPythonInstalled
|
|
462
|
-
: this.toBoolean(pythonSupportedFlag);
|
|
463
|
-
this.firstRunPythonVersion = String(settings['pythonVersion'] || settings['pythonversion'] || '').trim();
|
|
464
|
-
if (!this.firstRunPythonInstalled) {
|
|
465
|
-
this.firstRunForm.installRag = false;
|
|
466
|
-
}
|
|
467
436
|
if (!isFirstRun) {
|
|
468
437
|
this.showFirstRunInstall = false;
|
|
469
438
|
this.complete.emit();
|
|
@@ -764,8 +733,6 @@ class WuicFirstRunWizardComponent {
|
|
|
764
733
|
adminUsername,
|
|
765
734
|
adminPassword,
|
|
766
735
|
adminLanguage: this.firstRunForm.adminLanguage,
|
|
767
|
-
installRag: this.firstRunForm.installRag ? 'true' : 'false',
|
|
768
|
-
useCuda: this.firstRunForm.useCuda ? 'true' : 'false',
|
|
769
736
|
anthropicApiKey: (this.firstRunForm.anthropicApiKey || '').trim(),
|
|
770
737
|
// Crash reporting opt-in (skill crash-reporting Commit 8). Quando true,
|
|
771
738
|
// configure_wuic deve scrivere `CrashReporting.Enabled=true`,
|
|
@@ -906,27 +873,6 @@ class WuicFirstRunWizardComponent {
|
|
|
906
873
|
});
|
|
907
874
|
}
|
|
908
875
|
// ════════════════════════════════════════════════════════════════════════
|
|
909
|
-
// RAG RESUME (POST-LOGIN HOOK)
|
|
910
|
-
// ════════════════════════════════════════════════════════════════════════
|
|
911
|
-
triggerRagSetupResumeIfPending() {
|
|
912
|
-
try {
|
|
913
|
-
const userInfo = this.injector.get(UserInfoService, null);
|
|
914
|
-
const userId = Number(userInfo?.getuserInfo()?.user_id ?? 0);
|
|
915
|
-
if (!userId || userId <= 0) {
|
|
916
|
-
return;
|
|
917
|
-
}
|
|
918
|
-
const globalRoot = WtoolboxService.appSettings?.global_root_url || '';
|
|
919
|
-
const url = `${globalRoot}MetaService.resumeRagSetupIfPending`;
|
|
920
|
-
this.http.post(url, { userId }).subscribe({
|
|
921
|
-
next: (res) => { console.log('[rag-resume]', res); },
|
|
922
|
-
error: (err) => { console.warn('[rag-resume] skipped:', err?.message ?? err); }
|
|
923
|
-
});
|
|
924
|
-
}
|
|
925
|
-
catch {
|
|
926
|
-
/* best effort */
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
// ════════════════════════════════════════════════════════════════════════
|
|
930
876
|
// CONNECTION-STRING UTILITIES
|
|
931
877
|
// ════════════════════════════════════════════════════════════════════════
|
|
932
878
|
parseConnectionString(connectionString) {
|
|
@@ -1308,7 +1254,7 @@ class WuicFirstRunWizardComponent {
|
|
|
1308
1254
|
}
|
|
1309
1255
|
}
|
|
1310
1256
|
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 });
|
|
1311
|
-
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 first-run-checkbox-row\">\n <label>\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.installRag\"\n (ngModelChange)=\"firstRunForm.installRag = !!$event\"\n [disabled]=\"firstRunInstalling || !firstRunPythonInstalled\" />\n Installa e avvia il server RAG\n <i class=\"pi pi-info-circle first-run-info-icon\"\n [pTooltip]=\"'firstrun.rag.installTooltip' | translate\"\n tooltipPosition=\"right\"\n [tooltipStyleClass]=\"'first-run-tooltip'\"\n [escape]=\"false\"></i>\n </label>\n @if (firstRunPythonInstalled && firstRunPythonSupported) {\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\">\n Python {{ firstRunPythonVersion || '3.12' }} rilevato \u2713. Al primo login post-wizard, crea <code>.venv</code>,\n installa torch + transformers + FastAPI, avvia il server su <code>:8765</code>.\n Richiede ~5-10 min + ~200 MB di download (CPU).\n </small>\n } @else if (firstRunPythonInstalled && !firstRunPythonSupported) {\n <div class=\"first-run-python-note\">\n <strong>\u24D8 Python {{ firstRunPythonVersion }} rilevato \u2014 versione non testata</strong>\n <div style=\"margin-top:4px;\">\n WUIC \u00E8 pinnato a <strong>Python 3.12.x</strong> (wheels torch / transformers / LoRA pi\u00F9 stabili).\n Procedere con <code>{{ firstRunPythonVersion }}</code> pu\u00F2 funzionare ma non \u00E8 testato:\n se <code>pip install torch</code> fallisce con \"no matching distribution\", installa\n <a href=\"https://www.python.org/downloads/release/python-3120/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"first-run-python-warning-link\">Python 3.12</a>\n a fianco e metti la sua cartella prima di quella di {{ firstRunPythonVersion }} nel PATH.\n </div>\n </div>\n } @else {\n <div class=\"first-run-python-warning\">\n <strong>\u26A0 Python 3.12 non rilevato sul sistema</strong>\n <div style=\"margin-top:6px;\">\n Il setup RAG richiede Python 3.12. Lo zip di deploy include l'installer embeddable + uno script\n che fa tutto: estrae Python in <code>C:\\Python312</code>, installa pip, aggiorna PATH, riavvia IIS.\n </div>\n <ol style=\"margin:8px 0 4px 20px; padding:0;\">\n <li>\n Vai nella cartella dove hai estratto il deploy zip (dove c'\u00E8 <code>WuicCore.dll</code>).\n </li>\n <li>\n <strong>Right-click su <code>rag-setup.ps1</code> \u2192 \"Esegui come amministratore\"</strong>,\n oppure da pwsh-admin: <code>pwsh -ExecutionPolicy Bypass -File .\\rag-setup.ps1</code>.\n Lo script si auto-eleva via UAC se non gi\u00E0 elevato.\n </li>\n <li>\n Ricarica questa pagina (Ctrl+F5) \u2014 la checkbox si abilita automaticamente.\n </li>\n </ol>\n <div style=\"margin-top:4px; opacity:0.8;\">\n Lo script gestisce anche l'edge case GPO <code>DisableMSI</code> su Windows Server (usa il bundle\n embeddable zip, non MSI). Per il download manuale di Python da python.org:\n <a href=\"https://www.python.org/downloads/release/python-3120/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"first-run-python-warning-link\">\n python.org/downloads/release/python-3120/\n <i class=\"pi pi-external-link\" style=\"font-size:0.75rem; margin-left:3px;\"></i>\n </a>.\n Dettagli in <code>FIRST_STEPS.md</code> accanto al deploy. Il resto del setup (DB, admin user)\n pu\u00F2 procedere senza Python \u2014 installa il RAG dopo.\n </div>\n </div>\n }\n </div>\n\n @if (firstRunForm.installRag) {\n <div class=\"first-run-field first-run-checkbox-row\">\n <label>\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.useCuda\"\n (ngModelChange)=\"firstRunForm.useCuda = !!$event\"\n [disabled]=\"firstRunInstalling\" />\n Usa CUDA (GPU NVIDIA)\n <i class=\"pi pi-info-circle first-run-info-icon\"\n [pTooltip]=\"'firstrun.rag.cudaTooltip' | translate\"\n tooltipPosition=\"right\"\n [tooltipStyleClass]=\"'first-run-tooltip'\"\n [escape]=\"false\"></i>\n </label>\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\">\n Attiva torch GPU (CUDA 12.1, ~2.5 GB download) invece di CPU (~200 MB).\n Richiede una GPU NVIDIA + driver CUDA installati lato sistema.\n </small>\n </div>\n\n <div class=\"first-run-field\">\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 server RAG funziona solo in modalit\u00E0 retrieval (ricerca snippet).\n Con chiave abilita la chat LLM via Claude.\n </small>\n </div>\n }\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: i6.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: i11.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "unit", "mode", "color"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6$1.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 });
|
|
1257
|
+
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: i6.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: i11.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "unit", "mode", "color"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6$1.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 });
|
|
1312
1258
|
}
|
|
1313
1259
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: WuicFirstRunWizardComponent, decorators: [{
|
|
1314
1260
|
type: Component,
|
|
@@ -1321,10 +1267,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1321
1267
|
ProgressBarModule,
|
|
1322
1268
|
TooltipModule,
|
|
1323
1269
|
DialogModule
|
|
1324
|
-
], 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 first-run-checkbox-row\">\n <label>\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.installRag\"\n (ngModelChange)=\"firstRunForm.installRag = !!$event\"\n [disabled]=\"firstRunInstalling || !firstRunPythonInstalled\" />\n Installa e avvia il server RAG\n <i class=\"pi pi-info-circle first-run-info-icon\"\n [pTooltip]=\"'firstrun.rag.installTooltip' | translate\"\n tooltipPosition=\"right\"\n [tooltipStyleClass]=\"'first-run-tooltip'\"\n [escape]=\"false\"></i>\n </label>\n @if (firstRunPythonInstalled && firstRunPythonSupported) {\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\">\n Python {{ firstRunPythonVersion || '3.12' }} rilevato \u2713. Al primo login post-wizard, crea <code>.venv</code>,\n installa torch + transformers + FastAPI, avvia il server su <code>:8765</code>.\n Richiede ~5-10 min + ~200 MB di download (CPU).\n </small>\n } @else if (firstRunPythonInstalled && !firstRunPythonSupported) {\n <div class=\"first-run-python-note\">\n <strong>\u24D8 Python {{ firstRunPythonVersion }} rilevato \u2014 versione non testata</strong>\n <div style=\"margin-top:4px;\">\n WUIC \u00E8 pinnato a <strong>Python 3.12.x</strong> (wheels torch / transformers / LoRA pi\u00F9 stabili).\n Procedere con <code>{{ firstRunPythonVersion }}</code> pu\u00F2 funzionare ma non \u00E8 testato:\n se <code>pip install torch</code> fallisce con \"no matching distribution\", installa\n <a href=\"https://www.python.org/downloads/release/python-3120/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"first-run-python-warning-link\">Python 3.12</a>\n a fianco e metti la sua cartella prima di quella di {{ firstRunPythonVersion }} nel PATH.\n </div>\n </div>\n } @else {\n <div class=\"first-run-python-warning\">\n <strong>\u26A0 Python 3.12 non rilevato sul sistema</strong>\n <div style=\"margin-top:6px;\">\n Il setup RAG richiede Python 3.12. Lo zip di deploy include l'installer embeddable + uno script\n che fa tutto: estrae Python in <code>C:\\Python312</code>, installa pip, aggiorna PATH, riavvia IIS.\n </div>\n <ol style=\"margin:8px 0 4px 20px; padding:0;\">\n <li>\n Vai nella cartella dove hai estratto il deploy zip (dove c'\u00E8 <code>WuicCore.dll</code>).\n </li>\n <li>\n <strong>Right-click su <code>rag-setup.ps1</code> \u2192 \"Esegui come amministratore\"</strong>,\n oppure da pwsh-admin: <code>pwsh -ExecutionPolicy Bypass -File .\\rag-setup.ps1</code>.\n Lo script si auto-eleva via UAC se non gi\u00E0 elevato.\n </li>\n <li>\n Ricarica questa pagina (Ctrl+F5) \u2014 la checkbox si abilita automaticamente.\n </li>\n </ol>\n <div style=\"margin-top:4px; opacity:0.8;\">\n Lo script gestisce anche l'edge case GPO <code>DisableMSI</code> su Windows Server (usa il bundle\n embeddable zip, non MSI). Per il download manuale di Python da python.org:\n <a href=\"https://www.python.org/downloads/release/python-3120/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"first-run-python-warning-link\">\n python.org/downloads/release/python-3120/\n <i class=\"pi pi-external-link\" style=\"font-size:0.75rem; margin-left:3px;\"></i>\n </a>.\n Dettagli in <code>FIRST_STEPS.md</code> accanto al deploy. Il resto del setup (DB, admin user)\n pu\u00F2 procedere senza Python \u2014 installa il RAG dopo.\n </div>\n </div>\n }\n </div>\n\n @if (firstRunForm.installRag) {\n <div class=\"first-run-field first-run-checkbox-row\">\n <label>\n <input type=\"checkbox\" [ngModel]=\"firstRunForm.useCuda\"\n (ngModelChange)=\"firstRunForm.useCuda = !!$event\"\n [disabled]=\"firstRunInstalling\" />\n Usa CUDA (GPU NVIDIA)\n <i class=\"pi pi-info-circle first-run-info-icon\"\n [pTooltip]=\"'firstrun.rag.cudaTooltip' | translate\"\n tooltipPosition=\"right\"\n [tooltipStyleClass]=\"'first-run-tooltip'\"\n [escape]=\"false\"></i>\n </label>\n <small style=\"display:block; margin-top:4px; opacity:0.75; font-size:0.8rem; line-height:1.35;\">\n Attiva torch GPU (CUDA 12.1, ~2.5 GB download) invece di CPU (~200 MB).\n Richiede una GPU NVIDIA + driver CUDA installati lato sistema.\n </small>\n </div>\n\n <div class=\"first-run-field\">\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 server RAG funziona solo in modalit\u00E0 retrieval (ricerca snippet).\n Con chiave abilita la chat LLM via Claude.\n </small>\n </div>\n }\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"] }]
|
|
1270
|
+
], 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"] }]
|
|
1325
1271
|
}], ctorParameters: () => [{ type: i1.HttpClient }, { type: i8.TranslateService }, { type: i3.MessageService }, { type: i0.Injector }], propDecorators: { complete: [{
|
|
1326
1272
|
type: Output
|
|
1327
1273
|
}] } });
|
|
1328
1274
|
|
|
1329
1275
|
export { WuicFirstRunWizardComponent };
|
|
1330
|
-
//# sourceMappingURL=wuic-framework-lib-first-run-wizard.component-
|
|
1276
|
+
//# sourceMappingURL=wuic-framework-lib-first-run-wizard.component-lW7-xMm3.mjs.map
|