@memberjunction/ng-explorer-settings 5.38.0 → 5.39.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.
@@ -23,8 +23,9 @@ function SqlLoggingComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
23
23
  i0.ɵɵelementStart(0, "button", 9);
24
24
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.openStartSessionDialog()); });
25
25
  i0.ɵɵelement(1, "i", 10);
26
- i0.ɵɵtext(2, " Start New Session ");
27
- i0.ɵɵelementEnd();
26
+ i0.ɵɵelementStart(2, "span", 11);
27
+ i0.ɵɵtext(3, "Start New Session");
28
+ i0.ɵɵelementEnd()();
28
29
  } if (rf & 2) {
29
30
  const ctx_r1 = i0.ɵɵnextContext();
30
31
  i0.ɵɵproperty("disabled", ctx_r1.loading || ctx_r1.activeSessions.length >= ((ctx_r1.sqlLoggingConfig == null ? null : ctx_r1.sqlLoggingConfig.maxActiveSessions) || 5));
@@ -32,53 +33,53 @@ function SqlLoggingComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
32
33
  } }
33
34
  function SqlLoggingComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
34
35
  const _r3 = i0.ɵɵgetCurrentView();
35
- i0.ɵɵelementStart(0, "div", 4)(1, "button", 11);
36
+ i0.ɵɵelementStart(0, "div", 4)(1, "button", 12);
36
37
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_5_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showStats = !ctx_r1.showStats); });
37
- i0.ɵɵelementStart(2, "div", 12)(3, "div", 13);
38
- i0.ɵɵelement(4, "i", 14);
38
+ i0.ɵɵelementStart(2, "div", 13)(3, "div", 14);
39
+ i0.ɵɵelement(4, "i", 15);
39
40
  i0.ɵɵelementEnd();
40
- i0.ɵɵelementStart(5, "div", 15)(6, "h3", 16);
41
+ i0.ɵɵelementStart(5, "div", 16)(6, "h3", 17);
41
42
  i0.ɵɵtext(7, "Statistics");
42
43
  i0.ɵɵelementEnd();
43
- i0.ɵɵelementStart(8, "p", 17);
44
+ i0.ɵɵelementStart(8, "p", 18);
44
45
  i0.ɵɵtext(9, "View session statistics and metrics");
45
46
  i0.ɵɵelementEnd()()();
46
- i0.ɵɵelement(10, "i", 18);
47
+ i0.ɵɵelement(10, "i", 19);
47
48
  i0.ɵɵelementEnd();
48
- i0.ɵɵelementStart(11, "div", 19)(12, "div", 20)(13, "div", 21);
49
- i0.ɵɵelement(14, "i", 22);
49
+ i0.ɵɵelementStart(11, "div", 20)(12, "div", 21)(13, "div", 22);
50
+ i0.ɵɵelement(14, "i", 23);
50
51
  i0.ɵɵelementEnd();
51
- i0.ɵɵelementStart(15, "div", 23)(16, "div", 24);
52
+ i0.ɵɵelementStart(15, "div", 24)(16, "div", 25);
52
53
  i0.ɵɵtext(17);
53
54
  i0.ɵɵelementEnd();
54
- i0.ɵɵelementStart(18, "div", 25);
55
+ i0.ɵɵelementStart(18, "div", 26);
55
56
  i0.ɵɵtext(19, "Status");
56
57
  i0.ɵɵelementEnd()()();
57
- i0.ɵɵelementStart(20, "div", 20)(21, "div", 26);
58
- i0.ɵɵelement(22, "i", 27);
58
+ i0.ɵɵelementStart(20, "div", 21)(21, "div", 27);
59
+ i0.ɵɵelement(22, "i", 28);
59
60
  i0.ɵɵelementEnd();
60
- i0.ɵɵelementStart(23, "div", 23)(24, "div", 24);
61
+ i0.ɵɵelementStart(23, "div", 24)(24, "div", 25);
61
62
  i0.ɵɵtext(25);
62
63
  i0.ɵɵelementEnd();
63
- i0.ɵɵelementStart(26, "div", 25);
64
+ i0.ɵɵelementStart(26, "div", 26);
64
65
  i0.ɵɵtext(27, "Active Sessions");
65
66
  i0.ɵɵelementEnd()()();
66
- i0.ɵɵelementStart(28, "div", 20)(29, "div", 28);
67
- i0.ɵɵelement(30, "i", 29);
67
+ i0.ɵɵelementStart(28, "div", 21)(29, "div", 29);
68
+ i0.ɵɵelement(30, "i", 30);
68
69
  i0.ɵɵelementEnd();
69
- i0.ɵɵelementStart(31, "div", 23)(32, "div", 24);
70
+ i0.ɵɵelementStart(31, "div", 24)(32, "div", 25);
70
71
  i0.ɵɵtext(33);
71
72
  i0.ɵɵelementEnd();
72
- i0.ɵɵelementStart(34, "div", 25);
73
+ i0.ɵɵelementStart(34, "div", 26);
73
74
  i0.ɵɵtext(35, "Max Sessions");
74
75
  i0.ɵɵelementEnd()()();
75
- i0.ɵɵelementStart(36, "div", 20)(37, "div", 30);
76
- i0.ɵɵelement(38, "i", 31);
76
+ i0.ɵɵelementStart(36, "div", 21)(37, "div", 31);
77
+ i0.ɵɵelement(38, "i", 32);
77
78
  i0.ɵɵelementEnd();
78
- i0.ɵɵelementStart(39, "div", 23)(40, "div", 24);
79
+ i0.ɵɵelementStart(39, "div", 24)(40, "div", 25);
79
80
  i0.ɵɵtext(41);
80
81
  i0.ɵɵelementEnd();
81
- i0.ɵɵelementStart(42, "div", 25);
82
+ i0.ɵɵelementStart(42, "div", 26);
82
83
  i0.ɵɵtext(43, "Total Statements");
83
84
  i0.ɵɵelementEnd()()()()();
84
85
  } if (rf & 2) {
@@ -107,35 +108,35 @@ function SqlLoggingComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
107
108
  } }
108
109
  function SqlLoggingComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
109
110
  i0.ɵɵelementStart(0, "div", 5);
110
- i0.ɵɵelement(1, "mj-loading", 32);
111
+ i0.ɵɵelement(1, "mj-loading", 33);
111
112
  i0.ɵɵelementEnd();
112
113
  } }
113
114
  function SqlLoggingComponent_Conditional_7_Conditional_1_Template(rf, ctx) { if (rf & 1) {
114
115
  const _r4 = i0.ɵɵgetCurrentView();
115
- i0.ɵɵelementStart(0, "div", 33);
116
- i0.ɵɵelement(1, "i", 36);
117
- i0.ɵɵelementStart(2, "p", 37);
116
+ i0.ɵɵelementStart(0, "div", 34);
117
+ i0.ɵɵelement(1, "i", 37);
118
+ i0.ɵɵelementStart(2, "p", 38);
118
119
  i0.ɵɵtext(3, "Access Denied");
119
120
  i0.ɵɵelementEnd();
120
- i0.ɵɵelementStart(4, "p", 38);
121
+ i0.ɵɵelementStart(4, "p", 39);
121
122
  i0.ɵɵtext(5, "SQL logging requires Owner privileges. Please contact your system administrator for access.");
122
123
  i0.ɵɵelementEnd();
123
- i0.ɵɵelementStart(6, "button", 39);
124
+ i0.ɵɵelementStart(6, "button", 40);
124
125
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_7_Conditional_1_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.refreshUserPermissions()); });
125
- i0.ɵɵelement(7, "i", 40);
126
+ i0.ɵɵelement(7, "i", 41);
126
127
  i0.ɵɵtext(8, " Refresh Permissions ");
127
128
  i0.ɵɵelementEnd()();
128
129
  } }
129
130
  function SqlLoggingComponent_Conditional_7_Conditional_2_Template(rf, ctx) { if (rf & 1) {
130
- i0.ɵɵelementStart(0, "div", 33);
131
- i0.ɵɵelement(1, "i", 41);
132
- i0.ɵɵelementStart(2, "p", 37);
131
+ i0.ɵɵelementStart(0, "div", 34);
132
+ i0.ɵɵelement(1, "i", 42);
133
+ i0.ɵɵelementStart(2, "p", 38);
133
134
  i0.ɵɵtext(3, "SQL Logging Disabled");
134
135
  i0.ɵɵelementEnd();
135
- i0.ɵɵelementStart(4, "p", 38);
136
+ i0.ɵɵelementStart(4, "p", 39);
136
137
  i0.ɵɵtext(5, "SQL logging is not enabled in the server configuration.");
137
138
  i0.ɵɵelementEnd();
138
- i0.ɵɵelementStart(6, "div", 42)(7, "h4");
139
+ i0.ɵɵelementStart(6, "div", 43)(7, "h4");
139
140
  i0.ɵɵtext(8, "To enable SQL logging:");
140
141
  i0.ɵɵelementEnd();
141
142
  i0.ɵɵelementStart(9, "ol")(10, "li");
@@ -154,15 +155,15 @@ function SqlLoggingComponent_Conditional_7_Conditional_2_Template(rf, ctx) { if
154
155
  } }
155
156
  function SqlLoggingComponent_Conditional_7_Conditional_3_Template(rf, ctx) { if (rf & 1) {
156
157
  const _r5 = i0.ɵɵgetCurrentView();
157
- i0.ɵɵelementStart(0, "div", 34);
158
- i0.ɵɵelement(1, "i", 43);
159
- i0.ɵɵelementStart(2, "p", 37);
158
+ i0.ɵɵelementStart(0, "div", 35);
159
+ i0.ɵɵelement(1, "i", 44);
160
+ i0.ɵɵelementStart(2, "p", 38);
160
161
  i0.ɵɵtext(3, "No Active Sessions");
161
162
  i0.ɵɵelementEnd();
162
- i0.ɵɵelementStart(4, "p", 38);
163
+ i0.ɵɵelementStart(4, "p", 39);
163
164
  i0.ɵɵtext(5, "Start a new SQL logging session to begin capturing SQL statements.");
164
165
  i0.ɵɵelementEnd();
165
- i0.ɵɵelementStart(6, "button", 44);
166
+ i0.ɵɵelementStart(6, "button", 45);
166
167
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_7_Conditional_3_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.openStartSessionDialog()); });
167
168
  i0.ɵɵelement(7, "i", 10);
168
169
  i0.ɵɵtext(8, " Start New Session ");
@@ -170,9 +171,9 @@ function SqlLoggingComponent_Conditional_7_Conditional_3_Template(rf, ctx) { if
170
171
  } }
171
172
  function SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_5_Template(rf, ctx) { if (rf & 1) {
172
173
  const _r6 = i0.ɵɵgetCurrentView();
173
- i0.ɵɵelementStart(0, "button", 52);
174
+ i0.ɵɵelementStart(0, "button", 53);
174
175
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.openStopAllSessionsConfirm()); });
175
- i0.ɵɵelement(1, "i", 53);
176
+ i0.ɵɵelement(1, "i", 54);
176
177
  i0.ɵɵtext(2, " Stop All ");
177
178
  i0.ɵɵelementEnd();
178
179
  } if (rf & 2) {
@@ -180,40 +181,40 @@ function SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_5_Template(
180
181
  i0.ɵɵproperty("disabled", ctx_r1.loading);
181
182
  } }
182
183
  function SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Conditional_15_Template(rf, ctx) { if (rf & 1) {
183
- i0.ɵɵelementStart(0, "span", 63);
184
- i0.ɵɵelement(1, "i", 66);
184
+ i0.ɵɵelementStart(0, "span", 64);
185
+ i0.ɵɵelement(1, "i", 67);
185
186
  i0.ɵɵtext(2, " User Filtered ");
186
187
  i0.ɵɵelementEnd();
187
188
  } }
188
189
  function SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Conditional_16_Template(rf, ctx) { if (rf & 1) {
189
- i0.ɵɵelementStart(0, "span", 64);
190
- i0.ɵɵelement(1, "i", 67);
190
+ i0.ɵɵelementStart(0, "span", 65);
191
+ i0.ɵɵelement(1, "i", 68);
191
192
  i0.ɵɵtext(2, " Migration ");
192
193
  i0.ɵɵelementEnd();
193
194
  } }
194
195
  function SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Template(rf, ctx) { if (rf & 1) {
195
196
  const _r7 = i0.ɵɵgetCurrentView();
196
- i0.ɵɵelementStart(0, "div", 54);
197
+ i0.ɵɵelementStart(0, "div", 55);
197
198
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Template_div_click_0_listener() { const session_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectSession(session_r8)); })("keydown.enter", function SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Template_div_keydown_enter_0_listener() { const session_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.selectSession(session_r8)); })("keydown.space", function SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Template_div_keydown_space_0_listener($event) { const session_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); ctx_r1.selectSession(session_r8); return i0.ɵɵresetView($event.preventDefault()); });
198
- i0.ɵɵelementStart(1, "div", 55)(2, "div", 56)(3, "h4", 57);
199
+ i0.ɵɵelementStart(1, "div", 56)(2, "div", 57)(3, "h4", 58);
199
200
  i0.ɵɵtext(4);
200
201
  i0.ɵɵelementEnd();
201
- i0.ɵɵelementStart(5, "div", 58)(6, "span", 59);
202
- i0.ɵɵelement(7, "i", 60);
202
+ i0.ɵɵelementStart(5, "div", 59)(6, "span", 60);
203
+ i0.ɵɵelement(7, "i", 61);
203
204
  i0.ɵɵtext(8);
204
205
  i0.ɵɵelementEnd();
205
- i0.ɵɵelementStart(9, "span", 59);
206
- i0.ɵɵelement(10, "i", 31);
206
+ i0.ɵɵelementStart(9, "span", 60);
207
+ i0.ɵɵelement(10, "i", 32);
207
208
  i0.ɵɵtext(11);
208
209
  i0.ɵɵelementEnd()()();
209
- i0.ɵɵelementStart(12, "button", 61);
210
+ i0.ɵɵelementStart(12, "button", 62);
210
211
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Template_button_click_12_listener($event) { const session_r8 = i0.ɵɵrestoreView(_r7).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.openStopSessionConfirm(session_r8, $event)); });
211
- i0.ɵɵelement(13, "i", 53);
212
+ i0.ɵɵelement(13, "i", 54);
212
213
  i0.ɵɵelementEnd()();
213
- i0.ɵɵelementStart(14, "div", 62);
214
- i0.ɵɵconditionalCreate(15, SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Conditional_15_Template, 3, 0, "span", 63);
215
- i0.ɵɵconditionalCreate(16, SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Conditional_16_Template, 3, 0, "span", 64);
216
- i0.ɵɵelementStart(17, "span", 65);
214
+ i0.ɵɵelementStart(14, "div", 63);
215
+ i0.ɵɵconditionalCreate(15, SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Conditional_15_Template, 3, 0, "span", 64);
216
+ i0.ɵɵconditionalCreate(16, SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Conditional_16_Template, 3, 0, "span", 65);
217
+ i0.ɵɵelementStart(17, "span", 66);
217
218
  i0.ɵɵtext(18);
218
219
  i0.ɵɵelementEnd()()();
219
220
  } if (rf & 2) {
@@ -238,24 +239,24 @@ function SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Template(rf, ctx)
238
239
  } }
239
240
  function SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_10_Template(rf, ctx) { if (rf & 1) {
240
241
  const _r9 = i0.ɵɵgetCurrentView();
241
- i0.ɵɵelementStart(0, "div", 46)(1, "h3", 47);
242
+ i0.ɵɵelementStart(0, "div", 47)(1, "h3", 48);
242
243
  i0.ɵɵtext(2);
243
244
  i0.ɵɵelementEnd();
244
- i0.ɵɵelementStart(3, "div", 68)(4, "label", 69)(5, "input", 70);
245
+ i0.ɵɵelementStart(3, "div", 69)(4, "label", 70)(5, "input", 71);
245
246
  i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_10_Template_input_ngModelChange_5_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(3); i0.ɵɵtwoWayBindingSet(ctx_r1.autoRefresh, $event) || (ctx_r1.autoRefresh = $event); return i0.ɵɵresetView($event); });
246
247
  i0.ɵɵelementEnd();
247
248
  i0.ɵɵtext(6, " Auto-refresh ");
248
249
  i0.ɵɵelementEnd();
249
- i0.ɵɵelementStart(7, "button", 71);
250
+ i0.ɵɵelementStart(7, "button", 72);
250
251
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_10_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.loadSessionLog(ctx_r1.selectedSession)); });
251
- i0.ɵɵelement(8, "i", 40);
252
+ i0.ɵɵelement(8, "i", 41);
252
253
  i0.ɵɵelementEnd();
253
- i0.ɵɵelementStart(9, "button", 72);
254
+ i0.ɵɵelementStart(9, "button", 73);
254
255
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_10_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r9); const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.toggleLogViewerExpand()); });
255
- i0.ɵɵelement(10, "i", 73);
256
+ i0.ɵɵelement(10, "i", 74);
256
257
  i0.ɵɵelementEnd()()();
257
- i0.ɵɵelementStart(11, "div", 74);
258
- i0.ɵɵelement(12, "mj-code-editor", 75);
258
+ i0.ɵɵelementStart(11, "div", 75);
259
+ i0.ɵɵelement(12, "mj-code-editor", 76);
259
260
  i0.ɵɵelementEnd();
260
261
  } if (rf & 2) {
261
262
  const ctx_r1 = i0.ɵɵnextContext(3);
@@ -273,26 +274,26 @@ function SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_10_Template
273
274
  i0.ɵɵproperty("value", ctx_r1.logContent)("readonly", true)("disabled", true)("language", "sql")("setup", "basic")("lineWrapping", true)("highlightWhitespace", false);
274
275
  } }
275
276
  function SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_11_Template(rf, ctx) { if (rf & 1) {
276
- i0.ɵɵelementStart(0, "div", 34);
277
- i0.ɵɵelement(1, "i", 76);
278
- i0.ɵɵelementStart(2, "p", 37);
277
+ i0.ɵɵelementStart(0, "div", 35);
278
+ i0.ɵɵelement(1, "i", 77);
279
+ i0.ɵɵelementStart(2, "p", 38);
279
280
  i0.ɵɵtext(3, "Select a Session");
280
281
  i0.ɵɵelementEnd();
281
- i0.ɵɵelementStart(4, "p", 38);
282
+ i0.ɵɵelementStart(4, "p", 39);
282
283
  i0.ɵɵtext(5, "Choose a session from the list to view its SQL log.");
283
284
  i0.ɵɵelementEnd()();
284
285
  } }
