ngrx-entity-crud 19.4.0-beta.7 → 19.4.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -399,9 +399,14 @@ import { NecDashboardComponent } from 'ngrx-entity-crud/devtools';
399
399
  lazyReportUrl="assets/lazy-report.json"
400
400
  [idbDatabaseNames]="['NgRxStateStore']"
401
401
  [allowRevealValues]="false"
402
- [pollingMs]="0"></nec-dashboard>`,
402
+ [pollingMs]="0"
403
+ (sliceReset)="onSliceReset($event)"></nec-dashboard>`,
403
404
  })
404
- export class DevPanelComponent {}
405
+ export class DevPanelComponent {
406
+ onSliceReset(sliceKey: string): void {
407
+ // reactivity hook: a CRUD slice has just been reset to its initial state
408
+ }
409
+ }
405
410
  ```
406
411
 
407
412
  Inputs: `blacklist` / `whitelist` (`string[]`, filter store slices), `lazyReportUrl`
@@ -410,13 +415,27 @@ Inputs: `blacklist` / `whitelist` (`string[]`, filter store slices), `lazyReport
410
415
  Firefox / older Safari), `pollingMs` (`number`, auto-refresh; `0` = manual), `allowRevealValues`
411
416
  (`boolean`, opt-in masked value reveal).
412
417
 
418
+ Outputs: `sliceReset` (`EventEmitter<string>`) emits the slice key whenever a full `Reset` is
419
+ dispatched (including via the global **Azzera tutte** button).
420
+
413
421
  Notes:
422
+ - The **Store NgRx** panel exposes per-row actions: **reset** dispatches the library's `Reset`
423
+ action (`[key] Reset`), restoring the slice to its `initialState` (empty entities, selection,
424
+ criteria and responses); **reset responses** dispatches the lighter `ResetResponses`
425
+ (`[key] Reset Response`). A toolbar **Azzera tutte** button resets every listed slice at once.
426
+ All three are destructive and require an inline two-step confirmation before dispatching.
427
+ Because the slice key in the root state matches the action name by convention (the `store`
428
+ schematic feeds the same `Names.NAME` to both `StoreModule.forFeature` and `createCrudActions`),
429
+ the dashboard can target the right action from the slice key alone — no per-domain wiring needed.
430
+ After a reset the dashboard refreshes its counts; if you persist the NgRx state (e.g. to
431
+ IndexedDB), your persistence layer will write back the emptied state, clearing the local data.
414
432
  - IndexedDB is introspected **agnostically** via native APIs (`indexedDB.databases()` + `count()`),
415
433
  with an optional `NEC_IDB_ADAPTER` injection token for custom providers. Byte sizes per
416
434
  record/store are not measurable; only record counts and the aggregate origin quota
417
435
  (`navigator.storage.estimate()`) are shown.
418
- - `<nec-dashboard>` requires Angular 17+ on the consumer (standalone component + control flow);
419
- the main entry-point keeps the wider peer range.
436
+ - `<nec-dashboard>` is a standalone component built with the classic structural directives
437
+ (`*ngIf`/`*ngFor`), so it stays compatible with Angular 14+ consumers; the main entry-point keeps
438
+ the wider peer range.
420
439
 
421
440
  ## Running unit tests
422
441
  Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
@@ -1,4 +1,4 @@
1
- import { OnDestroy, OnInit } from '@angular/core';
1
+ import { EventEmitter, OnDestroy, OnInit } from '@angular/core';
2
2
  import { NecIdbReport, NecQuotaEstimate, NecStorageReport, NecStoreReport } from './models';
3
3
  import * as i0 from "@angular/core";
4
4
  /**
@@ -11,7 +11,7 @@ import * as i0 from "@angular/core";
11
11
  *
12
12
  * Il template usa le direttive strutturali classiche (`*ngIf`/`*ngFor` + `CommonModule`)
13
13
  * anziché il control-flow `@if`/`@for`: così il componente resta compatibile con Angular
14
- * >= 12 (la nuova sintassi alzerebbe il `minVersion` del pacchetto a 17).
14
+ * >= 14 (il `minVersion` del componente standalone; il control-flow lo alzerebbe a 17).
15
15
  */
