@esfaenza/admin-module 20.3.22 → 20.3.23
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.
|
@@ -1969,11 +1969,11 @@ class AdmProfilerV2Component {
|
|
|
1969
1969
|
return ret;
|
|
1970
1970
|
}
|
|
1971
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" }] }); }
|
|
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: 1350px){.pv2-main{grid-template-columns:minmax(0,1fr)}.pv2-detail{position:static;max-height:none}}.pv2-panel{padding:12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);min-width:0}.pv2-view-bar{display:flex;flex-wrap:wrap;align-items:center;gap:14px 10px;padding-top:6px;margin-bottom:10px}.pv2-crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:2px 4px;margin-bottom:8px;font-size:12px}.pv2-crumb{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:2px 6px;border:0;border-radius:4px;background:transparent;color:var(--p-primary-color, #6366f1);cursor:pointer}.pv2-crumb:hover{background:var(--p-highlight-background, #eef2ff)}.pv2-crumb-current{color:var(--p-text-color, #334155);font-weight:500;cursor:default}.pv2-crumb-current:hover{background:transparent}.pv2-crumb-sep{color:var(--p-text-muted-color, #64748b)}.pv2-alert{position:relative;margin-bottom:8px;padding:6px 30px 6px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-size:13px}.pv2-alert.pv2-alert-warn{border-color:#fcd34d;background:#fffbeb;color:#92400e}.pv2-alert.pv2-alert-error{border-color:#fca5a5;background:#fef2f2;color:#991b1b}.pv2-alert-close{position:absolute;top:3px;right:6px;border:0;background:transparent;color:inherit;font-size:16px;cursor:pointer}.pv2-table-wrap{max-height:68vh;overflow:auto;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px)}.pv2-table-wrap:focus-visible{outline:2px solid var(--p-primary-color, #6366f1);outline-offset:1px}.pv2-table{width:100%;border-collapse:separate;border-spacing:0;font-size:13px;color:var(--p-text-color, #334155)}.pv2-table th{position:sticky;top:0;z-index:1;padding:7px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);background:var(--p-content-hover-background, #f8fafc);color:var(--p-text-muted-color, #64748b);font-size:12px;font-weight:500;white-space:nowrap;text-align:left}.pv2-table td{padding:4px 10px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);white-space:nowrap;vertical-align:middle}.pv2-col-node{width:100%;max-width:0}.pv2-col-node .pv2-node{min-width:260px}.pv2-num{text-align:right!important;font-variant-numeric:tabular-nums}.pv2-row{cursor:pointer}.pv2-row:hover td{background:var(--p-content-hover-background, #f8fafc)}.pv2-row.pv2-selected td{background:var(--p-highlight-background, #eef2ff)}.pv2-row.pv2-idle td{color:var(--p-text-muted-color, #64748b)}.pv2-row.pv2-idle td .pv2-name{opacity:.75}.pv2-node{display:flex;align-items:center;gap:6px;min-width:0}.pv2-caret{flex:none;width:18px;height:20px;padding:0;border:0;background:transparent;color:var(--p-text-muted-color, #64748b);text-align:center;cursor:pointer}.pv2-type{flex:none;display:inline-flex;align-items:center;gap:5px;padding:0 6px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:10px;color:var(--p-text-muted-color, #64748b);font-size:11px;line-height:18px;white-space:nowrap}.pv2-dot{flex:none;display:inline-block;width:8px;height:8px;border-radius:50%}.pv2-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pv2-name mark{padding:0 1px;border-radius:2px;background:#fde68a;color:#1f2937}.pv2-perc{width:1%}.pv2-perc-cell{display:flex;align-items:center;gap:8px}.pv2-bar{flex:none;width:64px;height:7px;border-radius:2px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc);box-shadow:inset 0 0 0 1px var(--p-content-border-color, #e2e8f0)}.pv2-bar>div{height:100%}.pv2-threads>*+*{margin-left:8px}.pv2-active{display:inline-flex;align-items:center;gap:5px;font-weight:500}.pv2-active-dot{width:7px;height:7px;border-radius:50%;background:#16a34a;box-shadow:0 0 0 3px #16a34a2e}.pv2-long{display:inline-flex;align-items:center;gap:4px;padding:0 6px;border:1px solid #fcd34d;border-radius:10px;background:#fffbeb;color:#92400e;font-size:11px;line-height:18px;white-space:nowrap}.pv2-service td{padding:5px 10px;color:var(--p-text-muted-color, #64748b);font-size:12px;background:var(--p-content-background, #fff)}.pv2-sub td{padding:8px 10px 10px 34px;background:var(--p-content-hover-background, #f8fafc);white-space:normal}.pv2-sub-title{margin-bottom:4px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-sub-item{display:flex;align-items:center;gap:10px;padding:2px 0}.pv2-sub-item code{font-size:12px}.pv2-link{margin-left:6px;padding:0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;cursor:pointer}.pv2-link:hover{text-decoration:underline}.pv2-empty{padding:28px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-footer{margin-top:8px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-muted{color:var(--p-text-muted-color, #64748b)}.pv2-small{font-size:12px}.pv2-detail{position:sticky;top:10px;max-height:calc(100vh - 20px);overflow:auto;font-size:13px;color:var(--p-text-color, #334155);transition:opacity .15s}.pv2-detail.pv2-stale{opacity:.55}.pv2-placeholder{padding:36px 12px;color:var(--p-text-muted-color, #64748b);text-align:center}.pv2-error-text{color:#dc2626}.pv2-d-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.pv2-fullname{max-height:140px;overflow:auto;padding:8px 10px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-hover-background, #f8fafc);font-family:ui-monospace,Cascadia Mono,Consolas,monospace;font-size:12px;white-space:pre-wrap;word-break:break-word}.pv2-id{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-id code{font-size:12px}.pv2-d-title{margin:16px 0 6px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase}.pv2-path{display:flex;flex-direction:column}.pv2-path-item{display:flex;align-items:center;gap:6px;max-width:100%;padding:2px 0;border:0;background:transparent;color:var(--p-primary-color, #6366f1);font-size:12px;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.pv2-path-item:hover{text-decoration:underline}.pv2-path-current{color:var(--p-text-color, #334155);font-weight:600;cursor:default}.pv2-path-current:hover{text-decoration:none}.pv2-kv{display:grid;grid-template-columns:auto 1fr;gap:3px 14px;margin:0}.pv2-kv dt{color:var(--p-text-muted-color, #64748b);font-weight:400}.pv2-kv dd{margin:0;text-align:right;font-variant-numeric:tabular-nums}.pv2-stack{display:flex;height:12px;border-radius:3px;overflow:hidden;background:var(--p-content-hover-background, #f8fafc)}.pv2-legend{display:flex;flex-wrap:wrap;gap:4px 12px;margin-top:6px;font-size:12px}.pv2-legend-item{display:inline-flex;align-items:center;gap:5px}.pv2-swatch{width:10px;height:10px;border-radius:2px}.pv2-chart{display:grid;grid-template-columns:auto 1fr;gap:2px 6px}.pv2-chart-y{display:flex;flex-direction:column;justify-content:space-between;height:110px;color:var(--p-text-muted-color, #64748b);font-size:11px;text-align:right;line-height:1}.pv2-chart-plot{position:relative;height:110px;border-left:1px solid var(--p-content-border-color, #e2e8f0);border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-chart-plot svg{display:block;width:100%;height:100%}.pv2-chart-grid{stroke:var(--p-content-border-color, #e2e8f0);stroke-dasharray:3 3}.pv2-chart-last{position:absolute;width:8px;height:8px;border:2px solid var(--p-content-background, #fff);border-radius:50%;transform:translate(-50%,-50%)}.pv2-chart-x{display:flex;justify-content:space-between;color:var(--p-text-muted-color, #64748b);font-size:11px}.pv2-caption{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.pv2-mini{width:100%;font-size:12px}.pv2-mini th{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0);color:var(--p-text-muted-color, #64748b);font-weight:500}.pv2-mini td{padding:3px 6px;border-bottom:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-ellipsis{display:inline-block;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.pv2-d-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px;margin-top:16px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.pv2-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 12px;border:1px solid var(--p-form-field-border-color, #cbd5e1);border-radius:var(--p-form-field-border-radius, 6px);background:var(--p-content-background, #fff);color:var(--p-text-color, #334155);font-size:13px;cursor:pointer}.pv2-btn:hover{background:var(--p-highlight-background, #eef2ff);color:var(--p-highlight-color, #4338ca)}\n"], dependencies: [{ kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i9.EsFormInputComponent, selector: "form-input", inputs: ["minlength", "maxlength", "pattern", "Password", "Type"] }, { kind: "component", type: i9.EsFormSelectComponent, selector: "form-select", inputs: ["OptionsTemplate"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }, { kind: "pipe", type: ProfilerFormatPipe, name: "pv2fmt" }] }); }
|
|
1973
1973
|
}
|
|
1974
1974
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmProfilerV2Component, decorators: [{
|
|
1975
1975
|
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"] }]
|
|
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: 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
1977
|
}], 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
1978
|
type: Inject,
|
|
1979
1979
|
args: [ADM_MODULE_PATH]
|
|
@@ -2657,6 +2657,12 @@ class MetricsV2ChartComponent {
|
|
|
2657
2657
|
case "line":
|
|
2658
2658
|
case "step":
|
|
2659
2659
|
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 });
|
|
2660
|
+
// Un punto senza vicini (per esempio la durata di un timer con poche chiamate) come linea non si vedrebbe: diventa un pallino
|
|
2661
|
+
if ((s.opacity ?? 1) > 0)
|
|
2662
|
+
points.forEach((p, i) => {
|
|
2663
|
+
if ((i == 0 || p.gap) && (i == points.length - 1 || points[i + 1].gap))
|
|
2664
|
+
dots.push({ key: `${s.key}~${i}`, x: this.x(p.t), y: this.y(p.v), color: s.color });
|
|
2665
|
+
});
|
|
2660
2666
|
break;
|
|
2661
2667
|
case "band":
|
|
2662
2668
|
paths.push({ key: s.key, d: this.bandPath(points), color: s.color, fill: true, dash: null, opacity: s.opacity ?? 0.2 });
|