285
286
  function SqlLoggingComponent_Conditional_7_Conditional_4_Template(rf, ctx) { if (rf & 1) {
286
- i0.ɵɵelementStart(0, "div", 35)(1, "div", 45)(2, "div", 46)(3, "h3", 47);
287
+ i0.ɵɵelementStart(0, "div", 36)(1, "div", 46)(2, "div", 47)(3, "h3", 48);
287
288
  i0.ɵɵtext(4, "Active Sessions");
288
289
  i0.ɵɵelementEnd();
289
- i0.ɵɵconditionalCreate(5, SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_5_Template, 3, 1, "button", 48);
290
+ i0.ɵɵconditionalCreate(5, SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_5_Template, 3, 1, "button", 49);
290
291
  i0.ɵɵelementEnd();
291
- i0.ɵɵelementStart(6, "div", 49);
292
- i0.ɵɵrepeaterCreate(7, SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Template, 19, 11, "div", 50, _forTrack0);
292
+ i0.ɵɵelementStart(6, "div", 50);
293
+ i0.ɵɵrepeaterCreate(7, SqlLoggingComponent_Conditional_7_Conditional_4_For_8_Template, 19, 11, "div", 51, _forTrack0);
293
294
  i0.ɵɵelementEnd()();
294
- i0.ɵɵelementStart(9, "div", 51);
295
- i0.ɵɵconditionalCreate(10, SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_10_Template, 13, 17)(11, SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_11_Template, 6, 0, "div", 34);
295
+ i0.ɵɵelementStart(9, "div", 52);
296
+ i0.ɵɵconditionalCreate(10, SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_10_Template, 13, 17)(11, SqlLoggingComponent_Conditional_7_Conditional_4_Conditional_11_Template, 6, 0, "div", 35);
296
297
  i0.ɵɵelementEnd()();
297
298
  } if (rf & 2) {
298
299
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -307,7 +308,7 @@ function SqlLoggingComponent_Conditional_7_Conditional_4_Template(rf, ctx) { if
307
308
  } }
308
309
  function SqlLoggingComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
309
310
  i0.ɵɵelementStart(0, "div", 6);
310
- i0.ɵɵconditionalCreate(1, SqlLoggingComponent_Conditional_7_Conditional_1_Template, 9, 0, "div", 33)(2, SqlLoggingComponent_Conditional_7_Conditional_2_Template, 19, 0, "div", 33)(3, SqlLoggingComponent_Conditional_7_Conditional_3_Template, 9, 0, "div", 34)(4, SqlLoggingComponent_Conditional_7_Conditional_4_Template, 12, 4, "div", 35);
311
+ i0.ɵɵconditionalCreate(1, SqlLoggingComponent_Conditional_7_Conditional_1_Template, 9, 0, "div", 34)(2, SqlLoggingComponent_Conditional_7_Conditional_2_Template, 19, 0, "div", 34)(3, SqlLoggingComponent_Conditional_7_Conditional_3_Template, 9, 0, "div", 35)(4, SqlLoggingComponent_Conditional_7_Conditional_4_Template, 12, 4, "div", 36);
311
312
  i0.ɵɵelementEnd();
312
313
  } if (rf & 2) {
313
314
  const ctx_r1 = i0.ɵɵnextContext();
@@ -315,7 +316,7 @@ function SqlLoggingComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
315
316
  i0.ɵɵconditional(!ctx_r1.isOwner ? 1 : !ctx_r1.configEnabled ? 2 : ctx_r1.activeSessions.length === 0 ? 3 : 4);
316
317
  } }
317
318
  function SqlLoggingComponent_Conditional_8_For_29_Template(rf, ctx) { if (rf & 1) {
318
- i0.ɵɵelementStart(0, "option", 95);
319
+ i0.ɵɵelementStart(0, "option", 96);
319
320
  i0.ɵɵtext(1);
320
321
  i0.ɵɵelementEnd();
321
322
  } if (rf & 2) {
@@ -325,7 +326,7 @@ function SqlLoggingComponent_Conditional_8_For_29_Template(rf, ctx) { if (rf & 1
325
326
  i0.ɵɵtextInterpolate(option_r11.text);
326
327
  } }
327
328
  function SqlLoggingComponent_Conditional_8_For_51_Template(rf, ctx) { if (rf & 1) {
328
- i0.ɵɵelementStart(0, "option", 95);
329
+ i0.ɵɵelementStart(0, "option", 96);
329
330
  i0.ɵɵtext(1);
330
331
  i0.ɵɵelementEnd();
331
332
  } if (rf & 2) {
@@ -336,13 +337,13 @@ function SqlLoggingComponent_Conditional_8_For_51_Template(rf, ctx) { if (rf & 1
336
337
  } }
337
338
  function SqlLoggingComponent_Conditional_8_Conditional_64_Template(rf, ctx) { if (rf & 1) {
338
339
  const _r13 = i0.ɵɵgetCurrentView();
339
- i0.ɵɵelementStart(0, "div", 86)(1, "label", 114);
340
+ i0.ɵɵelementStart(0, "div", 87)(1, "label", 115);
340
341
  i0.ɵɵtext(2, "Default Schema Name");
341
342
  i0.ɵɵelementEnd();
342
- i0.ɵɵelementStart(3, "input", 115);
343
+ i0.ɵɵelementStart(3, "input", 116);
343
344
  i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_8_Conditional_64_Template_input_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(2); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.defaultSchemaName, $event) || (ctx_r1.newSessionOptions.defaultSchemaName = $event); return i0.ɵɵresetView($event); });
344
345
  i0.ɵɵelementEnd();
345
- i0.ɵɵelementStart(4, "div", 116);
346
+ i0.ɵɵelementStart(4, "div", 117);
346
347
  i0.ɵɵtext(5, "Schema name to replace with ${flyway:defaultSchema} placeholder.");
347
348
  i0.ɵɵelementEnd()();
348
349
  } if (rf & 2) {
@@ -351,7 +352,7 @@ function SqlLoggingComponent_Conditional_8_Conditional_64_Template(rf, ctx) { if
351
352
  i0.ɵɵtwoWayProperty("ngModel", ctx_r1.newSessionOptions.defaultSchemaName);
352
353
  } }
353
354
  function SqlLoggingComponent_Conditional_8_Conditional_73_Template(rf, ctx) { if (rf & 1) {
354
- i0.ɵɵelement(0, "i", 117);
355
+ i0.ɵɵelement(0, "i", 118);
355
356
  i0.ɵɵtext(1, " Starting... ");
356
357
  } }
357
358
  function SqlLoggingComponent_Conditional_8_Conditional_74_Template(rf, ctx) { if (rf & 1) {
@@ -360,106 +361,106 @@ function SqlLoggingComponent_Conditional_8_Conditional_74_Template(rf, ctx) { if
360
361
  } }
361
362
  function SqlLoggingComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
362
363
  const _r10 = i0.ɵɵgetCurrentView();
363
- i0.ɵɵelementStart(0, "div", 77);
364
+ i0.ɵɵelementStart(0, "div", 78);
364
365
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_8_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showStartSessionDialog = false); });
365
- i0.ɵɵelementStart(1, "div", 78);
366
+ i0.ɵɵelementStart(1, "div", 79);
366
367
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_8_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r10); return i0.ɵɵresetView($event.stopPropagation()); });
367
- i0.ɵɵelementStart(2, "div", 79)(3, "h3", 80);
368
+ i0.ɵɵelementStart(2, "div", 80)(3, "h3", 81);
368
369
  i0.ɵɵelement(4, "i", 10);
369
370
  i0.ɵɵtext(5, " Start SQL Logging Session ");
370
371
  i0.ɵɵelementEnd();
371
- i0.ɵɵelementStart(6, "div", 81)(7, "button", 82);
372
+ i0.ɵɵelementStart(6, "div", 82)(7, "button", 83);
372
373
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_8_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.toggleStartDialogFullscreen()); });
373
- i0.ɵɵelement(8, "i", 73);
374
+ i0.ɵɵelement(8, "i", 74);
374
375
  i0.ɵɵelementEnd();
375
- i0.ɵɵelementStart(9, "button", 83);
376
+ i0.ɵɵelementStart(9, "button", 84);
376
377
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_8_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showStartSessionDialog = false); });
377
- i0.ɵɵelement(10, "i", 84);
378
+ i0.ɵɵelement(10, "i", 85);
378
379
  i0.ɵɵelementEnd()()();
379
- i0.ɵɵelementStart(11, "div", 85)(12, "div", 86)(13, "label", 87);
380
+ i0.ɵɵelementStart(11, "div", 86)(12, "div", 87)(13, "label", 88);
380
381
  i0.ɵɵtext(14, "Session Name");
381
382
  i0.ɵɵelementEnd();
382
- i0.ɵɵelementStart(15, "input", 88);
383
+ i0.ɵɵelementStart(15, "input", 89);
383
384
  i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_8_Template_input_ngModelChange_15_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.sessionName, $event) || (ctx_r1.newSessionOptions.sessionName = $event); return i0.ɵɵresetView($event); });
384
385
  i0.ɵɵelementEnd();
385
- i0.ɵɵelementStart(16, "div", 89);
386
+ i0.ɵɵelementStart(16, "div", 90);
386
387
  i0.ɵɵtext(17, "A descriptive name to identify this logging session");
387
388
  i0.ɵɵelementEnd()();
388
- i0.ɵɵelementStart(18, "div", 86)(19, "label", 90);
389
+ i0.ɵɵelementStart(18, "div", 87)(19, "label", 91);
389
390
  i0.ɵɵtext(20, "File Name");
390
391
  i0.ɵɵelementEnd();
391
- i0.ɵɵelementStart(21, "input", 91);
392
+ i0.ɵɵelementStart(21, "input", 92);
392
393
  i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_8_Template_input_ngModelChange_21_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.fileName, $event) || (ctx_r1.newSessionOptions.fileName = $event); return i0.ɵɵresetView($event); });
393
394
  i0.ɵɵelementEnd();
394
- i0.ɵɵelementStart(22, "div", 92);
395
+ i0.ɵɵelementStart(22, "div", 93);
395
396
  i0.ɵɵtext(23, "The SQL log will be saved to this file");
396
397
  i0.ɵɵelementEnd()();
397
- i0.ɵɵelementStart(24, "div", 86)(25, "label", 93);
398
+ i0.ɵɵelementStart(24, "div", 87)(25, "label", 94);
398
399
  i0.ɵɵtext(26, "Statement Types");
399
400
  i0.ɵɵelementEnd();
400
- i0.ɵɵelementStart(27, "select", 94);
401
+ i0.ɵɵelementStart(27, "select", 95);
401
402
  i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_8_Template_select_ngModelChange_27_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.statementTypes, $event) || (ctx_r1.newSessionOptions.statementTypes = $event); return i0.ɵɵresetView($event); });
402
- i0.ɵɵrepeaterCreate(28, SqlLoggingComponent_Conditional_8_For_29_Template, 2, 2, "option", 95, _forTrack1);
403
+ i0.ɵɵrepeaterCreate(28, SqlLoggingComponent_Conditional_8_For_29_Template, 2, 2, "option", 96, _forTrack1);
403
404
  i0.ɵɵelementEnd();
404
- i0.ɵɵelementStart(30, "div", 96);
405
+ i0.ɵɵelementStart(30, "div", 97);
405
406
  i0.ɵɵtext(31, "Filter which types of SQL statements to capture");
406
407
  i0.ɵɵelementEnd()();
407
- i0.ɵɵelementStart(32, "div", 97)(33, "label", 69)(34, "input", 98);
408
+ i0.ɵɵelementStart(32, "div", 98)(33, "label", 70)(34, "input", 99);
408
409
  i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_8_Template_input_ngModelChange_34_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.filterToCurrentUser, $event) || (ctx_r1.newSessionOptions.filterToCurrentUser = $event); return i0.ɵɵresetView($event); });
409
410
  i0.ɵɵelementEnd();
410
411
  i0.ɵɵtext(35, " Filter to my SQL statements only ");
411
412
  i0.ɵɵelementEnd();
412
- i0.ɵɵelementStart(36, "label", 69)(37, "input", 98);
413
+ i0.ɵɵelementStart(36, "label", 70)(37, "input", 99);
413
414
  i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_8_Template_input_ngModelChange_37_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.formatAsMigration, $event) || (ctx_r1.newSessionOptions.formatAsMigration = $event); return i0.ɵɵresetView($event); });
414
415
  i0.ɵɵelementEnd();
415
416
  i0.ɵɵtext(38, " Format as migration file ");
416
417
  i0.ɵɵelementEnd();
417
- i0.ɵɵelementStart(39, "label", 69)(40, "input", 98);
418
+ i0.ɵɵelementStart(39, "label", 70)(40, "input", 99);
418
419
  i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_8_Template_input_ngModelChange_40_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.prettyPrint, $event) || (ctx_r1.newSessionOptions.prettyPrint = $event); return i0.ɵɵresetView($event); });
419
420
  i0.ɵɵelementEnd();
420
421
  i0.ɵɵtext(41, " Pretty print SQL statements ");
421
422
  i0.ɵɵelementEnd()();
422
- i0.ɵɵelementStart(42, "div", 99)(43, "h4", 100);
423
- i0.ɵɵelement(44, "i", 101);
423
+ i0.ɵɵelementStart(42, "div", 100)(43, "h4", 101);
424
+ i0.ɵɵelement(44, "i", 102);
424
425
  i0.ɵɵtext(45, " SQL Pattern Filtering ");
425
426
  i0.ɵɵelementEnd();
426
- i0.ɵɵelementStart(46, "div", 86)(47, "label", 102);
427
+ i0.ɵɵelementStart(46, "div", 87)(47, "label", 103);
427
428
  i0.ɵɵtext(48, "Filter Mode");
428
429
  i0.ɵɵelementEnd();
429
- i0.ɵɵelementStart(49, "select", 103);
430
+ i0.ɵɵelementStart(49, "select", 104);
430
431
  i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_8_Template_select_ngModelChange_49_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.filterType, $event) || (ctx_r1.newSessionOptions.filterType = $event); return i0.ɵɵresetView($event); });
431
- i0.ɵɵrepeaterCreate(50, SqlLoggingComponent_Conditional_8_For_51_Template, 2, 2, "option", 95, _forTrack1);
432
+ i0.ɵɵrepeaterCreate(50, SqlLoggingComponent_Conditional_8_For_51_Template, 2, 2, "option", 96, _forTrack1);
432
433
  i0.ɵɵelementEnd();
433
- i0.ɵɵelementStart(52, "div", 104);
434
+ i0.ɵɵelementStart(52, "div", 105);
434
435
  i0.ɵɵtext(53, "Exclude: Skip SQL matching any pattern. Include: Only log SQL matching a pattern.");
435
436
  i0.ɵɵelementEnd()();
436
- i0.ɵɵelementStart(54, "div", 86)(55, "label", 105);
437
+ i0.ɵɵelementStart(54, "div", 87)(55, "label", 106);
437
438
  i0.ɵɵtext(56, "Filter Patterns (one per line or comma-separated)");
438
439
  i0.ɵɵelementEnd();
439
- i0.ɵɵelementStart(57, "textarea", 106);
440
+ i0.ɵɵelementStart(57, "textarea", 107);
440
441
  i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_8_Template_textarea_ngModelChange_57_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.filterPatterns, $event) || (ctx_r1.newSessionOptions.filterPatterns = $event); return i0.ɵɵresetView($event); });
441
442
  i0.ɵɵelementEnd();
442
- i0.ɵɵelementStart(58, "div", 107);
443
+ i0.ɵɵelementStart(58, "div", 108);
443
444
  i0.ɵɵtext(59, "Supports wildcards (*) and regex (/pattern/flags). Example: *spCreate* matches any SP starting with spCreate.");
444
445
  i0.ɵɵelementEnd()()();
445
- i0.ɵɵelementStart(60, "div", 99)(61, "h4", 100);
446
- i0.ɵɵelement(62, "i", 108);
446
+ i0.ɵɵelementStart(60, "div", 100)(61, "h4", 101);
447
+ i0.ɵɵelement(62, "i", 109);
447
448
  i0.ɵɵtext(63, " Advanced Options ");
448
449
  i0.ɵɵelementEnd();
449
- i0.ɵɵconditionalCreate(64, SqlLoggingComponent_Conditional_8_Conditional_64_Template, 6, 1, "div", 86);
450
- i0.ɵɵelementStart(65, "div", 109)(66, "label", 69)(67, "input", 98);
450
+ i0.ɵɵconditionalCreate(64, SqlLoggingComponent_Conditional_8_Conditional_64_Template, 6, 1, "div", 87);
451
+ i0.ɵɵelementStart(65, "div", 110)(66, "label", 70)(67, "input", 99);
451
452
  i0.ɵɵtwoWayListener("ngModelChange", function SqlLoggingComponent_Conditional_8_Template_input_ngModelChange_67_listener($event) { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.newSessionOptions.verboseOutput, $event) || (ctx_r1.newSessionOptions.verboseOutput = $event); return i0.ɵɵresetView($event); });
452
453
  i0.ɵɵelementEnd();
453
454
  i0.ɵɵtext(68, " Verbose Debug Output ");
454
455
  i0.ɵɵelementEnd();
455
- i0.ɵɵelementStart(69, "div", 110);
456
+ i0.ɵɵelementStart(69, "div", 111);
456
457
  i0.ɵɵtext(70, "Log detailed filter decisions to server console (for debugging).");
457
458
  i0.ɵɵelementEnd()()()();
458
- i0.ɵɵelementStart(71, "div", 111)(72, "button", 112);
459
+ i0.ɵɵelementStart(71, "div", 112)(72, "button", 113);
459
460
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_8_Template_button_click_72_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.startNewSession()); });
460
461
  i0.ɵɵconditionalCreate(73, SqlLoggingComponent_Conditional_8_Conditional_73_Template, 2, 0)(74, SqlLoggingComponent_Conditional_8_Conditional_74_Template, 2, 0);
461
462
  i0.ɵɵelementEnd();
462
- i0.ɵɵelementStart(75, "button", 113);
463
+ i0.ɵɵelementStart(75, "button", 114);
463
464
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_8_Template_button_click_75_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showStartSessionDialog = false); });
464
465
  i0.ɵɵtext(76, "Cancel");
