@esfaenza/admin-module 20.3.14 → 20.3.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@ import { CommonModule } from '@angular/common';
3
3
  import * as i7 from '@angular/forms';
4
4
  import { FormsModule } from '@angular/forms';
5
5
  import * as i0 from '@angular/core';
6
- import { InjectionToken, Injectable, Inject, Component, ViewChild, EventEmitter, Output, Input, Pipe, NgModule } from '@angular/core';
6
+ import { InjectionToken, Injectable, Inject, Component, ViewChild, EventEmitter, Output, Input, Pipe, inject, NgModule } from '@angular/core';
7
7
  import * as i4 from '@angular/router';
8
8
  import { RouterModule } from '@angular/router';
9
9
  import * as i8$1 from 'ngx-bootstrap/modal';
@@ -30,6 +30,7 @@ import * as i10 from '@esfaenza/core/directives';
30
30
  import { DirectivesModule } from '@esfaenza/core/directives';
31
31
  import { GenericItem, KeyValue as KeyValue$1 } from '@esfaenza/core/domain';
32
32
  import { __decorate } from 'tslib';
33
+ import * as am5 from '@amcharts/amcharts5';
33
34
  import { ComponentsModule } from '@esfaenza/core/components';
34
35
 
35
36
  class AuditsView extends AppSearch {
@@ -42,6 +43,7 @@ class AuditsView extends AppSearch {
42
43
 
43
44
  const ADM_MODULE_PATH = new InjectionToken('ADM_MODULE_PATH');
44
45
  const ADM_CONVERSATIONS = new InjectionToken('ADM_CONVERSATIONS');
46
+ const ADM_TOPACT_V2 = new InjectionToken('ADM_TOPACT_V2');
45
47
 
46
48
  class AdmAuditLoc extends LocalizationService {
47
49
  constructor(injector) {
@@ -152,6 +154,12 @@ class AdminModuleBaseService {
152
154
  let ret = await firstValueFrom(this.http.post(POST_Director_GetTopActivities, sv, pars));
153
155
  return ret;
154
156
  }
157
+ // Stesso URL di getTopActivities: con DirectorFeature.TopActivityV2 attivo il backend-for-frontend risponde con il contratto v2
158
+ async getTopActivitiesV2(be, req) {
159
+ var pars = new HttpParams().set("be", be ?? "");
160
+ let ret = await firstValueFrom(this.http.post(POST_Director_GetTopActivities, req, pars));
161
+ return ret;
162
+ }
155
163
  async getInfos(be) {
156
164
  var pars = new HttpParams().set("be", be ?? "");
157
165
  let ret = await firstValueFrom(this.http.get(GET_Director_GetInfos, pars, null, false).pipe(catchError(_ => of(null))));
@@ -1094,6 +1102,648 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
1094
1102
  args: [ADM_MODULE_PATH]
1095
1103
  }] }] });
1096
1104
 
