@esfaenza/admin-module 20.3.23 → 20.3.25

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,783 @@ 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", "Sullo storico il nodo si cerca solo negli snapshot della finestra: prova \"Dal vivo\" o una finestra più ampia", ["In history the node is only looked up in the window's snapshots: try \"Live\" or a wider window"]);
870
+ super.set("it->en", "Carico i Dati", ["Loading data"]);
871
+ super.set("it->en", "Copia", ["Copy"]);
872
+ super.set("it->en", "Copiato", ["Copied"]);
873
+ super.set("it->en", "Apri nel profiler", ["Open in profiler"]);
874
+ super.set("it->en", "Sessioni su questo evento", ["Sessions on this event"]);
875
+ super.set("it->en", "Solo l'evento esatto: il lavoro dei discendenti non è compreso", ["Exact event only: the descendants' work is not included"]);
876
+ super.set("it->en", "Top Activity filtrata su questo evento", ["Top Activity filtered on this event"]);
877
+ super.set("it->en", "discendenti esclusi", ["descendants excluded"]);
878
+ super.set("it->en", "Statistiche", ["Statistics"]);
879
+ super.set("it->en", "Dall'avvio", ["Since startup"]);
880
+ super.set("it->en", "Dall'ultimo snapshot", ["Since the last snapshot"]);
881
+ super.set("it->en", "Nella finestra", ["In the window"]);
882
+ super.set("it->en", "Esecuzioni", ["Executions"]);
883
+ super.set("it->en", "Tempo totale", ["Total time"]);
884
+ super.set("it->en", "Tempo proprio", ["Self time"]);
885
+ super.set("it->en", "Medio", ["Average"]);
886
+ super.set("it->en", "Massimo", ["Peak"]);
887
+ super.set("it->en", "Minimo", ["Minimum"]);
888
+ super.set("it->en", "Thread dentro adesso", ["Threads inside now"]);
889
+ super.set("it->en", "In corso da", ["Running for"]);
890
+ super.set("it->en", "Ultima uscita", ["Last exit"]);
891
+ super.set("it->en", "Dove va il tempo", ["Where the time goes"]);
892
+ super.set("it->en", "tempo proprio del sottoalbero", ["self time of the subtree"]);
893
+ super.set("it->en", "Idle è tempo di attesa senza lavoro", ["Idle is waiting time with no work"]);
894
+ super.set("it->en", "Per istanza", ["By instance"]);
895
+ super.set("it->en", "Istanza", ["Instance"]);
896
+ super.set("it->en", "Tempo", ["Time"]);
897
+ super.set("it->en", "Thread attivi", ["Active threads"]);
898
+ super.set("it->en", "Attività nel tempo", ["Activity over time"]);
899
+ super.set("it->en", "sessioni attive medie", ["average active sessions"]);
900
+ super.set("it->en", "picco", ["peak"]);
901
+ super.set("it->en", "un punto ogni", ["one point every"]);
902
+ super.set("it->en", "stima per campionamento", ["sampling estimate"]);
903
+ super.set("it->en", "Valori stimati contando i campioni", ["Values estimated by counting samples"]);
904
+ super.set("it->en", "sessioni", ["sessions"]);
905
+ super.set("it->en", "Nessuna attività nella finestra", ["No activity in the window"]);
906
+ super.set("it->en", "Prima delle", ["Before"]);
907
+ super.set("it->en", "i dati vengono dallo storico, con meno risoluzione", ["data comes from history, with lower resolution"]);
908
+ super.set("it->en", "Comprende il lavoro dei discendenti", ["Includes the descendants' work"]);
909
+ super.set("it->en", "Discendenti principali", ["Top descendants"]);
910
+ super.set("it->en", "Figli", ["Children"]);
911
+ super.set("it->en", "Discendenti", ["Descendants"]);
912
+ super.set("it->en", "Nome", ["Name"]);
913
+ super.set("it->en", "Tipo", ["Type"]);
914
+ super.set("it->en", "Livello", ["Level"]);
915
+ super.set("it->en", "del nodo", ["of the node"]);
916
+ super.set("it->en", "Terminata", ["Terminated"]);
917
+ super.set("it->en", "Utente", ["User"]);
918
+ super.set("it->en", "Gruppo di consumo", ["Consumer group"]);
919
+ super.set("it->en", "Sessione di background", ["Background session"]);
920
+ super.set("it->en", "Inizio", ["Start"]);
921
+ super.set("it->en", "collegata da", ["connected for"]);
922
+ super.set("it->en", "Ultima attività", ["Last activity"]);
923
+ 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"]);
924
+ super.set("it->en", "Sessioni attive medie", ["Average active sessions"]);
925
+ super.set("it->en", "Media", ["Average"]);
926
+ super.set("it->en", "Picco", ["Peak"]);
927
+ super.set("it->en", "Dividi per", ["Split by"]);
928
+ super.set("it->en", "Classe di attesa", ["Wait class"]);
929
+ super.set("it->en", "Tipo di evento", ["Event type"]);
930
+ super.set("it->en", "Evento", ["Event"]);
931
+ super.set("it->en", "Bassa", ["Low"]);
932
+ super.set("it->en", "Alta", ["High"]);
933
+ super.set("it->en", "Massima", ["Maximum"]);
934
+ super.set("it->en", "Eventi", ["Events"]);
935
+ super.set("it->en", "Attività", ["Activity"]);
936
+ super.set("it->en", "Altri", ["Others"]);
937
+ super.set("it->en", "(nessuno)", ["(none)"]);
938
+ super.set("it->en", "(non attribuito)", ["(unattributed)"]);
939
+ super.set("it->en", "Thread adesso", ["Threads now"]);
940
+ super.set("it->en", "Stato", ["Status"]);
941
+ super.set("it->en", "Priorità", ["Priority"]);
942
+ super.set("it->en", "Macchina", ["Machine"]);
943
+ super.set("it->en", "Evento corrente", ["Current event"]);
944
+ super.set("it->en", "nessun evento in corso", ["no event in progress"]);
945
+ super.set("it->en", "Pila completa degli eventi", ["Full event stack"]);
946
+ super.set("it->en", "Nessun evento", ["No event"]);
947
+ super.set("it->en", "Operazioni lunghe", ["Long operations"]);
948
+ super.set("it->en", "di", ["of"]);
949
+ super.set("it->en", "Trascorso", ["Elapsed"]);
950
+ super.set("it->en", "Alla fine", ["Remaining"]);
951
+ super.set("it->en", "non stimabile", ["not estimable"]);
952
+ }
953
+ 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 }); }
954
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Loc }); }
955
+ }
956
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Loc, decorators: [{
957
+ type: Injectable
958
+ }], ctorParameters: () => [{ type: i0.Injector }] });
959
+
960
+ // Angular
961
+ class ActivityChartV2Component_Item {
962
+ }
963
+ class LegendItem {
964
+ }
965
+ /**
966
+ * Grafico impilato delle sessioni attive medie, con le regole e i colori del grafico della Top Activity v2:
967
+ * un gradino per bucket, una serie per componente (l'ultimo, "altri", in grigio) e la legenda sotto.
968
+ * Lo usano i dettagli v2 di nodo (per classe di attesa) e di sessione (la sua Top Activity)
969
+ */
970
+ class ActivityChartV2Component {
971
+ constructor() {
972
+ // Chiavi con colore fisso: classi di attesa e tipi di evento
973
+ this.FixedColors = true;
974
+ this.name = "activitychartv2";
975
+ this.legend = [];
976
+ }
977
+ get emptyText() {
978
+ return this.EmptyText ?? "";
979
+ }
980
+ ngOnChanges() {
981
+ let times = (this.Times ?? []).map(t => parseUtc(t));
982
+ let components = this.Components ?? [];
983
+ if (times.length == 0 || components.length == 0) {
984
+ this.chartData = null;
985
+ this.legend = [];
986
+ return;
987
+ }
988
+ let interval = bucketInterval(this.BucketSeconds);
989
+ let series = [];
990
+ this.legend = components.map((c, i) => {
991
+ let color = componentColor(c.key, c.other, i, this.FixedColors);
992
+ series.push(new LineSerie(c.label, times.map((t, j) => new DateValue(t, c.values?.[j] ?? 0)), interval, color, this.Uom));
993
+ return { label: c.label, color: color, percentage: c.percentage };
994
+ });
995
+ this.chartData = new LineChartData(series);
996
+ }
997
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ActivityChartV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
998
+ 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: `
999
+ @if (chartData) {
1000
+ <div class="acv2-chart">
1001
+ <es-line-chart [MinGridDistance]="65" [Timeline]="false" [FinalInstants]="false" [Stacked]="true" [Step]="true" [Fill]="true" [MergeDatasets]="true"
1002
+ [AllowGaps]="false" [Legend]="false" [Data]="chartData" [name]="name" [DataGroupingThreshold]="99999999"></es-line-chart>
1003
+ </div>
1004
+ <div class="acv2-legend">
1005
+ @for (item of legend; track $index) {
1006
+ <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>
1007
+ }
1008
+ </div>
1009
+ } @else {
1010
+ <div class="acv2-empty">{{emptyText}}</div>
1011
+ }`, 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" }] }); }
1012
+ }
1013
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ActivityChartV2Component, decorators: [{
1014
+ type: Component,
1015
+ args: [{ selector: "activity-chart-v2", template: `
1016
+ @if (chartData) {
1017
+ <div class="acv2-chart">
1018
+ <es-line-chart [MinGridDistance]="65" [Timeline]="false" [FinalInstants]="false" [Stacked]="true" [Step]="true" [Fill]="true" [MergeDatasets]="true"
1019
+ [AllowGaps]="false" [Legend]="false" [Data]="chartData" [name]="name" [DataGroupingThreshold]="99999999"></es-line-chart>
1020
+ </div>
1021
+ <div class="acv2-legend">
1022
+ @for (item of legend; track $index) {
1023
+ <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>
1024
+ }
1025
+ </div>
1026
+ } @else {
1027
+ <div class="acv2-empty">{{emptyText}}</div>
1028
+ }`, 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"] }]
1029
+ }], propDecorators: { Times: [{
1030
+ type: Input
1031
+ }], Components: [{
1032
+ type: Input
1033
+ }], BucketSeconds: [{
1034
+ type: Input
1035
+ }], FixedColors: [{
1036
+ type: Input
1037
+ }], Uom: [{
1038
+ type: Input
1039
+ }], EmptyText: [{
1040
+ type: Input
1041
+ }], name: [{
1042
+ type: Input
1043
+ }] } });
1044
+
1045
+ // Angular
1046
+ // Formati del profiler v2 (specifica "Profiler gerarchico"): durate nell'unità più leggibile, interi con il separatore
1047
+ // delle migliaia italiano, percentuali con un decimale sotto 10. Un dato mancante è "—"
1048
+ class ProfilerFormatPipe {
1049
+ transform(value, kind) {
1050
+ if (value == null || isNaN(value))
1051
+ return "—";
1052
+ switch (kind) {
1053
+ case "dur": return formatDuration(value);
1054
+ case "pct": return formatPercentage(value);
1055
+ default: return formatNumber(value, "it", "1.0-0");
1056
+ }
1057
+ }
1058
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
1059
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, isStandalone: true, name: "pv2fmt" }); }
1060
+ }
1061
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, decorators: [{
1062
+ type: Pipe,
1063
+ args: [{ name: "pv2fmt" }]
1064
+ }] });
1065
+ // Secondi: "850 µs", "4,27 ms", "312,5 ms", "8,41 s", "4 min 12 s", "3 h 20 min", "76 h"
1066
+ function formatDuration(seconds) {
1067
+ if (seconds == null || isNaN(seconds))
1068
+ return "—";
1069
+ let abs = Math.abs(seconds);
1070
+ if (abs < 0.001)
1071
+ return `${formatNumber(seconds * 1000000, "it", "1.0-0")} µs`;
1072
+ if (abs < 1)
1073
+ return `${formatNumber(seconds * 1000, "it", abs < 0.01 ? "1.2-2" : "1.1-1")} ms`;
1074
+ if (abs < 60)
1075
+ return `${formatNumber(seconds, "it", abs < 10 ? "1.2-2" : "1.1-1")} s`;
1076
+ if (abs < 3600)
1077
+ return `${Math.floor(abs / 60)} min ${Math.floor(abs % 60)} s`;
1078
+ if (abs < 48 * 3600)
1079
+ return `${Math.floor(abs / 3600)} h ${Math.floor(abs % 3600 / 60)} min`;
1080
+ return `${formatNumber(Math.floor(abs / 3600), "it", "1.0-0")} h`;
1081
+ }
1082
+ // Da 0 a 100: "4,2%", "34%"
1083
+ function formatPercentage(value) {
1084
+ if (value == null || isNaN(value))
1085
+ return "—";
1086
+ return `${formatNumber(value, "it", Math.abs(value) < 10 ? "1.1-1" : "1.0-0")}%`;
1087
+ }
1088
+
1089
+ // Angular
1090
+ const HOUR_MS$1 = 3600 * 1000;
1091
+ const MAX_WINDOW_MS = 24 * HOUR_MS$1;
1092
+ // Una finestra che finisce entro questo margine da adesso è "agganciata": l'aggiornamento automatico la sposta in avanti
1093
+ const ANCHOR_MARGIN_MS = 2 * 60 * 1000;
1094
+ // Una voce della pila di navigazione (D1): cosa mostrare, con quale finestra e sorgente
1095
+ class DetailsV2Entry {
1096
+ }
1097
+ // Contesto della pagina da cui si apre un dettaglio
1098
+ class DetailsV2Options {
1099
+ }
1100
+ class DetailsV2EventLink {
1101
+ }
1102
+ class StatRow {
1103
+ }
1104
+ class TypePart {
1105
+ }
1106
+ /**
1107
+ * Dettaglio di un nodo del profiler e di una sessione (specifica "Dettaglio nodo e sessione"), in una finestra di dialogo con la pila
1108
+ * di navigazione: dalla sessione si apre il nodo di un evento, dal nodo i suoi antenati e discendenti, "Indietro" torna al precedente.
1109
+ * Le chiamate sono GetNodeStats e GetSessionStats con DirectorFeature.DetailsV2 attivo
1110
+ */
1111
+ class AdmDetailsV2Component {
1112
+ constructor(lc, dateExts, adms) {
1113
+ this.lc = lc;
1114
+ this.dateExts = dateExts;
1115
+ this.adms = adms;
1116
+ this.Be = "";
1117
+ // "Sessioni su questo evento" ha senso solo con la Top Activity v2 (N8)
1118
+ this.CanShowSessions = false;
1119
+ // "Apri nel profiler" ha senso solo con il profiler v2, che sa usare un nodo come radice (N7)
1120
+ this.CanOpenProfiler = false;
1121
+ this.closed = new EventEmitter();
1122
+ this.sessionsOnEvent = new EventEmitter();
1123
+ this.openProfiler = new EventEmitter();
1124
+ this.Dim = TopActivityDimension;
1125
+ this.QuickRanges = [1, 6, 24];
1126
+ this.stack = [];
1127
+ this.loading = false;
1128
+ this.notFound = false;
1129
+ this.paused = false;
1130
+ this.refreshSeconds = 0;
1131
+ this.filterfrom = "";
1132
+ this.filterto = "";
1133
+ this.windowClamped = false;
1134
+ // Viste derivate dalla risposta
1135
+ this.nodeChartTimes = [];
1136
+ this.nodeChart = [];
1137
+ this.nodeStats = [];
1138
+ this.typeParts = [];
1139
+ this.sessionChart = [];
1140
+ this.sessionTables = [];
1141
+ this.copied = false;
1142
+ this.Dimensions = [];
1143
+ this.Resolutions = [];
1144
+ // Il tempo in corso dei thread avanza fra un aggiornamento e l'altro (S4)
1145
+ this.now = Date.now();
1146
+ this.loadedAt = Date.now();
1147
+ this.colors = {};
1148
+ this.visible = false;
1149
+ this.requestId = 0;
1150
+ this.Dimensions = [
1151
+ new KeyValue(String(TopActivityDimension.WaitClass), this.lc.loc("Classe di attesa")),
1152
+ new KeyValue(String(TopActivityDimension.EventType), this.lc.loc("Tipo di evento")),
1153
+ new KeyValue(String(TopActivityDimension.Thread), "Thread"),
1154
+ new KeyValue(String(TopActivityDimension.Api), "API"),
1155
+ new KeyValue(String(TopActivityDimension.WaitEvent), this.lc.loc("Evento"))
1156
+ ];
1157
+ this.Resolutions = [
1158
+ new KeyValue(String(TopActivityResolution.Low), this.lc.loc("Bassa")),
1159
+ new KeyValue(String(TopActivityResolution.Medium), this.lc.loc("Media")),
1160
+ new KeyValue(String(TopActivityResolution.High), this.lc.loc("Alta")),
1161
+ new KeyValue(String(TopActivityResolution.Maximum), this.lc.loc("Massima"))
1162
+ ];
1163
+ }
1164
+ ngOnDestroy() {
1165
+ this.stopTimers();
1166
+ }
1167
+ get current() {
1168
+ return this.stack[this.stack.length - 1];
1169
+ }
1170
+ // #region Apertura e navigazione (D1)
1171
+ openNode(nodeId, o) {
1172
+ // D3: dal vivo nel caso normale; lo storico solo se la finestra è tutta prima dei campioni in memoria
1173
+ let realTime = o.realTime ?? !(o.memoryFrom && o.to.getTime() <= o.memoryFrom.getTime());
1174
+ this.start({ kind: "node", nodeId: nodeId, global: o.instanceId ? null : (o.global ?? true), instanceId: o.instanceId || null, realTime: realTime, ...this.window(o) }, o);
1175
+ }
1176
+ openSession(instanceId, sid, serial, o) {
1177
+ this.start({ kind: "session", instanceId: instanceId, sid: sid, serial: serial, dimension: TopActivityDimension.WaitClass, resolution: TopActivityResolution.Medium, realTime: o.realTime ?? false, ...this.window(o) }, o);
1178
+ }
1179
+ // Da una sessione l'istanza è quella della sessione e il nodo si legge dal vivo; da un nodo valgono gli stessi parametri
1180
+ pushNode(nodeId) {
1181
+ let cur = this.current;
1182
+ if (!nodeId || !cur)
1183
+ return;
1184
+ let entry = cur.kind == "session"
1185
+ ? { kind: "node", nodeId: nodeId, global: null, instanceId: cur.instanceId, realTime: true, from: cur.from, to: cur.to, anchored: cur.anchored }
1186
+ : { ...cur, nodeId: nodeId };
1187
+ this.stack.push(entry);
1188
+ this.load();
1189
+ }
1190
+ back() {
1191
+ if (this.stack.length < 2)
1192
+ return;
1193
+ this.stack.pop();
1194
+ this.load();
1195
+ }
1196
+ close() {
1197
+ this.stop();
1198
+ this.closed.emit();
1199
+ }
1200
+ // Da chiamare quando la finestra di dialogo si chiude: l'aggiornamento automatico si ferma (D5)
1201
+ stop() {
1202
+ this.visible = false;
1203
+ this.stopTimers();
1204
+ }
1205
+ start(entry, o) {
1206
+ this.refreshSeconds = o.refreshSeconds ?? 0;
1207
+ this.paused = false;
1208
+ this.stack = [entry];
1209
+ this.visible = true;
1210
+ this.load();
1211
+ this.startTimers();
1212
+ }
1213
+ window(o) {
1214
+ let to = (o.to ?? new Date()).getTime();
1215
+ let from = (o.from ?? new Date(to - HOUR_MS$1)).getTime();
1216
+ return { from: Math.max(from, to - MAX_WINDOW_MS), to: to, anchored: Math.abs(Date.now() - to) < ANCHOR_MARGIN_MS };
1217
+ }
1218
+ // #endregion
1219
+ // #region Caricamento
1220
+ async load(refresh = false) {
1221
+ let entry = this.current;
1222
+ if (!entry)
1223
+ return;
1224
+ this.syncWindowFields();
1225
+ let id = ++this.requestId;
1226
+ this.loading = true;
1227
+ this.error = null;
1228
+ if (!refresh) {
1229
+ this.node = null;
1230
+ this.session = null;
1231
+ this.notFound = false;
1232
+ this.expandedTid = null;
1233
+ this.highlightedTid = null;
1234
+ }
1235
+ try {
1236
+ if (entry.kind == "node") {
1237
+ let res = await this.adms.getNodeDetailV2(this.Be, this.nodeRequest(entry));
1238
+ if (id != this.requestId)
1239
+ return;
1240
+ this.node = res;
1241
+ this.buildNodeView();
1242
+ }
1243
+ else {
1244
+ let res = await this.adms.getSessionDetailV2(this.Be, this.sessionRequest(entry));
1245
+ if (id != this.requestId)
1246
+ return;
1247
+ this.session = res;
1248
+ this.buildSessionView();
1249
+ }
1250
+ this.notFound = !this.node && !this.session;
1251
+ this.updatedAt = new Date();
1252
+ this.loadedAt = Date.now();
1253
+ this.now = this.loadedAt;
1254
+ }
1255
+ catch (err) {
1256
+ if (id != this.requestId || err?.status == 401)
1257
+ return;
1258
+ this.node = null;
1259
+ this.session = null;
1260
+ // 400 del backend (finestra non valida): arriva come 542 con il message (D6)
1261
+ this.error = err?.status == 542 ? this.adms.errorText(err) : `${this.lc.loc("Errore")} ${err?.status ?? ""}: ${this.adms.errorText(err)}`;
1262
+ }
1263
+ finally {
1264
+ if (id == this.requestId)
1265
+ this.loading = false;
1266
+ }
1267
+ }
1268
+ nodeRequest(e) {
1269
+ return {
1270
+ nodeId: e.nodeId,
1271
+ realTime: e.realTime,
1272
+ global: e.instanceId ? null : e.global,
1273
+ instanceId: e.instanceId,
1274
+ snapFrom: new Date(e.from).toISOString(),
1275
+ snapTo: new Date(e.to).toISOString()
1276
+ };
1277
+ }
1278
+ sessionRequest(e) {
1279
+ return {
1280
+ instanceId: e.instanceId,
1281
+ sid: e.sid,
1282
+ serial: e.serial,
1283
+ realTime: e.realTime,
1284
+ snapFrom: new Date(e.from).toISOString(),
1285
+ snapTo: new Date(e.to).toISOString(),
1286
+ dimension: e.dimension,
1287
+ resolution: e.resolution
1288
+ };
1289
+ }
1290
+ // #endregion
1291
+ // #region Finestra, sorgente e aggiornamento (D2, D3, D5)
1292
+ quickRange(hours) {
1293
+ let e = this.current;
1294
+ e.to = Date.now();
1295
+ e.from = e.to - hours * HOUR_MS$1;
1296
+ e.anchored = true;
1297
+ this.load();
1298
+ }
1299
+ applyDates() {
1300
+ let e = this.current;
1301
+ let to = this.toDate(this.filterto)?.getTime() ?? Date.now();
1302
+ let from = this.toDate(this.filterfrom)?.getTime() ?? to - HOUR_MS$1;
1303
+ // Al massimo 24 ore; una finestra rovesciata la rifiuta il backend con il suo messaggio
1304
+ this.windowClamped = to - from > MAX_WINDOW_MS;
1305
+ e.from = this.windowClamped ? to - MAX_WINDOW_MS : from;
1306
+ e.to = to;
1307
+ e.anchored = Math.abs(Date.now() - to) < ANCHOR_MARGIN_MS;
1308
+ this.load();
1309
+ }
1310
+ setRealTime(realTime) {
1311
+ if (this.current.realTime == realTime)
1312
+ return;
1313
+ this.current.realTime = realTime;
1314
+ this.load();
1315
+ }
1316
+ setDimension(id) {
1317
+ this.current.dimension = +id;
1318
+ this.load(true);
1319
+ }
1320
+ setResolution(id) {
1321
+ this.current.resolution = +id;
1322
+ this.load(true);
1323
+ }
1324
+ togglePause() {
1325
+ this.paused = !this.paused;
1326
+ }
1327
+ get autoRefresh() {
1328
+ return this.refreshSeconds > 0 && !!this.current?.anchored;
1329
+ }
1330
+ get windowLabel() {
1331
+ let e = this.current;
1332
+ if (!e)
1333
+ return "";
1334
+ let sameDay = dayjs(e.from).isSame(dayjs(e.to), "day");
1335
+ let fmtFrom = dayjs(e.from).format(sameDay ? "HH:mm" : "DD/MM HH:mm");
1336
+ let fmtTo = dayjs(e.to).format(sameDay ? "HH:mm" : "DD/MM HH:mm");
1337
+ return `${this.lc.loc("dalle")} ${fmtFrom} ${this.lc.loc("alle")} ${fmtTo} (${this.timeZone()})`;
1338
+ }
1339
+ startTimers() {
1340
+ this.stopTimers();
1341
+ this.tickTimer = setInterval(() => this.now = Date.now(), 1000);
1342
+ if (this.refreshSeconds > 0)
1343
+ this.refreshTimer = setInterval(() => this.autoRefreshTick(), this.refreshSeconds * 1000);
1344
+ }
1345
+ stopTimers() {
1346
+ clearInterval(this.tickTimer);
1347
+ clearInterval(this.refreshTimer);
1348
+ this.tickTimer = null;
1349
+ this.refreshTimer = null;
1350
+ }
1351
+ // Sposta in avanti la finestra della stessa durata, solo se è agganciata ad adesso, non in pausa e il dettaglio si vede
1352
+ autoRefreshTick() {
1353
+ let e = this.current;
1354
+ if (!e || !e.anchored || this.paused || this.loading || !this.visible || document.hidden)
1355
+ return;
1356
+ let length = e.to - e.from;
1357
+ e.to = Date.now();
1358
+ e.from = e.to - length;
1359
+ this.load(true);
1360
+ }
1361
+ syncWindowFields() {
1362
+ let e = this.current;
1363
+ this.filterfrom = this.fmt(new Date(e.from));
1364
+ this.filterto = this.fmt(new Date(e.to));
1365
+ }
1366
+ // #endregion
1367
+ // #region Nodo (N1-N8)
1368
+ get nodeLive() {
1369
+ return !!this.node && this.current?.realTime && this.node.snapDeltaExecutions != null;
1370
+ }
1371
+ buildNodeView() {
1372
+ let n = this.node;
1373
+ if (!n) {
1374
+ this.nodeChart = [];
1375
+ this.nodeChartTimes = [];
1376
+ this.nodeStats = [];
1377
+ this.typeParts = [];
1378
+ return;
1379
+ }
1380
+ this.nodeChartTimes = (n.activeSessions ?? []).map(t => t.timestamp);
1381
+ this.nodeChart = (n.activityByClass ?? []).map(c => ({ ...c, label: c.other ? this.lc.loc("Altri") : c.label }));
1382
+ // minTime vale 0 senza esecuzioni concluse, snapDeltaMinTime null: in tutti e due i casi non c'è un minimo da mostrare
1383
+ this.nodeStats = [
1384
+ { label: this.lc.loc("Esecuzioni"), total: n.executions, snap: n.snapDeltaExecutions, kind: "int" },
1385
+ { label: this.lc.loc("Tempo totale"), total: n.elapsedTime, snap: n.snapDeltaElapsedTime, kind: "dur" },
1386
+ { label: this.lc.loc("Tempo proprio"), total: n.elapsedTimeLessChildren, snap: n.snapDeltaElapsedTimeLessChildren, kind: "dur" },
1387
+ { label: this.lc.loc("Medio"), total: n.executions ? n.avgTime : null, snap: n.snapDeltaExecutions ? n.snapDeltaAvgTime : null, kind: "dur" },
1388
+ { label: this.lc.loc("Massimo"), total: n.executions ? n.peakTime : null, snap: n.snapDeltaExecutions ? n.snapDeltaPeakTime : null, kind: "dur" },
1389
+ { label: this.lc.loc("Minimo"), total: n.executions ? n.minTime : null, snap: n.snapDeltaMinTime, kind: "dur" }
1390
+ ];
1391
+ this.typeParts = [
1392
+ { label: "CPU", color: FIXED_COLORS.Cpu, percentage: n.cpuPerc, idle: false },
1393
+ { label: "Database", color: FIXED_COLORS.Database, percentage: n.dbPerc, idle: false },
1394
+ { label: "Wait", color: FIXED_COLORS.Wait, percentage: n.waitPerc, idle: false },
1395
+ { label: "Script", color: FIXED_COLORS.Script, percentage: n.scriptPerc, idle: false },
1396
+ { label: "IO", color: FIXED_COLORS.IO, percentage: n.ioPerc, idle: false },
1397
+ { label: "Network", color: FIXED_COLORS.Network, percentage: n.networkPerc, idle: false },
1398
+ { label: "Throttle", color: FIXED_COLORS.Throttle, percentage: n.throttlePerc, idle: false },
1399
+ { label: "Sleep", color: FIXED_COLORS.Sleep, percentage: n.sleepPerc, idle: false },
1400
+ { label: "Idle", color: OTHER_COLOR, percentage: n.idlePerc, idle: true }
1401
+ ].filter(t => (t.percentage ?? 0) > 0);
1402
+ }
1403
+ // Con lo storico, la parte del grafico prima dei campioni in memoria ha meno risoluzione: la pagina la segnala
1404
+ get nodeHistoryBefore() {
1405
+ let n = this.node;
1406
+ if (!n || this.current?.realTime || !n.memoryFrom)
1407
+ return null;
1408
+ let memory = parseUtc(n.memoryFrom)?.getTime();
1409
+ let from = parseUtc(n.activityFrom)?.getTime();
1410
+ let to = parseUtc(n.activityTo)?.getTime();
1411
+ return memory > from && memory < to ? this.localTime(n.memoryFrom) : null;
1412
+ }
1413
+ copyName() {
1414
+ navigator.clipboard?.writeText(this.node?.nodeName ?? "").then(() => {
1415
+ this.copied = true;
1416
+ setTimeout(() => this.copied = false, 1500);
1417
+ });
1418
+ }
1419
+ showSessions() {
1420
+ let e = this.current;
1421
+ this.sessionsOnEvent.emit({ nodeId: this.node.nodeId, nodeName: this.node.nodeName, from: new Date(e.from), to: new Date(e.to) });
1422
+ }
1423
+ // #endregion
1424
+ // #region Sessione (S1-S6)
1425
+ buildSessionView() {
1426
+ let ta = this.session?.topActivity;
1427
+ let fixed = ta?.dimension == TopActivityDimension.WaitClass || ta?.dimension == TopActivityDimension.EventType;
1428
+ this.colors = {};
1429
+ this.sessionChart = (ta?.components ?? []).map((c, i) => {
1430
+ if (c.key != null)
1431
+ this.colors[c.key] = componentColor(c.key, c.other, i, fixed);
1432
+ return { ...c, label: this.valueLabel(c.label, c.other, ta.dimension) };
1433
+ });
1434
+ // Nell'ordine della specifica: eventi, thread, API
1435
+ let order = [TopActivityDimension.WaitEvent, TopActivityDimension.Thread, TopActivityDimension.Api];
1436
+ this.sessionTables = order.map(d => ta?.tables?.find(t => t.dimension == d)).filter(t => !!t);
1437
+ }
1438
+ get sessionFixedColors() {
1439
+ let d = this.session?.topActivity?.dimension;
1440
+ return d == TopActivityDimension.WaitClass || d == TopActivityDimension.EventType;
1441
+ }
1442
+ tableTitle(table) {
1443
+ switch (table.dimension) {
1444
+ case TopActivityDimension.WaitEvent: return this.lc.loc("Eventi");
1445
+ case TopActivityDimension.Thread: return "Thread";
1446
+ case TopActivityDimension.Api: return "API";
1447
+ }
1448
+ return String(table.dimension);
1449
+ }
1450
+ itemLabel(item, table) {
1451
+ return this.valueLabel(item.label, item.other, table.dimension);
1452
+ }
1453
+ isItemClickable(item, table) {
1454
+ if (item.other)
1455
+ return false;
1456
+ if (table.dimension == TopActivityDimension.WaitEvent)
1457
+ return !!item.event?.eventId;
1458
+ return table.dimension == TopActivityDimension.Thread && this.isThreadAlive(this.tidOf(item.key));
1459
+ }
1460
+ // Una riga evento apre il nodo; una riga thread evidenzia il thread fra quelli di adesso
1461
+ itemClicked(item, table) {
1462
+ if (!this.isItemClickable(item, table))
1463
+ return;
1464
+ if (table.dimension == TopActivityDimension.WaitEvent)
1465
+ this.pushNode(item.event.eventId);
1466
+ else
1467
+ this.highlightedTid = this.tidOf(item.key);
1468
+ }
1469
+ breakdownWidth(item, part) {
1470
+ return item.activity ? part.activity / item.activity * 100 : 0;
1471
+ }
1472
+ breakdownColor(part) {
1473
+ return part.other || part.key == null ? OTHER_COLOR : this.colors[part.key] ?? FIXED_COLORS[part.key] ?? OTHER_COLOR;
1474
+ }
1475
+ toggleThread(thread) {
1476
+ this.expandedTid = this.expandedTid == thread.tid ? null : thread.tid;
1477
+ }
1478
+ // Tempo nell'evento corrente: parte da waitTime e avanza fino al prossimo aggiornamento
1479
+ runningSeconds(thread) {
1480
+ return thread.inWait ? (thread.waitTime ?? 0) + Math.max(0, this.now - this.loadedAt) / 1000 : null;
1481
+ }
1482
+ progress(op) {
1483
+ return op.totalWork ? Math.min(100, op.soFar / op.totalWork * 100) : 0;
1484
+ }
1485
+ connectedFor() {
1486
+ let start = parseUtc(this.session?.startTime);
1487
+ return start ? Math.max(0, (this.now - start.getTime()) / 1000) : null;
1488
+ }
1489
+ tidOf(key) {
1490
+ let tid = parseInt((key ?? "").split("@")[0], 10);
1491
+ return isNaN(tid) ? null : tid;
1492
+ }
1493
+ isThreadAlive(tid) {
1494
+ return tid != null && !!this.session?.connected && (this.session.threads ?? []).some(t => t.tid == tid);
1495
+ }
1496
+ // #endregion
1497
+ // #region Supporto
1498
+ localTime(value) {
1499
+ let date = parseUtc(value);
1500
+ return date ? dayjs(date).format("DD/MM/YYYY HH:mm:ss") : "";
1501
+ }
1502
+ shortTime(value) {
1503
+ let date = parseUtc(value);
1504
+ return date ? dayjs(date).format("HH:mm") : "";
1505
+ }
1506
+ // Colore del tipo di evento, o della classe per i wait, come nel grafico della Top Activity
1507
+ typeColor(type, waitClass) {
1508
+ return FIXED_COLORS[waitClass && waitClass != "None" ? waitClass : type] ?? OTHER_COLOR;
1509
+ }
1510
+ typeLabel(type, waitClass) {
1511
+ return waitClass && waitClass != "None" ? `${type} · ${waitClass}` : type;
1512
+ }
1513
+ valueLabel(label, other, dimension) {
1514
+ if (other)
1515
+ return this.lc.loc("Altri");
1516
+ if (label == null || label === "")
1517
+ return this.lc.loc(dimension == TopActivityDimension.WaitEvent ? "(non attribuito)" : "(nessuno)");
1518
+ return label;
1519
+ }
1520
+ timeZone() {
1521
+ let minutes = -new Date().getTimezoneOffset();
1522
+ let sign = minutes >= 0 ? "+" : "-";
1523
+ let abs = Math.abs(minutes);
1524
+ return `UTC${sign}${Math.floor(abs / 60)}${abs % 60 ? ":" + String(abs % 60).padStart(2, "0") : ""}`;
1525
+ }
1526
+ toDate(value) {
1527
+ return value ? this.dateExts.getDateConvertion(value).toDate() : null;
1528
+ }
1529
+ fmt(date) {
1530
+ return dayjs(date).format(this.lc.token("getFullDateDisplayFormat"));
1531
+ }
1532
+ 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 }); }
1533
+ 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 @if (current.kind == 'node' && !current.realTime) {\n <div class=\"dv2-small\">{{'Sullo storico il nodo si cerca solo negli snapshot della finestra: prova \"Dal vivo\" o una finestra pi\u00F9 ampia' | localize: lc}}</div>\n }\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" }] }); }
1534
+ }
1535
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Component, decorators: [{
1536
+ type: Component,
1537
+ 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 @if (current.kind == 'node' && !current.realTime) {\n <div class=\"dv2-small\">{{'Sullo storico il nodo si cerca solo negli snapshot della finestra: prova \"Dal vivo\" o una finestra pi\u00F9 ampia' | localize: lc}}</div>\n }\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"] }]
1538
+ }], ctorParameters: () => [{ type: i1.LocalizationService }, { type: i1$1.DateService }, { type: AdminModuleBaseService }], propDecorators: { Be: [{
1539
+ type: Input
1540
+ }], CanShowSessions: [{
1541
+ type: Input
1542
+ }], CanOpenProfiler: [{
1543
+ type: Input
1544
+ }], closed: [{
1545
+ type: Output
1546
+ }], sessionsOnEvent: [{
1547
+ type: Output
1548
+ }], openProfiler: [{
1549
+ type: Output
1550
+ }] } });
1551
+
756
1552
  class AdmProfilerComponentLoc extends LocalizationService {
757
1553
  constructor(injector) {
758
1554
  super(injector);
@@ -842,7 +1638,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
842
1638
 
843
1639
  // Angular
844
1640
  class AdmProfilerComponent {
845
- constructor(lc, localStorage, location, intercom, route, adms, router, mod, workloadV2) {
1641
+ constructor(lc, localStorage, location, intercom, route, adms, router, mod, workloadV2,
1642
+ // Con DirectorFeature.DetailsV2 GetNodeStats risponde solo con il contratto nuovo: il nodo si apre nel dettaglio v2
1643
+ dateExts, detailsV2Enabled, topActV2Enabled) {
846
1644
  this.lc = lc;
847
1645
  this.localStorage = localStorage;
848
1646
  this.location = location;
@@ -852,6 +1650,9 @@ class AdmProfilerComponent {
852
1650
  this.router = router;
853
1651
  this.mod = mod;
854
1652
  this.workloadV2 = workloadV2;
1653
+ this.dateExts = dateExts;
1654
+ this.detailsV2Enabled = detailsV2Enabled;
1655
+ this.topActV2Enabled = topActV2Enabled;
855
1656
  this.searchView = new ProfilerDataNodesView();
856
1657
  this.be = route.snapshot.params["be"] || "";
857
1658
  this.intercom.send(InboundMessageTypes.Navigation, { sub: false, routeTitle: this.lc.loc(this.route.snapshot.data["title"]) });
@@ -916,18 +1717,39 @@ class AdmProfilerComponent {
916
1717
  let res = await this.adms.getProfilerDataNodes(this.be, view);
917
1718
  dataCallBack(res.items, ProfilerDataNode);
918
1719
  }
1720
+ openNodeDetails(nodeId) {
1721
+ if (this.detailsV2Enabled) {
1722
+ // Senza date la pagina è dal vivo (l'ultima ora per il grafico), con le date legge lo storico
1723
+ let history = !!(this.searchView.filterfrom || this.searchView.filterto);
1724
+ let to = this.searchView.filterto ? this.dateExts.getDateConvertion(this.searchView.filterto).toDate() : new Date();
1725
+ let from = this.searchView.filterfrom ? this.dateExts.getDateConvertion(this.searchView.filterfrom).toDate() : new Date(to.getTime() - 3600 * 1000);
1726
+ this.detailsV2.openNode(nodeId, { from: from, to: to, realTime: !history, global: this.searchView.filterglobal });
1727
+ this.dlgDetailsV2.show();
1728
+ return;
1729
+ }
1730
+ this.loadNodeDetails(nodeId);
1731
+ this.dlgNodeDetails.show();
1732
+ }
1733
+ // N8: la Top Activity v2 filtrata sull'evento, nella finestra del dettaglio
1734
+ showEventSessions(link) {
1735
+ this.dlgDetailsV2.hide();
1736
+ 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() } });
1737
+ }
1738
+ openInProfiler(nodeId) {
1739
+ this.dlgDetailsV2.hide();
1740
+ }
919
1741
  loadNodeDetails(nodeId) {
920
1742
  this.NodeDetails = null;
921
1743
  requestAnimationFrame(async () => {
922
1744
  this.NodeDetails = await this.adms.getNodeStats(this.be, nodeId);
923
1745
  });
924
1746
  }
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" }] }); }
1747
+ 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 }); }
1748
+ 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
1749
  }
