@esfaenza/admin-module 20.3.23 → 20.3.24

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.
@@ -3,7 +3,7 @@ import { formatNumber, CommonModule } from '@angular/common';
3
3
  import * as i7 from '@angular/forms';
4
4
  import { FormsModule } from '@angular/forms';
5
5
  import * as i0 from '@angular/core';
6
- import { InjectionToken, Injectable, Inject, Component, ViewChild, EventEmitter, Output, Input, Optional, Pipe, inject, NgModule } from '@angular/core';
6
+ import { InjectionToken, Injectable, Inject, Component, ViewChild, Input, Pipe, EventEmitter, Output, Optional, inject, NgModule } from '@angular/core';
7
7
  import * as i4 from '@angular/router';
8
8
  import { RouterModule } from '@angular/router';
9
9
  import * as i8$1 from 'ngx-bootstrap/modal';
@@ -15,7 +15,7 @@ import { AppSearch, EsTableOperationDefinition, EsTableModule } from '@esfaenza/
15
15
  import * as i9 from '@esfaenza/forms-and-validations';
16
16
  import { FormsAndValidationsModule } from '@esfaenza/forms-and-validations';
17
17
  import * as i2 from '@esfaenza/es-charts';
18
- import { LineSerie, LineChartData, PieChartData, KeyValueColor, DateValue, Limit, EsChartsModule } from '@esfaenza/es-charts';
18
+ import { LineSerie, DateValue, LineChartData, PieChartData, KeyValueColor, Limit, EsChartsModule } from '@esfaenza/es-charts';
19
19
  import { EsGertrudeModule } from '@esfaenza/gertrude';
20
20
  import * as i1$1 from '@esfaenza/extensions';
21
21
  import { MessageService, InboundMessageTypes, Export, ExportLocalization, ExtensionsModule } from '@esfaenza/extensions';
@@ -48,6 +48,7 @@ const ADM_TOPACT_V2 = new InjectionToken('ADM_TOPACT_V2');
48
48
  const ADM_PROFILER_V2 = new InjectionToken('ADM_PROFILER_V2');
49
49
  const ADM_WORKLOAD_V2 = new InjectionToken('ADM_WORKLOAD_V2');
50
50
  const ADM_METRICS_V2 = new InjectionToken('ADM_METRICS_V2');
51
+ const ADM_DETAILS_V2 = new InjectionToken('ADM_DETAILS_V2');
51
52
 
52
53
  class AdmAuditLoc extends LocalizationService {
53
54
  constructor(injector) {
@@ -207,7 +208,9 @@ class AdminModuleBaseService {
207
208
  // Testo di un errore delle chiamate v2: il backend-for-frontend manda il messaggio come stringa JSON (542 per i 400 del backend).
208
209
  // Solo la prima riga, perché i 500 portano lo stack
209
210
  errorText(err) {
210
- let message = typeof err?.error === "string" ? err.error : err?.error?.message ?? err?.message ?? "";
211
+ // Il corpo può essere anche un oggetto: MdmErrorResponse (message) o il ProblemDetails di ASP.NET (title, detail)
212
+ let body = err?.error;
213
+ let message = typeof body === "string" ? body : body?.message ?? body?.Message ?? body?.detail ?? body?.title ?? err?.message ?? "";
211
214
  return String(message).split(/\r?\n/)[0];
212
215
  }
213
216
  async getInfos(be) {
@@ -225,6 +228,22 @@ class AdminModuleBaseService {
225
228
  let ret = await firstValueFrom(this.http.get(GET_Director_GetSessionStats, pars));
226
229
  return ret;
227
230
  }
231
+ // Stesso URL di getNodeStats: con DirectorFeature.DetailsV2 attivo il backend-for-frontend risponde con il dettaglio v2. null se il nodo non c'è
232
+ async getNodeDetailV2(be, req) {
233
+ let ret = await this.v2Call(this.http.get(GET_Director_GetNodeStats, this.queryParams(be, req), null, false));
234
+ return ret;
235
+ }
236
+ // Stesso URL di getSessionStats, come sopra. null se la sessione non esiste più e nella finestra non era attiva
237
+ async getSessionDetailV2(be, req) {
238
+ let ret = await this.v2Call(this.http.get(GET_Director_GetSessionStats, this.queryParams(be, req), null, false));
239
+ return ret;
240
+ }
241
+ // Parametri in query string senza i null, così vale il default del backend
242
+ queryParams(be, req) {
243
+ let pars = new HttpParams().set("be", be ?? "");
244
+ Object.entries(req).filter(([_, v]) => v != null && v !== "").forEach(([k, v]) => pars = pars.set(k, String(v)));
245
+ return pars;
246
+ }
228
247
  async getProfilerDataNodes(be, sv) {
229
248
  var pars = new HttpParams().set("be", be ?? "");
230
249
  let ret = await firstValueFrom(this.http.post(POST_Director_GetProfilerDataNodes, sv, pars));
@@ -753,6 +772,782 @@ class ProfilerDataNodesView extends AppSearch {
753
772
  constructor() { super(); }
754
773
  }
755
774
 
775
+ // Enum della Top Activity v2: i numeri sono quelli del backend (le risposte li riportano come numeri)
776
+ var TopActivityDimension;
777
+ (function (TopActivityDimension) {
778
+ TopActivityDimension[TopActivityDimension["WaitClass"] = 0] = "WaitClass";
779
+ TopActivityDimension[TopActivityDimension["EventType"] = 1] = "EventType";
780
+ TopActivityDimension[TopActivityDimension["WaitEvent"] = 2] = "WaitEvent";
781
+ TopActivityDimension[TopActivityDimension["Instance"] = 3] = "Instance";
782
+ TopActivityDimension[TopActivityDimension["UserSession"] = 4] = "UserSession";
783
+ TopActivityDimension[TopActivityDimension["UserName"] = 5] = "UserName";
784
+ TopActivityDimension[TopActivityDimension["Tenant"] = 6] = "Tenant";
785
+ TopActivityDimension[TopActivityDimension["SessionType"] = 7] = "SessionType";
786
+ TopActivityDimension[TopActivityDimension["BackgroundSession"] = 8] = "BackgroundSession";
787
+ TopActivityDimension[TopActivityDimension["JobName"] = 9] = "JobName";
788
+ TopActivityDimension[TopActivityDimension["ConsumerGroup"] = 10] = "ConsumerGroup";
789
+ TopActivityDimension[TopActivityDimension["ThreadType"] = 11] = "ThreadType";
790
+ TopActivityDimension[TopActivityDimension["Api"] = 12] = "Api";
791
+ TopActivityDimension[TopActivityDimension["Machine"] = 13] = "Machine";
792
+ // Chiave TID@istanza, etichetta il TID (specifica "Dettaglio nodo e sessione")
793
+ TopActivityDimension[TopActivityDimension["Thread"] = 14] = "Thread";
794
+ })(TopActivityDimension || (TopActivityDimension = {}));
795
+ var TopActivityDataSource;
796
+ (function (TopActivityDataSource) {
797
+ TopActivityDataSource[TopActivityDataSource["Memory"] = 0] = "Memory";
798
+ TopActivityDataSource[TopActivityDataSource["MemoryAndStored"] = 1] = "MemoryAndStored";
799
+ })(TopActivityDataSource || (TopActivityDataSource = {}));
800
+ var TopActivityResolution;
801
+ (function (TopActivityResolution) {
802
+ TopActivityResolution[TopActivityResolution["Low"] = 0] = "Low";
803
+ TopActivityResolution[TopActivityResolution["Medium"] = 1] = "Medium";
804
+ TopActivityResolution[TopActivityResolution["High"] = 2] = "High";
805
+ TopActivityResolution[TopActivityResolution["Maximum"] = 3] = "Maximum";
806
+ })(TopActivityResolution || (TopActivityResolution = {}));
807
+ var TopActivityMaximumThreads;
808
+ (function (TopActivityMaximumThreads) {
809
+ TopActivityMaximumThreads[TopActivityMaximumThreads["None"] = 0] = "None";
810
+ TopActivityMaximumThreads[TopActivityMaximumThreads["Cores"] = 1] = "Cores";
811
+ TopActivityMaximumThreads[TopActivityMaximumThreads["Threads"] = 2] = "Threads";
812
+ })(TopActivityMaximumThreads || (TopActivityMaximumThreads = {}));
813
+
814
+ // Colori e regole del grafico della Top Activity v2, condivisi con i dettagli di nodo e sessione: le stesse chiavi hanno gli stessi colori
815
+ // WaitClass ed EventType hanno valori fissi: colori fissi, così il grafico si legge sempre allo stesso modo
816
+ const FIXED_COLORS = {
817
+ Cpu: "#43a047", Database: "#1e88e5", Script: "#8e24aa", Network: "#8d6e63", IO: "#00acc1", Sleep: "#b0bec5", Throttle: "#fb8c00", Wait: "#fdd835",
818
+ Latch: "#e53935", Semaphore: "#f06292", Enqueue: "#c62828", ReadWriteLock: "#ad1457", Fence: "#6d4c41", ConditionVariable: "#00897b", Scheduler: "#5e35b1"
819
+ };
820
+ const PALETTE = ["#1e88e5", "#43a047", "#fb8c00", "#8e24aa", "#e53935", "#00897b", "#fdd835", "#6d4c41", "#3949ab", "#c0ca33"];
821
+ const OTHER_COLOR = "#9e9e9e";
822
+ const TOTAL_COLOR = "#263238";
823
+ const LIMIT_COLOR = "#e53935";
824
+ // Colore del componente i-esimo: fisso per le chiavi note (classi di attesa e tipi di evento), dalla tavolozza per le altre
825
+ function componentColor(key, other, index, fixed) {
826
+ return other ? OTHER_COLOR : (fixed && FIXED_COLORS[key]) || PALETTE[index % PALETTE.length];
827
+ }
828
+ // es-charts ricava la griglia dell'asse dal passo fra i punti ma la arrotonda all'unità superiore: 30 s diventano 1 minuto, 5 minuti 1 ora.
829
+ // amCharts mette allora più bucket nella stessa cella e i gradini si sovrappongono (aree, linea del totale e tooltip non tornano).
830
+ // Il passo lo dà la risposta, e i bucket della specifica (1-30 s, 1-30 min, 1 h) dividono sempre il minuto o l'ora
831
+ function bucketInterval(seconds) {
832
+ if (!seconds)
833
+ return null;
834
+ if (seconds % 3600 == 0)
835
+ return { timeunit: "hour", count: seconds / 3600 };
836
+ if (seconds % 60 == 0)
837
+ return { timeunit: "minute", count: seconds / 60 };
838
+ return { timeunit: "second", count: seconds };
839
+ }
840
+ // Le date delle risposte del Director v2 sono UTC "dd/MM/yyyy HH:mm:ss" senza fuso
841
+ function parseUtc(value) {
842
+ let m = /^(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2}):(\d{2})$/.exec(value ?? "");
843
+ return m ? new Date(Date.UTC(+m[3], +m[2] - 1, +m[1], +m[4], +m[5], +m[6])) : value ? new Date(value) : null;
844
+ }
845
+
846
+ class AdmDetailsV2Loc extends LocalizationService {
847
+ constructor(injector) {
848
+ super(injector);
849
+ super.set("it->en", "Indietro", ["Back"]);
850
+ super.set("it->en", "Dettaglio nodo", ["Node detail"]);
851
+ super.set("it->en", "Sessione", ["Session"]);
852
+ super.set("it->en", "Ultime", ["Last"]);
853
+ super.set("it->en", "Da", ["From"]);
854
+ super.set("it->en", "A", ["To"]);
855
+ super.set("it->en", "Applica", ["Apply"]);
856
+ super.set("it->en", "dalle", ["from"]);
857
+ super.set("it->en", "alle", ["to"]);
858
+ super.set("it->en", "Memoria", ["Memory"]);
859
+ super.set("it->en", "Memoria e storico", ["Memory and history"]);
860
+ super.set("it->en", "Dal vivo", ["Live"]);
861
+ super.set("it->en", "Storico", ["History"]);
862
+ super.set("it->en", "Aggiornato alle", ["Updated at"]);
863
+ super.set("it->en", "Pausa", ["Pause"]);
864
+ super.set("it->en", "Riprendi", ["Resume"]);
865
+ super.set("it->en", "La finestra è stata ridotta alle ultime 24 ore", ["The window was reduced to the last 24 hours"]);
866
+ super.set("it->en", "Errore", ["Error"]);
867
+ super.set("it->en", "Nodo non trovato", ["Node not found"]);
868
+ super.set("it->en", "Sessione non trovata: non esiste più e nella finestra non era attiva", ["Session not found: it no longer exists and was not active in the window"]);
869
+ super.set("it->en", "Carico i Dati", ["Loading data"]);
870
+ super.set("it->en", "Copia", ["Copy"]);
871
+ super.set("it->en", "Copiato", ["Copied"]);
872
+ super.set("it->en", "Apri nel profiler", ["Open in profiler"]);
873
+ super.set("it->en", "Sessioni su questo evento", ["Sessions on this event"]);
874
+ super.set("it->en", "Solo l'evento esatto: il lavoro dei discendenti non è compreso", ["Exact event only: the descendants' work is not included"]);
875
+ super.set("it->en", "Top Activity filtrata su questo evento", ["Top Activity filtered on this event"]);
876
+ super.set("it->en", "discendenti esclusi", ["descendants excluded"]);
877
+ super.set("it->en", "Statistiche", ["Statistics"]);
878
+ super.set("it->en", "Dall'avvio", ["Since startup"]);
879
+ super.set("it->en", "Dall'ultimo snapshot", ["Since the last snapshot"]);
880
+ super.set("it->en", "Nella finestra", ["In the window"]);
881
+ super.set("it->en", "Esecuzioni", ["Executions"]);
882
+ super.set("it->en", "Tempo totale", ["Total time"]);
883
+ super.set("it->en", "Tempo proprio", ["Self time"]);
884
+ super.set("it->en", "Medio", ["Average"]);
885
+ super.set("it->en", "Massimo", ["Peak"]);
886
+ super.set("it->en", "Minimo", ["Minimum"]);
887
+ super.set("it->en", "Thread dentro adesso", ["Threads inside now"]);
888
+ super.set("it->en", "In corso da", ["Running for"]);
889
+ super.set("it->en", "Ultima uscita", ["Last exit"]);
890
+ super.set("it->en", "Dove va il tempo", ["Where the time goes"]);
891
+ super.set("it->en", "tempo proprio del sottoalbero", ["self time of the subtree"]);
892
+ super.set("it->en", "Idle è tempo di attesa senza lavoro", ["Idle is waiting time with no work"]);
893
+ super.set("it->en", "Per istanza", ["By instance"]);
894
+ super.set("it->en", "Istanza", ["Instance"]);
895
+ super.set("it->en", "Tempo", ["Time"]);
896
+ super.set("it->en", "Thread attivi", ["Active threads"]);
897
+ super.set("it->en", "Attività nel tempo", ["Activity over time"]);
898
+ super.set("it->en", "sessioni attive medie", ["average active sessions"]);
899
+ super.set("it->en", "picco", ["peak"]);
900
+ super.set("it->en", "un punto ogni", ["one point every"]);
901
+ super.set("it->en", "stima per campionamento", ["sampling estimate"]);
902
+ super.set("it->en", "Valori stimati contando i campioni", ["Values estimated by counting samples"]);
903
+ super.set("it->en", "sessioni", ["sessions"]);
904
+ super.set("it->en", "Nessuna attività nella finestra", ["No activity in the window"]);
905
+ super.set("it->en", "Prima delle", ["Before"]);
906
+ super.set("it->en", "i dati vengono dallo storico, con meno risoluzione", ["data comes from history, with lower resolution"]);
907
+ super.set("it->en", "Comprende il lavoro dei discendenti", ["Includes the descendants' work"]);
908
+ super.set("it->en", "Discendenti principali", ["Top descendants"]);
909
+ super.set("it->en", "Figli", ["Children"]);
910
+ super.set("it->en", "Discendenti", ["Descendants"]);
911
+ super.set("it->en", "Nome", ["Name"]);
912
+ super.set("it->en", "Tipo", ["Type"]);
913
+ super.set("it->en", "Livello", ["Level"]);
914
+ super.set("it->en", "del nodo", ["of the node"]);
915
+ super.set("it->en", "Terminata", ["Terminated"]);
916
+ super.set("it->en", "Utente", ["User"]);
917
+ super.set("it->en", "Gruppo di consumo", ["Consumer group"]);
918
+ super.set("it->en", "Sessione di background", ["Background session"]);
919
+ super.set("it->en", "Inizio", ["Start"]);
920
+ super.set("it->en", "collegata da", ["connected for"]);
921
+ super.set("it->en", "Ultima attività", ["Last activity"]);
922
+ super.set("it->en", "La sessione non esiste più: i suoi dati vengono dall'ultimo campione, delle", ["The session no longer exists: its data comes from the last sample, taken at"]);
923
+ super.set("it->en", "Sessioni attive medie", ["Average active sessions"]);
924
+ super.set("it->en", "Media", ["Average"]);
925
+ super.set("it->en", "Picco", ["Peak"]);
926
+ super.set("it->en", "Dividi per", ["Split by"]);
927
+ super.set("it->en", "Classe di attesa", ["Wait class"]);
928
+ super.set("it->en", "Tipo di evento", ["Event type"]);
929
+ super.set("it->en", "Evento", ["Event"]);
930
+ super.set("it->en", "Bassa", ["Low"]);
931
+ super.set("it->en", "Alta", ["High"]);
932
+ super.set("it->en", "Massima", ["Maximum"]);
933
+ super.set("it->en", "Eventi", ["Events"]);
934
+ super.set("it->en", "Attività", ["Activity"]);
935
+ super.set("it->en", "Altri", ["Others"]);
936
+ super.set("it->en", "(nessuno)", ["(none)"]);
937
+ super.set("it->en", "(non attribuito)", ["(unattributed)"]);
938
+ super.set("it->en", "Thread adesso", ["Threads now"]);
939
+ super.set("it->en", "Stato", ["Status"]);
940
+ super.set("it->en", "Priorità", ["Priority"]);
941
+ super.set("it->en", "Macchina", ["Machine"]);
942
+ super.set("it->en", "Evento corrente", ["Current event"]);
943
+ super.set("it->en", "nessun evento in corso", ["no event in progress"]);
944
+ super.set("it->en", "Pila completa degli eventi", ["Full event stack"]);
945
+ super.set("it->en", "Nessun evento", ["No event"]);
946
+ super.set("it->en", "Operazioni lunghe", ["Long operations"]);
947
+ super.set("it->en", "di", ["of"]);
948
+ super.set("it->en", "Trascorso", ["Elapsed"]);
949
+ super.set("it->en", "Alla fine", ["Remaining"]);
950
+ super.set("it->en", "non stimabile", ["not estimable"]);
951
+ }
952
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Loc, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
953
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Loc }); }
954
+ }
955
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Loc, decorators: [{
956
+ type: Injectable
957
+ }], ctorParameters: () => [{ type: i0.Injector }] });
958
+
959
+ // Angular
960
+ class ActivityChartV2Component_Item {
961
+ }
962
+ class LegendItem {
963
+ }
964
+ /**
965
+ * Grafico impilato delle sessioni attive medie, con le regole e i colori del grafico della Top Activity v2:
966
+ * un gradino per bucket, una serie per componente (l'ultimo, "altri", in grigio) e la legenda sotto.
967
+ * Lo usano i dettagli v2 di nodo (per classe di attesa) e di sessione (la sua Top Activity)
968
+ */
969
+ class ActivityChartV2Component {
970
+ constructor() {
971
+ // Chiavi con colore fisso: classi di attesa e tipi di evento
972
+ this.FixedColors = true;
973
+ this.name = "activitychartv2";
974
+ this.legend = [];
975
+ }
976
+ get emptyText() {
977
+ return this.EmptyText ?? "";
978
+ }
979
+ ngOnChanges() {
980
+ let times = (this.Times ?? []).map(t => parseUtc(t));
981
+ let components = this.Components ?? [];
982
+ if (times.length == 0 || components.length == 0) {
983
+ this.chartData = null;
984
+ this.legend = [];
985
+ return;
986
+ }
987
+ let interval = bucketInterval(this.BucketSeconds);
988
+ let series = [];
989
+ this.legend = components.map((c, i) => {
990
+ let color = componentColor(c.key, c.other, i, this.FixedColors);
991
+ series.push(new LineSerie(c.label, times.map((t, j) => new DateValue(t, c.values?.[j] ?? 0)), interval, color, this.Uom));
992
+ return { label: c.label, color: color, percentage: c.percentage };
993
+ });
994
+ this.chartData = new LineChartData(series);
995
+ }
996
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ActivityChartV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
997
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: ActivityChartV2Component, isStandalone: false, selector: "activity-chart-v2", inputs: { Times: "Times", Components: "Components", BucketSeconds: "BucketSeconds", FixedColors: "FixedColors", Uom: "Uom", EmptyText: "EmptyText", name: "name" }, usesOnChanges: true, ngImport: i0, template: `
998
+ @if (chartData) {
999
+ <div class="acv2-chart">
1000
+ <es-line-chart [MinGridDistance]="65" [Timeline]="false" [FinalInstants]="false" [Stacked]="true" [Step]="true" [Fill]="true" [MergeDatasets]="true"
1001
+ [AllowGaps]="false" [Legend]="false" [Data]="chartData" [name]="name" [DataGroupingThreshold]="99999999"></es-line-chart>
1002
+ </div>
1003
+ <div class="acv2-legend">
1004
+ @for (item of legend; track $index) {
1005
+ <span class="acv2-legend-item"><span class="acv2-swatch" [style.background]="item.color"></span>{{item.label}} <span class="acv2-muted">{{item.percentage | number : '1.0-1' : 'it'}}%</span></span>
1006
+ }
1007
+ </div>
1008
+ } @else {
1009
+ <div class="acv2-empty">{{emptyText}}</div>
1010
+ }`, isInline: true, styles: [":host{display:block}.acv2-chart{height:240px}.acv2-legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin-top:6px;font-size:12px}.acv2-legend-item{display:inline-flex;align-items:center;gap:5px}.acv2-swatch{width:10px;height:10px;border-radius:2px}.acv2-muted{color:var(--p-text-muted-color, #64748b)}.acv2-empty{padding:40px 0;text-align:center;color:var(--p-text-muted-color, #64748b)}\n"], dependencies: [{ kind: "component", type: i2.EsLineChartComponent, selector: "es-line-chart", inputs: ["Data", "DataArray", "Step", "DataGroupBucketSize", "DataGroupingThreshold", "StrokeSize", "AllowGaps", "MergeDatasets", "FinalInstants", "Min", "Max", "Fill", "Stacked"] }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }] }); }
1011
+ }
1012
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ActivityChartV2Component, decorators: [{
1013
+ type: Component,
1014
+ args: [{ selector: "activity-chart-v2", template: `
1015
+ @if (chartData) {
1016
+ <div class="acv2-chart">
1017
+ <es-line-chart [MinGridDistance]="65" [Timeline]="false" [FinalInstants]="false" [Stacked]="true" [Step]="true" [Fill]="true" [MergeDatasets]="true"
1018
+ [AllowGaps]="false" [Legend]="false" [Data]="chartData" [name]="name" [DataGroupingThreshold]="99999999"></es-line-chart>
1019
+ </div>
1020
+ <div class="acv2-legend">
1021
+ @for (item of legend; track $index) {
1022
+ <span class="acv2-legend-item"><span class="acv2-swatch" [style.background]="item.color"></span>{{item.label}} <span class="acv2-muted">{{item.percentage | number : '1.0-1' : 'it'}}%</span></span>
1023
+ }
1024
+ </div>
1025
+ } @else {
1026
+ <div class="acv2-empty">{{emptyText}}</div>
1027
+ }`, standalone: false, styles: [":host{display:block}.acv2-chart{height:240px}.acv2-legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin-top:6px;font-size:12px}.acv2-legend-item{display:inline-flex;align-items:center;gap:5px}.acv2-swatch{width:10px;height:10px;border-radius:2px}.acv2-muted{color:var(--p-text-muted-color, #64748b)}.acv2-empty{padding:40px 0;text-align:center;color:var(--p-text-muted-color, #64748b)}\n"] }]
1028
+ }], propDecorators: { Times: [{
1029
+ type: Input
1030
+ }], Components: [{
1031
+ type: Input
1032
+ }], BucketSeconds: [{
1033
+ type: Input
1034
+ }], FixedColors: [{
1035
+ type: Input
1036
+ }], Uom: [{
1037
+ type: Input
1038
+ }], EmptyText: [{
1039
+ type: Input
1040
+ }], name: [{
1041
+ type: Input
1042
+ }] } });
1043
+
1044
+ // Angular
1045
+ // Formati del profiler v2 (specifica "Profiler gerarchico"): durate nell'unità più leggibile, interi con il separatore
1046
+ // delle migliaia italiano, percentuali con un decimale sotto 10. Un dato mancante è "—"
1047
+ class ProfilerFormatPipe {
1048
+ transform(value, kind) {
1049
+ if (value == null || isNaN(value))
1050
+ return "—";
1051
+ switch (kind) {
1052
+ case "dur": return formatDuration(value);
1053
+ case "pct": return formatPercentage(value);
1054
+ default: return formatNumber(value, "it", "1.0-0");
1055
+ }
1056
+ }
1057
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
1058
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, isStandalone: true, name: "pv2fmt" }); }
1059
+ }
1060
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, decorators: [{
1061
+ type: Pipe,
1062
+ args: [{ name: "pv2fmt" }]
1063
+ }] });
1064
+ // Secondi: "850 µs", "4,27 ms", "312,5 ms", "8,41 s", "4 min 12 s", "3 h 20 min", "76 h"
1065
+ function formatDuration(seconds) {
1066
+ if (seconds == null || isNaN(seconds))
1067
+ return "—";
1068
+ let abs = Math.abs(seconds);
1069
+ if (abs < 0.001)
1070
+ return `${formatNumber(seconds * 1000000, "it", "1.0-0")} µs`;
1071
+ if (abs < 1)
1072
+ return `${formatNumber(seconds * 1000, "it", abs < 0.01 ? "1.2-2" : "1.1-1")} ms`;
1073
+ if (abs < 60)
1074
+ return `${formatNumber(seconds, "it", abs < 10 ? "1.2-2" : "1.1-1")} s`;
1075
+ if (abs < 3600)
1076
+ return `${Math.floor(abs / 60)} min ${Math.floor(abs % 60)} s`;
1077
+ if (abs < 48 * 3600)
1078
+ return `${Math.floor(abs / 3600)} h ${Math.floor(abs % 3600 / 60)} min`;
1079
+ return `${formatNumber(Math.floor(abs / 3600), "it", "1.0-0")} h`;
1080
+ }
1081
+ // Da 0 a 100: "4,2%", "34%"
1082
+ function formatPercentage(value) {
1083
+ if (value == null || isNaN(value))
1084
+ return "—";
1085
+ return `${formatNumber(value, "it", Math.abs(value) < 10 ? "1.1-1" : "1.0-0")}%`;
1086
+ }
1087
+
1088
+ // Angular
1089
+ const HOUR_MS$1 = 3600 * 1000;
1090
+ const MAX_WINDOW_MS = 24 * HOUR_MS$1;
1091
+ // Una finestra che finisce entro questo margine da adesso è "agganciata": l'aggiornamento automatico la sposta in avanti
1092
+ const ANCHOR_MARGIN_MS = 2 * 60 * 1000;
1093
+ // Una voce della pila di navigazione (D1): cosa mostrare, con quale finestra e sorgente
1094
+ class DetailsV2Entry {
1095
+ }
1096
+ // Contesto della pagina da cui si apre un dettaglio
1097
+ class DetailsV2Options {
1098
+ }
1099
+ class DetailsV2EventLink {
1100
+ }
1101
+ class StatRow {
1102
+ }
1103
+ class TypePart {
1104
+ }
1105
+ /**
1106
+ * Dettaglio di un nodo del profiler e di una sessione (specifica "Dettaglio nodo e sessione"), in una finestra di dialogo con la pila
1107
+ * di navigazione: dalla sessione si apre il nodo di un evento, dal nodo i suoi antenati e discendenti, "Indietro" torna al precedente.
1108
+ * Le chiamate sono GetNodeStats e GetSessionStats con DirectorFeature.DetailsV2 attivo
1109
+ */
1110
+ class AdmDetailsV2Component {
1111
+ constructor(lc, dateExts, adms) {
1112
+ this.lc = lc;
1113
+ this.dateExts = dateExts;
1114
+ this.adms = adms;
1115
+ this.Be = "";
1116
+ // "Sessioni su questo evento" ha senso solo con la Top Activity v2 (N8)
1117
+ this.CanShowSessions = false;
1118
+ // "Apri nel profiler" ha senso solo con il profiler v2, che sa usare un nodo come radice (N7)
1119
+ this.CanOpenProfiler = false;
1120
+ this.closed = new EventEmitter();
1121
+ this.sessionsOnEvent = new EventEmitter();
1122
+ this.openProfiler = new EventEmitter();
1123
+ this.Dim = TopActivityDimension;
1124
+ this.QuickRanges = [1, 6, 24];
1125
+ this.stack = [];
1126
+ this.loading = false;
1127
+ this.notFound = false;
1128
+ this.paused = false;
1129
+ this.refreshSeconds = 0;
1130
+ this.filterfrom = "";
1131
+ this.filterto = "";
1132
+ this.windowClamped = false;
1133
+ // Viste derivate dalla risposta
1134
+ this.nodeChartTimes = [];
1135
+ this.nodeChart = [];
1136
+ this.nodeStats = [];
1137
+ this.typeParts = [];
1138
+ this.sessionChart = [];
1139
+ this.sessionTables = [];
1140
+ this.copied = false;
1141
+ this.Dimensions = [];
1142
+ this.Resolutions = [];
1143
+ // Il tempo in corso dei thread avanza fra un aggiornamento e l'altro (S4)
1144
+ this.now = Date.now();
1145
+ this.loadedAt = Date.now();
1146
+ this.colors = {};
1147
+ this.visible = false;
1148
+ this.requestId = 0;
1149
+ this.Dimensions = [
1150
+ new KeyValue(String(TopActivityDimension.WaitClass), this.lc.loc("Classe di attesa")),
1151
+ new KeyValue(String(TopActivityDimension.EventType), this.lc.loc("Tipo di evento")),
1152
+ new KeyValue(String(TopActivityDimension.Thread), "Thread"),
1153
+ new KeyValue(String(TopActivityDimension.Api), "API"),
1154
+ new KeyValue(String(TopActivityDimension.WaitEvent), this.lc.loc("Evento"))
1155
+ ];
1156
+ this.Resolutions = [
1157
+ new KeyValue(String(TopActivityResolution.Low), this.lc.loc("Bassa")),
1158
+ new KeyValue(String(TopActivityResolution.Medium), this.lc.loc("Media")),
1159
+ new KeyValue(String(TopActivityResolution.High), this.lc.loc("Alta")),
1160
+ new KeyValue(String(TopActivityResolution.Maximum), this.lc.loc("Massima"))
1161
+ ];
1162
+ }
1163
+ ngOnDestroy() {
1164
+ this.stopTimers();
1165
+ }
1166
+ get current() {
1167
+ return this.stack[this.stack.length - 1];
1168
+ }
1169
+ // #region Apertura e navigazione (D1)
1170
+ openNode(nodeId, o) {
1171
+ // D3: dal vivo nel caso normale; lo storico solo se la finestra è tutta prima dei campioni in memoria
1172
+ let realTime = o.realTime ?? !(o.memoryFrom && o.to.getTime() <= o.memoryFrom.getTime());
1173
+ this.start({ kind: "node", nodeId: nodeId, global: o.instanceId ? null : (o.global ?? true), instanceId: o.instanceId || null, realTime: realTime, ...this.window(o) }, o);
1174
+ }
1175
+ openSession(instanceId, sid, serial, o) {
1176
+ this.start({ kind: "session", instanceId: instanceId, sid: sid, serial: serial, dimension: TopActivityDimension.WaitClass, resolution: TopActivityResolution.Medium, realTime: o.realTime ?? false, ...this.window(o) }, o);
1177
+ }
1178
+ // Da una sessione l'istanza è quella della sessione e il nodo si legge dal vivo; da un nodo valgono gli stessi parametri
1179
+ pushNode(nodeId) {
1180
+ let cur = this.current;
1181
+ if (!nodeId || !cur)
1182
+ return;
1183
+ let entry = cur.kind == "session"
1184
+ ? { kind: "node", nodeId: nodeId, global: null, instanceId: cur.instanceId, realTime: true, from: cur.from, to: cur.to, anchored: cur.anchored }
1185
+ : { ...cur, nodeId: nodeId };
1186
+ this.stack.push(entry);
1187
+ this.load();
1188
+ }
1189
+ back() {
1190
+ if (this.stack.length < 2)
1191
+ return;
1192
+ this.stack.pop();
1193
+ this.load();
1194
+ }
1195
+ close() {
1196
+ this.stop();
1197
+ this.closed.emit();
1198
+ }
1199
+ // Da chiamare quando la finestra di dialogo si chiude: l'aggiornamento automatico si ferma (D5)
1200
+ stop() {
1201
+ this.visible = false;
1202
+ this.stopTimers();
1203
+ }
1204
+ start(entry, o) {
1205
+ this.refreshSeconds = o.refreshSeconds ?? 0;
1206
+ this.paused = false;
1207
+ this.stack = [entry];
1208
+ this.visible = true;
1209
+ this.load();
1210
+ this.startTimers();
1211
+ }
1212
+ window(o) {
1213
+ let to = (o.to ?? new Date()).getTime();
1214
+ let from = (o.from ?? new Date(to - HOUR_MS$1)).getTime();
1215
+ return { from: Math.max(from, to - MAX_WINDOW_MS), to: to, anchored: Math.abs(Date.now() - to) < ANCHOR_MARGIN_MS };
1216
+ }
1217
+ // #endregion
1218
+ // #region Caricamento
1219
+ async load(refresh = false) {
1220
+ let entry = this.current;
1221
+ if (!entry)
1222
+ return;
1223
+ this.syncWindowFields();
1224
+ let id = ++this.requestId;
1225
+ this.loading = true;
1226
+ this.error = null;
1227
+ if (!refresh) {
1228
+ this.node = null;
1229
+ this.session = null;
1230
+ this.notFound = false;
1231
+ this.expandedTid = null;
1232
+ this.highlightedTid = null;
1233
+ }
1234
+ try {
1235
+ if (entry.kind == "node") {
1236
+ let res = await this.adms.getNodeDetailV2(this.Be, this.nodeRequest(entry));
1237
+ if (id != this.requestId)
1238
+ return;
1239
+ this.node = res;
1240
+ this.buildNodeView();
1241
+ }
1242
+ else {
1243
+ let res = await this.adms.getSessionDetailV2(this.Be, this.sessionRequest(entry));
1244
+ if (id != this.requestId)
1245
+ return;
1246
+ this.session = res;
1247
+ this.buildSessionView();
1248
+ }
1249
+ this.notFound = !this.node && !this.session;
1250
+ this.updatedAt = new Date();
1251
+ this.loadedAt = Date.now();
1252
+ this.now = this.loadedAt;
1253
+ }
1254
+ catch (err) {
1255
+ if (id != this.requestId || err?.status == 401)
1256
+ return;
1257
+ this.node = null;
1258
+ this.session = null;
1259
+ // 400 del backend (finestra non valida): arriva come 542 con il message (D6)
1260
+ this.error = err?.status == 542 ? this.adms.errorText(err) : `${this.lc.loc("Errore")} ${err?.status ?? ""}: ${this.adms.errorText(err)}`;
1261
+ }
1262
+ finally {
1263
+ if (id == this.requestId)
1264
+ this.loading = false;
1265
+ }
1266
+ }
1267
+ nodeRequest(e) {
1268
+ return {
1269
+ nodeId: e.nodeId,
1270
+ realTime: e.realTime,
1271
+ global: e.instanceId ? null : e.global,
1272
+ instanceId: e.instanceId,
1273
+ snapFrom: new Date(e.from).toISOString(),
1274
+ snapTo: new Date(e.to).toISOString()
1275
+ };
1276
+ }
1277
+ sessionRequest(e) {
1278
+ return {
1279
+ instanceId: e.instanceId,
1280
+ sid: e.sid,
1281
+ serial: e.serial,
1282
+ realTime: e.realTime,
1283
+ snapFrom: new Date(e.from).toISOString(),
1284
+ snapTo: new Date(e.to).toISOString(),
1285
+ dimension: e.dimension,
1286
+ resolution: e.resolution
1287
+ };
1288
+ }
1289
+ // #endregion
1290
+ // #region Finestra, sorgente e aggiornamento (D2, D3, D5)
1291
+ quickRange(hours) {
1292
+ let e = this.current;
1293
+ e.to = Date.now();
1294
+ e.from = e.to - hours * HOUR_MS$1;
1295
+ e.anchored = true;
1296
+ this.load();
1297
+ }
1298
+ applyDates() {
1299
+ let e = this.current;
1300
+ let to = this.toDate(this.filterto)?.getTime() ?? Date.now();
1301
+ let from = this.toDate(this.filterfrom)?.getTime() ?? to - HOUR_MS$1;
1302
+ // Al massimo 24 ore; una finestra rovesciata la rifiuta il backend con il suo messaggio
1303
+ this.windowClamped = to - from > MAX_WINDOW_MS;
1304
+ e.from = this.windowClamped ? to - MAX_WINDOW_MS : from;
1305
+ e.to = to;
1306
+ e.anchored = Math.abs(Date.now() - to) < ANCHOR_MARGIN_MS;
1307
+ this.load();
1308
+ }
1309
+ setRealTime(realTime) {
1310
+ if (this.current.realTime == realTime)
1311
+ return;
1312
+ this.current.realTime = realTime;
1313
+ this.load();
1314
+ }
1315
+ setDimension(id) {
1316
+ this.current.dimension = +id;
1317
+ this.load(true);
1318
+ }
1319
+ setResolution(id) {
1320
+ this.current.resolution = +id;
1321
+ this.load(true);
1322
+ }
1323
+ togglePause() {
1324
+ this.paused = !this.paused;
1325
+ }
1326
+ get autoRefresh() {
1327
+ return this.refreshSeconds > 0 && !!this.current?.anchored;
1328
+ }
1329
+ get windowLabel() {
1330
+ let e = this.current;
1331
+ if (!e)
1332
+ return "";
1333
+ let sameDay = dayjs(e.from).isSame(dayjs(e.to), "day");
1334
+ let fmtFrom = dayjs(e.from).format(sameDay ? "HH:mm" : "DD/MM HH:mm");
1335
+ let fmtTo = dayjs(e.to).format(sameDay ? "HH:mm" : "DD/MM HH:mm");
1336
+ return `${this.lc.loc("dalle")} ${fmtFrom} ${this.lc.loc("alle")} ${fmtTo} (${this.timeZone()})`;
1337
+ }
1338
+ startTimers() {
1339
+ this.stopTimers();
1340
+ this.tickTimer = setInterval(() => this.now = Date.now(), 1000);
1341
+ if (this.refreshSeconds > 0)
1342
+ this.refreshTimer = setInterval(() => this.autoRefreshTick(), this.refreshSeconds * 1000);
1343
+ }
1344
+ stopTimers() {
1345
+ clearInterval(this.tickTimer);
1346
+ clearInterval(this.refreshTimer);
1347
+ this.tickTimer = null;
1348
+ this.refreshTimer = null;
1349
+ }
1350
+ // Sposta in avanti la finestra della stessa durata, solo se è agganciata ad adesso, non in pausa e il dettaglio si vede
1351
+ autoRefreshTick() {
1352
+ let e = this.current;
1353
+ if (!e || !e.anchored || this.paused || this.loading || !this.visible || document.hidden)
1354
+ return;
1355
+ let length = e.to - e.from;
1356
+ e.to = Date.now();
1357
+ e.from = e.to - length;
1358
+ this.load(true);
1359
+ }
1360
+ syncWindowFields() {
1361
+ let e = this.current;
1362
+ this.filterfrom = this.fmt(new Date(e.from));
1363
+ this.filterto = this.fmt(new Date(e.to));
1364
+ }
1365
+ // #endregion
1366
+ // #region Nodo (N1-N8)
1367
+ get nodeLive() {
1368
+ return !!this.node && this.current?.realTime && this.node.snapDeltaExecutions != null;
1369
+ }
1370
+ buildNodeView() {
1371
+ let n = this.node;
1372
+ if (!n) {
1373
+ this.nodeChart = [];
1374
+ this.nodeChartTimes = [];
1375
+ this.nodeStats = [];
1376
+ this.typeParts = [];
1377
+ return;
1378
+ }
1379
+ this.nodeChartTimes = (n.activeSessions ?? []).map(t => t.timestamp);
1380
+ this.nodeChart = (n.activityByClass ?? []).map(c => ({ ...c, label: c.other ? this.lc.loc("Altri") : c.label }));
1381
+ // minTime vale 0 senza esecuzioni concluse, snapDeltaMinTime null: in tutti e due i casi non c'è un minimo da mostrare
1382
+ this.nodeStats = [
1383
+ { label: this.lc.loc("Esecuzioni"), total: n.executions, snap: n.snapDeltaExecutions, kind: "int" },
1384
+ { label: this.lc.loc("Tempo totale"), total: n.elapsedTime, snap: n.snapDeltaElapsedTime, kind: "dur" },
1385
+ { label: this.lc.loc("Tempo proprio"), total: n.elapsedTimeLessChildren, snap: n.snapDeltaElapsedTimeLessChildren, kind: "dur" },
1386
+ { label: this.lc.loc("Medio"), total: n.executions ? n.avgTime : null, snap: n.snapDeltaExecutions ? n.snapDeltaAvgTime : null, kind: "dur" },
1387
+ { label: this.lc.loc("Massimo"), total: n.executions ? n.peakTime : null, snap: n.snapDeltaExecutions ? n.snapDeltaPeakTime : null, kind: "dur" },
1388
+ { label: this.lc.loc("Minimo"), total: n.executions ? n.minTime : null, snap: n.snapDeltaMinTime, kind: "dur" }
1389
+ ];
1390
+ this.typeParts = [
1391
+ { label: "CPU", color: FIXED_COLORS.Cpu, percentage: n.cpuPerc, idle: false },
1392
+ { label: "Database", color: FIXED_COLORS.Database, percentage: n.dbPerc, idle: false },
1393
+ { label: "Wait", color: FIXED_COLORS.Wait, percentage: n.waitPerc, idle: false },
1394
+ { label: "Script", color: FIXED_COLORS.Script, percentage: n.scriptPerc, idle: false },
1395
+ { label: "IO", color: FIXED_COLORS.IO, percentage: n.ioPerc, idle: false },
1396
+ { label: "Network", color: FIXED_COLORS.Network, percentage: n.networkPerc, idle: false },
1397
+ { label: "Throttle", color: FIXED_COLORS.Throttle, percentage: n.throttlePerc, idle: false },
1398
+ { label: "Sleep", color: FIXED_COLORS.Sleep, percentage: n.sleepPerc, idle: false },
1399
+ { label: "Idle", color: OTHER_COLOR, percentage: n.idlePerc, idle: true }
1400
+ ].filter(t => (t.percentage ?? 0) > 0);
1401
+ }
1402
+ // Con lo storico, la parte del grafico prima dei campioni in memoria ha meno risoluzione: la pagina la segnala
1403
+ get nodeHistoryBefore() {
1404
+ let n = this.node;
1405
+ if (!n || this.current?.realTime || !n.memoryFrom)
1406
+ return null;
1407
+ let memory = parseUtc(n.memoryFrom)?.getTime();
1408
+ let from = parseUtc(n.activityFrom)?.getTime();
1409
+ let to = parseUtc(n.activityTo)?.getTime();
1410
+ return memory > from && memory < to ? this.localTime(n.memoryFrom) : null;
1411
+ }
1412
+ copyName() {
1413
+ navigator.clipboard?.writeText(this.node?.nodeName ?? "").then(() => {
1414
+ this.copied = true;
1415
+ setTimeout(() => this.copied = false, 1500);
1416
+ });
1417
+ }
1418
+ showSessions() {
1419
+ let e = this.current;
1420
+ this.sessionsOnEvent.emit({ nodeId: this.node.nodeId, nodeName: this.node.nodeName, from: new Date(e.from), to: new Date(e.to) });
1421
+ }
1422
+ // #endregion
1423
+ // #region Sessione (S1-S6)
1424
+ buildSessionView() {
1425
+ let ta = this.session?.topActivity;
1426
+ let fixed = ta?.dimension == TopActivityDimension.WaitClass || ta?.dimension == TopActivityDimension.EventType;
1427
+ this.colors = {};
1428
+ this.sessionChart = (ta?.components ?? []).map((c, i) => {
1429
+ if (c.key != null)
1430
+ this.colors[c.key] = componentColor(c.key, c.other, i, fixed);
1431
+ return { ...c, label: this.valueLabel(c.label, c.other, ta.dimension) };
1432
+ });
1433
+ // Nell'ordine della specifica: eventi, thread, API
1434
+ let order = [TopActivityDimension.WaitEvent, TopActivityDimension.Thread, TopActivityDimension.Api];
1435
+ this.sessionTables = order.map(d => ta?.tables?.find(t => t.dimension == d)).filter(t => !!t);
1436
+ }
1437
+ get sessionFixedColors() {
1438
+ let d = this.session?.topActivity?.dimension;
1439
+ return d == TopActivityDimension.WaitClass || d == TopActivityDimension.EventType;
1440
+ }
1441
+ tableTitle(table) {
1442
+ switch (table.dimension) {
1443
+ case TopActivityDimension.WaitEvent: return this.lc.loc("Eventi");
1444
+ case TopActivityDimension.Thread: return "Thread";
1445
+ case TopActivityDimension.Api: return "API";
1446
+ }
1447
+ return String(table.dimension);
1448
+ }
1449
+ itemLabel(item, table) {
1450
+ return this.valueLabel(item.label, item.other, table.dimension);
1451
+ }
1452
+ isItemClickable(item, table) {
1453
+ if (item.other)
1454
+ return false;
1455
+ if (table.dimension == TopActivityDimension.WaitEvent)
1456
+ return !!item.event?.eventId;
1457
+ return table.dimension == TopActivityDimension.Thread && this.isThreadAlive(this.tidOf(item.key));
1458
+ }
1459
+ // Una riga evento apre il nodo; una riga thread evidenzia il thread fra quelli di adesso
1460
+ itemClicked(item, table) {
1461
+ if (!this.isItemClickable(item, table))
1462
+ return;
1463
+ if (table.dimension == TopActivityDimension.WaitEvent)
1464
+ this.pushNode(item.event.eventId);
1465
+ else
1466
+ this.highlightedTid = this.tidOf(item.key);
1467
+ }
1468
+ breakdownWidth(item, part) {
1469
+ return item.activity ? part.activity / item.activity * 100 : 0;
1470
+ }
1471
+ breakdownColor(part) {
1472
+ return part.other || part.key == null ? OTHER_COLOR : this.colors[part.key] ?? FIXED_COLORS[part.key] ?? OTHER_COLOR;
1473
+ }
1474
+ toggleThread(thread) {
1475
+ this.expandedTid = this.expandedTid == thread.tid ? null : thread.tid;
1476
+ }
1477
+ // Tempo nell'evento corrente: parte da waitTime e avanza fino al prossimo aggiornamento
1478
+ runningSeconds(thread) {
1479
+ return thread.inWait ? (thread.waitTime ?? 0) + Math.max(0, this.now - this.loadedAt) / 1000 : null;
1480
+ }
1481
+ progress(op) {
1482
+ return op.totalWork ? Math.min(100, op.soFar / op.totalWork * 100) : 0;
1483
+ }
1484
+ connectedFor() {
1485
+ let start = parseUtc(this.session?.startTime);
1486
+ return start ? Math.max(0, (this.now - start.getTime()) / 1000) : null;
1487
+ }
1488
+ tidOf(key) {
1489
+ let tid = parseInt((key ?? "").split("@")[0], 10);
1490
+ return isNaN(tid) ? null : tid;
1491
+ }
1492
+ isThreadAlive(tid) {
1493
+ return tid != null && !!this.session?.connected && (this.session.threads ?? []).some(t => t.tid == tid);
1494
+ }
1495
+ // #endregion
1496
+ // #region Supporto
1497
+ localTime(value) {
1498
+ let date = parseUtc(value);
1499
+ return date ? dayjs(date).format("DD/MM/YYYY HH:mm:ss") : "";
1500
+ }
1501
+ shortTime(value) {
1502
+ let date = parseUtc(value);
1503
+ return date ? dayjs(date).format("HH:mm") : "";
1504
+ }
1505
+ // Colore del tipo di evento, o della classe per i wait, come nel grafico della Top Activity
1506
+ typeColor(type, waitClass) {
1507
+ return FIXED_COLORS[waitClass && waitClass != "None" ? waitClass : type] ?? OTHER_COLOR;
1508
+ }
1509
+ typeLabel(type, waitClass) {
1510
+ return waitClass && waitClass != "None" ? `${type} · ${waitClass}` : type;
1511
+ }
1512
+ valueLabel(label, other, dimension) {
1513
+ if (other)
1514
+ return this.lc.loc("Altri");
1515
+ if (label == null || label === "")
1516
+ return this.lc.loc(dimension == TopActivityDimension.WaitEvent ? "(non attribuito)" : "(nessuno)");
1517
+ return label;
1518
+ }
1519
+ timeZone() {
1520
+ let minutes = -new Date().getTimezoneOffset();
1521
+ let sign = minutes >= 0 ? "+" : "-";
1522
+ let abs = Math.abs(minutes);
1523
+ return `UTC${sign}${Math.floor(abs / 60)}${abs % 60 ? ":" + String(abs % 60).padStart(2, "0") : ""}`;
1524
+ }
1525
+ toDate(value) {
1526
+ return value ? this.dateExts.getDateConvertion(value).toDate() : null;
1527
+ }
1528
+ fmt(date) {
1529
+ return dayjs(date).format(this.lc.token("getFullDateDisplayFormat"));
1530
+ }
1531
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Component, deps: [{ token: i1.LocalizationService }, { token: i1$1.DateService }, { token: AdminModuleBaseService }], target: i0.ɵɵFactoryTarget.Component }); }
1532
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmDetailsV2Component, isStandalone: false, selector: "adm-details-v2", inputs: { Be: "Be", CanShowSessions: "CanShowSessions", CanOpenProfiler: "CanOpenProfiler" }, outputs: { closed: "closed", sessionsOnEvent: "sessionsOnEvent", openProfiler: "openProfiler" }, providers: [{ provide: LocalizationService, useClass: AdmDetailsV2Loc }], ngImport: i0, template: "<div class=\"modal-dialog modal-xl\" emaDraggable>\n <div class=\"modal-content\">\n <!-- Navigazione: \"Indietro\" torna al dettaglio precedente con la sua finestra (D1) -->\n <div class=\"modal-header dv2-header\">\n <div class=\"dv2-heading\">\n @if (stack.length > 1) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" (click)=\"back()\"><i class=\"fa fa-arrow-left\"></i> {{'Indietro' | localize: lc}}</button>\n }\n <h4 class=\"modal-title\">\n @if (current?.kind == 'node') {\n {{'Dettaglio nodo' | localize: lc}}\n } @else if (current) {\n {{'Sessione' | localize: lc}} {{current.sid}},{{current.serial}}\n @if (current.instanceId) {\n <span class=\"dv2-muted\">&middot; {{current.instanceId}}</span>\n }\n }\n </h4>\n </div>\n <button type=\"button\" class=\"close\" (click)=\"close()\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\n </div>\n\n <div class=\"modal-body\">\n @if (current) {\n <!-- Finestra, sorgente, aggiornamento (D2, D3, D5) -->\n <div class=\"dv2-toolbar\">\n <div class=\"dv2-group\">\n <span class=\"dv2-window\"><i class=\"fa fa-clock\"></i> {{windowLabel}}</span>\n <div class=\"dv2-seg\">\n @for (h of QuickRanges; track h) {\n <button type=\"button\" (click)=\"quickRange(h)\" [title]=\"'Ultime' | localize: lc\">{{h}} h</button>\n }\n </div>\n </div>\n <div class=\"dv2-group dv2-dates\">\n <div class=\"dv2-field\"><form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterfrom\" name=\"dv2from\" [Placeholder]=\"'Da' | localize: lc\"></form-datetime></div>\n <div class=\"dv2-field\"><form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterto\" name=\"dv2to\" [Placeholder]=\"'A' | localize: lc\"></form-datetime></div>\n <button type=\"button\" class=\"btn app-btn-search\" [disabled]=\"loading\" (click)=\"applyDates()\" [title]=\"'Applica' | localize: lc\"><i class=\"fa fa-search\"></i></button>\n </div>\n <div class=\"dv2-seg\">\n @if (current.kind == 'session') {\n <button type=\"button\" [class.dv2-on]=\"current.realTime\" (click)=\"setRealTime(true)\">{{'Memoria' | localize: lc}}</button>\n <button type=\"button\" [class.dv2-on]=\"!current.realTime\" (click)=\"setRealTime(false)\">{{'Memoria e storico' | localize: lc}}</button>\n } @else {\n <button type=\"button\" [class.dv2-on]=\"current.realTime\" (click)=\"setRealTime(true)\">{{'Dal vivo' | localize: lc}}</button>\n <button type=\"button\" [class.dv2-on]=\"!current.realTime\" (click)=\"setRealTime(false)\">{{'Storico' | localize: lc}}</button>\n }\n </div>\n <div class=\"dv2-group dv2-end\">\n @if (loading) {\n <i class=\"fa fa-spinner fa-spin\"></i>\n }\n @if (updatedAt) {\n <span class=\"dv2-muted\">{{'Aggiornato alle' | localize: lc}} {{updatedAt | date: 'HH:mm:ss'}}</span>\n }\n @if (autoRefresh) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" (click)=\"togglePause()\">\n <i class=\"fa\" [class.fa-pause]=\"!paused\" [class.fa-play]=\"paused\"></i> {{(paused ? 'Riprendi' : 'Pausa') | localize: lc}}\n </button>\n }\n </div>\n </div>\n @if (windowClamped) {\n <div class=\"dv2-note\"><i class=\"fa fa-info-circle\"></i> {{'La finestra \u00E8 stata ridotta alle ultime 24 ore' | localize: lc}}</div>\n }\n\n <!-- Stati (D6) -->\n @if (error) {\n <div class=\"alert alert-warning dv2-state\">{{error}}</div>\n } @else if (notFound && !loading) {\n <div class=\"alert alert-info dv2-state\">\n {{(current.kind == 'node' ? 'Nodo non trovato' : 'Sessione non trovata: non esiste pi\u00F9 e nella finestra non era attiva') | localize: lc}}\n </div>\n } @else if (loading && !node && !session) {\n <div class=\"dv2-empty\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Carico i Dati' | localize: lc}}</div>\n }\n\n <!-- ==================== Nodo ==================== -->\n @if (node && current.kind == 'node') {\n <!-- N1 Intestazione -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-node-name\">{{node.nodeName}}</div>\n <div class=\"dv2-meta\">\n <span><span class=\"dv2-swatch\" [style.background]=\"typeColor(node.eventTypeName, node.waitClassName)\"></span>{{typeLabel(node.eventTypeName, node.waitClassName)}}</span>\n <span class=\"dv2-muted\">Id <code>{{node.nodeId}}</code></span>\n <button type=\"button\" class=\"btn btn-sm btn-link\" (click)=\"copyName()\"><i class=\"fa\" [class.fa-copy]=\"!copied\" [class.fa-check]=\"copied\"></i> {{(copied ? 'Copiato' : 'Copia') | localize: lc}}</button>\n </div>\n @if (node.fullWaitStack?.length) {\n <div class=\"dv2-path\">\n @for (item of node.fullWaitStack; track item.nodeId) {\n <span class=\"app-link dv2-path-item\" [title]=\"item.nodeName\" (click)=\"pushNode(item.nodeId)\">{{item.nodeName}}</span>\n <i class=\"fa fa-angle-right dv2-muted\"></i>\n }\n <span class=\"dv2-path-item dv2-path-current\" [title]=\"node.nodeName\">{{node.nodeName}}</span>\n </div>\n }\n <div class=\"dv2-actions\">\n @if (CanOpenProfiler) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-primary\" (click)=\"openProfiler.emit(node.nodeId)\"><i class=\"fa fa-sitemap\"></i> {{'Apri nel profiler' | localize: lc}}</button>\n }\n @if (CanShowSessions) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-primary\" (click)=\"showSessions()\" [title]=\"(node.numChildren > 0 ? 'Solo l\\'evento esatto: il lavoro dei discendenti non \u00E8 compreso' : 'Top Activity filtrata su questo evento') | localize: lc\">\n <i class=\"fa fa-users\"></i> {{'Sessioni su questo evento' | localize: lc}}\n </button>\n @if (node.numChildren > 0) {\n <span class=\"dv2-muted\">{{'discendenti esclusi' | localize: lc}}</span>\n }\n }\n </div>\n </div>\n\n <div class=\"dv2-grid\">\n <!-- N2 Statistiche -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Statistiche' | localize: lc}}</div>\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th></th>\n @if (nodeLive) {\n <th class=\"dv2-right\">{{'Dall\\'avvio' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Dall\\'ultimo snapshot' | localize: lc}} <span class=\"dv2-muted\">({{'dalle' | localize: lc}} {{shortTime(node.snapFrom)}})</span></th>\n } @else {\n <th class=\"dv2-right\">{{'Nella finestra' | localize: lc}} <span class=\"dv2-muted\">({{shortTime(node.snapFrom)}} - {{shortTime(node.snapTo)}})</span></th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of nodeStats; track row.label) {\n <tr>\n <td>{{row.label}}</td>\n <td class=\"dv2-right\">{{row.total == null ? '\u2014' : (row.total | pv2fmt: row.kind)}}</td>\n @if (nodeLive) {\n <td class=\"dv2-right\">{{row.snap == null ? '\u2014' : (row.snap | pv2fmt: row.kind)}}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n @if (nodeLive) {\n <div class=\"dv2-live\">\n <span>{{'Thread dentro adesso' | localize: lc}} <strong>{{node.activeThreads ?? 0}}</strong></span>\n <span>{{'In corso da' | localize: lc}} <strong>{{node.activeMaxTime ? (node.activeMaxTime | pv2fmt: 'dur') : '\u2014'}}</strong></span>\n <span>{{'Ultima uscita' | localize: lc}} <strong>{{node.lastExitTime ? localTime(node.lastExitTime) : '\u2014'}}</strong></span>\n </div>\n }\n </div>\n\n <!-- N4 Dove va il tempo -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Dove va il tempo' | localize: lc}} <span class=\"dv2-muted\">{{'tempo proprio del sottoalbero' | localize: lc}}</span></div>\n <div class=\"dv2-typebar\">\n @for (part of typeParts; track part.label) {\n <div [style.width.%]=\"part.percentage\" [style.background]=\"part.color\" [class.dv2-idle]=\"part.idle\" [title]=\"part.label + ' ' + (part.percentage | number : '1.1-1' : 'it') + '%'\"></div>\n }\n </div>\n <div class=\"dv2-legend\">\n @for (part of typeParts; track part.label) {\n <span><span class=\"dv2-swatch\" [class.dv2-idle]=\"part.idle\" [style.background]=\"part.color\"></span>{{part.label}} <span class=\"dv2-muted\">{{part.percentage | number : '1.1-1' : 'it'}}%</span></span>\n }\n </div>\n @if (typeParts.length && typeParts[typeParts.length - 1].idle) {\n <div class=\"dv2-muted dv2-small\">{{'Idle \u00E8 tempo di attesa senza lavoro' | localize: lc}}</div>\n }\n\n <!-- N3 Per istanza -->\n @if ((node.instances?.length ?? 0) > 1) {\n <div class=\"dv2-title dv2-spaced\">{{'Per istanza' | localize: lc}}</div>\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th>{{'Istanza' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Esecuzioni' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Tempo' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Tempo proprio' | localize: lc}}</th>\n @if (nodeLive) {\n <th class=\"dv2-right\">{{'Thread attivi' | localize: lc}}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (inst of node.instances; track inst.instanceId) {\n <tr>\n <td class=\"app-nowrap\">{{inst.instanceId}}</td>\n <td class=\"dv2-right\">{{inst.executions | pv2fmt: 'int'}}</td>\n <td class=\"dv2-right\">{{inst.elapsedTime | pv2fmt: 'dur'}}</td>\n <td class=\"dv2-right\">{{inst.elapsedTimeLessChildren | pv2fmt: 'dur'}}</td>\n @if (nodeLive) {\n <td class=\"dv2-right\">{{inst.activeThreads ?? 0}}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n }\n </div>\n </div>\n\n <!-- N6 Attivit\u00E0 nel tempo -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">\n {{'Attivit\u00E0 nel tempo' | localize: lc}}\n <span class=\"dv2-muted\">\u2248 <strong>{{node.averageActiveSessions | number : '1.2-3' : 'it'}}</strong> {{'sessioni attive medie' | localize: lc}} &middot; {{'picco' | localize: lc}} <strong>{{node.peakActiveSessions | number : '1.2-3' : 'it'}}</strong> &middot; {{'un punto ogni' | localize: lc}} {{node.bucketSeconds}} s</span>\n <span class=\"dv2-estimate\" [title]=\"'Valori stimati contando i campioni' | localize: lc\">{{'stima per campionamento' | localize: lc}}</span>\n </div>\n <activity-chart-v2 [Times]=\"nodeChartTimes\" [Components]=\"nodeChart\" [BucketSeconds]=\"node.bucketSeconds\" [Uom]=\"'sessioni' | localize: lc\"\n [EmptyText]=\"'Nessuna attivit\u00E0 nella finestra' | localize: lc\" name=\"dv2nodechart\"></activity-chart-v2>\n @if (nodeHistoryBefore) {\n <div class=\"dv2-note\"><i class=\"fa fa-info-circle\"></i> {{'Prima delle' | localize: lc}} {{nodeHistoryBefore}} {{'i dati vengono dallo storico, con meno risoluzione' | localize: lc}}</div>\n }\n @if (node.numChildren > 0) {\n <div class=\"dv2-muted dv2-small\">{{'Comprende il lavoro dei discendenti' | localize: lc}}</div>\n }\n </div>\n\n <!-- N5 Discendenti principali -->\n @if (node.numChildren > 0) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Discendenti principali' | localize: lc}} <span class=\"dv2-muted\">{{'Figli' | localize: lc}}: {{node.numChildren}} &middot; {{'Discendenti' | localize: lc}}: {{node.numDescendants}}</span></div>\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th>{{'Nome' | localize: lc}}</th>\n <th>{{'Tipo' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Livello' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Esecuzioni' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Tempo proprio' | localize: lc}}</th>\n <th class=\"dv2-right\">% {{'del nodo' | localize: lc}}</th>\n </tr>\n </thead>\n <tbody>\n @for (d of node.topDescendants ?? []; track d.nodeId) {\n <tr>\n <td><span class=\"app-link dv2-ellipsis\" [title]=\"d.nodeName\" (click)=\"pushNode(d.nodeId)\">{{d.nodeName}}</span></td>\n <td class=\"app-nowrap\">{{typeLabel(d.eventTypeName, d.waitClassName)}}</td>\n <td class=\"dv2-right\">{{d.depth}}</td>\n <td class=\"dv2-right\">{{d.executions | pv2fmt: 'int'}}</td>\n <td class=\"dv2-right\">{{d.elapsedTimeLessChildren | pv2fmt: 'dur'}}</td>\n <td class=\"dv2-right\">{{d.percentage | number : '1.1-1' : 'it'}}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n }\n\n <!-- ==================== Sessione ==================== -->\n @if (session && current.kind == 'session') {\n <!-- S1 Intestazione -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-meta dv2-session-head\">\n @if (session.connected) {\n <span class=\"dv2-badge\">{{session.currentStatus}}</span>\n } @else {\n <span class=\"dv2-badge dv2-badge-off\">{{'Terminata' | localize: lc}}</span>\n }\n <span>{{'Utente' | localize: lc}} <strong>{{session.user}}</strong>@if (session.tenant) {<span class=\"dv2-muted\"> &middot; {{session.tenant}}</span>}</span>\n <span>{{'Tipo' | localize: lc}} <strong>{{session.type | titlecase}}</strong></span>\n @if (session.resourceConsumerGroup) {\n <span>{{'Gruppo di consumo' | localize: lc}} <strong>{{session.resourceConsumerGroup}}</strong></span>\n }\n @if (session.bgSessionName) {\n <span>{{'Sessione di background' | localize: lc}} <strong>{{session.bgSessionName}}</strong></span>\n }\n @if (session.jobName) {\n <span>Job <strong>{{session.jobName}}</strong></span>\n }\n </div>\n <div class=\"dv2-meta\">\n @if (session.startTime) {\n <span>{{'Inizio' | localize: lc}} <strong>{{localTime(session.startTime)}}</strong> <span class=\"dv2-muted\">({{'collegata da' | localize: lc}} {{connectedFor() | pv2fmt: 'dur'}})</span></span>\n }\n @if (session.numThreads != null) {\n <span>Thread <strong>{{session.numThreads}}</strong></span>\n }\n <span>{{'Ultima attivit\u00E0' | localize: lc}} <strong>{{session.lastSampleTime ? localTime(session.lastSampleTime) : '\u2014'}}</strong></span>\n </div>\n </div>\n\n <!-- S6 Sessione terminata -->\n @if (!session.connected) {\n <div class=\"alert alert-warning dv2-state\">\n {{'La sessione non esiste pi\u00F9: i suoi dati vengono dall\\'ultimo campione, delle' | localize: lc}} {{localTime(session.lastSampleTime)}}\n </div>\n }\n\n <!-- S2 Grafico -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-chart-head\">\n <span class=\"dv2-title\">\n {{'Sessioni attive medie' | localize: lc}}\n @if (session.topActivity) {\n <span class=\"dv2-muted\">\n {{'Media' | localize: lc}} <strong>{{session.topActivity.estimated ? '\u2248 ' : ''}}{{session.topActivity.averageActiveSessions | number : '1.2-3' : 'it'}}</strong>\n &middot; {{'Picco' | localize: lc}} <strong>{{session.topActivity.estimated ? '\u2248 ' : ''}}{{session.topActivity.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\n &middot; {{'un punto ogni' | localize: lc}} {{session.topActivity.bucketSeconds}} s\n </span>\n @if (session.topActivity.estimated) {\n <span class=\"dv2-estimate\">{{'stima per campionamento' | localize: lc}}</span>\n }\n }\n </span>\n <div class=\"dv2-group\">\n <div class=\"dv2-field dv2-field-wide dv2-noclear\">\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"'' + current.dimension\" (ngModelChange)=\"setDimension($event)\" name=\"dv2dim\" [Source]=\"Dimensions\" [Placeholder]=\"'Dividi per' | localize: lc\"></form-select>\n </div>\n <div class=\"dv2-seg\">\n @for (o of Resolutions; track o.id) {\n <button type=\"button\" [class.dv2-on]=\"'' + current.resolution == o.id\" (click)=\"setResolution(o.id)\">{{o.description}}</button>\n }\n </div>\n </div>\n </div>\n <activity-chart-v2 [Times]=\"session.topActivity?.times\" [Components]=\"sessionChart\" [BucketSeconds]=\"session.topActivity?.bucketSeconds\" [FixedColors]=\"sessionFixedColors\"\n [Uom]=\"'sessioni' | localize: lc\" [EmptyText]=\"'Nessuna attivit\u00E0 nella finestra' | localize: lc\" name=\"dv2sessionchart\"></activity-chart-v2>\n </div>\n\n <!-- S3 Tabelle: eventi, thread, API -->\n <div class=\"dv2-tables\">\n @for (table of sessionTables; track table.dimension) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">\n {{tableTitle(table)}}@if (table.estimated) { \u2248}\n <span class=\"dv2-muted\">{{'Attivit\u00E0' | localize: lc}} <strong>{{table.estimated ? '\u2248 ' : ''}}{{table.activity | number : '1.2-3' : 'it'}}</strong></span>\n </div>\n <table class=\"table table-sm dv2-table\">\n <tbody>\n @for (item of table.items; track $index) {\n <tr [class.dv2-highlight]=\"table.dimension == Dim.Thread && highlightedTid != null && item.key?.startsWith(highlightedTid + '@')\">\n <td>\n @if (isItemClickable(item, table)) {\n <span class=\"app-link dv2-ellipsis\" [title]=\"item.label || item.key\" (click)=\"itemClicked(item, table)\">{{itemLabel(item, table)}}</span>\n } @else {\n <span class=\"dv2-ellipsis\" [class.dv2-muted]=\"item.other || !item.label\" [title]=\"item.label || ''\">{{itemLabel(item, table)}}</span>\n }\n </td>\n <td class=\"app-nowrap\">\n <div class=\"dv2-bar-cell\">\n <div class=\"dv2-bar\">\n @for (part of item.breakdown; track $index) {\n <div [style.width.%]=\"breakdownWidth(item, part)\" [style.background]=\"breakdownColor(part)\" [title]=\"part.key\"></div>\n }\n </div>\n <span>{{table.estimated ? '\u2248 ' : ''}}{{item.activity | number : '1.2-3' : 'it'}}</span>\n </div>\n </td>\n <td class=\"dv2-right app-nowrap\">{{item.percentage | number : '1.1-1' : 'it'}}%</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n\n <!-- S4 Thread adesso -->\n @if (session.connected && session.threads?.length) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Thread adesso' | localize: lc}}</div>\n <div class=\"dv2-scroll\">\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th></th>\n <th>TID</th>\n <th>{{'Nome' | localize: lc}}</th>\n <th>{{'Tipo' | localize: lc}}</th>\n <th>{{'Stato' | localize: lc}}</th>\n <th>{{'Priorit\u00E0' | localize: lc}}</th>\n <th>API</th>\n <th>{{'Macchina' | localize: lc}}</th>\n <th>{{'Evento corrente' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'In corso da' | localize: lc}}</th>\n <th>p1 - p3</th>\n </tr>\n </thead>\n <tbody>\n @for (thread of session.threads; track thread.tid) {\n <tr [class.dv2-highlight]=\"thread.tid == highlightedTid\">\n <td><button type=\"button\" class=\"btn btn-sm btn-link dv2-toggle\" (click)=\"toggleThread(thread)\" [title]=\"'Pila completa degli eventi' | localize: lc\"><i class=\"fa\" [class.fa-caret-right]=\"expandedTid != thread.tid\" [class.fa-caret-down]=\"expandedTid == thread.tid\"></i></button></td>\n <td>{{thread.tid}}</td>\n <td class=\"app-nowrap\">{{thread.name}}</td>\n <td class=\"app-nowrap\">{{thread.type}}</td>\n <td>{{thread.currentStatus}}</td>\n <td>{{thread.priority}}</td>\n <td><span class=\"dv2-ellipsis dv2-ellipsis-short\" [title]=\"thread.currentApi || ''\">{{thread.currentApi}}</span></td>\n <td>{{thread.machineName}}</td>\n <td>\n @if (thread.inWait && thread.currentWaitNodeId) {\n <span class=\"app-link dv2-ellipsis\" [title]=\"thread.currentWait\" (click)=\"pushNode(thread.currentWaitNodeId)\">{{thread.currentWait}}</span>\n <span class=\"dv2-muted\">{{typeLabel(thread.waitEventTypeName, thread.waitClassName)}}</span>\n } @else {\n <span class=\"dv2-muted\">{{'nessun evento in corso' | localize: lc}}</span>\n }\n </td>\n <td class=\"dv2-right app-nowrap\">{{thread.inWait ? (runningSeconds(thread) | pv2fmt: 'dur') : '\u2014'}}</td>\n <td class=\"dv2-muted\"><span class=\"dv2-ellipsis dv2-ellipsis-short\" [title]=\"[thread.waitParam1, thread.waitParam2, thread.waitParam3].join(' \u00B7 ')\">{{[thread.waitParam1, thread.waitParam2, thread.waitParam3].join(' \u00B7 ')}}</span></td>\n </tr>\n @if (expandedTid == thread.tid) {\n <tr class=\"dv2-stack-row\">\n <td colspan=\"11\"><pre class=\"dv2-stack\">{{thread.fullWaitStack || ('Nessun evento' | localize: lc)}}</pre></td>\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n\n <!-- S5 Operazioni lunghe -->\n @if (session.connected && session.longOps?.length) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Operazioni lunghe' | localize: lc}}</div>\n @for (op of session.longOps; track $index) {\n <div class=\"dv2-longop\">\n <div class=\"dv2-meta\">\n <strong>{{op.opName}}</strong>\n <span>{{op.target}} @if (op.targetDesc) {<span class=\"dv2-muted\">({{op.targetDesc}})</span>}</span>\n <span class=\"dv2-muted\">Thread {{op.tid}}</span>\n </div>\n <div class=\"dv2-progress\"><div [style.width.%]=\"progress(op)\"></div></div>\n <div class=\"dv2-meta dv2-small\">\n <span>{{op.soFar | number : '1.0-0' : 'it'}} {{'di' | localize: lc}} {{op.totalWork | number : '1.0-0' : 'it'}} {{op.units}} ({{progress(op) | number : '1.0-1' : 'it'}}%)</span>\n <span>{{'Trascorso' | localize: lc}} {{op.elapsedSeconds | pv2fmt: 'dur'}}</span>\n <span>{{'Alla fine' | localize: lc}} {{op.timeRemaining == null ? ('non stimabile' | localize: lc) : (op.timeRemaining | pv2fmt: 'dur')}}</span>\n @if (op.message) {\n <span class=\"dv2-muted\">{{op.message}}</span>\n }\n </div>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n </div>\n</div>\n", styles: [":host{display:block}:host ::ng-deep .dv2-noclear .p-select-clear-icon{display:none}.dv2-header{align-items:center}.dv2-heading{display:flex;flex:1 1 auto;align-items:center;gap:12px;min-width:0}.dv2-heading .btn{flex:none;white-space:nowrap}.dv2-heading .modal-title{margin:0;overflow-wrap:anywhere}.dv2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px 18px;padding-top:6px}.dv2-group{display:flex;align-items:center;gap:8px}.dv2-end{margin-left:auto}.dv2-window{font-weight:600;white-space:nowrap}.dv2-field{width:170px}.dv2-field-wide{width:200px}.dv2-seg{display:inline-flex;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden}.dv2-seg button{border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;padding:4px 10px;font-size:12px;white-space:nowrap;cursor:pointer}.dv2-seg button:first-child{border-left:0}.dv2-seg button.dv2-on{background:var(--p-primary-color, #6366f1);color:#fff}.dv2-panel{margin-top:12px;padding:10px 12px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);min-width:0}.dv2-title{font-weight:600;margin-bottom:6px}.dv2-title .dv2-muted{font-weight:400;margin-left:8px}.dv2-spaced{margin-top:14px}.dv2-chart-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px 14px;padding-top:6px;margin-bottom:6px}.dv2-muted{color:var(--p-text-muted-color, #64748b);font-size:12px}.dv2-small{font-size:12px}.dv2-note{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.dv2-state{margin:12px 0 0}.dv2-empty{padding:40px 0;text-align:center;color:var(--p-text-muted-color, #64748b)}.dv2-estimate{display:inline-block;margin-left:6px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;font-weight:400}.dv2-badge{display:inline-block;padding:1px 8px;border-radius:10px;background:#dcfce7;color:#166534;font-size:12px;font-weight:600}.dv2-badge-off{background:#fee2e2;color:#991b1b}.dv2-node-name{font-family:var(--p-font-family-mono, Consolas, monospace);font-size:13px;white-space:pre-wrap;word-break:break-word;max-height:160px;overflow:auto}.dv2-meta{display:flex;flex-wrap:wrap;align-items:center;gap:4px 16px;margin-top:6px}.dv2-session-head{margin-top:0}.dv2-path{display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px;margin-top:8px;font-size:12px}.dv2-path-item{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dv2-path-current{font-weight:600}.dv2-actions{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:10px}.dv2-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:0 12px}@media(max-width:991px){.dv2-grid{grid-template-columns:minmax(0,1fr)}}.dv2-table{margin-bottom:0;font-size:12px}.dv2-table th{font-weight:600;white-space:nowrap}.dv2-table td{vertical-align:middle}.dv2-right{text-align:right}.dv2-live{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:8px;font-size:12px}.dv2-typebar{display:flex;height:14px;border-radius:3px;overflow:hidden;background:var(--p-content-border-color, #e2e8f0)}.dv2-idle{background-image:repeating-linear-gradient(45deg,rgba(255,255,255,.55) 0 3px,transparent 3px 6px)}.dv2-legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin-top:6px;font-size:12px}.dv2-swatch{display:inline-block;width:10px;height:10px;margin-right:5px;border-radius:2px;vertical-align:-1px}.dv2-tables{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:0 12px}.dv2-tables .dv2-table{table-layout:fixed;width:100%}.dv2-tables .dv2-table td:nth-child(2){width:120px}.dv2-tables .dv2-table td:nth-child(3){width:58px}.dv2-tables .dv2-ellipsis{display:block;max-width:100%}.dv2-ellipsis{display:inline-block;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.dv2-ellipsis-short{max-width:160px}.dv2-ellipsis+.dv2-muted{margin-left:6px}.dv2-bar-cell{display:flex;align-items:center;gap:8px}.dv2-bar{display:flex;flex:none;width:70px;height:8px;border-radius:2px;overflow:hidden;background:var(--p-content-border-color, #e2e8f0)}.dv2-highlight>td{background:#eef2ff}.dv2-scroll{overflow-x:auto}.dv2-toggle{padding:0 4px}.dv2-stack-row>td{border-top:0}.dv2-stack{margin:0;padding:8px;max-height:240px;overflow:auto;border-radius:4px;background:#f8fafc;font-size:11px;white-space:pre}.dv2-longop+.dv2-longop{margin-top:12px}.dv2-progress{height:8px;margin-top:6px;border-radius:4px;overflow:hidden;background:var(--p-content-border-color, #e2e8f0)}.dv2-progress div{height:100%;background:var(--p-primary-color, #6366f1)}\n"], dependencies: [{ kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i9.EsFormSelectComponent, selector: "form-select", inputs: ["OptionsTemplate"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "directive", type: i10.Draggable, selector: "[emaDraggable]", inputs: ["emaDraggable"] }, { kind: "component", type: ActivityChartV2Component, selector: "activity-chart-v2", inputs: ["Times", "Components", "BucketSeconds", "FixedColors", "Uom", "EmptyText", "name"] }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }, { kind: "pipe", type: i5.TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: i5.DatePipe, name: "date" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }, { kind: "pipe", type: ProfilerFormatPipe, name: "pv2fmt" }] }); }
1533
+ }
1534
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Component, decorators: [{
1535
+ type: Component,
1536
+ args: [{ selector: "adm-details-v2", providers: [{ provide: LocalizationService, useClass: AdmDetailsV2Loc }], standalone: false, template: "<div class=\"modal-dialog modal-xl\" emaDraggable>\n <div class=\"modal-content\">\n <!-- Navigazione: \"Indietro\" torna al dettaglio precedente con la sua finestra (D1) -->\n <div class=\"modal-header dv2-header\">\n <div class=\"dv2-heading\">\n @if (stack.length > 1) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" (click)=\"back()\"><i class=\"fa fa-arrow-left\"></i> {{'Indietro' | localize: lc}}</button>\n }\n <h4 class=\"modal-title\">\n @if (current?.kind == 'node') {\n {{'Dettaglio nodo' | localize: lc}}\n } @else if (current) {\n {{'Sessione' | localize: lc}} {{current.sid}},{{current.serial}}\n @if (current.instanceId) {\n <span class=\"dv2-muted\">&middot; {{current.instanceId}}</span>\n }\n }\n </h4>\n </div>\n <button type=\"button\" class=\"close\" (click)=\"close()\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\n </div>\n\n <div class=\"modal-body\">\n @if (current) {\n <!-- Finestra, sorgente, aggiornamento (D2, D3, D5) -->\n <div class=\"dv2-toolbar\">\n <div class=\"dv2-group\">\n <span class=\"dv2-window\"><i class=\"fa fa-clock\"></i> {{windowLabel}}</span>\n <div class=\"dv2-seg\">\n @for (h of QuickRanges; track h) {\n <button type=\"button\" (click)=\"quickRange(h)\" [title]=\"'Ultime' | localize: lc\">{{h}} h</button>\n }\n </div>\n </div>\n <div class=\"dv2-group dv2-dates\">\n <div class=\"dv2-field\"><form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterfrom\" name=\"dv2from\" [Placeholder]=\"'Da' | localize: lc\"></form-datetime></div>\n <div class=\"dv2-field\"><form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterto\" name=\"dv2to\" [Placeholder]=\"'A' | localize: lc\"></form-datetime></div>\n <button type=\"button\" class=\"btn app-btn-search\" [disabled]=\"loading\" (click)=\"applyDates()\" [title]=\"'Applica' | localize: lc\"><i class=\"fa fa-search\"></i></button>\n </div>\n <div class=\"dv2-seg\">\n @if (current.kind == 'session') {\n <button type=\"button\" [class.dv2-on]=\"current.realTime\" (click)=\"setRealTime(true)\">{{'Memoria' | localize: lc}}</button>\n <button type=\"button\" [class.dv2-on]=\"!current.realTime\" (click)=\"setRealTime(false)\">{{'Memoria e storico' | localize: lc}}</button>\n } @else {\n <button type=\"button\" [class.dv2-on]=\"current.realTime\" (click)=\"setRealTime(true)\">{{'Dal vivo' | localize: lc}}</button>\n <button type=\"button\" [class.dv2-on]=\"!current.realTime\" (click)=\"setRealTime(false)\">{{'Storico' | localize: lc}}</button>\n }\n </div>\n <div class=\"dv2-group dv2-end\">\n @if (loading) {\n <i class=\"fa fa-spinner fa-spin\"></i>\n }\n @if (updatedAt) {\n <span class=\"dv2-muted\">{{'Aggiornato alle' | localize: lc}} {{updatedAt | date: 'HH:mm:ss'}}</span>\n }\n @if (autoRefresh) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" (click)=\"togglePause()\">\n <i class=\"fa\" [class.fa-pause]=\"!paused\" [class.fa-play]=\"paused\"></i> {{(paused ? 'Riprendi' : 'Pausa') | localize: lc}}\n </button>\n }\n </div>\n </div>\n @if (windowClamped) {\n <div class=\"dv2-note\"><i class=\"fa fa-info-circle\"></i> {{'La finestra \u00E8 stata ridotta alle ultime 24 ore' | localize: lc}}</div>\n }\n\n <!-- Stati (D6) -->\n @if (error) {\n <div class=\"alert alert-warning dv2-state\">{{error}}</div>\n } @else if (notFound && !loading) {\n <div class=\"alert alert-info dv2-state\">\n {{(current.kind == 'node' ? 'Nodo non trovato' : 'Sessione non trovata: non esiste pi\u00F9 e nella finestra non era attiva') | localize: lc}}\n </div>\n } @else if (loading && !node && !session) {\n <div class=\"dv2-empty\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Carico i Dati' | localize: lc}}</div>\n }\n\n <!-- ==================== Nodo ==================== -->\n @if (node && current.kind == 'node') {\n <!-- N1 Intestazione -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-node-name\">{{node.nodeName}}</div>\n <div class=\"dv2-meta\">\n <span><span class=\"dv2-swatch\" [style.background]=\"typeColor(node.eventTypeName, node.waitClassName)\"></span>{{typeLabel(node.eventTypeName, node.waitClassName)}}</span>\n <span class=\"dv2-muted\">Id <code>{{node.nodeId}}</code></span>\n <button type=\"button\" class=\"btn btn-sm btn-link\" (click)=\"copyName()\"><i class=\"fa\" [class.fa-copy]=\"!copied\" [class.fa-check]=\"copied\"></i> {{(copied ? 'Copiato' : 'Copia') | localize: lc}}</button>\n </div>\n @if (node.fullWaitStack?.length) {\n <div class=\"dv2-path\">\n @for (item of node.fullWaitStack; track item.nodeId) {\n <span class=\"app-link dv2-path-item\" [title]=\"item.nodeName\" (click)=\"pushNode(item.nodeId)\">{{item.nodeName}}</span>\n <i class=\"fa fa-angle-right dv2-muted\"></i>\n }\n <span class=\"dv2-path-item dv2-path-current\" [title]=\"node.nodeName\">{{node.nodeName}}</span>\n </div>\n }\n <div class=\"dv2-actions\">\n @if (CanOpenProfiler) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-primary\" (click)=\"openProfiler.emit(node.nodeId)\"><i class=\"fa fa-sitemap\"></i> {{'Apri nel profiler' | localize: lc}}</button>\n }\n @if (CanShowSessions) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-primary\" (click)=\"showSessions()\" [title]=\"(node.numChildren > 0 ? 'Solo l\\'evento esatto: il lavoro dei discendenti non \u00E8 compreso' : 'Top Activity filtrata su questo evento') | localize: lc\">\n <i class=\"fa fa-users\"></i> {{'Sessioni su questo evento' | localize: lc}}\n </button>\n @if (node.numChildren > 0) {\n <span class=\"dv2-muted\">{{'discendenti esclusi' | localize: lc}}</span>\n }\n }\n </div>\n </div>\n\n <div class=\"dv2-grid\">\n <!-- N2 Statistiche -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Statistiche' | localize: lc}}</div>\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th></th>\n @if (nodeLive) {\n <th class=\"dv2-right\">{{'Dall\\'avvio' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Dall\\'ultimo snapshot' | localize: lc}} <span class=\"dv2-muted\">({{'dalle' | localize: lc}} {{shortTime(node.snapFrom)}})</span></th>\n } @else {\n <th class=\"dv2-right\">{{'Nella finestra' | localize: lc}} <span class=\"dv2-muted\">({{shortTime(node.snapFrom)}} - {{shortTime(node.snapTo)}})</span></th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of nodeStats; track row.label) {\n <tr>\n <td>{{row.label}}</td>\n <td class=\"dv2-right\">{{row.total == null ? '\u2014' : (row.total | pv2fmt: row.kind)}}</td>\n @if (nodeLive) {\n <td class=\"dv2-right\">{{row.snap == null ? '\u2014' : (row.snap | pv2fmt: row.kind)}}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n @if (nodeLive) {\n <div class=\"dv2-live\">\n <span>{{'Thread dentro adesso' | localize: lc}} <strong>{{node.activeThreads ?? 0}}</strong></span>\n <span>{{'In corso da' | localize: lc}} <strong>{{node.activeMaxTime ? (node.activeMaxTime | pv2fmt: 'dur') : '\u2014'}}</strong></span>\n <span>{{'Ultima uscita' | localize: lc}} <strong>{{node.lastExitTime ? localTime(node.lastExitTime) : '\u2014'}}</strong></span>\n </div>\n }\n </div>\n\n <!-- N4 Dove va il tempo -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Dove va il tempo' | localize: lc}} <span class=\"dv2-muted\">{{'tempo proprio del sottoalbero' | localize: lc}}</span></div>\n <div class=\"dv2-typebar\">\n @for (part of typeParts; track part.label) {\n <div [style.width.%]=\"part.percentage\" [style.background]=\"part.color\" [class.dv2-idle]=\"part.idle\" [title]=\"part.label + ' ' + (part.percentage | number : '1.1-1' : 'it') + '%'\"></div>\n }\n </div>\n <div class=\"dv2-legend\">\n @for (part of typeParts; track part.label) {\n <span><span class=\"dv2-swatch\" [class.dv2-idle]=\"part.idle\" [style.background]=\"part.color\"></span>{{part.label}} <span class=\"dv2-muted\">{{part.percentage | number : '1.1-1' : 'it'}}%</span></span>\n }\n </div>\n @if (typeParts.length && typeParts[typeParts.length - 1].idle) {\n <div class=\"dv2-muted dv2-small\">{{'Idle \u00E8 tempo di attesa senza lavoro' | localize: lc}}</div>\n }\n\n <!-- N3 Per istanza -->\n @if ((node.instances?.length ?? 0) > 1) {\n <div class=\"dv2-title dv2-spaced\">{{'Per istanza' | localize: lc}}</div>\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th>{{'Istanza' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Esecuzioni' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Tempo' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Tempo proprio' | localize: lc}}</th>\n @if (nodeLive) {\n <th class=\"dv2-right\">{{'Thread attivi' | localize: lc}}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (inst of node.instances; track inst.instanceId) {\n <tr>\n <td class=\"app-nowrap\">{{inst.instanceId}}</td>\n <td class=\"dv2-right\">{{inst.executions | pv2fmt: 'int'}}</td>\n <td class=\"dv2-right\">{{inst.elapsedTime | pv2fmt: 'dur'}}</td>\n <td class=\"dv2-right\">{{inst.elapsedTimeLessChildren | pv2fmt: 'dur'}}</td>\n @if (nodeLive) {\n <td class=\"dv2-right\">{{inst.activeThreads ?? 0}}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n }\n </div>\n </div>\n\n <!-- N6 Attivit\u00E0 nel tempo -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">\n {{'Attivit\u00E0 nel tempo' | localize: lc}}\n <span class=\"dv2-muted\">\u2248 <strong>{{node.averageActiveSessions | number : '1.2-3' : 'it'}}</strong> {{'sessioni attive medie' | localize: lc}} &middot; {{'picco' | localize: lc}} <strong>{{node.peakActiveSessions | number : '1.2-3' : 'it'}}</strong> &middot; {{'un punto ogni' | localize: lc}} {{node.bucketSeconds}} s</span>\n <span class=\"dv2-estimate\" [title]=\"'Valori stimati contando i campioni' | localize: lc\">{{'stima per campionamento' | localize: lc}}</span>\n </div>\n <activity-chart-v2 [Times]=\"nodeChartTimes\" [Components]=\"nodeChart\" [BucketSeconds]=\"node.bucketSeconds\" [Uom]=\"'sessioni' | localize: lc\"\n [EmptyText]=\"'Nessuna attivit\u00E0 nella finestra' | localize: lc\" name=\"dv2nodechart\"></activity-chart-v2>\n @if (nodeHistoryBefore) {\n <div class=\"dv2-note\"><i class=\"fa fa-info-circle\"></i> {{'Prima delle' | localize: lc}} {{nodeHistoryBefore}} {{'i dati vengono dallo storico, con meno risoluzione' | localize: lc}}</div>\n }\n @if (node.numChildren > 0) {\n <div class=\"dv2-muted dv2-small\">{{'Comprende il lavoro dei discendenti' | localize: lc}}</div>\n }\n </div>\n\n <!-- N5 Discendenti principali -->\n @if (node.numChildren > 0) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Discendenti principali' | localize: lc}} <span class=\"dv2-muted\">{{'Figli' | localize: lc}}: {{node.numChildren}} &middot; {{'Discendenti' | localize: lc}}: {{node.numDescendants}}</span></div>\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th>{{'Nome' | localize: lc}}</th>\n <th>{{'Tipo' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Livello' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Esecuzioni' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Tempo proprio' | localize: lc}}</th>\n <th class=\"dv2-right\">% {{'del nodo' | localize: lc}}</th>\n </tr>\n </thead>\n <tbody>\n @for (d of node.topDescendants ?? []; track d.nodeId) {\n <tr>\n <td><span class=\"app-link dv2-ellipsis\" [title]=\"d.nodeName\" (click)=\"pushNode(d.nodeId)\">{{d.nodeName}}</span></td>\n <td class=\"app-nowrap\">{{typeLabel(d.eventTypeName, d.waitClassName)}}</td>\n <td class=\"dv2-right\">{{d.depth}}</td>\n <td class=\"dv2-right\">{{d.executions | pv2fmt: 'int'}}</td>\n <td class=\"dv2-right\">{{d.elapsedTimeLessChildren | pv2fmt: 'dur'}}</td>\n <td class=\"dv2-right\">{{d.percentage | number : '1.1-1' : 'it'}}</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n }\n\n <!-- ==================== Sessione ==================== -->\n @if (session && current.kind == 'session') {\n <!-- S1 Intestazione -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-meta dv2-session-head\">\n @if (session.connected) {\n <span class=\"dv2-badge\">{{session.currentStatus}}</span>\n } @else {\n <span class=\"dv2-badge dv2-badge-off\">{{'Terminata' | localize: lc}}</span>\n }\n <span>{{'Utente' | localize: lc}} <strong>{{session.user}}</strong>@if (session.tenant) {<span class=\"dv2-muted\"> &middot; {{session.tenant}}</span>}</span>\n <span>{{'Tipo' | localize: lc}} <strong>{{session.type | titlecase}}</strong></span>\n @if (session.resourceConsumerGroup) {\n <span>{{'Gruppo di consumo' | localize: lc}} <strong>{{session.resourceConsumerGroup}}</strong></span>\n }\n @if (session.bgSessionName) {\n <span>{{'Sessione di background' | localize: lc}} <strong>{{session.bgSessionName}}</strong></span>\n }\n @if (session.jobName) {\n <span>Job <strong>{{session.jobName}}</strong></span>\n }\n </div>\n <div class=\"dv2-meta\">\n @if (session.startTime) {\n <span>{{'Inizio' | localize: lc}} <strong>{{localTime(session.startTime)}}</strong> <span class=\"dv2-muted\">({{'collegata da' | localize: lc}} {{connectedFor() | pv2fmt: 'dur'}})</span></span>\n }\n @if (session.numThreads != null) {\n <span>Thread <strong>{{session.numThreads}}</strong></span>\n }\n <span>{{'Ultima attivit\u00E0' | localize: lc}} <strong>{{session.lastSampleTime ? localTime(session.lastSampleTime) : '\u2014'}}</strong></span>\n </div>\n </div>\n\n <!-- S6 Sessione terminata -->\n @if (!session.connected) {\n <div class=\"alert alert-warning dv2-state\">\n {{'La sessione non esiste pi\u00F9: i suoi dati vengono dall\\'ultimo campione, delle' | localize: lc}} {{localTime(session.lastSampleTime)}}\n </div>\n }\n\n <!-- S2 Grafico -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-chart-head\">\n <span class=\"dv2-title\">\n {{'Sessioni attive medie' | localize: lc}}\n @if (session.topActivity) {\n <span class=\"dv2-muted\">\n {{'Media' | localize: lc}} <strong>{{session.topActivity.estimated ? '\u2248 ' : ''}}{{session.topActivity.averageActiveSessions | number : '1.2-3' : 'it'}}</strong>\n &middot; {{'Picco' | localize: lc}} <strong>{{session.topActivity.estimated ? '\u2248 ' : ''}}{{session.topActivity.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\n &middot; {{'un punto ogni' | localize: lc}} {{session.topActivity.bucketSeconds}} s\n </span>\n @if (session.topActivity.estimated) {\n <span class=\"dv2-estimate\">{{'stima per campionamento' | localize: lc}}</span>\n }\n }\n </span>\n <div class=\"dv2-group\">\n <div class=\"dv2-field dv2-field-wide dv2-noclear\">\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"'' + current.dimension\" (ngModelChange)=\"setDimension($event)\" name=\"dv2dim\" [Source]=\"Dimensions\" [Placeholder]=\"'Dividi per' | localize: lc\"></form-select>\n </div>\n <div class=\"dv2-seg\">\n @for (o of Resolutions; track o.id) {\n <button type=\"button\" [class.dv2-on]=\"'' + current.resolution == o.id\" (click)=\"setResolution(o.id)\">{{o.description}}</button>\n }\n </div>\n </div>\n </div>\n <activity-chart-v2 [Times]=\"session.topActivity?.times\" [Components]=\"sessionChart\" [BucketSeconds]=\"session.topActivity?.bucketSeconds\" [FixedColors]=\"sessionFixedColors\"\n [Uom]=\"'sessioni' | localize: lc\" [EmptyText]=\"'Nessuna attivit\u00E0 nella finestra' | localize: lc\" name=\"dv2sessionchart\"></activity-chart-v2>\n </div>\n\n <!-- S3 Tabelle: eventi, thread, API -->\n <div class=\"dv2-tables\">\n @for (table of sessionTables; track table.dimension) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">\n {{tableTitle(table)}}@if (table.estimated) { \u2248}\n <span class=\"dv2-muted\">{{'Attivit\u00E0' | localize: lc}} <strong>{{table.estimated ? '\u2248 ' : ''}}{{table.activity | number : '1.2-3' : 'it'}}</strong></span>\n </div>\n <table class=\"table table-sm dv2-table\">\n <tbody>\n @for (item of table.items; track $index) {\n <tr [class.dv2-highlight]=\"table.dimension == Dim.Thread && highlightedTid != null && item.key?.startsWith(highlightedTid + '@')\">\n <td>\n @if (isItemClickable(item, table)) {\n <span class=\"app-link dv2-ellipsis\" [title]=\"item.label || item.key\" (click)=\"itemClicked(item, table)\">{{itemLabel(item, table)}}</span>\n } @else {\n <span class=\"dv2-ellipsis\" [class.dv2-muted]=\"item.other || !item.label\" [title]=\"item.label || ''\">{{itemLabel(item, table)}}</span>\n }\n </td>\n <td class=\"app-nowrap\">\n <div class=\"dv2-bar-cell\">\n <div class=\"dv2-bar\">\n @for (part of item.breakdown; track $index) {\n <div [style.width.%]=\"breakdownWidth(item, part)\" [style.background]=\"breakdownColor(part)\" [title]=\"part.key\"></div>\n }\n </div>\n <span>{{table.estimated ? '\u2248 ' : ''}}{{item.activity | number : '1.2-3' : 'it'}}</span>\n </div>\n </td>\n <td class=\"dv2-right app-nowrap\">{{item.percentage | number : '1.1-1' : 'it'}}%</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n\n <!-- S4 Thread adesso -->\n @if (session.connected && session.threads?.length) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Thread adesso' | localize: lc}}</div>\n <div class=\"dv2-scroll\">\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th></th>\n <th>TID</th>\n <th>{{'Nome' | localize: lc}}</th>\n <th>{{'Tipo' | localize: lc}}</th>\n <th>{{'Stato' | localize: lc}}</th>\n <th>{{'Priorit\u00E0' | localize: lc}}</th>\n <th>API</th>\n <th>{{'Macchina' | localize: lc}}</th>\n <th>{{'Evento corrente' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'In corso da' | localize: lc}}</th>\n <th>p1 - p3</th>\n </tr>\n </thead>\n <tbody>\n @for (thread of session.threads; track thread.tid) {\n <tr [class.dv2-highlight]=\"thread.tid == highlightedTid\">\n <td><button type=\"button\" class=\"btn btn-sm btn-link dv2-toggle\" (click)=\"toggleThread(thread)\" [title]=\"'Pila completa degli eventi' | localize: lc\"><i class=\"fa\" [class.fa-caret-right]=\"expandedTid != thread.tid\" [class.fa-caret-down]=\"expandedTid == thread.tid\"></i></button></td>\n <td>{{thread.tid}}</td>\n <td class=\"app-nowrap\">{{thread.name}}</td>\n <td class=\"app-nowrap\">{{thread.type}}</td>\n <td>{{thread.currentStatus}}</td>\n <td>{{thread.priority}}</td>\n <td><span class=\"dv2-ellipsis dv2-ellipsis-short\" [title]=\"thread.currentApi || ''\">{{thread.currentApi}}</span></td>\n <td>{{thread.machineName}}</td>\n <td>\n @if (thread.inWait && thread.currentWaitNodeId) {\n <span class=\"app-link dv2-ellipsis\" [title]=\"thread.currentWait\" (click)=\"pushNode(thread.currentWaitNodeId)\">{{thread.currentWait}}</span>\n <span class=\"dv2-muted\">{{typeLabel(thread.waitEventTypeName, thread.waitClassName)}}</span>\n } @else {\n <span class=\"dv2-muted\">{{'nessun evento in corso' | localize: lc}}</span>\n }\n </td>\n <td class=\"dv2-right app-nowrap\">{{thread.inWait ? (runningSeconds(thread) | pv2fmt: 'dur') : '\u2014'}}</td>\n <td class=\"dv2-muted\"><span class=\"dv2-ellipsis dv2-ellipsis-short\" [title]=\"[thread.waitParam1, thread.waitParam2, thread.waitParam3].join(' \u00B7 ')\">{{[thread.waitParam1, thread.waitParam2, thread.waitParam3].join(' \u00B7 ')}}</span></td>\n </tr>\n @if (expandedTid == thread.tid) {\n <tr class=\"dv2-stack-row\">\n <td colspan=\"11\"><pre class=\"dv2-stack\">{{thread.fullWaitStack || ('Nessun evento' | localize: lc)}}</pre></td>\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n\n <!-- S5 Operazioni lunghe -->\n @if (session.connected && session.longOps?.length) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Operazioni lunghe' | localize: lc}}</div>\n @for (op of session.longOps; track $index) {\n <div class=\"dv2-longop\">\n <div class=\"dv2-meta\">\n <strong>{{op.opName}}</strong>\n <span>{{op.target}} @if (op.targetDesc) {<span class=\"dv2-muted\">({{op.targetDesc}})</span>}</span>\n <span class=\"dv2-muted\">Thread {{op.tid}}</span>\n </div>\n <div class=\"dv2-progress\"><div [style.width.%]=\"progress(op)\"></div></div>\n <div class=\"dv2-meta dv2-small\">\n <span>{{op.soFar | number : '1.0-0' : 'it'}} {{'di' | localize: lc}} {{op.totalWork | number : '1.0-0' : 'it'}} {{op.units}} ({{progress(op) | number : '1.0-1' : 'it'}}%)</span>\n <span>{{'Trascorso' | localize: lc}} {{op.elapsedSeconds | pv2fmt: 'dur'}}</span>\n <span>{{'Alla fine' | localize: lc}} {{op.timeRemaining == null ? ('non stimabile' | localize: lc) : (op.timeRemaining | pv2fmt: 'dur')}}</span>\n @if (op.message) {\n <span class=\"dv2-muted\">{{op.message}}</span>\n }\n </div>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n </div>\n</div>\n", styles: [":host{display:block}:host ::ng-deep .dv2-noclear .p-select-clear-icon{display:none}.dv2-header{align-items:center}.dv2-heading{display:flex;flex:1 1 auto;align-items:center;gap:12px;min-width:0}.dv2-heading .btn{flex:none;white-space:nowrap}.dv2-heading .modal-title{margin:0;overflow-wrap:anywhere}.dv2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px 18px;padding-top:6px}.dv2-group{display:flex;align-items:center;gap:8px}.dv2-end{margin-left:auto}.dv2-window{font-weight:600;white-space:nowrap}.dv2-field{width:170px}.dv2-field-wide{width:200px}.dv2-seg{display:inline-flex;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden}.dv2-seg button{border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;padding:4px 10px;font-size:12px;white-space:nowrap;cursor:pointer}.dv2-seg button:first-child{border-left:0}.dv2-seg button.dv2-on{background:var(--p-primary-color, #6366f1);color:#fff}.dv2-panel{margin-top:12px;padding:10px 12px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);min-width:0}.dv2-title{font-weight:600;margin-bottom:6px}.dv2-title .dv2-muted{font-weight:400;margin-left:8px}.dv2-spaced{margin-top:14px}.dv2-chart-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px 14px;padding-top:6px;margin-bottom:6px}.dv2-muted{color:var(--p-text-muted-color, #64748b);font-size:12px}.dv2-small{font-size:12px}.dv2-note{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.dv2-state{margin:12px 0 0}.dv2-empty{padding:40px 0;text-align:center;color:var(--p-text-muted-color, #64748b)}.dv2-estimate{display:inline-block;margin-left:6px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;font-weight:400}.dv2-badge{display:inline-block;padding:1px 8px;border-radius:10px;background:#dcfce7;color:#166534;font-size:12px;font-weight:600}.dv2-badge-off{background:#fee2e2;color:#991b1b}.dv2-node-name{font-family:var(--p-font-family-mono, Consolas, monospace);font-size:13px;white-space:pre-wrap;word-break:break-word;max-height:160px;overflow:auto}.dv2-meta{display:flex;flex-wrap:wrap;align-items:center;gap:4px 16px;margin-top:6px}.dv2-session-head{margin-top:0}.dv2-path{display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px;margin-top:8px;font-size:12px}.dv2-path-item{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dv2-path-current{font-weight:600}.dv2-actions{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:10px}.dv2-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:0 12px}@media(max-width:991px){.dv2-grid{grid-template-columns:minmax(0,1fr)}}.dv2-table{margin-bottom:0;font-size:12px}.dv2-table th{font-weight:600;white-space:nowrap}.dv2-table td{vertical-align:middle}.dv2-right{text-align:right}.dv2-live{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:8px;font-size:12px}.dv2-typebar{display:flex;height:14px;border-radius:3px;overflow:hidden;background:var(--p-content-border-color, #e2e8f0)}.dv2-idle{background-image:repeating-linear-gradient(45deg,rgba(255,255,255,.55) 0 3px,transparent 3px 6px)}.dv2-legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin-top:6px;font-size:12px}.dv2-swatch{display:inline-block;width:10px;height:10px;margin-right:5px;border-radius:2px;vertical-align:-1px}.dv2-tables{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:0 12px}.dv2-tables .dv2-table{table-layout:fixed;width:100%}.dv2-tables .dv2-table td:nth-child(2){width:120px}.dv2-tables .dv2-table td:nth-child(3){width:58px}.dv2-tables .dv2-ellipsis{display:block;max-width:100%}.dv2-ellipsis{display:inline-block;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.dv2-ellipsis-short{max-width:160px}.dv2-ellipsis+.dv2-muted{margin-left:6px}.dv2-bar-cell{display:flex;align-items:center;gap:8px}.dv2-bar{display:flex;flex:none;width:70px;height:8px;border-radius:2px;overflow:hidden;background:var(--p-content-border-color, #e2e8f0)}.dv2-highlight>td{background:#eef2ff}.dv2-scroll{overflow-x:auto}.dv2-toggle{padding:0 4px}.dv2-stack-row>td{border-top:0}.dv2-stack{margin:0;padding:8px;max-height:240px;overflow:auto;border-radius:4px;background:#f8fafc;font-size:11px;white-space:pre}.dv2-longop+.dv2-longop{margin-top:12px}.dv2-progress{height:8px;margin-top:6px;border-radius:4px;overflow:hidden;background:var(--p-content-border-color, #e2e8f0)}.dv2-progress div{height:100%;background:var(--p-primary-color, #6366f1)}\n"] }]
1537
+ }], ctorParameters: () => [{ type: i1.LocalizationService }, { type: i1$1.DateService }, { type: AdminModuleBaseService }], propDecorators: { Be: [{
1538
+ type: Input
1539
+ }], CanShowSessions: [{
1540
+ type: Input
1541
+ }], CanOpenProfiler: [{
1542
+ type: Input
1543
+ }], closed: [{
1544
+ type: Output
1545
+ }], sessionsOnEvent: [{
1546
+ type: Output
1547
+ }], openProfiler: [{
1548
+ type: Output
1549
+ }] } });
1550
+
756
1551
  class AdmProfilerComponentLoc extends LocalizationService {
757
1552
  constructor(injector) {
758
1553
  super(injector);
@@ -842,7 +1637,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
842
1637
 
843
1638
  // Angular
844
1639
  class AdmProfilerComponent {
845
- constructor(lc, localStorage, location, intercom, route, adms, router, mod, workloadV2) {
1640
+ constructor(lc, localStorage, location, intercom, route, adms, router, mod, workloadV2,
1641
+ // Con DirectorFeature.DetailsV2 GetNodeStats risponde solo con il contratto nuovo: il nodo si apre nel dettaglio v2
1642
+ dateExts, detailsV2Enabled, topActV2Enabled) {
846
1643
  this.lc = lc;
847
1644
  this.localStorage = localStorage;
848
1645
  this.location = location;
@@ -852,6 +1649,9 @@ class AdmProfilerComponent {
852
1649
  this.router = router;
853
1650
  this.mod = mod;
854
1651
  this.workloadV2 = workloadV2;
1652
+ this.dateExts = dateExts;
1653
+ this.detailsV2Enabled = detailsV2Enabled;
1654
+ this.topActV2Enabled = topActV2Enabled;
855
1655
  this.searchView = new ProfilerDataNodesView();
856
1656
  this.be = route.snapshot.params["be"] || "";
857
1657
  this.intercom.send(InboundMessageTypes.Navigation, { sub: false, routeTitle: this.lc.loc(this.route.snapshot.data["title"]) });
@@ -916,18 +1716,39 @@ class AdmProfilerComponent {
916
1716
  let res = await this.adms.getProfilerDataNodes(this.be, view);
917
1717
  dataCallBack(res.items, ProfilerDataNode);
918
1718
  }
1719
+ openNodeDetails(nodeId) {
1720
+ if (this.detailsV2Enabled) {
1721
+ // Senza date la pagina è dal vivo (l'ultima ora per il grafico), con le date legge lo storico
1722
+ let history = !!(this.searchView.filterfrom || this.searchView.filterto);
1723
+ let to = this.searchView.filterto ? this.dateExts.getDateConvertion(this.searchView.filterto).toDate() : new Date();
1724
+ let from = this.searchView.filterfrom ? this.dateExts.getDateConvertion(this.searchView.filterfrom).toDate() : new Date(to.getTime() - 3600 * 1000);
1725
+ this.detailsV2.openNode(nodeId, { from: from, to: to, realTime: !history, global: this.searchView.filterglobal });
1726
+ this.dlgDetailsV2.show();
1727
+ return;
1728
+ }
1729
+ this.loadNodeDetails(nodeId);
1730
+ this.dlgNodeDetails.show();
1731
+ }
1732
+ // N8: la Top Activity v2 filtrata sull'evento, nella finestra del dettaglio
1733
+ showEventSessions(link) {
1734
+ this.dlgDetailsV2.hide();
1735
+ this.router.navigate([`/pages/${this.mod}/topact`, ...(this.be ? [this.be] : [])], { queryParams: { event: link.nodeId, eventName: link.nodeName, from: link.from.toISOString(), to: link.to.toISOString() } });
1736
+ }
1737
+ openInProfiler(nodeId) {
1738
+ this.dlgDetailsV2.hide();
1739
+ }
919
1740
  loadNodeDetails(nodeId) {
920
1741
  this.NodeDetails = null;
921
1742
  requestAnimationFrame(async () => {
922
1743
  this.NodeDetails = await this.adms.getNodeStats(this.be, nodeId);
923
1744
  });
924
1745
  }
925
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerComponent, deps: [{ token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i5.Location }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: AdminModuleBaseService }, { token: i4.Router }, { token: ADM_MODULE_PATH }, { token: ADM_WORKLOAD_V2, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
926
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmProfilerComponent, isStandalone: false, selector: "adm_profiler", providers: [{ provide: LocalizationService, useClass: AdmProfilerComponentLoc }], ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-12\">\n <div class=\"card app-overflow-visible\" widget>\n <div class=\"card-header\">\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span>&nbsp;\n </div>\n <div class=\"card-body widget-body\">\n <div class=\"col-md-12 bottom-15\">\n <form role=\"form\">\n <div class=\"row app-first-filter-line\">\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\n <form-date [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\"></form-date>\n </div>\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\n <form-date [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\"></form-date>\n </div>\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\" style=\"display: flex; height: 38px;\">\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterglobal\" name=\"filterglobal\"></form-checkbox>&nbsp;\n <span class=\"app-pointer app-padding-top-5 app-padding-left-5\" (click)=\"searchView.filterglobal = !searchView.filterglobal\">{{'Globale' | localize: lc}}</span>\n </div>\n\n <button [disabled]=\"searchView.searchinprogress\" class=\"input-group-addon btn app-btn-search app-margin-top-20 app-margin-right-5\" (click)=\"sendSearch()\" type=\"submit\"><i class=\"fa fa-search\"></i></button>\n <button class=\"input-group-addon btn app-btn-search app-margin-top-20\" (click)=\"downloadWorkloadReport()\" type=\"submit\" [title]=\"workloadV2 ? 'Workload report' : ''\"><i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i></button>\n </div>\n </form>\n </div>\n <div class=\"row\">\n <div class=\"col-md-12\">\n @if (!searchView) {\n <p><em>{{'Carico i Dati' | localize: lc}}</em></p>\n }\n @if (searchView) {\n <div>\n <es-table [(ngModel)]=\"searchView\" [Hierarchy]=\"true\" [OrderByColumn]=\"false\" [ParentKey]=\"'parentid'\"\n [OwnKey]=\"'id'\" [StartsExpanded]=\"false\" [ExportFunction]=\"prepareExport.bind(this)\" [Export]=\"true\"\n [ExportFileName]=\"'Profiler Export.csv'\" [HidePaging]=\"true\" (onSearchRequest)=\"sendSearch($event);\">\n <span *th=\"'1'\">{{'ID' | localize : lc}}</span>\n <span *th=\"'2'\">{{'Descrizione' | localize: lc}}</span>\n <span *th=\"'3'\">{{'Chiamate' | localize: lc}}</span>\n <span *th=\"'4'\">{{'Tempo' | localize: lc}}</span>\n <span *th=\"'5'\">{{'Tempo Max' | localize: lc}}</span>\n <span *th=\"'6'\">{{'Tempo Min' | localize: lc}}</span>\n <span *th=\"'7'\">{{'Tempo Medio' | localize: lc}}</span>\n <span *th=\"'8'\">{{'Tempo Specifico' | localize: lc}}</span>\n <span *th=\"'9'\">{{'Percentuale' | localize: lc}}</span>\n <span *th=\"'10'\">{{'Chiamate Periodo' | localize: lc}}</span>\n <span *th=\"'11'\">{{'Tempo Periodo' | localize: lc}}</span>\n <span *th=\"'12'\">{{'Tempo Max Periodo' | localize: lc}}</span>\n <span *th=\"'13'\">{{'Tempo Min Periodo' | localize: lc}}</span>\n <span *th=\"'14'\">{{'Tempo Medio Periodo' | localize: lc}}</span>\n <span *th=\"'15'\">{{'Tempo Specifico Periodo' | localize: lc}}</span>\n <span *th=\"'16'\">{{'Percentuale Periodo' | localize: lc}}</span>\n <span *th=\"'17'\">{{'Nome Tipologia Evento' | localize: lc}}</span>\n <span *th=\"'18'\">{{'Nome Classe Attesa' | localize: lc}}</span>\n <span *th=\"'19'\">{{'Numero Istanze' | localize: lc}}</span>\n <span *td=\"'1'; let item\"><span class=\"app-link app-inline\" (click)=\"loadNodeDetails(item.id); dlgNodeDetails.show();\">{{item.id}}</span></span>\n <span *td=\"'2'; let item\" title=\"{{item.description}}\">{{item.description.length <= 50 ? item.description : item.description.substr(0,50) + \"[...]\" }}</span>\n <span *td=\"'3'; let item\">{{item.calls}}</span>\n <span *td=\"'4'; let item\">{{item.time}}</span>\n <span *td=\"'5'; let item\">{{item.peaktime}}</span>\n <span *td=\"'6'; let item\">{{item.mintime}}</span>\n <span *td=\"'7'; let item\">{{item.avgtime}}</span>\n <span *td=\"'8'; let item\">{{item.timewithoutchildren }}</span>\n <span *td=\"'9'; let item\">{{item.percentage}}</span>\n <span *td=\"'10' let item\">{{item.snapdeltacalls}}</span>\n <span *td=\"'11' let item\">{{item.snapdeltatime}}</span>\n <span *td=\"'12' let item\">{{item.snappeaktime}}</span>\n <span *td=\"'13' let item\">{{item.snapmintime}}</span>\n <span *td=\"'14' let item\">{{item.snapavgtime}}</span>\n <span *td=\"'15' let item\">{{item.snaptimewithoutchildren}}</span>\n <span *td=\"'16' let item\">{{item.snappercentage}}</span>\n <span *td=\"'17' let item\">{{item.eventtypename}}</span>\n <span *td=\"'18' let item\">{{item.waitclassname}}</span>\n <span *td=\"'19' let item\">{{item.numinstances}}</span>\n </es-table>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\n @if (NodeDetails) {\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\n }\n</div>", dependencies: [{ kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "directive", type: i8.EsTdDirective, selector: "[td]", inputs: ["tdVisible", "td", "tdForProperty", "tdIf", "tdClass", "tdPropertyAccessor", "tdAlignment", "tdFormat", "tdIconClass", "tdConditionField", "tdConditionValue", "tdTitle", "tdContent"] }, { kind: "directive", type: i8.EsThDirective, selector: "[th]", inputs: ["th", "thPinned", "thPinnedRight", "thPinnable", "thPinnedWidth", "thVisible", "thFixed", "thParent", "thOrder", "thOrderable", "thWrap", "thResizable", "thClass", "thShrink", "thGroupClass", "thIf", "thEmpty", "thGroup", "thAggregation", "thProperty", "thType", "thSource", "thMulti", "thStaticContent", "thBackgroundColor", "thAlignment", "thFormat", "thEditorName", "thEditorOptions", "thRendererName", "thRoutePath", "thRouteParameterProperties"] }, { kind: "component", type: i8.EsTableComponent, selector: "es-table", inputs: ["globalCheck", "autoUpdate", "seconds", "researchInProgress", "globalColVisCheck", "EsThTdProvider", "CornerMenuOptions", "ColumnsResizable", "ColumnsPinnable", "AutoUpdate", "Height", "EmptySpaceBackgroundColor", "EsTableHandledSearch", "MaxHeight", "ContainerClass", "XLSXExport", "CSVExport", "AllSearch", "HighCellDensity", "Selection", "ShowLoadingOnBootstrap", "Removal", "RemovalCondition", "Export", "ShiftClick", "CountLabel", "HidePaging", "HidePagingCount", "HidePagingButtons", "ContextMenu", "ExportFileName", "TableClass", "ExportFunction", "ExportOnlyVisibleColumns", "HasHeaderGroup", "HasSecondaryHeaderGroup", "HeaderHidden", "BodyHidden", "SelectionDisabled", "SingleSelection", "RowClassAssigner", "OrderByColumn", "MultipleOrderingDirectives", "HiddenColumns", "ColumnsOrdering", "SearchView", "SelectAll", "UseArrayModePaging", "DynamicRowColumnsDefinition", "DynamicOperations", "Hierarchy", "ParentKey", "OwnKey", "AutoSortHierarchy", "StartsExpanded", "SavePreferences", "DefaultAlignment", "PagingStyle", "RowGroupingPagingStyle", "ItemSourceProperty", "UseSelectionCache", "ShowItemGroupsColumns", "Editable", "RangeSelection", "SearchThrottle", "ArraymodeItemsPerPage"], outputs: ["globalCheckChange", "autoUpdateChange", "secondsChange", "researchInProgressChange", "globalColVisCheckChange", "onOrderChanged", "onSearchRequest", "onSelectionChanged", "onRemoval", "onAbortRemoval", "onModelChange", "onOpenContextMenu", "onCornerAction", "onDynamicOperation"] }, { kind: "component", type: i9.EsFormDateComponent, selector: "form-date", inputs: ["InOutFormat", "FloatingLabel", "DateFormat"] }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: NodeDetailComponent, selector: "node-detail", inputs: ["NodeDetails"], outputs: ["onClose"] }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }] }); }
1746
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerComponent, deps: [{ token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i5.Location }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: AdminModuleBaseService }, { token: i4.Router }, { token: ADM_MODULE_PATH }, { token: ADM_WORKLOAD_V2, optional: true }, { token: i1$1.DateService }, { token: ADM_DETAILS_V2, optional: true }, { token: ADM_TOPACT_V2, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
1747
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmProfilerComponent, isStandalone: false, selector: "adm_profiler", providers: [{ provide: LocalizationService, useClass: AdmProfilerComponentLoc }], viewQueries: [{ propertyName: "dlgNodeDetails", first: true, predicate: ["dlgNodeDetails"], descendants: true }, { propertyName: "dlgDetailsV2", first: true, predicate: ["dlgDetailsV2"], descendants: true }, { propertyName: "detailsV2", first: true, predicate: AdmDetailsV2Component, descendants: true }], ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-12\">\n <div class=\"card app-overflow-visible\" widget>\n <div class=\"card-header\">\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span>&nbsp;\n </div>\n <div class=\"card-body widget-body\">\n <div class=\"col-md-12 bottom-15\">\n <form role=\"form\">\n <div class=\"row app-first-filter-line\">\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\n <form-date [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\"></form-date>\n </div>\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\n <form-date [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\"></form-date>\n </div>\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\" style=\"display: flex; height: 38px;\">\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterglobal\" name=\"filterglobal\"></form-checkbox>&nbsp;\n <span class=\"app-pointer app-padding-top-5 app-padding-left-5\" (click)=\"searchView.filterglobal = !searchView.filterglobal\">{{'Globale' | localize: lc}}</span>\n </div>\n\n <button [disabled]=\"searchView.searchinprogress\" class=\"input-group-addon btn app-btn-search app-margin-top-20 app-margin-right-5\" (click)=\"sendSearch()\" type=\"submit\"><i class=\"fa fa-search\"></i></button>\n <button class=\"input-group-addon btn app-btn-search app-margin-top-20\" (click)=\"downloadWorkloadReport()\" type=\"submit\" [title]=\"workloadV2 ? 'Workload report' : ''\"><i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i></button>\n </div>\n </form>\n </div>\n <div class=\"row\">\n <div class=\"col-md-12\">\n @if (!searchView) {\n <p><em>{{'Carico i Dati' | localize: lc}}</em></p>\n }\n @if (searchView) {\n <div>\n <es-table [(ngModel)]=\"searchView\" [Hierarchy]=\"true\" [OrderByColumn]=\"false\" [ParentKey]=\"'parentid'\"\n [OwnKey]=\"'id'\" [StartsExpanded]=\"false\" [ExportFunction]=\"prepareExport.bind(this)\" [Export]=\"true\"\n [ExportFileName]=\"'Profiler Export.csv'\" [HidePaging]=\"true\" (onSearchRequest)=\"sendSearch($event);\">\n <span *th=\"'1'\">{{'ID' | localize : lc}}</span>\n <span *th=\"'2'\">{{'Descrizione' | localize: lc}}</span>\n <span *th=\"'3'\">{{'Chiamate' | localize: lc}}</span>\n <span *th=\"'4'\">{{'Tempo' | localize: lc}}</span>\n <span *th=\"'5'\">{{'Tempo Max' | localize: lc}}</span>\n <span *th=\"'6'\">{{'Tempo Min' | localize: lc}}</span>\n <span *th=\"'7'\">{{'Tempo Medio' | localize: lc}}</span>\n <span *th=\"'8'\">{{'Tempo Specifico' | localize: lc}}</span>\n <span *th=\"'9'\">{{'Percentuale' | localize: lc}}</span>\n <span *th=\"'10'\">{{'Chiamate Periodo' | localize: lc}}</span>\n <span *th=\"'11'\">{{'Tempo Periodo' | localize: lc}}</span>\n <span *th=\"'12'\">{{'Tempo Max Periodo' | localize: lc}}</span>\n <span *th=\"'13'\">{{'Tempo Min Periodo' | localize: lc}}</span>\n <span *th=\"'14'\">{{'Tempo Medio Periodo' | localize: lc}}</span>\n <span *th=\"'15'\">{{'Tempo Specifico Periodo' | localize: lc}}</span>\n <span *th=\"'16'\">{{'Percentuale Periodo' | localize: lc}}</span>\n <span *th=\"'17'\">{{'Nome Tipologia Evento' | localize: lc}}</span>\n <span *th=\"'18'\">{{'Nome Classe Attesa' | localize: lc}}</span>\n <span *th=\"'19'\">{{'Numero Istanze' | localize: lc}}</span>\n <span *td=\"'1'; let item\"><span class=\"app-link app-inline\" (click)=\"openNodeDetails(item.id)\">{{item.id}}</span></span>\n <span *td=\"'2'; let item\" title=\"{{item.description}}\">{{item.description.length <= 50 ? item.description : item.description.substr(0,50) + \"[...]\" }}</span>\n <span *td=\"'3'; let item\">{{item.calls}}</span>\n <span *td=\"'4'; let item\">{{item.time}}</span>\n <span *td=\"'5'; let item\">{{item.peaktime}}</span>\n <span *td=\"'6'; let item\">{{item.mintime}}</span>\n <span *td=\"'7'; let item\">{{item.avgtime}}</span>\n <span *td=\"'8'; let item\">{{item.timewithoutchildren }}</span>\n <span *td=\"'9'; let item\">{{item.percentage}}</span>\n <span *td=\"'10' let item\">{{item.snapdeltacalls}}</span>\n <span *td=\"'11' let item\">{{item.snapdeltatime}}</span>\n <span *td=\"'12' let item\">{{item.snappeaktime}}</span>\n <span *td=\"'13' let item\">{{item.snapmintime}}</span>\n <span *td=\"'14' let item\">{{item.snapavgtime}}</span>\n <span *td=\"'15' let item\">{{item.snaptimewithoutchildren}}</span>\n <span *td=\"'16' let item\">{{item.snappercentage}}</span>\n <span *td=\"'17' let item\">{{item.eventtypename}}</span>\n <span *td=\"'18' let item\">{{item.waitclassname}}</span>\n <span *td=\"'19' let item\">{{item.numinstances}}</span>\n </es-table>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\n @if (NodeDetails) {\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\n }\n</div>\n\n<!-- Dettaglio v2 di nodo e sessione (DirectorFeature.DetailsV2) -->\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\n @if (detailsV2Enabled) {\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"!!topActV2Enabled\" [CanOpenProfiler]=\"false\" (closed)=\"dlgDetailsV2.hide()\"\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"openInProfiler($event)\"></adm-details-v2>\n }\n</div>\n", dependencies: [{ kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "directive", type: i8.EsTdDirective, selector: "[td]", inputs: ["tdVisible", "td", "tdForProperty", "tdIf", "tdClass", "tdPropertyAccessor", "tdAlignment", "tdFormat", "tdIconClass", "tdConditionField", "tdConditionValue", "tdTitle", "tdContent"] }, { kind: "directive", type: i8.EsThDirective, selector: "[th]", inputs: ["th", "thPinned", "thPinnedRight", "thPinnable", "thPinnedWidth", "thVisible", "thFixed", "thParent", "thOrder", "thOrderable", "thWrap", "thResizable", "thClass", "thShrink", "thGroupClass", "thIf", "thEmpty", "thGroup", "thAggregation", "thProperty", "thType", "thSource", "thMulti", "thStaticContent", "thBackgroundColor", "thAlignment", "thFormat", "thEditorName", "thEditorOptions", "thRendererName", "thRoutePath", "thRouteParameterProperties"] }, { kind: "component", type: i8.EsTableComponent, selector: "es-table", inputs: ["globalCheck", "autoUpdate", "seconds", "researchInProgress", "globalColVisCheck", "EsThTdProvider", "CornerMenuOptions", "ColumnsResizable", "ColumnsPinnable", "AutoUpdate", "Height", "EmptySpaceBackgroundColor", "EsTableHandledSearch", "MaxHeight", "ContainerClass", "XLSXExport", "CSVExport", "AllSearch", "HighCellDensity", "Selection", "ShowLoadingOnBootstrap", "Removal", "RemovalCondition", "Export", "ShiftClick", "CountLabel", "HidePaging", "HidePagingCount", "HidePagingButtons", "ContextMenu", "ExportFileName", "TableClass", "ExportFunction", "ExportOnlyVisibleColumns", "HasHeaderGroup", "HasSecondaryHeaderGroup", "HeaderHidden", "BodyHidden", "SelectionDisabled", "SingleSelection", "RowClassAssigner", "OrderByColumn", "MultipleOrderingDirectives", "HiddenColumns", "ColumnsOrdering", "SearchView", "SelectAll", "UseArrayModePaging", "DynamicRowColumnsDefinition", "DynamicOperations", "Hierarchy", "ParentKey", "OwnKey", "AutoSortHierarchy", "StartsExpanded", "SavePreferences", "DefaultAlignment", "PagingStyle", "RowGroupingPagingStyle", "ItemSourceProperty", "UseSelectionCache", "ShowItemGroupsColumns", "Editable", "RangeSelection", "SearchThrottle", "ArraymodeItemsPerPage"], outputs: ["globalCheckChange", "autoUpdateChange", "secondsChange", "researchInProgressChange", "globalColVisCheckChange", "onOrderChanged", "onSearchRequest", "onSelectionChanged", "onRemoval", "onAbortRemoval", "onModelChange", "onOpenContextMenu", "onCornerAction", "onDynamicOperation"] }, { kind: "component", type: i9.EsFormDateComponent, selector: "form-date", inputs: ["InOutFormat", "FloatingLabel", "DateFormat"] }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: AdmDetailsV2Component, selector: "adm-details-v2", inputs: ["Be", "CanShowSessions", "CanOpenProfiler"], outputs: ["closed", "sessionsOnEvent", "openProfiler"] }, { kind: "component", type: NodeDetailComponent, selector: "node-detail", inputs: ["NodeDetails"], outputs: ["onClose"] }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }] }); }
927
1748
  }
928
1749
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerComponent, decorators: [{
929
1750
  type: Component,
930
- args: [{ selector: "adm_profiler", providers: [{ provide: LocalizationService, useClass: AdmProfilerComponentLoc }], standalone: false, template: "<div class=\"row\">\n <div class=\"col-12\">\n <div class=\"card app-overflow-visible\" widget>\n <div class=\"card-header\">\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span>&nbsp;\n </div>\n <div class=\"card-body widget-body\">\n <div class=\"col-md-12 bottom-15\">\n <form role=\"form\">\n <div class=\"row app-first-filter-line\">\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\n <form-date [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\"></form-date>\n </div>\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\n <form-date [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\"></form-date>\n </div>\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\" style=\"display: flex; height: 38px;\">\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterglobal\" name=\"filterglobal\"></form-checkbox>&nbsp;\n <span class=\"app-pointer app-padding-top-5 app-padding-left-5\" (click)=\"searchView.filterglobal = !searchView.filterglobal\">{{'Globale' | localize: lc}}</span>\n </div>\n\n <button [disabled]=\"searchView.searchinprogress\" class=\"input-group-addon btn app-btn-search app-margin-top-20 app-margin-right-5\" (click)=\"sendSearch()\" type=\"submit\"><i class=\"fa fa-search\"></i></button>\n <button class=\"input-group-addon btn app-btn-search app-margin-top-20\" (click)=\"downloadWorkloadReport()\" type=\"submit\" [title]=\"workloadV2 ? 'Workload report' : ''\"><i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i></button>\n </div>\n </form>\n </div>\n <div class=\"row\">\n <div class=\"col-md-12\">\n @if (!searchView) {\n <p><em>{{'Carico i Dati' | localize: lc}}</em></p>\n }\n @if (searchView) {\n <div>\n <es-table [(ngModel)]=\"searchView\" [Hierarchy]=\"true\" [OrderByColumn]=\"false\" [ParentKey]=\"'parentid'\"\n [OwnKey]=\"'id'\" [StartsExpanded]=\"false\" [ExportFunction]=\"prepareExport.bind(this)\" [Export]=\"true\"\n [ExportFileName]=\"'Profiler Export.csv'\" [HidePaging]=\"true\" (onSearchRequest)=\"sendSearch($event);\">\n <span *th=\"'1'\">{{'ID' | localize : lc}}</span>\n <span *th=\"'2'\">{{'Descrizione' | localize: lc}}</span>\n <span *th=\"'3'\">{{'Chiamate' | localize: lc}}</span>\n <span *th=\"'4'\">{{'Tempo' | localize: lc}}</span>\n <span *th=\"'5'\">{{'Tempo Max' | localize: lc}}</span>\n <span *th=\"'6'\">{{'Tempo Min' | localize: lc}}</span>\n <span *th=\"'7'\">{{'Tempo Medio' | localize: lc}}</span>\n <span *th=\"'8'\">{{'Tempo Specifico' | localize: lc}}</span>\n <span *th=\"'9'\">{{'Percentuale' | localize: lc}}</span>\n <span *th=\"'10'\">{{'Chiamate Periodo' | localize: lc}}</span>\n <span *th=\"'11'\">{{'Tempo Periodo' | localize: lc}}</span>\n <span *th=\"'12'\">{{'Tempo Max Periodo' | localize: lc}}</span>\n <span *th=\"'13'\">{{'Tempo Min Periodo' | localize: lc}}</span>\n <span *th=\"'14'\">{{'Tempo Medio Periodo' | localize: lc}}</span>\n <span *th=\"'15'\">{{'Tempo Specifico Periodo' | localize: lc}}</span>\n <span *th=\"'16'\">{{'Percentuale Periodo' | localize: lc}}</span>\n <span *th=\"'17'\">{{'Nome Tipologia Evento' | localize: lc}}</span>\n <span *th=\"'18'\">{{'Nome Classe Attesa' | localize: lc}}</span>\n <span *th=\"'19'\">{{'Numero Istanze' | localize: lc}}</span>\n <span *td=\"'1'; let item\"><span class=\"app-link app-inline\" (click)=\"loadNodeDetails(item.id); dlgNodeDetails.show();\">{{item.id}}</span></span>\n <span *td=\"'2'; let item\" title=\"{{item.description}}\">{{item.description.length <= 50 ? item.description : item.description.substr(0,50) + \"[...]\" }}</span>\n <span *td=\"'3'; let item\">{{item.calls}}</span>\n <span *td=\"'4'; let item\">{{item.time}}</span>\n <span *td=\"'5'; let item\">{{item.peaktime}}</span>\n <span *td=\"'6'; let item\">{{item.mintime}}</span>\n <span *td=\"'7'; let item\">{{item.avgtime}}</span>\n <span *td=\"'8'; let item\">{{item.timewithoutchildren }}</span>\n <span *td=\"'9'; let item\">{{item.percentage}}</span>\n <span *td=\"'10' let item\">{{item.snapdeltacalls}}</span>\n <span *td=\"'11' let item\">{{item.snapdeltatime}}</span>\n <span *td=\"'12' let item\">{{item.snappeaktime}}</span>\n <span *td=\"'13' let item\">{{item.snapmintime}}</span>\n <span *td=\"'14' let item\">{{item.snapavgtime}}</span>\n <span *td=\"'15' let item\">{{item.snaptimewithoutchildren}}</span>\n <span *td=\"'16' let item\">{{item.snappercentage}}</span>\n <span *td=\"'17' let item\">{{item.eventtypename}}</span>\n <span *td=\"'18' let item\">{{item.waitclassname}}</span>\n <span *td=\"'19' let item\">{{item.numinstances}}</span>\n </es-table>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\n @if (NodeDetails) {\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\n }\n</div>" }]
1751
+ args: [{ selector: "adm_profiler", providers: [{ provide: LocalizationService, useClass: AdmProfilerComponentLoc }], standalone: false, template: "<div class=\"row\">\n <div class=\"col-12\">\n <div class=\"card app-overflow-visible\" widget>\n <div class=\"card-header\">\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span>&nbsp;\n </div>\n <div class=\"card-body widget-body\">\n <div class=\"col-md-12 bottom-15\">\n <form role=\"form\">\n <div class=\"row app-first-filter-line\">\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\n <form-date [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\"></form-date>\n </div>\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\n <form-date [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\"></form-date>\n </div>\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\" style=\"display: flex; height: 38px;\">\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterglobal\" name=\"filterglobal\"></form-checkbox>&nbsp;\n <span class=\"app-pointer app-padding-top-5 app-padding-left-5\" (click)=\"searchView.filterglobal = !searchView.filterglobal\">{{'Globale' | localize: lc}}</span>\n </div>\n\n <button [disabled]=\"searchView.searchinprogress\" class=\"input-group-addon btn app-btn-search app-margin-top-20 app-margin-right-5\" (click)=\"sendSearch()\" type=\"submit\"><i class=\"fa fa-search\"></i></button>\n <button class=\"input-group-addon btn app-btn-search app-margin-top-20\" (click)=\"downloadWorkloadReport()\" type=\"submit\" [title]=\"workloadV2 ? 'Workload report' : ''\"><i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i></button>\n </div>\n </form>\n </div>\n <div class=\"row\">\n <div class=\"col-md-12\">\n @if (!searchView) {\n <p><em>{{'Carico i Dati' | localize: lc}}</em></p>\n }\n @if (searchView) {\n <div>\n <es-table [(ngModel)]=\"searchView\" [Hierarchy]=\"true\" [OrderByColumn]=\"false\" [ParentKey]=\"'parentid'\"\n [OwnKey]=\"'id'\" [StartsExpanded]=\"false\" [ExportFunction]=\"prepareExport.bind(this)\" [Export]=\"true\"\n [ExportFileName]=\"'Profiler Export.csv'\" [HidePaging]=\"true\" (onSearchRequest)=\"sendSearch($event);\">\n <span *th=\"'1'\">{{'ID' | localize : lc}}</span>\n <span *th=\"'2'\">{{'Descrizione' | localize: lc}}</span>\n <span *th=\"'3'\">{{'Chiamate' | localize: lc}}</span>\n <span *th=\"'4'\">{{'Tempo' | localize: lc}}</span>\n <span *th=\"'5'\">{{'Tempo Max' | localize: lc}}</span>\n <span *th=\"'6'\">{{'Tempo Min' | localize: lc}}</span>\n <span *th=\"'7'\">{{'Tempo Medio' | localize: lc}}</span>\n <span *th=\"'8'\">{{'Tempo Specifico' | localize: lc}}</span>\n <span *th=\"'9'\">{{'Percentuale' | localize: lc}}</span>\n <span *th=\"'10'\">{{'Chiamate Periodo' | localize: lc}}</span>\n <span *th=\"'11'\">{{'Tempo Periodo' | localize: lc}}</span>\n <span *th=\"'12'\">{{'Tempo Max Periodo' | localize: lc}}</span>\n <span *th=\"'13'\">{{'Tempo Min Periodo' | localize: lc}}</span>\n <span *th=\"'14'\">{{'Tempo Medio Periodo' | localize: lc}}</span>\n <span *th=\"'15'\">{{'Tempo Specifico Periodo' | localize: lc}}</span>\n <span *th=\"'16'\">{{'Percentuale Periodo' | localize: lc}}</span>\n <span *th=\"'17'\">{{'Nome Tipologia Evento' | localize: lc}}</span>\n <span *th=\"'18'\">{{'Nome Classe Attesa' | localize: lc}}</span>\n <span *th=\"'19'\">{{'Numero Istanze' | localize: lc}}</span>\n <span *td=\"'1'; let item\"><span class=\"app-link app-inline\" (click)=\"openNodeDetails(item.id)\">{{item.id}}</span></span>\n <span *td=\"'2'; let item\" title=\"{{item.description}}\">{{item.description.length <= 50 ? item.description : item.description.substr(0,50) + \"[...]\" }}</span>\n <span *td=\"'3'; let item\">{{item.calls}}</span>\n <span *td=\"'4'; let item\">{{item.time}}</span>\n <span *td=\"'5'; let item\">{{item.peaktime}}</span>\n <span *td=\"'6'; let item\">{{item.mintime}}</span>\n <span *td=\"'7'; let item\">{{item.avgtime}}</span>\n <span *td=\"'8'; let item\">{{item.timewithoutchildren }}</span>\n <span *td=\"'9'; let item\">{{item.percentage}}</span>\n <span *td=\"'10' let item\">{{item.snapdeltacalls}}</span>\n <span *td=\"'11' let item\">{{item.snapdeltatime}}</span>\n <span *td=\"'12' let item\">{{item.snappeaktime}}</span>\n <span *td=\"'13' let item\">{{item.snapmintime}}</span>\n <span *td=\"'14' let item\">{{item.snapavgtime}}</span>\n <span *td=\"'15' let item\">{{item.snaptimewithoutchildren}}</span>\n <span *td=\"'16' let item\">{{item.snappercentage}}</span>\n <span *td=\"'17' let item\">{{item.eventtypename}}</span>\n <span *td=\"'18' let item\">{{item.waitclassname}}</span>\n <span *td=\"'19' let item\">{{item.numinstances}}</span>\n </es-table>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\n @if (NodeDetails) {\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\n }\n</div>\n\n<!-- Dettaglio v2 di nodo e sessione (DirectorFeature.DetailsV2) -->\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\n @if (detailsV2Enabled) {\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"!!topActV2Enabled\" [CanOpenProfiler]=\"false\" (closed)=\"dlgDetailsV2.hide()\"\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"openInProfiler($event)\"></adm-details-v2>\n }\n</div>\n" }]
931
1752
  }], ctorParameters: () => [{ type: i1.LocalizationService }, { type: i3.PreferencesService }, { type: i5.Location }, { type: i1$1.InterComService }, { type: i4.ActivatedRoute }, { type: AdminModuleBaseService }, { type: i4.Router }, { type: undefined, decorators: [{
932
1753
  type: Inject,
933
1754
  args: [ADM_MODULE_PATH]
@@ -936,7 +1757,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
936
1757
  }, {
937
1758
  type: Inject,
938
1759
  args: [ADM_WORKLOAD_V2]
939
- }] }] });
1760
+ }] }, { type: i1$1.DateService }, { type: undefined, decorators: [{
1761
+ type: Optional
1762
+ }, {
1763
+ type: Inject,
1764
+ args: [ADM_DETAILS_V2]
1765
+ }] }, { type: undefined, decorators: [{
1766
+ type: Optional
1767
+ }, {
1768
+ type: Inject,
1769
+ args: [ADM_TOPACT_V2]
1770
+ }] }], propDecorators: { dlgNodeDetails: [{
1771
+ type: ViewChild,
1772
+ args: ["dlgNodeDetails"]
1773
+ }], dlgDetailsV2: [{
1774
+ type: ViewChild,
1775
+ args: ["dlgDetailsV2"]
1776
+ }], detailsV2: [{
1777
+ type: ViewChild,
1778
+ args: [AdmDetailsV2Component]
1779
+ }] } });
940
1780
 
941
1781
  // Ordinamento decrescente del profiler v2 (figli nell'albero, righe nella vista per nome). I numeri sono quelli del backend
942
1782
  var ProfilerOrderBy;
@@ -964,50 +1804,6 @@ class ProfilerV2NodeRequest extends ProfilerV2Request {
964
1804
  class ProfilerV2FlatRequest extends ProfilerV2Request {
965
1805
  }
966
1806
 
967
- // Angular
968
- // Formati del profiler v2 (specifica "Profiler gerarchico"): durate nell'unità più leggibile, interi con il separatore
969
- // delle migliaia italiano, percentuali con un decimale sotto 10. Un dato mancante è "—"
970
- class ProfilerFormatPipe {
971
- transform(value, kind) {
972
- if (value == null || isNaN(value))
973
- return "—";
974
- switch (kind) {
975
- case "dur": return formatDuration(value);
976
- case "pct": return formatPercentage(value);
977
- default: return formatNumber(value, "it", "1.0-0");
978
- }
979
- }
980
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
981
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, isStandalone: true, name: "pv2fmt" }); }
982
- }
983
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, decorators: [{
984
- type: Pipe,
985
- args: [{ name: "pv2fmt" }]
986
- }] });
987
- // Secondi: "850 µs", "4,27 ms", "312,5 ms", "8,41 s", "4 min 12 s", "3 h 20 min", "76 h"
988
- function formatDuration(seconds) {
989
- if (seconds == null || isNaN(seconds))
990
- return "—";
991
- let abs = Math.abs(seconds);
992
- if (abs < 0.001)
993
- return `${formatNumber(seconds * 1000000, "it", "1.0-0")} µs`;
994
- if (abs < 1)
995
- return `${formatNumber(seconds * 1000, "it", abs < 0.01 ? "1.2-2" : "1.1-1")} ms`;
996
- if (abs < 60)
997
- return `${formatNumber(seconds, "it", abs < 10 ? "1.2-2" : "1.1-1")} s`;
998
- if (abs < 3600)
999
- return `${Math.floor(abs / 60)} min ${Math.floor(abs % 60)} s`;
1000
- if (abs < 48 * 3600)
1001
- return `${Math.floor(abs / 3600)} h ${Math.floor(abs % 3600 / 60)} min`;
1002
- return `${formatNumber(Math.floor(abs / 3600), "it", "1.0-0")} h`;
1003
- }
1004
- // Da 0 a 100: "4,2%", "34%"
1005
- function formatPercentage(value) {
1006
- if (value == null || isNaN(value))
1007
- return "—";
1008
- return `${formatNumber(value, "it", Math.abs(value) < 10 ? "1.1-1" : "1.0-0")}%`;
1009
- }
1010
-
1011
1807
  class AdmProfilerV2Loc extends LocalizationService {
1012
1808
  constructor(injector) {
1013
1809
  super(injector);
@@ -1103,6 +1899,7 @@ class AdmProfilerV2Loc extends LocalizationService {
1103
1899
  super.set("it->en", "Il nodo non c'è nelle istanze o nella finestra scelte.", ["The node is not in the chosen instances or window."]);
1104
1900
  super.set("it->en", "Copia", ["Copy"]);
1105
1901
  super.set("it->en", "Copiato", ["Copied"]);
1902
+ super.set("it->en", "Dettaglio completo", ["Full detail"]);
1106
1903
  super.set("it->en", "Percorso", ["Path"]);
1107
1904
  super.set("it->en", "Nella finestra", ["In window"]);
1108
1905
  super.set("it->en", "Esecuzioni", ["Executions"]);
@@ -1179,7 +1976,9 @@ class ProfilerV2Chart {
1179
1976
  class ProfilerV2Settings {
1180
1977
  }
1181
1978
  class AdmProfilerV2Component {
1182
- constructor(dateExts, lc, localStorage, intercom, route, router, location, adms, mod, workloadV2) {
1979
+ constructor(dateExts, lc, localStorage, intercom, route, router, location, adms, mod, workloadV2,
1980
+ // Con DirectorFeature.DetailsV2 il pannello apre anche il dettaglio completo del nodo; "Sessioni su questo evento" vuole la Top Activity v2
1981
+ detailsV2Enabled, topActV2Enabled) {
1183
1982
  this.dateExts = dateExts;
1184
1983
  this.lc = lc;
1185
1984
  this.localStorage = localStorage;
@@ -1190,6 +1989,8 @@ class AdmProfilerV2Component {
1190
1989
  this.adms = adms;
1191
1990
  this.mod = mod;
1192
1991
  this.workloadV2 = workloadV2;
1992
+ this.detailsV2Enabled = detailsV2Enabled;
1993
+ this.topActV2Enabled = topActV2Enabled;
1193
1994
  this.EventTypes = EVENT_TYPES;
1194
1995
  // Barra dei comandi
1195
1996
  this.live = true;
@@ -1725,6 +2526,28 @@ class AdmProfilerV2Component {
1725
2526
  this.setRoot(nodeId);
1726
2527
  this.select(nodeId);
1727
2528
  }
2529
+ // Dettaglio completo del nodo (specifica "Dettaglio nodo e sessione") con la sorgente, le istanze e la finestra della pagina:
2530
+ // dal vivo l'ultima ora, sullo storico la finestra scelta
2531
+ openFullDetail() {
2532
+ if (!this.detail)
2533
+ return;
2534
+ let req = this.baseRequest(new ProfilerV2NodeRequest());
2535
+ let to = req.snapTo ? new Date(req.snapTo) : new Date();
2536
+ let from = req.snapFrom ? new Date(req.snapFrom) : new Date(to.getTime() - 3600 * 1000);
2537
+ this.detailsV2.openNode(this.detail.nodeId, { from: from, to: to, realTime: this.live, global: req.global, instanceId: req.instanceId });
2538
+ this.dlgDetailsV2.show();
2539
+ }
2540
+ // N7 dal dettaglio completo: l'albero con il nodo come radice, in questa pagina
2541
+ rootFromDetails(nodeId) {
2542
+ this.dlgDetailsV2.hide();
2543
+ this.setRoot(nodeId);
2544
+ this.select(nodeId);
2545
+ }
2546
+ // N8: la Top Activity v2 filtrata sull'evento, nella finestra del dettaglio
2547
+ showEventSessions(link) {
2548
+ this.dlgDetailsV2.hide();
2549
+ this.router.navigate([`/pages/${this.mod}/topact`, ...(this.be ? [this.be] : [])], { queryParams: { event: link.nodeId, eventName: link.nodeName, from: link.from.toISOString(), to: link.to.toISOString() } });
2550
+ }
1728
2551
  showDetail(nodeId, event) {
1729
2552
  event.stopPropagation();
1730
2553
  this.select(nodeId);
@@ -1968,12 +2791,12 @@ class AdmProfilerV2Component {
1968
2791
  ret.setMinutes(0, 0, 0);
1969
2792
  return ret;
1970
2793
  }
1971
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerV2Component, deps: [{ token: i1$1.DateService }, { token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: i4.Router }, { token: i5.Location }, { token: AdminModuleBaseService }, { token: ADM_MODULE_PATH }, { token: ADM_WORKLOAD_V2, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
1972
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmProfilerV2Component, isStandalone: false, selector: "profiler_v2", providers: [{ provide: LocalizationService, useClass: AdmProfilerV2Loc }], ngImport: i0, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span>\r\n </div>\r\n <div class=\"card-body widget-body pv2-body\">\r\n <!-- Barra dei comandi: quali dati caricare. Ogni cambio ricarica la vista e il dettaglio aperto -->\r\n <div class=\"pv2-toolbar\">\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Sorgente' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"live\" (click)=\"setLive(true)\"><span class=\"pv2-live-dot\"></span>Live</button>\r\n <button type=\"button\" [class.pv2-on]=\"!live\" (click)=\"setLive(false)\">{{'Storico' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n <div class=\"pv2-field pv2-field-wide pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"instance\" (ngModelChange)=\"setInstance($event)\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanze' | localize: lc\"></form-select>\r\n </div>\r\n </div>\r\n\r\n @if (!live) {\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterfrom\" (ngModelChange)=\"filterfrom = $event; datesChanged()\" name=\"filterfrom\" [Placeholder]=\"'Dal' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterto\" (ngModelChange)=\"filterto = $event; datesChanged()\" name=\"filterto\" [Placeholder]=\"'Al' | localize: lc\"></form-datetime>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Valori' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"!snapValues\" (click)=\"setSnapValues(false)\">{{\"Dall'avvio\" | localize: lc}}</button>\r\n <button type=\"button\" [class.pv2-on]=\"snapValues\" (click)=\"setSnapValues(true)\">{{\"Dall'ultimo snapshot\" | localize: lc}}</button>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"pv2-cluster pv2-cluster-end\">\r\n <button type=\"button\" class=\"btn app-btn-search\" [disabled]=\"loading\" (click)=\"reloadAll()\" [title]=\"'Aggiorna' | localize: lc\">\r\n <i class=\"fa fa-refresh\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n <button type=\"button\" class=\"btn app-btn-search\" (click)=\"downloadWorkloadReport()\" [title]=\"(workloadV2 ? 'Workload report' : 'Scarica il workload report') | localize: lc\">\r\n <i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Riga della finestra: sempre visibile sopra la vista -->\r\n <div class=\"pv2-window\">\r\n <span><strong>{{live ? 'Live' : ('Storico' | localize: lc)}}</strong> &middot; {{instanceLabel}}</span>\r\n @if (current?.snapFrom; as snapFrom) {\r\n @if (live) {\r\n <span>{{\"Delta dall'ultimo snapshot delle\" | localize: lc}} {{hhmm(snapFrom)}} ({{minutesAgo(snapFrom)}} {{'min fa' | localize: lc}})</span>\r\n } @else {\r\n <span>{{'Snapshot dalle' | localize: lc}} {{ddmmhhmm(snapFrom)}} {{'alle' | localize: lc}} {{ddmmhhmm(current?.snapTo)}}</span>\r\n }\r\n } @else if (current && !live) {\r\n <span class=\"pv2-warn-text\">{{'Nessuno snapshot termina nella finestra scelta' | localize: lc}}</span>\r\n }\r\n @if (view == 'tree' && tree?.idleNode) {\r\n <span>{{tree.numNodes | pv2fmt: 'int'}} {{\"nodi nell'albero\" | localize: lc}} &middot; {{tree.numReturnedNodes | pv2fmt: 'int'}} {{'nella risposta' | localize: lc}}</span>\r\n }\r\n @if (view == 'flat' && flat) {\r\n <span>{{flat.numItems | pv2fmt: 'int'}} {{'eventi distinti' | localize: lc}}</span>\r\n }\r\n @if (loading) {\r\n <span class=\"pv2-muted\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Caricamento\u2026' | localize: lc}}</span>\r\n }\r\n </div>\r\n\r\n <div class=\"pv2-main\">\r\n <!-- Vista: albero o eventi per nome -->\r\n <div class=\"pv2-panel pv2-view\">\r\n <div class=\"pv2-view-bar\">\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"view == 'tree'\" (click)=\"setView('tree')\"><i class=\"fa fa-sitemap\"></i> {{'Albero' | localize: lc}}</button>\r\n <button type=\"button\" [class.pv2-on]=\"view == 'flat'\" (click)=\"setView('flat')\"><i class=\"fa fa-list\"></i> {{'Per nome' | localize: lc}}</button>\r\n </div>\r\n\r\n @if (view == 'tree') {\r\n <div class=\"pv2-field pv2-field-search\" [title]=\"'Per esempio MRD_METERREADINGS, ENQUEUE, ProfilesMgr' | localize: lc\">\r\n <form-input [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"searchText\" (ngModelChange)=\"searchText = $event; searchChanged()\" name=\"search\" [Placeholder]=\"'Cerca nei nomi o per id' | localize: lc\"></form-input>\r\n </div>\r\n <div class=\"pv2-field pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"orderBy\" (ngModelChange)=\"setOrderBy($event)\" name=\"orderBy\" [Source]=\"TreeOrderOptions\" [Placeholder]=\"'Ordina per' | localize: lc\"></form-select>\r\n </div>\r\n <div class=\"pv2-group\" [class.pv2-disabled]=\"!!activeSearch\">\r\n <span class=\"pv2-group-label\">{{'Figli per nodo' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n @for (o of ChildrenOptions; track o.id) {\r\n <button type=\"button\" [disabled]=\"!!activeSearch\" [class.pv2-on]=\"maxChildren == o.id\" (click)=\"setMaxChildren(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"pv2-group\" [class.pv2-disabled]=\"!!activeSearch\">\r\n <span class=\"pv2-group-label\">{{'Soglia' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n @for (o of ThresholdOptions; track o.id) {\r\n <button type=\"button\" [disabled]=\"!!activeSearch\" [class.pv2-on]=\"minPercentage == o.id\" (click)=\"setMinPercentage(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"pv2-field pv2-field-search\">\r\n <form-input [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"flatSearch\" (ngModelChange)=\"flatSearch = $event; flatSearchChanged()\" name=\"flatSearch\" [Placeholder]=\"'Cerca nei nomi' | localize: lc\"></form-input>\r\n </div>\r\n <div class=\"pv2-field pv2-field-narrow pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"flatType\" (ngModelChange)=\"flatType = $event; flatChanged()\" name=\"flatType\" [Source]=\"FlatTypes\" [Placeholder]=\"'Tipo' | localize: lc\"></form-select>\r\n </div>\r\n <div class=\"pv2-field pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"flatOrderBy\" (ngModelChange)=\"flatOrderBy = $event; flatChanged()\" name=\"flatOrderBy\" [Source]=\"FlatOrderOptions\" [Placeholder]=\"'Ordina per' | localize: lc\"></form-select>\r\n </div>\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Righe' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n @for (o of FlatRows; track o.id) {\r\n <button type=\"button\" [class.pv2-on]=\"flatTop == o.id\" (click)=\"setFlatTop(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"pv2-toggle\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [ngModel]=\"flatIncludeIdle\" (ngModelChange)=\"flatIncludeIdle = $event; flatChanged()\" name=\"flatIncludeIdle\"></form-checkbox>\r\n <span class=\"pv2-pointer\" (click)=\"flatIncludeIdle = !flatIncludeIdle; flatChanged()\">{{'Anche gli eventi idle' | localize: lc}}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (view == 'tree') {\r\n <!-- Percorso della radice: ogni antenato riporta l'albero a quel nodo -->\r\n @if (tree?.idleNode && tree?.rootPath?.length) {\r\n <nav class=\"pv2-crumbs\">\r\n @for (item of tree.rootPath; track item.nodeId) {\r\n <button type=\"button\" class=\"pv2-crumb\" [title]=\"item.nodeName\" (click)=\"setRoot(item.nodeId)\">{{item.nodeName}}</button>\r\n <span class=\"pv2-crumb-sep\">&rsaquo;</span>\r\n }\r\n <span class=\"pv2-crumb pv2-crumb-current\" [title]=\"tree.idleNode.nodeName\">{{tree.idleNode.nodeName}}</span>\r\n </nav>\r\n }\r\n\r\n @if (treeNotice) {\r\n <div class=\"pv2-alert pv2-alert-warn\">\r\n {{treeNotice}}\r\n <button type=\"button\" class=\"pv2-alert-close\" [title]=\"'Chiudi' | localize: lc\" (click)=\"treeNotice = null\">&times;</button>\r\n </div>\r\n }\r\n @if (activeSearch && tree) {\r\n @if (matchCount > 0) {\r\n <div class=\"pv2-alert\" [class.pv2-alert-warn]=\"tree.truncated\">\r\n {{matchCount | pv2fmt: 'int'}} {{'nodi trovati, con i loro antenati.' | localize: lc}}\r\n @if (tree.truncated) {\r\n <strong>{{'I nodi trovati sono pi\u00F9 di 1.000: sono mostrati i primi per l\\'ordinamento scelto.' | localize: lc}}</strong>\r\n }\r\n </div>\r\n } @else if (!treeLoading) {\r\n <div class=\"pv2-alert\">{{'Nessun nodo contiene' | localize: lc}} &laquo;{{activeSearch}}&raquo;.</div>\r\n }\r\n }\r\n @if (treeError) {\r\n <div class=\"pv2-alert pv2-alert-error\">{{treeError}}</div>\r\n }\r\n\r\n <div class=\"pv2-table-wrap\" tabindex=\"0\" (keydown)=\"treeKeydown($event)\">\r\n <table class=\"pv2-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"pv2-col-node\">{{'Nodo' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Chiamate' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Tempo' | localize: lc}}</th>\r\n <th>{{snapMode ? '\u0394 ' : ''}}{{'% del padre' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{(snapMode ? '\u0394 Proprio' : 'Tempo proprio') | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Medio' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Picco' | localize: lc}}</th>\r\n @if (live) {\r\n <th class=\"pv2-num\">{{'Thread ora' | localize: lc}}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of rows; track row.key) {\r\n @if (row.kind == 'node') {\r\n <tr [id]=\"'pv2-row-' + row.node.nodeId\" class=\"pv2-row\"\r\n [class.pv2-selected]=\"row.node.nodeId == selectedId\"\r\n [class.pv2-idle]=\"isIdle(row.node.eventTypeName, row.node.waitClassName)\"\r\n (click)=\"rowClicked(row.node)\" (dblclick)=\"toggle(row.node)\">\r\n <td class=\"pv2-col-node\">\r\n <div class=\"pv2-node\" [style.padding-left.px]=\"row.depth * 16\">\r\n @if (hasChildren(row.node)) {\r\n <button type=\"button\" class=\"pv2-caret\" tabindex=\"-1\" [attr.aria-expanded]=\"isExpanded(row.node)\" (click)=\"toggle(row.node, $event)\">\r\n <i class=\"fa\" [class.fa-caret-down]=\"isExpanded(row.node)\" [class.fa-caret-right]=\"!isExpanded(row.node)\"></i>\r\n </button>\r\n } @else {\r\n <span class=\"pv2-caret\"></span>\r\n }\r\n <span class=\"pv2-type\"><span class=\"pv2-dot\" [style.background]=\"typeColor(row.node.eventTypeName, row.node.waitClassName)\"></span>{{typeLabel(row.node.eventTypeName, row.node.waitClassName)}}</span>\r\n <span class=\"pv2-name\" [title]=\"row.node.nodeName\">@if (row.node.searchMatch && activeSearch) {@for (part of nameParts(row.node.nodeName, activeSearch); track $index) {@if (part.hit) {<mark>{{part.text}}</mark>} @else {<span>{{part.text}}</span>}}} @else {<span>{{row.node.nodeName}}</span>}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{calls(row.node) | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{time(row.node) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-perc\" [title]=\"(parentPerc(row.node) | pv2fmt: 'pct') + ' ' + ('del padre' | localize: lc) + ' \u00B7 ' + (firstLevelPerc(row.node) | pv2fmt: 'pct') + ' ' + ('del nodo di primo livello' | localize: lc)\">\r\n <div class=\"pv2-perc-cell\">\r\n <div class=\"pv2-bar\"><div [style.width.%]=\"parentPerc(row.node)\" [style.background]=\"typeColor(row.node.eventTypeName, row.node.waitClassName)\"></div></div>\r\n <span>{{parentPerc(row.node) | pv2fmt: 'pct'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{self(row.node) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{avg(row.node) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{peak(row.node) | pv2fmt: 'dur'}}</td>\r\n @if (live) {\r\n <td class=\"pv2-num pv2-threads\">\r\n @if (isLongRunning(row.node.eventTypeName, row.node.waitClassName, row.node.activeMaxTime)) {\r\n <span class=\"pv2-long\" [title]=\"('Esecuzione in corso da' | localize: lc) + ' ' + duration(row.node.activeMaxTime) + ': ' + ('forse bloccata' | localize: lc)\"><i class=\"fa fa-clock\"></i> {{duration(row.node.activeMaxTime)}}</span>\r\n }\r\n @if (row.node.activeThreads > 0) {\r\n <span class=\"pv2-active\"><span class=\"pv2-active-dot\"></span>{{row.node.activeThreads}}</span>\r\n } @else {\r\n <span class=\"pv2-muted\">{{row.node.activeThreads ?? '\u2014'}}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n } @else if (row.kind == 'loading') {\r\n <tr class=\"pv2-service\">\r\n <td [attr.colspan]=\"live ? 8 : 7\">\r\n <div [style.padding-left.px]=\"row.depth * 16 + 24\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Caricamento dei figli\u2026' | localize: lc}}</div>\r\n </td>\r\n </tr>\r\n } @else {\r\n <tr class=\"pv2-service\">\r\n <td [attr.colspan]=\"live ? 8 : 7\">\r\n <div [style.padding-left.px]=\"row.depth * 16 + 24\">\r\n {{row.node.omittedChildren | pv2fmt: 'int'}} {{'figli non mostrati' | localize: lc}} &middot; {{omittedTime(row.node) | pv2fmt: 'dur'}}\r\n @if (!snapMode) {\r\n &middot; {{row.node.omittedCalls | pv2fmt: 'int'}} {{'chiamate' | localize: lc}}\r\n }\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"showAll(row.node, $event)\">{{'Mostra tutti' | localize: lc}}</button>\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n @if (rows.length == 0 && !treeError) {\r\n <div class=\"pv2-empty\">\r\n @if (!tree) {\r\n {{'Caricamento\u2026' | localize: lc}}\r\n } @else if (!tree.snapFrom && !live) {\r\n {{'Nessuno snapshot termina nella finestra scelta: allargala o spostala indietro.' | localize: lc}}\r\n } @else {\r\n {{\"Il nodo non c'\u00E8 nelle istanze scelte.\" | localize: lc}}\r\n }\r\n </div>\r\n }\r\n </div>\r\n } @else {\r\n @if (flatError) {\r\n <div class=\"pv2-alert pv2-alert-error\">{{flatError}}</div>\r\n }\r\n <div class=\"pv2-table-wrap\">\r\n <table class=\"pv2-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"pv2-col-node\">{{'Evento' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Percorsi' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Chiamate' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{(snapMode ? '\u0394 Proprio' : 'Tempo proprio') | localize: lc}}</th>\r\n <th>{{snapMode ? '\u0394 ' : ''}}{{'% proprio' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Tempo' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Medio' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{(snapMode ? \"Picco dall'avvio\" : 'Picco') | localize: lc}}</th>\r\n @if (live) {\r\n <th class=\"pv2-num\">{{'Thread' | localize: lc}}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (item of flat?.items ?? []; track flatKey(item)) {\r\n <tr class=\"pv2-row\" [class.pv2-idle]=\"isIdle(item.eventTypeName, item.waitClassName)\" [class.pv2-selected]=\"openFlat.has(flatKey(item))\" (click)=\"toggleFlat(item)\">\r\n <td class=\"pv2-col-node\">\r\n <div class=\"pv2-node\">\r\n <span class=\"pv2-caret\"><i class=\"fa\" [class.fa-caret-down]=\"openFlat.has(flatKey(item))\" [class.fa-caret-right]=\"!openFlat.has(flatKey(item))\"></i></span>\r\n <span class=\"pv2-type\"><span class=\"pv2-dot\" [style.background]=\"typeColor(item.eventTypeName, item.waitClassName)\"></span>{{typeLabel(item.eventTypeName, item.waitClassName)}}</span>\r\n <span class=\"pv2-name\" [title]=\"item.nodeName\">@for (part of nameParts(item.nodeName, (flatSearch ?? '').trim()); track $index) {@if (part.hit) {<mark>{{part.text}}</mark>} @else {<span>{{part.text}}</span>}}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{item.numPaths | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{flatCalls(item) | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{flatSelf(item) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-perc\">\r\n <div class=\"pv2-perc-cell\">\r\n <div class=\"pv2-bar\"><div [style.width.%]=\"flatPerc(item)\" [style.background]=\"typeColor(item.eventTypeName, item.waitClassName)\"></div></div>\r\n <span>{{flatPerc(item) | pv2fmt: 'pct'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{flatTime(item) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{flatAvg(item) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{item.peakTime | pv2fmt: 'dur'}}</td>\r\n @if (live) {\r\n <td class=\"pv2-num pv2-threads\">\r\n @if (item.activeThreads > 0) {\r\n <span class=\"pv2-active\"><span class=\"pv2-active-dot\"></span>{{item.activeThreads}}</span>\r\n } @else {\r\n <span class=\"pv2-muted\">{{item.activeThreads ?? '\u2014'}}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n @if (openFlat.has(flatKey(item))) {\r\n <tr class=\"pv2-sub\">\r\n <td [attr.colspan]=\"live ? 9 : 8\">\r\n <div class=\"pv2-sub-title\">{{'Nodi con pi\u00F9 tempo' | localize: lc}}</div>\r\n @for (id of item.nodeIds ?? []; track id) {\r\n <div class=\"pv2-sub-item\">\r\n <code>{{id}}</code>\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"showDetail(id, $event)\">{{'Dettaglio' | localize: lc}}</button>\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"openInTree(id, $event)\">{{\"Apri nell'albero\" | localize: lc}}</button>\r\n </div>\r\n }\r\n @if (item.numPaths > (item.nodeIds?.length ?? 0)) {\r\n <div class=\"pv2-muted\">+{{item.numPaths - (item.nodeIds?.length ?? 0) | pv2fmt: 'int'}} {{'altri' | localize: lc}}</div>\r\n }\r\n </td>\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n @if (!flatError && (!flat || !flat.items?.length)) {\r\n <div class=\"pv2-empty\">{{(flat ? 'Nessun evento con questi filtri.' : 'Caricamento\u2026') | localize: lc}}</div>\r\n }\r\n </div>\r\n @if (flat?.items?.length) {\r\n <div class=\"pv2-footer\">\r\n {{flat.numItems | pv2fmt: 'int'}} {{'eventi distinti' | localize: lc}}@if (flat.numItems > flat.items.length) {, {{'mostrati i primi' | localize: lc}} {{flat.items.length | pv2fmt: 'int'}}}.\r\n {{'La percentuale \u00E8 sul tempo proprio di tutti gli eventi non idle.' | localize: lc}}\r\n </div>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Dettaglio del nodo selezionato, lo stesso per le due viste -->\r\n <aside class=\"pv2-panel pv2-detail\" [class.pv2-stale]=\"detailStale\">\r\n @if (!selectedId) {\r\n <div class=\"pv2-placeholder\">{{'Seleziona un nodo per vederne il dettaglio.' | localize: lc}}</div>\r\n } @else if (detailMissing && !detailLoading) {\r\n <div class=\"pv2-placeholder\">{{\"Il nodo non c'\u00E8 nelle istanze o nella finestra scelte.\" | localize: lc}}</div>\r\n } @else if (detailError && !detailLoading) {\r\n <div class=\"pv2-placeholder pv2-error-text\">{{detailError}}</div>\r\n } @else if (!detail) {\r\n <div class=\"pv2-placeholder\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Caricamento\u2026' | localize: lc}}</div>\r\n } @else {\r\n <div class=\"pv2-d-head\">\r\n <span class=\"pv2-type\"><span class=\"pv2-dot\" [style.background]=\"typeColor(detail.eventTypeName, detail.waitClassName)\"></span>{{typeLabel(detail.eventTypeName, detail.waitClassName)}}</span>\r\n @if (detailLoading) {\r\n <i class=\"fa fa-spinner fa-spin pv2-muted\"></i>\r\n }\r\n </div>\r\n <div class=\"pv2-fullname\">{{detail.nodeName}}</div>\r\n <div class=\"pv2-id\">\r\n Id <code #idText>{{detail.nodeId}}</code>\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"copyId(idText)\">{{(copied ? 'Copiato' : 'Copia') | localize: lc}}</button>\r\n </div>\r\n\r\n <div class=\"pv2-d-title\">{{'Percorso' | localize: lc}}</div>\r\n <div class=\"pv2-path\">\r\n @for (item of detail.fullWaitStack ?? []; track item.nodeId; let i = $index) {\r\n <button type=\"button\" class=\"pv2-path-item\" [style.padding-left.px]=\"i * 10\" [title]=\"item.nodeName\" (click)=\"select(item.nodeId)\">\r\n <span class=\"pv2-dot\" [style.background]=\"typeColor(item.eventTypeName, item.waitClassName)\"></span>{{item.nodeName}}\r\n </button>\r\n }\r\n <div class=\"pv2-path-item pv2-path-current\" [style.padding-left.px]=\"(detail.fullWaitStack?.length ?? 0) * 10\" [title]=\"detail.nodeName\">\r\n <span class=\"pv2-dot\" [style.background]=\"typeColor(detail.eventTypeName, detail.waitClassName)\"></span>{{detail.nodeName}}\r\n </div>\r\n </div>\r\n\r\n <div class=\"pv2-d-title\">{{(live ? \"Dall'avvio\" : 'Nella finestra') | localize: lc}}</div>\r\n <dl class=\"pv2-kv\">\r\n <dt>{{'Esecuzioni' | localize: lc}}</dt><dd>{{detail.executions | pv2fmt: 'int'}}</dd>\r\n <dt>{{'Tempo totale' | localize: lc}}</dt><dd>{{detail.elapsedTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Tempo proprio' | localize: lc}}</dt><dd>{{detail.elapsedTimeLessChildren | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Medio' | localize: lc}}</dt><dd>{{detail.avgTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Picco' | localize: lc}}</dt><dd>{{detail.peakTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Minimo' | localize: lc}}</dt><dd>{{detail.minTime ? (detail.minTime | pv2fmt: 'dur') : '\u2014'}}</dd>\r\n </dl>\r\n\r\n @if (live) {\r\n <div class=\"pv2-d-title\">{{\"Dall'ultimo snapshot\" | localize: lc}}, {{hhmm(detail.snapFrom)}}</div>\r\n <dl class=\"pv2-kv\">\r\n <dt>{{'Esecuzioni' | localize: lc}}</dt><dd>{{detail.snapDeltaExecutions | pv2fmt: 'int'}}</dd>\r\n <dt>{{'Tempo totale' | localize: lc}}</dt><dd>{{detail.snapDeltaElapsedTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Tempo proprio' | localize: lc}}</dt><dd>{{detail.snapDeltaElapsedTimeLessChildren | pv2fmt: 'dur'}}</dd>\r\n </dl>\r\n\r\n <div class=\"pv2-d-title\">{{'Adesso' | localize: lc}}</div>\r\n <dl class=\"pv2-kv\">\r\n <dt>{{'Thread dentro' | localize: lc}}</dt>\r\n <dd>\r\n @if (detail.activeThreads > 0) {\r\n <span class=\"pv2-active\"><span class=\"pv2-active-dot\"></span>{{detail.activeThreads}}</span>\r\n } @else {\r\n {{detail.activeThreads ?? '\u2014'}}\r\n }\r\n </dd>\r\n <dt>{{'Esecuzione pi\u00F9 lunga' | localize: lc}}</dt>\r\n <dd>\r\n @if (detail.activeThreads > 0) {\r\n {{detail.activeMaxTime | pv2fmt: 'dur'}}\r\n @if (isLongRunning(detail.eventTypeName, detail.waitClassName, detail.activeMaxTime)) {\r\n <span class=\"pv2-long\"><i class=\"fa fa-clock\"></i> {{'forse bloccata' | localize: lc}}</span>\r\n }\r\n } @else {\r\n \u2014\r\n }\r\n </dd>\r\n <dt>{{'Ultima uscita' | localize: lc}}</dt><dd>{{relative(detail.lastExitTime)}}</dd>\r\n </dl>\r\n }\r\n\r\n @if (typeParts.length > 0) {\r\n <div class=\"pv2-d-title\">{{'Tempo proprio del sottoalbero per tipo' | localize: lc}}</div>\r\n <div class=\"pv2-stack\">\r\n @for (part of typeParts; track part.type) {\r\n <div [style.width.%]=\"part.percentage\" [style.background]=\"part.color\" [title]=\"part.label + ' ' + (part.percentage | pv2fmt: 'pct')\"></div>\r\n }\r\n </div>\r\n <div class=\"pv2-legend\">\r\n @for (part of typeParts; track part.type) {\r\n <span class=\"pv2-legend-item\"><span class=\"pv2-swatch\" [style.background]=\"part.color\"></span>{{part.label}} <strong>{{part.percentage | pv2fmt: 'pct'}}</strong></span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"pv2-d-title\">{{'Sessioni attive sul nodo e sui discendenti' | localize: lc}}</div>\r\n @if (chart) {\r\n <div class=\"pv2-chart\">\r\n <div class=\"pv2-chart-y\">\r\n <span>{{axisValue(chart.max)}}</span>\r\n <span>{{axisValue(chart.max / 2)}}</span>\r\n <span>0</span>\r\n </div>\r\n <div class=\"pv2-chart-plot\">\r\n <svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\r\n <line x1=\"0\" y1=\"50\" x2=\"100\" y2=\"50\" class=\"pv2-chart-grid\" vector-effect=\"non-scaling-stroke\" />\r\n <path [attr.d]=\"chart.area\" [attr.fill]=\"chart.color\" fill-opacity=\"0.25\" />\r\n <path [attr.d]=\"chart.line\" [attr.stroke]=\"chart.color\" fill=\"none\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\" />\r\n </svg>\r\n <span class=\"pv2-chart-last\" [style.left.%]=\"chart.lastX\" [style.top.%]=\"chart.lastY\" [style.background]=\"chart.color\"></span>\r\n </div>\r\n <span></span>\r\n <div class=\"pv2-chart-x\">\r\n <span>{{chart.start}}</span>\r\n <span>{{chart.middle}}</span>\r\n <span>{{chart.end}}</span>\r\n </div>\r\n </div>\r\n <div class=\"pv2-caption\">\r\n {{'Media' | localize: lc}} {{axisValue(chart.average)}} &middot; {{'picco' | localize: lc}} {{axisValue(chart.peak)}} {{'sessioni' | localize: lc}}.\r\n {{chart.points | pv2fmt: 'int'}} {{\"punti dell'API\" | localize: lc}},\r\n @if (chart.interval == 1) {\r\n {{'uno al secondo' | localize: lc}},\r\n } @else {\r\n {{'uno ogni' | localize: lc}} {{chart.interval}} s,\r\n }\r\n {{'raggruppati a' | localize: lc}} {{chart.group}} s\r\n </div>\r\n } @else {\r\n <div class=\"pv2-muted pv2-small\">{{'Nessun campione in memoria per questa finestra: il grafico copre solo le ultime due ore circa.' | localize: lc}}</div>\r\n }\r\n\r\n @if (detail.instances?.length) {\r\n <div class=\"pv2-d-title\">{{'Per istanza' | localize: lc}}</div>\r\n <table class=\"pv2-mini\">\r\n <thead>\r\n <tr>\r\n <th>{{'Istanza' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Esecuzioni' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Tempo' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Proprio' | localize: lc}}</th>\r\n @if (live) {\r\n <th class=\"pv2-num\">{{'Thread' | localize: lc}}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (inst of detail.instances; track inst.instanceId) {\r\n <tr>\r\n <td><span class=\"pv2-ellipsis\" [title]=\"inst.instanceId\">{{inst.instanceId}}</span></td>\r\n <td class=\"pv2-num\">{{inst.executions | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{inst.elapsedTime | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{inst.elapsedTimeLessChildren | pv2fmt: 'dur'}}</td>\r\n @if (live) {\r\n <td class=\"pv2-num\">{{inst.activeThreads ?? '\u2014'}}</td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n <div class=\"pv2-d-foot\">\r\n <span class=\"pv2-muted\">{{detail.numChildren | pv2fmt: 'int'}} {{'figli diretti' | localize: lc}} &middot; {{detail.numDescendants | pv2fmt: 'int'}} {{'discendenti' | localize: lc}}</span>\r\n <button type=\"button\" class=\"pv2-btn\" (click)=\"setRoot(detail.nodeId)\"><i class=\"fa fa-sitemap\"></i> {{'Apri come radice' | localize: lc}}</button>\r\n </div>\r\n }\r\n </aside>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: ["@charset \"UTF-8\";:host{display:block}:host ::ng-deep .pv2-noclear .p-select-clear-icon{display:none}.pv2-body{container-type:inline-size}.pv2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;padding-top:6px}.pv2-cluster{display:flex;flex-wrap:nowrap;align-items:center;gap:10px}.pv2-cluster-end{margin-left:auto}.pv2-field{width:190px}.pv2-field-wide{width:290px}.pv2-field-narrow{width:140px}.pv2-field-search{flex:1 1 220px;min-width:200px;max-width:340px}.pv2-toggle{display:flex;align-items:center;gap:8px;height:39px;white-space:nowrap}.pv2-pointer{cursor:pointer}.pv2-group{position:relative;display:inline-flex}.pv2-group.pv2-disabled{opacity:.5}.pv2-group-label{position:absolute;top:-8px;left:8px;z-index:1;padding:0 4px;background:var(--p-content-background, #fff);color:var(--p-text-muted-color, #64748b);font-size:12px;line-height:15px;white-space:nowrap;pointer-events:none}.pv2-seg{display:inline-flex;height:39px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden;background:var(--p-content-background, #fff)}.pv2-seg button{display:inline-flex;align-items:center;gap:6px;padding:0 12px;border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;color:var(--p-text-color, #334155);font-size:13px;white-space:nowrap;cursor:pointer}.pv2-seg button:first-child{border-left:0}.pv2-seg button:hover:not(.pv2-on):not(:disabled){background:var(--p-content-hover-background, #f8fafc)}.pv2-seg button:disabled{cursor:default}.pv2-seg button:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:-2px}.pv2-seg button.pv2-on{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca);font-weight:500;box-shadow:inset 0 -2px 0 var(--p-primary-color, #6366f1)}.pv2-live-dot{width:8px;height:8px;border-radius:50%;background:#16a34a}.pv2-window{display:flex;flex-wrap:wrap;align-items:center;row-gap:4px;margin-top:12px;padding:7px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-color, #334155);font-size:13px}.pv2-window>span+span:before{content:\"\\b7\";margin:0 10px;color:var(--p-text-muted-color, #64748b)}.pv2-warn-text{color:#92400e}.pv2-main{display:grid;grid-template-columns:minmax(0,1fr) 380px;gap:14px;align-items:start;margin-top:14px}@container (max-width: 1350px){.pv2-main{grid-template-columns:minmax(0,1fr)}.pv2-detail{position:static;max-height:none}}.pv2-panel{padding:12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);min-width:0}.pv2-view-bar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px;padding-top:6px;margin-bottom:10px}.pv2-crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;margin-bottom:8px;font-size:12px}.pv2-crumb{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:2px 6px;border:0;border-radius:4px;background:transparent;color:var(--p-primary-color, #6366f1);cursor:pointer}.pv2-crumb:hover{background:var(--p-highlight-background, #eef2ff)}.pv2-crumb-current{color:var(--p-text-color, #334155);font-weight:500;cursor:default}.pv2-crumb-current:hover{background:transparent}.pv2-crumb-sep{color:var(--p-text-muted-color, #64748b)}.pv2-alert{position:relative;margin-bottom:8px;padding:6px 30px 6px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-size:13px}.pv2-alert.pv2-alert-warn{border-color:#fcd34d;background:#fffbeb;color:#92400e}.pv2-alert.pv2-alert-error{border-color:#fca5a5;background:#fef2f2;color:#991b1b}.pv2-alert-close{position:absolute;top:3px;right:6px;border:0;background:transparent;color:inherit;font-size:16px;cursor:pointer}.pv2-table-wrap{max-height:68vh;overflow:auto;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px)}.pv2-table-wrap:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:1px}.pv2-table{width:100%;border-collapse:separate;border-spacing:0;font-size:13px;color:var(--p-text-color, #334155)}.pv2-table th{position:sticky;top:0;z-index:1;padding:7px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-muted-color, #64748b);font-size:12px;font-weight:500;white-space:nowrap;text-align:left}.pv2-table td{padding:4px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);white-space:nowrap;vertical-align:middle}.pv2-col-node{width:100%;max-width:0}.pv2-col-node .pv2-node{min-width:260px}.pv2-num{text-align:right!important;font-variant-numeric:tabular-nums}.pv2-row{cursor:pointer}.pv2-row:hover td{background:var(--p-content-hover-background, #f8fafc)}.pv2-row.pv2-selected td{background:var(--p-highlight-background, #eef2ff)}.pv2-row.pv2-idle td{color:var(--p-text-muted-color, #64748b)}.pv2-row.pv2-idle td .pv2-name{opacity:.75}.pv2-node{display:flex;align-items:center;gap:6px;min-width:0}.pv2-caret{flex:none;width:18px;height:20px;padding:0;border:0;background:transparent;color:var(--p-text-muted-color, #64748b);text-align:center;cursor:pointer}.pv2-type{flex:none;display:inline-flex;align-items:center;gap:5px;padding:0 6px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:10px;color:var(--p-text-muted-color, #64748b);font-size:11px;line-height:18px;white-space:nowrap}.pv2-dot{flex:none;display:inline-block;width:8px;height:8px;border-radius:50%}.pv2-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pv2-name mark{padding:0 1px;border-radius:2px;background:#fde68a;color:#1f2937}.pv2-perc{width:1%}.pv2-perc-cell{display:flex;align-items:center;gap:8px}.pv2-bar{flex:none;width:64px;height:7px;border-radius:2px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc);box-shadow:inset 0 0 0 1px var(--p-content-border-color, #e2e8f0)}.pv2-bar>div{height:100%}.pv2-threads>*+*{margin-left:8px}.pv2-active{display:inline-flex;align-items:center;gap:5px;font-weight:500}.pv2-active-dot{width:7px;height:7px;border-radius:50%;background:#16a34a;box-shadow:0 0 0 3px #16a34a2e}.pv2-long{display:inline-flex;align-items:center;gap:4px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:18px;white-space:nowrap}.pv2-service td{padding:5px 10px;color:var(--p-text-muted-color, #64748b);font-size:12px;background:var(--p-content-background, #fff)}.pv2-sub td{padding:8px 10px 10px 34px;background:var(--p-content-hover-background, #f8fafc);white-space:normal}.pv2-sub-title{margin-bottom:4px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-sub-item{display:flex;align-items:center;gap:10px;padding:2px 0}.pv2-sub-item code{font-size:12px}.pv2-link{margin-left:6px;padding:0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;cursor:pointer}.pv2-link:hover{text-decoration:underline}.pv2-empty{padding:28px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-footer{margin-top:8px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-muted{color:var(--p-text-muted-color, #64748b)}.pv2-small{font-size:12px}.pv2-detail{position:sticky;top:10px;max-height:calc(100vh - 20px);overflow:auto;font-size:13px;color:var(--p-text-color, #334155);transition:opacity .15s}.pv2-detail.pv2-stale{opacity:.55}.pv2-placeholder{padding:36px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-error-text{color:#dc2626}.pv2-d-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.pv2-fullname{max-height:140px;overflow:auto;padding:8px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-family:ui-monospace,Cascadia Mono,Consolas,monospace;font-size:12px;white-space:pre-wrap;word-break:break-word}.pv2-id{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-id code{font-size:12px}.pv2-d-title{margin:16px 0 6px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}.pv2-path{display:flex;flex-direction:column}.pv2-path-item{display:flex;align-items:center;gap:6px;max-width:100%;padding:2px 0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.pv2-path-item:hover{text-decoration:underline}.pv2-path-current{color:var(--p-text-color, #334155);font-weight:600;cursor:default}.pv2-path-current:hover{text-decoration:none}.pv2-kv{display:grid;grid-template-columns:auto 1fr;gap:3px 14px;margin:0}.pv2-kv dt{color:var(--p-text-muted-color, #64748b);font-weight:400}.pv2-kv dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}.pv2-stack{display:flex;height:12px;border-radius:3px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc)}.pv2-legend{display:flex;flex-wrap:wrap;gap:4px 12px;margin-top:6px;font-size:12px}.pv2-legend-item{display:inline-flex;align-items:center;gap:5px}.pv2-swatch{width:10px;height:10px;border-radius:2px}.pv2-chart{display:grid;grid-template-columns:auto 1fr;gap:2px 6px}.pv2-chart-y{display:flex;flex-direction:column;justify-content:space-between;height:110px;color:var(--p-text-muted-color, #64748b);font-size:11px;text-align:right;line-height:1}.pv2-chart-plot{position:relative;height:110px;border-left:1px solid var(--p-content-border-color, #e2e8f0);border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-chart-plot svg{display:block;width:100%;height:100%}.pv2-chart-grid{stroke:var(--p-content-border-color, #e2e8f0);stroke-dasharray:3 3}.pv2-chart-last{position:absolute;width:8px;height:8px;border:2px solid var(--p-content-background, #fff);border-radius:50%;transform:translate(-50%,-50%)}.pv2-chart-x{display:flex;justify-content:space-between;color:var(--p-text-muted-color, #64748b);font-size:11px}.pv2-caption{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-mini{width:100%;font-size:12px}.pv2-mini th{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-weight:500}.pv2-mini td{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-ellipsis{display:inline-block;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.pv2-d-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px;margin-top:16px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);color:var(--p-text-color, #334155);font-size:13px;cursor:pointer}.pv2-btn:hover{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca)}\n"], dependencies: [{ kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i9.EsFormInputComponent, selector: "form-input", inputs: ["minlength", "maxlength", "pattern", "Password", "Type"] }, { kind: "component", type: i9.EsFormSelectComponent, selector: "form-select", inputs: ["OptionsTemplate"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }, { kind: "pipe", type: ProfilerFormatPipe, name: "pv2fmt" }] }); }
2794
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerV2Component, deps: [{ token: i1$1.DateService }, { token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: i4.Router }, { token: i5.Location }, { token: AdminModuleBaseService }, { token: ADM_MODULE_PATH }, { token: ADM_WORKLOAD_V2, optional: true }, { token: ADM_DETAILS_V2, optional: true }, { token: ADM_TOPACT_V2, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
2795
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmProfilerV2Component, isStandalone: false, selector: "profiler_v2", providers: [{ provide: LocalizationService, useClass: AdmProfilerV2Loc }], viewQueries: [{ propertyName: "dlgDetailsV2", first: true, predicate: ["dlgDetailsV2"], descendants: true }, { propertyName: "detailsV2", first: true, predicate: AdmDetailsV2Component, descendants: true }], ngImport: i0, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span>\r\n </div>\r\n <div class=\"card-body widget-body pv2-body\">\r\n <!-- Barra dei comandi: quali dati caricare. Ogni cambio ricarica la vista e il dettaglio aperto -->\r\n <div class=\"pv2-toolbar\">\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Sorgente' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"live\" (click)=\"setLive(true)\"><span class=\"pv2-live-dot\"></span>Live</button>\r\n <button type=\"button\" [class.pv2-on]=\"!live\" (click)=\"setLive(false)\">{{'Storico' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n <div class=\"pv2-field pv2-field-wide pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"instance\" (ngModelChange)=\"setInstance($event)\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanze' | localize: lc\"></form-select>\r\n </div>\r\n </div>\r\n\r\n @if (!live) {\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterfrom\" (ngModelChange)=\"filterfrom = $event; datesChanged()\" name=\"filterfrom\" [Placeholder]=\"'Dal' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterto\" (ngModelChange)=\"filterto = $event; datesChanged()\" name=\"filterto\" [Placeholder]=\"'Al' | localize: lc\"></form-datetime>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Valori' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"!snapValues\" (click)=\"setSnapValues(false)\">{{\"Dall'avvio\" | localize: lc}}</button>\r\n <button type=\"button\" [class.pv2-on]=\"snapValues\" (click)=\"setSnapValues(true)\">{{\"Dall'ultimo snapshot\" | localize: lc}}</button>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"pv2-cluster pv2-cluster-end\">\r\n <button type=\"button\" class=\"btn app-btn-search\" [disabled]=\"loading\" (click)=\"reloadAll()\" [title]=\"'Aggiorna' | localize: lc\">\r\n <i class=\"fa fa-refresh\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n <button type=\"button\" class=\"btn app-btn-search\" (click)=\"downloadWorkloadReport()\" [title]=\"(workloadV2 ? 'Workload report' : 'Scarica il workload report') | localize: lc\">\r\n <i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Riga della finestra: sempre visibile sopra la vista -->\r\n <div class=\"pv2-window\">\r\n <span><strong>{{live ? 'Live' : ('Storico' | localize: lc)}}</strong> &middot; {{instanceLabel}}</span>\r\n @if (current?.snapFrom; as snapFrom) {\r\n @if (live) {\r\n <span>{{\"Delta dall'ultimo snapshot delle\" | localize: lc}} {{hhmm(snapFrom)}} ({{minutesAgo(snapFrom)}} {{'min fa' | localize: lc}})</span>\r\n } @else {\r\n <span>{{'Snapshot dalle' | localize: lc}} {{ddmmhhmm(snapFrom)}} {{'alle' | localize: lc}} {{ddmmhhmm(current?.snapTo)}}</span>\r\n }\r\n } @else if (current && !live) {\r\n <span class=\"pv2-warn-text\">{{'Nessuno snapshot termina nella finestra scelta' | localize: lc}}</span>\r\n }\r\n @if (view == 'tree' && tree?.idleNode) {\r\n <span>{{tree.numNodes | pv2fmt: 'int'}} {{\"nodi nell'albero\" | localize: lc}} &middot; {{tree.numReturnedNodes | pv2fmt: 'int'}} {{'nella risposta' | localize: lc}}</span>\r\n }\r\n @if (view == 'flat' && flat) {\r\n <span>{{flat.numItems | pv2fmt: 'int'}} {{'eventi distinti' | localize: lc}}</span>\r\n }\r\n @if (loading) {\r\n <span class=\"pv2-muted\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Caricamento\u2026' | localize: lc}}</span>\r\n }\r\n </div>\r\n\r\n <div class=\"pv2-main\">\r\n <!-- Vista: albero o eventi per nome -->\r\n <div class=\"pv2-panel pv2-view\">\r\n <div class=\"pv2-view-bar\">\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"view == 'tree'\" (click)=\"setView('tree')\"><i class=\"fa fa-sitemap\"></i> {{'Albero' | localize: lc}}</button>\r\n <button type=\"button\" [class.pv2-on]=\"view == 'flat'\" (click)=\"setView('flat')\"><i class=\"fa fa-list\"></i> {{'Per nome' | localize: lc}}</button>\r\n </div>\r\n\r\n @if (view == 'tree') {\r\n <div class=\"pv2-field pv2-field-search\" [title]=\"'Per esempio MRD_METERREADINGS, ENQUEUE, ProfilesMgr' | localize: lc\">\r\n <form-input [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"searchText\" (ngModelChange)=\"searchText = $event; searchChanged()\" name=\"search\" [Placeholder]=\"'Cerca nei nomi o per id' | localize: lc\"></form-input>\r\n </div>\r\n <div class=\"pv2-field pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"orderBy\" (ngModelChange)=\"setOrderBy($event)\" name=\"orderBy\" [Source]=\"TreeOrderOptions\" [Placeholder]=\"'Ordina per' | localize: lc\"></form-select>\r\n </div>\r\n <div class=\"pv2-group\" [class.pv2-disabled]=\"!!activeSearch\">\r\n <span class=\"pv2-group-label\">{{'Figli per nodo' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n @for (o of ChildrenOptions; track o.id) {\r\n <button type=\"button\" [disabled]=\"!!activeSearch\" [class.pv2-on]=\"maxChildren == o.id\" (click)=\"setMaxChildren(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"pv2-group\" [class.pv2-disabled]=\"!!activeSearch\">\r\n <span class=\"pv2-group-label\">{{'Soglia' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n @for (o of ThresholdOptions; track o.id) {\r\n <button type=\"button\" [disabled]=\"!!activeSearch\" [class.pv2-on]=\"minPercentage == o.id\" (click)=\"setMinPercentage(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"pv2-field pv2-field-search\">\r\n <form-input [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"flatSearch\" (ngModelChange)=\"flatSearch = $event; flatSearchChanged()\" name=\"flatSearch\" [Placeholder]=\"'Cerca nei nomi' | localize: lc\"></form-input>\r\n </div>\r\n <div class=\"pv2-field pv2-field-narrow pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"flatType\" (ngModelChange)=\"flatType = $event; flatChanged()\" name=\"flatType\" [Source]=\"FlatTypes\" [Placeholder]=\"'Tipo' | localize: lc\"></form-select>\r\n </div>\r\n <div class=\"pv2-field pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"flatOrderBy\" (ngModelChange)=\"flatOrderBy = $event; flatChanged()\" name=\"flatOrderBy\" [Source]=\"FlatOrderOptions\" [Placeholder]=\"'Ordina per' | localize: lc\"></form-select>\r\n </div>\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Righe' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n @for (o of FlatRows; track o.id) {\r\n <button type=\"button\" [class.pv2-on]=\"flatTop == o.id\" (click)=\"setFlatTop(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"pv2-toggle\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [ngModel]=\"flatIncludeIdle\" (ngModelChange)=\"flatIncludeIdle = $event; flatChanged()\" name=\"flatIncludeIdle\"></form-checkbox>\r\n <span class=\"pv2-pointer\" (click)=\"flatIncludeIdle = !flatIncludeIdle; flatChanged()\">{{'Anche gli eventi idle' | localize: lc}}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (view == 'tree') {\r\n <!-- Percorso della radice: ogni antenato riporta l'albero a quel nodo -->\r\n @if (tree?.idleNode && tree?.rootPath?.length) {\r\n <nav class=\"pv2-crumbs\">\r\n @for (item of tree.rootPath; track item.nodeId) {\r\n <button type=\"button\" class=\"pv2-crumb\" [title]=\"item.nodeName\" (click)=\"setRoot(item.nodeId)\">{{item.nodeName}}</button>\r\n <span class=\"pv2-crumb-sep\">&rsaquo;</span>\r\n }\r\n <span class=\"pv2-crumb pv2-crumb-current\" [title]=\"tree.idleNode.nodeName\">{{tree.idleNode.nodeName}}</span>\r\n </nav>\r\n }\r\n\r\n @if (treeNotice) {\r\n <div class=\"pv2-alert pv2-alert-warn\">\r\n {{treeNotice}}\r\n <button type=\"button\" class=\"pv2-alert-close\" [title]=\"'Chiudi' | localize: lc\" (click)=\"treeNotice = null\">&times;</button>\r\n </div>\r\n }\r\n @if (activeSearch && tree) {\r\n @if (matchCount > 0) {\r\n <div class=\"pv2-alert\" [class.pv2-alert-warn]=\"tree.truncated\">\r\n {{matchCount | pv2fmt: 'int'}} {{'nodi trovati, con i loro antenati.' | localize: lc}}\r\n @if (tree.truncated) {\r\n <strong>{{'I nodi trovati sono pi\u00F9 di 1.000: sono mostrati i primi per l\\'ordinamento scelto.' | localize: lc}}</strong>\r\n }\r\n </div>\r\n } @else if (!treeLoading) {\r\n <div class=\"pv2-alert\">{{'Nessun nodo contiene' | localize: lc}} &laquo;{{activeSearch}}&raquo;.</div>\r\n }\r\n }\r\n @if (treeError) {\r\n <div class=\"pv2-alert pv2-alert-error\">{{treeError}}</div>\r\n }\r\n\r\n <div class=\"pv2-table-wrap\" tabindex=\"0\" (keydown)=\"treeKeydown($event)\">\r\n <table class=\"pv2-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"pv2-col-node\">{{'Nodo' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Chiamate' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Tempo' | localize: lc}}</th>\r\n <th>{{snapMode ? '\u0394 ' : ''}}{{'% del padre' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{(snapMode ? '\u0394 Proprio' : 'Tempo proprio') | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Medio' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Picco' | localize: lc}}</th>\r\n @if (live) {\r\n <th class=\"pv2-num\">{{'Thread ora' | localize: lc}}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of rows; track row.key) {\r\n @if (row.kind == 'node') {\r\n <tr [id]=\"'pv2-row-' + row.node.nodeId\" class=\"pv2-row\"\r\n [class.pv2-selected]=\"row.node.nodeId == selectedId\"\r\n [class.pv2-idle]=\"isIdle(row.node.eventTypeName, row.node.waitClassName)\"\r\n (click)=\"rowClicked(row.node)\" (dblclick)=\"toggle(row.node)\">\r\n <td class=\"pv2-col-node\">\r\n <div class=\"pv2-node\" [style.padding-left.px]=\"row.depth * 16\">\r\n @if (hasChildren(row.node)) {\r\n <button type=\"button\" class=\"pv2-caret\" tabindex=\"-1\" [attr.aria-expanded]=\"isExpanded(row.node)\" (click)=\"toggle(row.node, $event)\">\r\n <i class=\"fa\" [class.fa-caret-down]=\"isExpanded(row.node)\" [class.fa-caret-right]=\"!isExpanded(row.node)\"></i>\r\n </button>\r\n } @else {\r\n <span class=\"pv2-caret\"></span>\r\n }\r\n <span class=\"pv2-type\"><span class=\"pv2-dot\" [style.background]=\"typeColor(row.node.eventTypeName, row.node.waitClassName)\"></span>{{typeLabel(row.node.eventTypeName, row.node.waitClassName)}}</span>\r\n <span class=\"pv2-name\" [title]=\"row.node.nodeName\">@if (row.node.searchMatch && activeSearch) {@for (part of nameParts(row.node.nodeName, activeSearch); track $index) {@if (part.hit) {<mark>{{part.text}}</mark>} @else {<span>{{part.text}}</span>}}} @else {<span>{{row.node.nodeName}}</span>}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{calls(row.node) | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{time(row.node) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-perc\" [title]=\"(parentPerc(row.node) | pv2fmt: 'pct') + ' ' + ('del padre' | localize: lc) + ' \u00B7 ' + (firstLevelPerc(row.node) | pv2fmt: 'pct') + ' ' + ('del nodo di primo livello' | localize: lc)\">\r\n <div class=\"pv2-perc-cell\">\r\n <div class=\"pv2-bar\"><div [style.width.%]=\"parentPerc(row.node)\" [style.background]=\"typeColor(row.node.eventTypeName, row.node.waitClassName)\"></div></div>\r\n <span>{{parentPerc(row.node) | pv2fmt: 'pct'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{self(row.node) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{avg(row.node) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{peak(row.node) | pv2fmt: 'dur'}}</td>\r\n @if (live) {\r\n <td class=\"pv2-num pv2-threads\">\r\n @if (isLongRunning(row.node.eventTypeName, row.node.waitClassName, row.node.activeMaxTime)) {\r\n <span class=\"pv2-long\" [title]=\"('Esecuzione in corso da' | localize: lc) + ' ' + duration(row.node.activeMaxTime) + ': ' + ('forse bloccata' | localize: lc)\"><i class=\"fa fa-clock\"></i> {{duration(row.node.activeMaxTime)}}</span>\r\n }\r\n @if (row.node.activeThreads > 0) {\r\n <span class=\"pv2-active\"><span class=\"pv2-active-dot\"></span>{{row.node.activeThreads}}</span>\r\n } @else {\r\n <span class=\"pv2-muted\">{{row.node.activeThreads ?? '\u2014'}}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n } @else if (row.kind == 'loading') {\r\n <tr class=\"pv2-service\">\r\n <td [attr.colspan]=\"live ? 8 : 7\">\r\n <div [style.padding-left.px]=\"row.depth * 16 + 24\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Caricamento dei figli\u2026' | localize: lc}}</div>\r\n </td>\r\n </tr>\r\n } @else {\r\n <tr class=\"pv2-service\">\r\n <td [attr.colspan]=\"live ? 8 : 7\">\r\n <div [style.padding-left.px]=\"row.depth * 16 + 24\">\r\n {{row.node.omittedChildren | pv2fmt: 'int'}} {{'figli non mostrati' | localize: lc}} &middot; {{omittedTime(row.node) | pv2fmt: 'dur'}}\r\n @if (!snapMode) {\r\n &middot; {{row.node.omittedCalls | pv2fmt: 'int'}} {{'chiamate' | localize: lc}}\r\n }\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"showAll(row.node, $event)\">{{'Mostra tutti' | localize: lc}}</button>\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n @if (rows.length == 0 && !treeError) {\r\n <div class=\"pv2-empty\">\r\n @if (!tree) {\r\n {{'Caricamento\u2026' | localize: lc}}\r\n } @else if (!tree.snapFrom && !live) {\r\n {{'Nessuno snapshot termina nella finestra scelta: allargala o spostala indietro.' | localize: lc}}\r\n } @else {\r\n {{\"Il nodo non c'\u00E8 nelle istanze scelte.\" | localize: lc}}\r\n }\r\n </div>\r\n }\r\n </div>\r\n } @else {\r\n @if (flatError) {\r\n <div class=\"pv2-alert pv2-alert-error\">{{flatError}}</div>\r\n }\r\n <div class=\"pv2-table-wrap\">\r\n <table class=\"pv2-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"pv2-col-node\">{{'Evento' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Percorsi' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Chiamate' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{(snapMode ? '\u0394 Proprio' : 'Tempo proprio') | localize: lc}}</th>\r\n <th>{{snapMode ? '\u0394 ' : ''}}{{'% proprio' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Tempo' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Medio' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{(snapMode ? \"Picco dall'avvio\" : 'Picco') | localize: lc}}</th>\r\n @if (live) {\r\n <th class=\"pv2-num\">{{'Thread' | localize: lc}}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (item of flat?.items ?? []; track flatKey(item)) {\r\n <tr class=\"pv2-row\" [class.pv2-idle]=\"isIdle(item.eventTypeName, item.waitClassName)\" [class.pv2-selected]=\"openFlat.has(flatKey(item))\" (click)=\"toggleFlat(item)\">\r\n <td class=\"pv2-col-node\">\r\n <div class=\"pv2-node\">\r\n <span class=\"pv2-caret\"><i class=\"fa\" [class.fa-caret-down]=\"openFlat.has(flatKey(item))\" [class.fa-caret-right]=\"!openFlat.has(flatKey(item))\"></i></span>\r\n <span class=\"pv2-type\"><span class=\"pv2-dot\" [style.background]=\"typeColor(item.eventTypeName, item.waitClassName)\"></span>{{typeLabel(item.eventTypeName, item.waitClassName)}}</span>\r\n <span class=\"pv2-name\" [title]=\"item.nodeName\">@for (part of nameParts(item.nodeName, (flatSearch ?? '').trim()); track $index) {@if (part.hit) {<mark>{{part.text}}</mark>} @else {<span>{{part.text}}</span>}}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{item.numPaths | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{flatCalls(item) | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{flatSelf(item) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-perc\">\r\n <div class=\"pv2-perc-cell\">\r\n <div class=\"pv2-bar\"><div [style.width.%]=\"flatPerc(item)\" [style.background]=\"typeColor(item.eventTypeName, item.waitClassName)\"></div></div>\r\n <span>{{flatPerc(item) | pv2fmt: 'pct'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{flatTime(item) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{flatAvg(item) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{item.peakTime | pv2fmt: 'dur'}}</td>\r\n @if (live) {\r\n <td class=\"pv2-num pv2-threads\">\r\n @if (item.activeThreads > 0) {\r\n <span class=\"pv2-active\"><span class=\"pv2-active-dot\"></span>{{item.activeThreads}}</span>\r\n } @else {\r\n <span class=\"pv2-muted\">{{item.activeThreads ?? '\u2014'}}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n @if (openFlat.has(flatKey(item))) {\r\n <tr class=\"pv2-sub\">\r\n <td [attr.colspan]=\"live ? 9 : 8\">\r\n <div class=\"pv2-sub-title\">{{'Nodi con pi\u00F9 tempo' | localize: lc}}</div>\r\n @for (id of item.nodeIds ?? []; track id) {\r\n <div class=\"pv2-sub-item\">\r\n <code>{{id}}</code>\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"showDetail(id, $event)\">{{'Dettaglio' | localize: lc}}</button>\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"openInTree(id, $event)\">{{\"Apri nell'albero\" | localize: lc}}</button>\r\n </div>\r\n }\r\n @if (item.numPaths > (item.nodeIds?.length ?? 0)) {\r\n <div class=\"pv2-muted\">+{{item.numPaths - (item.nodeIds?.length ?? 0) | pv2fmt: 'int'}} {{'altri' | localize: lc}}</div>\r\n }\r\n </td>\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n @if (!flatError && (!flat || !flat.items?.length)) {\r\n <div class=\"pv2-empty\">{{(flat ? 'Nessun evento con questi filtri.' : 'Caricamento\u2026') | localize: lc}}</div>\r\n }\r\n </div>\r\n @if (flat?.items?.length) {\r\n <div class=\"pv2-footer\">\r\n {{flat.numItems | pv2fmt: 'int'}} {{'eventi distinti' | localize: lc}}@if (flat.numItems > flat.items.length) {, {{'mostrati i primi' | localize: lc}} {{flat.items.length | pv2fmt: 'int'}}}.\r\n {{'La percentuale \u00E8 sul tempo proprio di tutti gli eventi non idle.' | localize: lc}}\r\n </div>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Dettaglio del nodo selezionato, lo stesso per le due viste -->\r\n <aside class=\"pv2-panel pv2-detail\" [class.pv2-stale]=\"detailStale\">\r\n @if (!selectedId) {\r\n <div class=\"pv2-placeholder\">{{'Seleziona un nodo per vederne il dettaglio.' | localize: lc}}</div>\r\n } @else if (detailMissing && !detailLoading) {\r\n <div class=\"pv2-placeholder\">{{\"Il nodo non c'\u00E8 nelle istanze o nella finestra scelte.\" | localize: lc}}</div>\r\n } @else if (detailError && !detailLoading) {\r\n <div class=\"pv2-placeholder pv2-error-text\">{{detailError}}</div>\r\n } @else if (!detail) {\r\n <div class=\"pv2-placeholder\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Caricamento\u2026' | localize: lc}}</div>\r\n } @else {\r\n <div class=\"pv2-d-head\">\r\n <span class=\"pv2-type\"><span class=\"pv2-dot\" [style.background]=\"typeColor(detail.eventTypeName, detail.waitClassName)\"></span>{{typeLabel(detail.eventTypeName, detail.waitClassName)}}</span>\r\n @if (detailLoading) {\r\n <i class=\"fa fa-spinner fa-spin pv2-muted\"></i>\r\n }\r\n </div>\r\n <div class=\"pv2-fullname\">{{detail.nodeName}}</div>\r\n <div class=\"pv2-id\">\r\n Id <code #idText>{{detail.nodeId}}</code>\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"copyId(idText)\">{{(copied ? 'Copiato' : 'Copia') | localize: lc}}</button>\r\n @if (detailsV2Enabled) {\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"openFullDetail()\">{{'Dettaglio completo' | localize: lc}}</button>\r\n }\r\n </div>\r\n\r\n <div class=\"pv2-d-title\">{{'Percorso' | localize: lc}}</div>\r\n <div class=\"pv2-path\">\r\n @for (item of detail.fullWaitStack ?? []; track item.nodeId; let i = $index) {\r\n <button type=\"button\" class=\"pv2-path-item\" [style.padding-left.px]=\"i * 10\" [title]=\"item.nodeName\" (click)=\"select(item.nodeId)\">\r\n <span class=\"pv2-dot\" [style.background]=\"typeColor(item.eventTypeName, item.waitClassName)\"></span>{{item.nodeName}}\r\n </button>\r\n }\r\n <div class=\"pv2-path-item pv2-path-current\" [style.padding-left.px]=\"(detail.fullWaitStack?.length ?? 0) * 10\" [title]=\"detail.nodeName\">\r\n <span class=\"pv2-dot\" [style.background]=\"typeColor(detail.eventTypeName, detail.waitClassName)\"></span>{{detail.nodeName}}\r\n </div>\r\n </div>\r\n\r\n <div class=\"pv2-d-title\">{{(live ? \"Dall'avvio\" : 'Nella finestra') | localize: lc}}</div>\r\n <dl class=\"pv2-kv\">\r\n <dt>{{'Esecuzioni' | localize: lc}}</dt><dd>{{detail.executions | pv2fmt: 'int'}}</dd>\r\n <dt>{{'Tempo totale' | localize: lc}}</dt><dd>{{detail.elapsedTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Tempo proprio' | localize: lc}}</dt><dd>{{detail.elapsedTimeLessChildren | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Medio' | localize: lc}}</dt><dd>{{detail.avgTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Picco' | localize: lc}}</dt><dd>{{detail.peakTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Minimo' | localize: lc}}</dt><dd>{{detail.minTime ? (detail.minTime | pv2fmt: 'dur') : '\u2014'}}</dd>\r\n </dl>\r\n\r\n @if (live) {\r\n <div class=\"pv2-d-title\">{{\"Dall'ultimo snapshot\" | localize: lc}}, {{hhmm(detail.snapFrom)}}</div>\r\n <dl class=\"pv2-kv\">\r\n <dt>{{'Esecuzioni' | localize: lc}}</dt><dd>{{detail.snapDeltaExecutions | pv2fmt: 'int'}}</dd>\r\n <dt>{{'Tempo totale' | localize: lc}}</dt><dd>{{detail.snapDeltaElapsedTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Tempo proprio' | localize: lc}}</dt><dd>{{detail.snapDeltaElapsedTimeLessChildren | pv2fmt: 'dur'}}</dd>\r\n </dl>\r\n\r\n <div class=\"pv2-d-title\">{{'Adesso' | localize: lc}}</div>\r\n <dl class=\"pv2-kv\">\r\n <dt>{{'Thread dentro' | localize: lc}}</dt>\r\n <dd>\r\n @if (detail.activeThreads > 0) {\r\n <span class=\"pv2-active\"><span class=\"pv2-active-dot\"></span>{{detail.activeThreads}}</span>\r\n } @else {\r\n {{detail.activeThreads ?? '\u2014'}}\r\n }\r\n </dd>\r\n <dt>{{'Esecuzione pi\u00F9 lunga' | localize: lc}}</dt>\r\n <dd>\r\n @if (detail.activeThreads > 0) {\r\n {{detail.activeMaxTime | pv2fmt: 'dur'}}\r\n @if (isLongRunning(detail.eventTypeName, detail.waitClassName, detail.activeMaxTime)) {\r\n <span class=\"pv2-long\"><i class=\"fa fa-clock\"></i> {{'forse bloccata' | localize: lc}}</span>\r\n }\r\n } @else {\r\n \u2014\r\n }\r\n </dd>\r\n <dt>{{'Ultima uscita' | localize: lc}}</dt><dd>{{relative(detail.lastExitTime)}}</dd>\r\n </dl>\r\n }\r\n\r\n @if (typeParts.length > 0) {\r\n <div class=\"pv2-d-title\">{{'Tempo proprio del sottoalbero per tipo' | localize: lc}}</div>\r\n <div class=\"pv2-stack\">\r\n @for (part of typeParts; track part.type) {\r\n <div [style.width.%]=\"part.percentage\" [style.background]=\"part.color\" [title]=\"part.label + ' ' + (part.percentage | pv2fmt: 'pct')\"></div>\r\n }\r\n </div>\r\n <div class=\"pv2-legend\">\r\n @for (part of typeParts; track part.type) {\r\n <span class=\"pv2-legend-item\"><span class=\"pv2-swatch\" [style.background]=\"part.color\"></span>{{part.label}} <strong>{{part.percentage | pv2fmt: 'pct'}}</strong></span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"pv2-d-title\">{{'Sessioni attive sul nodo e sui discendenti' | localize: lc}}</div>\r\n @if (chart) {\r\n <div class=\"pv2-chart\">\r\n <div class=\"pv2-chart-y\">\r\n <span>{{axisValue(chart.max)}}</span>\r\n <span>{{axisValue(chart.max / 2)}}</span>\r\n <span>0</span>\r\n </div>\r\n <div class=\"pv2-chart-plot\">\r\n <svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\r\n <line x1=\"0\" y1=\"50\" x2=\"100\" y2=\"50\" class=\"pv2-chart-grid\" vector-effect=\"non-scaling-stroke\" />\r\n <path [attr.d]=\"chart.area\" [attr.fill]=\"chart.color\" fill-opacity=\"0.25\" />\r\n <path [attr.d]=\"chart.line\" [attr.stroke]=\"chart.color\" fill=\"none\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\" />\r\n </svg>\r\n <span class=\"pv2-chart-last\" [style.left.%]=\"chart.lastX\" [style.top.%]=\"chart.lastY\" [style.background]=\"chart.color\"></span>\r\n </div>\r\n <span></span>\r\n <div class=\"pv2-chart-x\">\r\n <span>{{chart.start}}</span>\r\n <span>{{chart.middle}}</span>\r\n <span>{{chart.end}}</span>\r\n </div>\r\n </div>\r\n <div class=\"pv2-caption\">\r\n {{'Media' | localize: lc}} {{axisValue(chart.average)}} &middot; {{'picco' | localize: lc}} {{axisValue(chart.peak)}} {{'sessioni' | localize: lc}}.\r\n {{chart.points | pv2fmt: 'int'}} {{\"punti dell'API\" | localize: lc}},\r\n @if (chart.interval == 1) {\r\n {{'uno al secondo' | localize: lc}},\r\n } @else {\r\n {{'uno ogni' | localize: lc}} {{chart.interval}} s,\r\n }\r\n {{'raggruppati a' | localize: lc}} {{chart.group}} s\r\n </div>\r\n } @else {\r\n <div class=\"pv2-muted pv2-small\">{{'Nessun campione in memoria per questa finestra: il grafico copre solo le ultime due ore circa.' | localize: lc}}</div>\r\n }\r\n\r\n @if (detail.instances?.length) {\r\n <div class=\"pv2-d-title\">{{'Per istanza' | localize: lc}}</div>\r\n <table class=\"pv2-mini\">\r\n <thead>\r\n <tr>\r\n <th>{{'Istanza' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Esecuzioni' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Tempo' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Proprio' | localize: lc}}</th>\r\n @if (live) {\r\n <th class=\"pv2-num\">{{'Thread' | localize: lc}}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (inst of detail.instances; track inst.instanceId) {\r\n <tr>\r\n <td><span class=\"pv2-ellipsis\" [title]=\"inst.instanceId\">{{inst.instanceId}}</span></td>\r\n <td class=\"pv2-num\">{{inst.executions | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{inst.elapsedTime | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{inst.elapsedTimeLessChildren | pv2fmt: 'dur'}}</td>\r\n @if (live) {\r\n <td class=\"pv2-num\">{{inst.activeThreads ?? '\u2014'}}</td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n <div class=\"pv2-d-foot\">\r\n <span class=\"pv2-muted\">{{detail.numChildren | pv2fmt: 'int'}} {{'figli diretti' | localize: lc}} &middot; {{detail.numDescendants | pv2fmt: 'int'}} {{'discendenti' | localize: lc}}</span>\r\n <button type=\"button\" class=\"pv2-btn\" (click)=\"setRoot(detail.nodeId)\"><i class=\"fa fa-sitemap\"></i> {{'Apri come radice' | localize: lc}}</button>\r\n </div>\r\n }\r\n </aside>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Dettaglio completo del nodo (DirectorFeature.DetailsV2) -->\r\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\r\n @if (detailsV2Enabled) {\r\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"!!topActV2Enabled\" [CanOpenProfiler]=\"true\" (closed)=\"dlgDetailsV2.hide()\"\r\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"rootFromDetails($event)\"></adm-details-v2>\r\n }\r\n</div>\r\n", styles: ["@charset \"UTF-8\";:host{display:block}:host ::ng-deep .pv2-noclear .p-select-clear-icon{display:none}.pv2-body{container-type:inline-size}.pv2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;padding-top:6px}.pv2-cluster{display:flex;flex-wrap:nowrap;align-items:center;gap:10px}.pv2-cluster-end{margin-left:auto}.pv2-field{width:190px}.pv2-field-wide{width:290px}.pv2-field-narrow{width:140px}.pv2-field-search{flex:1 1 220px;min-width:200px;max-width:340px}.pv2-toggle{display:flex;align-items:center;gap:8px;height:39px;white-space:nowrap}.pv2-pointer{cursor:pointer}.pv2-group{position:relative;display:inline-flex}.pv2-group.pv2-disabled{opacity:.5}.pv2-group-label{position:absolute;top:-8px;left:8px;z-index:1;padding:0 4px;background:var(--p-content-background, #fff);color:var(--p-text-muted-color, #64748b);font-size:12px;line-height:15px;white-space:nowrap;pointer-events:none}.pv2-seg{display:inline-flex;height:39px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden;background:var(--p-content-background, #fff)}.pv2-seg button{display:inline-flex;align-items:center;gap:6px;padding:0 12px;border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;color:var(--p-text-color, #334155);font-size:13px;white-space:nowrap;cursor:pointer}.pv2-seg button:first-child{border-left:0}.pv2-seg button:hover:not(.pv2-on):not(:disabled){background:var(--p-content-hover-background, #f8fafc)}.pv2-seg button:disabled{cursor:default}.pv2-seg button:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:-2px}.pv2-seg button.pv2-on{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca);font-weight:500;box-shadow:inset 0 -2px 0 var(--p-primary-color, #6366f1)}.pv2-live-dot{width:8px;height:8px;border-radius:50%;background:#16a34a}.pv2-window{display:flex;flex-wrap:wrap;align-items:center;row-gap:4px;margin-top:12px;padding:7px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-color, #334155);font-size:13px}.pv2-window>span+span:before{content:\"\\b7\";margin:0 10px;color:var(--p-text-muted-color, #64748b)}.pv2-warn-text{color:#92400e}.pv2-main{display:grid;grid-template-columns:minmax(0,1fr) 380px;gap:14px;align-items:start;margin-top:14px}@container (max-width: 1350px){.pv2-main{grid-template-columns:minmax(0,1fr)}.pv2-detail{position:static;max-height:none}}.pv2-panel{padding:12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);min-width:0}.pv2-view-bar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px;padding-top:6px;margin-bottom:10px}.pv2-crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;margin-bottom:8px;font-size:12px}.pv2-crumb{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:2px 6px;border:0;border-radius:4px;background:transparent;color:var(--p-primary-color, #6366f1);cursor:pointer}.pv2-crumb:hover{background:var(--p-highlight-background, #eef2ff)}.pv2-crumb-current{color:var(--p-text-color, #334155);font-weight:500;cursor:default}.pv2-crumb-current:hover{background:transparent}.pv2-crumb-sep{color:var(--p-text-muted-color, #64748b)}.pv2-alert{position:relative;margin-bottom:8px;padding:6px 30px 6px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-size:13px}.pv2-alert.pv2-alert-warn{border-color:#fcd34d;background:#fffbeb;color:#92400e}.pv2-alert.pv2-alert-error{border-color:#fca5a5;background:#fef2f2;color:#991b1b}.pv2-alert-close{position:absolute;top:3px;right:6px;border:0;background:transparent;color:inherit;font-size:16px;cursor:pointer}.pv2-table-wrap{max-height:68vh;overflow:auto;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px)}.pv2-table-wrap:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:1px}.pv2-table{width:100%;border-collapse:separate;border-spacing:0;font-size:13px;color:var(--p-text-color, #334155)}.pv2-table th{position:sticky;top:0;z-index:1;padding:7px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-muted-color, #64748b);font-size:12px;font-weight:500;white-space:nowrap;text-align:left}.pv2-table td{padding:4px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);white-space:nowrap;vertical-align:middle}.pv2-col-node{width:100%;max-width:0}.pv2-col-node .pv2-node{min-width:260px}.pv2-num{text-align:right!important;font-variant-numeric:tabular-nums}.pv2-row{cursor:pointer}.pv2-row:hover td{background:var(--p-content-hover-background, #f8fafc)}.pv2-row.pv2-selected td{background:var(--p-highlight-background, #eef2ff)}.pv2-row.pv2-idle td{color:var(--p-text-muted-color, #64748b)}.pv2-row.pv2-idle td .pv2-name{opacity:.75}.pv2-node{display:flex;align-items:center;gap:6px;min-width:0}.pv2-caret{flex:none;width:18px;height:20px;padding:0;border:0;background:transparent;color:var(--p-text-muted-color, #64748b);text-align:center;cursor:pointer}.pv2-type{flex:none;display:inline-flex;align-items:center;gap:5px;padding:0 6px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:10px;color:var(--p-text-muted-color, #64748b);font-size:11px;line-height:18px;white-space:nowrap}.pv2-dot{flex:none;display:inline-block;width:8px;height:8px;border-radius:50%}.pv2-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pv2-name mark{padding:0 1px;border-radius:2px;background:#fde68a;color:#1f2937}.pv2-perc{width:1%}.pv2-perc-cell{display:flex;align-items:center;gap:8px}.pv2-bar{flex:none;width:64px;height:7px;border-radius:2px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc);box-shadow:inset 0 0 0 1px var(--p-content-border-color, #e2e8f0)}.pv2-bar>div{height:100%}.pv2-threads>*+*{margin-left:8px}.pv2-active{display:inline-flex;align-items:center;gap:5px;font-weight:500}.pv2-active-dot{width:7px;height:7px;border-radius:50%;background:#16a34a;box-shadow:0 0 0 3px #16a34a2e}.pv2-long{display:inline-flex;align-items:center;gap:4px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:18px;white-space:nowrap}.pv2-service td{padding:5px 10px;color:var(--p-text-muted-color, #64748b);font-size:12px;background:var(--p-content-background, #fff)}.pv2-sub td{padding:8px 10px 10px 34px;background:var(--p-content-hover-background, #f8fafc);white-space:normal}.pv2-sub-title{margin-bottom:4px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-sub-item{display:flex;align-items:center;gap:10px;padding:2px 0}.pv2-sub-item code{font-size:12px}.pv2-link{margin-left:6px;padding:0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;cursor:pointer}.pv2-link:hover{text-decoration:underline}.pv2-empty{padding:28px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-footer{margin-top:8px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-muted{color:var(--p-text-muted-color, #64748b)}.pv2-small{font-size:12px}.pv2-detail{position:sticky;top:10px;max-height:calc(100vh - 20px);overflow:auto;font-size:13px;color:var(--p-text-color, #334155);transition:opacity .15s}.pv2-detail.pv2-stale{opacity:.55}.pv2-placeholder{padding:36px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-error-text{color:#dc2626}.pv2-d-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.pv2-fullname{max-height:140px;overflow:auto;padding:8px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-family:ui-monospace,Cascadia Mono,Consolas,monospace;font-size:12px;white-space:pre-wrap;word-break:break-word}.pv2-id{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-id code{font-size:12px}.pv2-d-title{margin:16px 0 6px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}.pv2-path{display:flex;flex-direction:column}.pv2-path-item{display:flex;align-items:center;gap:6px;max-width:100%;padding:2px 0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.pv2-path-item:hover{text-decoration:underline}.pv2-path-current{color:var(--p-text-color, #334155);font-weight:600;cursor:default}.pv2-path-current:hover{text-decoration:none}.pv2-kv{display:grid;grid-template-columns:auto 1fr;gap:3px 14px;margin:0}.pv2-kv dt{color:var(--p-text-muted-color, #64748b);font-weight:400}.pv2-kv dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}.pv2-stack{display:flex;height:12px;border-radius:3px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc)}.pv2-legend{display:flex;flex-wrap:wrap;gap:4px 12px;margin-top:6px;font-size:12px}.pv2-legend-item{display:inline-flex;align-items:center;gap:5px}.pv2-swatch{width:10px;height:10px;border-radius:2px}.pv2-chart{display:grid;grid-template-columns:auto 1fr;gap:2px 6px}.pv2-chart-y{display:flex;flex-direction:column;justify-content:space-between;height:110px;color:var(--p-text-muted-color, #64748b);font-size:11px;text-align:right;line-height:1}.pv2-chart-plot{position:relative;height:110px;border-left:1px solid var(--p-content-border-color, #e2e8f0);border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-chart-plot svg{display:block;width:100%;height:100%}.pv2-chart-grid{stroke:var(--p-content-border-color, #e2e8f0);stroke-dasharray:3 3}.pv2-chart-last{position:absolute;width:8px;height:8px;border:2px solid var(--p-content-background, #fff);border-radius:50%;transform:translate(-50%,-50%)}.pv2-chart-x{display:flex;justify-content:space-between;color:var(--p-text-muted-color, #64748b);font-size:11px}.pv2-caption{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-mini{width:100%;font-size:12px}.pv2-mini th{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-weight:500}.pv2-mini td{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-ellipsis{display:inline-block;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.pv2-d-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px;margin-top:16px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);color:var(--p-text-color, #334155);font-size:13px;cursor:pointer}.pv2-btn:hover{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca)}\n"], dependencies: [{ kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "component", type: i9.EsFormInputComponent, selector: "form-input", inputs: ["minlength", "maxlength", "pattern", "Password", "Type"] }, { kind: "component", type: i9.EsFormSelectComponent, selector: "form-select", inputs: ["OptionsTemplate"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: AdmDetailsV2Component, selector: "adm-details-v2", inputs: ["Be", "CanShowSessions", "CanOpenProfiler"], outputs: ["closed", "sessionsOnEvent", "openProfiler"] }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }, { kind: "pipe", type: ProfilerFormatPipe, name: "pv2fmt" }] }); }
1973
2796
  }
1974
2797
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerV2Component, decorators: [{
1975
2798
  type: Component,
1976
- args: [{ selector: "profiler_v2", providers: [{ provide: LocalizationService, useClass: AdmProfilerV2Loc }], standalone: false, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span>\r\n </div>\r\n <div class=\"card-body widget-body pv2-body\">\r\n <!-- Barra dei comandi: quali dati caricare. Ogni cambio ricarica la vista e il dettaglio aperto -->\r\n <div class=\"pv2-toolbar\">\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Sorgente' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"live\" (click)=\"setLive(true)\"><span class=\"pv2-live-dot\"></span>Live</button>\r\n <button type=\"button\" [class.pv2-on]=\"!live\" (click)=\"setLive(false)\">{{'Storico' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n <div class=\"pv2-field pv2-field-wide pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"instance\" (ngModelChange)=\"setInstance($event)\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanze' | localize: lc\"></form-select>\r\n </div>\r\n </div>\r\n\r\n @if (!live) {\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterfrom\" (ngModelChange)=\"filterfrom = $event; datesChanged()\" name=\"filterfrom\" [Placeholder]=\"'Dal' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterto\" (ngModelChange)=\"filterto = $event; datesChanged()\" name=\"filterto\" [Placeholder]=\"'Al' | localize: lc\"></form-datetime>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Valori' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"!snapValues\" (click)=\"setSnapValues(false)\">{{\"Dall'avvio\" | localize: lc}}</button>\r\n <button type=\"button\" [class.pv2-on]=\"snapValues\" (click)=\"setSnapValues(true)\">{{\"Dall'ultimo snapshot\" | localize: lc}}</button>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"pv2-cluster pv2-cluster-end\">\r\n <button type=\"button\" class=\"btn app-btn-search\" [disabled]=\"loading\" (click)=\"reloadAll()\" [title]=\"'Aggiorna' | localize: lc\">\r\n <i class=\"fa fa-refresh\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n <button type=\"button\" class=\"btn app-btn-search\" (click)=\"downloadWorkloadReport()\" [title]=\"(workloadV2 ? 'Workload report' : 'Scarica il workload report') | localize: lc\">\r\n <i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Riga della finestra: sempre visibile sopra la vista -->\r\n <div class=\"pv2-window\">\r\n <span><strong>{{live ? 'Live' : ('Storico' | localize: lc)}}</strong> &middot; {{instanceLabel}}</span>\r\n @if (current?.snapFrom; as snapFrom) {\r\n @if (live) {\r\n <span>{{\"Delta dall'ultimo snapshot delle\" | localize: lc}} {{hhmm(snapFrom)}} ({{minutesAgo(snapFrom)}} {{'min fa' | localize: lc}})</span>\r\n } @else {\r\n <span>{{'Snapshot dalle' | localize: lc}} {{ddmmhhmm(snapFrom)}} {{'alle' | localize: lc}} {{ddmmhhmm(current?.snapTo)}}</span>\r\n }\r\n } @else if (current && !live) {\r\n <span class=\"pv2-warn-text\">{{'Nessuno snapshot termina nella finestra scelta' | localize: lc}}</span>\r\n }\r\n @if (view == 'tree' && tree?.idleNode) {\r\n <span>{{tree.numNodes | pv2fmt: 'int'}} {{\"nodi nell'albero\" | localize: lc}} &middot; {{tree.numReturnedNodes | pv2fmt: 'int'}} {{'nella risposta' | localize: lc}}</span>\r\n }\r\n @if (view == 'flat' && flat) {\r\n <span>{{flat.numItems | pv2fmt: 'int'}} {{'eventi distinti' | localize: lc}}</span>\r\n }\r\n @if (loading) {\r\n <span class=\"pv2-muted\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Caricamento\u2026' | localize: lc}}</span>\r\n }\r\n </div>\r\n\r\n <div class=\"pv2-main\">\r\n <!-- Vista: albero o eventi per nome -->\r\n <div class=\"pv2-panel pv2-view\">\r\n <div class=\"pv2-view-bar\">\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"view == 'tree'\" (click)=\"setView('tree')\"><i class=\"fa fa-sitemap\"></i> {{'Albero' | localize: lc}}</button>\r\n <button type=\"button\" [class.pv2-on]=\"view == 'flat'\" (click)=\"setView('flat')\"><i class=\"fa fa-list\"></i> {{'Per nome' | localize: lc}}</button>\r\n </div>\r\n\r\n @if (view == 'tree') {\r\n <div class=\"pv2-field pv2-field-search\" [title]=\"'Per esempio MRD_METERREADINGS, ENQUEUE, ProfilesMgr' | localize: lc\">\r\n <form-input [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"searchText\" (ngModelChange)=\"searchText = $event; searchChanged()\" name=\"search\" [Placeholder]=\"'Cerca nei nomi o per id' | localize: lc\"></form-input>\r\n </div>\r\n <div class=\"pv2-field pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"orderBy\" (ngModelChange)=\"setOrderBy($event)\" name=\"orderBy\" [Source]=\"TreeOrderOptions\" [Placeholder]=\"'Ordina per' | localize: lc\"></form-select>\r\n </div>\r\n <div class=\"pv2-group\" [class.pv2-disabled]=\"!!activeSearch\">\r\n <span class=\"pv2-group-label\">{{'Figli per nodo' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n @for (o of ChildrenOptions; track o.id) {\r\n <button type=\"button\" [disabled]=\"!!activeSearch\" [class.pv2-on]=\"maxChildren == o.id\" (click)=\"setMaxChildren(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"pv2-group\" [class.pv2-disabled]=\"!!activeSearch\">\r\n <span class=\"pv2-group-label\">{{'Soglia' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n @for (o of ThresholdOptions; track o.id) {\r\n <button type=\"button\" [disabled]=\"!!activeSearch\" [class.pv2-on]=\"minPercentage == o.id\" (click)=\"setMinPercentage(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"pv2-field pv2-field-search\">\r\n <form-input [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"flatSearch\" (ngModelChange)=\"flatSearch = $event; flatSearchChanged()\" name=\"flatSearch\" [Placeholder]=\"'Cerca nei nomi' | localize: lc\"></form-input>\r\n </div>\r\n <div class=\"pv2-field pv2-field-narrow pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"flatType\" (ngModelChange)=\"flatType = $event; flatChanged()\" name=\"flatType\" [Source]=\"FlatTypes\" [Placeholder]=\"'Tipo' | localize: lc\"></form-select>\r\n </div>\r\n <div class=\"pv2-field pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"flatOrderBy\" (ngModelChange)=\"flatOrderBy = $event; flatChanged()\" name=\"flatOrderBy\" [Source]=\"FlatOrderOptions\" [Placeholder]=\"'Ordina per' | localize: lc\"></form-select>\r\n </div>\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Righe' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n @for (o of FlatRows; track o.id) {\r\n <button type=\"button\" [class.pv2-on]=\"flatTop == o.id\" (click)=\"setFlatTop(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"pv2-toggle\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [ngModel]=\"flatIncludeIdle\" (ngModelChange)=\"flatIncludeIdle = $event; flatChanged()\" name=\"flatIncludeIdle\"></form-checkbox>\r\n <span class=\"pv2-pointer\" (click)=\"flatIncludeIdle = !flatIncludeIdle; flatChanged()\">{{'Anche gli eventi idle' | localize: lc}}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (view == 'tree') {\r\n <!-- Percorso della radice: ogni antenato riporta l'albero a quel nodo -->\r\n @if (tree?.idleNode && tree?.rootPath?.length) {\r\n <nav class=\"pv2-crumbs\">\r\n @for (item of tree.rootPath; track item.nodeId) {\r\n <button type=\"button\" class=\"pv2-crumb\" [title]=\"item.nodeName\" (click)=\"setRoot(item.nodeId)\">{{item.nodeName}}</button>\r\n <span class=\"pv2-crumb-sep\">&rsaquo;</span>\r\n }\r\n <span class=\"pv2-crumb pv2-crumb-current\" [title]=\"tree.idleNode.nodeName\">{{tree.idleNode.nodeName}}</span>\r\n </nav>\r\n }\r\n\r\n @if (treeNotice) {\r\n <div class=\"pv2-alert pv2-alert-warn\">\r\n {{treeNotice}}\r\n <button type=\"button\" class=\"pv2-alert-close\" [title]=\"'Chiudi' | localize: lc\" (click)=\"treeNotice = null\">&times;</button>\r\n </div>\r\n }\r\n @if (activeSearch && tree) {\r\n @if (matchCount > 0) {\r\n <div class=\"pv2-alert\" [class.pv2-alert-warn]=\"tree.truncated\">\r\n {{matchCount | pv2fmt: 'int'}} {{'nodi trovati, con i loro antenati.' | localize: lc}}\r\n @if (tree.truncated) {\r\n <strong>{{'I nodi trovati sono pi\u00F9 di 1.000: sono mostrati i primi per l\\'ordinamento scelto.' | localize: lc}}</strong>\r\n }\r\n </div>\r\n } @else if (!treeLoading) {\r\n <div class=\"pv2-alert\">{{'Nessun nodo contiene' | localize: lc}} &laquo;{{activeSearch}}&raquo;.</div>\r\n }\r\n }\r\n @if (treeError) {\r\n <div class=\"pv2-alert pv2-alert-error\">{{treeError}}</div>\r\n }\r\n\r\n <div class=\"pv2-table-wrap\" tabindex=\"0\" (keydown)=\"treeKeydown($event)\">\r\n <table class=\"pv2-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"pv2-col-node\">{{'Nodo' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Chiamate' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Tempo' | localize: lc}}</th>\r\n <th>{{snapMode ? '\u0394 ' : ''}}{{'% del padre' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{(snapMode ? '\u0394 Proprio' : 'Tempo proprio') | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Medio' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Picco' | localize: lc}}</th>\r\n @if (live) {\r\n <th class=\"pv2-num\">{{'Thread ora' | localize: lc}}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of rows; track row.key) {\r\n @if (row.kind == 'node') {\r\n <tr [id]=\"'pv2-row-' + row.node.nodeId\" class=\"pv2-row\"\r\n [class.pv2-selected]=\"row.node.nodeId == selectedId\"\r\n [class.pv2-idle]=\"isIdle(row.node.eventTypeName, row.node.waitClassName)\"\r\n (click)=\"rowClicked(row.node)\" (dblclick)=\"toggle(row.node)\">\r\n <td class=\"pv2-col-node\">\r\n <div class=\"pv2-node\" [style.padding-left.px]=\"row.depth * 16\">\r\n @if (hasChildren(row.node)) {\r\n <button type=\"button\" class=\"pv2-caret\" tabindex=\"-1\" [attr.aria-expanded]=\"isExpanded(row.node)\" (click)=\"toggle(row.node, $event)\">\r\n <i class=\"fa\" [class.fa-caret-down]=\"isExpanded(row.node)\" [class.fa-caret-right]=\"!isExpanded(row.node)\"></i>\r\n </button>\r\n } @else {\r\n <span class=\"pv2-caret\"></span>\r\n }\r\n <span class=\"pv2-type\"><span class=\"pv2-dot\" [style.background]=\"typeColor(row.node.eventTypeName, row.node.waitClassName)\"></span>{{typeLabel(row.node.eventTypeName, row.node.waitClassName)}}</span>\r\n <span class=\"pv2-name\" [title]=\"row.node.nodeName\">@if (row.node.searchMatch && activeSearch) {@for (part of nameParts(row.node.nodeName, activeSearch); track $index) {@if (part.hit) {<mark>{{part.text}}</mark>} @else {<span>{{part.text}}</span>}}} @else {<span>{{row.node.nodeName}}</span>}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{calls(row.node) | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{time(row.node) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-perc\" [title]=\"(parentPerc(row.node) | pv2fmt: 'pct') + ' ' + ('del padre' | localize: lc) + ' \u00B7 ' + (firstLevelPerc(row.node) | pv2fmt: 'pct') + ' ' + ('del nodo di primo livello' | localize: lc)\">\r\n <div class=\"pv2-perc-cell\">\r\n <div class=\"pv2-bar\"><div [style.width.%]=\"parentPerc(row.node)\" [style.background]=\"typeColor(row.node.eventTypeName, row.node.waitClassName)\"></div></div>\r\n <span>{{parentPerc(row.node) | pv2fmt: 'pct'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{self(row.node) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{avg(row.node) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{peak(row.node) | pv2fmt: 'dur'}}</td>\r\n @if (live) {\r\n <td class=\"pv2-num pv2-threads\">\r\n @if (isLongRunning(row.node.eventTypeName, row.node.waitClassName, row.node.activeMaxTime)) {\r\n <span class=\"pv2-long\" [title]=\"('Esecuzione in corso da' | localize: lc) + ' ' + duration(row.node.activeMaxTime) + ': ' + ('forse bloccata' | localize: lc)\"><i class=\"fa fa-clock\"></i> {{duration(row.node.activeMaxTime)}}</span>\r\n }\r\n @if (row.node.activeThreads > 0) {\r\n <span class=\"pv2-active\"><span class=\"pv2-active-dot\"></span>{{row.node.activeThreads}}</span>\r\n } @else {\r\n <span class=\"pv2-muted\">{{row.node.activeThreads ?? '\u2014'}}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n } @else if (row.kind == 'loading') {\r\n <tr class=\"pv2-service\">\r\n <td [attr.colspan]=\"live ? 8 : 7\">\r\n <div [style.padding-left.px]=\"row.depth * 16 + 24\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Caricamento dei figli\u2026' | localize: lc}}</div>\r\n </td>\r\n </tr>\r\n } @else {\r\n <tr class=\"pv2-service\">\r\n <td [attr.colspan]=\"live ? 8 : 7\">\r\n <div [style.padding-left.px]=\"row.depth * 16 + 24\">\r\n {{row.node.omittedChildren | pv2fmt: 'int'}} {{'figli non mostrati' | localize: lc}} &middot; {{omittedTime(row.node) | pv2fmt: 'dur'}}\r\n @if (!snapMode) {\r\n &middot; {{row.node.omittedCalls | pv2fmt: 'int'}} {{'chiamate' | localize: lc}}\r\n }\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"showAll(row.node, $event)\">{{'Mostra tutti' | localize: lc}}</button>\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n @if (rows.length == 0 && !treeError) {\r\n <div class=\"pv2-empty\">\r\n @if (!tree) {\r\n {{'Caricamento\u2026' | localize: lc}}\r\n } @else if (!tree.snapFrom && !live) {\r\n {{'Nessuno snapshot termina nella finestra scelta: allargala o spostala indietro.' | localize: lc}}\r\n } @else {\r\n {{\"Il nodo non c'\u00E8 nelle istanze scelte.\" | localize: lc}}\r\n }\r\n </div>\r\n }\r\n </div>\r\n } @else {\r\n @if (flatError) {\r\n <div class=\"pv2-alert pv2-alert-error\">{{flatError}}</div>\r\n }\r\n <div class=\"pv2-table-wrap\">\r\n <table class=\"pv2-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"pv2-col-node\">{{'Evento' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Percorsi' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Chiamate' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{(snapMode ? '\u0394 Proprio' : 'Tempo proprio') | localize: lc}}</th>\r\n <th>{{snapMode ? '\u0394 ' : ''}}{{'% proprio' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Tempo' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Medio' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{(snapMode ? \"Picco dall'avvio\" : 'Picco') | localize: lc}}</th>\r\n @if (live) {\r\n <th class=\"pv2-num\">{{'Thread' | localize: lc}}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (item of flat?.items ?? []; track flatKey(item)) {\r\n <tr class=\"pv2-row\" [class.pv2-idle]=\"isIdle(item.eventTypeName, item.waitClassName)\" [class.pv2-selected]=\"openFlat.has(flatKey(item))\" (click)=\"toggleFlat(item)\">\r\n <td class=\"pv2-col-node\">\r\n <div class=\"pv2-node\">\r\n <span class=\"pv2-caret\"><i class=\"fa\" [class.fa-caret-down]=\"openFlat.has(flatKey(item))\" [class.fa-caret-right]=\"!openFlat.has(flatKey(item))\"></i></span>\r\n <span class=\"pv2-type\"><span class=\"pv2-dot\" [style.background]=\"typeColor(item.eventTypeName, item.waitClassName)\"></span>{{typeLabel(item.eventTypeName, item.waitClassName)}}</span>\r\n <span class=\"pv2-name\" [title]=\"item.nodeName\">@for (part of nameParts(item.nodeName, (flatSearch ?? '').trim()); track $index) {@if (part.hit) {<mark>{{part.text}}</mark>} @else {<span>{{part.text}}</span>}}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{item.numPaths | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{flatCalls(item) | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{flatSelf(item) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-perc\">\r\n <div class=\"pv2-perc-cell\">\r\n <div class=\"pv2-bar\"><div [style.width.%]=\"flatPerc(item)\" [style.background]=\"typeColor(item.eventTypeName, item.waitClassName)\"></div></div>\r\n <span>{{flatPerc(item) | pv2fmt: 'pct'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{flatTime(item) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{flatAvg(item) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{item.peakTime | pv2fmt: 'dur'}}</td>\r\n @if (live) {\r\n <td class=\"pv2-num pv2-threads\">\r\n @if (item.activeThreads > 0) {\r\n <span class=\"pv2-active\"><span class=\"pv2-active-dot\"></span>{{item.activeThreads}}</span>\r\n } @else {\r\n <span class=\"pv2-muted\">{{item.activeThreads ?? '\u2014'}}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n @if (openFlat.has(flatKey(item))) {\r\n <tr class=\"pv2-sub\">\r\n <td [attr.colspan]=\"live ? 9 : 8\">\r\n <div class=\"pv2-sub-title\">{{'Nodi con pi\u00F9 tempo' | localize: lc}}</div>\r\n @for (id of item.nodeIds ?? []; track id) {\r\n <div class=\"pv2-sub-item\">\r\n <code>{{id}}</code>\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"showDetail(id, $event)\">{{'Dettaglio' | localize: lc}}</button>\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"openInTree(id, $event)\">{{\"Apri nell'albero\" | localize: lc}}</button>\r\n </div>\r\n }\r\n @if (item.numPaths > (item.nodeIds?.length ?? 0)) {\r\n <div class=\"pv2-muted\">+{{item.numPaths - (item.nodeIds?.length ?? 0) | pv2fmt: 'int'}} {{'altri' | localize: lc}}</div>\r\n }\r\n </td>\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n @if (!flatError && (!flat || !flat.items?.length)) {\r\n <div class=\"pv2-empty\">{{(flat ? 'Nessun evento con questi filtri.' : 'Caricamento\u2026') | localize: lc}}</div>\r\n }\r\n </div>\r\n @if (flat?.items?.length) {\r\n <div class=\"pv2-footer\">\r\n {{flat.numItems | pv2fmt: 'int'}} {{'eventi distinti' | localize: lc}}@if (flat.numItems > flat.items.length) {, {{'mostrati i primi' | localize: lc}} {{flat.items.length | pv2fmt: 'int'}}}.\r\n {{'La percentuale \u00E8 sul tempo proprio di tutti gli eventi non idle.' | localize: lc}}\r\n </div>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Dettaglio del nodo selezionato, lo stesso per le due viste -->\r\n <aside class=\"pv2-panel pv2-detail\" [class.pv2-stale]=\"detailStale\">\r\n @if (!selectedId) {\r\n <div class=\"pv2-placeholder\">{{'Seleziona un nodo per vederne il dettaglio.' | localize: lc}}</div>\r\n } @else if (detailMissing && !detailLoading) {\r\n <div class=\"pv2-placeholder\">{{\"Il nodo non c'\u00E8 nelle istanze o nella finestra scelte.\" | localize: lc}}</div>\r\n } @else if (detailError && !detailLoading) {\r\n <div class=\"pv2-placeholder pv2-error-text\">{{detailError}}</div>\r\n } @else if (!detail) {\r\n <div class=\"pv2-placeholder\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Caricamento\u2026' | localize: lc}}</div>\r\n } @else {\r\n <div class=\"pv2-d-head\">\r\n <span class=\"pv2-type\"><span class=\"pv2-dot\" [style.background]=\"typeColor(detail.eventTypeName, detail.waitClassName)\"></span>{{typeLabel(detail.eventTypeName, detail.waitClassName)}}</span>\r\n @if (detailLoading) {\r\n <i class=\"fa fa-spinner fa-spin pv2-muted\"></i>\r\n }\r\n </div>\r\n <div class=\"pv2-fullname\">{{detail.nodeName}}</div>\r\n <div class=\"pv2-id\">\r\n Id <code #idText>{{detail.nodeId}}</code>\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"copyId(idText)\">{{(copied ? 'Copiato' : 'Copia') | localize: lc}}</button>\r\n </div>\r\n\r\n <div class=\"pv2-d-title\">{{'Percorso' | localize: lc}}</div>\r\n <div class=\"pv2-path\">\r\n @for (item of detail.fullWaitStack ?? []; track item.nodeId; let i = $index) {\r\n <button type=\"button\" class=\"pv2-path-item\" [style.padding-left.px]=\"i * 10\" [title]=\"item.nodeName\" (click)=\"select(item.nodeId)\">\r\n <span class=\"pv2-dot\" [style.background]=\"typeColor(item.eventTypeName, item.waitClassName)\"></span>{{item.nodeName}}\r\n </button>\r\n }\r\n <div class=\"pv2-path-item pv2-path-current\" [style.padding-left.px]=\"(detail.fullWaitStack?.length ?? 0) * 10\" [title]=\"detail.nodeName\">\r\n <span class=\"pv2-dot\" [style.background]=\"typeColor(detail.eventTypeName, detail.waitClassName)\"></span>{{detail.nodeName}}\r\n </div>\r\n </div>\r\n\r\n <div class=\"pv2-d-title\">{{(live ? \"Dall'avvio\" : 'Nella finestra') | localize: lc}}</div>\r\n <dl class=\"pv2-kv\">\r\n <dt>{{'Esecuzioni' | localize: lc}}</dt><dd>{{detail.executions | pv2fmt: 'int'}}</dd>\r\n <dt>{{'Tempo totale' | localize: lc}}</dt><dd>{{detail.elapsedTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Tempo proprio' | localize: lc}}</dt><dd>{{detail.elapsedTimeLessChildren | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Medio' | localize: lc}}</dt><dd>{{detail.avgTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Picco' | localize: lc}}</dt><dd>{{detail.peakTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Minimo' | localize: lc}}</dt><dd>{{detail.minTime ? (detail.minTime | pv2fmt: 'dur') : '\u2014'}}</dd>\r\n </dl>\r\n\r\n @if (live) {\r\n <div class=\"pv2-d-title\">{{\"Dall'ultimo snapshot\" | localize: lc}}, {{hhmm(detail.snapFrom)}}</div>\r\n <dl class=\"pv2-kv\">\r\n <dt>{{'Esecuzioni' | localize: lc}}</dt><dd>{{detail.snapDeltaExecutions | pv2fmt: 'int'}}</dd>\r\n <dt>{{'Tempo totale' | localize: lc}}</dt><dd>{{detail.snapDeltaElapsedTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Tempo proprio' | localize: lc}}</dt><dd>{{detail.snapDeltaElapsedTimeLessChildren | pv2fmt: 'dur'}}</dd>\r\n </dl>\r\n\r\n <div class=\"pv2-d-title\">{{'Adesso' | localize: lc}}</div>\r\n <dl class=\"pv2-kv\">\r\n <dt>{{'Thread dentro' | localize: lc}}</dt>\r\n <dd>\r\n @if (detail.activeThreads > 0) {\r\n <span class=\"pv2-active\"><span class=\"pv2-active-dot\"></span>{{detail.activeThreads}}</span>\r\n } @else {\r\n {{detail.activeThreads ?? '\u2014'}}\r\n }\r\n </dd>\r\n <dt>{{'Esecuzione pi\u00F9 lunga' | localize: lc}}</dt>\r\n <dd>\r\n @if (detail.activeThreads > 0) {\r\n {{detail.activeMaxTime | pv2fmt: 'dur'}}\r\n @if (isLongRunning(detail.eventTypeName, detail.waitClassName, detail.activeMaxTime)) {\r\n <span class=\"pv2-long\"><i class=\"fa fa-clock\"></i> {{'forse bloccata' | localize: lc}}</span>\r\n }\r\n } @else {\r\n \u2014\r\n }\r\n </dd>\r\n <dt>{{'Ultima uscita' | localize: lc}}</dt><dd>{{relative(detail.lastExitTime)}}</dd>\r\n </dl>\r\n }\r\n\r\n @if (typeParts.length > 0) {\r\n <div class=\"pv2-d-title\">{{'Tempo proprio del sottoalbero per tipo' | localize: lc}}</div>\r\n <div class=\"pv2-stack\">\r\n @for (part of typeParts; track part.type) {\r\n <div [style.width.%]=\"part.percentage\" [style.background]=\"part.color\" [title]=\"part.label + ' ' + (part.percentage | pv2fmt: 'pct')\"></div>\r\n }\r\n </div>\r\n <div class=\"pv2-legend\">\r\n @for (part of typeParts; track part.type) {\r\n <span class=\"pv2-legend-item\"><span class=\"pv2-swatch\" [style.background]=\"part.color\"></span>{{part.label}} <strong>{{part.percentage | pv2fmt: 'pct'}}</strong></span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"pv2-d-title\">{{'Sessioni attive sul nodo e sui discendenti' | localize: lc}}</div>\r\n @if (chart) {\r\n <div class=\"pv2-chart\">\r\n <div class=\"pv2-chart-y\">\r\n <span>{{axisValue(chart.max)}}</span>\r\n <span>{{axisValue(chart.max / 2)}}</span>\r\n <span>0</span>\r\n </div>\r\n <div class=\"pv2-chart-plot\">\r\n <svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\r\n <line x1=\"0\" y1=\"50\" x2=\"100\" y2=\"50\" class=\"pv2-chart-grid\" vector-effect=\"non-scaling-stroke\" />\r\n <path [attr.d]=\"chart.area\" [attr.fill]=\"chart.color\" fill-opacity=\"0.25\" />\r\n <path [attr.d]=\"chart.line\" [attr.stroke]=\"chart.color\" fill=\"none\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\" />\r\n </svg>\r\n <span class=\"pv2-chart-last\" [style.left.%]=\"chart.lastX\" [style.top.%]=\"chart.lastY\" [style.background]=\"chart.color\"></span>\r\n </div>\r\n <span></span>\r\n <div class=\"pv2-chart-x\">\r\n <span>{{chart.start}}</span>\r\n <span>{{chart.middle}}</span>\r\n <span>{{chart.end}}</span>\r\n </div>\r\n </div>\r\n <div class=\"pv2-caption\">\r\n {{'Media' | localize: lc}} {{axisValue(chart.average)}} &middot; {{'picco' | localize: lc}} {{axisValue(chart.peak)}} {{'sessioni' | localize: lc}}.\r\n {{chart.points | pv2fmt: 'int'}} {{\"punti dell'API\" | localize: lc}},\r\n @if (chart.interval == 1) {\r\n {{'uno al secondo' | localize: lc}},\r\n } @else {\r\n {{'uno ogni' | localize: lc}} {{chart.interval}} s,\r\n }\r\n {{'raggruppati a' | localize: lc}} {{chart.group}} s\r\n </div>\r\n } @else {\r\n <div class=\"pv2-muted pv2-small\">{{'Nessun campione in memoria per questa finestra: il grafico copre solo le ultime due ore circa.' | localize: lc}}</div>\r\n }\r\n\r\n @if (detail.instances?.length) {\r\n <div class=\"pv2-d-title\">{{'Per istanza' | localize: lc}}</div>\r\n <table class=\"pv2-mini\">\r\n <thead>\r\n <tr>\r\n <th>{{'Istanza' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Esecuzioni' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Tempo' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Proprio' | localize: lc}}</th>\r\n @if (live) {\r\n <th class=\"pv2-num\">{{'Thread' | localize: lc}}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (inst of detail.instances; track inst.instanceId) {\r\n <tr>\r\n <td><span class=\"pv2-ellipsis\" [title]=\"inst.instanceId\">{{inst.instanceId}}</span></td>\r\n <td class=\"pv2-num\">{{inst.executions | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{inst.elapsedTime | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{inst.elapsedTimeLessChildren | pv2fmt: 'dur'}}</td>\r\n @if (live) {\r\n <td class=\"pv2-num\">{{inst.activeThreads ?? '\u2014'}}</td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n <div class=\"pv2-d-foot\">\r\n <span class=\"pv2-muted\">{{detail.numChildren | pv2fmt: 'int'}} {{'figli diretti' | localize: lc}} &middot; {{detail.numDescendants | pv2fmt: 'int'}} {{'discendenti' | localize: lc}}</span>\r\n <button type=\"button\" class=\"pv2-btn\" (click)=\"setRoot(detail.nodeId)\"><i class=\"fa fa-sitemap\"></i> {{'Apri come radice' | localize: lc}}</button>\r\n </div>\r\n }\r\n </aside>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n", styles: ["@charset \"UTF-8\";:host{display:block}:host ::ng-deep .pv2-noclear .p-select-clear-icon{display:none}.pv2-body{container-type:inline-size}.pv2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;padding-top:6px}.pv2-cluster{display:flex;flex-wrap:nowrap;align-items:center;gap:10px}.pv2-cluster-end{margin-left:auto}.pv2-field{width:190px}.pv2-field-wide{width:290px}.pv2-field-narrow{width:140px}.pv2-field-search{flex:1 1 220px;min-width:200px;max-width:340px}.pv2-toggle{display:flex;align-items:center;gap:8px;height:39px;white-space:nowrap}.pv2-pointer{cursor:pointer}.pv2-group{position:relative;display:inline-flex}.pv2-group.pv2-disabled{opacity:.5}.pv2-group-label{position:absolute;top:-8px;left:8px;z-index:1;padding:0 4px;background:var(--p-content-background, #fff);color:var(--p-text-muted-color, #64748b);font-size:12px;line-height:15px;white-space:nowrap;pointer-events:none}.pv2-seg{display:inline-flex;height:39px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden;background:var(--p-content-background, #fff)}.pv2-seg button{display:inline-flex;align-items:center;gap:6px;padding:0 12px;border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;color:var(--p-text-color, #334155);font-size:13px;white-space:nowrap;cursor:pointer}.pv2-seg button:first-child{border-left:0}.pv2-seg button:hover:not(.pv2-on):not(:disabled){background:var(--p-content-hover-background, #f8fafc)}.pv2-seg button:disabled{cursor:default}.pv2-seg button:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:-2px}.pv2-seg button.pv2-on{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca);font-weight:500;box-shadow:inset 0 -2px 0 var(--p-primary-color, #6366f1)}.pv2-live-dot{width:8px;height:8px;border-radius:50%;background:#16a34a}.pv2-window{display:flex;flex-wrap:wrap;align-items:center;row-gap:4px;margin-top:12px;padding:7px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-color, #334155);font-size:13px}.pv2-window>span+span:before{content:\"\\b7\";margin:0 10px;color:var(--p-text-muted-color, #64748b)}.pv2-warn-text{color:#92400e}.pv2-main{display:grid;grid-template-columns:minmax(0,1fr) 380px;gap:14px;align-items:start;margin-top:14px}@container (max-width: 1350px){.pv2-main{grid-template-columns:minmax(0,1fr)}.pv2-detail{position:static;max-height:none}}.pv2-panel{padding:12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);min-width:0}.pv2-view-bar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px;padding-top:6px;margin-bottom:10px}.pv2-crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;margin-bottom:8px;font-size:12px}.pv2-crumb{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:2px 6px;border:0;border-radius:4px;background:transparent;color:var(--p-primary-color, #6366f1);cursor:pointer}.pv2-crumb:hover{background:var(--p-highlight-background, #eef2ff)}.pv2-crumb-current{color:var(--p-text-color, #334155);font-weight:500;cursor:default}.pv2-crumb-current:hover{background:transparent}.pv2-crumb-sep{color:var(--p-text-muted-color, #64748b)}.pv2-alert{position:relative;margin-bottom:8px;padding:6px 30px 6px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-size:13px}.pv2-alert.pv2-alert-warn{border-color:#fcd34d;background:#fffbeb;color:#92400e}.pv2-alert.pv2-alert-error{border-color:#fca5a5;background:#fef2f2;color:#991b1b}.pv2-alert-close{position:absolute;top:3px;right:6px;border:0;background:transparent;color:inherit;font-size:16px;cursor:pointer}.pv2-table-wrap{max-height:68vh;overflow:auto;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px)}.pv2-table-wrap:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:1px}.pv2-table{width:100%;border-collapse:separate;border-spacing:0;font-size:13px;color:var(--p-text-color, #334155)}.pv2-table th{position:sticky;top:0;z-index:1;padding:7px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-muted-color, #64748b);font-size:12px;font-weight:500;white-space:nowrap;text-align:left}.pv2-table td{padding:4px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);white-space:nowrap;vertical-align:middle}.pv2-col-node{width:100%;max-width:0}.pv2-col-node .pv2-node{min-width:260px}.pv2-num{text-align:right!important;font-variant-numeric:tabular-nums}.pv2-row{cursor:pointer}.pv2-row:hover td{background:var(--p-content-hover-background, #f8fafc)}.pv2-row.pv2-selected td{background:var(--p-highlight-background, #eef2ff)}.pv2-row.pv2-idle td{color:var(--p-text-muted-color, #64748b)}.pv2-row.pv2-idle td .pv2-name{opacity:.75}.pv2-node{display:flex;align-items:center;gap:6px;min-width:0}.pv2-caret{flex:none;width:18px;height:20px;padding:0;border:0;background:transparent;color:var(--p-text-muted-color, #64748b);text-align:center;cursor:pointer}.pv2-type{flex:none;display:inline-flex;align-items:center;gap:5px;padding:0 6px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:10px;color:var(--p-text-muted-color, #64748b);font-size:11px;line-height:18px;white-space:nowrap}.pv2-dot{flex:none;display:inline-block;width:8px;height:8px;border-radius:50%}.pv2-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pv2-name mark{padding:0 1px;border-radius:2px;background:#fde68a;color:#1f2937}.pv2-perc{width:1%}.pv2-perc-cell{display:flex;align-items:center;gap:8px}.pv2-bar{flex:none;width:64px;height:7px;border-radius:2px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc);box-shadow:inset 0 0 0 1px var(--p-content-border-color, #e2e8f0)}.pv2-bar>div{height:100%}.pv2-threads>*+*{margin-left:8px}.pv2-active{display:inline-flex;align-items:center;gap:5px;font-weight:500}.pv2-active-dot{width:7px;height:7px;border-radius:50%;background:#16a34a;box-shadow:0 0 0 3px #16a34a2e}.pv2-long{display:inline-flex;align-items:center;gap:4px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:18px;white-space:nowrap}.pv2-service td{padding:5px 10px;color:var(--p-text-muted-color, #64748b);font-size:12px;background:var(--p-content-background, #fff)}.pv2-sub td{padding:8px 10px 10px 34px;background:var(--p-content-hover-background, #f8fafc);white-space:normal}.pv2-sub-title{margin-bottom:4px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-sub-item{display:flex;align-items:center;gap:10px;padding:2px 0}.pv2-sub-item code{font-size:12px}.pv2-link{margin-left:6px;padding:0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;cursor:pointer}.pv2-link:hover{text-decoration:underline}.pv2-empty{padding:28px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-footer{margin-top:8px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-muted{color:var(--p-text-muted-color, #64748b)}.pv2-small{font-size:12px}.pv2-detail{position:sticky;top:10px;max-height:calc(100vh - 20px);overflow:auto;font-size:13px;color:var(--p-text-color, #334155);transition:opacity .15s}.pv2-detail.pv2-stale{opacity:.55}.pv2-placeholder{padding:36px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-error-text{color:#dc2626}.pv2-d-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.pv2-fullname{max-height:140px;overflow:auto;padding:8px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-family:ui-monospace,Cascadia Mono,Consolas,monospace;font-size:12px;white-space:pre-wrap;word-break:break-word}.pv2-id{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-id code{font-size:12px}.pv2-d-title{margin:16px 0 6px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}.pv2-path{display:flex;flex-direction:column}.pv2-path-item{display:flex;align-items:center;gap:6px;max-width:100%;padding:2px 0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.pv2-path-item:hover{text-decoration:underline}.pv2-path-current{color:var(--p-text-color, #334155);font-weight:600;cursor:default}.pv2-path-current:hover{text-decoration:none}.pv2-kv{display:grid;grid-template-columns:auto 1fr;gap:3px 14px;margin:0}.pv2-kv dt{color:var(--p-text-muted-color, #64748b);font-weight:400}.pv2-kv dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}.pv2-stack{display:flex;height:12px;border-radius:3px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc)}.pv2-legend{display:flex;flex-wrap:wrap;gap:4px 12px;margin-top:6px;font-size:12px}.pv2-legend-item{display:inline-flex;align-items:center;gap:5px}.pv2-swatch{width:10px;height:10px;border-radius:2px}.pv2-chart{display:grid;grid-template-columns:auto 1fr;gap:2px 6px}.pv2-chart-y{display:flex;flex-direction:column;justify-content:space-between;height:110px;color:var(--p-text-muted-color, #64748b);font-size:11px;text-align:right;line-height:1}.pv2-chart-plot{position:relative;height:110px;border-left:1px solid var(--p-content-border-color, #e2e8f0);border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-chart-plot svg{display:block;width:100%;height:100%}.pv2-chart-grid{stroke:var(--p-content-border-color, #e2e8f0);stroke-dasharray:3 3}.pv2-chart-last{position:absolute;width:8px;height:8px;border:2px solid var(--p-content-background, #fff);border-radius:50%;transform:translate(-50%,-50%)}.pv2-chart-x{display:flex;justify-content:space-between;color:var(--p-text-muted-color, #64748b);font-size:11px}.pv2-caption{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-mini{width:100%;font-size:12px}.pv2-mini th{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-weight:500}.pv2-mini td{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-ellipsis{display:inline-block;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.pv2-d-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px;margin-top:16px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);color:var(--p-text-color, #334155);font-size:13px;cursor:pointer}.pv2-btn:hover{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca)}\n"] }]
2799
+ args: [{ selector: "profiler_v2", providers: [{ provide: LocalizationService, useClass: AdmProfilerV2Loc }], standalone: false, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span>\r\n </div>\r\n <div class=\"card-body widget-body pv2-body\">\r\n <!-- Barra dei comandi: quali dati caricare. Ogni cambio ricarica la vista e il dettaglio aperto -->\r\n <div class=\"pv2-toolbar\">\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Sorgente' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"live\" (click)=\"setLive(true)\"><span class=\"pv2-live-dot\"></span>Live</button>\r\n <button type=\"button\" [class.pv2-on]=\"!live\" (click)=\"setLive(false)\">{{'Storico' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n <div class=\"pv2-field pv2-field-wide pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"instance\" (ngModelChange)=\"setInstance($event)\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanze' | localize: lc\"></form-select>\r\n </div>\r\n </div>\r\n\r\n @if (!live) {\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterfrom\" (ngModelChange)=\"filterfrom = $event; datesChanged()\" name=\"filterfrom\" [Placeholder]=\"'Dal' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterto\" (ngModelChange)=\"filterto = $event; datesChanged()\" name=\"filterto\" [Placeholder]=\"'Al' | localize: lc\"></form-datetime>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Valori' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"!snapValues\" (click)=\"setSnapValues(false)\">{{\"Dall'avvio\" | localize: lc}}</button>\r\n <button type=\"button\" [class.pv2-on]=\"snapValues\" (click)=\"setSnapValues(true)\">{{\"Dall'ultimo snapshot\" | localize: lc}}</button>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"pv2-cluster pv2-cluster-end\">\r\n <button type=\"button\" class=\"btn app-btn-search\" [disabled]=\"loading\" (click)=\"reloadAll()\" [title]=\"'Aggiorna' | localize: lc\">\r\n <i class=\"fa fa-refresh\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n <button type=\"button\" class=\"btn app-btn-search\" (click)=\"downloadWorkloadReport()\" [title]=\"(workloadV2 ? 'Workload report' : 'Scarica il workload report') | localize: lc\">\r\n <i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Riga della finestra: sempre visibile sopra la vista -->\r\n <div class=\"pv2-window\">\r\n <span><strong>{{live ? 'Live' : ('Storico' | localize: lc)}}</strong> &middot; {{instanceLabel}}</span>\r\n @if (current?.snapFrom; as snapFrom) {\r\n @if (live) {\r\n <span>{{\"Delta dall'ultimo snapshot delle\" | localize: lc}} {{hhmm(snapFrom)}} ({{minutesAgo(snapFrom)}} {{'min fa' | localize: lc}})</span>\r\n } @else {\r\n <span>{{'Snapshot dalle' | localize: lc}} {{ddmmhhmm(snapFrom)}} {{'alle' | localize: lc}} {{ddmmhhmm(current?.snapTo)}}</span>\r\n }\r\n } @else if (current && !live) {\r\n <span class=\"pv2-warn-text\">{{'Nessuno snapshot termina nella finestra scelta' | localize: lc}}</span>\r\n }\r\n @if (view == 'tree' && tree?.idleNode) {\r\n <span>{{tree.numNodes | pv2fmt: 'int'}} {{\"nodi nell'albero\" | localize: lc}} &middot; {{tree.numReturnedNodes | pv2fmt: 'int'}} {{'nella risposta' | localize: lc}}</span>\r\n }\r\n @if (view == 'flat' && flat) {\r\n <span>{{flat.numItems | pv2fmt: 'int'}} {{'eventi distinti' | localize: lc}}</span>\r\n }\r\n @if (loading) {\r\n <span class=\"pv2-muted\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Caricamento\u2026' | localize: lc}}</span>\r\n }\r\n </div>\r\n\r\n <div class=\"pv2-main\">\r\n <!-- Vista: albero o eventi per nome -->\r\n <div class=\"pv2-panel pv2-view\">\r\n <div class=\"pv2-view-bar\">\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"view == 'tree'\" (click)=\"setView('tree')\"><i class=\"fa fa-sitemap\"></i> {{'Albero' | localize: lc}}</button>\r\n <button type=\"button\" [class.pv2-on]=\"view == 'flat'\" (click)=\"setView('flat')\"><i class=\"fa fa-list\"></i> {{'Per nome' | localize: lc}}</button>\r\n </div>\r\n\r\n @if (view == 'tree') {\r\n <div class=\"pv2-field pv2-field-search\" [title]=\"'Per esempio MRD_METERREADINGS, ENQUEUE, ProfilesMgr' | localize: lc\">\r\n <form-input [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"searchText\" (ngModelChange)=\"searchText = $event; searchChanged()\" name=\"search\" [Placeholder]=\"'Cerca nei nomi o per id' | localize: lc\"></form-input>\r\n </div>\r\n <div class=\"pv2-field pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"orderBy\" (ngModelChange)=\"setOrderBy($event)\" name=\"orderBy\" [Source]=\"TreeOrderOptions\" [Placeholder]=\"'Ordina per' | localize: lc\"></form-select>\r\n </div>\r\n <div class=\"pv2-group\" [class.pv2-disabled]=\"!!activeSearch\">\r\n <span class=\"pv2-group-label\">{{'Figli per nodo' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n @for (o of ChildrenOptions; track o.id) {\r\n <button type=\"button\" [disabled]=\"!!activeSearch\" [class.pv2-on]=\"maxChildren == o.id\" (click)=\"setMaxChildren(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"pv2-group\" [class.pv2-disabled]=\"!!activeSearch\">\r\n <span class=\"pv2-group-label\">{{'Soglia' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n @for (o of ThresholdOptions; track o.id) {\r\n <button type=\"button\" [disabled]=\"!!activeSearch\" [class.pv2-on]=\"minPercentage == o.id\" (click)=\"setMinPercentage(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"pv2-field pv2-field-search\">\r\n <form-input [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"flatSearch\" (ngModelChange)=\"flatSearch = $event; flatSearchChanged()\" name=\"flatSearch\" [Placeholder]=\"'Cerca nei nomi' | localize: lc\"></form-input>\r\n </div>\r\n <div class=\"pv2-field pv2-field-narrow pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"flatType\" (ngModelChange)=\"flatType = $event; flatChanged()\" name=\"flatType\" [Source]=\"FlatTypes\" [Placeholder]=\"'Tipo' | localize: lc\"></form-select>\r\n </div>\r\n <div class=\"pv2-field pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"flatOrderBy\" (ngModelChange)=\"flatOrderBy = $event; flatChanged()\" name=\"flatOrderBy\" [Source]=\"FlatOrderOptions\" [Placeholder]=\"'Ordina per' | localize: lc\"></form-select>\r\n </div>\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Righe' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n @for (o of FlatRows; track o.id) {\r\n <button type=\"button\" [class.pv2-on]=\"flatTop == o.id\" (click)=\"setFlatTop(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"pv2-toggle\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [ngModel]=\"flatIncludeIdle\" (ngModelChange)=\"flatIncludeIdle = $event; flatChanged()\" name=\"flatIncludeIdle\"></form-checkbox>\r\n <span class=\"pv2-pointer\" (click)=\"flatIncludeIdle = !flatIncludeIdle; flatChanged()\">{{'Anche gli eventi idle' | localize: lc}}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (view == 'tree') {\r\n <!-- Percorso della radice: ogni antenato riporta l'albero a quel nodo -->\r\n @if (tree?.idleNode && tree?.rootPath?.length) {\r\n <nav class=\"pv2-crumbs\">\r\n @for (item of tree.rootPath; track item.nodeId) {\r\n <button type=\"button\" class=\"pv2-crumb\" [title]=\"item.nodeName\" (click)=\"setRoot(item.nodeId)\">{{item.nodeName}}</button>\r\n <span class=\"pv2-crumb-sep\">&rsaquo;</span>\r\n }\r\n <span class=\"pv2-crumb pv2-crumb-current\" [title]=\"tree.idleNode.nodeName\">{{tree.idleNode.nodeName}}</span>\r\n </nav>\r\n }\r\n\r\n @if (treeNotice) {\r\n <div class=\"pv2-alert pv2-alert-warn\">\r\n {{treeNotice}}\r\n <button type=\"button\" class=\"pv2-alert-close\" [title]=\"'Chiudi' | localize: lc\" (click)=\"treeNotice = null\">&times;</button>\r\n </div>\r\n }\r\n @if (activeSearch && tree) {\r\n @if (matchCount > 0) {\r\n <div class=\"pv2-alert\" [class.pv2-alert-warn]=\"tree.truncated\">\r\n {{matchCount | pv2fmt: 'int'}} {{'nodi trovati, con i loro antenati.' | localize: lc}}\r\n @if (tree.truncated) {\r\n <strong>{{'I nodi trovati sono pi\u00F9 di 1.000: sono mostrati i primi per l\\'ordinamento scelto.' | localize: lc}}</strong>\r\n }\r\n </div>\r\n } @else if (!treeLoading) {\r\n <div class=\"pv2-alert\">{{'Nessun nodo contiene' | localize: lc}} &laquo;{{activeSearch}}&raquo;.</div>\r\n }\r\n }\r\n @if (treeError) {\r\n <div class=\"pv2-alert pv2-alert-error\">{{treeError}}</div>\r\n }\r\n\r\n <div class=\"pv2-table-wrap\" tabindex=\"0\" (keydown)=\"treeKeydown($event)\">\r\n <table class=\"pv2-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"pv2-col-node\">{{'Nodo' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Chiamate' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Tempo' | localize: lc}}</th>\r\n <th>{{snapMode ? '\u0394 ' : ''}}{{'% del padre' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{(snapMode ? '\u0394 Proprio' : 'Tempo proprio') | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Medio' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Picco' | localize: lc}}</th>\r\n @if (live) {\r\n <th class=\"pv2-num\">{{'Thread ora' | localize: lc}}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (row of rows; track row.key) {\r\n @if (row.kind == 'node') {\r\n <tr [id]=\"'pv2-row-' + row.node.nodeId\" class=\"pv2-row\"\r\n [class.pv2-selected]=\"row.node.nodeId == selectedId\"\r\n [class.pv2-idle]=\"isIdle(row.node.eventTypeName, row.node.waitClassName)\"\r\n (click)=\"rowClicked(row.node)\" (dblclick)=\"toggle(row.node)\">\r\n <td class=\"pv2-col-node\">\r\n <div class=\"pv2-node\" [style.padding-left.px]=\"row.depth * 16\">\r\n @if (hasChildren(row.node)) {\r\n <button type=\"button\" class=\"pv2-caret\" tabindex=\"-1\" [attr.aria-expanded]=\"isExpanded(row.node)\" (click)=\"toggle(row.node, $event)\">\r\n <i class=\"fa\" [class.fa-caret-down]=\"isExpanded(row.node)\" [class.fa-caret-right]=\"!isExpanded(row.node)\"></i>\r\n </button>\r\n } @else {\r\n <span class=\"pv2-caret\"></span>\r\n }\r\n <span class=\"pv2-type\"><span class=\"pv2-dot\" [style.background]=\"typeColor(row.node.eventTypeName, row.node.waitClassName)\"></span>{{typeLabel(row.node.eventTypeName, row.node.waitClassName)}}</span>\r\n <span class=\"pv2-name\" [title]=\"row.node.nodeName\">@if (row.node.searchMatch && activeSearch) {@for (part of nameParts(row.node.nodeName, activeSearch); track $index) {@if (part.hit) {<mark>{{part.text}}</mark>} @else {<span>{{part.text}}</span>}}} @else {<span>{{row.node.nodeName}}</span>}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{calls(row.node) | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{time(row.node) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-perc\" [title]=\"(parentPerc(row.node) | pv2fmt: 'pct') + ' ' + ('del padre' | localize: lc) + ' \u00B7 ' + (firstLevelPerc(row.node) | pv2fmt: 'pct') + ' ' + ('del nodo di primo livello' | localize: lc)\">\r\n <div class=\"pv2-perc-cell\">\r\n <div class=\"pv2-bar\"><div [style.width.%]=\"parentPerc(row.node)\" [style.background]=\"typeColor(row.node.eventTypeName, row.node.waitClassName)\"></div></div>\r\n <span>{{parentPerc(row.node) | pv2fmt: 'pct'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{self(row.node) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{avg(row.node) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{peak(row.node) | pv2fmt: 'dur'}}</td>\r\n @if (live) {\r\n <td class=\"pv2-num pv2-threads\">\r\n @if (isLongRunning(row.node.eventTypeName, row.node.waitClassName, row.node.activeMaxTime)) {\r\n <span class=\"pv2-long\" [title]=\"('Esecuzione in corso da' | localize: lc) + ' ' + duration(row.node.activeMaxTime) + ': ' + ('forse bloccata' | localize: lc)\"><i class=\"fa fa-clock\"></i> {{duration(row.node.activeMaxTime)}}</span>\r\n }\r\n @if (row.node.activeThreads > 0) {\r\n <span class=\"pv2-active\"><span class=\"pv2-active-dot\"></span>{{row.node.activeThreads}}</span>\r\n } @else {\r\n <span class=\"pv2-muted\">{{row.node.activeThreads ?? '\u2014'}}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n } @else if (row.kind == 'loading') {\r\n <tr class=\"pv2-service\">\r\n <td [attr.colspan]=\"live ? 8 : 7\">\r\n <div [style.padding-left.px]=\"row.depth * 16 + 24\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Caricamento dei figli\u2026' | localize: lc}}</div>\r\n </td>\r\n </tr>\r\n } @else {\r\n <tr class=\"pv2-service\">\r\n <td [attr.colspan]=\"live ? 8 : 7\">\r\n <div [style.padding-left.px]=\"row.depth * 16 + 24\">\r\n {{row.node.omittedChildren | pv2fmt: 'int'}} {{'figli non mostrati' | localize: lc}} &middot; {{omittedTime(row.node) | pv2fmt: 'dur'}}\r\n @if (!snapMode) {\r\n &middot; {{row.node.omittedCalls | pv2fmt: 'int'}} {{'chiamate' | localize: lc}}\r\n }\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"showAll(row.node, $event)\">{{'Mostra tutti' | localize: lc}}</button>\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n @if (rows.length == 0 && !treeError) {\r\n <div class=\"pv2-empty\">\r\n @if (!tree) {\r\n {{'Caricamento\u2026' | localize: lc}}\r\n } @else if (!tree.snapFrom && !live) {\r\n {{'Nessuno snapshot termina nella finestra scelta: allargala o spostala indietro.' | localize: lc}}\r\n } @else {\r\n {{\"Il nodo non c'\u00E8 nelle istanze scelte.\" | localize: lc}}\r\n }\r\n </div>\r\n }\r\n </div>\r\n } @else {\r\n @if (flatError) {\r\n <div class=\"pv2-alert pv2-alert-error\">{{flatError}}</div>\r\n }\r\n <div class=\"pv2-table-wrap\">\r\n <table class=\"pv2-table\">\r\n <thead>\r\n <tr>\r\n <th class=\"pv2-col-node\">{{'Evento' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Percorsi' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Chiamate' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{(snapMode ? '\u0394 Proprio' : 'Tempo proprio') | localize: lc}}</th>\r\n <th>{{snapMode ? '\u0394 ' : ''}}{{'% proprio' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Tempo' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{snapMode ? '\u0394 ' : ''}}{{'Medio' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{(snapMode ? \"Picco dall'avvio\" : 'Picco') | localize: lc}}</th>\r\n @if (live) {\r\n <th class=\"pv2-num\">{{'Thread' | localize: lc}}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (item of flat?.items ?? []; track flatKey(item)) {\r\n <tr class=\"pv2-row\" [class.pv2-idle]=\"isIdle(item.eventTypeName, item.waitClassName)\" [class.pv2-selected]=\"openFlat.has(flatKey(item))\" (click)=\"toggleFlat(item)\">\r\n <td class=\"pv2-col-node\">\r\n <div class=\"pv2-node\">\r\n <span class=\"pv2-caret\"><i class=\"fa\" [class.fa-caret-down]=\"openFlat.has(flatKey(item))\" [class.fa-caret-right]=\"!openFlat.has(flatKey(item))\"></i></span>\r\n <span class=\"pv2-type\"><span class=\"pv2-dot\" [style.background]=\"typeColor(item.eventTypeName, item.waitClassName)\"></span>{{typeLabel(item.eventTypeName, item.waitClassName)}}</span>\r\n <span class=\"pv2-name\" [title]=\"item.nodeName\">@for (part of nameParts(item.nodeName, (flatSearch ?? '').trim()); track $index) {@if (part.hit) {<mark>{{part.text}}</mark>} @else {<span>{{part.text}}</span>}}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{item.numPaths | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{flatCalls(item) | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{flatSelf(item) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-perc\">\r\n <div class=\"pv2-perc-cell\">\r\n <div class=\"pv2-bar\"><div [style.width.%]=\"flatPerc(item)\" [style.background]=\"typeColor(item.eventTypeName, item.waitClassName)\"></div></div>\r\n <span>{{flatPerc(item) | pv2fmt: 'pct'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"pv2-num\">{{flatTime(item) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{flatAvg(item) | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{item.peakTime | pv2fmt: 'dur'}}</td>\r\n @if (live) {\r\n <td class=\"pv2-num pv2-threads\">\r\n @if (item.activeThreads > 0) {\r\n <span class=\"pv2-active\"><span class=\"pv2-active-dot\"></span>{{item.activeThreads}}</span>\r\n } @else {\r\n <span class=\"pv2-muted\">{{item.activeThreads ?? '\u2014'}}</span>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n @if (openFlat.has(flatKey(item))) {\r\n <tr class=\"pv2-sub\">\r\n <td [attr.colspan]=\"live ? 9 : 8\">\r\n <div class=\"pv2-sub-title\">{{'Nodi con pi\u00F9 tempo' | localize: lc}}</div>\r\n @for (id of item.nodeIds ?? []; track id) {\r\n <div class=\"pv2-sub-item\">\r\n <code>{{id}}</code>\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"showDetail(id, $event)\">{{'Dettaglio' | localize: lc}}</button>\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"openInTree(id, $event)\">{{\"Apri nell'albero\" | localize: lc}}</button>\r\n </div>\r\n }\r\n @if (item.numPaths > (item.nodeIds?.length ?? 0)) {\r\n <div class=\"pv2-muted\">+{{item.numPaths - (item.nodeIds?.length ?? 0) | pv2fmt: 'int'}} {{'altri' | localize: lc}}</div>\r\n }\r\n </td>\r\n </tr>\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n @if (!flatError && (!flat || !flat.items?.length)) {\r\n <div class=\"pv2-empty\">{{(flat ? 'Nessun evento con questi filtri.' : 'Caricamento\u2026') | localize: lc}}</div>\r\n }\r\n </div>\r\n @if (flat?.items?.length) {\r\n <div class=\"pv2-footer\">\r\n {{flat.numItems | pv2fmt: 'int'}} {{'eventi distinti' | localize: lc}}@if (flat.numItems > flat.items.length) {, {{'mostrati i primi' | localize: lc}} {{flat.items.length | pv2fmt: 'int'}}}.\r\n {{'La percentuale \u00E8 sul tempo proprio di tutti gli eventi non idle.' | localize: lc}}\r\n </div>\r\n }\r\n }\r\n </div>\r\n\r\n <!-- Dettaglio del nodo selezionato, lo stesso per le due viste -->\r\n <aside class=\"pv2-panel pv2-detail\" [class.pv2-stale]=\"detailStale\">\r\n @if (!selectedId) {\r\n <div class=\"pv2-placeholder\">{{'Seleziona un nodo per vederne il dettaglio.' | localize: lc}}</div>\r\n } @else if (detailMissing && !detailLoading) {\r\n <div class=\"pv2-placeholder\">{{\"Il nodo non c'\u00E8 nelle istanze o nella finestra scelte.\" | localize: lc}}</div>\r\n } @else if (detailError && !detailLoading) {\r\n <div class=\"pv2-placeholder pv2-error-text\">{{detailError}}</div>\r\n } @else if (!detail) {\r\n <div class=\"pv2-placeholder\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Caricamento\u2026' | localize: lc}}</div>\r\n } @else {\r\n <div class=\"pv2-d-head\">\r\n <span class=\"pv2-type\"><span class=\"pv2-dot\" [style.background]=\"typeColor(detail.eventTypeName, detail.waitClassName)\"></span>{{typeLabel(detail.eventTypeName, detail.waitClassName)}}</span>\r\n @if (detailLoading) {\r\n <i class=\"fa fa-spinner fa-spin pv2-muted\"></i>\r\n }\r\n </div>\r\n <div class=\"pv2-fullname\">{{detail.nodeName}}</div>\r\n <div class=\"pv2-id\">\r\n Id <code #idText>{{detail.nodeId}}</code>\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"copyId(idText)\">{{(copied ? 'Copiato' : 'Copia') | localize: lc}}</button>\r\n @if (detailsV2Enabled) {\r\n <button type=\"button\" class=\"pv2-link\" (click)=\"openFullDetail()\">{{'Dettaglio completo' | localize: lc}}</button>\r\n }\r\n </div>\r\n\r\n <div class=\"pv2-d-title\">{{'Percorso' | localize: lc}}</div>\r\n <div class=\"pv2-path\">\r\n @for (item of detail.fullWaitStack ?? []; track item.nodeId; let i = $index) {\r\n <button type=\"button\" class=\"pv2-path-item\" [style.padding-left.px]=\"i * 10\" [title]=\"item.nodeName\" (click)=\"select(item.nodeId)\">\r\n <span class=\"pv2-dot\" [style.background]=\"typeColor(item.eventTypeName, item.waitClassName)\"></span>{{item.nodeName}}\r\n </button>\r\n }\r\n <div class=\"pv2-path-item pv2-path-current\" [style.padding-left.px]=\"(detail.fullWaitStack?.length ?? 0) * 10\" [title]=\"detail.nodeName\">\r\n <span class=\"pv2-dot\" [style.background]=\"typeColor(detail.eventTypeName, detail.waitClassName)\"></span>{{detail.nodeName}}\r\n </div>\r\n </div>\r\n\r\n <div class=\"pv2-d-title\">{{(live ? \"Dall'avvio\" : 'Nella finestra') | localize: lc}}</div>\r\n <dl class=\"pv2-kv\">\r\n <dt>{{'Esecuzioni' | localize: lc}}</dt><dd>{{detail.executions | pv2fmt: 'int'}}</dd>\r\n <dt>{{'Tempo totale' | localize: lc}}</dt><dd>{{detail.elapsedTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Tempo proprio' | localize: lc}}</dt><dd>{{detail.elapsedTimeLessChildren | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Medio' | localize: lc}}</dt><dd>{{detail.avgTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Picco' | localize: lc}}</dt><dd>{{detail.peakTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Minimo' | localize: lc}}</dt><dd>{{detail.minTime ? (detail.minTime | pv2fmt: 'dur') : '\u2014'}}</dd>\r\n </dl>\r\n\r\n @if (live) {\r\n <div class=\"pv2-d-title\">{{\"Dall'ultimo snapshot\" | localize: lc}}, {{hhmm(detail.snapFrom)}}</div>\r\n <dl class=\"pv2-kv\">\r\n <dt>{{'Esecuzioni' | localize: lc}}</dt><dd>{{detail.snapDeltaExecutions | pv2fmt: 'int'}}</dd>\r\n <dt>{{'Tempo totale' | localize: lc}}</dt><dd>{{detail.snapDeltaElapsedTime | pv2fmt: 'dur'}}</dd>\r\n <dt>{{'Tempo proprio' | localize: lc}}</dt><dd>{{detail.snapDeltaElapsedTimeLessChildren | pv2fmt: 'dur'}}</dd>\r\n </dl>\r\n\r\n <div class=\"pv2-d-title\">{{'Adesso' | localize: lc}}</div>\r\n <dl class=\"pv2-kv\">\r\n <dt>{{'Thread dentro' | localize: lc}}</dt>\r\n <dd>\r\n @if (detail.activeThreads > 0) {\r\n <span class=\"pv2-active\"><span class=\"pv2-active-dot\"></span>{{detail.activeThreads}}</span>\r\n } @else {\r\n {{detail.activeThreads ?? '\u2014'}}\r\n }\r\n </dd>\r\n <dt>{{'Esecuzione pi\u00F9 lunga' | localize: lc}}</dt>\r\n <dd>\r\n @if (detail.activeThreads > 0) {\r\n {{detail.activeMaxTime | pv2fmt: 'dur'}}\r\n @if (isLongRunning(detail.eventTypeName, detail.waitClassName, detail.activeMaxTime)) {\r\n <span class=\"pv2-long\"><i class=\"fa fa-clock\"></i> {{'forse bloccata' | localize: lc}}</span>\r\n }\r\n } @else {\r\n \u2014\r\n }\r\n </dd>\r\n <dt>{{'Ultima uscita' | localize: lc}}</dt><dd>{{relative(detail.lastExitTime)}}</dd>\r\n </dl>\r\n }\r\n\r\n @if (typeParts.length > 0) {\r\n <div class=\"pv2-d-title\">{{'Tempo proprio del sottoalbero per tipo' | localize: lc}}</div>\r\n <div class=\"pv2-stack\">\r\n @for (part of typeParts; track part.type) {\r\n <div [style.width.%]=\"part.percentage\" [style.background]=\"part.color\" [title]=\"part.label + ' ' + (part.percentage | pv2fmt: 'pct')\"></div>\r\n }\r\n </div>\r\n <div class=\"pv2-legend\">\r\n @for (part of typeParts; track part.type) {\r\n <span class=\"pv2-legend-item\"><span class=\"pv2-swatch\" [style.background]=\"part.color\"></span>{{part.label}} <strong>{{part.percentage | pv2fmt: 'pct'}}</strong></span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"pv2-d-title\">{{'Sessioni attive sul nodo e sui discendenti' | localize: lc}}</div>\r\n @if (chart) {\r\n <div class=\"pv2-chart\">\r\n <div class=\"pv2-chart-y\">\r\n <span>{{axisValue(chart.max)}}</span>\r\n <span>{{axisValue(chart.max / 2)}}</span>\r\n <span>0</span>\r\n </div>\r\n <div class=\"pv2-chart-plot\">\r\n <svg viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\" aria-hidden=\"true\">\r\n <line x1=\"0\" y1=\"50\" x2=\"100\" y2=\"50\" class=\"pv2-chart-grid\" vector-effect=\"non-scaling-stroke\" />\r\n <path [attr.d]=\"chart.area\" [attr.fill]=\"chart.color\" fill-opacity=\"0.25\" />\r\n <path [attr.d]=\"chart.line\" [attr.stroke]=\"chart.color\" fill=\"none\" stroke-width=\"1.5\" vector-effect=\"non-scaling-stroke\" />\r\n </svg>\r\n <span class=\"pv2-chart-last\" [style.left.%]=\"chart.lastX\" [style.top.%]=\"chart.lastY\" [style.background]=\"chart.color\"></span>\r\n </div>\r\n <span></span>\r\n <div class=\"pv2-chart-x\">\r\n <span>{{chart.start}}</span>\r\n <span>{{chart.middle}}</span>\r\n <span>{{chart.end}}</span>\r\n </div>\r\n </div>\r\n <div class=\"pv2-caption\">\r\n {{'Media' | localize: lc}} {{axisValue(chart.average)}} &middot; {{'picco' | localize: lc}} {{axisValue(chart.peak)}} {{'sessioni' | localize: lc}}.\r\n {{chart.points | pv2fmt: 'int'}} {{\"punti dell'API\" | localize: lc}},\r\n @if (chart.interval == 1) {\r\n {{'uno al secondo' | localize: lc}},\r\n } @else {\r\n {{'uno ogni' | localize: lc}} {{chart.interval}} s,\r\n }\r\n {{'raggruppati a' | localize: lc}} {{chart.group}} s\r\n </div>\r\n } @else {\r\n <div class=\"pv2-muted pv2-small\">{{'Nessun campione in memoria per questa finestra: il grafico copre solo le ultime due ore circa.' | localize: lc}}</div>\r\n }\r\n\r\n @if (detail.instances?.length) {\r\n <div class=\"pv2-d-title\">{{'Per istanza' | localize: lc}}</div>\r\n <table class=\"pv2-mini\">\r\n <thead>\r\n <tr>\r\n <th>{{'Istanza' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Esecuzioni' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Tempo' | localize: lc}}</th>\r\n <th class=\"pv2-num\">{{'Proprio' | localize: lc}}</th>\r\n @if (live) {\r\n <th class=\"pv2-num\">{{'Thread' | localize: lc}}</th>\r\n }\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (inst of detail.instances; track inst.instanceId) {\r\n <tr>\r\n <td><span class=\"pv2-ellipsis\" [title]=\"inst.instanceId\">{{inst.instanceId}}</span></td>\r\n <td class=\"pv2-num\">{{inst.executions | pv2fmt: 'int'}}</td>\r\n <td class=\"pv2-num\">{{inst.elapsedTime | pv2fmt: 'dur'}}</td>\r\n <td class=\"pv2-num\">{{inst.elapsedTimeLessChildren | pv2fmt: 'dur'}}</td>\r\n @if (live) {\r\n <td class=\"pv2-num\">{{inst.activeThreads ?? '\u2014'}}</td>\r\n }\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n\r\n <div class=\"pv2-d-foot\">\r\n <span class=\"pv2-muted\">{{detail.numChildren | pv2fmt: 'int'}} {{'figli diretti' | localize: lc}} &middot; {{detail.numDescendants | pv2fmt: 'int'}} {{'discendenti' | localize: lc}}</span>\r\n <button type=\"button\" class=\"pv2-btn\" (click)=\"setRoot(detail.nodeId)\"><i class=\"fa fa-sitemap\"></i> {{'Apri come radice' | localize: lc}}</button>\r\n </div>\r\n }\r\n </aside>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Dettaglio completo del nodo (DirectorFeature.DetailsV2) -->\r\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\r\n @if (detailsV2Enabled) {\r\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"!!topActV2Enabled\" [CanOpenProfiler]=\"true\" (closed)=\"dlgDetailsV2.hide()\"\r\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"rootFromDetails($event)\"></adm-details-v2>\r\n }\r\n</div>\r\n", styles: ["@charset \"UTF-8\";:host{display:block}:host ::ng-deep .pv2-noclear .p-select-clear-icon{display:none}.pv2-body{container-type:inline-size}.pv2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;padding-top:6px}.pv2-cluster{display:flex;flex-wrap:nowrap;align-items:center;gap:10px}.pv2-cluster-end{margin-left:auto}.pv2-field{width:190px}.pv2-field-wide{width:290px}.pv2-field-narrow{width:140px}.pv2-field-search{flex:1 1 220px;min-width:200px;max-width:340px}.pv2-toggle{display:flex;align-items:center;gap:8px;height:39px;white-space:nowrap}.pv2-pointer{cursor:pointer}.pv2-group{position:relative;display:inline-flex}.pv2-group.pv2-disabled{opacity:.5}.pv2-group-label{position:absolute;top:-8px;left:8px;z-index:1;padding:0 4px;background:var(--p-content-background, #fff);color:var(--p-text-muted-color, #64748b);font-size:12px;line-height:15px;white-space:nowrap;pointer-events:none}.pv2-seg{display:inline-flex;height:39px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden;background:var(--p-content-background, #fff)}.pv2-seg button{display:inline-flex;align-items:center;gap:6px;padding:0 12px;border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;color:var(--p-text-color, #334155);font-size:13px;white-space:nowrap;cursor:pointer}.pv2-seg button:first-child{border-left:0}.pv2-seg button:hover:not(.pv2-on):not(:disabled){background:var(--p-content-hover-background, #f8fafc)}.pv2-seg button:disabled{cursor:default}.pv2-seg button:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:-2px}.pv2-seg button.pv2-on{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca);font-weight:500;box-shadow:inset 0 -2px 0 var(--p-primary-color, #6366f1)}.pv2-live-dot{width:8px;height:8px;border-radius:50%;background:#16a34a}.pv2-window{display:flex;flex-wrap:wrap;align-items:center;row-gap:4px;margin-top:12px;padding:7px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-color, #334155);font-size:13px}.pv2-window>span+span:before{content:\"\\b7\";margin:0 10px;color:var(--p-text-muted-color, #64748b)}.pv2-warn-text{color:#92400e}.pv2-main{display:grid;grid-template-columns:minmax(0,1fr) 380px;gap:14px;align-items:start;margin-top:14px}@container (max-width: 1350px){.pv2-main{grid-template-columns:minmax(0,1fr)}.pv2-detail{position:static;max-height:none}}.pv2-panel{padding:12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);min-width:0}.pv2-view-bar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px;padding-top:6px;margin-bottom:10px}.pv2-crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;margin-bottom:8px;font-size:12px}.pv2-crumb{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:2px 6px;border:0;border-radius:4px;background:transparent;color:var(--p-primary-color, #6366f1);cursor:pointer}.pv2-crumb:hover{background:var(--p-highlight-background, #eef2ff)}.pv2-crumb-current{color:var(--p-text-color, #334155);font-weight:500;cursor:default}.pv2-crumb-current:hover{background:transparent}.pv2-crumb-sep{color:var(--p-text-muted-color, #64748b)}.pv2-alert{position:relative;margin-bottom:8px;padding:6px 30px 6px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-size:13px}.pv2-alert.pv2-alert-warn{border-color:#fcd34d;background:#fffbeb;color:#92400e}.pv2-alert.pv2-alert-error{border-color:#fca5a5;background:#fef2f2;color:#991b1b}.pv2-alert-close{position:absolute;top:3px;right:6px;border:0;background:transparent;color:inherit;font-size:16px;cursor:pointer}.pv2-table-wrap{max-height:68vh;overflow:auto;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px)}.pv2-table-wrap:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:1px}.pv2-table{width:100%;border-collapse:separate;border-spacing:0;font-size:13px;color:var(--p-text-color, #334155)}.pv2-table th{position:sticky;top:0;z-index:1;padding:7px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-muted-color, #64748b);font-size:12px;font-weight:500;white-space:nowrap;text-align:left}.pv2-table td{padding:4px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);white-space:nowrap;vertical-align:middle}.pv2-col-node{width:100%;max-width:0}.pv2-col-node .pv2-node{min-width:260px}.pv2-num{text-align:right!important;font-variant-numeric:tabular-nums}.pv2-row{cursor:pointer}.pv2-row:hover td{background:var(--p-content-hover-background, #f8fafc)}.pv2-row.pv2-selected td{background:var(--p-highlight-background, #eef2ff)}.pv2-row.pv2-idle td{color:var(--p-text-muted-color, #64748b)}.pv2-row.pv2-idle td .pv2-name{opacity:.75}.pv2-node{display:flex;align-items:center;gap:6px;min-width:0}.pv2-caret{flex:none;width:18px;height:20px;padding:0;border:0;background:transparent;color:var(--p-text-muted-color, #64748b);text-align:center;cursor:pointer}.pv2-type{flex:none;display:inline-flex;align-items:center;gap:5px;padding:0 6px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:10px;color:var(--p-text-muted-color, #64748b);font-size:11px;line-height:18px;white-space:nowrap}.pv2-dot{flex:none;display:inline-block;width:8px;height:8px;border-radius:50%}.pv2-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pv2-name mark{padding:0 1px;border-radius:2px;background:#fde68a;color:#1f2937}.pv2-perc{width:1%}.pv2-perc-cell{display:flex;align-items:center;gap:8px}.pv2-bar{flex:none;width:64px;height:7px;border-radius:2px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc);box-shadow:inset 0 0 0 1px var(--p-content-border-color, #e2e8f0)}.pv2-bar>div{height:100%}.pv2-threads>*+*{margin-left:8px}.pv2-active{display:inline-flex;align-items:center;gap:5px;font-weight:500}.pv2-active-dot{width:7px;height:7px;border-radius:50%;background:#16a34a;box-shadow:0 0 0 3px #16a34a2e}.pv2-long{display:inline-flex;align-items:center;gap:4px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:18px;white-space:nowrap}.pv2-service td{padding:5px 10px;color:var(--p-text-muted-color, #64748b);font-size:12px;background:var(--p-content-background, #fff)}.pv2-sub td{padding:8px 10px 10px 34px;background:var(--p-content-hover-background, #f8fafc);white-space:normal}.pv2-sub-title{margin-bottom:4px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-sub-item{display:flex;align-items:center;gap:10px;padding:2px 0}.pv2-sub-item code{font-size:12px}.pv2-link{margin-left:6px;padding:0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;cursor:pointer}.pv2-link:hover{text-decoration:underline}.pv2-empty{padding:28px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-footer{margin-top:8px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-muted{color:var(--p-text-muted-color, #64748b)}.pv2-small{font-size:12px}.pv2-detail{position:sticky;top:10px;max-height:calc(100vh - 20px);overflow:auto;font-size:13px;color:var(--p-text-color, #334155);transition:opacity .15s}.pv2-detail.pv2-stale{opacity:.55}.pv2-placeholder{padding:36px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-error-text{color:#dc2626}.pv2-d-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.pv2-fullname{max-height:140px;overflow:auto;padding:8px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-family:ui-monospace,Cascadia Mono,Consolas,monospace;font-size:12px;white-space:pre-wrap;word-break:break-word}.pv2-id{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-id code{font-size:12px}.pv2-d-title{margin:16px 0 6px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}.pv2-path{display:flex;flex-direction:column}.pv2-path-item{display:flex;align-items:center;gap:6px;max-width:100%;padding:2px 0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.pv2-path-item:hover{text-decoration:underline}.pv2-path-current{color:var(--p-text-color, #334155);font-weight:600;cursor:default}.pv2-path-current:hover{text-decoration:none}.pv2-kv{display:grid;grid-template-columns:auto 1fr;gap:3px 14px;margin:0}.pv2-kv dt{color:var(--p-text-muted-color, #64748b);font-weight:400}.pv2-kv dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}.pv2-stack{display:flex;height:12px;border-radius:3px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc)}.pv2-legend{display:flex;flex-wrap:wrap;gap:4px 12px;margin-top:6px;font-size:12px}.pv2-legend-item{display:inline-flex;align-items:center;gap:5px}.pv2-swatch{width:10px;height:10px;border-radius:2px}.pv2-chart{display:grid;grid-template-columns:auto 1fr;gap:2px 6px}.pv2-chart-y{display:flex;flex-direction:column;justify-content:space-between;height:110px;color:var(--p-text-muted-color, #64748b);font-size:11px;text-align:right;line-height:1}.pv2-chart-plot{position:relative;height:110px;border-left:1px solid var(--p-content-border-color, #e2e8f0);border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-chart-plot svg{display:block;width:100%;height:100%}.pv2-chart-grid{stroke:var(--p-content-border-color, #e2e8f0);stroke-dasharray:3 3}.pv2-chart-last{position:absolute;width:8px;height:8px;border:2px solid var(--p-content-background, #fff);border-radius:50%;transform:translate(-50%,-50%)}.pv2-chart-x{display:flex;justify-content:space-between;color:var(--p-text-muted-color, #64748b);font-size:11px}.pv2-caption{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-mini{width:100%;font-size:12px}.pv2-mini th{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-weight:500}.pv2-mini td{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-ellipsis{display:inline-block;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.pv2-d-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px;margin-top:16px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);color:var(--p-text-color, #334155);font-size:13px;cursor:pointer}.pv2-btn:hover{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca)}\n"] }]
1977
2800
  }], ctorParameters: () => [{ type: i1$1.DateService }, { type: i1.LocalizationService }, { type: i3.PreferencesService }, { type: i1$1.InterComService }, { type: i4.ActivatedRoute }, { type: i4.Router }, { type: i5.Location }, { type: AdminModuleBaseService }, { type: undefined, decorators: [{
1978
2801
  type: Inject,
1979
2802
  args: [ADM_MODULE_PATH]
@@ -1982,7 +2805,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
1982
2805
  }, {
1983
2806
  type: Inject,
1984
2807
  args: [ADM_WORKLOAD_V2]
1985
- }] }] });
2808
+ }] }, { type: undefined, decorators: [{
2809
+ type: Optional
2810
+ }, {
2811
+ type: Inject,
2812
+ args: [ADM_DETAILS_V2]
2813
+ }] }, { type: undefined, decorators: [{
2814
+ type: Optional
2815
+ }, {
2816
+ type: Inject,
2817
+ args: [ADM_TOPACT_V2]
2818
+ }] }], propDecorators: { dlgDetailsV2: [{
2819
+ type: ViewChild,
2820
+ args: ["dlgDetailsV2"]
2821
+ }], detailsV2: [{
2822
+ type: ViewChild,
2823
+ args: [AdmDetailsV2Component]
2824
+ }] } });
1986
2825
 
1987
2826
  // Workload report v2 (specifica "Workload report"): richieste e risposte come le vuole e le manda il backend (camelCase).
1988
2827
  // Le date delle risposte sono UTC "dd/MM/yyyy HH:mm:ss" senza fuso
@@ -3849,7 +4688,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
3849
4688
 
3850
4689
  // Angular
3851
4690
  class AdmTopActivitiesComponent {
3852
- constructor(dateExts, lc, localStorage, location, intercom, route, adms, mod) {
4691
+ constructor(dateExts, lc, localStorage, location, intercom, route, adms, mod, router,
4692
+ // Con DirectorFeature.DetailsV2 il backend-for-frontend risponde a GetNodeStats e GetSessionStats solo con il contratto nuovo:
4693
+ // nodi e sessioni si aprono nel dettaglio v2 anche da questa pagina
4694
+ detailsV2Enabled, profilerV2Enabled) {
3853
4695
  this.dateExts = dateExts;
3854
4696
  this.lc = lc;
3855
4697
  this.localStorage = localStorage;
@@ -3858,6 +4700,9 @@ class AdmTopActivitiesComponent {
3858
4700
  this.route = route;
3859
4701
  this.adms = adms;
3860
4702
  this.mod = mod;
4703
+ this.router = router;
4704
+ this.detailsV2Enabled = detailsV2Enabled;
4705
+ this.profilerV2Enabled = profilerV2Enabled;
3861
4706
  this.searchView = new TopActivitiesDataView();
3862
4707
  this.autoUpdate = false;
3863
4708
  this.seconds = "5";
@@ -3959,6 +4804,38 @@ class AdmTopActivitiesComponent {
3959
4804
  this.searchView.searchinprogress = false;
3960
4805
  this.reviewBindings(update, res, dirinfos);
3961
4806
  }
4807
+ openNodeDetails(nodeId) {
4808
+ if (this.detailsV2Enabled) {
4809
+ this.detailsV2.openNode(nodeId, { ...this.detailsWindow(), global: this.searchView.filterglobal });
4810
+ this.dlgDetailsV2.show();
4811
+ return;
4812
+ }
4813
+ this.loadNodeDetails(nodeId);
4814
+ this.dlgNodeDetails.show();
4815
+ }
4816
+ openSessionDetails(sessionId, serialNo, instanceid) {
4817
+ if (this.detailsV2Enabled) {
4818
+ this.detailsV2.openSession(instanceid, sessionId, serialNo, { ...this.detailsWindow(), realTime: !!this.searchView.filterrealtime });
4819
+ this.dlgDetailsV2.show();
4820
+ return;
4821
+ }
4822
+ this.loadSessionDetails(sessionId, serialNo, instanceid);
4823
+ this.dlgSessionDetails.show();
4824
+ }
4825
+ // La finestra della ricerca, di default l'ultima ora
4826
+ detailsWindow() {
4827
+ let to = this.searchView.filterto ? this.dateExts.getDateConvertion(this.searchView.filterto).toDate() : new Date();
4828
+ let from = this.searchView.filterfrom ? this.dateExts.getDateConvertion(this.searchView.filterfrom).toDate() : new Date(to.getTime() - 3600 * 1000);
4829
+ return { from: from, to: to };
4830
+ }
4831
+ // Senza la Top Activity v2 "Sessioni su questo evento" non si propone; il nodo come radice c'è solo nel profiler v2
4832
+ showEventSessions(link) {
4833
+ this.dlgDetailsV2.hide();
4834
+ }
4835
+ openInProfiler(nodeId) {
4836
+ this.dlgDetailsV2.hide();
4837
+ this.router.navigate([`/pages/${this.mod}/profiler`, ...(this.be ? [this.be] : [])], { queryParams: { root: nodeId } });
4838
+ }
3962
4839
  loadNodeDetails(nodeId) {
3963
4840
  this.NodeDetails = null;
3964
4841
  requestAnimationFrame(async () => {
@@ -4064,53 +4941,38 @@ class AdmTopActivitiesComponent {
4064
4941
  this.SelectedSessions = new LineChartData(series);
4065
4942
  });
4066
4943
  }
4067
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivitiesComponent, deps: [{ token: i1$1.DateService }, { token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i5.Location }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: AdminModuleBaseService }, { token: ADM_MODULE_PATH }], target: i0.ɵɵFactoryTarget.Component }); }
4068
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.34", type: AdmTopActivitiesComponent, isStandalone: false, selector: "topact_search", providers: [{ provide: LocalizationService, useClass: AdmTopActivitieLoc }], ngImport: i0, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n <span *ngIf=\"DirInfos && !DirInfosGlobal\">&nbsp;-&nbsp;\r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span>&nbsp;\r\n <span *ngIf=\"DirInfosGlobal\">&nbsp;|&nbsp;\r\n {{'' + DirInfosGlobal.cpus + ' ' + ('CPU (Global)' | localize: lc) + (DirInfosGlobal.rssplan ? ' - ' + DirInfosGlobal.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfosGlobal.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfosGlobal.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfosGlobal.lavg15 | number : '1.1-2' : 'it'}}\r\n <span *ngIf=\"(DirInfosGlobal?.perinstancedata?.length || 0) > 0\">\r\n &nbsp;\r\n <a class=\"app-link app-pointer app-inline\" (click)=\"dlgDirInfos.show();\">[{{'Info per Istanza' | localize: lc}}...]</a>\r\n </span>\r\n </span>&nbsp;\r\n </span>\r\n </div>\r\n <div class=\"card-body widget-body\">\r\n <div class=\"col-md-12 app-relative\">\r\n <form role=\"form\">\r\n <div class=\"row app-first-filter-line\">\r\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\r\n <form-datetime [readonly]=\"autoUpdate\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\r\n <form-datetime [readonly]=\"autoUpdate\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\" style=\"display: flex; height: 38px;\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterglobal\" name=\"filterglobal\"></form-checkbox>&nbsp;\r\n <span class=\"app-pointer app-padding-top-5 app-padding-left-5\" (click)=\"searchView.filterglobal = !searchView.filterglobal\">{{'Globale' | localize: lc}}</span>\r\n </div>\r\n <button [disabled]=\"searchView.searchinprogress || autoUpdate\" class=\"input-group-addon btn app-btn-search app-margin-top-20\" (click)=\"sendSearch()\" type=\"submit\"><i class=\"fa fa-search\"></i></button>\r\n\r\n <div class=\"app-absolute app-right-25 app-top-40\">\r\n <div class=\"pull-right\">\r\n {{'Aggiorna ogni' | localize: lc}}&nbsp;<input [readonly]=\"autoUpdate\" maxlength=\"3\" class=\"form-control app-updevery-input\" type=\"text\" [(ngModel)]=\"seconds\" name=\"seconds\" />&nbsp;{{'secondo/i' | localize: lc}}\r\n </div>\r\n <div class=\"pull-right m-t-2 app-margin-right-5\">\r\n <label class=\"switch\">\r\n <input type=\"checkbox\" [(ngModel)]=\"autoUpdate\" name=\"autoUpdate\" (ngModelChange)=\"autoUpdateChanged();\" />\r\n <div class=\"slider round\"></div>\r\n </label>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n </div>\r\n </div>\r\n </form>\r\n </div>\r\n <div class=\"row\">\r\n <div class=\"col-md-12 app-margin-top-5\">\r\n <p *ngIf=\"!searchView\"><em>{{'Carico i Dati' | localize: lc}}</em></p>\r\n <div *ngIf=\"searchView\" class=\"row\">\r\n <div class=\"col-md-12 app-no-padding\">\r\n <div style=\"width: 100%; height: 290px\">\r\n <es-line-chart *ngIf=\"TopActiveSessions\"\r\n [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [LegendPadding]=\"{top: 0, bottom: 7, right: 0, left: 10}\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"TopActiveSessions\"\r\n [Legend]=\"true\" \r\n name=\"topactsession\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (onSelectionChanged)=\"dataSelectionChanged($event)\" (chartLoaded)=\"onChartLoaded($event)\"></es-line-chart>\r\n </div>\r\n </div>\r\n <div class=\"col-md-5\">\r\n <h5>{{'Prime Istruzioni' | localize: lc}}</h5>\r\n <es-table [(ngModel)]=\"TopNodes\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">{{'Nodo' | localize: lc}}</th>\r\n <th>{{'Descrizione Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n <ng-template #body let-node>\r\n <td class=\"app-col-min\"><span class=\"app-link\" (click)=\"loadNodeDetails(node.profnodeid); dlgNodeDetails.show();\">{{node.profnodeid}}</span></td>\r\n <td><span title=\"{{node.profnodedesc}}\">{{node.profnodedesc.length > 40 ? node.profnodedesc.substr(0,40) + \"...\" : node.profnodedesc}}</span></td>\r\n <td class=\"app-nowrap\">{{node.activity | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{node.nodetypename}}</td>\r\n <td>{{node.waitclassname}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n <div class=\"col-md-7\">\r\n <h5>{{'Prime Sessioni' | localize: lc}}</h5>\r\n <es-table [(ngModel)]=\"TopSessions\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">ID</th>\r\n <th>{{'Utente' | localize: lc}}</th>\r\n <th>{{'Tenant' | localize : lc}}</th>\r\n <th>{{'Processo' | localize: lc}}</th>\r\n <th>{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th>Cpu</th>\r\n <th>Wait</th>\r\n <th>DB</th>\r\n <th>Script</th>\r\n <th>Throttle</th>\r\n <th>Sleep</th>\r\n <th>Networking</th>\r\n <th>IO</th>\r\n </ng-template>\r\n\r\n <ng-template #body let-session>\r\n <td class=\"app-col-min\"><span class=\"app-link\" title=\"{{session.instanceid? (' - ' + session.instanceid) : ''}}\" (click)=\"loadSessionDetails(session.sid, session.serial, session.instanceid); dlgSessionDetails.show();\">{{session.sid}}</span></td>\r\n <td>{{session.user}}</td>\r\n <td>{{session.tenant}}</td>\r\n <td>{{session.bgprocess}}</td>\r\n <td>{{session.activity | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.cpu | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.wait | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.db | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.script | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.throttle | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.sleep | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.net | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.io | number : '1.1-2' : 'it'}} %</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgDirInfos=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <div class=\"modal-dialog modal-feminist\" emaDraggable>\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title pull-left\">{{'Dettaglio per Istanza' | localize: lc}}</h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"dlgDirInfos.hide()\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\r\n </div>\r\n <div class=\"modal-body\" *ngIf=\"(DirInfosGlobal?.perinstancedata?.length || 0) > 0\">\r\n <div class=\"row\" *ngFor=\"let info of DirInfosGlobal.perinstancedata\">\r\n <div class=\"col-md-12\"> \r\n <strong>{{info.instance}}</strong>:&nbsp;\r\n {{'' + info.cpus + ' ' + ('CPU (Global)' | localize: lc) + (info.rssplan ? ' - ' + info.rssplan : '')}}&nbsp;\r\n Load average: {{ info.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ info.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ info.lavg15 | number : '1.1-2' : 'it'}}\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"dlgDirInfos.hide()\">{{'Chiudi' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <node-detail *ngIf=\"NodeDetails\" [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\r\n</div>\r\n\r\n<div bsModal #dlgSessionDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <div class=\"modal-dialog modal-feminist\" emaDraggable>\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title pull-left\">{{'Dettaglio Sessione' | localize: lc}}<span *ngIf=\"SessionDetails\">&nbsp;{{SessionDetails.sid}}</span></h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"dlgSessionDetails.hide()\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\r\n </div>\r\n <div class=\"modal-body\" *ngIf=\"SessionDetails\">\r\n <div class=\"row\">\r\n <div *ngIf=\"SessionDetails.instanceid\" class=\"col-md-6\"><strong>{{'Istanza' | localize: lc}}</strong>:&nbsp;{{SessionDetails.instanceid}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Seriale' | localize: lc}}</strong>:&nbsp;{{SessionDetails.serial}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Stato' | localize: lc}}</strong>:&nbsp;{{SessionDetails.status}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Tipo' | localize: lc}}</strong>:&nbsp;{{SessionDetails.type}}</div>\r\n <div class=\"col-md-6\"><strong>{{'Utente' | localize: lc}}</strong>:&nbsp;{{SessionDetails.user}}&nbsp;<span *ngIf=\"SessionDetails.tenant\">({{SessionDetails.tenant}})</span></div>\r\n </div>\r\n\r\n <div style=\"display: flex; width: 100%; margin-top: 15px;\">\r\n <div style=\"flex-grow: 0;display: flex;flex-direction: column\">\r\n <h5>Prime Istruzioni</h5>\r\n <div *ngIf=\"SelectedTopNodes\">\r\n <es-table [(ngModel)]=\"SelectedTopNodes\" [ArraymodeItemsPerPage]=\"10\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">{{'Nodo' | localize: lc}}</th>\r\n <th>{{'Descrizione Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n \r\n <ng-template #body let-node>\r\n <td class=\"app-col-min\"><span class=\"app-link\"(click)=\"loadNodeDetails(node.profnodeid); dlgNodeDetails.show();\">{{node.profnodeid}}</span></td>\r\n <td><span title=\"{{node.profnodedesc}}\">{{node.profnodedesc.length > 40 ? node.profnodedesc.substr(0,40) + \"...\" : node.profnodedesc}}</span></td>\r\n <td class=\"app-nowrap\">{{(node.activity == \"NaN\" ? null : node.activity) | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{node.nodetypename}}</td>\r\n <td>{{node.waitclassname}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n <div style=\"width: 15px;\"></div>\r\n <div style=\"flex-grow: 2;display: flex;flex-direction: column\">\r\n <h5>Attivit\u00E0</h5>\r\n <div *ngIf=\"SelectedSessions\" style=\"width: 100%; height: 290px\">\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [LegendPadding]=\"{top: 0, bottom: 7, right: 0, left: 10}\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"SelectedSessions\"\r\n [Legend]=\"true\" \r\n name=\"session_details\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event, true)\">\r\n </es-line-chart>\r\n </div>\r\n \r\n </div>\r\n </div>\r\n <div style=\"display: flex; width: 100%;\">\r\n <div style=\"flex-grow: 1;\">\r\n <h5>Statistiche Thread</h5>\r\n <div>\r\n <es-table [(ngModel)]=\"SessionDetails.threads\" [ArraymodeItemsPerPage]=\"10\" [Selection]=\"true\" [SingleSelection]=\"true\" (onSelectionChanged)=\"threadSelectionChanged($event)\">\r\n <ng-template #header>\r\n <th>Thread</th>\r\n <th>Stato</th>\r\n <th>Tipo</th>\r\n <th>API</th>\r\n <th>Attesa corrente</th>\r\n <th>Nodo di attesa</th>\r\n <th>Attesa su</th>\r\n <th>Classe</th>\r\n <th>Par. 1</th>\r\n <th>Par. 2</th>\r\n <th>Par. 3</th>\r\n <th>Tempo Attesa</th>\r\n </ng-template>\r\n \r\n <ng-template #body let-thread>\r\n <td>{{thread.tid}}</td>\r\n <td>{{thread.status}}</td>\r\n <td>{{thread.type}}</td>\r\n <td>{{thread.api}}</td>\r\n <td>{{thread.wait}}</td>\r\n <td>{{thread.waitnode}}</td>\r\n <td>{{thread.waiteventtype}}</td>\r\n <td>{{thread.waitclassname}}</td>\r\n <td>{{thread.waitpar1}}</td>\r\n <td>{{thread.waitpar2}}</td>\r\n <td>{{thread.waitpar3}}</td>\r\n <td>{{(thread.waittime == \"NaN\" ? null : thread.waittime) | number : '1.1-2' : 'it'}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"dlgSessionDetails.hide()\">{{'Chiudi' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i7.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "component", type: i8.EsTableComponent, selector: "es-table", inputs: ["globalCheck", "autoUpdate", "seconds", "researchInProgress", "globalColVisCheck", "EsThTdProvider", "CornerMenuOptions", "ColumnsResizable", "ColumnsPinnable", "AutoUpdate", "Height", "EmptySpaceBackgroundColor", "EsTableHandledSearch", "MaxHeight", "ContainerClass", "XLSXExport", "CSVExport", "AllSearch", "HighCellDensity", "Selection", "ShowLoadingOnBootstrap", "Removal", "RemovalCondition", "Export", "ShiftClick", "CountLabel", "HidePaging", "HidePagingCount", "HidePagingButtons", "ContextMenu", "ExportFileName", "TableClass", "ExportFunction", "ExportOnlyVisibleColumns", "HasHeaderGroup", "HasSecondaryHeaderGroup", "HeaderHidden", "BodyHidden", "SelectionDisabled", "SingleSelection", "RowClassAssigner", "OrderByColumn", "MultipleOrderingDirectives", "HiddenColumns", "ColumnsOrdering", "SearchView", "SelectAll", "UseArrayModePaging", "DynamicRowColumnsDefinition", "DynamicOperations", "Hierarchy", "ParentKey", "OwnKey", "AutoSortHierarchy", "StartsExpanded", "SavePreferences", "DefaultAlignment", "PagingStyle", "RowGroupingPagingStyle", "ItemSourceProperty", "UseSelectionCache", "ShowItemGroupsColumns", "Editable", "RangeSelection", "SearchThrottle", "ArraymodeItemsPerPage"], outputs: ["globalCheckChange", "autoUpdateChange", "secondsChange", "researchInProgressChange", "globalColVisCheckChange", "onOrderChanged", "onSearchRequest", "onSelectionChanged", "onRemoval", "onAbortRemoval", "onModelChange", "onOpenContextMenu", "onCornerAction", "onDynamicOperation"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "component", type: i2.EsLineChartComponent, selector: "es-line-chart", inputs: ["Data", "DataArray", "Step", "DataGroupBucketSize", "DataGroupingThreshold", "StrokeSize", "AllowGaps", "MergeDatasets", "FinalInstants", "Min", "Max", "Fill", "Stacked"] }, { kind: "directive", type: i10.Draggable, selector: "[emaDraggable]", inputs: ["emaDraggable"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: NodeDetailComponent, selector: "node-detail", inputs: ["NodeDetails"], outputs: ["onClose"] }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }] }); }
4944
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivitiesComponent, deps: [{ token: i1$1.DateService }, { token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i5.Location }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: AdminModuleBaseService }, { token: ADM_MODULE_PATH }, { token: i4.Router }, { token: ADM_DETAILS_V2, optional: true }, { token: ADM_PROFILER_V2, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
4945
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmTopActivitiesComponent, isStandalone: false, selector: "topact_search", providers: [{ provide: LocalizationService, useClass: AdmTopActivitieLoc }], viewQueries: [{ propertyName: "dlgNodeDetails", first: true, predicate: ["dlgNodeDetails"], descendants: true }, { propertyName: "dlgSessionDetails", first: true, predicate: ["dlgSessionDetails"], descendants: true }, { propertyName: "dlgDetailsV2", first: true, predicate: ["dlgDetailsV2"], descendants: true }, { propertyName: "detailsV2", first: true, predicate: AdmDetailsV2Component, descendants: true }], ngImport: i0, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n <span *ngIf=\"DirInfos && !DirInfosGlobal\">&nbsp;-&nbsp;\r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span>&nbsp;\r\n <span *ngIf=\"DirInfosGlobal\">&nbsp;|&nbsp;\r\n {{'' + DirInfosGlobal.cpus + ' ' + ('CPU (Global)' | localize: lc) + (DirInfosGlobal.rssplan ? ' - ' + DirInfosGlobal.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfosGlobal.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfosGlobal.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfosGlobal.lavg15 | number : '1.1-2' : 'it'}}\r\n <span *ngIf=\"(DirInfosGlobal?.perinstancedata?.length || 0) > 0\">\r\n &nbsp;\r\n <a class=\"app-link app-pointer app-inline\" (click)=\"dlgDirInfos.show();\">[{{'Info per Istanza' | localize: lc}}...]</a>\r\n </span>\r\n </span>&nbsp;\r\n </span>\r\n </div>\r\n <div class=\"card-body widget-body\">\r\n <div class=\"col-md-12 app-relative\">\r\n <form role=\"form\">\r\n <div class=\"row app-first-filter-line\">\r\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\r\n <form-datetime [readonly]=\"autoUpdate\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\r\n <form-datetime [readonly]=\"autoUpdate\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\" style=\"display: flex; height: 38px;\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterglobal\" name=\"filterglobal\"></form-checkbox>&nbsp;\r\n <span class=\"app-pointer app-padding-top-5 app-padding-left-5\" (click)=\"searchView.filterglobal = !searchView.filterglobal\">{{'Globale' | localize: lc}}</span>\r\n </div>\r\n <button [disabled]=\"searchView.searchinprogress || autoUpdate\" class=\"input-group-addon btn app-btn-search app-margin-top-20\" (click)=\"sendSearch()\" type=\"submit\"><i class=\"fa fa-search\"></i></button>\r\n\r\n <div class=\"app-absolute app-right-25 app-top-40\">\r\n <div class=\"pull-right\">\r\n {{'Aggiorna ogni' | localize: lc}}&nbsp;<input [readonly]=\"autoUpdate\" maxlength=\"3\" class=\"form-control app-updevery-input\" type=\"text\" [(ngModel)]=\"seconds\" name=\"seconds\" />&nbsp;{{'secondo/i' | localize: lc}}\r\n </div>\r\n <div class=\"pull-right m-t-2 app-margin-right-5\">\r\n <label class=\"switch\">\r\n <input type=\"checkbox\" [(ngModel)]=\"autoUpdate\" name=\"autoUpdate\" (ngModelChange)=\"autoUpdateChanged();\" />\r\n <div class=\"slider round\"></div>\r\n </label>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n </div>\r\n </div>\r\n </form>\r\n </div>\r\n <div class=\"row\">\r\n <div class=\"col-md-12 app-margin-top-5\">\r\n <p *ngIf=\"!searchView\"><em>{{'Carico i Dati' | localize: lc}}</em></p>\r\n <div *ngIf=\"searchView\" class=\"row\">\r\n <div class=\"col-md-12 app-no-padding\">\r\n <div style=\"width: 100%; height: 290px\">\r\n <es-line-chart *ngIf=\"TopActiveSessions\"\r\n [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [LegendPadding]=\"{top: 0, bottom: 7, right: 0, left: 10}\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"TopActiveSessions\"\r\n [Legend]=\"true\" \r\n name=\"topactsession\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (onSelectionChanged)=\"dataSelectionChanged($event)\" (chartLoaded)=\"onChartLoaded($event)\"></es-line-chart>\r\n </div>\r\n </div>\r\n <div class=\"col-md-5\">\r\n <h5>{{'Prime Istruzioni' | localize: lc}}</h5>\r\n <es-table [(ngModel)]=\"TopNodes\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">{{'Nodo' | localize: lc}}</th>\r\n <th>{{'Descrizione Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n <ng-template #body let-node>\r\n <td class=\"app-col-min\"><span class=\"app-link\" (click)=\"openNodeDetails(node.profnodeid)\">{{node.profnodeid}}</span></td>\r\n <td><span title=\"{{node.profnodedesc}}\">{{node.profnodedesc.length > 40 ? node.profnodedesc.substr(0,40) + \"...\" : node.profnodedesc}}</span></td>\r\n <td class=\"app-nowrap\">{{node.activity | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{node.nodetypename}}</td>\r\n <td>{{node.waitclassname}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n <div class=\"col-md-7\">\r\n <h5>{{'Prime Sessioni' | localize: lc}}</h5>\r\n <es-table [(ngModel)]=\"TopSessions\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">ID</th>\r\n <th>{{'Utente' | localize: lc}}</th>\r\n <th>{{'Tenant' | localize : lc}}</th>\r\n <th>{{'Processo' | localize: lc}}</th>\r\n <th>{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th>Cpu</th>\r\n <th>Wait</th>\r\n <th>DB</th>\r\n <th>Script</th>\r\n <th>Throttle</th>\r\n <th>Sleep</th>\r\n <th>Networking</th>\r\n <th>IO</th>\r\n </ng-template>\r\n\r\n <ng-template #body let-session>\r\n <td class=\"app-col-min\"><span class=\"app-link\" title=\"{{session.instanceid? (' - ' + session.instanceid) : ''}}\" (click)=\"openSessionDetails(session.sid, session.serial, session.instanceid)\">{{session.sid}}</span></td>\r\n <td>{{session.user}}</td>\r\n <td>{{session.tenant}}</td>\r\n <td>{{session.bgprocess}}</td>\r\n <td>{{session.activity | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.cpu | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.wait | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.db | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.script | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.throttle | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.sleep | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.net | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.io | number : '1.1-2' : 'it'}} %</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgDirInfos=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <div class=\"modal-dialog modal-feminist\" emaDraggable>\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title pull-left\">{{'Dettaglio per Istanza' | localize: lc}}</h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"dlgDirInfos.hide()\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\r\n </div>\r\n <div class=\"modal-body\" *ngIf=\"(DirInfosGlobal?.perinstancedata?.length || 0) > 0\">\r\n <div class=\"row\" *ngFor=\"let info of DirInfosGlobal.perinstancedata\">\r\n <div class=\"col-md-12\"> \r\n <strong>{{info.instance}}</strong>:&nbsp;\r\n {{'' + info.cpus + ' ' + ('CPU (Global)' | localize: lc) + (info.rssplan ? ' - ' + info.rssplan : '')}}&nbsp;\r\n Load average: {{ info.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ info.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ info.lavg15 | number : '1.1-2' : 'it'}}\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"dlgDirInfos.hide()\">{{'Chiudi' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <node-detail *ngIf=\"NodeDetails\" [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\r\n</div>\r\n\r\n<div bsModal #dlgSessionDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <div class=\"modal-dialog modal-feminist\" emaDraggable>\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title pull-left\">{{'Dettaglio Sessione' | localize: lc}}<span *ngIf=\"SessionDetails\">&nbsp;{{SessionDetails.sid}}</span></h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"dlgSessionDetails.hide()\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\r\n </div>\r\n <div class=\"modal-body\" *ngIf=\"SessionDetails\">\r\n <div class=\"row\">\r\n <div *ngIf=\"SessionDetails.instanceid\" class=\"col-md-6\"><strong>{{'Istanza' | localize: lc}}</strong>:&nbsp;{{SessionDetails.instanceid}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Seriale' | localize: lc}}</strong>:&nbsp;{{SessionDetails.serial}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Stato' | localize: lc}}</strong>:&nbsp;{{SessionDetails.status}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Tipo' | localize: lc}}</strong>:&nbsp;{{SessionDetails.type}}</div>\r\n <div class=\"col-md-6\"><strong>{{'Utente' | localize: lc}}</strong>:&nbsp;{{SessionDetails.user}}&nbsp;<span *ngIf=\"SessionDetails.tenant\">({{SessionDetails.tenant}})</span></div>\r\n </div>\r\n\r\n <div style=\"display: flex; width: 100%; margin-top: 15px;\">\r\n <div style=\"flex-grow: 0;display: flex;flex-direction: column\">\r\n <h5>Prime Istruzioni</h5>\r\n <div *ngIf=\"SelectedTopNodes\">\r\n <es-table [(ngModel)]=\"SelectedTopNodes\" [ArraymodeItemsPerPage]=\"10\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">{{'Nodo' | localize: lc}}</th>\r\n <th>{{'Descrizione Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n \r\n <ng-template #body let-node>\r\n <td class=\"app-col-min\"><span class=\"app-link\"(click)=\"loadNodeDetails(node.profnodeid); dlgNodeDetails.show();\">{{node.profnodeid}}</span></td>\r\n <td><span title=\"{{node.profnodedesc}}\">{{node.profnodedesc.length > 40 ? node.profnodedesc.substr(0,40) + \"...\" : node.profnodedesc}}</span></td>\r\n <td class=\"app-nowrap\">{{(node.activity == \"NaN\" ? null : node.activity) | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{node.nodetypename}}</td>\r\n <td>{{node.waitclassname}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n <div style=\"width: 15px;\"></div>\r\n <div style=\"flex-grow: 2;display: flex;flex-direction: column\">\r\n <h5>Attivit\u00E0</h5>\r\n <div *ngIf=\"SelectedSessions\" style=\"width: 100%; height: 290px\">\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [LegendPadding]=\"{top: 0, bottom: 7, right: 0, left: 10}\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"SelectedSessions\"\r\n [Legend]=\"true\" \r\n name=\"session_details\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event, true)\">\r\n </es-line-chart>\r\n </div>\r\n \r\n </div>\r\n </div>\r\n <div style=\"display: flex; width: 100%;\">\r\n <div style=\"flex-grow: 1;\">\r\n <h5>Statistiche Thread</h5>\r\n <div>\r\n <es-table [(ngModel)]=\"SessionDetails.threads\" [ArraymodeItemsPerPage]=\"10\" [Selection]=\"true\" [SingleSelection]=\"true\" (onSelectionChanged)=\"threadSelectionChanged($event)\">\r\n <ng-template #header>\r\n <th>Thread</th>\r\n <th>Stato</th>\r\n <th>Tipo</th>\r\n <th>API</th>\r\n <th>Attesa corrente</th>\r\n <th>Nodo di attesa</th>\r\n <th>Attesa su</th>\r\n <th>Classe</th>\r\n <th>Par. 1</th>\r\n <th>Par. 2</th>\r\n <th>Par. 3</th>\r\n <th>Tempo Attesa</th>\r\n </ng-template>\r\n \r\n <ng-template #body let-thread>\r\n <td>{{thread.tid}}</td>\r\n <td>{{thread.status}}</td>\r\n <td>{{thread.type}}</td>\r\n <td>{{thread.api}}</td>\r\n <td>{{thread.wait}}</td>\r\n <td>{{thread.waitnode}}</td>\r\n <td>{{thread.waiteventtype}}</td>\r\n <td>{{thread.waitclassname}}</td>\r\n <td>{{thread.waitpar1}}</td>\r\n <td>{{thread.waitpar2}}</td>\r\n <td>{{thread.waitpar3}}</td>\r\n <td>{{(thread.waittime == \"NaN\" ? null : thread.waittime) | number : '1.1-2' : 'it'}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"dlgSessionDetails.hide()\">{{'Chiudi' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Dettaglio v2 di nodo e sessione (DirectorFeature.DetailsV2) -->\r\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\r\n @if (detailsV2Enabled) {\r\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"false\" [CanOpenProfiler]=\"!!profilerV2Enabled\" (closed)=\"dlgDetailsV2.hide()\"\r\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"openInProfiler($event)\"></adm-details-v2>\r\n }\r\n</div>\r\n", dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i7.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "component", type: i8.EsTableComponent, selector: "es-table", inputs: ["globalCheck", "autoUpdate", "seconds", "researchInProgress", "globalColVisCheck", "EsThTdProvider", "CornerMenuOptions", "ColumnsResizable", "ColumnsPinnable", "AutoUpdate", "Height", "EmptySpaceBackgroundColor", "EsTableHandledSearch", "MaxHeight", "ContainerClass", "XLSXExport", "CSVExport", "AllSearch", "HighCellDensity", "Selection", "ShowLoadingOnBootstrap", "Removal", "RemovalCondition", "Export", "ShiftClick", "CountLabel", "HidePaging", "HidePagingCount", "HidePagingButtons", "ContextMenu", "ExportFileName", "TableClass", "ExportFunction", "ExportOnlyVisibleColumns", "HasHeaderGroup", "HasSecondaryHeaderGroup", "HeaderHidden", "BodyHidden", "SelectionDisabled", "SingleSelection", "RowClassAssigner", "OrderByColumn", "MultipleOrderingDirectives", "HiddenColumns", "ColumnsOrdering", "SearchView", "SelectAll", "UseArrayModePaging", "DynamicRowColumnsDefinition", "DynamicOperations", "Hierarchy", "ParentKey", "OwnKey", "AutoSortHierarchy", "StartsExpanded", "SavePreferences", "DefaultAlignment", "PagingStyle", "RowGroupingPagingStyle", "ItemSourceProperty", "UseSelectionCache", "ShowItemGroupsColumns", "Editable", "RangeSelection", "SearchThrottle", "ArraymodeItemsPerPage"], outputs: ["globalCheckChange", "autoUpdateChange", "secondsChange", "researchInProgressChange", "globalColVisCheckChange", "onOrderChanged", "onSearchRequest", "onSelectionChanged", "onRemoval", "onAbortRemoval", "onModelChange", "onOpenContextMenu", "onCornerAction", "onDynamicOperation"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "component", type: i2.EsLineChartComponent, selector: "es-line-chart", inputs: ["Data", "DataArray", "Step", "DataGroupBucketSize", "DataGroupingThreshold", "StrokeSize", "AllowGaps", "MergeDatasets", "FinalInstants", "Min", "Max", "Fill", "Stacked"] }, { kind: "directive", type: i10.Draggable, selector: "[emaDraggable]", inputs: ["emaDraggable"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: AdmDetailsV2Component, selector: "adm-details-v2", inputs: ["Be", "CanShowSessions", "CanOpenProfiler"], outputs: ["closed", "sessionsOnEvent", "openProfiler"] }, { kind: "component", type: NodeDetailComponent, selector: "node-detail", inputs: ["NodeDetails"], outputs: ["onClose"] }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }] }); }
4069
4946
  }
4070
4947
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivitiesComponent, decorators: [{
4071
4948
  type: Component,
4072
- args: [{ selector: "topact_search", providers: [{ provide: LocalizationService, useClass: AdmTopActivitieLoc }], standalone: false, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n <span *ngIf=\"DirInfos && !DirInfosGlobal\">&nbsp;-&nbsp;\r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span>&nbsp;\r\n <span *ngIf=\"DirInfosGlobal\">&nbsp;|&nbsp;\r\n {{'' + DirInfosGlobal.cpus + ' ' + ('CPU (Global)' | localize: lc) + (DirInfosGlobal.rssplan ? ' - ' + DirInfosGlobal.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfosGlobal.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfosGlobal.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfosGlobal.lavg15 | number : '1.1-2' : 'it'}}\r\n <span *ngIf=\"(DirInfosGlobal?.perinstancedata?.length || 0) > 0\">\r\n &nbsp;\r\n <a class=\"app-link app-pointer app-inline\" (click)=\"dlgDirInfos.show();\">[{{'Info per Istanza' | localize: lc}}...]</a>\r\n </span>\r\n </span>&nbsp;\r\n </span>\r\n </div>\r\n <div class=\"card-body widget-body\">\r\n <div class=\"col-md-12 app-relative\">\r\n <form role=\"form\">\r\n <div class=\"row app-first-filter-line\">\r\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\r\n <form-datetime [readonly]=\"autoUpdate\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\r\n <form-datetime [readonly]=\"autoUpdate\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\" style=\"display: flex; height: 38px;\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterglobal\" name=\"filterglobal\"></form-checkbox>&nbsp;\r\n <span class=\"app-pointer app-padding-top-5 app-padding-left-5\" (click)=\"searchView.filterglobal = !searchView.filterglobal\">{{'Globale' | localize: lc}}</span>\r\n </div>\r\n <button [disabled]=\"searchView.searchinprogress || autoUpdate\" class=\"input-group-addon btn app-btn-search app-margin-top-20\" (click)=\"sendSearch()\" type=\"submit\"><i class=\"fa fa-search\"></i></button>\r\n\r\n <div class=\"app-absolute app-right-25 app-top-40\">\r\n <div class=\"pull-right\">\r\n {{'Aggiorna ogni' | localize: lc}}&nbsp;<input [readonly]=\"autoUpdate\" maxlength=\"3\" class=\"form-control app-updevery-input\" type=\"text\" [(ngModel)]=\"seconds\" name=\"seconds\" />&nbsp;{{'secondo/i' | localize: lc}}\r\n </div>\r\n <div class=\"pull-right m-t-2 app-margin-right-5\">\r\n <label class=\"switch\">\r\n <input type=\"checkbox\" [(ngModel)]=\"autoUpdate\" name=\"autoUpdate\" (ngModelChange)=\"autoUpdateChanged();\" />\r\n <div class=\"slider round\"></div>\r\n </label>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n </div>\r\n </div>\r\n </form>\r\n </div>\r\n <div class=\"row\">\r\n <div class=\"col-md-12 app-margin-top-5\">\r\n <p *ngIf=\"!searchView\"><em>{{'Carico i Dati' | localize: lc}}</em></p>\r\n <div *ngIf=\"searchView\" class=\"row\">\r\n <div class=\"col-md-12 app-no-padding\">\r\n <div style=\"width: 100%; height: 290px\">\r\n <es-line-chart *ngIf=\"TopActiveSessions\"\r\n [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [LegendPadding]=\"{top: 0, bottom: 7, right: 0, left: 10}\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"TopActiveSessions\"\r\n [Legend]=\"true\" \r\n name=\"topactsession\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (onSelectionChanged)=\"dataSelectionChanged($event)\" (chartLoaded)=\"onChartLoaded($event)\"></es-line-chart>\r\n </div>\r\n </div>\r\n <div class=\"col-md-5\">\r\n <h5>{{'Prime Istruzioni' | localize: lc}}</h5>\r\n <es-table [(ngModel)]=\"TopNodes\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">{{'Nodo' | localize: lc}}</th>\r\n <th>{{'Descrizione Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n <ng-template #body let-node>\r\n <td class=\"app-col-min\"><span class=\"app-link\" (click)=\"loadNodeDetails(node.profnodeid); dlgNodeDetails.show();\">{{node.profnodeid}}</span></td>\r\n <td><span title=\"{{node.profnodedesc}}\">{{node.profnodedesc.length > 40 ? node.profnodedesc.substr(0,40) + \"...\" : node.profnodedesc}}</span></td>\r\n <td class=\"app-nowrap\">{{node.activity | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{node.nodetypename}}</td>\r\n <td>{{node.waitclassname}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n <div class=\"col-md-7\">\r\n <h5>{{'Prime Sessioni' | localize: lc}}</h5>\r\n <es-table [(ngModel)]=\"TopSessions\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">ID</th>\r\n <th>{{'Utente' | localize: lc}}</th>\r\n <th>{{'Tenant' | localize : lc}}</th>\r\n <th>{{'Processo' | localize: lc}}</th>\r\n <th>{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th>Cpu</th>\r\n <th>Wait</th>\r\n <th>DB</th>\r\n <th>Script</th>\r\n <th>Throttle</th>\r\n <th>Sleep</th>\r\n <th>Networking</th>\r\n <th>IO</th>\r\n </ng-template>\r\n\r\n <ng-template #body let-session>\r\n <td class=\"app-col-min\"><span class=\"app-link\" title=\"{{session.instanceid? (' - ' + session.instanceid) : ''}}\" (click)=\"loadSessionDetails(session.sid, session.serial, session.instanceid); dlgSessionDetails.show();\">{{session.sid}}</span></td>\r\n <td>{{session.user}}</td>\r\n <td>{{session.tenant}}</td>\r\n <td>{{session.bgprocess}}</td>\r\n <td>{{session.activity | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.cpu | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.wait | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.db | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.script | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.throttle | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.sleep | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.net | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.io | number : '1.1-2' : 'it'}} %</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgDirInfos=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <div class=\"modal-dialog modal-feminist\" emaDraggable>\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title pull-left\">{{'Dettaglio per Istanza' | localize: lc}}</h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"dlgDirInfos.hide()\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\r\n </div>\r\n <div class=\"modal-body\" *ngIf=\"(DirInfosGlobal?.perinstancedata?.length || 0) > 0\">\r\n <div class=\"row\" *ngFor=\"let info of DirInfosGlobal.perinstancedata\">\r\n <div class=\"col-md-12\"> \r\n <strong>{{info.instance}}</strong>:&nbsp;\r\n {{'' + info.cpus + ' ' + ('CPU (Global)' | localize: lc) + (info.rssplan ? ' - ' + info.rssplan : '')}}&nbsp;\r\n Load average: {{ info.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ info.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ info.lavg15 | number : '1.1-2' : 'it'}}\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"dlgDirInfos.hide()\">{{'Chiudi' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <node-detail *ngIf=\"NodeDetails\" [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\r\n</div>\r\n\r\n<div bsModal #dlgSessionDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <div class=\"modal-dialog modal-feminist\" emaDraggable>\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title pull-left\">{{'Dettaglio Sessione' | localize: lc}}<span *ngIf=\"SessionDetails\">&nbsp;{{SessionDetails.sid}}</span></h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"dlgSessionDetails.hide()\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\r\n </div>\r\n <div class=\"modal-body\" *ngIf=\"SessionDetails\">\r\n <div class=\"row\">\r\n <div *ngIf=\"SessionDetails.instanceid\" class=\"col-md-6\"><strong>{{'Istanza' | localize: lc}}</strong>:&nbsp;{{SessionDetails.instanceid}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Seriale' | localize: lc}}</strong>:&nbsp;{{SessionDetails.serial}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Stato' | localize: lc}}</strong>:&nbsp;{{SessionDetails.status}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Tipo' | localize: lc}}</strong>:&nbsp;{{SessionDetails.type}}</div>\r\n <div class=\"col-md-6\"><strong>{{'Utente' | localize: lc}}</strong>:&nbsp;{{SessionDetails.user}}&nbsp;<span *ngIf=\"SessionDetails.tenant\">({{SessionDetails.tenant}})</span></div>\r\n </div>\r\n\r\n <div style=\"display: flex; width: 100%; margin-top: 15px;\">\r\n <div style=\"flex-grow: 0;display: flex;flex-direction: column\">\r\n <h5>Prime Istruzioni</h5>\r\n <div *ngIf=\"SelectedTopNodes\">\r\n <es-table [(ngModel)]=\"SelectedTopNodes\" [ArraymodeItemsPerPage]=\"10\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">{{'Nodo' | localize: lc}}</th>\r\n <th>{{'Descrizione Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n \r\n <ng-template #body let-node>\r\n <td class=\"app-col-min\"><span class=\"app-link\"(click)=\"loadNodeDetails(node.profnodeid); dlgNodeDetails.show();\">{{node.profnodeid}}</span></td>\r\n <td><span title=\"{{node.profnodedesc}}\">{{node.profnodedesc.length > 40 ? node.profnodedesc.substr(0,40) + \"...\" : node.profnodedesc}}</span></td>\r\n <td class=\"app-nowrap\">{{(node.activity == \"NaN\" ? null : node.activity) | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{node.nodetypename}}</td>\r\n <td>{{node.waitclassname}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n <div style=\"width: 15px;\"></div>\r\n <div style=\"flex-grow: 2;display: flex;flex-direction: column\">\r\n <h5>Attivit\u00E0</h5>\r\n <div *ngIf=\"SelectedSessions\" style=\"width: 100%; height: 290px\">\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [LegendPadding]=\"{top: 0, bottom: 7, right: 0, left: 10}\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"SelectedSessions\"\r\n [Legend]=\"true\" \r\n name=\"session_details\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event, true)\">\r\n </es-line-chart>\r\n </div>\r\n \r\n </div>\r\n </div>\r\n <div style=\"display: flex; width: 100%;\">\r\n <div style=\"flex-grow: 1;\">\r\n <h5>Statistiche Thread</h5>\r\n <div>\r\n <es-table [(ngModel)]=\"SessionDetails.threads\" [ArraymodeItemsPerPage]=\"10\" [Selection]=\"true\" [SingleSelection]=\"true\" (onSelectionChanged)=\"threadSelectionChanged($event)\">\r\n <ng-template #header>\r\n <th>Thread</th>\r\n <th>Stato</th>\r\n <th>Tipo</th>\r\n <th>API</th>\r\n <th>Attesa corrente</th>\r\n <th>Nodo di attesa</th>\r\n <th>Attesa su</th>\r\n <th>Classe</th>\r\n <th>Par. 1</th>\r\n <th>Par. 2</th>\r\n <th>Par. 3</th>\r\n <th>Tempo Attesa</th>\r\n </ng-template>\r\n \r\n <ng-template #body let-thread>\r\n <td>{{thread.tid}}</td>\r\n <td>{{thread.status}}</td>\r\n <td>{{thread.type}}</td>\r\n <td>{{thread.api}}</td>\r\n <td>{{thread.wait}}</td>\r\n <td>{{thread.waitnode}}</td>\r\n <td>{{thread.waiteventtype}}</td>\r\n <td>{{thread.waitclassname}}</td>\r\n <td>{{thread.waitpar1}}</td>\r\n <td>{{thread.waitpar2}}</td>\r\n <td>{{thread.waitpar3}}</td>\r\n <td>{{(thread.waittime == \"NaN\" ? null : thread.waittime) | number : '1.1-2' : 'it'}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"dlgSessionDetails.hide()\">{{'Chiudi' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>" }]
4949
+ args: [{ selector: "topact_search", providers: [{ provide: LocalizationService, useClass: AdmTopActivitieLoc }], standalone: false, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n <span *ngIf=\"DirInfos && !DirInfosGlobal\">&nbsp;-&nbsp;\r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span>&nbsp;\r\n <span *ngIf=\"DirInfosGlobal\">&nbsp;|&nbsp;\r\n {{'' + DirInfosGlobal.cpus + ' ' + ('CPU (Global)' | localize: lc) + (DirInfosGlobal.rssplan ? ' - ' + DirInfosGlobal.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfosGlobal.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfosGlobal.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfosGlobal.lavg15 | number : '1.1-2' : 'it'}}\r\n <span *ngIf=\"(DirInfosGlobal?.perinstancedata?.length || 0) > 0\">\r\n &nbsp;\r\n <a class=\"app-link app-pointer app-inline\" (click)=\"dlgDirInfos.show();\">[{{'Info per Istanza' | localize: lc}}...]</a>\r\n </span>\r\n </span>&nbsp;\r\n </span>\r\n </div>\r\n <div class=\"card-body widget-body\">\r\n <div class=\"col-md-12 app-relative\">\r\n <form role=\"form\">\r\n <div class=\"row app-first-filter-line\">\r\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\r\n <form-datetime [readonly]=\"autoUpdate\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\">\r\n <form-datetime [readonly]=\"autoUpdate\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"col-xl-2 col-lg-2 col-md-12 app-filter-wrapper\" style=\"display: flex; height: 38px;\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"searchView.filterglobal\" name=\"filterglobal\"></form-checkbox>&nbsp;\r\n <span class=\"app-pointer app-padding-top-5 app-padding-left-5\" (click)=\"searchView.filterglobal = !searchView.filterglobal\">{{'Globale' | localize: lc}}</span>\r\n </div>\r\n <button [disabled]=\"searchView.searchinprogress || autoUpdate\" class=\"input-group-addon btn app-btn-search app-margin-top-20\" (click)=\"sendSearch()\" type=\"submit\"><i class=\"fa fa-search\"></i></button>\r\n\r\n <div class=\"app-absolute app-right-25 app-top-40\">\r\n <div class=\"pull-right\">\r\n {{'Aggiorna ogni' | localize: lc}}&nbsp;<input [readonly]=\"autoUpdate\" maxlength=\"3\" class=\"form-control app-updevery-input\" type=\"text\" [(ngModel)]=\"seconds\" name=\"seconds\" />&nbsp;{{'secondo/i' | localize: lc}}\r\n </div>\r\n <div class=\"pull-right m-t-2 app-margin-right-5\">\r\n <label class=\"switch\">\r\n <input type=\"checkbox\" [(ngModel)]=\"autoUpdate\" name=\"autoUpdate\" (ngModelChange)=\"autoUpdateChanged();\" />\r\n <div class=\"slider round\"></div>\r\n </label>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n </div>\r\n </div>\r\n </form>\r\n </div>\r\n <div class=\"row\">\r\n <div class=\"col-md-12 app-margin-top-5\">\r\n <p *ngIf=\"!searchView\"><em>{{'Carico i Dati' | localize: lc}}</em></p>\r\n <div *ngIf=\"searchView\" class=\"row\">\r\n <div class=\"col-md-12 app-no-padding\">\r\n <div style=\"width: 100%; height: 290px\">\r\n <es-line-chart *ngIf=\"TopActiveSessions\"\r\n [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [LegendPadding]=\"{top: 0, bottom: 7, right: 0, left: 10}\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"TopActiveSessions\"\r\n [Legend]=\"true\" \r\n name=\"topactsession\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (onSelectionChanged)=\"dataSelectionChanged($event)\" (chartLoaded)=\"onChartLoaded($event)\"></es-line-chart>\r\n </div>\r\n </div>\r\n <div class=\"col-md-5\">\r\n <h5>{{'Prime Istruzioni' | localize: lc}}</h5>\r\n <es-table [(ngModel)]=\"TopNodes\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">{{'Nodo' | localize: lc}}</th>\r\n <th>{{'Descrizione Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n <ng-template #body let-node>\r\n <td class=\"app-col-min\"><span class=\"app-link\" (click)=\"openNodeDetails(node.profnodeid)\">{{node.profnodeid}}</span></td>\r\n <td><span title=\"{{node.profnodedesc}}\">{{node.profnodedesc.length > 40 ? node.profnodedesc.substr(0,40) + \"...\" : node.profnodedesc}}</span></td>\r\n <td class=\"app-nowrap\">{{node.activity | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{node.nodetypename}}</td>\r\n <td>{{node.waitclassname}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n <div class=\"col-md-7\">\r\n <h5>{{'Prime Sessioni' | localize: lc}}</h5>\r\n <es-table [(ngModel)]=\"TopSessions\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">ID</th>\r\n <th>{{'Utente' | localize: lc}}</th>\r\n <th>{{'Tenant' | localize : lc}}</th>\r\n <th>{{'Processo' | localize: lc}}</th>\r\n <th>{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th>Cpu</th>\r\n <th>Wait</th>\r\n <th>DB</th>\r\n <th>Script</th>\r\n <th>Throttle</th>\r\n <th>Sleep</th>\r\n <th>Networking</th>\r\n <th>IO</th>\r\n </ng-template>\r\n\r\n <ng-template #body let-session>\r\n <td class=\"app-col-min\"><span class=\"app-link\" title=\"{{session.instanceid? (' - ' + session.instanceid) : ''}}\" (click)=\"openSessionDetails(session.sid, session.serial, session.instanceid)\">{{session.sid}}</span></td>\r\n <td>{{session.user}}</td>\r\n <td>{{session.tenant}}</td>\r\n <td>{{session.bgprocess}}</td>\r\n <td>{{session.activity | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.cpu | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.wait | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.db | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.script | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.throttle | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.sleep | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.net | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{session.io | number : '1.1-2' : 'it'}} %</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n <div class=\"clearfix\"></div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgDirInfos=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <div class=\"modal-dialog modal-feminist\" emaDraggable>\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title pull-left\">{{'Dettaglio per Istanza' | localize: lc}}</h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"dlgDirInfos.hide()\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\r\n </div>\r\n <div class=\"modal-body\" *ngIf=\"(DirInfosGlobal?.perinstancedata?.length || 0) > 0\">\r\n <div class=\"row\" *ngFor=\"let info of DirInfosGlobal.perinstancedata\">\r\n <div class=\"col-md-12\"> \r\n <strong>{{info.instance}}</strong>:&nbsp;\r\n {{'' + info.cpus + ' ' + ('CPU (Global)' | localize: lc) + (info.rssplan ? ' - ' + info.rssplan : '')}}&nbsp;\r\n Load average: {{ info.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ info.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ info.lavg15 | number : '1.1-2' : 'it'}}\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"dlgDirInfos.hide()\">{{'Chiudi' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <node-detail *ngIf=\"NodeDetails\" [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\r\n</div>\r\n\r\n<div bsModal #dlgSessionDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n <div class=\"modal-dialog modal-feminist\" emaDraggable>\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title pull-left\">{{'Dettaglio Sessione' | localize: lc}}<span *ngIf=\"SessionDetails\">&nbsp;{{SessionDetails.sid}}</span></h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"dlgSessionDetails.hide()\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\r\n </div>\r\n <div class=\"modal-body\" *ngIf=\"SessionDetails\">\r\n <div class=\"row\">\r\n <div *ngIf=\"SessionDetails.instanceid\" class=\"col-md-6\"><strong>{{'Istanza' | localize: lc}}</strong>:&nbsp;{{SessionDetails.instanceid}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Seriale' | localize: lc}}</strong>:&nbsp;{{SessionDetails.serial}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Stato' | localize: lc}}</strong>:&nbsp;{{SessionDetails.status}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Tipo' | localize: lc}}</strong>:&nbsp;{{SessionDetails.type}}</div>\r\n <div class=\"col-md-6\"><strong>{{'Utente' | localize: lc}}</strong>:&nbsp;{{SessionDetails.user}}&nbsp;<span *ngIf=\"SessionDetails.tenant\">({{SessionDetails.tenant}})</span></div>\r\n </div>\r\n\r\n <div style=\"display: flex; width: 100%; margin-top: 15px;\">\r\n <div style=\"flex-grow: 0;display: flex;flex-direction: column\">\r\n <h5>Prime Istruzioni</h5>\r\n <div *ngIf=\"SelectedTopNodes\">\r\n <es-table [(ngModel)]=\"SelectedTopNodes\" [ArraymodeItemsPerPage]=\"10\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">{{'Nodo' | localize: lc}}</th>\r\n <th>{{'Descrizione Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n \r\n <ng-template #body let-node>\r\n <td class=\"app-col-min\"><span class=\"app-link\"(click)=\"loadNodeDetails(node.profnodeid); dlgNodeDetails.show();\">{{node.profnodeid}}</span></td>\r\n <td><span title=\"{{node.profnodedesc}}\">{{node.profnodedesc.length > 40 ? node.profnodedesc.substr(0,40) + \"...\" : node.profnodedesc}}</span></td>\r\n <td class=\"app-nowrap\">{{(node.activity == \"NaN\" ? null : node.activity) | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{node.nodetypename}}</td>\r\n <td>{{node.waitclassname}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n <div style=\"width: 15px;\"></div>\r\n <div style=\"flex-grow: 2;display: flex;flex-direction: column\">\r\n <h5>Attivit\u00E0</h5>\r\n <div *ngIf=\"SelectedSessions\" style=\"width: 100%; height: 290px\">\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [LegendPadding]=\"{top: 0, bottom: 7, right: 0, left: 10}\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"SelectedSessions\"\r\n [Legend]=\"true\" \r\n name=\"session_details\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event, true)\">\r\n </es-line-chart>\r\n </div>\r\n \r\n </div>\r\n </div>\r\n <div style=\"display: flex; width: 100%;\">\r\n <div style=\"flex-grow: 1;\">\r\n <h5>Statistiche Thread</h5>\r\n <div>\r\n <es-table [(ngModel)]=\"SessionDetails.threads\" [ArraymodeItemsPerPage]=\"10\" [Selection]=\"true\" [SingleSelection]=\"true\" (onSelectionChanged)=\"threadSelectionChanged($event)\">\r\n <ng-template #header>\r\n <th>Thread</th>\r\n <th>Stato</th>\r\n <th>Tipo</th>\r\n <th>API</th>\r\n <th>Attesa corrente</th>\r\n <th>Nodo di attesa</th>\r\n <th>Attesa su</th>\r\n <th>Classe</th>\r\n <th>Par. 1</th>\r\n <th>Par. 2</th>\r\n <th>Par. 3</th>\r\n <th>Tempo Attesa</th>\r\n </ng-template>\r\n \r\n <ng-template #body let-thread>\r\n <td>{{thread.tid}}</td>\r\n <td>{{thread.status}}</td>\r\n <td>{{thread.type}}</td>\r\n <td>{{thread.api}}</td>\r\n <td>{{thread.wait}}</td>\r\n <td>{{thread.waitnode}}</td>\r\n <td>{{thread.waiteventtype}}</td>\r\n <td>{{thread.waitclassname}}</td>\r\n <td>{{thread.waitpar1}}</td>\r\n <td>{{thread.waitpar2}}</td>\r\n <td>{{thread.waitpar3}}</td>\r\n <td>{{(thread.waittime == \"NaN\" ? null : thread.waittime) | number : '1.1-2' : 'it'}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"dlgSessionDetails.hide()\">{{'Chiudi' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Dettaglio v2 di nodo e sessione (DirectorFeature.DetailsV2) -->\r\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\r\n @if (detailsV2Enabled) {\r\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"false\" [CanOpenProfiler]=\"!!profilerV2Enabled\" (closed)=\"dlgDetailsV2.hide()\"\r\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"openInProfiler($event)\"></adm-details-v2>\r\n }\r\n</div>\r\n" }]
4073
4950
  }], ctorParameters: () => [{ type: i1$1.DateService }, { type: i1.LocalizationService }, { type: i3.PreferencesService }, { type: i5.Location }, { type: i1$1.InterComService }, { type: i4.ActivatedRoute }, { type: AdminModuleBaseService }, { type: undefined, decorators: [{
4074
4951
  type: Inject,
4075
4952
  args: [ADM_MODULE_PATH]
4076
- }] }] });
4077
-
4078
- // Enum della Top Activity v2: i numeri sono quelli del backend (le risposte li riportano come numeri)
4079
- var TopActivityDimension;
4080
- (function (TopActivityDimension) {
4081
- TopActivityDimension[TopActivityDimension["WaitClass"] = 0] = "WaitClass";
4082
- TopActivityDimension[TopActivityDimension["EventType"] = 1] = "EventType";
4083
- TopActivityDimension[TopActivityDimension["WaitEvent"] = 2] = "WaitEvent";
4084
- TopActivityDimension[TopActivityDimension["Instance"] = 3] = "Instance";
4085
- TopActivityDimension[TopActivityDimension["UserSession"] = 4] = "UserSession";
4086
- TopActivityDimension[TopActivityDimension["UserName"] = 5] = "UserName";
4087
- TopActivityDimension[TopActivityDimension["Tenant"] = 6] = "Tenant";
4088
- TopActivityDimension[TopActivityDimension["SessionType"] = 7] = "SessionType";
4089
- TopActivityDimension[TopActivityDimension["BackgroundSession"] = 8] = "BackgroundSession";
4090
- TopActivityDimension[TopActivityDimension["JobName"] = 9] = "JobName";
4091
- TopActivityDimension[TopActivityDimension["ConsumerGroup"] = 10] = "ConsumerGroup";
4092
- TopActivityDimension[TopActivityDimension["ThreadType"] = 11] = "ThreadType";
4093
- TopActivityDimension[TopActivityDimension["Api"] = 12] = "Api";
4094
- TopActivityDimension[TopActivityDimension["Machine"] = 13] = "Machine";
4095
- })(TopActivityDimension || (TopActivityDimension = {}));
4096
- var TopActivityDataSource;
4097
- (function (TopActivityDataSource) {
4098
- TopActivityDataSource[TopActivityDataSource["Memory"] = 0] = "Memory";
4099
- TopActivityDataSource[TopActivityDataSource["MemoryAndStored"] = 1] = "MemoryAndStored";
4100
- })(TopActivityDataSource || (TopActivityDataSource = {}));
4101
- var TopActivityResolution;
4102
- (function (TopActivityResolution) {
4103
- TopActivityResolution[TopActivityResolution["Low"] = 0] = "Low";
4104
- TopActivityResolution[TopActivityResolution["Medium"] = 1] = "Medium";
4105
- TopActivityResolution[TopActivityResolution["High"] = 2] = "High";
4106
- TopActivityResolution[TopActivityResolution["Maximum"] = 3] = "Maximum";
4107
- })(TopActivityResolution || (TopActivityResolution = {}));
4108
- var TopActivityMaximumThreads;
4109
- (function (TopActivityMaximumThreads) {
4110
- TopActivityMaximumThreads[TopActivityMaximumThreads["None"] = 0] = "None";
4111
- TopActivityMaximumThreads[TopActivityMaximumThreads["Cores"] = 1] = "Cores";
4112
- TopActivityMaximumThreads[TopActivityMaximumThreads["Threads"] = 2] = "Threads";
4113
- })(TopActivityMaximumThreads || (TopActivityMaximumThreads = {}));
4953
+ }] }, { type: i4.Router }, { type: undefined, decorators: [{
4954
+ type: Optional
4955
+ }, {
4956
+ type: Inject,
4957
+ args: [ADM_DETAILS_V2]
4958
+ }] }, { type: undefined, decorators: [{
4959
+ type: Optional
4960
+ }, {
4961
+ type: Inject,
4962
+ args: [ADM_PROFILER_V2]
4963
+ }] }], propDecorators: { dlgNodeDetails: [{
4964
+ type: ViewChild,
4965
+ args: ["dlgNodeDetails"]
4966
+ }], dlgSessionDetails: [{
4967
+ type: ViewChild,
4968
+ args: ["dlgSessionDetails"]
4969
+ }], dlgDetailsV2: [{
4970
+ type: ViewChild,
4971
+ args: ["dlgDetailsV2"]
4972
+ }], detailsV2: [{
4973
+ type: ViewChild,
4974
+ args: [AdmDetailsV2Component]
4975
+ }] } });
4114
4976
 
4115
4977
  class TopActivityV2Filter {
4116
4978
  }
@@ -4300,15 +5162,6 @@ const STORAGE_KEY = "HotSearchTopActV2";
4300
5162
  const TABLES_WINDOW_MS = 5 * 60 * 1000;
4301
5163
  const INSTANCE_CURRENT = "@current";
4302
5164
  const INSTANCE_ALL = "@all";
4303
- // WaitClass ed EventType hanno valori fissi: colori fissi, così il grafico si legge sempre allo stesso modo
4304
- const FIXED_COLORS = {
4305
- Cpu: "#43a047", Database: "#1e88e5", Script: "#8e24aa", Network: "#8d6e63", IO: "#00acc1", Sleep: "#b0bec5", Throttle: "#fb8c00", Wait: "#fdd835",
4306
- Latch: "#e53935", Semaphore: "#f06292", Enqueue: "#c62828", ReadWriteLock: "#ad1457", Fence: "#6d4c41", ConditionVariable: "#00897b", Scheduler: "#5e35b1"
4307
- };
4308
- const PALETTE = ["#1e88e5", "#43a047", "#fb8c00", "#8e24aa", "#e53935", "#00897b", "#fdd835", "#6d4c41", "#3949ab", "#c0ca33"];
4309
- const OTHER_COLOR = "#9e9e9e";
4310
- const TOTAL_COLOR = "#263238";
4311
- const LIMIT_COLOR = "#e53935";
4312
5165
  class TopActivityV2LegendItem {
4313
5166
  }
4314
5167
  class TopActivityV2FilterChip {
@@ -4317,7 +5170,9 @@ class TopActivityV2FilterChip {
4317
5170
  class TopActivityV2Settings {
4318
5171
  }
4319
5172
  class AdmTopActivityV2Component {
4320
- constructor(dateExts, lc, localStorage, intercom, route, adms, zone) {
5173
+ constructor(dateExts, lc, localStorage, intercom, route, adms, zone, router, mod,
5174
+ // Con DirectorFeature.DetailsV2 nodi e sessioni si aprono nel dettaglio v2; "Apri nel profiler" vuole il profiler v2
5175
+ detailsV2Enabled, profilerV2Enabled) {
4321
5176
  this.dateExts = dateExts;
4322
5177
  this.lc = lc;
4323
5178
  this.localStorage = localStorage;
@@ -4325,6 +5180,10 @@ class AdmTopActivityV2Component {
4325
5180
  this.route = route;
4326
5181
  this.adms = adms;
4327
5182
  this.zone = zone;
5183
+ this.router = router;
5184
+ this.mod = mod;
5185
+ this.detailsV2Enabled = detailsV2Enabled;
5186
+ this.profilerV2Enabled = profilerV2Enabled;
4328
5187
  this.Dim = TopActivityDimension;
4329
5188
  this.TotalColor = TOTAL_COLOR;
4330
5189
  this.LimitColor = LIMIT_COLOR;
@@ -4375,6 +5234,10 @@ class AdmTopActivityV2Component {
4375
5234
  if (saved)
4376
5235
  this.applySettings(saved);
4377
5236
  this.setLastHours(this.activeRange);
5237
+ // "Sessioni su questo evento" dal dettaglio di un nodo aperto in un'altra pagina (profiler): filtro sull'evento, stessa finestra
5238
+ let query = this.route.snapshot.queryParams;
5239
+ if (query["event"])
5240
+ this.applyEventFilter(query["event"], query["eventName"], query["from"] ? new Date(query["from"]) : null, query["to"] ? new Date(query["to"]) : null);
4378
5241
  this.loadInstances();
4379
5242
  this.refreshInfos();
4380
5243
  this.search();
@@ -4485,7 +5348,7 @@ class AdmTopActivityV2Component {
4485
5348
  this.lastChartKey = null;
4486
5349
  return;
4487
5350
  }
4488
- let memoryFrom = res.memoryFrom ? this.parseUtc(res.memoryFrom) : null;
5351
+ let memoryFrom = res.memoryFrom ? parseUtc(res.memoryFrom) : null;
4489
5352
  this.memoryFrom = memoryFrom && memoryFrom.getTime() > this.chartFrom ? this.fmt(memoryFrom) : null;
4490
5353
  this.limitLabel = this.lc.loc(+this.maxThreadsKind == TopActivityMaximumThreads.Cores ? "CPU Massime" : "Thread Massimi");
4491
5354
  // Se è cambiata solo la finestra delle tabelle il grafico resta quello di prima: ridisegnarlo lo farebbe lampeggiare
@@ -4495,22 +5358,23 @@ class AdmTopActivityV2Component {
4495
5358
  return;
4496
5359
  }
4497
5360
  this.lastChartKey = chartKey;
4498
- let times = (res.times ?? []).map(t => this.parseUtc(t));
5361
+ let times = (res.times ?? []).map(t => parseUtc(t));
5362
+ let interval = bucketInterval(res.bucketSeconds);
4499
5363
  let fixed = res.dimension == TopActivityDimension.WaitClass || res.dimension == TopActivityDimension.EventType;
4500
5364
  let uom = this.lc.loc("sessioni");
4501
5365
  let series = [];
4502
5366
  this.colors = {};
4503
5367
  this.legend = (res.components ?? []).map((c, i) => {
4504
- let color = c.other ? OTHER_COLOR : (fixed && FIXED_COLORS[c.key]) || PALETTE[i % PALETTE.length];
5368
+ let color = componentColor(c.key, c.other, i, fixed);
4505
5369
  if (c.key != null)
4506
5370
  this.colors[c.key] = color;
4507
5371
  let label = this.valueLabel(c.label, c.other, res.dimension);
4508
- series.push(new LineSerie(label, times.map((t, j) => new DateValue(t, c.values?.[j] ?? 0)), null, color, uom));
5372
+ series.push(new LineSerie(label, times.map((t, j) => new DateValue(t, c.values?.[j] ?? 0)), interval, color, uom));
4509
5373
  return { key: c.key, label: label, color: color, other: c.other, activity: c.activity, percentage: c.percentage };
4510
5374
  });
4511
5375
  // L'attività totale è una linea scura sopra le aree impilate, non impilata a sua volta
4512
5376
  if (res.totalActivity)
4513
- series.push(new LineSerie(this.lc.loc("Attività totale"), times.map((t, j) => new DateValue(t, res.totalActivity[j] ?? 0)), null, TOTAL_COLOR, uom, false, false));
5377
+ series.push(new LineSerie(this.lc.loc("Attività totale"), times.map((t, j) => new DateValue(t, res.totalActivity[j] ?? 0)), interval, TOTAL_COLOR, uom, false, false));
4514
5378
  let limit = null;
4515
5379
  if (res.maximumThreads != null)
4516
5380
  limit = new Limit(res.maximumThreads, this.limitLabel, LIMIT_COLOR);
@@ -4604,6 +5468,14 @@ class AdmTopActivityV2Component {
4604
5468
  return this.valueLabel(item.label, item.other, table.dimension);
4605
5469
  }
4606
5470
  loadNodeDetails(nodeId) {
5471
+ if (this.detailsV2Enabled) {
5472
+ // D4: tutte le istanze, l'istanza scelta, oppure quella che risponde
5473
+ let instance = this.instance != INSTANCE_CURRENT && this.instance != INSTANCE_ALL ? this.instance : null;
5474
+ let memoryFrom = this.result?.memoryFrom ? parseUtc(this.result.memoryFrom) : null;
5475
+ this.detailsV2.openNode(nodeId, { ...this.detailsWindow(), global: this.instance == INSTANCE_ALL, instanceId: instance, memoryFrom: memoryFrom });
5476
+ this.dlgDetailsV2.show();
5477
+ return;
5478
+ }
4607
5479
  this.NodeDetails = null;
4608
5480
  this.dlgNodeDetails.show();
4609
5481
  requestAnimationFrame(async () => {
@@ -4611,6 +5483,11 @@ class AdmTopActivityV2Component {
4611
5483
  });
4612
5484
  }
4613
5485
  loadSessionDetails(session) {
5486
+ if (this.detailsV2Enabled) {
5487
+ this.detailsV2.openSession(session.instanceId, session.sessionId, session.serialNo, { ...this.detailsWindow(), realTime: +this.dataSource == TopActivityDataSource.Memory });
5488
+ this.dlgDetailsV2.show();
5489
+ return;
5490
+ }
4614
5491
  this.SessionDetails = null;
4615
5492
  this.dlgSessionDetails.show();
4616
5493
  requestAnimationFrame(async () => {
@@ -4618,6 +5495,35 @@ class AdmTopActivityV2Component {
4618
5495
  });
4619
5496
  }
4620
5497
  // #endregion
5498
+ // #region Dettaglio v2 di nodo e sessione
5499
+ // Il dettaglio eredita la finestra del grafico, non quella delle tabelle, e l'aggiornamento automatico della pagina (D2, D5)
5500
+ detailsWindow() {
5501
+ return { from: new Date(this.chartFrom), to: new Date(this.chartTo), refreshSeconds: +this.refreshSeconds };
5502
+ }
5503
+ // N8: questa pagina filtrata sull'evento esatto, con la tabella per sessione e la finestra del dettaglio
5504
+ showEventSessions(link) {
5505
+ this.dlgDetailsV2.hide();
5506
+ this.applyEventFilter(link.nodeId, link.nodeName, link.from, link.to);
5507
+ this.search();
5508
+ }
5509
+ // N7: il profiler v2 con il nodo come radice
5510
+ openInProfiler(nodeId) {
5511
+ this.dlgDetailsV2.hide();
5512
+ this.router.navigate([`/pages/${this.mod}/profiler`, ...(this.be ? [this.be] : [])], { queryParams: { root: nodeId } });
5513
+ }
5514
+ applyEventFilter(nodeId, nodeName, from, to) {
5515
+ let filter = new TopActivityV2Filter();
5516
+ filter.dimension = TopActivityDimension.WaitEvent;
5517
+ filter.value = nodeId;
5518
+ this.filters = [{ filter: filter, label: `${this.dimensionLabel(TopActivityDimension.WaitEvent)} = ${nodeName || nodeId}` }];
5519
+ this.tableDims = [String(TopActivityDimension.UserSession), this.tableDims[1] ?? String(TopActivityDimension.WaitEvent)];
5520
+ if (from && to && !isNaN(from.getTime()) && !isNaN(to.getTime())) {
5521
+ this.filterfrom = this.fmt(from);
5522
+ this.filterto = this.fmt(to);
5523
+ this.activeRange = null;
5524
+ }
5525
+ }
5526
+ // #endregion
4621
5527
  // #region Aggiornamento automatico
4622
5528
  refreshChanged() {
4623
5529
  clearInterval(this.refreshTimer);
@@ -4696,6 +5602,7 @@ class AdmTopActivityV2Component {
4696
5602
  case TopActivityDimension.ThreadType: return this.lc.loc("Tipo thread");
4697
5603
  case TopActivityDimension.Api: return "API";
4698
5604
  case TopActivityDimension.Machine: return this.lc.loc("Macchina");
5605
+ case TopActivityDimension.Thread: return "Thread";
4699
5606
  }
4700
5607
  return String(dimension);
4701
5608
  }
@@ -4741,23 +5648,37 @@ class AdmTopActivityV2Component {
4741
5648
  fmt(date) {
4742
5649
  return dayjs(date).format(this.lc.token("getFullDateDisplayFormat"));
4743
5650
  }
4744
- // Le date della risposta sono UTC "dd/MM/yyyy HH:mm:ss" senza fuso
4745
- parseUtc(value) {
4746
- let m = /^(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2}):(\d{2})$/.exec(value ?? "");
4747
- return m ? new Date(Date.UTC(+m[3], +m[2] - 1, +m[1], +m[4], +m[5], +m[6])) : new Date(value);
4748
- }
4749
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivityV2Component, deps: [{ token: i1$1.DateService }, { token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: AdminModuleBaseService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
4750
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmTopActivityV2Component, isStandalone: false, selector: "topact_v2", providers: [{ provide: LocalizationService, useClass: AdmTopActivityV2Loc }], viewQueries: [{ propertyName: "dlgNodeDetails", first: true, predicate: ["dlgNodeDetails"], descendants: true }, { propertyName: "dlgSessionDetails", first: true, predicate: ["dlgSessionDetails"], descendants: true }], ngImport: i0, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n @if (DirInfos) {\r\n <span>&nbsp;-&nbsp;\r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span>\r\n }\r\n </span>\r\n </div>\r\n <div class=\"card-body widget-body\">\r\n <!-- Barra in alto: quali dati caricare (finestra, istanza, origine). Come disegnarli sta nell'intestazione del grafico -->\r\n <form role=\"form\">\r\n <!-- Tre gruppi che vanno a capo interi: periodo, sorgente (con la ricerca), aggiornamento automatico -->\r\n <div class=\"tav2-toolbar\">\r\n <div class=\"tav2-cluster\">\r\n <div class=\"tav2-field\">\r\n <form-datetime [readonly]=\"refreshSeconds != '0'\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\" (inputChange)=\"datesEdited()\"></form-datetime>\r\n </div>\r\n <div class=\"tav2-field\">\r\n <form-datetime [readonly]=\"refreshSeconds != '0'\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\" (inputChange)=\"datesEdited()\"></form-datetime>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Ultime' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (h of QuickRanges; track h) {\r\n <button type=\"button\" [class.tav2-on]=\"activeRange == h\" (click)=\"quickRange(h)\">{{h}} h</button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"tav2-cluster\">\r\n <div class=\"tav2-field tav2-field-wide tav2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"instance\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanza' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Origine dati' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of DataSources; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"dataSource == o.id\" (click)=\"setDataSource(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <button [disabled]=\"loading || refreshSeconds != '0'\" class=\"btn app-btn-search\" (click)=\"searchClicked()\" type=\"submit\" [title]=\"'Cerca' | localize: lc\">\r\n <i class=\"fa\" [class.fa-search]=\"!loading\" [class.fa-spinner]=\"loading\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n </div>\r\n\r\n <div class=\"tav2-cluster tav2-cluster-end\">\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\"><i class=\"fa fa-refresh\"></i> {{'Aggiornamento automatico' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of RefreshOptions; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"refreshSeconds == o.id\" (click)=\"setRefresh(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <!-- Grafico -->\r\n <div class=\"tav2-panel\">\r\n <div class=\"tav2-panel-header tav2-chart-header\">\r\n <div class=\"tav2-heading\">\r\n <span class=\"tav2-title\">{{'Sessioni attive medie per' | localize: lc}} {{dimensionLabel(result?.dimension ?? +dimension) | lowercase}}</span>\r\n @if (result) {\r\n <span class=\"tav2-muted\">\r\n {{'Media' | localize: lc}} <strong>{{result.estimated ? '\u2248 ' : ''}}{{result.averageActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n &middot; {{'Picco' | localize: lc}} <strong>{{result.estimated ? '\u2248 ' : ''}}{{result.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n &middot; {{'un punto ogni' | localize: lc}} {{result.bucketSeconds}} s\r\n @if (result.estimated) {\r\n <span class=\"tav2-estimate\" [title]=\"'Valori stimati contando i campioni, come in Oracle, invece che misurati' | localize: lc\">{{'stima per campionamento' | localize: lc}}</span>\r\n }\r\n @if (loading) {\r\n &nbsp;<i class=\"fa fa-spinner fa-spin\"></i>\r\n }\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Come disegnare i dati -->\r\n <div class=\"tav2-view-controls\">\r\n <div class=\"tav2-field tav2-field-wide tav2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"dimension\" name=\"dimension\" [Source]=\"Dimensions\" [Placeholder]=\"'Dividi per' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Risoluzione' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of Resolutions; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"resolution == o.id\" (click)=\"setResolution(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Limite' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of LimitOptions; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"limitValue == o.id\" (click)=\"setLimit(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"tav2-toggle\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"totalActivity\" (inputChange)=\"search()\"></form-checkbox>\r\n <span class=\"tav2-pointer\" (click)=\"totalActivity = !totalActivity; search()\">{{'Attivit\u00E0 totale' | localize: lc}}</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n @if (filters.length > 0) {\r\n <div class=\"tav2-chips\">\r\n <span class=\"tav2-muted\">{{'Filtri' | localize: lc}}</span>\r\n @for (chip of filters; track $index) {\r\n <span class=\"tav2-chip\">\r\n {{chip.label}}\r\n <button type=\"button\" [title]=\"'Rimuovi' | localize: lc\" (click)=\"removeFilter($index)\">&times;</button>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"tav2-chart\">\r\n @if (chartData) {\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [Step]=\"true\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"chartData\"\r\n [Max]=\"chartMax\"\r\n [Legend]=\"false\"\r\n name=\"topactv2\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event)\"></es-line-chart>\r\n } @else {\r\n <div class=\"tav2-empty\">{{(loading ? 'Carico i Dati' : 'Nessun dato nella finestra') | localize: lc}}</div>\r\n }\r\n </div>\r\n\r\n <!-- Legenda: un clic su una voce la aggiunge ai filtri (\"altri\" non \u00E8 filtrabile) -->\r\n @if (legend.length > 0) {\r\n <div class=\"tav2-legend\">\r\n @for (item of legend; track $index) {\r\n <span class=\"tav2-legend-item\" [class.tav2-clickable]=\"!item.other\" [title]=\"item.other ? '' : ('Clic per filtrare' | localize: lc)\" (click)=\"addFilter(item)\">\r\n <span class=\"tav2-swatch\" [style.background]=\"item.color\"></span>\r\n {{item.label}}\r\n <span class=\"tav2-muted\">{{item.percentage | number : '1.0-1' : 'it'}}%</span>\r\n </span>\r\n }\r\n @if (result?.totalActivity) {\r\n <span class=\"tav2-legend-item\">\r\n <span class=\"tav2-line\" [style.border-color]=\"TotalColor\"></span>\r\n {{'Attivit\u00E0 totale' | localize: lc}}\r\n </span>\r\n }\r\n @if (result?.maximumThreads != null) {\r\n <span class=\"tav2-legend-item\">\r\n <span class=\"tav2-line\" [style.border-color]=\"LimitColor\"></span>\r\n {{limitLabel}} <strong>{{result.maximumThreads}}</strong>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n @if (memoryFrom) {\r\n <div class=\"tav2-note\">\r\n <i class=\"fa fa-info-circle\"></i>\r\n {{'Prima di questo istante i dati vengono dallo storico (un campione ogni 10 secondi)' | localize: lc}}: {{memoryFrom}}\r\n </div>\r\n }\r\n\r\n <!-- Time slider: finestra di 5 minuti per le tabelle -->\r\n @if (sliderMax > sliderMin) {\r\n <div class=\"tav2-slider\">\r\n <span class=\"tav2-slider-label\">\r\n <span class=\"tav2-muted\">{{'Finestra tabelle' | localize: lc}}</span>\r\n <strong>{{tablesWindowLabel}}</strong>\r\n </span>\r\n <input type=\"range\" [min]=\"sliderMin\" [max]=\"sliderMax\" [step]=\"sliderStep\" [ngModel]=\"sliderValue\" (ngModelChange)=\"sliderValue = $event; sliderMoving()\" (change)=\"sliderChanged()\" />\r\n <span class=\"tav2-badge\" [class.tav2-badge-off]=\"!sliderAnchored\">{{(sliderAnchored ? 'Ultimi 5 minuti' : 'Finestra fissa') | localize: lc}}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Tabelle -->\r\n <div class=\"tav2-tables\">\r\n @for (table of tables; track $index; let i = $index) {\r\n <div class=\"tav2-panel\">\r\n <div class=\"tav2-panel-header\">\r\n <span class=\"tav2-title\">{{'Prime righe per' | localize: lc}}</span>\r\n <div class=\"tav2-field tav2-field-wide tav2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"tableDims[i]\" name=\"tabledim{{i}}\" [Source]=\"Dimensions\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <span class=\"tav2-muted\">{{'Attivit\u00E0' | localize: lc}} <strong>{{table.estimated ? '\u2248 ' : ''}}{{table.activity | number : '1.2-3' : 'it'}}</strong></span>\r\n @if (table.estimated) {\r\n <span class=\"tav2-estimate\" [title]=\"'Stima contando i campioni: il totale pu\u00F2 differire di poco da quello misurato delle sessioni' | localize: lc\">{{'stima per campionamento' | localize: lc}}</span>\r\n }\r\n </div>\r\n <es-table [(ngModel)]=\"table.items\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th>{{dimensionLabel(table.dimension)}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min tav2-right\">%</th>\r\n @if (table.dimension == Dim.UserSession) {\r\n <th>{{'Utente' | localize: lc}}</th>\r\n <th>{{'Tipo' | localize: lc}}</th>\r\n <th>{{'Processo' | localize: lc}}</th>\r\n }\r\n @if (table.dimension == Dim.WaitEvent) {\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo' | localize: lc}}</th>\r\n }\r\n </ng-template>\r\n <ng-template #body let-item>\r\n <td>\r\n @if (isClickable(item)) {\r\n <span class=\"app-link tav2-ellipsis\" [title]=\"item.label || item.key\" (click)=\"openItem(item)\">{{itemLabel(item, table)}}</span>\r\n } @else {\r\n <span class=\"tav2-ellipsis\" [class.tav2-muted]=\"item.other || !item.label\">{{itemLabel(item, table)}}</span>\r\n }\r\n </td>\r\n <td class=\"app-nowrap\">\r\n <div class=\"tav2-bar-cell\">\r\n <div class=\"tav2-bar\">\r\n @for (part of item.breakdown; track $index) {\r\n <div [style.width.%]=\"breakdownWidth(item, part)\" [style.background]=\"breakdownColor(part)\" [title]=\"part.key\"></div>\r\n }\r\n </div>\r\n <span>{{table.estimated ? '\u2248 ' : ''}}{{item.activity | number : '1.2-3' : 'it'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"app-nowrap tav2-right\">{{item.percentage | number : '1.1-1' : 'it'}}</td>\r\n @if (table.dimension == Dim.UserSession) {\r\n <td class=\"app-nowrap\">\r\n {{item.session?.userName}}\r\n @if (item.session?.tenantId) {\r\n <span class=\"tav2-muted\">&middot; {{item.session.tenantId}}</span>\r\n }\r\n </td>\r\n <td class=\"tav2-muted\">{{item.session?.sessionType | titlecase}}</td>\r\n <td><span class=\"tav2-ellipsis tav2-ellipsis-short\" [title]=\"item.session?.bgProcessName || item.session?.jobName || ''\">{{item.session?.bgProcessName || item.session?.jobName}}</span></td>\r\n }\r\n @if (table.dimension == Dim.WaitEvent) {\r\n <td class=\"app-nowrap\">\r\n {{item.event?.eventType}}\r\n @if (item.event?.waitClass && item.event.waitClass != 'None') {\r\n <span class=\"tav2-muted\">&middot; {{item.event.waitClass}}</span>\r\n }\r\n </td>\r\n }\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (NodeDetails) {\r\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\r\n }\r\n</div>\r\n\r\n<div bsModal #dlgSessionDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (SessionDetails) {\r\n <session-detail [SessionDetails]=\"SessionDetails\" (onClose)=\"dlgSessionDetails.hide()\" (onNodeSelected)=\"loadNodeDetails($event)\"></session-detail>\r\n }\r\n</div>\r\n", styles: [":host{display:block}:host ::ng-deep .tav2-noclear .p-select-clear-icon{display:none}.tav2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;padding-top:6px}.tav2-cluster{display:flex;flex-wrap:nowrap;align-items:center;gap:10px}.tav2-cluster-end{margin-left:auto}.tav2-field{width:165px}.tav2-field-wide{width:210px}.tav2-spacer{flex:1 1 auto}.tav2-toggle{display:flex;align-items:center;gap:8px;height:39px;white-space:nowrap}.tav2-pointer{cursor:pointer}.tav2-group{position:relative;display:inline-flex}.tav2-group-label{position:absolute;top:-8px;left:8px;z-index:1;padding:0 4px;background:#fff;color:var(--p-text-muted-color, #64748b);font-size:12px;line-height:15px;white-space:nowrap;pointer-events:none}.tav2-seg{display:inline-flex;height:39px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden;background:#fff}.tav2-seg button{padding:0 12px;border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;color:#334155;font-size:13px;white-space:nowrap;cursor:pointer}.tav2-seg button:first-child{border-left:0}.tav2-seg button:hover:not(.tav2-on){background:#f8fafc}.tav2-seg button:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:-2px}.tav2-seg button.tav2-on{background:#eef2ff;color:#4338ca;font-weight:500;box-shadow:inset 0 -2px 0 var(--p-primary-color, #6366f1)}.tav2-panel{margin-top:14px;padding:10px 12px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:#fff;min-width:0}.tav2-panel-header{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;min-height:32px;margin-bottom:6px}.tav2-chart-header{justify-content:space-between;padding-top:8px;margin-bottom:10px}.tav2-heading{display:flex;flex-direction:column;gap:2px}.tav2-view-controls{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px}.tav2-title{font-size:12px;font-weight:500;letter-spacing:.03em;text-transform:uppercase;color:#344154}.tav2-muted{color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-right{text-align:right}.tav2-estimate{display:inline-block;margin-left:6px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:16px;white-space:nowrap;cursor:help}.tav2-ellipsis{display:inline-block;max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.tav2-ellipsis-short{max-width:170px}.tav2-tables .tav2-panel{container-type:inline-size}@container (min-width: 900px){.tav2-ellipsis{max-width:520px}.tav2-ellipsis-short{max-width:300px}}.tav2-chips{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:6px}.tav2-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 10px;border-radius:12px;background:#eef2ff;color:#3730a3;font-size:12px}.tav2-chip button{border:0;background:transparent;color:inherit;cursor:pointer;font-size:15px;line-height:1;padding:0 4px}.tav2-chart{position:relative;height:300px}.tav2-empty{display:flex;align-items:center;justify-content:center;height:100%;border:1px dashed var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);color:var(--p-text-muted-color, #64748b)}.tav2-legend{display:flex;flex-wrap:wrap;gap:4px 6px;margin-top:6px}.tav2-legend-item{display:inline-flex;align-items:center;gap:6px;padding:2px 8px;border:1px solid transparent;border-radius:4px;font-size:12px;white-space:nowrap}.tav2-legend-item.tav2-clickable{cursor:pointer}.tav2-legend-item.tav2-clickable:hover{border-color:var(--p-content-border-color, #e2e8f0);background:#f8fafc}.tav2-swatch{flex:none;width:10px;height:10px;border-radius:2px}.tav2-line{flex:none;width:16px;height:0;border-top:2px solid}.tav2-note{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-slider{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin-top:10px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.tav2-slider input[type=range]{flex:1 1 260px;min-width:200px;accent-color:var(--p-primary-color, #6366f1);cursor:pointer}.tav2-slider-label{display:inline-flex;flex-direction:column;line-height:1.2;font-size:12px}.tav2-badge{padding:2px 8px;border-radius:10px;background:#eef2ff;color:#3730a3;font-size:11px;white-space:nowrap}.tav2-badge.tav2-badge-off{background:#f1f5f9;color:var(--p-text-muted-color, #64748b)}.tav2-tables{display:grid;grid-template-columns:repeat(auto-fit,minmax(560px,1fr));gap:0 14px}.tav2-bar-cell{display:flex;align-items:center;gap:8px}.tav2-bar{display:flex;flex:none;width:70px;height:8px;border-radius:2px;overflow:hidden;background:#edf2f7}\n"], dependencies: [{ kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i7.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "component", type: i8.EsTableComponent, selector: "es-table", inputs: ["globalCheck", "autoUpdate", "seconds", "researchInProgress", "globalColVisCheck", "EsThTdProvider", "CornerMenuOptions", "ColumnsResizable", "ColumnsPinnable", "AutoUpdate", "Height", "EmptySpaceBackgroundColor", "EsTableHandledSearch", "MaxHeight", "ContainerClass", "XLSXExport", "CSVExport", "AllSearch", "HighCellDensity", "Selection", "ShowLoadingOnBootstrap", "Removal", "RemovalCondition", "Export", "ShiftClick", "CountLabel", "HidePaging", "HidePagingCount", "HidePagingButtons", "ContextMenu", "ExportFileName", "TableClass", "ExportFunction", "ExportOnlyVisibleColumns", "HasHeaderGroup", "HasSecondaryHeaderGroup", "HeaderHidden", "BodyHidden", "SelectionDisabled", "SingleSelection", "RowClassAssigner", "OrderByColumn", "MultipleOrderingDirectives", "HiddenColumns", "ColumnsOrdering", "SearchView", "SelectAll", "UseArrayModePaging", "DynamicRowColumnsDefinition", "DynamicOperations", "Hierarchy", "ParentKey", "OwnKey", "AutoSortHierarchy", "StartsExpanded", "SavePreferences", "DefaultAlignment", "PagingStyle", "RowGroupingPagingStyle", "ItemSourceProperty", "UseSelectionCache", "ShowItemGroupsColumns", "Editable", "RangeSelection", "SearchThrottle", "ArraymodeItemsPerPage"], outputs: ["globalCheckChange", "autoUpdateChange", "secondsChange", "researchInProgressChange", "globalColVisCheckChange", "onOrderChanged", "onSearchRequest", "onSelectionChanged", "onRemoval", "onAbortRemoval", "onModelChange", "onOpenContextMenu", "onCornerAction", "onDynamicOperation"] }, { kind: "component", type: i9.EsFormSelectComponent, selector: "form-select", inputs: ["OptionsTemplate"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "component", type: i2.EsLineChartComponent, selector: "es-line-chart", inputs: ["Data", "DataArray", "Step", "DataGroupBucketSize", "DataGroupingThreshold", "StrokeSize", "AllowGaps", "MergeDatasets", "FinalInstants", "Min", "Max", "Fill", "Stacked"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: SessionDetailComponent, selector: "session-detail", inputs: ["SessionDetails"], outputs: ["onClose", "onNodeSelected"] }, { kind: "component", type: NodeDetailComponent, selector: "node-detail", inputs: ["NodeDetails"], outputs: ["onClose"] }, { kind: "pipe", type: i5.LowerCasePipe, name: "lowercase" }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }, { kind: "pipe", type: i5.TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }] }); }
5651
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivityV2Component, deps: [{ token: i1$1.DateService }, { token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: AdminModuleBaseService }, { token: i0.NgZone }, { token: i4.Router }, { token: ADM_MODULE_PATH }, { token: ADM_DETAILS_V2, optional: true }, { token: ADM_PROFILER_V2, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
5652
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmTopActivityV2Component, isStandalone: false, selector: "topact_v2", providers: [{ provide: LocalizationService, useClass: AdmTopActivityV2Loc }], viewQueries: [{ propertyName: "dlgNodeDetails", first: true, predicate: ["dlgNodeDetails"], descendants: true }, { propertyName: "dlgSessionDetails", first: true, predicate: ["dlgSessionDetails"], descendants: true }, { propertyName: "dlgDetailsV2", first: true, predicate: ["dlgDetailsV2"], descendants: true }, { propertyName: "detailsV2", first: true, predicate: AdmDetailsV2Component, descendants: true }], ngImport: i0, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n @if (DirInfos) {\r\n <span>&nbsp;-&nbsp;\r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span>\r\n }\r\n </span>\r\n </div>\r\n <div class=\"card-body widget-body\">\r\n <!-- Barra in alto: quali dati caricare (finestra, istanza, origine). Come disegnarli sta nell'intestazione del grafico -->\r\n <form role=\"form\">\r\n <!-- Tre gruppi che vanno a capo interi: periodo, sorgente (con la ricerca), aggiornamento automatico -->\r\n <div class=\"tav2-toolbar\">\r\n <div class=\"tav2-cluster\">\r\n <div class=\"tav2-field\">\r\n <form-datetime [readonly]=\"refreshSeconds != '0'\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\" (inputChange)=\"datesEdited()\"></form-datetime>\r\n </div>\r\n <div class=\"tav2-field\">\r\n <form-datetime [readonly]=\"refreshSeconds != '0'\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\" (inputChange)=\"datesEdited()\"></form-datetime>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Ultime' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (h of QuickRanges; track h) {\r\n <button type=\"button\" [class.tav2-on]=\"activeRange == h\" (click)=\"quickRange(h)\">{{h}} h</button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"tav2-cluster\">\r\n <div class=\"tav2-field tav2-field-wide tav2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"instance\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanza' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Origine dati' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of DataSources; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"dataSource == o.id\" (click)=\"setDataSource(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <button [disabled]=\"loading || refreshSeconds != '0'\" class=\"btn app-btn-search\" (click)=\"searchClicked()\" type=\"submit\" [title]=\"'Cerca' | localize: lc\">\r\n <i class=\"fa\" [class.fa-search]=\"!loading\" [class.fa-spinner]=\"loading\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n </div>\r\n\r\n <div class=\"tav2-cluster tav2-cluster-end\">\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\"><i class=\"fa fa-refresh\"></i> {{'Aggiornamento automatico' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of RefreshOptions; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"refreshSeconds == o.id\" (click)=\"setRefresh(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <!-- Grafico -->\r\n <div class=\"tav2-panel\">\r\n <div class=\"tav2-panel-header tav2-chart-header\">\r\n <div class=\"tav2-heading\">\r\n <span class=\"tav2-title\">{{'Sessioni attive medie per' | localize: lc}} {{dimensionLabel(result?.dimension ?? +dimension) | lowercase}}</span>\r\n @if (result) {\r\n <span class=\"tav2-muted\">\r\n {{'Media' | localize: lc}} <strong>{{result.estimated ? '\u2248 ' : ''}}{{result.averageActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n &middot; {{'Picco' | localize: lc}} <strong>{{result.estimated ? '\u2248 ' : ''}}{{result.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n &middot; {{'un punto ogni' | localize: lc}} {{result.bucketSeconds}} s\r\n @if (result.estimated) {\r\n <span class=\"tav2-estimate\" [title]=\"'Valori stimati contando i campioni, come in Oracle, invece che misurati' | localize: lc\">{{'stima per campionamento' | localize: lc}}</span>\r\n }\r\n @if (loading) {\r\n &nbsp;<i class=\"fa fa-spinner fa-spin\"></i>\r\n }\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Come disegnare i dati -->\r\n <div class=\"tav2-view-controls\">\r\n <div class=\"tav2-field tav2-field-wide tav2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"dimension\" name=\"dimension\" [Source]=\"Dimensions\" [Placeholder]=\"'Dividi per' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Risoluzione' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of Resolutions; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"resolution == o.id\" (click)=\"setResolution(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Limite' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of LimitOptions; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"limitValue == o.id\" (click)=\"setLimit(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"tav2-toggle\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"totalActivity\" (inputChange)=\"search()\"></form-checkbox>\r\n <span class=\"tav2-pointer\" (click)=\"totalActivity = !totalActivity; search()\">{{'Attivit\u00E0 totale' | localize: lc}}</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n @if (filters.length > 0) {\r\n <div class=\"tav2-chips\">\r\n <span class=\"tav2-muted\">{{'Filtri' | localize: lc}}</span>\r\n @for (chip of filters; track $index) {\r\n <span class=\"tav2-chip\">\r\n {{chip.label}}\r\n <button type=\"button\" [title]=\"'Rimuovi' | localize: lc\" (click)=\"removeFilter($index)\">&times;</button>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"tav2-chart\">\r\n @if (chartData) {\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [Step]=\"true\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [AllowGaps]=\"false\"\r\n [Data]=\"chartData\"\r\n [Max]=\"chartMax\"\r\n [Legend]=\"false\"\r\n name=\"topactv2\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event)\"></es-line-chart>\r\n } @else {\r\n <div class=\"tav2-empty\">{{(loading ? 'Carico i Dati' : 'Nessun dato nella finestra') | localize: lc}}</div>\r\n }\r\n </div>\r\n\r\n <!-- Legenda: un clic su una voce la aggiunge ai filtri (\"altri\" non \u00E8 filtrabile) -->\r\n @if (legend.length > 0) {\r\n <div class=\"tav2-legend\">\r\n @for (item of legend; track $index) {\r\n <span class=\"tav2-legend-item\" [class.tav2-clickable]=\"!item.other\" [title]=\"item.other ? '' : ('Clic per filtrare' | localize: lc)\" (click)=\"addFilter(item)\">\r\n <span class=\"tav2-swatch\" [style.background]=\"item.color\"></span>\r\n {{item.label}}\r\n <span class=\"tav2-muted\">{{item.percentage | number : '1.0-1' : 'it'}}%</span>\r\n </span>\r\n }\r\n @if (result?.totalActivity) {\r\n <span class=\"tav2-legend-item\">\r\n <span class=\"tav2-line\" [style.border-color]=\"TotalColor\"></span>\r\n {{'Attivit\u00E0 totale' | localize: lc}}\r\n </span>\r\n }\r\n @if (result?.maximumThreads != null) {\r\n <span class=\"tav2-legend-item\">\r\n <span class=\"tav2-line\" [style.border-color]=\"LimitColor\"></span>\r\n {{limitLabel}} <strong>{{result.maximumThreads}}</strong>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n @if (memoryFrom) {\r\n <div class=\"tav2-note\">\r\n <i class=\"fa fa-info-circle\"></i>\r\n {{'Prima di questo istante i dati vengono dallo storico (un campione ogni 10 secondi)' | localize: lc}}: {{memoryFrom}}\r\n </div>\r\n }\r\n\r\n <!-- Time slider: finestra di 5 minuti per le tabelle -->\r\n @if (sliderMax > sliderMin) {\r\n <div class=\"tav2-slider\">\r\n <span class=\"tav2-slider-label\">\r\n <span class=\"tav2-muted\">{{'Finestra tabelle' | localize: lc}}</span>\r\n <strong>{{tablesWindowLabel}}</strong>\r\n </span>\r\n <input type=\"range\" [min]=\"sliderMin\" [max]=\"sliderMax\" [step]=\"sliderStep\" [ngModel]=\"sliderValue\" (ngModelChange)=\"sliderValue = $event; sliderMoving()\" (change)=\"sliderChanged()\" />\r\n <span class=\"tav2-badge\" [class.tav2-badge-off]=\"!sliderAnchored\">{{(sliderAnchored ? 'Ultimi 5 minuti' : 'Finestra fissa') | localize: lc}}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Tabelle -->\r\n <div class=\"tav2-tables\">\r\n @for (table of tables; track $index; let i = $index) {\r\n <div class=\"tav2-panel\">\r\n <div class=\"tav2-panel-header\">\r\n <span class=\"tav2-title\">{{'Prime righe per' | localize: lc}}</span>\r\n <div class=\"tav2-field tav2-field-wide tav2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"tableDims[i]\" name=\"tabledim{{i}}\" [Source]=\"Dimensions\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <span class=\"tav2-muted\">{{'Attivit\u00E0' | localize: lc}} <strong>{{table.estimated ? '\u2248 ' : ''}}{{table.activity | number : '1.2-3' : 'it'}}</strong></span>\r\n @if (table.estimated) {\r\n <span class=\"tav2-estimate\" [title]=\"'Stima contando i campioni: il totale pu\u00F2 differire di poco da quello misurato delle sessioni' | localize: lc\">{{'stima per campionamento' | localize: lc}}</span>\r\n }\r\n </div>\r\n <es-table [(ngModel)]=\"table.items\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th>{{dimensionLabel(table.dimension)}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min tav2-right\">%</th>\r\n @if (table.dimension == Dim.UserSession) {\r\n <th>{{'Utente' | localize: lc}}</th>\r\n <th>{{'Tipo' | localize: lc}}</th>\r\n <th>{{'Processo' | localize: lc}}</th>\r\n }\r\n @if (table.dimension == Dim.WaitEvent) {\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo' | localize: lc}}</th>\r\n }\r\n </ng-template>\r\n <ng-template #body let-item>\r\n <td>\r\n @if (isClickable(item)) {\r\n <span class=\"app-link tav2-ellipsis\" [title]=\"item.label || item.key\" (click)=\"openItem(item)\">{{itemLabel(item, table)}}</span>\r\n } @else {\r\n <span class=\"tav2-ellipsis\" [class.tav2-muted]=\"item.other || !item.label\">{{itemLabel(item, table)}}</span>\r\n }\r\n </td>\r\n <td class=\"app-nowrap\">\r\n <div class=\"tav2-bar-cell\">\r\n <div class=\"tav2-bar\">\r\n @for (part of item.breakdown; track $index) {\r\n <div [style.width.%]=\"breakdownWidth(item, part)\" [style.background]=\"breakdownColor(part)\" [title]=\"part.key\"></div>\r\n }\r\n </div>\r\n <span>{{table.estimated ? '\u2248 ' : ''}}{{item.activity | number : '1.2-3' : 'it'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"app-nowrap tav2-right\">{{item.percentage | number : '1.1-1' : 'it'}}</td>\r\n @if (table.dimension == Dim.UserSession) {\r\n <td class=\"app-nowrap\">\r\n {{item.session?.userName}}\r\n @if (item.session?.tenantId) {\r\n <span class=\"tav2-muted\">&middot; {{item.session.tenantId}}</span>\r\n }\r\n </td>\r\n <td class=\"tav2-muted\">{{item.session?.sessionType | titlecase}}</td>\r\n <td><span class=\"tav2-ellipsis tav2-ellipsis-short\" [title]=\"item.session?.bgProcessName || item.session?.jobName || ''\">{{item.session?.bgProcessName || item.session?.jobName}}</span></td>\r\n }\r\n @if (table.dimension == Dim.WaitEvent) {\r\n <td class=\"app-nowrap\">\r\n {{item.event?.eventType}}\r\n @if (item.event?.waitClass && item.event.waitClass != 'None') {\r\n <span class=\"tav2-muted\">&middot; {{item.event.waitClass}}</span>\r\n }\r\n </td>\r\n }\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Dettaglio v2 di nodo e sessione (DirectorFeature.DetailsV2) -->\r\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\r\n @if (detailsV2Enabled) {\r\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"true\" [CanOpenProfiler]=\"!!profilerV2Enabled\" (closed)=\"dlgDetailsV2.hide()\"\r\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"openInProfiler($event)\"></adm-details-v2>\r\n }\r\n</div>\r\n\r\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (NodeDetails) {\r\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\r\n }\r\n</div>\r\n\r\n<div bsModal #dlgSessionDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (SessionDetails) {\r\n <session-detail [SessionDetails]=\"SessionDetails\" (onClose)=\"dlgSessionDetails.hide()\" (onNodeSelected)=\"loadNodeDetails($event)\"></session-detail>\r\n }\r\n</div>\r\n", styles: [":host{display:block}:host ::ng-deep .tav2-noclear .p-select-clear-icon{display:none}.tav2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;padding-top:6px}.tav2-cluster{display:flex;flex-wrap:nowrap;align-items:center;gap:10px}.tav2-cluster-end{margin-left:auto}.tav2-field{width:165px}.tav2-field-wide{width:210px}.tav2-spacer{flex:1 1 auto}.tav2-toggle{display:flex;align-items:center;gap:8px;height:39px;white-space:nowrap}.tav2-pointer{cursor:pointer}.tav2-group{position:relative;display:inline-flex}.tav2-group-label{position:absolute;top:-8px;left:8px;z-index:1;padding:0 4px;background:#fff;color:var(--p-text-muted-color, #64748b);font-size:12px;line-height:15px;white-space:nowrap;pointer-events:none}.tav2-seg{display:inline-flex;height:39px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden;background:#fff}.tav2-seg button{padding:0 12px;border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;color:#334155;font-size:13px;white-space:nowrap;cursor:pointer}.tav2-seg button:first-child{border-left:0}.tav2-seg button:hover:not(.tav2-on){background:#f8fafc}.tav2-seg button:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:-2px}.tav2-seg button.tav2-on{background:#eef2ff;color:#4338ca;font-weight:500;box-shadow:inset 0 -2px 0 var(--p-primary-color, #6366f1)}.tav2-panel{margin-top:14px;padding:10px 12px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:#fff;min-width:0}.tav2-panel-header{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;min-height:32px;margin-bottom:6px}.tav2-chart-header{justify-content:space-between;padding-top:8px;margin-bottom:10px}.tav2-heading{display:flex;flex-direction:column;gap:2px}.tav2-view-controls{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px}.tav2-title{font-size:12px;font-weight:500;letter-spacing:.03em;text-transform:uppercase;color:#344154}.tav2-muted{color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-right{text-align:right}.tav2-estimate{display:inline-block;margin-left:6px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:16px;white-space:nowrap;cursor:help}.tav2-ellipsis{display:inline-block;max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.tav2-ellipsis-short{max-width:170px}.tav2-tables .tav2-panel{container-type:inline-size}@container (min-width: 900px){.tav2-ellipsis{max-width:520px}.tav2-ellipsis-short{max-width:300px}}.tav2-chips{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:6px}.tav2-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 10px;border-radius:12px;background:#eef2ff;color:#3730a3;font-size:12px}.tav2-chip button{border:0;background:transparent;color:inherit;cursor:pointer;font-size:15px;line-height:1;padding:0 4px}.tav2-chart{position:relative;height:300px}.tav2-empty{display:flex;align-items:center;justify-content:center;height:100%;border:1px dashed var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);color:var(--p-text-muted-color, #64748b)}.tav2-legend{display:flex;flex-wrap:wrap;gap:4px 6px;margin-top:6px}.tav2-legend-item{display:inline-flex;align-items:center;gap:6px;padding:2px 8px;border:1px solid transparent;border-radius:4px;font-size:12px;white-space:nowrap}.tav2-legend-item.tav2-clickable{cursor:pointer}.tav2-legend-item.tav2-clickable:hover{border-color:var(--p-content-border-color, #e2e8f0);background:#f8fafc}.tav2-swatch{flex:none;width:10px;height:10px;border-radius:2px}.tav2-line{flex:none;width:16px;height:0;border-top:2px solid}.tav2-note{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-slider{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin-top:10px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.tav2-slider input[type=range]{flex:1 1 260px;min-width:200px;accent-color:var(--p-primary-color, #6366f1);cursor:pointer}.tav2-slider-label{display:inline-flex;flex-direction:column;line-height:1.2;font-size:12px}.tav2-badge{padding:2px 8px;border-radius:10px;background:#eef2ff;color:#3730a3;font-size:11px;white-space:nowrap}.tav2-badge.tav2-badge-off{background:#f1f5f9;color:var(--p-text-muted-color, #64748b)}.tav2-tables{display:grid;grid-template-columns:repeat(auto-fit,minmax(560px,1fr));gap:0 14px}.tav2-bar-cell{display:flex;align-items:center;gap:8px}.tav2-bar{display:flex;flex:none;width:70px;height:8px;border-radius:2px;overflow:hidden;background:#edf2f7}\n"], dependencies: [{ kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i7.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "component", type: i8.EsTableComponent, selector: "es-table", inputs: ["globalCheck", "autoUpdate", "seconds", "researchInProgress", "globalColVisCheck", "EsThTdProvider", "CornerMenuOptions", "ColumnsResizable", "ColumnsPinnable", "AutoUpdate", "Height", "EmptySpaceBackgroundColor", "EsTableHandledSearch", "MaxHeight", "ContainerClass", "XLSXExport", "CSVExport", "AllSearch", "HighCellDensity", "Selection", "ShowLoadingOnBootstrap", "Removal", "RemovalCondition", "Export", "ShiftClick", "CountLabel", "HidePaging", "HidePagingCount", "HidePagingButtons", "ContextMenu", "ExportFileName", "TableClass", "ExportFunction", "ExportOnlyVisibleColumns", "HasHeaderGroup", "HasSecondaryHeaderGroup", "HeaderHidden", "BodyHidden", "SelectionDisabled", "SingleSelection", "RowClassAssigner", "OrderByColumn", "MultipleOrderingDirectives", "HiddenColumns", "ColumnsOrdering", "SearchView", "SelectAll", "UseArrayModePaging", "DynamicRowColumnsDefinition", "DynamicOperations", "Hierarchy", "ParentKey", "OwnKey", "AutoSortHierarchy", "StartsExpanded", "SavePreferences", "DefaultAlignment", "PagingStyle", "RowGroupingPagingStyle", "ItemSourceProperty", "UseSelectionCache", "ShowItemGroupsColumns", "Editable", "RangeSelection", "SearchThrottle", "ArraymodeItemsPerPage"], outputs: ["globalCheckChange", "autoUpdateChange", "secondsChange", "researchInProgressChange", "globalColVisCheckChange", "onOrderChanged", "onSearchRequest", "onSelectionChanged", "onRemoval", "onAbortRemoval", "onModelChange", "onOpenContextMenu", "onCornerAction", "onDynamicOperation"] }, { kind: "component", type: i9.EsFormSelectComponent, selector: "form-select", inputs: ["OptionsTemplate"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "component", type: i2.EsLineChartComponent, selector: "es-line-chart", inputs: ["Data", "DataArray", "Step", "DataGroupBucketSize", "DataGroupingThreshold", "StrokeSize", "AllowGaps", "MergeDatasets", "FinalInstants", "Min", "Max", "Fill", "Stacked"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: AdmDetailsV2Component, selector: "adm-details-v2", inputs: ["Be", "CanShowSessions", "CanOpenProfiler"], outputs: ["closed", "sessionsOnEvent", "openProfiler"] }, { kind: "component", type: SessionDetailComponent, selector: "session-detail", inputs: ["SessionDetails"], outputs: ["onClose", "onNodeSelected"] }, { kind: "component", type: NodeDetailComponent, selector: "node-detail", inputs: ["NodeDetails"], outputs: ["onClose"] }, { kind: "pipe", type: i5.LowerCasePipe, name: "lowercase" }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }, { kind: "pipe", type: i5.TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }] }); }
4751
5653
  }
4752
5654
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivityV2Component, decorators: [{
4753
5655
  type: Component,
4754
- args: [{ selector: "topact_v2", providers: [{ provide: LocalizationService, useClass: AdmTopActivityV2Loc }], standalone: false, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n @if (DirInfos) {\r\n <span>&nbsp;-&nbsp;\r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span>\r\n }\r\n </span>\r\n </div>\r\n <div class=\"card-body widget-body\">\r\n <!-- Barra in alto: quali dati caricare (finestra, istanza, origine). Come disegnarli sta nell'intestazione del grafico -->\r\n <form role=\"form\">\r\n <!-- Tre gruppi che vanno a capo interi: periodo, sorgente (con la ricerca), aggiornamento automatico -->\r\n <div class=\"tav2-toolbar\">\r\n <div class=\"tav2-cluster\">\r\n <div class=\"tav2-field\">\r\n <form-datetime [readonly]=\"refreshSeconds != '0'\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\" (inputChange)=\"datesEdited()\"></form-datetime>\r\n </div>\r\n <div class=\"tav2-field\">\r\n <form-datetime [readonly]=\"refreshSeconds != '0'\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\" (inputChange)=\"datesEdited()\"></form-datetime>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Ultime' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (h of QuickRanges; track h) {\r\n <button type=\"button\" [class.tav2-on]=\"activeRange == h\" (click)=\"quickRange(h)\">{{h}} h</button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"tav2-cluster\">\r\n <div class=\"tav2-field tav2-field-wide tav2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"instance\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanza' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Origine dati' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of DataSources; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"dataSource == o.id\" (click)=\"setDataSource(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <button [disabled]=\"loading || refreshSeconds != '0'\" class=\"btn app-btn-search\" (click)=\"searchClicked()\" type=\"submit\" [title]=\"'Cerca' | localize: lc\">\r\n <i class=\"fa\" [class.fa-search]=\"!loading\" [class.fa-spinner]=\"loading\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n </div>\r\n\r\n <div class=\"tav2-cluster tav2-cluster-end\">\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\"><i class=\"fa fa-refresh\"></i> {{'Aggiornamento automatico' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of RefreshOptions; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"refreshSeconds == o.id\" (click)=\"setRefresh(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <!-- Grafico -->\r\n <div class=\"tav2-panel\">\r\n <div class=\"tav2-panel-header tav2-chart-header\">\r\n <div class=\"tav2-heading\">\r\n <span class=\"tav2-title\">{{'Sessioni attive medie per' | localize: lc}} {{dimensionLabel(result?.dimension ?? +dimension) | lowercase}}</span>\r\n @if (result) {\r\n <span class=\"tav2-muted\">\r\n {{'Media' | localize: lc}} <strong>{{result.estimated ? '\u2248 ' : ''}}{{result.averageActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n &middot; {{'Picco' | localize: lc}} <strong>{{result.estimated ? '\u2248 ' : ''}}{{result.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n &middot; {{'un punto ogni' | localize: lc}} {{result.bucketSeconds}} s\r\n @if (result.estimated) {\r\n <span class=\"tav2-estimate\" [title]=\"'Valori stimati contando i campioni, come in Oracle, invece che misurati' | localize: lc\">{{'stima per campionamento' | localize: lc}}</span>\r\n }\r\n @if (loading) {\r\n &nbsp;<i class=\"fa fa-spinner fa-spin\"></i>\r\n }\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Come disegnare i dati -->\r\n <div class=\"tav2-view-controls\">\r\n <div class=\"tav2-field tav2-field-wide tav2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"dimension\" name=\"dimension\" [Source]=\"Dimensions\" [Placeholder]=\"'Dividi per' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Risoluzione' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of Resolutions; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"resolution == o.id\" (click)=\"setResolution(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Limite' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of LimitOptions; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"limitValue == o.id\" (click)=\"setLimit(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"tav2-toggle\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"totalActivity\" (inputChange)=\"search()\"></form-checkbox>\r\n <span class=\"tav2-pointer\" (click)=\"totalActivity = !totalActivity; search()\">{{'Attivit\u00E0 totale' | localize: lc}}</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n @if (filters.length > 0) {\r\n <div class=\"tav2-chips\">\r\n <span class=\"tav2-muted\">{{'Filtri' | localize: lc}}</span>\r\n @for (chip of filters; track $index) {\r\n <span class=\"tav2-chip\">\r\n {{chip.label}}\r\n <button type=\"button\" [title]=\"'Rimuovi' | localize: lc\" (click)=\"removeFilter($index)\">&times;</button>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"tav2-chart\">\r\n @if (chartData) {\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [Step]=\"true\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"chartData\"\r\n [Max]=\"chartMax\"\r\n [Legend]=\"false\"\r\n name=\"topactv2\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event)\"></es-line-chart>\r\n } @else {\r\n <div class=\"tav2-empty\">{{(loading ? 'Carico i Dati' : 'Nessun dato nella finestra') | localize: lc}}</div>\r\n }\r\n </div>\r\n\r\n <!-- Legenda: un clic su una voce la aggiunge ai filtri (\"altri\" non \u00E8 filtrabile) -->\r\n @if (legend.length > 0) {\r\n <div class=\"tav2-legend\">\r\n @for (item of legend; track $index) {\r\n <span class=\"tav2-legend-item\" [class.tav2-clickable]=\"!item.other\" [title]=\"item.other ? '' : ('Clic per filtrare' | localize: lc)\" (click)=\"addFilter(item)\">\r\n <span class=\"tav2-swatch\" [style.background]=\"item.color\"></span>\r\n {{item.label}}\r\n <span class=\"tav2-muted\">{{item.percentage | number : '1.0-1' : 'it'}}%</span>\r\n </span>\r\n }\r\n @if (result?.totalActivity) {\r\n <span class=\"tav2-legend-item\">\r\n <span class=\"tav2-line\" [style.border-color]=\"TotalColor\"></span>\r\n {{'Attivit\u00E0 totale' | localize: lc}}\r\n </span>\r\n }\r\n @if (result?.maximumThreads != null) {\r\n <span class=\"tav2-legend-item\">\r\n <span class=\"tav2-line\" [style.border-color]=\"LimitColor\"></span>\r\n {{limitLabel}} <strong>{{result.maximumThreads}}</strong>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n @if (memoryFrom) {\r\n <div class=\"tav2-note\">\r\n <i class=\"fa fa-info-circle\"></i>\r\n {{'Prima di questo istante i dati vengono dallo storico (un campione ogni 10 secondi)' | localize: lc}}: {{memoryFrom}}\r\n </div>\r\n }\r\n\r\n <!-- Time slider: finestra di 5 minuti per le tabelle -->\r\n @if (sliderMax > sliderMin) {\r\n <div class=\"tav2-slider\">\r\n <span class=\"tav2-slider-label\">\r\n <span class=\"tav2-muted\">{{'Finestra tabelle' | localize: lc}}</span>\r\n <strong>{{tablesWindowLabel}}</strong>\r\n </span>\r\n <input type=\"range\" [min]=\"sliderMin\" [max]=\"sliderMax\" [step]=\"sliderStep\" [ngModel]=\"sliderValue\" (ngModelChange)=\"sliderValue = $event; sliderMoving()\" (change)=\"sliderChanged()\" />\r\n <span class=\"tav2-badge\" [class.tav2-badge-off]=\"!sliderAnchored\">{{(sliderAnchored ? 'Ultimi 5 minuti' : 'Finestra fissa') | localize: lc}}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Tabelle -->\r\n <div class=\"tav2-tables\">\r\n @for (table of tables; track $index; let i = $index) {\r\n <div class=\"tav2-panel\">\r\n <div class=\"tav2-panel-header\">\r\n <span class=\"tav2-title\">{{'Prime righe per' | localize: lc}}</span>\r\n <div class=\"tav2-field tav2-field-wide tav2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"tableDims[i]\" name=\"tabledim{{i}}\" [Source]=\"Dimensions\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <span class=\"tav2-muted\">{{'Attivit\u00E0' | localize: lc}} <strong>{{table.estimated ? '\u2248 ' : ''}}{{table.activity | number : '1.2-3' : 'it'}}</strong></span>\r\n @if (table.estimated) {\r\n <span class=\"tav2-estimate\" [title]=\"'Stima contando i campioni: il totale pu\u00F2 differire di poco da quello misurato delle sessioni' | localize: lc\">{{'stima per campionamento' | localize: lc}}</span>\r\n }\r\n </div>\r\n <es-table [(ngModel)]=\"table.items\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th>{{dimensionLabel(table.dimension)}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min tav2-right\">%</th>\r\n @if (table.dimension == Dim.UserSession) {\r\n <th>{{'Utente' | localize: lc}}</th>\r\n <th>{{'Tipo' | localize: lc}}</th>\r\n <th>{{'Processo' | localize: lc}}</th>\r\n }\r\n @if (table.dimension == Dim.WaitEvent) {\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo' | localize: lc}}</th>\r\n }\r\n </ng-template>\r\n <ng-template #body let-item>\r\n <td>\r\n @if (isClickable(item)) {\r\n <span class=\"app-link tav2-ellipsis\" [title]=\"item.label || item.key\" (click)=\"openItem(item)\">{{itemLabel(item, table)}}</span>\r\n } @else {\r\n <span class=\"tav2-ellipsis\" [class.tav2-muted]=\"item.other || !item.label\">{{itemLabel(item, table)}}</span>\r\n }\r\n </td>\r\n <td class=\"app-nowrap\">\r\n <div class=\"tav2-bar-cell\">\r\n <div class=\"tav2-bar\">\r\n @for (part of item.breakdown; track $index) {\r\n <div [style.width.%]=\"breakdownWidth(item, part)\" [style.background]=\"breakdownColor(part)\" [title]=\"part.key\"></div>\r\n }\r\n </div>\r\n <span>{{table.estimated ? '\u2248 ' : ''}}{{item.activity | number : '1.2-3' : 'it'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"app-nowrap tav2-right\">{{item.percentage | number : '1.1-1' : 'it'}}</td>\r\n @if (table.dimension == Dim.UserSession) {\r\n <td class=\"app-nowrap\">\r\n {{item.session?.userName}}\r\n @if (item.session?.tenantId) {\r\n <span class=\"tav2-muted\">&middot; {{item.session.tenantId}}</span>\r\n }\r\n </td>\r\n <td class=\"tav2-muted\">{{item.session?.sessionType | titlecase}}</td>\r\n <td><span class=\"tav2-ellipsis tav2-ellipsis-short\" [title]=\"item.session?.bgProcessName || item.session?.jobName || ''\">{{item.session?.bgProcessName || item.session?.jobName}}</span></td>\r\n }\r\n @if (table.dimension == Dim.WaitEvent) {\r\n <td class=\"app-nowrap\">\r\n {{item.event?.eventType}}\r\n @if (item.event?.waitClass && item.event.waitClass != 'None') {\r\n <span class=\"tav2-muted\">&middot; {{item.event.waitClass}}</span>\r\n }\r\n </td>\r\n }\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (NodeDetails) {\r\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\r\n }\r\n</div>\r\n\r\n<div bsModal #dlgSessionDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (SessionDetails) {\r\n <session-detail [SessionDetails]=\"SessionDetails\" (onClose)=\"dlgSessionDetails.hide()\" (onNodeSelected)=\"loadNodeDetails($event)\"></session-detail>\r\n }\r\n</div>\r\n", styles: [":host{display:block}:host ::ng-deep .tav2-noclear .p-select-clear-icon{display:none}.tav2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;padding-top:6px}.tav2-cluster{display:flex;flex-wrap:nowrap;align-items:center;gap:10px}.tav2-cluster-end{margin-left:auto}.tav2-field{width:165px}.tav2-field-wide{width:210px}.tav2-spacer{flex:1 1 auto}.tav2-toggle{display:flex;align-items:center;gap:8px;height:39px;white-space:nowrap}.tav2-pointer{cursor:pointer}.tav2-group{position:relative;display:inline-flex}.tav2-group-label{position:absolute;top:-8px;left:8px;z-index:1;padding:0 4px;background:#fff;color:var(--p-text-muted-color, #64748b);font-size:12px;line-height:15px;white-space:nowrap;pointer-events:none}.tav2-seg{display:inline-flex;height:39px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden;background:#fff}.tav2-seg button{padding:0 12px;border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;color:#334155;font-size:13px;white-space:nowrap;cursor:pointer}.tav2-seg button:first-child{border-left:0}.tav2-seg button:hover:not(.tav2-on){background:#f8fafc}.tav2-seg button:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:-2px}.tav2-seg button.tav2-on{background:#eef2ff;color:#4338ca;font-weight:500;box-shadow:inset 0 -2px 0 var(--p-primary-color, #6366f1)}.tav2-panel{margin-top:14px;padding:10px 12px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:#fff;min-width:0}.tav2-panel-header{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;min-height:32px;margin-bottom:6px}.tav2-chart-header{justify-content:space-between;padding-top:8px;margin-bottom:10px}.tav2-heading{display:flex;flex-direction:column;gap:2px}.tav2-view-controls{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px}.tav2-title{font-size:12px;font-weight:500;letter-spacing:.03em;text-transform:uppercase;color:#344154}.tav2-muted{color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-right{text-align:right}.tav2-estimate{display:inline-block;margin-left:6px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:16px;white-space:nowrap;cursor:help}.tav2-ellipsis{display:inline-block;max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.tav2-ellipsis-short{max-width:170px}.tav2-tables .tav2-panel{container-type:inline-size}@container (min-width: 900px){.tav2-ellipsis{max-width:520px}.tav2-ellipsis-short{max-width:300px}}.tav2-chips{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:6px}.tav2-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 10px;border-radius:12px;background:#eef2ff;color:#3730a3;font-size:12px}.tav2-chip button{border:0;background:transparent;color:inherit;cursor:pointer;font-size:15px;line-height:1;padding:0 4px}.tav2-chart{position:relative;height:300px}.tav2-empty{display:flex;align-items:center;justify-content:center;height:100%;border:1px dashed var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);color:var(--p-text-muted-color, #64748b)}.tav2-legend{display:flex;flex-wrap:wrap;gap:4px 6px;margin-top:6px}.tav2-legend-item{display:inline-flex;align-items:center;gap:6px;padding:2px 8px;border:1px solid transparent;border-radius:4px;font-size:12px;white-space:nowrap}.tav2-legend-item.tav2-clickable{cursor:pointer}.tav2-legend-item.tav2-clickable:hover{border-color:var(--p-content-border-color, #e2e8f0);background:#f8fafc}.tav2-swatch{flex:none;width:10px;height:10px;border-radius:2px}.tav2-line{flex:none;width:16px;height:0;border-top:2px solid}.tav2-note{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-slider{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin-top:10px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.tav2-slider input[type=range]{flex:1 1 260px;min-width:200px;accent-color:var(--p-primary-color, #6366f1);cursor:pointer}.tav2-slider-label{display:inline-flex;flex-direction:column;line-height:1.2;font-size:12px}.tav2-badge{padding:2px 8px;border-radius:10px;background:#eef2ff;color:#3730a3;font-size:11px;white-space:nowrap}.tav2-badge.tav2-badge-off{background:#f1f5f9;color:var(--p-text-muted-color, #64748b)}.tav2-tables{display:grid;grid-template-columns:repeat(auto-fit,minmax(560px,1fr));gap:0 14px}.tav2-bar-cell{display:flex;align-items:center;gap:8px}.tav2-bar{display:flex;flex:none;width:70px;height:8px;border-radius:2px;overflow:hidden;background:#edf2f7}\n"] }]
4755
- }], ctorParameters: () => [{ type: i1$1.DateService }, { type: i1.LocalizationService }, { type: i3.PreferencesService }, { type: i1$1.InterComService }, { type: i4.ActivatedRoute }, { type: AdminModuleBaseService }, { type: i0.NgZone }], propDecorators: { dlgNodeDetails: [{
5656
+ args: [{ selector: "topact_v2", providers: [{ provide: LocalizationService, useClass: AdmTopActivityV2Loc }], standalone: false, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n @if (DirInfos) {\r\n <span>&nbsp;-&nbsp;\r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span>\r\n }\r\n </span>\r\n </div>\r\n <div class=\"card-body widget-body\">\r\n <!-- Barra in alto: quali dati caricare (finestra, istanza, origine). Come disegnarli sta nell'intestazione del grafico -->\r\n <form role=\"form\">\r\n <!-- Tre gruppi che vanno a capo interi: periodo, sorgente (con la ricerca), aggiornamento automatico -->\r\n <div class=\"tav2-toolbar\">\r\n <div class=\"tav2-cluster\">\r\n <div class=\"tav2-field\">\r\n <form-datetime [readonly]=\"refreshSeconds != '0'\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\" (inputChange)=\"datesEdited()\"></form-datetime>\r\n </div>\r\n <div class=\"tav2-field\">\r\n <form-datetime [readonly]=\"refreshSeconds != '0'\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\" (inputChange)=\"datesEdited()\"></form-datetime>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Ultime' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (h of QuickRanges; track h) {\r\n <button type=\"button\" [class.tav2-on]=\"activeRange == h\" (click)=\"quickRange(h)\">{{h}} h</button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"tav2-cluster\">\r\n <div class=\"tav2-field tav2-field-wide tav2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"instance\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanza' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Origine dati' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of DataSources; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"dataSource == o.id\" (click)=\"setDataSource(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <button [disabled]=\"loading || refreshSeconds != '0'\" class=\"btn app-btn-search\" (click)=\"searchClicked()\" type=\"submit\" [title]=\"'Cerca' | localize: lc\">\r\n <i class=\"fa\" [class.fa-search]=\"!loading\" [class.fa-spinner]=\"loading\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n </div>\r\n\r\n <div class=\"tav2-cluster tav2-cluster-end\">\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\"><i class=\"fa fa-refresh\"></i> {{'Aggiornamento automatico' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of RefreshOptions; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"refreshSeconds == o.id\" (click)=\"setRefresh(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </form>\r\n\r\n <!-- Grafico -->\r\n <div class=\"tav2-panel\">\r\n <div class=\"tav2-panel-header tav2-chart-header\">\r\n <div class=\"tav2-heading\">\r\n <span class=\"tav2-title\">{{'Sessioni attive medie per' | localize: lc}} {{dimensionLabel(result?.dimension ?? +dimension) | lowercase}}</span>\r\n @if (result) {\r\n <span class=\"tav2-muted\">\r\n {{'Media' | localize: lc}} <strong>{{result.estimated ? '\u2248 ' : ''}}{{result.averageActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n &middot; {{'Picco' | localize: lc}} <strong>{{result.estimated ? '\u2248 ' : ''}}{{result.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n &middot; {{'un punto ogni' | localize: lc}} {{result.bucketSeconds}} s\r\n @if (result.estimated) {\r\n <span class=\"tav2-estimate\" [title]=\"'Valori stimati contando i campioni, come in Oracle, invece che misurati' | localize: lc\">{{'stima per campionamento' | localize: lc}}</span>\r\n }\r\n @if (loading) {\r\n &nbsp;<i class=\"fa fa-spinner fa-spin\"></i>\r\n }\r\n </span>\r\n }\r\n </div>\r\n\r\n <!-- Come disegnare i dati -->\r\n <div class=\"tav2-view-controls\">\r\n <div class=\"tav2-field tav2-field-wide tav2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"dimension\" name=\"dimension\" [Source]=\"Dimensions\" [Placeholder]=\"'Dividi per' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Risoluzione' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of Resolutions; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"resolution == o.id\" (click)=\"setResolution(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"tav2-group\">\r\n <span class=\"tav2-group-label\">{{'Limite' | localize: lc}}</span>\r\n <div class=\"tav2-seg\">\r\n @for (o of LimitOptions; track o.id) {\r\n <button type=\"button\" [class.tav2-on]=\"limitValue == o.id\" (click)=\"setLimit(o.id)\">{{o.description}}</button>\r\n }\r\n </div>\r\n </div>\r\n <div class=\"tav2-toggle\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"totalActivity\" (inputChange)=\"search()\"></form-checkbox>\r\n <span class=\"tav2-pointer\" (click)=\"totalActivity = !totalActivity; search()\">{{'Attivit\u00E0 totale' | localize: lc}}</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n @if (filters.length > 0) {\r\n <div class=\"tav2-chips\">\r\n <span class=\"tav2-muted\">{{'Filtri' | localize: lc}}</span>\r\n @for (chip of filters; track $index) {\r\n <span class=\"tav2-chip\">\r\n {{chip.label}}\r\n <button type=\"button\" [title]=\"'Rimuovi' | localize: lc\" (click)=\"removeFilter($index)\">&times;</button>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"tav2-chart\">\r\n @if (chartData) {\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [Step]=\"true\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [AllowGaps]=\"false\"\r\n [Data]=\"chartData\"\r\n [Max]=\"chartMax\"\r\n [Legend]=\"false\"\r\n name=\"topactv2\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event)\"></es-line-chart>\r\n } @else {\r\n <div class=\"tav2-empty\">{{(loading ? 'Carico i Dati' : 'Nessun dato nella finestra') | localize: lc}}</div>\r\n }\r\n </div>\r\n\r\n <!-- Legenda: un clic su una voce la aggiunge ai filtri (\"altri\" non \u00E8 filtrabile) -->\r\n @if (legend.length > 0) {\r\n <div class=\"tav2-legend\">\r\n @for (item of legend; track $index) {\r\n <span class=\"tav2-legend-item\" [class.tav2-clickable]=\"!item.other\" [title]=\"item.other ? '' : ('Clic per filtrare' | localize: lc)\" (click)=\"addFilter(item)\">\r\n <span class=\"tav2-swatch\" [style.background]=\"item.color\"></span>\r\n {{item.label}}\r\n <span class=\"tav2-muted\">{{item.percentage | number : '1.0-1' : 'it'}}%</span>\r\n </span>\r\n }\r\n @if (result?.totalActivity) {\r\n <span class=\"tav2-legend-item\">\r\n <span class=\"tav2-line\" [style.border-color]=\"TotalColor\"></span>\r\n {{'Attivit\u00E0 totale' | localize: lc}}\r\n </span>\r\n }\r\n @if (result?.maximumThreads != null) {\r\n <span class=\"tav2-legend-item\">\r\n <span class=\"tav2-line\" [style.border-color]=\"LimitColor\"></span>\r\n {{limitLabel}} <strong>{{result.maximumThreads}}</strong>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n @if (memoryFrom) {\r\n <div class=\"tav2-note\">\r\n <i class=\"fa fa-info-circle\"></i>\r\n {{'Prima di questo istante i dati vengono dallo storico (un campione ogni 10 secondi)' | localize: lc}}: {{memoryFrom}}\r\n </div>\r\n }\r\n\r\n <!-- Time slider: finestra di 5 minuti per le tabelle -->\r\n @if (sliderMax > sliderMin) {\r\n <div class=\"tav2-slider\">\r\n <span class=\"tav2-slider-label\">\r\n <span class=\"tav2-muted\">{{'Finestra tabelle' | localize: lc}}</span>\r\n <strong>{{tablesWindowLabel}}</strong>\r\n </span>\r\n <input type=\"range\" [min]=\"sliderMin\" [max]=\"sliderMax\" [step]=\"sliderStep\" [ngModel]=\"sliderValue\" (ngModelChange)=\"sliderValue = $event; sliderMoving()\" (change)=\"sliderChanged()\" />\r\n <span class=\"tav2-badge\" [class.tav2-badge-off]=\"!sliderAnchored\">{{(sliderAnchored ? 'Ultimi 5 minuti' : 'Finestra fissa') | localize: lc}}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Tabelle -->\r\n <div class=\"tav2-tables\">\r\n @for (table of tables; track $index; let i = $index) {\r\n <div class=\"tav2-panel\">\r\n <div class=\"tav2-panel-header\">\r\n <span class=\"tav2-title\">{{'Prime righe per' | localize: lc}}</span>\r\n <div class=\"tav2-field tav2-field-wide tav2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"tableDims[i]\" name=\"tabledim{{i}}\" [Source]=\"Dimensions\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <span class=\"tav2-muted\">{{'Attivit\u00E0' | localize: lc}} <strong>{{table.estimated ? '\u2248 ' : ''}}{{table.activity | number : '1.2-3' : 'it'}}</strong></span>\r\n @if (table.estimated) {\r\n <span class=\"tav2-estimate\" [title]=\"'Stima contando i campioni: il totale pu\u00F2 differire di poco da quello misurato delle sessioni' | localize: lc\">{{'stima per campionamento' | localize: lc}}</span>\r\n }\r\n </div>\r\n <es-table [(ngModel)]=\"table.items\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th>{{dimensionLabel(table.dimension)}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min tav2-right\">%</th>\r\n @if (table.dimension == Dim.UserSession) {\r\n <th>{{'Utente' | localize: lc}}</th>\r\n <th>{{'Tipo' | localize: lc}}</th>\r\n <th>{{'Processo' | localize: lc}}</th>\r\n }\r\n @if (table.dimension == Dim.WaitEvent) {\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo' | localize: lc}}</th>\r\n }\r\n </ng-template>\r\n <ng-template #body let-item>\r\n <td>\r\n @if (isClickable(item)) {\r\n <span class=\"app-link tav2-ellipsis\" [title]=\"item.label || item.key\" (click)=\"openItem(item)\">{{itemLabel(item, table)}}</span>\r\n } @else {\r\n <span class=\"tav2-ellipsis\" [class.tav2-muted]=\"item.other || !item.label\">{{itemLabel(item, table)}}</span>\r\n }\r\n </td>\r\n <td class=\"app-nowrap\">\r\n <div class=\"tav2-bar-cell\">\r\n <div class=\"tav2-bar\">\r\n @for (part of item.breakdown; track $index) {\r\n <div [style.width.%]=\"breakdownWidth(item, part)\" [style.background]=\"breakdownColor(part)\" [title]=\"part.key\"></div>\r\n }\r\n </div>\r\n <span>{{table.estimated ? '\u2248 ' : ''}}{{item.activity | number : '1.2-3' : 'it'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"app-nowrap tav2-right\">{{item.percentage | number : '1.1-1' : 'it'}}</td>\r\n @if (table.dimension == Dim.UserSession) {\r\n <td class=\"app-nowrap\">\r\n {{item.session?.userName}}\r\n @if (item.session?.tenantId) {\r\n <span class=\"tav2-muted\">&middot; {{item.session.tenantId}}</span>\r\n }\r\n </td>\r\n <td class=\"tav2-muted\">{{item.session?.sessionType | titlecase}}</td>\r\n <td><span class=\"tav2-ellipsis tav2-ellipsis-short\" [title]=\"item.session?.bgProcessName || item.session?.jobName || ''\">{{item.session?.bgProcessName || item.session?.jobName}}</span></td>\r\n }\r\n @if (table.dimension == Dim.WaitEvent) {\r\n <td class=\"app-nowrap\">\r\n {{item.event?.eventType}}\r\n @if (item.event?.waitClass && item.event.waitClass != 'None') {\r\n <span class=\"tav2-muted\">&middot; {{item.event.waitClass}}</span>\r\n }\r\n </td>\r\n }\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Dettaglio v2 di nodo e sessione (DirectorFeature.DetailsV2) -->\r\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\r\n @if (detailsV2Enabled) {\r\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"true\" [CanOpenProfiler]=\"!!profilerV2Enabled\" (closed)=\"dlgDetailsV2.hide()\"\r\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"openInProfiler($event)\"></adm-details-v2>\r\n }\r\n</div>\r\n\r\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (NodeDetails) {\r\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\r\n }\r\n</div>\r\n\r\n<div bsModal #dlgSessionDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (SessionDetails) {\r\n <session-detail [SessionDetails]=\"SessionDetails\" (onClose)=\"dlgSessionDetails.hide()\" (onNodeSelected)=\"loadNodeDetails($event)\"></session-detail>\r\n }\r\n</div>\r\n", styles: [":host{display:block}:host ::ng-deep .tav2-noclear .p-select-clear-icon{display:none}.tav2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;padding-top:6px}.tav2-cluster{display:flex;flex-wrap:nowrap;align-items:center;gap:10px}.tav2-cluster-end{margin-left:auto}.tav2-field{width:165px}.tav2-field-wide{width:210px}.tav2-spacer{flex:1 1 auto}.tav2-toggle{display:flex;align-items:center;gap:8px;height:39px;white-space:nowrap}.tav2-pointer{cursor:pointer}.tav2-group{position:relative;display:inline-flex}.tav2-group-label{position:absolute;top:-8px;left:8px;z-index:1;padding:0 4px;background:#fff;color:var(--p-text-muted-color, #64748b);font-size:12px;line-height:15px;white-space:nowrap;pointer-events:none}.tav2-seg{display:inline-flex;height:39px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden;background:#fff}.tav2-seg button{padding:0 12px;border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;color:#334155;font-size:13px;white-space:nowrap;cursor:pointer}.tav2-seg button:first-child{border-left:0}.tav2-seg button:hover:not(.tav2-on){background:#f8fafc}.tav2-seg button:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:-2px}.tav2-seg button.tav2-on{background:#eef2ff;color:#4338ca;font-weight:500;box-shadow:inset 0 -2px 0 var(--p-primary-color, #6366f1)}.tav2-panel{margin-top:14px;padding:10px 12px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:#fff;min-width:0}.tav2-panel-header{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;min-height:32px;margin-bottom:6px}.tav2-chart-header{justify-content:space-between;padding-top:8px;margin-bottom:10px}.tav2-heading{display:flex;flex-direction:column;gap:2px}.tav2-view-controls{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px}.tav2-title{font-size:12px;font-weight:500;letter-spacing:.03em;text-transform:uppercase;color:#344154}.tav2-muted{color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-right{text-align:right}.tav2-estimate{display:inline-block;margin-left:6px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:16px;white-space:nowrap;cursor:help}.tav2-ellipsis{display:inline-block;max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.tav2-ellipsis-short{max-width:170px}.tav2-tables .tav2-panel{container-type:inline-size}@container (min-width: 900px){.tav2-ellipsis{max-width:520px}.tav2-ellipsis-short{max-width:300px}}.tav2-chips{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:6px}.tav2-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 10px;border-radius:12px;background:#eef2ff;color:#3730a3;font-size:12px}.tav2-chip button{border:0;background:transparent;color:inherit;cursor:pointer;font-size:15px;line-height:1;padding:0 4px}.tav2-chart{position:relative;height:300px}.tav2-empty{display:flex;align-items:center;justify-content:center;height:100%;border:1px dashed var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);color:var(--p-text-muted-color, #64748b)}.tav2-legend{display:flex;flex-wrap:wrap;gap:4px 6px;margin-top:6px}.tav2-legend-item{display:inline-flex;align-items:center;gap:6px;padding:2px 8px;border:1px solid transparent;border-radius:4px;font-size:12px;white-space:nowrap}.tav2-legend-item.tav2-clickable{cursor:pointer}.tav2-legend-item.tav2-clickable:hover{border-color:var(--p-content-border-color, #e2e8f0);background:#f8fafc}.tav2-swatch{flex:none;width:10px;height:10px;border-radius:2px}.tav2-line{flex:none;width:16px;height:0;border-top:2px solid}.tav2-note{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-slider{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin-top:10px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.tav2-slider input[type=range]{flex:1 1 260px;min-width:200px;accent-color:var(--p-primary-color, #6366f1);cursor:pointer}.tav2-slider-label{display:inline-flex;flex-direction:column;line-height:1.2;font-size:12px}.tav2-badge{padding:2px 8px;border-radius:10px;background:#eef2ff;color:#3730a3;font-size:11px;white-space:nowrap}.tav2-badge.tav2-badge-off{background:#f1f5f9;color:var(--p-text-muted-color, #64748b)}.tav2-tables{display:grid;grid-template-columns:repeat(auto-fit,minmax(560px,1fr));gap:0 14px}.tav2-bar-cell{display:flex;align-items:center;gap:8px}.tav2-bar{display:flex;flex:none;width:70px;height:8px;border-radius:2px;overflow:hidden;background:#edf2f7}\n"] }]
5657
+ }], ctorParameters: () => [{ type: i1$1.DateService }, { type: i1.LocalizationService }, { type: i3.PreferencesService }, { type: i1$1.InterComService }, { type: i4.ActivatedRoute }, { type: AdminModuleBaseService }, { type: i0.NgZone }, { type: i4.Router }, { type: undefined, decorators: [{
5658
+ type: Inject,
5659
+ args: [ADM_MODULE_PATH]
5660
+ }] }, { type: undefined, decorators: [{
5661
+ type: Optional
5662
+ }, {
5663
+ type: Inject,
5664
+ args: [ADM_DETAILS_V2]
5665
+ }] }, { type: undefined, decorators: [{
5666
+ type: Optional
5667
+ }, {
5668
+ type: Inject,
5669
+ args: [ADM_PROFILER_V2]
5670
+ }] }], propDecorators: { dlgNodeDetails: [{
4756
5671
  type: ViewChild,
4757
5672
  args: ["dlgNodeDetails"]
4758
5673
  }], dlgSessionDetails: [{
4759
5674
  type: ViewChild,
4760
5675
  args: ["dlgSessionDetails"]
5676
+ }], dlgDetailsV2: [{
5677
+ type: ViewChild,
5678
+ args: ["dlgDetailsV2"]
5679
+ }], detailsV2: [{
5680
+ type: ViewChild,
5681
+ args: [AdmDetailsV2Component]
4761
5682
  }] } });
4762
5683
 
4763
5684
  class LocksView extends AppSearch {
@@ -5495,7 +6416,7 @@ const routeConfig = [
5495
6416
  { path: "serveraudits/:be", component: AdmAuditsComponent, data: { title: "Ricerca Audit Applicativi", internalNavigation: false } },
5496
6417
  { path: "serverenqueues/:be", component: AdmEnqComponent, data: { title: "Ricerca Lock Applicativi", internalNavigation: false } },
5497
6418
  { path: "serverviews/:be", component: AdmDynamicViewsComponent, data: { title: "Ricerca Viste Dinamiche Applicative", internalNavigation: false } },
5498
- { path: "metadataquery/:be", component: MtdQueryComponent, data: { title: "Ricerca Viste Dinamiche Applicative", internalNavigation: false } },
6419
+ { path: "metadataquery/:be", component: MtdQueryComponent, data: { title: "Query Viste Dinamiche", internalNavigation: false } },
5499
6420
  { path: "serverworkers", component: AdmWrkComponent, data: { title: "Ricerca Processi Applicativi", internalNavigation: false } },
5500
6421
  { path: "profiler", component: AdmProfilerV2Component, canMatch: [profilerV2Enabled], data: { title: "Profiler del Server", internalNavigation: false } },
5501
6422
  { path: "profiler", component: AdmProfilerComponent, data: { title: "Profiler del Server", internalNavigation: false } },
@@ -5508,7 +6429,7 @@ const routeConfig = [
5508
6429
  { path: "serveraudits", component: AdmAuditsComponent, data: { title: "Ricerca Audit Applicativi", internalNavigation: false } },
5509
6430
  { path: "serverenqueues", component: AdmEnqComponent, data: { title: "Ricerca Lock Applicativi", internalNavigation: false } },
5510
6431
  { path: "serverviews", component: AdmDynamicViewsComponent, data: { title: "Ricerca Viste Dinamiche Applicative", internalNavigation: false } },
5511
- { path: "metadataquery", component: MtdQueryComponent, data: { title: "Ricerca Viste Dinamiche Applicative", internalNavigation: false } },
6432
+ { path: "metadataquery", component: MtdQueryComponent, data: { title: "Query Viste Dinamiche", internalNavigation: false } },
5512
6433
  { path: "syspars", component: AdmSystemParametersComponent, data: { title: "Parametri di sistema", internalNavigation: false } }
5513
6434
  ]
5514
6435
  }
@@ -5540,6 +6461,8 @@ const COMPONENTS = [
5540
6461
  AdmWorkloadV2Component,
5541
6462
  AdmMetricsV2Component,
5542
6463
  MetricsV2ChartComponent,
6464
+ AdmDetailsV2Component,
6465
+ ActivityChartV2Component,
5543
6466
  AdmTopActivitiesComponent,
5544
6467
  AdmTopActivityV2Component,
5545
6468
  SessionDetailComponent,
@@ -5569,6 +6492,8 @@ class AdmModule {
5569
6492
  AdmWorkloadV2Component,
5570
6493
  AdmMetricsV2Component,
5571
6494
  MetricsV2ChartComponent,
6495
+ AdmDetailsV2Component,
6496
+ ActivityChartV2Component,
5572
6497
  AdmTopActivitiesComponent,
5573
6498
  AdmTopActivityV2Component,
5574
6499
  SessionDetailComponent,
@@ -5604,7 +6529,10 @@ class AdmModule {
5604
6529
  { provide: ADM_TOPACT_V2, useFactory: () => !!myconfig?.DirectorFeature?.TopActivityV2 },
5605
6530
  { provide: ADM_PROFILER_V2, useFactory: () => !!myconfig?.DirectorFeature?.ProfilerV2 },
5606
6531
  { provide: ADM_WORKLOAD_V2, useFactory: () => !!myconfig?.DirectorFeature?.WorkloadReportV2 },
5607
- { provide: ADM_METRICS_V2, useFactory: () => !!myconfig?.DirectorFeature?.MetricsV2 }
6532
+ { provide: ADM_METRICS_V2, useFactory: () => !!myconfig?.DirectorFeature?.MetricsV2 },
6533
+ // Dettaglio di nodo e sessione v2: lo aprono tutte le pagine che mostrano nodi e sessioni, v1 comprese, perché con il flag il backend-for-frontend
6534
+ // risponde a GetNodeStats e GetSessionStats solo con il contratto nuovo
6535
+ { provide: ADM_DETAILS_V2, useFactory: () => !!myconfig?.DirectorFeature?.DetailsV2 }
5608
6536
  ], imports: [MODULES] }); }
5609
6537
  }
5610
6538
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmModule, decorators: [{
@@ -5618,7 +6546,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
5618
6546
  { provide: ADM_TOPACT_V2, useFactory: () => !!myconfig?.DirectorFeature?.TopActivityV2 },
5619
6547
  { provide: ADM_PROFILER_V2, useFactory: () => !!myconfig?.DirectorFeature?.ProfilerV2 },
5620
6548
  { provide: ADM_WORKLOAD_V2, useFactory: () => !!myconfig?.DirectorFeature?.WorkloadReportV2 },
5621
- { provide: ADM_METRICS_V2, useFactory: () => !!myconfig?.DirectorFeature?.MetricsV2 }
6549
+ { provide: ADM_METRICS_V2, useFactory: () => !!myconfig?.DirectorFeature?.MetricsV2 },
6550
+ // Dettaglio di nodo e sessione v2: lo aprono tutte le pagine che mostrano nodi e sessioni, v1 comprese, perché con il flag il backend-for-frontend
6551
+ // risponde a GetNodeStats e GetSessionStats solo con il contratto nuovo
6552
+ { provide: ADM_DETAILS_V2, useFactory: () => !!myconfig?.DirectorFeature?.DetailsV2 }
5622
6553
  ]
5623
6554
  }]
5624
6555
  }], ctorParameters: () => [{ type: AdminModuleCommService }] });
@@ -5631,5 +6562,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
5631
6562
  * Generated bundle index. Do not edit.
5632
6563
  */
5633
6564
 
5634
- export { ADM_CONVERSATIONS, ADM_METRICS_V2, ADM_MODULE_PATH, ADM_PROFILER_V2, ADM_TOPACT_V2, ADM_WORKLOAD_V2, AdmMessageTypes, AdmModule, MK_ADM, metricsV2Enabled, profilerV2Enabled, routeConfig, topActivityV2Enabled, workloadReportV2Enabled };
6565
+ export { ADM_CONVERSATIONS, ADM_DETAILS_V2, ADM_METRICS_V2, ADM_MODULE_PATH, ADM_PROFILER_V2, ADM_TOPACT_V2, ADM_WORKLOAD_V2, AdmMessageTypes, AdmModule, MK_ADM, metricsV2Enabled, profilerV2Enabled, routeConfig, topActivityV2Enabled, workloadReportV2Enabled };
5635
6566
  //# sourceMappingURL=esfaenza-admin-module.mjs.map