1105
+ // Enum della Top Activity v2: i numeri sono quelli del backend (le risposte li riportano come numeri)
1106
+ var TopActivityDimension;
1107
+ (function (TopActivityDimension) {
1108
+ TopActivityDimension[TopActivityDimension["WaitClass"] = 0] = "WaitClass";
1109
+ TopActivityDimension[TopActivityDimension["EventType"] = 1] = "EventType";
1110
+ TopActivityDimension[TopActivityDimension["WaitEvent"] = 2] = "WaitEvent";
1111
+ TopActivityDimension[TopActivityDimension["Instance"] = 3] = "Instance";
1112
+ TopActivityDimension[TopActivityDimension["UserSession"] = 4] = "UserSession";
1113
+ TopActivityDimension[TopActivityDimension["UserName"] = 5] = "UserName";
1114
+ TopActivityDimension[TopActivityDimension["Tenant"] = 6] = "Tenant";
1115
+ TopActivityDimension[TopActivityDimension["SessionType"] = 7] = "SessionType";
1116
+ TopActivityDimension[TopActivityDimension["BackgroundSession"] = 8] = "BackgroundSession";
1117
+ TopActivityDimension[TopActivityDimension["JobName"] = 9] = "JobName";
1118
+ TopActivityDimension[TopActivityDimension["ConsumerGroup"] = 10] = "ConsumerGroup";
1119
+ TopActivityDimension[TopActivityDimension["ThreadType"] = 11] = "ThreadType";
1120
+ TopActivityDimension[TopActivityDimension["Api"] = 12] = "Api";
1121
+ TopActivityDimension[TopActivityDimension["Machine"] = 13] = "Machine";
1122
+ })(TopActivityDimension || (TopActivityDimension = {}));
1123
+ var TopActivityDataSource;
1124
+ (function (TopActivityDataSource) {
1125
+ TopActivityDataSource[TopActivityDataSource["Memory"] = 0] = "Memory";
1126
+ TopActivityDataSource[TopActivityDataSource["MemoryAndStored"] = 1] = "MemoryAndStored";
1127
+ })(TopActivityDataSource || (TopActivityDataSource = {}));
1128
+ var TopActivityResolution;
1129
+ (function (TopActivityResolution) {
1130
+ TopActivityResolution[TopActivityResolution["Low"] = 0] = "Low";
1131
+ TopActivityResolution[TopActivityResolution["Medium"] = 1] = "Medium";
1132
+ TopActivityResolution[TopActivityResolution["High"] = 2] = "High";
1133
+ TopActivityResolution[TopActivityResolution["Maximum"] = 3] = "Maximum";
1134
+ })(TopActivityResolution || (TopActivityResolution = {}));
1135
+ var TopActivityMaximumThreads;
1136
+ (function (TopActivityMaximumThreads) {
1137
+ TopActivityMaximumThreads[TopActivityMaximumThreads["None"] = 0] = "None";
1138
+ TopActivityMaximumThreads[TopActivityMaximumThreads["Cores"] = 1] = "Cores";
1139
+ TopActivityMaximumThreads[TopActivityMaximumThreads["Threads"] = 2] = "Threads";
1140
+ })(TopActivityMaximumThreads || (TopActivityMaximumThreads = {}));
1141
+
1142
+ class TopActivityV2Filter {
1143
+ }
1144
+ // Richiesta della Top Activity v2: date in ISO UTC (…Z), campi non valorizzati = default del backend.
1145
+ // Il backend-for-frontend legge i nomi senza badare a maiuscole e minuscole
1146
+ class TopActivityV2Request {
1147
+ }
1148
+
1149
+ class AdmTopActivityV2Loc extends LocalizationService {
1150
+ constructor(injector) {
1151
+ super(injector);
1152
+ super.set("it->en", "Attività Principali", ["Top Activities"]);
1153
+ super.set("it->en", "CPU", ["CPUs"]);
1154
+ super.set("it->en", "Da", ["From"]);
1155
+ super.set("it->en", "A", ["To"]);
1156
+ super.set("it->en", "Cerca", ["Search"]);
1157
+ super.set("it->en", "Istanza", ["Instance"]);
1158
+ super.set("it->en", "Istanza corrente", ["Current instance"]);
1159
+ super.set("it->en", "Tutte le istanze", ["All instances"]);
1160
+ super.set("it->en", "Origine dati", ["Data source"]);
1161
+ super.set("it->en", "Memoria e storico", ["Memory and history"]);
1162
+ super.set("it->en", "Solo memoria", ["Memory only"]);
1163
+ super.set("it->en", "Aggiornamento", ["Refresh"]);
1164
+ super.set("it->en", "Spento", ["Off"]);
1165
+ super.set("it->en", "Ogni 15 s", ["Every 15 s"]);
1166
+ super.set("it->en", "Ogni 30 s", ["Every 30 s"]);
1167
+ super.set("it->en", "Ogni 60 s", ["Every 60 s"]);
1168
+ super.set("it->en", "Dividi per", ["Split by"]);
1169
+ super.set("it->en", "Risoluzione", ["Resolution"]);
1170
+ super.set("it->en", "Bassa", ["Low"]);
1171
+ super.set("it->en", "Media", ["Medium"]);
1172
+ super.set("it->en", "Alta", ["High"]);
1173
+ super.set("it->en", "Massima", ["Maximum"]);
1174
+ super.set("it->en", "Attività totale", ["Total activity"]);
1175
+ super.set("it->en", "Limite", ["Limit"]);
1176
+ super.set("it->en", "Worker thread", ["Worker threads"]);
1177
+ super.set("it->en", "CPU Massime", ["Maximum CPUs"]);
1178
+ super.set("it->en", "Thread Massimi", ["Maximum Threads"]);
1179
+ super.set("it->en", "Sessioni attive medie per", ["Average active sessions by"]);
1180
+ super.set("it->en", "Picco", ["Peak"]);
1181
+ super.set("it->en", "un punto ogni", ["one point every"]);
1182
+ super.set("it->en", "Filtri", ["Filters"]);
1183
+ super.set("it->en", "Rimuovi", ["Remove"]);
1184
+ super.set("it->en", "Clic per filtrare", ["Click to filter"]);
1185
+ super.set("it->en", "Prima di questo istante i dati vengono dallo storico (un campione ogni 10 secondi)", ["Before this instant data comes from history (one sample every 10 seconds)"]);
1186
+ super.set("it->en", "sessioni", ["sessions"]);
1187
+ super.set("it->en", "Carico i Dati", ["Loading Data"]);
1188
+ super.set("it->en", "Nessun dato nella finestra", ["No data in the window"]);
1189
+ super.set("it->en", "Finestra tabelle", ["Tables window"]);
1190
+ super.set("it->en", "Ultimi 5 minuti", ["Last 5 minutes"]);
1191
+ super.set("it->en", "Finestra fissa", ["Fixed window"]);
1192
+ super.set("it->en", "Prime righe per", ["Top rows by"]);
1193
+ super.set("it->en", "Attività", ["Activity"]);
1194
+ super.set("it->en", "Altri", ["Others"]);
1195
+ super.set("it->en", "(non attribuito)", ["(not attributed)"]);
1196
+ super.set("it->en", "(nessuno)", ["(none)"]);
1197
+ super.set("it->en", "Classe di attesa", ["Wait class"]);
1198
+ super.set("it->en", "Tipo evento", ["Event type"]);
1199
+ super.set("it->en", "Nodo", ["Node"]);
1200
+ super.set("it->en", "Sessione", ["Session"]);
1201
+ super.set("it->en", "Utente", ["User"]);
1202
+ super.set("it->en", "Tenant", ["Tenant"]);
1203
+ super.set("it->en", "Tipo sessione", ["Session type"]);
1204
+ super.set("it->en", "Sessione di background", ["Background session"]);
1205
+ super.set("it->en", "Job", ["Job"]);
1206
+ super.set("it->en", "Gruppo di consumo", ["Consumer group"]);
1207
+ super.set("it->en", "Tipo thread", ["Thread type"]);
1208
+ super.set("it->en", "Macchina", ["Machine"]);
1209
+ super.set("it->en", "Tipo", ["Type"]);
1210
+ super.set("it->en", "Processo", ["Process"]);
1211
+ }
1212
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivityV2Loc, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
1213
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivityV2Loc }); }
1214
+ }
1215
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivityV2Loc, decorators: [{
1216
+ type: Injectable
1217
+ }], ctorParameters: () => [{ type: i0.Injector }] });
1218
+
1219
+ class SessionDetailLoc extends LocalizationService {
1220
+ constructor(injector) {
1221
+ super(injector);
1222
+ super.set("it->en", "Dettaglio Sessione", ["Session Detail"]);
1223
+ super.set("it->en", "Istanza", ["Instance"]);
1224
+ super.set("it->en", "Seriale", ["Serial"]);
1225
+ super.set("it->en", "Stato", ["Status"]);
1226
+ super.set("it->en", "Tipo", ["Type"]);
1227
+ super.set("it->en", "Utente", ["User"]);
1228
+ super.set("it->en", "Prime Istruzioni", ["Top Nodes"]);
1229
+ super.set("it->en", "Nodo", ["Node"]);
1230
+ super.set("it->en", "Descrizione Nodo", ["Node Description"]);
1231
+ super.set("it->en", "Attività", ["Activity"]);
1232
+ super.set("it->en", "Tipo Nodo", ["Node Type"]);
1233
+ super.set("it->en", "Classe Attesa", ["Wait Class Name"]);
1234
+ super.set("it->en", "Statistiche Thread", ["Thread Statistics"]);
1235
+ super.set("it->en", "Attesa corrente", ["Current Wait"]);
1236
+ super.set("it->en", "Nodo di attesa", ["Wait Node"]);
1237
+ super.set("it->en", "Attesa su", ["Waiting On"]);
1238
+ super.set("it->en", "Classe", ["Class"]);
1239
+ super.set("it->en", "Tempo Attesa", ["Wait Time"]);
1240
+ super.set("it->en", "Chiudi", ["Close"]);
1241
+ }
1242
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: SessionDetailLoc, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); }
1243
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: SessionDetailLoc }); }
1244
+ }
1245
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: SessionDetailLoc, decorators: [{
1246
+ type: Injectable
1247
+ }], ctorParameters: () => [{ type: i0.Injector }] });
1248
+
1249
+ // Angular
1250
+ // Dettaglio sessione condiviso (stesso contenuto del dialog della pagina Top Activity di sempre): il dialog che lo ospita resta del chiamante,
1251
+ // il clic su un nodo viene rilanciato con onNodeSelected perché il dettaglio nodo è anch'esso un dialog del chiamante
1252
+ class SessionDetailComponent {
1253
+ constructor(lc) {
1254
+ this.lc = lc;
1255
+ this.onClose = new EventEmitter();
1256
+ this.onNodeSelected = new EventEmitter();
1257
+ this.seriesPropertiesMapping = {};
1258
+ this.propertiesSeriesMapping = {
1259
+ ["cputime"]: "CPU",
1260
+ ["waittime"]: "Wait",
1261
+ ["scripttime"]: "Scripting",
1262
+ ["dbtime"]: "DB",
1263
+ ["nettime"]: "Network",
1264
+ ["throttletime"]: "Throttling",
1265
+ ["sleeptime"]: "Sleep",
1266
+ ["iotime"]: "IO"
1267
+ };
1268
+ }
1269
+ ngOnInit() {
1270
+ this.threadSelectionChanged(null);
1271
+ }
1272
+ threadSelectionChanged(selection) {
1273
+ this.SelectedTopNodes = null;
1274
+ this.SelectedSessions = null;
1275
+ requestAnimationFrame(() => {
1276
+ let sessDet = (selection?.count || 0) == 0 ? this.SessionDetails : selection.items[0];
1277
+ this.SelectedTopNodes = sessDet.nodes;
1278
+ if (!sessDet.sessions || sessDet.sessions.length == 0)
1279
+ return;
1280
+ let series = [];
1281
+ let props = Object.keys(sessDet.sessions[0]);
1282
+ for (let i = 0; i < props.length; i++) {
1283
+ if (props[i] != 'sampletime') {
1284
+ let s = new LineSerie(this.propertiesSeriesMapping[props[i]], [], null, null, "sessions");
1285
+ series.push(s);
1286
+ this.seriesPropertiesMapping[props[i]] = s;
1287
+ }
1288
+ }
1289
+ for (let i = 0; i < sessDet.sessions.length; i++) {
1290
+ let itemref = sessDet.sessions[i];
1291
+ let theD = new Date(itemref.sampletime);
1292
+ for (let i = 0; i < props.length; i++)
1293
+ if (props[i] != 'sampletime')
1294
+ this.seriesPropertiesMapping[props[i]].values.push(new DateValue(theD, itemref[props[i]]));
1295
+ }
1296
+ this.SelectedSessions = new LineChartData(series);
1297
+ });
1298
+ }
1299
+ onChartLoaded(chart) {
1300
+ let readyHandler = () => {
1301
+ chart.Chart.xAxes.each(x => x.zoom(0, 1, 0));
1302
+ chart.Chart.yAxes.each(y => y.zoom(0, 1, 0));
1303
+ chart.Chart.root.events.off("frameended", readyHandler);
1304
+ };
1305
+ chart.Chart.root.events.onDebounced("frameended", readyHandler, 500);
1306
+ }
1307
+ closeDialog() {
1308
+ this.onClose.emit(true);
1309
+ }
1310
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: SessionDetailComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component }); }
1311
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.34", type: SessionDetailComponent, isStandalone: false, selector: "session-detail", inputs: { SessionDetails: "SessionDetails" }, outputs: { onClose: "onClose", onNodeSelected: "onNodeSelected" }, ngImport: i0, template: "<div class=\"modal-dialog modal-feminist\" emaDraggable>\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title pull-left\">{{'Dettaglio Sessione' | localize: lc}}<span *ngIf=\"SessionDetails\">&nbsp;{{SessionDetails.sid}}</span></h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"closeDialog()\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\r\n </div>\r\n <div class=\"modal-body\" *ngIf=\"SessionDetails\">\r\n <div class=\"row\">\r\n <div *ngIf=\"SessionDetails.instanceid\" class=\"col-md-6\"><strong>{{'Istanza' | localize: lc}}</strong>:&nbsp;{{SessionDetails.instanceid}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Seriale' | localize: lc}}</strong>:&nbsp;{{SessionDetails.serial}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Stato' | localize: lc}}</strong>:&nbsp;{{SessionDetails.status}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Tipo' | localize: lc}}</strong>:&nbsp;{{SessionDetails.type}}</div>\r\n <div class=\"col-md-6\"><strong>{{'Utente' | localize: lc}}</strong>:&nbsp;{{SessionDetails.user}}&nbsp;<span *ngIf=\"SessionDetails.tenant\">({{SessionDetails.tenant}})</span></div>\r\n </div>\r\n\r\n <div style=\"display: flex; width: 100%; margin-top: 15px;\">\r\n <div style=\"flex-grow: 0;display: flex;flex-direction: column\">\r\n <h5>{{'Prime Istruzioni' | localize: lc}}</h5>\r\n <div *ngIf=\"SelectedTopNodes\">\r\n <es-table [(ngModel)]=\"SelectedTopNodes\" [ArraymodeItemsPerPage]=\"10\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">{{'Nodo' | localize: lc}}</th>\r\n <th>{{'Descrizione Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n\r\n <ng-template #body let-node>\r\n <td class=\"app-col-min\"><span class=\"app-link\" (click)=\"onNodeSelected.emit(node.profnodeid)\">{{node.profnodeid}}</span></td>\r\n <td><span title=\"{{node.profnodedesc}}\">{{node.profnodedesc?.length > 40 ? node.profnodedesc.substr(0,40) + \"...\" : node.profnodedesc}}</span></td>\r\n <td class=\"app-nowrap\">{{(node.activity == \"NaN\" ? null : node.activity) | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{node.nodetypename}}</td>\r\n <td>{{node.waitclassname}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n <div style=\"width: 15px;\"></div>\r\n <div style=\"flex-grow: 2;display: flex;flex-direction: column\">\r\n <h5>{{'Attivit\u00E0' | localize: lc}}</h5>\r\n <div *ngIf=\"SelectedSessions\" style=\"width: 100%; height: 290px\">\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [LegendPadding]=\"{top: 0, bottom: 7, right: 0, left: 10}\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"SelectedSessions\"\r\n [Legend]=\"true\"\r\n name=\"shared_session_details\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event)\">\r\n </es-line-chart>\r\n </div>\r\n </div>\r\n </div>\r\n <div style=\"display: flex; width: 100%;\">\r\n <div style=\"flex-grow: 1;\">\r\n <h5>{{'Statistiche Thread' | localize: lc}}</h5>\r\n <div>\r\n <es-table [(ngModel)]=\"SessionDetails.threads\" [ArraymodeItemsPerPage]=\"10\" [Selection]=\"true\" [SingleSelection]=\"true\" (onSelectionChanged)=\"threadSelectionChanged($event)\">\r\n <ng-template #header>\r\n <th>Thread</th>\r\n <th>{{'Stato' | localize: lc}}</th>\r\n <th>{{'Tipo' | localize: lc}}</th>\r\n <th>API</th>\r\n <th>{{'Attesa corrente' | localize: lc}}</th>\r\n <th>{{'Nodo di attesa' | localize: lc}}</th>\r\n <th>{{'Attesa su' | localize: lc}}</th>\r\n <th>{{'Classe' | localize: lc}}</th>\r\n <th>Par. 1</th>\r\n <th>Par. 2</th>\r\n <th>Par. 3</th>\r\n <th>{{'Tempo Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n\r\n <ng-template #body let-thread>\r\n <td>{{thread.tid}}</td>\r\n <td>{{thread.status}}</td>\r\n <td>{{thread.type}}</td>\r\n <td>{{thread.api}}</td>\r\n <td>{{thread.wait}}</td>\r\n <td>{{thread.waitnode}}</td>\r\n <td>{{thread.waiteventtype}}</td>\r\n <td>{{thread.waitclassname}}</td>\r\n <td>{{thread.waitpar1}}</td>\r\n <td>{{thread.waitpar2}}</td>\r\n <td>{{thread.waitpar3}}</td>\r\n <td>{{(thread.waittime == \"NaN\" ? null : thread.waittime) | number : '1.1-2' : 'it'}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"closeDialog()\">{{'Chiudi' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n</div>\r\n", dependencies: [{ kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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: i8.EsTableComponent, selector: "es-table", inputs: ["globalCheck", "autoUpdate", "seconds", "researchInProgress", "globalColVisCheck", "EsThTdProvider", "CornerMenuOptions", "ColumnsResizable", "ColumnsPinnable", "AutoUpdate", "Height", "EmptySpaceBackgroundColor", "EsTableHandledSearch", "MaxHeight", "ContainerClass", "XLSXExport", "CSVExport", "AllSearch", "HighCellDensity", "Selection", "ShowLoadingOnBootstrap", "Removal", "RemovalCondition", "Export", "ShiftClick", "CountLabel", "HidePaging", "HidePagingCount", "HidePagingButtons", "ContextMenu", "ExportFileName", "TableClass", "ExportFunction", "ExportOnlyVisibleColumns", "HasHeaderGroup", "HasSecondaryHeaderGroup", "HeaderHidden", "BodyHidden", "SelectionDisabled", "SingleSelection", "RowClassAssigner", "OrderByColumn", "MultipleOrderingDirectives", "HiddenColumns", "ColumnsOrdering", "SearchView", "SelectAll", "UseArrayModePaging", "DynamicRowColumnsDefinition", "DynamicOperations", "Hierarchy", "ParentKey", "OwnKey", "AutoSortHierarchy", "StartsExpanded", "SavePreferences", "DefaultAlignment", "PagingStyle", "RowGroupingPagingStyle", "ItemSourceProperty", "UseSelectionCache", "ShowItemGroupsColumns", "Editable", "RangeSelection", "SearchThrottle", "ArraymodeItemsPerPage"], outputs: ["globalCheckChange", "autoUpdateChange", "secondsChange", "researchInProgressChange", "globalColVisCheckChange", "onOrderChanged", "onSearchRequest", "onSelectionChanged", "onRemoval", "onAbortRemoval", "onModelChange", "onOpenContextMenu", "onCornerAction", "onDynamicOperation"] }, { kind: "component", type: i2.EsLineChartComponent, selector: "es-line-chart", inputs: ["Data", "DataArray", "Step", "DataGroupBucketSize", "DataGroupingThreshold", "StrokeSize", "AllowGaps", "MergeDatasets", "FinalInstants", "Min", "Max", "Fill", "Stacked"] }, { kind: "directive", type: i10.Draggable, selector: "[emaDraggable]", inputs: ["emaDraggable"] }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }], viewProviders: [{ provide: LocalizationService, useClass: SessionDetailLoc }] }); }
1312
+ }
1313
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: SessionDetailComponent, decorators: [{
1314
+ type: Component,
1315
+ args: [{ selector: "session-detail", viewProviders: [{ provide: LocalizationService, useClass: SessionDetailLoc }], standalone: false, template: "<div class=\"modal-dialog modal-feminist\" emaDraggable>\r\n <div class=\"modal-content\">\r\n <div class=\"modal-header\">\r\n <h4 class=\"modal-title pull-left\">{{'Dettaglio Sessione' | localize: lc}}<span *ngIf=\"SessionDetails\">&nbsp;{{SessionDetails.sid}}</span></h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"closeDialog()\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\r\n </div>\r\n <div class=\"modal-body\" *ngIf=\"SessionDetails\">\r\n <div class=\"row\">\r\n <div *ngIf=\"SessionDetails.instanceid\" class=\"col-md-6\"><strong>{{'Istanza' | localize: lc}}</strong>:&nbsp;{{SessionDetails.instanceid}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Seriale' | localize: lc}}</strong>:&nbsp;{{SessionDetails.serial}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Stato' | localize: lc}}</strong>:&nbsp;{{SessionDetails.status}}&nbsp;</div>\r\n <div class=\"col-md-6\"><strong>{{'Tipo' | localize: lc}}</strong>:&nbsp;{{SessionDetails.type}}</div>\r\n <div class=\"col-md-6\"><strong>{{'Utente' | localize: lc}}</strong>:&nbsp;{{SessionDetails.user}}&nbsp;<span *ngIf=\"SessionDetails.tenant\">({{SessionDetails.tenant}})</span></div>\r\n </div>\r\n\r\n <div style=\"display: flex; width: 100%; margin-top: 15px;\">\r\n <div style=\"flex-grow: 0;display: flex;flex-direction: column\">\r\n <h5>{{'Prime Istruzioni' | localize: lc}}</h5>\r\n <div *ngIf=\"SelectedTopNodes\">\r\n <es-table [(ngModel)]=\"SelectedTopNodes\" [ArraymodeItemsPerPage]=\"10\">\r\n <ng-template #header>\r\n <th class=\"app-col-min\">{{'Nodo' | localize: lc}}</th>\r\n <th>{{'Descrizione Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo Nodo' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n\r\n <ng-template #body let-node>\r\n <td class=\"app-col-min\"><span class=\"app-link\" (click)=\"onNodeSelected.emit(node.profnodeid)\">{{node.profnodeid}}</span></td>\r\n <td><span title=\"{{node.profnodedesc}}\">{{node.profnodedesc?.length > 40 ? node.profnodedesc.substr(0,40) + \"...\" : node.profnodedesc}}</span></td>\r\n <td class=\"app-nowrap\">{{(node.activity == \"NaN\" ? null : node.activity) | number : '1.1-2' : 'it'}} %</td>\r\n <td>{{node.nodetypename}}</td>\r\n <td>{{node.waitclassname}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n <div style=\"width: 15px;\"></div>\r\n <div style=\"flex-grow: 2;display: flex;flex-direction: column\">\r\n <h5>{{'Attivit\u00E0' | localize: lc}}</h5>\r\n <div *ngIf=\"SelectedSessions\" style=\"width: 100%; height: 290px\">\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [LegendPadding]=\"{top: 0, bottom: 7, right: 0, left: 10}\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"SelectedSessions\"\r\n [Legend]=\"true\"\r\n name=\"shared_session_details\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event)\">\r\n </es-line-chart>\r\n </div>\r\n </div>\r\n </div>\r\n <div style=\"display: flex; width: 100%;\">\r\n <div style=\"flex-grow: 1;\">\r\n <h5>{{'Statistiche Thread' | localize: lc}}</h5>\r\n <div>\r\n <es-table [(ngModel)]=\"SessionDetails.threads\" [ArraymodeItemsPerPage]=\"10\" [Selection]=\"true\" [SingleSelection]=\"true\" (onSelectionChanged)=\"threadSelectionChanged($event)\">\r\n <ng-template #header>\r\n <th>Thread</th>\r\n <th>{{'Stato' | localize: lc}}</th>\r\n <th>{{'Tipo' | localize: lc}}</th>\r\n <th>API</th>\r\n <th>{{'Attesa corrente' | localize: lc}}</th>\r\n <th>{{'Nodo di attesa' | localize: lc}}</th>\r\n <th>{{'Attesa su' | localize: lc}}</th>\r\n <th>{{'Classe' | localize: lc}}</th>\r\n <th>Par. 1</th>\r\n <th>Par. 2</th>\r\n <th>Par. 3</th>\r\n <th>{{'Tempo Attesa' | localize: lc}}</th>\r\n </ng-template>\r\n\r\n <ng-template #body let-thread>\r\n <td>{{thread.tid}}</td>\r\n <td>{{thread.status}}</td>\r\n <td>{{thread.type}}</td>\r\n <td>{{thread.api}}</td>\r\n <td>{{thread.wait}}</td>\r\n <td>{{thread.waitnode}}</td>\r\n <td>{{thread.waiteventtype}}</td>\r\n <td>{{thread.waitclassname}}</td>\r\n <td>{{thread.waitpar1}}</td>\r\n <td>{{thread.waitpar2}}</td>\r\n <td>{{thread.waitpar3}}</td>\r\n <td>{{(thread.waittime == \"NaN\" ? null : thread.waittime) | number : '1.1-2' : 'it'}}</td>\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"closeDialog()\">{{'Chiudi' | localize: lc}}</button>\r\n </div>\r\n </div>\r\n</div>\r\n" }]
1316
+ }], ctorParameters: () => [{ type: i1.LocalizationService }], propDecorators: { SessionDetails: [{
1317
+ type: Input
1318
+ }], onClose: [{
1319
+ type: Output
1320
+ }], onNodeSelected: [{
1321
+ type: Output
1322
+ }] } });
1323
+
1324
+ // Angular
1325
+ const STORAGE_KEY = "HotSearchTopActV2";
1326
+ const TABLES_WINDOW_MS = 5 * 60 * 1000;
1327
+ const INSTANCE_CURRENT = "@current";
1328
+ const INSTANCE_ALL = "@all";
1329
+ // WaitClass ed EventType hanno valori fissi: colori fissi, così il grafico si legge sempre allo stesso modo
1330
+ const FIXED_COLORS = {
1331
+ Cpu: "#43a047", Database: "#1e88e5", Script: "#8e24aa", Network: "#8d6e63", IO: "#00acc1", Sleep: "#b0bec5", Throttle: "#fb8c00", Wait: "#fdd835",
1332
+ Latch: "#e53935", Semaphore: "#f06292", Enqueue: "#c62828", ReadWriteLock: "#ad1457", Fence: "#6d4c41", ConditionVariable: "#00897b", Scheduler: "#5e35b1"
1333
+ };
1334
+ const PALETTE = ["#1e88e5", "#43a047", "#fb8c00", "#8e24aa", "#e53935", "#00897b", "#fdd835", "#6d4c41", "#3949ab", "#c0ca33"];
1335
+ const OTHER_COLOR = "#9e9e9e";
1336
+ const TOTAL_COLOR = "#263238";
1337
+ const LIMIT_COLOR = "#e53935";
1338
+ class TopActivityV2LegendItem {
1339
+ }
1340
+ class TopActivityV2FilterChip {
1341
+ }
1342
+ // Impostazioni ricordate fra una visita e l'altra (la finestra temporale riparte sempre dall'ultima ora)
1343
+ class TopActivityV2Settings {
1344
+ }
1345
+ class AdmTopActivityV2Component {
1346
+ constructor(dateExts, lc, localStorage, intercom, route, adms, zone) {
1347
+ this.dateExts = dateExts;
1348
+ this.lc = lc;
1349
+ this.localStorage = localStorage;
1350
+ this.intercom = intercom;
1351
+ this.route = route;
1352
+ this.adms = adms;
1353
+ this.zone = zone;
1354
+ this.Dim = TopActivityDimension;
1355
+ this.TotalColor = TOTAL_COLOR;
1356
+ this.LimitColor = LIMIT_COLOR;
1357
+ // Filtri
1358
+ this.filterfrom = "";
1359
+ this.filterto = "";
1360
+ this.instance = INSTANCE_CURRENT;
1361
+ this.dataSource = String(TopActivityDataSource.MemoryAndStored);
1362
+ this.dimension = String(TopActivityDimension.WaitClass);
1363
+ this.resolution = String(TopActivityResolution.Medium);
1364
+ this.totalActivity = false;
1365
+ this.maxCpu = true;
1366
+ this.maxThreadsKind = String(TopActivityMaximumThreads.Threads);
1367
+ this.tableDims = [String(TopActivityDimension.UserSession), String(TopActivityDimension.WaitEvent)];
1368
+ this.filters = [];
1369
+ this.refreshSeconds = "0";
1370
+ // Sorgenti delle select
1371
+ this.Instances = [];
1372
+ this.DataSources = [];
1373
+ this.Dimensions = [];
1374
+ this.Resolutions = [];
1375
+ this.ThreadKinds = [];
1376
+ this.RefreshOptions = [];
1377
+ // Risultato
1378
+ this.loading = false;
1379
+ this.legend = [];
1380
+ this.tables = [];
1381
+ // Time slider: fine della finestra di 5 minuti delle tabelle, in millisecondi
1382
+ this.sliderMin = 0;
1383
+ this.sliderMax = 0;
1384
+ this.sliderStep = 1000;
1385
+ this.sliderValue = 0;
1386
+ this.sliderAnchored = true;
1387
+ this.tablesWindowLabel = "";
1388
+ this.chartFrom = 0;
1389
+ this.chartTo = 0;
1390
+ this.colors = {};
1391
+ this.be = route.snapshot.params["be"] || "";
1392
+ this.intercom.send(InboundMessageTypes.Navigation, { sub: false, routeTitle: this.lc.loc(this.route.snapshot.data["title"]) });
1393
+ }
1394
+ async ngOnInit() {
1395
+ this.buildSources();
1396
+ let saved = this.route.snapshot.queryParams["ignoreStorage"] ? null : await firstValueFrom(this.localStorage.getItem(STORAGE_KEY), { defaultValue: null });
1397
+ if (saved)
1398
+ this.applySettings(saved);
1399
+ this.setLastHour();
1400
+ this.loadInstances();
1401
+ this.refreshInfos();
1402
+ this.search();
1403
+ }
1404
+ ngOnDestroy() {
1405
+ clearInterval(this.refreshTimer);
1406
+ }
1407
+ // #region Ricerca
1408
+ searchClicked() {
1409
+ this.refreshInfos();
1410
+ this.search();
1411
+ }
1412
+ async search() {
1413
+ let req = this.buildRequest();
1414
+ this.loading = true;
1415
+ try {
1416
+ let res = await this.adms.getTopActivitiesV2(this.be, req);
1417
+ this.applyResult(req, res);
1418
+ this.saveSettings();
1419
+ }
1420
+ catch {
1421
+ // L'errore (finestra non valida, backend non raggiungibile...) lo mostra già HTTPService
1422
+ }
1423
+ finally {
1424
+ this.loading = false;
1425
+ }
1426
+ }
1427
+ buildRequest() {
1428
+ let to = this.toDate(this.filterto) ?? new Date();
1429
+ let from = this.toDate(this.filterfrom) ?? new Date(to.getTime() - 3600 * 1000);
1430
+ let req = new TopActivityV2Request();
1431
+ req.from = from.toISOString();
1432
+ req.to = to.toISOString();
1433
+ req.global = this.instance != INSTANCE_CURRENT;
1434
+ if (this.instance != INSTANCE_CURRENT && this.instance != INSTANCE_ALL)
1435
+ req.instanceId = this.instance;
1436
+ req.dataSource = +this.dataSource;
1437
+ req.dimension = +this.dimension;
1438
+ if (this.filters.length > 0)
1439
+ req.filters = this.filters.map(t => t.filter);
1440
+ req.totalActivity = this.totalActivity;
1441
+ req.maximumThreads = this.maxCpu ? +this.maxThreadsKind : TopActivityMaximumThreads.None;
1442
+ req.resolution = +this.resolution;
1443
+ req.tables = this.tableDims.map(t => +t);
1444
+ req.topCount = 10;
1445
+ // Lo slider agganciato a destra segue la fine del grafico; spostato resta fermo finché cade dentro la finestra
1446
+ let outside = this.sliderValue <= from.getTime() || this.sliderValue > to.getTime();
1447
+ if (this.sliderAnchored || outside) {
1448
+ this.sliderAnchored = true;
1449
+ this.sliderValue = to.getTime();
1450
+ }
1451
+ req.tablesTo = new Date(this.sliderValue).toISOString();
1452
+ req.tablesFrom = new Date(Math.max(from.getTime(), this.sliderValue - TABLES_WINDOW_MS)).toISOString();
1453
+ return req;
1454
+ }
1455
+ applyResult(req, res) {
1456
+ this.result = res;
1457
+ this.tables = res?.tables ?? [];
1458
+ this.chartFrom = new Date(req.from).getTime();
1459
+ this.chartTo = new Date(req.to).getTime();
1460
+ this.sliderStep = Math.max(1, res?.bucketSeconds || 1) * 1000;
1461
+ this.sliderMin = Math.min(this.chartTo, this.chartFrom + TABLES_WINDOW_MS);
1462
+ this.sliderMax = this.chartTo;
1463
+ this.sliderValue = new Date(req.tablesTo).getTime();
1464
+ this.updateTablesWindowLabel();
1465
+ if (!res) {
1466
+ this.chartData = null;
1467
+ this.legend = [];
1468
+ this.lastChartKey = null;
1469
+ return;
1470
+ }
1471
+ let memoryFrom = res.memoryFrom ? this.parseUtc(res.memoryFrom) : null;
1472
+ this.memoryFrom = memoryFrom && memoryFrom.getTime() > this.chartFrom ? this.fmt(memoryFrom) : null;
1473
+ this.limitLabel = this.lc.loc(+this.maxThreadsKind == TopActivityMaximumThreads.Cores ? "CPU Massime" : "Thread Massimi");
1474
+ // Se è cambiata solo la finestra delle tabelle il grafico resta quello di prima: ridisegnarlo lo farebbe lampeggiare
1475
+ let chartKey = JSON.stringify({ ...req, tablesFrom: null, tablesTo: null, tables: null, topCount: null });
1476
+ if (chartKey == this.lastChartKey && this.chartData) {
1477
+ this.drawTablesWindow();
1478
+ return;
1479
+ }
1480
+ this.lastChartKey = chartKey;
1481
+ let times = (res.times ?? []).map(t => this.parseUtc(t));
1482
+ let fixed = res.dimension == TopActivityDimension.WaitClass || res.dimension == TopActivityDimension.EventType;
1483
+ let uom = this.lc.loc("sessioni");
1484
+ let series = [];
1485
+ this.colors = {};
1486
+ this.legend = (res.components ?? []).map((c, i) => {
1487
+ let color = c.other ? OTHER_COLOR : (fixed && FIXED_COLORS[c.key]) || PALETTE[i % PALETTE.length];
1488
+ if (c.key != null)
1489
+ this.colors[c.key] = color;
1490
+ let label = this.valueLabel(c.label, c.other, res.dimension);
1491
+ series.push(new LineSerie(label, times.map((t, j) => new DateValue(t, c.values?.[j] ?? 0)), null, color, uom));
1492
+ return { key: c.key, label: label, color: color, other: c.other, activity: c.activity, percentage: c.percentage };
1493
+ });
1494
+ // L'attività totale è una linea scura sopra le aree impilate, non impilata a sua volta
1495
+ if (res.totalActivity)
1496
+ series.push(new LineSerie(this.lc.loc("Attività totale"), times.map((t, j) => new DateValue(t, res.totalActivity[j] ?? 0)), null, TOTAL_COLOR, uom, false, false));
1497
+ let limit = null;
1498
+ if (res.maximumThreads != null)
1499
+ limit = new Limit(res.maximumThreads, this.limitLabel, LIMIT_COLOR);
1500
+ // L'asse Y non si allarga da solo per le linee limite: lo allargo solo se l'attività arriva ad almeno un quarto del limite,
1501
+ // altrimenti con il sistema scarico il grafico diventerebbe una riga piatta sul fondo (il valore del limite resta in legenda)
1502
+ let peak = Math.max(res.peakActiveSessions ?? 0, ...(res.totalActivity ?? [0]));
1503
+ this.chartMax = limit && peak >= res.maximumThreads / 4 ? Math.max(peak, res.maximumThreads) * 1.1 : undefined;
1504
+ this.chartData = series.length > 0 ? new LineChartData(series, limit) : null;
1505
+ }
1506
+ // #endregion
1507
+ // #region Grafico, legenda e filtri
1508
+ onChartLoaded(chart) {
1509
+ // Il grafico viene ricreato a ogni cambio di dati: l'area della finestra delle tabelle va rifatta
1510
+ this.chart = chart;
1511
+ this.windowAxis = null;
1512
+ this.drawTablesWindow();
1513
+ }
1514
+ drawTablesWindow() {
1515
+ let dateAxis = this.chart?.ChartService?.dateAxis;
1516
+ if (!dateAxis || !this.sliderMax)
1517
+ return;
1518
+ let end = this.sliderValue;
1519
+ let start = Math.max(this.chartFrom, end - TABLES_WINDOW_MS);
1520
+ this.zone.runOutsideAngular(() => {
1521
+ if (this.windowAxis !== dateAxis) {
1522
+ this.windowAxis = dateAxis;
1523
+ this.windowRange = dateAxis.makeDataItem({ value: start, endValue: end });
1524
+ dateAxis.createAxisRange(this.windowRange);
1525
+ this.windowRange.get("axisFill")?.setAll({ fill: am5.color(0x6366f1), fillOpacity: 0.12, visible: true });
1526
+ this.windowRange.get("grid")?.set("forceHidden", true);
1527
+ this.windowRange.get("label")?.set("forceHidden", true);
1528
+ }
1529
+ else
1530
+ this.windowRange.setAll({ value: start, endValue: end });
1531
+ });
1532
+ }
1533
+ addFilter(item) {
1534
+ // Il componente "altri" non è filtrabile, come in Oracle
1535
+ if (item.other || !this.result)
1536
+ return;
1537
+ let filter = new TopActivityV2Filter();
1538
+ filter.dimension = this.result.dimension;
1539
+ filter.value = item.key ?? "";
1540
+ if (this.filters.some(t => t.filter.dimension == filter.dimension && t.filter.value == filter.value))
1541
+ return;
1542
+ this.filters.push({ filter: filter, label: `${this.dimensionLabel(filter.dimension)} = ${item.label}` });
1543
+ this.totalActivity = true;
1544
+ this.search();
1545
+ }
1546
+ removeFilter(index) {
1547
+ this.filters.splice(index, 1);
1548
+ this.search();
1549
+ }
1550
+ // #endregion
1551
+ // #region Time slider e tabelle
1552
+ sliderMoving() {
1553
+ this.updateTablesWindowLabel();
1554
+ this.drawTablesWindow();
1555
+ }
1556
+ sliderChanged() {
1557
+ // Il range input arrotonda al passo: "agganciato" se è a meno di un passo dalla fine
1558
+ this.sliderAnchored = this.sliderMax - this.sliderValue < this.sliderStep;
1559
+ this.search();
1560
+ }
1561
+ updateTablesWindowLabel() {
1562
+ if (!this.sliderMax) {
1563
+ this.tablesWindowLabel = "";
1564
+ return;
1565
+ }
1566
+ let start = Math.max(this.chartFrom, this.sliderValue - TABLES_WINDOW_MS);
1567
+ this.tablesWindowLabel = `${this.fmt(new Date(start))} - ${this.fmt(new Date(this.sliderValue))}`;
1568
+ }
1569
+ isClickable(item) {
1570
+ return !item.other && (!!item.session || !!item.event?.eventId);
1571
+ }
1572
+ openItem(item) {
1573
+ if (!this.isClickable(item))
1574
+ return;
1575
+ if (item.session)
1576
+ this.loadSessionDetails(item.session);
1577
+ else
1578
+ this.loadNodeDetails(item.event.eventId);
1579
+ }
1580
+ breakdownWidth(item, part) {
1581
+ return item.activity ? part.activity / item.activity * 100 : 0;
1582
+ }
1583
+ breakdownColor(part) {
1584
+ return part.other || part.key == null ? OTHER_COLOR : this.colors[part.key] ?? OTHER_COLOR;
1585
+ }
1586
+ itemLabel(item, table) {
1587
+ return this.valueLabel(item.label, item.other, table.dimension);
1588
+ }
1589
+ loadNodeDetails(nodeId) {
1590
+ this.NodeDetails = null;
1591
+ this.dlgNodeDetails.show();
1592
+ requestAnimationFrame(async () => {
1593
+ this.NodeDetails = await this.adms.getNodeStats(this.be, nodeId, this.instance != INSTANCE_CURRENT);
1594
+ });
1595
+ }
1596
+ loadSessionDetails(session) {
1597
+ this.SessionDetails = null;
1598
+ this.dlgSessionDetails.show();
1599
+ requestAnimationFrame(async () => {
1600
+ this.SessionDetails = await this.adms.getSessionStats(this.be, session.sessionId?.toString(), session.serialNo?.toString(), session.instanceId);
1601
+ });
1602
+ }
1603
+ // #endregion
1604
+ // #region Aggiornamento automatico
1605
+ refreshChanged() {
1606
+ clearInterval(this.refreshTimer);
1607
+ this.refreshTimer = null;
1608
+ let seconds = +this.refreshSeconds;
1609
+ if (seconds > 0)
1610
+ this.refreshTimer = setInterval(() => this.shiftWindow(), seconds * 1000);
1611
+ }
1612
+ // Sposta in avanti la finestra della stessa durata: lo slider agganciato la segue, quello spostato resta dov'è
1613
+ shiftWindow() {
1614
+ if (this.loading)
1615
+ return;
1616
+ let to = this.toDate(this.filterto) ?? new Date();
1617
+ let from = this.toDate(this.filterfrom) ?? new Date(to.getTime() - 3600 * 1000);
1618
+ let now = new Date();
1619
+ this.filterfrom = this.fmt(new Date(now.getTime() - (to.getTime() - from.getTime())));
1620
+ this.filterto = this.fmt(now);
1621
+ this.search();
1622
+ }
1623
+ // #endregion
1624
+ // #region Supporto
1625
+ buildSources() {
1626
+ this.DataSources = [
1627
+ new KeyValue(String(TopActivityDataSource.MemoryAndStored), this.lc.loc("Memoria e storico")),
1628
+ new KeyValue(String(TopActivityDataSource.Memory), this.lc.loc("Solo memoria"))
1629
+ ];
1630
+ this.Dimensions = Object.keys(TopActivityDimension).filter(t => !isNaN(+t)).map(t => new KeyValue(t, this.dimensionLabel(+t)));
1631
+ this.Resolutions = [
1632
+ new KeyValue(String(TopActivityResolution.Low), this.lc.loc("Bassa")),
1633
+ new KeyValue(String(TopActivityResolution.Medium), this.lc.loc("Media")),
1634
+ new KeyValue(String(TopActivityResolution.High), this.lc.loc("Alta")),
1635
+ new KeyValue(String(TopActivityResolution.Maximum), this.lc.loc("Massima"))
1636
+ ];
1637
+ this.ThreadKinds = [
1638
+ new KeyValue(String(TopActivityMaximumThreads.Threads), this.lc.loc("Worker thread")),
1639
+ new KeyValue(String(TopActivityMaximumThreads.Cores), "CPU")
1640
+ ];
1641
+ this.RefreshOptions = [
1642
+ new KeyValue("0", this.lc.loc("Spento")),
1643
+ new KeyValue("15", this.lc.loc("Ogni 15 s")),
1644
+ new KeyValue("30", this.lc.loc("Ogni 30 s")),
1645
+ new KeyValue("60", this.lc.loc("Ogni 60 s"))
1646
+ ];
1647
+ this.Instances = [
1648
+ new KeyValue(INSTANCE_CURRENT, this.lc.loc("Istanza corrente")),
1649
+ new KeyValue(INSTANCE_ALL, this.lc.loc("Tutte le istanze"))
1650
+ ];
1651
+ }
1652
+ async loadInstances() {
1653
+ try {
1654
+ let instances = await this.adms.getInstances(this.be);
1655
+ this.Instances = [...this.Instances.slice(0, 2), ...(instances ?? []).map(t => new KeyValue(t.id, t.description))];
1656
+ }
1657
+ catch {
1658
+ // Senza elenco istanze restano "corrente" e "tutte"
1659
+ }
1660
+ }
1661
+ async refreshInfos() {
1662
+ // DirectorInfos è facoltativo: se scoppia la pagina va avanti lo stesso
1663
+ this.DirInfos = await this.adms.getInfos(this.be);
1664
+ }
1665
+ dimensionLabel(dimension) {
1666
+ switch (dimension) {
1667
+ case TopActivityDimension.WaitClass: return this.lc.loc("Classe di attesa");
1668
+ case TopActivityDimension.EventType: return this.lc.loc("Tipo evento");
1669
+ case TopActivityDimension.WaitEvent: return this.lc.loc("Nodo");
1670
+ case TopActivityDimension.Instance: return this.lc.loc("Istanza");
1671
+ case TopActivityDimension.UserSession: return this.lc.loc("Sessione");
1672
+ case TopActivityDimension.UserName: return this.lc.loc("Utente");
1673
+ case TopActivityDimension.Tenant: return this.lc.loc("Tenant");
1674
+ case TopActivityDimension.SessionType: return this.lc.loc("Tipo sessione");
1675
+ case TopActivityDimension.BackgroundSession: return this.lc.loc("Sessione di background");
1676
+ case TopActivityDimension.JobName: return this.lc.loc("Job");
1677
+ case TopActivityDimension.ConsumerGroup: return this.lc.loc("Gruppo di consumo");
1678
+ case TopActivityDimension.ThreadType: return this.lc.loc("Tipo thread");
1679
+ case TopActivityDimension.Api: return "API";
1680
+ case TopActivityDimension.Machine: return this.lc.loc("Macchina");
1681
+ }
1682
+ return String(dimension);
1683
+ }
1684
+ valueLabel(label, other, dimension) {
1685
+ if (other)
1686
+ return this.lc.loc("Altri");
1687
+ if (label == null || label === "")
1688
+ return this.lc.loc(dimension == TopActivityDimension.WaitEvent ? "(non attribuito)" : "(nessuno)");
1689
+ return label;
1690
+ }
1691
+ applySettings(saved) {
1692
+ this.instance = saved.instance ?? this.instance;
1693
+ this.dataSource = saved.dataSource ?? this.dataSource;
1694
+ this.dimension = saved.dimension ?? this.dimension;
1695
+ this.resolution = saved.resolution ?? this.resolution;
1696
+ this.totalActivity = saved.totalActivity ?? this.totalActivity;
1697
+ this.maxCpu = saved.maxCpu ?? this.maxCpu;
1698
+ this.maxThreadsKind = saved.maxThreadsKind ?? this.maxThreadsKind;
1699
+ this.tableDims = saved.tableDims?.length == 2 ? saved.tableDims : this.tableDims;
1700
+ // Filtri salvati con i nomi delle prime versioni (PascalCase) non sono più validi
1701
+ this.filters = (saved.filters ?? []).filter(t => t?.filter?.dimension != null);
1702
+ }
1703
+ saveSettings() {
1704
+ let settings = {
1705
+ instance: this.instance,
1706
+ dataSource: this.dataSource,
1707
+ dimension: this.dimension,
1708
+ resolution: this.resolution,
1709
+ totalActivity: this.totalActivity,
1710
+ maxCpu: this.maxCpu,
1711
+ maxThreadsKind: this.maxThreadsKind,
1712
+ tableDims: this.tableDims,
1713
+ filters: this.filters
1714
+ };
1715
+ this.localStorage.setItem(STORAGE_KEY, settings).subscribe();
1716
+ }
1717
+ setLastHour() {
1718
+ let now = new Date();
1719
+ this.filterfrom = this.fmt(new Date(now.getTime() - 3600 * 1000));
1720
+ this.filterto = this.fmt(now);
1721
+ }
1722
+ toDate(value) {
1723
+ return value ? this.dateExts.getDateConvertion(value).toDate() : null;
1724
+ }
1725
+ fmt(date) {
1726
+ return dayjs(date).format(this.lc.token("getFullDateDisplayFormat"));
1727
+ }
1728
+ // Le date della risposta sono UTC "dd/MM/yyyy HH:mm:ss" senza fuso
1729
+ parseUtc(value) {
1730
+ let m = /^(\d{2})\/(\d{2})\/(\d{4}) (\d{2}):(\d{2}):(\d{2})$/.exec(value ?? "");
1731
+ return m ? new Date(Date.UTC(+m[3], +m[2] - 1, +m[1], +m[4], +m[5], +m[6])) : new Date(value);
1732
+ }
1733
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivityV2Component, deps: [{ token: i1$1.DateService }, { token: i1.LocalizationService }, { token: i3.PreferencesService }, { token: i1$1.InterComService }, { token: i4.ActivatedRoute }, { token: AdminModuleBaseService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
1734
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.34", type: AdmTopActivityV2Component, isStandalone: false, selector: "topact_v2", providers: [{ provide: LocalizationService, useClass: AdmTopActivityV2Loc }], viewQueries: [{ propertyName: "dlgNodeDetails", first: true, predicate: ["dlgNodeDetails"], descendants: true }, { propertyName: "dlgSessionDetails", first: true, predicate: ["dlgSessionDetails"], descendants: true }], ngImport: i0, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n @if (DirInfos) {\r\n <span>&nbsp;-&nbsp;\r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span>\r\n }\r\n </span>\r\n </div>\r\n <div class=\"card-body widget-body\">\r\n <form role=\"form\">\r\n <!-- Finestra e origine dei dati -->\r\n <div class=\"tav2-toolbar\">\r\n <div class=\"tav2-field\">\r\n <form-datetime [readonly]=\"refreshSeconds != '0'\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"tav2-field\">\r\n <form-datetime [readonly]=\"refreshSeconds != '0'\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"tav2-field tav2-field-wide\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"instance\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanza' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-field\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"dataSource\" name=\"dataSource\" [Source]=\"DataSources\" [Placeholder]=\"'Origine dati' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-spacer\"></div>\r\n <div class=\"tav2-field tav2-field-narrow\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"refreshSeconds\" name=\"refreshSeconds\" [Source]=\"RefreshOptions\" [Placeholder]=\"'Aggiornamento' | localize: lc\" (inputChange)=\"refreshChanged()\"></form-select>\r\n </div>\r\n <button [disabled]=\"loading || refreshSeconds != '0'\" class=\"btn app-btn-search\" (click)=\"searchClicked()\" type=\"submit\" [title]=\"'Cerca' | localize: lc\">\r\n <i class=\"fa\" [class.fa-search]=\"!loading\" [class.fa-spinner]=\"loading\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Come dividere e cosa disegnare -->\r\n <div class=\"tav2-toolbar\">\r\n <div class=\"tav2-field tav2-field-wide\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"dimension\" name=\"dimension\" [Source]=\"Dimensions\" [Placeholder]=\"'Dividi per' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-field tav2-field-narrow\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"resolution\" name=\"resolution\" [Source]=\"Resolutions\" [Placeholder]=\"'Risoluzione' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-toggle\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"totalActivity\" name=\"totalActivity\" (inputChange)=\"search()\"></form-checkbox>\r\n <span>{{'Attivit\u00E0 totale' | localize: lc}}</span>\r\n </div>\r\n <div class=\"tav2-toggle\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"maxCpu\" name=\"maxCpu\" (inputChange)=\"search()\"></form-checkbox>\r\n <span>{{'Limite' | localize: lc}}</span>\r\n </div>\r\n @if (maxCpu) {\r\n <div class=\"tav2-field tav2-field-narrow\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"maxThreadsKind\" name=\"maxThreadsKind\" [Source]=\"ThreadKinds\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n }\r\n </div>\r\n </form>\r\n\r\n <!-- Grafico -->\r\n <div class=\"tav2-panel\">\r\n <div class=\"tav2-panel-header\">\r\n <span class=\"tav2-title\">{{'Sessioni attive medie per' | localize: lc}} {{dimensionLabel(result?.dimension ?? +dimension) | lowercase}}</span>\r\n @if (result) {\r\n <span class=\"tav2-muted\">\r\n {{'Media' | localize: lc}} <strong>{{result.averageActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n &middot; {{'Picco' | localize: lc}} <strong>{{result.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n &middot; {{'un punto ogni' | localize: lc}} {{result.bucketSeconds}} s\r\n </span>\r\n }\r\n @if (loading) {\r\n <span class=\"tav2-muted\"><i class=\"fa fa-spinner fa-spin\"></i></span>\r\n }\r\n </div>\r\n\r\n @if (filters.length > 0) {\r\n <div class=\"tav2-chips\">\r\n <span class=\"tav2-muted\">{{'Filtri' | localize: lc}}</span>\r\n @for (chip of filters; track $index) {\r\n <span class=\"tav2-chip\">\r\n {{chip.label}}\r\n <button type=\"button\" [title]=\"'Rimuovi' | localize: lc\" (click)=\"removeFilter($index)\">&times;</button>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"tav2-chart\">\r\n @if (chartData) {\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [Step]=\"true\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"chartData\"\r\n [Max]=\"chartMax\"\r\n [Legend]=\"false\"\r\n name=\"topactv2\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event)\"></es-line-chart>\r\n } @else {\r\n <div class=\"tav2-empty\">{{(loading ? 'Carico i Dati' : 'Nessun dato nella finestra') | localize: lc}}</div>\r\n }\r\n </div>\r\n\r\n <!-- Legenda: un clic su una voce la aggiunge ai filtri (\"altri\" non \u00E8 filtrabile) -->\r\n @if (legend.length > 0) {\r\n <div class=\"tav2-legend\">\r\n @for (item of legend; track $index) {\r\n <span class=\"tav2-legend-item\" [class.tav2-clickable]=\"!item.other\" [title]=\"item.other ? '' : ('Clic per filtrare' | localize: lc)\" (click)=\"addFilter(item)\">\r\n <span class=\"tav2-swatch\" [style.background]=\"item.color\"></span>\r\n {{item.label}}\r\n <span class=\"tav2-muted\">{{item.percentage | number : '1.0-1' : 'it'}}%</span>\r\n </span>\r\n }\r\n @if (result?.totalActivity) {\r\n <span class=\"tav2-legend-item\">\r\n <span class=\"tav2-line\" [style.border-color]=\"TotalColor\"></span>\r\n {{'Attivit\u00E0 totale' | localize: lc}}\r\n </span>\r\n }\r\n @if (result?.maximumThreads != null) {\r\n <span class=\"tav2-legend-item\">\r\n <span class=\"tav2-line\" [style.border-color]=\"LimitColor\"></span>\r\n {{limitLabel}} <strong>{{result.maximumThreads}}</strong>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n @if (memoryFrom) {\r\n <div class=\"tav2-note\">\r\n <i class=\"fa fa-info-circle\"></i>\r\n {{'Prima di questo istante i dati vengono dallo storico (un campione ogni 10 secondi)' | localize: lc}}: {{memoryFrom}}\r\n </div>\r\n }\r\n\r\n <!-- Time slider: finestra di 5 minuti per le tabelle -->\r\n @if (sliderMax > sliderMin) {\r\n <div class=\"tav2-slider\">\r\n <span class=\"tav2-slider-label\">\r\n <span class=\"tav2-muted\">{{'Finestra tabelle' | localize: lc}}</span>\r\n <strong>{{tablesWindowLabel}}</strong>\r\n </span>\r\n <input type=\"range\" [min]=\"sliderMin\" [max]=\"sliderMax\" [step]=\"sliderStep\" [ngModel]=\"sliderValue\" (ngModelChange)=\"sliderValue = $event; sliderMoving()\" (change)=\"sliderChanged()\" />\r\n <span class=\"tav2-badge\" [class.tav2-badge-off]=\"!sliderAnchored\">{{(sliderAnchored ? 'Ultimi 5 minuti' : 'Finestra fissa') | localize: lc}}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Tabelle -->\r\n <div class=\"tav2-tables\">\r\n @for (table of tables; track $index; let i = $index) {\r\n <div class=\"tav2-panel\">\r\n <div class=\"tav2-panel-header\">\r\n <span class=\"tav2-title\">{{'Prime righe per' | localize: lc}}</span>\r\n <div class=\"tav2-field tav2-field-wide\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"tableDims[i]\" name=\"tabledim{{i}}\" [Source]=\"Dimensions\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <span class=\"tav2-muted\">{{'Attivit\u00E0' | localize: lc}} <strong>{{table.activity | number : '1.2-3' : 'it'}}</strong></span>\r\n </div>\r\n <es-table [(ngModel)]=\"table.items\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th>{{dimensionLabel(table.dimension)}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min tav2-right\">%</th>\r\n @if (table.dimension == Dim.UserSession) {\r\n <th>{{'Utente' | localize: lc}}</th>\r\n <th>{{'Tenant' | localize: lc}}</th>\r\n <th>{{'Tipo' | localize: lc}}</th>\r\n <th>{{'Processo' | localize: lc}}</th>\r\n }\r\n @if (table.dimension == Dim.WaitEvent) {\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo evento' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe di attesa' | localize: lc}}</th>\r\n }\r\n </ng-template>\r\n <ng-template #body let-item>\r\n <td>\r\n @if (isClickable(item)) {\r\n <span class=\"app-link tav2-ellipsis\" [title]=\"item.label || item.key\" (click)=\"openItem(item)\">{{itemLabel(item, table)}}</span>\r\n } @else {\r\n <span class=\"tav2-ellipsis\" [class.tav2-muted]=\"item.other || !item.label\">{{itemLabel(item, table)}}</span>\r\n }\r\n </td>\r\n <td class=\"app-nowrap\">\r\n <div class=\"tav2-bar-cell\">\r\n <div class=\"tav2-bar\">\r\n @for (part of item.breakdown; track $index) {\r\n <div [style.width.%]=\"breakdownWidth(item, part)\" [style.background]=\"breakdownColor(part)\" [title]=\"part.key\"></div>\r\n }\r\n </div>\r\n <span>{{item.activity | number : '1.2-3' : 'it'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"app-nowrap tav2-right\">{{item.percentage | number : '1.1-1' : 'it'}}</td>\r\n @if (table.dimension == Dim.UserSession) {\r\n <td>{{item.session?.userName}}</td>\r\n <td>{{item.session?.tenantId}}</td>\r\n <td>{{item.session?.sessionType}}</td>\r\n <td><span class=\"tav2-ellipsis\" [title]=\"item.session?.bgProcessName || item.session?.jobName || ''\">{{item.session?.bgProcessName || item.session?.jobName}}</span></td>\r\n }\r\n @if (table.dimension == Dim.WaitEvent) {\r\n <td>{{item.event?.eventType}}</td>\r\n <td>{{item.event?.waitClass}}</td>\r\n }\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (NodeDetails) {\r\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\r\n }\r\n</div>\r\n\r\n<div bsModal #dlgSessionDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (SessionDetails) {\r\n <session-detail [SessionDetails]=\"SessionDetails\" (onClose)=\"dlgSessionDetails.hide()\" (onNodeSelected)=\"loadNodeDetails($event)\"></session-detail>\r\n }\r\n</div>\r\n", styles: [":host{display:block}.tav2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px}.tav2-toolbar+.tav2-toolbar{margin-top:8px}.tav2-field{width:175px}.tav2-field-wide{width:220px}.tav2-field-narrow{width:150px}.tav2-spacer{flex:1 1 auto}.tav2-toggle{display:flex;align-items:center;gap:8px;height:38px;padding:0 6px;white-space:nowrap}.tav2-panel{margin-top:14px;padding:10px 12px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:#fff;min-width:0}.tav2-panel-header{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;min-height:32px;margin-bottom:6px}.tav2-title{font-size:12px;font-weight:500;letter-spacing:.03em;text-transform:uppercase;color:#344154}.tav2-muted{color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-right{text-align:right}.tav2-ellipsis{display:inline-block;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.tav2-chips{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:6px}.tav2-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 10px;border-radius:12px;background:#eef2ff;color:#3730a3;font-size:12px}.tav2-chip button{border:0;background:transparent;color:inherit;cursor:pointer;font-size:15px;line-height:1;padding:0 4px}.tav2-chart{position:relative;height:300px}.tav2-empty{display:flex;align-items:center;justify-content:center;height:100%;border:1px dashed var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);color:var(--p-text-muted-color, #64748b)}.tav2-legend{display:flex;flex-wrap:wrap;gap:4px 6px;margin-top:6px}.tav2-legend-item{display:inline-flex;align-items:center;gap:6px;padding:2px 8px;border:1px solid transparent;border-radius:4px;font-size:12px;white-space:nowrap}.tav2-legend-item.tav2-clickable{cursor:pointer}.tav2-legend-item.tav2-clickable:hover{border-color:var(--p-content-border-color, #e2e8f0);background:#f8fafc}.tav2-swatch{flex:none;width:10px;height:10px;border-radius:2px}.tav2-line{flex:none;width:16px;height:0;border-top:2px solid}.tav2-note{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-slider{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin-top:10px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.tav2-slider input[type=range]{flex:1 1 260px;min-width:200px;accent-color:var(--p-primary-color, #6366f1);cursor:pointer}.tav2-slider-label{display:inline-flex;flex-direction:column;line-height:1.2;font-size:12px}.tav2-badge{padding:2px 8px;border-radius:10px;background:#eef2ff;color:#3730a3;font-size:11px;white-space:nowrap}.tav2-badge.tav2-badge-off{background:#f1f5f9;color:var(--p-text-muted-color, #64748b)}.tav2-tables{display:grid;grid-template-columns:repeat(auto-fit,minmax(460px,1fr));gap:0 14px}.tav2-bar-cell{display:flex;align-items:center;gap:8px}.tav2-bar{display:flex;flex:none;width:90px;height:8px;border-radius:2px;overflow:hidden;background:#edf2f7}\n"], dependencies: [{ kind: "directive", type: i7.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i7.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i7.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i7.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i7.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i7.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i8$1.ModalDirective, selector: "[bsModal]", inputs: ["config", "closeInterceptor"], outputs: ["onShow", "onShown", "onHide", "onHidden"], exportAs: ["bs-modal"] }, { kind: "component", type: i8.EsTableComponent, selector: "es-table", inputs: ["globalCheck", "autoUpdate", "seconds", "researchInProgress", "globalColVisCheck", "EsThTdProvider", "CornerMenuOptions", "ColumnsResizable", "ColumnsPinnable", "AutoUpdate", "Height", "EmptySpaceBackgroundColor", "EsTableHandledSearch", "MaxHeight", "ContainerClass", "XLSXExport", "CSVExport", "AllSearch", "HighCellDensity", "Selection", "ShowLoadingOnBootstrap", "Removal", "RemovalCondition", "Export", "ShiftClick", "CountLabel", "HidePaging", "HidePagingCount", "HidePagingButtons", "ContextMenu", "ExportFileName", "TableClass", "ExportFunction", "ExportOnlyVisibleColumns", "HasHeaderGroup", "HasSecondaryHeaderGroup", "HeaderHidden", "BodyHidden", "SelectionDisabled", "SingleSelection", "RowClassAssigner", "OrderByColumn", "MultipleOrderingDirectives", "HiddenColumns", "ColumnsOrdering", "SearchView", "SelectAll", "UseArrayModePaging", "DynamicRowColumnsDefinition", "DynamicOperations", "Hierarchy", "ParentKey", "OwnKey", "AutoSortHierarchy", "StartsExpanded", "SavePreferences", "DefaultAlignment", "PagingStyle", "RowGroupingPagingStyle", "ItemSourceProperty", "UseSelectionCache", "ShowItemGroupsColumns", "Editable", "RangeSelection", "SearchThrottle", "ArraymodeItemsPerPage"], outputs: ["globalCheckChange", "autoUpdateChange", "secondsChange", "researchInProgressChange", "globalColVisCheckChange", "onOrderChanged", "onSearchRequest", "onSelectionChanged", "onRemoval", "onAbortRemoval", "onModelChange", "onOpenContextMenu", "onCornerAction", "onDynamicOperation"] }, { kind: "component", type: i9.EsFormSelectComponent, selector: "form-select", inputs: ["OptionsTemplate"] }, { kind: "component", type: i9.EsFormDateTimeComponent, selector: "form-datetime" }, { kind: "component", type: i9.EsFormCheckboxComponent, selector: "form-checkbox", inputs: ["SliderMode"] }, { kind: "component", type: i2.EsLineChartComponent, selector: "es-line-chart", inputs: ["Data", "DataArray", "Step", "DataGroupBucketSize", "DataGroupingThreshold", "StrokeSize", "AllowGaps", "MergeDatasets", "FinalInstants", "Min", "Max", "Fill", "Stacked"] }, { kind: "directive", type: i10.Widget, selector: "[widget]" }, { kind: "component", type: SessionDetailComponent, selector: "session-detail", inputs: ["SessionDetails"], outputs: ["onClose", "onNodeSelected"] }, { kind: "component", type: NodeDetailComponent, selector: "node-detail", inputs: ["NodeDetails"], outputs: ["onClose"] }, { kind: "pipe", type: i5.LowerCasePipe, name: "lowercase" }, { kind: "pipe", type: i5.DecimalPipe, name: "number" }, { kind: "pipe", type: i1.LocalizePipe, name: "localize" }] }); }
1735
+ }
1736
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmTopActivityV2Component, decorators: [{
1737
+ type: Component,
1738
+ args: [{ selector: "topact_v2", providers: [{ provide: LocalizationService, useClass: AdmTopActivityV2Loc }], standalone: false, template: "<div class=\"row\">\r\n <div class=\"col-12\">\r\n <div class=\"card app-overflow-visible\" widget>\r\n <div class=\"card-header\">\r\n <span class=\"text-uppercase\">\r\n {{'Attivit\u00E0 Principali' | localize: lc}}\r\n @if (DirInfos) {\r\n <span>&nbsp;-&nbsp;\r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}}&nbsp;\r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg5 | number : '1.1-2' : 'it'}}&nbsp;{{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span>\r\n }\r\n </span>\r\n </div>\r\n <div class=\"card-body widget-body\">\r\n <form role=\"form\">\r\n <!-- Finestra e origine dei dati -->\r\n <div class=\"tav2-toolbar\">\r\n <div class=\"tav2-field\">\r\n <form-datetime [readonly]=\"refreshSeconds != '0'\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterfrom\" name=\"filterfrom\" [Placeholder]=\"'Da' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"tav2-field\">\r\n <form-datetime [readonly]=\"refreshSeconds != '0'\" [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"filterto\" name=\"filterto\" [Placeholder]=\"'A' | localize: lc\"></form-datetime>\r\n </div>\r\n <div class=\"tav2-field tav2-field-wide\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"instance\" name=\"instance\" [Source]=\"Instances\" [Placeholder]=\"'Istanza' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-field\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"dataSource\" name=\"dataSource\" [Source]=\"DataSources\" [Placeholder]=\"'Origine dati' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-spacer\"></div>\r\n <div class=\"tav2-field tav2-field-narrow\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"refreshSeconds\" name=\"refreshSeconds\" [Source]=\"RefreshOptions\" [Placeholder]=\"'Aggiornamento' | localize: lc\" (inputChange)=\"refreshChanged()\"></form-select>\r\n </div>\r\n <button [disabled]=\"loading || refreshSeconds != '0'\" class=\"btn app-btn-search\" (click)=\"searchClicked()\" type=\"submit\" [title]=\"'Cerca' | localize: lc\">\r\n <i class=\"fa\" [class.fa-search]=\"!loading\" [class.fa-spinner]=\"loading\" [class.fa-spin]=\"loading\"></i>\r\n </button>\r\n </div>\r\n\r\n <!-- Come dividere e cosa disegnare -->\r\n <div class=\"tav2-toolbar\">\r\n <div class=\"tav2-field tav2-field-wide\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"dimension\" name=\"dimension\" [Source]=\"Dimensions\" [Placeholder]=\"'Dividi per' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-field tav2-field-narrow\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"resolution\" name=\"resolution\" [Source]=\"Resolutions\" [Placeholder]=\"'Risoluzione' | localize: lc\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <div class=\"tav2-toggle\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"totalActivity\" name=\"totalActivity\" (inputChange)=\"search()\"></form-checkbox>\r\n <span>{{'Attivit\u00E0 totale' | localize: lc}}</span>\r\n </div>\r\n <div class=\"tav2-toggle\">\r\n <form-checkbox [FormLayout]=\"false\" [SliderMode]=\"true\" [Validation]=\"false\" [(ngModel)]=\"maxCpu\" name=\"maxCpu\" (inputChange)=\"search()\"></form-checkbox>\r\n <span>{{'Limite' | localize: lc}}</span>\r\n </div>\r\n @if (maxCpu) {\r\n <div class=\"tav2-field tav2-field-narrow\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"maxThreadsKind\" name=\"maxThreadsKind\" [Source]=\"ThreadKinds\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n }\r\n </div>\r\n </form>\r\n\r\n <!-- Grafico -->\r\n <div class=\"tav2-panel\">\r\n <div class=\"tav2-panel-header\">\r\n <span class=\"tav2-title\">{{'Sessioni attive medie per' | localize: lc}} {{dimensionLabel(result?.dimension ?? +dimension) | lowercase}}</span>\r\n @if (result) {\r\n <span class=\"tav2-muted\">\r\n {{'Media' | localize: lc}} <strong>{{result.averageActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n &middot; {{'Picco' | localize: lc}} <strong>{{result.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n &middot; {{'un punto ogni' | localize: lc}} {{result.bucketSeconds}} s\r\n </span>\r\n }\r\n @if (loading) {\r\n <span class=\"tav2-muted\"><i class=\"fa fa-spinner fa-spin\"></i></span>\r\n }\r\n </div>\r\n\r\n @if (filters.length > 0) {\r\n <div class=\"tav2-chips\">\r\n <span class=\"tav2-muted\">{{'Filtri' | localize: lc}}</span>\r\n @for (chip of filters; track $index) {\r\n <span class=\"tav2-chip\">\r\n {{chip.label}}\r\n <button type=\"button\" [title]=\"'Rimuovi' | localize: lc\" (click)=\"removeFilter($index)\">&times;</button>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"tav2-chart\">\r\n @if (chartData) {\r\n <es-line-chart [MinGridDistance]=\"65\"\r\n [Timeline]=\"false\"\r\n [FinalInstants]=\"false\"\r\n [Stacked]=\"true\"\r\n [Step]=\"true\"\r\n [Fill]=\"true\"\r\n [MergeDatasets]=\"true\"\r\n [Data]=\"chartData\"\r\n [Max]=\"chartMax\"\r\n [Legend]=\"false\"\r\n name=\"topactv2\"\r\n [DataGroupingThreshold]=\"99999999\"\r\n (chartLoaded)=\"onChartLoaded($event)\"></es-line-chart>\r\n } @else {\r\n <div class=\"tav2-empty\">{{(loading ? 'Carico i Dati' : 'Nessun dato nella finestra') | localize: lc}}</div>\r\n }\r\n </div>\r\n\r\n <!-- Legenda: un clic su una voce la aggiunge ai filtri (\"altri\" non \u00E8 filtrabile) -->\r\n @if (legend.length > 0) {\r\n <div class=\"tav2-legend\">\r\n @for (item of legend; track $index) {\r\n <span class=\"tav2-legend-item\" [class.tav2-clickable]=\"!item.other\" [title]=\"item.other ? '' : ('Clic per filtrare' | localize: lc)\" (click)=\"addFilter(item)\">\r\n <span class=\"tav2-swatch\" [style.background]=\"item.color\"></span>\r\n {{item.label}}\r\n <span class=\"tav2-muted\">{{item.percentage | number : '1.0-1' : 'it'}}%</span>\r\n </span>\r\n }\r\n @if (result?.totalActivity) {\r\n <span class=\"tav2-legend-item\">\r\n <span class=\"tav2-line\" [style.border-color]=\"TotalColor\"></span>\r\n {{'Attivit\u00E0 totale' | localize: lc}}\r\n </span>\r\n }\r\n @if (result?.maximumThreads != null) {\r\n <span class=\"tav2-legend-item\">\r\n <span class=\"tav2-line\" [style.border-color]=\"LimitColor\"></span>\r\n {{limitLabel}} <strong>{{result.maximumThreads}}</strong>\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n @if (memoryFrom) {\r\n <div class=\"tav2-note\">\r\n <i class=\"fa fa-info-circle\"></i>\r\n {{'Prima di questo istante i dati vengono dallo storico (un campione ogni 10 secondi)' | localize: lc}}: {{memoryFrom}}\r\n </div>\r\n }\r\n\r\n <!-- Time slider: finestra di 5 minuti per le tabelle -->\r\n @if (sliderMax > sliderMin) {\r\n <div class=\"tav2-slider\">\r\n <span class=\"tav2-slider-label\">\r\n <span class=\"tav2-muted\">{{'Finestra tabelle' | localize: lc}}</span>\r\n <strong>{{tablesWindowLabel}}</strong>\r\n </span>\r\n <input type=\"range\" [min]=\"sliderMin\" [max]=\"sliderMax\" [step]=\"sliderStep\" [ngModel]=\"sliderValue\" (ngModelChange)=\"sliderValue = $event; sliderMoving()\" (change)=\"sliderChanged()\" />\r\n <span class=\"tav2-badge\" [class.tav2-badge-off]=\"!sliderAnchored\">{{(sliderAnchored ? 'Ultimi 5 minuti' : 'Finestra fissa') | localize: lc}}</span>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Tabelle -->\r\n <div class=\"tav2-tables\">\r\n @for (table of tables; track $index; let i = $index) {\r\n <div class=\"tav2-panel\">\r\n <div class=\"tav2-panel-header\">\r\n <span class=\"tav2-title\">{{'Prime righe per' | localize: lc}}</span>\r\n <div class=\"tav2-field tav2-field-wide\">\r\n <form-select [FormLayout]=\"false\" [Validation]=\"false\" [(ngModel)]=\"tableDims[i]\" name=\"tabledim{{i}}\" [Source]=\"Dimensions\" (inputChange)=\"search()\"></form-select>\r\n </div>\r\n <span class=\"tav2-muted\">{{'Attivit\u00E0' | localize: lc}} <strong>{{table.activity | number : '1.2-3' : 'it'}}</strong></span>\r\n </div>\r\n <es-table [(ngModel)]=\"table.items\" [HidePaging]=\"true\">\r\n <ng-template #header>\r\n <th>{{dimensionLabel(table.dimension)}}</th>\r\n <th class=\"app-col-min\">{{'Attivit\u00E0' | localize: lc}}</th>\r\n <th class=\"app-col-min tav2-right\">%</th>\r\n @if (table.dimension == Dim.UserSession) {\r\n <th>{{'Utente' | localize: lc}}</th>\r\n <th>{{'Tenant' | localize: lc}}</th>\r\n <th>{{'Tipo' | localize: lc}}</th>\r\n <th>{{'Processo' | localize: lc}}</th>\r\n }\r\n @if (table.dimension == Dim.WaitEvent) {\r\n <th class=\"app-col-min app-nowrap\">{{'Tipo evento' | localize: lc}}</th>\r\n <th class=\"app-col-min app-nowrap\">{{'Classe di attesa' | localize: lc}}</th>\r\n }\r\n </ng-template>\r\n <ng-template #body let-item>\r\n <td>\r\n @if (isClickable(item)) {\r\n <span class=\"app-link tav2-ellipsis\" [title]=\"item.label || item.key\" (click)=\"openItem(item)\">{{itemLabel(item, table)}}</span>\r\n } @else {\r\n <span class=\"tav2-ellipsis\" [class.tav2-muted]=\"item.other || !item.label\">{{itemLabel(item, table)}}</span>\r\n }\r\n </td>\r\n <td class=\"app-nowrap\">\r\n <div class=\"tav2-bar-cell\">\r\n <div class=\"tav2-bar\">\r\n @for (part of item.breakdown; track $index) {\r\n <div [style.width.%]=\"breakdownWidth(item, part)\" [style.background]=\"breakdownColor(part)\" [title]=\"part.key\"></div>\r\n }\r\n </div>\r\n <span>{{item.activity | number : '1.2-3' : 'it'}}</span>\r\n </div>\r\n </td>\r\n <td class=\"app-nowrap tav2-right\">{{item.percentage | number : '1.1-1' : 'it'}}</td>\r\n @if (table.dimension == Dim.UserSession) {\r\n <td>{{item.session?.userName}}</td>\r\n <td>{{item.session?.tenantId}}</td>\r\n <td>{{item.session?.sessionType}}</td>\r\n <td><span class=\"tav2-ellipsis\" [title]=\"item.session?.bgProcessName || item.session?.jobName || ''\">{{item.session?.bgProcessName || item.session?.jobName}}</span></td>\r\n }\r\n @if (table.dimension == Dim.WaitEvent) {\r\n <td>{{item.event?.eventType}}</td>\r\n <td>{{item.event?.waitClass}}</td>\r\n }\r\n </ng-template>\r\n </es-table>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<div bsModal #dlgNodeDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (NodeDetails) {\r\n <node-detail [NodeDetails]=\"NodeDetails\" (onClose)=\"dlgNodeDetails.hide()\"></node-detail>\r\n }\r\n</div>\r\n\r\n<div bsModal #dlgSessionDetails=\"bs-modal\" class=\"modal fade\" role=\"dialog\" aria-hidden=\"true\">\r\n @if (SessionDetails) {\r\n <session-detail [SessionDetails]=\"SessionDetails\" (onClose)=\"dlgSessionDetails.hide()\" (onNodeSelected)=\"loadNodeDetails($event)\"></session-detail>\r\n }\r\n</div>\r\n", styles: [":host{display:block}.tav2-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 10px}.tav2-toolbar+.tav2-toolbar{margin-top:8px}.tav2-field{width:175px}.tav2-field-wide{width:220px}.tav2-field-narrow{width:150px}.tav2-spacer{flex:1 1 auto}.tav2-toggle{display:flex;align-items:center;gap:8px;height:38px;padding:0 6px;white-space:nowrap}.tav2-panel{margin-top:14px;padding:10px 12px 12px;border:1px solid var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);background:#fff;min-width:0}.tav2-panel-header{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;min-height:32px;margin-bottom:6px}.tav2-title{font-size:12px;font-weight:500;letter-spacing:.03em;text-transform:uppercase;color:#344154}.tav2-muted{color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-right{text-align:right}.tav2-ellipsis{display:inline-block;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}.tav2-chips{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:6px}.tav2-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 4px 2px 10px;border-radius:12px;background:#eef2ff;color:#3730a3;font-size:12px}.tav2-chip button{border:0;background:transparent;color:inherit;cursor:pointer;font-size:15px;line-height:1;padding:0 4px}.tav2-chart{position:relative;height:300px}.tav2-empty{display:flex;align-items:center;justify-content:center;height:100%;border:1px dashed var(--p-content-border-color, #e2e8f0);border-radius:var(--p-form-field-border-radius, 6px);color:var(--p-text-muted-color, #64748b)}.tav2-legend{display:flex;flex-wrap:wrap;gap:4px 6px;margin-top:6px}.tav2-legend-item{display:inline-flex;align-items:center;gap:6px;padding:2px 8px;border:1px solid transparent;border-radius:4px;font-size:12px;white-space:nowrap}.tav2-legend-item.tav2-clickable{cursor:pointer}.tav2-legend-item.tav2-clickable:hover{border-color:var(--p-content-border-color, #e2e8f0);background:#f8fafc}.tav2-swatch{flex:none;width:10px;height:10px;border-radius:2px}.tav2-line{flex:none;width:16px;height:0;border-top:2px solid}.tav2-note{margin-top:6px;color:var(--p-text-muted-color, #64748b);font-size:12px}.tav2-slider{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin-top:10px;padding-top:10px;border-top:1px solid var(--p-content-border-color, #e2e8f0)}.tav2-slider input[type=range]{flex:1 1 260px;min-width:200px;accent-color:var(--p-primary-color, #6366f1);cursor:pointer}.tav2-slider-label{display:inline-flex;flex-direction:column;line-height:1.2;font-size:12px}.tav2-badge{padding:2px 8px;border-radius:10px;background:#eef2ff;color:#3730a3;font-size:11px;white-space:nowrap}.tav2-badge.tav2-badge-off{background:#f1f5f9;color:var(--p-text-muted-color, #64748b)}.tav2-tables{display:grid;grid-template-columns:repeat(auto-fit,minmax(460px,1fr));gap:0 14px}.tav2-bar-cell{display:flex;align-items:center;gap:8px}.tav2-bar{display:flex;flex:none;width:90px;height:8px;border-radius:2px;overflow:hidden;background:#edf2f7}\n"] }]
1739
+ }], ctorParameters: () => [{ type: i1$1.DateService }, { type: i1.LocalizationService }, { type: i3.PreferencesService }, { type: i1$1.InterComService }, { type: i4.ActivatedRoute }, { type: AdminModuleBaseService }, { type: i0.NgZone }], propDecorators: { dlgNodeDetails: [{
1740
+ type: ViewChild,
1741
+ args: ["dlgNodeDetails"]
1742
+ }], dlgSessionDetails: [{
1743
+ type: ViewChild,
1744
+ args: ["dlgSessionDetails"]
1745
+ }] } });
1746
+
1097
1747
  class LocksView extends AppSearch {
1098
1748
  constructor() { super(); }
1099
1749
  }