928
1750
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerComponent, decorators: [{
929
1751
  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>" }]
1752
+ 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
1753
  }], 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
1754
  type: Inject,
933
1755
  args: [ADM_MODULE_PATH]
@@ -936,7 +1758,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
936
1758
  }, {
937
1759
  type: Inject,
938
1760
  args: [ADM_WORKLOAD_V2]
939
- }] }] });
1761
+ }] }, { type: i1$1.DateService }, { type: undefined, decorators: [{
1762
+ type: Optional
1763
+ }, {
1764
+ type: Inject,
1765
+ args: [ADM_DETAILS_V2]
1766
+ }] }, { type: undefined, decorators: [{
1767
+ type: Optional
1768
+ }, {
1769
+ type: Inject,
1770
+ args: [ADM_TOPACT_V2]
1771
+ }] }], propDecorators: { dlgNodeDetails: [{
1772
+ type: ViewChild,
1773
+ args: ["dlgNodeDetails"]
1774
+ }], dlgDetailsV2: [{
1775
+ type: ViewChild,
1776
+ args: ["dlgDetailsV2"]
1777
+ }], detailsV2: [{
1778
+ type: ViewChild,
1779
+ args: [AdmDetailsV2Component]
1780
+ }] } });
940
1781
 
941
1782
  // Ordinamento decrescente del profiler v2 (figli nell'albero, righe nella vista per nome). I numeri sono quelli del backend
