slicejs-web-framework 3.4.2 → 3.4.3
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.
|
@@ -31,10 +31,14 @@ export default class LogViewer extends HTMLElement {
|
|
|
31
31
|
this.$header = this.querySelector('.lv__header');
|
|
32
32
|
this.$body = this.querySelector('[data-body]');
|
|
33
33
|
this.$count = this.querySelector('[data-count]');
|
|
34
|
+
this.$componentSelect = this.querySelector('[data-component-select]');
|
|
35
|
+
this.$queryInput = this.querySelector('[data-query-input]');
|
|
34
36
|
|
|
35
37
|
this._isOpen = false;
|
|
36
38
|
this._logCount = 0;
|
|
37
39
|
this._filters = new Set();
|
|
40
|
+
this._componentFilter = '';
|
|
41
|
+
this._queryFilter = '';
|
|
38
42
|
this._dragState = null;
|
|
39
43
|
this._logHandler = null;
|
|
40
44
|
}
|
|
@@ -45,6 +49,8 @@ export default class LogViewer extends HTMLElement {
|
|
|
45
49
|
this._attachClear();
|
|
46
50
|
this._attachMinimize();
|
|
47
51
|
this._attachBodyClick();
|
|
52
|
+
this._attachComponentSelect();
|
|
53
|
+
this._attachQueryInput();
|
|
48
54
|
this._render();
|
|
49
55
|
this._subscribeLogger();
|
|
50
56
|
}
|
|
@@ -165,6 +171,28 @@ export default class LogViewer extends HTMLElement {
|
|
|
165
171
|
});
|
|
166
172
|
}
|
|
167
173
|
|
|
174
|
+
/* -- component select -- */
|
|
175
|
+
_attachComponentSelect() {
|
|
176
|
+
if (!this.$componentSelect) return;
|
|
177
|
+
this.$componentSelect.addEventListener('change', () => {
|
|
178
|
+
this._componentFilter = this.$componentSelect.value;
|
|
179
|
+
this._render();
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* -- query text input (debounced) -- */
|
|
184
|
+
_attachQueryInput() {
|
|
185
|
+
if (!this.$queryInput) return;
|
|
186
|
+
let timer;
|
|
187
|
+
this.$queryInput.addEventListener('input', () => {
|
|
188
|
+
clearTimeout(timer);
|
|
189
|
+
timer = setTimeout(() => {
|
|
190
|
+
this._queryFilter = this.$queryInput.value.trim().toLowerCase();
|
|
191
|
+
this._render();
|
|
192
|
+
}, 150);
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
168
196
|
/* -- real-time subscription via logger.onLog -- */
|
|
169
197
|
_subscribeLogger() {
|
|
170
198
|
const logger = slice.logger;
|
|
@@ -192,11 +220,25 @@ export default class LogViewer extends HTMLElement {
|
|
|
192
220
|
|
|
193
221
|
const filters = this._filters;
|
|
194
222
|
const hasFilters = filters.size > 0;
|
|
223
|
+
const hasComponent = this._componentFilter !== '';
|
|
224
|
+
const hasQuery = this._queryFilter !== '';
|
|
195
225
|
|
|
196
226
|
if (this.$count) {
|
|
197
227
|
this.$count.textContent = logs.length;
|
|
198
228
|
}
|
|
199
229
|
|
|
230
|
+
/* refresh component select options */
|
|
231
|
+
if (this.$componentSelect) {
|
|
232
|
+
const currentVal = this.$componentSelect.value;
|
|
233
|
+
const components = [...new Set(logs.map(l => l.componentSliceId).filter(Boolean))].sort();
|
|
234
|
+
let opts = '<option value="">All components</option>';
|
|
235
|
+
for (const c of components) {
|
|
236
|
+
const sel = c === currentVal ? ' selected' : '';
|
|
237
|
+
opts += `<option value="${escapeHtml(c)}"${sel}>${escapeHtml(c)}</option>`;
|
|
238
|
+
}
|
|
239
|
+
this.$componentSelect.innerHTML = opts;
|
|
240
|
+
}
|
|
241
|
+
|
|
200
242
|
if (!this.$body) return;
|
|
201
243
|
|
|
202
244
|
if (logs.length === 0) {
|
|
@@ -204,9 +246,19 @@ export default class LogViewer extends HTMLElement {
|
|
|
204
246
|
return;
|
|
205
247
|
}
|
|
206
248
|
|
|
207
|
-
|
|
249
|
+
let filtered = logs;
|
|
250
|
+
if (hasFilters) filtered = filtered.filter((log) => filters.has(log.logType));
|
|
251
|
+
if (hasComponent) filtered = filtered.filter((log) => log.componentSliceId === this._componentFilter);
|
|
252
|
+
if (hasQuery) filtered = filtered.filter((log) => (log.message || '').toLowerCase().includes(this._queryFilter));
|
|
208
253
|
const reversed = [...filtered].reverse();
|
|
209
254
|
|
|
255
|
+
if (reversed.length === 0) {
|
|
256
|
+
this.$body.innerHTML = '<div class="lv__empty"><span class="lv__empty-icon">🔍</span><span>No matches</span></div>';
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const prevScrollTop = this.$body.scrollTop;
|
|
261
|
+
|
|
210
262
|
let html = '';
|
|
211
263
|
for (const log of reversed) {
|
|
212
264
|
const type = log.logType || 'info';
|
|
@@ -233,9 +285,8 @@ export default class LogViewer extends HTMLElement {
|
|
|
233
285
|
}
|
|
234
286
|
|
|
235
287
|
this.$body.innerHTML = html;
|
|
236
|
-
if
|
|
237
|
-
|
|
238
|
-
}
|
|
288
|
+
/* preserve scroll — if user was at top (newest), stay at top */
|
|
289
|
+
this.$body.scrollTop = prevScrollTop === 0 ? 0 : Math.min(prevScrollTop, this.$body.scrollHeight);
|
|
239
290
|
}
|
|
240
291
|
}
|
|
241
292
|
|
|
@@ -286,6 +337,7 @@ slice-log-viewer[data-minimized] {
|
|
|
286
337
|
min-height: 0;
|
|
287
338
|
}
|
|
288
339
|
|
|
340
|
+
slice-log-viewer[data-minimized] .lv__toolbar,
|
|
289
341
|
slice-log-viewer[data-minimized] .lv__body {
|
|
290
342
|
display: none;
|
|
291
343
|
}
|
|
@@ -390,10 +442,73 @@ slice-log-viewer[data-minimized] .lv__body {
|
|
|
390
442
|
padding: 3px 8px 4px;
|
|
391
443
|
}
|
|
392
444
|
|
|
445
|
+
.lv__toolbar {
|
|
446
|
+
display: flex;
|
|
447
|
+
align-items: center;
|
|
448
|
+
gap: 6px;
|
|
449
|
+
padding: 5px 10px;
|
|
450
|
+
background: color-mix(in srgb, var(--si-surface, #1e1e2e) 98%, #000);
|
|
451
|
+
border-bottom: 1px solid color-mix(in srgb, var(--si-border, #555) 18%, transparent);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.lv__component-select {
|
|
455
|
+
all: unset;
|
|
456
|
+
flex: 0 0 auto;
|
|
457
|
+
max-width: 160px;
|
|
458
|
+
font-size: 10px;
|
|
459
|
+
font-weight: 600;
|
|
460
|
+
font-family: inherit;
|
|
461
|
+
color: var(--si-text, #cdd6f4);
|
|
462
|
+
background: color-mix(in srgb, var(--si-border, #555) 20%, transparent);
|
|
463
|
+
padding: 3px 20px 3px 7px;
|
|
464
|
+
border-radius: 6px;
|
|
465
|
+
cursor: pointer;
|
|
466
|
+
white-space: nowrap;
|
|
467
|
+
overflow: hidden;
|
|
468
|
+
text-overflow: ellipsis;
|
|
469
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cpath fill='%23a6adc8' d='M2 2.5l2 2 2-2'/%3E%3C/svg%3E");
|
|
470
|
+
background-repeat: no-repeat;
|
|
471
|
+
background-position: right 6px center;
|
|
472
|
+
appearance: none;
|
|
473
|
+
-webkit-appearance: none;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.lv__component-select:hover {
|
|
477
|
+
background-color: color-mix(in srgb, var(--si-border, #555) 35%, transparent);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
.lv__component-select option {
|
|
481
|
+
background: var(--si-surface, #1e1e2e);
|
|
482
|
+
color: var(--si-text, #cdd6f4);
|
|
483
|
+
font-size: 10px;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.lv__query-input {
|
|
487
|
+
all: unset;
|
|
488
|
+
flex: 1;
|
|
489
|
+
min-width: 0;
|
|
490
|
+
font-size: 10px;
|
|
491
|
+
font-family: inherit;
|
|
492
|
+
color: var(--si-text, #cdd6f4);
|
|
493
|
+
background: color-mix(in srgb, var(--si-border, #555) 15%, transparent);
|
|
494
|
+
padding: 3px 7px;
|
|
495
|
+
border-radius: 6px;
|
|
496
|
+
transition: background .12s ease;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.lv__query-input::placeholder {
|
|
500
|
+
color: color-mix(in srgb, var(--si-dim, #a6adc8) 45%, transparent);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.lv__query-input:focus {
|
|
504
|
+
background: color-mix(in srgb, var(--si-border, #555) 25%, transparent);
|
|
505
|
+
outline: 1px solid color-mix(in srgb, var(--si-accent, #6ee7ff) 30%, transparent);
|
|
506
|
+
}
|
|
507
|
+
|
|
393
508
|
.lv__body {
|
|
394
509
|
overflow-y: auto;
|
|
395
510
|
overflow-x: hidden;
|
|
396
|
-
height: calc(100% -
|
|
511
|
+
height: calc(100% - 76px);
|
|
397
512
|
padding: 4px 0;
|
|
398
513
|
cursor: auto;
|
|
399
514
|
}
|
|
@@ -536,6 +651,12 @@ function productionOnlyHtml() {
|
|
|
536
651
|
<button class="lv__close" title="Close">×</button>
|
|
537
652
|
</div>
|
|
538
653
|
</div>
|
|
654
|
+
<div class="lv__toolbar">
|
|
655
|
+
<select class="lv__component-select" data-component-select>
|
|
656
|
+
<option value="">All components</option>
|
|
657
|
+
</select>
|
|
658
|
+
<input class="lv__query-input" data-query-input type="text" placeholder="Search logs..." />
|
|
659
|
+
</div>
|
|
539
660
|
<div class="lv__body" data-body></div>
|
|
540
661
|
</div>`;
|
|
541
662
|
}
|