@@ -1805,11 +2455,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
1805
2455
  }], ctorParameters: () => [{ type: i1$1.InterComService }] });
1806
2456
 
1807
2457
  // Angular
2458
+ // La Top Activity v2 prende la rotta "topact" solo se DirectorFeature.TopActivityV2 è attivo nella configurazione del modulo,
2459
+ // altrimenti la guardia fallisce e la rotta successiva apre la pagina di sempre
2460
+ const topActivityV2Enabled = () => inject(ADM_TOPACT_V2, { optional: true }) ?? false;
1808
2461
  const routeConfig = [
1809
2462
  {
1810
2463
  path: "", children: [
1811
2464
  { path: "serverworkers/:be", component: AdmWrkComponent, data: { title: "Ricerca Processi Applicativi", internalNavigation: false } },
1812
2465
  { path: "profiler/:be", component: AdmProfilerComponent, data: { title: "Profiler del Server", internalNavigation: false } },
2466
+ { path: "topact/:be", component: AdmTopActivityV2Component, canMatch: [topActivityV2Enabled], data: { title: "Attività Principali", internalNavigation: false } },
1813
2467
  { path: "topact/:be", component: AdmTopActivitiesComponent, data: { title: "Attività Principali", internalNavigation: false } },
1814
2468
  { path: "metrics/:be", component: AdmMetricsComponent, data: { title: "Metriche di Sistema", internalNavigation: false } },
1815
2469
  { path: "serverlogs/:be", component: AdmLogsComponent, data: { title: "Log del Server", internalNavigation: false } },
@@ -1819,6 +2473,7 @@ const routeConfig = [
1819
2473
  { path: "metadataquery/:be", component: MtdQueryComponent, data: { title: "Ricerca Viste Dinamiche Applicative", internalNavigation: false } },
1820
2474
  { path: "serverworkers", component: AdmWrkComponent, data: { title: "Ricerca Processi Applicativi", internalNavigation: false } },
1821
2475
  { path: "profiler", component: AdmProfilerComponent, data: { title: "Profiler del Server", internalNavigation: false } },
2476
+ { path: "topact", component: AdmTopActivityV2Component, canMatch: [topActivityV2Enabled], data: { title: "Attività Principali", internalNavigation: false } },
1822
2477
  { path: "topact", component: AdmTopActivitiesComponent, data: { title: "Attività Principali", internalNavigation: false } },
1823
2478
  { path: "metrics", component: AdmMetricsComponent, data: { title: "Metriche di Sistema", internalNavigation: false } },
1824
2479
  { path: "serverlogs", component: AdmLogsComponent, data: { title: "Log del Server", internalNavigation: false } },
@@ -1854,6 +2509,8 @@ const COMPONENTS = [
1854
2509
  AdmWrkComponent,
1855
2510
  AdmProfilerComponent,
1856
2511
  AdmTopActivitiesComponent,
2512
+ AdmTopActivityV2Component,
2513
+ SessionDetailComponent,
1857
2514
  AdmDynamicViewsComponent,
1858
2515
  AdmLogsComponent,
1859
2516
  AdmAuditsComponent,
@@ -1876,6 +2533,8 @@ class AdmModule {
1876
2533
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.34", ngImport: i0, type: AdmModule, declarations: [AdmWrkComponent,
1877
2534
  AdmProfilerComponent,
1878
2535
  AdmTopActivitiesComponent,
2536
+ AdmTopActivityV2Component,
2537
+ SessionDetailComponent,
1879
2538
  AdmDynamicViewsComponent,
1880
2539
  AdmLogsComponent,
1881
2540
  AdmAuditsComponent,
@@ -1903,7 +2562,8 @@ class AdmModule {
1903
2562
  DirectivesModule, i4.RouterModule, FormatTimePipe] }); }
1904
2563
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmModule, providers: [
1905
2564
  AdminModuleCommService,
1906
- { provide: ADM_CONVERSATIONS, useFactory: () => !!myconfig.TransactionTimeoutSeconds }
2565
+ { provide: ADM_CONVERSATIONS, useFactory: () => !!myconfig.TransactionTimeoutSeconds },
2566
+ { provide: ADM_TOPACT_V2, useFactory: () => !!myconfig?.DirectorFeature?.TopActivityV2 }
1907
2567
  ], imports: [MODULES] }); }