942
1783
  var ProfilerOrderBy;
@@ -964,50 +1805,6 @@ class ProfilerV2NodeRequest extends ProfilerV2Request {
964
1805
  class ProfilerV2FlatRequest extends ProfilerV2Request {
965
1806
  }
966
1807
 
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
1808
  class AdmProfilerV2Loc extends LocalizationService {
1012
1809
  constructor(injector) {
1013
1810
  super(injector);
@@ -1103,6 +1900,7 @@ class AdmProfilerV2Loc extends LocalizationService {
1103
1900
  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
1901
  super.set("it->en", "Copia", ["Copy"]);
1105
1902
  super.set("it->en", "Copiato", ["Copied"]);
1903
+ super.set("it->en", "Dettaglio completo", ["Full detail"]);
1106
1904
  super.set("it->en", "Percorso", ["Path"]);
1107
1905
  super.set("it->en", "Nella finestra", ["In window"]);
1108
1906
  super.set("it->en", "Esecuzioni", ["Executions"]);
@@ -1179,7 +1977,9 @@ class ProfilerV2Chart {
1179
1977
  class ProfilerV2Settings {
1180
1978
  }
1181
1979
  class AdmProfilerV2Component {
1182
- constructor(dateExts, lc, localStorage, intercom, route, router, location, adms, mod, workloadV2) {
1980
+ constructor(dateExts, lc, localStorage, intercom, route, router, location, adms, mod, workloadV2,
1981
+ // Con DirectorFeature.DetailsV2 il pannello apre anche il dettaglio completo del nodo; "Sessioni su questo evento" vuole la Top Activity v2
1982
+ detailsV2Enabled, topActV2Enabled) {
1183
1983
  this.dateExts = dateExts;
1184
1984
  this.lc = lc;
1185
1985
  this.localStorage = localStorage;
@@ -1190,6 +1990,8 @@ class AdmProfilerV2Component {
1190
1990
  this.adms = adms;
1191
1991
  this.mod = mod;
1192
1992
  this.workloadV2 = workloadV2;
1993
+ this.detailsV2Enabled = detailsV2Enabled;
1994
+ this.topActV2Enabled = topActV2Enabled;
1193
1995
  this.EventTypes = EVENT_TYPES;
1194
1996
  // Barra dei comandi
1195
1997
  this.live = true;
@@ -1725,6 +2527,28 @@ class AdmProfilerV2Component {
1725
2527
  this.setRoot(nodeId);
1726
2528
  this.select(nodeId);
1727
2529
  }
2530
+ // Dettaglio completo del nodo (specifica "Dettaglio nodo e sessione") con la sorgente, le istanze e la finestra della pagina:
2531
+ // dal vivo l'ultima ora, sullo storico la finestra scelta
2532
+ openFullDetail() {
2533
+ if (!this.detail)
2534
+ return;
2535
+ let req = this.baseRequest(new ProfilerV2NodeRequest());
2536
+ let to = req.snapTo ? new Date(req.snapTo) : new Date();
2537
+ let from = req.snapFrom ? new Date(req.snapFrom) : new Date(to.getTime() - 3600 * 1000);
2538
+ this.detailsV2.openNode(this.detail.nodeId, { from: from, to: to, realTime: this.live, global: req.global, instanceId: req.instanceId });
2539
+ this.dlgDetailsV2.show();
2540
+ }
2541
+ // N7 dal dettaglio completo: l'albero con il nodo come radice, in questa pagina
2542
+ rootFromDetails(nodeId) {
2543
+ this.dlgDetailsV2.hide();
2544
+ this.setRoot(nodeId);
2545
+ this.select(nodeId);
2546
+ }
2547
+ // N8: la Top Activity v2 filtrata sull'evento, nella finestra del dettaglio
2548
+ showEventSessions(link) {
2549
+ this.dlgDetailsV2.hide();
2550
+ 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() } });
2551
+ }
1728
2552
  showDetail(nodeId, event) {
1729
2553
  event.stopPropagation();
1730
2554
  this.select(nodeId);
@@ -1968,12 +2792,12 @@ class AdmProfilerV2Component {
1968
2792
  ret.setMinutes(0, 0, 0);
1969
2793
  return ret;
1970
2794
  }
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" }] }); }
2795
+ 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 }); }
2796
+ 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
2797
  }
1974
2798
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerV2Component, decorators: [{
1975
2799
  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"] }]
2800
+ 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
2801
  }], 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
2802
  type: Inject,
1979
2803
  args: [ADM_MODULE_PATH]
@@ -1982,7 +2806,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
1982
2806
  }, {
1983
2807
  type: Inject,
1984
2808
  args: [ADM_WORKLOAD_V2]
1985
- }] }] });
2809
+ }] }, { type: undefined, decorators: [{
2810
+ type: Optional
2811
+ }, {
2812
+ type: Inject,
2813
+ args: [ADM_DETAILS_V2]
2814
+ }] }, { type: undefined, decorators: [{
2815
+ type: Optional
2816
+ }, {
2817
+ type: Inject,
2818
+ args: [ADM_TOPACT_V2]
2819
+ }] }], propDecorators: { dlgDetailsV2: [{
2820
+ type: ViewChild,
2821
+ args: ["dlgDetailsV2"]
2822
+ }], detailsV2: [{
2823
+ type: ViewChild,
2824
+ args: [AdmDetailsV2Component]
2825
+ }] } });
1986
2826
 
