@memberjunction/ng-explorer-settings 3.1.0 → 3.2.0
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/dist/lib/module.d.ts +27 -26
- package/dist/lib/module.d.ts.map +1 -1
- package/dist/lib/module.js +5 -0
- package/dist/lib/module.js.map +1 -1
- package/dist/lib/notification-preferences/notification-preferences.component.d.ts +36 -0
- package/dist/lib/notification-preferences/notification-preferences.component.d.ts.map +1 -0
- package/dist/lib/notification-preferences/notification-preferences.component.js +306 -0
- package/dist/lib/notification-preferences/notification-preferences.component.js.map +1 -0
- package/dist/lib/settings/settings.component.d.ts.map +1 -1
- package/dist/lib/settings/settings.component.js +51 -41
- package/dist/lib/settings/settings.component.js.map +1 -1
- package/dist/lib/sql-logging/sql-logging.component.d.ts +58 -7
- package/dist/lib/sql-logging/sql-logging.component.d.ts.map +1 -1
- package/dist/lib/sql-logging/sql-logging.component.js +326 -57
- package/dist/lib/sql-logging/sql-logging.component.js.map +1 -1
- package/dist/public-api.d.ts +1 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +1 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +20 -20
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { Component } from '@angular/core';
|
|
7
|
+
import { Component, HostListener } from '@angular/core';
|
|
8
8
|
import { Subject, interval } from 'rxjs';
|
|
9
9
|
import { takeUntil } from 'rxjs/operators';
|
|
10
10
|
import { Metadata } from '@memberjunction/core';
|
|
@@ -145,7 +145,7 @@ function SqlLoggingComponent_Conditional_8_Conditional_3_Template(rf, ctx) { if
|
|
|
145
145
|
function SqlLoggingComponent_Conditional_8_Conditional_4_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
146
146
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
147
147
|
i0.ɵɵelementStart(0, "button", 44);
|
|
148
|
-
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_8_Conditional_4_Conditional_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.
|
|
148
|
+
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_8_Conditional_4_Conditional_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.openStopAllSessionsConfirm()); });
|
|
149
149
|
i0.ɵɵelement(1, "i", 45);
|
|
150
150
|
i0.ɵɵtext(2, " Stop All ");
|
|
151
151
|
i0.ɵɵelementEnd();
|
|
@@ -181,7 +181,7 @@ function SqlLoggingComponent_Conditional_8_Conditional_4_For_8_Template(rf, ctx)
|
|
|
181
181
|
i0.ɵɵtext(11);
|
|
182
182
|
i0.ɵɵelementEnd()()();
|
|
183
183
|
i0.ɵɵelementStart(12, "button", 53);
|
|
184
|
-
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_8_Conditional_4_For_8_Template_button_click_12_listener($event) { const session_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.
|
|
184
|
+
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_8_Conditional_4_For_8_Template_button_click_12_listener($event) { const session_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.openStopSessionConfirm(session_r7, $event)); });
|
|
185
185
|
i0.ɵɵelement(13, "i", 45);
|
|
186
186
|
i0.ɵɵelementEnd()();
|
|
187
187
|
i0.ɵɵelementStart(14, "div", 54);
|
|
@@ -219,9 +219,13 @@ function SqlLoggingComponent_Conditional_8_Conditional_4_Conditional_10_Template
|
|
|
219
219
|
i0.ɵɵelementStart(7, "button", 63);
|
|
220
220
|
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_8_Conditional_4_Conditional_10_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.loadSessionLog(ctx_r1.selectedSession)); });
|
|
221
221
|
i0.ɵɵelement(8, "i", 32);
|
|
222
|
+
i0.ɵɵelementEnd();
|
|
223
|
+
i0.ɵɵelementStart(9, "button", 64);
|
|
224
|
+
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_8_Conditional_4_Conditional_10_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.toggleLogViewerExpand()); });
|
|
225
|
+
i0.ɵɵelement(10, "i", 65);
|
|
222
226
|
i0.ɵɵelementEnd()()();
|
|
223
|
-
i0.ɵɵelementStart(
|
|
224
|
-
i0.ɵɵelement(
|
|
227
|
+
i0.ɵɵelementStart(11, "div", 66);
|
|
228
|
+
i0.ɵɵelement(12, "mj-code-editor", 67);
|
|
225
229
|
i0.ɵɵelementEnd();
|
|
226
230
|
} if (rf & 2) {
|
|
227
231
|
const ctx_r1 = i0.ɵɵnextContext(3);
|
|
@@ -231,12 +235,16 @@ function SqlLoggingComponent_Conditional_8_Conditional_4_Conditional_10_Template
|
|
|
231
235
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.autoRefresh);
|
|
232
236
|
i0.ɵɵadvance(3);
|
|
233
237
|
i0.ɵɵclassProp("fa-spin", ctx_r1.loading);
|
|
238
|
+
i0.ɵɵadvance();
|
|
239
|
+
i0.ɵɵproperty("title", ctx_r1.isLogViewerExpanded ? "Collapse" : "Expand");
|
|
240
|
+
i0.ɵɵadvance();
|
|
241
|
+
i0.ɵɵclassProp("fa-expand", !ctx_r1.isLogViewerExpanded)("fa-compress", ctx_r1.isLogViewerExpanded);
|
|
234
242
|
i0.ɵɵadvance(2);
|
|
235
243
|
i0.ɵɵproperty("value", ctx_r1.logContent)("readonly", true)("disabled", true)("language", "sql")("setup", "basic")("lineWrapping", true)("highlightWhitespace", false);
|
|
236
244
|
} }
|
|
237
245
|
function SqlLoggingComponent_Conditional_8_Conditional_4_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
238
246
|
i0.ɵɵelementStart(0, "div", 26);
|
|
239
|
-
i0.ɵɵelement(1, "i",
|
|
247
|
+
i0.ɵɵelement(1, "i", 68);
|
|
240
248
|
i0.ɵɵelementStart(2, "p", 29);
|
|
241
249
|
i0.ɵɵtext(3, "Select a Session");
|
|
242
250
|
i0.ɵɵelementEnd();
|
|
@@ -254,7 +262,7 @@ function SqlLoggingComponent_Conditional_8_Conditional_4_Template(rf, ctx) { if
|
|
|
254
262
|
i0.ɵɵrepeaterCreate(7, SqlLoggingComponent_Conditional_8_Conditional_4_For_8_Template, 19, 8, "div", 42, _forTrack0);
|
|
255
263
|
i0.ɵɵelementEnd()();
|
|
256
264
|
i0.ɵɵelementStart(9, "div", 43);
|
|
257
|
-
i0.ɵɵtemplate(10, SqlLoggingComponent_Conditional_8_Conditional_4_Conditional_10_Template,
|
|
265
|
+
i0.ɵɵtemplate(10, SqlLoggingComponent_Conditional_8_Conditional_4_Conditional_10_Template, 13, 16)(11, SqlLoggingComponent_Conditional_8_Conditional_4_Conditional_11_Template, 6, 0, "div", 26);
|
|
258
266
|
i0.ɵɵelementEnd()();
|
|
259
267
|
} if (rf & 2) {
|
|
260
268
|
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
@@ -262,12 +270,14 @@ function SqlLoggingComponent_Conditional_8_Conditional_4_Template(rf, ctx) { if
|
|
|
262
270
|
i0.ɵɵconditional(ctx_r1.activeSessions.length > 0 ? 5 : -1);
|
|
263
271
|
i0.ɵɵadvance(2);
|
|
264
272
|
i0.ɵɵrepeater(ctx_r1.activeSessions);
|
|
265
|
-
i0.ɵɵadvance(
|
|
273
|
+
i0.ɵɵadvance(2);
|
|
274
|
+
i0.ɵɵclassProp("expanded", ctx_r1.isLogViewerExpanded);
|
|
275
|
+
i0.ɵɵadvance();
|
|
266
276
|
i0.ɵɵconditional(ctx_r1.selectedSession ? 10 : 11);
|
|
267
277
|
} }
|
|
268
278
|
function SqlLoggingComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
269
279
|
i0.ɵɵelementStart(0, "div", 7);
|
|
270
|
-
i0.ɵɵtemplate(1, SqlLoggingComponent_Conditional_8_Conditional_1_Template, 9, 0, "div", 26)(2, SqlLoggingComponent_Conditional_8_Conditional_2_Template, 19, 0, "div", 26)(3, SqlLoggingComponent_Conditional_8_Conditional_3_Template, 9, 0, "div", 26)(4, SqlLoggingComponent_Conditional_8_Conditional_4_Template, 12,
|
|
280
|
+
i0.ɵɵtemplate(1, SqlLoggingComponent_Conditional_8_Conditional_1_Template, 9, 0, "div", 26)(2, SqlLoggingComponent_Conditional_8_Conditional_2_Template, 19, 0, "div", 26)(3, SqlLoggingComponent_Conditional_8_Conditional_3_Template, 9, 0, "div", 26)(4, SqlLoggingComponent_Conditional_8_Conditional_4_Template, 12, 4, "div", 27);
|
|
271
281
|
i0.ɵɵelementEnd();
|
|
272
282
|
} if (rf & 2) {
|
|
273
283
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -275,7 +285,7 @@ function SqlLoggingComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
|
275
285
|
i0.ɵɵconditional(!ctx_r1.isOwner ? 1 : !ctx_r1.configEnabled ? 2 : ctx_r1.activeSessions.length === 0 ? 3 : 4);
|
|
276
286
|
} }
|
|
277
287
|
function SqlLoggingComponent_Conditional_9_For_24_Template(rf, ctx) { if (rf & 1) {
|
|
278
|
-
i0.ɵɵelementStart(0, "option",
|
|
288
|
+
i0.ɵɵelementStart(0, "option", 82);
|
|
279
289
|
i0.ɵɵtext(1);
|
|
280
290
|
i0.ɵɵelementEnd();
|
|
281
291
|
} if (rf & 2) {
|
|
@@ -284,43 +294,69 @@ function SqlLoggingComponent_Conditional_9_For_24_Template(rf, ctx) { if (rf & 1
|
|
|
284
294
|
i0.ɵɵadvance();
|
|
285
295
|
i0.ɵɵtextInterpolate(option_r10.text);
|
|
286
296
|
} }
|
|
297
|
+
function SqlLoggingComponent_Conditional_9_For_44_Template(rf, ctx) { if (rf & 1) {
|
|
298
|
+
i0.ɵɵelementStart(0, "option", 82);
|
|
299
|
+
i0.ɵɵtext(1);
|
|
300
|
+
i0.ɵɵelementEnd();
|
|
301
|
+
} if (rf & 2) {
|
|
302
|
+
const option_r11 = ctx.$implicit;
|
|
303
|
+
i0.ɵɵproperty("value", option_r11.value);
|
|
304
|
+
i0.ɵɵadvance();
|
|
305
|
+
i0.ɵɵtextInterpolate(option_r11.text);
|
|
306
|
+
} }
|
|
307
|
+
function SqlLoggingComponent_Conditional_9_Conditional_57_Template(rf, ctx) { if (rf & 1) {
|
|
308
|
+
const _r12 = i0.ɵɵgetCurrentView();
|
|
309
|
+
i0.ɵɵelementStart(0, "div", 76)(1, "label", 77);
|
|
310
|
+
i0.ɵɵtext(2, "Default Schema Name");
|
|
311
|
+
i0.ɵɵelementEnd();
|
|
312
|
+
i0.ɵɵelementStart(3, "input", 93);
|
|
313
|
+
i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_9_Conditional_57_Template_input_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r12); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.defaultSchemaName, $event) || (ctx_r1.newSessionOptions.defaultSchemaName = $event); return i0.ɵɵresetView($event); });
|
|
314
|
+
i0.ɵɵelementEnd();
|
|
315
|
+
i0.ɵɵelementStart(4, "div", 80);
|
|
316
|
+
i0.ɵɵtext(5, " Schema name to replace with ${flyway:defaultSchema} placeholder. ");
|
|
317
|
+
i0.ɵɵelementEnd()();
|
|
318
|
+
} if (rf & 2) {
|
|
319
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
320
|
+
i0.ɵɵadvance(3);
|
|
321
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newSessionOptions.defaultSchemaName);
|
|
322
|
+
} }
|
|
287
323
|
function SqlLoggingComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
288
324
|
const _r9 = i0.ɵɵgetCurrentView();
|
|
289
|
-
i0.ɵɵelementStart(0, "div",
|
|
325
|
+
i0.ɵɵelementStart(0, "div", 69);
|
|
290
326
|
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_9_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showStartSessionDialog = false); });
|
|
291
|
-
i0.ɵɵelementStart(1, "div",
|
|
327
|
+
i0.ɵɵelementStart(1, "div", 70);
|
|
292
328
|
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_9_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r9); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
293
|
-
i0.ɵɵelementStart(2, "div",
|
|
329
|
+
i0.ɵɵelementStart(2, "div", 71)(3, "h3", 72);
|
|
294
330
|
i0.ɵɵelement(4, "i", 10);
|
|
295
331
|
i0.ɵɵtext(5, " Start SQL Logging Session ");
|
|
296
332
|
i0.ɵɵelementEnd();
|
|
297
|
-
i0.ɵɵelementStart(6, "button",
|
|
333
|
+
i0.ɵɵelementStart(6, "button", 73);
|
|
298
334
|
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_9_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showStartSessionDialog = false); });
|
|
299
|
-
i0.ɵɵelement(7, "i",
|
|
335
|
+
i0.ɵɵelement(7, "i", 74);
|
|
300
336
|
i0.ɵɵelementEnd()();
|
|
301
|
-
i0.ɵɵelementStart(8, "div",
|
|
337
|
+
i0.ɵɵelementStart(8, "div", 75)(9, "div", 76)(10, "label", 77);
|
|
302
338
|
i0.ɵɵtext(11, "Session Name");
|
|
303
339
|
i0.ɵɵelementEnd();
|
|
304
|
-
i0.ɵɵelementStart(12, "input",
|
|
340
|
+
i0.ɵɵelementStart(12, "input", 78);
|
|
305
341
|
i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_9_Template_input_ngModelChange_12_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.sessionName, $event) || (ctx_r1.newSessionOptions.sessionName = $event); return i0.ɵɵresetView($event); });
|
|
306
342
|
i0.ɵɵelementEnd()();
|
|
307
|
-
i0.ɵɵelementStart(13, "div",
|
|
343
|
+
i0.ɵɵelementStart(13, "div", 76)(14, "label", 77);
|
|
308
344
|
i0.ɵɵtext(15, "File Name");
|
|
309
345
|
i0.ɵɵelementEnd();
|
|
310
|
-
i0.ɵɵelementStart(16, "input",
|
|
346
|
+
i0.ɵɵelementStart(16, "input", 79);
|
|
311
347
|
i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_9_Template_input_ngModelChange_16_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.fileName, $event) || (ctx_r1.newSessionOptions.fileName = $event); return i0.ɵɵresetView($event); });
|
|
312
348
|
i0.ɵɵelementEnd();
|
|
313
|
-
i0.ɵɵelementStart(17, "div",
|
|
349
|
+
i0.ɵɵelementStart(17, "div", 80);
|
|
314
350
|
i0.ɵɵtext(18, "The SQL log will be saved to this file");
|
|
315
351
|
i0.ɵɵelementEnd()();
|
|
316
|
-
i0.ɵɵelementStart(19, "div",
|
|
352
|
+
i0.ɵɵelementStart(19, "div", 76)(20, "label", 77);
|
|
317
353
|
i0.ɵɵtext(21, "Statement Types");
|
|
318
354
|
i0.ɵɵelementEnd();
|
|
319
|
-
i0.ɵɵelementStart(22, "select",
|
|
355
|
+
i0.ɵɵelementStart(22, "select", 81);
|
|
320
356
|
i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_9_Template_select_ngModelChange_22_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.statementTypes, $event) || (ctx_r1.newSessionOptions.statementTypes = $event); return i0.ɵɵresetView($event); });
|
|
321
|
-
i0.ɵɵrepeaterCreate(23, SqlLoggingComponent_Conditional_9_For_24_Template, 2, 2, "option",
|
|
357
|
+
i0.ɵɵrepeaterCreate(23, SqlLoggingComponent_Conditional_9_For_24_Template, 2, 2, "option", 82, _forTrack1);
|
|
322
358
|
i0.ɵɵelementEnd()();
|
|
323
|
-
i0.ɵɵelementStart(25, "div",
|
|
359
|
+
i0.ɵɵelementStart(25, "div", 83)(26, "label", 61)(27, "input", 62);
|
|
324
360
|
i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_9_Template_input_ngModelChange_27_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.filterToCurrentUser, $event) || (ctx_r1.newSessionOptions.filterToCurrentUser = $event); return i0.ɵɵresetView($event); });
|
|
325
361
|
i0.ɵɵelementEnd();
|
|
326
362
|
i0.ɵɵtext(28, " Filter to my SQL statements only ");
|
|
@@ -334,15 +370,51 @@ function SqlLoggingComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
|
334
370
|
i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_9_Template_input_ngModelChange_33_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.prettyPrint, $event) || (ctx_r1.newSessionOptions.prettyPrint = $event); return i0.ɵɵresetView($event); });
|
|
335
371
|
i0.ɵɵelementEnd();
|
|
336
372
|
i0.ɵɵtext(34, " Pretty print SQL statements ");
|
|
373
|
+
i0.ɵɵelementEnd()();
|
|
374
|
+
i0.ɵɵelementStart(35, "div", 84)(36, "h4", 85);
|
|
375
|
+
i0.ɵɵelement(37, "i", 86);
|
|
376
|
+
i0.ɵɵtext(38, " SQL Pattern Filtering ");
|
|
377
|
+
i0.ɵɵelementEnd();
|
|
378
|
+
i0.ɵɵelementStart(39, "div", 76)(40, "label", 77);
|
|
379
|
+
i0.ɵɵtext(41, "Filter Mode");
|
|
380
|
+
i0.ɵɵelementEnd();
|
|
381
|
+
i0.ɵɵelementStart(42, "select", 81);
|
|
382
|
+
i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_9_Template_select_ngModelChange_42_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.filterType, $event) || (ctx_r1.newSessionOptions.filterType = $event); return i0.ɵɵresetView($event); });
|
|
383
|
+
i0.ɵɵrepeaterCreate(43, SqlLoggingComponent_Conditional_9_For_44_Template, 2, 2, "option", 82, _forTrack1);
|
|
384
|
+
i0.ɵɵelementEnd();
|
|
385
|
+
i0.ɵɵelementStart(45, "div", 80);
|
|
386
|
+
i0.ɵɵtext(46, " Exclude: Skip SQL matching any pattern. Include: Only log SQL matching a pattern. ");
|
|
387
|
+
i0.ɵɵelementEnd()();
|
|
388
|
+
i0.ɵɵelementStart(47, "div", 76)(48, "label", 77);
|
|
389
|
+
i0.ɵɵtext(49, "Filter Patterns (one per line or comma-separated)");
|
|
390
|
+
i0.ɵɵelementEnd();
|
|
391
|
+
i0.ɵɵelementStart(50, "textarea", 87);
|
|
392
|
+
i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_9_Template_textarea_ngModelChange_50_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.filterPatterns, $event) || (ctx_r1.newSessionOptions.filterPatterns = $event); return i0.ɵɵresetView($event); });
|
|
393
|
+
i0.ɵɵelementEnd();
|
|
394
|
+
i0.ɵɵelementStart(51, "div", 80);
|
|
395
|
+
i0.ɵɵtext(52, " Supports wildcards (*) and regex (/pattern/flags). Example: *spCreate* matches any SP starting with spCreate. ");
|
|
337
396
|
i0.ɵɵelementEnd()()();
|
|
338
|
-
i0.ɵɵelementStart(
|
|
339
|
-
i0.ɵɵ
|
|
340
|
-
i0.ɵɵtext(
|
|
341
|
-
i0.ɵɵelementEnd();
|
|
342
|
-
i0.ɵɵ
|
|
343
|
-
i0.ɵɵ
|
|
344
|
-
i0.ɵɵ
|
|
345
|
-
i0.ɵɵ
|
|
397
|
+
i0.ɵɵelementStart(53, "div", 84)(54, "h4", 85);
|
|
398
|
+
i0.ɵɵelement(55, "i", 88);
|
|
399
|
+
i0.ɵɵtext(56, " Advanced Options ");
|
|
400
|
+
i0.ɵɵelementEnd();
|
|
401
|
+
i0.ɵɵtemplate(57, SqlLoggingComponent_Conditional_9_Conditional_57_Template, 6, 1, "div", 76);
|
|
402
|
+
i0.ɵɵelementStart(58, "div", 83)(59, "label", 61)(60, "input", 62);
|
|
403
|
+
i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_9_Template_input_ngModelChange_60_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.verboseOutput, $event) || (ctx_r1.newSessionOptions.verboseOutput = $event); return i0.ɵɵresetView($event); });
|
|
404
|
+
i0.ɵɵelementEnd();
|
|
405
|
+
i0.ɵɵtext(61, " Verbose Debug Output ");
|
|
406
|
+
i0.ɵɵelementEnd();
|
|
407
|
+
i0.ɵɵelementStart(62, "div", 89);
|
|
408
|
+
i0.ɵɵtext(63, " Log detailed filter decisions to server console (for debugging). ");
|
|
409
|
+
i0.ɵɵelementEnd()()()();
|
|
410
|
+
i0.ɵɵelementStart(64, "div", 90)(65, "button", 91);
|
|
411
|
+
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_9_Template_button_click_65_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.startNewSession()); });
|
|
412
|
+
i0.ɵɵelement(66, "i", 10);
|
|
413
|
+
i0.ɵɵtext(67, " Start Session ");
|
|
414
|
+
i0.ɵɵelementEnd();
|
|
415
|
+
i0.ɵɵelementStart(68, "button", 92);
|
|
416
|
+
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_9_Template_button_click_68_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showStartSessionDialog = false); });
|
|
417
|
+
i0.ɵɵtext(69, " Cancel ");
|
|
346
418
|
i0.ɵɵelementEnd()()()();
|
|
347
419
|
} if (rf & 2) {
|
|
348
420
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
@@ -360,9 +432,106 @@ function SqlLoggingComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
|
360
432
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newSessionOptions.formatAsMigration);
|
|
361
433
|
i0.ɵɵadvance(3);
|
|
362
434
|
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newSessionOptions.prettyPrint);
|
|
435
|
+
i0.ɵɵadvance(9);
|
|
436
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newSessionOptions.filterType);
|
|
437
|
+
i0.ɵɵadvance();
|
|
438
|
+
i0.ɵɵrepeater(ctx_r1.filterTypeOptions);
|
|
439
|
+
i0.ɵɵadvance(7);
|
|
440
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newSessionOptions.filterPatterns);
|
|
441
|
+
i0.ɵɵadvance(7);
|
|
442
|
+
i0.ɵɵconditional(ctx_r1.newSessionOptions.formatAsMigration ? 57 : -1);
|
|
443
|
+
i0.ɵɵadvance(3);
|
|
444
|
+
i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newSessionOptions.verboseOutput);
|
|
363
445
|
i0.ɵɵadvance(5);
|
|
364
446
|
i0.ɵɵproperty("disabled", ctx_r1.loading);
|
|
365
447
|
} }
|
|
448
|
+
function SqlLoggingComponent_Conditional_10_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
449
|
+
i0.ɵɵtext(0, " Stop All Sessions? ");
|
|
450
|
+
} }
|
|
451
|
+
function SqlLoggingComponent_Conditional_10_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
452
|
+
i0.ɵɵtext(0, " Stop Session? ");
|
|
453
|
+
} }
|
|
454
|
+
function SqlLoggingComponent_Conditional_10_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
455
|
+
i0.ɵɵtext(0, " Are you sure you want to stop ");
|
|
456
|
+
i0.ɵɵelementStart(1, "strong");
|
|
457
|
+
i0.ɵɵtext(2);
|
|
458
|
+
i0.ɵɵelementEnd();
|
|
459
|
+
i0.ɵɵtext(3, " SQL logging sessions? This action cannot be undone. ");
|
|
460
|
+
} if (rf & 2) {
|
|
461
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
462
|
+
i0.ɵɵadvance(2);
|
|
463
|
+
i0.ɵɵtextInterpolate1("all ", ctx_r1.activeSessions.length, " active");
|
|
464
|
+
} }
|
|
465
|
+
function SqlLoggingComponent_Conditional_10_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
466
|
+
i0.ɵɵtext(0, " Are you sure you want to stop the session ");
|
|
467
|
+
i0.ɵɵelementStart(1, "strong");
|
|
468
|
+
i0.ɵɵtext(2);
|
|
469
|
+
i0.ɵɵelementEnd();
|
|
470
|
+
i0.ɵɵtext(3, "? ");
|
|
471
|
+
i0.ɵɵelementStart(4, "span", 102);
|
|
472
|
+
i0.ɵɵtext(5);
|
|
473
|
+
i0.ɵɵelementEnd();
|
|
474
|
+
} if (rf & 2) {
|
|
475
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
476
|
+
i0.ɵɵadvance(2);
|
|
477
|
+
i0.ɵɵtextInterpolate1("\"", ctx_r1.sessionToStop.sessionName, "\"");
|
|
478
|
+
i0.ɵɵadvance(3);
|
|
479
|
+
i0.ɵɵtextInterpolate1(" This session has captured ", ctx_r1.sessionToStop.statementCount, " SQL statements. ");
|
|
480
|
+
} }
|
|
481
|
+
function SqlLoggingComponent_Conditional_10_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
482
|
+
i0.ɵɵelement(0, "i", 103);
|
|
483
|
+
i0.ɵɵtext(1, " Stopping... ");
|
|
484
|
+
} }
|
|
485
|
+
function SqlLoggingComponent_Conditional_10_Conditional_14_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
486
|
+
i0.ɵɵtext(0, " Stop All Sessions ");
|
|
487
|
+
} }
|
|
488
|
+
function SqlLoggingComponent_Conditional_10_Conditional_14_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
489
|
+
i0.ɵɵtext(0, " Stop Session ");
|
|
490
|
+
} }
|
|
491
|
+
function SqlLoggingComponent_Conditional_10_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
492
|
+
i0.ɵɵelement(0, "i", 45);
|
|
493
|
+
i0.ɵɵtemplate(1, SqlLoggingComponent_Conditional_10_Conditional_14_Conditional_1_Template, 1, 0)(2, SqlLoggingComponent_Conditional_10_Conditional_14_Conditional_2_Template, 1, 0);
|
|
494
|
+
} if (rf & 2) {
|
|
495
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
496
|
+
i0.ɵɵadvance();
|
|
497
|
+
i0.ɵɵconditional(ctx_r1.isStoppingAll ? 1 : 2);
|
|
498
|
+
} }
|
|
499
|
+
function SqlLoggingComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
500
|
+
const _r13 = i0.ɵɵgetCurrentView();
|
|
501
|
+
i0.ɵɵelementStart(0, "div", 69);
|
|
502
|
+
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_10_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelStopConfirm()); });
|
|
503
|
+
i0.ɵɵelementStart(1, "div", 94);
|
|
504
|
+
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_10_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r13); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
505
|
+
i0.ɵɵelementStart(2, "div", 95);
|
|
506
|
+
i0.ɵɵelement(3, "i", 96);
|
|
507
|
+
i0.ɵɵelementEnd();
|
|
508
|
+
i0.ɵɵelementStart(4, "div", 97)(5, "h3", 98);
|
|
509
|
+
i0.ɵɵtemplate(6, SqlLoggingComponent_Conditional_10_Conditional_6_Template, 1, 0)(7, SqlLoggingComponent_Conditional_10_Conditional_7_Template, 1, 0);
|
|
510
|
+
i0.ɵɵelementEnd();
|
|
511
|
+
i0.ɵɵelementStart(8, "p", 99);
|
|
512
|
+
i0.ɵɵtemplate(9, SqlLoggingComponent_Conditional_10_Conditional_9_Template, 4, 1)(10, SqlLoggingComponent_Conditional_10_Conditional_10_Template, 6, 2);
|
|
513
|
+
i0.ɵɵelementEnd()();
|
|
514
|
+
i0.ɵɵelementStart(11, "div", 100)(12, "button", 101);
|
|
515
|
+
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_10_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmStopSession()); });
|
|
516
|
+
i0.ɵɵtemplate(13, SqlLoggingComponent_Conditional_10_Conditional_13_Template, 2, 0)(14, SqlLoggingComponent_Conditional_10_Conditional_14_Template, 3, 1);
|
|
517
|
+
i0.ɵɵelementEnd();
|
|
518
|
+
i0.ɵɵelementStart(15, "button", 2);
|
|
519
|
+
i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_10_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelStopConfirm()); });
|
|
520
|
+
i0.ɵɵtext(16, " Cancel ");
|
|
521
|
+
i0.ɵɵelementEnd()()()();
|
|
522
|
+
} if (rf & 2) {
|
|
523
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
524
|
+
i0.ɵɵadvance(6);
|
|
525
|
+
i0.ɵɵconditional(ctx_r1.isStoppingAll ? 6 : 7);
|
|
526
|
+
i0.ɵɵadvance(3);
|
|
527
|
+
i0.ɵɵconditional(ctx_r1.isStoppingAll ? 9 : ctx_r1.sessionToStop ? 10 : -1);
|
|
528
|
+
i0.ɵɵadvance(3);
|
|
529
|
+
i0.ɵɵproperty("disabled", ctx_r1.loading);
|
|
530
|
+
i0.ɵɵadvance();
|
|
531
|
+
i0.ɵɵconditional(ctx_r1.loading ? 13 : 14);
|
|
532
|
+
i0.ɵɵadvance(2);
|
|
533
|
+
i0.ɵɵproperty("disabled", ctx_r1.loading);
|
|
534
|
+
} }
|
|
366
535
|
/**
|
|
367
536
|
* Angular component for managing SQL logging sessions in MemberJunction.
|
|
368
537
|
*
|
|
@@ -407,6 +576,14 @@ let SqlLoggingComponent = class SqlLoggingComponent extends BaseDashboard {
|
|
|
407
576
|
refreshInterval = 5000; // 5 seconds
|
|
408
577
|
/** Whether the start session dialog is currently visible */
|
|
409
578
|
showStartSessionDialog = false;
|
|
579
|
+
/** Whether the log viewer is in expanded (fullscreen) mode */
|
|
580
|
+
isLogViewerExpanded = false;
|
|
581
|
+
/** Whether the stop session confirmation dialog is visible */
|
|
582
|
+
showStopConfirmDialog = false;
|
|
583
|
+
/** Session pending stop confirmation (single session or null for all) */
|
|
584
|
+
sessionToStop = null;
|
|
585
|
+
/** Whether stopping all sessions (vs single session) */
|
|
586
|
+
isStoppingAll = false;
|
|
410
587
|
/** Options for creating a new SQL logging session */
|
|
411
588
|
newSessionOptions = {
|
|
412
589
|
/** Custom filename for the log file */
|
|
@@ -420,7 +597,12 @@ let SqlLoggingComponent = class SqlLoggingComponent extends BaseDashboard {
|
|
|
420
597
|
/** Whether to format SQL with proper indentation */
|
|
421
598
|
prettyPrint: true,
|
|
422
599
|
/** Human-readable name for the session */
|
|
423
|
-
sessionName: ''
|
|
600
|
+
sessionName: '',
|
|
601
|
+
/** Regex filter options */
|
|
602
|
+
filterPatterns: '', // Comma or newline separated patterns
|
|
603
|
+
filterType: 'exclude',
|
|
604
|
+
verboseOutput: false,
|
|
605
|
+
defaultSchemaName: '__mj', // Default MJ schema
|
|
424
606
|
};
|
|
425
607
|
/** Available options for SQL statement type filtering */
|
|
426
608
|
statementTypeOptions = [
|
|
@@ -428,6 +610,11 @@ let SqlLoggingComponent = class SqlLoggingComponent extends BaseDashboard {
|
|
|
428
610
|
{ text: 'Queries Only', value: 'queries' },
|
|
429
611
|
{ text: 'Mutations Only', value: 'mutations' }
|
|
430
612
|
];
|
|
613
|
+
/** Options for Regex filter */
|
|
614
|
+
filterTypeOptions = [
|
|
615
|
+
{ text: 'Exclude Matching (default)', value: 'exclude' },
|
|
616
|
+
{ text: 'Include Matching Only', value: 'include' }
|
|
617
|
+
];
|
|
431
618
|
constructor(sharedService) {
|
|
432
619
|
super();
|
|
433
620
|
this.sharedService = sharedService;
|
|
@@ -553,7 +740,12 @@ let SqlLoggingComponent = class SqlLoggingComponent extends BaseDashboard {
|
|
|
553
740
|
formatAsMigration: this.newSessionOptions.formatAsMigration,
|
|
554
741
|
statementTypes: this.newSessionOptions.statementTypes,
|
|
555
742
|
prettyPrint: this.newSessionOptions.prettyPrint,
|
|
556
|
-
sessionName: this.newSessionOptions.sessionName
|
|
743
|
+
sessionName: this.newSessionOptions.sessionName,
|
|
744
|
+
// Regex Filter Option
|
|
745
|
+
filterPatterns: this.parseFilterPatterns(this.newSessionOptions.filterPatterns),
|
|
746
|
+
filterType: this.newSessionOptions.filterType,
|
|
747
|
+
verboseOutput: this.newSessionOptions.verboseOutput,
|
|
748
|
+
defaultSchemaName: this.newSessionOptions.defaultSchemaName,
|
|
557
749
|
}
|
|
558
750
|
}
|
|
559
751
|
};
|
|
@@ -579,18 +771,12 @@ let SqlLoggingComponent = class SqlLoggingComponent extends BaseDashboard {
|
|
|
579
771
|
}
|
|
580
772
|
}
|
|
581
773
|
/**
|
|
582
|
-
*
|
|
774
|
+
* Executes the stop operation for a specific SQL logging session.
|
|
775
|
+
* Called after user confirms via the confirmation dialog.
|
|
583
776
|
*
|
|
584
777
|
* @param session - The session object to stop
|
|
585
|
-
* @param event - Optional event to stop propagation
|
|
586
778
|
*/
|
|
587
|
-
async
|
|
588
|
-
if (event) {
|
|
589
|
-
event.stopPropagation();
|
|
590
|
-
}
|
|
591
|
-
if (!confirm(`Stop SQL logging session "${session.sessionName}"?`)) {
|
|
592
|
-
return;
|
|
593
|
-
}
|
|
779
|
+
async executeStopSession(session) {
|
|
594
780
|
try {
|
|
595
781
|
this.loading = true;
|
|
596
782
|
const dataProvider = Metadata.Provider;
|
|
@@ -611,21 +797,19 @@ let SqlLoggingComponent = class SqlLoggingComponent extends BaseDashboard {
|
|
|
611
797
|
await this.loadActiveSessions();
|
|
612
798
|
}
|
|
613
799
|
catch (error) {
|
|
800
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to stop SQL logging session';
|
|
614
801
|
console.error('Error stopping SQL logging session:', error);
|
|
615
|
-
MJNotificationService.Instance.CreateSimpleNotification(`Error: ${
|
|
802
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Error: ${errorMessage}`, 'error', 5000);
|
|
616
803
|
}
|
|
617
804
|
finally {
|
|
618
805
|
this.loading = false;
|
|
619
806
|
}
|
|
620
807
|
}
|
|
621
808
|
/**
|
|
622
|
-
*
|
|
623
|
-
*
|
|
809
|
+
* Executes the stop operation for all active SQL logging sessions.
|
|
810
|
+
* Called after user confirms via the confirmation dialog.
|
|
624
811
|
*/
|
|
625
|
-
async
|
|
626
|
-
if (!confirm('Stop ALL active SQL logging sessions?')) {
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
812
|
+
async executeStopAllSessions() {
|
|
629
813
|
try {
|
|
630
814
|
this.loading = true;
|
|
631
815
|
const dataProvider = Metadata.Provider;
|
|
@@ -644,8 +828,9 @@ let SqlLoggingComponent = class SqlLoggingComponent extends BaseDashboard {
|
|
|
644
828
|
await this.loadActiveSessions();
|
|
645
829
|
}
|
|
646
830
|
catch (error) {
|
|
831
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to stop all SQL logging sessions';
|
|
647
832
|
console.error('Error stopping all SQL logging sessions:', error);
|
|
648
|
-
MJNotificationService.Instance.CreateSimpleNotification(`Error: ${
|
|
833
|
+
MJNotificationService.Instance.CreateSimpleNotification(`Error: ${errorMessage}`, 'error', 5000);
|
|
649
834
|
}
|
|
650
835
|
finally {
|
|
651
836
|
this.loading = false;
|
|
@@ -872,12 +1057,89 @@ let SqlLoggingComponent = class SqlLoggingComponent extends BaseDashboard {
|
|
|
872
1057
|
}
|
|
873
1058
|
/**
|
|
874
1059
|
* Calculates the total number of SQL statements across all active sessions.
|
|
875
|
-
*
|
|
876
1060
|
* @returns Total statement count
|
|
877
1061
|
*/
|
|
878
1062
|
getTotalStatementCount() {
|
|
879
1063
|
return this.activeSessions.reduce((sum, session) => sum + (session.statementCount || 0), 0);
|
|
880
1064
|
}
|
|
1065
|
+
/**
|
|
1066
|
+
* Parses a string of filter patterns (comma or newline separated) into an array
|
|
1067
|
+
* @param patternsString - Comma or newline separated patterns
|
|
1068
|
+
* @returns Array of pattern strings, or undefined if empty
|
|
1069
|
+
*/
|
|
1070
|
+
parseFilterPatterns(patternsString) {
|
|
1071
|
+
if (!patternsString || !patternsString.trim()) {
|
|
1072
|
+
return undefined;
|
|
1073
|
+
}
|
|
1074
|
+
/** Split by comma or newline, trim whitespace, filter empty */
|
|
1075
|
+
return patternsString
|
|
1076
|
+
.split(/[,\n]/)
|
|
1077
|
+
.map((p) => p.trim())
|
|
1078
|
+
.filter((p) => p.length > 0);
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Toggles the log viewer between normal and expanded (fullscreen) mode.
|
|
1082
|
+
*/
|
|
1083
|
+
toggleLogViewerExpand() {
|
|
1084
|
+
this.isLogViewerExpanded = !this.isLogViewerExpanded;
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Handles keyboard events for the component.
|
|
1088
|
+
* Closes expanded log viewer or confirmation dialog when Escape is pressed.
|
|
1089
|
+
*/
|
|
1090
|
+
onEscapeKey() {
|
|
1091
|
+
if (this.showStopConfirmDialog) {
|
|
1092
|
+
this.cancelStopConfirm();
|
|
1093
|
+
}
|
|
1094
|
+
else if (this.isLogViewerExpanded) {
|
|
1095
|
+
this.isLogViewerExpanded = false;
|
|
1096
|
+
}
|
|
1097
|
+
else if (this.showStartSessionDialog) {
|
|
1098
|
+
this.showStartSessionDialog = false;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Opens the confirmation dialog for stopping a single session.
|
|
1103
|
+
*
|
|
1104
|
+
* @param session - The session to stop
|
|
1105
|
+
* @param event - Optional event to stop propagation
|
|
1106
|
+
*/
|
|
1107
|
+
openStopSessionConfirm(session, event) {
|
|
1108
|
+
if (event) {
|
|
1109
|
+
event.stopPropagation();
|
|
1110
|
+
}
|
|
1111
|
+
this.sessionToStop = session;
|
|
1112
|
+
this.isStoppingAll = false;
|
|
1113
|
+
this.showStopConfirmDialog = true;
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Opens the confirmation dialog for stopping all sessions.
|
|
1117
|
+
*/
|
|
1118
|
+
openStopAllSessionsConfirm() {
|
|
1119
|
+
this.sessionToStop = null;
|
|
1120
|
+
this.isStoppingAll = true;
|
|
1121
|
+
this.showStopConfirmDialog = true;
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Closes the stop confirmation dialog without taking action.
|
|
1125
|
+
*/
|
|
1126
|
+
cancelStopConfirm() {
|
|
1127
|
+
this.showStopConfirmDialog = false;
|
|
1128
|
+
this.sessionToStop = null;
|
|
1129
|
+
this.isStoppingAll = false;
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Confirms and executes the stop action (single session or all sessions).
|
|
1133
|
+
*/
|
|
1134
|
+
async confirmStopSession() {
|
|
1135
|
+
if (this.isStoppingAll) {
|
|
1136
|
+
await this.executeStopAllSessions();
|
|
1137
|
+
}
|
|
1138
|
+
else if (this.sessionToStop) {
|
|
1139
|
+
await this.executeStopSession(this.sessionToStop);
|
|
1140
|
+
}
|
|
1141
|
+
this.cancelStopConfirm();
|
|
1142
|
+
}
|
|
881
1143
|
/**
|
|
882
1144
|
* Debug method to test contextUser flow for SQL filtering.
|
|
883
1145
|
* This shows how the new architecture handles user context without storing email in provider.
|
|
@@ -907,7 +1169,9 @@ let SqlLoggingComponent = class SqlLoggingComponent extends BaseDashboard {
|
|
|
907
1169
|
}
|
|
908
1170
|
}
|
|
909
1171
|
static ɵfac = function SqlLoggingComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SqlLoggingComponent)(i0.ɵɵdirectiveInject(i1.SharedService)); };
|
|
910
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SqlLoggingComponent, selectors: [["mj-sql-logging"]],
|
|
1172
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SqlLoggingComponent, selectors: [["mj-sql-logging"]], hostBindings: function SqlLoggingComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
1173
|
+
i0.ɵɵlistener("keydown.escape", function SqlLoggingComponent_keydown_escape_HostBindingHandler() { return ctx.onEscapeKey(); }, false, i0.ɵɵresolveDocument);
|
|
1174
|
+
} }, features: [i0.ɵɵInheritDefinitionFeature], decls: 11, vars: 9, consts: [[1, "sql-logging-container"], [1, "action-buttons"], [1, "btn-secondary", 3, "click", "disabled"], [1, "fa-solid", "fa-refresh"], ["title", "Start SQL logging session", 1, "btn-primary", 3, "disabled"], [1, "stats-grid", 2, "display", "flex"], [1, "loading-container"], [1, "content-area"], [1, "modal-backdrop"], ["title", "Start SQL logging session", 1, "btn-primary", 3, "click", "disabled"], [1, "fa-solid", "fa-play"], [1, "stat-card"], [1, "stat-icon", "stat-icon-status"], [1, "fa-solid", "fa-power-off"], [1, "stat-content"], [1, "stat-value"], [1, "stat-label"], [1, "stat-icon", "stat-icon-active"], [1, "fa-solid", "fa-play-circle"], [1, "stat-icon", "stat-icon-limit"], [1, "fa-solid", "fa-gauge-high"], [1, "stat-icon", "stat-icon-total"], [1, "fa-solid", "fa-database"], [1, "loading-spinner"], [1, "spinner-ring"], [1, "loading-text"], [1, "empty-state"], [1, "sessions-layout"], [1, "fa-solid", "fa-lock", "empty-icon"], [1, "empty-text"], [1, "empty-subtext"], [1, "btn-secondary", 2, "margin-top", "1rem", 3, "click"], [1, "fa-solid", "fa-sync"], [1, "fa-solid", "fa-exclamation-triangle", "empty-icon", "warning"], [1, "info-box"], [1, "fa-solid", "fa-file-code", "empty-icon"], [1, "btn-primary", 2, "margin-top", "1rem", 3, "click"], [1, "sessions-panel"], [1, "panel-header"], [1, "panel-title"], ["title", "Stop all sessions", 1, "btn-danger", "btn-small", 3, "disabled"], [1, "sessions-list"], [1, "session-card", 3, "selected"], [1, "log-viewer-panel"], ["title", "Stop all sessions", 1, "btn-danger", "btn-small", 3, "click", "disabled"], [1, "fa-solid", "fa-stop"], [1, "session-card", 3, "click"], [1, "session-header"], [1, "session-info"], [1, "session-title"], [1, "session-meta"], [1, "meta-item"], [1, "fa-solid", "fa-clock"], ["title", "Stop session", 1, "action-btn", "action-btn-danger", 3, "click"], [1, "session-badges"], [1, "badge", "badge-user"], [1, "badge", "badge-migration"], [1, "badge", "badge-type"], [1, "fa-solid", "fa-user"], [1, "fa-solid", "fa-code-branch"], [1, "panel-actions"], [1, "checkbox-label"], ["type", "checkbox", 3, "ngModelChange", "ngModel"], ["title", "Refresh log", 1, "action-btn", 3, "click"], [1, "action-btn", 3, "click", "title"], [1, "fa-solid"], [1, "log-content"], [2, "height", "100%", 3, "value", "readonly", "disabled", "language", "setup", "lineWrapping", "highlightWhitespace"], [1, "fa-solid", "fa-arrow-left", "empty-icon"], [1, "modal-backdrop", 3, "click"], [1, "modal-dialog", "modal-large", 3, "click"], [1, "modal-header"], [1, "modal-title"], [1, "modal-close", 3, "click"], [1, "fa-solid", "fa-times"], [1, "modal-body"], [1, "form-group"], [1, "form-label"], ["type", "text", "placeholder", "Enter a descriptive name for this session", 1, "form-input", 3, "ngModelChange", "ngModel"], ["type", "text", "placeholder", "sql-log-2024-01-01.sql", 1, "form-input", 3, "ngModelChange", "ngModel"], [1, "form-hint"], [1, "form-select", 3, "ngModelChange", "ngModel"], [3, "value"], [1, "form-checkboxes"], [1, "form-section"], [1, "form-section-title"], [1, "fa-solid", "fa-filter"], ["rows", "4", "placeholder", "Examples:\n*AIPrompt*\n/spCreate.*Run/i\nSELECT * FROM vwMetadata", 1, "form-textarea", 3, "ngModelChange", "ngModel"], [1, "fa-solid", "fa-cog"], [1, "form-hint", 2, "margin-left", "1.5rem"], [1, "modal-footer"], [1, "btn-primary", 3, "click", "disabled"], [1, "btn-secondary", 3, "click"], ["type", "text", "placeholder", "__mj", 1, "form-input", 3, "ngModelChange", "ngModel"], [1, "confirm-dialog", 3, "click"], [1, "confirm-dialog-icon"], [1, "fa-solid", "fa-exclamation-triangle"], [1, "confirm-dialog-content"], [1, "confirm-dialog-title"], [1, "confirm-dialog-message"], [1, "confirm-dialog-actions"], [1, "btn-danger", 3, "click", "disabled"], [1, "confirm-dialog-details"], [1, "fa-solid", "fa-spinner", "fa-spin"]], template: function SqlLoggingComponent_Template(rf, ctx) { if (rf & 1) {
|
|
911
1175
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "button", 2);
|
|
912
1176
|
i0.ɵɵlistener("click", function SqlLoggingComponent_Template_button_click_2_listener() { return ctx.loadActiveSessions(); });
|
|
913
1177
|
i0.ɵɵelement(3, "i", 3);
|
|
@@ -915,7 +1179,7 @@ let SqlLoggingComponent = class SqlLoggingComponent extends BaseDashboard {
|
|
|
915
1179
|
i0.ɵɵelementEnd();
|
|
916
1180
|
i0.ɵɵtemplate(5, SqlLoggingComponent_Conditional_5_Template, 3, 1, "button", 4);
|
|
917
1181
|
i0.ɵɵelementEnd();
|
|
918
|
-
i0.ɵɵtemplate(6, SqlLoggingComponent_Conditional_6_Template, 33, 4, "div", 5)(7, SqlLoggingComponent_Conditional_7_Template, 7, 0, "div", 6)(8, SqlLoggingComponent_Conditional_8_Template, 5, 1, "div", 7)(9, SqlLoggingComponent_Conditional_9_Template,
|
|
1182
|
+
i0.ɵɵtemplate(6, SqlLoggingComponent_Conditional_6_Template, 33, 4, "div", 5)(7, SqlLoggingComponent_Conditional_7_Template, 7, 0, "div", 6)(8, SqlLoggingComponent_Conditional_8_Template, 5, 1, "div", 7)(9, SqlLoggingComponent_Conditional_9_Template, 70, 11, "div", 8)(10, SqlLoggingComponent_Conditional_10_Template, 17, 5, "div", 8);
|
|
919
1183
|
i0.ɵɵelementEnd();
|
|
920
1184
|
} if (rf & 2) {
|
|
921
1185
|
i0.ɵɵadvance(2);
|
|
@@ -932,7 +1196,9 @@ let SqlLoggingComponent = class SqlLoggingComponent extends BaseDashboard {
|
|
|
932
1196
|
i0.ɵɵconditional(!ctx.loading || ctx.activeSessions.length > 0 ? 8 : -1);
|
|
933
1197
|
i0.ɵɵadvance();
|
|
934
1198
|
i0.ɵɵconditional(ctx.showStartSessionDialog ? 9 : -1);
|
|
935
|
-
} }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.CheckboxControlValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.CodeEditorComponent], styles: ["@keyframes _ngcontent-%COMP%_shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.sql-logging-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n max-height: 100%;\n overflow: hidden;\n position: relative;\n max-width: 1400px;\n margin: 0 auto;\n padding: 2rem;\n}\n\n.action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n margin-bottom: 1.5rem;\n}\n@media (max-width: 768px) {\n .action-buttons[_ngcontent-%COMP%] {\n justify-content: center;\n flex-wrap: wrap;\n }\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n padding: 0.625rem 1.25rem;\n font-size: 0.95rem;\n font-weight: 500;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n background-color: #2196f3;\n color: white;\n}\n.btn-primary[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-primary[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n}\n.btn-primary[_ngcontent-%COMP%]:hover {\n background-color: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n padding: 0.625rem 1.25rem;\n font-size: 0.95rem;\n font-weight: 500;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n background-color: #ffffff;\n color: #374151;\n border: 1px solid #e5e7eb;\n}\n.btn-secondary[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-secondary[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n}\n.btn-secondary[_ngcontent-%COMP%]:hover {\n background-color: #f9fafb;\n border-color: #2196f3;\n color: #2196f3;\n}\n\n.btn-danger[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n padding: 0.625rem 1.25rem;\n font-size: 0.95rem;\n font-weight: 500;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n background-color: #f44336;\n color: white;\n}\n.btn-danger[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-danger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n}\n.btn-danger[_ngcontent-%COMP%]:hover {\n background-color: #d32f2f;\n}\n.btn-danger.btn-small[_ngcontent-%COMP%] {\n padding: 0.375rem 0.75rem;\n font-size: 0.875rem;\n}\n\n.stats-grid[_ngcontent-%COMP%] {\n display: grid !important;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 1.5rem;\n margin-bottom: 2rem;\n width: 100%;\n}\n@media (max-width: 768px) {\n .stats-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n }\n}\n\n.stat-card[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n padding: 1.5rem;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n display: flex;\n margin-right: 10px;\n align-items: center;\n gap: 1rem;\n transition: all 0.3s ease;\n min-width: 0;\n}\n.stat-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n}\n\n.stat-icon[_ngcontent-%COMP%] {\n width: 60px;\n height: 60px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.5rem;\n}\n.stat-icon-status[_ngcontent-%COMP%] {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n}\n.stat-icon-active[_ngcontent-%COMP%] {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n}\n.stat-icon-limit[_ngcontent-%COMP%] {\n background: rgba(255, 152, 0, 0.1);\n color: #ff9800;\n}\n.stat-icon-total[_ngcontent-%COMP%] {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n}\n\n.stat-content[_ngcontent-%COMP%] {\n flex: 1;\n}\n.stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 2rem;\n font-weight: 700;\n color: #1f2937;\n line-height: 1;\n}\n.stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n color: #6b7280;\n font-size: 0.875rem;\n margin-top: 0.25rem;\n}\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n position: relative;\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n padding: 1.5rem;\n min-height: 400px;\n}\n\n.sessions-layout[_ngcontent-%COMP%] {\n display: flex;\n gap: 1.5rem;\n height: calc(100vh - 450px);\n min-height: 400px;\n max-height: 600px;\n}\n@media (max-width: 1024px) {\n .sessions-layout[_ngcontent-%COMP%] {\n flex-direction: column;\n height: auto;\n max-height: none;\n }\n}\n\n.sessions-panel[_ngcontent-%COMP%] {\n flex: 0 0 400px;\n display: flex;\n flex-direction: column;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n overflow: hidden;\n}\n@media (max-width: 1024px) {\n .sessions-panel[_ngcontent-%COMP%] {\n flex: 1;\n max-height: 400px;\n }\n}\n\n.panel-header[_ngcontent-%COMP%] {\n padding: 1rem;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n.panel-header[_ngcontent-%COMP%] .panel-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 1.125rem;\n font-weight: 600;\n color: #1f2937;\n}\n\n.panel-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.sessions-list[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n position: relative;\n padding: 0.75rem;\n}\n\n.session-card[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n padding: 1rem;\n margin-bottom: 0.75rem;\n cursor: pointer;\n transition: all 0.2s;\n}\n.session-card[_ngcontent-%COMP%]:hover {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n.session-card.selected[_ngcontent-%COMP%] {\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.session-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 0.75rem;\n}\n\n.session-info[_ngcontent-%COMP%] {\n flex: 1;\n}\n.session-info[_ngcontent-%COMP%] .session-title[_ngcontent-%COMP%] {\n margin: 0 0 0.5rem 0;\n font-size: 0.95rem;\n font-weight: 600;\n color: #1f2937;\n}\n\n.session-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 1rem;\n font-size: 0.75rem;\n color: #6b7280;\n}\n.session-meta[_ngcontent-%COMP%] .meta-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.session-badges[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n\n.badge[_ngcontent-%COMP%] {\n padding: 0.25rem 0.5rem;\n border-radius: 12px;\n font-size: 0.625rem;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n.badge-user[_ngcontent-%COMP%] {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n}\n.badge-migration[_ngcontent-%COMP%] {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n}\n.badge-type[_ngcontent-%COMP%] {\n background: rgba(255, 152, 0, 0.1);\n color: #ff9800;\n}\n\n.action-btn[_ngcontent-%COMP%] {\n padding: 0.375rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 0.875rem;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.2s;\n}\n.action-btn[_ngcontent-%COMP%]:hover {\n background: #f3f4f6;\n color: #374151;\n}\n.action-btn-danger[_ngcontent-%COMP%]:hover {\n color: #f44336;\n}\n\n.log-viewer-panel[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.log-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n position: relative;\n background: #1e1e1e;\n color: #d4d4d4;\n padding: 0;\n min-height: 300px;\n height: 100%;\n position: relative;\n}\n.log-content[_ngcontent-%COMP%] .cm-editor {\n height: 100%;\n font-family: \"Consolas\", \"Monaco\", \"Courier New\", monospace;\n font-size: 0.875rem;\n}\n.log-content[_ngcontent-%COMP%] .cm-scroller {\n font-family: inherit;\n}\n.log-content[_ngcontent-%COMP%] .cm-content {\n background: #1e1e1e;\n color: #d4d4d4;\n}\n.log-content[_ngcontent-%COMP%] .cm-gutters {\n background: #252526;\n color: #858585;\n border-right: 1px solid #464647;\n}\n.log-content[_ngcontent-%COMP%] .cm-activeLineGutter {\n background: #2a2a2a;\n}\n.log-content[_ngcontent-%COMP%] .cm-activeLine {\n background: rgba(255, 255, 255, 0.04);\n}\n\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n.empty-state[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 4rem;\n color: #e5e7eb;\n margin-bottom: 1rem;\n}\n.empty-state[_ngcontent-%COMP%] .empty-icon.warning[_ngcontent-%COMP%] {\n color: #ffc107;\n}\n.empty-state[_ngcontent-%COMP%] .empty-text[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n font-weight: 600;\n color: #374151;\n margin: 0 0 0.5rem 0;\n}\n.empty-state[_ngcontent-%COMP%] .empty-subtext[_ngcontent-%COMP%] {\n color: #6b7280;\n margin: 0;\n}\n\n.info-box[_ngcontent-%COMP%] {\n background: #f3f4f6;\n border-radius: 8px;\n padding: 1.5rem;\n margin-top: 2rem;\n text-align: left;\n max-width: 500px;\n margin-left: auto;\n margin-right: auto;\n}\n.info-box[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 1rem 0;\n color: #1f2937;\n}\n.info-box[_ngcontent-%COMP%] ol[_ngcontent-%COMP%] {\n margin: 0;\n padding-left: 1.25rem;\n color: #374151;\n}\n.info-box[_ngcontent-%COMP%] ol[_ngcontent-%COMP%] li[_ngcontent-%COMP%] {\n margin-bottom: 0.5rem;\n}\n.info-box[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: #e5e7eb;\n padding: 0.125rem 0.375rem;\n border-radius: 4px;\n font-size: 0.875rem;\n}\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n min-height: 400px;\n}\n\n.loading-spinner[_ngcontent-%COMP%] {\n position: relative;\n width: 60px;\n height: 60px;\n margin-bottom: 1rem;\n}\n.loading-spinner[_ngcontent-%COMP%] .spinner-ring[_ngcontent-%COMP%] {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-radius: 50%;\n animation: _ngcontent-%COMP%_spin 1.5s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n}\n.loading-spinner[_ngcontent-%COMP%] .spinner-ring[_ngcontent-%COMP%]:nth-child(1) {\n border-color: #2196f3 transparent transparent transparent;\n animation-delay: -0.45s;\n}\n.loading-spinner[_ngcontent-%COMP%] .spinner-ring[_ngcontent-%COMP%]:nth-child(2) {\n border-color: transparent #9c27b0 transparent transparent;\n animation-delay: -0.3s;\n}\n.loading-spinner[_ngcontent-%COMP%] .spinner-ring[_ngcontent-%COMP%]:nth-child(3) {\n border-color: transparent transparent #4caf50 transparent;\n animation-delay: -0.15s;\n}\n\n@keyframes _ngcontent-%COMP%_spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n.loading-text[_ngcontent-%COMP%] {\n color: #6b7280;\n font-size: 0.95rem;\n}\n\n.modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: _ngcontent-%COMP%_fadeIn 0.2s ease;\n}\n\n.modal-dialog[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUp 0.3s ease;\n}\n.modal-dialog.modal-large[_ngcontent-%COMP%] {\n max-width: 700px;\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid #e5e7eb;\n}\n.modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: #1f2937;\n margin: 0;\n}\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%] {\n padding: 0.5rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n}\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%]:hover {\n background: #f3f4f6;\n color: #374151;\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n max-height: 60vh;\n overflow-y: auto;\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid #e5e7eb;\n background: #f9fafb;\n}\n\n.form-group[_ngcontent-%COMP%] {\n margin-bottom: 1.5rem;\n}\n\n.form-label[_ngcontent-%COMP%] {\n display: block;\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n margin-bottom: 0.5rem;\n}\n\n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n transition: all 0.2s;\n}\n.form-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.form-select[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n background: white;\n cursor: pointer;\n transition: all 0.2s;\n}\n.form-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.form-hint[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.25rem;\n}\n\n.form-checkboxes[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.checkbox-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n color: #374151;\n font-size: 0.95rem;\n cursor: pointer;\n}\n.checkbox-label[_ngcontent-%COMP%] input[type=checkbox][_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes _ngcontent-%COMP%_slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}"] });
|
|
1199
|
+
i0.ɵɵadvance();
|
|
1200
|
+
i0.ɵɵconditional(ctx.showStopConfirmDialog ? 10 : -1);
|
|
1201
|
+
} }, dependencies: [i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.CheckboxControlValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.CodeEditorComponent], styles: ["@keyframes _ngcontent-%COMP%_shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.sql-logging-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n max-height: 100%;\n overflow: hidden;\n position: relative;\n max-width: 1400px;\n margin: 0 auto;\n padding: 2rem;\n}\n\n.action-buttons[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n margin-bottom: 1.5rem;\n}\n@media (max-width: 768px) {\n .action-buttons[_ngcontent-%COMP%] {\n justify-content: center;\n flex-wrap: wrap;\n }\n}\n\n.btn-primary[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n padding: 0.625rem 1.25rem;\n font-size: 0.95rem;\n font-weight: 500;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n background-color: #2196f3;\n color: white;\n}\n.btn-primary[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-primary[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n}\n.btn-primary[_ngcontent-%COMP%]:hover {\n background-color: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n padding: 0.625rem 1.25rem;\n font-size: 0.95rem;\n font-weight: 500;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n background-color: #ffffff;\n color: #374151;\n border: 1px solid #e5e7eb;\n}\n.btn-secondary[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-secondary[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n}\n.btn-secondary[_ngcontent-%COMP%]:hover {\n background-color: #f9fafb;\n border-color: #2196f3;\n color: #2196f3;\n}\n\n.btn-danger[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n padding: 0.625rem 1.25rem;\n font-size: 0.95rem;\n font-weight: 500;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n background-color: #f44336;\n color: white;\n}\n.btn-danger[_ngcontent-%COMP%]:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-danger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.875rem;\n}\n.btn-danger[_ngcontent-%COMP%]:hover {\n background-color: #d32f2f;\n}\n.btn-danger.btn-small[_ngcontent-%COMP%] {\n padding: 0.375rem 0.75rem;\n font-size: 0.875rem;\n}\n\n.stats-grid[_ngcontent-%COMP%] {\n display: grid !important;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 1.5rem;\n margin-bottom: 2rem;\n width: 100%;\n}\n@media (max-width: 768px) {\n .stats-grid[_ngcontent-%COMP%] {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n }\n}\n\n.stat-card[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n padding: 1.5rem;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n display: flex;\n margin-right: 10px;\n align-items: center;\n gap: 1rem;\n transition: all 0.3s ease;\n min-width: 0;\n}\n.stat-card[_ngcontent-%COMP%]:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n}\n\n.stat-icon[_ngcontent-%COMP%] {\n width: 60px;\n height: 60px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.5rem;\n}\n.stat-icon-status[_ngcontent-%COMP%] {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n}\n.stat-icon-active[_ngcontent-%COMP%] {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n}\n.stat-icon-limit[_ngcontent-%COMP%] {\n background: rgba(255, 152, 0, 0.1);\n color: #ff9800;\n}\n.stat-icon-total[_ngcontent-%COMP%] {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n}\n\n.stat-content[_ngcontent-%COMP%] {\n flex: 1;\n}\n.stat-content[_ngcontent-%COMP%] .stat-value[_ngcontent-%COMP%] {\n font-size: 2rem;\n font-weight: 700;\n color: #1f2937;\n line-height: 1;\n}\n.stat-content[_ngcontent-%COMP%] .stat-label[_ngcontent-%COMP%] {\n color: #6b7280;\n font-size: 0.875rem;\n margin-top: 0.25rem;\n}\n\n.content-area[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n position: relative;\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n padding: 1.5rem;\n min-height: 400px;\n}\n\n.sessions-layout[_ngcontent-%COMP%] {\n display: flex;\n gap: 1.5rem;\n height: calc(100vh - 450px);\n min-height: 400px;\n max-height: 600px;\n}\n@media (max-width: 1024px) {\n .sessions-layout[_ngcontent-%COMP%] {\n flex-direction: column;\n height: auto;\n max-height: none;\n }\n}\n\n.sessions-panel[_ngcontent-%COMP%] {\n flex: 0 0 400px;\n display: flex;\n flex-direction: column;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n overflow: hidden;\n}\n@media (max-width: 1024px) {\n .sessions-panel[_ngcontent-%COMP%] {\n flex: 1;\n max-height: 400px;\n }\n}\n\n.panel-header[_ngcontent-%COMP%] {\n padding: 1rem;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n.panel-header[_ngcontent-%COMP%] .panel-title[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 1.125rem;\n font-weight: 600;\n color: #1f2937;\n}\n\n.panel-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.sessions-list[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n position: relative;\n padding: 0.75rem;\n}\n\n.session-card[_ngcontent-%COMP%] {\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n padding: 1rem;\n margin-bottom: 0.75rem;\n cursor: pointer;\n transition: all 0.2s;\n}\n.session-card[_ngcontent-%COMP%]:hover {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n.session-card.selected[_ngcontent-%COMP%] {\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.session-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 0.75rem;\n}\n\n.session-info[_ngcontent-%COMP%] {\n flex: 1;\n}\n.session-info[_ngcontent-%COMP%] .session-title[_ngcontent-%COMP%] {\n margin: 0 0 0.5rem 0;\n font-size: 0.95rem;\n font-weight: 600;\n color: #1f2937;\n}\n\n.session-meta[_ngcontent-%COMP%] {\n display: flex;\n gap: 1rem;\n font-size: 0.75rem;\n color: #6b7280;\n}\n.session-meta[_ngcontent-%COMP%] .meta-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.session-badges[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n\n.badge[_ngcontent-%COMP%] {\n padding: 0.25rem 0.5rem;\n border-radius: 12px;\n font-size: 0.625rem;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n.badge-user[_ngcontent-%COMP%] {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n}\n.badge-migration[_ngcontent-%COMP%] {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n}\n.badge-type[_ngcontent-%COMP%] {\n background: rgba(255, 152, 0, 0.1);\n color: #ff9800;\n}\n\n.action-btn[_ngcontent-%COMP%] {\n padding: 0.375rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 0.875rem;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.2s;\n}\n.action-btn[_ngcontent-%COMP%]:hover {\n background: #f3f4f6;\n color: #374151;\n}\n.action-btn-danger[_ngcontent-%COMP%]:hover {\n color: #f44336;\n}\n\n.log-viewer-panel[_ngcontent-%COMP%] {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.log-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n position: relative;\n background: #1e1e1e;\n color: #d4d4d4;\n padding: 0;\n min-height: 300px;\n height: 100%;\n position: relative;\n}\n.log-content[_ngcontent-%COMP%] .cm-editor {\n height: 100%;\n font-family: \"Consolas\", \"Monaco\", \"Courier New\", monospace;\n font-size: 0.875rem;\n}\n.log-content[_ngcontent-%COMP%] .cm-scroller {\n font-family: inherit;\n}\n.log-content[_ngcontent-%COMP%] .cm-content {\n background: #1e1e1e;\n color: #d4d4d4;\n}\n.log-content[_ngcontent-%COMP%] .cm-gutters {\n background: #252526;\n color: #858585;\n border-right: 1px solid #464647;\n}\n.log-content[_ngcontent-%COMP%] .cm-activeLineGutter {\n background: #2a2a2a;\n}\n.log-content[_ngcontent-%COMP%] .cm-activeLine {\n background: rgba(255, 255, 255, 0.04);\n}\n\n.empty-state[_ngcontent-%COMP%] {\n text-align: center;\n padding: 4rem 2rem;\n}\n.empty-state[_ngcontent-%COMP%] .empty-icon[_ngcontent-%COMP%] {\n font-size: 4rem;\n color: #e5e7eb;\n margin-bottom: 1rem;\n}\n.empty-state[_ngcontent-%COMP%] .empty-icon.warning[_ngcontent-%COMP%] {\n color: #ffc107;\n}\n.empty-state[_ngcontent-%COMP%] .empty-text[_ngcontent-%COMP%] {\n font-size: 1.25rem;\n font-weight: 600;\n color: #374151;\n margin: 0 0 0.5rem 0;\n}\n.empty-state[_ngcontent-%COMP%] .empty-subtext[_ngcontent-%COMP%] {\n color: #6b7280;\n margin: 0;\n}\n\n.info-box[_ngcontent-%COMP%] {\n background: #f3f4f6;\n border-radius: 8px;\n padding: 1.5rem;\n margin-top: 2rem;\n text-align: left;\n max-width: 500px;\n margin-left: auto;\n margin-right: auto;\n}\n.info-box[_ngcontent-%COMP%] h4[_ngcontent-%COMP%] {\n margin: 0 0 1rem 0;\n color: #1f2937;\n}\n.info-box[_ngcontent-%COMP%] ol[_ngcontent-%COMP%] {\n margin: 0;\n padding-left: 1.25rem;\n color: #374151;\n}\n.info-box[_ngcontent-%COMP%] ol[_ngcontent-%COMP%] li[_ngcontent-%COMP%] {\n margin-bottom: 0.5rem;\n}\n.info-box[_ngcontent-%COMP%] code[_ngcontent-%COMP%] {\n background: #e5e7eb;\n padding: 0.125rem 0.375rem;\n border-radius: 4px;\n font-size: 0.875rem;\n}\n\n.loading-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n min-height: 400px;\n}\n\n.loading-spinner[_ngcontent-%COMP%] {\n position: relative;\n width: 60px;\n height: 60px;\n margin-bottom: 1rem;\n}\n.loading-spinner[_ngcontent-%COMP%] .spinner-ring[_ngcontent-%COMP%] {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-radius: 50%;\n animation: _ngcontent-%COMP%_spin 1.5s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n}\n.loading-spinner[_ngcontent-%COMP%] .spinner-ring[_ngcontent-%COMP%]:nth-child(1) {\n border-color: #2196f3 transparent transparent transparent;\n animation-delay: -0.45s;\n}\n.loading-spinner[_ngcontent-%COMP%] .spinner-ring[_ngcontent-%COMP%]:nth-child(2) {\n border-color: transparent #9c27b0 transparent transparent;\n animation-delay: -0.3s;\n}\n.loading-spinner[_ngcontent-%COMP%] .spinner-ring[_ngcontent-%COMP%]:nth-child(3) {\n border-color: transparent transparent #4caf50 transparent;\n animation-delay: -0.15s;\n}\n\n@keyframes _ngcontent-%COMP%_spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n.loading-text[_ngcontent-%COMP%] {\n color: #6b7280;\n font-size: 0.95rem;\n}\n\n.modal-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: _ngcontent-%COMP%_fadeIn 0.2s ease;\n}\n\n.modal-dialog[_ngcontent-%COMP%] {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow: hidden;\n animation: _ngcontent-%COMP%_slideUp 0.3s ease;\n}\n.modal-dialog.modal-large[_ngcontent-%COMP%] {\n max-width: 700px;\n}\n\n.modal-header[_ngcontent-%COMP%] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid #e5e7eb;\n}\n.modal-header[_ngcontent-%COMP%] .modal-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: #1f2937;\n margin: 0;\n}\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%] {\n padding: 0.5rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n}\n.modal-header[_ngcontent-%COMP%] .modal-close[_ngcontent-%COMP%]:hover {\n background: #f3f4f6;\n color: #374151;\n}\n\n.modal-body[_ngcontent-%COMP%] {\n padding: 1.5rem;\n max-height: 60vh;\n overflow-y: auto;\n}\n\n.modal-footer[_ngcontent-%COMP%] {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid #e5e7eb;\n background: #f9fafb;\n}\n\n.form-group[_ngcontent-%COMP%] {\n margin-bottom: 1.5rem;\n}\n\n.form-label[_ngcontent-%COMP%] {\n display: block;\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n margin-bottom: 0.5rem;\n}\n\n.form-input[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n transition: all 0.2s;\n}\n.form-input[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.form-select[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n background: white;\n cursor: pointer;\n transition: all 0.2s;\n}\n.form-select[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.form-hint[_ngcontent-%COMP%] {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.25rem;\n}\n\n.form-checkboxes[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.checkbox-label[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n color: #374151;\n font-size: 0.95rem;\n cursor: pointer;\n}\n.checkbox-label[_ngcontent-%COMP%] input[type=checkbox][_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n\n\n.form-section[_ngcontent-%COMP%] {\n margin-top: 1.5rem;\n padding: 1.25rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n background: #f9fafb;\n}\n\n.form-section-title[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin: 0 0 1rem 0;\n font-size: 1rem;\n font-weight: 600;\n color: #374151;\n}\n\n.form-section-title[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: #6b7280;\n}\n\n.form-textarea[_ngcontent-%COMP%] {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n font-family: \"Consolas\", \"Monaco\", \"Courier New\", monospace;\n resize: vertical;\n transition: all 0.2s;\n}\n\n.form-textarea[_ngcontent-%COMP%]:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.form-textarea[_ngcontent-%COMP%]::placeholder {\n color: #9ca3af;\n font-style: italic;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes _ngcontent-%COMP%_slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n\n\n.log-viewer-panel.expanded[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n border-radius: 0;\n margin: 0;\n max-height: none;\n height: 100vh;\n animation: _ngcontent-%COMP%_expandIn 0.3s ease;\n}\n\n.log-viewer-panel.expanded[_ngcontent-%COMP%] .panel-header[_ngcontent-%COMP%] {\n border-radius: 0;\n}\n\n.log-viewer-panel.expanded[_ngcontent-%COMP%] .log-content[_ngcontent-%COMP%] {\n max-height: calc(100vh - 60px);\n min-height: calc(100vh - 60px);\n}\n\n@keyframes _ngcontent-%COMP%_expandIn {\n from {\n transform: scale(0.95);\n opacity: 0;\n }\n to {\n transform: scale(1);\n opacity: 1;\n }\n}\n\n\n\n.confirm-dialog[_ngcontent-%COMP%] {\n background: white;\n border-radius: 16px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n max-width: 420px;\n width: 90%;\n padding: 2rem;\n text-align: center;\n animation: _ngcontent-%COMP%_dialogBounce 0.3s ease;\n}\n\n@keyframes _ngcontent-%COMP%_dialogBounce {\n 0% {\n transform: scale(0.9) translateY(10px);\n opacity: 0;\n }\n 50% {\n transform: scale(1.02) translateY(-5px);\n }\n 100% {\n transform: scale(1) translateY(0);\n opacity: 1;\n }\n}\n\n.confirm-dialog-icon[_ngcontent-%COMP%] {\n width: 64px;\n height: 64px;\n border-radius: 50%;\n background: linear-gradient(135deg, #fff3e0 0%, #ffe0b2 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1.5rem;\n box-shadow: 0 4px 12px rgba(255, 152, 0, 0.2);\n}\n\n.confirm-dialog-icon[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 1.75rem;\n color: #f57c00;\n}\n\n.confirm-dialog-content[_ngcontent-%COMP%] {\n margin-bottom: 1.5rem;\n}\n\n.confirm-dialog-title[_ngcontent-%COMP%] {\n margin: 0 0 0.75rem 0;\n font-size: 1.375rem;\n font-weight: 700;\n color: #1f2937;\n}\n\n.confirm-dialog-message[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 0.95rem;\n color: #4b5563;\n line-height: 1.6;\n}\n\n.confirm-dialog-message[_ngcontent-%COMP%] strong[_ngcontent-%COMP%] {\n color: #1f2937;\n font-weight: 600;\n}\n\n.confirm-dialog-details[_ngcontent-%COMP%] {\n display: block;\n margin-top: 0.75rem;\n padding: 0.75rem;\n background: #f3f4f6;\n border-radius: 8px;\n font-size: 0.875rem;\n color: #6b7280;\n}\n\n.confirm-dialog-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.75rem;\n justify-content: center;\n}\n\n.confirm-dialog-actions[_ngcontent-%COMP%] .btn-danger[_ngcontent-%COMP%] {\n min-width: 140px;\n}\n\n.confirm-dialog-actions[_ngcontent-%COMP%] .btn-secondary[_ngcontent-%COMP%] {\n min-width: 100px;\n}"] });
|
|
936
1202
|
};
|
|
937
1203
|
SqlLoggingComponent = __decorate([
|
|
938
1204
|
RegisterClass(BaseDashboard, 'SqlLogging')
|
|
@@ -940,7 +1206,10 @@ SqlLoggingComponent = __decorate([
|
|
|
940
1206
|
export { SqlLoggingComponent };
|
|
941
1207
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SqlLoggingComponent, [{
|
|
942
1208
|
type: Component,
|
|
943
|
-
args: [{ selector: 'mj-sql-logging', template: "<div class=\"sql-logging-container\">\n <!-- Action Buttons -->\n <div class=\"action-buttons\">\n <button class=\"btn-secondary\" (click)=\"loadActiveSessions()\" [disabled]=\"loading\">\n <i class=\"fa-solid fa-refresh\" [class.fa-spin]=\"loading\"></i>\n Refresh\n </button>\n @if (isOwner && configEnabled) {\n <button \n class=\"btn-primary\"\n [disabled]=\"loading || activeSessions.length >= (sqlLoggingConfig?.maxActiveSessions || 5)\"\n (click)=\"openStartSessionDialog()\"\n title=\"Start SQL logging session\"\n >\n <i class=\"fa-solid fa-play\"></i>\n Start New Session\n </button>\n }\n </div>\n\n <!-- Stats Cards -->\n @if (isOwner && configEnabled) {\n <div class=\"stats-grid\" style=\"display: flex\">\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-status\">\n <i class=\"fa-solid fa-power-off\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ configEnabled ? 'Enabled' : 'Disabled' }}</div>\n <div class=\"stat-label\">Status</div>\n </div>\n </div>\n \n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-active\">\n <i class=\"fa-solid fa-play-circle\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ activeSessions.length }}</div>\n <div class=\"stat-label\">Active Sessions</div>\n </div>\n </div>\n \n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-limit\">\n <i class=\"fa-solid fa-gauge-high\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ sqlLoggingConfig?.maxActiveSessions || 5 }}</div>\n <div class=\"stat-label\">Max Sessions</div>\n </div>\n </div>\n \n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-total\">\n <i class=\"fa-solid fa-database\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ getTotalStatementCount() }}</div>\n <div class=\"stat-label\">Total Statements</div>\n </div>\n </div>\n </div>\n }\n\n <!-- Loading State -->\n @if (loading && !activeSessions.length) {\n <div class=\"loading-container\">\n <div class=\"loading-spinner\">\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n </div>\n <div class=\"loading-text\">Loading SQL logging configuration...</div>\n </div>\n }\n\n <!-- Content Area -->\n @if (!loading || activeSessions.length > 0) {\n <div class=\"content-area\">\n @if (!isOwner) {\n <!-- Not authorized -->\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-lock empty-icon\"></i>\n <p class=\"empty-text\">Access Denied</p>\n <p class=\"empty-subtext\">SQL logging requires Owner privileges. Please contact your system administrator for access.</p>\n <button \n class=\"btn-secondary\"\n (click)=\"refreshUserPermissions()\"\n style=\"margin-top: 1rem\"\n >\n <i class=\"fa-solid fa-sync\"></i>\n Refresh Permissions\n </button>\n </div>\n } @else if (!configEnabled) {\n <!-- Not enabled in config -->\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-exclamation-triangle empty-icon warning\"></i>\n <p class=\"empty-text\">SQL Logging Disabled</p>\n <p class=\"empty-subtext\">SQL logging is not enabled in the server configuration.</p>\n <div class=\"info-box\">\n <h4>To enable SQL logging:</h4>\n <ol>\n <li>Set <code>sqlLogging.enabled = true</code> in mj.config.cjs</li>\n <li>Restart the MJ API server</li>\n <li>Refresh this page</li>\n </ol>\n </div>\n </div>\n } @else if (activeSessions.length === 0) {\n <!-- No active sessions -->\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-file-code empty-icon\"></i>\n <p class=\"empty-text\">No Active Sessions</p>\n <p class=\"empty-subtext\">Start a new SQL logging session to begin capturing SQL statements.</p>\n <button \n class=\"btn-primary\"\n (click)=\"openStartSessionDialog()\"\n style=\"margin-top: 1rem\"\n >\n <i class=\"fa-solid fa-play\"></i>\n Start New Session\n </button>\n </div>\n } @else {\n <!-- Sessions layout -->\n <div class=\"sessions-layout\">\n <!-- Sessions panel -->\n <div class=\"sessions-panel\">\n <div class=\"panel-header\">\n <h3 class=\"panel-title\">Active Sessions</h3>\n @if (activeSessions.length > 0) {\n <button \n class=\"btn-danger btn-small\"\n (click)=\"stopAllSessions()\"\n [disabled]=\"loading\"\n title=\"Stop all sessions\"\n >\n <i class=\"fa-solid fa-stop\"></i>\n Stop All\n </button>\n }\n </div>\n <div class=\"sessions-list\">\n @for (session of activeSessions; track session.id) {\n <div \n class=\"session-card\" \n [class.selected]=\"selectedSession?.id === session.id\"\n (click)=\"selectSession(session)\"\n >\n <div class=\"session-header\">\n <div class=\"session-info\">\n <h4 class=\"session-title\">{{ session.sessionName }}</h4>\n <div class=\"session-meta\">\n <span class=\"meta-item\">\n <i class=\"fa-solid fa-clock\"></i>\n {{ getSessionDuration(session.startTime) }}\n </span>\n <span class=\"meta-item\">\n <i class=\"fa-solid fa-database\"></i>\n {{ session.statementCount }} statements\n </span>\n </div>\n </div>\n <button \n class=\"action-btn action-btn-danger\"\n (click)=\"stopSession(session, $event)\"\n title=\"Stop session\"\n >\n <i class=\"fa-solid fa-stop\"></i>\n </button>\n </div>\n <div class=\"session-badges\">\n @if (session.filterByUserId) {\n <span class=\"badge badge-user\">\n <i class=\"fa-solid fa-user\"></i>\n User Filtered\n </span>\n }\n @if (session.options?.formatAsMigration) {\n <span class=\"badge badge-migration\">\n <i class=\"fa-solid fa-code-branch\"></i>\n Migration\n </span>\n }\n <span class=\"badge badge-type\">\n {{ session.options?.statementTypes || 'both' }}\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n \n <!-- Log viewer panel -->\n <div class=\"log-viewer-panel\">\n @if (selectedSession) {\n <div class=\"panel-header\">\n <h3 class=\"panel-title\">{{ selectedSession.sessionName }}</h3>\n <div class=\"panel-actions\">\n <label class=\"checkbox-label\">\n <input \n type=\"checkbox\" \n [(ngModel)]=\"autoRefresh\"\n />\n Auto-refresh\n </label>\n <button \n class=\"action-btn\"\n (click)=\"loadSessionLog(selectedSession)\"\n title=\"Refresh log\"\n >\n <i class=\"fa-solid fa-sync\" [class.fa-spin]=\"loading\"></i>\n </button>\n </div>\n </div>\n <div class=\"log-content\">\n <mj-code-editor\n [value]=\"logContent\"\n [readonly]=\"true\"\n [disabled]=\"true\"\n [language]=\"'sql'\"\n [setup]=\"'basic'\"\n [lineWrapping]=\"true\"\n [highlightWhitespace]=\"false\"\n style=\"height: 100%;\"\n ></mj-code-editor>\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-arrow-left empty-icon\"></i>\n <p class=\"empty-text\">Select a Session</p>\n <p class=\"empty-subtext\">Choose a session from the list to view its SQL log.</p>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Start Session Dialog -->\n @if (showStartSessionDialog) {\n <div class=\"modal-backdrop\" (click)=\"showStartSessionDialog = false\">\n <div class=\"modal-dialog modal-large\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3 class=\"modal-title\">\n <i class=\"fa-solid fa-play\"></i>\n Start SQL Logging Session\n </h3>\n <button class=\"modal-close\" (click)=\"showStartSessionDialog = false\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <div class=\"modal-body\">\n <div class=\"form-group\">\n <label class=\"form-label\">Session Name</label>\n <input \n type=\"text\"\n class=\"form-input\" \n [(ngModel)]=\"newSessionOptions.sessionName\"\n placeholder=\"Enter a descriptive name for this session\"\n />\n </div>\n \n <div class=\"form-group\">\n <label class=\"form-label\">File Name</label>\n <input \n type=\"text\"\n class=\"form-input\" \n [(ngModel)]=\"newSessionOptions.fileName\"\n placeholder=\"sql-log-2024-01-01.sql\"\n />\n <div class=\"form-hint\">The SQL log will be saved to this file</div>\n </div>\n \n <div class=\"form-group\">\n <label class=\"form-label\">Statement Types</label>\n <select\n class=\"form-select\"\n [(ngModel)]=\"newSessionOptions.statementTypes\"\n >\n @for (option of statementTypeOptions; track option.value) {\n <option [value]=\"option.value\">{{ option.text }}</option>\n }\n </select>\n </div>\n \n <div class=\"form-checkboxes\">\n <label class=\"checkbox-label\">\n <input \n type=\"checkbox\" \n [(ngModel)]=\"newSessionOptions.filterToCurrentUser\"\n />\n Filter to my SQL statements only\n </label>\n \n <label class=\"checkbox-label\">\n <input \n type=\"checkbox\" \n [(ngModel)]=\"newSessionOptions.formatAsMigration\"\n />\n Format as migration file\n </label>\n \n <label class=\"checkbox-label\">\n <input \n type=\"checkbox\" \n [(ngModel)]=\"newSessionOptions.prettyPrint\"\n />\n Pretty print SQL statements\n </label>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button class=\"btn-secondary\" (click)=\"showStartSessionDialog = false\">\n Cancel\n </button>\n <button class=\"btn-primary\" (click)=\"startNewSession()\" [disabled]=\"loading\">\n <i class=\"fa-solid fa-play\"></i>\n Start Session\n </button>\n </div>\n </div>\n </div>\n }\n</div>", styles: ["@keyframes shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.sql-logging-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n max-height: 100%;\n overflow: hidden;\n position: relative;\n max-width: 1400px;\n margin: 0 auto;\n padding: 2rem;\n}\n\n.action-buttons {\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n margin-bottom: 1.5rem;\n}\n@media (max-width: 768px) {\n .action-buttons {\n justify-content: center;\n flex-wrap: wrap;\n }\n}\n\n.btn-primary {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n padding: 0.625rem 1.25rem;\n font-size: 0.95rem;\n font-weight: 500;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n background-color: #2196f3;\n color: white;\n}\n.btn-primary:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-primary i {\n font-size: 0.875rem;\n}\n.btn-primary:hover {\n background-color: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);\n}\n\n.btn-secondary {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n padding: 0.625rem 1.25rem;\n font-size: 0.95rem;\n font-weight: 500;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n background-color: #ffffff;\n color: #374151;\n border: 1px solid #e5e7eb;\n}\n.btn-secondary:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-secondary i {\n font-size: 0.875rem;\n}\n.btn-secondary:hover {\n background-color: #f9fafb;\n border-color: #2196f3;\n color: #2196f3;\n}\n\n.btn-danger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n padding: 0.625rem 1.25rem;\n font-size: 0.95rem;\n font-weight: 500;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n background-color: #f44336;\n color: white;\n}\n.btn-danger:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-danger i {\n font-size: 0.875rem;\n}\n.btn-danger:hover {\n background-color: #d32f2f;\n}\n.btn-danger.btn-small {\n padding: 0.375rem 0.75rem;\n font-size: 0.875rem;\n}\n\n.stats-grid {\n display: grid !important;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 1.5rem;\n margin-bottom: 2rem;\n width: 100%;\n}\n@media (max-width: 768px) {\n .stats-grid {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n }\n}\n\n.stat-card {\n background: white;\n border-radius: 12px;\n padding: 1.5rem;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n display: flex;\n margin-right: 10px;\n align-items: center;\n gap: 1rem;\n transition: all 0.3s ease;\n min-width: 0;\n}\n.stat-card:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n}\n\n.stat-icon {\n width: 60px;\n height: 60px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.5rem;\n}\n.stat-icon-status {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n}\n.stat-icon-active {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n}\n.stat-icon-limit {\n background: rgba(255, 152, 0, 0.1);\n color: #ff9800;\n}\n.stat-icon-total {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n}\n\n.stat-content {\n flex: 1;\n}\n.stat-content .stat-value {\n font-size: 2rem;\n font-weight: 700;\n color: #1f2937;\n line-height: 1;\n}\n.stat-content .stat-label {\n color: #6b7280;\n font-size: 0.875rem;\n margin-top: 0.25rem;\n}\n\n.content-area {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n position: relative;\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n padding: 1.5rem;\n min-height: 400px;\n}\n\n.sessions-layout {\n display: flex;\n gap: 1.5rem;\n height: calc(100vh - 450px);\n min-height: 400px;\n max-height: 600px;\n}\n@media (max-width: 1024px) {\n .sessions-layout {\n flex-direction: column;\n height: auto;\n max-height: none;\n }\n}\n\n.sessions-panel {\n flex: 0 0 400px;\n display: flex;\n flex-direction: column;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n overflow: hidden;\n}\n@media (max-width: 1024px) {\n .sessions-panel {\n flex: 1;\n max-height: 400px;\n }\n}\n\n.panel-header {\n padding: 1rem;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n.panel-header .panel-title {\n margin: 0;\n font-size: 1.125rem;\n font-weight: 600;\n color: #1f2937;\n}\n\n.panel-actions {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.sessions-list {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n position: relative;\n padding: 0.75rem;\n}\n\n.session-card {\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n padding: 1rem;\n margin-bottom: 0.75rem;\n cursor: pointer;\n transition: all 0.2s;\n}\n.session-card:hover {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n.session-card.selected {\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.session-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 0.75rem;\n}\n\n.session-info {\n flex: 1;\n}\n.session-info .session-title {\n margin: 0 0 0.5rem 0;\n font-size: 0.95rem;\n font-weight: 600;\n color: #1f2937;\n}\n\n.session-meta {\n display: flex;\n gap: 1rem;\n font-size: 0.75rem;\n color: #6b7280;\n}\n.session-meta .meta-item {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.session-badges {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n\n.badge {\n padding: 0.25rem 0.5rem;\n border-radius: 12px;\n font-size: 0.625rem;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n.badge-user {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n}\n.badge-migration {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n}\n.badge-type {\n background: rgba(255, 152, 0, 0.1);\n color: #ff9800;\n}\n\n.action-btn {\n padding: 0.375rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 0.875rem;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.2s;\n}\n.action-btn:hover {\n background: #f3f4f6;\n color: #374151;\n}\n.action-btn-danger:hover {\n color: #f44336;\n}\n\n.log-viewer-panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.log-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n position: relative;\n background: #1e1e1e;\n color: #d4d4d4;\n padding: 0;\n min-height: 300px;\n height: 100%;\n position: relative;\n}\n.log-content ::ng-deep .cm-editor {\n height: 100%;\n font-family: \"Consolas\", \"Monaco\", \"Courier New\", monospace;\n font-size: 0.875rem;\n}\n.log-content ::ng-deep .cm-scroller {\n font-family: inherit;\n}\n.log-content ::ng-deep .cm-content {\n background: #1e1e1e;\n color: #d4d4d4;\n}\n.log-content ::ng-deep .cm-gutters {\n background: #252526;\n color: #858585;\n border-right: 1px solid #464647;\n}\n.log-content ::ng-deep .cm-activeLineGutter {\n background: #2a2a2a;\n}\n.log-content ::ng-deep .cm-activeLine {\n background: rgba(255, 255, 255, 0.04);\n}\n\n.empty-state {\n text-align: center;\n padding: 4rem 2rem;\n}\n.empty-state .empty-icon {\n font-size: 4rem;\n color: #e5e7eb;\n margin-bottom: 1rem;\n}\n.empty-state .empty-icon.warning {\n color: #ffc107;\n}\n.empty-state .empty-text {\n font-size: 1.25rem;\n font-weight: 600;\n color: #374151;\n margin: 0 0 0.5rem 0;\n}\n.empty-state .empty-subtext {\n color: #6b7280;\n margin: 0;\n}\n\n.info-box {\n background: #f3f4f6;\n border-radius: 8px;\n padding: 1.5rem;\n margin-top: 2rem;\n text-align: left;\n max-width: 500px;\n margin-left: auto;\n margin-right: auto;\n}\n.info-box h4 {\n margin: 0 0 1rem 0;\n color: #1f2937;\n}\n.info-box ol {\n margin: 0;\n padding-left: 1.25rem;\n color: #374151;\n}\n.info-box ol li {\n margin-bottom: 0.5rem;\n}\n.info-box code {\n background: #e5e7eb;\n padding: 0.125rem 0.375rem;\n border-radius: 4px;\n font-size: 0.875rem;\n}\n\n.loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n min-height: 400px;\n}\n\n.loading-spinner {\n position: relative;\n width: 60px;\n height: 60px;\n margin-bottom: 1rem;\n}\n.loading-spinner .spinner-ring {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-radius: 50%;\n animation: spin 1.5s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n}\n.loading-spinner .spinner-ring:nth-child(1) {\n border-color: #2196f3 transparent transparent transparent;\n animation-delay: -0.45s;\n}\n.loading-spinner .spinner-ring:nth-child(2) {\n border-color: transparent #9c27b0 transparent transparent;\n animation-delay: -0.3s;\n}\n.loading-spinner .spinner-ring:nth-child(3) {\n border-color: transparent transparent #4caf50 transparent;\n animation-delay: -0.15s;\n}\n\n@keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n.loading-text {\n color: #6b7280;\n font-size: 0.95rem;\n}\n\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s ease;\n}\n\n.modal-dialog {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow: hidden;\n animation: slideUp 0.3s ease;\n}\n.modal-dialog.modal-large {\n max-width: 700px;\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid #e5e7eb;\n}\n.modal-header .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: #1f2937;\n margin: 0;\n}\n.modal-header .modal-close {\n padding: 0.5rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n}\n.modal-header .modal-close:hover {\n background: #f3f4f6;\n color: #374151;\n}\n\n.modal-body {\n padding: 1.5rem;\n max-height: 60vh;\n overflow-y: auto;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid #e5e7eb;\n background: #f9fafb;\n}\n\n.form-group {\n margin-bottom: 1.5rem;\n}\n\n.form-label {\n display: block;\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n margin-bottom: 0.5rem;\n}\n\n.form-input {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n transition: all 0.2s;\n}\n.form-input:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.form-select {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n background: white;\n cursor: pointer;\n transition: all 0.2s;\n}\n.form-select:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.form-hint {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.25rem;\n}\n\n.form-checkboxes {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.checkbox-label {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n color: #374151;\n font-size: 0.95rem;\n cursor: pointer;\n}\n.checkbox-label input[type=checkbox] {\n cursor: pointer;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n"] }]
|
|
944
|
-
}], () => [{ type: i1.SharedService }],
|
|
1209
|
+
args: [{ selector: 'mj-sql-logging', template: "<div class=\"sql-logging-container\">\n <!-- Action Buttons -->\n <div class=\"action-buttons\">\n <button class=\"btn-secondary\" (click)=\"loadActiveSessions()\" [disabled]=\"loading\">\n <i class=\"fa-solid fa-refresh\" [class.fa-spin]=\"loading\"></i>\n Refresh\n </button>\n @if (isOwner && configEnabled) {\n <button \n class=\"btn-primary\"\n [disabled]=\"loading || activeSessions.length >= (sqlLoggingConfig?.maxActiveSessions || 5)\"\n (click)=\"openStartSessionDialog()\"\n title=\"Start SQL logging session\"\n >\n <i class=\"fa-solid fa-play\"></i>\n Start New Session\n </button>\n }\n </div>\n\n <!-- Stats Cards -->\n @if (isOwner && configEnabled) {\n <div class=\"stats-grid\" style=\"display: flex\">\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-status\">\n <i class=\"fa-solid fa-power-off\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ configEnabled ? 'Enabled' : 'Disabled' }}</div>\n <div class=\"stat-label\">Status</div>\n </div>\n </div>\n \n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-active\">\n <i class=\"fa-solid fa-play-circle\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ activeSessions.length }}</div>\n <div class=\"stat-label\">Active Sessions</div>\n </div>\n </div>\n \n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-limit\">\n <i class=\"fa-solid fa-gauge-high\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ sqlLoggingConfig?.maxActiveSessions || 5 }}</div>\n <div class=\"stat-label\">Max Sessions</div>\n </div>\n </div>\n \n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-total\">\n <i class=\"fa-solid fa-database\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\">{{ getTotalStatementCount() }}</div>\n <div class=\"stat-label\">Total Statements</div>\n </div>\n </div>\n </div>\n }\n\n <!-- Loading State -->\n @if (loading && !activeSessions.length) {\n <div class=\"loading-container\">\n <div class=\"loading-spinner\">\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n <div class=\"spinner-ring\"></div>\n </div>\n <div class=\"loading-text\">Loading SQL logging configuration...</div>\n </div>\n }\n\n <!-- Content Area -->\n @if (!loading || activeSessions.length > 0) {\n <div class=\"content-area\">\n @if (!isOwner) {\n <!-- Not authorized -->\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-lock empty-icon\"></i>\n <p class=\"empty-text\">Access Denied</p>\n <p class=\"empty-subtext\">SQL logging requires Owner privileges. Please contact your system administrator for access.</p>\n <button \n class=\"btn-secondary\"\n (click)=\"refreshUserPermissions()\"\n style=\"margin-top: 1rem\"\n >\n <i class=\"fa-solid fa-sync\"></i>\n Refresh Permissions\n </button>\n </div>\n } @else if (!configEnabled) {\n <!-- Not enabled in config -->\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-exclamation-triangle empty-icon warning\"></i>\n <p class=\"empty-text\">SQL Logging Disabled</p>\n <p class=\"empty-subtext\">SQL logging is not enabled in the server configuration.</p>\n <div class=\"info-box\">\n <h4>To enable SQL logging:</h4>\n <ol>\n <li>Set <code>sqlLogging.enabled = true</code> in mj.config.cjs</li>\n <li>Restart the MJ API server</li>\n <li>Refresh this page</li>\n </ol>\n </div>\n </div>\n } @else if (activeSessions.length === 0) {\n <!-- No active sessions -->\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-file-code empty-icon\"></i>\n <p class=\"empty-text\">No Active Sessions</p>\n <p class=\"empty-subtext\">Start a new SQL logging session to begin capturing SQL statements.</p>\n <button \n class=\"btn-primary\"\n (click)=\"openStartSessionDialog()\"\n style=\"margin-top: 1rem\"\n >\n <i class=\"fa-solid fa-play\"></i>\n Start New Session\n </button>\n </div>\n } @else {\n <!-- Sessions layout -->\n <div class=\"sessions-layout\">\n <!-- Sessions panel -->\n <div class=\"sessions-panel\">\n <div class=\"panel-header\">\n <h3 class=\"panel-title\">Active Sessions</h3>\n @if (activeSessions.length > 0) {\n <button\n class=\"btn-danger btn-small\"\n (click)=\"openStopAllSessionsConfirm()\"\n [disabled]=\"loading\"\n title=\"Stop all sessions\"\n >\n <i class=\"fa-solid fa-stop\"></i>\n Stop All\n </button>\n }\n </div>\n <div class=\"sessions-list\">\n @for (session of activeSessions; track session.id) {\n <div \n class=\"session-card\" \n [class.selected]=\"selectedSession?.id === session.id\"\n (click)=\"selectSession(session)\"\n >\n <div class=\"session-header\">\n <div class=\"session-info\">\n <h4 class=\"session-title\">{{ session.sessionName }}</h4>\n <div class=\"session-meta\">\n <span class=\"meta-item\">\n <i class=\"fa-solid fa-clock\"></i>\n {{ getSessionDuration(session.startTime) }}\n </span>\n <span class=\"meta-item\">\n <i class=\"fa-solid fa-database\"></i>\n {{ session.statementCount }} statements\n </span>\n </div>\n </div>\n <button\n class=\"action-btn action-btn-danger\"\n (click)=\"openStopSessionConfirm(session, $event)\"\n title=\"Stop session\"\n >\n <i class=\"fa-solid fa-stop\"></i>\n </button>\n </div>\n <div class=\"session-badges\">\n @if (session.filterByUserId) {\n <span class=\"badge badge-user\">\n <i class=\"fa-solid fa-user\"></i>\n User Filtered\n </span>\n }\n @if (session.options?.formatAsMigration) {\n <span class=\"badge badge-migration\">\n <i class=\"fa-solid fa-code-branch\"></i>\n Migration\n </span>\n }\n <span class=\"badge badge-type\">\n {{ session.options?.statementTypes || 'both' }}\n </span>\n </div>\n </div>\n }\n </div>\n </div>\n \n <!-- Log viewer panel -->\n <div class=\"log-viewer-panel\" [class.expanded]=\"isLogViewerExpanded\">\n @if (selectedSession) {\n <div class=\"panel-header\">\n <h3 class=\"panel-title\">{{ selectedSession.sessionName }}</h3>\n <div class=\"panel-actions\">\n <label class=\"checkbox-label\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"autoRefresh\"\n />\n Auto-refresh\n </label>\n <button\n class=\"action-btn\"\n (click)=\"loadSessionLog(selectedSession)\"\n title=\"Refresh log\"\n >\n <i class=\"fa-solid fa-sync\" [class.fa-spin]=\"loading\"></i>\n </button>\n <button\n class=\"action-btn\"\n (click)=\"toggleLogViewerExpand()\"\n [title]=\"isLogViewerExpanded ? 'Collapse' : 'Expand'\"\n >\n <i class=\"fa-solid\" [class.fa-expand]=\"!isLogViewerExpanded\" [class.fa-compress]=\"isLogViewerExpanded\"></i>\n </button>\n </div>\n </div>\n <div class=\"log-content\">\n <mj-code-editor\n [value]=\"logContent\"\n [readonly]=\"true\"\n [disabled]=\"true\"\n [language]=\"'sql'\"\n [setup]=\"'basic'\"\n [lineWrapping]=\"true\"\n [highlightWhitespace]=\"false\"\n style=\"height: 100%;\"\n ></mj-code-editor>\n </div>\n } @else {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-arrow-left empty-icon\"></i>\n <p class=\"empty-text\">Select a Session</p>\n <p class=\"empty-subtext\">Choose a session from the list to view its SQL log.</p>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Start Session Dialog -->\n @if (showStartSessionDialog) {\n <div class=\"modal-backdrop\" (click)=\"showStartSessionDialog = false\">\n <div class=\"modal-dialog modal-large\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3 class=\"modal-title\">\n <i class=\"fa-solid fa-play\"></i>\n Start SQL Logging Session\n </h3>\n <button class=\"modal-close\" (click)=\"showStartSessionDialog = false\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n <div class=\"modal-body\">\n <div class=\"form-group\">\n <label class=\"form-label\">Session Name</label>\n <input \n type=\"text\"\n class=\"form-input\" \n [(ngModel)]=\"newSessionOptions.sessionName\"\n placeholder=\"Enter a descriptive name for this session\"\n />\n </div>\n \n <div class=\"form-group\">\n <label class=\"form-label\">File Name</label>\n <input \n type=\"text\"\n class=\"form-input\" \n [(ngModel)]=\"newSessionOptions.fileName\"\n placeholder=\"sql-log-2024-01-01.sql\"\n />\n <div class=\"form-hint\">The SQL log will be saved to this file</div>\n </div>\n \n <div class=\"form-group\">\n <label class=\"form-label\">Statement Types</label>\n <select\n class=\"form-select\"\n [(ngModel)]=\"newSessionOptions.statementTypes\"\n >\n @for (option of statementTypeOptions; track option.value) {\n <option [value]=\"option.value\">{{ option.text }}</option>\n }\n </select>\n </div>\n \n <div class=\"form-checkboxes\">\n <label class=\"checkbox-label\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"newSessionOptions.filterToCurrentUser\"\n />\n Filter to my SQL statements only\n </label>\n\n <label class=\"checkbox-label\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"newSessionOptions.formatAsMigration\"\n />\n Format as migration file\n </label>\n\n <label class=\"checkbox-label\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"newSessionOptions.prettyPrint\"\n />\n Pretty print SQL statements\n </label>\n </div>\n\n <!-- SQL Pattern Filtering Section -->\n <div class=\"form-section\">\n <h4 class=\"form-section-title\">\n <i class=\"fa-solid fa-filter\"></i>\n SQL Pattern Filtering\n </h4>\n\n <div class=\"form-group\">\n <label class=\"form-label\">Filter Mode</label>\n <select\n class=\"form-select\"\n [(ngModel)]=\"newSessionOptions.filterType\"\n >\n @for (option of filterTypeOptions; track option.value) {\n <option [value]=\"option.value\">{{ option.text }}</option>\n }\n </select>\n <div class=\"form-hint\">\n Exclude: Skip SQL matching any pattern. Include: Only log SQL matching a pattern.\n </div>\n </div>\n\n <div class=\"form-group\">\n <label class=\"form-label\">Filter Patterns (one per line or comma-separated)</label>\n <textarea\n class=\"form-textarea\"\n [(ngModel)]=\"newSessionOptions.filterPatterns\"\n rows=\"4\"\n placeholder=\"Examples: *AIPrompt* /spCreate.*Run/i SELECT * FROM vwMetadata\"\n ></textarea>\n <div class=\"form-hint\">\n Supports wildcards (*) and regex (/pattern/flags).\n Example: *spCreate* matches any SP starting with spCreate.\n </div>\n </div>\n </div>\n\n <!-- Advanced Options Section -->\n <div class=\"form-section\">\n <h4 class=\"form-section-title\">\n <i class=\"fa-solid fa-cog\"></i>\n Advanced Options\n </h4>\n\n @if (newSessionOptions.formatAsMigration) {\n <div class=\"form-group\">\n <label class=\"form-label\">Default Schema Name</label>\n <input\n type=\"text\"\n class=\"form-input\"\n [(ngModel)]=\"newSessionOptions.defaultSchemaName\"\n placeholder=\"__mj\"\n />\n <div class=\"form-hint\">\n Schema name to replace with ${flyway:defaultSchema} placeholder.\n </div>\n </div>\n }\n\n <div class=\"form-checkboxes\">\n <label class=\"checkbox-label\">\n <input\n type=\"checkbox\"\n [(ngModel)]=\"newSessionOptions.verboseOutput\"\n />\n Verbose Debug Output\n </label>\n <div class=\"form-hint\" style=\"margin-left: 1.5rem;\">\n Log detailed filter decisions to server console (for debugging).\n </div>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button class=\"btn-primary\" (click)=\"startNewSession()\" [disabled]=\"loading\">\n <i class=\"fa-solid fa-play\"></i>\n Start Session\n </button>\n <button class=\"btn-secondary\" (click)=\"showStartSessionDialog = false\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n\n <!-- Stop Session Confirmation Dialog -->\n @if (showStopConfirmDialog) {\n <div class=\"modal-backdrop\" (click)=\"cancelStopConfirm()\">\n <div class=\"confirm-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"confirm-dialog-icon\">\n <i class=\"fa-solid fa-exclamation-triangle\"></i>\n </div>\n <div class=\"confirm-dialog-content\">\n <h3 class=\"confirm-dialog-title\">\n @if (isStoppingAll) {\n Stop All Sessions?\n } @else {\n Stop Session?\n }\n </h3>\n <p class=\"confirm-dialog-message\">\n @if (isStoppingAll) {\n Are you sure you want to stop <strong>all {{ activeSessions.length }} active</strong> SQL logging sessions? This action cannot be undone.\n } @else if (sessionToStop) {\n Are you sure you want to stop the session <strong>\"{{ sessionToStop.sessionName }}\"</strong>?\n <span class=\"confirm-dialog-details\">\n This session has captured {{ sessionToStop.statementCount }} SQL statements.\n </span>\n }\n </p>\n </div>\n <div class=\"confirm-dialog-actions\">\n <button\n class=\"btn-danger\"\n (click)=\"confirmStopSession()\"\n [disabled]=\"loading\"\n >\n @if (loading) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n Stopping...\n } @else {\n <i class=\"fa-solid fa-stop\"></i>\n @if (isStoppingAll) {\n Stop All Sessions\n } @else {\n Stop Session\n }\n }\n </button>\n <button class=\"btn-secondary\" (click)=\"cancelStopConfirm()\" [disabled]=\"loading\">\n Cancel\n </button>\n </div>\n </div>\n </div>\n }\n</div>", styles: ["@keyframes shimmer {\n 0% {\n background-position: -200% 0;\n }\n 100% {\n background-position: 200% 0;\n }\n}\n.sql-logging-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n max-height: 100%;\n overflow: hidden;\n position: relative;\n max-width: 1400px;\n margin: 0 auto;\n padding: 2rem;\n}\n\n.action-buttons {\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n margin-bottom: 1.5rem;\n}\n@media (max-width: 768px) {\n .action-buttons {\n justify-content: center;\n flex-wrap: wrap;\n }\n}\n\n.btn-primary {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n padding: 0.625rem 1.25rem;\n font-size: 0.95rem;\n font-weight: 500;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n background-color: #2196f3;\n color: white;\n}\n.btn-primary:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-primary i {\n font-size: 0.875rem;\n}\n.btn-primary:hover {\n background-color: #1976d2;\n transform: translateY(-1px);\n box-shadow: 0 4px 12px rgba(33, 150, 243, 0.3);\n}\n\n.btn-secondary {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n padding: 0.625rem 1.25rem;\n font-size: 0.95rem;\n font-weight: 500;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n background-color: #ffffff;\n color: #374151;\n border: 1px solid #e5e7eb;\n}\n.btn-secondary:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-secondary i {\n font-size: 0.875rem;\n}\n.btn-secondary:hover {\n background-color: #f9fafb;\n border-color: #2196f3;\n color: #2196f3;\n}\n\n.btn-danger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.375rem;\n padding: 0.625rem 1.25rem;\n font-size: 0.95rem;\n font-weight: 500;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n transition: all 0.2s;\n white-space: nowrap;\n background-color: #f44336;\n color: white;\n}\n.btn-danger:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.btn-danger i {\n font-size: 0.875rem;\n}\n.btn-danger:hover {\n background-color: #d32f2f;\n}\n.btn-danger.btn-small {\n padding: 0.375rem 0.75rem;\n font-size: 0.875rem;\n}\n\n.stats-grid {\n display: grid !important;\n grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));\n gap: 1.5rem;\n margin-bottom: 2rem;\n width: 100%;\n}\n@media (max-width: 768px) {\n .stats-grid {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n }\n}\n\n.stat-card {\n background: white;\n border-radius: 12px;\n padding: 1.5rem;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n display: flex;\n margin-right: 10px;\n align-items: center;\n gap: 1rem;\n transition: all 0.3s ease;\n min-width: 0;\n}\n.stat-card:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n}\n\n.stat-icon {\n width: 60px;\n height: 60px;\n border-radius: 12px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.5rem;\n}\n.stat-icon-status {\n background: rgba(76, 175, 80, 0.1);\n color: #4caf50;\n}\n.stat-icon-active {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n}\n.stat-icon-limit {\n background: rgba(255, 152, 0, 0.1);\n color: #ff9800;\n}\n.stat-icon-total {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n}\n\n.stat-content {\n flex: 1;\n}\n.stat-content .stat-value {\n font-size: 2rem;\n font-weight: 700;\n color: #1f2937;\n line-height: 1;\n}\n.stat-content .stat-label {\n color: #6b7280;\n font-size: 0.875rem;\n margin-top: 0.25rem;\n}\n\n.content-area {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n position: relative;\n background: white;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n padding: 1.5rem;\n min-height: 400px;\n}\n\n.sessions-layout {\n display: flex;\n gap: 1.5rem;\n height: calc(100vh - 450px);\n min-height: 400px;\n max-height: 600px;\n}\n@media (max-width: 1024px) {\n .sessions-layout {\n flex-direction: column;\n height: auto;\n max-height: none;\n }\n}\n\n.sessions-panel {\n flex: 0 0 400px;\n display: flex;\n flex-direction: column;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n overflow: hidden;\n}\n@media (max-width: 1024px) {\n .sessions-panel {\n flex: 1;\n max-height: 400px;\n }\n}\n\n.panel-header {\n padding: 1rem;\n background: #f9fafb;\n border-bottom: 1px solid #e5e7eb;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n.panel-header .panel-title {\n margin: 0;\n font-size: 1.125rem;\n font-weight: 600;\n color: #1f2937;\n}\n\n.panel-actions {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.sessions-list {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n position: relative;\n padding: 0.75rem;\n}\n\n.session-card {\n background: white;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n padding: 1rem;\n margin-bottom: 0.75rem;\n cursor: pointer;\n transition: all 0.2s;\n}\n.session-card:hover {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n.session-card.selected {\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.session-header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 0.75rem;\n}\n\n.session-info {\n flex: 1;\n}\n.session-info .session-title {\n margin: 0 0 0.5rem 0;\n font-size: 0.95rem;\n font-weight: 600;\n color: #1f2937;\n}\n\n.session-meta {\n display: flex;\n gap: 1rem;\n font-size: 0.75rem;\n color: #6b7280;\n}\n.session-meta .meta-item {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n\n.session-badges {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n\n.badge {\n padding: 0.25rem 0.5rem;\n border-radius: 12px;\n font-size: 0.625rem;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 0.25rem;\n}\n.badge-user {\n background: rgba(33, 150, 243, 0.1);\n color: #2196f3;\n}\n.badge-migration {\n background: rgba(156, 39, 176, 0.1);\n color: #9c27b0;\n}\n.badge-type {\n background: rgba(255, 152, 0, 0.1);\n color: #ff9800;\n}\n\n.action-btn {\n padding: 0.375rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 0.875rem;\n border-radius: 4px;\n cursor: pointer;\n transition: all 0.2s;\n}\n.action-btn:hover {\n background: #f3f4f6;\n color: #374151;\n}\n.action-btn-danger:hover {\n color: #f44336;\n}\n\n.log-viewer-panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.log-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n min-height: 0;\n position: relative;\n background: #1e1e1e;\n color: #d4d4d4;\n padding: 0;\n min-height: 300px;\n height: 100%;\n position: relative;\n}\n.log-content ::ng-deep .cm-editor {\n height: 100%;\n font-family: \"Consolas\", \"Monaco\", \"Courier New\", monospace;\n font-size: 0.875rem;\n}\n.log-content ::ng-deep .cm-scroller {\n font-family: inherit;\n}\n.log-content ::ng-deep .cm-content {\n background: #1e1e1e;\n color: #d4d4d4;\n}\n.log-content ::ng-deep .cm-gutters {\n background: #252526;\n color: #858585;\n border-right: 1px solid #464647;\n}\n.log-content ::ng-deep .cm-activeLineGutter {\n background: #2a2a2a;\n}\n.log-content ::ng-deep .cm-activeLine {\n background: rgba(255, 255, 255, 0.04);\n}\n\n.empty-state {\n text-align: center;\n padding: 4rem 2rem;\n}\n.empty-state .empty-icon {\n font-size: 4rem;\n color: #e5e7eb;\n margin-bottom: 1rem;\n}\n.empty-state .empty-icon.warning {\n color: #ffc107;\n}\n.empty-state .empty-text {\n font-size: 1.25rem;\n font-weight: 600;\n color: #374151;\n margin: 0 0 0.5rem 0;\n}\n.empty-state .empty-subtext {\n color: #6b7280;\n margin: 0;\n}\n\n.info-box {\n background: #f3f4f6;\n border-radius: 8px;\n padding: 1.5rem;\n margin-top: 2rem;\n text-align: left;\n max-width: 500px;\n margin-left: auto;\n margin-right: auto;\n}\n.info-box h4 {\n margin: 0 0 1rem 0;\n color: #1f2937;\n}\n.info-box ol {\n margin: 0;\n padding-left: 1.25rem;\n color: #374151;\n}\n.info-box ol li {\n margin-bottom: 0.5rem;\n}\n.info-box code {\n background: #e5e7eb;\n padding: 0.125rem 0.375rem;\n border-radius: 4px;\n font-size: 0.875rem;\n}\n\n.loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n min-height: 400px;\n}\n\n.loading-spinner {\n position: relative;\n width: 60px;\n height: 60px;\n margin-bottom: 1rem;\n}\n.loading-spinner .spinner-ring {\n position: absolute;\n width: 100%;\n height: 100%;\n border: 3px solid transparent;\n border-radius: 50%;\n animation: spin 1.5s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n}\n.loading-spinner .spinner-ring:nth-child(1) {\n border-color: #2196f3 transparent transparent transparent;\n animation-delay: -0.45s;\n}\n.loading-spinner .spinner-ring:nth-child(2) {\n border-color: transparent #9c27b0 transparent transparent;\n animation-delay: -0.3s;\n}\n.loading-spinner .spinner-ring:nth-child(3) {\n border-color: transparent transparent #4caf50 transparent;\n animation-delay: -0.15s;\n}\n\n@keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n.loading-text {\n color: #6b7280;\n font-size: 0.95rem;\n}\n\n.modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s ease;\n}\n\n.modal-dialog {\n background: white;\n border-radius: 12px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n max-width: 500px;\n width: 90%;\n max-height: 90vh;\n overflow: hidden;\n animation: slideUp 0.3s ease;\n}\n.modal-dialog.modal-large {\n max-width: 700px;\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.5rem;\n border-bottom: 1px solid #e5e7eb;\n}\n.modal-header .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: #1f2937;\n margin: 0;\n}\n.modal-header .modal-close {\n padding: 0.5rem;\n border: none;\n background: transparent;\n color: #6b7280;\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: 6px;\n transition: all 0.2s;\n}\n.modal-header .modal-close:hover {\n background: #f3f4f6;\n color: #374151;\n}\n\n.modal-body {\n padding: 1.5rem;\n max-height: 60vh;\n overflow-y: auto;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid #e5e7eb;\n background: #f9fafb;\n}\n\n.form-group {\n margin-bottom: 1.5rem;\n}\n\n.form-label {\n display: block;\n font-size: 0.875rem;\n font-weight: 500;\n color: #374151;\n margin-bottom: 0.5rem;\n}\n\n.form-input {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n transition: all 0.2s;\n}\n.form-input:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.form-select {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n background: white;\n cursor: pointer;\n transition: all 0.2s;\n}\n.form-select:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.form-hint {\n font-size: 0.75rem;\n color: #6b7280;\n margin-top: 0.25rem;\n}\n\n.form-checkboxes {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.checkbox-label {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n color: #374151;\n font-size: 0.95rem;\n cursor: pointer;\n}\n.checkbox-label input[type=checkbox] {\n cursor: pointer;\n}\n\n/* Form Section Styles */\n.form-section {\n margin-top: 1.5rem;\n padding: 1.25rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n background: #f9fafb;\n}\n\n.form-section-title {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin: 0 0 1rem 0;\n font-size: 1rem;\n font-weight: 600;\n color: #374151;\n}\n\n.form-section-title i {\n color: #6b7280;\n}\n\n.form-textarea {\n width: 100%;\n padding: 0.75rem 1rem;\n border: 1px solid #e5e7eb;\n border-radius: 8px;\n font-size: 0.95rem;\n font-family: \"Consolas\", \"Monaco\", \"Courier New\", monospace;\n resize: vertical;\n transition: all 0.2s;\n}\n\n.form-textarea:focus {\n outline: none;\n border-color: #2196f3;\n box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);\n}\n\n.form-textarea::placeholder {\n color: #9ca3af;\n font-style: italic;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n@keyframes slideUp {\n from {\n transform: translateY(20px);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n/* Expanded Log Viewer Styles */\n.log-viewer-panel.expanded {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 999;\n border-radius: 0;\n margin: 0;\n max-height: none;\n height: 100vh;\n animation: expandIn 0.3s ease;\n}\n\n.log-viewer-panel.expanded .panel-header {\n border-radius: 0;\n}\n\n.log-viewer-panel.expanded .log-content {\n max-height: calc(100vh - 60px);\n min-height: calc(100vh - 60px);\n}\n\n@keyframes expandIn {\n from {\n transform: scale(0.95);\n opacity: 0;\n }\n to {\n transform: scale(1);\n opacity: 1;\n }\n}\n\n/* Confirmation Dialog Styles */\n.confirm-dialog {\n background: white;\n border-radius: 16px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n max-width: 420px;\n width: 90%;\n padding: 2rem;\n text-align: center;\n animation: dialogBounce 0.3s ease;\n}\n\n@keyframes dialogBounce {\n 0% {\n transform: scale(0.9) translateY(10px);\n opacity: 0;\n }\n 50% {\n transform: scale(1.02) translateY(-5px);\n }\n 100% {\n transform: scale(1) translateY(0);\n opacity: 1;\n }\n}\n\n.confirm-dialog-icon {\n width: 64px;\n height: 64px;\n border-radius: 50%;\n background: linear-gradient(135deg, #fff3e0 0%, #ffe0b2 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1.5rem;\n box-shadow: 0 4px 12px rgba(255, 152, 0, 0.2);\n}\n\n.confirm-dialog-icon i {\n font-size: 1.75rem;\n color: #f57c00;\n}\n\n.confirm-dialog-content {\n margin-bottom: 1.5rem;\n}\n\n.confirm-dialog-title {\n margin: 0 0 0.75rem 0;\n font-size: 1.375rem;\n font-weight: 700;\n color: #1f2937;\n}\n\n.confirm-dialog-message {\n margin: 0;\n font-size: 0.95rem;\n color: #4b5563;\n line-height: 1.6;\n}\n\n.confirm-dialog-message strong {\n color: #1f2937;\n font-weight: 600;\n}\n\n.confirm-dialog-details {\n display: block;\n margin-top: 0.75rem;\n padding: 0.75rem;\n background: #f3f4f6;\n border-radius: 8px;\n font-size: 0.875rem;\n color: #6b7280;\n}\n\n.confirm-dialog-actions {\n display: flex;\n gap: 0.75rem;\n justify-content: center;\n}\n\n.confirm-dialog-actions .btn-danger {\n min-width: 140px;\n}\n\n.confirm-dialog-actions .btn-secondary {\n min-width: 100px;\n}\n"] }]
|
|
1210
|
+
}], () => [{ type: i1.SharedService }], { onEscapeKey: [{
|
|
1211
|
+
type: HostListener,
|
|
1212
|
+
args: ['document:keydown.escape']
|
|
1213
|
+
}] }); })();
|
|
945
1214
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SqlLoggingComponent, { className: "SqlLoggingComponent", filePath: "src/lib/sql-logging/sql-logging.component.ts", lineNumber: 65 }); })();
|
|
946
1215
|
//# sourceMappingURL=sql-logging.component.js.map
|