1908
2568
  }
1909
2569
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: AdmModule, decorators: [{
@@ -1913,7 +2573,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
1913
2573
  declarations: [...COMPONENTS],
1914
2574
  providers: [
1915
2575
  AdminModuleCommService,
1916
- { provide: ADM_CONVERSATIONS, useFactory: () => !!myconfig.TransactionTimeoutSeconds }
2576
+ { provide: ADM_CONVERSATIONS, useFactory: () => !!myconfig.TransactionTimeoutSeconds },
2577
+ { provide: ADM_TOPACT_V2, useFactory: () => !!myconfig?.DirectorFeature?.TopActivityV2 }
1917
2578
  ]
1918
2579
  }]
1919
2580
  }], ctorParameters: () => [{ type: AdminModuleCommService }] });
@@ -1926,5 +2587,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImpo
1926
2587
  * Generated bundle index. Do not edit.
1927
2588
  */
1928
2589
 
1929
- export { ADM_CONVERSATIONS, ADM_MODULE_PATH, AdmMessageTypes, AdmModule, MK_ADM, routeConfig };
2590
+ export { ADM_CONVERSATIONS, ADM_MODULE_PATH, ADM_TOPACT_V2, AdmMessageTypes, AdmModule, MK_ADM, routeConfig, topActivityV2Enabled };
1930
2591
  //# sourceMappingURL=esfaenza-admin-module.mjs.map