1987
2827
  // Workload report v2 (specifica "Workload report"): richieste e risposte come le vuole e le manda il backend (camelCase).
1988
2828
  // Le date delle risposte sono UTC "dd/MM/yyyy HH:mm:ss" senza fuso
@@ -3849,7 +4689,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
3849
4689
 
3850
4690
  // Angular
3851
4691
  class AdmTopActivitiesComponent {
3852
- constructor(dateExts, lc, localStorage, location, intercom, route, adms, mod) {
4692
+ constructor(dateExts, lc, localStorage, location, intercom, route, adms, mod, router,
4693
+ // Con DirectorFeature.DetailsV2 il backend-for-frontend risponde a GetNodeStats e GetSessionStats solo con il contratto nuovo:
4694
+ // nodi e sessioni si aprono nel dettaglio v2 anche da questa pagina
4695
+ detailsV2Enabled, profilerV2Enabled) {
3853
4696
  this.dateExts = dateExts;
3854
4697
  this.lc = lc;
3855
4698
  this.localStorage = localStorage;
@@ -3858,6 +4701,9 @@ class AdmTopActivitiesComponent {
3858
4701
  this.route = route;
3859
4702
  this.adms = adms;
3860
4703
  this.mod = mod;
4704
+ this.router = router;
4705
+ this.detailsV2Enabled = detailsV2Enabled;
4706
+ this.profilerV2Enabled = profilerV2Enabled;
3861
4707
  this.searchView = new TopActivitiesDataView();
3862
4708
  this.autoUpdate = false;
3863
4709
  this.seconds = "5";
@@ -3959,6 +4805,38 @@ class AdmTopActivitiesComponent {
3959
4805
  this.searchView.searchinprogress = false;
3960
4806
  this.reviewBindings(update, res, dirinfos);
3961
4807
  }
4808
+ openNodeDetails(nodeId) {
4809
+ if (this.detailsV2Enabled) {
4810
+ this.detailsV2.openNode(nodeId, { ...this.detailsWindow(), global: this.searchView.filterglobal });
4811
+ this.dlgDetailsV2.show();
4812
+ return;
4813
+ }
4814
+ this.loadNodeDetails(nodeId);
4815
+ this.dlgNodeDetails.show();
4816
+ }
4817
+ openSessionDetails(sessionId, serialNo, instanceid) {
4818
+ if (this.detailsV2Enabled) {
4819
+ this.detailsV2.openSession(instanceid, sessionId, serialNo, { ...this.detailsWindow(), realTime: !!this.searchView.filterrealtime });
4820
+ this.dlgDetailsV2.show();
4821
+ return;
4822
+ }
4823
+ this.loadSessionDetails(sessionId, serialNo, instanceid);
4824
+ this.dlgSessionDetails.show();
4825
+ }
4826
+ // La finestra della ricerca, di default l'ultima ora
4827
+ detailsWindow() {
4828
+ let to = this.searchView.filterto ? this.dateExts.getDateConvertion(this.searchView.filterto).toDate() : new Date();
4829
+ let from = this.searchView.filterfrom ? this.dateExts.getDateConvertion(this.searchView.filterfrom).toDate() : new Date(to.getTime() - 3600 * 1000);
4830
+ return { from: from, to: to };
4831
+ }
4832
+ // Senza la Top Activity v2 "Sessioni su questo evento" non si propone; il nodo come radice c'è solo nel profiler v2
4833
+ showEventSessions(link) {
4834
+ this.dlgDetailsV2.hide();
4835
+ }
4836
+ openInProfiler(nodeId) {
4837
+ this.dlgDetailsV2.hide();
4838
+ this.router.navigate([`/pages/${this.mod}/profiler`, ...(this.be ? [this.be] : [])], { queryParams: { root: nodeId } });
4839
+ }
3962
4840
  loadNodeDetails(nodeId) {
3963
4841
  this.NodeDetails = null;
3964
4842
  requestAnimationFrame(async () => {
@@ -4064,53 +4942,38 @@ class AdmTopActivitiesComponent {
4064
4942
  this.SelectedSessions = new LineChartData(series);
4065
4943
  });
4066
4944
  }
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" }] }); }
4945
+ 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 }); }
4946
+ 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
4947
  }
4070
4948
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivitiesComponent, decorators: [{
4071
4949
  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>" }]
4950
+ 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
4951
  }], 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
4952
  type: Inject,
4075
4953
  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 = {}));