465
466
  i0.ɵɵelementEnd()()()();
@@ -523,7 +524,7 @@ function SqlLoggingComponent_Conditional_9_Conditional_10_Template(rf, ctx) { if
523
524
  i0.ɵɵtext(2);
524
525
  i0.ɵɵelementEnd();
525
526
  i0.ɵɵtext(3, "? ");
526
- i0.ɵɵelementStart(4, "span", 128);
527
+ i0.ɵɵelementStart(4, "span", 129);
527
528
  i0.ɵɵtext(5);
528
529
  i0.ɵɵelementEnd();
529
530
  } if (rf & 2) {
@@ -534,7 +535,7 @@ function SqlLoggingComponent_Conditional_9_Conditional_10_Template(rf, ctx) { if
534
535
  i0.ɵɵtextInterpolate1(" This session has captured ", ctx_r1.sessionToStop.statementCount, " SQL statements. ");
535
536
  } }
536
537
  function SqlLoggingComponent_Conditional_9_Conditional_13_Template(rf, ctx) { if (rf & 1) {
537
- i0.ɵɵelement(0, "i", 117);
538
+ i0.ɵɵelement(0, "i", 118);
538
539
  i0.ɵɵtext(1, " Stopping... ");
539
540
  } }
540
541
  function SqlLoggingComponent_Conditional_9_Conditional_14_Conditional_1_Template(rf, ctx) { if (rf & 1) {
@@ -544,7 +545,7 @@ function SqlLoggingComponent_Conditional_9_Conditional_14_Conditional_2_Template
544
545
  i0.ɵɵtext(0, " Stop Session ");
545
546
  } }
546
547
  function SqlLoggingComponent_Conditional_9_Conditional_14_Template(rf, ctx) { if (rf & 1) {
547
- i0.ɵɵelement(0, "i", 53);
548
+ i0.ɵɵelement(0, "i", 54);
548
549
  i0.ɵɵconditionalCreate(1, SqlLoggingComponent_Conditional_9_Conditional_14_Conditional_1_Template, 1, 0)(2, SqlLoggingComponent_Conditional_9_Conditional_14_Conditional_2_Template, 1, 0);
549
550
  } if (rf & 2) {
550
551
  const ctx_r1 = i0.ɵɵnextContext(2);
@@ -553,24 +554,24 @@ function SqlLoggingComponent_Conditional_9_Conditional_14_Template(rf, ctx) { if
553
554
  } }
554
555
  function SqlLoggingComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
555
556
  const _r14 = i0.ɵɵgetCurrentView();
556
- i0.ɵɵelementStart(0, "div", 118);
557
+ i0.ɵɵelementStart(0, "div", 119);
557
558
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_9_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r14); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelStopConfirm()); });
558
- i0.ɵɵelementStart(1, "div", 119);
559
+ i0.ɵɵelementStart(1, "div", 120);
559
560
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_9_Template_div_click_1_listener($event) { i0.ɵɵrestoreView(_r14); return i0.ɵɵresetView($event.stopPropagation()); });
560
- i0.ɵɵelementStart(2, "div", 120);
561
- i0.ɵɵelement(3, "i", 121);
561
+ i0.ɵɵelementStart(2, "div", 121);
562
+ i0.ɵɵelement(3, "i", 122);
562
563
  i0.ɵɵelementEnd();
563
- i0.ɵɵelementStart(4, "div", 122)(5, "h3", 123);
564
+ i0.ɵɵelementStart(4, "div", 123)(5, "h3", 124);
564
565
  i0.ɵɵconditionalCreate(6, SqlLoggingComponent_Conditional_9_Conditional_6_Template, 1, 0)(7, SqlLoggingComponent_Conditional_9_Conditional_7_Template, 1, 0);
565
566
  i0.ɵɵelementEnd();
566
- i0.ɵɵelementStart(8, "p", 124);
567
+ i0.ɵɵelementStart(8, "p", 125);
567
568
  i0.ɵɵconditionalCreate(9, SqlLoggingComponent_Conditional_9_Conditional_9_Template, 4, 1)(10, SqlLoggingComponent_Conditional_9_Conditional_10_Template, 6, 2);
568
569
  i0.ɵɵelementEnd()();
569
- i0.ɵɵelementStart(11, "div", 125)(12, "button", 126);
570
+ i0.ɵɵelementStart(11, "div", 126)(12, "button", 127);
570
571
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_9_Template_button_click_12_listener() { i0.ɵɵrestoreView(_r14); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmStopSession()); });
571
572
  i0.ɵɵconditionalCreate(13, SqlLoggingComponent_Conditional_9_Conditional_13_Template, 2, 0)(14, SqlLoggingComponent_Conditional_9_Conditional_14_Template, 3, 1);
572
573
  i0.ɵɵelementEnd();
573
- i0.ɵɵelementStart(15, "button", 127);
574
+ i0.ɵɵelementStart(15, "button", 128);
574
575
  i0.ɵɵlistener("click", function SqlLoggingComponent_Conditional_9_Template_button_click_15_listener() { i0.ɵɵrestoreView(_r14); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelStopConfirm()); });
575
576
  i0.ɵɵtext(16, "Cancel");
576
577
  i0.ɵɵelementEnd()()()();
