wuic-framework-lib 1.0.20 → 1.2.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.
Files changed (16) hide show
  1. package/fesm2022/{wuic-framework-lib-chart-list.component-B44k_wZe.mjs → wuic-framework-lib-chart-list.component-B1V8Q-Qq.mjs} +2 -2
  2. package/fesm2022/{wuic-framework-lib-code-editor.component-D1dy4Dl9.mjs → wuic-framework-lib-code-editor.component-4N95qt3D.mjs} +26 -5
  3. package/fesm2022/{wuic-framework-lib-designer.component-CnOQbvEH.mjs → wuic-framework-lib-designer.component-pW1YK-oY.mjs} +4 -4
  4. package/fesm2022/{wuic-framework-lib-first-run-wizard.component-C9lswoxG.mjs → wuic-framework-lib-first-run-wizard.component-CaGePYLi.mjs} +14 -4
  5. package/fesm2022/{wuic-framework-lib-framework-docs.component-B6qNTs5H.mjs → wuic-framework-lib-framework-docs.component-m0IlS0Sl.mjs} +406 -10
  6. package/fesm2022/{wuic-framework-lib-pivot-builder.component-DMk26H0M.mjs → wuic-framework-lib-pivot-builder.component-VIs0CIH_.mjs} +19 -16
  7. package/fesm2022/{wuic-framework-lib-prompt-dialog-fallback-host.component-y3shST6g.mjs → wuic-framework-lib-prompt-dialog-fallback-host.component-Dm9GTZ07.mjs} +3 -3
  8. package/fesm2022/{wuic-framework-lib-report-designer.component-BnngR2eL.mjs → wuic-framework-lib-report-designer.component-FiAwNkPM.mjs} +2 -2
  9. package/fesm2022/{wuic-framework-lib-report-viewer.component-LGNRIQh2.mjs → wuic-framework-lib-report-viewer.component-DY0dGMrt.mjs} +2 -2
  10. package/fesm2022/{wuic-framework-lib-scheduler-list.component-DbcFMwx5.mjs → wuic-framework-lib-scheduler-list.component-3E5m-9Qd.mjs} +31 -5
  11. package/fesm2022/{wuic-framework-lib-spreadsheet-list-sf.component-DXyRX0YK.mjs → wuic-framework-lib-spreadsheet-list-sf.component-D9P9WbDl.mjs} +483 -24
  12. package/fesm2022/{wuic-framework-lib-workflow-designer.component-Bm719AWV.mjs → wuic-framework-lib-workflow-designer.component-4RC2EkGA.mjs} +25 -5
  13. package/fesm2022/{wuic-framework-lib-wuic-framework-lib-CGCZvtKK.mjs → wuic-framework-lib-wuic-framework-lib-BSyGhpM1.mjs} +5082 -3802
  14. package/fesm2022/wuic-framework-lib.mjs +1 -1
  15. package/package.json +1 -1
  16. package/types/wuic-framework-lib.d.ts +1271 -646
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { ErrorHandler, Injector, OnInit, OnDestroy, ChangeDetectorRef, AfterViewInit, EventEmitter, ElementRef, NgZone, OnChanges, SimpleChanges, QueryList, ViewContainerRef, AfterViewChecked, DoCheck, TemplateRef, Type, NgModuleRef, PipeTransform } from '@angular/core';
2
+ import { ErrorHandler, Injector, OnInit, OnDestroy, ChangeDetectorRef, NgZone, AfterViewInit, EventEmitter, ElementRef, OnChanges, SimpleChanges, QueryList, AfterViewChecked, ViewContainerRef, DoCheck, TemplateRef, Type, NgModuleRef, PipeTransform } from '@angular/core';
3
3
  import * as rxjs from 'rxjs';
4
4
  import { BehaviorSubject, Subject, Observable } from 'rxjs';
5
5
  import { MenuItem, MessageService, ConfirmationService, Confirmation, TreeNode, MegaMenuItem } from 'primeng/api';