4954
+ }] }, { type: i4.Router }, { type: undefined, decorators: [{
4955
+ type: Optional
4956
+ }, {
4957
+ type: Inject,
4958
+ args: [ADM_DETAILS_V2]
4959
+ }] }, { type: undefined, decorators: [{
4960
+ type: Optional
4961
+ }, {
4962
+ type: Inject,
4963
+ args: [ADM_PROFILER_V2]
4964
+ }] }], propDecorators: { dlgNodeDetails: [{
4965
+ type: ViewChild,
4966
+ args: ["dlgNodeDetails"]
4967
+ }], dlgSessionDetails: [{
4968
+ type: ViewChild,
4969
+ args: ["dlgSessionDetails"]
4970
+ }], dlgDetailsV2: [{
4971
+ type: ViewChild,
4972
+ args: ["dlgDetailsV2"]
4973
+ }], detailsV2: [{
4974
+ type: ViewChild,
4975
+ args: [AdmDetailsV2Component]
4976
+ }] } });
4114
4977
 
4115
4978
  class TopActivityV2Filter {
4116
4979
  }
@@ -4300,15 +5163,6 @@ const STORAGE_KEY = "HotSearchTopActV2";
4300
5163
  const TABLES_WINDOW_MS = 5 * 60 * 1000;
