@esfaenza/admin-module 20.3.22 → 20.3.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/esfaenza-admin-module.mjs +1065 -128
- package/fesm2022/esfaenza-admin-module.mjs.map +1 -1
- package/index.d.ts +405 -32
- package/package.json +1 -1
|
@@ -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,
|
|
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,
|
|
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
|
-
|
|
211
|
+
// Il corpo può essere anche un oggetto: MdmErrorResponse (message) o il ProblemDetails di ASP.NET (title, detail)
|
|
212
|
+
let body = err?.error;
|
|
213
|
+
let message = typeof body === "string" ? body : body?.message ?? body?.Message ?? body?.detail ?? body?.title ?? err?.message ?? "";
|
|
211
214
|
return String(message).split(/\r?\n/)[0];
|
|
212
215
|
}
|
|
213
216
|
async getInfos(be) {
|
|
@@ -225,6 +228,22 @@ class AdminModuleBaseService {
|
|
|
225
228
|
let ret = await firstValueFrom(this.http.get(GET_Director_GetSessionStats, pars));
|
|
226
229
|
return ret;
|
|
227
230
|
}
|
|
231
|
+
// Stesso URL di getNodeStats: con DirectorFeature.DetailsV2 attivo il backend-for-frontend risponde con il dettaglio v2. null se il nodo non c'è
|
|
232
|
+
async getNodeDetailV2(be, req) {
|
|
233
|
+
let ret = await this.v2Call(this.http.get(GET_Director_GetNodeStats, this.queryParams(be, req), null, false));
|
|
234
|
+
return ret;
|
|
235
|
+
}
|
|
236
|
+
// Stesso URL di getSessionStats, come sopra. null se la sessione non esiste più e nella finestra non era attiva
|
|
237
|
+
async getSessionDetailV2(be, req) {
|
|
238
|
+
let ret = await this.v2Call(this.http.get(GET_Director_GetSessionStats, this.queryParams(be, req), null, false));
|
|
239
|
+
return ret;
|
|
240
|
+
}
|
|
241
|
+
// Parametri in query string senza i null, così vale il default del backend
|
|
242
|
+
queryParams(be, req) {
|
|
243
|
+
let pars = new HttpParams().set("be", be ?? "");
|
|
244
|
+
Object.entries(req).filter(([_, v]) => v != null && v !== "").forEach(([k, v]) => pars = pars.set(k, String(v)));
|
|
245
|
+
return pars;
|
|
246
|
+
}
|
|
228
247
|
async getProfilerDataNodes(be, sv) {
|
|
229
248
|
var pars = new HttpParams().set("be", be ?? "");
|
|
230
249
|
let ret = await firstValueFrom(this.http.post(POST_Director_GetProfilerDataNodes, sv, pars));
|
|
@@ -753,6 +772,782 @@ class ProfilerDataNodesView extends AppSearch {
|
|
|
753
772
|
constructor() { super(); }
|
|
754
773
|
}
|
|
755
774
|
|
|
775
|
+
// Enum della Top Activity v2: i numeri sono quelli del backend (le risposte li riportano come numeri)
|
|
776
|
+
var TopActivityDimension;
|
|
777
|
+
(function (TopActivityDimension) {
|
|
778
|
+
TopActivityDimension[TopActivityDimension["WaitClass"] = 0] = "WaitClass";
|
|
779
|
+
TopActivityDimension[TopActivityDimension["EventType"] = 1] = "EventType";
|
|
780
|
+
TopActivityDimension[TopActivityDimension["WaitEvent"] = 2] = "WaitEvent";
|
|
781
|
+
TopActivityDimension[TopActivityDimension["Instance"] = 3] = "Instance";
|
|
782
|
+
TopActivityDimension[TopActivityDimension["UserSession"] = 4] = "UserSession";
|
|
783
|
+
TopActivityDimension[TopActivityDimension["UserName"] = 5] = "UserName";
|
|
784
|
+
TopActivityDimension[TopActivityDimension["Tenant"] = 6] = "Tenant";
|
|
785
|
+
TopActivityDimension[TopActivityDimension["SessionType"] = 7] = "SessionType";
|
|
786
|
+
TopActivityDimension[TopActivityDimension["BackgroundSession"] = 8] = "BackgroundSession";
|
|
787
|
+
TopActivityDimension[TopActivityDimension["JobName"] = 9] = "JobName";
|
|
788
|
+
TopActivityDimension[TopActivityDimension["ConsumerGroup"] = 10] = "ConsumerGroup";
|
|
789
|
+
TopActivityDimension[TopActivityDimension["ThreadType"] = 11] = "ThreadType";
|
|
790
|
+
TopActivityDimension[TopActivityDimension["Api"] = 12] = "Api";
|
|
791
|
+
TopActivityDimension[TopActivityDimension["Machine"] = 13] = "Machine";
|
|
792
|
+
// Chiave TID@istanza, etichetta il TID (specifica "Dettaglio nodo e sessione")
|
|
793
|
+
TopActivityDimension[TopActivityDimension["Thread"] = 14] = "Thread";
|
|
794
|
+
})(TopActivityDimension || (TopActivityDimension = {}));
|
|
795
|
+
var TopActivityDataSource;
|
|
796
|
+
(function (TopActivityDataSource) {
|
|
797
|
+
TopActivityDataSource[TopActivityDataSource["Memory"] = 0] = "Memory";
|
|
798
|
+
TopActivityDataSource[TopActivityDataSource["MemoryAndStored"] = 1] = "MemoryAndStored";
|
|
799
|
+
})(TopActivityDataSource || (TopActivityDataSource = {}));
|
|
800
|
+
var TopActivityResolution;
|
|
801
|
+
(function (TopActivityResolution) {
|
|
802
|
+
TopActivityResolution[TopActivityResolution["Low"] = 0] = "Low";
|
|
803
|
+
TopActivityResolution[TopActivityResolution["Medium"] = 1] = "Medium";
|
|
804
|
+
TopActivityResolution[TopActivityResolution["High"] = 2] = "High";
|
|
805
|
+
TopActivityResolution[TopActivityResolution["Maximum"] = 3] = "Maximum";
|
|
806
|
+
})(TopActivityResolution || (TopActivityResolution = {}));
|
|
807
|
+
var TopActivityMaximumThreads;
|
|
808
|
+
(function (TopActivityMaximumThreads) {
|
|
809
|
+
TopActivityMaximumThreads[TopActivityMaximumThreads["None"] = 0] = "None";
|
|
810
|
+
TopActivityMaximumThreads[TopActivityMaximumThreads["Cores"] = 1] = "Cores";
|
|
811
|
+
TopActivityMaximumThreads[TopActivityMaximumThreads["Threads"] = 2] = "Threads";
|
|
812
|
+
})(TopActivityMaximumThreads || (TopActivityMaximumThreads = {}));
|
|
813
|
+
|
|
814
|
+
// Colori e regole del grafico della Top Activity v2, condivisi con i dettagli di nodo e sessione: le stesse chiavi hanno gli stessi colori
|
|
815
|
+
// WaitClass ed EventType hanno valori fissi: colori fissi, così il grafico si legge sempre allo stesso modo
|
|
816
|
+
const FIXED_COLORS = {
|
|
817
|
+
Cpu: "#43a047", Database: "#1e88e5", Script: "#8e24aa", Network: "#8d6e63", IO: "#00acc1", Sleep: "#b0bec5", Throttle: "#fb8c00", Wait: "#fdd835",
|
|
818
|
+
Latch: "#e53935", Semaphore: "#f06292", Enqueue: "#c62828", ReadWriteLock: "#ad1457", Fence: "#6d4c41", ConditionVariable: "#00897b", Scheduler: "#5e35b1"
|
|
819
|
+
};
|
|
820
|
+
const PALETTE = ["#1e88e5", "#43a047", "#fb8c00", "#8e24aa", "#e53935", "#00897b", "#fdd835", "#6d4c41", "#3949ab", "#c0ca33"];
|
|
821
|
+
const OTHER_COLOR = "#9e9e9e";
|
|
822
|
+
const TOTAL_COLOR = "#263238";
|
|
823
|
+
const LIMIT_COLOR = "#e53935";
|
|
824
|
+
// Colore del componente i-esimo: fisso per le chiavi note (classi di attesa e tipi di evento), dalla tavolozza per le altre
|
|
825
|
+
function componentColor(key, other, index, fixed) {
|
|
826
|
+
return other ? OTHER_COLOR : (fixed && FIXED_COLORS[key]) || PALETTE[index % PALETTE.length];
|
|
827
|
+
}
|
|
828
|
+
// es-charts ricava la griglia dell'asse dal passo fra i punti ma la arrotonda all'unità superiore: 30 s diventano 1 minuto, 5 minuti 1 ora.
|
|
829
|
+
// amCharts mette allora più bucket nella stessa cella e i gradini si sovrappongono (aree, linea del totale e tooltip non tornano).
|
|
830
|
+
// Il passo lo dà la risposta, e i bucket della specifica (1-30 s, 1-30 min, 1 h) dividono sempre il minuto o l'ora
|
|
831
|
+
function bucketInterval(seconds) {
|
|
832
|
+
if (!seconds)
|
|
833
|
+
return null;
|
|
834
|
+
if (seconds % 3600 == 0)
|
|
835
|
+
return { timeunit: "hour", count: seconds / 3600 };
|
|
836
|
+
if (seconds % 60 == 0)
|
|
837
|
+
return { timeunit: "minute", count: seconds / 60 };
|
|
838
|
+
return { timeunit: "second", count: seconds };
|
|
839
|
+
}
|
|
840
|
+
// Le date delle risposte del Director v2 sono UTC "dd/MM/yyyy HH:mm:ss" senza fuso
|
|
841
|
+
function parseUtc(value) {
|
|
842
|
+
let m = /^(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2}):(\d{2})$/.exec(value ?? "");
|
|
843
|
+
return m ? new Date(Date.UTC(+m[3], +m[2] - 1, +m[1], +m[4], +m[5], +m[6])) : value ? new Date(value) : null;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
class AdmDetailsV2Loc extends LocalizationService {
|
|
847
|
+
constructor(injector) {
|
|
848
|
+
super(injector);
|
|
849
|
+
super.set("it->en", "Indietro", ["Back"]);
|
|
850
|
+
super.set("it->en", "Dettaglio nodo", ["Node detail"]);
|
|
851
|
+
super.set("it->en", "Sessione", ["Session"]);
|
|
852
|
+
super.set("it->en", "Ultime", ["Last"]);
|
|
853
|
+
super.set("it->en", "Da", ["From"]);
|
|
854
|
+
super.set("it->en", "A", ["To"]);
|
|
855
|
+
super.set("it->en", "Applica", ["Apply"]);
|
|
856
|
+
super.set("it->en", "dalle", ["from"]);
|
|
857
|
+
super.set("it->en", "alle", ["to"]);
|
|
858
|
+
super.set("it->en", "Memoria", ["Memory"]);
|
|
859
|
+
super.set("it->en", "Memoria e storico", ["Memory and history"]);
|
|
860
|
+
super.set("it->en", "Dal vivo", ["Live"]);
|
|
861
|
+
super.set("it->en", "Storico", ["History"]);
|
|
862
|
+
super.set("it->en", "Aggiornato alle", ["Updated at"]);
|
|
863
|
+
super.set("it->en", "Pausa", ["Pause"]);
|
|
864
|
+
super.set("it->en", "Riprendi", ["Resume"]);
|
|
865
|
+
super.set("it->en", "La finestra è stata ridotta alle ultime 24 ore", ["The window was reduced to the last 24 hours"]);
|
|
866
|
+
super.set("it->en", "Errore", ["Error"]);
|
|
867
|
+
super.set("it->en", "Nodo non trovato", ["Node not found"]);
|
|
868
|
+
super.set("it->en", "Sessione non trovata: non esiste più e nella finestra non era attiva", ["Session not found: it no longer exists and was not active in the window"]);
|
|
869
|
+
super.set("it->en", "Carico i Dati", ["Loading data"]);
|
|
870
|
+
super.set("it->en", "Copia", ["Copy"]);
|
|
871
|
+
super.set("it->en", "Copiato", ["Copied"]);
|
|
872
|
+
super.set("it->en", "Apri nel profiler", ["Open in profiler"]);
|
|
873
|
+
super.set("it->en", "Sessioni su questo evento", ["Sessions on this event"]);
|
|
874
|
+
super.set("it->en", "Solo l'evento esatto: il lavoro dei discendenti non è compreso", ["Exact event only: the descendants' work is not included"]);
|
|
875
|
+
super.set("it->en", "Top Activity filtrata su questo evento", ["Top Activity filtered on this event"]);
|
|
876
|
+
super.set("it->en", "discendenti esclusi", ["descendants excluded"]);
|
|
877
|
+
super.set("it->en", "Statistiche", ["Statistics"]);
|
|
878
|
+
super.set("it->en", "Dall'avvio", ["Since startup"]);
|
|
879
|
+
super.set("it->en", "Dall'ultimo snapshot", ["Since the last snapshot"]);
|
|
880
|
+
super.set("it->en", "Nella finestra", ["In the window"]);
|
|
881
|
+
super.set("it->en", "Esecuzioni", ["Executions"]);
|
|
882
|
+
super.set("it->en", "Tempo totale", ["Total time"]);
|
|
883
|
+
super.set("it->en", "Tempo proprio", ["Self time"]);
|
|
884
|
+
super.set("it->en", "Medio", ["Average"]);
|
|
885
|
+
super.set("it->en", "Massimo", ["Peak"]);
|
|
886
|
+
super.set("it->en", "Minimo", ["Minimum"]);
|
|
887
|
+
super.set("it->en", "Thread dentro adesso", ["Threads inside now"]);
|
|
888
|
+
super.set("it->en", "In corso da", ["Running for"]);
|
|
889
|
+
super.set("it->en", "Ultima uscita", ["Last exit"]);
|
|
890
|
+
super.set("it->en", "Dove va il tempo", ["Where the time goes"]);
|
|
891
|
+
super.set("it->en", "tempo proprio del sottoalbero", ["self time of the subtree"]);
|
|
892
|
+
super.set("it->en", "Idle è tempo di attesa senza lavoro", ["Idle is waiting time with no work"]);
|
|
893
|
+
super.set("it->en", "Per istanza", ["By instance"]);
|
|
894
|
+
super.set("it->en", "Istanza", ["Instance"]);
|
|
895
|
+
super.set("it->en", "Tempo", ["Time"]);
|
|
896
|
+
super.set("it->en", "Thread attivi", ["Active threads"]);
|
|
897
|
+
super.set("it->en", "Attività nel tempo", ["Activity over time"]);
|
|
898
|
+
super.set("it->en", "sessioni attive medie", ["average active sessions"]);
|
|
899
|
+
super.set("it->en", "picco", ["peak"]);
|
|
900
|
+
super.set("it->en", "un punto ogni", ["one point every"]);
|
|
901
|
+
super.set("it->en", "stima per campionamento", ["sampling estimate"]);
|
|
902
|
+
super.set("it->en", "Valori stimati contando i campioni", ["Values estimated by counting samples"]);
|
|
903
|
+
super.set("it->en", "sessioni", ["sessions"]);
|
|
904
|
+
super.set("it->en", "Nessuna attività nella finestra", ["No activity in the window"]);
|
|
905
|
+
super.set("it->en", "Prima delle", ["Before"]);
|
|
906
|
+
super.set("it->en", "i dati vengono dallo storico, con meno risoluzione", ["data comes from history, with lower resolution"]);
|
|
907
|
+
super.set("it->en", "Comprende il lavoro dei discendenti", ["Includes the descendants' work"]);
|
|
908
|
+
super.set("it->en", "Discendenti principali", ["Top descendants"]);
|
|
909
|
+
super.set("it->en", "Figli", ["Children"]);
|
|
910
|
+
super.set("it->en", "Discendenti", ["Descendants"]);
|
|
911
|
+
super.set("it->en", "Nome", ["Name"]);
|
|
912
|
+
super.set("it->en", "Tipo", ["Type"]);
|
|
913
|
+
super.set("it->en", "Livello", ["Level"]);
|
|
914
|
+
super.set("it->en", "del nodo", ["of the node"]);
|
|
915
|
+
super.set("it->en", "Terminata", ["Terminated"]);
|
|
916
|
+
super.set("it->en", "Utente", ["User"]);
|
|
917
|
+
super.set("it->en", "Gruppo di consumo", ["Consumer group"]);
|
|
918
|
+
super.set("it->en", "Sessione di background", ["Background session"]);
|
|
919
|
+
super.set("it->en", "Inizio", ["Start"]);
|
|
920
|
+
super.set("it->en", "collegata da", ["connected for"]);
|
|
921
|
+
super.set("it->en", "Ultima attività", ["Last activity"]);
|
|
922
|
+
super.set("it->en", "La sessione non esiste più: i suoi dati vengono dall'ultimo campione, delle", ["The session no longer exists: its data comes from the last sample, taken at"]);
|
|
923
|
+
super.set("it->en", "Sessioni attive medie", ["Average active sessions"]);
|
|
924
|
+
super.set("it->en", "Media", ["Average"]);
|
|
925
|
+
super.set("it->en", "Picco", ["Peak"]);
|
|
926
|
+
super.set("it->en", "Dividi per", ["Split by"]);
|
|
927
|
+
super.set("it->en", "Classe di attesa", ["Wait class"]);
|
|
928
|
+
super.set("it->en", "Tipo di evento", ["Event type"]);
|
|
929
|
+
super.set("it->en", "Evento", ["Event"]);
|
|
930
|
+
super.set("it->en", "Bassa", ["Low"]);
|
|
931
|
+
super.set("it->en", "Alta", ["High"]);
|
|
932
|
+
super.set("it->en", "Massima", ["Maximum"]);
|
|
933
|
+
super.set("it->en", "Eventi", ["Events"]);
|
|
934
|
+
super.set("it->en", "Attività", ["Activity"]);
|
|
935
|
+
super.set("it->en", "Altri", ["Others"]);
|
|
936
|
+
super.set("it->en", "(nessuno)", ["(none)"]);
|
|
937
|
+
super.set("it->en", "(non attribuito)", ["(unattributed)"]);
|
|
938
|
+
super.set("it->en", "Thread adesso", ["Threads now"]);
|
|
939
|
+
super.set("it->en", "Stato", ["Status"]);
|
|
940
|
+
super.set("it->en", "Priorità", ["Priority"]);
|
|
941
|
+
super.set("it->en", "Macchina", ["Machine"]);
|
|
942
|
+
super.set("it->en", "Evento corrente", ["Current event"]);
|
|
943
|
+
super.set("it->en", "nessun evento in corso", ["no event in progress"]);
|
|
944
|
+
super.set("it->en", "Pila completa degli eventi", ["Full event stack"]);
|
|
945
|
+
super.set("it->en", "Nessun evento", ["No event"]);
|
|
946
|
+
super.set("it->en", "Operazioni lunghe", ["Long operations"]);
|
|
947
|
+
super.set("it->en", "di", ["of"]);
|
|
948
|
+
super.set("it->en", "Trascorso", ["Elapsed"]);
|
|
949
|
+
super.set("it->en", "Alla fine", ["Remaining"]);
|
|
950
|
+
super.set("it->en", "non stimabile", ["not estimable"]);
|
|
951
|
+
}
|
|
952
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Loc, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
953
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Loc }); }
|
|
954
|
+
}
|
|
955
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Loc, decorators: [{
|
|
956
|
+
type: Injectable
|
|
957
|
+
}], ctorParameters: () => [{ type: i0.Injector }] });
|
|
958
|
+
|
|
959
|
+
// Angular
|
|
960
|
+
class ActivityChartV2Component_Item {
|
|
961
|
+
}
|
|
962
|
+
class LegendItem {
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Grafico impilato delle sessioni attive medie, con le regole e i colori del grafico della Top Activity v2:
|
|
966
|
+
* un gradino per bucket, una serie per componente (l'ultimo, "altri", in grigio) e la legenda sotto.
|
|
967
|
+
* Lo usano i dettagli v2 di nodo (per classe di attesa) e di sessione (la sua Top Activity)
|
|
968
|
+
*/
|
|
969
|
+
class ActivityChartV2Component {
|
|
970
|
+
constructor() {
|
|
971
|
+
// Chiavi con colore fisso: classi di attesa e tipi di evento
|
|
972
|
+
this.FixedColors = true;
|
|
973
|
+
this.name = "activitychartv2";
|
|
974
|
+
this.legend = [];
|
|
975
|
+
}
|
|
976
|
+
get emptyText() {
|
|
977
|
+
return this.EmptyText ?? "";
|
|
978
|
+
}
|
|
979
|
+
ngOnChanges() {
|
|
980
|
+
let times = (this.Times ?? []).map(t => parseUtc(t));
|
|
981
|
+
let components = this.Components ?? [];
|
|
982
|
+
if (times.length == 0 || components.length == 0) {
|
|
983
|
+
this.chartData = null;
|
|
984
|
+
this.legend = [];
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
let interval = bucketInterval(this.BucketSeconds);
|
|
988
|
+
let series = [];
|
|
989
|
+
this.legend = components.map((c, i) => {
|
|
990
|
+
let color = componentColor(c.key, c.other, i, this.FixedColors);
|
|
991
|
+
series.push(new LineSerie(c.label, times.map((t, j) => new DateValue(t, c.values?.[j] ?? 0)), interval, color, this.Uom));
|
|
992
|
+
return { label: c.label, color: color, percentage: c.percentage };
|
|
993
|
+
});
|
|
994
|
+
this.chartData = new LineChartData(series);
|
|
995
|
+
}
|
|
996
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ActivityChartV2Component, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
997
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: ActivityChartV2Component, isStandalone: false, selector: "activity-chart-v2", inputs: { Times: "Times", Components: "Components", BucketSeconds: "BucketSeconds", FixedColors: "FixedColors", Uom: "Uom", EmptyText: "EmptyText", name: "name" }, usesOnChanges: true, ngImport: i0, template: `
|
|
998
|
+
@if (chartData) {
|
|
999
|
+
<div class="acv2-chart">
|
|
1000
|
+
<es-line-chart [MinGridDistance]="65" [Timeline]="false" [FinalInstants]="false" [Stacked]="true" [Step]="true" [Fill]="true" [MergeDatasets]="true"
|
|
1001
|
+
[AllowGaps]="false" [Legend]="false" [Data]="chartData" [name]="name" [DataGroupingThreshold]="99999999"></es-line-chart>
|
|
1002
|
+
</div>
|
|
1003
|
+
<div class="acv2-legend">
|
|
1004
|
+
@for (item of legend; track $index) {
|
|
1005
|
+
<span class="acv2-legend-item"><span class="acv2-swatch" [style.background]="item.color"></span>{{item.label}} <span class="acv2-muted">{{item.percentage | number : '1.0-1' : 'it'}}%</span></span>
|
|
1006
|
+
}
|
|
1007
|
+
</div>
|
|
1008
|
+
} @else {
|
|
1009
|
+
<div class="acv2-empty">{{emptyText}}</div>
|
|
1010
|
+
}`, isInline: true, styles: [":host{display:block}.acv2-chart{height:240px}.acv2-legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin-top:6px;font-size:12px}.acv2-legend-item{display:inline-flex;align-items:center;gap:5px}.acv2-swatch{width:10px;height:10px;border-radius:2px}.acv2-muted{color:var(--p-text-muted-color, #64748b)}.acv2-empty{padding:40px 0;text-align:center;color:var(--p-text-muted-color, #64748b)}\n"], dependencies: [{ kind: "component", type: i2.EsLineChartComponent, selector: "es-line-chart", inputs: ["Data", "DataArray", "Step", "DataGroupBucketSize", "DataGroupingThreshold", "StrokeSize", "AllowGaps", "MergeDatasets", "FinalInstants", "Min", "Max", "Fill", "Stacked"] }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }] }); }
|
|
1011
|
+
}
|
|
1012
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ActivityChartV2Component, decorators: [{
|
|
1013
|
+
type: Component,
|
|
1014
|
+
args: [{ selector: "activity-chart-v2", template: `
|
|
1015
|
+
@if (chartData) {
|
|
1016
|
+
<div class="acv2-chart">
|
|
1017
|
+
<es-line-chart [MinGridDistance]="65" [Timeline]="false" [FinalInstants]="false" [Stacked]="true" [Step]="true" [Fill]="true" [MergeDatasets]="true"
|
|
1018
|
+
[AllowGaps]="false" [Legend]="false" [Data]="chartData" [name]="name" [DataGroupingThreshold]="99999999"></es-line-chart>
|
|
1019
|
+
</div>
|
|
1020
|
+
<div class="acv2-legend">
|
|
1021
|
+
@for (item of legend; track $index) {
|
|
1022
|
+
<span class="acv2-legend-item"><span class="acv2-swatch" [style.background]="item.color"></span>{{item.label}} <span class="acv2-muted">{{item.percentage | number : '1.0-1' : 'it'}}%</span></span>
|
|
1023
|
+
}
|
|
1024
|
+
</div>
|
|
1025
|
+
} @else {
|
|
1026
|
+
<div class="acv2-empty">{{emptyText}}</div>
|
|
1027
|
+
}`, standalone: false, styles: [":host{display:block}.acv2-chart{height:240px}.acv2-legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin-top:6px;font-size:12px}.acv2-legend-item{display:inline-flex;align-items:center;gap:5px}.acv2-swatch{width:10px;height:10px;border-radius:2px}.acv2-muted{color:var(--p-text-muted-color, #64748b)}.acv2-empty{padding:40px 0;text-align:center;color:var(--p-text-muted-color, #64748b)}\n"] }]
|
|
1028
|
+
}], propDecorators: { Times: [{
|
|
1029
|
+
type: Input
|
|
1030
|
+
}], Components: [{
|
|
1031
|
+
type: Input
|
|
1032
|
+
}], BucketSeconds: [{
|
|
1033
|
+
type: Input
|
|
1034
|
+
}], FixedColors: [{
|
|
1035
|
+
type: Input
|
|
1036
|
+
}], Uom: [{
|
|
1037
|
+
type: Input
|
|
1038
|
+
}], EmptyText: [{
|
|
1039
|
+
type: Input
|
|
1040
|
+
}], name: [{
|
|
1041
|
+
type: Input
|
|
1042
|
+
}] } });
|
|
1043
|
+
|
|
1044
|
+
// Angular
|
|
1045
|
+
// Formati del profiler v2 (specifica "Profiler gerarchico"): durate nell'unità più leggibile, interi con il separatore
|
|
1046
|
+
// delle migliaia italiano, percentuali con un decimale sotto 10. Un dato mancante è "—"
|
|
1047
|
+
class ProfilerFormatPipe {
|
|
1048
|
+
transform(value, kind) {
|
|
1049
|
+
if (value == null || isNaN(value))
|
|
1050
|
+
return "—";
|
|
1051
|
+
switch (kind) {
|
|
1052
|
+
case "dur": return formatDuration(value);
|
|
1053
|
+
case "pct": return formatPercentage(value);
|
|
1054
|
+
default: return formatNumber(value, "it", "1.0-0");
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
1058
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, isStandalone: true, name: "pv2fmt" }); }
|
|
1059
|
+
}
|
|
1060
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, decorators: [{
|
|
1061
|
+
type: Pipe,
|
|
1062
|
+
args: [{ name: "pv2fmt" }]
|
|
1063
|
+
}] });
|
|
1064
|
+
// Secondi: "850 µs", "4,27 ms", "312,5 ms", "8,41 s", "4 min 12 s", "3 h 20 min", "76 h"
|
|
1065
|
+
function formatDuration(seconds) {
|
|
1066
|
+
if (seconds == null || isNaN(seconds))
|
|
1067
|
+
return "—";
|
|
1068
|
+
let abs = Math.abs(seconds);
|
|
1069
|
+
if (abs < 0.001)
|
|
1070
|
+
return `${formatNumber(seconds * 1000000, "it", "1.0-0")} µs`;
|
|
1071
|
+
if (abs < 1)
|
|
1072
|
+
return `${formatNumber(seconds * 1000, "it", abs < 0.01 ? "1.2-2" : "1.1-1")} ms`;
|
|
1073
|
+
if (abs < 60)
|
|
1074
|
+
return `${formatNumber(seconds, "it", abs < 10 ? "1.2-2" : "1.1-1")} s`;
|
|
1075
|
+
if (abs < 3600)
|
|
1076
|
+
return `${Math.floor(abs / 60)} min ${Math.floor(abs % 60)} s`;
|
|
1077
|
+
if (abs < 48 * 3600)
|
|
1078
|
+
return `${Math.floor(abs / 3600)} h ${Math.floor(abs % 3600 / 60)} min`;
|
|
1079
|
+
return `${formatNumber(Math.floor(abs / 3600), "it", "1.0-0")} h`;
|
|
1080
|
+
}
|
|
1081
|
+
// Da 0 a 100: "4,2%", "34%"
|
|
1082
|
+
function formatPercentage(value) {
|
|
1083
|
+
if (value == null || isNaN(value))
|
|
1084
|
+
return "—";
|
|
1085
|
+
return `${formatNumber(value, "it", Math.abs(value) < 10 ? "1.1-1" : "1.0-0")}%`;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// Angular
|
|
1089
|
+
const HOUR_MS$1 = 3600 * 1000;
|
|
1090
|
+
const MAX_WINDOW_MS = 24 * HOUR_MS$1;
|
|
1091
|
+
// Una finestra che finisce entro questo margine da adesso è "agganciata": l'aggiornamento automatico la sposta in avanti
|
|
1092
|
+
const ANCHOR_MARGIN_MS = 2 * 60 * 1000;
|
|
1093
|
+
// Una voce della pila di navigazione (D1): cosa mostrare, con quale finestra e sorgente
|
|
1094
|
+
class DetailsV2Entry {
|
|
1095
|
+
}
|
|
1096
|
+
// Contesto della pagina da cui si apre un dettaglio
|
|
1097
|
+
class DetailsV2Options {
|
|
1098
|
+
}
|
|
1099
|
+
class DetailsV2EventLink {
|
|
1100
|
+
}
|
|
1101
|
+
class StatRow {
|
|
1102
|
+
}
|
|
1103
|
+
class TypePart {
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Dettaglio di un nodo del profiler e di una sessione (specifica "Dettaglio nodo e sessione"), in una finestra di dialogo con la pila
|
|
1107
|
+
* di navigazione: dalla sessione si apre il nodo di un evento, dal nodo i suoi antenati e discendenti, "Indietro" torna al precedente.
|
|
1108
|
+
* Le chiamate sono GetNodeStats e GetSessionStats con DirectorFeature.DetailsV2 attivo
|
|
1109
|
+
*/
|
|
1110
|
+
class AdmDetailsV2Component {
|
|
1111
|
+
constructor(lc, dateExts, adms) {
|
|
1112
|
+
this.lc = lc;
|
|
1113
|
+
this.dateExts = dateExts;
|
|
1114
|
+
this.adms = adms;
|
|
1115
|
+
this.Be = "";
|
|
1116
|
+
// "Sessioni su questo evento" ha senso solo con la Top Activity v2 (N8)
|
|
1117
|
+
this.CanShowSessions = false;
|
|
1118
|
+
// "Apri nel profiler" ha senso solo con il profiler v2, che sa usare un nodo come radice (N7)
|
|
1119
|
+
this.CanOpenProfiler = false;
|
|
1120
|
+
this.closed = new EventEmitter();
|
|
1121
|
+
this.sessionsOnEvent = new EventEmitter();
|
|
1122
|
+
this.openProfiler = new EventEmitter();
|
|
1123
|
+
this.Dim = TopActivityDimension;
|
|
1124
|
+
this.QuickRanges = [1, 6, 24];
|
|
1125
|
+
this.stack = [];
|
|
1126
|
+
this.loading = false;
|
|
1127
|
+
this.notFound = false;
|
|
1128
|
+
this.paused = false;
|
|
1129
|
+
this.refreshSeconds = 0;
|
|
1130
|
+
this.filterfrom = "";
|
|
1131
|
+
this.filterto = "";
|
|
1132
|
+
this.windowClamped = false;
|
|
1133
|
+
// Viste derivate dalla risposta
|
|
1134
|
+
this.nodeChartTimes = [];
|
|
1135
|
+
this.nodeChart = [];
|
|
1136
|
+
this.nodeStats = [];
|
|
1137
|
+
this.typeParts = [];
|
|
1138
|
+
this.sessionChart = [];
|
|
1139
|
+
this.sessionTables = [];
|
|
1140
|
+
this.copied = false;
|
|
1141
|
+
this.Dimensions = [];
|
|
1142
|
+
this.Resolutions = [];
|
|
1143
|
+
// Il tempo in corso dei thread avanza fra un aggiornamento e l'altro (S4)
|
|
1144
|
+
this.now = Date.now();
|
|
1145
|
+
this.loadedAt = Date.now();
|
|
1146
|
+
this.colors = {};
|
|
1147
|
+
this.visible = false;
|
|
1148
|
+
this.requestId = 0;
|
|
1149
|
+
this.Dimensions = [
|
|
1150
|
+
new KeyValue(String(TopActivityDimension.WaitClass), this.lc.loc("Classe di attesa")),
|
|
1151
|
+
new KeyValue(String(TopActivityDimension.EventType), this.lc.loc("Tipo di evento")),
|
|
1152
|
+
new KeyValue(String(TopActivityDimension.Thread), "Thread"),
|
|
1153
|
+
new KeyValue(String(TopActivityDimension.Api), "API"),
|
|
1154
|
+
new KeyValue(String(TopActivityDimension.WaitEvent), this.lc.loc("Evento"))
|
|
1155
|
+
];
|
|
1156
|
+
this.Resolutions = [
|
|
1157
|
+
new KeyValue(String(TopActivityResolution.Low), this.lc.loc("Bassa")),
|
|
1158
|
+
new KeyValue(String(TopActivityResolution.Medium), this.lc.loc("Media")),
|
|
1159
|
+
new KeyValue(String(TopActivityResolution.High), this.lc.loc("Alta")),
|
|
1160
|
+
new KeyValue(String(TopActivityResolution.Maximum), this.lc.loc("Massima"))
|
|
1161
|
+
];
|
|
1162
|
+
}
|
|
1163
|
+
ngOnDestroy() {
|
|
1164
|
+
this.stopTimers();
|
|
1165
|
+
}
|
|
1166
|
+
get current() {
|
|
1167
|
+
return this.stack[this.stack.length - 1];
|
|
1168
|
+
}
|
|
1169
|
+
// #region Apertura e navigazione (D1)
|
|
1170
|
+
openNode(nodeId, o) {
|
|
1171
|
+
// D3: dal vivo nel caso normale; lo storico solo se la finestra è tutta prima dei campioni in memoria
|
|
1172
|
+
let realTime = o.realTime ?? !(o.memoryFrom && o.to.getTime() <= o.memoryFrom.getTime());
|
|
1173
|
+
this.start({ kind: "node", nodeId: nodeId, global: o.instanceId ? null : (o.global ?? true), instanceId: o.instanceId || null, realTime: realTime, ...this.window(o) }, o);
|
|
1174
|
+
}
|
|
1175
|
+
openSession(instanceId, sid, serial, o) {
|
|
1176
|
+
this.start({ kind: "session", instanceId: instanceId, sid: sid, serial: serial, dimension: TopActivityDimension.WaitClass, resolution: TopActivityResolution.Medium, realTime: o.realTime ?? false, ...this.window(o) }, o);
|
|
1177
|
+
}
|
|
1178
|
+
// Da una sessione l'istanza è quella della sessione e il nodo si legge dal vivo; da un nodo valgono gli stessi parametri
|
|
1179
|
+
pushNode(nodeId) {
|
|
1180
|
+
let cur = this.current;
|
|
1181
|
+
if (!nodeId || !cur)
|
|
1182
|
+
return;
|
|
1183
|
+
let entry = cur.kind == "session"
|
|
1184
|
+
? { kind: "node", nodeId: nodeId, global: null, instanceId: cur.instanceId, realTime: true, from: cur.from, to: cur.to, anchored: cur.anchored }
|
|
1185
|
+
: { ...cur, nodeId: nodeId };
|
|
1186
|
+
this.stack.push(entry);
|
|
1187
|
+
this.load();
|
|
1188
|
+
}
|
|
1189
|
+
back() {
|
|
1190
|
+
if (this.stack.length < 2)
|
|
1191
|
+
return;
|
|
1192
|
+
this.stack.pop();
|
|
1193
|
+
this.load();
|
|
1194
|
+
}
|
|
1195
|
+
close() {
|
|
1196
|
+
this.stop();
|
|
1197
|
+
this.closed.emit();
|
|
1198
|
+
}
|
|
1199
|
+
// Da chiamare quando la finestra di dialogo si chiude: l'aggiornamento automatico si ferma (D5)
|
|
1200
|
+
stop() {
|
|
1201
|
+
this.visible = false;
|
|
1202
|
+
this.stopTimers();
|
|
1203
|
+
}
|
|
1204
|
+
start(entry, o) {
|
|
1205
|
+
this.refreshSeconds = o.refreshSeconds ?? 0;
|
|
1206
|
+
this.paused = false;
|
|
1207
|
+
this.stack = [entry];
|
|
1208
|
+
this.visible = true;
|
|
1209
|
+
this.load();
|
|
1210
|
+
this.startTimers();
|
|
1211
|
+
}
|
|
1212
|
+
window(o) {
|
|
1213
|
+
let to = (o.to ?? new Date()).getTime();
|
|
1214
|
+
let from = (o.from ?? new Date(to - HOUR_MS$1)).getTime();
|
|
1215
|
+
return { from: Math.max(from, to - MAX_WINDOW_MS), to: to, anchored: Math.abs(Date.now() - to) < ANCHOR_MARGIN_MS };
|
|
1216
|
+
}
|
|
1217
|
+
// #endregion
|
|
1218
|
+
// #region Caricamento
|
|
1219
|
+
async load(refresh = false) {
|
|
1220
|
+
let entry = this.current;
|
|
1221
|
+
if (!entry)
|
|
1222
|
+
return;
|
|
1223
|
+
this.syncWindowFields();
|
|
1224
|
+
let id = ++this.requestId;
|
|
1225
|
+
this.loading = true;
|
|
1226
|
+
this.error = null;
|
|
1227
|
+
if (!refresh) {
|
|
1228
|
+
this.node = null;
|
|
1229
|
+
this.session = null;
|
|
1230
|
+
this.notFound = false;
|
|
1231
|
+
this.expandedTid = null;
|
|
1232
|
+
this.highlightedTid = null;
|
|
1233
|
+
}
|
|
1234
|
+
try {
|
|
1235
|
+
if (entry.kind == "node") {
|
|
1236
|
+
let res = await this.adms.getNodeDetailV2(this.Be, this.nodeRequest(entry));
|
|
1237
|
+
if (id != this.requestId)
|
|
1238
|
+
return;
|
|
1239
|
+
this.node = res;
|
|
1240
|
+
this.buildNodeView();
|
|
1241
|
+
}
|
|
1242
|
+
else {
|
|
1243
|
+
let res = await this.adms.getSessionDetailV2(this.Be, this.sessionRequest(entry));
|
|
1244
|
+
if (id != this.requestId)
|
|
1245
|
+
return;
|
|
1246
|
+
this.session = res;
|
|
1247
|
+
this.buildSessionView();
|
|
1248
|
+
}
|
|
1249
|
+
this.notFound = !this.node && !this.session;
|
|
1250
|
+
this.updatedAt = new Date();
|
|
1251
|
+
this.loadedAt = Date.now();
|
|
1252
|
+
this.now = this.loadedAt;
|
|
1253
|
+
}
|
|
1254
|
+
catch (err) {
|
|
1255
|
+
if (id != this.requestId || err?.status == 401)
|
|
1256
|
+
return;
|
|
1257
|
+
this.node = null;
|
|
1258
|
+
this.session = null;
|
|
1259
|
+
// 400 del backend (finestra non valida): arriva come 542 con il message (D6)
|
|
1260
|
+
this.error = err?.status == 542 ? this.adms.errorText(err) : `${this.lc.loc("Errore")} ${err?.status ?? ""}: ${this.adms.errorText(err)}`;
|
|
1261
|
+
}
|
|
1262
|
+
finally {
|
|
1263
|
+
if (id == this.requestId)
|
|
1264
|
+
this.loading = false;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
nodeRequest(e) {
|
|
1268
|
+
return {
|
|
1269
|
+
nodeId: e.nodeId,
|
|
1270
|
+
realTime: e.realTime,
|
|
1271
|
+
global: e.instanceId ? null : e.global,
|
|
1272
|
+
instanceId: e.instanceId,
|
|
1273
|
+
snapFrom: new Date(e.from).toISOString(),
|
|
1274
|
+
snapTo: new Date(e.to).toISOString()
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
sessionRequest(e) {
|
|
1278
|
+
return {
|
|
1279
|
+
instanceId: e.instanceId,
|
|
1280
|
+
sid: e.sid,
|
|
1281
|
+
serial: e.serial,
|
|
1282
|
+
realTime: e.realTime,
|
|
1283
|
+
snapFrom: new Date(e.from).toISOString(),
|
|
1284
|
+
snapTo: new Date(e.to).toISOString(),
|
|
1285
|
+
dimension: e.dimension,
|
|
1286
|
+
resolution: e.resolution
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
// #endregion
|
|
1290
|
+
// #region Finestra, sorgente e aggiornamento (D2, D3, D5)
|
|
1291
|
+
quickRange(hours) {
|
|
1292
|
+
let e = this.current;
|
|
1293
|
+
e.to = Date.now();
|
|
1294
|
+
e.from = e.to - hours * HOUR_MS$1;
|
|
1295
|
+
e.anchored = true;
|
|
1296
|
+
this.load();
|
|
1297
|
+
}
|
|
1298
|
+
applyDates() {
|
|
1299
|
+
let e = this.current;
|
|
1300
|
+
let to = this.toDate(this.filterto)?.getTime() ?? Date.now();
|
|
1301
|
+
let from = this.toDate(this.filterfrom)?.getTime() ?? to - HOUR_MS$1;
|
|
1302
|
+
// Al massimo 24 ore; una finestra rovesciata la rifiuta il backend con il suo messaggio
|
|
1303
|
+
this.windowClamped = to - from > MAX_WINDOW_MS;
|
|
1304
|
+
e.from = this.windowClamped ? to - MAX_WINDOW_MS : from;
|
|
1305
|
+
e.to = to;
|
|
1306
|
+
e.anchored = Math.abs(Date.now() - to) < ANCHOR_MARGIN_MS;
|
|
1307
|
+
this.load();
|
|
1308
|
+
}
|
|
1309
|
+
setRealTime(realTime) {
|
|
1310
|
+
if (this.current.realTime == realTime)
|
|
1311
|
+
return;
|
|
1312
|
+
this.current.realTime = realTime;
|
|
1313
|
+
this.load();
|
|
1314
|
+
}
|
|
1315
|
+
setDimension(id) {
|
|
1316
|
+
this.current.dimension = +id;
|
|
1317
|
+
this.load(true);
|
|
1318
|
+
}
|
|
1319
|
+
setResolution(id) {
|
|
1320
|
+
this.current.resolution = +id;
|
|
1321
|
+
this.load(true);
|
|
1322
|
+
}
|
|
1323
|
+
togglePause() {
|
|
1324
|
+
this.paused = !this.paused;
|
|
1325
|
+
}
|
|
1326
|
+
get autoRefresh() {
|
|
1327
|
+
return this.refreshSeconds > 0 && !!this.current?.anchored;
|
|
1328
|
+
}
|
|
1329
|
+
get windowLabel() {
|
|
1330
|
+
let e = this.current;
|
|
1331
|
+
if (!e)
|
|
1332
|
+
return "";
|
|
1333
|
+
let sameDay = dayjs(e.from).isSame(dayjs(e.to), "day");
|
|
1334
|
+
let fmtFrom = dayjs(e.from).format(sameDay ? "HH:mm" : "DD/MM HH:mm");
|
|
1335
|
+
let fmtTo = dayjs(e.to).format(sameDay ? "HH:mm" : "DD/MM HH:mm");
|
|
1336
|
+
return `${this.lc.loc("dalle")} ${fmtFrom} ${this.lc.loc("alle")} ${fmtTo} (${this.timeZone()})`;
|
|
1337
|
+
}
|
|
1338
|
+
startTimers() {
|
|
1339
|
+
this.stopTimers();
|
|
1340
|
+
this.tickTimer = setInterval(() => this.now = Date.now(), 1000);
|
|
1341
|
+
if (this.refreshSeconds > 0)
|
|
1342
|
+
this.refreshTimer = setInterval(() => this.autoRefreshTick(), this.refreshSeconds * 1000);
|
|
1343
|
+
}
|
|
1344
|
+
stopTimers() {
|
|
1345
|
+
clearInterval(this.tickTimer);
|
|
1346
|
+
clearInterval(this.refreshTimer);
|
|
1347
|
+
this.tickTimer = null;
|
|
1348
|
+
this.refreshTimer = null;
|
|
1349
|
+
}
|
|
1350
|
+
// Sposta in avanti la finestra della stessa durata, solo se è agganciata ad adesso, non in pausa e il dettaglio si vede
|
|
1351
|
+
autoRefreshTick() {
|
|
1352
|
+
let e = this.current;
|
|
1353
|
+
if (!e || !e.anchored || this.paused || this.loading || !this.visible || document.hidden)
|
|
1354
|
+
return;
|
|
1355
|
+
let length = e.to - e.from;
|
|
1356
|
+
e.to = Date.now();
|
|
1357
|
+
e.from = e.to - length;
|
|
1358
|
+
this.load(true);
|
|
1359
|
+
}
|
|
1360
|
+
syncWindowFields() {
|
|
1361
|
+
let e = this.current;
|
|
1362
|
+
this.filterfrom = this.fmt(new Date(e.from));
|
|
1363
|
+
this.filterto = this.fmt(new Date(e.to));
|
|
1364
|
+
}
|
|
1365
|
+
// #endregion
|
|
1366
|
+
// #region Nodo (N1-N8)
|
|
1367
|
+
get nodeLive() {
|
|
1368
|
+
return !!this.node && this.current?.realTime && this.node.snapDeltaExecutions != null;
|
|
1369
|
+
}
|
|
1370
|
+
buildNodeView() {
|
|
1371
|
+
let n = this.node;
|
|
1372
|
+
if (!n) {
|
|
1373
|
+
this.nodeChart = [];
|
|
1374
|
+
this.nodeChartTimes = [];
|
|
1375
|
+
this.nodeStats = [];
|
|
1376
|
+
this.typeParts = [];
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
this.nodeChartTimes = (n.activeSessions ?? []).map(t => t.timestamp);
|
|
1380
|
+
this.nodeChart = (n.activityByClass ?? []).map(c => ({ ...c, label: c.other ? this.lc.loc("Altri") : c.label }));
|
|
1381
|
+
// minTime vale 0 senza esecuzioni concluse, snapDeltaMinTime null: in tutti e due i casi non c'è un minimo da mostrare
|
|
1382
|
+
this.nodeStats = [
|
|
1383
|
+
{ label: this.lc.loc("Esecuzioni"), total: n.executions, snap: n.snapDeltaExecutions, kind: "int" },
|
|
1384
|
+
{ label: this.lc.loc("Tempo totale"), total: n.elapsedTime, snap: n.snapDeltaElapsedTime, kind: "dur" },
|
|
1385
|
+
{ label: this.lc.loc("Tempo proprio"), total: n.elapsedTimeLessChildren, snap: n.snapDeltaElapsedTimeLessChildren, kind: "dur" },
|
|
1386
|
+
{ label: this.lc.loc("Medio"), total: n.executions ? n.avgTime : null, snap: n.snapDeltaExecutions ? n.snapDeltaAvgTime : null, kind: "dur" },
|
|
1387
|
+
{ label: this.lc.loc("Massimo"), total: n.executions ? n.peakTime : null, snap: n.snapDeltaExecutions ? n.snapDeltaPeakTime : null, kind: "dur" },
|
|
1388
|
+
{ label: this.lc.loc("Minimo"), total: n.executions ? n.minTime : null, snap: n.snapDeltaMinTime, kind: "dur" }
|
|
1389
|
+
];
|
|
1390
|
+
this.typeParts = [
|
|
1391
|
+
{ label: "CPU", color: FIXED_COLORS.Cpu, percentage: n.cpuPerc, idle: false },
|
|
1392
|
+
{ label: "Database", color: FIXED_COLORS.Database, percentage: n.dbPerc, idle: false },
|
|
1393
|
+
{ label: "Wait", color: FIXED_COLORS.Wait, percentage: n.waitPerc, idle: false },
|
|
1394
|
+
{ label: "Script", color: FIXED_COLORS.Script, percentage: n.scriptPerc, idle: false },
|
|
1395
|
+
{ label: "IO", color: FIXED_COLORS.IO, percentage: n.ioPerc, idle: false },
|
|
1396
|
+
{ label: "Network", color: FIXED_COLORS.Network, percentage: n.networkPerc, idle: false },
|
|
1397
|
+
{ label: "Throttle", color: FIXED_COLORS.Throttle, percentage: n.throttlePerc, idle: false },
|
|
1398
|
+
{ label: "Sleep", color: FIXED_COLORS.Sleep, percentage: n.sleepPerc, idle: false },
|
|
1399
|
+
{ label: "Idle", color: OTHER_COLOR, percentage: n.idlePerc, idle: true }
|
|
1400
|
+
].filter(t => (t.percentage ?? 0) > 0);
|
|
1401
|
+
}
|
|
1402
|
+
// Con lo storico, la parte del grafico prima dei campioni in memoria ha meno risoluzione: la pagina la segnala
|
|
1403
|
+
get nodeHistoryBefore() {
|
|
1404
|
+
let n = this.node;
|
|
1405
|
+
if (!n || this.current?.realTime || !n.memoryFrom)
|
|
1406
|
+
return null;
|
|
1407
|
+
let memory = parseUtc(n.memoryFrom)?.getTime();
|
|
1408
|
+
let from = parseUtc(n.activityFrom)?.getTime();
|
|
1409
|
+
let to = parseUtc(n.activityTo)?.getTime();
|
|
1410
|
+
return memory > from && memory < to ? this.localTime(n.memoryFrom) : null;
|
|
1411
|
+
}
|
|
1412
|
+
copyName() {
|
|
1413
|
+
navigator.clipboard?.writeText(this.node?.nodeName ?? "").then(() => {
|
|
1414
|
+
this.copied = true;
|
|
1415
|
+
setTimeout(() => this.copied = false, 1500);
|
|
1416
|
+
});
|
|
1417
|
+
}
|
|
1418
|
+
showSessions() {
|
|
1419
|
+
let e = this.current;
|
|
1420
|
+
this.sessionsOnEvent.emit({ nodeId: this.node.nodeId, nodeName: this.node.nodeName, from: new Date(e.from), to: new Date(e.to) });
|
|
1421
|
+
}
|
|
1422
|
+
// #endregion
|
|
1423
|
+
// #region Sessione (S1-S6)
|
|
1424
|
+
buildSessionView() {
|
|
1425
|
+
let ta = this.session?.topActivity;
|
|
1426
|
+
let fixed = ta?.dimension == TopActivityDimension.WaitClass || ta?.dimension == TopActivityDimension.EventType;
|
|
1427
|
+
this.colors = {};
|
|
1428
|
+
this.sessionChart = (ta?.components ?? []).map((c, i) => {
|
|
1429
|
+
if (c.key != null)
|
|
1430
|
+
this.colors[c.key] = componentColor(c.key, c.other, i, fixed);
|
|
1431
|
+
return { ...c, label: this.valueLabel(c.label, c.other, ta.dimension) };
|
|
1432
|
+
});
|
|
1433
|
+
// Nell'ordine della specifica: eventi, thread, API
|
|
1434
|
+
let order = [TopActivityDimension.WaitEvent, TopActivityDimension.Thread, TopActivityDimension.Api];
|
|
1435
|
+
this.sessionTables = order.map(d => ta?.tables?.find(t => t.dimension == d)).filter(t => !!t);
|
|
1436
|
+
}
|
|
1437
|
+
get sessionFixedColors() {
|
|
1438
|
+
let d = this.session?.topActivity?.dimension;
|
|
1439
|
+
return d == TopActivityDimension.WaitClass || d == TopActivityDimension.EventType;
|
|
1440
|
+
}
|
|
1441
|
+
tableTitle(table) {
|
|
1442
|
+
switch (table.dimension) {
|
|
1443
|
+
case TopActivityDimension.WaitEvent: return this.lc.loc("Eventi");
|
|
1444
|
+
case TopActivityDimension.Thread: return "Thread";
|
|
1445
|
+
case TopActivityDimension.Api: return "API";
|
|
1446
|
+
}
|
|
1447
|
+
return String(table.dimension);
|
|
1448
|
+
}
|
|
1449
|
+
itemLabel(item, table) {
|
|
1450
|
+
return this.valueLabel(item.label, item.other, table.dimension);
|
|
1451
|
+
}
|
|
1452
|
+
isItemClickable(item, table) {
|
|
1453
|
+
if (item.other)
|
|
1454
|
+
return false;
|
|
1455
|
+
if (table.dimension == TopActivityDimension.WaitEvent)
|
|
1456
|
+
return !!item.event?.eventId;
|
|
1457
|
+
return table.dimension == TopActivityDimension.Thread && this.isThreadAlive(this.tidOf(item.key));
|
|
1458
|
+
}
|
|
1459
|
+
// Una riga evento apre il nodo; una riga thread evidenzia il thread fra quelli di adesso
|
|
1460
|
+
itemClicked(item, table) {
|
|
1461
|
+
if (!this.isItemClickable(item, table))
|
|
1462
|
+
return;
|
|
1463
|
+
if (table.dimension == TopActivityDimension.WaitEvent)
|
|
1464
|
+
this.pushNode(item.event.eventId);
|
|
1465
|
+
else
|
|
1466
|
+
this.highlightedTid = this.tidOf(item.key);
|
|
1467
|
+
}
|
|
1468
|
+
breakdownWidth(item, part) {
|
|
1469
|
+
return item.activity ? part.activity / item.activity * 100 : 0;
|
|
1470
|
+
}
|
|
1471
|
+
breakdownColor(part) {
|
|
1472
|
+
return part.other || part.key == null ? OTHER_COLOR : this.colors[part.key] ?? FIXED_COLORS[part.key] ?? OTHER_COLOR;
|
|
1473
|
+
}
|
|
1474
|
+
toggleThread(thread) {
|
|
1475
|
+
this.expandedTid = this.expandedTid == thread.tid ? null : thread.tid;
|
|
1476
|
+
}
|
|
1477
|
+
// Tempo nell'evento corrente: parte da waitTime e avanza fino al prossimo aggiornamento
|
|
1478
|
+
runningSeconds(thread) {
|
|
1479
|
+
return thread.inWait ? (thread.waitTime ?? 0) + Math.max(0, this.now - this.loadedAt) / 1000 : null;
|
|
1480
|
+
}
|
|
1481
|
+
progress(op) {
|
|
1482
|
+
return op.totalWork ? Math.min(100, op.soFar / op.totalWork * 100) : 0;
|
|
1483
|
+
}
|
|
1484
|
+
connectedFor() {
|
|
1485
|
+
let start = parseUtc(this.session?.startTime);
|
|
1486
|
+
return start ? Math.max(0, (this.now - start.getTime()) / 1000) : null;
|
|
1487
|
+
}
|
|
1488
|
+
tidOf(key) {
|
|
1489
|
+
let tid = parseInt((key ?? "").split("@")[0], 10);
|
|
1490
|
+
return isNaN(tid) ? null : tid;
|
|
1491
|
+
}
|
|
1492
|
+
isThreadAlive(tid) {
|
|
1493
|
+
return tid != null && !!this.session?.connected && (this.session.threads ?? []).some(t => t.tid == tid);
|
|
1494
|
+
}
|
|
1495
|
+
// #endregion
|
|
1496
|
+
// #region Supporto
|
|
1497
|
+
localTime(value) {
|
|
1498
|
+
let date = parseUtc(value);
|
|
1499
|
+
return date ? dayjs(date).format("DD/MM/YYYY HH:mm:ss") : "";
|
|
1500
|
+
}
|
|
1501
|
+
shortTime(value) {
|
|
1502
|
+
let date = parseUtc(value);
|
|
1503
|
+
return date ? dayjs(date).format("HH:mm") : "";
|
|
1504
|
+
}
|
|
1505
|
+
// Colore del tipo di evento, o della classe per i wait, come nel grafico della Top Activity
|
|
1506
|
+
typeColor(type, waitClass) {
|
|
1507
|
+
return FIXED_COLORS[waitClass && waitClass != "None" ? waitClass : type] ?? OTHER_COLOR;
|
|
1508
|
+
}
|
|
1509
|
+
typeLabel(type, waitClass) {
|
|
1510
|
+
return waitClass && waitClass != "None" ? `${type} · ${waitClass}` : type;
|
|
1511
|
+
}
|
|
1512
|
+
valueLabel(label, other, dimension) {
|
|
1513
|
+
if (other)
|
|
1514
|
+
return this.lc.loc("Altri");
|
|
1515
|
+
if (label == null || label === "")
|
|
1516
|
+
return this.lc.loc(dimension == TopActivityDimension.WaitEvent ? "(non attribuito)" : "(nessuno)");
|
|
1517
|
+
return label;
|
|
1518
|
+
}
|
|
1519
|
+
timeZone() {
|
|
1520
|
+
let minutes = -new Date().getTimezoneOffset();
|
|
1521
|
+
let sign = minutes >= 0 ? "+" : "-";
|
|
1522
|
+
let abs = Math.abs(minutes);
|
|
1523
|
+
return `UTC${sign}${Math.floor(abs / 60)}${abs % 60 ? ":" + String(abs % 60).padStart(2, "0") : ""}`;
|
|
1524
|
+
}
|
|
1525
|
+
toDate(value) {
|
|
1526
|
+
return value ? this.dateExts.getDateConvertion(value).toDate() : null;
|
|
1527
|
+
}
|
|
1528
|
+
fmt(date) {
|
|
1529
|
+
return dayjs(date).format(this.lc.token("getFullDateDisplayFormat"));
|
|
1530
|
+
}
|
|
1531
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Component, deps: [{ token: i1.LocalizationService }, { token: i1$1.DateService }, { token: AdminModuleBaseService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1532
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmDetailsV2Component, isStandalone: false, selector: "adm-details-v2", inputs: { Be: "Be", CanShowSessions: "CanShowSessions", CanOpenProfiler: "CanOpenProfiler" }, outputs: { closed: "closed", sessionsOnEvent: "sessionsOnEvent", openProfiler: "openProfiler" }, providers: [{ provide: LocalizationService, useClass: AdmDetailsV2Loc }], ngImport: i0, template: "<div class=\"modal-dialog modal-xl\" emaDraggable>\n <div class=\"modal-content\">\n <!-- Navigazione: \"Indietro\" torna al dettaglio precedente con la sua finestra (D1) -->\n <div class=\"modal-header dv2-header\">\n <div class=\"dv2-heading\">\n @if (stack.length > 1) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" (click)=\"back()\"><i class=\"fa fa-arrow-left\"></i> {{'Indietro' | localize: lc}}</button>\n }\n <h4 class=\"modal-title\">\n @if (current?.kind == 'node') {\n {{'Dettaglio nodo' | localize: lc}}\n } @else if (current) {\n {{'Sessione' | localize: lc}} {{current.sid}},{{current.serial}}\n @if (current.instanceId) {\n <span class=\"dv2-muted\">· {{current.instanceId}}</span>\n }\n }\n </h4>\n </div>\n <button type=\"button\" class=\"close\" (click)=\"close()\" aria-label=\"Close\"><span aria-hidden=\"true\">×</span></button>\n </div>\n\n <div class=\"modal-body\">\n @if (current) {\n <!-- Finestra, sorgente, aggiornamento (D2, D3, D5) -->\n <div class=\"dv2-toolbar\">\n <div class=\"dv2-group\">\n <span class=\"dv2-window\"><i class=\"fa fa-clock\"></i> {{windowLabel}}</span>\n <div class=\"dv2-seg\">\n @for (h of QuickRanges; track h) {\n <button type=\"button\" (click)=\"quickRange(h)\" [title]=\"'Ultime' | localize: lc\">{{h}} h</button>\n }\n </div>\n </div>\n <div class=\"dv2-group dv2-dates\">\n <div class=\"dv2-field\"><form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterfrom\" name=\"dv2from\" [Placeholder]=\"'Da' | localize: lc\"></form-datetime></div>\n <div class=\"dv2-field\"><form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterto\" name=\"dv2to\" [Placeholder]=\"'A' | localize: lc\"></form-datetime></div>\n <button type=\"button\" class=\"btn app-btn-search\" [disabled]=\"loading\" (click)=\"applyDates()\" [title]=\"'Applica' | localize: lc\"><i class=\"fa fa-search\"></i></button>\n </div>\n <div class=\"dv2-seg\">\n @if (current.kind == 'session') {\n <button type=\"button\" [class.dv2-on]=\"current.realTime\" (click)=\"setRealTime(true)\">{{'Memoria' | localize: lc}}</button>\n <button type=\"button\" [class.dv2-on]=\"!current.realTime\" (click)=\"setRealTime(false)\">{{'Memoria e storico' | localize: lc}}</button>\n } @else {\n <button type=\"button\" [class.dv2-on]=\"current.realTime\" (click)=\"setRealTime(true)\">{{'Dal vivo' | localize: lc}}</button>\n <button type=\"button\" [class.dv2-on]=\"!current.realTime\" (click)=\"setRealTime(false)\">{{'Storico' | localize: lc}}</button>\n }\n </div>\n <div class=\"dv2-group dv2-end\">\n @if (loading) {\n <i class=\"fa fa-spinner fa-spin\"></i>\n }\n @if (updatedAt) {\n <span class=\"dv2-muted\">{{'Aggiornato alle' | localize: lc}} {{updatedAt | date: 'HH:mm:ss'}}</span>\n }\n @if (autoRefresh) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" (click)=\"togglePause()\">\n <i class=\"fa\" [class.fa-pause]=\"!paused\" [class.fa-play]=\"paused\"></i> {{(paused ? 'Riprendi' : 'Pausa') | localize: lc}}\n </button>\n }\n </div>\n </div>\n @if (windowClamped) {\n <div class=\"dv2-note\"><i class=\"fa fa-info-circle\"></i> {{'La finestra \u00E8 stata ridotta alle ultime 24 ore' | localize: lc}}</div>\n }\n\n <!-- Stati (D6) -->\n @if (error) {\n <div class=\"alert alert-warning dv2-state\">{{error}}</div>\n } @else if (notFound && !loading) {\n <div class=\"alert alert-info dv2-state\">\n {{(current.kind == 'node' ? 'Nodo non trovato' : 'Sessione non trovata: non esiste pi\u00F9 e nella finestra non era attiva') | localize: lc}}\n </div>\n } @else if (loading && !node && !session) {\n <div class=\"dv2-empty\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Carico i Dati' | localize: lc}}</div>\n }\n\n <!-- ==================== Nodo ==================== -->\n @if (node && current.kind == 'node') {\n <!-- N1 Intestazione -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-node-name\">{{node.nodeName}}</div>\n <div class=\"dv2-meta\">\n <span><span class=\"dv2-swatch\" [style.background]=\"typeColor(node.eventTypeName, node.waitClassName)\"></span>{{typeLabel(node.eventTypeName, node.waitClassName)}}</span>\n <span class=\"dv2-muted\">Id <code>{{node.nodeId}}</code></span>\n <button type=\"button\" class=\"btn btn-sm btn-link\" (click)=\"copyName()\"><i class=\"fa\" [class.fa-copy]=\"!copied\" [class.fa-check]=\"copied\"></i> {{(copied ? 'Copiato' : 'Copia') | localize: lc}}</button>\n </div>\n @if (node.fullWaitStack?.length) {\n <div class=\"dv2-path\">\n @for (item of node.fullWaitStack; track item.nodeId) {\n <span class=\"app-link dv2-path-item\" [title]=\"item.nodeName\" (click)=\"pushNode(item.nodeId)\">{{item.nodeName}}</span>\n <i class=\"fa fa-angle-right dv2-muted\"></i>\n }\n <span class=\"dv2-path-item dv2-path-current\" [title]=\"node.nodeName\">{{node.nodeName}}</span>\n </div>\n }\n <div class=\"dv2-actions\">\n @if (CanOpenProfiler) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-primary\" (click)=\"openProfiler.emit(node.nodeId)\"><i class=\"fa fa-sitemap\"></i> {{'Apri nel profiler' | localize: lc}}</button>\n }\n @if (CanShowSessions) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-primary\" (click)=\"showSessions()\" [title]=\"(node.numChildren > 0 ? 'Solo l\\'evento esatto: il lavoro dei discendenti non \u00E8 compreso' : 'Top Activity filtrata su questo evento') | localize: lc\">\n <i class=\"fa fa-users\"></i> {{'Sessioni su questo evento' | localize: lc}}\n </button>\n @if (node.numChildren > 0) {\n <span class=\"dv2-muted\">{{'discendenti esclusi' | localize: lc}}</span>\n }\n }\n </div>\n </div>\n\n <div class=\"dv2-grid\">\n <!-- N2 Statistiche -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Statistiche' | localize: lc}}</div>\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th></th>\n @if (nodeLive) {\n <th class=\"dv2-right\">{{'Dall\\'avvio' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Dall\\'ultimo snapshot' | localize: lc}} <span class=\"dv2-muted\">({{'dalle' | localize: lc}} {{shortTime(node.snapFrom)}})</span></th>\n } @else {\n <th class=\"dv2-right\">{{'Nella finestra' | localize: lc}} <span class=\"dv2-muted\">({{shortTime(node.snapFrom)}} - {{shortTime(node.snapTo)}})</span></th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of nodeStats; track row.label) {\n <tr>\n <td>{{row.label}}</td>\n <td class=\"dv2-right\">{{row.total == null ? '\u2014' : (row.total | pv2fmt: row.kind)}}</td>\n @if (nodeLive) {\n <td class=\"dv2-right\">{{row.snap == null ? '\u2014' : (row.snap | pv2fmt: row.kind)}}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n @if (nodeLive) {\n <div class=\"dv2-live\">\n <span>{{'Thread dentro adesso' | localize: lc}} <strong>{{node.activeThreads ?? 0}}</strong></span>\n <span>{{'In corso da' | localize: lc}} <strong>{{node.activeMaxTime ? (node.activeMaxTime | pv2fmt: 'dur') : '\u2014'}}</strong></span>\n <span>{{'Ultima uscita' | localize: lc}} <strong>{{node.lastExitTime ? localTime(node.lastExitTime) : '\u2014'}}</strong></span>\n </div>\n }\n </div>\n\n <!-- N4 Dove va il tempo -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Dove va il tempo' | localize: lc}} <span class=\"dv2-muted\">{{'tempo proprio del sottoalbero' | localize: lc}}</span></div>\n <div class=\"dv2-typebar\">\n @for (part of typeParts; track part.label) {\n <div [style.width.%]=\"part.percentage\" [style.background]=\"part.color\" [class.dv2-idle]=\"part.idle\" [title]=\"part.label + ' ' + (part.percentage | number : '1.1-1' : 'it') + '%'\"></div>\n }\n </div>\n <div class=\"dv2-legend\">\n @for (part of typeParts; track part.label) {\n <span><span class=\"dv2-swatch\" [class.dv2-idle]=\"part.idle\" [style.background]=\"part.color\"></span>{{part.label}} <span class=\"dv2-muted\">{{part.percentage | number : '1.1-1' : 'it'}}%</span></span>\n }\n </div>\n @if (typeParts.length && typeParts[typeParts.length - 1].idle) {\n <div class=\"dv2-muted dv2-small\">{{'Idle \u00E8 tempo di attesa senza lavoro' | localize: lc}}</div>\n }\n\n <!-- N3 Per istanza -->\n @if ((node.instances?.length ?? 0) > 1) {\n <div class=\"dv2-title dv2-spaced\">{{'Per istanza' | localize: lc}}</div>\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th>{{'Istanza' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Esecuzioni' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Tempo' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Tempo proprio' | localize: lc}}</th>\n @if (nodeLive) {\n <th class=\"dv2-right\">{{'Thread attivi' | localize: lc}}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (inst of node.instances; track inst.instanceId) {\n <tr>\n <td class=\"app-nowrap\">{{inst.instanceId}}</td>\n <td class=\"dv2-right\">{{inst.executions | pv2fmt: 'int'}}</td>\n <td class=\"dv2-right\">{{inst.elapsedTime | pv2fmt: 'dur'}}</td>\n <td class=\"dv2-right\">{{inst.elapsedTimeLessChildren | pv2fmt: 'dur'}}</td>\n @if (nodeLive) {\n <td class=\"dv2-right\">{{inst.activeThreads ?? 0}}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n }\n </div>\n </div>\n\n <!-- N6 Attivit\u00E0 nel tempo -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">\n {{'Attivit\u00E0 nel tempo' | localize: lc}}\n <span class=\"dv2-muted\">\u2248 <strong>{{node.averageActiveSessions | number : '1.2-3' : 'it'}}</strong> {{'sessioni attive medie' | localize: lc}} · {{'picco' | localize: lc}} <strong>{{node.peakActiveSessions | number : '1.2-3' : 'it'}}</strong> · {{'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}} · {{'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\"> · {{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 · {{'Picco' | localize: lc}} <strong>{{session.topActivity.estimated ? '\u2248 ' : ''}}{{session.topActivity.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\n · {{'un punto ogni' | localize: lc}} {{session.topActivity.bucketSeconds}} s\n </span>\n @if (session.topActivity.estimated) {\n <span class=\"dv2-estimate\">{{'stima per campionamento' | localize: lc}}</span>\n }\n }\n </span>\n <div class=\"dv2-group\">\n <div class=\"dv2-field dv2-field-wide dv2-noclear\">\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"'' + current.dimension\" (ngModelChange)=\"setDimension($event)\" name=\"dv2dim\" [Source]=\"Dimensions\" [Placeholder]=\"'Dividi per' | localize: lc\"></form-select>\n </div>\n <div class=\"dv2-seg\">\n @for (o of Resolutions; track o.id) {\n <button type=\"button\" [class.dv2-on]=\"'' + current.resolution == o.id\" (click)=\"setResolution(o.id)\">{{o.description}}</button>\n }\n </div>\n </div>\n </div>\n <activity-chart-v2 [Times]=\"session.topActivity?.times\" [Components]=\"sessionChart\" [BucketSeconds]=\"session.topActivity?.bucketSeconds\" [FixedColors]=\"sessionFixedColors\"\n [Uom]=\"'sessioni' | localize: lc\" [EmptyText]=\"'Nessuna attivit\u00E0 nella finestra' | localize: lc\" name=\"dv2sessionchart\"></activity-chart-v2>\n </div>\n\n <!-- S3 Tabelle: eventi, thread, API -->\n <div class=\"dv2-tables\">\n @for (table of sessionTables; track table.dimension) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">\n {{tableTitle(table)}}@if (table.estimated) { \u2248}\n <span class=\"dv2-muted\">{{'Attivit\u00E0' | localize: lc}} <strong>{{table.estimated ? '\u2248 ' : ''}}{{table.activity | number : '1.2-3' : 'it'}}</strong></span>\n </div>\n <table class=\"table table-sm dv2-table\">\n <tbody>\n @for (item of table.items; track $index) {\n <tr [class.dv2-highlight]=\"table.dimension == Dim.Thread && highlightedTid != null && item.key?.startsWith(highlightedTid + '@')\">\n <td>\n @if (isItemClickable(item, table)) {\n <span class=\"app-link dv2-ellipsis\" [title]=\"item.label || item.key\" (click)=\"itemClicked(item, table)\">{{itemLabel(item, table)}}</span>\n } @else {\n <span class=\"dv2-ellipsis\" [class.dv2-muted]=\"item.other || !item.label\" [title]=\"item.label || ''\">{{itemLabel(item, table)}}</span>\n }\n </td>\n <td class=\"app-nowrap\">\n <div class=\"dv2-bar-cell\">\n <div class=\"dv2-bar\">\n @for (part of item.breakdown; track $index) {\n <div [style.width.%]=\"breakdownWidth(item, part)\" [style.background]=\"breakdownColor(part)\" [title]=\"part.key\"></div>\n }\n </div>\n <span>{{table.estimated ? '\u2248 ' : ''}}{{item.activity | number : '1.2-3' : 'it'}}</span>\n </div>\n </td>\n <td class=\"dv2-right app-nowrap\">{{item.percentage | number : '1.1-1' : 'it'}}%</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n\n <!-- S4 Thread adesso -->\n @if (session.connected && session.threads?.length) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Thread adesso' | localize: lc}}</div>\n <div class=\"dv2-scroll\">\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th></th>\n <th>TID</th>\n <th>{{'Nome' | localize: lc}}</th>\n <th>{{'Tipo' | localize: lc}}</th>\n <th>{{'Stato' | localize: lc}}</th>\n <th>{{'Priorit\u00E0' | localize: lc}}</th>\n <th>API</th>\n <th>{{'Macchina' | localize: lc}}</th>\n <th>{{'Evento corrente' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'In corso da' | localize: lc}}</th>\n <th>p1 - p3</th>\n </tr>\n </thead>\n <tbody>\n @for (thread of session.threads; track thread.tid) {\n <tr [class.dv2-highlight]=\"thread.tid == highlightedTid\">\n <td><button type=\"button\" class=\"btn btn-sm btn-link dv2-toggle\" (click)=\"toggleThread(thread)\" [title]=\"'Pila completa degli eventi' | localize: lc\"><i class=\"fa\" [class.fa-caret-right]=\"expandedTid != thread.tid\" [class.fa-caret-down]=\"expandedTid == thread.tid\"></i></button></td>\n <td>{{thread.tid}}</td>\n <td class=\"app-nowrap\">{{thread.name}}</td>\n <td class=\"app-nowrap\">{{thread.type}}</td>\n <td>{{thread.currentStatus}}</td>\n <td>{{thread.priority}}</td>\n <td><span class=\"dv2-ellipsis dv2-ellipsis-short\" [title]=\"thread.currentApi || ''\">{{thread.currentApi}}</span></td>\n <td>{{thread.machineName}}</td>\n <td>\n @if (thread.inWait && thread.currentWaitNodeId) {\n <span class=\"app-link dv2-ellipsis\" [title]=\"thread.currentWait\" (click)=\"pushNode(thread.currentWaitNodeId)\">{{thread.currentWait}}</span>\n <span class=\"dv2-muted\">{{typeLabel(thread.waitEventTypeName, thread.waitClassName)}}</span>\n } @else {\n <span class=\"dv2-muted\">{{'nessun evento in corso' | localize: lc}}</span>\n }\n </td>\n <td class=\"dv2-right app-nowrap\">{{thread.inWait ? (runningSeconds(thread) | pv2fmt: 'dur') : '\u2014'}}</td>\n <td class=\"dv2-muted\"><span class=\"dv2-ellipsis dv2-ellipsis-short\" [title]=\"[thread.waitParam1, thread.waitParam2, thread.waitParam3].join(' \u00B7 ')\">{{[thread.waitParam1, thread.waitParam2, thread.waitParam3].join(' \u00B7 ')}}</span></td>\n </tr>\n @if (expandedTid == thread.tid) {\n <tr class=\"dv2-stack-row\">\n <td colspan=\"11\"><pre class=\"dv2-stack\">{{thread.fullWaitStack || ('Nessun evento' | localize: lc)}}</pre></td>\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n\n <!-- S5 Operazioni lunghe -->\n @if (session.connected && session.longOps?.length) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Operazioni lunghe' | localize: lc}}</div>\n @for (op of session.longOps; track $index) {\n <div class=\"dv2-longop\">\n <div class=\"dv2-meta\">\n <strong>{{op.opName}}</strong>\n <span>{{op.target}} @if (op.targetDesc) {<span class=\"dv2-muted\">({{op.targetDesc}})</span>}</span>\n <span class=\"dv2-muted\">Thread {{op.tid}}</span>\n </div>\n <div class=\"dv2-progress\"><div [style.width.%]=\"progress(op)\"></div></div>\n <div class=\"dv2-meta dv2-small\">\n <span>{{op.soFar | number : '1.0-0' : 'it'}} {{'di' | localize: lc}} {{op.totalWork | number : '1.0-0' : 'it'}} {{op.units}} ({{progress(op) | number : '1.0-1' : 'it'}}%)</span>\n <span>{{'Trascorso' | localize: lc}} {{op.elapsedSeconds | pv2fmt: 'dur'}}</span>\n <span>{{'Alla fine' | localize: lc}} {{op.timeRemaining == null ? ('non stimabile' | localize: lc) : (op.timeRemaining | pv2fmt: 'dur')}}</span>\n @if (op.message) {\n <span class=\"dv2-muted\">{{op.message}}</span>\n }\n </div>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n </div>\n</div>\n", styles: [":host{display:block}:host ::ng-deep .dv2-noclear .p-select-clear-icon{display:none}.dv2-header{align-items:center}.dv2-heading{display:flex;flex:1 1 auto;align-items:center;gap:12px;min-width:0}.dv2-heading .btn{flex:none;white-space:nowrap}.dv2-heading .modal-title{margin:0;overflow-wrap:anywhere}.dv2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px 18px;padding-top:6px}.dv2-group{display:flex;align-items:center;gap:8px}.dv2-end{margin-left:auto}.dv2-window{font-weight:600;white-space:nowrap}.dv2-field{width:170px}.dv2-field-wide{width:200px}.dv2-seg{display:inline-flex;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden}.dv2-seg button{border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;padding:4px 10px;font-size:12px;white-space:nowrap;cursor:pointer}.dv2-seg button:first-child{border-left:0}.dv2-seg button.dv2-on{background:var(--p-primary-color, #6366f1);color:#fff}.dv2-panel{margin-top:12px;padding:10px 12px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);min-width:0}.dv2-title{font-weight:600;margin-bottom:6px}.dv2-title .dv2-muted{font-weight:400;margin-left:8px}.dv2-spaced{margin-top:14px}.dv2-chart-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px 14px;padding-top:6px;margin-bottom:6px}.dv2-muted{color:var(--p-text-muted-color, #64748b);font-size:12px}.dv2-small{font-size:12px}.dv2-note{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.dv2-state{margin:12px 0 0}.dv2-empty{padding:40px 0;text-align:center;color:var(--p-text-muted-color, #64748b)}.dv2-estimate{display:inline-block;margin-left:6px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;font-weight:400}.dv2-badge{display:inline-block;padding:1px 8px;border-radius:10px;background:#dcfce7;color:#166534;font-size:12px;font-weight:600}.dv2-badge-off{background:#fee2e2;color:#991b1b}.dv2-node-name{font-family:var(--p-font-family-mono, Consolas, monospace);font-size:13px;white-space:pre-wrap;word-break:break-word;max-height:160px;overflow:auto}.dv2-meta{display:flex;flex-wrap:wrap;align-items:center;gap:4px 16px;margin-top:6px}.dv2-session-head{margin-top:0}.dv2-path{display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px;margin-top:8px;font-size:12px}.dv2-path-item{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dv2-path-current{font-weight:600}.dv2-actions{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:10px}.dv2-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:0 12px}@media(max-width:991px){.dv2-grid{grid-template-columns:minmax(0,1fr)}}.dv2-table{margin-bottom:0;font-size:12px}.dv2-table th{font-weight:600;white-space:nowrap}.dv2-table td{vertical-align:middle}.dv2-right{text-align:right}.dv2-live{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:8px;font-size:12px}.dv2-typebar{display:flex;height:14px;border-radius:3px;overflow:hidden;background:var(--p-content-border-color, #e2e8f0)}.dv2-idle{background-image:repeating-linear-gradient(45deg,rgba(255,255,255,.55) 0 3px,transparent 3px 6px)}.dv2-legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin-top:6px;font-size:12px}.dv2-swatch{display:inline-block;width:10px;height:10px;margin-right:5px;border-radius:2px;vertical-align:-1px}.dv2-tables{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:0 12px}.dv2-tables .dv2-table{table-layout:fixed;width:100%}.dv2-tables .dv2-table td:nth-child(2){width:120px}.dv2-tables .dv2-table td:nth-child(3){width:58px}.dv2-tables .dv2-ellipsis{display:block;max-width:100%}.dv2-ellipsis{display:inline-block;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.dv2-ellipsis-short{max-width:160px}.dv2-ellipsis+.dv2-muted{margin-left:6px}.dv2-bar-cell{display:flex;align-items:center;gap:8px}.dv2-bar{display:flex;flex:none;width:70px;height:8px;border-radius:2px;overflow:hidden;background:var(--p-content-border-color, #e2e8f0)}.dv2-highlight>td{background:#eef2ff}.dv2-scroll{overflow-x:auto}.dv2-toggle{padding:0 4px}.dv2-stack-row>td{border-top:0}.dv2-stack{margin:0;padding:8px;max-height:240px;overflow:auto;border-radius:4px;background:#f8fafc;font-size:11px;white-space:pre}.dv2-longop+.dv2-longop{margin-top:12px}.dv2-progress{height:8px;margin-top:6px;border-radius:4px;overflow:hidden;background:var(--p-content-border-color, #e2e8f0)}.dv2-progress div{height:100%;background:var(--p-primary-color, #6366f1)}\n"], dependencies: [{ kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i9.EsFormSelectComponent, selector: "form-select", inputs: ["OptionsTemplate"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "directive", type: i10.Draggable, selector: "[emaDraggable]", inputs: ["emaDraggable"] }, { kind: "component", type: ActivityChartV2Component, selector: "activity-chart-v2", inputs: ["Times", "Components", "BucketSeconds", "FixedColors", "Uom", "EmptyText", "name"] }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }, { kind: "pipe", type: i5.TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: i5.DatePipe, name: "date" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }, { kind: "pipe", type: ProfilerFormatPipe, name: "pv2fmt" }] }); }
|
|
1533
|
+
}
|
|
1534
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmDetailsV2Component, decorators: [{
|
|
1535
|
+
type: Component,
|
|
1536
|
+
args: [{ selector: "adm-details-v2", providers: [{ provide: LocalizationService, useClass: AdmDetailsV2Loc }], standalone: false, template: "<div class=\"modal-dialog modal-xl\" emaDraggable>\n <div class=\"modal-content\">\n <!-- Navigazione: \"Indietro\" torna al dettaglio precedente con la sua finestra (D1) -->\n <div class=\"modal-header dv2-header\">\n <div class=\"dv2-heading\">\n @if (stack.length > 1) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" (click)=\"back()\"><i class=\"fa fa-arrow-left\"></i> {{'Indietro' | localize: lc}}</button>\n }\n <h4 class=\"modal-title\">\n @if (current?.kind == 'node') {\n {{'Dettaglio nodo' | localize: lc}}\n } @else if (current) {\n {{'Sessione' | localize: lc}} {{current.sid}},{{current.serial}}\n @if (current.instanceId) {\n <span class=\"dv2-muted\">· {{current.instanceId}}</span>\n }\n }\n </h4>\n </div>\n <button type=\"button\" class=\"close\" (click)=\"close()\" aria-label=\"Close\"><span aria-hidden=\"true\">×</span></button>\n </div>\n\n <div class=\"modal-body\">\n @if (current) {\n <!-- Finestra, sorgente, aggiornamento (D2, D3, D5) -->\n <div class=\"dv2-toolbar\">\n <div class=\"dv2-group\">\n <span class=\"dv2-window\"><i class=\"fa fa-clock\"></i> {{windowLabel}}</span>\n <div class=\"dv2-seg\">\n @for (h of QuickRanges; track h) {\n <button type=\"button\" (click)=\"quickRange(h)\" [title]=\"'Ultime' | localize: lc\">{{h}} h</button>\n }\n </div>\n </div>\n <div class=\"dv2-group dv2-dates\">\n <div class=\"dv2-field\"><form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterfrom\" name=\"dv2from\" [Placeholder]=\"'Da' | localize: lc\"></form-datetime></div>\n <div class=\"dv2-field\"><form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterto\" name=\"dv2to\" [Placeholder]=\"'A' | localize: lc\"></form-datetime></div>\n <button type=\"button\" class=\"btn app-btn-search\" [disabled]=\"loading\" (click)=\"applyDates()\" [title]=\"'Applica' | localize: lc\"><i class=\"fa fa-search\"></i></button>\n </div>\n <div class=\"dv2-seg\">\n @if (current.kind == 'session') {\n <button type=\"button\" [class.dv2-on]=\"current.realTime\" (click)=\"setRealTime(true)\">{{'Memoria' | localize: lc}}</button>\n <button type=\"button\" [class.dv2-on]=\"!current.realTime\" (click)=\"setRealTime(false)\">{{'Memoria e storico' | localize: lc}}</button>\n } @else {\n <button type=\"button\" [class.dv2-on]=\"current.realTime\" (click)=\"setRealTime(true)\">{{'Dal vivo' | localize: lc}}</button>\n <button type=\"button\" [class.dv2-on]=\"!current.realTime\" (click)=\"setRealTime(false)\">{{'Storico' | localize: lc}}</button>\n }\n </div>\n <div class=\"dv2-group dv2-end\">\n @if (loading) {\n <i class=\"fa fa-spinner fa-spin\"></i>\n }\n @if (updatedAt) {\n <span class=\"dv2-muted\">{{'Aggiornato alle' | localize: lc}} {{updatedAt | date: 'HH:mm:ss'}}</span>\n }\n @if (autoRefresh) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-secondary\" (click)=\"togglePause()\">\n <i class=\"fa\" [class.fa-pause]=\"!paused\" [class.fa-play]=\"paused\"></i> {{(paused ? 'Riprendi' : 'Pausa') | localize: lc}}\n </button>\n }\n </div>\n </div>\n @if (windowClamped) {\n <div class=\"dv2-note\"><i class=\"fa fa-info-circle\"></i> {{'La finestra \u00E8 stata ridotta alle ultime 24 ore' | localize: lc}}</div>\n }\n\n <!-- Stati (D6) -->\n @if (error) {\n <div class=\"alert alert-warning dv2-state\">{{error}}</div>\n } @else if (notFound && !loading) {\n <div class=\"alert alert-info dv2-state\">\n {{(current.kind == 'node' ? 'Nodo non trovato' : 'Sessione non trovata: non esiste pi\u00F9 e nella finestra non era attiva') | localize: lc}}\n </div>\n } @else if (loading && !node && !session) {\n <div class=\"dv2-empty\"><i class=\"fa fa-spinner fa-spin\"></i> {{'Carico i Dati' | localize: lc}}</div>\n }\n\n <!-- ==================== Nodo ==================== -->\n @if (node && current.kind == 'node') {\n <!-- N1 Intestazione -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-node-name\">{{node.nodeName}}</div>\n <div class=\"dv2-meta\">\n <span><span class=\"dv2-swatch\" [style.background]=\"typeColor(node.eventTypeName, node.waitClassName)\"></span>{{typeLabel(node.eventTypeName, node.waitClassName)}}</span>\n <span class=\"dv2-muted\">Id <code>{{node.nodeId}}</code></span>\n <button type=\"button\" class=\"btn btn-sm btn-link\" (click)=\"copyName()\"><i class=\"fa\" [class.fa-copy]=\"!copied\" [class.fa-check]=\"copied\"></i> {{(copied ? 'Copiato' : 'Copia') | localize: lc}}</button>\n </div>\n @if (node.fullWaitStack?.length) {\n <div class=\"dv2-path\">\n @for (item of node.fullWaitStack; track item.nodeId) {\n <span class=\"app-link dv2-path-item\" [title]=\"item.nodeName\" (click)=\"pushNode(item.nodeId)\">{{item.nodeName}}</span>\n <i class=\"fa fa-angle-right dv2-muted\"></i>\n }\n <span class=\"dv2-path-item dv2-path-current\" [title]=\"node.nodeName\">{{node.nodeName}}</span>\n </div>\n }\n <div class=\"dv2-actions\">\n @if (CanOpenProfiler) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-primary\" (click)=\"openProfiler.emit(node.nodeId)\"><i class=\"fa fa-sitemap\"></i> {{'Apri nel profiler' | localize: lc}}</button>\n }\n @if (CanShowSessions) {\n <button type=\"button\" class=\"btn btn-sm btn-outline-primary\" (click)=\"showSessions()\" [title]=\"(node.numChildren > 0 ? 'Solo l\\'evento esatto: il lavoro dei discendenti non \u00E8 compreso' : 'Top Activity filtrata su questo evento') | localize: lc\">\n <i class=\"fa fa-users\"></i> {{'Sessioni su questo evento' | localize: lc}}\n </button>\n @if (node.numChildren > 0) {\n <span class=\"dv2-muted\">{{'discendenti esclusi' | localize: lc}}</span>\n }\n }\n </div>\n </div>\n\n <div class=\"dv2-grid\">\n <!-- N2 Statistiche -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Statistiche' | localize: lc}}</div>\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th></th>\n @if (nodeLive) {\n <th class=\"dv2-right\">{{'Dall\\'avvio' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Dall\\'ultimo snapshot' | localize: lc}} <span class=\"dv2-muted\">({{'dalle' | localize: lc}} {{shortTime(node.snapFrom)}})</span></th>\n } @else {\n <th class=\"dv2-right\">{{'Nella finestra' | localize: lc}} <span class=\"dv2-muted\">({{shortTime(node.snapFrom)}} - {{shortTime(node.snapTo)}})</span></th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of nodeStats; track row.label) {\n <tr>\n <td>{{row.label}}</td>\n <td class=\"dv2-right\">{{row.total == null ? '\u2014' : (row.total | pv2fmt: row.kind)}}</td>\n @if (nodeLive) {\n <td class=\"dv2-right\">{{row.snap == null ? '\u2014' : (row.snap | pv2fmt: row.kind)}}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n @if (nodeLive) {\n <div class=\"dv2-live\">\n <span>{{'Thread dentro adesso' | localize: lc}} <strong>{{node.activeThreads ?? 0}}</strong></span>\n <span>{{'In corso da' | localize: lc}} <strong>{{node.activeMaxTime ? (node.activeMaxTime | pv2fmt: 'dur') : '\u2014'}}</strong></span>\n <span>{{'Ultima uscita' | localize: lc}} <strong>{{node.lastExitTime ? localTime(node.lastExitTime) : '\u2014'}}</strong></span>\n </div>\n }\n </div>\n\n <!-- N4 Dove va il tempo -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Dove va il tempo' | localize: lc}} <span class=\"dv2-muted\">{{'tempo proprio del sottoalbero' | localize: lc}}</span></div>\n <div class=\"dv2-typebar\">\n @for (part of typeParts; track part.label) {\n <div [style.width.%]=\"part.percentage\" [style.background]=\"part.color\" [class.dv2-idle]=\"part.idle\" [title]=\"part.label + ' ' + (part.percentage | number : '1.1-1' : 'it') + '%'\"></div>\n }\n </div>\n <div class=\"dv2-legend\">\n @for (part of typeParts; track part.label) {\n <span><span class=\"dv2-swatch\" [class.dv2-idle]=\"part.idle\" [style.background]=\"part.color\"></span>{{part.label}} <span class=\"dv2-muted\">{{part.percentage | number : '1.1-1' : 'it'}}%</span></span>\n }\n </div>\n @if (typeParts.length && typeParts[typeParts.length - 1].idle) {\n <div class=\"dv2-muted dv2-small\">{{'Idle \u00E8 tempo di attesa senza lavoro' | localize: lc}}</div>\n }\n\n <!-- N3 Per istanza -->\n @if ((node.instances?.length ?? 0) > 1) {\n <div class=\"dv2-title dv2-spaced\">{{'Per istanza' | localize: lc}}</div>\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th>{{'Istanza' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Esecuzioni' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Tempo' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'Tempo proprio' | localize: lc}}</th>\n @if (nodeLive) {\n <th class=\"dv2-right\">{{'Thread attivi' | localize: lc}}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (inst of node.instances; track inst.instanceId) {\n <tr>\n <td class=\"app-nowrap\">{{inst.instanceId}}</td>\n <td class=\"dv2-right\">{{inst.executions | pv2fmt: 'int'}}</td>\n <td class=\"dv2-right\">{{inst.elapsedTime | pv2fmt: 'dur'}}</td>\n <td class=\"dv2-right\">{{inst.elapsedTimeLessChildren | pv2fmt: 'dur'}}</td>\n @if (nodeLive) {\n <td class=\"dv2-right\">{{inst.activeThreads ?? 0}}</td>\n }\n </tr>\n }\n </tbody>\n </table>\n }\n </div>\n </div>\n\n <!-- N6 Attivit\u00E0 nel tempo -->\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">\n {{'Attivit\u00E0 nel tempo' | localize: lc}}\n <span class=\"dv2-muted\">\u2248 <strong>{{node.averageActiveSessions | number : '1.2-3' : 'it'}}</strong> {{'sessioni attive medie' | localize: lc}} · {{'picco' | localize: lc}} <strong>{{node.peakActiveSessions | number : '1.2-3' : 'it'}}</strong> · {{'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}} · {{'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\"> · {{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 · {{'Picco' | localize: lc}} <strong>{{session.topActivity.estimated ? '\u2248 ' : ''}}{{session.topActivity.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\n · {{'un punto ogni' | localize: lc}} {{session.topActivity.bucketSeconds}} s\n </span>\n @if (session.topActivity.estimated) {\n <span class=\"dv2-estimate\">{{'stima per campionamento' | localize: lc}}</span>\n }\n }\n </span>\n <div class=\"dv2-group\">\n <div class=\"dv2-field dv2-field-wide dv2-noclear\">\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"'' + current.dimension\" (ngModelChange)=\"setDimension($event)\" name=\"dv2dim\" [Source]=\"Dimensions\" [Placeholder]=\"'Dividi per' | localize: lc\"></form-select>\n </div>\n <div class=\"dv2-seg\">\n @for (o of Resolutions; track o.id) {\n <button type=\"button\" [class.dv2-on]=\"'' + current.resolution == o.id\" (click)=\"setResolution(o.id)\">{{o.description}}</button>\n }\n </div>\n </div>\n </div>\n <activity-chart-v2 [Times]=\"session.topActivity?.times\" [Components]=\"sessionChart\" [BucketSeconds]=\"session.topActivity?.bucketSeconds\" [FixedColors]=\"sessionFixedColors\"\n [Uom]=\"'sessioni' | localize: lc\" [EmptyText]=\"'Nessuna attivit\u00E0 nella finestra' | localize: lc\" name=\"dv2sessionchart\"></activity-chart-v2>\n </div>\n\n <!-- S3 Tabelle: eventi, thread, API -->\n <div class=\"dv2-tables\">\n @for (table of sessionTables; track table.dimension) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">\n {{tableTitle(table)}}@if (table.estimated) { \u2248}\n <span class=\"dv2-muted\">{{'Attivit\u00E0' | localize: lc}} <strong>{{table.estimated ? '\u2248 ' : ''}}{{table.activity | number : '1.2-3' : 'it'}}</strong></span>\n </div>\n <table class=\"table table-sm dv2-table\">\n <tbody>\n @for (item of table.items; track $index) {\n <tr [class.dv2-highlight]=\"table.dimension == Dim.Thread && highlightedTid != null && item.key?.startsWith(highlightedTid + '@')\">\n <td>\n @if (isItemClickable(item, table)) {\n <span class=\"app-link dv2-ellipsis\" [title]=\"item.label || item.key\" (click)=\"itemClicked(item, table)\">{{itemLabel(item, table)}}</span>\n } @else {\n <span class=\"dv2-ellipsis\" [class.dv2-muted]=\"item.other || !item.label\" [title]=\"item.label || ''\">{{itemLabel(item, table)}}</span>\n }\n </td>\n <td class=\"app-nowrap\">\n <div class=\"dv2-bar-cell\">\n <div class=\"dv2-bar\">\n @for (part of item.breakdown; track $index) {\n <div [style.width.%]=\"breakdownWidth(item, part)\" [style.background]=\"breakdownColor(part)\" [title]=\"part.key\"></div>\n }\n </div>\n <span>{{table.estimated ? '\u2248 ' : ''}}{{item.activity | number : '1.2-3' : 'it'}}</span>\n </div>\n </td>\n <td class=\"dv2-right app-nowrap\">{{item.percentage | number : '1.1-1' : 'it'}}%</td>\n </tr>\n }\n </tbody>\n </table>\n </div>\n }\n </div>\n\n <!-- S4 Thread adesso -->\n @if (session.connected && session.threads?.length) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Thread adesso' | localize: lc}}</div>\n <div class=\"dv2-scroll\">\n <table class=\"table table-sm dv2-table\">\n <thead>\n <tr>\n <th></th>\n <th>TID</th>\n <th>{{'Nome' | localize: lc}}</th>\n <th>{{'Tipo' | localize: lc}}</th>\n <th>{{'Stato' | localize: lc}}</th>\n <th>{{'Priorit\u00E0' | localize: lc}}</th>\n <th>API</th>\n <th>{{'Macchina' | localize: lc}}</th>\n <th>{{'Evento corrente' | localize: lc}}</th>\n <th class=\"dv2-right\">{{'In corso da' | localize: lc}}</th>\n <th>p1 - p3</th>\n </tr>\n </thead>\n <tbody>\n @for (thread of session.threads; track thread.tid) {\n <tr [class.dv2-highlight]=\"thread.tid == highlightedTid\">\n <td><button type=\"button\" class=\"btn btn-sm btn-link dv2-toggle\" (click)=\"toggleThread(thread)\" [title]=\"'Pila completa degli eventi' | localize: lc\"><i class=\"fa\" [class.fa-caret-right]=\"expandedTid != thread.tid\" [class.fa-caret-down]=\"expandedTid == thread.tid\"></i></button></td>\n <td>{{thread.tid}}</td>\n <td class=\"app-nowrap\">{{thread.name}}</td>\n <td class=\"app-nowrap\">{{thread.type}}</td>\n <td>{{thread.currentStatus}}</td>\n <td>{{thread.priority}}</td>\n <td><span class=\"dv2-ellipsis dv2-ellipsis-short\" [title]=\"thread.currentApi || ''\">{{thread.currentApi}}</span></td>\n <td>{{thread.machineName}}</td>\n <td>\n @if (thread.inWait && thread.currentWaitNodeId) {\n <span class=\"app-link dv2-ellipsis\" [title]=\"thread.currentWait\" (click)=\"pushNode(thread.currentWaitNodeId)\">{{thread.currentWait}}</span>\n <span class=\"dv2-muted\">{{typeLabel(thread.waitEventTypeName, thread.waitClassName)}}</span>\n } @else {\n <span class=\"dv2-muted\">{{'nessun evento in corso' | localize: lc}}</span>\n }\n </td>\n <td class=\"dv2-right app-nowrap\">{{thread.inWait ? (runningSeconds(thread) | pv2fmt: 'dur') : '\u2014'}}</td>\n <td class=\"dv2-muted\"><span class=\"dv2-ellipsis dv2-ellipsis-short\" [title]=\"[thread.waitParam1, thread.waitParam2, thread.waitParam3].join(' \u00B7 ')\">{{[thread.waitParam1, thread.waitParam2, thread.waitParam3].join(' \u00B7 ')}}</span></td>\n </tr>\n @if (expandedTid == thread.tid) {\n <tr class=\"dv2-stack-row\">\n <td colspan=\"11\"><pre class=\"dv2-stack\">{{thread.fullWaitStack || ('Nessun evento' | localize: lc)}}</pre></td>\n </tr>\n }\n }\n </tbody>\n </table>\n </div>\n </div>\n }\n\n <!-- S5 Operazioni lunghe -->\n @if (session.connected && session.longOps?.length) {\n <div class=\"dv2-panel\">\n <div class=\"dv2-title\">{{'Operazioni lunghe' | localize: lc}}</div>\n @for (op of session.longOps; track $index) {\n <div class=\"dv2-longop\">\n <div class=\"dv2-meta\">\n <strong>{{op.opName}}</strong>\n <span>{{op.target}} @if (op.targetDesc) {<span class=\"dv2-muted\">({{op.targetDesc}})</span>}</span>\n <span class=\"dv2-muted\">Thread {{op.tid}}</span>\n </div>\n <div class=\"dv2-progress\"><div [style.width.%]=\"progress(op)\"></div></div>\n <div class=\"dv2-meta dv2-small\">\n <span>{{op.soFar | number : '1.0-0' : 'it'}} {{'di' | localize: lc}} {{op.totalWork | number : '1.0-0' : 'it'}} {{op.units}} ({{progress(op) | number : '1.0-1' : 'it'}}%)</span>\n <span>{{'Trascorso' | localize: lc}} {{op.elapsedSeconds | pv2fmt: 'dur'}}</span>\n <span>{{'Alla fine' | localize: lc}} {{op.timeRemaining == null ? ('non stimabile' | localize: lc) : (op.timeRemaining | pv2fmt: 'dur')}}</span>\n @if (op.message) {\n <span class=\"dv2-muted\">{{op.message}}</span>\n }\n </div>\n </div>\n }\n </div>\n }\n }\n }\n </div>\n </div>\n</div>\n", styles: [":host{display:block}:host ::ng-deep .dv2-noclear .p-select-clear-icon{display:none}.dv2-header{align-items:center}.dv2-heading{display:flex;flex:1 1 auto;align-items:center;gap:12px;min-width:0}.dv2-heading .btn{flex:none;white-space:nowrap}.dv2-heading .modal-title{margin:0;overflow-wrap:anywhere}.dv2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px 18px;padding-top:6px}.dv2-group{display:flex;align-items:center;gap:8px}.dv2-end{margin-left:auto}.dv2-window{font-weight:600;white-space:nowrap}.dv2-field{width:170px}.dv2-field-wide{width:200px}.dv2-seg{display:inline-flex;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden}.dv2-seg button{border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;padding:4px 10px;font-size:12px;white-space:nowrap;cursor:pointer}.dv2-seg button:first-child{border-left:0}.dv2-seg button.dv2-on{background:var(--p-primary-color, #6366f1);color:#fff}.dv2-panel{margin-top:12px;padding:10px 12px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);min-width:0}.dv2-title{font-weight:600;margin-bottom:6px}.dv2-title .dv2-muted{font-weight:400;margin-left:8px}.dv2-spaced{margin-top:14px}.dv2-chart-head{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px 14px;padding-top:6px;margin-bottom:6px}.dv2-muted{color:var(--p-text-muted-color, #64748b);font-size:12px}.dv2-small{font-size:12px}.dv2-note{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.dv2-state{margin:12px 0 0}.dv2-empty{padding:40px 0;text-align:center;color:var(--p-text-muted-color, #64748b)}.dv2-estimate{display:inline-block;margin-left:6px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;font-weight:400}.dv2-badge{display:inline-block;padding:1px 8px;border-radius:10px;background:#dcfce7;color:#166534;font-size:12px;font-weight:600}.dv2-badge-off{background:#fee2e2;color:#991b1b}.dv2-node-name{font-family:var(--p-font-family-mono, Consolas, monospace);font-size:13px;white-space:pre-wrap;word-break:break-word;max-height:160px;overflow:auto}.dv2-meta{display:flex;flex-wrap:wrap;align-items:center;gap:4px 16px;margin-top:6px}.dv2-session-head{margin-top:0}.dv2-path{display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px;margin-top:8px;font-size:12px}.dv2-path-item{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dv2-path-current{font-weight:600}.dv2-actions{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:10px}.dv2-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:0 12px}@media(max-width:991px){.dv2-grid{grid-template-columns:minmax(0,1fr)}}.dv2-table{margin-bottom:0;font-size:12px}.dv2-table th{font-weight:600;white-space:nowrap}.dv2-table td{vertical-align:middle}.dv2-right{text-align:right}.dv2-live{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:8px;font-size:12px}.dv2-typebar{display:flex;height:14px;border-radius:3px;overflow:hidden;background:var(--p-content-border-color, #e2e8f0)}.dv2-idle{background-image:repeating-linear-gradient(45deg,rgba(255,255,255,.55) 0 3px,transparent 3px 6px)}.dv2-legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin-top:6px;font-size:12px}.dv2-swatch{display:inline-block;width:10px;height:10px;margin-right:5px;border-radius:2px;vertical-align:-1px}.dv2-tables{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:0 12px}.dv2-tables .dv2-table{table-layout:fixed;width:100%}.dv2-tables .dv2-table td:nth-child(2){width:120px}.dv2-tables .dv2-table td:nth-child(3){width:58px}.dv2-tables .dv2-ellipsis{display:block;max-width:100%}.dv2-ellipsis{display:inline-block;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.dv2-ellipsis-short{max-width:160px}.dv2-ellipsis+.dv2-muted{margin-left:6px}.dv2-bar-cell{display:flex;align-items:center;gap:8px}.dv2-bar{display:flex;flex:none;width:70px;height:8px;border-radius:2px;overflow:hidden;background:var(--p-content-border-color, #e2e8f0)}.dv2-highlight>td{background:#eef2ff}.dv2-scroll{overflow-x:auto}.dv2-toggle{padding:0 4px}.dv2-stack-row>td{border-top:0}.dv2-stack{margin:0;padding:8px;max-height:240px;overflow:auto;border-radius:4px;background:#f8fafc;font-size:11px;white-space:pre}.dv2-longop+.dv2-longop{margin-top:12px}.dv2-progress{height:8px;margin-top:6px;border-radius:4px;overflow:hidden;background:var(--p-content-border-color, #e2e8f0)}.dv2-progress div{height:100%;background:var(--p-primary-color, #6366f1)}\n"] }]
|
|
1537
|
+
}], ctorParameters: () => [{ type: i1.LocalizationService }, { type: i1$1.DateService }, { type: AdminModuleBaseService }], propDecorators: { Be: [{
|
|
1538
|
+
type: Input
|
|
1539
|
+
}], CanShowSessions: [{
|
|
1540
|
+
type: Input
|
|
1541
|
+
}], CanOpenProfiler: [{
|
|
1542
|
+
type: Input
|
|
1543
|
+
}], closed: [{
|
|
1544
|
+
type: Output
|
|
1545
|
+
}], sessionsOnEvent: [{
|
|
1546
|
+
type: Output
|
|
1547
|
+
}], openProfiler: [{
|
|
1548
|
+
type: Output
|
|
1549
|
+
}] } });
|
|
1550
|
+
|
|
756
1551
|
class AdmProfilerComponentLoc extends LocalizationService {
|
|
757
1552
|
constructor(injector) {
|
|
758
1553
|
super(injector);
|
|
@@ -842,7 +1637,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
842
1637
|
|
|
843
1638
|
// Angular
|
|
844
1639
|
class AdmProfilerComponent {
|
|
845
|
-
constructor(lc, localStorage, location, intercom, route, adms, router, mod, workloadV2
|
|
1640
|
+
constructor(lc, localStorage, location, intercom, route, adms, router, mod, workloadV2,
|
|
1641
|
+
// Con DirectorFeature.DetailsV2 GetNodeStats risponde solo con il contratto nuovo: il nodo si apre nel dettaglio v2
|
|
1642
|
+
dateExts, detailsV2Enabled, topActV2Enabled) {
|
|
846
1643
|
this.lc = lc;
|
|
847
1644
|
this.localStorage = localStorage;
|
|
848
1645
|
this.location = location;
|
|
@@ -852,6 +1649,9 @@ class AdmProfilerComponent {
|
|
|
852
1649
|
this.router = router;
|
|
853
1650
|
this.mod = mod;
|
|
854
1651
|
this.workloadV2 = workloadV2;
|
|
1652
|
+
this.dateExts = dateExts;
|
|
1653
|
+
this.detailsV2Enabled = detailsV2Enabled;
|
|
1654
|
+
this.topActV2Enabled = topActV2Enabled;
|
|
855
1655
|
this.searchView = new ProfilerDataNodesView();
|
|
856
1656
|
this.be = route.snapshot.params["be"] || "";
|
|
857
1657
|
this.intercom.send(InboundMessageTypes.Navigation, { sub: false, routeTitle: this.lc.loc(this.route.snapshot.data["title"]) });
|
|
@@ -916,18 +1716,39 @@ class AdmProfilerComponent {
|
|
|
916
1716
|
let res = await this.adms.getProfilerDataNodes(this.be, view);
|
|
917
1717
|
dataCallBack(res.items, ProfilerDataNode);
|
|
918
1718
|
}
|
|
1719
|
+
openNodeDetails(nodeId) {
|
|
1720
|
+
if (this.detailsV2Enabled) {
|
|
1721
|
+
// Senza date la pagina è dal vivo (l'ultima ora per il grafico), con le date legge lo storico
|
|
1722
|
+
let history = !!(this.searchView.filterfrom || this.searchView.filterto);
|
|
1723
|
+
let to = this.searchView.filterto ? this.dateExts.getDateConvertion(this.searchView.filterto).toDate() : new Date();
|
|
1724
|
+
let from = this.searchView.filterfrom ? this.dateExts.getDateConvertion(this.searchView.filterfrom).toDate() : new Date(to.getTime() - 3600 * 1000);
|
|
1725
|
+
this.detailsV2.openNode(nodeId, { from: from, to: to, realTime: !history, global: this.searchView.filterglobal });
|
|
1726
|
+
this.dlgDetailsV2.show();
|
|
1727
|
+
return;
|
|
1728
|
+
}
|
|
1729
|
+
this.loadNodeDetails(nodeId);
|
|
1730
|
+
this.dlgNodeDetails.show();
|
|
1731
|
+
}
|
|
1732
|
+
// N8: la Top Activity v2 filtrata sull'evento, nella finestra del dettaglio
|
|
1733
|
+
showEventSessions(link) {
|
|
1734
|
+
this.dlgDetailsV2.hide();
|
|
1735
|
+
this.router.navigate([`/pages/${this.mod}/topact`, ...(this.be ? [this.be] : [])], { queryParams: { event: link.nodeId, eventName: link.nodeName, from: link.from.toISOString(), to: link.to.toISOString() } });
|
|
1736
|
+
}
|
|
1737
|
+
openInProfiler(nodeId) {
|
|
1738
|
+
this.dlgDetailsV2.hide();
|
|
1739
|
+
}
|
|
919
1740
|
loadNodeDetails(nodeId) {
|
|
920
1741
|
this.NodeDetails = null;
|
|
921
1742
|
requestAnimationFrame(async () => {
|
|
922
1743
|
this.NodeDetails = await this.adms.getNodeStats(this.be, nodeId);
|
|
923
1744
|
});
|
|
924
1745
|
}
|
|
925
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerComponent, deps: [{ token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i5.Location }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: AdminModuleBaseService }, { token: i4.Router }, { token: ADM_MODULE_PATH }, { token: ADM_WORKLOAD_V2, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
926
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmProfilerComponent, isStandalone: false, selector: "adm_profiler", providers: [{ provide: LocalizationService, useClass: AdmProfilerComponentLoc }], ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-12\">\n <div class=\"card app-overflow-visible\" widget>\n <div class=\"card-header\">\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span> \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> \n <span class=\"app-pointer app-padding-top-5 app-padding-left-5\" (click)=\"searchView.filterglobal = !searchView.filterglobal\">{{'Globale' | localize: lc}}</span>\n </div>\n\n <button [disabled]=\"searchView.searchinprogress\" class=\"input-group-addon btn app-btn-search app-margin-top-20 app-margin-right-5\" (click)=\"sendSearch()\" type=\"submit\"><i class=\"fa fa-search\"></i></button>\n <button class=\"input-group-addon btn app-btn-search app-margin-top-20\" (click)=\"downloadWorkloadReport()\" type=\"submit\" [title]=\"workloadV2 ? 'Workload report' : ''\"><i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i></button>\n </div>\n </form>\n </div>\n <div class=\"row\">\n <div class=\"col-md-12\">\n @if (!searchView) {\n <p><em>{{'Carico i Dati' | localize: lc}}</em></p>\n }\n @if (searchView) {\n <div>\n <es-table [(ngModel)]=\"searchView\" [Hierarchy]=\"true\" [OrderByColumn]=\"false\" [ParentKey]=\"'parentid'\"\n [OwnKey]=\"'id'\" [StartsExpanded]=\"false\" [ExportFunction]=\"prepareExport.bind(this)\" [Export]=\"true\"\n [ExportFileName]=\"'Profiler Export.csv'\" [HidePaging]=\"true\" (onSearchRequest)=\"sendSearch($event);\">\n <span *th=\"'1'\">{{'ID' | localize : lc}}</span>\n <span *th=\"'2'\">{{'Descrizione' | localize: lc}}</span>\n <span *th=\"'3'\">{{'Chiamate' | localize: lc}}</span>\n <span *th=\"'4'\">{{'Tempo' | localize: lc}}</span>\n <span *th=\"'5'\">{{'Tempo Max' | localize: lc}}</span>\n <span *th=\"'6'\">{{'Tempo Min' | localize: lc}}</span>\n <span *th=\"'7'\">{{'Tempo Medio' | localize: lc}}</span>\n <span *th=\"'8'\">{{'Tempo Specifico' | localize: lc}}</span>\n <span *th=\"'9'\">{{'Percentuale' | localize: lc}}</span>\n <span *th=\"'10'\">{{'Chiamate Periodo' | localize: lc}}</span>\n <span *th=\"'11'\">{{'Tempo Periodo' | localize: lc}}</span>\n <span *th=\"'12'\">{{'Tempo Max Periodo' | localize: lc}}</span>\n <span *th=\"'13'\">{{'Tempo Min Periodo' | localize: lc}}</span>\n <span *th=\"'14'\">{{'Tempo Medio Periodo' | localize: lc}}</span>\n <span *th=\"'15'\">{{'Tempo Specifico Periodo' | localize: lc}}</span>\n <span *th=\"'16'\">{{'Percentuale Periodo' | localize: lc}}</span>\n <span *th=\"'17'\">{{'Nome Tipologia Evento' | localize: lc}}</span>\n <span *th=\"'18'\">{{'Nome Classe Attesa' | localize: lc}}</span>\n <span *th=\"'19'\">{{'Numero Istanze' | localize: lc}}</span>\n <span *td=\"'1'; let item\"><span class=\"app-link app-inline\" (click)=\"loadNodeDetails(item.id); dlgNodeDetails.show();\">{{item.id}}</span></span>\n <span *td=\"'2'; let item\" title=\"{{item.description}}\">{{item.description.length <= 50 ? item.description : item.description.substr(0,50) + \"[...]\" }}</span>\n <span *td=\"'3'; let item\">{{item.calls}}</span>\n <span *td=\"'4'; let item\">{{item.time}}</span>\n <span *td=\"'5'; let item\">{{item.peaktime}}</span>\n <span *td=\"'6'; let item\">{{item.mintime}}</span>\n <span *td=\"'7'; let item\">{{item.avgtime}}</span>\n <span *td=\"'8'; let item\">{{item.timewithoutchildren }}</span>\n <span *td=\"'9'; let item\">{{item.percentage}}</span>\n <span *td=\"'10' let item\">{{item.snapdeltacalls}}</span>\n <span *td=\"'11' let item\">{{item.snapdeltatime}}</span>\n <span *td=\"'12' let item\">{{item.snappeaktime}}</span>\n <span *td=\"'13' let item\">{{item.snapmintime}}</span>\n <span *td=\"'14' let item\">{{item.snapavgtime}}</span>\n <span *td=\"'15' let item\">{{item.snaptimewithoutchildren}}</span>\n <span *td=\"'16' let item\">{{item.snappercentage}}</span>\n <span *td=\"'17' let item\">{{item.eventtypename}}</span>\n <span *td=\"'18' let item\">{{item.waitclassname}}</span>\n <span *td=\"'19' let item\">{{item.numinstances}}</span>\n </es-table>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\n @if (NodeDetails) {\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\n }\n</div>", dependencies: [{ kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "directive", type: i8.EsTdDirective, selector: "[td]", inputs: ["tdVisible", "td", "tdForProperty", "tdIf", "tdClass", "tdPropertyAccessor", "tdAlignment", "tdFormat", "tdIconClass", "tdConditionField", "tdConditionValue", "tdTitle", "tdContent"] }, { kind: "directive", type: i8.EsThDirective, selector: "[th]", inputs: ["th", "thPinned", "thPinnedRight", "thPinnable", "thPinnedWidth", "thVisible", "thFixed", "thParent", "thOrder", "thOrderable", "thWrap", "thResizable", "thClass", "thShrink", "thGroupClass", "thIf", "thEmpty", "thGroup", "thAggregation", "thProperty", "thType", "thSource", "thMulti", "thStaticContent", "thBackgroundColor", "thAlignment", "thFormat", "thEditorName", "thEditorOptions", "thRendererName", "thRoutePath", "thRouteParameterProperties"] }, { kind: "component", type: i8.EsTableComponent, selector: "es-table", inputs: ["globalCheck", "autoUpdate", "seconds", "researchInProgress", "globalColVisCheck", "EsThTdProvider", "CornerMenuOptions", "ColumnsResizable", "ColumnsPinnable", "AutoUpdate", "Height", "EmptySpaceBackgroundColor", "EsTableHandledSearch", "MaxHeight", "ContainerClass", "XLSXExport", "CSVExport", "AllSearch", "HighCellDensity", "Selection", "ShowLoadingOnBootstrap", "Removal", "RemovalCondition", "Export", "ShiftClick", "CountLabel", "HidePaging", "HidePagingCount", "HidePagingButtons", "ContextMenu", "ExportFileName", "TableClass", "ExportFunction", "ExportOnlyVisibleColumns", "HasHeaderGroup", "HasSecondaryHeaderGroup", "HeaderHidden", "BodyHidden", "SelectionDisabled", "SingleSelection", "RowClassAssigner", "OrderByColumn", "MultipleOrderingDirectives", "HiddenColumns", "ColumnsOrdering", "SearchView", "SelectAll", "UseArrayModePaging", "DynamicRowColumnsDefinition", "DynamicOperations", "Hierarchy", "ParentKey", "OwnKey", "AutoSortHierarchy", "StartsExpanded", "SavePreferences", "DefaultAlignment", "PagingStyle", "RowGroupingPagingStyle", "ItemSourceProperty", "UseSelectionCache", "ShowItemGroupsColumns", "Editable", "RangeSelection", "SearchThrottle", "ArraymodeItemsPerPage"], outputs: ["globalCheckChange", "autoUpdateChange", "secondsChange", "researchInProgressChange", "globalColVisCheckChange", "onOrderChanged", "onSearchRequest", "onSelectionChanged", "onRemoval", "onAbortRemoval", "onModelChange", "onOpenContextMenu", "onCornerAction", "onDynamicOperation"] }, { kind: "component", type: i9.EsFormDateComponent, selector: "form-date", inputs: ["InOutFormat", "FloatingLabel", "DateFormat"] }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: NodeDetailComponent, selector: "node-detail", inputs: ["NodeDetails"], outputs: ["onClose"] }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }] }); }
|
|
1746
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerComponent, deps: [{ token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i5.Location }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: AdminModuleBaseService }, { token: i4.Router }, { token: ADM_MODULE_PATH }, { token: ADM_WORKLOAD_V2, optional: true }, { token: i1$1.DateService }, { token: ADM_DETAILS_V2, optional: true }, { token: ADM_TOPACT_V2, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1747
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmProfilerComponent, isStandalone: false, selector: "adm_profiler", providers: [{ provide: LocalizationService, useClass: AdmProfilerComponentLoc }], viewQueries: [{ propertyName: "dlgNodeDetails", first: true, predicate: ["dlgNodeDetails"], descendants: true }, { propertyName: "dlgDetailsV2", first: true, predicate: ["dlgDetailsV2"], descendants: true }, { propertyName: "detailsV2", first: true, predicate: AdmDetailsV2Component, descendants: true }], ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-12\">\n <div class=\"card app-overflow-visible\" widget>\n <div class=\"card-header\">\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span> \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> \n <span class=\"app-pointer app-padding-top-5 app-padding-left-5\" (click)=\"searchView.filterglobal = !searchView.filterglobal\">{{'Globale' | localize: lc}}</span>\n </div>\n\n <button [disabled]=\"searchView.searchinprogress\" class=\"input-group-addon btn app-btn-search app-margin-top-20 app-margin-right-5\" (click)=\"sendSearch()\" type=\"submit\"><i class=\"fa fa-search\"></i></button>\n <button class=\"input-group-addon btn app-btn-search app-margin-top-20\" (click)=\"downloadWorkloadReport()\" type=\"submit\" [title]=\"workloadV2 ? 'Workload report' : ''\"><i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i></button>\n </div>\n </form>\n </div>\n <div class=\"row\">\n <div class=\"col-md-12\">\n @if (!searchView) {\n <p><em>{{'Carico i Dati' | localize: lc}}</em></p>\n }\n @if (searchView) {\n <div>\n <es-table [(ngModel)]=\"searchView\" [Hierarchy]=\"true\" [OrderByColumn]=\"false\" [ParentKey]=\"'parentid'\"\n [OwnKey]=\"'id'\" [StartsExpanded]=\"false\" [ExportFunction]=\"prepareExport.bind(this)\" [Export]=\"true\"\n [ExportFileName]=\"'Profiler Export.csv'\" [HidePaging]=\"true\" (onSearchRequest)=\"sendSearch($event);\">\n <span *th=\"'1'\">{{'ID' | localize : lc}}</span>\n <span *th=\"'2'\">{{'Descrizione' | localize: lc}}</span>\n <span *th=\"'3'\">{{'Chiamate' | localize: lc}}</span>\n <span *th=\"'4'\">{{'Tempo' | localize: lc}}</span>\n <span *th=\"'5'\">{{'Tempo Max' | localize: lc}}</span>\n <span *th=\"'6'\">{{'Tempo Min' | localize: lc}}</span>\n <span *th=\"'7'\">{{'Tempo Medio' | localize: lc}}</span>\n <span *th=\"'8'\">{{'Tempo Specifico' | localize: lc}}</span>\n <span *th=\"'9'\">{{'Percentuale' | localize: lc}}</span>\n <span *th=\"'10'\">{{'Chiamate Periodo' | localize: lc}}</span>\n <span *th=\"'11'\">{{'Tempo Periodo' | localize: lc}}</span>\n <span *th=\"'12'\">{{'Tempo Max Periodo' | localize: lc}}</span>\n <span *th=\"'13'\">{{'Tempo Min Periodo' | localize: lc}}</span>\n <span *th=\"'14'\">{{'Tempo Medio Periodo' | localize: lc}}</span>\n <span *th=\"'15'\">{{'Tempo Specifico Periodo' | localize: lc}}</span>\n <span *th=\"'16'\">{{'Percentuale Periodo' | localize: lc}}</span>\n <span *th=\"'17'\">{{'Nome Tipologia Evento' | localize: lc}}</span>\n <span *th=\"'18'\">{{'Nome Classe Attesa' | localize: lc}}</span>\n <span *th=\"'19'\">{{'Numero Istanze' | localize: lc}}</span>\n <span *td=\"'1'; let item\"><span class=\"app-link app-inline\" (click)=\"openNodeDetails(item.id)\">{{item.id}}</span></span>\n <span *td=\"'2'; let item\" title=\"{{item.description}}\">{{item.description.length <= 50 ? item.description : item.description.substr(0,50) + \"[...]\" }}</span>\n <span *td=\"'3'; let item\">{{item.calls}}</span>\n <span *td=\"'4'; let item\">{{item.time}}</span>\n <span *td=\"'5'; let item\">{{item.peaktime}}</span>\n <span *td=\"'6'; let item\">{{item.mintime}}</span>\n <span *td=\"'7'; let item\">{{item.avgtime}}</span>\n <span *td=\"'8'; let item\">{{item.timewithoutchildren }}</span>\n <span *td=\"'9'; let item\">{{item.percentage}}</span>\n <span *td=\"'10' let item\">{{item.snapdeltacalls}}</span>\n <span *td=\"'11' let item\">{{item.snapdeltatime}}</span>\n <span *td=\"'12' let item\">{{item.snappeaktime}}</span>\n <span *td=\"'13' let item\">{{item.snapmintime}}</span>\n <span *td=\"'14' let item\">{{item.snapavgtime}}</span>\n <span *td=\"'15' let item\">{{item.snaptimewithoutchildren}}</span>\n <span *td=\"'16' let item\">{{item.snappercentage}}</span>\n <span *td=\"'17' let item\">{{item.eventtypename}}</span>\n <span *td=\"'18' let item\">{{item.waitclassname}}</span>\n <span *td=\"'19' let item\">{{item.numinstances}}</span>\n </es-table>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\n @if (NodeDetails) {\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\n }\n</div>\n\n<!-- Dettaglio v2 di nodo e sessione (DirectorFeature.DetailsV2) -->\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\n @if (detailsV2Enabled) {\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"!!topActV2Enabled\" [CanOpenProfiler]=\"false\" (closed)=\"dlgDetailsV2.hide()\"\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"openInProfiler($event)\"></adm-details-v2>\n }\n</div>\n", dependencies: [{ kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "directive", type: i8.EsTdDirective, selector: "[td]", inputs: ["tdVisible", "td", "tdForProperty", "tdIf", "tdClass", "tdPropertyAccessor", "tdAlignment", "tdFormat", "tdIconClass", "tdConditionField", "tdConditionValue", "tdTitle", "tdContent"] }, { kind: "directive", type: i8.EsThDirective, selector: "[th]", inputs: ["th", "thPinned", "thPinnedRight", "thPinnable", "thPinnedWidth", "thVisible", "thFixed", "thParent", "thOrder", "thOrderable", "thWrap", "thResizable", "thClass", "thShrink", "thGroupClass", "thIf", "thEmpty", "thGroup", "thAggregation", "thProperty", "thType", "thSource", "thMulti", "thStaticContent", "thBackgroundColor", "thAlignment", "thFormat", "thEditorName", "thEditorOptions", "thRendererName", "thRoutePath", "thRouteParameterProperties"] }, { kind: "component", type: i8.EsTableComponent, selector: "es-table", inputs: ["globalCheck", "autoUpdate", "seconds", "researchInProgress", "globalColVisCheck", "EsThTdProvider", "CornerMenuOptions", "ColumnsResizable", "ColumnsPinnable", "AutoUpdate", "Height", "EmptySpaceBackgroundColor", "EsTableHandledSearch", "MaxHeight", "ContainerClass", "XLSXExport", "CSVExport", "AllSearch", "HighCellDensity", "Selection", "ShowLoadingOnBootstrap", "Removal", "RemovalCondition", "Export", "ShiftClick", "CountLabel", "HidePaging", "HidePagingCount", "HidePagingButtons", "ContextMenu", "ExportFileName", "TableClass", "ExportFunction", "ExportOnlyVisibleColumns", "HasHeaderGroup", "HasSecondaryHeaderGroup", "HeaderHidden", "BodyHidden", "SelectionDisabled", "SingleSelection", "RowClassAssigner", "OrderByColumn", "MultipleOrderingDirectives", "HiddenColumns", "ColumnsOrdering", "SearchView", "SelectAll", "UseArrayModePaging", "DynamicRowColumnsDefinition", "DynamicOperations", "Hierarchy", "ParentKey", "OwnKey", "AutoSortHierarchy", "StartsExpanded", "SavePreferences", "DefaultAlignment", "PagingStyle", "RowGroupingPagingStyle", "ItemSourceProperty", "UseSelectionCache", "ShowItemGroupsColumns", "Editable", "RangeSelection", "SearchThrottle", "ArraymodeItemsPerPage"], outputs: ["globalCheckChange", "autoUpdateChange", "secondsChange", "researchInProgressChange", "globalColVisCheckChange", "onOrderChanged", "onSearchRequest", "onSelectionChanged", "onRemoval", "onAbortRemoval", "onModelChange", "onOpenContextMenu", "onCornerAction", "onDynamicOperation"] }, { kind: "component", type: i9.EsFormDateComponent, selector: "form-date", inputs: ["InOutFormat", "FloatingLabel", "DateFormat"] }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: AdmDetailsV2Component, selector: "adm-details-v2", inputs: ["Be", "CanShowSessions", "CanOpenProfiler"], outputs: ["closed", "sessionsOnEvent", "openProfiler"] }, { kind: "component", type: NodeDetailComponent, selector: "node-detail", inputs: ["NodeDetails"], outputs: ["onClose"] }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }] }); }
|
|
927
1748
|
}
|
|
928
1749
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerComponent, decorators: [{
|
|
929
1750
|
type: Component,
|
|
930
|
-
args: [{ selector: "adm_profiler", providers: [{ provide: LocalizationService, useClass: AdmProfilerComponentLoc }], standalone: false, template: "<div class=\"row\">\n <div class=\"col-12\">\n <div class=\"card app-overflow-visible\" widget>\n <div class=\"card-header\">\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span> \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> \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)=\"
|
|
1751
|
+
args: [{ selector: "adm_profiler", providers: [{ provide: LocalizationService, useClass: AdmProfilerComponentLoc }], standalone: false, template: "<div class=\"row\">\n <div class=\"col-12\">\n <div class=\"card app-overflow-visible\" widget>\n <div class=\"card-header\">\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span> \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> \n <span class=\"app-pointer app-padding-top-5 app-padding-left-5\" (click)=\"searchView.filterglobal = !searchView.filterglobal\">{{'Globale' | localize: lc}}</span>\n </div>\n\n <button [disabled]=\"searchView.searchinprogress\" class=\"input-group-addon btn app-btn-search app-margin-top-20 app-margin-right-5\" (click)=\"sendSearch()\" type=\"submit\"><i class=\"fa fa-search\"></i></button>\n <button class=\"input-group-addon btn app-btn-search app-margin-top-20\" (click)=\"downloadWorkloadReport()\" type=\"submit\" [title]=\"workloadV2 ? 'Workload report' : ''\"><i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i></button>\n </div>\n </form>\n </div>\n <div class=\"row\">\n <div class=\"col-md-12\">\n @if (!searchView) {\n <p><em>{{'Carico i Dati' | localize: lc}}</em></p>\n }\n @if (searchView) {\n <div>\n <es-table [(ngModel)]=\"searchView\" [Hierarchy]=\"true\" [OrderByColumn]=\"false\" [ParentKey]=\"'parentid'\"\n [OwnKey]=\"'id'\" [StartsExpanded]=\"false\" [ExportFunction]=\"prepareExport.bind(this)\" [Export]=\"true\"\n [ExportFileName]=\"'Profiler Export.csv'\" [HidePaging]=\"true\" (onSearchRequest)=\"sendSearch($event);\">\n <span *th=\"'1'\">{{'ID' | localize : lc}}</span>\n <span *th=\"'2'\">{{'Descrizione' | localize: lc}}</span>\n <span *th=\"'3'\">{{'Chiamate' | localize: lc}}</span>\n <span *th=\"'4'\">{{'Tempo' | localize: lc}}</span>\n <span *th=\"'5'\">{{'Tempo Max' | localize: lc}}</span>\n <span *th=\"'6'\">{{'Tempo Min' | localize: lc}}</span>\n <span *th=\"'7'\">{{'Tempo Medio' | localize: lc}}</span>\n <span *th=\"'8'\">{{'Tempo Specifico' | localize: lc}}</span>\n <span *th=\"'9'\">{{'Percentuale' | localize: lc}}</span>\n <span *th=\"'10'\">{{'Chiamate Periodo' | localize: lc}}</span>\n <span *th=\"'11'\">{{'Tempo Periodo' | localize: lc}}</span>\n <span *th=\"'12'\">{{'Tempo Max Periodo' | localize: lc}}</span>\n <span *th=\"'13'\">{{'Tempo Min Periodo' | localize: lc}}</span>\n <span *th=\"'14'\">{{'Tempo Medio Periodo' | localize: lc}}</span>\n <span *th=\"'15'\">{{'Tempo Specifico Periodo' | localize: lc}}</span>\n <span *th=\"'16'\">{{'Percentuale Periodo' | localize: lc}}</span>\n <span *th=\"'17'\">{{'Nome Tipologia Evento' | localize: lc}}</span>\n <span *th=\"'18'\">{{'Nome Classe Attesa' | localize: lc}}</span>\n <span *th=\"'19'\">{{'Numero Istanze' | localize: lc}}</span>\n <span *td=\"'1'; let item\"><span class=\"app-link app-inline\" (click)=\"openNodeDetails(item.id)\">{{item.id}}</span></span>\n <span *td=\"'2'; let item\" title=\"{{item.description}}\">{{item.description.length <= 50 ? item.description : item.description.substr(0,50) + \"[...]\" }}</span>\n <span *td=\"'3'; let item\">{{item.calls}}</span>\n <span *td=\"'4'; let item\">{{item.time}}</span>\n <span *td=\"'5'; let item\">{{item.peaktime}}</span>\n <span *td=\"'6'; let item\">{{item.mintime}}</span>\n <span *td=\"'7'; let item\">{{item.avgtime}}</span>\n <span *td=\"'8'; let item\">{{item.timewithoutchildren }}</span>\n <span *td=\"'9'; let item\">{{item.percentage}}</span>\n <span *td=\"'10' let item\">{{item.snapdeltacalls}}</span>\n <span *td=\"'11' let item\">{{item.snapdeltatime}}</span>\n <span *td=\"'12' let item\">{{item.snappeaktime}}</span>\n <span *td=\"'13' let item\">{{item.snapmintime}}</span>\n <span *td=\"'14' let item\">{{item.snapavgtime}}</span>\n <span *td=\"'15' let item\">{{item.snaptimewithoutchildren}}</span>\n <span *td=\"'16' let item\">{{item.snappercentage}}</span>\n <span *td=\"'17' let item\">{{item.eventtypename}}</span>\n <span *td=\"'18' let item\">{{item.waitclassname}}</span>\n <span *td=\"'19' let item\">{{item.numinstances}}</span>\n </es-table>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\n @if (NodeDetails) {\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\n }\n</div>\n\n<!-- Dettaglio v2 di nodo e sessione (DirectorFeature.DetailsV2) -->\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\n @if (detailsV2Enabled) {\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"!!topActV2Enabled\" [CanOpenProfiler]=\"false\" (closed)=\"dlgDetailsV2.hide()\"\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"openInProfiler($event)\"></adm-details-v2>\n }\n</div>\n" }]
|
|
931
1752
|
}], ctorParameters: () => [{ type: i1.LocalizationService }, { type: i3.PreferencesService }, { type: i5.Location }, { type: i1$1.InterComService }, { type: i4.ActivatedRoute }, { type: AdminModuleBaseService }, { type: i4.Router }, { type: undefined, decorators: [{
|
|
932
1753
|
type: Inject,
|
|
933
1754
|
args: [ADM_MODULE_PATH]
|
|
@@ -936,7 +1757,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
936
1757
|
}, {
|
|
937
1758
|
type: Inject,
|
|
938
1759
|
args: [ADM_WORKLOAD_V2]
|
|
939
|
-
}] }
|
|
1760
|
+
}] }, { type: i1$1.DateService }, { type: undefined, decorators: [{
|
|
1761
|
+
type: Optional
|
|
1762
|
+
}, {
|
|
1763
|
+
type: Inject,
|
|
1764
|
+
args: [ADM_DETAILS_V2]
|
|
1765
|
+
}] }, { type: undefined, decorators: [{
|
|
1766
|
+
type: Optional
|
|
1767
|
+
}, {
|
|
1768
|
+
type: Inject,
|
|
1769
|
+
args: [ADM_TOPACT_V2]
|
|
1770
|
+
}] }], propDecorators: { dlgNodeDetails: [{
|
|
1771
|
+
type: ViewChild,
|
|
1772
|
+
args: ["dlgNodeDetails"]
|
|
1773
|
+
}], dlgDetailsV2: [{
|
|
1774
|
+
type: ViewChild,
|
|
1775
|
+
args: ["dlgDetailsV2"]
|
|
1776
|
+
}], detailsV2: [{
|
|
1777
|
+
type: ViewChild,
|
|
1778
|
+
args: [AdmDetailsV2Component]
|
|
1779
|
+
}] } });
|
|
940
1780
|
|
|
941
1781
|
// Ordinamento decrescente del profiler v2 (figli nell'albero, righe nella vista per nome). I numeri sono quelli del backend
|
|
942
1782
|
var ProfilerOrderBy;
|
|
@@ -964,50 +1804,6 @@ class ProfilerV2NodeRequest extends ProfilerV2Request {
|
|
|
964
1804
|
class ProfilerV2FlatRequest extends ProfilerV2Request {
|
|
965
1805
|
}
|
|
966
1806
|
|
|
967
|
-
// Angular
|
|
968
|
-
// Formati del profiler v2 (specifica "Profiler gerarchico"): durate nell'unità più leggibile, interi con il separatore
|
|
969
|
-
// delle migliaia italiano, percentuali con un decimale sotto 10. Un dato mancante è "—"
|
|
970
|
-
class ProfilerFormatPipe {
|
|
971
|
-
transform(value, kind) {
|
|
972
|
-
if (value == null || isNaN(value))
|
|
973
|
-
return "—";
|
|
974
|
-
switch (kind) {
|
|
975
|
-
case "dur": return formatDuration(value);
|
|
976
|
-
case "pct": return formatPercentage(value);
|
|
977
|
-
default: return formatNumber(value, "it", "1.0-0");
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
981
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, isStandalone: true, name: "pv2fmt" }); }
|
|
982
|
-
}
|
|
983
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: ProfilerFormatPipe, decorators: [{
|
|
984
|
-
type: Pipe,
|
|
985
|
-
args: [{ name: "pv2fmt" }]
|
|
986
|
-
}] });
|
|
987
|
-
// Secondi: "850 µs", "4,27 ms", "312,5 ms", "8,41 s", "4 min 12 s", "3 h 20 min", "76 h"
|
|
988
|
-
function formatDuration(seconds) {
|
|
989
|
-
if (seconds == null || isNaN(seconds))
|
|
990
|
-
return "—";
|
|
991
|
-
let abs = Math.abs(seconds);
|
|
992
|
-
if (abs < 0.001)
|
|
993
|
-
return `${formatNumber(seconds * 1000000, "it", "1.0-0")} µs`;
|
|
994
|
-
if (abs < 1)
|
|
995
|
-
return `${formatNumber(seconds * 1000, "it", abs < 0.01 ? "1.2-2" : "1.1-1")} ms`;
|
|
996
|
-
if (abs < 60)
|
|
997
|
-
return `${formatNumber(seconds, "it", abs < 10 ? "1.2-2" : "1.1-1")} s`;
|
|
998
|
-
if (abs < 3600)
|
|
999
|
-
return `${Math.floor(abs / 60)} min ${Math.floor(abs % 60)} s`;
|
|
1000
|
-
if (abs < 48 * 3600)
|
|
1001
|
-
return `${Math.floor(abs / 3600)} h ${Math.floor(abs % 3600 / 60)} min`;
|
|
1002
|
-
return `${formatNumber(Math.floor(abs / 3600), "it", "1.0-0")} h`;
|
|
1003
|
-
}
|
|
1004
|
-
// Da 0 a 100: "4,2%", "34%"
|
|
1005
|
-
function formatPercentage(value) {
|
|
1006
|
-
if (value == null || isNaN(value))
|
|
1007
|
-
return "—";
|
|
1008
|
-
return `${formatNumber(value, "it", Math.abs(value) < 10 ? "1.1-1" : "1.0-0")}%`;
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
1807
|
class AdmProfilerV2Loc extends LocalizationService {
|
|
1012
1808
|
constructor(injector) {
|
|
1013
1809
|
super(injector);
|
|
@@ -1103,6 +1899,7 @@ class AdmProfilerV2Loc extends LocalizationService {
|
|
|
1103
1899
|
super.set("it->en", "Il nodo non c'è nelle istanze o nella finestra scelte.", ["The node is not in the chosen instances or window."]);
|
|
1104
1900
|
super.set("it->en", "Copia", ["Copy"]);
|
|
1105
1901
|
super.set("it->en", "Copiato", ["Copied"]);
|
|
1902
|
+
super.set("it->en", "Dettaglio completo", ["Full detail"]);
|
|
1106
1903
|
super.set("it->en", "Percorso", ["Path"]);
|
|
1107
1904
|
super.set("it->en", "Nella finestra", ["In window"]);
|
|
1108
1905
|
super.set("it->en", "Esecuzioni", ["Executions"]);
|
|
@@ -1179,7 +1976,9 @@ class ProfilerV2Chart {
|
|
|
1179
1976
|
class ProfilerV2Settings {
|
|
1180
1977
|
}
|
|
1181
1978
|
class AdmProfilerV2Component {
|
|
1182
|
-
constructor(dateExts, lc, localStorage, intercom, route, router, location, adms, mod, workloadV2
|
|
1979
|
+
constructor(dateExts, lc, localStorage, intercom, route, router, location, adms, mod, workloadV2,
|
|
1980
|
+
// Con DirectorFeature.DetailsV2 il pannello apre anche il dettaglio completo del nodo; "Sessioni su questo evento" vuole la Top Activity v2
|
|
1981
|
+
detailsV2Enabled, topActV2Enabled) {
|
|
1183
1982
|
this.dateExts = dateExts;
|
|
1184
1983
|
this.lc = lc;
|
|
1185
1984
|
this.localStorage = localStorage;
|
|
@@ -1190,6 +1989,8 @@ class AdmProfilerV2Component {
|
|
|
1190
1989
|
this.adms = adms;
|
|
1191
1990
|
this.mod = mod;
|
|
1192
1991
|
this.workloadV2 = workloadV2;
|
|
1992
|
+
this.detailsV2Enabled = detailsV2Enabled;
|
|
1993
|
+
this.topActV2Enabled = topActV2Enabled;
|
|
1193
1994
|
this.EventTypes = EVENT_TYPES;
|
|
1194
1995
|
// Barra dei comandi
|
|
1195
1996
|
this.live = true;
|
|
@@ -1725,6 +2526,28 @@ class AdmProfilerV2Component {
|
|
|
1725
2526
|
this.setRoot(nodeId);
|
|
1726
2527
|
this.select(nodeId);
|
|
1727
2528
|
}
|
|
2529
|
+
// Dettaglio completo del nodo (specifica "Dettaglio nodo e sessione") con la sorgente, le istanze e la finestra della pagina:
|
|
2530
|
+
// dal vivo l'ultima ora, sullo storico la finestra scelta
|
|
2531
|
+
openFullDetail() {
|
|
2532
|
+
if (!this.detail)
|
|
2533
|
+
return;
|
|
2534
|
+
let req = this.baseRequest(new ProfilerV2NodeRequest());
|
|
2535
|
+
let to = req.snapTo ? new Date(req.snapTo) : new Date();
|
|
2536
|
+
let from = req.snapFrom ? new Date(req.snapFrom) : new Date(to.getTime() - 3600 * 1000);
|
|
2537
|
+
this.detailsV2.openNode(this.detail.nodeId, { from: from, to: to, realTime: this.live, global: req.global, instanceId: req.instanceId });
|
|
2538
|
+
this.dlgDetailsV2.show();
|
|
2539
|
+
}
|
|
2540
|
+
// N7 dal dettaglio completo: l'albero con il nodo come radice, in questa pagina
|
|
2541
|
+
rootFromDetails(nodeId) {
|
|
2542
|
+
this.dlgDetailsV2.hide();
|
|
2543
|
+
this.setRoot(nodeId);
|
|
2544
|
+
this.select(nodeId);
|
|
2545
|
+
}
|
|
2546
|
+
// N8: la Top Activity v2 filtrata sull'evento, nella finestra del dettaglio
|
|
2547
|
+
showEventSessions(link) {
|
|
2548
|
+
this.dlgDetailsV2.hide();
|
|
2549
|
+
this.router.navigate([`/pages/${this.mod}/topact`, ...(this.be ? [this.be] : [])], { queryParams: { event: link.nodeId, eventName: link.nodeName, from: link.from.toISOString(), to: link.to.toISOString() } });
|
|
2550
|
+
}
|
|
1728
2551
|
showDetail(nodeId, event) {
|
|
1729
2552
|
event.stopPropagation();
|
|
1730
2553
|
this.select(nodeId);
|
|
@@ -1968,12 +2791,12 @@ class AdmProfilerV2Component {
|
|
|
1968
2791
|
ret.setMinutes(0, 0, 0);
|
|
1969
2792
|
return ret;
|
|
1970
2793
|
}
|
|
1971
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerV2Component, deps: [{ token: i1$1.DateService }, { token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: i4.Router }, { token: i5.Location }, { token: AdminModuleBaseService }, { token: ADM_MODULE_PATH }, { token: ADM_WORKLOAD_V2, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1972
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmProfilerV2Component, isStandalone: false, selector: "profiler_v2", providers: [{ provide: LocalizationService, useClass: AdmProfilerV2Loc }], ngImport: i0, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span>\r\n </div>\r\n <div class=\"card-body widget-body pv2-body\">\r\n <!-- Barra dei comandi: quali dati caricare. Ogni cambio ricarica la vista e il dettaglio aperto -->\r\n <div class=\"pv2-toolbar\">\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Sorgente' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"live\" (click)=\"setLive(true)\"><span class=\"pv2-live-dot\"></span>Live</button>\r\n <button type=\"button\" [class.pv2-on]=\"!live\" (click)=\"setLive(false)\">{{'Storico' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n <div class=\"pv2-field pv2-field-wide pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"instance\" (ngModelChange)=\"setInstance($event)\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanze' | localize: lc\"></form-select>\r\n </div>\r\n </div>\r\n\r\n @if (!live) {\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterfrom\" (ngModelChange)=\"filterfrom = $event; datesChanged()\" name=\"filterfrom\" [Placeholder]=\"'Dal' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterto\" (ngModelChange)=\"filterto = $event; datesChanged()\" name=\"filterto\" [Placeholder]=\"'Al' | localize: lc\"></form-datetime>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Valori' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"!snapValues\" (click)=\"setSnapValues(false)\">{{\"Dall'avvio\" | localize: lc}}</button>\r\n <button type=\"button\" [class.pv2-on]=\"snapValues\" (click)=\"setSnapValues(true)\">{{\"Dall'ultimo snapshot\" | localize: lc}}</button>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"pv2-cluster pv2-cluster-end\">\r\n <button type=\"button\" class=\"btn app-btn-search\" [disabled]=\"loading\" (click)=\"reloadAll()\" [title]=\"'Aggiorna' | localize: lc\">\r\n <i class=\"fa fa-refresh\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n <button type=\"button\" class=\"btn app-btn-search\" (click)=\"downloadWorkloadReport()\" [title]=\"(workloadV2 ? 'Workload report' : 'Scarica il workload report') | localize: lc\">\r\n <i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Riga della finestra: sempre visibile sopra la vista -->\r\n <div class=\"pv2-window\">\r\n <span><strong>{{live ? 'Live' : ('Storico' | localize: lc)}}</strong> · {{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}} · {{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\">›</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\">×</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}} «{{activeSearch}}».</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}} · {{omittedTime(row.node) | pv2fmt: 'dur'}}\r\n @if (!snapMode) {\r\n · {{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)}} · {{'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}} · {{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: 1000px){.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%;min-width:740px;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-num{text-align:right!important;font-variant-numeric:tabular-nums}.pv2-row{cursor:pointer}.pv2-row:hover td{background:var(--p-content-hover-background, #f8fafc)}.pv2-row.pv2-selected td{background:var(--p-highlight-background, #eef2ff)}.pv2-row.pv2-idle td{color:var(--p-text-muted-color, #64748b)}.pv2-row.pv2-idle td .pv2-name{opacity:.75}.pv2-node{display:flex;align-items:center;gap:6px;min-width:0}.pv2-caret{flex:none;width:18px;height:20px;padding:0;border:0;background:transparent;color:var(--p-text-muted-color, #64748b);text-align:center;cursor:pointer}.pv2-type{flex:none;display:inline-flex;align-items:center;gap:5px;padding:0 6px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:10px;color:var(--p-text-muted-color, #64748b);font-size:11px;line-height:18px;white-space:nowrap}.pv2-dot{flex:none;display:inline-block;width:8px;height:8px;border-radius:50%}.pv2-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pv2-name mark{padding:0 1px;border-radius:2px;background:#fde68a;color:#1f2937}.pv2-perc{width:1%}.pv2-perc-cell{display:flex;align-items:center;gap:8px}.pv2-bar{flex:none;width:64px;height:7px;border-radius:2px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc);box-shadow:inset 0 0 0 1px var(--p-content-border-color, #e2e8f0)}.pv2-bar>div{height:100%}.pv2-threads>*+*{margin-left:8px}.pv2-active{display:inline-flex;align-items:center;gap:5px;font-weight:500}.pv2-active-dot{width:7px;height:7px;border-radius:50%;background:#16a34a;box-shadow:0 0 0 3px #16a34a2e}.pv2-long{display:inline-flex;align-items:center;gap:4px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:18px;white-space:nowrap}.pv2-service td{padding:5px 10px;color:var(--p-text-muted-color, #64748b);font-size:12px;background:var(--p-content-background, #fff)}.pv2-sub td{padding:8px 10px 10px 34px;background:var(--p-content-hover-background, #f8fafc);white-space:normal}.pv2-sub-title{margin-bottom:4px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-sub-item{display:flex;align-items:center;gap:10px;padding:2px 0}.pv2-sub-item code{font-size:12px}.pv2-link{margin-left:6px;padding:0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;cursor:pointer}.pv2-link:hover{text-decoration:underline}.pv2-empty{padding:28px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-footer{margin-top:8px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-muted{color:var(--p-text-muted-color, #64748b)}.pv2-small{font-size:12px}.pv2-detail{position:sticky;top:10px;max-height:calc(100vh - 20px);overflow:auto;font-size:13px;color:var(--p-text-color, #334155);transition:opacity .15s}.pv2-detail.pv2-stale{opacity:.55}.pv2-placeholder{padding:36px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-error-text{color:#dc2626}.pv2-d-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.pv2-fullname{max-height:140px;overflow:auto;padding:8px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-family:ui-monospace,Cascadia Mono,Consolas,monospace;font-size:12px;white-space:pre-wrap;word-break:break-word}.pv2-id{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-id code{font-size:12px}.pv2-d-title{margin:16px 0 6px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}.pv2-path{display:flex;flex-direction:column}.pv2-path-item{display:flex;align-items:center;gap:6px;max-width:100%;padding:2px 0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.pv2-path-item:hover{text-decoration:underline}.pv2-path-current{color:var(--p-text-color, #334155);font-weight:600;cursor:default}.pv2-path-current:hover{text-decoration:none}.pv2-kv{display:grid;grid-template-columns:auto 1fr;gap:3px 14px;margin:0}.pv2-kv dt{color:var(--p-text-muted-color, #64748b);font-weight:400}.pv2-kv dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}.pv2-stack{display:flex;height:12px;border-radius:3px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc)}.pv2-legend{display:flex;flex-wrap:wrap;gap:4px 12px;margin-top:6px;font-size:12px}.pv2-legend-item{display:inline-flex;align-items:center;gap:5px}.pv2-swatch{width:10px;height:10px;border-radius:2px}.pv2-chart{display:grid;grid-template-columns:auto 1fr;gap:2px 6px}.pv2-chart-y{display:flex;flex-direction:column;justify-content:space-between;height:110px;color:var(--p-text-muted-color, #64748b);font-size:11px;text-align:right;line-height:1}.pv2-chart-plot{position:relative;height:110px;border-left:1px solid var(--p-content-border-color, #e2e8f0);border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-chart-plot svg{display:block;width:100%;height:100%}.pv2-chart-grid{stroke:var(--p-content-border-color, #e2e8f0);stroke-dasharray:3 3}.pv2-chart-last{position:absolute;width:8px;height:8px;border:2px solid var(--p-content-background, #fff);border-radius:50%;transform:translate(-50%,-50%)}.pv2-chart-x{display:flex;justify-content:space-between;color:var(--p-text-muted-color, #64748b);font-size:11px}.pv2-caption{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-mini{width:100%;font-size:12px}.pv2-mini th{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-weight:500}.pv2-mini td{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-ellipsis{display:inline-block;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.pv2-d-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px;margin-top:16px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);color:var(--p-text-color, #334155);font-size:13px;cursor:pointer}.pv2-btn:hover{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca)}\n"], dependencies: [{ kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i9.EsFormInputComponent, selector: "form-input", inputs: ["minlength", "maxlength", "pattern", "Password", "Type"] }, { kind: "component", type: i9.EsFormSelectComponent, selector: "form-select", inputs: ["OptionsTemplate"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }, { kind: "pipe", type: ProfilerFormatPipe, name: "pv2fmt" }] }); }
|
|
2794
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerV2Component, deps: [{ token: i1$1.DateService }, { token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: i4.Router }, { token: i5.Location }, { token: AdminModuleBaseService }, { token: ADM_MODULE_PATH }, { token: ADM_WORKLOAD_V2, optional: true }, { token: ADM_DETAILS_V2, optional: true }, { token: ADM_TOPACT_V2, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2795
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmProfilerV2Component, isStandalone: false, selector: "profiler_v2", providers: [{ provide: LocalizationService, useClass: AdmProfilerV2Loc }], viewQueries: [{ propertyName: "dlgDetailsV2", first: true, predicate: ["dlgDetailsV2"], descendants: true }, { propertyName: "detailsV2", first: true, predicate: AdmDetailsV2Component, descendants: true }], ngImport: i0, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span>\r\n </div>\r\n <div class=\"card-body widget-body pv2-body\">\r\n <!-- Barra dei comandi: quali dati caricare. Ogni cambio ricarica la vista e il dettaglio aperto -->\r\n <div class=\"pv2-toolbar\">\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Sorgente' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"live\" (click)=\"setLive(true)\"><span class=\"pv2-live-dot\"></span>Live</button>\r\n <button type=\"button\" [class.pv2-on]=\"!live\" (click)=\"setLive(false)\">{{'Storico' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n <div class=\"pv2-field pv2-field-wide pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"instance\" (ngModelChange)=\"setInstance($event)\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanze' | localize: lc\"></form-select>\r\n </div>\r\n </div>\r\n\r\n @if (!live) {\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterfrom\" (ngModelChange)=\"filterfrom = $event; datesChanged()\" name=\"filterfrom\" [Placeholder]=\"'Dal' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterto\" (ngModelChange)=\"filterto = $event; datesChanged()\" name=\"filterto\" [Placeholder]=\"'Al' | localize: lc\"></form-datetime>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Valori' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"!snapValues\" (click)=\"setSnapValues(false)\">{{\"Dall'avvio\" | localize: lc}}</button>\r\n <button type=\"button\" [class.pv2-on]=\"snapValues\" (click)=\"setSnapValues(true)\">{{\"Dall'ultimo snapshot\" | localize: lc}}</button>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"pv2-cluster pv2-cluster-end\">\r\n <button type=\"button\" class=\"btn app-btn-search\" [disabled]=\"loading\" (click)=\"reloadAll()\" [title]=\"'Aggiorna' | localize: lc\">\r\n <i class=\"fa fa-refresh\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n <button type=\"button\" class=\"btn app-btn-search\" (click)=\"downloadWorkloadReport()\" [title]=\"(workloadV2 ? 'Workload report' : 'Scarica il workload report') | localize: lc\">\r\n <i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Riga della finestra: sempre visibile sopra la vista -->\r\n <div class=\"pv2-window\">\r\n <span><strong>{{live ? 'Live' : ('Storico' | localize: lc)}}</strong> · {{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}} · {{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\">›</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\">×</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}} «{{activeSearch}}».</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}} · {{omittedTime(row.node) | pv2fmt: 'dur'}}\r\n @if (!snapMode) {\r\n · {{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)}} · {{'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}} · {{detail.numDescendants | pv2fmt: 'int'}} {{'discendenti' | localize: lc}}</span>\r\n <button type=\"button\" class=\"pv2-btn\" (click)=\"setRoot(detail.nodeId)\"><i class=\"fa fa-sitemap\"></i> {{'Apri come radice' | localize: lc}}</button>\r\n </div>\r\n }\r\n </aside>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Dettaglio completo del nodo (DirectorFeature.DetailsV2) -->\r\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\r\n @if (detailsV2Enabled) {\r\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"!!topActV2Enabled\" [CanOpenProfiler]=\"true\" (closed)=\"dlgDetailsV2.hide()\"\r\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"rootFromDetails($event)\"></adm-details-v2>\r\n }\r\n</div>\r\n", styles: ["@charset \"UTF-8\";:host{display:block}:host ::ng-deep .pv2-noclear .p-select-clear-icon{display:none}.pv2-body{container-type:inline-size}.pv2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;padding-top:6px}.pv2-cluster{display:flex;flex-wrap:nowrap;align-items:center;gap:10px}.pv2-cluster-end{margin-left:auto}.pv2-field{width:190px}.pv2-field-wide{width:290px}.pv2-field-narrow{width:140px}.pv2-field-search{flex:1 1 220px;min-width:200px;max-width:340px}.pv2-toggle{display:flex;align-items:center;gap:8px;height:39px;white-space:nowrap}.pv2-pointer{cursor:pointer}.pv2-group{position:relative;display:inline-flex}.pv2-group.pv2-disabled{opacity:.5}.pv2-group-label{position:absolute;top:-8px;left:8px;z-index:1;padding:0 4px;background:var(--p-content-background, #fff);color:var(--p-text-muted-color, #64748b);font-size:12px;line-height:15px;white-space:nowrap;pointer-events:none}.pv2-seg{display:inline-flex;height:39px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden;background:var(--p-content-background, #fff)}.pv2-seg button{display:inline-flex;align-items:center;gap:6px;padding:0 12px;border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;color:var(--p-text-color, #334155);font-size:13px;white-space:nowrap;cursor:pointer}.pv2-seg button:first-child{border-left:0}.pv2-seg button:hover:not(.pv2-on):not(:disabled){background:var(--p-content-hover-background, #f8fafc)}.pv2-seg button:disabled{cursor:default}.pv2-seg button:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:-2px}.pv2-seg button.pv2-on{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca);font-weight:500;box-shadow:inset 0 -2px 0 var(--p-primary-color, #6366f1)}.pv2-live-dot{width:8px;height:8px;border-radius:50%;background:#16a34a}.pv2-window{display:flex;flex-wrap:wrap;align-items:center;row-gap:4px;margin-top:12px;padding:7px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-color, #334155);font-size:13px}.pv2-window>span+span:before{content:\"\\b7\";margin:0 10px;color:var(--p-text-muted-color, #64748b)}.pv2-warn-text{color:#92400e}.pv2-main{display:grid;grid-template-columns:minmax(0,1fr) 380px;gap:14px;align-items:start;margin-top:14px}@container (max-width: 1350px){.pv2-main{grid-template-columns:minmax(0,1fr)}.pv2-detail{position:static;max-height:none}}.pv2-panel{padding:12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);min-width:0}.pv2-view-bar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px;padding-top:6px;margin-bottom:10px}.pv2-crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;margin-bottom:8px;font-size:12px}.pv2-crumb{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:2px 6px;border:0;border-radius:4px;background:transparent;color:var(--p-primary-color, #6366f1);cursor:pointer}.pv2-crumb:hover{background:var(--p-highlight-background, #eef2ff)}.pv2-crumb-current{color:var(--p-text-color, #334155);font-weight:500;cursor:default}.pv2-crumb-current:hover{background:transparent}.pv2-crumb-sep{color:var(--p-text-muted-color, #64748b)}.pv2-alert{position:relative;margin-bottom:8px;padding:6px 30px 6px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-size:13px}.pv2-alert.pv2-alert-warn{border-color:#fcd34d;background:#fffbeb;color:#92400e}.pv2-alert.pv2-alert-error{border-color:#fca5a5;background:#fef2f2;color:#991b1b}.pv2-alert-close{position:absolute;top:3px;right:6px;border:0;background:transparent;color:inherit;font-size:16px;cursor:pointer}.pv2-table-wrap{max-height:68vh;overflow:auto;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px)}.pv2-table-wrap:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:1px}.pv2-table{width:100%;border-collapse:separate;border-spacing:0;font-size:13px;color:var(--p-text-color, #334155)}.pv2-table th{position:sticky;top:0;z-index:1;padding:7px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-muted-color, #64748b);font-size:12px;font-weight:500;white-space:nowrap;text-align:left}.pv2-table td{padding:4px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);white-space:nowrap;vertical-align:middle}.pv2-col-node{width:100%;max-width:0}.pv2-col-node .pv2-node{min-width:260px}.pv2-num{text-align:right!important;font-variant-numeric:tabular-nums}.pv2-row{cursor:pointer}.pv2-row:hover td{background:var(--p-content-hover-background, #f8fafc)}.pv2-row.pv2-selected td{background:var(--p-highlight-background, #eef2ff)}.pv2-row.pv2-idle td{color:var(--p-text-muted-color, #64748b)}.pv2-row.pv2-idle td .pv2-name{opacity:.75}.pv2-node{display:flex;align-items:center;gap:6px;min-width:0}.pv2-caret{flex:none;width:18px;height:20px;padding:0;border:0;background:transparent;color:var(--p-text-muted-color, #64748b);text-align:center;cursor:pointer}.pv2-type{flex:none;display:inline-flex;align-items:center;gap:5px;padding:0 6px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:10px;color:var(--p-text-muted-color, #64748b);font-size:11px;line-height:18px;white-space:nowrap}.pv2-dot{flex:none;display:inline-block;width:8px;height:8px;border-radius:50%}.pv2-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pv2-name mark{padding:0 1px;border-radius:2px;background:#fde68a;color:#1f2937}.pv2-perc{width:1%}.pv2-perc-cell{display:flex;align-items:center;gap:8px}.pv2-bar{flex:none;width:64px;height:7px;border-radius:2px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc);box-shadow:inset 0 0 0 1px var(--p-content-border-color, #e2e8f0)}.pv2-bar>div{height:100%}.pv2-threads>*+*{margin-left:8px}.pv2-active{display:inline-flex;align-items:center;gap:5px;font-weight:500}.pv2-active-dot{width:7px;height:7px;border-radius:50%;background:#16a34a;box-shadow:0 0 0 3px #16a34a2e}.pv2-long{display:inline-flex;align-items:center;gap:4px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:18px;white-space:nowrap}.pv2-service td{padding:5px 10px;color:var(--p-text-muted-color, #64748b);font-size:12px;background:var(--p-content-background, #fff)}.pv2-sub td{padding:8px 10px 10px 34px;background:var(--p-content-hover-background, #f8fafc);white-space:normal}.pv2-sub-title{margin-bottom:4px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-sub-item{display:flex;align-items:center;gap:10px;padding:2px 0}.pv2-sub-item code{font-size:12px}.pv2-link{margin-left:6px;padding:0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;cursor:pointer}.pv2-link:hover{text-decoration:underline}.pv2-empty{padding:28px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-footer{margin-top:8px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-muted{color:var(--p-text-muted-color, #64748b)}.pv2-small{font-size:12px}.pv2-detail{position:sticky;top:10px;max-height:calc(100vh - 20px);overflow:auto;font-size:13px;color:var(--p-text-color, #334155);transition:opacity .15s}.pv2-detail.pv2-stale{opacity:.55}.pv2-placeholder{padding:36px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-error-text{color:#dc2626}.pv2-d-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.pv2-fullname{max-height:140px;overflow:auto;padding:8px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-family:ui-monospace,Cascadia Mono,Consolas,monospace;font-size:12px;white-space:pre-wrap;word-break:break-word}.pv2-id{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-id code{font-size:12px}.pv2-d-title{margin:16px 0 6px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}.pv2-path{display:flex;flex-direction:column}.pv2-path-item{display:flex;align-items:center;gap:6px;max-width:100%;padding:2px 0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.pv2-path-item:hover{text-decoration:underline}.pv2-path-current{color:var(--p-text-color, #334155);font-weight:600;cursor:default}.pv2-path-current:hover{text-decoration:none}.pv2-kv{display:grid;grid-template-columns:auto 1fr;gap:3px 14px;margin:0}.pv2-kv dt{color:var(--p-text-muted-color, #64748b);font-weight:400}.pv2-kv dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}.pv2-stack{display:flex;height:12px;border-radius:3px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc)}.pv2-legend{display:flex;flex-wrap:wrap;gap:4px 12px;margin-top:6px;font-size:12px}.pv2-legend-item{display:inline-flex;align-items:center;gap:5px}.pv2-swatch{width:10px;height:10px;border-radius:2px}.pv2-chart{display:grid;grid-template-columns:auto 1fr;gap:2px 6px}.pv2-chart-y{display:flex;flex-direction:column;justify-content:space-between;height:110px;color:var(--p-text-muted-color, #64748b);font-size:11px;text-align:right;line-height:1}.pv2-chart-plot{position:relative;height:110px;border-left:1px solid var(--p-content-border-color, #e2e8f0);border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-chart-plot svg{display:block;width:100%;height:100%}.pv2-chart-grid{stroke:var(--p-content-border-color, #e2e8f0);stroke-dasharray:3 3}.pv2-chart-last{position:absolute;width:8px;height:8px;border:2px solid var(--p-content-background, #fff);border-radius:50%;transform:translate(-50%,-50%)}.pv2-chart-x{display:flex;justify-content:space-between;color:var(--p-text-muted-color, #64748b);font-size:11px}.pv2-caption{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-mini{width:100%;font-size:12px}.pv2-mini th{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-weight:500}.pv2-mini td{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-ellipsis{display:inline-block;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.pv2-d-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px;margin-top:16px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);color:var(--p-text-color, #334155);font-size:13px;cursor:pointer}.pv2-btn:hover{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca)}\n"], dependencies: [{ kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "component", type: i9.EsFormInputComponent, selector: "form-input", inputs: ["minlength", "maxlength", "pattern", "Password", "Type"] }, { kind: "component", type: i9.EsFormSelectComponent, selector: "form-select", inputs: ["OptionsTemplate"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: AdmDetailsV2Component, selector: "adm-details-v2", inputs: ["Be", "CanShowSessions", "CanOpenProfiler"], outputs: ["closed", "sessionsOnEvent", "openProfiler"] }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }, { kind: "pipe", type: ProfilerFormatPipe, name: "pv2fmt" }] }); }
|
|
1973
2796
|
}
|
|
1974
2797
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerV2Component, decorators: [{
|
|
1975
2798
|
type: Component,
|
|
1976
|
-
args: [{ selector: "profiler_v2", providers: [{ provide: LocalizationService, useClass: AdmProfilerV2Loc }], standalone: false, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span>\r\n </div>\r\n <div class=\"card-body widget-body pv2-body\">\r\n <!-- Barra dei comandi: quali dati caricare. Ogni cambio ricarica la vista e il dettaglio aperto -->\r\n <div class=\"pv2-toolbar\">\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Sorgente' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"live\" (click)=\"setLive(true)\"><span class=\"pv2-live-dot\"></span>Live</button>\r\n <button type=\"button\" [class.pv2-on]=\"!live\" (click)=\"setLive(false)\">{{'Storico' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n <div class=\"pv2-field pv2-field-wide pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"instance\" (ngModelChange)=\"setInstance($event)\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanze' | localize: lc\"></form-select>\r\n </div>\r\n </div>\r\n\r\n @if (!live) {\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterfrom\" (ngModelChange)=\"filterfrom = $event; datesChanged()\" name=\"filterfrom\" [Placeholder]=\"'Dal' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterto\" (ngModelChange)=\"filterto = $event; datesChanged()\" name=\"filterto\" [Placeholder]=\"'Al' | localize: lc\"></form-datetime>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Valori' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"!snapValues\" (click)=\"setSnapValues(false)\">{{\"Dall'avvio\" | localize: lc}}</button>\r\n <button type=\"button\" [class.pv2-on]=\"snapValues\" (click)=\"setSnapValues(true)\">{{\"Dall'ultimo snapshot\" | localize: lc}}</button>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"pv2-cluster pv2-cluster-end\">\r\n <button type=\"button\" class=\"btn app-btn-search\" [disabled]=\"loading\" (click)=\"reloadAll()\" [title]=\"'Aggiorna' | localize: lc\">\r\n <i class=\"fa fa-refresh\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n <button type=\"button\" class=\"btn app-btn-search\" (click)=\"downloadWorkloadReport()\" [title]=\"(workloadV2 ? 'Workload report' : 'Scarica il workload report') | localize: lc\">\r\n <i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Riga della finestra: sempre visibile sopra la vista -->\r\n <div class=\"pv2-window\">\r\n <span><strong>{{live ? 'Live' : ('Storico' | localize: lc)}}</strong> · {{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}} · {{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\">›</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\">×</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}} «{{activeSearch}}».</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}} · {{omittedTime(row.node) | pv2fmt: 'dur'}}\r\n @if (!snapMode) {\r\n · {{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)}} · {{'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}} · {{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: 1000px){.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%;min-width:740px;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-num{text-align:right!important;font-variant-numeric:tabular-nums}.pv2-row{cursor:pointer}.pv2-row:hover td{background:var(--p-content-hover-background, #f8fafc)}.pv2-row.pv2-selected td{background:var(--p-highlight-background, #eef2ff)}.pv2-row.pv2-idle td{color:var(--p-text-muted-color, #64748b)}.pv2-row.pv2-idle td .pv2-name{opacity:.75}.pv2-node{display:flex;align-items:center;gap:6px;min-width:0}.pv2-caret{flex:none;width:18px;height:20px;padding:0;border:0;background:transparent;color:var(--p-text-muted-color, #64748b);text-align:center;cursor:pointer}.pv2-type{flex:none;display:inline-flex;align-items:center;gap:5px;padding:0 6px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:10px;color:var(--p-text-muted-color, #64748b);font-size:11px;line-height:18px;white-space:nowrap}.pv2-dot{flex:none;display:inline-block;width:8px;height:8px;border-radius:50%}.pv2-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pv2-name mark{padding:0 1px;border-radius:2px;background:#fde68a;color:#1f2937}.pv2-perc{width:1%}.pv2-perc-cell{display:flex;align-items:center;gap:8px}.pv2-bar{flex:none;width:64px;height:7px;border-radius:2px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc);box-shadow:inset 0 0 0 1px var(--p-content-border-color, #e2e8f0)}.pv2-bar>div{height:100%}.pv2-threads>*+*{margin-left:8px}.pv2-active{display:inline-flex;align-items:center;gap:5px;font-weight:500}.pv2-active-dot{width:7px;height:7px;border-radius:50%;background:#16a34a;box-shadow:0 0 0 3px #16a34a2e}.pv2-long{display:inline-flex;align-items:center;gap:4px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:18px;white-space:nowrap}.pv2-service td{padding:5px 10px;color:var(--p-text-muted-color, #64748b);font-size:12px;background:var(--p-content-background, #fff)}.pv2-sub td{padding:8px 10px 10px 34px;background:var(--p-content-hover-background, #f8fafc);white-space:normal}.pv2-sub-title{margin-bottom:4px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-sub-item{display:flex;align-items:center;gap:10px;padding:2px 0}.pv2-sub-item code{font-size:12px}.pv2-link{margin-left:6px;padding:0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;cursor:pointer}.pv2-link:hover{text-decoration:underline}.pv2-empty{padding:28px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-footer{margin-top:8px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-muted{color:var(--p-text-muted-color, #64748b)}.pv2-small{font-size:12px}.pv2-detail{position:sticky;top:10px;max-height:calc(100vh - 20px);overflow:auto;font-size:13px;color:var(--p-text-color, #334155);transition:opacity .15s}.pv2-detail.pv2-stale{opacity:.55}.pv2-placeholder{padding:36px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-error-text{color:#dc2626}.pv2-d-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.pv2-fullname{max-height:140px;overflow:auto;padding:8px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-family:ui-monospace,Cascadia Mono,Consolas,monospace;font-size:12px;white-space:pre-wrap;word-break:break-word}.pv2-id{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-id code{font-size:12px}.pv2-d-title{margin:16px 0 6px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}.pv2-path{display:flex;flex-direction:column}.pv2-path-item{display:flex;align-items:center;gap:6px;max-width:100%;padding:2px 0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.pv2-path-item:hover{text-decoration:underline}.pv2-path-current{color:var(--p-text-color, #334155);font-weight:600;cursor:default}.pv2-path-current:hover{text-decoration:none}.pv2-kv{display:grid;grid-template-columns:auto 1fr;gap:3px 14px;margin:0}.pv2-kv dt{color:var(--p-text-muted-color, #64748b);font-weight:400}.pv2-kv dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}.pv2-stack{display:flex;height:12px;border-radius:3px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc)}.pv2-legend{display:flex;flex-wrap:wrap;gap:4px 12px;margin-top:6px;font-size:12px}.pv2-legend-item{display:inline-flex;align-items:center;gap:5px}.pv2-swatch{width:10px;height:10px;border-radius:2px}.pv2-chart{display:grid;grid-template-columns:auto 1fr;gap:2px 6px}.pv2-chart-y{display:flex;flex-direction:column;justify-content:space-between;height:110px;color:var(--p-text-muted-color, #64748b);font-size:11px;text-align:right;line-height:1}.pv2-chart-plot{position:relative;height:110px;border-left:1px solid var(--p-content-border-color, #e2e8f0);border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-chart-plot svg{display:block;width:100%;height:100%}.pv2-chart-grid{stroke:var(--p-content-border-color, #e2e8f0);stroke-dasharray:3 3}.pv2-chart-last{position:absolute;width:8px;height:8px;border:2px solid var(--p-content-background, #fff);border-radius:50%;transform:translate(-50%,-50%)}.pv2-chart-x{display:flex;justify-content:space-between;color:var(--p-text-muted-color, #64748b);font-size:11px}.pv2-caption{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-mini{width:100%;font-size:12px}.pv2-mini th{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-weight:500}.pv2-mini td{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-ellipsis{display:inline-block;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.pv2-d-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px;margin-top:16px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);color:var(--p-text-color, #334155);font-size:13px;cursor:pointer}.pv2-btn:hover{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca)}\n"] }]
|
|
2799
|
+
args: [{ selector: "profiler_v2", providers: [{ provide: LocalizationService, useClass: AdmProfilerV2Loc }], standalone: false, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">{{'Profiler del Server' | localize: lc}}</span>\r\n </div>\r\n <div class=\"card-body widget-body pv2-body\">\r\n <!-- Barra dei comandi: quali dati caricare. Ogni cambio ricarica la vista e il dettaglio aperto -->\r\n <div class=\"pv2-toolbar\">\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Sorgente' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"live\" (click)=\"setLive(true)\"><span class=\"pv2-live-dot\"></span>Live</button>\r\n <button type=\"button\" [class.pv2-on]=\"!live\" (click)=\"setLive(false)\">{{'Storico' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n <div class=\"pv2-field pv2-field-wide pv2-noclear\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"instance\" (ngModelChange)=\"setInstance($event)\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanze' | localize: lc\"></form-select>\r\n </div>\r\n </div>\r\n\r\n @if (!live) {\r\n <div class=\"pv2-cluster\">\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterfrom\" (ngModelChange)=\"filterfrom = $event; datesChanged()\" name=\"filterfrom\" [Placeholder]=\"'Dal' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"pv2-field\">\r\n <form-datetime [FormLayout]=\"false\" [Validation]=\"false\" [ngModel]=\"filterto\" (ngModelChange)=\"filterto = $event; datesChanged()\" name=\"filterto\" [Placeholder]=\"'Al' | localize: lc\"></form-datetime>\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"pv2-group\">\r\n <span class=\"pv2-group-label\">{{'Valori' | localize: lc}}</span>\r\n <div class=\"pv2-seg\">\r\n <button type=\"button\" [class.pv2-on]=\"!snapValues\" (click)=\"setSnapValues(false)\">{{\"Dall'avvio\" | localize: lc}}</button>\r\n <button type=\"button\" [class.pv2-on]=\"snapValues\" (click)=\"setSnapValues(true)\">{{\"Dall'ultimo snapshot\" | localize: lc}}</button>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"pv2-cluster pv2-cluster-end\">\r\n <button type=\"button\" class=\"btn app-btn-search\" [disabled]=\"loading\" (click)=\"reloadAll()\" [title]=\"'Aggiorna' | localize: lc\">\r\n <i class=\"fa fa-refresh\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n <button type=\"button\" class=\"btn app-btn-search\" (click)=\"downloadWorkloadReport()\" [title]=\"(workloadV2 ? 'Workload report' : 'Scarica il workload report') | localize: lc\">\r\n <i class=\"fa\" [class.fa-download]=\"!workloadV2\" [class.fa-file-text]=\"workloadV2\"></i>\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- Riga della finestra: sempre visibile sopra la vista -->\r\n <div class=\"pv2-window\">\r\n <span><strong>{{live ? 'Live' : ('Storico' | localize: lc)}}</strong> · {{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}} · {{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\">›</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\">×</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}} «{{activeSearch}}».</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}} · {{omittedTime(row.node) | pv2fmt: 'dur'}}\r\n @if (!snapMode) {\r\n · {{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)}} · {{'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}} · {{detail.numDescendants | pv2fmt: 'int'}} {{'discendenti' | localize: lc}}</span>\r\n <button type=\"button\" class=\"pv2-btn\" (click)=\"setRoot(detail.nodeId)\"><i class=\"fa fa-sitemap\"></i> {{'Apri come radice' | localize: lc}}</button>\r\n </div>\r\n }\r\n </aside>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Dettaglio completo del nodo (DirectorFeature.DetailsV2) -->\r\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\r\n @if (detailsV2Enabled) {\r\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"!!topActV2Enabled\" [CanOpenProfiler]=\"true\" (closed)=\"dlgDetailsV2.hide()\"\r\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"rootFromDetails($event)\"></adm-details-v2>\r\n }\r\n</div>\r\n", styles: ["@charset \"UTF-8\";:host{display:block}:host ::ng-deep .pv2-noclear .p-select-clear-icon{display:none}.pv2-body{container-type:inline-size}.pv2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;padding-top:6px}.pv2-cluster{display:flex;flex-wrap:nowrap;align-items:center;gap:10px}.pv2-cluster-end{margin-left:auto}.pv2-field{width:190px}.pv2-field-wide{width:290px}.pv2-field-narrow{width:140px}.pv2-field-search{flex:1 1 220px;min-width:200px;max-width:340px}.pv2-toggle{display:flex;align-items:center;gap:8px;height:39px;white-space:nowrap}.pv2-pointer{cursor:pointer}.pv2-group{position:relative;display:inline-flex}.pv2-group.pv2-disabled{opacity:.5}.pv2-group-label{position:absolute;top:-8px;left:8px;z-index:1;padding:0 4px;background:var(--p-content-background, #fff);color:var(--p-text-muted-color, #64748b);font-size:12px;line-height:15px;white-space:nowrap;pointer-events:none}.pv2-seg{display:inline-flex;height:39px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden;background:var(--p-content-background, #fff)}.pv2-seg button{display:inline-flex;align-items:center;gap:6px;padding:0 12px;border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;color:var(--p-text-color, #334155);font-size:13px;white-space:nowrap;cursor:pointer}.pv2-seg button:first-child{border-left:0}.pv2-seg button:hover:not(.pv2-on):not(:disabled){background:var(--p-content-hover-background, #f8fafc)}.pv2-seg button:disabled{cursor:default}.pv2-seg button:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:-2px}.pv2-seg button.pv2-on{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca);font-weight:500;box-shadow:inset 0 -2px 0 var(--p-primary-color, #6366f1)}.pv2-live-dot{width:8px;height:8px;border-radius:50%;background:#16a34a}.pv2-window{display:flex;flex-wrap:wrap;align-items:center;row-gap:4px;margin-top:12px;padding:7px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-color, #334155);font-size:13px}.pv2-window>span+span:before{content:\"\\b7\";margin:0 10px;color:var(--p-text-muted-color, #64748b)}.pv2-warn-text{color:#92400e}.pv2-main{display:grid;grid-template-columns:minmax(0,1fr) 380px;gap:14px;align-items:start;margin-top:14px}@container (max-width: 1350px){.pv2-main{grid-template-columns:minmax(0,1fr)}.pv2-detail{position:static;max-height:none}}.pv2-panel{padding:12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);min-width:0}.pv2-view-bar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px;padding-top:6px;margin-bottom:10px}.pv2-crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;margin-bottom:8px;font-size:12px}.pv2-crumb{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:2px 6px;border:0;border-radius:4px;background:transparent;color:var(--p-primary-color, #6366f1);cursor:pointer}.pv2-crumb:hover{background:var(--p-highlight-background, #eef2ff)}.pv2-crumb-current{color:var(--p-text-color, #334155);font-weight:500;cursor:default}.pv2-crumb-current:hover{background:transparent}.pv2-crumb-sep{color:var(--p-text-muted-color, #64748b)}.pv2-alert{position:relative;margin-bottom:8px;padding:6px 30px 6px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-size:13px}.pv2-alert.pv2-alert-warn{border-color:#fcd34d;background:#fffbeb;color:#92400e}.pv2-alert.pv2-alert-error{border-color:#fca5a5;background:#fef2f2;color:#991b1b}.pv2-alert-close{position:absolute;top:3px;right:6px;border:0;background:transparent;color:inherit;font-size:16px;cursor:pointer}.pv2-table-wrap{max-height:68vh;overflow:auto;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px)}.pv2-table-wrap:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:1px}.pv2-table{width:100%;border-collapse:separate;border-spacing:0;font-size:13px;color:var(--p-text-color, #334155)}.pv2-table th{position:sticky;top:0;z-index:1;padding:7px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-muted-color, #64748b);font-size:12px;font-weight:500;white-space:nowrap;text-align:left}.pv2-table td{padding:4px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);white-space:nowrap;vertical-align:middle}.pv2-col-node{width:100%;max-width:0}.pv2-col-node .pv2-node{min-width:260px}.pv2-num{text-align:right!important;font-variant-numeric:tabular-nums}.pv2-row{cursor:pointer}.pv2-row:hover td{background:var(--p-content-hover-background, #f8fafc)}.pv2-row.pv2-selected td{background:var(--p-highlight-background, #eef2ff)}.pv2-row.pv2-idle td{color:var(--p-text-muted-color, #64748b)}.pv2-row.pv2-idle td .pv2-name{opacity:.75}.pv2-node{display:flex;align-items:center;gap:6px;min-width:0}.pv2-caret{flex:none;width:18px;height:20px;padding:0;border:0;background:transparent;color:var(--p-text-muted-color, #64748b);text-align:center;cursor:pointer}.pv2-type{flex:none;display:inline-flex;align-items:center;gap:5px;padding:0 6px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:10px;color:var(--p-text-muted-color, #64748b);font-size:11px;line-height:18px;white-space:nowrap}.pv2-dot{flex:none;display:inline-block;width:8px;height:8px;border-radius:50%}.pv2-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pv2-name mark{padding:0 1px;border-radius:2px;background:#fde68a;color:#1f2937}.pv2-perc{width:1%}.pv2-perc-cell{display:flex;align-items:center;gap:8px}.pv2-bar{flex:none;width:64px;height:7px;border-radius:2px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc);box-shadow:inset 0 0 0 1px var(--p-content-border-color, #e2e8f0)}.pv2-bar>div{height:100%}.pv2-threads>*+*{margin-left:8px}.pv2-active{display:inline-flex;align-items:center;gap:5px;font-weight:500}.pv2-active-dot{width:7px;height:7px;border-radius:50%;background:#16a34a;box-shadow:0 0 0 3px #16a34a2e}.pv2-long{display:inline-flex;align-items:center;gap:4px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:18px;white-space:nowrap}.pv2-service td{padding:5px 10px;color:var(--p-text-muted-color, #64748b);font-size:12px;background:var(--p-content-background, #fff)}.pv2-sub td{padding:8px 10px 10px 34px;background:var(--p-content-hover-background, #f8fafc);white-space:normal}.pv2-sub-title{margin-bottom:4px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-sub-item{display:flex;align-items:center;gap:10px;padding:2px 0}.pv2-sub-item code{font-size:12px}.pv2-link{margin-left:6px;padding:0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;cursor:pointer}.pv2-link:hover{text-decoration:underline}.pv2-empty{padding:28px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-footer{margin-top:8px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-muted{color:var(--p-text-muted-color, #64748b)}.pv2-small{font-size:12px}.pv2-detail{position:sticky;top:10px;max-height:calc(100vh - 20px);overflow:auto;font-size:13px;color:var(--p-text-color, #334155);transition:opacity .15s}.pv2-detail.pv2-stale{opacity:.55}.pv2-placeholder{padding:36px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-error-text{color:#dc2626}.pv2-d-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.pv2-fullname{max-height:140px;overflow:auto;padding:8px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-family:ui-monospace,Cascadia Mono,Consolas,monospace;font-size:12px;white-space:pre-wrap;word-break:break-word}.pv2-id{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-id code{font-size:12px}.pv2-d-title{margin:16px 0 6px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}.pv2-path{display:flex;flex-direction:column}.pv2-path-item{display:flex;align-items:center;gap:6px;max-width:100%;padding:2px 0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.pv2-path-item:hover{text-decoration:underline}.pv2-path-current{color:var(--p-text-color, #334155);font-weight:600;cursor:default}.pv2-path-current:hover{text-decoration:none}.pv2-kv{display:grid;grid-template-columns:auto 1fr;gap:3px 14px;margin:0}.pv2-kv dt{color:var(--p-text-muted-color, #64748b);font-weight:400}.pv2-kv dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}.pv2-stack{display:flex;height:12px;border-radius:3px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc)}.pv2-legend{display:flex;flex-wrap:wrap;gap:4px 12px;margin-top:6px;font-size:12px}.pv2-legend-item{display:inline-flex;align-items:center;gap:5px}.pv2-swatch{width:10px;height:10px;border-radius:2px}.pv2-chart{display:grid;grid-template-columns:auto 1fr;gap:2px 6px}.pv2-chart-y{display:flex;flex-direction:column;justify-content:space-between;height:110px;color:var(--p-text-muted-color, #64748b);font-size:11px;text-align:right;line-height:1}.pv2-chart-plot{position:relative;height:110px;border-left:1px solid var(--p-content-border-color, #e2e8f0);border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-chart-plot svg{display:block;width:100%;height:100%}.pv2-chart-grid{stroke:var(--p-content-border-color, #e2e8f0);stroke-dasharray:3 3}.pv2-chart-last{position:absolute;width:8px;height:8px;border:2px solid var(--p-content-background, #fff);border-radius:50%;transform:translate(-50%,-50%)}.pv2-chart-x{display:flex;justify-content:space-between;color:var(--p-text-muted-color, #64748b);font-size:11px}.pv2-caption{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-mini{width:100%;font-size:12px}.pv2-mini th{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-weight:500}.pv2-mini td{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-ellipsis{display:inline-block;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.pv2-d-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px;margin-top:16px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);color:var(--p-text-color, #334155);font-size:13px;cursor:pointer}.pv2-btn:hover{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca)}\n"] }]
|
|
1977
2800
|
}], ctorParameters: () => [{ type: i1$1.DateService }, { type: i1.LocalizationService }, { type: i3.PreferencesService }, { type: i1$1.InterComService }, { type: i4.ActivatedRoute }, { type: i4.Router }, { type: i5.Location }, { type: AdminModuleBaseService }, { type: undefined, decorators: [{
|
|
1978
2801
|
type: Inject,
|
|
1979
2802
|
args: [ADM_MODULE_PATH]
|
|
@@ -1982,7 +2805,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
1982
2805
|
}, {
|
|
1983
2806
|
type: Inject,
|
|
1984
2807
|
args: [ADM_WORKLOAD_V2]
|
|
1985
|
-
}] }
|
|
2808
|
+
}] }, { type: undefined, decorators: [{
|
|
2809
|
+
type: Optional
|
|
2810
|
+
}, {
|
|
2811
|
+
type: Inject,
|
|
2812
|
+
args: [ADM_DETAILS_V2]
|
|
2813
|
+
}] }, { type: undefined, decorators: [{
|
|
2814
|
+
type: Optional
|
|
2815
|
+
}, {
|
|
2816
|
+
type: Inject,
|
|
2817
|
+
args: [ADM_TOPACT_V2]
|
|
2818
|
+
}] }], propDecorators: { dlgDetailsV2: [{
|
|
2819
|
+
type: ViewChild,
|
|
2820
|
+
args: ["dlgDetailsV2"]
|
|
2821
|
+
}], detailsV2: [{
|
|
2822
|
+
type: ViewChild,
|
|
2823
|
+
args: [AdmDetailsV2Component]
|
|
2824
|
+
}] } });
|
|
1986
2825
|
|
|
1987
2826
|
// Workload report v2 (specifica "Workload report"): richieste e risposte come le vuole e le manda il backend (camelCase).
|
|
1988
2827
|
// Le date delle risposte sono UTC "dd/MM/yyyy HH:mm:ss" senza fuso
|
|
@@ -2657,6 +3496,12 @@ class MetricsV2ChartComponent {
|
|
|
2657
3496
|
case "line":
|
|
2658
3497
|
case "step":
|
|
2659
3498
|
paths.push({ key: s.key, d: this.linePath(points, s.kind == "step"), color: s.color, fill: false, dash: s.dash ?? null, opacity: s.opacity ?? 1 });
|
|
3499
|
+
// Un punto senza vicini (per esempio la durata di un timer con poche chiamate) come linea non si vedrebbe: diventa un pallino
|
|
3500
|
+
if ((s.opacity ?? 1) > 0)
|
|
3501
|
+
points.forEach((p, i) => {
|
|
3502
|
+
if ((i == 0 || p.gap) && (i == points.length - 1 || points[i + 1].gap))
|
|
3503
|
+
dots.push({ key: `${s.key}~${i}`, x: this.x(p.t), y: this.y(p.v), color: s.color });
|
|
3504
|
+
});
|
|
2660
3505
|
break;
|
|
2661
3506
|
case "band":
|
|
2662
3507
|
paths.push({ key: s.key, d: this.bandPath(points), color: s.color, fill: true, dash: null, opacity: s.opacity ?? 0.2 });
|
|
@@ -3843,7 +4688,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
3843
4688
|
|
|
3844
4689
|
// Angular
|
|
3845
4690
|
class AdmTopActivitiesComponent {
|
|
3846
|
-
constructor(dateExts, lc, localStorage, location, intercom, route, adms, mod
|
|
4691
|
+
constructor(dateExts, lc, localStorage, location, intercom, route, adms, mod, router,
|
|
4692
|
+
// Con DirectorFeature.DetailsV2 il backend-for-frontend risponde a GetNodeStats e GetSessionStats solo con il contratto nuovo:
|
|
4693
|
+
// nodi e sessioni si aprono nel dettaglio v2 anche da questa pagina
|
|
4694
|
+
detailsV2Enabled, profilerV2Enabled) {
|
|
3847
4695
|
this.dateExts = dateExts;
|
|
3848
4696
|
this.lc = lc;
|
|
3849
4697
|
this.localStorage = localStorage;
|
|
@@ -3852,6 +4700,9 @@ class AdmTopActivitiesComponent {
|
|
|
3852
4700
|
this.route = route;
|
|
3853
4701
|
this.adms = adms;
|
|
3854
4702
|
this.mod = mod;
|
|
4703
|
+
this.router = router;
|
|
4704
|
+
this.detailsV2Enabled = detailsV2Enabled;
|
|
4705
|
+
this.profilerV2Enabled = profilerV2Enabled;
|
|
3855
4706
|
this.searchView = new TopActivitiesDataView();
|
|
3856
4707
|
this.autoUpdate = false;
|
|
3857
4708
|
this.seconds = "5";
|
|
@@ -3953,6 +4804,38 @@ class AdmTopActivitiesComponent {
|
|
|
3953
4804
|
this.searchView.searchinprogress = false;
|
|
3954
4805
|
this.reviewBindings(update, res, dirinfos);
|
|
3955
4806
|
}
|
|
4807
|
+
openNodeDetails(nodeId) {
|
|
4808
|
+
if (this.detailsV2Enabled) {
|
|
4809
|
+
this.detailsV2.openNode(nodeId, { ...this.detailsWindow(), global: this.searchView.filterglobal });
|
|
4810
|
+
this.dlgDetailsV2.show();
|
|
4811
|
+
return;
|
|
4812
|
+
}
|
|
4813
|
+
this.loadNodeDetails(nodeId);
|
|
4814
|
+
this.dlgNodeDetails.show();
|
|
4815
|
+
}
|
|
4816
|
+
openSessionDetails(sessionId, serialNo, instanceid) {
|
|
4817
|
+
if (this.detailsV2Enabled) {
|
|
4818
|
+
this.detailsV2.openSession(instanceid, sessionId, serialNo, { ...this.detailsWindow(), realTime: !!this.searchView.filterrealtime });
|
|
4819
|
+
this.dlgDetailsV2.show();
|
|
4820
|
+
return;
|
|
4821
|
+
}
|
|
4822
|
+
this.loadSessionDetails(sessionId, serialNo, instanceid);
|
|
4823
|
+
this.dlgSessionDetails.show();
|
|
4824
|
+
}
|
|
4825
|
+
// La finestra della ricerca, di default l'ultima ora
|
|
4826
|
+
detailsWindow() {
|
|
4827
|
+
let to = this.searchView.filterto ? this.dateExts.getDateConvertion(this.searchView.filterto).toDate() : new Date();
|
|
4828
|
+
let from = this.searchView.filterfrom ? this.dateExts.getDateConvertion(this.searchView.filterfrom).toDate() : new Date(to.getTime() - 3600 * 1000);
|
|
4829
|
+
return { from: from, to: to };
|
|
4830
|
+
}
|
|
4831
|
+
// Senza la Top Activity v2 "Sessioni su questo evento" non si propone; il nodo come radice c'è solo nel profiler v2
|
|
4832
|
+
showEventSessions(link) {
|
|
4833
|
+
this.dlgDetailsV2.hide();
|
|
4834
|
+
}
|
|
4835
|
+
openInProfiler(nodeId) {
|
|
4836
|
+
this.dlgDetailsV2.hide();
|
|
4837
|
+
this.router.navigate([`/pages/${this.mod}/profiler`, ...(this.be ? [this.be] : [])], { queryParams: { root: nodeId } });
|
|
4838
|
+
}
|
|
3956
4839
|
loadNodeDetails(nodeId) {
|
|
3957
4840
|
this.NodeDetails = null;
|
|
3958
4841
|
requestAnimationFrame(async () => {
|
|
@@ -4058,53 +4941,38 @@ class AdmTopActivitiesComponent {
|
|
|
4058
4941
|
this.SelectedSessions = new LineChartData(series);
|
|
4059
4942
|
});
|
|
4060
4943
|
}
|
|
4061
|
-
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 }); }
|
|
4062
|
-
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\"> - \r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}} \r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg5 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span> \r\n <span *ngIf=\"DirInfosGlobal\"> | \r\n {{'' + DirInfosGlobal.cpus + ' ' + ('CPU (Global)' | localize: lc) + (DirInfosGlobal.rssplan ? ' - ' + DirInfosGlobal.rssplan : '')}} \r\n Load average: {{ DirInfosGlobal.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfosGlobal.lavg5 | number : '1.1-2' : 'it'}} {{ DirInfosGlobal.lavg15 | number : '1.1-2' : 'it'}}\r\n <span *ngIf=\"(DirInfosGlobal?.perinstancedata?.length || 0) > 0\">\r\n \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> \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> \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}} <input [readonly]=\"autoUpdate\" maxlength=\"3\" class=\"form-control app-updevery-input\" type=\"text\" [(ngModel)]=\"seconds\" name=\"seconds\" /> {{'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\">×</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>: \r\n {{'' + info.cpus + ' ' + ('CPU (Global)' | localize: lc) + (info.rssplan ? ' - ' + info.rssplan : '')}} \r\n Load average: {{ info.lavg1 | number : '1.1-2' : 'it'}} {{ info.lavg5 | number : '1.1-2' : 'it'}} {{ 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\"> {{SessionDetails.sid}}</span></h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"dlgSessionDetails.hide()\" aria-label=\"Close\"><span aria-hidden=\"true\">×</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>: {{SessionDetails.instanceid}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Seriale' | localize: lc}}</strong>: {{SessionDetails.serial}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Stato' | localize: lc}}</strong>: {{SessionDetails.status}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Tipo' | localize: lc}}</strong>: {{SessionDetails.type}}</div>\r\n <div class=\"col-md-6\"><strong>{{'Utente' | localize: lc}}</strong>: {{SessionDetails.user}} <span *ngIf=\"SessionDetails.tenant\">({{SessionDetails.tenant}})</span></div>\r\n </div>\r\n\r\n <div style=\"display: flex; width: 100%; margin-top: 15px;\">\r\n <div style=\"flex-grow: 0;display: flex;flex-direction: column\">\r\n <h5>Prime Istruzioni</h5>\r\n <div *ngIf=\"SelectedTopNodes\">\r\n <es-table [(ngModel)]=\"SelectedTopNodes\" [ArraymodeItemsPerPage]=\"10\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">{{'Nodo' | localize: lc}}</th>\r\n <th>{{'Descrizione Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n \r\n <ng-template #body let-node>\r\n <td class=\"app-col-min\"><span class=\"app-link\"(click)=\"loadNodeDetails(node.profnodeid); dlgNodeDetails.show();\">{{node.profnodeid}}</span></td>\r\n <td><span title=\"{{node.profnodedesc}}\">{{node.profnodedesc.length > 40 ? node.profnodedesc.substr(0,40) + \"...\" : node.profnodedesc}}</span></td>\r\n <td class=\"app-nowrap\">{{(node.activity == \"NaN\" ? null : node.activity) | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{node.nodetypename}}</td>\r\n <td>{{node.waitclassname}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n <div style=\"width: 15px;\"></div>\r\n <div style=\"flex-grow: 2;display: flex;flex-direction: column\">\r\n <h5>Attivit\u00E0</h5>\r\n <div *ngIf=\"SelectedSessions\" style=\"width: 100%; height: 290px\">\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [LegendPadding]=\"{top: 0, bottom: 7, right: 0, left: 10}\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"SelectedSessions\"\r\n [Legend]=\"true\" \r\n name=\"session_details\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event, true)\">\r\n </es-line-chart>\r\n </div>\r\n \r\n </div>\r\n </div>\r\n <div style=\"display: flex; width: 100%;\">\r\n <div style=\"flex-grow: 1;\">\r\n <h5>Statistiche Thread</h5>\r\n <div>\r\n <es-table [(ngModel)]=\"SessionDetails.threads\" [ArraymodeItemsPerPage]=\"10\" [Selection]=\"true\" [SingleSelection]=\"true\" (onSelectionChanged)=\"threadSelectionChanged($event)\">\r\n <ng-template #header>\r\n <th>Thread</th>\r\n <th>Stato</th>\r\n <th>Tipo</th>\r\n <th>API</th>\r\n <th>Attesa corrente</th>\r\n <th>Nodo di attesa</th>\r\n <th>Attesa su</th>\r\n <th>Classe</th>\r\n <th>Par. 1</th>\r\n <th>Par. 2</th>\r\n <th>Par. 3</th>\r\n <th>Tempo Attesa</th>\r\n </ng-template>\r\n \r\n <ng-template #body let-thread>\r\n <td>{{thread.tid}}</td>\r\n <td>{{thread.status}}</td>\r\n <td>{{thread.type}}</td>\r\n <td>{{thread.api}}</td>\r\n <td>{{thread.wait}}</td>\r\n <td>{{thread.waitnode}}</td>\r\n <td>{{thread.waiteventtype}}</td>\r\n <td>{{thread.waitclassname}}</td>\r\n <td>{{thread.waitpar1}}</td>\r\n <td>{{thread.waitpar2}}</td>\r\n <td>{{thread.waitpar3}}</td>\r\n <td>{{(thread.waittime == \"NaN\" ? null : thread.waittime) | number : '1.1-2' : 'it'}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"dlgSessionDetails.hide()\">{{'Chiudi' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>", dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i7.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "component", type: i8.EsTableComponent, selector: "es-table", inputs: ["globalCheck", "autoUpdate", "seconds", "researchInProgress", "globalColVisCheck", "EsThTdProvider", "CornerMenuOptions", "ColumnsResizable", "ColumnsPinnable", "AutoUpdate", "Height", "EmptySpaceBackgroundColor", "EsTableHandledSearch", "MaxHeight", "ContainerClass", "XLSXExport", "CSVExport", "AllSearch", "HighCellDensity", "Selection", "ShowLoadingOnBootstrap", "Removal", "RemovalCondition", "Export", "ShiftClick", "CountLabel", "HidePaging", "HidePagingCount", "HidePagingButtons", "ContextMenu", "ExportFileName", "TableClass", "ExportFunction", "ExportOnlyVisibleColumns", "HasHeaderGroup", "HasSecondaryHeaderGroup", "HeaderHidden", "BodyHidden", "SelectionDisabled", "SingleSelection", "RowClassAssigner", "OrderByColumn", "MultipleOrderingDirectives", "HiddenColumns", "ColumnsOrdering", "SearchView", "SelectAll", "UseArrayModePaging", "DynamicRowColumnsDefinition", "DynamicOperations", "Hierarchy", "ParentKey", "OwnKey", "AutoSortHierarchy", "StartsExpanded", "SavePreferences", "DefaultAlignment", "PagingStyle", "RowGroupingPagingStyle", "ItemSourceProperty", "UseSelectionCache", "ShowItemGroupsColumns", "Editable", "RangeSelection", "SearchThrottle", "ArraymodeItemsPerPage"], outputs: ["globalCheckChange", "autoUpdateChange", "secondsChange", "researchInProgressChange", "globalColVisCheckChange", "onOrderChanged", "onSearchRequest", "onSelectionChanged", "onRemoval", "onAbortRemoval", "onModelChange", "onOpenContextMenu", "onCornerAction", "onDynamicOperation"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "component", type: i2.EsLineChartComponent, selector: "es-line-chart", inputs: ["Data", "DataArray", "Step", "DataGroupBucketSize", "DataGroupingThreshold", "StrokeSize", "AllowGaps", "MergeDatasets", "FinalInstants", "Min", "Max", "Fill", "Stacked"] }, { kind: "directive", type: i10.Draggable, selector: "[emaDraggable]", inputs: ["emaDraggable"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: NodeDetailComponent, selector: "node-detail", inputs: ["NodeDetails"], outputs: ["onClose"] }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }] }); }
|
|
4944
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivitiesComponent, deps: [{ token: i1$1.DateService }, { token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i5.Location }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: AdminModuleBaseService }, { token: ADM_MODULE_PATH }, { token: i4.Router }, { token: ADM_DETAILS_V2, optional: true }, { token: ADM_PROFILER_V2, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4945
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmTopActivitiesComponent, isStandalone: false, selector: "topact_search", providers: [{ provide: LocalizationService, useClass: AdmTopActivitieLoc }], viewQueries: [{ propertyName: "dlgNodeDetails", first: true, predicate: ["dlgNodeDetails"], descendants: true }, { propertyName: "dlgSessionDetails", first: true, predicate: ["dlgSessionDetails"], descendants: true }, { propertyName: "dlgDetailsV2", first: true, predicate: ["dlgDetailsV2"], descendants: true }, { propertyName: "detailsV2", first: true, predicate: AdmDetailsV2Component, descendants: true }], ngImport: i0, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n <span *ngIf=\"DirInfos && !DirInfosGlobal\"> - \r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}} \r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg5 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span> \r\n <span *ngIf=\"DirInfosGlobal\"> | \r\n {{'' + DirInfosGlobal.cpus + ' ' + ('CPU (Global)' | localize: lc) + (DirInfosGlobal.rssplan ? ' - ' + DirInfosGlobal.rssplan : '')}} \r\n Load average: {{ DirInfosGlobal.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfosGlobal.lavg5 | number : '1.1-2' : 'it'}} {{ DirInfosGlobal.lavg15 | number : '1.1-2' : 'it'}}\r\n <span *ngIf=\"(DirInfosGlobal?.perinstancedata?.length || 0) > 0\">\r\n \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> \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> \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}} <input [readonly]=\"autoUpdate\" maxlength=\"3\" class=\"form-control app-updevery-input\" type=\"text\" [(ngModel)]=\"seconds\" name=\"seconds\" /> {{'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\">×</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>: \r\n {{'' + info.cpus + ' ' + ('CPU (Global)' | localize: lc) + (info.rssplan ? ' - ' + info.rssplan : '')}} \r\n Load average: {{ info.lavg1 | number : '1.1-2' : 'it'}} {{ info.lavg5 | number : '1.1-2' : 'it'}} {{ 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\"> {{SessionDetails.sid}}</span></h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"dlgSessionDetails.hide()\" aria-label=\"Close\"><span aria-hidden=\"true\">×</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>: {{SessionDetails.instanceid}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Seriale' | localize: lc}}</strong>: {{SessionDetails.serial}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Stato' | localize: lc}}</strong>: {{SessionDetails.status}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Tipo' | localize: lc}}</strong>: {{SessionDetails.type}}</div>\r\n <div class=\"col-md-6\"><strong>{{'Utente' | localize: lc}}</strong>: {{SessionDetails.user}} <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" }] }); }
|
|
4063
4946
|
}
|
|
4064
4947
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivitiesComponent, decorators: [{
|
|
4065
4948
|
type: Component,
|
|
4066
|
-
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\"> - \r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}} \r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg5 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span> \r\n <span *ngIf=\"DirInfosGlobal\"> | \r\n {{'' + DirInfosGlobal.cpus + ' ' + ('CPU (Global)' | localize: lc) + (DirInfosGlobal.rssplan ? ' - ' + DirInfosGlobal.rssplan : '')}} \r\n Load average: {{ DirInfosGlobal.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfosGlobal.lavg5 | number : '1.1-2' : 'it'}} {{ DirInfosGlobal.lavg15 | number : '1.1-2' : 'it'}}\r\n <span *ngIf=\"(DirInfosGlobal?.perinstancedata?.length || 0) > 0\">\r\n \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> \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> \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}} <input [readonly]=\"autoUpdate\" maxlength=\"3\" class=\"form-control app-updevery-input\" type=\"text\" [(ngModel)]=\"seconds\" name=\"seconds\" /> {{'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\">×</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>: \r\n {{'' + info.cpus + ' ' + ('CPU (Global)' | localize: lc) + (info.rssplan ? ' - ' + info.rssplan : '')}} \r\n Load average: {{ info.lavg1 | number : '1.1-2' : 'it'}} {{ info.lavg5 | number : '1.1-2' : 'it'}} {{ 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\"> {{SessionDetails.sid}}</span></h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"dlgSessionDetails.hide()\" aria-label=\"Close\"><span aria-hidden=\"true\">×</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>: {{SessionDetails.instanceid}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Seriale' | localize: lc}}</strong>: {{SessionDetails.serial}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Stato' | localize: lc}}</strong>: {{SessionDetails.status}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Tipo' | localize: lc}}</strong>: {{SessionDetails.type}}</div>\r\n <div class=\"col-md-6\"><strong>{{'Utente' | localize: lc}}</strong>: {{SessionDetails.user}} <span *ngIf=\"SessionDetails.tenant\">({{SessionDetails.tenant}})</span></div>\r\n </div>\r\n\r\n <div style=\"display: flex; width: 100%; margin-top: 15px;\">\r\n <div style=\"flex-grow: 0;display: flex;flex-direction: column\">\r\n <h5>Prime Istruzioni</h5>\r\n <div *ngIf=\"SelectedTopNodes\">\r\n <es-table [(ngModel)]=\"SelectedTopNodes\" [ArraymodeItemsPerPage]=\"10\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">{{'Nodo' | localize: lc}}</th>\r\n <th>{{'Descrizione Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n \r\n <ng-template #body let-node>\r\n <td class=\"app-col-min\"><span class=\"app-link\"(click)=\"loadNodeDetails(node.profnodeid); dlgNodeDetails.show();\">{{node.profnodeid}}</span></td>\r\n <td><span title=\"{{node.profnodedesc}}\">{{node.profnodedesc.length > 40 ? node.profnodedesc.substr(0,40) + \"...\" : node.profnodedesc}}</span></td>\r\n <td class=\"app-nowrap\">{{(node.activity == \"NaN\" ? null : node.activity) | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{node.nodetypename}}</td>\r\n <td>{{node.waitclassname}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n <div style=\"width: 15px;\"></div>\r\n <div style=\"flex-grow: 2;display: flex;flex-direction: column\">\r\n <h5>Attivit\u00E0</h5>\r\n <div *ngIf=\"SelectedSessions\" style=\"width: 100%; height: 290px\">\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [LegendPadding]=\"{top: 0, bottom: 7, right: 0, left: 10}\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"SelectedSessions\"\r\n [Legend]=\"true\" \r\n name=\"session_details\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event, true)\">\r\n </es-line-chart>\r\n </div>\r\n \r\n </div>\r\n </div>\r\n <div style=\"display: flex; width: 100%;\">\r\n <div style=\"flex-grow: 1;\">\r\n <h5>Statistiche Thread</h5>\r\n <div>\r\n <es-table [(ngModel)]=\"SessionDetails.threads\" [ArraymodeItemsPerPage]=\"10\" [Selection]=\"true\" [SingleSelection]=\"true\" (onSelectionChanged)=\"threadSelectionChanged($event)\">\r\n <ng-template #header>\r\n <th>Thread</th>\r\n <th>Stato</th>\r\n <th>Tipo</th>\r\n <th>API</th>\r\n <th>Attesa corrente</th>\r\n <th>Nodo di attesa</th>\r\n <th>Attesa su</th>\r\n <th>Classe</th>\r\n <th>Par. 1</th>\r\n <th>Par. 2</th>\r\n <th>Par. 3</th>\r\n <th>Tempo Attesa</th>\r\n </ng-template>\r\n \r\n <ng-template #body let-thread>\r\n <td>{{thread.tid}}</td>\r\n <td>{{thread.status}}</td>\r\n <td>{{thread.type}}</td>\r\n <td>{{thread.api}}</td>\r\n <td>{{thread.wait}}</td>\r\n <td>{{thread.waitnode}}</td>\r\n <td>{{thread.waiteventtype}}</td>\r\n <td>{{thread.waitclassname}}</td>\r\n <td>{{thread.waitpar1}}</td>\r\n <td>{{thread.waitpar2}}</td>\r\n <td>{{thread.waitpar3}}</td>\r\n <td>{{(thread.waittime == \"NaN\" ? null : thread.waittime) | number : '1.1-2' : 'it'}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"dlgSessionDetails.hide()\">{{'Chiudi' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n </div>\r\n</div>" }]
|
|
4949
|
+
args: [{ selector: "topact_search", providers: [{ provide: LocalizationService, useClass: AdmTopActivitieLoc }], standalone: false, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n <span *ngIf=\"DirInfos && !DirInfosGlobal\"> - \r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}} \r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg5 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span> \r\n <span *ngIf=\"DirInfosGlobal\"> | \r\n {{'' + DirInfosGlobal.cpus + ' ' + ('CPU (Global)' | localize: lc) + (DirInfosGlobal.rssplan ? ' - ' + DirInfosGlobal.rssplan : '')}} \r\n Load average: {{ DirInfosGlobal.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfosGlobal.lavg5 | number : '1.1-2' : 'it'}} {{ DirInfosGlobal.lavg15 | number : '1.1-2' : 'it'}}\r\n <span *ngIf=\"(DirInfosGlobal?.perinstancedata?.length || 0) > 0\">\r\n \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> \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> \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}} <input [readonly]=\"autoUpdate\" maxlength=\"3\" class=\"form-control app-updevery-input\" type=\"text\" [(ngModel)]=\"seconds\" name=\"seconds\" /> {{'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\">×</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>: \r\n {{'' + info.cpus + ' ' + ('CPU (Global)' | localize: lc) + (info.rssplan ? ' - ' + info.rssplan : '')}} \r\n Load average: {{ info.lavg1 | number : '1.1-2' : 'it'}} {{ info.lavg5 | number : '1.1-2' : 'it'}} {{ 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\"> {{SessionDetails.sid}}</span></h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"dlgSessionDetails.hide()\" aria-label=\"Close\"><span aria-hidden=\"true\">×</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>: {{SessionDetails.instanceid}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Seriale' | localize: lc}}</strong>: {{SessionDetails.serial}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Stato' | localize: lc}}</strong>: {{SessionDetails.status}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Tipo' | localize: lc}}</strong>: {{SessionDetails.type}}</div>\r\n <div class=\"col-md-6\"><strong>{{'Utente' | localize: lc}}</strong>: {{SessionDetails.user}} <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" }]
|
|
4067
4950
|
}], ctorParameters: () => [{ type: i1$1.DateService }, { type: i1.LocalizationService }, { type: i3.PreferencesService }, { type: i5.Location }, { type: i1$1.InterComService }, { type: i4.ActivatedRoute }, { type: AdminModuleBaseService }, { type: undefined, decorators: [{
|
|
4068
4951
|
type: Inject,
|
|
4069
4952
|
args: [ADM_MODULE_PATH]
|
|
4070
|
-
}] }
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
}
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
TopActivityDataSource[TopActivityDataSource["MemoryAndStored"] = 1] = "MemoryAndStored";
|
|
4094
|
-
})(TopActivityDataSource || (TopActivityDataSource = {}));
|
|
4095
|
-
var TopActivityResolution;
|
|
4096
|
-
(function (TopActivityResolution) {
|
|
4097
|
-
TopActivityResolution[TopActivityResolution["Low"] = 0] = "Low";
|
|
4098
|
-
TopActivityResolution[TopActivityResolution["Medium"] = 1] = "Medium";
|
|
4099
|
-
TopActivityResolution[TopActivityResolution["High"] = 2] = "High";
|
|
4100
|
-
TopActivityResolution[TopActivityResolution["Maximum"] = 3] = "Maximum";
|
|
4101
|
-
})(TopActivityResolution || (TopActivityResolution = {}));
|
|
4102
|
-
var TopActivityMaximumThreads;
|
|
4103
|
-
(function (TopActivityMaximumThreads) {
|
|
4104
|
-
TopActivityMaximumThreads[TopActivityMaximumThreads["None"] = 0] = "None";
|
|
4105
|
-
TopActivityMaximumThreads[TopActivityMaximumThreads["Cores"] = 1] = "Cores";
|
|
4106
|
-
TopActivityMaximumThreads[TopActivityMaximumThreads["Threads"] = 2] = "Threads";
|
|
4107
|
-
})(TopActivityMaximumThreads || (TopActivityMaximumThreads = {}));
|
|
4953
|
+
}] }, { type: i4.Router }, { type: undefined, decorators: [{
|
|
4954
|
+
type: Optional
|
|
4955
|
+
}, {
|
|
4956
|
+
type: Inject,
|
|
4957
|
+
args: [ADM_DETAILS_V2]
|
|
4958
|
+
}] }, { type: undefined, decorators: [{
|
|
4959
|
+
type: Optional
|
|
4960
|
+
}, {
|
|
4961
|
+
type: Inject,
|
|
4962
|
+
args: [ADM_PROFILER_V2]
|
|
4963
|
+
}] }], propDecorators: { dlgNodeDetails: [{
|
|
4964
|
+
type: ViewChild,
|
|
4965
|
+
args: ["dlgNodeDetails"]
|
|
4966
|
+
}], dlgSessionDetails: [{
|
|
4967
|
+
type: ViewChild,
|
|
4968
|
+
args: ["dlgSessionDetails"]
|
|
4969
|
+
}], dlgDetailsV2: [{
|
|
4970
|
+
type: ViewChild,
|
|
4971
|
+
args: ["dlgDetailsV2"]
|
|
4972
|
+
}], detailsV2: [{
|
|
4973
|
+
type: ViewChild,
|
|
4974
|
+
args: [AdmDetailsV2Component]
|
|
4975
|
+
}] } });
|
|
4108
4976
|
|
|
4109
4977
|
class TopActivityV2Filter {
|
|
4110
4978
|
}
|
|
@@ -4294,15 +5162,6 @@ const STORAGE_KEY = "HotSearchTopActV2";
|
|
|
4294
5162
|
const TABLES_WINDOW_MS = 5 * 60 * 1000;
|
|
4295
5163
|
const INSTANCE_CURRENT = "@current";
|
|
4296
5164
|
const INSTANCE_ALL = "@all";
|
|
4297
|
-
// WaitClass ed EventType hanno valori fissi: colori fissi, così il grafico si legge sempre allo stesso modo
|
|
4298
|
-
const FIXED_COLORS = {
|
|
4299
|
-
Cpu: "#43a047", Database: "#1e88e5", Script: "#8e24aa", Network: "#8d6e63", IO: "#00acc1", Sleep: "#b0bec5", Throttle: "#fb8c00", Wait: "#fdd835",
|
|
4300
|
-
Latch: "#e53935", Semaphore: "#f06292", Enqueue: "#c62828", ReadWriteLock: "#ad1457", Fence: "#6d4c41", ConditionVariable: "#00897b", Scheduler: "#5e35b1"
|
|
4301
|
-
};
|
|
4302
|
-
const PALETTE = ["#1e88e5", "#43a047", "#fb8c00", "#8e24aa", "#e53935", "#00897b", "#fdd835", "#6d4c41", "#3949ab", "#c0ca33"];
|
|
4303
|
-
const OTHER_COLOR = "#9e9e9e";
|
|
4304
|
-
const TOTAL_COLOR = "#263238";
|
|
4305
|
-
const LIMIT_COLOR = "#e53935";
|
|
4306
5165
|
class TopActivityV2LegendItem {
|
|
4307
5166
|
}
|
|
4308
5167
|
class TopActivityV2FilterChip {
|
|
@@ -4311,7 +5170,9 @@ class TopActivityV2FilterChip {
|
|
|
4311
5170
|
class TopActivityV2Settings {
|
|
4312
5171
|
}
|
|
4313
5172
|
class AdmTopActivityV2Component {
|
|
4314
|
-
constructor(dateExts, lc, localStorage, intercom, route, adms, zone
|
|
5173
|
+
constructor(dateExts, lc, localStorage, intercom, route, adms, zone, router, mod,
|
|
5174
|
+
// Con DirectorFeature.DetailsV2 nodi e sessioni si aprono nel dettaglio v2; "Apri nel profiler" vuole il profiler v2
|
|
5175
|
+
detailsV2Enabled, profilerV2Enabled) {
|
|
4315
5176
|
this.dateExts = dateExts;
|
|
4316
5177
|
this.lc = lc;
|
|
4317
5178
|
this.localStorage = localStorage;
|
|
@@ -4319,6 +5180,10 @@ class AdmTopActivityV2Component {
|
|
|
4319
5180
|
this.route = route;
|
|
4320
5181
|
this.adms = adms;
|
|
4321
5182
|
this.zone = zone;
|
|
5183
|
+
this.router = router;
|
|
5184
|
+
this.mod = mod;
|
|
5185
|
+
this.detailsV2Enabled = detailsV2Enabled;
|
|
5186
|
+
this.profilerV2Enabled = profilerV2Enabled;
|
|
4322
5187
|
this.Dim = TopActivityDimension;
|
|
4323
5188
|
this.TotalColor = TOTAL_COLOR;
|
|
4324
5189
|
this.LimitColor = LIMIT_COLOR;
|
|
@@ -4369,6 +5234,10 @@ class AdmTopActivityV2Component {
|
|
|
4369
5234
|
if (saved)
|
|
4370
5235
|
this.applySettings(saved);
|
|
4371
5236
|
this.setLastHours(this.activeRange);
|
|
5237
|
+
// "Sessioni su questo evento" dal dettaglio di un nodo aperto in un'altra pagina (profiler): filtro sull'evento, stessa finestra
|
|
5238
|
+
let query = this.route.snapshot.queryParams;
|
|
5239
|
+
if (query["event"])
|
|
5240
|
+
this.applyEventFilter(query["event"], query["eventName"], query["from"] ? new Date(query["from"]) : null, query["to"] ? new Date(query["to"]) : null);
|
|
4372
5241
|
this.loadInstances();
|
|
4373
5242
|
this.refreshInfos();
|
|
4374
5243
|
this.search();
|
|
@@ -4479,7 +5348,7 @@ class AdmTopActivityV2Component {
|
|
|
4479
5348
|
this.lastChartKey = null;
|
|
4480
5349
|
return;
|
|
4481
5350
|
}
|
|
4482
|
-
let memoryFrom = res.memoryFrom ?
|
|
5351
|
+
let memoryFrom = res.memoryFrom ? parseUtc(res.memoryFrom) : null;
|
|
4483
5352
|
this.memoryFrom = memoryFrom && memoryFrom.getTime() > this.chartFrom ? this.fmt(memoryFrom) : null;
|
|
4484
5353
|
this.limitLabel = this.lc.loc(+this.maxThreadsKind == TopActivityMaximumThreads.Cores ? "CPU Massime" : "Thread Massimi");
|
|
4485
5354
|
// Se è cambiata solo la finestra delle tabelle il grafico resta quello di prima: ridisegnarlo lo farebbe lampeggiare
|
|
@@ -4489,22 +5358,23 @@ class AdmTopActivityV2Component {
|
|
|
4489
5358
|
return;
|
|
4490
5359
|
}
|
|
4491
5360
|
this.lastChartKey = chartKey;
|
|
4492
|
-
let times = (res.times ?? []).map(t =>
|
|
5361
|
+
let times = (res.times ?? []).map(t => parseUtc(t));
|
|
5362
|
+
let interval = bucketInterval(res.bucketSeconds);
|
|
4493
5363
|
let fixed = res.dimension == TopActivityDimension.WaitClass || res.dimension == TopActivityDimension.EventType;
|
|
4494
5364
|
let uom = this.lc.loc("sessioni");
|
|
4495
5365
|
let series = [];
|
|
4496
5366
|
this.colors = {};
|
|
4497
5367
|
this.legend = (res.components ?? []).map((c, i) => {
|
|
4498
|
-
let color = c.
|
|
5368
|
+
let color = componentColor(c.key, c.other, i, fixed);
|
|
4499
5369
|
if (c.key != null)
|
|
4500
5370
|
this.colors[c.key] = color;
|
|
4501
5371
|
let label = this.valueLabel(c.label, c.other, res.dimension);
|
|
4502
|
-
series.push(new LineSerie(label, times.map((t, j) => new DateValue(t, c.values?.[j] ?? 0)),
|
|
5372
|
+
series.push(new LineSerie(label, times.map((t, j) => new DateValue(t, c.values?.[j] ?? 0)), interval, color, uom));
|
|
4503
5373
|
return { key: c.key, label: label, color: color, other: c.other, activity: c.activity, percentage: c.percentage };
|
|
4504
5374
|
});
|
|
4505
5375
|
// L'attività totale è una linea scura sopra le aree impilate, non impilata a sua volta
|
|
4506
5376
|
if (res.totalActivity)
|
|
4507
|
-
series.push(new LineSerie(this.lc.loc("Attività totale"), times.map((t, j) => new DateValue(t, res.totalActivity[j] ?? 0)),
|
|
5377
|
+
series.push(new LineSerie(this.lc.loc("Attività totale"), times.map((t, j) => new DateValue(t, res.totalActivity[j] ?? 0)), interval, TOTAL_COLOR, uom, false, false));
|
|
4508
5378
|
let limit = null;
|
|
4509
5379
|
if (res.maximumThreads != null)
|
|
4510
5380
|
limit = new Limit(res.maximumThreads, this.limitLabel, LIMIT_COLOR);
|
|
@@ -4598,6 +5468,14 @@ class AdmTopActivityV2Component {
|
|
|
4598
5468
|
return this.valueLabel(item.label, item.other, table.dimension);
|
|
4599
5469
|
}
|
|
4600
5470
|
loadNodeDetails(nodeId) {
|
|
5471
|
+
if (this.detailsV2Enabled) {
|
|
5472
|
+
// D4: tutte le istanze, l'istanza scelta, oppure quella che risponde
|
|
5473
|
+
let instance = this.instance != INSTANCE_CURRENT && this.instance != INSTANCE_ALL ? this.instance : null;
|
|
5474
|
+
let memoryFrom = this.result?.memoryFrom ? parseUtc(this.result.memoryFrom) : null;
|
|
5475
|
+
this.detailsV2.openNode(nodeId, { ...this.detailsWindow(), global: this.instance == INSTANCE_ALL, instanceId: instance, memoryFrom: memoryFrom });
|
|
5476
|
+
this.dlgDetailsV2.show();
|
|
5477
|
+
return;
|
|
5478
|
+
}
|
|
4601
5479
|
this.NodeDetails = null;
|
|
4602
5480
|
this.dlgNodeDetails.show();
|
|
4603
5481
|
requestAnimationFrame(async () => {
|
|
@@ -4605,6 +5483,11 @@ class AdmTopActivityV2Component {
|
|
|
4605
5483
|
});
|
|
4606
5484
|
}
|
|
4607
5485
|
loadSessionDetails(session) {
|
|
5486
|
+
if (this.detailsV2Enabled) {
|
|
5487
|
+
this.detailsV2.openSession(session.instanceId, session.sessionId, session.serialNo, { ...this.detailsWindow(), realTime: +this.dataSource == TopActivityDataSource.Memory });
|
|
5488
|
+
this.dlgDetailsV2.show();
|
|
5489
|
+
return;
|
|
5490
|
+
}
|
|
4608
5491
|
this.SessionDetails = null;
|
|
4609
5492
|
this.dlgSessionDetails.show();
|
|
4610
5493
|
requestAnimationFrame(async () => {
|
|
@@ -4612,6 +5495,35 @@ class AdmTopActivityV2Component {
|
|
|
4612
5495
|
});
|
|
4613
5496
|
}
|
|
4614
5497
|
// #endregion
|
|
5498
|
+
// #region Dettaglio v2 di nodo e sessione
|
|
5499
|
+
// Il dettaglio eredita la finestra del grafico, non quella delle tabelle, e l'aggiornamento automatico della pagina (D2, D5)
|
|
5500
|
+
detailsWindow() {
|
|
5501
|
+
return { from: new Date(this.chartFrom), to: new Date(this.chartTo), refreshSeconds: +this.refreshSeconds };
|
|
5502
|
+
}
|
|
5503
|
+
// N8: questa pagina filtrata sull'evento esatto, con la tabella per sessione e la finestra del dettaglio
|
|
5504
|
+
showEventSessions(link) {
|
|
5505
|
+
this.dlgDetailsV2.hide();
|
|
5506
|
+
this.applyEventFilter(link.nodeId, link.nodeName, link.from, link.to);
|
|
5507
|
+
this.search();
|
|
5508
|
+
}
|
|
5509
|
+
// N7: il profiler v2 con il nodo come radice
|
|
5510
|
+
openInProfiler(nodeId) {
|
|
5511
|
+
this.dlgDetailsV2.hide();
|
|
5512
|
+
this.router.navigate([`/pages/${this.mod}/profiler`, ...(this.be ? [this.be] : [])], { queryParams: { root: nodeId } });
|
|
5513
|
+
}
|
|
5514
|
+
applyEventFilter(nodeId, nodeName, from, to) {
|
|
5515
|
+
let filter = new TopActivityV2Filter();
|
|
5516
|
+
filter.dimension = TopActivityDimension.WaitEvent;
|
|
5517
|
+
filter.value = nodeId;
|
|
5518
|
+
this.filters = [{ filter: filter, label: `${this.dimensionLabel(TopActivityDimension.WaitEvent)} = ${nodeName || nodeId}` }];
|
|
5519
|
+
this.tableDims = [String(TopActivityDimension.UserSession), this.tableDims[1] ?? String(TopActivityDimension.WaitEvent)];
|
|
5520
|
+
if (from && to && !isNaN(from.getTime()) && !isNaN(to.getTime())) {
|
|
5521
|
+
this.filterfrom = this.fmt(from);
|
|
5522
|
+
this.filterto = this.fmt(to);
|
|
5523
|
+
this.activeRange = null;
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5526
|
+
// #endregion
|
|
4615
5527
|
// #region Aggiornamento automatico
|
|
4616
5528
|
refreshChanged() {
|
|
4617
5529
|
clearInterval(this.refreshTimer);
|
|
@@ -4690,6 +5602,7 @@ class AdmTopActivityV2Component {
|
|
|
4690
5602
|
case TopActivityDimension.ThreadType: return this.lc.loc("Tipo thread");
|
|
4691
5603
|
case TopActivityDimension.Api: return "API";
|
|
4692
5604
|
case TopActivityDimension.Machine: return this.lc.loc("Macchina");
|
|
5605
|
+
case TopActivityDimension.Thread: return "Thread";
|
|
4693
5606
|
}
|
|
4694
5607
|
return String(dimension);
|
|
4695
5608
|
}
|
|
@@ -4735,23 +5648,37 @@ class AdmTopActivityV2Component {
|
|
|
4735
5648
|
fmt(date) {
|
|
4736
5649
|
return dayjs(date).format(this.lc.token("getFullDateDisplayFormat"));
|
|
4737
5650
|
}
|
|
4738
|
-
|
|
4739
|
-
parseUtc(value) {
|
|
4740
|
-
let m = /^(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2}):(\d{2})$/.exec(value ?? "");
|
|
4741
|
-
return m ? new Date(Date.UTC(+m[3], +m[2] - 1, +m[1], +m[4], +m[5], +m[6])) : new Date(value);
|
|
4742
|
-
}
|
|
4743
|
-
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 }); }
|
|
4744
|
-
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> - \r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}} \r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg5 | number : '1.1-2' : 'it'}} {{ 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 · {{'Picco' | localize: lc}} <strong>{{result.estimated ? '\u2248 ' : ''}}{{result.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n · {{'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 <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)\">×</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\">· {{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\">· {{item.event.waitClass}}</span>\r\n }\r\n </td>\r\n }\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (NodeDetails) {\r\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\r\n }\r\n</div>\r\n\r\n<div bsModal #dlgSessionDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (SessionDetails) {\r\n <session-detail [SessionDetails]=\"SessionDetails\" (onClose)=\"dlgSessionDetails.hide()\" (onNodeSelected)=\"loadNodeDetails($event)\"></session-detail>\r\n }\r\n</div>\r\n", styles: [":host{display:block}:host ::ng-deep .tav2-noclear .p-select-clear-icon{display:none}.tav2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;padding-top:6px}.tav2-cluster{display:flex;flex-wrap:nowrap;align-items:center;gap:10px}.tav2-cluster-end{margin-left:auto}.tav2-field{width:165px}.tav2-field-wide{width:210px}.tav2-spacer{flex:1 1 auto}.tav2-toggle{display:flex;align-items:center;gap:8px;height:39px;white-space:nowrap}.tav2-pointer{cursor:pointer}.tav2-group{position:relative;display:inline-flex}.tav2-group-label{position:absolute;top:-8px;left:8px;z-index:1;padding:0 4px;background:#fff;color:var(--p-text-muted-color, #64748b);font-size:12px;line-height:15px;white-space:nowrap;pointer-events:none}.tav2-seg{display:inline-flex;height:39px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden;background:#fff}.tav2-seg button{padding:0 12px;border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;color:#334155;font-size:13px;white-space:nowrap;cursor:pointer}.tav2-seg button:first-child{border-left:0}.tav2-seg button:hover:not(.tav2-on){background:#f8fafc}.tav2-seg button:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:-2px}.tav2-seg button.tav2-on{background:#eef2ff;color:#4338ca;font-weight:500;box-shadow:inset 0 -2px 0 var(--p-primary-color, #6366f1)}.tav2-panel{margin-top:14px;padding:10px 12px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:#fff;min-width:0}.tav2-panel-header{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;min-height:32px;margin-bottom:6px}.tav2-chart-header{justify-content:space-between;padding-top:8px;margin-bottom:10px}.tav2-heading{display:flex;flex-direction:column;gap:2px}.tav2-view-controls{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px}.tav2-title{font-size:12px;font-weight:500;letter-spacing:.03em;text-transform:uppercase;color:#344154}.tav2-muted{color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-right{text-align:right}.tav2-estimate{display:inline-block;margin-left:6px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:16px;white-space:nowrap;cursor:help}.tav2-ellipsis{display:inline-block;max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.tav2-ellipsis-short{max-width:170px}.tav2-tables .tav2-panel{container-type:inline-size}@container (min-width: 900px){.tav2-ellipsis{max-width:520px}.tav2-ellipsis-short{max-width:300px}}.tav2-chips{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:6px}.tav2-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 10px;border-radius:12px;background:#eef2ff;color:#3730a3;font-size:12px}.tav2-chip button{border:0;background:transparent;color:inherit;cursor:pointer;font-size:15px;line-height:1;padding:0 4px}.tav2-chart{position:relative;height:300px}.tav2-empty{display:flex;align-items:center;justify-content:center;height:100%;border:1px dashed var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);color:var(--p-text-muted-color, #64748b)}.tav2-legend{display:flex;flex-wrap:wrap;gap:4px 6px;margin-top:6px}.tav2-legend-item{display:inline-flex;align-items:center;gap:6px;padding:2px 8px;border:1px solid transparent;border-radius:4px;font-size:12px;white-space:nowrap}.tav2-legend-item.tav2-clickable{cursor:pointer}.tav2-legend-item.tav2-clickable:hover{border-color:var(--p-content-border-color, #e2e8f0);background:#f8fafc}.tav2-swatch{flex:none;width:10px;height:10px;border-radius:2px}.tav2-line{flex:none;width:16px;height:0;border-top:2px solid}.tav2-note{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-slider{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin-top:10px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.tav2-slider input[type=range]{flex:1 1 260px;min-width:200px;accent-color:var(--p-primary-color, #6366f1);cursor:pointer}.tav2-slider-label{display:inline-flex;flex-direction:column;line-height:1.2;font-size:12px}.tav2-badge{padding:2px 8px;border-radius:10px;background:#eef2ff;color:#3730a3;font-size:11px;white-space:nowrap}.tav2-badge.tav2-badge-off{background:#f1f5f9;color:var(--p-text-muted-color, #64748b)}.tav2-tables{display:grid;grid-template-columns:repeat(auto-fit,minmax(560px,1fr));gap:0 14px}.tav2-bar-cell{display:flex;align-items:center;gap:8px}.tav2-bar{display:flex;flex:none;width:70px;height:8px;border-radius:2px;overflow:hidden;background:#edf2f7}\n"], dependencies: [{ kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i7.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "component", type: i8.EsTableComponent, selector: "es-table", inputs: ["globalCheck", "autoUpdate", "seconds", "researchInProgress", "globalColVisCheck", "EsThTdProvider", "CornerMenuOptions", "ColumnsResizable", "ColumnsPinnable", "AutoUpdate", "Height", "EmptySpaceBackgroundColor", "EsTableHandledSearch", "MaxHeight", "ContainerClass", "XLSXExport", "CSVExport", "AllSearch", "HighCellDensity", "Selection", "ShowLoadingOnBootstrap", "Removal", "RemovalCondition", "Export", "ShiftClick", "CountLabel", "HidePaging", "HidePagingCount", "HidePagingButtons", "ContextMenu", "ExportFileName", "TableClass", "ExportFunction", "ExportOnlyVisibleColumns", "HasHeaderGroup", "HasSecondaryHeaderGroup", "HeaderHidden", "BodyHidden", "SelectionDisabled", "SingleSelection", "RowClassAssigner", "OrderByColumn", "MultipleOrderingDirectives", "HiddenColumns", "ColumnsOrdering", "SearchView", "SelectAll", "UseArrayModePaging", "DynamicRowColumnsDefinition", "DynamicOperations", "Hierarchy", "ParentKey", "OwnKey", "AutoSortHierarchy", "StartsExpanded", "SavePreferences", "DefaultAlignment", "PagingStyle", "RowGroupingPagingStyle", "ItemSourceProperty", "UseSelectionCache", "ShowItemGroupsColumns", "Editable", "RangeSelection", "SearchThrottle", "ArraymodeItemsPerPage"], outputs: ["globalCheckChange", "autoUpdateChange", "secondsChange", "researchInProgressChange", "globalColVisCheckChange", "onOrderChanged", "onSearchRequest", "onSelectionChanged", "onRemoval", "onAbortRemoval", "onModelChange", "onOpenContextMenu", "onCornerAction", "onDynamicOperation"] }, { kind: "component", type: i9.EsFormSelectComponent, selector: "form-select", inputs: ["OptionsTemplate"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "component", type: i2.EsLineChartComponent, selector: "es-line-chart", inputs: ["Data", "DataArray", "Step", "DataGroupBucketSize", "DataGroupingThreshold", "StrokeSize", "AllowGaps", "MergeDatasets", "FinalInstants", "Min", "Max", "Fill", "Stacked"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: SessionDetailComponent, selector: "session-detail", inputs: ["SessionDetails"], outputs: ["onClose", "onNodeSelected"] }, { kind: "component", type: NodeDetailComponent, selector: "node-detail", inputs: ["NodeDetails"], outputs: ["onClose"] }, { kind: "pipe", type: i5.LowerCasePipe, name: "lowercase" }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }, { kind: "pipe", type: i5.TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }] }); }
|
|
5651
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivityV2Component, deps: [{ token: i1$1.DateService }, { token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: AdminModuleBaseService }, { token: i0.NgZone }, { token: i4.Router }, { token: ADM_MODULE_PATH }, { token: ADM_DETAILS_V2, optional: true }, { token: ADM_PROFILER_V2, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5652
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmTopActivityV2Component, isStandalone: false, selector: "topact_v2", providers: [{ provide: LocalizationService, useClass: AdmTopActivityV2Loc }], viewQueries: [{ propertyName: "dlgNodeDetails", first: true, predicate: ["dlgNodeDetails"], descendants: true }, { propertyName: "dlgSessionDetails", first: true, predicate: ["dlgSessionDetails"], descendants: true }, { propertyName: "dlgDetailsV2", first: true, predicate: ["dlgDetailsV2"], descendants: true }, { propertyName: "detailsV2", first: true, predicate: AdmDetailsV2Component, descendants: true }], ngImport: i0, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n @if (DirInfos) {\r\n <span> - \r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}} \r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg5 | number : '1.1-2' : 'it'}} {{ 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 · {{'Picco' | localize: lc}} <strong>{{result.estimated ? '\u2248 ' : ''}}{{result.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n · {{'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 <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)\">×</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\">· {{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\">· {{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" }] }); }
|
|
4745
5653
|
}
|
|
4746
5654
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivityV2Component, decorators: [{
|
|
4747
5655
|
type: Component,
|
|
4748
|
-
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> - \r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}} \r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg5 | number : '1.1-2' : 'it'}} {{ 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 · {{'Picco' | localize: lc}} <strong>{{result.estimated ? '\u2248 ' : ''}}{{result.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n · {{'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 <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)\">×</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\">· {{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\">· {{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"] }]
|
|
4749
|
-
}], ctorParameters: () => [{ type: i1$1.DateService }, { type: i1.LocalizationService }, { type: i3.PreferencesService }, { type: i1$1.InterComService }, { type: i4.ActivatedRoute }, { type: AdminModuleBaseService }, { type: i0.NgZone }
|
|
5656
|
+
args: [{ selector: "topact_v2", providers: [{ provide: LocalizationService, useClass: AdmTopActivityV2Loc }], standalone: false, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n @if (DirInfos) {\r\n <span> - \r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}} \r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg5 | number : '1.1-2' : 'it'}} {{ 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 · {{'Picco' | localize: lc}} <strong>{{result.estimated ? '\u2248 ' : ''}}{{result.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n · {{'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 <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)\">×</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\">· {{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\">· {{item.event.waitClass}}</span>\r\n }\r\n </td>\r\n }\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Dettaglio v2 di nodo e sessione (DirectorFeature.DetailsV2) -->\r\n<div bsModal #dlgDetailsV2=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\" (onHidden)=\"detailsV2?.stop()\">\r\n @if (detailsV2Enabled) {\r\n <adm-details-v2 [Be]=\"be\" [CanShowSessions]=\"true\" [CanOpenProfiler]=\"!!profilerV2Enabled\" (closed)=\"dlgDetailsV2.hide()\"\r\n (sessionsOnEvent)=\"showEventSessions($event)\" (openProfiler)=\"openInProfiler($event)\"></adm-details-v2>\r\n }\r\n</div>\r\n\r\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (NodeDetails) {\r\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\r\n }\r\n</div>\r\n\r\n<div bsModal #dlgSessionDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (SessionDetails) {\r\n <session-detail [SessionDetails]=\"SessionDetails\" (onClose)=\"dlgSessionDetails.hide()\" (onNodeSelected)=\"loadNodeDetails($event)\"></session-detail>\r\n }\r\n</div>\r\n", styles: [":host{display:block}:host ::ng-deep .tav2-noclear .p-select-clear-icon{display:none}.tav2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 22px;padding-top:6px}.tav2-cluster{display:flex;flex-wrap:nowrap;align-items:center;gap:10px}.tav2-cluster-end{margin-left:auto}.tav2-field{width:165px}.tav2-field-wide{width:210px}.tav2-spacer{flex:1 1 auto}.tav2-toggle{display:flex;align-items:center;gap:8px;height:39px;white-space:nowrap}.tav2-pointer{cursor:pointer}.tav2-group{position:relative;display:inline-flex}.tav2-group-label{position:absolute;top:-8px;left:8px;z-index:1;padding:0 4px;background:#fff;color:var(--p-text-muted-color, #64748b);font-size:12px;line-height:15px;white-space:nowrap;pointer-events:none}.tav2-seg{display:inline-flex;height:39px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);overflow:hidden;background:#fff}.tav2-seg button{padding:0 12px;border:0;border-left:1px solid var(--p-form-field-border-color, #cbd5e1);background:transparent;color:#334155;font-size:13px;white-space:nowrap;cursor:pointer}.tav2-seg button:first-child{border-left:0}.tav2-seg button:hover:not(.tav2-on){background:#f8fafc}.tav2-seg button:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:-2px}.tav2-seg button.tav2-on{background:#eef2ff;color:#4338ca;font-weight:500;box-shadow:inset 0 -2px 0 var(--p-primary-color, #6366f1)}.tav2-panel{margin-top:14px;padding:10px 12px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:#fff;min-width:0}.tav2-panel-header{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;min-height:32px;margin-bottom:6px}.tav2-chart-header{justify-content:space-between;padding-top:8px;margin-bottom:10px}.tav2-heading{display:flex;flex-direction:column;gap:2px}.tav2-view-controls{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px}.tav2-title{font-size:12px;font-weight:500;letter-spacing:.03em;text-transform:uppercase;color:#344154}.tav2-muted{color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-right{text-align:right}.tav2-estimate{display:inline-block;margin-left:6px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:16px;white-space:nowrap;cursor:help}.tav2-ellipsis{display:inline-block;max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.tav2-ellipsis-short{max-width:170px}.tav2-tables .tav2-panel{container-type:inline-size}@container (min-width: 900px){.tav2-ellipsis{max-width:520px}.tav2-ellipsis-short{max-width:300px}}.tav2-chips{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:6px}.tav2-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 10px;border-radius:12px;background:#eef2ff;color:#3730a3;font-size:12px}.tav2-chip button{border:0;background:transparent;color:inherit;cursor:pointer;font-size:15px;line-height:1;padding:0 4px}.tav2-chart{position:relative;height:300px}.tav2-empty{display:flex;align-items:center;justify-content:center;height:100%;border:1px dashed var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);color:var(--p-text-muted-color, #64748b)}.tav2-legend{display:flex;flex-wrap:wrap;gap:4px 6px;margin-top:6px}.tav2-legend-item{display:inline-flex;align-items:center;gap:6px;padding:2px 8px;border:1px solid transparent;border-radius:4px;font-size:12px;white-space:nowrap}.tav2-legend-item.tav2-clickable{cursor:pointer}.tav2-legend-item.tav2-clickable:hover{border-color:var(--p-content-border-color, #e2e8f0);background:#f8fafc}.tav2-swatch{flex:none;width:10px;height:10px;border-radius:2px}.tav2-line{flex:none;width:16px;height:0;border-top:2px solid}.tav2-note{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-slider{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin-top:10px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.tav2-slider input[type=range]{flex:1 1 260px;min-width:200px;accent-color:var(--p-primary-color, #6366f1);cursor:pointer}.tav2-slider-label{display:inline-flex;flex-direction:column;line-height:1.2;font-size:12px}.tav2-badge{padding:2px 8px;border-radius:10px;background:#eef2ff;color:#3730a3;font-size:11px;white-space:nowrap}.tav2-badge.tav2-badge-off{background:#f1f5f9;color:var(--p-text-muted-color, #64748b)}.tav2-tables{display:grid;grid-template-columns:repeat(auto-fit,minmax(560px,1fr));gap:0 14px}.tav2-bar-cell{display:flex;align-items:center;gap:8px}.tav2-bar{display:flex;flex:none;width:70px;height:8px;border-radius:2px;overflow:hidden;background:#edf2f7}\n"] }]
|
|
5657
|
+
}], ctorParameters: () => [{ type: i1$1.DateService }, { type: i1.LocalizationService }, { type: i3.PreferencesService }, { type: i1$1.InterComService }, { type: i4.ActivatedRoute }, { type: AdminModuleBaseService }, { type: i0.NgZone }, { type: i4.Router }, { type: undefined, decorators: [{
|
|
5658
|
+
type: Inject,
|
|
5659
|
+
args: [ADM_MODULE_PATH]
|
|
5660
|
+
}] }, { type: undefined, decorators: [{
|
|
5661
|
+
type: Optional
|
|
5662
|
+
}, {
|
|
5663
|
+
type: Inject,
|
|
5664
|
+
args: [ADM_DETAILS_V2]
|
|
5665
|
+
}] }, { type: undefined, decorators: [{
|
|
5666
|
+
type: Optional
|
|
5667
|
+
}, {
|
|
5668
|
+
type: Inject,
|
|
5669
|
+
args: [ADM_PROFILER_V2]
|
|
5670
|
+
}] }], propDecorators: { dlgNodeDetails: [{
|
|
4750
5671
|
type: ViewChild,
|
|
4751
5672
|
args: ["dlgNodeDetails"]
|
|
4752
5673
|
}], dlgSessionDetails: [{
|
|
4753
5674
|
type: ViewChild,
|
|
4754
5675
|
args: ["dlgSessionDetails"]
|
|
5676
|
+
}], dlgDetailsV2: [{
|
|
5677
|
+
type: ViewChild,
|
|
5678
|
+
args: ["dlgDetailsV2"]
|
|
5679
|
+
}], detailsV2: [{
|
|
5680
|
+
type: ViewChild,
|
|
5681
|
+
args: [AdmDetailsV2Component]
|
|
4755
5682
|
}] } });
|
|
4756
5683
|
|
|
4757
5684
|
class LocksView extends AppSearch {
|
|
@@ -5489,7 +6416,7 @@ const routeConfig = [
|
|
|
5489
6416
|
{ path: "serveraudits/:be", component: AdmAuditsComponent, data: { title: "Ricerca Audit Applicativi", internalNavigation: false } },
|
|
5490
6417
|
{ path: "serverenqueues/:be", component: AdmEnqComponent, data: { title: "Ricerca Lock Applicativi", internalNavigation: false } },
|
|
5491
6418
|
{ path: "serverviews/:be", component: AdmDynamicViewsComponent, data: { title: "Ricerca Viste Dinamiche Applicative", internalNavigation: false } },
|
|
5492
|
-
{ path: "metadataquery/:be", component: MtdQueryComponent, data: { title: "
|
|
6419
|
+
{ path: "metadataquery/:be", component: MtdQueryComponent, data: { title: "Query Viste Dinamiche", internalNavigation: false } },
|
|
5493
6420
|
{ path: "serverworkers", component: AdmWrkComponent, data: { title: "Ricerca Processi Applicativi", internalNavigation: false } },
|
|
5494
6421
|
{ path: "profiler", component: AdmProfilerV2Component, canMatch: [profilerV2Enabled], data: { title: "Profiler del Server", internalNavigation: false } },
|
|
5495
6422
|
{ path: "profiler", component: AdmProfilerComponent, data: { title: "Profiler del Server", internalNavigation: false } },
|
|
@@ -5502,7 +6429,7 @@ const routeConfig = [
|
|
|
5502
6429
|
{ path: "serveraudits", component: AdmAuditsComponent, data: { title: "Ricerca Audit Applicativi", internalNavigation: false } },
|
|
5503
6430
|
{ path: "serverenqueues", component: AdmEnqComponent, data: { title: "Ricerca Lock Applicativi", internalNavigation: false } },
|
|
5504
6431
|
{ path: "serverviews", component: AdmDynamicViewsComponent, data: { title: "Ricerca Viste Dinamiche Applicative", internalNavigation: false } },
|
|
5505
|
-
{ path: "metadataquery", component: MtdQueryComponent, data: { title: "
|
|
6432
|
+
{ path: "metadataquery", component: MtdQueryComponent, data: { title: "Query Viste Dinamiche", internalNavigation: false } },
|
|
5506
6433
|
{ path: "syspars", component: AdmSystemParametersComponent, data: { title: "Parametri di sistema", internalNavigation: false } }
|
|
5507
6434
|
]
|
|
5508
6435
|
}
|
|
@@ -5534,6 +6461,8 @@ const COMPONENTS = [
|
|
|
5534
6461
|
AdmWorkloadV2Component,
|
|
5535
6462
|
AdmMetricsV2Component,
|
|
5536
6463
|
MetricsV2ChartComponent,
|
|
6464
|
+
AdmDetailsV2Component,
|
|
6465
|
+
ActivityChartV2Component,
|
|
5537
6466
|
AdmTopActivitiesComponent,
|
|
5538
6467
|
AdmTopActivityV2Component,
|
|
5539
6468
|
SessionDetailComponent,
|
|
@@ -5563,6 +6492,8 @@ class AdmModule {
|
|
|
5563
6492
|
AdmWorkloadV2Component,
|
|
5564
6493
|
AdmMetricsV2Component,
|
|
5565
6494
|
MetricsV2ChartComponent,
|
|
6495
|
+
AdmDetailsV2Component,
|
|
6496
|
+
ActivityChartV2Component,
|
|
5566
6497
|
AdmTopActivitiesComponent,
|
|
5567
6498
|
AdmTopActivityV2Component,
|
|
5568
6499
|
SessionDetailComponent,
|
|
@@ -5598,7 +6529,10 @@ class AdmModule {
|
|
|
5598
6529
|
{ provide: ADM_TOPACT_V2, useFactory: () => !!myconfig?.DirectorFeature?.TopActivityV2 },
|
|
5599
6530
|
{ provide: ADM_PROFILER_V2, useFactory: () => !!myconfig?.DirectorFeature?.ProfilerV2 },
|
|
5600
6531
|
{ provide: ADM_WORKLOAD_V2, useFactory: () => !!myconfig?.DirectorFeature?.WorkloadReportV2 },
|
|
5601
|
-
{ provide: ADM_METRICS_V2, useFactory: () => !!myconfig?.DirectorFeature?.MetricsV2 }
|
|
6532
|
+
{ provide: ADM_METRICS_V2, useFactory: () => !!myconfig?.DirectorFeature?.MetricsV2 },
|
|
6533
|
+
// Dettaglio di nodo e sessione v2: lo aprono tutte le pagine che mostrano nodi e sessioni, v1 comprese, perché con il flag il backend-for-frontend
|
|
6534
|
+
// risponde a GetNodeStats e GetSessionStats solo con il contratto nuovo
|
|
6535
|
+
{ provide: ADM_DETAILS_V2, useFactory: () => !!myconfig?.DirectorFeature?.DetailsV2 }
|
|
5602
6536
|
], imports: [MODULES] }); }
|
|
5603
6537
|
}
|
|
5604
6538
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmModule, decorators: [{
|
|
@@ -5612,7 +6546,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
5612
6546
|
{ provide: ADM_TOPACT_V2, useFactory: () => !!myconfig?.DirectorFeature?.TopActivityV2 },
|
|
5613
6547
|
{ provide: ADM_PROFILER_V2, useFactory: () => !!myconfig?.DirectorFeature?.ProfilerV2 },
|
|
5614
6548
|
{ provide: ADM_WORKLOAD_V2, useFactory: () => !!myconfig?.DirectorFeature?.WorkloadReportV2 },
|
|
5615
|
-
{ provide: ADM_METRICS_V2, useFactory: () => !!myconfig?.DirectorFeature?.MetricsV2 }
|
|
6549
|
+
{ provide: ADM_METRICS_V2, useFactory: () => !!myconfig?.DirectorFeature?.MetricsV2 },
|
|
6550
|
+
// Dettaglio di nodo e sessione v2: lo aprono tutte le pagine che mostrano nodi e sessioni, v1 comprese, perché con il flag il backend-for-frontend
|
|
6551
|
+
// risponde a GetNodeStats e GetSessionStats solo con il contratto nuovo
|
|
6552
|
+
{ provide: ADM_DETAILS_V2, useFactory: () => !!myconfig?.DirectorFeature?.DetailsV2 }
|
|
5616
6553
|
]
|
|
5617
6554
|
}]
|
|
5618
6555
|
}], ctorParameters: () => [{ type: AdminModuleCommService }] });
|
|
@@ -5625,5 +6562,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
|
|
|
5625
6562
|
* Generated bundle index. Do not edit.
|
|
5626
6563
|
*/
|
|
5627
6564
|
|
|
5628
|
-
export { ADM_CONVERSATIONS, ADM_METRICS_V2, ADM_MODULE_PATH, ADM_PROFILER_V2, ADM_TOPACT_V2, ADM_WORKLOAD_V2, AdmMessageTypes, AdmModule, MK_ADM, metricsV2Enabled, profilerV2Enabled, routeConfig, topActivityV2Enabled, workloadReportV2Enabled };
|
|
6565
|
+
export { ADM_CONVERSATIONS, ADM_DETAILS_V2, ADM_METRICS_V2, ADM_MODULE_PATH, ADM_PROFILER_V2, ADM_TOPACT_V2, ADM_WORKLOAD_V2, AdmMessageTypes, AdmModule, MK_ADM, metricsV2Enabled, profilerV2Enabled, routeConfig, topActivityV2Enabled, workloadReportV2Enabled };
|
|
5629
6566
|
//# sourceMappingURL=esfaenza-admin-module.mjs.map
|