@@ -385,6 +385,29 @@ declare class UserInfo {
385
385
  lingua: Lingua;
386
386
  language?: string;
387
387
  optimisticCheckEnabled?: boolean;
388
+ /**
389
+ * Multi-tenant: id azienda attiva per la sessione corrente. Quando il
390
+ * server gira con `multiConnectionEnabled=true` e l'utente ha un
391
+ * `utenti.id_azienda` impostato (o e' un superadmin che ha selezionato
392
+ * un'azienda via `MetaService.switchAzienda`), questo campo riflette
393
+ * l'azienda. Valore `0` = "no tenant scope" (single-tenant mode oppure
394
+ * superadmin senza azienda selezionata).
395
+ *
396
+ * Usato dal client per:
397
+ * - costruire il nome del DB Dexie (`MetaDB__a${azienda_id}`,
398
+ * `WuicClientSideCrudDB__a${azienda_id}`);
399
+ * - suffissare le chiavi `localStorage` di metadata / settings utente;
400
+ * - decidere se mostrare il componente `<wuic-azienda-switcher>`
401
+ * (solo se `isSuperAdmin === true`).
402
+ */
403
+ azienda_id?: number;
404
+ /**
405
+ * Mirror del flag server `Cms.multiConnectionEnabled`. Se `true`, il
406
+ * client applica lo scoping per tenant (Dexie name, localStorage keys);
407
+ * se `false`/undefined, mantiene il comportamento single-tenant
408
+ * bit-identico al pre-rollout.
409
+ */
410
+ multiConnectionEnabled?: boolean;
388
411
  constructor(params: {
389
412
  user_id: number;
390
413
  user_name: string;
@@ -396,6 +419,8 @@ declare class UserInfo {
396
419
  lingua: Lingua;
397
420
  language?: string;
398
421
  optimisticCheckEnabled?: boolean;
422
+ azienda_id?: number;
423
+ multiConnectionEnabled?: boolean;
399
424
  });
400
425
  }
401
426
 
@@ -481,6 +506,24 @@ declare class UserInfoService {
481
506
  * @returns Profilo utente corrente.
482
507
  */
483
508
  getuserInfo(): UserInfo;
509
+ /**
510
+ * Multi-tenant: ritorna l'`id_azienda` attivo per la sessione corrente,
511
+ * oppure `0` se non c'e' tenant scope (single-tenant mode oppure
512
+ * superadmin senza azienda selezionata). Wrapper safe in tutti gli stati
513
+ * (no user logged in, multiConnectionEnabled=false, ecc).
514
+ */
515
+ getCurrentAziendaId(): number;
516
+ /**
517
+ * `true` SOLO se il server e' in modalita' multi-connection E l'utente
518
+ * corrente ha un tenant scope attivo (`azienda_id > 0`). Usato dal client
519
+ * per decidere il suffisso `__a{id}` su Dexie / localStorage.
520
+ */
521
+ isTenantScoped(): boolean;
522
+ /**
523
+ * Suffisso univoco per chiavi storage / nomi Dexie quando l'utente e'
524
+ * tenant-scoped. Stringa vuota altrimenti → backward compat dei naming.
525
+ */
526
+ getTenantSuffix(): string;
484
527
  /**
485
528
  * Read path: prefer sessionStorage (source of truth, works in both cookie
486
529
  * modes) and fall back to the JS-readable cookie when sessionStorage is
@@ -517,6 +560,24 @@ declare class TranslationManagerService {
517
560
  private backendRetryTimer?;
518
561
  private firstRunStatusChecked;
519
562
  private firstRunStatusValue;
563
+ /**
564
+ * Circuit breaker BE-offline: dopo {@link MAX_BACKEND_RETRIES} fallimenti
565
+ * consecutivi di `loadTranslations`, smettiamo di rischedulare il retry
566
+ * automatico. Con il vecchio loop a 1s, un BE offline generava ~60 chiamate
567
+ * fallite/min (vedi screenshot 2026-05-19: 318 errori console + ~190 XHR in
568
+ * pochi secondi). Ora dopo 5 fallimenti il timer si ferma e l'utente vede
569
+ * un banner globale "Backend offline" + bottone "Riprova" che chiama
570
+ * `retryBackendNow()` per resettare il circuito.
571
+ *
572
+ * Reset condizioni:
573
+ * - chiamata esplicita a `ensureTranslationsLoaded(true)` (forceReload);
574
+ * - chiamata esplicita a `retryBackendNow()` (bottone UI);
575
+ * - prima chiamata con successo (counter back to 0).
576
+ */
577
+ private static readonly MAX_BACKEND_RETRIES;
578
+ private consecutiveBackendFailures;
579
+ /** True quando MAX_BACKEND_RETRIES e' stato raggiunto → niente piu' retry automatici. */
580
+ backendCircuitOpen$: BehaviorSubject<boolean>;
520
581
  /**
521
582
  * Dedup set per i warning "Missing translation resource". Senza questo
522
583
  * Angular ChangeDetection invoca `instant(key)` ad ogni ciclo per ogni
@@ -620,6 +681,33 @@ declare class TranslationManagerService {
620
681
  * Legge/scrive dati persistenti su storage browser.
621
682
  */
622
683
  loadTranslations(): Promise<void>;
684
+ /**
685
+ * Reset esplicito del circuit breaker BE-offline + retry immediato.
686
+ * Da chiamare quando l'utente clicca "Riprova" sul banner offline, o
687
+ * quando un altro servizio rileva che il BE e' tornato online (es. ping
688
+ * health check, network 'online' event, ecc.). NON usare in retry loops
689
+ * automatici — il senso del breaker e' proprio fermarli.
690
+ */
691
+ retryBackendNow(): void;
692
+ /**
693
+ * Revalidate background: rifetcha la tabella traduzioni dal backend SENZA
694
+ * bloccare l'UI. Confronta size + contenuto (hash leggero su `id,resource,
695
+ * translation`) con la tabella attualmente in memoria; se differente,
696
+ * sostituisce + `syncNgxTranslate()` cosi' il translate pipe rivaluta
697
+ * automaticamente via evento `onTranslationChange`. Usato dal branch cache-
698
+ * hit di `ensureTranslationsLoaded` per propagare key aggiunte/modificate
699
+ * lato DB dopo la prima sessione (es. scaffolding di una route nuova che
700
+ * aggiunge `menu.x.y` in `_wuic_translations`).
701
+ *
702
+ * Best-effort: errori network NON propagano. L'UI ha gia' la cache come
703
+ * fallback funzionante, una revalidate fallita non e' peggio della cache.
704
+ */
705
+ private revalidateCacheInBackground;
706
+ /**
707
+ * Fingerprint deterministico di una tabella traduzioni. Usato per decidere
708
+ * se la cache differisce dal backend senza confronto byte-a-byte.
709
+ */
710
+ private computeTableFingerprint;
623
711
  /**
624
712
  * Controlla che la translationTable contenga le chiavi indispensabili per
625
713
  * renderizzare il form di login senza chiavi grezze visibili. Se anche una
@@ -1067,6 +1155,18 @@ declare class DataSourceComponent implements OnInit, OnDestroy {
1067
1155
  private aRoute;
1068
1156
  private userInfo;
1069
1157
  private static readonly liveInstances;
1158
+ /**
1159
+ * Riferimento al DOM host element. Iniettato via `inject()` (Angular 14+ functional
1160
+ * DI) invece che da costruttore per non rompere i call site manuali tipo
1161
+ * `new DataSourceComponent(metaSrv, dataSrv, ...)` in designer.component.ts
1162
+ * e metadata-editor.service.ts (che mantengono i 7 params posizionali storici).
1163
+ * `{ optional: true }` rende il field null fuori da un Angular DI context
1164
+ * (es. unit test che istanziano la classe a mano) — il consumo in ngOnInit
1165
+ * usa `?.nativeElement` per sopportare entrambi i path.
1166
+ * Scopo: esporre `this` su `host.__wuicCmp` per E2E introspection senza
1167
+ * dipendere da `window.ng.getComponent` (tree-shaken in prod build).
1168
+ */
1169
+ private elementRef;
1070
1170
  static getLiveInstances(): DataSourceComponent[];
1071
1171
  /**
1072
1172
  * Input dal componente padre per route; usata nella configurazione e nel rendering del componente.
@@ -2334,6 +2434,24 @@ declare class MetadatiTabella {
2334
2434
  md_inline_cell_editing: boolean;
2335
2435
  md_batch_save: boolean;
2336
2436
  md_props_bag: any;
2437
+ /**
2438
+ * Phase I.3 — Custom Attributes integration (W0.1 = A full parity).
2439
+ * Quando valorizzato (es. 'program', 'project', 'resource', 'scenario',
2440
+ * 'xbs_node'), il framework attiva il pattern "custom attributes runtime"
2441
+ * per questa route:
2442
+ * - `<wuic-parametric-dialog>` renderizza inline i CA della entity corrente
2443
+ * chiamando `CustomAttributesService.resolve(context, scope)`.
2444
+ * - `<wuic-list-grid>` accetta filter tokens `CA_<code>___value` e
2445
+ * `CS_<code>___order` per filtrare/ordinare per Custom Value.
2446
+ * - Save batch su entity invoca anche `CustomAttributesService.upsert()`
2447
+ * per gli eventuali CV editati.
2448
+ *
2449
+ * App-side: ogni app che vuole usare i CA deve avere le 5 tabelle
2450
+ * `core.custom_attribute*` (Phase I.1 schema) + endpoint
2451
+ * `/api/custom-attributes/*` (Phase I.2 controller). Backward-compat:
2452
+ * route che NON settano questo campo si comportano esattamente come prima.
2453
+ */
2454
+ custom_attribute_context: string;
2337
2455
  md_hide_select_all_check: boolean;
2338
2456
  md_multiple_radio_selection: boolean;
2339
2457
  md_persist_row_selection_accross_paging: boolean;
@@ -2759,6 +2877,33 @@ declare class MetadataProviderService {
2759
2877
  * @returns Istanza Dexie `MetaDB`.
2760
2878
  */
2761
2879
  static getMetaDB(): Promise<any>;
2880
+ /**
2881
+ * Calcola il nome del DB Dexie metadata tenant-scoped per l'utente
2882
+ * corrente. Read-only, statico, niente Angular DI: leggiamo direttamente
2883
+ * lo snapshot UserInfo da `sessionStorage` (chiave `k-user-memory`,
2884
+ * mirror-ata anche da UserInfoService).
2885
+ *
2886
+ * Regola: `MetaDB__a{azienda_id}` quando
2887
+ * `userInfo.multiConnectionEnabled === true` E `azienda_id > 0`. In tutti
2888
+ * gli altri casi (single-tenant, utente non loggato, superadmin senza
2889
+ * azienda selezionata) ritorna `MetaDB` — backward compat con installazioni
2890
+ * pre-multi-tenant.
2891
+ *
2892
+ * Inline helper qui dentro evita di importare `UserInfoService` (che ha
2893
+ * dipendenze su CookieService) in un metodo statico.
2894
+ */
2895
+ static resolveTenantDbName(baseName?: string): string;
2896
+ /**
2897
+ * Cleanup orfani di Dexie tenant-scoped. Drop di tutti i DB
2898
+ * `MetaDB__a*` e `WuicClientSideCrudDB__a*` il cui suffisso non
2899
+ * corrisponde all'azienda attiva. Da invocare all'avvio app (post-`me()`
2900
+ * hydration) per evitare accumulo di DB di tenant precedenti quando un
2901
+ * superadmin switcha frequentemente.
2902
+ *
2903
+ * No-op se `indexedDB.databases()` non e' supportato (Safari < 15) — in
2904
+ * quel caso i DB orfani restano ma non si rompe nulla.
2905
+ */
2906
+ static cleanupOrphanTenantDbs(currentAziendaId: number): Promise<void>;
2762
2907
  /**
2763
2908
  * Inizializza (o riusa) il database Dexie `MetaDB` con lo schema metadata richiesto dalla versione passata.
2764
2909
  * Configura tabelle/indici per colonne, tabelle, stili, autorizzazioni, condition group e custom actions.
@@ -2810,7 +2955,17 @@ declare class MetadataProviderService {
2810
2955
  */
2811
2956
  private isClientSideCrudModeEnabled;
2812
2957
  /**
2813
- * Costruisce la chiave cache menu utente (`menu_{userId}`) usata per persistenza localStorage.
2958
+ * Multi-tenant: suffisso tenant per la chiave locale corrente. Mirror di
2959
+ * `UserInfoService.getTenantSuffix()` ma legge sessionStorage direttamente
2960
+ * per evitare DI Angular in metodi statici / helper privati. Empty quando
2961
+ * il flag server `multiConnectionEnabled` e' off oppure non c'e' tenant
2962
+ * scope (`azienda_id = 0`) → backward compat keys originali.
2963
+ */
2964
+ private getTenantSuffix;
2965
+ /**
2966
+ * Costruisce la chiave cache menu utente. Tenant-scoped quando l'utente
2967
+ * e' su un tenant (`menu_{userId}__a{aziendaId}`), plain altrimenti
2968
+ * (`menu_{userId}`) per backward compat single-tenant.
2814
2969
  * @param userId Identificativo utente usato per contesto e persistenza.
2815
2970
  * @returns Chiave localStorage della cache menu.
2816
2971
  */
@@ -2901,7 +3056,7 @@ declare class MetadataProviderService {
2901
3056
  * @param col Metadato colonna da analizzare.
2902
3057
  * @returns Nome tipo TypeScript stimato (`string`, `number`, `boolean`, `Date`, `any`).
2903
3058
  */
2904
- static getTSTypeFromMetaColumn(col: MetadatiColonna): "string" | "any" | "boolean" | "number" | "Date";
3059
+ static getTSTypeFromMetaColumn(col: MetadatiColonna): "string" | "number" | "any" | "boolean" | "Date";
2905
3060
  /**
2906
3061
  * Normalizza e arricchisce i metadata colonna/tabella: ordina campi, inizializza callback dinamiche, parse di bag JSON
2907
3062
  * e garantisce fallback robusti per funzioni custom non compilabili.
@@ -3725,6 +3880,17 @@ declare class ClientSideCrudService {
3725
3880
  private db?;
3726
3881
  private dbInitPromise?;
3727
3882
  private readonly localModePrefix;
3883
+ /**
3884
+ * Multi-tenant: ritorna il nome Dexie tenant-scoped per l'utente corrente.
3885
+ * Mirror di `MetadataProviderService.resolveTenantDbName` per evitare un
3886
+ * import cross-service (questi due servizi non dovrebbero dipendere
3887
+ * l'uno dall'altro).
3888
+ *
3889
+ * `<baseName>__a{azienda_id}` quando `multiConnectionEnabled` e' attivo
3890
+ * e l'utente ha `azienda_id > 0`. Altrimenti `<baseName>` → backward
3891
+ * compat bit-identica.
3892
+ */
3893
+ static resolveTenantDbName(baseName: string): string;
3728
3894
  /**
3729
3895
  * Inizializza una sola volta il database Dexie locale (`WuicClientSideCrudDB`) e ne riusa l'istanza.
3730
3896
  * @returns Istanza DB locale usata per cache/sync CRUD client-side.
@@ -3782,6 +3948,12 @@ declare class ClientSideCrudService {
3782
3948
  * @param userId Identificativo utente usato per contesto e persistenza.
3783
3949
  * @returns Chiave storage del flag modalita locale.
3784
3950
  */
3951
+ /**
3952
+ * Suffisso tenant per la chiave locale (`__a{azienda_id}`) quando l'utente
3953
+ * e' su un tenant + server in modalita' multi-connection. Stringa vuota
3954
+ * altrimenti → backward compat single-tenant.
3955
+ */
3956
+ private getTenantSuffix;
3785
3957
  private getModeKey;
3786
3958
  /**
3787
3959
  * Attiva/disattiva il flag modalita CRUD locale per route+utente in localStorage.
@@ -5262,156 +5434,731 @@ declare class LazyDataSourceComponent implements OnInit {
5262
5434
  static ɵcmp: i0.ɵɵComponentDeclaration<LazyDataSourceComponent, "wuic-data-source-lazy", never, { "route": { "alias": "route"; "required": false; }; "routeFromRouting": { "alias": "routeFromRouting"; "required": false; }; "hardcodedRoute": { "alias": "hardcodedRoute"; "required": false; }; "autoload": { "alias": "autoload"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "changeTracking": { "alias": "changeTracking"; "required": false; }; "parentRecord": { "alias": "parentRecord"; "required": false; }; "parentMetaInfo": { "alias": "parentMetaInfo"; "required": false; }; "parentDatasource": { "alias": "parentDatasource"; "required": false; }; "componentRef": { "alias": "componentRef"; "required": false; }; }, {}, never, never, true, never>;
5263
5435
  }
5264
5436
 
5265
- declare class DeviceAwarenessService implements OnDestroy {
5266
- private static readonly DEFAULT_BREAKPOINT_PX;
5267
- private mediaQueryList?;
5268
- private mediaQueryListener?;
5269
- private readonly isMobileSubject;
5270
- readonly isMobile$: Observable<boolean>;
5271
- constructor();
5272
- get isMobile(): boolean;
5273
- ngOnDestroy(): void;
5274
- private resolveBreakpointPx;
5275
- static ɵfac: i0.ɵɵFactoryDeclaration<DeviceAwarenessService, never>;
5276
- static ɵprov: i0.ɵɵInjectableDeclaration<DeviceAwarenessService>;
5277
- }
5278
-
5279
- interface ListGridSavedState {
5280
- id: string;
5281
- name: string;
5282
- description: string;
5283
- isDefault: boolean;
5284
- createdAt: string;
5285
- filterInfo: any;
5286
- sortInfo: any[];
5287
- pageInfo: {
5288
- currentPage: number;
5289
- pageSize: number;
5290
- };
5291
- columnWidths: {
5292
- [field: string]: number;
5293
- };
5294
- columnLayout?: ListGridColumnLayout;
5295
- }
5296
- interface ListGridColumnLayout {
5297
- order: string[];
5298
- hidden: string[];
5299
- pinnedLeft: string[];
5300
- pinnedRight: string[];
5301
- }
5302
- interface ReportVariableInput {
5303
- name: string;
5304
- alias: string;
5305
- value: string;
5306
- type?: string;
5307
- }
5308
- interface GridPendingChangeItem {
5309
- id: string;
5310
- change: TrackedChange;
5311
- label: string;
5312
- details: string;
5313
- selected: boolean;
5314
- }
5315
- interface ListGridBeforeRowRenderEvent {
5316
- row: any;
5317
- rowIndex: number;
5318
- cancel: boolean;
5319
- cancelRender: () => void;
5320
- }
5321
- interface ListGridAfterRowRenderEvent {
5322
- row: any;
5323
- rowIndex: number;
5324
- }
5325
- interface ListGridAfterRenderEvent {
5326
- rows: any[];
5327
- totalRecords: number;
5328
- metaInfo: MetaInfo;
5329
- datasource?: DataSourceComponent;
5437
+ interface AuthSessionState {
5438
+ initialized: boolean;
5439
+ loading: boolean;
5440
+ enabled: boolean;
5441
+ authenticated: boolean;
5442
+ legacyAuthenticated: boolean;
5443
+ provider?: string;
5444
+ name?: string;
5445
+ legacyName?: string;
5446
+ legacyRole?: string;
5447
+ claims?: {
5448
+ type: string;
5449
+ value: string;
5450
+ }[];
5451
+ error?: string;
5452
+ returnUrl: string;
5453
+ sessionExpiring?: boolean;
5454
+ sessionExpiresInSeconds?: number;
5330
5455
  }
5331
- declare class ListGridComponent implements AfterViewInit, OnInit, OnDestroy, IDataBoundHostComponent {
5332
- private metaSrv;
5333
- private sanitizer;
5334
- private route;
5335
- private router;
5336
- private location;
5337
- private titleService;
5338
- private trslSrv;
5339
- private cd;
5340
- userInfo: UserInfoService;
5341
- private elementRef;
5342
- deviceAwareness: DeviceAwarenessService;
5343
- private static readonly FORCED_VIRTUALIZATION_PAGE_SIZE_THRESHOLD;
5344
- private static readonly FORCED_VIRTUALIZATION_ITEM_SIZE;
5345
- private static readonly ACTION_BUTTON_VISIBLE_ROWS_OVERSCAN;
5346
- private static readonly ACTION_BUTTON_INITIAL_VISIBLE_ROWS_FALLBACK;
5347
- private static readonly GRID_VIEW_STATES_SETTINGS_KEY;
5348
- private static readonly GRID_COLUMN_LAYOUT_SETTINGS_KEY;
5349
- private static selectButtonGuardInstalled;
5350
- private columnFilterRenderEpochByField;
5351
- private actionButtonsVisibleStartIndex;
5352
- private actionButtonsVisibleEndIndex;
5353
- private actionButtonsLimitToVisibleRows;
5354
- private actionButtonsPreLimitBeforeContainerReady;
5355
- private actionButtonsScrollContainer;
5356
- private actionButtonsScrollRafToken;
5357
- private actionButtonsScrollHandler;
5358
- private inlineCellSaveInFlightByRowKey;
5359
- private inlineCellSaveDebounceByRowKey;
5360
- private inlineCellLastChangedFieldByRowKey;
5361
- private inlineBatchOriginalByRowKey;
5362
- private inlineGridRuntimeFieldCacheByKey;
5363
- private suppressNextInlineFetchInfoRebind;
5364
- getRuntimeGridFieldMetaFn: (metaColumn: MetadatiColonna, rowData: any) => MetadatiColonna;
5365
- hardcodedRoute: string;
5366
- parentRecord: any;
5367
- parentMetaInfo: MetaInfo;
5368
- datasource: BehaviorSubject<DataSourceComponent>;
5369
- hardcodedDatasource: DataSourceComponent;
5370
- rowCustomSelect: (rowData: any, $event: any, dt: Table) => void;
5371
- hideToolbar: boolean;
5456
+ declare class AuthSessionService {
5457
+ private http;
5458
+ private userInfoService;
5459
+ private metadataProvider;
5460
+ private translationManager;
5461
+ private ngZone;
5462
+ private initialized;
5463
+ private sessionTimeoutMs;
5464
+ private sessionWarningMs;
5465
+ private sessionTimer;
5466
+ private sessionWarningTimer;
5467
+ private sessionCountdownTimer;
5468
+ private readonly stateSubject;
5469
+ readonly state$: rxjs.Observable<AuthSessionState>;
5470
+ get snapshot(): AuthSessionState;
5471
+ constructor(http: HttpClient, userInfoService: UserInfoService, metadataProvider: MetadataProviderService, translationManager: TranslationManagerService, ngZone: NgZone);
5372
5472
  /**
5373
- * Provider letto da `<wuic-import-export-button>` al click su Export XLS.
5374
- * Arrow function (NON metodo) per preservare il binding di `this` quando
5375
- * passata come Input — un metodo verrebbe richiamato col `this` del child.
5376
- * Ritorna lo stato filtri LIVE del datasource: include i filtri applicati
5377
- * via header/filter-bar che NON vengono propagati nella URL query string.
5473
+ * Allinea ngx-translate alla lingua dell'utente appena autenticato/hydratato.
5474
+ * Necessario perche' il TranslationManagerService bootstrap risolve la lingua
5475
+ * via `userInfoService.getuserInfo()` quando NESSUN utente e' ancora loggato,
5476
+ * finendo di default su `navigator.language` o 'it-IT'. Senza questa call
5477
+ * esplicita post-login, le traduzioni rese dal primo render (toolbar, menu,
5478
+ * dialog) restano "appiccicate" alla lingua di bootstrap finche' l'utente
5479
+ * non cambia lingua manualmente dal selettore, che invece chiama direttamente
5480
+ * `useLanguage()`. Chiamata best-effort: fallisce silenzioso se la lingua non
5481
+ * e' supportata o la tabella traduzioni non e' ancora pronta.
5378
5482
  */
5379
- getCurrentFilterInfoForExport: () => any;
5483
+ private applyUserLanguageToTranslations;
5380
5484
  /**
5381
- * Evento emesso subito prima del rendering logico della singola riga.
5382
- * Il consumer puo annullare la riga chiamando `cancelRender()`.
5485
+ * Inizializza il servizio una sola volta (o forzatamente) e carica lo stato sessione corrente via `refreshAll`.
5486
+ * @param force Se `true` forza una nuova inizializzazione anche se gia avvenuta.
5383
5487
  */
5384
- onBeforeRowRender: EventEmitter<ListGridBeforeRowRenderEvent>;
5488
+ initialize(force?: boolean): Promise<void>;
5385
5489
  /**
5386
- * Evento emesso subito dopo il rendering logico della singola riga.
5490
+ * Hydrates the UI-side user snapshot from the backend when sessionStorage
5491
+ * is empty but a server-managed HttpOnly `k-user` cookie might still be
5492
+ * valid. This is the critical step for `enableCookieAuthentication=true`:
5493
+ * after a browser restart (or new tab) sessionStorage is gone, the cookie
5494
+ * is HttpOnly and invisible to JS, so without this call the guard would
5495
+ * wrongly redirect to `/unauthorized` despite a valid session.
5496
+ *
5497
+ * Flow:
5498
+ * 1. If sessionStorage already has a snapshot → no hydration needed.
5499
+ * 2. Otherwise call `MetaService.me` with `withCredentials:true`. The
5500
+ * backend reads the HttpOnly cookie server-side and returns the
5501
+ * public user fields (and `cookieAuthEnabled` for introspection).
5502
+ * 3. If `me()` returns a populated payload, write it to sessionStorage
5503
+ * via `userInfoService.setUserInfoCookie` so subsequent calls see
5504
+ * the user. If `me()` returns an empty object `{}` (no valid
5505
+ * cookie) the hydration is a no-op and the UI stays logged out.
5506
+ *
5507
+ * Errors are swallowed on purpose: if `me()` throws (network, backend
5508
+ * down, legacy backend without the endpoint), we fall back to whatever
5509
+ * the cookie/sessionStorage already has without blocking the boot.
5387
5510
  */
5388
- onAfterRowRender: EventEmitter<ListGridAfterRowRenderEvent>;
5511
+ private hydrateFromServerCookie;
5389
5512
  /**
5390
- * Evento emesso al termine del ciclo di binding dati della griglia.
5513
+ * Ricalcola lo stato autenticazione combinando configurazione OAuth, endpoint `Auth/Enabled`, endpoint `Auth/Me`
5514
+ * e fallback sessione legacy (`k-user`), poi sincronizza eventuali custom settings utente.
5391
5515
  */
5392
- onAfterRender: EventEmitter<ListGridAfterRenderEvent>;
5516
+ refreshAll(): Promise<void>;
5393
5517
  /**
5394
- * Evento emesso su paging (evento p-table onPage).
5518
+ * Aggiorna il `returnUrl` nello stato sessione applicando normalizzazione anti-open-redirect.
5519
+ * @param returnUrl URL di ritorno post login/logout.
5395
5520
  */
5396
- onPaging: EventEmitter<any>;
5521
+ setReturnUrl(returnUrl: string): void;
5397
5522
  /**
5398
- * Evento emesso su sorting (evento p-table onSort).
5523
+ * Avvia il login OAuth reindirizzando il browser a `Auth/Login` con `returnUrl` codificato.
5524
+ * @param returnUrl URL di ritorno post login/logout.
5399
5525
  */
5400
- onSorting: EventEmitter<any>;
5526
+ login(returnUrl?: string): void;
5401
5527
  /**
5402
- * Evento emesso su filtering (evento p-table onFilter).
5528
+ * Esegue logout OAuth: pulisce prima stato client (storage + DB locali) e custom settings, poi redirect a `Auth/Logout`.
5529
+ * @param returnUrl URL di ritorno post login/logout.
5403
5530
  */
5404
- onFiltering: EventEmitter<any>;
5531
+ logout(returnUrl?: string): Promise<void>;
5405
5532
  /**
5406
- * Evento emesso dopo un refresh esplicito (click su bottone "Aggiorna"
5407
- * del toolbar o invocazione di `refresh()` da codice). Gli host in Pattern 3
5408
- * server-side possono usarlo per ri-fetchare dal loro backend custom.
5533
+ * Esegue login legacy via `MetaService.login`, interpreta le varianti payload storiche (`isLogged`, `value`, JSON string)
5534
+ * e in caso positivo salva l'utente nel cookie `k-user`.
5535
+ * @param username Username credenziale di autenticazione.
5536
+ * @param password Password credenziale di autenticazione.
5409
5537
  */
5410
- onRefresh: EventEmitter<void>;
5538
+ legacyLogin(username: string, password: string, captchaToken?: string): Promise<boolean>;
5411
5539
  /**
5412
- * Eventi p-table esposti lato host.
5413
- */
5414
- onPTableSelectionChange: EventEmitter<any>;
5540
+ * Logout flow that works in BOTH cookie modes:
5541
+ *
5542
+ * - **Server-managed mode** (`enableCookieAuthentication=true`): the
5543
+ * `k-user` cookie is HttpOnly, so the only way to delete it is via a
5544
+ * `Set-Cookie` delete header from the server. We call
5545
+ * `MetaService.logoutSession` (parameterless) which:
5546
+ * 1. derives the user from the cookie server-side,
5547
+ * 2. wipes the DB session token via the existing `logout(user)`
5548
+ * per-DBMS dispatcher,
5549
+ * 3. emits the `Set-Cookie` delete with matching CookieOptions.
5550
+ *
5551
+ * - **Legacy mode** (`enableCookieAuthentication=false`): we still call
5552
+ * `logoutSession` because the server-side helper is idempotent in
5553
+ * legacy mode and always wipes the DB token. The local
5554
+ * `userInfoService.clearUserInfo()` then deletes the JS-readable
5555
+ * cookie + sessionStorage snapshot.
5556
+ *
5557
+ * Why not call the legacy `MetaService.logout(user)` overload? It only
5558
+ * runs the per-DBMS DB cleanup; it does NOT emit the cookie delete
5559
+ * header, so the HttpOnly cookie would survive the logout in
5560
+ * server-managed mode and the next page load would re-hydrate the
5561
+ * supposedly-logged-out user via `MetaService.me`. The new
5562
+ * `logoutSession` does both atomically.
5563
+ */
5564
+ legacyLogout(): Promise<void>;
5565
+ /**
5566
+ * Multi-tenant: invoca `MetaService.switchAzienda` lato server per
5567
+ * cambiare l'azienda attiva della sessione corrente. Solo i superadmin
5568
+ * possono usarla — il server ritorna 401 altrimenti.
5569
+ *
5570
+ * Dopo lo switch e' OBBLIGATORIO un `window.location.reload()`:
5571
+ * - il cookie `k-user` e' stato riemesso con il nuovo `azienda_id`,
5572
+ * ma `UserInfoService` ha ancora in cache la vecchia copia;
5573
+ * - il singleton Dexie `MetaDB` punta al DB del tenant precedente,
5574
+ * `cleanupOrphanTenantDbs` lo droppa al boot successivo;
5575
+ * - tutte le pagine aperte vanno ricaricate per rifrescare menu /
5576
+ * metadata / cache locali con la tenant nuova.
5577
+ *
5578
+ * Convenzione: `idAzienda = 0` significa "torna al DB primario" (no
5579
+ * tenant scope) — utile a superadmin per amministrare il livello
5580
+ * primario senza loggare con un altro account.
5581
+ */
5582
+ switchAzienda(idAzienda: number): Promise<{
5583
+ ok: boolean;
5584
+ azienda_id: number;
5585
+ azienda_id_previous: number;
5586
+ } | null>;
5587
+ /**
5588
+ * Multi-tenant: legge la lista delle aziende disponibili dal server.
5589
+ * Usa l'endpoint AsmxProxy `MetaService.getCompaniesList` (legge da
5590
+ * tabella `aziende` sul DB metadati primario). Il server filtra alle
5591
+ * aziende con mapping di connessione valido (colonne
5592
+ * `Aziende.Connessione_DB_Dati` / `CONNESSIONE_DB_Meta` valorizzate)
5593
+ * quando il flag `multiConnectionEnabled` e' on.
5594
+ */
5595
+ getAvailableCompanies(): Promise<Array<{
5596
+ ID_Azienda: number;
5597
+ Nome_Azienda: string;
5598
+ }>>;
5599
+ /**
5600
+ * Pulisce lo stato runtime e le cache associate.
5601
+ * Gestisce anche persistenza locale su IndexedDB/Dexie quando prevista.
5602
+ * @returns Valore restituito dal metodo (Promise<void>).
5603
+ */
5604
+ private clearClientRuntimeState;
5605
+ /**
5606
+ * Pulisce lo stato runtime e le cache associate.
5607
+ * Legge/scrive dati persistenti su storage browser.
5608
+ */
5609
+ private clearBrowserStorage;
5610
+ /**
5611
+ * Rimuove i dati target aggiornando lo stato del servizio.
5612
+ * Gestisce anche persistenza locale su IndexedDB/Dexie quando prevista.
5613
+ * @param dbName Nome database locale/remote da trattare.
5614
+ * @returns Valore restituito dal metodo (Promise<void>).
5615
+ */
5616
+ private deleteDexieDatabase;
5617
+ /**
5618
+ * Rimuove i dati target aggiornando lo stato del servizio.
5619
+ * Gestisce anche persistenza locale su IndexedDB/Dexie quando prevista.
5620
+ * @param dbName Nome database locale/remote da trattare.
5621
+ * @returns Valore restituito dal metodo (Promise<void>).
5622
+ */
5623
+ private deleteIndexedDbByName;
5624
+ /**
5625
+ * Carica e cache-a i custom settings dell'utente loggato in localStorage allineando il bootstrap sessione con MetadataProvider.
5626
+ */
5627
+ private bootstrapUserCustomSettings;
5628
+ /**
5629
+ * Configura il timeout di sessione in minuti. Chiamato dal meta-menu dopo aver letto AuthConfig.
5630
+ */
5631
+ setSessionTimeout(minutes: number, warningMinutes?: number): void;
5632
+ private activityListenersAttached;
5633
+ /** Timestamp dell'ultimo reset throttled, in ms epoch. */
5634
+ private lastActivityResetAt;
5635
+ /** Min intervallo tra reset throttled (mousemove/scroll). 1s e' un buon compromesso
5636
+ * tra responsiveness al "vero" idle e overhead da event flood. */
5637
+ private static readonly ACTIVITY_RESET_THROTTLE_MS;
5638
+ private setupActivityListeners;
5639
+ /**
5640
+ * Avvia/riavvia i timer di sessione. Chiamato dopo login e ad ogni attività HTTP.
5641
+ */
5642
+ resetSessionTimer(): void;
5643
+ private startSessionExpiryCountdown;
5644
+ private handleSessionExpired;
5645
+ private clearSessionTimers;
5646
+ private isUserAuthenticated;
5647
+ /**
5648
+ * Applica un aggiornamento parziale allo stato `AuthSessionState` preservando le proprieta non toccate.
5649
+ * @param partial Delta stato da fondere con lo stato corrente.
5650
+ */
5651
+ /**
5652
+ * Sets a user-visible error message in the auth state.
5653
+ * Used by the auth-expired interceptor to communicate the logout
5654
+ * reason (e.g. "session replaced by another login") after the
5655
+ * logout flow has completed and the login form is visible.
5656
+ */
5657
+ setError(message: string): void;
5658
+ /** User-facing messages keyed by server reason code. */
5659
+ private static readonly REASON_MESSAGES;
5660
+ /**
5661
+ * Reads and removes the redirect reason left by the auth-expired
5662
+ * interceptor in localStorage, then sets the corresponding error
5663
+ * message in the auth state so the login form displays it.
5664
+ */
5665
+ private applyRedirectReason;
5666
+ private patchState;
5667
+ /**
5668
+ * Costruisce una struttura derivata a partire dallo stato corrente.
5669
+ * @param action Azione richiesta nel flusso corrente.
5670
+ */
5671
+ private buildEndpoint;
5672
+ /**
5673
+ * Costruisce una struttura derivata a partire dallo stato corrente.
5674
+ * @param fullMethodName Nome completo metodo legacy (es. `MetaService.login`).
5675
+ */
5676
+ private buildMetaAsmxEndpoint;
5677
+ /**
5678
+ * Risolve la base URL API usata dal servizio: preferisce `appSettings.api_url`, fallback su `${window.location.origin}/api/`.
5679
+ */
5680
+ private getApiBaseUrl;
5681
+ /**
5682
+ * Valuta una condizione booleana sullo stato o sull'input corrente.
5683
+ * @returns Valore restituito dal metodo (boolean).
5684
+ */
5685
+ private isOAuthEnabledInSettings;
5686
+ /**
5687
+ * Normalizza il payload in una forma coerente per i passaggi successivi.
5688
+ * @param returnUrl URL di ritorno post login/logout.
5689
+ */
5690
+ private normalizeReturnUrl;
5691
+ /**
5692
+ * Ritorna l'URL browser corrente usato come `returnUrl` predefinito in login/logout.
5693
+ */
5694
+ private getCurrentLocalUrl;
5695
+ /**
5696
+ * Esegue il parsing del valore in ingresso con fallback sicuro.
5697
+ * @param raw Payload legacy da interpretare (stringa JSON, oggetto o wrapper con `value`).
5698
+ * @returns Valore restituito dal metodo (any).
5699
+ */
5700
+ private parseLegacyLoginResponse;
5701
+ /**
5702
+ * Estrae un messaggio errore leggibile da payload legacy eterogenei (raw/parsing/error/value) del login storico.
5703
+ * @param raw Payload grezzo risposta/errore.
5704
+ * @param parsed Payload gia interpretato.
5705
+ * @returns Messaggio errore normalizzato oppure `null`.
5706
+ */
5707
+ private extractLegacyLoginError;
5708
+ /**
5709
+ * Prova a leggere un messaggio errore da stringhe plain/JSON o da oggetti con chiavi comuni (`message`, `error`, `ExceptionMessage`).
5710
+ * @param candidate Sorgente messaggio da analizzare.
5711
+ * @returns Messaggio trovato oppure `null`.
5712
+ */
5713
+ private readMessage;
5714
+ /**
5715
+ * Log diagnostico opzionale del flusso login legacy, attivo solo con `appSettings.debugLegacyLogin === true`.
5716
+ * @param kind Tipo evento (`response` o `error`).
5717
+ * @param payload Payload da tracciare in console.
5718
+ */
5719
+ private debugLegacyLogin;
5720
+ static ɵfac: i0.ɵɵFactoryDeclaration<AuthSessionService, never>;
5721
+ static ɵprov: i0.ɵɵInjectableDeclaration<AuthSessionService>;
5722
+ }
5723
+
5724
+ /**
5725
+ * Multi-tenant azienda switcher.
5726
+ *
5727
+ * Componente standalone visibile SOLO ai superadmin quando il server e' in
5728
+ * modalita' `multiConnectionEnabled`. Espone una dropdown con le aziende
5729
+ * disponibili (lette da `MetaService.getCompaniesList`, intersect con
5730
+ * mapping connection valido su Aziende) + un'opzione "Nessuna azienda" (id=0) che
5731
+ * fa tornare il superadmin al DB metadati primario (no tenant scope,
5732
+ * comportamento single-tenant).
5733
+ *
5734
+ * Lifecyle:
5735
+ * - alla creazione legge `UserInfoService` per determinare se mostrarsi;
5736
+ * - fetcha la lista aziende dal server una sola volta;
5737
+ * - su change → invoca `AuthSessionService.switchAzienda(id)` che riemette
5738
+ * il cookie e fa `window.location.reload()`.
5739
+ *
5740
+ * Drop-in usage (esempio in CrmApp / WuicTest topbar):
5741
+ * <code>&lt;wuic-azienda-switcher /&gt;</code>
5742
+ *
5743
+ * Performance:
5744
+ * - OnPush change detection;
5745
+ * - fetch one-shot al mount, niente polling;
5746
+ * - early return invisibile quando l'utente non e' superadmin → costo
5747
+ * trascurabile sulle shell che lo includono incondizionatamente.
5748
+ */
5749
+ declare class WuicAziendaSwitcherComponent implements OnInit {
5750
+ private userInfoService;
5751
+ private authSessionService;
5752
+ private cdr;
5753
+ /**
5754
+ * True se il componente deve renderizzare la dropdown. False per
5755
+ * (a) utenti non superadmin, (b) flag `multiConnectionEnabled=false`,
5756
+ * (c) sessione anonima. Calcolato una volta a `ngOnInit`.
5757
+ *
5758
+ * Quando `false`, l'**host element** stesso viene nascosto via
5759
+ * <see cref="hostHidden"/> HostBinding: niente margine, niente spazio
5760
+ * occupato. Cosi' chi embedda `<wuic-azienda-switcher />` in una topbar
5761
+ * non deve gestire la visibilita' del wrapper esternamente (regola DRY:
5762
+ * la condizione di mostrare/nascondere il widget e' una proprieta'
5763
+ * intrinseca del widget, non del consumer).
5764
+ */
5765
+ visible: boolean;
5766
+ /**
5767
+ * HostBinding: applica l'attributo HTML `hidden` sull'host quando il
5768
+ * widget non deve mostrarsi. `hidden` e' un attributo standard W3C che
5769
+ * imposta `display: none` di default → l'elemento collassa dal layout
5770
+ * (margini inclusi) e non e' nemmeno tab-navigable.
5771
+ *
5772
+ * Ritorno: stringa vuota (presente) o null (assente). Angular gestisce
5773
+ * la presenza/assenza dell'attributo in base al valore.
5774
+ */
5775
+ get hostHidden(): string | null;
5776
+ /**
5777
+ * Lista delle aziende disponibili. Sempre include `{ ID_Azienda: 0,
5778
+ * Nome_Azienda: 'Nessuna azienda (DB primario)' }` come prima opzione.
5779
+ * Ogni entry puo' avere `LogoFileName` (relativo a `/assets/azienda-logos/`)
5780
+ * — quando null/missing il client fa fallback alle iniziali del nome.
5781
+ */
5782
+ companies: Array<{
5783
+ ID_Azienda: number;
5784
+ Nome_Azienda: string;
5785
+ LogoFileName?: string | null;
5786
+ }>;
5787
+ /**
5788
+ * Base path per le immagini logo aziendali. `/assets/azienda-logos/` =
5789
+ * servito staticamente da ASP.NET Core (`wwwroot/assets/azienda-logos/`).
5790
+ */
5791
+ private static readonly LOGO_BASE;
5792
+ /**
5793
+ * ID dell'azienda attualmente selezionata. Bind two-way con la dropdown
5794
+ * PrimeNG. Inizializzato dall'`UserInfo.azienda_id` cached.
5795
+ */
5796
+ selectedAziendaId: number;
5797
+ /**
5798
+ * True mentre la chiamata HTTP `switchAzienda` e' in volo. Previene click
5799
+ * doppi che scatenerebbero due reload.
5800
+ */
5801
+ switching: boolean;
5802
+ /**
5803
+ * Eventuale messaggio di errore da mostrare sotto la dropdown. Reset al
5804
+ * prossimo tentativo.
5805
+ */
5806
+ errorMessage: string | null;
5807
+ /**
5808
+ * Label leggibile dell'azienda attiva nella sessione corrente. Mostrato
5809
+ * come tooltip al hover sul widget icon-only. Aggiornato al boot e ad
5810
+ * ogni `onAziendaChange`.
5811
+ */
5812
+ currentLabel: string;
5813
+ /**
5814
+ * URL del logo dell'azienda attiva, oppure null per fallback icona.
5815
+ */
5816
+ currentLogoUrl: string | null;
5817
+ constructor(userInfoService: UserInfoService, authSessionService: AuthSessionService, cdr: ChangeDetectorRef);
5818
+ ngOnInit(): Promise<void>;
5819
+ /**
5820
+ * Aggiorna `currentLabel`, `currentLogoUrl` dal `selectedAziendaId`
5821
+ * corrente. Chiamato dopo fetch lista e dopo cambio selezione. Quando
5822
+ * `selectedAziendaId` non corrisponde a nessuna azienda (tipicamente 0
5823
+ * = mai assegnato), tooltip + display mostrano "Seleziona azienda…".
5824
+ */
5825
+ private refreshCurrentLabel;
5826
+ /**
5827
+ * True se non c'e' un'azienda selezionata valida (selectedAziendaId=0
5828
+ * o id non presente nella lista). Usato dal template per swap
5829
+ * icona/placeholder.
5830
+ */
5831
+ get noSelection(): boolean;
5832
+ /**
5833
+ * Costruisce l'URL dell'immagine logo per l'azienda passata, o null se
5834
+ * non c'e' `LogoFileName`. URL e' assoluto relativo al root del frontend
5835
+ * (`/assets/azienda-logos/<file>`) — il dev server Angular proxa lo
5836
+ * stesso path da `wwwroot/assets/azienda-logos/` in prod.
5837
+ */
5838
+ logoUrlFor(c: {
5839
+ LogoFileName?: string | null;
5840
+ } | undefined | null): string | null;
5841
+ /**
5842
+ * Classe icona PrimeIcons di fallback quando l'azienda non ha `LogoFileName`
5843
+ * (o il file non si carica). Per le aziende reali sempre `pi-building`.
5844
+ * Per `id=0` (mai assegnato / lista vuota) `pi-question` come hint che
5845
+ * l'utente DEVE selezionare un'azienda.
5846
+ */
5847
+ defaultIconClassFor(idAzienda: number | undefined | null): string;
5848
+ /**
5849
+ * onerror handler dell'<img> nel selectedItem template. Se il logo
5850
+ * fallisce a caricarsi (404 o broken), ricadiamo sull'icona predefinita.
5851
+ */
5852
+ onLogoError(): void;
5853
+ /**
5854
+ * Handler del change PrimeNG. Filtra no-op (stesso valore) per evitare
5855
+ * reload infiniti se PrimeNG emette change al mount.
5856
+ */
5857
+ onAziendaChange(event: {
5858
+ value: number;
5859
+ }): Promise<void>;
5860
+ static ɵfac: i0.ɵɵFactoryDeclaration<WuicAziendaSwitcherComponent, never>;
5861
+ static ɵcmp: i0.ɵɵComponentDeclaration<WuicAziendaSwitcherComponent, "wuic-azienda-switcher", never, {}, {}, never, never, true, never>;
5862
+ }
5863
+
5864
+ /**
5865
+ * Phase I.3 — CustomAttributesService (framework, additive feature flag).
5866
+ *
5867
+ * Service centralizzato per leggere/scrivere Custom Attributes/Values/Lookup
5868
+ * per una entity in una route. Attivato per route con
5869
+ * `MetadatiTabella.custom_attribute_context` valorizzato.
5870
+ *
5871
+ * Backend contract (app-level, es. CostCnh `CustomAttributesController.cs`):
5872
+ * GET /api/custom-attributes/definitions?context=program
5873
+ * GET /api/custom-attributes/resolve?context=program&siteId=N&projectClassId=M
5874
+ * GET /api/custom-attributes/values?entitySchema=core&entityName=program&entityId=42
5875
+ * POST /api/custom-attributes/values (upsert batch)
5876
+ * DELETE /api/custom-attributes/values/{cvId}
5877
+ * GET /api/custom-attributes/lookup/{attributeId}
5878
+ * POST /api/custom-attributes/lookup (upsert option)
5879
+ *
5880
+ * App-side: per usare questo service, l'app deve esporre i 7 endpoint sopra.
5881
+ * Vedi `CostCnh.Controllers.CustomAttributesController` come reference impl.
5882
+ */
5883
+ interface CustomAttributeDefinition {
5884
+ id: number;
5885
+ context: string;
5886
+ code: string;
5887
+ display_name: string;
5888
+ description?: string;
5889
+ value_type: 'text' | 'number' | 'date' | 'bool' | 'lookup' | 'currency' | 'structure';
5890
+ allow_multiple: boolean;
5891
+ has_lookup: boolean;
5892
+ is_required: boolean;
5893
+ is_readonly: boolean;
5894
+ edit_order: number;
5895
+ is_time_based: boolean;
5896
+ mode: number;
5897
+ external_system?: string;
5898
+ external_code?: string;
5899
+ }
5900
+ interface CustomAttributeResolved extends CustomAttributeDefinition {
5901
+ attribute_id: number;
5902
+ mapping_id?: number;
5903
+ label_loc?: string;
5904
+ year_from?: number;
5905
+ year_to?: number;
5906
+ is_visible: boolean;
5907
+ effective_order: number;
5908
+ }
5909
+ interface CustomValue {
5910
+ cv_id: number;
5911
+ attribute_id: number;
5912
+ attribute_code: string;
5913
+ attribute_label: string;
5914
+ value_type: string;
5915
+ has_lookup: boolean;
5916
+ allow_multiple: boolean;
5917
+ value_text?: string | null;
5918
+ value_number?: number | null;
5919
+ value_date?: string | null;
5920
+ value_bool?: boolean | null;
5921
+ custom_lookup_id?: number | null;
5922
+ lookup_code?: string | null;
5923
+ lookup_value?: string | null;
5924
+ lookup_descr?: string | null;
5925
+ year_num?: number | null;
5926
+ ref_object_id?: string | null;
5927
+ }
5928
+ interface CustomLookupOption {
5929
+ id: number;
5930
+ custom_attribute_id: number;
5931
+ code: string;
5932
+ value: string;
5933
+ descr?: string;
5934
+ sort_order: number;
5935
+ is_active: boolean;
5936
+ external_id?: string;
5937
+ }
5938
+ interface CvUpsertItem {
5939
+ attributeId: number;
5940
+ entitySchema: string;
5941
+ entityName: string;
5942
+ entityId: string;
5943
+ valueText?: string | null;
5944
+ valueNumber?: number | null;
5945
+ valueDate?: string | null;
5946
+ valueBool?: boolean | null;
5947
+ customLookupId?: number | null;
5948
+ yearNum?: number | null;
5949
+ existingCvId?: number | null;
5950
+ }
5951
+ declare class CustomAttributesService {
5952
+ private http;
5953
+ /** Endpoint base. Override-abile via DI/config se l'app usa path diverso. */
5954
+ endpointBase: string;
5955
+ /**
5956
+ * Cache per (context+scope) → applicable definitions.
5957
+ * Invalidata su `clearCache()` (es. dopo invalidate-metadata-runtime).
5958
+ */
5959
+ private resolveCache;
5960
+ /** Cache per (attribute_id) → lookup options. */
5961
+ private lookupCache;
5962
+ constructor(http: HttpClient);
5963
+ /** Lista tutte le definizioni di un context (admin UI). */
5964
+ listDefinitions(context?: string): Promise<CustomAttributeDefinition[]>;
5965
+ /**
5966
+ * Risolve le CA applicabili a una entity in uno scope (site, project_class, tree_kind).
5967
+ * Usata da `<wuic-parametric-dialog>` per sapere quali field inline mostrare.
5968
+ */
5969
+ resolve(context: string, siteId?: number, projectClassId?: number, treeKindId?: number): Promise<CustomAttributeResolved[]>;
5970
+ /** Leggi i CV correnti di una entity specifica. */
5971
+ getValues(entitySchema: string, entityName: string, entityId: string | number, yearNum?: number): Promise<CustomValue[]>;
5972
+ /** Upsert batch (INSERT new + UPDATE existing via `existingCvId`). */
5973
+ upsertValues(items: CvUpsertItem[]): Promise<{
5974
+ upserted: number;
5975
+ }>;
5976
+ /** Soft delete di un CV. */
5977
+ deleteValue(cvId: number): Promise<{
5978
+ deleted: number;
5979
+ }>;
5980
+ /** Lookup options di un attribute (cached). */
5981
+ getLookupOptions(attributeId: number): Promise<CustomLookupOption[]>;
5982
+ /** Upsert lookup option (admin UI). Trigger cascade rename gestito server-side. */
5983
+ upsertLookup(option: Omit<CustomLookupOption, 'id' | 'is_active'> & {
5984
+ attributeId: number;
5985
+ }): Promise<{
5986
+ affected: number;
5987
+ }>;
5988
+ /** Reset cache (chiamato dopo `invalidateMetadataRuntime`). */
5989
+ clearCache(): void;
5990
+ /**
5991
+ * Estrae i CA token da una filter string e produce un payload separato
5992
+ * `wherestringCA` / `wherevaluesCA` da passare al backend, lasciando i
5993
+ * filter standard sui campi nativi non alterati.
5994
+ *
5995
+ * Pattern legacy: `CA_<attribute_code>___<value>` AND `CS_<attribute_code>___<sortdir>`.
5996
+ *
5997
+ * @returns { nativeFilter, caTokens: { code, value, op }[] }
5998
+ */
5999
+ parseFilterTokens(rawFilter: string | null | undefined): {
6000
+ nativeFilter: string;
6001
+ caTokens: {
6002
+ code: string;
6003
+ value: string;
6004
+ op: 'eq' | 'contains';
6005
+ }[];
6006
+ };
6007
+ static ɵfac: i0.ɵɵFactoryDeclaration<CustomAttributesService, never>;
6008
+ static ɵprov: i0.ɵɵInjectableDeclaration<CustomAttributesService>;
6009
+ }
6010
+
6011
+ declare class DeviceAwarenessService implements OnDestroy {
6012
+ private static readonly DEFAULT_BREAKPOINT_PX;
6013
+ private mediaQueryList?;
6014
+ private mediaQueryListener?;
6015
+ private readonly isMobileSubject;
6016
+ readonly isMobile$: Observable<boolean>;
6017
+ constructor();
6018
+ get isMobile(): boolean;
6019
+ ngOnDestroy(): void;
6020
+ private resolveBreakpointPx;
6021
+ static ɵfac: i0.ɵɵFactoryDeclaration<DeviceAwarenessService, never>;
6022
+ static ɵprov: i0.ɵɵInjectableDeclaration<DeviceAwarenessService>;
6023
+ }
6024
+
6025
+ interface ListGridSavedState {
6026
+ id: string;
6027
+ name: string;
6028
+ description: string;
6029
+ isDefault: boolean;
6030
+ createdAt: string;
6031
+ filterInfo: any;
6032
+ sortInfo: any[];
6033
+ pageInfo: {
6034
+ currentPage: number;
6035
+ pageSize: number;
6036
+ };
6037
+ columnWidths: {
6038
+ [field: string]: number;
6039
+ };
6040
+ columnLayout?: ListGridColumnLayout;
6041
+ }
6042
+ interface ListGridColumnLayout {
6043
+ order: string[];
6044
+ hidden: string[];
6045
+ pinnedLeft: string[];
6046
+ pinnedRight: string[];
6047
+ }
6048
+ interface ReportVariableInput {
6049
+ name: string;
6050
+ alias: string;
6051
+ value: string;
6052
+ type?: string;
6053
+ }
6054
+ interface GridPendingChangeItem {
6055
+ id: string;
6056
+ change: TrackedChange;
6057
+ label: string;
6058
+ details: string;
6059
+ selected: boolean;
6060
+ }
6061
+ interface ListGridBeforeRowRenderEvent {
6062
+ row: any;
6063
+ rowIndex: number;
6064
+ cancel: boolean;
6065
+ cancelRender: () => void;
6066
+ }
6067
+ interface ListGridAfterRowRenderEvent {
6068
+ row: any;
6069
+ rowIndex: number;
6070
+ }
6071
+ interface ListGridAfterRenderEvent {
6072
+ rows: any[];
6073
+ totalRecords: number;
6074
+ metaInfo: MetaInfo;
6075
+ datasource?: DataSourceComponent;
6076
+ }
6077
+ declare class ListGridComponent implements AfterViewInit, OnInit, OnDestroy, IDataBoundHostComponent {
6078
+ private metaSrv;
6079
+ private sanitizer;
6080
+ private route;
6081
+ private router;
6082
+ private location;
6083
+ private titleService;
6084
+ private trslSrv;
6085
+ private cd;
6086
+ userInfo: UserInfoService;
6087
+ private elementRef;
6088
+ deviceAwareness: DeviceAwarenessService;
6089
+ private customAttributesService?;
6090
+ private static readonly FORCED_VIRTUALIZATION_PAGE_SIZE_THRESHOLD;
6091
+ private static readonly FORCED_VIRTUALIZATION_ITEM_SIZE;
6092
+ private static readonly ACTION_BUTTON_VISIBLE_ROWS_OVERSCAN;
6093
+ private static readonly ACTION_BUTTON_INITIAL_VISIBLE_ROWS_FALLBACK;
6094
+ private static readonly GRID_VIEW_STATES_SETTINGS_KEY;
6095
+ private static readonly GRID_COLUMN_LAYOUT_SETTINGS_KEY;
6096
+ private static selectButtonGuardInstalled;
6097
+ private columnFilterRenderEpochByField;
6098
+ private actionButtonsVisibleStartIndex;
6099
+ private actionButtonsVisibleEndIndex;
6100
+ private actionButtonsLimitToVisibleRows;
6101
+ private actionButtonsPreLimitBeforeContainerReady;
6102
+ private actionButtonsScrollContainer;
6103
+ private actionButtonsScrollRafToken;
6104
+ private actionButtonsScrollHandler;
6105
+ private inlineCellSaveInFlightByRowKey;
6106
+ private inlineCellSaveDebounceByRowKey;
6107
+ private inlineCellLastChangedFieldByRowKey;
6108
+ private inlineBatchOriginalByRowKey;
6109
+ private inlineGridRuntimeFieldCacheByKey;
6110
+ private suppressNextInlineFetchInfoRebind;
6111
+ getRuntimeGridFieldMetaFn: (metaColumn: MetadatiColonna, rowData: any) => MetadatiColonna;
6112
+ hardcodedRoute: string;
6113
+ parentRecord: any;
6114
+ parentMetaInfo: MetaInfo;
6115
+ datasource: BehaviorSubject<DataSourceComponent>;
6116
+ hardcodedDatasource: DataSourceComponent;
6117
+ rowCustomSelect: (rowData: any, $event: any, dt: Table) => void;
6118
+ hideToolbar: boolean;
6119
+ /**
6120
+ * Provider letto da `<wuic-import-export-button>` al click su Export XLS.
6121
+ * Arrow function (NON metodo) per preservare il binding di `this` quando
6122
+ * passata come Input — un metodo verrebbe richiamato col `this` del child.
6123
+ * Ritorna lo stato filtri LIVE del datasource: include i filtri applicati
6124
+ * via header/filter-bar che NON vengono propagati nella URL query string.
6125
+ */
6126
+ getCurrentFilterInfoForExport: () => any;
6127
+ /**
6128
+ * Evento emesso subito prima del rendering logico della singola riga.
6129
+ * Il consumer puo annullare la riga chiamando `cancelRender()`.
6130
+ */
6131
+ onBeforeRowRender: EventEmitter<ListGridBeforeRowRenderEvent>;
6132
+ /**
6133
+ * Evento emesso subito dopo il rendering logico della singola riga.
6134
+ */
6135
+ onAfterRowRender: EventEmitter<ListGridAfterRowRenderEvent>;
6136
+ /**
6137
+ * Evento emesso al termine del ciclo di binding dati della griglia.
6138
+ */
6139
+ onAfterRender: EventEmitter<ListGridAfterRenderEvent>;
6140
+ /**
6141
+ * Evento emesso su paging (evento p-table onPage).
6142
+ */
6143
+ onPaging: EventEmitter<any>;
6144
+ /**
6145
+ * Evento emesso su sorting (evento p-table onSort).
6146
+ */
6147
+ onSorting: EventEmitter<any>;
6148
+ /**
6149
+ * Evento emesso su filtering (evento p-table onFilter).
6150
+ */
6151
+ onFiltering: EventEmitter<any>;
6152
+ /**
6153
+ * Evento emesso dopo un refresh esplicito (click su bottone "Aggiorna"
6154
+ * del toolbar o invocazione di `refresh()` da codice). Gli host in Pattern 3
6155
+ * server-side possono usarlo per ri-fetchare dal loro backend custom.
6156
+ */
6157
+ onRefresh: EventEmitter<void>;
6158
+ /**
6159
+ * Eventi p-table esposti lato host.
6160
+ */
6161
+ onPTableSelectionChange: EventEmitter<any>;
5415
6162
  onPTableRowExpand: EventEmitter<TableRowExpandEvent<any>>;
5416
6163
  onPTableRowCollapse: EventEmitter<TableRowCollapseEvent>;
5417
6164
  onPTableColumnResize: EventEmitter<any>;
@@ -5555,7 +6302,29 @@ declare class ListGridComponent implements AfterViewInit, OnInit, OnDestroy, IDa
5555
6302
  * @param cd Parametro in ingresso utilizzato per determinare il flusso operativo del metodo.
5556
6303
  * @param userInfo Parametro in ingresso utilizzato per determinare il flusso operativo del metodo.
5557
6304
  */
5558
- constructor(metaSrv: MetadataProviderService, sanitizer: DomSanitizer, route: ActivatedRoute, router: Router, location: Location, titleService: Title, trslSrv: TranslationManagerService, cd: ChangeDetectorRef, userInfo: UserInfoService, elementRef: ElementRef<HTMLElement>, deviceAwareness: DeviceAwarenessService);
6305
+ constructor(metaSrv: MetadataProviderService, sanitizer: DomSanitizer, route: ActivatedRoute, router: Router, location: Location, titleService: Title, trslSrv: TranslationManagerService, cd: ChangeDetectorRef, userInfo: UserInfoService, elementRef: ElementRef<HTMLElement>, deviceAwareness: DeviceAwarenessService, customAttributesService?: CustomAttributesService);
6306
+ /**
6307
+ * Phase I.3 — Estrae i CA token (CA_<code>___value / CS_<code>___order) dalla
6308
+ * filter string corrente, ritornandoli separati per il backend SP che
6309
+ * costruisce il JOIN dinamico su core.custom_value.
6310
+ *
6311
+ * Pattern legacy `Filter_ApplyProjects.sql` con `wherestringCA`/`wherevaluesCA`.
6312
+ *
6313
+ * Backward-compat: se nessun CA token presente, ritorna `caTokens: []`.
6314
+ * Le app possono usare questo getter per accodare i CA token al payload
6315
+ * delle chiamate stored procedure (es. via `_extra` field di filterInfo).
6316
+ */
6317
+ getCustomAttributeFilterTokens(): {
6318
+ code: string;
6319
+ value: string;
6320
+ op: 'eq' | 'contains';
6321
+ }[];
6322
+ /**
6323
+ * Helper interno: serializza i filtri attivi in una stringa con tokens CA_X / CS_X.
6324
+ * Cerca tra i filterInfo.filters quelli con field name del tipo `ca:code`
6325
+ * o `cs:code` (convenzione opt-in) e li emette in formato CA_code___value.
6326
+ */
6327
+ private serializeFilterInfoToTokenString;
5559
6328
  /**
5560
6329
  * Inizializza il componente preparando stato, sottoscrizioni e primi caricamenti richiesti.
5561
6330
  */
@@ -6709,7 +7478,7 @@ declare class ListGridComponent implements AfterViewInit, OnInit, OnDestroy, IDa
6709
7478
  * @returns Valore numerico derivato dai calcoli interni (conteggio, indice, priorita o metrica operativa).
6710
7479
  */
6711
7480
  private getWidthFromResizeEvent;
6712
- static ɵfac: i0.ɵɵFactoryDeclaration<ListGridComponent, never>;
7481
+ static ɵfac: i0.ɵɵFactoryDeclaration<ListGridComponent, [null, null, null, null, null, null, null, null, null, null, null, { optional: true; }]>;
6713
7482
  static ɵcmp: i0.ɵɵComponentDeclaration<ListGridComponent, "wuic-list-grid", never, { "hardcodedRoute": { "alias": "hardcodedRoute"; "required": false; }; "parentRecord": { "alias": "parentRecord"; "required": false; }; "parentMetaInfo": { "alias": "parentMetaInfo"; "required": false; }; "datasource": { "alias": "datasource"; "required": false; }; "hardcodedDatasource": { "alias": "hardcodedDatasource"; "required": false; }; "rowCustomSelect": { "alias": "rowCustomSelect"; "required": false; }; "hideToolbar": { "alias": "hideToolbar"; "required": false; }; }, { "onBeforeRowRender": "onBeforeRowRender"; "onAfterRowRender": "onAfterRowRender"; "onAfterRender": "onAfterRender"; "onPaging": "onPaging"; "onSorting": "onSorting"; "onFiltering": "onFiltering"; "onRefresh": "onRefresh"; "onPTableSelectionChange": "onPTableSelectionChange"; "onPTableRowExpand": "onPTableRowExpand"; "onPTableRowCollapse": "onPTableRowCollapse"; "onPTableColumnResize": "onPTableColumnResize"; "onPTableColumnReorder": "onPTableColumnReorder"; }, never, never, true, never>;
6714
7483
  }
6715
7484
 
@@ -8407,8 +9176,9 @@ declare class CarouselListComponent implements IBindable, IDesigner<CarouselOpti
8407
9176
  static ɵcmp: i0.ɵɵComponentDeclaration<CarouselListComponent, "wuic-carousel-list", never, { "hardcodedRoute": { "alias": "hardcodedRoute"; "required": false; }; "parentRecord": { "alias": "parentRecord"; "required": false; }; "parentMetaInfo": { "alias": "parentMetaInfo"; "required": false; }; "datasource": { "alias": "datasource"; "required": false; }; "hardcodedDatasource": { "alias": "hardcodedDatasource"; "required": false; }; "hideToolbar": { "alias": "hideToolbar"; "required": false; }; }, { "onCarouselPage": "onCarouselPage"; "onCarouselItemClick": "onCarouselItemClick"; "onCarouselDataBound": "onCarouselDataBound"; }, never, never, true, never>;
8408
9177
  }
8409
9178
 
8410
- declare class LazySpreadsheetListSfComponent implements OnInit {
9179
+ declare class LazySpreadsheetListSfComponent implements OnInit, OnDestroy, AfterViewChecked {
8411
9180
  private readonly cdr;
9181
+ private readonly activatedRoute;
8412
9182
  innerOutlet?: NgComponentOutlet;
8413
9183
  hardcodedRoute: string;
8414
9184
  parentRecord: any;
@@ -8416,9 +9186,46 @@ declare class LazySpreadsheetListSfComponent implements OnInit {
8416
9186
  datasource: BehaviorSubject<DataSourceComponent>;
8417
9187
  hardcodedDatasource: DataSourceComponent;
8418
9188
  hideToolbar: boolean;
9189
+ /** Override esplicito che forza l'attivazione lock-awareness. Default false. */
9190
+ enableLockAwareness: boolean;
9191
+ /**
9192
+ * Scope di lock generico. Se non valorizzato dal parent, viene auto-popolato
9193
+ * dalla URL: tutti i query param vengono caricati come key→value (numeric
9194
+ * coercion best-effort). La mdpropsbag della route definisce quali field sono
9195
+ * "primary" (URL path segment) e quali sono required.
9196
+ */
9197
+ lockScope: Record<string, any>;
9198
+ /**
9199
+ * Override heartbeat in secondi. Se omesso, viene preso dalla
9200
+ * `mdpropsbag.archetypes.spreadsheet.lock.heartbeatIntervalSec` (default 60).
9201
+ */
9202
+ heartbeatIntervalSec?: number;
9203
+ /** Mostra formula bar Syncfusion. Default false (BC). Override anche via URL `?show_formula_bar=1`. */
9204
+ showFormulaBar: boolean;
9205
+ /** Mostra ribbon Syncfusion completo. Default false. Override anche via URL `?show_ribbon=1`. */
9206
+ showRibbon: boolean;
9207
+ onLockAcquired: EventEmitter<{
9208
+ lockToken: string;
9209
+ lockId: number;
9210
+ lockExpiresUtc: Date;
9211
+ outcome: "acquired" | "refreshed";
9212
+ }>;
9213
+ onLockConflict: EventEmitter<{
9214
+ conflictUserId: number | null;
9215
+ lockExpiresUtc: Date | null;
9216
+ }>;
9217
+ onLockReleased: EventEmitter<{
9218
+ released: number;
9219
+ }>;
9220
+ onLockExpired: EventEmitter<void>;
8419
9221
  loadedComponent: any;
8420
- constructor(cdr: ChangeDetectorRef);
9222
+ private routeQuerySub?;
9223
+ constructor(cdr: ChangeDetectorRef, activatedRoute: ActivatedRoute);
8421
9224
  ngOnInit(): Promise<void>;
9225
+ ngOnDestroy(): void;
9226
+ private lockEventSubs;
9227
+ private innerHooked;
9228
+ ngAfterViewChecked(): void;
8422
9229
  componentInputs(): {
8423
9230
  hardcodedRoute: string;
8424
9231
  parentRecord: any;
@@ -8426,9 +9233,14 @@ declare class LazySpreadsheetListSfComponent implements OnInit {
8426
9233
  datasource: BehaviorSubject<DataSourceComponent>;
8427
9234
  hardcodedDatasource: DataSourceComponent;
8428
9235
  hideToolbar: boolean;
9236
+ enableLockAwareness: boolean;
9237
+ lockScope: Record<string, any>;
9238
+ heartbeatIntervalSec: number;
9239
+ showFormulaBar: boolean;
9240
+ showRibbon: boolean;
8429
9241
  };
8430
9242
  static ɵfac: i0.ɵɵFactoryDeclaration<LazySpreadsheetListSfComponent, never>;
8431
- static ɵcmp: i0.ɵɵComponentDeclaration<LazySpreadsheetListSfComponent, "wuic-spreadsheet-list-sf-lazy", never, { "hardcodedRoute": { "alias": "hardcodedRoute"; "required": false; }; "parentRecord": { "alias": "parentRecord"; "required": false; }; "parentMetaInfo": { "alias": "parentMetaInfo"; "required": false; }; "datasource": { "alias": "datasource"; "required": false; }; "hardcodedDatasource": { "alias": "hardcodedDatasource"; "required": false; }; "hideToolbar": { "alias": "hideToolbar"; "required": false; }; }, {}, never, never, true, never>;
9243
+ static ɵcmp: i0.ɵɵComponentDeclaration<LazySpreadsheetListSfComponent, "wuic-spreadsheet-list-sf-lazy", never, { "hardcodedRoute": { "alias": "hardcodedRoute"; "required": false; }; "parentRecord": { "alias": "parentRecord"; "required": false; }; "parentMetaInfo": { "alias": "parentMetaInfo"; "required": false; }; "datasource": { "alias": "datasource"; "required": false; }; "hardcodedDatasource": { "alias": "hardcodedDatasource"; "required": false; }; "hideToolbar": { "alias": "hideToolbar"; "required": false; }; "enableLockAwareness": { "alias": "enableLockAwareness"; "required": false; }; "lockScope": { "alias": "lockScope"; "required": false; }; "heartbeatIntervalSec": { "alias": "heartbeatIntervalSec"; "required": false; }; "showFormulaBar": { "alias": "showFormulaBar"; "required": false; }; "showRibbon": { "alias": "showRibbon"; "required": false; }; }, { "onLockAcquired": "onLockAcquired"; "onLockConflict": "onLockConflict"; "onLockReleased": "onLockReleased"; "onLockExpired": "onLockExpired"; }, never, never, true, never>;
8432
9244
  }
8433
9245
 
8434
9246
  declare class TreeListComponent implements OnInit, OnDestroy, IDataBoundHostComponent {
@@ -8649,6 +9461,7 @@ declare class ParametricDialogComponent implements OnInit, AfterViewInit, OnDest
8649
9461
  private router;
8650
9462
  private trnsl;
8651
9463
  private hostElementRef;
9464
+ private customAttributesService;
8652
9465
  private dialogService?;
8653
9466
  /**
8654
9467
  * Input dal componente padre per datasource; usata nella configurazione e nel rendering del componente.
@@ -8749,6 +9562,32 @@ declare class ParametricDialogComponent implements OnInit, AfterViewInit, OnDest
8749
9562
  * Configurazione di presentazione per form template, usata nel rendering del componente.
8750
9563
  */
8751
9564
  formTemplate: any;
9565
+ /**
9566
+ * Phase I.3 — Custom Attributes runtime state.
9567
+ * Popolato in `applyDatasourceSnapshot` quando `tableMetadata.custom_attribute_context`
9568
+ * e' valorizzato. Le definitions resolved vengono iniettate come MetadatiColonna sintetiche
9569
+ * (prefisso `__ca_<code>__`) in `metaInfo.columnMetadata`; i values esistenti vengono
9570
+ * caricati in `record['__ca_<code>__']`. Al save, l'app-level hook va connesso a
9571
+ * `(onCustomAttributesSave)` con `CustomAttributesService.upsertValues()`.
9572
+ */
9573
+ customAttributesResolved: CustomAttributeResolved[];
9574
+ customAttributesValues: CustomValue[];
9575
+ /** Emesso quando l'utente conferma il save: l'app dovrebbe chiamare `caService.upsertValues()`. */
9576
+ onCustomAttributesSave: EventEmitter<{
9577
+ items: {
9578
+ attributeId: number;
9579
+ entitySchema: string;
9580
+ entityName: string;
9581
+ entityId: string;
9582
+ valueText?: string;
9583
+ valueNumber?: number;
9584
+ valueDate?: string;
9585
+ valueBool?: boolean;
9586
+ customLookupId?: number;
9587
+ yearNum?: number;
9588
+ existingCvId?: number;
9589
+ }[];
9590
+ }>;
8752
9591
  /**
8753
9592
  * Flag di stato che governa il comportamento UI/logico relativo a cloning.
8754
9593
  */
@@ -8825,7 +9664,8 @@ declare class ParametricDialogComponent implements OnInit, AfterViewInit, OnDest
8825
9664
  * @param route Informazione di navigazione usata per risolvere la route di destinazione.
8826
9665
  * @param router Informazione di navigazione usata per risolvere la route di destinazione.
8827
9666
  */
8828
- constructor(ref: DynamicDialogRef | null, config: DynamicDialogConfig | null, route: ActivatedRoute, router: Router, trnsl: TranslationManagerService, hostElementRef: ElementRef<HTMLElement>, dialogService?: DialogService);
9667
+ constructor(ref: DynamicDialogRef | null, config: DynamicDialogConfig | null, route: ActivatedRoute, router: Router, trnsl: TranslationManagerService, hostElementRef: ElementRef<HTMLElement>, customAttributesService: CustomAttributesService | null, // Phase I.3
9668
+ dialogService?: DialogService);
8829
9669
  /**
8830
9670
  * Inizializza il componente preparando stato, sottoscrizioni e primi caricamenti richiesti.
8831
9671
  */
@@ -9028,8 +9868,25 @@ declare class ParametricDialogComponent implements OnInit, AfterViewInit, OnDest
9028
9868
  * quando la schermata viene riaperta subito dopo.
9029
9869
  */
9030
9870
  private reloadTranslationsIfMetadataSave;
9031
- static ɵfac: i0.ɵɵFactoryDeclaration<ParametricDialogComponent, [{ optional: true; }, { optional: true; }, null, null, null, null, { optional: true; }]>;
9032
- static ɵcmp: i0.ɵɵComponentDeclaration<ParametricDialogComponent, "wuic-parametric-dialog", never, { "datasource": { "alias": "datasource"; "required": false; }; "hardcodedDatasource": { "alias": "hardcodedDatasource"; "required": false; }; "hideToolbar": { "alias": "hideToolbar"; "required": false; }; "isWizard": { "alias": "isWizard"; "required": false; }; "isEditForm": { "alias": "isEditForm"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; }, { "onDialogDataBound": "onDialogDataBound"; "onDialogTabChange": "onDialogTabChange"; "onWizardStepChange": "onWizardStepChange"; "onDialogCustomAction": "onDialogCustomAction"; "onDialogSubmit": "onDialogSubmit"; "onDialogRollback": "onDialogRollback"; "onDialogCloseRequested": "onDialogCloseRequested"; }, never, never, true, never>;
9871
+ /**
9872
+ * Se la route ha `tableMetadata.custom_attribute_context` valorizzato e il
9873
+ * `CustomAttributesService` è injectabile, carica:
9874
+ * 1. Le definitions applicable allo scope (resolve TVF)
9875
+ * 2. I CV correnti della entity (getValues TVF)
9876
+ * I CV vengono mergiati in `record` con chiave `__ca_<code>__` cosi' che
9877
+ * eventuali template/form a livello app possano renderizzarli.
9878
+ * Feature flag: senza `custom_attribute_context` settato (default), NO-OP.
9879
+ */
9880
+ private tryLoadCustomAttributes;
9881
+ /**
9882
+ * Helper esposto per app-level form/template: collect i valori CA correnti
9883
+ * dal record e emette `onCustomAttributesSave`. L'app deve chiamare
9884
+ * `CustomAttributesService.upsertValues(items)` come step post-save standard.
9885
+ * Backward-compat: se il listener non e' attaccato, no-op silenzioso.
9886
+ */
9887
+ collectAndEmitCustomAttributesSave(): void;
9888
+ static ɵfac: i0.ɵɵFactoryDeclaration<ParametricDialogComponent, [{ optional: true; }, { optional: true; }, null, null, null, null, { optional: true; }, { optional: true; }]>;
9889
+ static ɵcmp: i0.ɵɵComponentDeclaration<ParametricDialogComponent, "wuic-parametric-dialog", never, { "datasource": { "alias": "datasource"; "required": false; }; "hardcodedDatasource": { "alias": "hardcodedDatasource"; "required": false; }; "hideToolbar": { "alias": "hideToolbar"; "required": false; }; "isWizard": { "alias": "isWizard"; "required": false; }; "isEditForm": { "alias": "isEditForm"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; }, { "onDialogDataBound": "onDialogDataBound"; "onDialogTabChange": "onDialogTabChange"; "onWizardStepChange": "onWizardStepChange"; "onDialogCustomAction": "onDialogCustomAction"; "onDialogSubmit": "onDialogSubmit"; "onDialogRollback": "onDialogRollback"; "onDialogCloseRequested": "onDialogCloseRequested"; "onCustomAttributesSave": "onCustomAttributesSave"; }, never, never, true, never>;
9033
9890
  }
9034
9891
 
9035
9892
  /**
@@ -9258,576 +10115,330 @@ declare class AppSettingsEditorComponent implements OnInit {
9258
10115
  * vecchio worker non e' ancora morto (~1-2s di sovrapposizione), ma sotto
9259
10116
  * ANCM/NSSM la finestra e' molto stretta e il caller (`saveAndApply`)
9260
10117
  * gia' fa un `sleep(Math.max(800, restartDelayMs+200))` prima di chiamare
9261
- * questo metodo, coprendo il caso normale.
9262
- */
9263
- private waitForHealthSimple;
9264
- /**
9265
- * Wrapper legacy mantenuto per back-compat: alias di
9266
- * `waitForHealthSimple`. Eventuali consumer storici che chiamavano
9267
- * `waitForHealth(ms)` continuano a vedere il polling semplice (non il
9268
- * 4-phase) — coerente con ambienti prod dove il supervisor gestisce
9269
- * il restart.
9270
- */
9271
- private waitForHealth;
9272
- private forceLogout;
9273
- static ɵfac: i0.ɵɵFactoryDeclaration<AppSettingsEditorComponent, never>;
9274
- static ɵcmp: i0.ɵɵComponentDeclaration<AppSettingsEditorComponent, "wuic-app-settings-editor", never, {}, {}, never, never, true, never>;
9275
- }
9276
-
9277
- declare class DataActionButtonComponent implements AfterViewInit, OnDestroy {
9278
- private trslSrv;
9279
- private cd;
9280
- private messageService;
9281
- private confirmationService;
9282
- private router;
9283
- private http;
9284
- private metadataProvider;
9285
- private static readonly ACTION_KEY_EDIT;
9286
- data: any;
9287
- metaInfo: MetaInfo;
9288
- datasource: BehaviorSubject<DataSourceComponent>;
9289
- filter?: () => void;
9290
- simplified: boolean;
9291
- parentField: string;
9292
- btn: SplitButton;
9293
- simpleMenu?: Menu;
9294
- simplifiedMenuOpen: boolean;
9295
- items: MenuItem[];
9296
- selectedValue: any;
9297
- pkName: string;
9298
- inlineItems: any[];
9299
- nonInlineEditingItems: MenuItem[];
9300
- private translationsLoadedSub?;
9301
- constructor(trslSrv: TranslationManagerService, cd: ChangeDetectorRef, messageService: MessageService, confirmationService: ConfirmationService, router: Router, http: HttpClient, metadataProvider: MetadataProviderService);
9302
- /**
9303
- * Hook di debug locale per ispezionare l'evento click sul pulsante azioni.
9304
- * @param $event Evento UI ricevuto dal template.
9305
- */
9306
- test($event: any): void;
9307
- /**
9308
- * Inizializza il menu azioni in base ai metadati tabella/colonna (`md_editable`, `md_deletable`, `md_inline_edit`, colonne `button`).
9309
- * Calcola anche la PK corrente per le azioni route-based.
9310
- */
9311
- ngAfterViewInit(): void;
9312
- ngOnDestroy(): void;
9313
- private rebuildActionMenus;
9314
- private translateLabel;
9315
- /**
9316
- * Esegue il comando dell'item selezionato se non disabilitato.
9317
- * @param item Voce menu azione.
9318
- */
9319
- select(item: any): void;
9320
- /**
9321
- * Aggiunge al menu le azioni dinamiche derivate dalle colonne metadata di tipo `button`.
9322
- * @param target Collezione menu da arricchire.
9323
- */
9324
- private appendMetadataButtonItems;
9325
- private getButtonActionRecord;
9326
- /**
9327
- * Valuta se un bottone metadata e attivo verificando callback azione e condizione visibilita (`mc_button_visibility_condition`).
9328
- * @param col Metadato colonna di tipo button.
9329
- * @returns `true` se il bottone e eseguibile.
9330
- */
9331
- private isMetadataButtonEnabled;
9332
- /**
9333
- * Esegue l'azione custom del bottone metadata, con eventuale conferma (`mc_button_confirm_message`) e gestione errori centralizzata.
9334
- * @param col Metadato colonna button.
9335
- * @param record Record osservabile corrente.
9336
- * @param event Evento UI di invocazione.
9337
- */
9338
- private executeMetadataButton;
9339
- /**
9340
- * Avvia il flusso edit del record corrente:
9341
- * inline edit, popup `EditFormComponent` oppure navigazione route `/{route}/edit/{pk}`.
9342
- */
9343
- edit(): void;
9344
- /**
9345
- * Richiede conferma e, in caso positivo, elimina il record via `datasource.syncData(..., true)` ricaricando la griglia.
9346
- */
9347
- delete(): Promise<void>;
9348
- private canRestoreFromChangeMaster;
9349
- private appendRestoreFromChangeMasterActionAsync;
9350
- private isLogicalDeleteSupportedRoute;
9351
- private getRecordFieldIgnoreCase;
9352
- private restoreFromChangeMaster;
9353
- /**
9354
- * Apre il record in modalita sola lettura tramite `EditFormComponent` con `readOnly: true`.
9355
- */
9356
- detail(): void;
9357
- /**
9358
- * Apre `EditFormComponent` in modalita cloning per creare una copia del record corrente.
9359
- */
9360
- clone(): void;
9361
- /**
9362
- * Salva modifiche inline sincronizzando il record osservabile con backend e riallineando il modello riga in tabella.
9363
- */
9364
- save(): Promise<void>;
9365
- /**
9366
- * Annulla l'inline edit locale della riga corrente.
9367
- */
9368
- cancelEdit(): Promise<void>;
9369
- /**
9370
- * Hook evento click principale (attualmente usato come placeholder/debug).
9371
- * @param $event Evento click.
9372
- */
9373
- onClick($event: any): void;
9374
- /**
9375
- * Hook richiamato alla chiusura del menu split button.
9376
- * @param $event Evento PrimeNG.
9377
- */
9378
- onMenuHide($event: any): void;
9379
- /**
9380
- * Hook richiamato all'apertura del menu split button.
9381
- * @param $event Evento PrimeNG.
9382
- */
9383
- onMenuShow($event: any): void;
9384
- /**
9385
- * Hook click dropdown del pulsante azioni (punto estensione per custom behavior).
9386
- * @param $event Evento click dropdown.
9387
- */
9388
- onDropdownClick($event: any): void;
9389
- /**
9390
- * Ferma la propagazione dell'evento per evitare side effects sul contenitore (es. row click/select).
9391
- * @param $event Evento DOM.
9392
- */
9393
- fix($event: any): void;
9394
- /**
9395
- * Apre/chiude il popup menu in modalita semplificata con overlay appeso al body.
9396
- * Evita clipping dentro i contenitori FullCalendar.
9397
- * @param event Evento click del trigger.
9398
- */
9399
- onSimplifiedMenuClick(event: Event): void;
9400
- onSimplifiedMenuShow(): void;
9401
- onSimplifiedMenuHide(): void;
9402
- /**
9403
- * Abilita modalita inline-cell-editing via metadata tabella (con fallback legacy).
9404
- */
9405
- isInlineCellEditingEnabled(): boolean;
9406
- /**
9407
- * In inline-cell-editing, anche se la riga e marcata editing, mostra menu standard senza "edit".
9408
- */
9409
- showInlineEditingMenu(): boolean;
9410
- /**
9411
- * Modello menu effettivo da renderizzare nel pulsante azioni.
9412
- */
9413
- getActionMenuModel(): MenuItem[];
9414
- private toBooleanLoose;
9415
- addRecord(): void;
9416
- static ɵfac: i0.ɵɵFactoryDeclaration<DataActionButtonComponent, never>;
9417
- static ɵcmp: i0.ɵɵComponentDeclaration<DataActionButtonComponent, "wuic-data-action-button", never, { "data": { "alias": "data"; "required": false; }; "metaInfo": { "alias": "metaInfo"; "required": false; }; "datasource": { "alias": "datasource"; "required": false; }; "filter": { "alias": "filter"; "required": false; }; "simplified": { "alias": "simplified"; "required": false; }; "parentField": { "alias": "parentField"; "required": false; }; }, {}, never, never, true, never>;
9418
- }
9419
-
9420
- declare class LazyDataActionButtonComponent implements OnInit {
9421
- private readonly cdr;
9422
- /**
9423
- * Input dal componente padre per data; usata nella configurazione e nel rendering del componente.
9424
- */
9425
- data: any;
9426
- /**
9427
- * Input dal componente padre per meta info; usata nella configurazione e nel rendering del componente.
9428
- */
9429
- metaInfo: MetaInfo;
9430
- /**
9431
- * Input dal componente padre per datasource; usata nella configurazione e nel rendering del componente.
9432
- */
9433
- datasource: BehaviorSubject<any>;
9434
- /**
9435
- * Input dal componente padre per filter; usata nella configurazione e nel rendering del componente.
9436
- */
9437
- filter?: () => void;
9438
- /**
9439
- * Input dal componente padre per simplified; usata nella configurazione e nel rendering del componente.
9440
- */
9441
- simplified: boolean;
9442
- parentField: string;
9443
- /**
9444
- * Proprieta di stato del componente per loaded component, usata dalla logica interna e dal template.
9445
- */
9446
- loadedComponent: any;
9447
- constructor(cdr: ChangeDetectorRef);
9448
- /**
9449
- * Inizializza il componente preparando stato, sottoscrizioni e primi caricamenti richiesti.
9450
- */
9451
- ngOnInit(): Promise<void>;
9452
- /**
9453
- * Gestisce la logica di `componentInputs` con regole guidate dai metadati server `_Metadati_*` (tabella/colonna).
9454
- * @returns Oggetto risultato costruito dal metodo per il passo successivo del flusso.
9455
- */
9456
- componentInputs(): {
9457
- data: any;
9458
- metaInfo: MetaInfo;
9459
- datasource: BehaviorSubject<any>;
9460
- filter: () => void;
9461
- simplified: boolean;
9462
- parentField: string;
9463
- };
9464
- static ɵfac: i0.ɵɵFactoryDeclaration<LazyDataActionButtonComponent, never>;
9465
- static ɵcmp: i0.ɵɵComponentDeclaration<LazyDataActionButtonComponent, "wuic-data-action-button-lazy", never, { "data": { "alias": "data"; "required": false; }; "metaInfo": { "alias": "metaInfo"; "required": false; }; "datasource": { "alias": "datasource"; "required": false; }; "filter": { "alias": "filter"; "required": false; }; "simplified": { "alias": "simplified"; "required": false; }; "parentField": { "alias": "parentField"; "required": false; }; }, {}, never, never, true, never>;
9466
- }
9467
-
9468
- /**
9469
- * Shape of the response returned by `/api/Meta/LicenseStatus` (GET).
9470
- * The endpoint is defined in `Controllers/MetaController.cs` LicenseStatus action.
9471
- */
9472
- interface LicenseStatusResponse {
9473
- machineFingerprint?: string;
9474
- licenseValid?: boolean;
9475
- licenseReason?: string;
9476
- licenseExpiryUtc?: string | null;
9477
- licenseEmail?: string;
9478
- maintenanceExpiryUtc?: string | null;
9479
- tier?: string;
9480
- features?: string[];
9481
- /**
9482
- * DBMS utilizzato dal backend per il **DB DATI** (`AppSettings.dbms`):
9483
- * `'mssql'` o `'mysql'`. Aggiunto 2026-04-28 per il tooltip license del
9484
- * meta-menu — sysadmin vede a colpo d'occhio su quale provider gira il
9485
- * deploy.
10118
+ * questo metodo, coprendo il caso normale.
9486
10119
  */
9487
- dataDbms?: string;
10120
+ private waitForHealthSimple;
9488
10121
  /**
9489
- * DBMS utilizzato dal backend per il **DB METADATI** (`AppSettings.meta-dbms`).
9490
- * Tipicamente uguale a `dataDbms` ma puo' divergere quando
9491
- * `allowMultipleDBMS=true` (es. data MySQL + metadata MSSQL).
10122
+ * Wrapper legacy mantenuto per back-compat: alias di
10123
+ * `waitForHealthSimple`. Eventuali consumer storici che chiamavano
10124
+ * `waitForHealth(ms)` continuano a vedere il polling semplice (non il
10125
+ * 4-phase) — coerente con ambienti prod dove il supervisor gestisce
10126
+ * il restart.
9492
10127
  */
9493
- metaDbms?: string;
10128
+ private waitForHealth;
10129
+ private forceLogout;
10130
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppSettingsEditorComponent, never>;
10131
+ static ɵcmp: i0.ɵɵComponentDeclaration<AppSettingsEditorComponent, "wuic-app-settings-editor", never, {}, {}, never, never, true, never>;
9494
10132
  }
9495
- /**
9496
- * Client-side view of the current license. Exposes synchronous `has(feature)`
9497
- * predicate for use in templates, directives, guards, and components.
9498
- *
9499
- * Lifecycle:
9500
- * 1) App bootstrap calls `refresh()` once.
9501
- * 2) All `*wuicFeature` directives and `FeatureRouteGuard` read from the
9502
- * cached snapshot via `has()`.
9503
- * 3) On license change (upgrade via new appsettings.json) restart the app
9504
- * OR call `refresh()` again to re-fetch.
9505
- *
9506
- * IMPORTANT: this service is a UX layer only. The real security is server-side
9507
- * (see `SanitizeBoardContent` + `[RequireFeature]` + data-decoration in
9508
- * `AsmxCrudRead`). A client can patch this service and unlock everything locally,
9509
- * but the server will still refuse premium operations.
9510
- */
9511
- declare class LicenseFeatureService {
10133
+
10134
+ declare class DataActionButtonComponent implements AfterViewInit, OnDestroy {
10135
+ private trslSrv;
10136
+ private cd;
10137
+ private messageService;
10138
+ private confirmationService;
10139
+ private router;
9512
10140
  private http;
9513
- private static readonly ALWAYS_ALLOWED_ARCHETYPES;
9514
- private statusSubject;
9515
- private loadedOnce;
10141
+ private metadataProvider;
10142
+ private static readonly ACTION_KEY_EDIT;
10143
+ data: any;
10144
+ metaInfo: MetaInfo;
10145
+ datasource: BehaviorSubject<DataSourceComponent>;
10146
+ filter?: () => void;
10147
+ simplified: boolean;
10148
+ parentField: string;
10149
+ btn: SplitButton;
10150
+ simpleMenu?: Menu;
10151
+ simplifiedMenuOpen: boolean;
10152
+ items: MenuItem[];
10153
+ selectedValue: any;
10154
+ pkName: string;
10155
+ inlineItems: any[];
10156
+ nonInlineEditingItems: MenuItem[];
10157
+ private translationsLoadedSub?;
10158
+ constructor(trslSrv: TranslationManagerService, cd: ChangeDetectorRef, messageService: MessageService, confirmationService: ConfirmationService, router: Router, http: HttpClient, metadataProvider: MetadataProviderService);
9516
10159
  /**
9517
- * Promise risolta dopo il PRIMO `refresh()` (success or fail-closed).
9518
- * Usata dai route guard per attendere che lo snapshot iniziale sia
9519
- * disponibile prima di decidere access → evita race post-refresh pagina
9520
- * dove il guard partiva con `statusSubject.value === null` e denyava la
9521
- * feature anche con licenza valida.
10160
+ * Hook di debug locale per ispezionare l'evento click sul pulsante azioni.
10161
+ * @param $event Evento UI ricevuto dal template.
9522
10162
  */
9523
- private readyResolve;
9524
- private readyPromise;
9525
- constructor(http: HttpClient);
10163
+ test($event: any): void;
9526
10164
  /**
9527
- * Ritorna una Promise che risolve quando il primo `refresh()` ha completato
9528
- * (con successo o con fail-closed fallback). Dopo il primo load, ritorna
9529
- * una Promise gia' risolta → overhead zero. Il guard la await per decidere
9530
- * solo con snapshot reale, non con `null` iniziale.
10165
+ * Inizializza il menu azioni in base ai metadati tabella/colonna (`md_editable`, `md_deletable`, `md_inline_edit`, colonne `button`).
10166
+ * Calcola anche la PK corrente per le azioni route-based.
9531
10167
  */
9532
- ready(): Promise<void>;
10168
+ ngAfterViewInit(): void;
10169
+ ngOnDestroy(): void;
10170
+ private rebuildActionMenus;
10171
+ private translateLabel;
9533
10172
  /**
9534
- * Observable of the current license status snapshot. Emits `null` until the
9535
- * first `refresh()` completes.
10173
+ * Esegue il comando dell'item selezionato se non disabilitato.
10174
+ * @param item Voce menu azione.
9536
10175
  */
9537
- status$(): Observable<LicenseStatusResponse | null>;
10176
+ select(item: any): void;
9538
10177
  /**
9539
- * Synchronous accessor to the cached snapshot. Returns `null` if not yet loaded.
10178
+ * Aggiunge al menu le azioni dinamiche derivate dalle colonne metadata di tipo `button`.
10179
+ * @param target Collezione menu da arricchire.
9540
10180
  */
9541
- snapshot(): LicenseStatusResponse | null;
10181
+ private appendMetadataButtonItems;
10182
+ private getButtonActionRecord;
9542
10183
  /**
9543
- * Fetches `/api/Meta/LicenseStatus` and caches the result. Returns the promise
9544
- * so callers (like an APP_INITIALIZER) can await it.
10184
+ * Valuta se un bottone metadata e attivo verificando callback azione e condizione visibilita (`mc_button_visibility_condition`).
10185
+ * @param col Metadato colonna di tipo button.
10186
+ * @returns `true` se il bottone e eseguibile.
9545
10187
  */
9546
- refresh(): Promise<LicenseStatusResponse | null>;
9547
- /** Idempotent: il primo refresh risolve `readyPromise`; i successivi no-op. */
9548
- private signalReady;
10188
+ private isMetadataButtonEnabled;
9549
10189
  /**
9550
- * Returns true when the current license includes the given feature flag.
9551
- * Returns `false` when:
9552
- * - license not yet loaded (conservative default);
9553
- * - license is invalid;
9554
- * - feature is not in the `features` array.
10190
+ * Esegue l'azione custom del bottone metadata, con eventuale conferma (`mc_button_confirm_message`) e gestione errori centralizzata.
10191
+ * @param col Metadato colonna button.
10192
+ * @param record Record osservabile corrente.
10193
+ * @param event Evento UI di invocazione.
9555
10194
  */
9556
- has(feature: string): boolean;
10195
+ private executeMetadataButton;
9557
10196
  /**
9558
- * Returns true when the archetype (e.g. "spreadsheet", "pivot-grid", "list")
9559
- * is permitted by the current license. Archetypes in the always-allowed set
9560
- * (list, kanban, chart, ...) return true unconditionally.
10197
+ * Avvia il flusso edit del record corrente:
10198
+ * inline edit, popup `EditFormComponent` oppure navigazione route `/{route}/edit/{pk}`.
9561
10199
  */
9562
- isArchetypeAllowed(archetype: string): boolean;
10200
+ edit(): void;
9563
10201
  /**
9564
- * Mirrors the server-side `LicenseFeatureMap.ArchetypeFeatureMap`. Kept
9565
- * hardcoded on both sides so a patched client gets UX unlock, but the
9566
- * server-side gate (boardcontent sanitizer + data-decoration) still enforces.
10202
+ * Richiede conferma e, in caso positivo, elimina il record via `datasource.syncData(..., true)` ricaricando la griglia.
9567
10203
  */
9568
- private archetypeToFeature;
10204
+ delete(): Promise<void>;
10205
+ private canRestoreFromChangeMaster;
10206
+ private appendRestoreFromChangeMasterActionAsync;
10207
+ private isLogicalDeleteSupportedRoute;
10208
+ private getRecordFieldIgnoreCase;
10209
+ private restoreFromChangeMaster;
9569
10210
  /**
9570
- * Builds the LicenseStatus endpoint URL from `global_root_url`. The root is
9571
- * typically `"/api/Meta/AsmxProxy/"` (AsmxProxy pattern) or `"/api/Meta/"`
9572
- * (direct). LicenseStatus is a direct GET action on MetaController, so we
9573
- * strip any trailing `AsmxProxy/` segment before appending the action name.
10211
+ * Apre il record in modalita sola lettura tramite `EditFormComponent` con `readOnly: true`.
9574
10212
  */
9575
- private resolveLicenseStatusUrl;
9576
- static ɵfac: i0.ɵɵFactoryDeclaration<LicenseFeatureService, never>;
9577
- static ɵprov: i0.ɵɵInjectableDeclaration<LicenseFeatureService>;
9578
- }
9579
-
9580
- interface AuthSessionState {
9581
- initialized: boolean;
9582
- loading: boolean;
9583
- enabled: boolean;
9584
- authenticated: boolean;
9585
- legacyAuthenticated: boolean;
9586
- provider?: string;
9587
- name?: string;
9588
- legacyName?: string;
9589
- legacyRole?: string;
9590
- claims?: {
9591
- type: string;
9592
- value: string;
9593
- }[];
9594
- error?: string;
9595
- returnUrl: string;
9596
- sessionExpiring?: boolean;
9597
- sessionExpiresInSeconds?: number;
9598
- }
9599
- declare class AuthSessionService {
9600
- private http;
9601
- private userInfoService;
9602
- private metadataProvider;
9603
- private translationManager;
9604
- private ngZone;
9605
- private initialized;
9606
- private sessionTimeoutMs;
9607
- private sessionWarningMs;
9608
- private sessionTimer;
9609
- private sessionWarningTimer;
9610
- private sessionCountdownTimer;
9611
- private readonly stateSubject;
9612
- readonly state$: rxjs.Observable<AuthSessionState>;
9613
- get snapshot(): AuthSessionState;
9614
- constructor(http: HttpClient, userInfoService: UserInfoService, metadataProvider: MetadataProviderService, translationManager: TranslationManagerService, ngZone: NgZone);
10213
+ detail(): void;
9615
10214
  /**
9616
- * Allinea ngx-translate alla lingua dell'utente appena autenticato/hydratato.
9617
- * Necessario perche' il TranslationManagerService bootstrap risolve la lingua
9618
- * via `userInfoService.getuserInfo()` quando NESSUN utente e' ancora loggato,
9619
- * finendo di default su `navigator.language` o 'it-IT'. Senza questa call
9620
- * esplicita post-login, le traduzioni rese dal primo render (toolbar, menu,
9621
- * dialog) restano "appiccicate" alla lingua di bootstrap finche' l'utente
9622
- * non cambia lingua manualmente dal selettore, che invece chiama direttamente
9623
- * `useLanguage()`. Chiamata best-effort: fallisce silenzioso se la lingua non
9624
- * e' supportata o la tabella traduzioni non e' ancora pronta.
10215
+ * Apre `EditFormComponent` in modalita cloning per creare una copia del record corrente.
9625
10216
  */
9626
- private applyUserLanguageToTranslations;
10217
+ clone(): void;
9627
10218
  /**
9628
- * Inizializza il servizio una sola volta (o forzatamente) e carica lo stato sessione corrente via `refreshAll`.
9629
- * @param force Se `true` forza una nuova inizializzazione anche se gia avvenuta.
10219
+ * Salva modifiche inline sincronizzando il record osservabile con backend e riallineando il modello riga in tabella.
9630
10220
  */
9631
- initialize(force?: boolean): Promise<void>;
10221
+ save(): Promise<void>;
9632
10222
  /**
9633
- * Hydrates the UI-side user snapshot from the backend when sessionStorage
9634
- * is empty but a server-managed HttpOnly `k-user` cookie might still be
9635
- * valid. This is the critical step for `enableCookieAuthentication=true`:
9636
- * after a browser restart (or new tab) sessionStorage is gone, the cookie
9637
- * is HttpOnly and invisible to JS, so without this call the guard would
9638
- * wrongly redirect to `/unauthorized` despite a valid session.
9639
- *
9640
- * Flow:
9641
- * 1. If sessionStorage already has a snapshot → no hydration needed.
9642
- * 2. Otherwise call `MetaService.me` with `withCredentials:true`. The
9643
- * backend reads the HttpOnly cookie server-side and returns the
9644
- * public user fields (and `cookieAuthEnabled` for introspection).
9645
- * 3. If `me()` returns a populated payload, write it to sessionStorage
9646
- * via `userInfoService.setUserInfoCookie` so subsequent calls see
9647
- * the user. If `me()` returns an empty object `{}` (no valid
9648
- * cookie) the hydration is a no-op and the UI stays logged out.
9649
- *
9650
- * Errors are swallowed on purpose: if `me()` throws (network, backend
9651
- * down, legacy backend without the endpoint), we fall back to whatever
9652
- * the cookie/sessionStorage already has without blocking the boot.
10223
+ * Annulla l'inline edit locale della riga corrente.
9653
10224
  */
9654
- private hydrateFromServerCookie;
10225
+ cancelEdit(): Promise<void>;
9655
10226
  /**
9656
- * Ricalcola lo stato autenticazione combinando configurazione OAuth, endpoint `Auth/Enabled`, endpoint `Auth/Me`
9657
- * e fallback sessione legacy (`k-user`), poi sincronizza eventuali custom settings utente.
10227
+ * Hook evento click principale (attualmente usato come placeholder/debug).
10228
+ * @param $event Evento click.
9658
10229
  */
9659
- refreshAll(): Promise<void>;
10230
+ onClick($event: any): void;
9660
10231
  /**
9661
- * Aggiorna il `returnUrl` nello stato sessione applicando normalizzazione anti-open-redirect.
9662
- * @param returnUrl URL di ritorno post login/logout.
10232
+ * Hook richiamato alla chiusura del menu split button.
10233
+ * @param $event Evento PrimeNG.
9663
10234
  */
9664
- setReturnUrl(returnUrl: string): void;
10235
+ onMenuHide($event: any): void;
9665
10236
  /**
9666
- * Avvia il login OAuth reindirizzando il browser a `Auth/Login` con `returnUrl` codificato.
9667
- * @param returnUrl URL di ritorno post login/logout.
10237
+ * Hook richiamato all'apertura del menu split button.
10238
+ * @param $event Evento PrimeNG.
9668
10239
  */
9669
- login(returnUrl?: string): void;
10240
+ onMenuShow($event: any): void;
9670
10241
  /**
9671
- * Esegue logout OAuth: pulisce prima stato client (storage + DB locali) e custom settings, poi redirect a `Auth/Logout`.
9672
- * @param returnUrl URL di ritorno post login/logout.
10242
+ * Hook click dropdown del pulsante azioni (punto estensione per custom behavior).
10243
+ * @param $event Evento click dropdown.
9673
10244
  */
9674
- logout(returnUrl?: string): Promise<void>;
10245
+ onDropdownClick($event: any): void;
9675
10246
  /**
9676
- * Esegue login legacy via `MetaService.login`, interpreta le varianti payload storiche (`isLogged`, `value`, JSON string)
9677
- * e in caso positivo salva l'utente nel cookie `k-user`.
9678
- * @param username Username credenziale di autenticazione.
9679
- * @param password Password credenziale di autenticazione.
10247
+ * Ferma la propagazione dell'evento per evitare side effects sul contenitore (es. row click/select).
10248
+ * @param $event Evento DOM.
9680
10249
  */
9681
- legacyLogin(username: string, password: string, captchaToken?: string): Promise<boolean>;
10250
+ fix($event: any): void;
10251
+ /**
10252
+ * Apre/chiude il popup menu in modalita semplificata con overlay appeso al body.
10253
+ * Evita clipping dentro i contenitori FullCalendar.
10254
+ * @param event Evento click del trigger.
10255
+ */
10256
+ onSimplifiedMenuClick(event: Event): void;
10257
+ onSimplifiedMenuShow(): void;
10258
+ onSimplifiedMenuHide(): void;
9682
10259
  /**
9683
- * Logout flow that works in BOTH cookie modes:
9684
- *
9685
- * - **Server-managed mode** (`enableCookieAuthentication=true`): the
9686
- * `k-user` cookie is HttpOnly, so the only way to delete it is via a
9687
- * `Set-Cookie` delete header from the server. We call
9688
- * `MetaService.logoutSession` (parameterless) which:
9689
- * 1. derives the user from the cookie server-side,
9690
- * 2. wipes the DB session token via the existing `logout(user)`
9691
- * per-DBMS dispatcher,
9692
- * 3. emits the `Set-Cookie` delete with matching CookieOptions.
9693
- *
9694
- * - **Legacy mode** (`enableCookieAuthentication=false`): we still call
9695
- * `logoutSession` because the server-side helper is idempotent in
9696
- * legacy mode and always wipes the DB token. The local
9697
- * `userInfoService.clearUserInfo()` then deletes the JS-readable
9698
- * cookie + sessionStorage snapshot.
9699
- *
9700
- * Why not call the legacy `MetaService.logout(user)` overload? It only
9701
- * runs the per-DBMS DB cleanup; it does NOT emit the cookie delete
9702
- * header, so the HttpOnly cookie would survive the logout in
9703
- * server-managed mode and the next page load would re-hydrate the
9704
- * supposedly-logged-out user via `MetaService.me`. The new
9705
- * `logoutSession` does both atomically.
10260
+ * Abilita modalita inline-cell-editing via metadata tabella (con fallback legacy).
9706
10261
  */
9707
- legacyLogout(): Promise<void>;
10262
+ isInlineCellEditingEnabled(): boolean;
9708
10263
  /**
9709
- * Pulisce lo stato runtime e le cache associate.
9710
- * Gestisce anche persistenza locale su IndexedDB/Dexie quando prevista.
9711
- * @returns Valore restituito dal metodo (Promise<void>).
10264
+ * In inline-cell-editing, anche se la riga e marcata editing, mostra menu standard senza "edit".
9712
10265
  */
9713
- private clearClientRuntimeState;
10266
+ showInlineEditingMenu(): boolean;
9714
10267
  /**
9715
- * Pulisce lo stato runtime e le cache associate.
9716
- * Legge/scrive dati persistenti su storage browser.
10268
+ * Modello menu effettivo da renderizzare nel pulsante azioni.
9717
10269
  */
9718
- private clearBrowserStorage;
10270
+ getActionMenuModel(): MenuItem[];
10271
+ private toBooleanLoose;
10272
+ addRecord(): void;
10273
+ static ɵfac: i0.ɵɵFactoryDeclaration<DataActionButtonComponent, never>;
10274
+ static ɵcmp: i0.ɵɵComponentDeclaration<DataActionButtonComponent, "wuic-data-action-button", never, { "data": { "alias": "data"; "required": false; }; "metaInfo": { "alias": "metaInfo"; "required": false; }; "datasource": { "alias": "datasource"; "required": false; }; "filter": { "alias": "filter"; "required": false; }; "simplified": { "alias": "simplified"; "required": false; }; "parentField": { "alias": "parentField"; "required": false; }; }, {}, never, never, true, never>;
10275
+ }
10276
+
10277
+ declare class LazyDataActionButtonComponent implements OnInit {
10278
+ private readonly cdr;
9719
10279
  /**
9720
- * Rimuove i dati target aggiornando lo stato del servizio.
9721
- * Gestisce anche persistenza locale su IndexedDB/Dexie quando prevista.
9722
- * @param dbName Nome database locale/remote da trattare.
9723
- * @returns Valore restituito dal metodo (Promise<void>).
10280
+ * Input dal componente padre per data; usata nella configurazione e nel rendering del componente.
9724
10281
  */
9725
- private deleteDexieDatabase;
10282
+ data: any;
9726
10283
  /**
9727
- * Rimuove i dati target aggiornando lo stato del servizio.
9728
- * Gestisce anche persistenza locale su IndexedDB/Dexie quando prevista.
9729
- * @param dbName Nome database locale/remote da trattare.
9730
- * @returns Valore restituito dal metodo (Promise<void>).
10284
+ * Input dal componente padre per meta info; usata nella configurazione e nel rendering del componente.
9731
10285
  */
9732
- private deleteIndexedDbByName;
10286
+ metaInfo: MetaInfo;
9733
10287
  /**
9734
- * Carica e cache-a i custom settings dell'utente loggato in localStorage allineando il bootstrap sessione con MetadataProvider.
10288
+ * Input dal componente padre per datasource; usata nella configurazione e nel rendering del componente.
9735
10289
  */
9736
- private bootstrapUserCustomSettings;
10290
+ datasource: BehaviorSubject<any>;
9737
10291
  /**
9738
- * Configura il timeout di sessione in minuti. Chiamato dal meta-menu dopo aver letto AuthConfig.
10292
+ * Input dal componente padre per filter; usata nella configurazione e nel rendering del componente.
9739
10293
  */
9740
- setSessionTimeout(minutes: number, warningMinutes?: number): void;
9741
- private activityListenersAttached;
9742
- /** Timestamp dell'ultimo reset throttled, in ms epoch. */
9743
- private lastActivityResetAt;
9744
- /** Min intervallo tra reset throttled (mousemove/scroll). 1s e' un buon compromesso
9745
- * tra responsiveness al "vero" idle e overhead da event flood. */
9746
- private static readonly ACTIVITY_RESET_THROTTLE_MS;
9747
- private setupActivityListeners;
10294
+ filter?: () => void;
9748
10295
  /**
9749
- * Avvia/riavvia i timer di sessione. Chiamato dopo login e ad ogni attività HTTP.
10296
+ * Input dal componente padre per simplified; usata nella configurazione e nel rendering del componente.
9750
10297
  */
9751
- resetSessionTimer(): void;
9752
- private startSessionExpiryCountdown;
9753
- private handleSessionExpired;
9754
- private clearSessionTimers;
9755
- private isUserAuthenticated;
10298
+ simplified: boolean;
10299
+ parentField: string;
9756
10300
  /**
9757
- * Applica un aggiornamento parziale allo stato `AuthSessionState` preservando le proprieta non toccate.
9758
- * @param partial Delta stato da fondere con lo stato corrente.
10301
+ * Proprieta di stato del componente per loaded component, usata dalla logica interna e dal template.
9759
10302
  */
10303
+ loadedComponent: any;
10304
+ constructor(cdr: ChangeDetectorRef);
9760
10305
  /**
9761
- * Sets a user-visible error message in the auth state.
9762
- * Used by the auth-expired interceptor to communicate the logout
9763
- * reason (e.g. "session replaced by another login") after the
9764
- * logout flow has completed and the login form is visible.
10306
+ * Inizializza il componente preparando stato, sottoscrizioni e primi caricamenti richiesti.
9765
10307
  */
9766
- setError(message: string): void;
9767
- /** User-facing messages keyed by server reason code. */
9768
- private static readonly REASON_MESSAGES;
10308
+ ngOnInit(): Promise<void>;
9769
10309
  /**
9770
- * Reads and removes the redirect reason left by the auth-expired
9771
- * interceptor in localStorage, then sets the corresponding error
9772
- * message in the auth state so the login form displays it.
10310
+ * Gestisce la logica di `componentInputs` con regole guidate dai metadati server `_Metadati_*` (tabella/colonna).
10311
+ * @returns Oggetto risultato costruito dal metodo per il passo successivo del flusso.
10312
+ */
10313
+ componentInputs(): {
10314
+ data: any;
10315
+ metaInfo: MetaInfo;
10316
+ datasource: BehaviorSubject<any>;
10317
+ filter: () => void;
10318
+ simplified: boolean;
10319
+ parentField: string;
10320
+ };
10321
+ static ɵfac: i0.ɵɵFactoryDeclaration<LazyDataActionButtonComponent, never>;
10322
+ static ɵcmp: i0.ɵɵComponentDeclaration<LazyDataActionButtonComponent, "wuic-data-action-button-lazy", never, { "data": { "alias": "data"; "required": false; }; "metaInfo": { "alias": "metaInfo"; "required": false; }; "datasource": { "alias": "datasource"; "required": false; }; "filter": { "alias": "filter"; "required": false; }; "simplified": { "alias": "simplified"; "required": false; }; "parentField": { "alias": "parentField"; "required": false; }; }, {}, never, never, true, never>;
10323
+ }
10324
+
10325
+ /**
10326
+ * Shape of the response returned by `/api/Meta/LicenseStatus` (GET).
10327
+ * The endpoint is defined in `Controllers/MetaController.cs` LicenseStatus action.
10328
+ */
10329
+ interface LicenseStatusResponse {
10330
+ machineFingerprint?: string;
10331
+ licenseValid?: boolean;
10332
+ licenseReason?: string;
10333
+ licenseExpiryUtc?: string | null;
10334
+ licenseEmail?: string;
10335
+ maintenanceExpiryUtc?: string | null;
10336
+ tier?: string;
10337
+ features?: string[];
10338
+ /**
10339
+ * DBMS utilizzato dal backend per il **DB DATI** (`AppSettings.dbms`):
10340
+ * `'mssql'` o `'mysql'`. Aggiunto 2026-04-28 per il tooltip license del
10341
+ * meta-menu — sysadmin vede a colpo d'occhio su quale provider gira il
10342
+ * deploy.
9773
10343
  */
9774
- private applyRedirectReason;
9775
- private patchState;
10344
+ dataDbms?: string;
9776
10345
  /**
9777
- * Costruisce una struttura derivata a partire dallo stato corrente.
9778
- * @param action Azione richiesta nel flusso corrente.
10346
+ * DBMS utilizzato dal backend per il **DB METADATI** (`AppSettings.meta-dbms`).
10347
+ * Tipicamente uguale a `dataDbms` ma puo' divergere quando
10348
+ * `allowMultipleDBMS=true` (es. data MySQL + metadata MSSQL).
9779
10349
  */
9780
- private buildEndpoint;
10350
+ metaDbms?: string;
10351
+ }
10352
+ /**
10353
+ * Client-side view of the current license. Exposes synchronous `has(feature)`
10354
+ * predicate for use in templates, directives, guards, and components.
10355
+ *
10356
+ * Lifecycle:
10357
+ * 1) App bootstrap calls `refresh()` once.
10358
+ * 2) All `*wuicFeature` directives and `FeatureRouteGuard` read from the
10359
+ * cached snapshot via `has()`.
10360
+ * 3) On license change (upgrade via new appsettings.json) restart the app
10361
+ * OR call `refresh()` again to re-fetch.
10362
+ *
10363
+ * IMPORTANT: this service is a UX layer only. The real security is server-side
10364
+ * (see `SanitizeBoardContent` + `[RequireFeature]` + data-decoration in
10365
+ * `AsmxCrudRead`). A client can patch this service and unlock everything locally,
10366
+ * but the server will still refuse premium operations.
10367
+ */
10368
+ declare class LicenseFeatureService {
10369
+ private http;
10370
+ private static readonly ALWAYS_ALLOWED_ARCHETYPES;
10371
+ private statusSubject;
10372
+ private loadedOnce;
9781
10373
  /**
9782
- * Costruisce una struttura derivata a partire dallo stato corrente.
9783
- * @param fullMethodName Nome completo metodo legacy (es. `MetaService.login`).
10374
+ * Promise risolta dopo il PRIMO `refresh()` (success or fail-closed).
10375
+ * Usata dai route guard per attendere che lo snapshot iniziale sia
10376
+ * disponibile prima di decidere access → evita race post-refresh pagina
10377
+ * dove il guard partiva con `statusSubject.value === null` e denyava la
10378
+ * feature anche con licenza valida.
9784
10379
  */
9785
- private buildMetaAsmxEndpoint;
10380
+ private readyResolve;
10381
+ private readyPromise;
10382
+ constructor(http: HttpClient);
9786
10383
  /**
9787
- * Risolve la base URL API usata dal servizio: preferisce `appSettings.api_url`, fallback su `${window.location.origin}/api/`.
10384
+ * Ritorna una Promise che risolve quando il primo `refresh()` ha completato
10385
+ * (con successo o con fail-closed fallback). Dopo il primo load, ritorna
10386
+ * una Promise gia' risolta → overhead zero. Il guard la await per decidere
10387
+ * solo con snapshot reale, non con `null` iniziale.
9788
10388
  */
9789
- private getApiBaseUrl;
10389
+ ready(): Promise<void>;
9790
10390
  /**
9791
- * Valuta una condizione booleana sullo stato o sull'input corrente.
9792
- * @returns Valore restituito dal metodo (boolean).
10391
+ * Observable of the current license status snapshot. Emits `null` until the
10392
+ * first `refresh()` completes.
9793
10393
  */
9794
- private isOAuthEnabledInSettings;
10394
+ status$(): Observable<LicenseStatusResponse | null>;
9795
10395
  /**
9796
- * Normalizza il payload in una forma coerente per i passaggi successivi.
9797
- * @param returnUrl URL di ritorno post login/logout.
10396
+ * Synchronous accessor to the cached snapshot. Returns `null` if not yet loaded.
9798
10397
  */
9799
- private normalizeReturnUrl;
10398
+ snapshot(): LicenseStatusResponse | null;
9800
10399
  /**
9801
- * Ritorna l'URL browser corrente usato come `returnUrl` predefinito in login/logout.
10400
+ * Fetches `/api/Meta/LicenseStatus` and caches the result. Returns the promise
10401
+ * so callers (like an APP_INITIALIZER) can await it.
9802
10402
  */
9803
- private getCurrentLocalUrl;
10403
+ refresh(): Promise<LicenseStatusResponse | null>;
10404
+ /** Idempotent: il primo refresh risolve `readyPromise`; i successivi no-op. */
10405
+ private signalReady;
9804
10406
  /**
9805
- * Esegue il parsing del valore in ingresso con fallback sicuro.
9806
- * @param raw Payload legacy da interpretare (stringa JSON, oggetto o wrapper con `value`).
9807
- * @returns Valore restituito dal metodo (any).
10407
+ * Returns true when the current license includes the given feature flag.
10408
+ * Returns `false` when:
10409
+ * - license not yet loaded (conservative default);
10410
+ * - license is invalid;
10411
+ * - feature is not in the `features` array.
10412
+ *
10413
+ * Wildcard `"*"` nel features array sblocca tutte le feature (usato dai
10414
+ * tier top-level "enterprise" / host-bound bundled e dal server-side
10415
+ * `LicenseFeatureMap.ExpandFeatures` per Pro tier). Senza questo branch
10416
+ * la licenza con `features:["*"]` falliva ogni `has('dashboard-designer'/
10417
+ * 'spreadsheet'/...)` e il client nascondeva tutte le voci di menu
10418
+ * archetype-gated nonostante `licenseValid:true` e tier `professional`.
9808
10419
  */
9809
- private parseLegacyLoginResponse;
10420
+ has(feature: string): boolean;
9810
10421
  /**
9811
- * Estrae un messaggio errore leggibile da payload legacy eterogenei (raw/parsing/error/value) del login storico.
9812
- * @param raw Payload grezzo risposta/errore.
9813
- * @param parsed Payload gia interpretato.
9814
- * @returns Messaggio errore normalizzato oppure `null`.
10422
+ * Returns true when the archetype (e.g. "spreadsheet", "pivot-grid", "list")
10423
+ * is permitted by the current license. Archetypes in the always-allowed set
10424
+ * (list, kanban, chart, ...) return true unconditionally.
9815
10425
  */
9816
- private extractLegacyLoginError;
10426
+ isArchetypeAllowed(archetype: string): boolean;
9817
10427
  /**
9818
- * Prova a leggere un messaggio errore da stringhe plain/JSON o da oggetti con chiavi comuni (`message`, `error`, `ExceptionMessage`).
9819
- * @param candidate Sorgente messaggio da analizzare.
9820
- * @returns Messaggio trovato oppure `null`.
10428
+ * Mirrors the server-side `LicenseFeatureMap.ArchetypeFeatureMap`. Kept
10429
+ * hardcoded on both sides so a patched client gets UX unlock, but the
10430
+ * server-side gate (boardcontent sanitizer + data-decoration) still enforces.
9821
10431
  */
9822
- private readMessage;
10432
+ private archetypeToFeature;
9823
10433
  /**
9824
- * Log diagnostico opzionale del flusso login legacy, attivo solo con `appSettings.debugLegacyLogin === true`.
9825
- * @param kind Tipo evento (`response` o `error`).
9826
- * @param payload Payload da tracciare in console.
10434
+ * Builds the LicenseStatus endpoint URL from `global_root_url`. The root is
10435
+ * typically `"/api/Meta/AsmxProxy/"` (AsmxProxy pattern) or `"/api/Meta/"`
10436
+ * (direct). LicenseStatus is a direct GET action on MetaController, so we
10437
+ * strip any trailing `AsmxProxy/` segment before appending the action name.
9827
10438
  */
9828
- private debugLegacyLogin;
9829
- static ɵfac: i0.ɵɵFactoryDeclaration<AuthSessionService, never>;
9830
- static ɵprov: i0.ɵɵInjectableDeclaration<AuthSessionService>;
10439
+ private resolveLicenseStatusUrl;
10440
+ static ɵfac: i0.ɵɵFactoryDeclaration<LicenseFeatureService, never>;
10441
+ static ɵprov: i0.ɵɵInjectableDeclaration<LicenseFeatureService>;
9831
10442
  }
9832
10443
 
9833
10444
  type WorkflowRuntimeMenuState = {
@@ -9973,6 +10584,13 @@ declare class MetaMenuComponent implements OnInit, AfterViewInit, OnDestroy {
9973
10584
  * tradotti, che e' un'esperienza confusa.
9974
10585
  */
9975
10586
  translationsLoaded$: Observable<boolean>;
10587
+ /**
10588
+ * Stato circuit breaker BE-offline esposto dal TranslationManagerService.
10589
+ * Quando true → mostriamo il banner "Backend offline" + bottone "Riprova"
10590
+ * al posto dello spinner "Loading…" altrimenti infinito. Il click sul
10591
+ * bottone chiama `retryBackend()` che riarma il circuito e ritenta.
10592
+ */
10593
+ backendCircuitOpen$: Observable<boolean>;
9976
10594
  /**
9977
10595
  * Proprieta di stato del componente per auth return url, usata dalla logica interna e dal template.
9978
10596
  */
@@ -10054,6 +10672,14 @@ declare class MetaMenuComponent implements OnInit, AfterViewInit, OnDestroy {
10054
10672
  * @param workflowRuntimeMenu Stream dei menu runtime da fondere con il menu base.
10055
10673
  */
10056
10674
  constructor(metaSrv: MetadataProviderService, authSession: AuthSessionService, trslSrv: TranslationManagerService, userInfo: UserInfoService, workflowRuntimeMenu: WorkflowRuntimeMenuService, http: HttpClient, ngZone: NgZone, router: Router, licenseFeature: LicenseFeatureService, elementRef: ElementRef);
10675
+ /**
10676
+ * Handler del bottone "Riprova" del banner BE-offline. Resetta il circuit
10677
+ * breaker nel TranslationManagerService e tenta immediatamente una nuova
10678
+ * fetch di `MetaService.GetTranslation`. Se il BE e' di nuovo online il
10679
+ * banner sparisce e parte lo spinner standard; se il BE e' ancora offline,
10680
+ * dopo altri 5 fallimenti consecutivi il banner riappare.
10681
+ */
10682
+ retryBackend(): void;
10057
10683
  /**
10058
10684
  * Completa inizializzazione dopo il rendering della view e collega riferimenti UI.
10059
10685
  */
@@ -10293,17 +10919,6 @@ declare class MetaMenuComponent implements OnInit, AfterViewInit, OnDestroy {
10293
10919
  * altrimenti svuota il menu locale e interrompe il flusso.
10294
10920
  */
10295
10921
  private loadMenuIfAllowed;
10296
- /**
10297
- * Removes menu entries pointing to routes that require a license feature not
10298
- * included in the current license. Works recursively on nested items. The
10299
- * `route` shape of menu items comes from `mm_uri_menu` and matches the
10300
- * Angular route templates (e.g. `workflow-designer`, `<route>/spreadsheet`,
10301
- * `<route>/pivot-builder`, `<route>/dashboard`, `rag-chatbot`).
10302
- *
10303
- * UX layer only — server-side `SanitizeBoardContent` + `[RequireFeature]`
10304
- * are the authoritative gates.
10305
- */
10306
- private filterMenuByLicenseFeatures;
10307
10922
  /**
10308
10923
  * Ricompone `items` unendo menu base e runtime; quando `runtimeMenuExclusive` è attivo
10309
10924
  * mostra solo le voci runtime.
@@ -12439,6 +13054,14 @@ declare class NotificationBellComponent implements OnInit, OnDestroy {
12439
13054
  deleteNotificationTitle: string;
12440
13055
  private readonly sub;
12441
13056
  constructor(realtime: NotificationRealtimeService, router: Router, trslSrv: TranslationManagerService);
13057
+ /**
13058
+ * Risolve il valore di una translation key con fallback safe.
13059
+ * ngx-translate's `instant()` ritorna la chiave letterale quando la
13060
+ * traduzione non e' ancora caricata; senza il controllo `!== key` il
13061
+ * fallback `|| default` non scatta (la stringa "notification_bell.title"
13062
+ * e' truthy) e l'UI renderizza la chiave grezza.
13063
+ */
13064
+ private safeT;
12442
13065
  /** Risolve i label dalle traduzioni, rispettando eventuali @Input espliciti. */
12443
13066
  private resolveLabels;
12444
13067
  ngOnInit(): Promise<void>;
@@ -12767,6 +13390,8 @@ declare class KanbanListComponent implements OnInit, OnDestroy, IDataBoundHostCo
12767
13390
  private trslSrv;
12768
13391
  private dataProviderSrv;
12769
13392
  private userInfo;
13393
+ private cdr;
13394
+ private ngZone;
12770
13395
  hardcodedRoute: string;
12771
13396
  parentRecord: any;
12772
13397
  parentMetaInfo: MetaInfo;
@@ -12814,7 +13439,7 @@ declare class KanbanListComponent implements OnInit, OnDestroy, IDataBoundHostCo
12814
13439
  private datasourceReadySubscription?;
12815
13440
  private fetchInfoSubscription?;
12816
13441
  private pendingChanges;
12817
- constructor(router: Router, trslSrv: TranslationManagerService, dataProviderSrv: DataProviderService, userInfo: UserInfoService);
13442
+ constructor(router: Router, trslSrv: TranslationManagerService, dataProviderSrv: DataProviderService, userInfo: UserInfoService, cdr: ChangeDetectorRef, ngZone: NgZone);
12818
13443
  private t;
12819
13444
  ngOnInit(): void;
12820
13445
  ngOnDestroy(): void;
@@ -14410,5 +15035,5 @@ declare const THEME_OPTIONS: ThemeOption[];
14410
15035
  declare function getThemeOptions(): ThemeOption[];
14411
15036
  declare function getThemePrimaryHex(value: string): string;
14412
15037
 
14413
- export { AUTH_REDIRECT_REASON_KEY, AppSettingsEditorComponent, AuthSessionService, BooleanEditorComponent, BoundedRepeaterComponent, ButtonEditorComponent, CallbackPipe, CallbackPipe2, CarouselListComponent, CodeAreaEditorComponent, ColorEditorComponent, CrashReporterService, CustomException, DataActionButtonComponent, DataProviderOdataService, DataRepeaterComponent, DataSourceComponent, DateEditorComponent, DesignerRouteComponent, DictionaryEditorComponent, DynamicCompilerService, DynamicRowTemplateComponent, FieldEditorComponent, FilterBarComponent, FilterInfo, FormatGridViewValuePipe, GetSrcUploadPreviewPipe, GlobalHandler, HtmlEditorComponent, ImageWrapperComponent, ImportExportButtonComponent, IsSelectedRowPipe, KanbanListComponent, KanbanOptions, KanbanStatusColumnItem, LazyChartListComponent, LazyCodeEditorComponent, LazyDataActionButtonComponent, LazyDataSourceComponent, LazyFieldEditorComponent, LazyFirstRunWizardComponent, LazyImageWrapperComponent, LazyKanbanListComponent, LazyMetaMenuComponent, LazyPivotBuilderComponent, LazyReportDesignerComponent, LazyReportViewerComponent, LazySchedulerListComponent, LazySpreadsheetListSfComponent, LicenseFeatureService, ListGridComponent, LookupEditorComponent, MapListComponent, MetaInfo, MetaMenuComponent, MetadataEditorService, MetadataProviderService, MetadatiColonna, MetadatiTabella, NotificationBellComponent, NotificationRealtimeService, NumberEditorComponent, PRIMARY_PALETTES, PagerComponent, ParametricDialogComponent, PropertyArrayEditorComponent, PropertyObjectEditorComponent, THEME_OPTIONS, TextAreaEditorComponent, TextEditorComponent, TranslationManagerService, TreeListComponent, TreeViewSelectorComponent, UploadDialogComponent, UploadEditorComponent, UserInfoService, ValidationRule, ValueChangedPayload, VisibleFieldListPipe, WidgetDefinition, WorkflowDesignerRouteComponent, WorkflowRunnerComponent, WorkflowRuntimeMetadataService, WtoolboxService, WuicErrorDialogComponent, WuicErrorInterceptor, WuicFeatureDirective, WuicFrozenColumnDirective, WuicRagChatbotComponent, WuicRagChatbotFabComponent, WuicRagService, WuicRowTogglerDirective, _PRIMENG_TABLE_DIRECTIVES_NAMES, authExpiredInterceptor, boundedRepeaterPendingChangesGuard, featureRouteCanActivateGuard, featureRouteCanMatchGuard, getThemeOptions, getThemePrimaryHex, inferTemplateFieldFromBaseClass, loadBooleanEditorComponent, loadButtonEditorComponent, loadCodeAreaEditorComponent, loadColorEditorComponent, loadDateEditorComponent, loadDictionaryEditorComponent, loadHtmlEditorComponent, loadLookupEditorComponent, loadNumberEditorComponent, loadPropertyArrayEditorComponent, loadPropertyObjectEditorComponent, loadTextAreaEditorComponent, loadTextEditorComponent, loadTreeViewSelectorComponent, loadUploadEditorComponent, menuRouteAccessCanActivateGuard, menuRouteAccessCanMatchGuard, routes, wuicErrorInterceptor };
14414
- export type { AuthSessionState, Breadcrumb, CompileDynamicComponentOptions, CrashReportPayload, CrashReportingConfig, DataSourceAfterSyncEvent, DataSourceBeforeSyncEvent, DataSourceSyncOperation, ErrorDelegate, ErrorDelegateContext, IDataBoundHostComponent, IFieldEditor, KanbanStatusColumn, LicenseStatusResponse, ListGridAfterRenderEvent, ListGridAfterRowRenderEvent, ListGridBeforeRowRenderEvent, MultiDatasourceMeta, NotificationItem, NotifyOptions, RagAskAcceptedResponse, RagAskRequest, RagChatHistorySnapshot, RagChatMessageDto, RagChatMessageStatus, RagChatRequest, RagChatResponse, RagChatSessionDto, RagChatTurn, RagChatbotTurn, RagHealthResponse, RagQueryRequest, RagQueryResponse, RagSource, RealtimeProgressEvent, ThemeOption, ThemePresetName, ThemePrimaryName, WorkflowRuntimeLinkedActionRouteMetadataEntry, WorkflowRuntimePreviousRouteNodeEntry, WorkflowRuntimeRouteMetadataEntry, WorkflowRuntimeRouteNodePayloadEntry };
15038
+ export { AUTH_REDIRECT_REASON_KEY, AppSettingsEditorComponent, AuthSessionService, BooleanEditorComponent, BoundedRepeaterComponent, ButtonEditorComponent, CallbackPipe, CallbackPipe2, CarouselListComponent, CodeAreaEditorComponent, ColorEditorComponent, CrashReporterService, CustomAttributesService, CustomException, DataActionButtonComponent, DataProviderOdataService, DataRepeaterComponent, DataSourceComponent, DateEditorComponent, DesignerRouteComponent, DictionaryEditorComponent, DynamicCompilerService, DynamicRowTemplateComponent, FieldEditorComponent, FilterBarComponent, FilterInfo, FormatGridViewValuePipe, GetSrcUploadPreviewPipe, GlobalHandler, HtmlEditorComponent, ImageWrapperComponent, ImportExportButtonComponent, IsSelectedRowPipe, KanbanListComponent, KanbanOptions, KanbanStatusColumnItem, LazyChartListComponent, LazyCodeEditorComponent, LazyDataActionButtonComponent, LazyDataSourceComponent, LazyFieldEditorComponent, LazyFirstRunWizardComponent, LazyImageWrapperComponent, LazyKanbanListComponent, LazyMetaMenuComponent, LazyPivotBuilderComponent, LazyReportDesignerComponent, LazyReportViewerComponent, LazySchedulerListComponent, LazySpreadsheetListSfComponent, LicenseFeatureService, ListGridComponent, LookupEditorComponent, MapListComponent, MetaInfo, MetaMenuComponent, MetadataEditorService, MetadataProviderService, MetadatiColonna, MetadatiTabella, NotificationBellComponent, NotificationRealtimeService, NumberEditorComponent, PRIMARY_PALETTES, PagerComponent, ParametricDialogComponent, PropertyArrayEditorComponent, PropertyObjectEditorComponent, THEME_OPTIONS, TextAreaEditorComponent, TextEditorComponent, TranslationManagerService, TreeListComponent, TreeViewSelectorComponent, UploadDialogComponent, UploadEditorComponent, UserInfoService, ValidationRule, ValueChangedPayload, VisibleFieldListPipe, WidgetDefinition, WorkflowDesignerRouteComponent, WorkflowRunnerComponent, WorkflowRuntimeMetadataService, WtoolboxService, WuicAziendaSwitcherComponent, WuicErrorDialogComponent, WuicErrorInterceptor, WuicFeatureDirective, WuicFrozenColumnDirective, WuicRagChatbotComponent, WuicRagChatbotFabComponent, WuicRagService, WuicRowTogglerDirective, _PRIMENG_TABLE_DIRECTIVES_NAMES, authExpiredInterceptor, boundedRepeaterPendingChangesGuard, featureRouteCanActivateGuard, featureRouteCanMatchGuard, getThemeOptions, getThemePrimaryHex, inferTemplateFieldFromBaseClass, loadBooleanEditorComponent, loadButtonEditorComponent, loadCodeAreaEditorComponent, loadColorEditorComponent, loadDateEditorComponent, loadDictionaryEditorComponent, loadHtmlEditorComponent, loadLookupEditorComponent, loadNumberEditorComponent, loadPropertyArrayEditorComponent, loadPropertyObjectEditorComponent, loadTextAreaEditorComponent, loadTextEditorComponent, loadTreeViewSelectorComponent, loadUploadEditorComponent, menuRouteAccessCanActivateGuard, menuRouteAccessCanMatchGuard, routes, wuicErrorInterceptor };
15039
+ export type { AuthSessionState, Breadcrumb, CompileDynamicComponentOptions, CrashReportPayload, CrashReportingConfig, CustomAttributeDefinition, CustomAttributeResolved, CustomLookupOption, CustomValue, CvUpsertItem, DataSourceAfterSyncEvent, DataSourceBeforeSyncEvent, DataSourceSyncOperation, ErrorDelegate, ErrorDelegateContext, IDataBoundHostComponent, IFieldEditor, KanbanStatusColumn, LicenseStatusResponse, ListGridAfterRenderEvent, ListGridAfterRowRenderEvent, ListGridBeforeRowRenderEvent, MultiDatasourceMeta, NotificationItem, NotifyOptions, RagAskAcceptedResponse, RagAskRequest, RagChatHistorySnapshot, RagChatMessageDto, RagChatMessageStatus, RagChatRequest, RagChatResponse, RagChatSessionDto, RagChatTurn, RagChatbotTurn, RagHealthResponse, RagQueryRequest, RagQueryResponse, RagSource, RealtimeProgressEvent, ThemeOption, ThemePresetName, ThemePrimaryName, WorkflowRuntimeLinkedActionRouteMetadataEntry, WorkflowRuntimePreviousRouteNodeEntry, WorkflowRuntimeRouteMetadataEntry, WorkflowRuntimeRouteNodePayloadEntry };