4301
5164
  const INSTANCE_CURRENT = "@current";
4302
5165
  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
5166
  class TopActivityV2LegendItem {
4313
5167
  }
4314
5168
  class TopActivityV2FilterChip {
@@ -4317,7 +5171,9 @@ class TopActivityV2FilterChip {
4317
5171
  class TopActivityV2Settings {
4318
5172
  }
4319
5173
  class AdmTopActivityV2Component {
4320
- constructor(dateExts, lc, localStorage, intercom, route, adms, zone) {
5174
+ constructor(dateExts, lc, localStorage, intercom, route, adms, zone, router, mod,
5175
+ // Con DirectorFeature.DetailsV2 nodi e sessioni si aprono nel dettaglio v2; "Apri nel profiler" vuole il profiler v2
5176
+ detailsV2Enabled, profilerV2Enabled) {
4321
5177
  this.dateExts = dateExts;
4322
5178
  this.lc = lc;
4323
5179
  this.localStorage = localStorage;
@@ -4325,6 +5181,10 @@ class AdmTopActivityV2Component {
4325
5181
  this.route = route;
4326
5182
  this.adms = adms;
4327
5183
  this.zone = zone;
5184
+ this.router = router;
5185
+ this.mod = mod;
5186
+ this.detailsV2Enabled = detailsV2Enabled;
5187
+ this.profilerV2Enabled = profilerV2Enabled;
4328
5188
  this.Dim = TopActivityDimension;
4329
5189
  this.TotalColor = TOTAL_COLOR;
4330
5190
  this.LimitColor = LIMIT_COLOR;
@@ -4375,6 +5235,10 @@ class AdmTopActivityV2Component {
4375
5235
  if (saved)
4376
5236
  this.applySettings(saved);
4377
5237
  this.setLastHours(this.activeRange);
5238
+ // "Sessioni su questo evento" dal dettaglio di un nodo aperto in un'altra pagina (profiler): filtro sull'evento, stessa finestra
5239
+ let query = this.route.snapshot.queryParams;
5240
+ if (query["event"])
5241
+ this.applyEventFilter(query["event"], query["eventName"], query["from"] ? new Date(query["from"]) : null, query["to"] ? new Date(query["to"]) : null);
4378
5242
  this.loadInstances();
4379
5243
  this.refreshInfos();
4380
5244
  this.search();
@@ -4485,7 +5349,7 @@ class AdmTopActivityV2Component {
4485
5349
  this.lastChartKey = null;
4486
5350
  return;
4487
5351
  }
4488
- let memoryFrom = res.memoryFrom ? this.parseUtc(res.memoryFrom) : null;
5352
+ let memoryFrom = res.memoryFrom ? parseUtc(res.memoryFrom) : null;
4489
5353
  this.memoryFrom = memoryFrom && memoryFrom.getTime() > this.chartFrom ? this.fmt(memoryFrom) : null;
4490
5354
  this.limitLabel = this.lc.loc(+this.maxThreadsKind == TopActivityMaximumThreads.Cores ? "CPU Massime" : "Thread Massimi");
4491
5355
  // Se è cambiata solo la finestra delle tabelle il grafico resta quello di prima: ridisegnarlo lo farebbe lampeggiare
@@ -4495,22 +5359,23 @@ class AdmTopActivityV2Component {
4495
5359
  return;
4496
5360
  }
4497
5361
  this.lastChartKey = chartKey;
4498
- let times = (res.times ?? []).map(t => this.parseUtc(t));
5362
+ let times = (res.times ?? []).map(t => parseUtc(t));
5363
+ let interval = bucketInterval(res.bucketSeconds);
4499
5364
  let fixed = res.dimension == TopActivityDimension.WaitClass || res.dimension == TopActivityDimension.EventType;
4500
5365
  let uom = this.lc.loc("sessioni");
4501
5366
  let series = [];
4502
5367
  this.colors = {};
4503
5368
  this.legend = (res.components ?? []).map((c, i) => {
4504
- let color = c.other ? OTHER_COLOR : (fixed && FIXED_COLORS[c.key]) || PALETTE[i % PALETTE.length];
5369
+ let color = componentColor(c.key, c.other, i, fixed);
4505
5370
  if (c.key != null)
4506
5371
  this.colors[c.key] = color;
4507
5372
  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));
5373
+ series.push(new LineSerie(label, times.map((t, j) => new DateValue(t, c.values?.[j] ?? 0)), interval, color, uom));
4509
5374
  return { key: c.key, label: label, color: color, other: c.other, activity: c.activity, percentage: c.percentage };
4510
5375
  });
4511
5376
  // L'attività totale è una linea scura sopra le aree impilate, non impilata a sua volta
4512
5377
  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));
5378
+ 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
5379
  let limit = null;
4515
5380
  if (res.maximumThreads != null)
4516
5381
  limit = new Limit(res.maximumThreads, this.limitLabel, LIMIT_COLOR);
@@ -4604,6 +5469,14 @@ class AdmTopActivityV2Component {
4604
5469
  return this.valueLabel(item.label, item.other, table.dimension);
4605
5470
  }
4606
5471
  loadNodeDetails(nodeId) {
5472
+ if (this.detailsV2Enabled) {
5473
+ // D4: tutte le istanze, l'istanza scelta, oppure quella che risponde
5474
+ let instance = this.instance != INSTANCE_CURRENT && this.instance != INSTANCE_ALL ? this.instance : null;
5475
+ let memoryFrom = this.result?.memoryFrom ? parseUtc(this.result.memoryFrom) : null;
5476
+ this.detailsV2.openNode(nodeId, { ...this.detailsWindow(), global: this.instance == INSTANCE_ALL, instanceId: instance, memoryFrom: memoryFrom });
5477
+ this.dlgDetailsV2.show();
5478
+ return;
5479
+ }
4607
5480
  this.NodeDetails = null;
4608
5481
  this.dlgNodeDetails.show();
4609
5482
  requestAnimationFrame(async () => {
@@ -4611,6 +5484,11 @@ class AdmTopActivityV2Component {
4611
5484
  });
4612
5485
  }
4613
5486
  loadSessionDetails(session) {
5487
+ if (this.detailsV2Enabled) {
5488
+ this.detailsV2.openSession(session.instanceId, session.sessionId, session.serialNo, { ...this.detailsWindow(), realTime: +this.dataSource == TopActivityDataSource.Memory });
5489
+ this.dlgDetailsV2.show();
5490
+ return;
5491
+ }
4614
5492
  this.SessionDetails = null;
4615
5493
  this.dlgSessionDetails.show();
4616
5494
  requestAnimationFrame(async () => {
@@ -4618,6 +5496,35 @@ class AdmTopActivityV2Component {
4618
5496
  });
4619
5497
  }
4620
5498
  // #endregion
5499
+ // #region Dettaglio v2 di nodo e sessione
5500
+ // Il dettaglio eredita la finestra del grafico, non quella delle tabelle, e l'aggiornamento automatico della pagina (D2, D5)
5501
+ detailsWindow() {
5502
+ return { from: new Date(this.chartFrom), to: new Date(this.chartTo), refreshSeconds: +this.refreshSeconds };
5503
+ }
5504
+ // N8: questa pagina filtrata sull'evento esatto, con la tabella per sessione e la finestra del dettaglio
5505
+ showEventSessions(link) {
5506
+ this.dlgDetailsV2.hide();
5507
+ this.applyEventFilter(link.nodeId, link.nodeName, link.from, link.to);
5508
+ this.search();
5509
+ }
5510
+ // N7: il profiler v2 con il nodo come radice
5511
+ openInProfiler(nodeId) {
5512
+ this.dlgDetailsV2.hide();
5513
+ this.router.navigate([`/pages/${this.mod}/profiler`, ...(this.be ? [this.be] : [])], { queryParams: { root: nodeId } });
5514
+ }
5515
+ applyEventFilter(nodeId, nodeName, from, to) {
5516
+ let filter = new TopActivityV2Filter();
5517
+ filter.dimension = TopActivityDimension.WaitEvent;
5518
+ filter.value = nodeId;
5519
+ this.filters = [{ filter: filter, label: `${this.dimensionLabel(TopActivityDimension.WaitEvent)} = ${nodeName || nodeId}` }];
5520
+ this.tableDims = [String(TopActivityDimension.UserSession), this.tableDims[1] ?? String(TopActivityDimension.WaitEvent)];
5521
+ if (from && to && !isNaN(from.getTime()) && !isNaN(to.getTime())) {
5522
+ this.filterfrom = this.fmt(from);
5523
+ this.filterto = this.fmt(to);
5524
+ this.activeRange = null;
5525
+ }
5526
+ }
5527
+ // #endregion
4621
5528
  // #region Aggiornamento automatico
4622
5529
  refreshChanged() {
4623
5530
  clearInterval(this.refreshTimer);
@@ -4696,6 +5603,7 @@ class AdmTopActivityV2Component {
4696
5603
  case TopActivityDimension.ThreadType: return this.lc.loc("Tipo thread");
4697
5604
  case TopActivityDimension.Api: return "API";
4698
5605
  case TopActivityDimension.Machine: return this.lc.loc("Macchina");
5606
+ case TopActivityDimension.Thread: return "Thread";
4699
5607
  }
4700
5608
  return String(dimension);
4701
5609
  }
@@ -4741,23 +5649,37 @@ class AdmTopActivityV2Component {
4741
5649
  fmt(date) {
4742
5650
  return dayjs(date).format(this.lc.token("getFullDateDisplayFormat"));
4743
5651
  }
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" }] }); }
5652
+ 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 }); }
5653
+ 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
5654
  }
4752
5655
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivityV2Component, decorators: [{
4753
5656
  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: [{
5657
+ 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"] }]
5658
+ }], 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: [{
5659
+ type: Inject,
5660
+ args: [ADM_MODULE_PATH]
5661
+ }] }, { type: undefined, decorators: [{
5662
+ type: Optional
5663
+ }, {
5664
+ type: Inject,
5665
+ args: [ADM_DETAILS_V2]
5666
+ }] }, { type: undefined, decorators: [{
5667
+ type: Optional
5668
+ }, {
5669
+ type: Inject,
5670
+ args: [ADM_PROFILER_V2]
5671
+ }] }], propDecorators: { dlgNodeDetails: [{
4756
5672
  type: ViewChild,
4757
5673
  args: ["dlgNodeDetails"]
4758
5674
  }], dlgSessionDetails: [{
4759
5675
  type: ViewChild,
4760
5676
  args: ["dlgSessionDetails"]
5677
+ }], dlgDetailsV2: [{
5678
+ type: ViewChild,
5679
+ args: ["dlgDetailsV2"]
5680
+ }], detailsV2: [{
5681
+ type: ViewChild,
5682
+ args: [AdmDetailsV2Component]
4761
5683
  }] } });
