@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.
- package/fesm2022/esfaenza-admin-module.mjs +665 -4
- package/fesm2022/esfaenza-admin-module.mjs.map +1 -1
- package/index.d.ts +282 -19
- package/package.json +1 -1
|
@@ -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\"> {{SessionDetails.sid}}</span></h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"closeDialog()\" aria-label=\"Close\"><span aria-hidden=\"true\">×</span></button>\r\n </div>\r\n <div class=\"modal-body\" *ngIf=\"SessionDetails\">\r\n <div class=\"row\">\r\n <div *ngIf=\"SessionDetails.instanceid\" class=\"col-md-6\"><strong>{{'Istanza' | localize: lc}}</strong>: {{SessionDetails.instanceid}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Seriale' | localize: lc}}</strong>: {{SessionDetails.serial}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Stato' | localize: lc}}</strong>: {{SessionDetails.status}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Tipo' | localize: lc}}</strong>: {{SessionDetails.type}}</div>\r\n <div class=\"col-md-6\"><strong>{{'Utente' | localize: lc}}</strong>: {{SessionDetails.user}} <span *ngIf=\"SessionDetails.tenant\">({{SessionDetails.tenant}})</span></div>\r\n </div>\r\n\r\n <div style=\"display: flex; width: 100%; margin-top: 15px;\">\r\n <div style=\"flex-grow: 0;display: flex;flex-direction: column\">\r\n <h5>{{'Prime Istruzioni' | 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\"> {{SessionDetails.sid}}</span></h4>\r\n <button type=\"button\" class=\"close pull-right\" (click)=\"closeDialog()\" aria-label=\"Close\"><span aria-hidden=\"true\">×</span></button>\r\n </div>\r\n <div class=\"modal-body\" *ngIf=\"SessionDetails\">\r\n <div class=\"row\">\r\n <div *ngIf=\"SessionDetails.instanceid\" class=\"col-md-6\"><strong>{{'Istanza' | localize: lc}}</strong>: {{SessionDetails.instanceid}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Seriale' | localize: lc}}</strong>: {{SessionDetails.serial}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Stato' | localize: lc}}</strong>: {{SessionDetails.status}} </div>\r\n <div class=\"col-md-6\"><strong>{{'Tipo' | localize: lc}}</strong>: {{SessionDetails.type}}</div>\r\n <div class=\"col-md-6\"><strong>{{'Utente' | localize: lc}}</strong>: {{SessionDetails.user}} <span *ngIf=\"SessionDetails.tenant\">({{SessionDetails.tenant}})</span></div>\r\n </div>\r\n\r\n <div style=\"display: flex; width: 100%; margin-top: 15px;\">\r\n <div style=\"flex-grow: 0;display: flex;flex-direction: column\">\r\n <h5>{{'Prime Istruzioni' | 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> - \r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}} \r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg5 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span>\r\n }\r\n </span>\r\n </div>\r\n <div class=\"card-body widget-body\">\r\n <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 · {{'Picco' | localize: lc}} <strong>{{result.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n · {{'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)\">×</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> - \r\n {{'' + DirInfos.cpus + ' ' + ('CPU' | localize: lc) + (DirInfos.rssplan ? ' - ' + DirInfos.rssplan : '')}} \r\n Load average: {{ DirInfos.lavg1 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg5 | number : '1.1-2' : 'it'}} {{ DirInfos.lavg15 | number : '1.1-2' : 'it'}}\r\n </span>\r\n }\r\n </span>\r\n </div>\r\n <div class=\"card-body widget-body\">\r\n <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 · {{'Picco' | localize: lc}} <strong>{{result.peakActiveSessions | number : '1.2-3' : 'it'}}</strong>\r\n · {{'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)\">×</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
|