@@ -1245,11 +1246,11 @@ let SqlLoggingComponent = class SqlLoggingComponent extends BaseDashboard {
1245
1246
  static ɵfac = function SqlLoggingComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SqlLoggingComponent)(i0.ɵɵdirectiveInject(i1.SharedService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
1246
1247
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SqlLoggingComponent, selectors: [["mj-sql-logging"]], hostBindings: function SqlLoggingComponent_HostBindings(rf, ctx) { if (rf & 1) {
1247
1248
  i0.ɵɵlistener("keydown.escape", function SqlLoggingComponent_keydown_escape_HostBindingHandler() { return ctx.onEscapeKey(); }, i0.ɵɵresolveDocument);
1248
- } }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 10, vars: 7, consts: [["Role", "region", "AriaLabel", "SQL logging actions", "Title", "SQL Logging", "Subtitle", "Capture and download SQL statements executed by the API"], ["actions", ""], [3, "Clicked", "Loading"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "disabled"], [1, "stats-toggle-container"], ["role", "status", "aria-live", "polite", "aria-busy", "true", 1, "loading-container"], [1, "content-area"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "start-session-dialog-title", 1, "modal-backdrop"], ["role", "alertdialog", "aria-modal", "true", "aria-labelledby", "stop-dialog-title", "aria-describedby", "stop-dialog-desc", 1, "modal-backdrop"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-play"], ["aria-controls", "stats-grid-content", 1, "stats-toggle-button", 3, "click"], [1, "stats-toggle-left"], [1, "stats-toggle-icon"], ["aria-hidden", "true", 1, "fa-solid", "fa-chart-line"], [1, "stats-toggle-text"], [1, "stats-toggle-title"], [1, "stats-toggle-subtitle"], ["aria-hidden", "true", 1, "fa-solid", "fa-chevron-down", "stats-toggle-arrow"], ["id", "stats-grid-content", "role", "region", "aria-label", "SQL logging statistics", 1, "stats-grid"], [1, "stat-card"], [1, "stat-icon", "stat-icon-status"], ["aria-hidden", "true", 1, "fa-solid", "fa-power-off"], [1, "stat-content"], [1, "stat-value"], [1, "stat-label"], [1, "stat-icon", "stat-icon-active"], ["aria-hidden", "true", 1, "fa-solid", "fa-play-circle"], [1, "stat-icon", "stat-icon-limit"], ["aria-hidden", "true", 1, "fa-solid", "fa-gauge-high"], [1, "stat-icon", "stat-icon-total"], ["aria-hidden", "true", 1, "fa-solid", "fa-database"], ["text", "Loading SQL logging configuration...", "size", "medium"], ["role", "alert", 1, "empty-state"], ["role", "status", 1, "empty-state"], [1, "sessions-layout"], ["aria-hidden", "true", 1, "fa-solid", "fa-lock", "empty-icon"], [1, "empty-text"], [1, "empty-subtext"], ["mjButton", "", "variant", "secondary", "size", "md", "aria-label", "Refresh user permissions", 2, "margin-top", "1rem", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-sync"], ["aria-hidden", "true", 1, "fa-solid", "fa-exclamation-triangle", "empty-icon", "warning"], [1, "info-box"], ["aria-hidden", "true", 1, "fa-solid", "fa-file-code", "empty-icon"], ["mjButton", "", "variant", "primary", "size", "md", "aria-label", "Start a new SQL logging session", 2, "margin-top", "1rem", 3, "click"], ["role", "region", "aria-label", "Active sessions list", 1, "sessions-panel"], [1, "panel-header"], [1, "panel-title"], ["mjButton", "", "variant", "danger", "size", "sm", "aria-label", "Stop all active sessions", 3, "disabled"], ["role", "list", "aria-label", "SQL logging sessions", 1, "sessions-list"], ["role", "listitem", "tabindex", "0", 1, "session-card", 3, "selected"], ["role", "region", "aria-label", "SQL log viewer", 1, "log-viewer-panel"], ["mjButton", "", "variant", "danger", "size", "sm", "aria-label", "Stop all active sessions", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-stop"], ["role", "listitem", "tabindex", "0", 1, "session-card", 3, "click", "keydown.enter", "keydown.space"], [1, "session-header"], [1, "session-info"], [1, "session-title"], [1, "session-meta"], [1, "meta-item"], ["aria-hidden", "true", 1, "fa-solid", "fa-clock"], ["mjButton", "", "variant", "danger", "size", "sm", 3, "click"], [1, "session-badges"], [1, "badge", "badge-user"], [1, "badge", "badge-migration"], [1, "badge", "badge-type"], ["aria-hidden", "true", 1, "fa-solid", "fa-user"], ["aria-hidden", "true", 1, "fa-solid", "fa-code-branch"], [1, "panel-actions"], [1, "checkbox-label"], ["type", "checkbox", "aria-label", "Enable auto-refresh", 3, "ngModelChange", "ngModel"], ["mjButton", "", "variant", "flat", "size", "sm", "aria-label", "Refresh log content", 3, "click"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click"], ["aria-hidden", "true", 1, "fa-solid"], [1, "log-content"], ["aria-label", "SQL log content", 2, "height", "100%", 3, "value", "readonly", "disabled", "language", "setup", "lineWrapping", "highlightWhitespace"], ["aria-hidden", "true", 1, "fa-solid", "fa-arrow-left", "empty-icon"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "start-session-dialog-title", 1, "modal-backdrop", 3, "click"], [1, "modal-dialog", "modal-large", 3, "click"], [1, "modal-header"], ["id", "start-session-dialog-title", 1, "modal-title"], [1, "modal-header-actions"], ["type", "button", 1, "modal-action-btn", 3, "click"], ["aria-label", "Close dialog", 1, "modal-close", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-times"], [1, "modal-body"], [1, "form-group"], ["for", "session-name", 1, "form-label"], ["type", "text", "id", "session-name", "placeholder", "Enter a descriptive name for this session", "aria-describedby", "session-name-hint", 1, "form-input", 3, "ngModelChange", "ngModel"], ["id", "session-name-hint", 1, "form-hint"], ["for", "file-name", 1, "form-label"], ["type", "text", "id", "file-name", "placeholder", "sql-log-2024-01-01.sql", "aria-describedby", "file-name-hint", 1, "form-input", 3, "ngModelChange", "ngModel"], ["id", "file-name-hint", 1, "form-hint"], ["for", "statement-types", 1, "form-label"], ["id", "statement-types", "aria-describedby", "statement-types-hint", 1, "form-select", 3, "ngModelChange", "ngModel"], [3, "value"], ["id", "statement-types-hint", 1, "form-hint"], ["role", "group", "aria-label", "Session options", 1, "form-checkboxes"], ["type", "checkbox", 3, "ngModelChange", "ngModel"], [1, "form-section"], [1, "form-section-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-filter"], ["for", "filter-type", 1, "form-label"], ["id", "filter-type", "aria-describedby", "filter-type-hint", 1, "form-select", 3, "ngModelChange", "ngModel"], ["id", "filter-type-hint", 1, "form-hint"], ["for", "filter-patterns", 1, "form-label"], ["id", "filter-patterns", "rows", "4", "placeholder", "Examples:\n*AIPrompt*\n/spCreate.*Run/i\nSELECT * FROM vwMetadata", "aria-describedby", "filter-patterns-hint", 1, "form-textarea", 3, "ngModelChange", "ngModel"], ["id", "filter-patterns-hint", 1, "form-hint"], ["aria-hidden", "true", 1, "fa-solid", "fa-cog"], [1, "form-checkboxes"], [1, "form-hint", 2, "margin-left", "1.75rem"], [1, "modal-footer"], ["mjButton", "", "variant", "primary", "size", "md", "aria-label", "Start the SQL logging session", 3, "click", "disabled"], ["mjButton", "", "variant", "secondary", "size", "md", "aria-label", "Cancel and close dialog", 3, "click"], ["for", "default-schema", 1, "form-label"], ["type", "text", "id", "default-schema", "placeholder", "__mj", "aria-describedby", "default-schema-hint", 1, "form-input", 3, "ngModelChange", "ngModel"], ["id", "default-schema-hint", 1, "form-hint"], ["aria-hidden", "true", 1, "fa-solid", "fa-spinner", "fa-spin"], ["role", "alertdialog", "aria-modal", "true", "aria-labelledby", "stop-dialog-title", "aria-describedby", "stop-dialog-desc", 1, "modal-backdrop", 3, "click"], [1, "confirm-dialog", 3, "click"], [1, "confirm-dialog-icon"], ["aria-hidden", "true", 1, "fa-solid", "fa-exclamation-triangle"], [1, "confirm-dialog-content"], ["id", "stop-dialog-title", 1, "confirm-dialog-title"], ["id", "stop-dialog-desc", 1, "confirm-dialog-message"], [1, "confirm-dialog-actions"], ["mjButton", "", "variant", "danger", "size", "md", 3, "click", "disabled"], ["mjButton", "", "variant", "secondary", "size", "md", "aria-label", "Cancel and keep sessions running", 3, "click", "disabled"], [1, "confirm-dialog-details"]], template: function SqlLoggingComponent_Template(rf, ctx) { if (rf & 1) {
1249
+ } }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 10, vars: 7, consts: [["Role", "region", "AriaLabel", "SQL logging actions", "Title", "SQL Logging", "Subtitle", "Capture and download SQL statements executed by the API"], ["actions", ""], [3, "Clicked", "Loading"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "disabled"], [1, "stats-toggle-container"], ["role", "status", "aria-live", "polite", "aria-busy", "true", 1, "loading-container"], [1, "content-area"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "start-session-dialog-title", 1, "modal-backdrop"], ["role", "alertdialog", "aria-modal", "true", "aria-labelledby", "stop-dialog-title", "aria-describedby", "stop-dialog-desc", 1, "modal-backdrop"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-play"], [1, "mj-action-label"], ["aria-controls", "stats-grid-content", 1, "stats-toggle-button", 3, "click"], [1, "stats-toggle-left"], [1, "stats-toggle-icon"], ["aria-hidden", "true", 1, "fa-solid", "fa-chart-line"], [1, "stats-toggle-text"], [1, "stats-toggle-title"], [1, "stats-toggle-subtitle"], ["aria-hidden", "true", 1, "fa-solid", "fa-chevron-down", "stats-toggle-arrow"], ["id", "stats-grid-content", "role", "region", "aria-label", "SQL logging statistics", 1, "stats-grid"], [1, "stat-card"], [1, "stat-icon", "stat-icon-status"], ["aria-hidden", "true", 1, "fa-solid", "fa-power-off"], [1, "stat-content"], [1, "stat-value"], [1, "stat-label"], [1, "stat-icon", "stat-icon-active"], ["aria-hidden", "true", 1, "fa-solid", "fa-play-circle"], [1, "stat-icon", "stat-icon-limit"], ["aria-hidden", "true", 1, "fa-solid", "fa-gauge-high"], [1, "stat-icon", "stat-icon-total"], ["aria-hidden", "true", 1, "fa-solid", "fa-database"], ["text", "Loading SQL logging configuration...", "size", "medium"], ["role", "alert", 1, "empty-state"], ["role", "status", 1, "empty-state"], [1, "sessions-layout"], ["aria-hidden", "true", 1, "fa-solid", "fa-lock", "empty-icon"], [1, "empty-text"], [1, "empty-subtext"], ["mjButton", "", "variant", "secondary", "size", "md", "aria-label", "Refresh user permissions", 2, "margin-top", "1rem", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-sync"], ["aria-hidden", "true", 1, "fa-solid", "fa-exclamation-triangle", "empty-icon", "warning"], [1, "info-box"], ["aria-hidden", "true", 1, "fa-solid", "fa-file-code", "empty-icon"], ["mjButton", "", "variant", "primary", "size", "md", "aria-label", "Start a new SQL logging session", 2, "margin-top", "1rem", 3, "click"], ["role", "region", "aria-label", "Active sessions list", 1, "sessions-panel"], [1, "panel-header"], [1, "panel-title"], ["mjButton", "", "variant", "danger", "size", "sm", "aria-label", "Stop all active sessions", 3, "disabled"], ["role", "list", "aria-label", "SQL logging sessions", 1, "sessions-list"], ["role", "listitem", "tabindex", "0", 1, "session-card", 3, "selected"], ["role", "region", "aria-label", "SQL log viewer", 1, "log-viewer-panel"], ["mjButton", "", "variant", "danger", "size", "sm", "aria-label", "Stop all active sessions", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa-solid", "fa-stop"], ["role", "listitem", "tabindex", "0", 1, "session-card", 3, "click", "keydown.enter", "keydown.space"], [1, "session-header"], [1, "session-info"], [1, "session-title"], [1, "session-meta"], [1, "meta-item"], ["aria-hidden", "true", 1, "fa-solid", "fa-clock"], ["mjButton", "", "variant", "danger", "size", "sm", 3, "click"], [1, "session-badges"], [1, "badge", "badge-user"], [1, "badge", "badge-migration"], [1, "badge", "badge-type"], ["aria-hidden", "true", 1, "fa-solid", "fa-user"], ["aria-hidden", "true", 1, "fa-solid", "fa-code-branch"], [1, "panel-actions"], [1, "checkbox-label"], ["type", "checkbox", "aria-label", "Enable auto-refresh", 3, "ngModelChange", "ngModel"], ["mjButton", "", "variant", "flat", "size", "sm", "aria-label", "Refresh log content", 3, "click"], ["mjButton", "", "variant", "flat", "size", "sm", 3, "click"], ["aria-hidden", "true", 1, "fa-solid"], [1, "log-content"], ["aria-label", "SQL log content", 2, "height", "100%", 3, "value", "readonly", "disabled", "language", "setup", "lineWrapping", "highlightWhitespace"], ["aria-hidden", "true", 1, "fa-solid", "fa-arrow-left", "empty-icon"], ["role", "dialog", "aria-modal", "true", "aria-labelledby", "start-session-dialog-title", 1, "modal-backdrop", 3, "click"], [1, "modal-dialog", "modal-large", 3, "click"], [1, "modal-header"], ["id", "start-session-dialog-title", 1, "modal-title"], [1, "modal-header-actions"], ["type", "button", 1, "modal-action-btn", 3, "click"], ["aria-label", "Close dialog", 1, "modal-close", 3, "click"], ["aria-hidden", "true", 1, "fa-solid", "fa-times"], [1, "modal-body"], [1, "form-group"], ["for", "session-name", 1, "form-label"], ["type", "text", "id", "session-name", "placeholder", "Enter a descriptive name for this session", "aria-describedby", "session-name-hint", 1, "form-input", 3, "ngModelChange", "ngModel"], ["id", "session-name-hint", 1, "form-hint"], ["for", "file-name", 1, "form-label"], ["type", "text", "id", "file-name", "placeholder", "sql-log-2024-01-01.sql", "aria-describedby", "file-name-hint", 1, "form-input", 3, "ngModelChange", "ngModel"], ["id", "file-name-hint", 1, "form-hint"], ["for", "statement-types", 1, "form-label"], ["id", "statement-types", "aria-describedby", "statement-types-hint", 1, "form-select", 3, "ngModelChange", "ngModel"], [3, "value"], ["id", "statement-types-hint", 1, "form-hint"], ["role", "group", "aria-label", "Session options", 1, "form-checkboxes"], ["type", "checkbox", 3, "ngModelChange", "ngModel"], [1, "form-section"], [1, "form-section-title"], ["aria-hidden", "true", 1, "fa-solid", "fa-filter"], ["for", "filter-type", 1, "form-label"], ["id", "filter-type", "aria-describedby", "filter-type-hint", 1, "form-select", 3, "ngModelChange", "ngModel"], ["id", "filter-type-hint", 1, "form-hint"], ["for", "filter-patterns", 1, "form-label"], ["id", "filter-patterns", "rows", "4", "placeholder", "Examples:\n*AIPrompt*\n/spCreate.*Run/i\nSELECT * FROM vwMetadata", "aria-describedby", "filter-patterns-hint", 1, "form-textarea", 3, "ngModelChange", "ngModel"], ["id", "filter-patterns-hint", 1, "form-hint"], ["aria-hidden", "true", 1, "fa-solid", "fa-cog"], [1, "form-checkboxes"], [1, "form-hint", 2, "margin-left", "1.75rem"], [1, "modal-footer"], ["mjButton", "", "variant", "primary", "size", "md", "aria-label", "Start the SQL logging session", 3, "click", "disabled"], ["mjButton", "", "variant", "secondary", "size", "md", "aria-label", "Cancel and close dialog", 3, "click"], ["for", "default-schema", 1, "form-label"], ["type", "text", "id", "default-schema", "placeholder", "__mj", "aria-describedby", "default-schema-hint", 1, "form-input", 3, "ngModelChange", "ngModel"], ["id", "default-schema-hint", 1, "form-hint"], ["aria-hidden", "true", 1, "fa-solid", "fa-spinner", "fa-spin"], ["role", "alertdialog", "aria-modal", "true", "aria-labelledby", "stop-dialog-title", "aria-describedby", "stop-dialog-desc", 1, "modal-backdrop", 3, "click"], [1, "confirm-dialog", 3, "click"], [1, "confirm-dialog-icon"], ["aria-hidden", "true", 1, "fa-solid", "fa-exclamation-triangle"], [1, "confirm-dialog-content"], ["id", "stop-dialog-title", 1, "confirm-dialog-title"], ["id", "stop-dialog-desc", 1, "confirm-dialog-message"], [1, "confirm-dialog-actions"], ["mjButton", "", "variant", "danger", "size", "md", 3, "click", "disabled"], ["mjButton", "", "variant", "secondary", "size", "md", "aria-label", "Cancel and keep sessions running", 3, "click", "disabled"], [1, "confirm-dialog-details"]], template: function SqlLoggingComponent_Template(rf, ctx) { if (rf & 1) {
1249
1250
  i0.ɵɵelementStart(0, "mj-page-header-interior", 0)(1, "div", 1)(2, "mj-refresh-button", 2);
1250
1251
  i0.ɵɵlistener("Clicked", function SqlLoggingComponent_Template_mj_refresh_button_Clicked_2_listener() { return ctx.loadActiveSessions(); });
1251
1252
  i0.ɵɵelementEnd();
1252
- i0.ɵɵconditionalCreate(3, SqlLoggingComponent_Conditional_3_Template, 3, 2, "button", 3);
1253
+ i0.ɵɵconditionalCreate(3, SqlLoggingComponent_Conditional_3_Template, 4, 2, "button", 3);
1253
1254
  i0.ɵɵelementEnd()();
1254
1255
  i0.ɵɵelementStart(4, "mj-page-body-interior");
1255
1256
  i0.ɵɵconditionalCreate(5, SqlLoggingComponent_Conditional_5_Template, 44, 13, "div", 4);
@@ -1281,7 +1282,7 @@ SqlLoggingComponent = __decorate([
1281
1282
  export { SqlLoggingComponent };
1282
1283
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SqlLoggingComponent, [{
1283
1284
  type: Component,
1284
- args: [{ standalone: false, selector: 'mj-sql-logging', template: "<!--\n Interior chrome \u2014 sub-page of Admin's Monitoring left-nav shell. Single section\n (no L2 tab nav) so [toolbar] is empty; actions land in [actions]. See Section 10\n of plans/explorer-chrome-conventions.md.\n-->\n<mj-page-header-interior\n Role=\"region\"\n AriaLabel=\"SQL logging actions\"\n Title=\"SQL Logging\"\n Subtitle=\"Capture and download SQL statements executed by the API\">\n <div actions>\n <mj-refresh-button\n [Loading]=\"loading\"\n (Clicked)=\"loadActiveSessions()\">\n </mj-refresh-button>\n @if (isOwner && configEnabled) {\n <button mjButton\n variant=\"primary\"\n size=\"sm\"\n [disabled]=\"loading || activeSessions.length >= (sqlLoggingConfig?.maxActiveSessions || 5)\"\n (click)=\"openStartSessionDialog()\"\n [attr.aria-label]=\"'Start new SQL logging session' + (activeSessions.length >= (sqlLoggingConfig?.maxActiveSessions || 5) ? ' (maximum sessions reached)' : '')\">\n <i class=\"fa-solid fa-play\" aria-hidden=\"true\"></i>\n Start New Session\n </button>\n }\n </div>\n</mj-page-header-interior>\n\n<mj-page-body-interior>\n\n <!-- Stats Cards with Toggle -->\n @if (isOwner && configEnabled) {\n <div class=\"stats-toggle-container\">\n <!-- Toggle Button -->\n <button\n class=\"stats-toggle-button\"\n [class.expanded]=\"showStats\"\n (click)=\"showStats = !showStats\"\n [attr.aria-expanded]=\"showStats\"\n aria-controls=\"stats-grid-content\"\n >\n <div class=\"stats-toggle-left\">\n <div class=\"stats-toggle-icon\">\n <i class=\"fa-solid fa-chart-line\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"stats-toggle-text\">\n <h3 class=\"stats-toggle-title\">Statistics</h3>\n <p class=\"stats-toggle-subtitle\">View session statistics and metrics</p>\n </div>\n </div>\n <i class=\"fa-solid fa-chevron-down stats-toggle-arrow\" aria-hidden=\"true\"></i>\n </button>\n\n <!-- Stats Grid (Collapsible) -->\n <div\n id=\"stats-grid-content\"\n class=\"stats-grid\"\n [class.visible]=\"showStats\"\n role=\"region\"\n aria-label=\"SQL logging statistics\"\n >\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-status\">\n <i class=\"fa-solid fa-power-off\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" [attr.aria-label]=\"'Status: ' + (configEnabled ? 'Enabled' : 'Disabled')\">\n {{ configEnabled ? \"Enabled\" : \"Disabled\" }}\n </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\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" [attr.aria-label]=\"activeSessions.length + ' active sessions'\">\n {{ activeSessions.length }}\n </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\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" [attr.aria-label]=\"(sqlLoggingConfig?.maxActiveSessions || 5) + ' maximum sessions allowed'\">\n {{ sqlLoggingConfig?.maxActiveSessions || 5 }}\n </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\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" [attr.aria-label]=\"getTotalStatementCount() + ' total SQL statements captured'\">\n {{ getTotalStatementCount() }}\n </div>\n <div class=\"stat-label\">Total Statements</div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- Loading State -->\n @if (loading && !activeSessions.length) {\n <div class=\"loading-container\" role=\"status\" aria-live=\"polite\" aria-busy=\"true\">\n <mj-loading text=\"Loading SQL logging configuration...\" size=\"medium\"></mj-loading>\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\" role=\"alert\">\n <i class=\"fa-solid fa-lock empty-icon\" aria-hidden=\"true\"></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 mjButton variant=\"secondary\" size=\"md\" (click)=\"refreshUserPermissions()\" style=\"margin-top: 1rem\" aria-label=\"Refresh user permissions\">\n <i class=\"fa-solid fa-sync\" aria-hidden=\"true\"></i>\n Refresh Permissions\n </button>\n </div>\n } @else if (!configEnabled) {\n <!-- Not enabled in config -->\n <div class=\"empty-state\" role=\"alert\">\n <i class=\"fa-solid fa-exclamation-triangle empty-icon warning\" aria-hidden=\"true\"></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\" role=\"status\">\n <i class=\"fa-solid fa-file-code empty-icon\" aria-hidden=\"true\"></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 mjButton variant=\"primary\" size=\"md\" (click)=\"openStartSessionDialog()\" style=\"margin-top: 1rem\" aria-label=\"Start a new SQL logging session\">\n <i class=\"fa-solid fa-play\" aria-hidden=\"true\"></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\" role=\"region\" aria-label=\"Active sessions list\">\n <div class=\"panel-header\">\n <h3 class=\"panel-title\">Active Sessions</h3>\n @if (activeSessions.length > 0) {\n <button mjButton\n variant=\"danger\"\n size=\"sm\"\n (click)=\"openStopAllSessionsConfirm()\"\n [disabled]=\"loading\"\n aria-label=\"Stop all active sessions\"\n >\n <i class=\"fa-solid fa-stop\" aria-hidden=\"true\"></i>\n Stop All\n </button>\n }\n </div>\n <div class=\"sessions-list\" role=\"list\" aria-label=\"SQL logging sessions\">\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 role=\"listitem\"\n tabindex=\"0\"\n (keydown.enter)=\"selectSession(session)\"\n (keydown.space)=\"selectSession(session); $event.preventDefault()\"\n [attr.aria-label]=\"'Session: ' + session.sessionName + ', ' + session.statementCount + ' statements, duration ' + getSessionDuration(session.startTime)\"\n [attr.aria-selected]=\"selectedSession?.id === session.id\"\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\" aria-hidden=\"true\"></i>\n {{ getSessionDuration(session.startTime) }}\n </span>\n <span class=\"meta-item\">\n <i class=\"fa-solid fa-database\" aria-hidden=\"true\"></i>\n {{ session.statementCount }} statements\n </span>\n </div>\n </div>\n <button mjButton\n variant=\"danger\"\n size=\"sm\"\n (click)=\"openStopSessionConfirm(session, $event)\"\n [attr.aria-label]=\"'Stop session ' + session.sessionName\"\n >\n <i class=\"fa-solid fa-stop\" aria-hidden=\"true\"></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\" aria-hidden=\"true\"></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\" aria-hidden=\"true\"></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\" role=\"region\" aria-label=\"SQL log viewer\">\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 aria-label=\"Enable auto-refresh\"\n />\n Auto-refresh\n </label>\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n (click)=\"loadSessionLog(selectedSession)\"\n aria-label=\"Refresh log content\"\n >\n <i class=\"fa-solid fa-sync\" [class.fa-spin]=\"loading\" aria-hidden=\"true\"></i>\n </button>\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n (click)=\"toggleLogViewerExpand()\"\n [attr.aria-label]=\"isLogViewerExpanded ? 'Collapse log viewer' : 'Expand log viewer to fullscreen'\"\n [attr.aria-expanded]=\"isLogViewerExpanded\"\n >\n <i class=\"fa-solid\" [class.fa-expand]=\"!isLogViewerExpanded\" [class.fa-compress]=\"isLogViewerExpanded\" aria-hidden=\"true\"></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 aria-label=\"SQL log content\"\n ></mj-code-editor>\n </div>\n } @else {\n <div class=\"empty-state\" role=\"status\">\n <i class=\"fa-solid fa-arrow-left empty-icon\" aria-hidden=\"true\"></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\n class=\"modal-backdrop\"\n (click)=\"showStartSessionDialog = false\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"start-session-dialog-title\"\n >\n <div class=\"modal-dialog modal-large\" [class.fullscreen]=\"isStartDialogFullscreen\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3 class=\"modal-title\" id=\"start-session-dialog-title\">\n <i class=\"fa-solid fa-play\" aria-hidden=\"true\"></i>\n Start SQL Logging Session\n </h3>\n <div class=\"modal-header-actions\">\n <button\n class=\"modal-action-btn\"\n (click)=\"toggleStartDialogFullscreen()\"\n [attr.aria-label]=\"isStartDialogFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'\"\n type=\"button\"\n >\n <i class=\"fa-solid\" [class.fa-compress]=\"isStartDialogFullscreen\" [class.fa-expand]=\"!isStartDialogFullscreen\" aria-hidden=\"true\"></i>\n </button>\n <button class=\"modal-close\" (click)=\"showStartSessionDialog = false\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n <div class=\"modal-body\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"session-name\">Session Name</label>\n <input\n type=\"text\"\n id=\"session-name\"\n class=\"form-input\"\n [(ngModel)]=\"newSessionOptions.sessionName\"\n placeholder=\"Enter a descriptive name for this session\"\n aria-describedby=\"session-name-hint\"\n />\n <div id=\"session-name-hint\" class=\"form-hint\">A descriptive name to identify this logging session</div>\n </div>\n\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"file-name\">File Name</label>\n <input\n type=\"text\"\n id=\"file-name\"\n class=\"form-input\"\n [(ngModel)]=\"newSessionOptions.fileName\"\n placeholder=\"sql-log-2024-01-01.sql\"\n aria-describedby=\"file-name-hint\"\n />\n <div id=\"file-name-hint\" 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\" for=\"statement-types\">Statement Types</label>\n <select\n id=\"statement-types\"\n class=\"form-select\"\n [(ngModel)]=\"newSessionOptions.statementTypes\"\n aria-describedby=\"statement-types-hint\"\n >\n @for (option of statementTypeOptions; track option.value) {\n <option [value]=\"option.value\">{{ option.text }}</option>\n }\n </select>\n <div id=\"statement-types-hint\" class=\"form-hint\">Filter which types of SQL statements to capture</div>\n </div>\n\n <div class=\"form-checkboxes\" role=\"group\" aria-label=\"Session options\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" [(ngModel)]=\"newSessionOptions.filterToCurrentUser\" />\n Filter to my SQL statements only\n </label>\n\n\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" [(ngModel)]=\"newSessionOptions.formatAsMigration\" />\n Format as migration file\n </label>\n\n\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" [(ngModel)]=\"newSessionOptions.prettyPrint\" />\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\" aria-hidden=\"true\"></i>\n SQL Pattern Filtering\n </h4>\n\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"filter-type\">Filter Mode</label>\n <select\n id=\"filter-type\"\n class=\"form-select\"\n [(ngModel)]=\"newSessionOptions.filterType\"\n aria-describedby=\"filter-type-hint\"\n >\n @for (option of filterTypeOptions; track option.value) {\n <option [value]=\"option.value\">{{ option.text }}</option>\n }\n </select>\n <div id=\"filter-type-hint\" class=\"form-hint\">Exclude: Skip SQL matching any pattern. Include: Only log SQL matching a pattern.</div>\n </div>\n\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"filter-patterns\">Filter Patterns (one per line or comma-separated)</label>\n <textarea\n id=\"filter-patterns\"\n class=\"form-textarea\"\n [(ngModel)]=\"newSessionOptions.filterPatterns\"\n rows=\"4\"\n placeholder=\"Examples:&#10;*AIPrompt*&#10;/spCreate.*Run/i&#10;SELECT * FROM vwMetadata\"\n aria-describedby=\"filter-patterns-hint\"\n ></textarea>\n <div id=\"filter-patterns-hint\" class=\"form-hint\">Supports wildcards (*) and regex (/pattern/flags). Example: *spCreate* matches any SP starting with spCreate.</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\" aria-hidden=\"true\"></i>\n Advanced Options\n </h4>\n\n @if (newSessionOptions.formatAsMigration) {\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"default-schema\">Default Schema Name</label>\n <input\n type=\"text\"\n id=\"default-schema\"\n class=\"form-input\"\n [(ngModel)]=\"newSessionOptions.defaultSchemaName\"\n placeholder=\"__mj\"\n aria-describedby=\"default-schema-hint\"\n />\n <div id=\"default-schema-hint\" class=\"form-hint\">Schema name to replace with $&#123;flyway:defaultSchema&#125; placeholder.</div>\n </div>\n }\n\n <div class=\"form-checkboxes\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" [(ngModel)]=\"newSessionOptions.verboseOutput\" />\n Verbose Debug Output\n </label>\n <div class=\"form-hint\" style=\"margin-left: 1.75rem\">Log detailed filter decisions to server console (for debugging).</div>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button mjButton variant=\"primary\" size=\"md\" (click)=\"startNewSession()\" [disabled]=\"loading\" aria-label=\"Start the SQL logging session\">\n @if (loading) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n Starting...\n } @else {\n <i class=\"fa-solid fa-play\" aria-hidden=\"true\"></i>\n Start Session\n }\n </button>\n <button mjButton variant=\"secondary\" size=\"md\" (click)=\"showStartSessionDialog = false\" aria-label=\"Cancel and close dialog\">Cancel</button>\n </div>\n </div>\n </div>\n }\n\n <!-- Stop Session Confirmation Dialog -->\n @if (showStopConfirmDialog) {\n <div\n class=\"modal-backdrop\"\n (click)=\"cancelStopConfirm()\"\n role=\"alertdialog\"\n aria-modal=\"true\"\n aria-labelledby=\"stop-dialog-title\"\n aria-describedby=\"stop-dialog-desc\"\n >\n <div class=\"confirm-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"confirm-dialog-icon\">\n <i class=\"fa-solid fa-exclamation-triangle\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"confirm-dialog-content\">\n <h3 class=\"confirm-dialog-title\" id=\"stop-dialog-title\">\n @if (isStoppingAll) {\n Stop All Sessions?\n } @else {\n Stop Session?\n }\n </h3>\n <p class=\"confirm-dialog-message\" id=\"stop-dialog-desc\">\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\"> This session has captured {{ sessionToStop.statementCount }} SQL statements. </span>\n }\n </p>\n </div>\n <div class=\"confirm-dialog-actions\">\n <button mjButton variant=\"danger\" size=\"md\" (click)=\"confirmStopSession()\" [disabled]=\"loading\" [attr.aria-label]=\"isStoppingAll ? 'Confirm stop all sessions' : 'Confirm stop session'\">\n @if (loading) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n Stopping...\n } @else {\n <i class=\"fa-solid fa-stop\" aria-hidden=\"true\"></i>\n @if (isStoppingAll) {\n Stop All Sessions\n } @else {\n Stop Session\n }\n }\n </button>\n <button mjButton variant=\"secondary\" size=\"md\" (click)=\"cancelStopConfirm()\" [disabled]=\"loading\" aria-label=\"Cancel and keep sessions running\">Cancel</button>\n </div>\n </div>\n </div>\n }\n</mj-page-body-interior>\n", styles: ["/* =============================================================================\n Shared Admin Patterns - MJ Design System\n Common styles shared across all admin settings components.\n Component-specific CSS files override these values where needed.\n ============================================================================= */\n\n/* -----------------------------------------------------------------------------\n Host & Container\n ----------------------------------------------------------------------------- */\n:host {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n/* -----------------------------------------------------------------------------\n Sticky Header\n ----------------------------------------------------------------------------- */\n.sticky-header {\n flex-shrink: 0;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n}\n\n/* -----------------------------------------------------------------------------\n Scrollable Content\n ----------------------------------------------------------------------------- */\n.scrollable-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .scrollable-content {\n padding: 1.5rem 2rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content {\n padding: 2rem;\n }\n}\n\n@media (min-width: 1440px) {\n .scrollable-content {\n padding: 2rem 2.5rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Action Buttons (In Sticky Header)\n ----------------------------------------------------------------------------- */\n.action-buttons {\n flex-shrink: 0;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .action-buttons {\n padding: 1rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .action-buttons {\n justify-content: center;\n flex-wrap: wrap;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Statistics Cards Grid - Static Display (Non-interactive)\n ----------------------------------------------------------------------------- */\n.mj-grid-4 {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 1rem 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .mj-grid-4 {\n grid-template-columns: repeat(4, 1fr);\n padding: 0 1.5rem 1rem 1.5rem;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-grid-4 {\n gap: 1rem;\n }\n}\n\n/* Static Card - No hover effects */\n.mj-card {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n pointer-events: none;\n}\n\n@media (min-width: 768px) {\n .mj-card {\n padding: 1rem 1.25rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Stat Icon Containers\n ----------------------------------------------------------------------------- */\n.stat-icon {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .stat-icon {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n.stat-icon-total {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-active {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n/* -----------------------------------------------------------------------------\n Stat Content Typography\n ----------------------------------------------------------------------------- */\n.stat-content {\n flex: 1;\n min-width: 0;\n}\n\n.stat-content .stat-value {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n letter-spacing: -0.02em;\n}\n\n@media (min-width: 768px) {\n .stat-content .stat-value {\n font-size: 2rem;\n }\n}\n\n.stat-content .stat-label {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 0.25rem;\n}\n\n@media (min-width: 768px) {\n .stat-content .stat-label {\n font-size: 0.8125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Filters Section\n ----------------------------------------------------------------------------- */\n.filters-section {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n margin: 0 1rem 0.75rem 1rem;\n padding: 0.75rem;\n border-radius: var(--mj-radius-lg);\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .filters-section {\n margin: 0 1.5rem 1rem 1.5rem;\n padding: 1rem 1.25rem;\n }\n}\n\n.filters-row {\n display: flex;\n gap: 1rem;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n@media (min-width: 768px) {\n .filters-row {\n gap: 1.5rem;\n }\n}\n\n.mj-filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mj-filter-label {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mj-filter-buttons {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Search Input\n ----------------------------------------------------------------------------- */\n.mj-search {\n position: relative;\n flex: 1;\n min-width: 200px;\n}\n\n@media (min-width: 640px) {\n .mj-search {\n min-width: 280px;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-search {\n min-width: 400px;\n max-width: 600px;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search {\n min-width: 500px;\n max-width: 800px;\n }\n}\n\n.mj-search .mj-search-icon {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 1024px) {\n .mj-search .mj-search-icon {\n left: 1.25rem;\n font-size: 1.125rem;\n }\n}\n\n.mj-search .mj-search-input {\n width: 100%;\n padding: 0.875rem 1rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n}\n\n@media (min-width: 1024px) {\n .mj-search .mj-search-input {\n padding: 1rem 1.25rem 1rem 3.25rem;\n font-size: 1.0625rem;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search .mj-search-input {\n padding: 1.125rem 1.5rem 1.125rem 3.5rem;\n }\n}\n\n.mj-search .mj-search-input::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.mj-search .mj-search-input:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-search .mj-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n background: var(--mj-bg-page);\n}\n\n.mj-search:focus-within .mj-search-icon {\n color: var(--mj-brand-primary);\n}\n\n/* -----------------------------------------------------------------------------\n Content Area\n ----------------------------------------------------------------------------- */\n.content-area {\n flex: 1 1 auto;\n overflow: visible;\n position: relative;\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-sm);\n padding: 1rem;\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .content-area {\n padding: 1.5rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Expand Button\n ----------------------------------------------------------------------------- */\n.expand-btn {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: var(--mj-radius-full);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.expand-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.expand-btn i {\n transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n/* -----------------------------------------------------------------------------\n Status Badge\n ----------------------------------------------------------------------------- */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge.status-active {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success);\n}\n\n.status-badge.status-inactive {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error);\n}\n\n.status-badge i {\n font-size: 0.625rem;\n}\n\n/* -----------------------------------------------------------------------------\n Mobile Actions Bar\n ----------------------------------------------------------------------------- */\n.mobile-actions-bar {\n display: none;\n}\n\n.mobile-action-buttons {\n display: flex;\n gap: 0.5rem;\n}\n\n/* -----------------------------------------------------------------------------\n Empty State\n ----------------------------------------------------------------------------- */\n.empty-state {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.empty-state .empty-icon {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 1.5rem;\n}\n\n.empty-state .empty-text {\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n.empty-state .empty-subtext {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Loading State\n ----------------------------------------------------------------------------- */\n.loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n}\n\n/* -----------------------------------------------------------------------------\n Error State\n ----------------------------------------------------------------------------- */\n.error-container {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.error-container .error-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.error-container .error-icon {\n font-size: 3.5rem;\n color: var(--mj-status-error);\n margin-bottom: 1rem;\n}\n\n.error-container .error-message {\n font-size: 1.0625rem;\n color: var(--mj-text-primary);\n margin: 0 0 1.5rem 0;\n}\n\n/* -----------------------------------------------------------------------------\n Modal Dialog\n ----------------------------------------------------------------------------- */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1rem;\n animation: fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 500px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n animation: slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\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 var(--mj-border-default);\n}\n\n.modal-header .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.modal-header .modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.modal-header .modal-close:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-body {\n padding: 1.5rem;\n}\n\n.modal-body p {\n font-size: 1rem;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n line-height: 1.5;\n}\n\n.modal-body p:last-child {\n margin-bottom: 0;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-start;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .modal-dialog {\n width: 95%;\n max-height: 85vh;\n }\n\n .modal-header {\n padding: 1rem;\n }\n\n .modal-header .modal-title {\n font-size: 1.125rem;\n }\n\n .modal-body {\n padding: 1rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n}\n\n/* The legacy \"MJ Button System\" rule block (.mj-btn / .mj-btn-primary /\n .mj-btn-secondary / .mj-btn-ghost / .mj-btn-danger / .mj-btn-sm /\n .mj-btn-icon-only / .mj-btn-icon-mobile) was removed 2026-05-19. These\n rules pre-dated the mjButton directive standardization (the directive\n uses BEM modifiers like .mj-btn--primary, single-dash names like\n .mj-btn-primary don't match it anyway). The base .mj-btn rule WAS active\n though \u2014 its component-scoped specificity outranked button.scss's global\n directive styles, so admin sub-page buttons rendered pill-shaped + 44px\n regardless of the variant/size requested via mjButton inputs. Removing the\n rule lets every sub-page fall back to the directive's intended look. */\n\n/* -----------------------------------------------------------------------------\n Filter Button (Mobile Only)\n ----------------------------------------------------------------------------- */\n.filter-button {\n display: none;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n min-width: 44px;\n}\n\n.filter-button:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.filter-button:active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-button i {\n font-size: 1rem;\n}\n\n/* -----------------------------------------------------------------------------\n Filter Modal (Mobile Bottom Sheet)\n ----------------------------------------------------------------------------- */\n.filter-modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: flex-end;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.filter-modal {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: slideUpFromBottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.filter-modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.filter-modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.filter-modal-title i {\n color: var(--mj-brand-primary);\n font-size: 1.375rem;\n}\n\n.filter-modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.filter-modal-close:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.filter-modal-body {\n padding: 1.5rem;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n.filter-modal-footer {\n display: flex;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.filter-modal-footer button {\n flex: 1;\n margin: 0;\n}\n\n/* Filter Options Container (Inside Modal) */\n.filter-options-container {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.filter-group-label {\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.filter-group-options {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.filter-option {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.filter-option:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-option.selected {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.filter-option input[type=\"checkbox\"],\n.filter-option input[type=\"radio\"] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.filter-option-label {\n flex: 1;\n font-size: 1rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.filter-option.selected .filter-option-label {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* -----------------------------------------------------------------------------\n Utility Classes\n ----------------------------------------------------------------------------- */\n.text-danger {\n color: var(--mj-status-error);\n}\n\n.text-warning {\n color: var(--mj-color-warning-500);\n}\n\n.text-success {\n color: var(--mj-status-success);\n}\n\n/* -----------------------------------------------------------------------------\n Animations\n ----------------------------------------------------------------------------- */\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\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@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes slideUpFromBottom {\n from {\n transform: translateY(100%);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Accessibility: Focus Indicators\n ----------------------------------------------------------------------------- */\n.mj-search-input:focus-visible,\nbutton:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Accessibility: Reduced Motion\n ----------------------------------------------------------------------------- */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n", "/* =============================================================================\n SQL Logging Component - Component-Specific Styles\n Shared patterns are in ../shared/styles/_admin-patterns.css\n ============================================================================= */\n\n/*\n Layout \u2014 host is flex column (from _admin-patterns.css :host).\n <mj-page-header-interior> sits pinned at the top; .scrollable-content\n (also from _admin-patterns) fills the rest with responsive padding.\n Buttons in this component use the mjButton directive \u2014 see Section 10\n of plans/explorer-chrome-conventions.md.\n*/\n\n/* Small-viewport adjustments for the collapsible stats toggle. */\n@media (max-width: 639px) {\n .stats-toggle-button {\n padding: 0.875rem 1rem;\n }\n\n .stats-toggle-icon {\n width: 40px;\n height: 40px;\n font-size: 1rem;\n }\n\n .stats-toggle-title {\n font-size: 0.9375rem;\n }\n\n .stats-toggle-subtitle {\n font-size: 0.75rem;\n }\n\n .stats-toggle-arrow {\n font-size: 1.125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Statistics Grid - Collapsible Cards\n ----------------------------------------------------------------------------- */\n.stats-toggle-container {\n margin-bottom: 1.5rem;\n}\n\n.stats-toggle-button {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem 1.5rem;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.stats-toggle-button:hover {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.stats-toggle-button.expanded {\n border-color: var(--mj-brand-primary);\n background: var(--mj-brand-accent-subtle);\n margin-bottom: 1rem;\n}\n\n.stats-toggle-left {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.stats-toggle-icon {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n background: var(--mj-brand-accent-subtle);\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n.stats-toggle-button.expanded .stats-toggle-icon {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.stats-toggle-text {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.stats-toggle-title {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.stats-toggle-button.expanded .stats-toggle-title {\n color: var(--mj-brand-primary);\n}\n\n.stats-toggle-subtitle {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.stats-toggle-arrow {\n font-size: 1.25rem;\n color: var(--mj-text-secondary);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.stats-toggle-button.expanded .stats-toggle-arrow {\n transform: rotate(180deg);\n color: var(--mj-brand-primary);\n}\n\n.stats-grid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 0.75rem;\n width: 100%;\n overflow: hidden;\n max-height: 0;\n opacity: 0;\n transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.stats-grid.visible {\n max-height: 1000px;\n opacity: 1;\n margin-bottom: 1.5rem;\n}\n\n@media (min-width: 640px) {\n .stats-grid {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n }\n}\n\n@media (min-width: 768px) {\n .stats-toggle-button {\n display: none;\n }\n\n .stats-grid {\n max-height: none;\n opacity: 1;\n margin-bottom: 1.5rem;\n gap: 1.25rem;\n }\n}\n\n@media (min-width: 1024px) {\n .stats-grid {\n grid-template-columns: repeat(4, 1fr);\n gap: 1.5rem;\n }\n}\n\n@media (min-width: 1440px) {\n .stats-grid {\n gap: 2rem;\n }\n}\n\n/* Static Display Card */\n.stat-card {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1.25rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n}\n\n/* Stat Icon Override - Different sizes */\n.stat-icon {\n width: 56px;\n height: 56px;\n font-size: 1.5rem;\n}\n\n@media (max-width: 639px) {\n .stat-icon {\n width: 48px;\n height: 48px;\n font-size: 1.25rem;\n }\n}\n\n.stat-icon-status {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n\n.stat-icon-active {\n background: var(--mj-brand-accent-subtle);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-limit {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.stat-icon-total {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n\n/* Stat Value Override for mobile */\n@media (max-width: 639px) {\n .stat-content .stat-value {\n font-size: 1.5rem;\n font-weight: 700;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Content Area Override - Different styling\n ----------------------------------------------------------------------------- */\n.content-area {\n flex: 1;\n min-height: 0;\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n box-shadow: none;\n}\n\n@media (min-width: 640px) {\n .content-area {\n padding: 1.25rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Sessions Layout - Two-panel design\n ----------------------------------------------------------------------------- */\n.sessions-layout {\n display: flex;\n gap: 1.5rem;\n min-height: 400px;\n overflow: visible;\n}\n\n@media (max-width: 767px) {\n .sessions-layout {\n flex-direction: column;\n gap: 1rem;\n min-height: auto;\n }\n}\n\n@media (min-width: 768px) and (max-width: 1023px) {\n .sessions-layout {\n gap: 1.25rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Sessions Panel\n ----------------------------------------------------------------------------- */\n.sessions-panel {\n flex: 0 0 380px;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n background: var(--mj-bg-surface);\n max-height: 600px;\n}\n\n@media (max-width: 767px) {\n .sessions-panel {\n flex: none;\n max-height: 350px;\n }\n}\n\n@media (min-width: 768px) and (max-width: 1023px) {\n .sessions-panel {\n flex: 0 0 320px;\n }\n}\n\n@media (min-width: 1440px) {\n .sessions-panel {\n flex: 0 0 420px;\n }\n}\n\n.panel-header {\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-shrink: 0;\n gap: 0.5rem;\n}\n\n@media (max-width: 639px) {\n .panel-header {\n padding: 0.75rem;\n flex-wrap: wrap;\n }\n}\n\n.panel-header .panel-title {\n margin: 0;\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n flex-shrink: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@media (max-width: 639px) {\n .panel-header .panel-title {\n font-size: 0.875rem;\n max-width: 50%;\n }\n}\n\n.panel-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n\n@media (max-width: 639px) {\n .panel-actions {\n gap: 0.25rem;\n }\n\n .panel-actions .checkbox-label {\n font-size: 0;\n gap: 0;\n min-height: 36px;\n padding: 0;\n }\n\n .panel-actions .checkbox-label::after {\n content: \"Auto\";\n font-size: 0.75rem;\n margin-left: 0.25rem;\n }\n}\n\n.sessions-list {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n min-height: 0;\n position: relative;\n padding: 0.75rem;\n}\n\n/* -----------------------------------------------------------------------------\n Session Cards\n ----------------------------------------------------------------------------- */\n.session-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 1rem;\n margin-bottom: 0.75rem;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.session-card:last-child {\n margin-bottom: 0;\n}\n\n.session-card:hover {\n box-shadow: var(--mj-shadow-sm);\n border-color: var(--mj-brand-primary);\n}\n\n.session-card.selected {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n background: var(--mj-brand-accent-subtle);\n}\n\n.session-card:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\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 min-width: 0;\n}\n\n.session-info .session-title {\n margin: 0 0 0.5rem 0;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.session-meta {\n display: flex;\n gap: 1rem;\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n flex-wrap: wrap;\n}\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 margin-top: 0.5rem;\n}\n\n/* -----------------------------------------------------------------------------\n Badges - Chips\n ----------------------------------------------------------------------------- */\n.badge {\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n}\n\n.badge-user {\n background: var(--mj-brand-accent-subtle);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n}\n\n.badge-migration {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success);\n}\n\n.badge-type {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning);\n}\n\n/* -----------------------------------------------------------------------------\n Action Buttons (Icon buttons)\n ----------------------------------------------------------------------------- */\n.action-btn {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.action-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.action-btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.action-btn-danger:hover {\n background: var(--mj-status-error);\n color: var(--mj-brand-on-primary);\n}\n\n/* -----------------------------------------------------------------------------\n Log Viewer Panel\n ----------------------------------------------------------------------------- */\n.log-viewer-panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n background: var(--mj-bg-surface);\n min-height: 400px;\n}\n\n@media (max-width: 767px) {\n .log-viewer-panel {\n min-height: 350px;\n }\n}\n\n/* Code editor keeps its dark theme for readability (intentionally hardcoded for code syntax) */\n.log-content {\n flex: 1;\n overflow: hidden;\n min-height: 300px;\n height: 100%;\n position: relative;\n background: var(--mj-text-primary);\n color: var(--mj-border-strong);\n}\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\n.log-content ::ng-deep .cm-scroller {\n font-family: inherit;\n}\n\n.log-content ::ng-deep .cm-content {\n background: var(--mj-text-primary);\n color: var(--mj-border-strong);\n}\n\n.log-content ::ng-deep .cm-gutters {\n background: var(--mj-text-primary);\n color: var(--mj-text-disabled);\n border-right: 1px solid var(--mj-text-secondary);\n}\n\n.log-content ::ng-deep .cm-activeLineGutter {\n background: var(--mj-text-primary);\n}\n\n.log-content ::ng-deep .cm-activeLine {\n background: rgba(255, 255, 255, 0.04);\n}\n\n/* Expanded Log Viewer */\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 cubic-bezier(0, 0, 0.2, 1);\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/* -----------------------------------------------------------------------------\n Empty State Override - Different icon.warning styling\n ----------------------------------------------------------------------------- */\n.empty-state .empty-icon.warning {\n color: var(--mj-status-warning);\n}\n\n.empty-state .empty-subtext {\n max-width: 400px;\n}\n\n/* -----------------------------------------------------------------------------\n Info Box\n ----------------------------------------------------------------------------- */\n.info-box {\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n padding: 1.5rem;\n margin-top: 1.5rem;\n text-align: left;\n max-width: 500px;\n border: 1px solid var(--mj-border-default);\n}\n\n.info-box h4 {\n margin: 0 0 1rem 0;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.info-box ol {\n margin: 0;\n padding-left: 1.25rem;\n font-size: 1rem;\n color: var(--mj-text-primary);\n}\n\n.info-box ol li {\n margin-bottom: 0.5rem;\n}\n\n.info-box code {\n background: var(--mj-bg-surface-active);\n padding: 0.125rem 0.5rem;\n border-radius: var(--mj-radius-sm);\n font-size: 0.8125rem;\n font-family: \"Consolas\", \"Monaco\", \"Courier New\", monospace;\n color: var(--mj-text-primary);\n}\n\n/* -----------------------------------------------------------------------------\n Loading Container Override\n ----------------------------------------------------------------------------- */\n.loading-container {\n min-height: 300px;\n}\n\n.loading-text {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin-top: 1rem;\n}\n\n/* -----------------------------------------------------------------------------\n Modal Dialog Overrides - SQL Logging has its own modal patterns\n ----------------------------------------------------------------------------- */\n.modal-backdrop {\n background: var(--mj-bg-overlay);\n}\n\n.modal-dialog {\n width: 90%;\n display: flex;\n flex-direction: column;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.modal-dialog.modal-large {\n max-width: 700px;\n}\n\n/* Fullscreen mode */\n.modal-dialog.fullscreen {\n max-width: 100vw;\n width: 100vw;\n max-height: 100vh;\n height: 100vh;\n border-radius: 0;\n margin: 0;\n}\n\n@media (max-width: 639px) {\n .modal-dialog {\n width: 95%;\n max-height: 85vh;\n border-radius: var(--mj-radius-2xl);\n }\n\n .modal-dialog.fullscreen {\n border-radius: 0;\n max-height: 100vh;\n }\n}\n\n.modal-header {\n flex-shrink: 0;\n}\n\n@media (max-width: 639px) {\n .modal-header {\n padding: 1rem 1.25rem;\n }\n}\n\n/* Modal Header Actions */\n.modal-header-actions {\n display: flex;\n gap: 0.5rem;\n align-items: center;\n flex-shrink: 0;\n}\n\n.modal-action-btn {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.125rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.modal-action-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-action-btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.modal-body {\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n@media (max-width: 639px) {\n .modal-body {\n padding: 1rem 1.25rem;\n }\n}\n\n.modal-footer {\n justify-content: flex-end;\n flex-shrink: 0;\n}\n\n@media (max-width: 639px) {\n .modal-footer {\n padding: 1rem 1.25rem;\n }\n\n /* Stretch the action buttons to full width on small viewports. */\n .modal-footer button {\n width: 100%;\n justify-content: center;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Form Elements\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: var(--mj-text-primary);\n margin-bottom: 0.5rem;\n}\n\n.form-input,\n.form-select,\n.form-textarea {\n width: 100%;\n min-height: 44px;\n padding: 0.875rem 1rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n font-size: 1rem;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.form-input:hover,\n.form-select:hover,\n.form-textarea:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.form-input:focus,\n.form-select:focus,\n.form-textarea:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n background: var(--mj-bg-surface);\n}\n\n.form-input::placeholder,\n.form-textarea::placeholder {\n color: var(--mj-text-secondary);\n opacity: 0.7;\n}\n\n.form-select {\n cursor: pointer;\n}\n\n.form-hint {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin-top: 0.375rem;\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.625rem;\n font-size: 1rem;\n color: var(--mj-text-primary);\n cursor: pointer;\n min-height: 44px;\n padding: 0.25rem 0;\n}\n\n.checkbox-label input[type=\"checkbox\"] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n/* Form Section */\n.form-section {\n margin-top: 1.5rem;\n padding: 1.25rem;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n background: var(--mj-bg-surface-sunken);\n}\n\n.form-section-title {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n margin: 0 0 1rem 0;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.form-section-title i {\n color: var(--mj-brand-primary);\n font-size: 1.125rem;\n}\n\n.form-textarea {\n font-family: \"Consolas\", \"Monaco\", \"Courier New\", monospace;\n resize: vertical;\n min-height: 100px;\n}\n\n/* -----------------------------------------------------------------------------\n Confirmation Dialog\n ----------------------------------------------------------------------------- */\n.confirm-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 420px;\n width: 90%;\n padding: 2rem;\n text-align: center;\n animation: dialogBounce 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n@media (max-width: 639px) {\n .confirm-dialog {\n padding: 1.5rem;\n border-radius: var(--mj-radius-2xl);\n }\n}\n\n.confirm-dialog-icon {\n width: 64px;\n height: 64px;\n border-radius: 50%;\n background: var(--mj-status-warning-bg);\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1.5rem;\n}\n\n.confirm-dialog-icon i {\n font-size: 1.75rem;\n color: var(--mj-status-warning-text);\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: 600;\n color: var(--mj-text-primary);\n}\n\n.confirm-dialog-message {\n margin: 0;\n font-size: 1rem;\n color: var(--mj-text-secondary);\n line-height: 1.6;\n}\n\n.confirm-dialog-message strong {\n color: var(--mj-text-primary);\n font-weight: 600;\n}\n\n.confirm-dialog-details {\n display: block;\n margin-top: 0.75rem;\n padding: 0.75rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n}\n\n.confirm-dialog-actions {\n display: flex;\n gap: 0.75rem;\n justify-content: center;\n}\n\n@media (max-width: 639px) {\n .confirm-dialog-actions {\n flex-direction: column-reverse;\n }\n\n /* Stretch the action buttons to full width on small viewports. */\n .confirm-dialog-actions button {\n width: 100%;\n justify-content: center;\n }\n}\n\n/* -----------------------------------------------------------------------------\n SQL-Logging-specific Animations\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@keyframes dialogBounce {\n 0% {\n transform: scale(0.9) translateY(10px);\n opacity: 0;\n }\n 70% {\n transform: scale(1.02) translateY(-5px);\n }\n 100% {\n transform: scale(1) translateY(0);\n opacity: 1;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Screen Reader Only\n ----------------------------------------------------------------------------- */\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n"] }]
1285
+ args: [{ standalone: false, selector: 'mj-sql-logging', template: "<!--\n Interior chrome \u2014 sub-page of Admin's Monitoring left-nav shell. Single section\n (no L2 tab nav) so [toolbar] is empty; actions land in [actions]. See Section 10\n of plans/explorer-chrome-conventions.md.\n-->\n<mj-page-header-interior\n Role=\"region\"\n AriaLabel=\"SQL logging actions\"\n Title=\"SQL Logging\"\n Subtitle=\"Capture and download SQL statements executed by the API\">\n <div actions>\n <mj-refresh-button\n [Loading]=\"loading\"\n (Clicked)=\"loadActiveSessions()\">\n </mj-refresh-button>\n @if (isOwner && configEnabled) {\n <button mjButton\n variant=\"primary\"\n size=\"sm\"\n [disabled]=\"loading || activeSessions.length >= (sqlLoggingConfig?.maxActiveSessions || 5)\"\n (click)=\"openStartSessionDialog()\"\n [attr.aria-label]=\"'Start new SQL logging session' + (activeSessions.length >= (sqlLoggingConfig?.maxActiveSessions || 5) ? ' (maximum sessions reached)' : '')\">\n <i class=\"fa-solid fa-play\" aria-hidden=\"true\"></i>\n <span class=\"mj-action-label\">Start New Session</span>\n </button>\n }\n </div>\n</mj-page-header-interior>\n\n<mj-page-body-interior>\n\n <!-- Stats Cards with Toggle -->\n @if (isOwner && configEnabled) {\n <div class=\"stats-toggle-container\">\n <!-- Toggle Button -->\n <button\n class=\"stats-toggle-button\"\n [class.expanded]=\"showStats\"\n (click)=\"showStats = !showStats\"\n [attr.aria-expanded]=\"showStats\"\n aria-controls=\"stats-grid-content\"\n >\n <div class=\"stats-toggle-left\">\n <div class=\"stats-toggle-icon\">\n <i class=\"fa-solid fa-chart-line\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"stats-toggle-text\">\n <h3 class=\"stats-toggle-title\">Statistics</h3>\n <p class=\"stats-toggle-subtitle\">View session statistics and metrics</p>\n </div>\n </div>\n <i class=\"fa-solid fa-chevron-down stats-toggle-arrow\" aria-hidden=\"true\"></i>\n </button>\n\n <!-- Stats Grid (Collapsible) -->\n <div\n id=\"stats-grid-content\"\n class=\"stats-grid\"\n [class.visible]=\"showStats\"\n role=\"region\"\n aria-label=\"SQL logging statistics\"\n >\n <div class=\"stat-card\">\n <div class=\"stat-icon stat-icon-status\">\n <i class=\"fa-solid fa-power-off\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" [attr.aria-label]=\"'Status: ' + (configEnabled ? 'Enabled' : 'Disabled')\">\n {{ configEnabled ? \"Enabled\" : \"Disabled\" }}\n </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\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" [attr.aria-label]=\"activeSessions.length + ' active sessions'\">\n {{ activeSessions.length }}\n </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\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" [attr.aria-label]=\"(sqlLoggingConfig?.maxActiveSessions || 5) + ' maximum sessions allowed'\">\n {{ sqlLoggingConfig?.maxActiveSessions || 5 }}\n </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\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"stat-content\">\n <div class=\"stat-value\" [attr.aria-label]=\"getTotalStatementCount() + ' total SQL statements captured'\">\n {{ getTotalStatementCount() }}\n </div>\n <div class=\"stat-label\">Total Statements</div>\n </div>\n </div>\n </div>\n </div>\n }\n\n <!-- Loading State -->\n @if (loading && !activeSessions.length) {\n <div class=\"loading-container\" role=\"status\" aria-live=\"polite\" aria-busy=\"true\">\n <mj-loading text=\"Loading SQL logging configuration...\" size=\"medium\"></mj-loading>\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\" role=\"alert\">\n <i class=\"fa-solid fa-lock empty-icon\" aria-hidden=\"true\"></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 mjButton variant=\"secondary\" size=\"md\" (click)=\"refreshUserPermissions()\" style=\"margin-top: 1rem\" aria-label=\"Refresh user permissions\">\n <i class=\"fa-solid fa-sync\" aria-hidden=\"true\"></i>\n Refresh Permissions\n </button>\n </div>\n } @else if (!configEnabled) {\n <!-- Not enabled in config -->\n <div class=\"empty-state\" role=\"alert\">\n <i class=\"fa-solid fa-exclamation-triangle empty-icon warning\" aria-hidden=\"true\"></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\" role=\"status\">\n <i class=\"fa-solid fa-file-code empty-icon\" aria-hidden=\"true\"></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 mjButton variant=\"primary\" size=\"md\" (click)=\"openStartSessionDialog()\" style=\"margin-top: 1rem\" aria-label=\"Start a new SQL logging session\">\n <i class=\"fa-solid fa-play\" aria-hidden=\"true\"></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\" role=\"region\" aria-label=\"Active sessions list\">\n <div class=\"panel-header\">\n <h3 class=\"panel-title\">Active Sessions</h3>\n @if (activeSessions.length > 0) {\n <button mjButton\n variant=\"danger\"\n size=\"sm\"\n (click)=\"openStopAllSessionsConfirm()\"\n [disabled]=\"loading\"\n aria-label=\"Stop all active sessions\"\n >\n <i class=\"fa-solid fa-stop\" aria-hidden=\"true\"></i>\n Stop All\n </button>\n }\n </div>\n <div class=\"sessions-list\" role=\"list\" aria-label=\"SQL logging sessions\">\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 role=\"listitem\"\n tabindex=\"0\"\n (keydown.enter)=\"selectSession(session)\"\n (keydown.space)=\"selectSession(session); $event.preventDefault()\"\n [attr.aria-label]=\"'Session: ' + session.sessionName + ', ' + session.statementCount + ' statements, duration ' + getSessionDuration(session.startTime)\"\n [attr.aria-selected]=\"selectedSession?.id === session.id\"\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\" aria-hidden=\"true\"></i>\n {{ getSessionDuration(session.startTime) }}\n </span>\n <span class=\"meta-item\">\n <i class=\"fa-solid fa-database\" aria-hidden=\"true\"></i>\n {{ session.statementCount }} statements\n </span>\n </div>\n </div>\n <button mjButton\n variant=\"danger\"\n size=\"sm\"\n (click)=\"openStopSessionConfirm(session, $event)\"\n [attr.aria-label]=\"'Stop session ' + session.sessionName\"\n >\n <i class=\"fa-solid fa-stop\" aria-hidden=\"true\"></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\" aria-hidden=\"true\"></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\" aria-hidden=\"true\"></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\" role=\"region\" aria-label=\"SQL log viewer\">\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 aria-label=\"Enable auto-refresh\"\n />\n Auto-refresh\n </label>\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n (click)=\"loadSessionLog(selectedSession)\"\n aria-label=\"Refresh log content\"\n >\n <i class=\"fa-solid fa-sync\" [class.fa-spin]=\"loading\" aria-hidden=\"true\"></i>\n </button>\n <button mjButton\n variant=\"flat\"\n size=\"sm\"\n (click)=\"toggleLogViewerExpand()\"\n [attr.aria-label]=\"isLogViewerExpanded ? 'Collapse log viewer' : 'Expand log viewer to fullscreen'\"\n [attr.aria-expanded]=\"isLogViewerExpanded\"\n >\n <i class=\"fa-solid\" [class.fa-expand]=\"!isLogViewerExpanded\" [class.fa-compress]=\"isLogViewerExpanded\" aria-hidden=\"true\"></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 aria-label=\"SQL log content\"\n ></mj-code-editor>\n </div>\n } @else {\n <div class=\"empty-state\" role=\"status\">\n <i class=\"fa-solid fa-arrow-left empty-icon\" aria-hidden=\"true\"></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\n class=\"modal-backdrop\"\n (click)=\"showStartSessionDialog = false\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"start-session-dialog-title\"\n >\n <div class=\"modal-dialog modal-large\" [class.fullscreen]=\"isStartDialogFullscreen\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\">\n <h3 class=\"modal-title\" id=\"start-session-dialog-title\">\n <i class=\"fa-solid fa-play\" aria-hidden=\"true\"></i>\n Start SQL Logging Session\n </h3>\n <div class=\"modal-header-actions\">\n <button\n class=\"modal-action-btn\"\n (click)=\"toggleStartDialogFullscreen()\"\n [attr.aria-label]=\"isStartDialogFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'\"\n type=\"button\"\n >\n <i class=\"fa-solid\" [class.fa-compress]=\"isStartDialogFullscreen\" [class.fa-expand]=\"!isStartDialogFullscreen\" aria-hidden=\"true\"></i>\n </button>\n <button class=\"modal-close\" (click)=\"showStartSessionDialog = false\" aria-label=\"Close dialog\">\n <i class=\"fa-solid fa-times\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n <div class=\"modal-body\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"session-name\">Session Name</label>\n <input\n type=\"text\"\n id=\"session-name\"\n class=\"form-input\"\n [(ngModel)]=\"newSessionOptions.sessionName\"\n placeholder=\"Enter a descriptive name for this session\"\n aria-describedby=\"session-name-hint\"\n />\n <div id=\"session-name-hint\" class=\"form-hint\">A descriptive name to identify this logging session</div>\n </div>\n\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"file-name\">File Name</label>\n <input\n type=\"text\"\n id=\"file-name\"\n class=\"form-input\"\n [(ngModel)]=\"newSessionOptions.fileName\"\n placeholder=\"sql-log-2024-01-01.sql\"\n aria-describedby=\"file-name-hint\"\n />\n <div id=\"file-name-hint\" 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\" for=\"statement-types\">Statement Types</label>\n <select\n id=\"statement-types\"\n class=\"form-select\"\n [(ngModel)]=\"newSessionOptions.statementTypes\"\n aria-describedby=\"statement-types-hint\"\n >\n @for (option of statementTypeOptions; track option.value) {\n <option [value]=\"option.value\">{{ option.text }}</option>\n }\n </select>\n <div id=\"statement-types-hint\" class=\"form-hint\">Filter which types of SQL statements to capture</div>\n </div>\n\n <div class=\"form-checkboxes\" role=\"group\" aria-label=\"Session options\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" [(ngModel)]=\"newSessionOptions.filterToCurrentUser\" />\n Filter to my SQL statements only\n </label>\n\n\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" [(ngModel)]=\"newSessionOptions.formatAsMigration\" />\n Format as migration file\n </label>\n\n\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" [(ngModel)]=\"newSessionOptions.prettyPrint\" />\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\" aria-hidden=\"true\"></i>\n SQL Pattern Filtering\n </h4>\n\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"filter-type\">Filter Mode</label>\n <select\n id=\"filter-type\"\n class=\"form-select\"\n [(ngModel)]=\"newSessionOptions.filterType\"\n aria-describedby=\"filter-type-hint\"\n >\n @for (option of filterTypeOptions; track option.value) {\n <option [value]=\"option.value\">{{ option.text }}</option>\n }\n </select>\n <div id=\"filter-type-hint\" class=\"form-hint\">Exclude: Skip SQL matching any pattern. Include: Only log SQL matching a pattern.</div>\n </div>\n\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"filter-patterns\">Filter Patterns (one per line or comma-separated)</label>\n <textarea\n id=\"filter-patterns\"\n class=\"form-textarea\"\n [(ngModel)]=\"newSessionOptions.filterPatterns\"\n rows=\"4\"\n placeholder=\"Examples:&#10;*AIPrompt*&#10;/spCreate.*Run/i&#10;SELECT * FROM vwMetadata\"\n aria-describedby=\"filter-patterns-hint\"\n ></textarea>\n <div id=\"filter-patterns-hint\" class=\"form-hint\">Supports wildcards (*) and regex (/pattern/flags). Example: *spCreate* matches any SP starting with spCreate.</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\" aria-hidden=\"true\"></i>\n Advanced Options\n </h4>\n\n @if (newSessionOptions.formatAsMigration) {\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"default-schema\">Default Schema Name</label>\n <input\n type=\"text\"\n id=\"default-schema\"\n class=\"form-input\"\n [(ngModel)]=\"newSessionOptions.defaultSchemaName\"\n placeholder=\"__mj\"\n aria-describedby=\"default-schema-hint\"\n />\n <div id=\"default-schema-hint\" class=\"form-hint\">Schema name to replace with $&#123;flyway:defaultSchema&#125; placeholder.</div>\n </div>\n }\n\n <div class=\"form-checkboxes\">\n <label class=\"checkbox-label\">\n <input type=\"checkbox\" [(ngModel)]=\"newSessionOptions.verboseOutput\" />\n Verbose Debug Output\n </label>\n <div class=\"form-hint\" style=\"margin-left: 1.75rem\">Log detailed filter decisions to server console (for debugging).</div>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button mjButton variant=\"primary\" size=\"md\" (click)=\"startNewSession()\" [disabled]=\"loading\" aria-label=\"Start the SQL logging session\">\n @if (loading) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n Starting...\n } @else {\n <i class=\"fa-solid fa-play\" aria-hidden=\"true\"></i>\n Start Session\n }\n </button>\n <button mjButton variant=\"secondary\" size=\"md\" (click)=\"showStartSessionDialog = false\" aria-label=\"Cancel and close dialog\">Cancel</button>\n </div>\n </div>\n </div>\n }\n\n <!-- Stop Session Confirmation Dialog -->\n @if (showStopConfirmDialog) {\n <div\n class=\"modal-backdrop\"\n (click)=\"cancelStopConfirm()\"\n role=\"alertdialog\"\n aria-modal=\"true\"\n aria-labelledby=\"stop-dialog-title\"\n aria-describedby=\"stop-dialog-desc\"\n >\n <div class=\"confirm-dialog\" (click)=\"$event.stopPropagation()\">\n <div class=\"confirm-dialog-icon\">\n <i class=\"fa-solid fa-exclamation-triangle\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"confirm-dialog-content\">\n <h3 class=\"confirm-dialog-title\" id=\"stop-dialog-title\">\n @if (isStoppingAll) {\n Stop All Sessions?\n } @else {\n Stop Session?\n }\n </h3>\n <p class=\"confirm-dialog-message\" id=\"stop-dialog-desc\">\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\"> This session has captured {{ sessionToStop.statementCount }} SQL statements. </span>\n }\n </p>\n </div>\n <div class=\"confirm-dialog-actions\">\n <button mjButton variant=\"danger\" size=\"md\" (click)=\"confirmStopSession()\" [disabled]=\"loading\" [attr.aria-label]=\"isStoppingAll ? 'Confirm stop all sessions' : 'Confirm stop session'\">\n @if (loading) {\n <i class=\"fa-solid fa-spinner fa-spin\" aria-hidden=\"true\"></i>\n Stopping...\n } @else {\n <i class=\"fa-solid fa-stop\" aria-hidden=\"true\"></i>\n @if (isStoppingAll) {\n Stop All Sessions\n } @else {\n Stop Session\n }\n }\n </button>\n <button mjButton variant=\"secondary\" size=\"md\" (click)=\"cancelStopConfirm()\" [disabled]=\"loading\" aria-label=\"Cancel and keep sessions running\">Cancel</button>\n </div>\n </div>\n </div>\n }\n</mj-page-body-interior>\n", styles: ["/* =============================================================================\n Shared Admin Patterns - MJ Design System\n Common styles shared across all admin settings components.\n Component-specific CSS files override these values where needed.\n ============================================================================= */\n\n/* -----------------------------------------------------------------------------\n Host & Container\n ----------------------------------------------------------------------------- */\n:host {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n/* -----------------------------------------------------------------------------\n Sticky Header\n ----------------------------------------------------------------------------- */\n.sticky-header {\n flex-shrink: 0;\n background: var(--mj-bg-page);\n border-bottom: 1px solid var(--mj-border-default);\n box-shadow: var(--mj-shadow-sm);\n z-index: 10;\n}\n\n/* -----------------------------------------------------------------------------\n Scrollable Content\n ----------------------------------------------------------------------------- */\n.scrollable-content {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (min-width: 768px) {\n .scrollable-content {\n padding: 1.5rem 2rem;\n }\n}\n\n@media (min-width: 1024px) {\n .scrollable-content {\n padding: 2rem;\n }\n}\n\n@media (min-width: 1440px) {\n .scrollable-content {\n padding: 2rem 2.5rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Action Buttons (In Sticky Header)\n ----------------------------------------------------------------------------- */\n.action-buttons {\n flex-shrink: 0;\n display: flex;\n gap: 0.75rem;\n justify-content: flex-end;\n padding: 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .action-buttons {\n padding: 1rem 1.5rem;\n }\n}\n\n@media (max-width: 639px) {\n .action-buttons {\n justify-content: center;\n flex-wrap: wrap;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Statistics Cards Grid - Static Display (Non-interactive)\n ----------------------------------------------------------------------------- */\n.mj-grid-4 {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 0.5rem;\n padding: 0 1rem 0.75rem 1rem;\n background: var(--mj-bg-page);\n}\n\n@media (min-width: 768px) {\n .mj-grid-4 {\n grid-template-columns: repeat(4, 1fr);\n padding: 0 1.5rem 1rem 1.5rem;\n gap: 0.75rem;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-grid-4 {\n gap: 1rem;\n }\n}\n\n/* Static Card - No hover effects */\n.mj-card {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n pointer-events: none;\n}\n\n@media (min-width: 768px) {\n .mj-card {\n padding: 1rem 1.25rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Stat Icon Containers\n ----------------------------------------------------------------------------- */\n.stat-icon {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n@media (min-width: 768px) {\n .stat-icon {\n width: 52px;\n height: 52px;\n font-size: 1.375rem;\n }\n}\n\n.stat-icon-total {\n background: var(--mj-color-accent-300);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-active {\n background: var(--mj-color-success-100);\n color: var(--mj-status-success);\n}\n\n/* -----------------------------------------------------------------------------\n Stat Content Typography\n ----------------------------------------------------------------------------- */\n.stat-content {\n flex: 1;\n min-width: 0;\n}\n\n.stat-content .stat-value {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1;\n letter-spacing: -0.02em;\n}\n\n@media (min-width: 768px) {\n .stat-content .stat-value {\n font-size: 2rem;\n }\n}\n\n.stat-content .stat-label {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin-top: 0.25rem;\n}\n\n@media (min-width: 768px) {\n .stat-content .stat-label {\n font-size: 0.8125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Filters Section\n ----------------------------------------------------------------------------- */\n.filters-section {\n flex-shrink: 0;\n background: var(--mj-bg-surface-card);\n margin: 0 1rem 0.75rem 1rem;\n padding: 0.75rem;\n border-radius: var(--mj-radius-lg);\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .filters-section {\n margin: 0 1.5rem 1rem 1.5rem;\n padding: 1rem 1.25rem;\n }\n}\n\n.filters-row {\n display: flex;\n gap: 1rem;\n align-items: flex-end;\n flex-wrap: wrap;\n}\n\n@media (min-width: 768px) {\n .filters-row {\n gap: 1.5rem;\n }\n}\n\n.mj-filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.mj-filter-label {\n font-size: 0.75rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n.mj-filter-buttons {\n display: flex;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-full);\n padding: 4px;\n gap: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Search Input\n ----------------------------------------------------------------------------- */\n.mj-search {\n position: relative;\n flex: 1;\n min-width: 200px;\n}\n\n@media (min-width: 640px) {\n .mj-search {\n min-width: 280px;\n }\n}\n\n@media (min-width: 1024px) {\n .mj-search {\n min-width: 400px;\n max-width: 600px;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search {\n min-width: 500px;\n max-width: 800px;\n }\n}\n\n.mj-search .mj-search-icon {\n position: absolute;\n left: 1rem;\n top: 50%;\n transform: translateY(-50%);\n color: var(--mj-text-secondary);\n font-size: 1rem;\n pointer-events: none;\n transition: color 0.2s ease;\n}\n\n@media (min-width: 1024px) {\n .mj-search .mj-search-icon {\n left: 1.25rem;\n font-size: 1.125rem;\n }\n}\n\n.mj-search .mj-search-input {\n width: 100%;\n padding: 0.875rem 1rem 0.875rem 2.75rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-full);\n font-size: 1rem;\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n}\n\n@media (min-width: 1024px) {\n .mj-search .mj-search-input {\n padding: 1rem 1.25rem 1rem 3.25rem;\n font-size: 1.0625rem;\n }\n}\n\n@media (min-width: 1440px) {\n .mj-search .mj-search-input {\n padding: 1.125rem 1.5rem 1.125rem 3.5rem;\n }\n}\n\n.mj-search .mj-search-input::placeholder {\n color: var(--mj-text-secondary);\n}\n\n.mj-search .mj-search-input:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.mj-search .mj-search-input:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px rgba(0, 118, 182, 0.2);\n background: var(--mj-bg-page);\n}\n\n.mj-search:focus-within .mj-search-icon {\n color: var(--mj-brand-primary);\n}\n\n/* -----------------------------------------------------------------------------\n Content Area\n ----------------------------------------------------------------------------- */\n.content-area {\n flex: 1 1 auto;\n overflow: visible;\n position: relative;\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-xl);\n box-shadow: var(--mj-shadow-sm);\n padding: 1rem;\n border: 1px solid var(--mj-border-default);\n}\n\n@media (min-width: 768px) {\n .content-area {\n padding: 1.5rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Expand Button\n ----------------------------------------------------------------------------- */\n.expand-btn {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n cursor: pointer;\n transition: all 0.2s ease;\n border-radius: var(--mj-radius-full);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.expand-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.expand-btn i {\n transition: transform 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n/* -----------------------------------------------------------------------------\n Status Badge\n ----------------------------------------------------------------------------- */\n.status-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n\n.status-badge.status-active {\n background: var(--mj-color-success-100);\n color: var(--mj-color-success-800);\n border: 1px solid var(--mj-status-success);\n}\n\n.status-badge.status-inactive {\n background: var(--mj-color-error-100);\n color: var(--mj-status-error);\n border: 1px solid var(--mj-status-error);\n}\n\n.status-badge i {\n font-size: 0.625rem;\n}\n\n/* -----------------------------------------------------------------------------\n Mobile Actions Bar\n ----------------------------------------------------------------------------- */\n.mobile-actions-bar {\n display: none;\n}\n\n.mobile-action-buttons {\n display: flex;\n gap: 0.5rem;\n}\n\n/* -----------------------------------------------------------------------------\n Empty State\n ----------------------------------------------------------------------------- */\n.empty-state {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.empty-state .empty-icon {\n font-size: 4rem;\n color: var(--mj-border-default);\n margin-bottom: 1.5rem;\n}\n\n.empty-state .empty-text {\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0 0 0.5rem 0;\n}\n\n.empty-state .empty-subtext {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n/* -----------------------------------------------------------------------------\n Loading State\n ----------------------------------------------------------------------------- */\n.loading-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 4rem 2rem;\n}\n\n/* -----------------------------------------------------------------------------\n Error State\n ----------------------------------------------------------------------------- */\n.error-container {\n text-align: center;\n padding: 4rem 2rem;\n}\n\n.error-container .error-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 1rem;\n}\n\n.error-container .error-icon {\n font-size: 3.5rem;\n color: var(--mj-status-error);\n margin-bottom: 1rem;\n}\n\n.error-container .error-message {\n font-size: 1.0625rem;\n color: var(--mj-text-primary);\n margin: 0 0 1.5rem 0;\n}\n\n/* -----------------------------------------------------------------------------\n Modal Dialog\n ----------------------------------------------------------------------------- */\n.modal-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 1rem;\n animation: fadeIn 0.2s cubic-bezier(0, 0, 0.2, 1);\n}\n\n.modal-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 500px;\n width: 100%;\n max-height: 90vh;\n overflow: hidden;\n animation: slideUp 0.3s cubic-bezier(0, 0, 0.2, 1);\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 var(--mj-border-default);\n}\n\n.modal-header .modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.375rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.modal-header .modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.modal-header .modal-close:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-body {\n padding: 1.5rem;\n}\n\n.modal-body p {\n font-size: 1rem;\n color: var(--mj-text-primary);\n margin: 0 0 1rem 0;\n line-height: 1.5;\n}\n\n.modal-body p:last-child {\n margin-bottom: 0;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-start;\n gap: 0.75rem;\n padding: 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n\n@media (max-width: 639px) {\n .modal-dialog {\n width: 95%;\n max-height: 85vh;\n }\n\n .modal-header {\n padding: 1rem;\n }\n\n .modal-header .modal-title {\n font-size: 1.125rem;\n }\n\n .modal-body {\n padding: 1rem;\n }\n\n .modal-footer {\n padding: 1rem;\n flex-direction: column;\n }\n\n}\n\n/* The legacy \"MJ Button System\" rule block (.mj-btn / .mj-btn-primary /\n .mj-btn-secondary / .mj-btn-ghost / .mj-btn-danger / .mj-btn-sm /\n .mj-btn-icon-only / .mj-btn-icon-mobile) was removed 2026-05-19. These\n rules pre-dated the mjButton directive standardization (the directive\n uses BEM modifiers like .mj-btn--primary, single-dash names like\n .mj-btn-primary don't match it anyway). The base .mj-btn rule WAS active\n though \u2014 its component-scoped specificity outranked button.scss's global\n directive styles, so admin sub-page buttons rendered pill-shaped + 44px\n regardless of the variant/size requested via mjButton inputs. Removing the\n rule lets every sub-page fall back to the directive's intended look. */\n\n/* -----------------------------------------------------------------------------\n Filter Button (Mobile Only)\n ----------------------------------------------------------------------------- */\n.filter-button {\n display: none;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: 0.75rem 1.25rem;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-page);\n color: var(--mj-text-primary);\n border-radius: var(--mj-radius-full);\n font-size: 0.875rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 44px;\n min-width: 44px;\n}\n\n.filter-button:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.filter-button:active {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-button i {\n font-size: 1rem;\n}\n\n/* -----------------------------------------------------------------------------\n Filter Modal (Mobile Bottom Sheet)\n ----------------------------------------------------------------------------- */\n.filter-modal-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(4px);\n display: flex;\n align-items: flex-end;\n justify-content: center;\n z-index: 1000;\n animation: fadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n}\n\n.filter-modal {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl) var(--mj-radius-2xl) 0 0;\n box-shadow: var(--mj-shadow-2xl);\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: slideUpFromBottom 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n display: flex;\n flex-direction: column;\n}\n\n.filter-modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 1.25rem 1.5rem;\n border-bottom: 1px solid var(--mj-border-default);\n flex-shrink: 0;\n}\n\n.filter-modal-title {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.filter-modal-title i {\n color: var(--mj-brand-primary);\n font-size: 1.375rem;\n}\n\n.filter-modal-close {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.25rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s ease;\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.filter-modal-close:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.filter-modal-body {\n padding: 1.5rem;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n.filter-modal-footer {\n display: flex;\n gap: 0.75rem;\n padding: 1.25rem 1.5rem;\n border-top: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n flex-shrink: 0;\n}\n\n.filter-modal-footer button {\n flex: 1;\n margin: 0;\n}\n\n/* Filter Options Container (Inside Modal) */\n.filter-options-container {\n display: flex;\n flex-direction: column;\n gap: 1.5rem;\n}\n\n.filter-group {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n}\n\n.filter-group-label {\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n margin: 0;\n}\n\n.filter-group-options {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n\n.filter-option {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.875rem 1rem;\n background: var(--mj-bg-surface-sunken);\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.filter-option:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface-sunken);\n}\n\n.filter-option.selected {\n background: var(--mj-color-accent-300);\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.filter-option input[type=\"checkbox\"],\n.filter-option input[type=\"radio\"] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n.filter-option-label {\n flex: 1;\n font-size: 1rem;\n font-weight: 500;\n color: var(--mj-text-primary);\n}\n\n.filter-option.selected .filter-option-label {\n color: var(--mj-brand-primary);\n font-weight: 600;\n}\n\n/* -----------------------------------------------------------------------------\n Utility Classes\n ----------------------------------------------------------------------------- */\n.text-danger {\n color: var(--mj-status-error);\n}\n\n.text-warning {\n color: var(--mj-color-warning-500);\n}\n\n.text-success {\n color: var(--mj-status-success);\n}\n\n/* -----------------------------------------------------------------------------\n Animations\n ----------------------------------------------------------------------------- */\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\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@keyframes slideDown {\n from {\n opacity: 0;\n transform: translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes slideUpFromBottom {\n from {\n transform: translateY(100%);\n opacity: 0;\n }\n to {\n transform: translateY(0);\n opacity: 1;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Accessibility: Focus Indicators\n ----------------------------------------------------------------------------- */\n.mj-search-input:focus-visible,\nbutton:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n/* -----------------------------------------------------------------------------\n Accessibility: Reduced Motion\n ----------------------------------------------------------------------------- */\n@media (prefers-reduced-motion: reduce) {\n *,\n *::before,\n *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n}\n", "/* =============================================================================\n SQL Logging Component - Component-Specific Styles\n Shared patterns are in ../shared/styles/_admin-patterns.css\n ============================================================================= */\n\n/*\n Layout \u2014 host is flex column (from _admin-patterns.css :host).\n <mj-page-header-interior> sits pinned at the top; .scrollable-content\n (also from _admin-patterns) fills the rest with responsive padding.\n Buttons in this component use the mjButton directive \u2014 see Section 10\n of plans/explorer-chrome-conventions.md.\n*/\n\n/* Small-viewport adjustments for the collapsible stats toggle. */\n@media (max-width: 639px) {\n .stats-toggle-button {\n padding: 0.875rem 1rem;\n }\n\n .stats-toggle-icon {\n width: 40px;\n height: 40px;\n font-size: 1rem;\n }\n\n .stats-toggle-title {\n font-size: 0.9375rem;\n }\n\n .stats-toggle-subtitle {\n font-size: 0.75rem;\n }\n\n .stats-toggle-arrow {\n font-size: 1.125rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Statistics Grid - Collapsible Cards\n ----------------------------------------------------------------------------- */\n.stats-toggle-container {\n margin-bottom: 1.5rem;\n}\n\n.stats-toggle-button {\n width: 100%;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 1rem 1.5rem;\n background: var(--mj-bg-surface-sunken);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-height: 56px;\n}\n\n.stats-toggle-button:hover {\n background: var(--mj-bg-surface-active);\n border-color: var(--mj-brand-primary);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.stats-toggle-button.expanded {\n border-color: var(--mj-brand-primary);\n background: var(--mj-brand-accent-subtle);\n margin-bottom: 1rem;\n}\n\n.stats-toggle-left {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.stats-toggle-icon {\n width: 48px;\n height: 48px;\n border-radius: var(--mj-radius-lg);\n background: var(--mj-brand-accent-subtle);\n color: var(--mj-brand-primary);\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25rem;\n flex-shrink: 0;\n}\n\n.stats-toggle-button.expanded .stats-toggle-icon {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.stats-toggle-text {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n}\n\n.stats-toggle-title {\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n margin: 0;\n}\n\n.stats-toggle-button.expanded .stats-toggle-title {\n color: var(--mj-brand-primary);\n}\n\n.stats-toggle-subtitle {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin: 0;\n}\n\n.stats-toggle-arrow {\n font-size: 1.25rem;\n color: var(--mj-text-secondary);\n transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.stats-toggle-button.expanded .stats-toggle-arrow {\n transform: rotate(180deg);\n color: var(--mj-brand-primary);\n}\n\n.stats-grid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 0.75rem;\n width: 100%;\n overflow: hidden;\n max-height: 0;\n opacity: 0;\n transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.stats-grid.visible {\n max-height: 1000px;\n opacity: 1;\n margin-bottom: 1.5rem;\n}\n\n@media (min-width: 640px) {\n .stats-grid {\n grid-template-columns: repeat(2, 1fr);\n gap: 1rem;\n }\n}\n\n@media (min-width: 768px) {\n .stats-toggle-button {\n display: none;\n }\n\n .stats-grid {\n max-height: none;\n opacity: 1;\n margin-bottom: 1.5rem;\n gap: 1.25rem;\n }\n}\n\n@media (min-width: 1024px) {\n .stats-grid {\n grid-template-columns: repeat(4, 1fr);\n gap: 1.5rem;\n }\n}\n\n@media (min-width: 1440px) {\n .stats-grid {\n gap: 2rem;\n }\n}\n\n/* Static Display Card */\n.stat-card {\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n padding: 1.25rem;\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n gap: 1rem;\n border: 1px solid var(--mj-border-default);\n cursor: default;\n}\n\n/* Stat Icon Override - Different sizes */\n.stat-icon {\n width: 56px;\n height: 56px;\n font-size: 1.5rem;\n}\n\n@media (max-width: 639px) {\n .stat-icon {\n width: 48px;\n height: 48px;\n font-size: 1.25rem;\n }\n}\n\n.stat-icon-status {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n\n.stat-icon-active {\n background: var(--mj-brand-accent-subtle);\n color: var(--mj-brand-primary);\n}\n\n.stat-icon-limit {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.stat-icon-total {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n\n/* Stat Value Override for mobile */\n@media (max-width: 639px) {\n .stat-content .stat-value {\n font-size: 1.5rem;\n font-weight: 700;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Content Area Override - Different styling\n ----------------------------------------------------------------------------- */\n.content-area {\n flex: 1;\n min-height: 0;\n background: var(--mj-bg-surface-card);\n border-radius: var(--mj-radius-lg);\n box-shadow: none;\n}\n\n@media (min-width: 640px) {\n .content-area {\n padding: 1.25rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Sessions Layout - Two-panel design\n ----------------------------------------------------------------------------- */\n.sessions-layout {\n display: flex;\n gap: 1.5rem;\n min-height: 400px;\n overflow: visible;\n}\n\n@media (max-width: 767px) {\n .sessions-layout {\n flex-direction: column;\n gap: 1rem;\n min-height: auto;\n }\n}\n\n@media (min-width: 768px) and (max-width: 1023px) {\n .sessions-layout {\n gap: 1.25rem;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Sessions Panel\n ----------------------------------------------------------------------------- */\n.sessions-panel {\n flex: 0 0 380px;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n background: var(--mj-bg-surface);\n max-height: 600px;\n}\n\n@media (max-width: 767px) {\n .sessions-panel {\n flex: none;\n max-height: 350px;\n }\n}\n\n@media (min-width: 768px) and (max-width: 1023px) {\n .sessions-panel {\n flex: 0 0 320px;\n }\n}\n\n@media (min-width: 1440px) {\n .sessions-panel {\n flex: 0 0 420px;\n }\n}\n\n.panel-header {\n padding: 1rem;\n background: var(--mj-bg-surface-sunken);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-shrink: 0;\n gap: 0.5rem;\n}\n\n@media (max-width: 639px) {\n .panel-header {\n padding: 0.75rem;\n flex-wrap: wrap;\n }\n}\n\n.panel-header .panel-title {\n margin: 0;\n font-size: 1rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n flex-shrink: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@media (max-width: 639px) {\n .panel-header .panel-title {\n font-size: 0.875rem;\n max-width: 50%;\n }\n}\n\n.panel-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n\n@media (max-width: 639px) {\n .panel-actions {\n gap: 0.25rem;\n }\n\n .panel-actions .checkbox-label {\n font-size: 0;\n gap: 0;\n min-height: 36px;\n padding: 0;\n }\n\n .panel-actions .checkbox-label::after {\n content: \"Auto\";\n font-size: 0.75rem;\n margin-left: 0.25rem;\n }\n}\n\n.sessions-list {\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n min-height: 0;\n position: relative;\n padding: 0.75rem;\n}\n\n/* -----------------------------------------------------------------------------\n Session Cards\n ----------------------------------------------------------------------------- */\n.session-card {\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n padding: 1rem;\n margin-bottom: 0.75rem;\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.session-card:last-child {\n margin-bottom: 0;\n}\n\n.session-card:hover {\n box-shadow: var(--mj-shadow-sm);\n border-color: var(--mj-brand-primary);\n}\n\n.session-card.selected {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n background: var(--mj-brand-accent-subtle);\n}\n\n.session-card:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\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 min-width: 0;\n}\n\n.session-info .session-title {\n margin: 0 0 0.5rem 0;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.session-meta {\n display: flex;\n gap: 1rem;\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n flex-wrap: wrap;\n}\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 margin-top: 0.5rem;\n}\n\n/* -----------------------------------------------------------------------------\n Badges - Chips\n ----------------------------------------------------------------------------- */\n.badge {\n padding: 0.375rem 0.875rem;\n border-radius: var(--mj-radius-full);\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n}\n\n.badge-user {\n background: var(--mj-brand-accent-subtle);\n color: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n}\n\n.badge-migration {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success);\n}\n\n.badge-type {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n border: 1px solid var(--mj-status-warning);\n}\n\n/* -----------------------------------------------------------------------------\n Action Buttons (Icon buttons)\n ----------------------------------------------------------------------------- */\n.action-btn {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1rem;\n border-radius: var(--mj-radius-full);\n cursor: pointer;\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.action-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.action-btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.action-btn-danger:hover {\n background: var(--mj-status-error);\n color: var(--mj-brand-on-primary);\n}\n\n/* -----------------------------------------------------------------------------\n Log Viewer Panel\n ----------------------------------------------------------------------------- */\n.log-viewer-panel {\n flex: 1;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n overflow: hidden;\n background: var(--mj-bg-surface);\n min-height: 400px;\n}\n\n@media (max-width: 767px) {\n .log-viewer-panel {\n min-height: 350px;\n }\n}\n\n/* Code editor keeps its dark theme for readability (intentionally hardcoded for code syntax) */\n.log-content {\n flex: 1;\n overflow: hidden;\n min-height: 300px;\n height: 100%;\n position: relative;\n background: var(--mj-text-primary);\n color: var(--mj-border-strong);\n}\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\n.log-content ::ng-deep .cm-scroller {\n font-family: inherit;\n}\n\n.log-content ::ng-deep .cm-content {\n background: var(--mj-text-primary);\n color: var(--mj-border-strong);\n}\n\n.log-content ::ng-deep .cm-gutters {\n background: var(--mj-text-primary);\n color: var(--mj-text-disabled);\n border-right: 1px solid var(--mj-text-secondary);\n}\n\n.log-content ::ng-deep .cm-activeLineGutter {\n background: var(--mj-text-primary);\n}\n\n.log-content ::ng-deep .cm-activeLine {\n background: rgba(255, 255, 255, 0.04);\n}\n\n/* Expanded Log Viewer */\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 cubic-bezier(0, 0, 0.2, 1);\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/* -----------------------------------------------------------------------------\n Empty State Override - Different icon.warning styling\n ----------------------------------------------------------------------------- */\n.empty-state .empty-icon.warning {\n color: var(--mj-status-warning);\n}\n\n.empty-state .empty-subtext {\n max-width: 400px;\n}\n\n/* -----------------------------------------------------------------------------\n Info Box\n ----------------------------------------------------------------------------- */\n.info-box {\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-lg);\n padding: 1.5rem;\n margin-top: 1.5rem;\n text-align: left;\n max-width: 500px;\n border: 1px solid var(--mj-border-default);\n}\n\n.info-box h4 {\n margin: 0 0 1rem 0;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.info-box ol {\n margin: 0;\n padding-left: 1.25rem;\n font-size: 1rem;\n color: var(--mj-text-primary);\n}\n\n.info-box ol li {\n margin-bottom: 0.5rem;\n}\n\n.info-box code {\n background: var(--mj-bg-surface-active);\n padding: 0.125rem 0.5rem;\n border-radius: var(--mj-radius-sm);\n font-size: 0.8125rem;\n font-family: \"Consolas\", \"Monaco\", \"Courier New\", monospace;\n color: var(--mj-text-primary);\n}\n\n/* -----------------------------------------------------------------------------\n Loading Container Override\n ----------------------------------------------------------------------------- */\n.loading-container {\n min-height: 300px;\n}\n\n.loading-text {\n font-size: 1rem;\n color: var(--mj-text-secondary);\n margin-top: 1rem;\n}\n\n/* -----------------------------------------------------------------------------\n Modal Dialog Overrides - SQL Logging has its own modal patterns\n ----------------------------------------------------------------------------- */\n.modal-backdrop {\n background: var(--mj-bg-overlay);\n}\n\n.modal-dialog {\n width: 90%;\n display: flex;\n flex-direction: column;\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.modal-dialog.modal-large {\n max-width: 700px;\n}\n\n/* Fullscreen mode */\n.modal-dialog.fullscreen {\n max-width: 100vw;\n width: 100vw;\n max-height: 100vh;\n height: 100vh;\n border-radius: 0;\n margin: 0;\n}\n\n@media (max-width: 639px) {\n .modal-dialog {\n width: 95%;\n max-height: 85vh;\n border-radius: var(--mj-radius-2xl);\n }\n\n .modal-dialog.fullscreen {\n border-radius: 0;\n max-height: 100vh;\n }\n}\n\n.modal-header {\n flex-shrink: 0;\n}\n\n@media (max-width: 639px) {\n .modal-header {\n padding: 1rem 1.25rem;\n }\n}\n\n/* Modal Header Actions */\n.modal-header-actions {\n display: flex;\n gap: 0.5rem;\n align-items: center;\n flex-shrink: 0;\n}\n\n.modal-action-btn {\n padding: 0.625rem;\n border: none;\n background: transparent;\n color: var(--mj-text-secondary);\n font-size: 1.125rem;\n cursor: pointer;\n border-radius: var(--mj-radius-full);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n min-width: 44px;\n min-height: 44px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.modal-action-btn:hover {\n background: var(--mj-brand-primary);\n color: var(--mj-brand-on-primary);\n}\n\n.modal-action-btn:focus-visible {\n outline: 2px solid var(--mj-brand-primary);\n outline-offset: 2px;\n}\n\n.modal-body {\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n flex: 1;\n}\n\n@media (max-width: 639px) {\n .modal-body {\n padding: 1rem 1.25rem;\n }\n}\n\n.modal-footer {\n justify-content: flex-end;\n flex-shrink: 0;\n}\n\n@media (max-width: 639px) {\n .modal-footer {\n padding: 1rem 1.25rem;\n }\n\n /* Stretch the action buttons to full width on small viewports. */\n .modal-footer button {\n width: 100%;\n justify-content: center;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Form Elements\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: var(--mj-text-primary);\n margin-bottom: 0.5rem;\n}\n\n.form-input,\n.form-select,\n.form-textarea {\n width: 100%;\n min-height: 44px;\n padding: 0.875rem 1rem;\n border: 2px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n font-size: 1rem;\n background: var(--mj-bg-surface);\n color: var(--mj-text-primary);\n transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.form-input:hover,\n.form-select:hover,\n.form-textarea:hover {\n border-color: var(--mj-brand-primary);\n background: var(--mj-bg-surface);\n}\n\n.form-input:focus,\n.form-select:focus,\n.form-textarea:focus {\n outline: none;\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 20%, transparent);\n background: var(--mj-bg-surface);\n}\n\n.form-input::placeholder,\n.form-textarea::placeholder {\n color: var(--mj-text-secondary);\n opacity: 0.7;\n}\n\n.form-select {\n cursor: pointer;\n}\n\n.form-hint {\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n margin-top: 0.375rem;\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.625rem;\n font-size: 1rem;\n color: var(--mj-text-primary);\n cursor: pointer;\n min-height: 44px;\n padding: 0.25rem 0;\n}\n\n.checkbox-label input[type=\"checkbox\"] {\n width: 20px;\n height: 20px;\n cursor: pointer;\n accent-color: var(--mj-brand-primary);\n flex-shrink: 0;\n}\n\n/* Form Section */\n.form-section {\n margin-top: 1.5rem;\n padding: 1.25rem;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n background: var(--mj-bg-surface-sunken);\n}\n\n.form-section-title {\n display: flex;\n align-items: center;\n gap: 0.625rem;\n margin: 0 0 1rem 0;\n font-size: 0.875rem;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.form-section-title i {\n color: var(--mj-brand-primary);\n font-size: 1.125rem;\n}\n\n.form-textarea {\n font-family: \"Consolas\", \"Monaco\", \"Courier New\", monospace;\n resize: vertical;\n min-height: 100px;\n}\n\n/* -----------------------------------------------------------------------------\n Confirmation Dialog\n ----------------------------------------------------------------------------- */\n.confirm-dialog {\n background: var(--mj-bg-page);\n border-radius: var(--mj-radius-2xl);\n box-shadow: var(--mj-shadow-2xl);\n max-width: 420px;\n width: 90%;\n padding: 2rem;\n text-align: center;\n animation: dialogBounce 0.3s cubic-bezier(0, 0, 0.2, 1);\n}\n\n@media (max-width: 639px) {\n .confirm-dialog {\n padding: 1.5rem;\n border-radius: var(--mj-radius-2xl);\n }\n}\n\n.confirm-dialog-icon {\n width: 64px;\n height: 64px;\n border-radius: 50%;\n background: var(--mj-status-warning-bg);\n display: flex;\n align-items: center;\n justify-content: center;\n margin: 0 auto 1.5rem;\n}\n\n.confirm-dialog-icon i {\n font-size: 1.75rem;\n color: var(--mj-status-warning-text);\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: 600;\n color: var(--mj-text-primary);\n}\n\n.confirm-dialog-message {\n margin: 0;\n font-size: 1rem;\n color: var(--mj-text-secondary);\n line-height: 1.6;\n}\n\n.confirm-dialog-message strong {\n color: var(--mj-text-primary);\n font-weight: 600;\n}\n\n.confirm-dialog-details {\n display: block;\n margin-top: 0.75rem;\n padding: 0.75rem;\n background: var(--mj-bg-surface-sunken);\n border-radius: var(--mj-radius-md);\n font-size: 0.8125rem;\n color: var(--mj-text-secondary);\n}\n\n.confirm-dialog-actions {\n display: flex;\n gap: 0.75rem;\n justify-content: center;\n}\n\n@media (max-width: 639px) {\n .confirm-dialog-actions {\n flex-direction: column-reverse;\n }\n\n /* Stretch the action buttons to full width on small viewports. */\n .confirm-dialog-actions button {\n width: 100%;\n justify-content: center;\n }\n}\n\n/* -----------------------------------------------------------------------------\n SQL-Logging-specific Animations\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@keyframes dialogBounce {\n 0% {\n transform: scale(0.9) translateY(10px);\n opacity: 0;\n }\n 70% {\n transform: scale(1.02) translateY(-5px);\n }\n 100% {\n transform: scale(1) translateY(0);\n opacity: 1;\n }\n}\n\n/* -----------------------------------------------------------------------------\n Screen Reader Only\n ----------------------------------------------------------------------------- */\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n"] }]
1285
1286
  }], () => [{ type: i1.SharedService }, { type: i0.ChangeDetectorRef }], { onEscapeKey: [{
1286
1287
  type: HostListener,
1287
1288
  args: ['document:keydown.escape']