4762
5684
 
4763
5685
  class LocksView extends AppSearch {
@@ -5495,7 +6417,7 @@ const routeConfig = [
5495
6417
  { path: "serveraudits/:be", component: AdmAuditsComponent, data: { title: "Ricerca Audit Applicativi", internalNavigation: false } },
5496
6418
  { path: "serverenqueues/:be", component: AdmEnqComponent, data: { title: "Ricerca Lock Applicativi", internalNavigation: false } },
5497
6419
  { 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 } },
6420
+ { path: "metadataquery/:be", component: MtdQueryComponent, data: { title: "Query Viste Dinamiche", internalNavigation: false } },
5499
6421
  { path: "serverworkers", component: AdmWrkComponent, data: { title: "Ricerca Processi Applicativi", internalNavigation: false } },
5500
6422
  { path: "profiler", component: AdmProfilerV2Component, canMatch: [profilerV2Enabled], data: { title: "Profiler del Server", internalNavigation: false } },
5501
6423
  { path: "profiler", component: AdmProfilerComponent, data: { title: "Profiler del Server", internalNavigation: false } },
@@ -5508,7 +6430,7 @@ const routeConfig = [
5508
6430
  { path: "serveraudits", component: AdmAuditsComponent, data: { title: "Ricerca Audit Applicativi", internalNavigation: false } },
5509
6431
  { path: "serverenqueues", component: AdmEnqComponent, data: { title: "Ricerca Lock Applicativi", internalNavigation: false } },
5510
6432
  { 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 } },
6433
+ { path: "metadataquery", component: MtdQueryComponent, data: { title: "Query Viste Dinamiche", internalNavigation: false } },
5512
6434
  { path: "syspars", component: AdmSystemParametersComponent, data: { title: "Parametri di sistema", internalNavigation: false } }
5513
6435
  ]