16
16
  export declare class NecDashboardComponent implements OnInit, OnDestroy {
17
17
  private readonly localStorageProbe;
@@ -29,6 +29,8 @@ export declare class NecDashboardComponent implements OnInit, OnDestroy {
29
29
  pollingMs: number;
30
30
  /** Abilita il reveal opt-in dei valori localStorage (sempre mascherati). Default: false. */
31
31
  allowRevealValues: boolean;
32
+ /** Emesso (con la slice key) a ogni `Reset` completo dispacciato, incluso l'azzera-tutte. */
33
+ sliceReset: EventEmitter<string>;
32
34
  readonly busy: import("@angular/core").WritableSignal<boolean>;
33
35
  readonly lastUpdated: import("@angular/core").WritableSignal<string>;
34
36
  readonly storage: import("@angular/core").WritableSignal<NecStorageReport>;
@@ -36,12 +38,34 @@ export declare class NecDashboardComponent implements OnInit, OnDestroy {
36
38
  readonly idb: import("@angular/core").WritableSignal<NecIdbReport>;
37
39
  readonly storeReport: import("@angular/core").WritableSignal<NecStoreReport>;
38
40
  readonly revealed: import("@angular/core").WritableSignal<Record<string, string>>;
41
+ /** Slice in attesa di conferma per il `Reset` completo (conferma a due step). */
42
+ readonly pendingResetKey: import("@angular/core").WritableSignal<string>;
43
+ /** Slice in attesa di conferma per il `ResetResponses`. */
44
+ readonly pendingResponsesKey: import("@angular/core").WritableSignal<string>;
45
+ /** `true` quando è in attesa di conferma l'azzeramento globale di tutte le slice. */
46
+ readonly pendingResetAll: import("@angular/core").WritableSignal<boolean>;
39
47
  private timer;
48
+ /** Un refresh richiesto mentre un altro è già in corso: viene ri-eseguito al termine. */
49
+ private pendingRefresh;
40
50
  ngOnInit(): void;
41
51
  ngOnDestroy(): void;
42
52
  refresh(): Promise<void>;
43
53
  /** Reveal opt-in di un valore localStorage, sempre passato per `maskValue` (privacy). */
44
54
  reveal(key: string): void;
55
+ /** Step 1: chiede conferma per il `Reset` completo della slice. */
56
+ requestReset(key: string): void;
57
+ /** Step 1: chiede conferma per il `ResetResponses` della slice. */
58
+ requestResetResponses(key: string): void;
59
+ /** Step 1: chiede conferma per l'azzeramento globale di tutte le slice. */
60
+ requestResetAll(): void;
61
+ /** Annulla qualsiasi conferma pendente (reset/responses/azzera-tutte). */
62
+ cancelPending(): void;
63
+ /** Step 2: dispaccia il `Reset` della slice, emette `sliceReset` e ricarica i conteggi. */
64
+ confirmReset(key: string): void;
65
+ /** Step 2: dispaccia il `ResetResponses` della slice e ricarica i conteggi. */
66
+ confirmResetResponses(key: string): void;
67
+ /** Step 2: dispaccia il `Reset` su tutte le slice elencate, emettendo `sliceReset` per ciascuna. */
68
+ confirmResetAll(): void;
45
69
  isSensitive(key: string): boolean;
46
70
  /** trackBy per le righe identificate da `key` (entry localStorage, slice store). */
47
71
  trackByKey(_: number, item: {
@@ -53,6 +77,6 @@ export declare class NecDashboardComponent implements OnInit, OnDestroy {
53
77
  }): string;
54
78
  formatBytes(n: number | undefined | null): string;
55
79
  static ɵfac: i0.ɵɵFactoryDeclaration<NecDashboardComponent, never>;
56
- static ɵcmp: i0.ɵɵComponentDeclaration<NecDashboardComponent, "nec-dashboard", never, { "blacklist": { "alias": "blacklist"; "required": false; }; "whitelist": { "alias": "whitelist"; "required": false; }; "lazyReportUrl": { "alias": "lazyReportUrl"; "required": false; }; "idbDatabaseNames": { "alias": "idbDatabaseNames"; "required": false; }; "pollingMs": { "alias": "pollingMs"; "required": false; }; "allowRevealValues": { "alias": "allowRevealValues"; "required": false; }; }, {}, never, never, true, never>;
80
+ static ɵcmp: i0.ɵɵComponentDeclaration<NecDashboardComponent, "nec-dashboard", never, { "blacklist": { "alias": "blacklist"; "required": false; }; "whitelist": { "alias": "whitelist"; "required": false; }; "lazyReportUrl": { "alias": "lazyReportUrl"; "required": false; }; "idbDatabaseNames": { "alias": "idbDatabaseNames"; "required": false; }; "pollingMs": { "alias": "pollingMs"; "required": false; }; "allowRevealValues": { "alias": "allowRevealValues"; "required": false; }; }, { "sliceReset": "sliceReset"; }, never, never, true, never>;
57
81
  }
58
82
  //# sourceMappingURL=nec-dashboard.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nec-dashboard.component.d.ts","sourceRoot":"","sources":["../../../libs/ngrx-entity-crud/devtools/nec-dashboard.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,SAAS,EACT,MAAM,EAEP,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAC,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EAAC,MAAM,UAAU,CAAC;;AAM1F;;;;;;;;;;;GAWG;AACH,qBAyQa,qBAAsB,YAAW,MAAM,EAAE,SAAS;IAC7D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAuC;IACzE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoC;IACnE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;IAE3D,2DAA2D;IAClD,SAAS,EAAE,MAAM,EAAE,CAAM;IAClC,oFAAoF;IAC3E,SAAS,EAAE,MAAM,EAAE,CAAM;IAClC,wFAAwF;IAC/E,aAAa,EAAE,MAAM,GAAG,IAAI,CAA6B;IAClE,0FAA0F;IACjF,gBAAgB,EAAE,MAAM,EAAE,CAAM;IACzC,oEAAoE;IAC3D,SAAS,SAAK;IACvB,4FAA4F;IACnF,iBAAiB,UAAS;IAEnC,QAAQ,CAAC,IAAI,kDAAiB;IAC9B,QAAQ,CAAC,WAAW,iDAA+B;IACnD,QAAQ,CAAC,OAAO,2DAAyC;IACzD,QAAQ,CAAC,KAAK,2DAAyC;IACvD,QAAQ,CAAC,GAAG,uDAAqC;IACjD,QAAQ,CAAC,WAAW,yDAAuC;IAC3D,QAAQ,CAAC,QAAQ,iEAAsC;IAEvD,OAAO,CAAC,KAAK,CAA+C;IAE5D,QAAQ,IAAI,IAAI;IAOhB,WAAW,IAAI,IAAI;IAOb,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB9B,yFAAyF;IACzF,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKzB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIjC,oFAAoF;IACpF,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;QAAC,GAAG,EAAE,MAAM,CAAA;KAAC,GAAG,MAAM;IAIlD,0FAA0F;IAC1F,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,GAAG,MAAM;IAIpD,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM;yCArFtC,qBAAqB;2CAArB,qBAAqB;CAiGjC"}
1
+ {"version":3,"file":"nec-dashboard.component.d.ts","sourceRoot":"","sources":["../../../libs/ngrx-entity-crud/devtools/nec-dashboard.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,YAAY,EAGZ,SAAS,EACT,MAAM,EAGP,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAC,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EAAC,MAAM,UAAU,CAAC;;AAM1F;;;;;;;;;;;GAWG;AACH,qBAiTa,qBAAsB,YAAW,MAAM,EAAE,SAAS;IAC7D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAuC;IACzE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoC;IACnE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;IAE3D,2DAA2D;IAClD,SAAS,EAAE,MAAM,EAAE,CAAM;IAClC,oFAAoF;IAC3E,SAAS,EAAE,MAAM,EAAE,CAAM;IAClC,wFAAwF;IAC/E,aAAa,EAAE,MAAM,GAAG,IAAI,CAA6B;IAClE,0FAA0F;IACjF,gBAAgB,EAAE,MAAM,EAAE,CAAM;IACzC,oEAAoE;IAC3D,SAAS,SAAK;IACvB,4FAA4F;IACnF,iBAAiB,UAAS;IAEnC,6FAA6F;IACnF,UAAU,uBAA8B;IAElD,QAAQ,CAAC,IAAI,kDAAiB;IAC9B,QAAQ,CAAC,WAAW,iDAA+B;IACnD,QAAQ,CAAC,OAAO,2DAAyC;IACzD,QAAQ,CAAC,KAAK,2DAAyC;IACvD,QAAQ,CAAC,GAAG,uDAAqC;IACjD,QAAQ,CAAC,WAAW,yDAAuC;IAC3D,QAAQ,CAAC,QAAQ,iEAAsC;IACvD,iFAAiF;IACjF,QAAQ,CAAC,eAAe,iDAA+B;IACvD,2DAA2D;IAC3D,QAAQ,CAAC,mBAAmB,iDAA+B;IAC3D,qFAAqF;IACrF,QAAQ,CAAC,eAAe,kDAAiB;IAEzC,OAAO,CAAC,KAAK,CAA+C;IAC5D,yFAAyF;IACzF,OAAO,CAAC,cAAc,CAAS;IAE/B,QAAQ,IAAI,IAAI;IAOhB,WAAW,IAAI,IAAI;IAOb,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B9B,yFAAyF;IACzF,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAKzB,mEAAmE;IACnE,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAM/B,mEAAmE;IACnE,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAMxC,2EAA2E;IAC3E,eAAe,IAAI,IAAI;IAMvB,0EAA0E;IAC1E,aAAa,IAAI,IAAI;IAMrB,2FAA2F;IAC3F,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAO/B,+EAA+E;IAC/E,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAMxC,oGAAoG;IACpG,eAAe,IAAI,IAAI;IAUvB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIjC,oFAAoF;IACpF,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;QAAC,GAAG,EAAE,MAAM,CAAA;KAAC,GAAG,MAAM;IAIlD,0FAA0F;IAC1F,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE;QAAC,IAAI,EAAE,MAAM,CAAA;KAAC,GAAG,MAAM;IAIpD,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM;yCA9JtC,qBAAqB;2CAArB,qBAAqB;CA0KjC"}
@@ -15,6 +15,24 @@ export declare class NecStoreProbeService {
15
15
  private readonly store;
16
16
  /** Lettura sincrona dello stato root (NgRx emette il valore corrente all'iscrizione). */
17
17
  read(opts?: ProbeOptions): NecStoreReport;
18
+ /**
19
+ * Type dell'azione `Reset` della libreria per una slice CRUD.
20
+ *
21
+ * Vale la convenzione degli schematic `store`: la feature key nello stato root coincide col
22
+ * nome passato a `createCrudActions` (entrambi `Names.NAME`), quindi il type `[key] Reset`
23
+ * (vedi `actions.ts`, `CrudEnum.RESET`) è ricostruibile dalla sola `key` letta da {@link read}.
24
+ */
25
+ resetActionType(sliceKey: string): string;
26
+ /** Type dell'azione `ResetResponses` (`[key] Reset Response`): svuota solo la cache delle response. */
27
+ resetResponsesActionType(sliceKey: string): string;
28
+ /**
29
+ * Dispaccia il `Reset` della slice: riporta lo stato a `initialState` (entità, selezione,
30
+ * criteri e response vuoti). La libreria di persistenza, reagendo al cambio di stato, riscrive
31
+ * lo stato vuoto e di fatto svuota i dati salvati in locale.
32
+ */
33
+ reset(sliceKey: string): void;
34
+ /** Dispaccia il `ResetResponses` della slice: svuota solo le response, lasciando entità e selezione. */
35
+ resetResponses(sliceKey: string): void;
18
36
  /** Come `read()`, ma correla con l'inventario statico di `lazy-report.json` (se raggiungibile). */
19
37
  readWithLazyReport(url: string, opts?: ProbeOptions): Promise<NecStoreReport>;
20
38
  private fetchLazyReport;
@@ -1 +1 @@
1
- {"version":3,"file":"nec-store-probe.service.d.ts","sourceRoot":"","sources":["../../../../libs/ngrx-entity-crud/devtools/probes/nec-store-probe.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6B,cAAc,EAAgB,MAAM,WAAW,CAAC;;AAEpF,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;;;GAMG;AACH,qBACa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IAEvC,yFAAyF;IACzF,IAAI,CAAC,IAAI,GAAE,YAAiB,GAAG,cAAc;IA4D7C,mGAAmG;IAC7F,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;YASzE,eAAe;IA6C7B;;;OAGG;IACH,OAAO,CAAC,UAAU;yCA3HP,oBAAoB;6CAApB,oBAAoB;CA8HhC"}
1
+ {"version":3,"file":"nec-store-probe.service.d.ts","sourceRoot":"","sources":["../../../../libs/ngrx-entity-crud/devtools/probes/nec-store-probe.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6B,cAAc,EAAgB,MAAM,WAAW,CAAC;;AAEpF,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;;;GAMG;AACH,qBACa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IAEvC,yFAAyF;IACzF,IAAI,CAAC,IAAI,GAAE,YAAiB,GAAG,cAAc;IA4D7C;;;;;;OAMG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAIzC,uGAAuG;IACvG,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAIlD;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAI7B,wGAAwG;IACxG,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAItC,mGAAmG;IAC7F,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;YASzE,eAAe;IA6C7B;;;OAGG;IACH,OAAO,CAAC,UAAU;yCAzJP,oBAAoB;6CAApB,oBAAoB;CA4JhC"}
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Injectable, Optional, Inject, inject, signal, Input, ChangeDetectionStrategy, Component } from '@angular/core';
2
+ import { InjectionToken, Injectable, Optional, Inject, inject, EventEmitter, signal, Output, Input, ChangeDetectionStrategy, Component } from '@angular/core';
3
3
  import { createSelector, Store } from '@ngrx/store';
4
4
  import { take } from 'rxjs/operators';
5
5
  import * as i1 from '@angular/common';
@@ -442,6 +442,32 @@ class NecStoreProbeService {
442
442
  slices.sort((a, b) => a.key.localeCompare(b.key));
443
443
  return { slices, loadingNames, errors };
444
444
  }
445
+ /**
446
+ * Type dell'azione `Reset` della libreria per una slice CRUD.
447
+ *
448
+ * Vale la convenzione degli schematic `store`: la feature key nello stato root coincide col
449
+ * nome passato a `createCrudActions` (entrambi `Names.NAME`), quindi il type `[key] Reset`
450
+ * (vedi `actions.ts`, `CrudEnum.RESET`) è ricostruibile dalla sola `key` letta da {@link read}.
451
+ */
452
+ resetActionType(sliceKey) {
453
+ return `[${sliceKey}] Reset`;
454
+ }
455
+ /** Type dell'azione `ResetResponses` (`[key] Reset Response`): svuota solo la cache delle response. */
456
+ resetResponsesActionType(sliceKey) {
457
+ return `[${sliceKey}] Reset Response`;
458
+ }
459
+ /**
460
+ * Dispaccia il `Reset` della slice: riporta lo stato a `initialState` (entità, selezione,
461
+ * criteri e response vuoti). La libreria di persistenza, reagendo al cambio di stato, riscrive
462
+ * lo stato vuoto e di fatto svuota i dati salvati in locale.
463
+ */
464
+ reset(sliceKey) {
465
+ this.store.dispatch({ type: this.resetActionType(sliceKey) });
466
+ }
467
+ /** Dispaccia il `ResetResponses` della slice: svuota solo le response, lasciando entità e selezione. */
468
+ resetResponses(sliceKey) {
469
+ this.store.dispatch({ type: this.resetResponsesActionType(sliceKey) });
470
+ }
445
471
  /** Come `read()`, ma correla con l'inventario statico di `lazy-report.json` (se raggiungibile). */
446
472
  async readWithLazyReport(url, opts = {}) {
447
473
  const report = this.read(opts);
@@ -514,7 +540,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
514
540
  *
515
541
  * Il template usa le direttive strutturali classiche (`*ngIf`/`*ngFor` + `CommonModule`)
516
542
  * anziché il control-flow `@if`/`@for`: così il componente resta compatibile con Angular
517
- * >= 12 (la nuova sintassi alzerebbe il `minVersion` del pacchetto a 17).
543
+ * >= 14 (il `minVersion` del componente standalone; il control-flow lo alzerebbe a 17).
518
544
  */
519
545
  class NecDashboardComponent {
520
546
  localStorageProbe = inject(NecLocalStorageProbeService);
@@ -532,6 +558,8 @@ class NecDashboardComponent {
532
558
  pollingMs = 0;
533
559
  /** Abilita il reveal opt-in dei valori localStorage (sempre mascherati). Default: false. */
534
560
  allowRevealValues = false;
561
+ /** Emesso (con la slice key) a ogni `Reset` completo dispacciato, incluso l'azzera-tutte. */
562
+ sliceReset = new EventEmitter();
535
563
  busy = signal(false);
536
564
  lastUpdated = signal(null);
537
565
  storage = signal(null);
@@ -539,7 +567,15 @@ class NecDashboardComponent {
539
567
  idb = signal(null);
540
568
  storeReport = signal(null);
541
569
  revealed = signal({});
570
+ /** Slice in attesa di conferma per il `Reset` completo (conferma a due step). */
571
+ pendingResetKey = signal(null);
572
+ /** Slice in attesa di conferma per il `ResetResponses`. */
573
+ pendingResponsesKey = signal(null);
574
+ /** `true` quando è in attesa di conferma l'azzeramento globale di tutte le slice. */
575
+ pendingResetAll = signal(false);
542
576
  timer = null;
577
+ /** Un refresh richiesto mentre un altro è già in corso: viene ri-eseguito al termine. */
578
+ pendingRefresh = false;
543
579
  ngOnInit() {
544
580
  void this.refresh();
545
581
  if (this.pollingMs > 0) {
@@ -554,10 +590,14 @@ class NecDashboardComponent {
554
590
  }
555
591
  async refresh() {
556
592
  if (this.busy()) {
593
+ // Un refresh è già in corso (es. polling): richiedine uno al termine così i conteggi
594
+ // post-reset non restano stantii se il dispatch arriva mentre l'altro è in volo.
595
+ this.pendingRefresh = true;
557
596
  return;
558
597
  }
559
598
  this.busy.set(true);
560
599
  this.revealed.set({}); // i valori rivelati non sopravvivono a un refresh
600
+ this.cancelPending(); // nessuna conferma "appesa" dopo un refresh/polling
561
601
  try {
562
602
  this.storage.set(this.localStorageProbe.read('local'));
563
603
  this.quota.set(await this.localStorageProbe.estimate());
@@ -573,6 +613,10 @@ class NecDashboardComponent {
573
613
  }
574
614
  finally {
575
615
  this.busy.set(false);
616
+ if (this.pendingRefresh) {
617
+ this.pendingRefresh = false;
618
+ void this.refresh();
619
+ }
576
620
  }
577
621
  }
578
622
  /** Reveal opt-in di un valore localStorage, sempre passato per `maskValue` (privacy). */
@@ -580,6 +624,53 @@ class NecDashboardComponent {
580
624
  const value = this.localStorageProbe.readValue(key) ?? '';
581
625
  this.revealed.update((m) => ({ ...m, [key]: maskValue(key, value) }));
582
626
  }
627
+ /** Step 1: chiede conferma per il `Reset` completo della slice. */
628
+ requestReset(key) {
629
+ this.pendingResponsesKey.set(null);
630
+ this.pendingResetAll.set(false);
631
+ this.pendingResetKey.set(key);
632
+ }
633
+ /** Step 1: chiede conferma per il `ResetResponses` della slice. */
634
+ requestResetResponses(key) {
635
+ this.pendingResetKey.set(null);
636
+ this.pendingResetAll.set(false);
637
+ this.pendingResponsesKey.set(key);
638
+ }
639
+ /** Step 1: chiede conferma per l'azzeramento globale di tutte le slice. */
640
+ requestResetAll() {
641
+ this.pendingResetKey.set(null);
642
+ this.pendingResponsesKey.set(null);
643
+ this.pendingResetAll.set(true);
644
+ }
645
+ /** Annulla qualsiasi conferma pendente (reset/responses/azzera-tutte). */
646
+ cancelPending() {
647
+ this.pendingResetKey.set(null);
648
+ this.pendingResponsesKey.set(null);
649
+ this.pendingResetAll.set(false);
650
+ }
651
+ /** Step 2: dispaccia il `Reset` della slice, emette `sliceReset` e ricarica i conteggi. */
652
+ confirmReset(key) {
653
+ this.storeProbe.reset(key);
654
+ this.sliceReset.emit(key);
655
+ this.cancelPending();
656
+ void this.refresh();
657
+ }
658
+ /** Step 2: dispaccia il `ResetResponses` della slice e ricarica i conteggi. */
659
+ confirmResetResponses(key) {
660
+ this.storeProbe.resetResponses(key);
661
+ this.cancelPending();
662
+ void this.refresh();
663
+ }
664
+ /** Step 2: dispaccia il `Reset` su tutte le slice elencate, emettendo `sliceReset` per ciascuna. */
665
+ confirmResetAll() {
666
+ const slices = this.storeReport()?.slices ?? [];
667
+ for (const s of slices) {
668
+ this.storeProbe.reset(s.key);
669
+ this.sliceReset.emit(s.key);
670
+ }
671
+ this.cancelPending();
672
+ void this.refresh();
673
+ }
583
674
  isSensitive(key) {
584
675
  return looksSensitiveKey(key);
585
676
  }
@@ -604,11 +695,21 @@ class NecDashboardComponent {
604
695
  return `${(n / 1024 / 1024).toFixed(2)} MB`;
605
696
  }
606
697
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: NecDashboardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
607
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: NecDashboardComponent, isStandalone: true, selector: "nec-dashboard", inputs: { blacklist: "blacklist", whitelist: "whitelist", lazyReportUrl: "lazyReportUrl", idbDatabaseNames: "idbDatabaseNames", pollingMs: "pollingMs", allowRevealValues: "allowRevealValues" }, ngImport: i0, template: `
698
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: NecDashboardComponent, isStandalone: true, selector: "nec-dashboard", inputs: { blacklist: "blacklist", whitelist: "whitelist", lazyReportUrl: "lazyReportUrl", idbDatabaseNames: "idbDatabaseNames", pollingMs: "pollingMs", allowRevealValues: "allowRevealValues" }, outputs: { sliceReset: "sliceReset" }, ngImport: i0, template: `
608
699
  <div class="nec-toolbar">
609
700
  <button type="button" (click)="refresh()" [disabled]="busy()">
610
701
  {{ busy() ? 'Aggiorno…' : 'Aggiorna' }}
611
702
  </button>
703
+ <ng-container *ngIf="storeReport()?.slices?.length">
704
+ <span class="nec-confirm" role="alert" *ngIf="pendingResetAll(); else resetAllBtn">
705
+ azzerare tutte le slice?
706
+ <button type="button" class="nec-danger" aria-label="Conferma azzeramento di tutte le slice" (click)="confirmResetAll()">Sì</button>
707
+ <button type="button" aria-label="Annulla azzeramento" (click)="cancelPending()">Annulla</button>
708
+ </span>
709
+ <ng-template #resetAllBtn>
710
+ <button type="button" class="nec-danger" (click)="requestResetAll()">Azzera tutte</button>
711
+ </ng-template>
712
+ </ng-container>
612
713
  <span class="nec-note" *ngIf="lastUpdated()">ultimo aggiornamento: {{ lastUpdated() }}</span>
613
714
  </div>
614
715
 
@@ -733,6 +834,7 @@ class NecDashboardComponent {
733
834
  <th class="num">entità</th>
734
835
  <th class="num">responses</th>
735
836
  <th>stato</th>
837
+ <th>azioni</th>
736
838
  </tr>
737
839
  </thead>
738
840
  <tbody>
@@ -748,6 +850,22 @@ class NecDashboardComponent {
748
850
  s.isLoaded ? 'caricato' : 'idle'
749
851
  }}</span>
750
852
  </td>
853
+ <td class="nec-actions">
854
+ <span class="nec-confirm" role="alert" *ngIf="pendingResetKey() === s.key">
855
+ azzerare la slice?
856
+ <button type="button" class="nec-danger" [attr.aria-label]="'Conferma azzeramento della slice ' + s.key" (click)="confirmReset(s.key)">Sì</button>
857
+ <button type="button" aria-label="Annulla azzeramento" (click)="cancelPending()">Annulla</button>
858
+ </span>
859
+ <span class="nec-confirm" role="alert" *ngIf="pendingResponsesKey() === s.key">
860
+ azzerare le responses?
861
+ <button type="button" class="nec-danger" [attr.aria-label]="'Conferma azzeramento delle responses di ' + s.key" (click)="confirmResetResponses(s.key)">Sì</button>
862
+ <button type="button" aria-label="Annulla azzeramento" (click)="cancelPending()">Annulla</button>
863
+ </span>
864
+ <ng-container *ngIf="pendingResetKey() !== s.key && pendingResponsesKey() !== s.key">
865
+ <button type="button" class="nec-danger" [attr.aria-label]="'Azzera la slice ' + s.key" (click)="requestReset(s.key)">reset</button>
866
+ <button type="button" [attr.aria-label]="'Azzera le responses di ' + s.key" (click)="requestResetResponses(s.key)">reset responses</button>
867
+ </ng-container>
868
+ </td>
751
869
  </tr>
752
870
  </tbody>
753
871
  </table>
@@ -794,7 +912,7 @@ class NecDashboardComponent {
794
912
  </ng-template>
795
913
  </ng-container>
796
914
  </div>
797
- `, isInline: true, styles: [":host{display:block;font-family:system-ui,sans-serif;font-size:13px;color:#1f2933}.nec-toolbar{display:flex;align-items:center;gap:12px;margin-bottom:12px}.nec-panel{border:1px solid #d7dce2;border-radius:6px;padding:12px 16px;margin-bottom:16px}.nec-panel h3{margin:0 0 8px;font-size:14px}table{width:100%;border-collapse:collapse}th,td{text-align:left;padding:4px 8px;border-bottom:1px solid #eceff3}th{font-weight:600;color:#52606d}td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}.nec-note{color:#7b8794;font-style:italic}.nec-badge{display:inline-block;padding:1px 6px;border-radius:10px;font-size:11px;background:#e4e7eb}.nec-badge.loading{background:#fde68a}.nec-badge.error{background:#fca5a5}.nec-badge.lazy{background:#bfdbfe}button{cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
915
+ `, isInline: true, styles: [":host{display:block;font-family:system-ui,sans-serif;font-size:13px;color:#1f2933}.nec-toolbar{display:flex;align-items:center;gap:12px;margin-bottom:12px}.nec-panel{border:1px solid #d7dce2;border-radius:6px;padding:12px 16px;margin-bottom:16px}.nec-panel h3{margin:0 0 8px;font-size:14px}table{width:100%;border-collapse:collapse}th,td{text-align:left;padding:4px 8px;border-bottom:1px solid #eceff3}th{font-weight:600;color:#52606d}td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}.nec-note{color:#7b8794;font-style:italic}.nec-badge{display:inline-block;padding:1px 6px;border-radius:10px;font-size:11px;background:#e4e7eb}.nec-badge.loading{background:#fde68a}.nec-badge.error{background:#fca5a5}.nec-badge.lazy{background:#bfdbfe}button{cursor:pointer}td.nec-actions{white-space:nowrap}.nec-confirm{display:inline-flex;align-items:center;gap:6px;color:#b91c1c}button.nec-danger{border-color:#fca5a5;color:#b91c1c}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
798
916
  }
799
917
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: NecDashboardComponent, decorators: [{
800
918
  type: Component,
@@ -803,6 +921,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
803
921
  <button type="button" (click)="refresh()" [disabled]="busy()">
804
922
  {{ busy() ? 'Aggiorno…' : 'Aggiorna' }}
805
923
  </button>
924
+ <ng-container *ngIf="storeReport()?.slices?.length">
925
+ <span class="nec-confirm" role="alert" *ngIf="pendingResetAll(); else resetAllBtn">
926
+ azzerare tutte le slice?
927
+ <button type="button" class="nec-danger" aria-label="Conferma azzeramento di tutte le slice" (click)="confirmResetAll()">Sì</button>
928
+ <button type="button" aria-label="Annulla azzeramento" (click)="cancelPending()">Annulla</button>
929
+ </span>
930
+ <ng-template #resetAllBtn>
931
+ <button type="button" class="nec-danger" (click)="requestResetAll()">Azzera tutte</button>
932
+ </ng-template>
933
+ </ng-container>
806
934
  <span class="nec-note" *ngIf="lastUpdated()">ultimo aggiornamento: {{ lastUpdated() }}</span>
807
935
  </div>
808
936
 
@@ -927,6 +1055,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
927
1055
  <th class="num">entità</th>
928
1056
  <th class="num">responses</th>
929
1057
  <th>stato</th>
1058
+ <th>azioni</th>
930
1059
  </tr>
931
1060
  </thead>
932
1061
  <tbody>
@@ -942,6 +1071,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
942
1071
  s.isLoaded ? 'caricato' : 'idle'
943
1072
  }}</span>
944
1073
  </td>
1074
+ <td class="nec-actions">
1075
+ <span class="nec-confirm" role="alert" *ngIf="pendingResetKey() === s.key">
1076
+ azzerare la slice?
1077
+ <button type="button" class="nec-danger" [attr.aria-label]="'Conferma azzeramento della slice ' + s.key" (click)="confirmReset(s.key)">Sì</button>
1078
+ <button type="button" aria-label="Annulla azzeramento" (click)="cancelPending()">Annulla</button>
1079
+ </span>
1080
+ <span class="nec-confirm" role="alert" *ngIf="pendingResponsesKey() === s.key">
1081
+ azzerare le responses?
1082
+ <button type="button" class="nec-danger" [attr.aria-label]="'Conferma azzeramento delle responses di ' + s.key" (click)="confirmResetResponses(s.key)">Sì</button>
1083
+ <button type="button" aria-label="Annulla azzeramento" (click)="cancelPending()">Annulla</button>
1084
+ </span>
1085
+ <ng-container *ngIf="pendingResetKey() !== s.key && pendingResponsesKey() !== s.key">
1086
+ <button type="button" class="nec-danger" [attr.aria-label]="'Azzera la slice ' + s.key" (click)="requestReset(s.key)">reset</button>
1087
+ <button type="button" [attr.aria-label]="'Azzera le responses di ' + s.key" (click)="requestResetResponses(s.key)">reset responses</button>
1088
+ </ng-container>
1089
+ </td>
945
1090
  </tr>
946
1091
  </tbody>
947
1092
  </table>
@@ -988,7 +1133,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
988
1133
  </ng-template>
989
1134
  </ng-container>
990
1135
  </div>
991
- `, styles: [":host{display:block;font-family:system-ui,sans-serif;font-size:13px;color:#1f2933}.nec-toolbar{display:flex;align-items:center;gap:12px;margin-bottom:12px}.nec-panel{border:1px solid #d7dce2;border-radius:6px;padding:12px 16px;margin-bottom:16px}.nec-panel h3{margin:0 0 8px;font-size:14px}table{width:100%;border-collapse:collapse}th,td{text-align:left;padding:4px 8px;border-bottom:1px solid #eceff3}th{font-weight:600;color:#52606d}td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}.nec-note{color:#7b8794;font-style:italic}.nec-badge{display:inline-block;padding:1px 6px;border-radius:10px;font-size:11px;background:#e4e7eb}.nec-badge.loading{background:#fde68a}.nec-badge.error{background:#fca5a5}.nec-badge.lazy{background:#bfdbfe}button{cursor:pointer}\n"] }]
1136
+ `, styles: [":host{display:block;font-family:system-ui,sans-serif;font-size:13px;color:#1f2933}.nec-toolbar{display:flex;align-items:center;gap:12px;margin-bottom:12px}.nec-panel{border:1px solid #d7dce2;border-radius:6px;padding:12px 16px;margin-bottom:16px}.nec-panel h3{margin:0 0 8px;font-size:14px}table{width:100%;border-collapse:collapse}th,td{text-align:left;padding:4px 8px;border-bottom:1px solid #eceff3}th{font-weight:600;color:#52606d}td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}.nec-note{color:#7b8794;font-style:italic}.nec-badge{display:inline-block;padding:1px 6px;border-radius:10px;font-size:11px;background:#e4e7eb}.nec-badge.loading{background:#fde68a}.nec-badge.error{background:#fca5a5}.nec-badge.lazy{background:#bfdbfe}button{cursor:pointer}td.nec-actions{white-space:nowrap}.nec-confirm{display:inline-flex;align-items:center;gap:6px;color:#b91c1c}button.nec-danger{border-color:#fca5a5;color:#b91c1c}\n"] }]
992
1137
  }], propDecorators: { blacklist: [{
993
1138
  type: Input
994
1139
  }], whitelist: [{
@@ -1001,6 +1146,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
1001
1146
  type: Input
1002
1147
  }], allowRevealValues: [{
1003
1148
  type: Input
1149
+ }], sliceReset: [{
1150
+ type: Output
1004
1151
  }] } });
1005
1152
 
1006
1153
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ngrx-entity-crud-devtools.mjs","sources":["../../../libs/ngrx-entity-crud/devtools/models.ts","../../../libs/ngrx-entity-crud/devtools/idb-adapter.token.ts","../../../libs/ngrx-entity-crud/devtools/agnostic-selectors.ts","../../../libs/ngrx-entity-crud/devtools/mask.ts","../../../libs/ngrx-entity-crud/devtools/probes/nec-local-storage-probe.service.ts","../../../libs/ngrx-entity-crud/devtools/probes/nec-indexeddb-probe.service.ts","../../../libs/ngrx-entity-crud/devtools/probes/nec-store-probe.service.ts","../../../libs/ngrx-entity-crud/devtools/nec-dashboard.component.ts","../../../libs/ngrx-entity-crud/devtools/public-api.ts","../../../libs/ngrx-entity-crud/devtools/ngrx-entity-crud-devtools.ts"],"sourcesContent":["/**\n * Modelli dei report prodotti dai probe della dashboard (`ngrx-entity-crud/devtools`).\n *\n * Sono volutamente indipendenti dai tipi del main entry-point: i probe leggono lo stato\n * per CONVENZIONE (vedi `EntityCrudBaseState` in `src/lib/models.ts`), non per tipo, così\n * il sotto-modulo `devtools` resta autonomo e agnostico rispetto alla persistenza usata.\n */\n\n// ---------------------------------------------------------------------------\n// localStorage / sessionStorage\n// ---------------------------------------------------------------------------\n\nexport interface NecStorageEntry {\n key: string;\n /** Byte verso la quota (UTF-16): `(key.length + value.length) * 2`. Metrica primaria. */\n bytesUtf16: number;\n /** Byte della serializzazione UTF-8 (`TextEncoder`/`Blob`). Metrica secondaria. */\n bytesUtf8: number;\n}\n\nexport interface NecStorageReport {\n available: boolean;\n type: 'local' | 'session';\n entries: NecStorageEntry[];\n count: number;\n totalBytesUtf16: number;\n totalBytesUtf8: number;\n}\n\n/** Stima quota AGGREGATA per-origine (localStorage + IndexedDB + Cache), non scorporabile. */\nexport interface NecQuotaEstimate {\n available: boolean;\n usage?: number;\n quota?: number;\n /** Non-standard (solo Chromium): byte per area. Assente su Firefox/Safari. */\n usageDetails?: Record<string, number>;\n}\n\n// ---------------------------------------------------------------------------\n// IndexedDB (agnostico)\n// ---------------------------------------------------------------------------\n\nexport interface NecIdbStoreReport {\n name: string;\n /** Numero record (`objectStore.count()`); `null` se non determinabile. */\n count: number | null;\n}\n\nexport interface NecIdbDbReport {\n name: string;\n version: number | null;\n stores: NecIdbStoreReport[];\n note?: string;\n}\n\nexport interface NecIdbReport {\n available: boolean;\n /** `false` se non è stato possibile elencare i database (es. Firefox senza nomi forniti). */\n enumerable: boolean;\n /** Nome dell'adapter usato: `'native'`, il nome di un `NecIdbAdapter`, o `null`. */\n adapter: string | null;\n databases: NecIdbDbReport[];\n note?: string;\n}\n\n/**\n * Punto di estensione agnostico: il consumer può fornire un adapter esplicito (via\n * `NEC_IDB_ADAPTER`) per conteggi accurati quando la sua libreria di persistenza nasconde\n * i nomi DB. Quando assente, il probe usa solo le API native.\n */\nexport interface NecIdbAdapter {\n name: string;\n isAvailable(): boolean;\n listDatabases(): Promise<NecIdbDbReport[]>;\n}\n\n// ---------------------------------------------------------------------------\n// Store NgRx + lazy\n// ---------------------------------------------------------------------------\n\nexport type NecSliceKind = 'plural' | 'singular' | 'unknown';\n\nexport interface NecStoreSlice {\n key: string;\n kind: NecSliceKind;\n isLoading: boolean;\n isLoaded: boolean;\n error: string | null;\n /** Numero entità (solo slice `plural`). */\n entityCount?: number;\n responsesCount: number;\n}\n\nexport type NecRuntimeStatus = 'loaded' | 'lazy-not-loaded' | 'unknown';\n\nexport interface NecLazyEntry {\n name: string;\n clazz?: string;\n type?: string;\n verdict?: string;\n isLazyCandidate: boolean;\n lazyRoute?: boolean;\n sections: string[];\n usedByShell: boolean;\n runtimeStatus: NecRuntimeStatus;\n}\n\nexport interface NecStoreReport {\n slices: NecStoreSlice[];\n loadingNames: string[];\n errors: string[];\n /** Presente solo se è stato fornito un `lazyReportUrl` e il fetch è riuscito. */\n lazy?: NecLazyEntry[];\n /** Timestamp ISO di generazione del `lazy-report.json` (per segnalare snapshot stantii). */\n lazyReportGeneratedAt?: string;\n}\n","import {InjectionToken} from '@angular/core';\nimport {NecIdbAdapter} from './models';\n\n/**\n * Adapter IndexedDB OPZIONALE, agnostico rispetto alla libreria di persistenza.\n *\n * Fornendolo, il `NecIndexedDbProbeService` lo usa con priorità per enumerare i database\n * (utile quando la libreria del consumer nasconde i nomi DB o su browser senza\n * `indexedDB.databases()`, es. Firefox). Quando NON fornito, il probe usa solo le API native.\n */\nexport const NEC_IDB_ADAPTER = new InjectionToken<NecIdbAdapter>('NEC_IDB_ADAPTER');\n","import {createSelector, MemoizedSelector} from '@ngrx/store';\n\n/**\n * Versione FACTORY (parametrizzabile) dei selettori agnostici di loading/error che il\n * template `ng-add` installa in `root-store/selectors.ts`.\n *\n * Il template resta invariato (retro-compatibilità): qui la logica è IDENTICA ma con\n * `rootSelector`/`blacklist`/`whitelist` resi parametri invece che costanti hardcoded, così\n * è riutilizzabile dal pacchetto npm (entry-point `ngrx-entity-crud/devtools`).\n *\n * Scandisce lo stato sfruttando la convenzione `EntityCrudBaseState`: ogni slice CRUD espone\n * `isLoading: boolean` ed `error: string | null` al livello top.\n */\nexport interface AgnosticLoadingSelectorsOptions {\n /** Selettore della radice da scandire (default: l'intero stato root). */\n rootSelector?: (state: any) => Record<string, any>;\n /** Chiavi di slice da escludere dallo scan. */\n blacklist?: ReadonlyArray<string>;\n /** Se valorizzata, considera SOLO queste chiavi (precede la blacklist). */\n whitelist?: ReadonlyArray<string>;\n}\n\nexport interface AgnosticLoadingSelectors {\n /** Nomi delle slice attualmente in caricamento (`isLoading === true`). */\n selectLoadingNames: MemoizedSelector<any, string[]>;\n /** `true` se almeno una slice CRUD è in caricamento. */\n selectIsLoading: MemoizedSelector<any, boolean>;\n /** Elenco degli errori non vuoti presenti nelle slice CRUD. */\n selectErrors: MemoizedSelector<any, string[]>;\n /** Concatenazione degli errori non vuoti (stringa vuota se non ce ne sono). */\n selectError: MemoizedSelector<any, string>;\n}\n\ninterface LoadingSlice {\n isLoading?: boolean;\n error?: string | null;\n}\n\nexport function createAgnosticLoadingSelectors(\n options: AgnosticLoadingSelectorsOptions = {}\n): AgnosticLoadingSelectors {\n const rootSelector = options.rootSelector ?? ((state: any): Record<string, any> => state);\n const blacklist = options.blacklist ?? [];\n const whitelist = options.whitelist ?? [];\n\n const isEligible = (key: string): boolean =>\n whitelist.length > 0 ? whitelist.includes(key) : !blacklist.includes(key);\n\n const isLoadingSlice = (value: any): value is LoadingSlice =>\n !!value && typeof value === 'object' && typeof value.isLoading === 'boolean';\n\n const crudEntries = (state: Record<string, any>): Array<[string, LoadingSlice]> =>\n Object.entries(state || {})\n .filter(([key]) => isEligible(key))\n .filter((entry): entry is [string, LoadingSlice] => isLoadingSlice(entry[1]));\n\n const selectLoadingNames = createSelector(rootSelector, (state): string[] =>\n crudEntries(state)\n .filter(([, slice]) => slice.isLoading === true)\n .map(([key]) => key)\n );\n\n const selectIsLoading = createSelector(\n selectLoadingNames,\n (names): boolean => names.length > 0\n );\n\n const selectErrors = createSelector(rootSelector, (state): string[] =>\n crudEntries(state)\n .map(([, slice]) => slice.error)\n .filter((error): error is string => typeof error === 'string' && error.length > 0)\n );\n\n const selectError = createSelector(selectErrors, (errors): string => errors.join('\\n'));\n\n return {selectLoadingNames, selectIsLoading, selectErrors, selectError};\n}\n","/**\n * Utility di privacy per la dashboard: poiché può girare anche in PRODUZIONE, i valori non\n * vengono mai mostrati di default e — quando il consumer abilita esplicitamente il reveal —\n * vengono comunque mascherati i pattern sensibili (token/JWT/email/segreti).\n */\n\nconst SENSITIVE_KEY =\n /(token|secret|password|passwd|pwd|auth(orization)?|credential|api[-_]?key|jwt|session|cookie|bearer)/i;\n\n/** `true` se il nome chiave suggerisce un contenuto sensibile (token, password, ecc.). */\nexport function looksSensitiveKey(key: string): boolean {\n return SENSITIVE_KEY.test(key || '');\n}\n\n/** Redige nel testo i pattern sensibili comuni (JWT, email, token/hex lunghi). */\nexport function redactSensitive(value: string): string {\n return (value || '')\n .replace(/eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, '«jwt-redatto»')\n .replace(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}/g, '«email-redatta»')\n .replace(/\\b[A-Fa-f0-9]{32,}\\b/g, '«hex-redatto»')\n .replace(/\\b[A-Za-z0-9_-]{40,}\\b/g, '«token-redatto»');\n}\n\n/**\n * Valore \"sicuro da mostrare\": se la chiave è sensibile, nasconde tutto (mostra solo la\n * lunghezza); altrimenti redige i pattern sensibili e tronca a `maxLength`.\n */\nexport function maskValue(key: string, value: string, maxLength = 200): string {\n if (looksSensitiveKey(key)) {\n return `«nascosto» (${(value || '').length} caratteri)`;\n }\n let out = redactSensitive(value);\n if (out.length > maxLength) {\n out = out.slice(0, maxLength) + '… (troncato)';\n }\n return out;\n}\n","import {Injectable} from '@angular/core';\nimport {NecQuotaEstimate, NecStorageEntry, NecStorageReport} from '../models';\n\n/**\n * Riepilogo di `localStorage` / `sessionStorage`.\n *\n * Sincrono per la lettura delle chiavi. NON espone i valori: solo chiavi e dimensioni\n * (privacy). La metrica primaria verso la quota è UTF-16 `(key.length + value.length) * 2`,\n * perché è ciò che conta verso il limite ~5-10MB; la metrica UTF-8 è secondaria.\n */\n@Injectable({providedIn: 'root'})\nexport class NecLocalStorageProbeService {\n read(type: 'local' | 'session' = 'local'): NecStorageReport {\n const empty: NecStorageReport = {\n available: false,\n type,\n entries: [],\n count: 0,\n totalBytesUtf16: 0,\n totalBytesUtf8: 0,\n };\n\n if (typeof window === 'undefined') {\n return empty;\n }\n\n let storage: Storage | null = null;\n try {\n storage = type === 'local' ? window.localStorage : window.sessionStorage;\n } catch {\n // accesso negato (sandbox/incognito/policy)\n return empty;\n }\n if (!storage) {\n return empty;\n }\n\n const entries: NecStorageEntry[] = [];\n let totalBytesUtf16 = 0;\n let totalBytesUtf8 = 0;\n\n try {\n for (let i = 0; i < storage.length; i++) {\n const key = storage.key(i);\n if (key == null) {\n continue;\n }\n const value = storage.getItem(key) ?? '';\n const bytesUtf16 = (key.length + value.length) * 2;\n const bytesUtf8 = this.utf8Bytes(key + value);\n totalBytesUtf16 += bytesUtf16;\n totalBytesUtf8 += bytesUtf8;\n entries.push({key, bytesUtf16, bytesUtf8});\n }\n } catch {\n // accesso parziale negato: ritorna ciò che è stato raccolto finora\n }\n\n entries.sort((a, b) => b.bytesUtf16 - a.bytesUtf16);\n\n return {\n available: true,\n type,\n entries,\n count: entries.length,\n totalBytesUtf16,\n totalBytesUtf8,\n };\n }\n\n /**\n * Legge ON-DEMAND il valore grezzo di una singola chiave (per il reveal esplicito in UI).\n * Non viene mai incluso nel report: la dashboard lo richiede solo su azione dell'utente e lo\n * maschera tramite `maskValue`.\n */\n readValue(key: string, type: 'local' | 'session' = 'local'): string | null {\n if (typeof window === 'undefined') {\n return null;\n }\n try {\n const storage = type === 'local' ? window.localStorage : window.sessionStorage;\n return storage ? storage.getItem(key) : null;\n } catch {\n return null;\n }\n }\n\n /**\n * Stima quota AGGREGATA per-origine (include anche IndexedDB e Cache): NON è scorporabile\n * per area. Può essere assente (Safari/contesto non sicuro) o arrotondata (anti-fingerprint).\n */\n async estimate(): Promise<NecQuotaEstimate> {\n const empty: NecQuotaEstimate = {available: false};\n if (\n typeof navigator === 'undefined' ||\n !navigator.storage ||\n typeof navigator.storage.estimate !== 'function'\n ) {\n return empty;\n }\n try {\n const est = await navigator.storage.estimate();\n return {\n available: true,\n usage: est.usage,\n quota: est.quota,\n usageDetails: (est as {usageDetails?: Record<string, number>}).usageDetails,\n };\n } catch {\n return empty;\n }\n }\n\n private utf8Bytes(s: string): number {\n try {\n if (typeof TextEncoder !== 'undefined') {\n return new TextEncoder().encode(s).length;\n }\n } catch {\n /* noop */\n }\n try {\n if (typeof Blob !== 'undefined') {\n return new Blob([s]).size;\n }\n } catch {\n /* noop */\n }\n return s.length;\n }\n}\n","import {Inject, Injectable, Optional} from '@angular/core';\nimport {NecIdbAdapter, NecIdbDbReport, NecIdbReport, NecIdbStoreReport} from '../models';\nimport {NEC_IDB_ADAPTER} from '../idb-adapter.token';\n\n/**\n * Riepilogo IndexedDB AGNOSTICO rispetto alla libreria di persistenza.\n *\n * Priorità reale: (1) `NEC_IDB_ADAPTER` esplicito, (2) API native\n * (`indexedDB.databases()` + `open()` + `count()`). NESSUN import di librerie di\n * persistenza. Mostra il numero di record per object store; i byte per-store NON sono\n * misurabili e non vengono promessi (solo la quota aggregata, altrove).\n */\n@Injectable({providedIn: 'root'})\nexport class NecIndexedDbProbeService {\n constructor(@Optional() @Inject(NEC_IDB_ADAPTER) private readonly adapter: NecIdbAdapter | null) {}\n\n /**\n * @param fallbackDatabaseNames nomi DB da ispezionare quando `indexedDB.databases()` non\n * è supportato (Firefox / Safari vecchi). Passa qui i nomi noti della tua persistenza.\n * @param openTimeoutMs timeout per ogni `open()` (default 3000ms).\n */\n async read(fallbackDatabaseNames: string[] = [], openTimeoutMs = 3000): Promise<NecIdbReport> {\n // 1) adapter esplicito: path prioritario e agnostico, indipendente dalle API native\n // (il consumer può fornire conteggi anche dove l'introspezione nativa non basta).\n if (this.adapter && this.adapter.isAvailable()) {\n try {\n const databases = await this.adapter.listDatabases();\n return {available: true, enumerable: true, adapter: this.adapter.name, databases};\n } catch {\n // degrada al path nativo\n }\n }\n\n // 2) path nativo: richiede l'API IndexedDB del browser\n if (typeof indexedDB === 'undefined') {\n return {\n available: false,\n enumerable: false,\n adapter: null,\n databases: [],\n note: 'IndexedDB non disponibile in questo contesto',\n };\n }\n\n const names = await this.listDatabaseNames(fallbackDatabaseNames);\n if (!names.length) {\n return {\n available: true,\n enumerable: false,\n adapter: 'native',\n databases: [],\n note:\n 'Impossibile elencare i database: indexedDB.databases() non supportato (es. Firefox) ' +\n 'e nessun nome fornito. Passa i nomi DB noti via input \"idbDatabaseNames\".',\n };\n }\n\n const databases: NecIdbDbReport[] = [];\n for (const name of names) {\n databases.push(await this.inspectDatabase(name, openTimeoutMs));\n }\n return {available: true, enumerable: true, adapter: 'native', databases};\n }\n\n private async listDatabaseNames(fallback: string[]): Promise<string[]> {\n const idbAny = indexedDB as unknown as {\n databases?: () => Promise<Array<{name?: string}>>;\n };\n if (typeof idbAny.databases === 'function') {\n try {\n const list = await idbAny.databases();\n const names = list.map((d) => d.name).filter((n): n is string => !!n);\n if (names.length) {\n return names;\n }\n } catch {\n // ignora: usa il fallback\n }\n }\n return Array.from(new Set(fallback.filter(Boolean)));\n }\n\n private inspectDatabase(name: string, timeoutMs: number): Promise<NecIdbDbReport> {\n return new Promise<NecIdbDbReport>((resolve) => {\n let settled = false;\n const done = (report: NecIdbDbReport): void => {\n if (settled) {\n return;\n }\n settled = true;\n resolve(report);\n };\n\n const timer = setTimeout(\n () => done({name, version: null, stores: [], note: 'timeout apertura DB'}),\n timeoutMs\n );\n\n let request: IDBOpenDBRequest;\n try {\n request = indexedDB.open(name);\n } catch {\n clearTimeout(timer);\n done({name, version: null, stores: [], note: 'open() fallita'});\n return;\n }\n\n request.onblocked = () => {\n clearTimeout(timer);\n done({\n name,\n version: null,\n stores: [],\n note: 'apertura bloccata (versionchange in un\\'altra scheda)',\n });\n };\n\n request.onerror = () => {\n clearTimeout(timer);\n done({name, version: null, stores: [], note: 'errore apertura DB (o DB inesistente)'});\n };\n\n request.onupgradeneeded = (event) => {\n // Il DB non esisteva: NON crearne lo schema. Annulla la transazione di upgrade\n // (provoca onerror e rollback della creazione) per non sporcare l'origine.\n try {\n (event.target as IDBOpenDBRequest).transaction?.abort();\n } catch {\n /* noop */\n }\n };\n\n request.onsuccess = () => {\n const db = request.result;\n const version = db.version;\n const storeNames = Array.from(db.objectStoreNames);\n\n if (!storeNames.length) {\n clearTimeout(timer);\n db.close();\n done({name, version, stores: []});\n return;\n }\n\n let tx: IDBTransaction;\n try {\n tx = db.transaction(storeNames, 'readonly');\n } catch {\n clearTimeout(timer);\n db.close();\n done({\n name,\n version,\n stores: storeNames.map((s): NecIdbStoreReport => ({name: s, count: null})),\n });\n return;\n }\n\n const stores: NecIdbStoreReport[] = storeNames.map((s) => ({name: s, count: null}));\n let pending = storeNames.length;\n const finalize = (): void => {\n if (--pending === 0) {\n clearTimeout(timer);\n db.close();\n done({name, version, stores});\n }\n };\n\n storeNames.forEach((s, idx) => {\n try {\n const countReq = tx.objectStore(s).count();\n countReq.onsuccess = () => {\n stores[idx].count = countReq.result;\n finalize();\n };\n countReq.onerror = () => finalize();\n } catch {\n finalize();\n }\n });\n };\n });\n }\n}\n","import {inject, Injectable} from '@angular/core';\nimport {Store} from '@ngrx/store';\nimport {take} from 'rxjs/operators';\nimport {NecLazyEntry, NecSliceKind, NecStoreReport, NecStoreSlice} from '../models';\n\ninterface ProbeOptions {\n blacklist?: string[];\n whitelist?: string[];\n}\n\n/**\n * Riepilogo degli store NgRx a runtime.\n *\n * Enumera le slice CRUD montate per CONVENZIONE (`typeof value.isLoading === 'boolean'`,\n * vedi `EntityCrudBaseState`), senza dipendere dai selettori per-dominio. Una slice lazy non\n * ancora caricata semplicemente non ha la chiave nello stato root.\n */\n@Injectable({providedIn: 'root'})\nexport class NecStoreProbeService {\n private readonly store = inject(Store);\n\n /** Lettura sincrona dello stato root (NgRx emette il valore corrente all'iscrizione). */\n read(opts: ProbeOptions = {}): NecStoreReport {\n const blacklist = opts.blacklist ?? [];\n const whitelist = opts.whitelist ?? [];\n\n let root: Record<string, any> = {};\n this.store\n .select((s) => s as Record<string, any>)\n .pipe(take(1))\n .subscribe((s) => (root = s ?? {}));\n\n const isEligible = (key: string): boolean =>\n whitelist.length > 0 ? whitelist.includes(key) : !blacklist.includes(key);\n\n const slices: NecStoreSlice[] = [];\n const loadingNames: string[] = [];\n const errors: string[] = [];\n\n for (const [key, value] of Object.entries(root)) {\n if (!isEligible(key)) {\n continue;\n }\n if (!value || typeof value !== 'object' || typeof value.isLoading !== 'boolean') {\n continue;\n }\n const v = value as Record<string, any>;\n const kind: NecSliceKind = Array.isArray(v['ids'])\n ? 'plural'\n : 'item' in v\n ? 'singular'\n : 'unknown';\n const error =\n typeof v['error'] === 'string' && v['error'].length > 0 ? (v['error'] as string) : null;\n\n const slice: NecStoreSlice = {\n key,\n kind,\n isLoading: v['isLoading'] === true,\n isLoaded: v['isLoaded'] === true,\n error,\n entityCount:\n kind === 'plural'\n ? Array.isArray(v['ids'])\n ? v['ids'].length\n : Object.keys(v['entities'] ?? {}).length\n : undefined,\n responsesCount: Array.isArray(v['responses']) ? v['responses'].length : 0,\n };\n slices.push(slice);\n if (slice.isLoading) {\n loadingNames.push(key);\n }\n if (slice.error) {\n errors.push(`${key}: ${slice.error}`);\n }\n }\n\n slices.sort((a, b) => a.key.localeCompare(b.key));\n return {slices, loadingNames, errors};\n }\n\n /** Come `read()`, ma correla con l'inventario statico di `lazy-report.json` (se raggiungibile). */\n async readWithLazyReport(url: string, opts: ProbeOptions = {}): Promise<NecStoreReport> {\n const report = this.read(opts);\n const fetched = await this.fetchLazyReport(url, report);\n if (!fetched) {\n return report;\n }\n return {...report, lazy: fetched.entries, lazyReportGeneratedAt: fetched.generatedAt};\n }\n\n private async fetchLazyReport(\n url: string,\n report: NecStoreReport\n ): Promise<{entries: NecLazyEntry[]; generatedAt?: string} | undefined> {\n if (typeof fetch !== 'function') {\n return undefined;\n }\n let json: any;\n try {\n const res = await fetch(url, {headers: {Accept: 'application/json'}});\n if (!res.ok) {\n return undefined;\n }\n json = await res.json();\n } catch {\n return undefined;\n }\n\n const stores: any[] = Array.isArray(json?.stores) ? json.stores : [];\n const mounted = new Set(report.slices.map((s) => s.key));\n const generatedAt = typeof json?.generatedAt === 'string' ? json.generatedAt : undefined;\n\n const entries = stores.map((st): NecLazyEntry => {\n const sliceKey = this.toSliceKey(st?.name);\n const isLoaded = mounted.has(sliceKey) || mounted.has(st?.name);\n const isLazyCandidate =\n typeof st?.isLazyCandidate === 'boolean'\n ? st.isLazyCandidate\n : /candidato lazy/i.test(st?.verdict ?? '');\n return {\n name: st?.name,\n clazz: st?.clazz,\n type: st?.type,\n verdict: st?.verdict,\n isLazyCandidate,\n lazyRoute: typeof st?.lazyRoute === 'boolean' ? st.lazyRoute : undefined,\n sections: Array.isArray(st?.sections) ? st.sections : [],\n usedByShell: !!st?.usedByShell,\n runtimeStatus: isLoaded ? 'loaded' : isLazyCandidate ? 'lazy-not-loaded' : 'unknown',\n };\n });\n\n return {entries, generatedAt};\n }\n\n /**\n * Best-effort: il root state usa `strings.underscore(name)` come chiave di slice, mentre il\n * report usa il nome dasherizzato. (Fase 1: far emettere a `lazy-report` la feature key reale.)\n */\n private toSliceKey(name: string): string {\n return (name ?? '').replace(/-/g, '_');\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n inject,\n Input,\n OnDestroy,\n OnInit,\n signal,\n} from '@angular/core';\nimport {CommonModule} from '@angular/common';\nimport {NecIdbReport, NecQuotaEstimate, NecStorageReport, NecStoreReport} from './models';\nimport {NecLocalStorageProbeService} from './probes/nec-local-storage-probe.service';\nimport {NecIndexedDbProbeService} from './probes/nec-indexeddb-probe.service';\nimport {NecStoreProbeService} from './probes/nec-store-probe.service';\nimport {looksSensitiveKey, maskValue} from './mask';\n\n/**\n * `<nec-dashboard>` — dashboard di gestione progetto plug-and-play.\n *\n * Standalone, OnPush, template HTML inline (nessun PrimeNG → importabile ovunque). Tre\n * pannelli: localStorage, IndexedDB (agnostico), store NgRx + sezioni lazy. Per privacy\n * mostra SOLO chiavi/dimensioni/conteggi, mai i valori grezzi. Refresh manuale di default;\n * polling opt-in via `pollingMs`. Pensato per essere usabile anche in produzione.\n *\n * Il template usa le direttive strutturali classiche (`*ngIf`/`*ngFor` + `CommonModule`)\n * anziché il control-flow `@if`/`@for`: così il componente resta compatibile con Angular\n * >= 12 (la nuova sintassi alzerebbe il `minVersion` del pacchetto a 17).\n */\n@Component({\n selector: 'nec-dashboard',\n standalone: true,\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n styles: [\n `\n :host {\n display: block;\n font-family: system-ui, sans-serif;\n font-size: 13px;\n color: #1f2933;\n }\n .nec-toolbar {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n }\n .nec-panel {\n border: 1px solid #d7dce2;\n border-radius: 6px;\n padding: 12px 16px;\n margin-bottom: 16px;\n }\n .nec-panel h3 {\n margin: 0 0 8px;\n font-size: 14px;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n }\n th,\n td {\n text-align: left;\n padding: 4px 8px;\n border-bottom: 1px solid #eceff3;\n }\n th {\n font-weight: 600;\n color: #52606d;\n }\n td.num,\n th.num {\n text-align: right;\n font-variant-numeric: tabular-nums;\n }\n .nec-note {\n color: #7b8794;\n font-style: italic;\n }\n .nec-badge {\n display: inline-block;\n padding: 1px 6px;\n border-radius: 10px;\n font-size: 11px;\n background: #e4e7eb;\n }\n .nec-badge.loading {\n background: #fde68a;\n }\n .nec-badge.error {\n background: #fca5a5;\n }\n .nec-badge.lazy {\n background: #bfdbfe;\n }\n button {\n cursor: pointer;\n }\n `,\n ],\n template: `\n <div class=\"nec-toolbar\">\n <button type=\"button\" (click)=\"refresh()\" [disabled]=\"busy()\">\n {{ busy() ? 'Aggiorno…' : 'Aggiorna' }}\n </button>\n <span class=\"nec-note\" *ngIf=\"lastUpdated()\">ultimo aggiornamento: {{ lastUpdated() }}</span>\n </div>\n\n <!-- Quota aggregata origine -->\n <div class=\"nec-panel\">\n <h3>Quota origine (aggregata)</h3>\n <ng-container *ngIf=\"quota()?.available; else noQuota\">\n <div>\n uso: <strong>{{ formatBytes(quota()?.usage) }}</strong> /\n quota: <strong>{{ formatBytes(quota()?.quota) }}</strong>\n </div>\n <div class=\"nec-note\">\n Stima per-origine: include localStorage + IndexedDB + Cache, non scorporabile.\n </div>\n </ng-container>\n <ng-template #noQuota>\n <div class=\"nec-note\">Stima quota non disponibile (Safari o contesto non sicuro).</div>\n </ng-template>\n </div>\n\n <!-- localStorage -->\n <div class=\"nec-panel\">\n <h3>localStorage</h3>\n <ng-container *ngIf=\"storage()?.available; else noLocalStorage\">\n <div>\n {{ storage()?.count }} chiavi · totale\n <strong>{{ formatBytes(storage()?.totalBytesUtf16) }}</strong> (UTF-16) /\n {{ formatBytes(storage()?.totalBytesUtf8) }} (UTF-8)\n </div>\n <ng-container *ngIf=\"storage()!.entries.length; else noLocalStorageEntries\">\n <table>\n <thead>\n <tr>\n <th>chiave</th>\n <th class=\"num\">UTF-16</th>\n <th class=\"num\">UTF-8</th>\n <th *ngIf=\"allowRevealValues\">valore</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let e of storage()!.entries; trackBy: trackByKey\">\n <td>\n {{ e.key }}\n <span\n class=\"nec-badge error\"\n title=\"chiave potenzialmente sensibile\"\n *ngIf=\"isSensitive(e.key)\"\n >⚠</span>\n </td>\n <td class=\"num\">{{ formatBytes(e.bytesUtf16) }}</td>\n <td class=\"num\">{{ formatBytes(e.bytesUtf8) }}</td>\n <td *ngIf=\"allowRevealValues\">\n <ng-container *ngIf=\"revealed()[e.key] !== undefined; else revealBtn\">\n <code>{{ revealed()[e.key] }}</code>\n </ng-container>\n <ng-template #revealBtn>\n <button type=\"button\" (click)=\"reveal(e.key)\">mostra</button>\n </ng-template>\n </td>\n </tr>\n </tbody>\n </table>\n </ng-container>\n <ng-template #noLocalStorageEntries>\n <div class=\"nec-note\">Nessuna chiave.</div>\n </ng-template>\n </ng-container>\n <ng-template #noLocalStorage>\n <div class=\"nec-note\">localStorage non disponibile.</div>\n </ng-template>\n </div>\n\n <!-- IndexedDB -->\n <div class=\"nec-panel\">\n <h3>IndexedDB</h3>\n <ng-container *ngIf=\"idb()?.available; else noIdb\">\n <div class=\"nec-note\">adapter: {{ idb()?.adapter }}</div>\n <div class=\"nec-note\" *ngIf=\"idb()?.note\">{{ idb()?.note }}</div>\n <table *ngIf=\"idb()!.databases.length\">\n <thead>\n <tr>\n <th>database</th>\n <th>object store</th>\n <th class=\"num\">record</th>\n </tr>\n </thead>\n <tbody>\n <ng-container *ngFor=\"let db of idb()!.databases; trackBy: trackByName\">\n <ng-container *ngIf=\"db.stores.length; else noStores\">\n <tr *ngFor=\"let st of db.stores; trackBy: trackByName\">\n <td>{{ db.name }} <span class=\"nec-note\">v{{ db.version }}</span></td>\n <td>{{ st.name }}</td>\n <td class=\"num\">{{ st.count ?? '–' }}</td>\n </tr>\n </ng-container>\n <ng-template #noStores>\n <tr>\n <td>{{ db.name }} <span class=\"nec-note\">v{{ db.version }}</span></td>\n <td class=\"nec-note\" colspan=\"2\">{{ db.note ?? 'nessun object store' }}</td>\n </tr>\n </ng-template>\n </ng-container>\n </tbody>\n </table>\n <div class=\"nec-note\">I byte per record/store non sono misurabili: si mostra solo il conteggio.</div>\n </ng-container>\n <ng-template #noIdb>\n <div class=\"nec-note\">IndexedDB non disponibile in questo contesto.</div>\n </ng-template>\n </div>\n\n <!-- Store NgRx + lazy -->\n <div class=\"nec-panel\">\n <h3>Store NgRx</h3>\n <ng-container *ngIf=\"storeReport()\">\n <ng-container *ngIf=\"storeReport()!.slices.length; else noSlices\">\n <table>\n <thead>\n <tr>\n <th>slice</th>\n <th>tipo</th>\n <th class=\"num\">entità</th>\n <th class=\"num\">responses</th>\n <th>stato</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let s of storeReport()!.slices; trackBy: trackByKey\">\n <td>{{ s.key }}</td>\n <td>{{ s.kind }}</td>\n <td class=\"num\">{{ s.entityCount ?? '–' }}</td>\n <td class=\"num\">{{ s.responsesCount }}</td>\n <td>\n <span class=\"nec-badge loading\" *ngIf=\"s.isLoading\">loading</span>\n <span class=\"nec-badge error\" [title]=\"s.error\" *ngIf=\"s.error\">error</span>\n <span class=\"nec-badge\" *ngIf=\"!s.isLoading && !s.error\">{{\n s.isLoaded ? 'caricato' : 'idle'\n }}</span>\n </td>\n </tr>\n </tbody>\n </table>\n </ng-container>\n <ng-template #noSlices>\n <div class=\"nec-note\">Nessuna slice CRUD montata.</div>\n </ng-template>\n\n <ng-container *ngIf=\"storeReport()!.lazy?.length; else noLazy\">\n <h3 style=\"margin-top:12px\">Sezioni lazy (da lazy-report)</h3>\n <div class=\"nec-note\" *ngIf=\"storeReport()!.lazyReportGeneratedAt\">\n snapshot generato il {{ storeReport()!.lazyReportGeneratedAt }} — rigenera con\n <code>ng generate ngrx-entity-crud:lazy-report --format=json</code> se obsoleto.\n </div>\n <table>\n <thead>\n <tr>\n <th>store</th>\n <th>sezioni</th>\n <th>verdetto</th>\n <th>runtime</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let l of storeReport()!.lazy!; trackBy: trackByName\">\n <td>{{ l.name }}</td>\n <td>{{ l.sections.join(', ') || '–' }}</td>\n <td>{{ l.verdict }}</td>\n <td>\n <span\n class=\"nec-badge\"\n [class.lazy]=\"l.runtimeStatus === 'lazy-not-loaded'\"\n >{{ l.runtimeStatus }}</span>\n </td>\n </tr>\n </tbody>\n </table>\n </ng-container>\n <ng-template #noLazy>\n <div class=\"nec-note\">\n Nessun lazy-report caricato (genera src/assets/lazy-report.json con\n <code>ng generate ngrx-entity-crud:lazy-report --format=json</code>).\n </div>\n </ng-template>\n </ng-container>\n </div>\n `,\n})\nexport class NecDashboardComponent implements OnInit, OnDestroy {\n private readonly localStorageProbe = inject(NecLocalStorageProbeService);\n private readonly indexedDbProbe = inject(NecIndexedDbProbeService);\n private readonly storeProbe = inject(NecStoreProbeService);\n\n /** Chiavi di slice da escludere dallo scan dello store. */\n @Input() blacklist: string[] = [];\n /** Se valorizzata, considera SOLO queste chiavi di slice (precede la blacklist). */\n @Input() whitelist: string[] = [];\n /** URL del report statico (`lazy-report --format=json`); `null`/'' per disattivarlo. */\n @Input() lazyReportUrl: string | null = 'assets/lazy-report.json';\n /** Nomi DB IndexedDB da ispezionare dove `databases()` non è supportato (es. Firefox). */\n @Input() idbDatabaseNames: string[] = [];\n /** Intervallo di auto-refresh in ms; 0 = solo manuale (default). */\n @Input() pollingMs = 0;\n /** Abilita il reveal opt-in dei valori localStorage (sempre mascherati). Default: false. */\n @Input() allowRevealValues = false;\n\n readonly busy = signal(false);\n readonly lastUpdated = signal<string | null>(null);\n readonly storage = signal<NecStorageReport | null>(null);\n readonly quota = signal<NecQuotaEstimate | null>(null);\n readonly idb = signal<NecIdbReport | null>(null);\n readonly storeReport = signal<NecStoreReport | null>(null);\n readonly revealed = signal<Record<string, string>>({});\n\n private timer: ReturnType<typeof setInterval> | null = null;\n\n ngOnInit(): void {\n void this.refresh();\n if (this.pollingMs > 0) {\n this.timer = setInterval(() => void this.refresh(), this.pollingMs);\n }\n }\n\n ngOnDestroy(): void {\n if (this.timer != null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n async refresh(): Promise<void> {\n if (this.busy()) {\n return;\n }\n this.busy.set(true);\n this.revealed.set({}); // i valori rivelati non sopravvivono a un refresh\n try {\n this.storage.set(this.localStorageProbe.read('local'));\n this.quota.set(await this.localStorageProbe.estimate());\n this.idb.set(await this.indexedDbProbe.read(this.idbDatabaseNames));\n\n const opts = {blacklist: this.blacklist, whitelist: this.whitelist};\n if (this.lazyReportUrl) {\n this.storeReport.set(await this.storeProbe.readWithLazyReport(this.lazyReportUrl, opts));\n } else {\n this.storeReport.set(this.storeProbe.read(opts));\n }\n this.lastUpdated.set(new Date().toLocaleTimeString());\n } finally {\n this.busy.set(false);\n }\n }\n\n /** Reveal opt-in di un valore localStorage, sempre passato per `maskValue` (privacy). */\n reveal(key: string): void {\n const value = this.localStorageProbe.readValue(key) ?? '';\n this.revealed.update((m) => ({...m, [key]: maskValue(key, value)}));\n }\n\n isSensitive(key: string): boolean {\n return looksSensitiveKey(key);\n }\n\n /** trackBy per le righe identificate da `key` (entry localStorage, slice store). */\n trackByKey(_: number, item: {key: string}): string {\n return item.key;\n }\n\n /** trackBy per le righe identificate da `name` (DB/object store IndexedDB, voci lazy). */\n trackByName(_: number, item: {name: string}): string {\n return item.name;\n }\n\n formatBytes(n: number | undefined | null): string {\n if (n == null) {\n return '–';\n }\n if (n < 1024) {\n return `${n} B`;\n }\n if (n < 1024 * 1024) {\n return `${(n / 1024).toFixed(1)} KB`;\n }\n return `${(n / 1024 / 1024).toFixed(2)} MB`;\n }\n}\n","/**\n * Secondary entry-point `ngrx-entity-crud/devtools`.\n *\n * Dashboard di gestione progetto: riepiloghi runtime di localStorage, IndexedDB (agnostico)\n * e store NgRx + sezioni promovibili al lazy loading. Tree-shakable: chi non lo importa non\n * lo paga nel bundle. Vedi `ngrx-entity-crud-dashboard-plan.md`.\n */\n\nexport * from './models';\nexport * from './idb-adapter.token';\nexport * from './agnostic-selectors';\nexport * from './mask';\nexport * from './probes/nec-local-storage-probe.service';\nexport * from './probes/nec-indexeddb-probe.service';\nexport * from './probes/nec-store-probe.service';\nexport * from './nec-dashboard.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngrx-entity-crud-devtools.mjs","sources":["../../../libs/ngrx-entity-crud/devtools/models.ts","../../../libs/ngrx-entity-crud/devtools/idb-adapter.token.ts","../../../libs/ngrx-entity-crud/devtools/agnostic-selectors.ts","../../../libs/ngrx-entity-crud/devtools/mask.ts","../../../libs/ngrx-entity-crud/devtools/probes/nec-local-storage-probe.service.ts","../../../libs/ngrx-entity-crud/devtools/probes/nec-indexeddb-probe.service.ts","../../../libs/ngrx-entity-crud/devtools/probes/nec-store-probe.service.ts","../../../libs/ngrx-entity-crud/devtools/nec-dashboard.component.ts","../../../libs/ngrx-entity-crud/devtools/public-api.ts","../../../libs/ngrx-entity-crud/devtools/ngrx-entity-crud-devtools.ts"],"sourcesContent":["/**\n * Modelli dei report prodotti dai probe della dashboard (`ngrx-entity-crud/devtools`).\n *\n * Sono volutamente indipendenti dai tipi del main entry-point: i probe leggono lo stato\n * per CONVENZIONE (vedi `EntityCrudBaseState` in `src/lib/models.ts`), non per tipo, così\n * il sotto-modulo `devtools` resta autonomo e agnostico rispetto alla persistenza usata.\n */\n\n// ---------------------------------------------------------------------------\n// localStorage / sessionStorage\n// ---------------------------------------------------------------------------\n\nexport interface NecStorageEntry {\n key: string;\n /** Byte verso la quota (UTF-16): `(key.length + value.length) * 2`. Metrica primaria. */\n bytesUtf16: number;\n /** Byte della serializzazione UTF-8 (`TextEncoder`/`Blob`). Metrica secondaria. */\n bytesUtf8: number;\n}\n\nexport interface NecStorageReport {\n available: boolean;\n type: 'local' | 'session';\n entries: NecStorageEntry[];\n count: number;\n totalBytesUtf16: number;\n totalBytesUtf8: number;\n}\n\n/** Stima quota AGGREGATA per-origine (localStorage + IndexedDB + Cache), non scorporabile. */\nexport interface NecQuotaEstimate {\n available: boolean;\n usage?: number;\n quota?: number;\n /** Non-standard (solo Chromium): byte per area. Assente su Firefox/Safari. */\n usageDetails?: Record<string, number>;\n}\n\n// ---------------------------------------------------------------------------\n// IndexedDB (agnostico)\n// ---------------------------------------------------------------------------\n\nexport interface NecIdbStoreReport {\n name: string;\n /** Numero record (`objectStore.count()`); `null` se non determinabile. */\n count: number | null;\n}\n\nexport interface NecIdbDbReport {\n name: string;\n version: number | null;\n stores: NecIdbStoreReport[];\n note?: string;\n}\n\nexport interface NecIdbReport {\n available: boolean;\n /** `false` se non è stato possibile elencare i database (es. Firefox senza nomi forniti). */\n enumerable: boolean;\n /** Nome dell'adapter usato: `'native'`, il nome di un `NecIdbAdapter`, o `null`. */\n adapter: string | null;\n databases: NecIdbDbReport[];\n note?: string;\n}\n\n/**\n * Punto di estensione agnostico: il consumer può fornire un adapter esplicito (via\n * `NEC_IDB_ADAPTER`) per conteggi accurati quando la sua libreria di persistenza nasconde\n * i nomi DB. Quando assente, il probe usa solo le API native.\n */\nexport interface NecIdbAdapter {\n name: string;\n isAvailable(): boolean;\n listDatabases(): Promise<NecIdbDbReport[]>;\n}\n\n// ---------------------------------------------------------------------------\n// Store NgRx + lazy\n// ---------------------------------------------------------------------------\n\nexport type NecSliceKind = 'plural' | 'singular' | 'unknown';\n\nexport interface NecStoreSlice {\n key: string;\n kind: NecSliceKind;\n isLoading: boolean;\n isLoaded: boolean;\n error: string | null;\n /** Numero entità (solo slice `plural`). */\n entityCount?: number;\n responsesCount: number;\n}\n\nexport type NecRuntimeStatus = 'loaded' | 'lazy-not-loaded' | 'unknown';\n\nexport interface NecLazyEntry {\n name: string;\n clazz?: string;\n type?: string;\n verdict?: string;\n isLazyCandidate: boolean;\n lazyRoute?: boolean;\n sections: string[];\n usedByShell: boolean;\n runtimeStatus: NecRuntimeStatus;\n}\n\nexport interface NecStoreReport {\n slices: NecStoreSlice[];\n loadingNames: string[];\n errors: string[];\n /** Presente solo se è stato fornito un `lazyReportUrl` e il fetch è riuscito. */\n lazy?: NecLazyEntry[];\n /** Timestamp ISO di generazione del `lazy-report.json` (per segnalare snapshot stantii). */\n lazyReportGeneratedAt?: string;\n}\n","import {InjectionToken} from '@angular/core';\nimport {NecIdbAdapter} from './models';\n\n/**\n * Adapter IndexedDB OPZIONALE, agnostico rispetto alla libreria di persistenza.\n *\n * Fornendolo, il `NecIndexedDbProbeService` lo usa con priorità per enumerare i database\n * (utile quando la libreria del consumer nasconde i nomi DB o su browser senza\n * `indexedDB.databases()`, es. Firefox). Quando NON fornito, il probe usa solo le API native.\n */\nexport const NEC_IDB_ADAPTER = new InjectionToken<NecIdbAdapter>('NEC_IDB_ADAPTER');\n","import {createSelector, MemoizedSelector} from '@ngrx/store';\n\n/**\n * Versione FACTORY (parametrizzabile) dei selettori agnostici di loading/error che il\n * template `ng-add` installa in `root-store/selectors.ts`.\n *\n * Il template resta invariato (retro-compatibilità): qui la logica è IDENTICA ma con\n * `rootSelector`/`blacklist`/`whitelist` resi parametri invece che costanti hardcoded, così\n * è riutilizzabile dal pacchetto npm (entry-point `ngrx-entity-crud/devtools`).\n *\n * Scandisce lo stato sfruttando la convenzione `EntityCrudBaseState`: ogni slice CRUD espone\n * `isLoading: boolean` ed `error: string | null` al livello top.\n */\nexport interface AgnosticLoadingSelectorsOptions {\n /** Selettore della radice da scandire (default: l'intero stato root). */\n rootSelector?: (state: any) => Record<string, any>;\n /** Chiavi di slice da escludere dallo scan. */\n blacklist?: ReadonlyArray<string>;\n /** Se valorizzata, considera SOLO queste chiavi (precede la blacklist). */\n whitelist?: ReadonlyArray<string>;\n}\n\nexport interface AgnosticLoadingSelectors {\n /** Nomi delle slice attualmente in caricamento (`isLoading === true`). */\n selectLoadingNames: MemoizedSelector<any, string[]>;\n /** `true` se almeno una slice CRUD è in caricamento. */\n selectIsLoading: MemoizedSelector<any, boolean>;\n /** Elenco degli errori non vuoti presenti nelle slice CRUD. */\n selectErrors: MemoizedSelector<any, string[]>;\n /** Concatenazione degli errori non vuoti (stringa vuota se non ce ne sono). */\n selectError: MemoizedSelector<any, string>;\n}\n\ninterface LoadingSlice {\n isLoading?: boolean;\n error?: string | null;\n}\n\nexport function createAgnosticLoadingSelectors(\n options: AgnosticLoadingSelectorsOptions = {}\n): AgnosticLoadingSelectors {\n const rootSelector = options.rootSelector ?? ((state: any): Record<string, any> => state);\n const blacklist = options.blacklist ?? [];\n const whitelist = options.whitelist ?? [];\n\n const isEligible = (key: string): boolean =>\n whitelist.length > 0 ? whitelist.includes(key) : !blacklist.includes(key);\n\n const isLoadingSlice = (value: any): value is LoadingSlice =>\n !!value && typeof value === 'object' && typeof value.isLoading === 'boolean';\n\n const crudEntries = (state: Record<string, any>): Array<[string, LoadingSlice]> =>\n Object.entries(state || {})\n .filter(([key]) => isEligible(key))\n .filter((entry): entry is [string, LoadingSlice] => isLoadingSlice(entry[1]));\n\n const selectLoadingNames = createSelector(rootSelector, (state): string[] =>\n crudEntries(state)\n .filter(([, slice]) => slice.isLoading === true)\n .map(([key]) => key)\n );\n\n const selectIsLoading = createSelector(\n selectLoadingNames,\n (names): boolean => names.length > 0\n );\n\n const selectErrors = createSelector(rootSelector, (state): string[] =>\n crudEntries(state)\n .map(([, slice]) => slice.error)\n .filter((error): error is string => typeof error === 'string' && error.length > 0)\n );\n\n const selectError = createSelector(selectErrors, (errors): string => errors.join('\\n'));\n\n return {selectLoadingNames, selectIsLoading, selectErrors, selectError};\n}\n","/**\n * Utility di privacy per la dashboard: poiché può girare anche in PRODUZIONE, i valori non\n * vengono mai mostrati di default e — quando il consumer abilita esplicitamente il reveal —\n * vengono comunque mascherati i pattern sensibili (token/JWT/email/segreti).\n */\n\nconst SENSITIVE_KEY =\n /(token|secret|password|passwd|pwd|auth(orization)?|credential|api[-_]?key|jwt|session|cookie|bearer)/i;\n\n/** `true` se il nome chiave suggerisce un contenuto sensibile (token, password, ecc.). */\nexport function looksSensitiveKey(key: string): boolean {\n return SENSITIVE_KEY.test(key || '');\n}\n\n/** Redige nel testo i pattern sensibili comuni (JWT, email, token/hex lunghi). */\nexport function redactSensitive(value: string): string {\n return (value || '')\n .replace(/eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, '«jwt-redatto»')\n .replace(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}/g, '«email-redatta»')\n .replace(/\\b[A-Fa-f0-9]{32,}\\b/g, '«hex-redatto»')\n .replace(/\\b[A-Za-z0-9_-]{40,}\\b/g, '«token-redatto»');\n}\n\n/**\n * Valore \"sicuro da mostrare\": se la chiave è sensibile, nasconde tutto (mostra solo la\n * lunghezza); altrimenti redige i pattern sensibili e tronca a `maxLength`.\n */\nexport function maskValue(key: string, value: string, maxLength = 200): string {\n if (looksSensitiveKey(key)) {\n return `«nascosto» (${(value || '').length} caratteri)`;\n }\n let out = redactSensitive(value);\n if (out.length > maxLength) {\n out = out.slice(0, maxLength) + '… (troncato)';\n }\n return out;\n}\n","import {Injectable} from '@angular/core';\nimport {NecQuotaEstimate, NecStorageEntry, NecStorageReport} from '../models';\n\n/**\n * Riepilogo di `localStorage` / `sessionStorage`.\n *\n * Sincrono per la lettura delle chiavi. NON espone i valori: solo chiavi e dimensioni\n * (privacy). La metrica primaria verso la quota è UTF-16 `(key.length + value.length) * 2`,\n * perché è ciò che conta verso il limite ~5-10MB; la metrica UTF-8 è secondaria.\n */\n@Injectable({providedIn: 'root'})\nexport class NecLocalStorageProbeService {\n read(type: 'local' | 'session' = 'local'): NecStorageReport {\n const empty: NecStorageReport = {\n available: false,\n type,\n entries: [],\n count: 0,\n totalBytesUtf16: 0,\n totalBytesUtf8: 0,\n };\n\n if (typeof window === 'undefined') {\n return empty;\n }\n\n let storage: Storage | null = null;\n try {\n storage = type === 'local' ? window.localStorage : window.sessionStorage;\n } catch {\n // accesso negato (sandbox/incognito/policy)\n return empty;\n }\n if (!storage) {\n return empty;\n }\n\n const entries: NecStorageEntry[] = [];\n let totalBytesUtf16 = 0;\n let totalBytesUtf8 = 0;\n\n try {\n for (let i = 0; i < storage.length; i++) {\n const key = storage.key(i);\n if (key == null) {\n continue;\n }\n const value = storage.getItem(key) ?? '';\n const bytesUtf16 = (key.length + value.length) * 2;\n const bytesUtf8 = this.utf8Bytes(key + value);\n totalBytesUtf16 += bytesUtf16;\n totalBytesUtf8 += bytesUtf8;\n entries.push({key, bytesUtf16, bytesUtf8});\n }\n } catch {\n // accesso parziale negato: ritorna ciò che è stato raccolto finora\n }\n\n entries.sort((a, b) => b.bytesUtf16 - a.bytesUtf16);\n\n return {\n available: true,\n type,\n entries,\n count: entries.length,\n totalBytesUtf16,\n totalBytesUtf8,\n };\n }\n\n /**\n * Legge ON-DEMAND il valore grezzo di una singola chiave (per il reveal esplicito in UI).\n * Non viene mai incluso nel report: la dashboard lo richiede solo su azione dell'utente e lo\n * maschera tramite `maskValue`.\n */\n readValue(key: string, type: 'local' | 'session' = 'local'): string | null {\n if (typeof window === 'undefined') {\n return null;\n }\n try {\n const storage = type === 'local' ? window.localStorage : window.sessionStorage;\n return storage ? storage.getItem(key) : null;\n } catch {\n return null;\n }\n }\n\n /**\n * Stima quota AGGREGATA per-origine (include anche IndexedDB e Cache): NON è scorporabile\n * per area. Può essere assente (Safari/contesto non sicuro) o arrotondata (anti-fingerprint).\n */\n async estimate(): Promise<NecQuotaEstimate> {\n const empty: NecQuotaEstimate = {available: false};\n if (\n typeof navigator === 'undefined' ||\n !navigator.storage ||\n typeof navigator.storage.estimate !== 'function'\n ) {\n return empty;\n }\n try {\n const est = await navigator.storage.estimate();\n return {\n available: true,\n usage: est.usage,\n quota: est.quota,\n usageDetails: (est as {usageDetails?: Record<string, number>}).usageDetails,\n };\n } catch {\n return empty;\n }\n }\n\n private utf8Bytes(s: string): number {\n try {\n if (typeof TextEncoder !== 'undefined') {\n return new TextEncoder().encode(s).length;\n }\n } catch {\n /* noop */\n }\n try {\n if (typeof Blob !== 'undefined') {\n return new Blob([s]).size;\n }\n } catch {\n /* noop */\n }\n return s.length;\n }\n}\n","import {Inject, Injectable, Optional} from '@angular/core';\nimport {NecIdbAdapter, NecIdbDbReport, NecIdbReport, NecIdbStoreReport} from '../models';\nimport {NEC_IDB_ADAPTER} from '../idb-adapter.token';\n\n/**\n * Riepilogo IndexedDB AGNOSTICO rispetto alla libreria di persistenza.\n *\n * Priorità reale: (1) `NEC_IDB_ADAPTER` esplicito, (2) API native\n * (`indexedDB.databases()` + `open()` + `count()`). NESSUN import di librerie di\n * persistenza. Mostra il numero di record per object store; i byte per-store NON sono\n * misurabili e non vengono promessi (solo la quota aggregata, altrove).\n */\n@Injectable({providedIn: 'root'})\nexport class NecIndexedDbProbeService {\n constructor(@Optional() @Inject(NEC_IDB_ADAPTER) private readonly adapter: NecIdbAdapter | null) {}\n\n /**\n * @param fallbackDatabaseNames nomi DB da ispezionare quando `indexedDB.databases()` non\n * è supportato (Firefox / Safari vecchi). Passa qui i nomi noti della tua persistenza.\n * @param openTimeoutMs timeout per ogni `open()` (default 3000ms).\n */\n async read(fallbackDatabaseNames: string[] = [], openTimeoutMs = 3000): Promise<NecIdbReport> {\n // 1) adapter esplicito: path prioritario e agnostico, indipendente dalle API native\n // (il consumer può fornire conteggi anche dove l'introspezione nativa non basta).\n if (this.adapter && this.adapter.isAvailable()) {\n try {\n const databases = await this.adapter.listDatabases();\n return {available: true, enumerable: true, adapter: this.adapter.name, databases};\n } catch {\n // degrada al path nativo\n }\n }\n\n // 2) path nativo: richiede l'API IndexedDB del browser\n if (typeof indexedDB === 'undefined') {\n return {\n available: false,\n enumerable: false,\n adapter: null,\n databases: [],\n note: 'IndexedDB non disponibile in questo contesto',\n };\n }\n\n const names = await this.listDatabaseNames(fallbackDatabaseNames);\n if (!names.length) {\n return {\n available: true,\n enumerable: false,\n adapter: 'native',\n databases: [],\n note:\n 'Impossibile elencare i database: indexedDB.databases() non supportato (es. Firefox) ' +\n 'e nessun nome fornito. Passa i nomi DB noti via input \"idbDatabaseNames\".',\n };\n }\n\n const databases: NecIdbDbReport[] = [];\n for (const name of names) {\n databases.push(await this.inspectDatabase(name, openTimeoutMs));\n }\n return {available: true, enumerable: true, adapter: 'native', databases};\n }\n\n private async listDatabaseNames(fallback: string[]): Promise<string[]> {\n const idbAny = indexedDB as unknown as {\n databases?: () => Promise<Array<{name?: string}>>;\n };\n if (typeof idbAny.databases === 'function') {\n try {\n const list = await idbAny.databases();\n const names = list.map((d) => d.name).filter((n): n is string => !!n);\n if (names.length) {\n return names;\n }\n } catch {\n // ignora: usa il fallback\n }\n }\n return Array.from(new Set(fallback.filter(Boolean)));\n }\n\n private inspectDatabase(name: string, timeoutMs: number): Promise<NecIdbDbReport> {\n return new Promise<NecIdbDbReport>((resolve) => {\n let settled = false;\n const done = (report: NecIdbDbReport): void => {\n if (settled) {\n return;\n }\n settled = true;\n resolve(report);\n };\n\n const timer = setTimeout(\n () => done({name, version: null, stores: [], note: 'timeout apertura DB'}),\n timeoutMs\n );\n\n let request: IDBOpenDBRequest;\n try {\n request = indexedDB.open(name);\n } catch {\n clearTimeout(timer);\n done({name, version: null, stores: [], note: 'open() fallita'});\n return;\n }\n\n request.onblocked = () => {\n clearTimeout(timer);\n done({\n name,\n version: null,\n stores: [],\n note: 'apertura bloccata (versionchange in un\\'altra scheda)',\n });\n };\n\n request.onerror = () => {\n clearTimeout(timer);\n done({name, version: null, stores: [], note: 'errore apertura DB (o DB inesistente)'});\n };\n\n request.onupgradeneeded = (event) => {\n // Il DB non esisteva: NON crearne lo schema. Annulla la transazione di upgrade\n // (provoca onerror e rollback della creazione) per non sporcare l'origine.\n try {\n (event.target as IDBOpenDBRequest).transaction?.abort();\n } catch {\n /* noop */\n }\n };\n\n request.onsuccess = () => {\n const db = request.result;\n const version = db.version;\n const storeNames = Array.from(db.objectStoreNames);\n\n if (!storeNames.length) {\n clearTimeout(timer);\n db.close();\n done({name, version, stores: []});\n return;\n }\n\n let tx: IDBTransaction;\n try {\n tx = db.transaction(storeNames, 'readonly');\n } catch {\n clearTimeout(timer);\n db.close();\n done({\n name,\n version,\n stores: storeNames.map((s): NecIdbStoreReport => ({name: s, count: null})),\n });\n return;\n }\n\n const stores: NecIdbStoreReport[] = storeNames.map((s) => ({name: s, count: null}));\n let pending = storeNames.length;\n const finalize = (): void => {\n if (--pending === 0) {\n clearTimeout(timer);\n db.close();\n done({name, version, stores});\n }\n };\n\n storeNames.forEach((s, idx) => {\n try {\n const countReq = tx.objectStore(s).count();\n countReq.onsuccess = () => {\n stores[idx].count = countReq.result;\n finalize();\n };\n countReq.onerror = () => finalize();\n } catch {\n finalize();\n }\n });\n };\n });\n }\n}\n","import {inject, Injectable} from '@angular/core';\nimport {Store} from '@ngrx/store';\nimport {take} from 'rxjs/operators';\nimport {NecLazyEntry, NecSliceKind, NecStoreReport, NecStoreSlice} from '../models';\n\ninterface ProbeOptions {\n blacklist?: string[];\n whitelist?: string[];\n}\n\n/**\n * Riepilogo degli store NgRx a runtime.\n *\n * Enumera le slice CRUD montate per CONVENZIONE (`typeof value.isLoading === 'boolean'`,\n * vedi `EntityCrudBaseState`), senza dipendere dai selettori per-dominio. Una slice lazy non\n * ancora caricata semplicemente non ha la chiave nello stato root.\n */\n@Injectable({providedIn: 'root'})\nexport class NecStoreProbeService {\n private readonly store = inject(Store);\n\n /** Lettura sincrona dello stato root (NgRx emette il valore corrente all'iscrizione). */\n read(opts: ProbeOptions = {}): NecStoreReport {\n const blacklist = opts.blacklist ?? [];\n const whitelist = opts.whitelist ?? [];\n\n let root: Record<string, any> = {};\n this.store\n .select((s) => s as Record<string, any>)\n .pipe(take(1))\n .subscribe((s) => (root = s ?? {}));\n\n const isEligible = (key: string): boolean =>\n whitelist.length > 0 ? whitelist.includes(key) : !blacklist.includes(key);\n\n const slices: NecStoreSlice[] = [];\n const loadingNames: string[] = [];\n const errors: string[] = [];\n\n for (const [key, value] of Object.entries(root)) {\n if (!isEligible(key)) {\n continue;\n }\n if (!value || typeof value !== 'object' || typeof value.isLoading !== 'boolean') {\n continue;\n }\n const v = value as Record<string, any>;\n const kind: NecSliceKind = Array.isArray(v['ids'])\n ? 'plural'\n : 'item' in v\n ? 'singular'\n : 'unknown';\n const error =\n typeof v['error'] === 'string' && v['error'].length > 0 ? (v['error'] as string) : null;\n\n const slice: NecStoreSlice = {\n key,\n kind,\n isLoading: v['isLoading'] === true,\n isLoaded: v['isLoaded'] === true,\n error,\n entityCount:\n kind === 'plural'\n ? Array.isArray(v['ids'])\n ? v['ids'].length\n : Object.keys(v['entities'] ?? {}).length\n : undefined,\n responsesCount: Array.isArray(v['responses']) ? v['responses'].length : 0,\n };\n slices.push(slice);\n if (slice.isLoading) {\n loadingNames.push(key);\n }\n if (slice.error) {\n errors.push(`${key}: ${slice.error}`);\n }\n }\n\n slices.sort((a, b) => a.key.localeCompare(b.key));\n return {slices, loadingNames, errors};\n }\n\n /**\n * Type dell'azione `Reset` della libreria per una slice CRUD.\n *\n * Vale la convenzione degli schematic `store`: la feature key nello stato root coincide col\n * nome passato a `createCrudActions` (entrambi `Names.NAME`), quindi il type `[key] Reset`\n * (vedi `actions.ts`, `CrudEnum.RESET`) è ricostruibile dalla sola `key` letta da {@link read}.\n */\n resetActionType(sliceKey: string): string {\n return `[${sliceKey}] Reset`;\n }\n\n /** Type dell'azione `ResetResponses` (`[key] Reset Response`): svuota solo la cache delle response. */\n resetResponsesActionType(sliceKey: string): string {\n return `[${sliceKey}] Reset Response`;\n }\n\n /**\n * Dispaccia il `Reset` della slice: riporta lo stato a `initialState` (entità, selezione,\n * criteri e response vuoti). La libreria di persistenza, reagendo al cambio di stato, riscrive\n * lo stato vuoto e di fatto svuota i dati salvati in locale.\n */\n reset(sliceKey: string): void {\n this.store.dispatch({type: this.resetActionType(sliceKey)});\n }\n\n /** Dispaccia il `ResetResponses` della slice: svuota solo le response, lasciando entità e selezione. */\n resetResponses(sliceKey: string): void {\n this.store.dispatch({type: this.resetResponsesActionType(sliceKey)});\n }\n\n /** Come `read()`, ma correla con l'inventario statico di `lazy-report.json` (se raggiungibile). */\n async readWithLazyReport(url: string, opts: ProbeOptions = {}): Promise<NecStoreReport> {\n const report = this.read(opts);\n const fetched = await this.fetchLazyReport(url, report);\n if (!fetched) {\n return report;\n }\n return {...report, lazy: fetched.entries, lazyReportGeneratedAt: fetched.generatedAt};\n }\n\n private async fetchLazyReport(\n url: string,\n report: NecStoreReport\n ): Promise<{entries: NecLazyEntry[]; generatedAt?: string} | undefined> {\n if (typeof fetch !== 'function') {\n return undefined;\n }\n let json: any;\n try {\n const res = await fetch(url, {headers: {Accept: 'application/json'}});\n if (!res.ok) {\n return undefined;\n }\n json = await res.json();\n } catch {\n return undefined;\n }\n\n const stores: any[] = Array.isArray(json?.stores) ? json.stores : [];\n const mounted = new Set(report.slices.map((s) => s.key));\n const generatedAt = typeof json?.generatedAt === 'string' ? json.generatedAt : undefined;\n\n const entries = stores.map((st): NecLazyEntry => {\n const sliceKey = this.toSliceKey(st?.name);\n const isLoaded = mounted.has(sliceKey) || mounted.has(st?.name);\n const isLazyCandidate =\n typeof st?.isLazyCandidate === 'boolean'\n ? st.isLazyCandidate\n : /candidato lazy/i.test(st?.verdict ?? '');\n return {\n name: st?.name,\n clazz: st?.clazz,\n type: st?.type,\n verdict: st?.verdict,\n isLazyCandidate,\n lazyRoute: typeof st?.lazyRoute === 'boolean' ? st.lazyRoute : undefined,\n sections: Array.isArray(st?.sections) ? st.sections : [],\n usedByShell: !!st?.usedByShell,\n runtimeStatus: isLoaded ? 'loaded' : isLazyCandidate ? 'lazy-not-loaded' : 'unknown',\n };\n });\n\n return {entries, generatedAt};\n }\n\n /**\n * Best-effort: il root state usa `strings.underscore(name)` come chiave di slice, mentre il\n * report usa il nome dasherizzato. (Fase 1: far emettere a `lazy-report` la feature key reale.)\n */\n private toSliceKey(name: string): string {\n return (name ?? '').replace(/-/g, '_');\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n inject,\n Input,\n OnDestroy,\n OnInit,\n Output,\n signal,\n} from '@angular/core';\nimport {CommonModule} from '@angular/common';\nimport {NecIdbReport, NecQuotaEstimate, NecStorageReport, NecStoreReport} from './models';\nimport {NecLocalStorageProbeService} from './probes/nec-local-storage-probe.service';\nimport {NecIndexedDbProbeService} from './probes/nec-indexeddb-probe.service';\nimport {NecStoreProbeService} from './probes/nec-store-probe.service';\nimport {looksSensitiveKey, maskValue} from './mask';\n\n/**\n * `<nec-dashboard>` — dashboard di gestione progetto plug-and-play.\n *\n * Standalone, OnPush, template HTML inline (nessun PrimeNG → importabile ovunque). Tre\n * pannelli: localStorage, IndexedDB (agnostico), store NgRx + sezioni lazy. Per privacy\n * mostra SOLO chiavi/dimensioni/conteggi, mai i valori grezzi. Refresh manuale di default;\n * polling opt-in via `pollingMs`. Pensato per essere usabile anche in produzione.\n *\n * Il template usa le direttive strutturali classiche (`*ngIf`/`*ngFor` + `CommonModule`)\n * anziché il control-flow `@if`/`@for`: così il componente resta compatibile con Angular\n * >= 14 (il `minVersion` del componente standalone; il control-flow lo alzerebbe a 17).\n */\n@Component({\n selector: 'nec-dashboard',\n standalone: true,\n imports: [CommonModule],\n changeDetection: ChangeDetectionStrategy.OnPush,\n styles: [\n `\n :host {\n display: block;\n font-family: system-ui, sans-serif;\n font-size: 13px;\n color: #1f2933;\n }\n .nec-toolbar {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 12px;\n }\n .nec-panel {\n border: 1px solid #d7dce2;\n border-radius: 6px;\n padding: 12px 16px;\n margin-bottom: 16px;\n }\n .nec-panel h3 {\n margin: 0 0 8px;\n font-size: 14px;\n }\n table {\n width: 100%;\n border-collapse: collapse;\n }\n th,\n td {\n text-align: left;\n padding: 4px 8px;\n border-bottom: 1px solid #eceff3;\n }\n th {\n font-weight: 600;\n color: #52606d;\n }\n td.num,\n th.num {\n text-align: right;\n font-variant-numeric: tabular-nums;\n }\n .nec-note {\n color: #7b8794;\n font-style: italic;\n }\n .nec-badge {\n display: inline-block;\n padding: 1px 6px;\n border-radius: 10px;\n font-size: 11px;\n background: #e4e7eb;\n }\n .nec-badge.loading {\n background: #fde68a;\n }\n .nec-badge.error {\n background: #fca5a5;\n }\n .nec-badge.lazy {\n background: #bfdbfe;\n }\n button {\n cursor: pointer;\n }\n td.nec-actions {\n white-space: nowrap;\n }\n .nec-confirm {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n color: #b91c1c;\n }\n button.nec-danger {\n border-color: #fca5a5;\n color: #b91c1c;\n }\n `,\n ],\n template: `\n <div class=\"nec-toolbar\">\n <button type=\"button\" (click)=\"refresh()\" [disabled]=\"busy()\">\n {{ busy() ? 'Aggiorno…' : 'Aggiorna' }}\n </button>\n <ng-container *ngIf=\"storeReport()?.slices?.length\">\n <span class=\"nec-confirm\" role=\"alert\" *ngIf=\"pendingResetAll(); else resetAllBtn\">\n azzerare tutte le slice?\n <button type=\"button\" class=\"nec-danger\" aria-label=\"Conferma azzeramento di tutte le slice\" (click)=\"confirmResetAll()\">Sì</button>\n <button type=\"button\" aria-label=\"Annulla azzeramento\" (click)=\"cancelPending()\">Annulla</button>\n </span>\n <ng-template #resetAllBtn>\n <button type=\"button\" class=\"nec-danger\" (click)=\"requestResetAll()\">Azzera tutte</button>\n </ng-template>\n </ng-container>\n <span class=\"nec-note\" *ngIf=\"lastUpdated()\">ultimo aggiornamento: {{ lastUpdated() }}</span>\n </div>\n\n <!-- Quota aggregata origine -->\n <div class=\"nec-panel\">\n <h3>Quota origine (aggregata)</h3>\n <ng-container *ngIf=\"quota()?.available; else noQuota\">\n <div>\n uso: <strong>{{ formatBytes(quota()?.usage) }}</strong> /\n quota: <strong>{{ formatBytes(quota()?.quota) }}</strong>\n </div>\n <div class=\"nec-note\">\n Stima per-origine: include localStorage + IndexedDB + Cache, non scorporabile.\n </div>\n </ng-container>\n <ng-template #noQuota>\n <div class=\"nec-note\">Stima quota non disponibile (Safari o contesto non sicuro).</div>\n </ng-template>\n </div>\n\n <!-- localStorage -->\n <div class=\"nec-panel\">\n <h3>localStorage</h3>\n <ng-container *ngIf=\"storage()?.available; else noLocalStorage\">\n <div>\n {{ storage()?.count }} chiavi · totale\n <strong>{{ formatBytes(storage()?.totalBytesUtf16) }}</strong> (UTF-16) /\n {{ formatBytes(storage()?.totalBytesUtf8) }} (UTF-8)\n </div>\n <ng-container *ngIf=\"storage()!.entries.length; else noLocalStorageEntries\">\n <table>\n <thead>\n <tr>\n <th>chiave</th>\n <th class=\"num\">UTF-16</th>\n <th class=\"num\">UTF-8</th>\n <th *ngIf=\"allowRevealValues\">valore</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let e of storage()!.entries; trackBy: trackByKey\">\n <td>\n {{ e.key }}\n <span\n class=\"nec-badge error\"\n title=\"chiave potenzialmente sensibile\"\n *ngIf=\"isSensitive(e.key)\"\n >⚠</span>\n </td>\n <td class=\"num\">{{ formatBytes(e.bytesUtf16) }}</td>\n <td class=\"num\">{{ formatBytes(e.bytesUtf8) }}</td>\n <td *ngIf=\"allowRevealValues\">\n <ng-container *ngIf=\"revealed()[e.key] !== undefined; else revealBtn\">\n <code>{{ revealed()[e.key] }}</code>\n </ng-container>\n <ng-template #revealBtn>\n <button type=\"button\" (click)=\"reveal(e.key)\">mostra</button>\n </ng-template>\n </td>\n </tr>\n </tbody>\n </table>\n </ng-container>\n <ng-template #noLocalStorageEntries>\n <div class=\"nec-note\">Nessuna chiave.</div>\n </ng-template>\n </ng-container>\n <ng-template #noLocalStorage>\n <div class=\"nec-note\">localStorage non disponibile.</div>\n </ng-template>\n </div>\n\n <!-- IndexedDB -->\n <div class=\"nec-panel\">\n <h3>IndexedDB</h3>\n <ng-container *ngIf=\"idb()?.available; else noIdb\">\n <div class=\"nec-note\">adapter: {{ idb()?.adapter }}</div>\n <div class=\"nec-note\" *ngIf=\"idb()?.note\">{{ idb()?.note }}</div>\n <table *ngIf=\"idb()!.databases.length\">\n <thead>\n <tr>\n <th>database</th>\n <th>object store</th>\n <th class=\"num\">record</th>\n </tr>\n </thead>\n <tbody>\n <ng-container *ngFor=\"let db of idb()!.databases; trackBy: trackByName\">\n <ng-container *ngIf=\"db.stores.length; else noStores\">\n <tr *ngFor=\"let st of db.stores; trackBy: trackByName\">\n <td>{{ db.name }} <span class=\"nec-note\">v{{ db.version }}</span></td>\n <td>{{ st.name }}</td>\n <td class=\"num\">{{ st.count ?? '–' }}</td>\n </tr>\n </ng-container>\n <ng-template #noStores>\n <tr>\n <td>{{ db.name }} <span class=\"nec-note\">v{{ db.version }}</span></td>\n <td class=\"nec-note\" colspan=\"2\">{{ db.note ?? 'nessun object store' }}</td>\n </tr>\n </ng-template>\n </ng-container>\n </tbody>\n </table>\n <div class=\"nec-note\">I byte per record/store non sono misurabili: si mostra solo il conteggio.</div>\n </ng-container>\n <ng-template #noIdb>\n <div class=\"nec-note\">IndexedDB non disponibile in questo contesto.</div>\n </ng-template>\n </div>\n\n <!-- Store NgRx + lazy -->\n <div class=\"nec-panel\">\n <h3>Store NgRx</h3>\n <ng-container *ngIf=\"storeReport()\">\n <ng-container *ngIf=\"storeReport()!.slices.length; else noSlices\">\n <table>\n <thead>\n <tr>\n <th>slice</th>\n <th>tipo</th>\n <th class=\"num\">entità</th>\n <th class=\"num\">responses</th>\n <th>stato</th>\n <th>azioni</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let s of storeReport()!.slices; trackBy: trackByKey\">\n <td>{{ s.key }}</td>\n <td>{{ s.kind }}</td>\n <td class=\"num\">{{ s.entityCount ?? '–' }}</td>\n <td class=\"num\">{{ s.responsesCount }}</td>\n <td>\n <span class=\"nec-badge loading\" *ngIf=\"s.isLoading\">loading</span>\n <span class=\"nec-badge error\" [title]=\"s.error\" *ngIf=\"s.error\">error</span>\n <span class=\"nec-badge\" *ngIf=\"!s.isLoading && !s.error\">{{\n s.isLoaded ? 'caricato' : 'idle'\n }}</span>\n </td>\n <td class=\"nec-actions\">\n <span class=\"nec-confirm\" role=\"alert\" *ngIf=\"pendingResetKey() === s.key\">\n azzerare la slice?\n <button type=\"button\" class=\"nec-danger\" [attr.aria-label]=\"'Conferma azzeramento della slice ' + s.key\" (click)=\"confirmReset(s.key)\">Sì</button>\n <button type=\"button\" aria-label=\"Annulla azzeramento\" (click)=\"cancelPending()\">Annulla</button>\n </span>\n <span class=\"nec-confirm\" role=\"alert\" *ngIf=\"pendingResponsesKey() === s.key\">\n azzerare le responses?\n <button type=\"button\" class=\"nec-danger\" [attr.aria-label]=\"'Conferma azzeramento delle responses di ' + s.key\" (click)=\"confirmResetResponses(s.key)\">Sì</button>\n <button type=\"button\" aria-label=\"Annulla azzeramento\" (click)=\"cancelPending()\">Annulla</button>\n </span>\n <ng-container *ngIf=\"pendingResetKey() !== s.key && pendingResponsesKey() !== s.key\">\n <button type=\"button\" class=\"nec-danger\" [attr.aria-label]=\"'Azzera la slice ' + s.key\" (click)=\"requestReset(s.key)\">reset</button>\n <button type=\"button\" [attr.aria-label]=\"'Azzera le responses di ' + s.key\" (click)=\"requestResetResponses(s.key)\">reset responses</button>\n </ng-container>\n </td>\n </tr>\n </tbody>\n </table>\n </ng-container>\n <ng-template #noSlices>\n <div class=\"nec-note\">Nessuna slice CRUD montata.</div>\n </ng-template>\n\n <ng-container *ngIf=\"storeReport()!.lazy?.length; else noLazy\">\n <h3 style=\"margin-top:12px\">Sezioni lazy (da lazy-report)</h3>\n <div class=\"nec-note\" *ngIf=\"storeReport()!.lazyReportGeneratedAt\">\n snapshot generato il {{ storeReport()!.lazyReportGeneratedAt }} — rigenera con\n <code>ng generate ngrx-entity-crud:lazy-report --format=json</code> se obsoleto.\n </div>\n <table>\n <thead>\n <tr>\n <th>store</th>\n <th>sezioni</th>\n <th>verdetto</th>\n <th>runtime</th>\n </tr>\n </thead>\n <tbody>\n <tr *ngFor=\"let l of storeReport()!.lazy!; trackBy: trackByName\">\n <td>{{ l.name }}</td>\n <td>{{ l.sections.join(', ') || '–' }}</td>\n <td>{{ l.verdict }}</td>\n <td>\n <span\n class=\"nec-badge\"\n [class.lazy]=\"l.runtimeStatus === 'lazy-not-loaded'\"\n >{{ l.runtimeStatus }}</span>\n </td>\n </tr>\n </tbody>\n </table>\n </ng-container>\n <ng-template #noLazy>\n <div class=\"nec-note\">\n Nessun lazy-report caricato (genera src/assets/lazy-report.json con\n <code>ng generate ngrx-entity-crud:lazy-report --format=json</code>).\n </div>\n </ng-template>\n </ng-container>\n </div>\n `,\n})\nexport class NecDashboardComponent implements OnInit, OnDestroy {\n private readonly localStorageProbe = inject(NecLocalStorageProbeService);\n private readonly indexedDbProbe = inject(NecIndexedDbProbeService);\n private readonly storeProbe = inject(NecStoreProbeService);\n\n /** Chiavi di slice da escludere dallo scan dello store. */\n @Input() blacklist: string[] = [];\n /** Se valorizzata, considera SOLO queste chiavi di slice (precede la blacklist). */\n @Input() whitelist: string[] = [];\n /** URL del report statico (`lazy-report --format=json`); `null`/'' per disattivarlo. */\n @Input() lazyReportUrl: string | null = 'assets/lazy-report.json';\n /** Nomi DB IndexedDB da ispezionare dove `databases()` non è supportato (es. Firefox). */\n @Input() idbDatabaseNames: string[] = [];\n /** Intervallo di auto-refresh in ms; 0 = solo manuale (default). */\n @Input() pollingMs = 0;\n /** Abilita il reveal opt-in dei valori localStorage (sempre mascherati). Default: false. */\n @Input() allowRevealValues = false;\n\n /** Emesso (con la slice key) a ogni `Reset` completo dispacciato, incluso l'azzera-tutte. */\n @Output() sliceReset = new EventEmitter<string>();\n\n readonly busy = signal(false);\n readonly lastUpdated = signal<string | null>(null);\n readonly storage = signal<NecStorageReport | null>(null);\n readonly quota = signal<NecQuotaEstimate | null>(null);\n readonly idb = signal<NecIdbReport | null>(null);\n readonly storeReport = signal<NecStoreReport | null>(null);\n readonly revealed = signal<Record<string, string>>({});\n /** Slice in attesa di conferma per il `Reset` completo (conferma a due step). */\n readonly pendingResetKey = signal<string | null>(null);\n /** Slice in attesa di conferma per il `ResetResponses`. */\n readonly pendingResponsesKey = signal<string | null>(null);\n /** `true` quando è in attesa di conferma l'azzeramento globale di tutte le slice. */\n readonly pendingResetAll = signal(false);\n\n private timer: ReturnType<typeof setInterval> | null = null;\n /** Un refresh richiesto mentre un altro è già in corso: viene ri-eseguito al termine. */\n private pendingRefresh = false;\n\n ngOnInit(): void {\n void this.refresh();\n if (this.pollingMs > 0) {\n this.timer = setInterval(() => void this.refresh(), this.pollingMs);\n }\n }\n\n ngOnDestroy(): void {\n if (this.timer != null) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n async refresh(): Promise<void> {\n if (this.busy()) {\n // Un refresh è già in corso (es. polling): richiedine uno al termine così i conteggi\n // post-reset non restano stantii se il dispatch arriva mentre l'altro è in volo.\n this.pendingRefresh = true;\n return;\n }\n this.busy.set(true);\n this.revealed.set({}); // i valori rivelati non sopravvivono a un refresh\n this.cancelPending(); // nessuna conferma \"appesa\" dopo un refresh/polling\n try {\n this.storage.set(this.localStorageProbe.read('local'));\n this.quota.set(await this.localStorageProbe.estimate());\n this.idb.set(await this.indexedDbProbe.read(this.idbDatabaseNames));\n\n const opts = {blacklist: this.blacklist, whitelist: this.whitelist};\n if (this.lazyReportUrl) {\n this.storeReport.set(await this.storeProbe.readWithLazyReport(this.lazyReportUrl, opts));\n } else {\n this.storeReport.set(this.storeProbe.read(opts));\n }\n this.lastUpdated.set(new Date().toLocaleTimeString());\n } finally {\n this.busy.set(false);\n if (this.pendingRefresh) {\n this.pendingRefresh = false;\n void this.refresh();\n }\n }\n }\n\n /** Reveal opt-in di un valore localStorage, sempre passato per `maskValue` (privacy). */\n reveal(key: string): void {\n const value = this.localStorageProbe.readValue(key) ?? '';\n this.revealed.update((m) => ({...m, [key]: maskValue(key, value)}));\n }\n\n /** Step 1: chiede conferma per il `Reset` completo della slice. */\n requestReset(key: string): void {\n this.pendingResponsesKey.set(null);\n this.pendingResetAll.set(false);\n this.pendingResetKey.set(key);\n }\n\n /** Step 1: chiede conferma per il `ResetResponses` della slice. */\n requestResetResponses(key: string): void {\n this.pendingResetKey.set(null);\n this.pendingResetAll.set(false);\n this.pendingResponsesKey.set(key);\n }\n\n /** Step 1: chiede conferma per l'azzeramento globale di tutte le slice. */\n requestResetAll(): void {\n this.pendingResetKey.set(null);\n this.pendingResponsesKey.set(null);\n this.pendingResetAll.set(true);\n }\n\n /** Annulla qualsiasi conferma pendente (reset/responses/azzera-tutte). */\n cancelPending(): void {\n this.pendingResetKey.set(null);\n this.pendingResponsesKey.set(null);\n this.pendingResetAll.set(false);\n }\n\n /** Step 2: dispaccia il `Reset` della slice, emette `sliceReset` e ricarica i conteggi. */\n confirmReset(key: string): void {\n this.storeProbe.reset(key);\n this.sliceReset.emit(key);\n this.cancelPending();\n void this.refresh();\n }\n\n /** Step 2: dispaccia il `ResetResponses` della slice e ricarica i conteggi. */\n confirmResetResponses(key: string): void {\n this.storeProbe.resetResponses(key);\n this.cancelPending();\n void this.refresh();\n }\n\n /** Step 2: dispaccia il `Reset` su tutte le slice elencate, emettendo `sliceReset` per ciascuna. */\n confirmResetAll(): void {\n const slices = this.storeReport()?.slices ?? [];\n for (const s of slices) {\n this.storeProbe.reset(s.key);\n this.sliceReset.emit(s.key);\n }\n this.cancelPending();\n void this.refresh();\n }\n\n isSensitive(key: string): boolean {\n return looksSensitiveKey(key);\n }\n\n /** trackBy per le righe identificate da `key` (entry localStorage, slice store). */\n trackByKey(_: number, item: {key: string}): string {\n return item.key;\n }\n\n /** trackBy per le righe identificate da `name` (DB/object store IndexedDB, voci lazy). */\n trackByName(_: number, item: {name: string}): string {\n return item.name;\n }\n\n formatBytes(n: number | undefined | null): string {\n if (n == null) {\n return '–';\n }\n if (n < 1024) {\n return `${n} B`;\n }\n if (n < 1024 * 1024) {\n return `${(n / 1024).toFixed(1)} KB`;\n }\n return `${(n / 1024 / 1024).toFixed(2)} MB`;\n }\n}\n","/**\n * Secondary entry-point `ngrx-entity-crud/devtools`.\n *\n * Dashboard di gestione progetto: riepiloghi runtime di localStorage, IndexedDB (agnostico)\n * e store NgRx + sezioni promovibili al lazy loading. Tree-shakable: chi non lo importa non\n * lo paga nel bundle. Vedi `ngrx-entity-crud-dashboard-plan.md`.\n */\n\nexport * from './models';\nexport * from './idb-adapter.token';\nexport * from './agnostic-selectors';\nexport * from './mask';\nexport * from './probes/nec-local-storage-probe.service';\nexport * from './probes/nec-indexeddb-probe.service';\nexport * from './probes/nec-store-probe.service';\nexport * from './nec-dashboard.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngrx-entity-crud",
3
- "version": "19.4.0-beta.7",
3
+ "version": "19.4.0-beta.8",
4
4
  "repository": "https://github.com/jucasoft/ngrx-entity-crud",
5
5
  "license": "MIT",
6
6
  "schematics": "./schematics/collection.json",
@@ -7,6 +7,9 @@
7
7
  - [idbDatabaseNames]: nomi DB da ispezionare dove indexedDB.databases() non è supportato
8
8
  (es. Firefox/Safari), p.es. [idbDatabaseNames]="['NgRxStateStore']".
9
9
  - [pollingMs]: auto-refresh in ms (0 = solo manuale).
10
+ Il pannello "Store NgRx" espone i pulsanti "reset" / "reset responses" per riga e
11
+ "Azzera tutte" (con conferma a due step); l'output (sliceReset)="..." emette la key
12
+ della slice azzerata.
10
13
  -->
11
14
  <nec-dashboard lazyReportUrl="assets/lazy-report.json"></nec-dashboard>
12
15
  </p-card>