5514
6436
  }
@@ -5540,6 +6462,8 @@ const COMPONENTS = [
5540
6462
  AdmWorkloadV2Component,
5541
6463
  AdmMetricsV2Component,
5542
6464
  MetricsV2ChartComponent,
6465
+ AdmDetailsV2Component,
6466
+ ActivityChartV2Component,
5543
6467
  AdmTopActivitiesComponent,
5544
6468
  AdmTopActivityV2Component,
5545
6469
  SessionDetailComponent,
@@ -5569,6 +6493,8 @@ class AdmModule {
5569
6493
  AdmWorkloadV2Component,
5570
6494
  AdmMetricsV2Component,
5571
6495
  MetricsV2ChartComponent,
6496
+ AdmDetailsV2Component,
6497
+ ActivityChartV2Component,
5572
6498
  AdmTopActivitiesComponent,
5573
6499
  AdmTopActivityV2Component,
5574
6500
  SessionDetailComponent,
@@ -5604,7 +6530,10 @@ class AdmModule {
5604
6530
  { provide: ADM_TOPACT_V2, useFactory: () => !!myconfig?.DirectorFeature?.TopActivityV2 },
5605
6531
  { provide: ADM_PROFILER_V2, useFactory: () => !!myconfig?.DirectorFeature?.ProfilerV2 },
5606
6532
  { provide: ADM_WORKLOAD_V2, useFactory: () => !!myconfig?.DirectorFeature?.WorkloadReportV2 },
5607
- { provide: ADM_METRICS_V2, useFactory: () => !!myconfig?.DirectorFeature?.MetricsV2 }
6533
+ { provide: ADM_METRICS_V2, useFactory: () => !!myconfig?.DirectorFeature?.MetricsV2 },
6534
+ // 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
6535
+ // risponde a GetNodeStats e GetSessionStats solo con il contratto nuovo
6536
+ { provide: ADM_DETAILS_V2, useFactory: () => !!myconfig?.DirectorFeature?.DetailsV2 }
5608
6537
  ], imports: [MODULES] }); }
5609
6538
  }
5610
6539
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmModule, decorators: [{
@@ -5618,7 +6547,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
5618
6547
  { provide: ADM_TOPACT_V2, useFactory: () => !!myconfig?.DirectorFeature?.TopActivityV2 },
5619
6548
  { provide: ADM_PROFILER_V2, useFactory: () => !!myconfig?.DirectorFeature?.ProfilerV2 },
5620
6549
  { provide: ADM_WORKLOAD_V2, useFactory: () => !!myconfig?.DirectorFeature?.WorkloadReportV2 },
5621
- { provide: ADM_METRICS_V2, useFactory: () => !!myconfig?.DirectorFeature?.MetricsV2 }
6550
+ { provide: ADM_METRICS_V2, useFactory: () => !!myconfig?.DirectorFeature?.MetricsV2 },
6551
+ // 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
6552
+ // risponde a GetNodeStats e GetSessionStats solo con il contratto nuovo
6553
+ { provide: ADM_DETAILS_V2, useFactory: () => !!myconfig?.DirectorFeature?.DetailsV2 }
5622
6554
  ]
5623
6555
  }]
5624
6556
  }], ctorParameters: () => [{ type: AdminModuleCommService }] });
@@ -5631,5 +6563,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
5631
6563
  * Generated bundle index. Do not edit.
5632
6564
  */
5633
6565
 
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 };
6566
+ 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
6567
  //# sourceMappingURL=esfaenza-admin-module.mjs.map