@vii7/div-table-widget 1.0.1 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,7 @@ A modern, flexible table widget built with CSS Grid and Flexbox instead of HTML
10
10
  - **Advanced Query Language**: Monaco Editor integration with intelligent autocomplete and syntax highlighting
11
11
  - **Virtual Scrolling**: Efficiently handle large datasets with pagination support
12
12
  - **Fixed (Frozen) Columns**: Keep important columns visible while scrolling horizontally
13
+ - **Summary Rows**: Aggregate calculations (sum, avg, count, min, max) with header and group summaries
13
14
  - **Auto-Fetch**: Automated pagination with play/pause/resume controls
14
15
  - **Grouping & Sorting**: Multi-level grouping with 4-state sorting (alphabetical asc/desc, count asc/desc)
15
16
  - **Selection Management**: Single and multi-row selection with checkbox support
@@ -22,9 +23,47 @@ A modern, flexible table widget built with CSS Grid and Flexbox instead of HTML
22
23
  ## Installation
23
24
 
24
25
  ```bash
25
- npm install divtable-widget monaco-editor
26
+ npm install @vii7/div-table-widget monaco-editor
26
27
  ```
27
28
 
29
+ ## Usage Options
30
+
31
+ ### Option 1: Minified (Production)
32
+
33
+ ```html
34
+ <!-- CSS -->
35
+ <link rel="stylesheet" href="node_modules/@vii7/div-table-widget/dist/divtable.min.css">
36
+
37
+ <!-- Monaco Editor (from CDN) -->
38
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs/loader.min.js"></script>
39
+
40
+ <!-- DivTable Widget -->
41
+ <script src="node_modules/@vii7/div-table-widget/src/query.js"></script>
42
+ <script src="node_modules/@vii7/div-table-widget/dist/divtable.min.js"></script>
43
+ ```
44
+
45
+ ### Option 2: Source (Development/Debugging)
46
+
47
+ ```html
48
+ <!-- CSS -->
49
+ <link rel="stylesheet" href="node_modules/@vii7/div-table-widget/src/div-table.css">
50
+
51
+ <!-- Monaco Editor (from CDN) -->
52
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs/loader.min.js"></script>
53
+
54
+ <!-- DivTable Widget -->
55
+ <script src="node_modules/@vii7/div-table-widget/src/query.js"></script>
56
+ <script src="node_modules/@vii7/div-table-widget/src/div-table.js"></script>
57
+ ```
58
+
59
+ | File | Size | Description |
60
+ |------|------|-------------|
61
+ | `dist/divtable.min.js` | ~98KB | Minified JavaScript |
62
+ | `dist/divtable.min.css` | ~22KB | Minified CSS |
63
+ | `src/div-table.js` | ~220KB | Source JavaScript |
64
+ | `src/div-table.css` | ~33KB | Source CSS (with CSS variables) |
65
+ | `src/query.js` | ~78KB | Query language engine (required) |
66
+
28
67
  ## Quick Start
29
68
 
30
69
  ### Basic Usage
@@ -33,14 +72,14 @@ npm install divtable-widget monaco-editor
33
72
  <!DOCTYPE html>
34
73
  <html>
35
74
  <head>
36
- <link rel="stylesheet" href="node_modules/divtable-widget/src/div-table.css">
75
+ <link rel="stylesheet" href="node_modules/@vii7/div-table-widget/dist/divtable.min.css">
37
76
  <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs/loader.min.js"></script>
38
77
  </head>
39
78
  <body>
40
79
  <div id="table-container"></div>
41
80
 
42
- <script src="node_modules/divtable-widget/src/query.js"></script>
43
- <script src="node_modules/divtable-widget/src/div-table.js"></script>
81
+ <script src="node_modules/@vii7/div-table-widget/src/query.js"></script>
82
+ <script src="node_modules/@vii7/div-table-widget/dist/divtable.min.js"></script>
44
83
  <script>
45
84
  // Initialize Monaco Editor
46
85
  require.config({ paths: { vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs' }});
@@ -109,6 +148,8 @@ const divTable = new DivTable(monaco, {
109
148
  | `group` | String | `null` | Field to group by initially (applies grouping on load) |
110
149
  | `sort` | Object | `null` | Initial sort: `{ field: string, direction: 'asc'|'desc' }` |
111
150
  | `fixedColumns` | Number | `0` | Number of columns to freeze on the left side when scrolling horizontally |
151
+ | `showHeaderSummary` | Boolean | `false` | Show summary row at top with aggregates for all visible data |
152
+ | `showGroupSummary` | Boolean | `false` | Show summary row after each group with group aggregates |
112
153
 
113
154
  ### Virtual Scrolling Options
114
155
 
@@ -269,6 +310,25 @@ divTable.stopAutoFetch();
269
310
 
270
311
  Keep the first N columns fixed (frozen) on the left side while scrolling horizontally:
271
312
 
313
+ **Visual Layout:**
314
+
315
+ ```
316
+ ┌──────────────────────────┬─────────────────────────────────────────────────┐
317
+ │ FIXED SECTION │ SCROLLABLE SECTION ──────────► │
318
+ │ (stays in place) │ (scrolls horizontally) │
319
+ ├──────────────────────────┼─────────────────────────────────────────────────┤
320
+ │ ☐ │ ID │ Name │ Email │ Department │ Status │ ...│
321
+ ├──────────────────────────┼─────────────────────────────────────────────────┤
322
+ │ ☐ │ 1 │ John Doe │ john@mail.com │ Engineering │ Active │ │
323
+ │ ☐ │ 2 │ Jane Smith │ jane@mail.com │ Marketing │ Active │ │
324
+ │ ☐ │ 3 │ Bob Wilson │ bob@mail.com │ Sales │ Inactive│ │
325
+ └──────────────────────────┴─────────────────────────────────────────────────┘
326
+ ▲ ▲
327
+ │ │
328
+ Columns 1-2 Columns 3+ scroll
329
+ stay fixed left/right
330
+ ```
331
+
272
332
  ```javascript
273
333
  const divTable = new DivTable(monaco, {
274
334
  tableWidgetElement: document.getElementById('table-container'),
@@ -292,6 +352,90 @@ const divTable = new DivTable(monaco, {
292
352
  - Checkbox column (if enabled) is always part of the fixed section
293
353
  - Works with composite columns - each composite group counts as one column
294
354
 
355
+ ### Summary Rows (Aggregates)
356
+
357
+ Display aggregate calculations in summary rows at the header level (grand totals) or after each group (subtotals):
358
+
359
+ **Visual Layout:**
360
+
361
+ ```
362
+ ┌─────────────────────────────────────────────────────────────────────────┐
363
+ │ ☐ │ Name │ Department │ Age │ Salary │
364
+ ├─────────────────────────────────────────────────────────────────────────┤
365
+ │ │ │ │ 32 avg │ $385,000 ◄── Header Summary (Grand Total)
366
+ ├═════════════════════════════════════════════════════════════════════════┤
367
+ │ ▼ │ Engineering (3) │ ◄── Group Header
368
+ ├─────────────────────────────────────────────────────────────────────────┤
369
+ │ ☐ │ Alice Chen │ Engineering │ 28 │ $95,000 │
370
+ │ ☐ │ Bob Smith │ Engineering │ 35 │ $120,000 │
371
+ │ ☐ │ Carol Davis │ Engineering │ 42 │ $110,000 │
372
+ ├─────────────────────────────────────────────────────────────────────────┤
373
+ │ │ │ │ 35 avg │ $325,000 ◄── Group Summary (Subtotal)
374
+ ├═════════════════════════════════════════════════════════════════════════┤
375
+ │ ▶ │ Marketing (2) (collapsed) │ ◄── Collapsed Group
376
+ ├─────────────────────────────────────────────────────────────────────────┤
377
+ │ │ │ │ 27 avg │ $60,000 ◄── Summary visible even when collapsed
378
+ └─────────────────────────────────────────────────────────────────────────┘
379
+ ```
380
+
381
+ ```javascript
382
+ const divTable = new DivTable(monaco, {
383
+ tableWidgetElement: document.getElementById('table-container'),
384
+ columns: [
385
+ { field: 'id', label: 'ID', primaryKey: true },
386
+ { field: 'name', label: 'Name' },
387
+ { field: 'department', label: 'Department', groupable: true },
388
+ {
389
+ field: 'salary',
390
+ label: 'Salary',
391
+ align: 'right', // Right-align numeric values
392
+ aggregate: 'sum', // Calculate sum for this column
393
+ aggregateRender: (value) => `$${value.toLocaleString()}` // Format aggregate value
394
+ },
395
+ {
396
+ field: 'age',
397
+ label: 'Age',
398
+ aggregate: 'avg', // Calculate average
399
+ aggregateRender: (value) => `${value.toFixed(1)} avg`
400
+ }
401
+ ],
402
+ data: myData,
403
+ group: 'department',
404
+ showHeaderSummary: true, // Show grand total row at top
405
+ showGroupSummary: true // Show subtotal after each group
406
+ });
407
+ ```
408
+
409
+ **Aggregate Types:**
410
+
411
+ | Type | Description |
412
+ |------|-------------|
413
+ | `sum` | Sum of all numeric values |
414
+ | `avg` | Average of all numeric values |
415
+ | `count` | Count of non-null values |
416
+ | `min` | Minimum value |
417
+ | `max` | Maximum value |
418
+
419
+ **Column Configuration for Aggregates:**
420
+
421
+ ```javascript
422
+ {
423
+ field: 'amount',
424
+ label: 'Amount',
425
+ align: 'right', // Align cell content (applies to both data and summary cells)
426
+ aggregate: 'sum', // Aggregate type: 'sum', 'avg', 'count', 'min', 'max'
427
+ aggregateRender: (value) => `$${value.toFixed(2)}` // Custom formatting for aggregate value
428
+ }
429
+ ```
430
+
431
+ **Features:**
432
+
433
+ - Summary rows remain visible even when groups are collapsed
434
+ - Aggregates automatically update when data changes or filters are applied
435
+ - Selection-aware: When rows are selected, aggregates reflect only selected data
436
+ - Works with fixed columns layout
437
+ - Supports custom formatting via `aggregateRender` function
438
+
295
439
  ## Column Configuration
296
440
 
297
441
  ### Basic Column
@@ -303,6 +447,7 @@ const divTable = new DivTable(monaco, {
303
447
  primaryKey: false, // Is this the primary key? (required for one column)
304
448
  hidden: false, // Hide column (default: false)
305
449
  groupable: true, // Allow grouping by this column (default: true)
450
+ align: 'left', // Text alignment: 'left', 'center', 'right' (default: 'left')
306
451
  render: (value, item) => `<strong>${value}</strong>` // Custom render function
307
452
  }
308
453
  ```
@@ -376,19 +521,100 @@ The widget automatically detects and handles different data types based on the d
376
521
  - **Booleans**: True/false values with = operator
377
522
  - **Arrays**: Array values are joined with commas for display
378
523
 
379
- ## Styling
524
+ ## Styling & Customization
380
525
 
381
- The widget uses CSS variables for easy customization:
526
+ The widget uses CSS custom properties (variables) for easy theming. Override these variables in your stylesheet to customize colors:
527
+
528
+ ### CSS Variables Reference
382
529
 
383
530
  ```css
384
- .div-table-widget {
385
- --table-border-color: #e0e0e0;
386
- --header-bg-color: #f5f5f5;
387
- --row-hover-color: #f9f9f9;
388
- --selected-row-color: #e3f2fd;
531
+ :root {
532
+ /* Primary/Accent Colors */
533
+ --dt-primary: #007bff; /* Main accent color */
534
+ --dt-primary-hover: #0056b3; /* Accent hover state */
535
+
536
+ /* Background Colors */
537
+ --dt-bg-base: #ffffff; /* Base background */
538
+ --dt-bg-light: #f9f9f7; /* Light background */
539
+ --dt-bg-hover: rgb(240, 247, 255); /* Row hover background */
540
+ --dt-bg-selected: rgba(0, 123, 255, 0.1); /* Selected row background */
541
+ --dt-bg-header: #f9f9f7; /* Header background */
542
+ --dt-bg-summary: #f8f9fa; /* Summary row background */
543
+
544
+ /* Border Colors */
545
+ --dt-border-light: #e9ecef; /* Light borders */
546
+ --dt-border-medium: #e1e5e9; /* Medium borders */
547
+ --dt-border-dark: #ced4da; /* Dark borders */
548
+ --dt-border-row: #f1f3f4; /* Row separator */
549
+
550
+ /* Text Colors */
551
+ --dt-text-primary: #374151; /* Primary text */
552
+ --dt-text-secondary: #495057; /* Secondary text */
553
+ --dt-text-muted: #6b7280; /* Muted/subtle text */
554
+ --dt-text-light: #666666; /* Light text */
555
+ --dt-text-disabled: #999999; /* Disabled text */
556
+
557
+ /* Shadow */
558
+ --dt-shadow: rgba(0, 0, 0, 0.1); /* Standard shadow */
559
+
560
+ /* State Colors */
561
+ --dt-error: #dc3545; /* Error color */
562
+ --dt-success: #28a745; /* Success color */
563
+ --dt-warning: #ffc107; /* Warning color */
564
+ --dt-info: #0ea5e9; /* Info color */
389
565
  }
390
566
  ```
391
567
 
568
+ ### Example: Dark Theme
569
+
570
+ ```css
571
+ /* custom-theme.css */
572
+ :root {
573
+ --dt-primary: #60a5fa;
574
+ --dt-primary-hover: #3b82f6;
575
+
576
+ --dt-bg-base: #1f2937;
577
+ --dt-bg-light: #374151;
578
+ --dt-bg-hover: #4b5563;
579
+ --dt-bg-selected: rgba(96, 165, 250, 0.2);
580
+ --dt-bg-header: #374151;
581
+ --dt-bg-summary: #374151;
582
+
583
+ --dt-border-light: #4b5563;
584
+ --dt-border-medium: #6b7280;
585
+ --dt-border-dark: #9ca3af;
586
+ --dt-border-row: #374151;
587
+
588
+ --dt-text-primary: #f9fafb;
589
+ --dt-text-secondary: #e5e7eb;
590
+ --dt-text-muted: #9ca3af;
591
+ --dt-text-light: #d1d5db;
592
+ --dt-text-disabled: #6b7280;
593
+ --dt-text-inverse: #1f2937;
594
+
595
+ --dt-shadow: rgba(0, 0, 0, 0.3);
596
+
597
+ --dt-button-bg: #4b5563;
598
+ --dt-button-bg-hover: #6b7280;
599
+ --dt-button-text: #f9fafb;
600
+
601
+ --dt-scrollbar-track: #374151;
602
+ --dt-scrollbar-thumb: #6b7280;
603
+ --dt-scrollbar-thumb-hover: #9ca3af;
604
+ }
605
+ ```
606
+
607
+ ### Variable Categories
608
+
609
+ | Category | Variables | Description |
610
+ |----------|-----------|-------------|
611
+ | Primary | `--dt-primary`, `--dt-primary-hover` | Brand/accent colors |
612
+ | Background | `--dt-bg-*` | Surface and container backgrounds |
613
+ | Border | `--dt-border-*` | Border and separator colors |
614
+ | Text | `--dt-text-*` | Typography colors |
615
+ | State | `--dt-error`, `--dt-success`, `--dt-warning`, `--dt-info` | Status indicator colors |
616
+ | UI | `--dt-button-*`, `--dt-scrollbar-*` | Button and scrollbar styling |
617
+
392
618
  ## Browser Support
393
619
 
394
620
  - Chrome/Edge: Latest 2 versions
@@ -0,0 +1 @@
1
+ :root{--dt-primary:#007bff;--dt-primary-hover:#0056b3;--dt-primary-light:rgba(0,123,255,.1);--dt-primary-lighter:rgba(0,123,255,.05);--dt-focus-ring:rgba(3,102,214,.1);--dt-bg-base:#fff;--dt-bg-light:#f9f9f7;--dt-bg-hover:#f0f7ff;--dt-bg-selected:rgba(0,123,255,.1);--dt-bg-header:#f9f9f7;--dt-bg-summary:#f9f9f7;--dt-bg-disabled:#f0f0f0;--dt-border-light:#e9ecef;--dt-border-medium:#e1e5e9;--dt-border-dark:#ced4da;--dt-border-row:#f1f3f4;--dt-border-focus:#123a67;--dt-border-hover:#b0b8c1;--dt-text-primary:#374151;--dt-text-secondary:#495057;--dt-text-muted:#6b7280;--dt-text-light:#666;--dt-text-disabled:#999;--dt-text-inverse:#fff;--dt-shadow:rgba(0,0,0,.1);--dt-shadow-medium:rgba(0,0,0,.12);--dt-shadow-heavy:rgba(0,0,0,.15);--dt-error:#dc3545;--dt-error-light:rgba(220,53,69,.6);--dt-error-hover:#c82333;--dt-error-active:#bd2130;--dt-error-bg:#fff5f5;--dt-error-border:#fed7d7;--dt-error-text:#c53030;--dt-error-border-hover:rgba(200,35,51,.6);--dt-error-focus-ring:rgba(220,53,69,.25);--dt-success:#28a745;--dt-success-bg:#e8f5e9;--dt-success-bg-hover:#c8e6c9;--dt-warning:#ffc107;--dt-warning-bg:#fff8e1;--dt-warning-bg-hover:#ffecb3;--dt-info:#0ea5e9;--dt-info-bg:#e0f2fe;--dt-info-bg-hover:#bae6fd;--dt-button-bg:#f0f0f0;--dt-button-bg-hover:#e0e0e0;--dt-button-text:#333;--dt-scrollbar-track:#f1f1f1;--dt-scrollbar-thumb:#c1c1c1;--dt-scrollbar-thumb-hover:#a8a8a8;--dt-spinner-track:#e3e3e3;--dt-spinner-active:#666;--dt-skeleton-base:#e9ecef;--dt-skeleton-shine:#f8f9fa;--dt-group-bg:hsla(60,14%,97%,.5);--dt-summary-border:#adb5bd}.div-table-widget{background:var(--dt-bg-base);border-radius:8px;box-shadow:0 2px 8px var(--dt-shadow);box-sizing:border-box;display:flex;flex-direction:column;overflow:hidden;width:100%}.div-table-toolbar{align-items:center;background:var(--dt-bg-light);border-bottom:1px solid var(--dt-border-light);display:flex;flex-shrink:0;gap:10px;padding:16px}.query-inputfield{background:var(--dt-bg-base);border:2px solid var(--dt-border-medium);border-radius:8px;box-shadow:0 1px 3px var(--dt-shadow);flex:1;min-width:50%;overflow:hidden;padding:10px 5px 4px 10px;transition:all .2s ease-in-out}.query-inputfield:hover{border-color:var(--dt-border-hover);box-shadow:0 2px 4px var(--dt-shadow-medium)}.query-inputfield.focused{border-color:var(--dt-border-focus);box-shadow:0 0 0 3px var(--dt-focus-ring),0 1px 3px var(--dt-shadow);outline:none}.query-inputfield.error{border-color:var(--dt-error-light)}.query-inputfield.error:hover{border-color:var(--dt-error-border-hover)}.query-inputfield.error.focused{border-color:var(--dt-error-light);box-shadow:0 0 0 3px var(--dt-error-focus-ring),0 1px 3px var(--dt-shadow)}.query-inputfield .monaco-editor{height:22px!important;--vscode-focusBorder:transparent}.div-table-toolbar select{appearance:none;-webkit-appearance:none;-moz-appearance:none;background:var(--dt-bg-base);background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right 8px center;background-repeat:no-repeat;background-size:16px;border:2px solid var(--dt-border-medium);border-radius:8px;box-shadow:0 1px 3px var(--dt-shadow);color:var(--dt-text-secondary);cursor:pointer;font-size:14px;min-width:150px;padding:10px 32px 10px 12px;transition:all .2s ease-in-out}.div-table-toolbar select:hover{border-color:var(--dt-border-hover);box-shadow:0 2px 4px var(--dt-shadow-medium)}.div-table-toolbar select:focus{border-color:var(--dt-border-focus);box-shadow:0 0 0 3px var(--dt-focus-ring),0 1px 3px var(--dt-shadow);outline:none}.div-table-toolbar select:disabled{background-color:var(--dt-bg-light);border-color:var(--dt-border-light);color:var(--dt-text-muted);cursor:not-allowed}.info-section{color:var(--dt-text-light);display:flex;flex-direction:column;font-size:.9em;gap:0;margin-left:auto;min-width:200px;padding:0;text-align:right}.info-line-container{gap:8px}.info-line,.info-line-container{align-items:center;display:flex;justify-content:flex-end}.info-line.secondary{color:var(--dt-text-disabled);font-size:.8em}.refresh-button{align-items:center;background:none;border:none;border-radius:3px;color:var(--dt-text-light);cursor:pointer;display:flex;flex-shrink:0;height:22px;justify-content:center;min-height:22px;min-width:22px;padding:4px;transition:all .2s ease;width:22px}.refresh-button:hover{background-color:var(--dt-button-bg);color:var(--dt-button-text)}.refresh-button:active{background-color:var(--dt-button-bg-hover)}.refresh-button.refreshing{color:var(--dt-primary)}.refresh-button.refreshing svg{animation:spin 1s linear infinite}.refresh-button svg{height:14px;transition:transform .2s ease;width:14px}.auto-fetch-button{align-items:center;background:none;border:none;border-radius:3px;color:var(--dt-text-light);cursor:pointer;display:flex;flex-shrink:0;height:22px;justify-content:center;margin-left:4px;min-height:22px;min-width:22px;padding:4px;transition:all .2s ease;width:22px}.auto-fetch-button:hover{background-color:var(--dt-button-bg);color:var(--dt-button-text)}.auto-fetch-button:active{background-color:var(--dt-button-bg-hover)}.auto-fetch-button.active{background-color:var(--dt-success-bg);color:var(--dt-success)}.auto-fetch-button.active:hover{background-color:var(--dt-success-bg-hover)}.auto-fetch-button.paused{background-color:var(--dt-warning-bg);color:var(--dt-warning)}.auto-fetch-button.paused:hover{background-color:var(--dt-warning-bg-hover)}.auto-fetch-button:disabled{cursor:not-allowed;opacity:.5}.auto-fetch-button svg{height:14px;transition:transform .2s ease;width:14px}.filter-selected-only-toggle-button{align-items:center;background:none;border:none;border-radius:3px;color:var(--dt-text-light);cursor:pointer;display:flex;flex-shrink:0;height:22px;justify-content:center;margin-right:6px;min-height:22px;min-width:22px;padding:4px;transition:all .2s ease;width:22px}.filter-selected-only-toggle-button:hover{background-color:var(--dt-button-bg);color:var(--dt-button-text)}.filter-selected-only-toggle-button:active{background-color:var(--dt-button-bg-hover)}.filter-selected-only-toggle-button.active{background-color:var(--dt-info-bg);color:var(--dt-info)}.filter-selected-only-toggle-button.active:hover{background-color:var(--dt-info-bg-hover)}.filter-selected-only-toggle-button svg{height:14px;transition:transform .2s ease;width:14px}.info-selection{font-weight:600}.info-stats{color:var(--dt-text-light)}.progress-line{align-items:center;display:flex;justify-content:flex-end;margin-top:2px}.loading-progress{background:var(--dt-border-light);border-radius:2px;height:4px;overflow:hidden;position:relative;width:120px}.progress-segment{border-radius:2px;height:100%;position:absolute;top:0;transition:width .3s ease,left .3s ease}.filtered-segment{background:var(--dt-error);z-index:3}.loaded-segment{background:var(--dt-text-secondary);z-index:2}.loading-segment{background:var(--dt-primary);z-index:1}.loading-segment:after{animation:loading-shimmer 1.5s infinite;background:linear-gradient(90deg,transparent,hsla(0,0%,100%,.8),transparent);bottom:0;content:"";left:0;position:absolute;right:0;top:0}.loading-progress[data-state=filtered-loading],.loading-progress[data-state=sequential-loading]{position:relative}.loading-progress[data-state=filtered] .loaded-segment{background:var(--dt-text-light)}.loading-progress-bar{background:var(--dt-text-secondary);border-radius:2px;height:100%;position:relative;transition:width .3s ease}.loading-progress-bar.loading:after{animation:loading-shimmer 1.5s infinite;background:linear-gradient(90deg,transparent,hsla(0,0%,100%,.8),transparent);bottom:0;content:"";left:0;position:absolute;right:0;top:0}.loading-progress[data-state=filtered] .loading-progress-bar{background:var(--dt-text-light)}.loading-progress[data-state=filtered] .loading-progress-bar.loading:after{animation:filtered-shimmer 2s infinite;background:linear-gradient(90deg,transparent,hsla(0,0%,100%,.4),transparent)}.loading-progress[data-state=loading] .loading-progress-bar{background:var(--dt-text-secondary)}@keyframes loading-shimmer{0%{transform:translateX(-100%)}to{transform:translateX(100%)}}@keyframes filtered-shimmer{0%{transform:translateX(-100%)}to{transform:translateX(100%)}}.div-table-container{background:var(--dt-bg-base);display:flex;flex:1;flex-direction:column;min-height:0;overflow:hidden;width:100%}.div-table-header{align-items:auto;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);background:var(--dt-bg-header);border-bottom:1px solid var(--dt-border-light);color:var(--dt-text-primary);display:grid;flex-shrink:0;min-height:48px;position:sticky;top:0;transition:box-shadow .3s cubic-bezier(.4,0,.2,1);z-index:10}.scrollbar-spacer{background:transparent;pointer-events:none}.div-table-header.scrolled{box-shadow:0 2px 8px var(--dt-shadow)}.div-table-body{background:var(--dt-bg-base);flex:1;min-height:0;overflow-y:auto}.div-table-row{align-items:stretch;border-bottom:1px solid var(--dt-border-row);box-sizing:border-box;cursor:pointer;display:grid;gap:0;min-height:40px;transition:all .2s ease}.div-table-row:hover{background-color:var(--dt-bg-hover)}.div-table-row:last-child{border-bottom:none}.div-table-cell{box-sizing:border-box;min-width:0;text-overflow:ellipsis;white-space:nowrap}.div-table-cell,.div-table-header-cell{align-items:flex-start;display:flex;overflow:hidden;padding:8px 12px}.div-table-header-cell{color:var(--dt-text-primary);cursor:pointer;justify-content:space-between;transition:background-color .2s ease;user-select:none}.header-left-content{align-items:center;display:flex;flex:1 1 auto;font-weight:600;gap:0;min-width:0;overflow:hidden}.header-left-content>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.header-right-content{align-items:center;display:flex;flex:0 0 auto;gap:4px;margin-left:8px}.div-table-header-cell:hover{background-color:var(--dt-shadow)}.group-indicator{align-items:center;display:inline-flex;font-size:12px;height:20px;justify-content:center;opacity:0;transition:opacity .2s ease;width:14px}.div-table-header-cell:hover .group-indicator{opacity:.5}.group-indicator:hover{opacity:1!important}.group-indicator.grouped{color:inherit;opacity:1!important}.sort-indicator{align-items:center;display:inline-flex;height:20px;justify-content:center;opacity:0;transition:opacity .2s ease;width:14px}.div-table-header-cell:hover .sort-indicator{opacity:.5}.sort-indicator.active{opacity:1!important}.header-right-content>span:last-child:not(.group-indicator):not(.sort-indicator){opacity:0;transition:opacity .2s ease}.div-table-header-cell:hover .header-right-content>span:last-child:not(.group-indicator):not(.sort-indicator){opacity:.5}.div-table-header-cell.sorted .header-right-content>span:last-child:not(.sort-indicator){opacity:1!important}.sub-sort-indicator{align-items:center;display:inline-flex;height:20px;justify-content:center;opacity:0;transition:opacity .2s ease;width:14px}.composite-header:hover .sub-sort-indicator,.composite-sub-header:hover .sub-sort-indicator{opacity:.5}.sub-sort-indicator.active{opacity:1!important}.div-table-cell.checkbox-column,.div-table-header-cell.checkbox-column{justify-content:center;max-width:40px;min-width:40px;padding:8px 4px;width:40px}.div-table-cell.checkbox-column input[type=checkbox],.div-table-header-cell.checkbox-column input[type=checkbox]{accent-color:var(--dt-primary);cursor:pointer;height:15px;margin:0;width:15px}input[type=checkbox]:indeterminate{background-color:var(--dt-primary);border-color:var(--dt-primary);position:relative}input[type=checkbox]:indeterminate:after{color:var(--dt-text-inverse);content:"━";font-size:10px;font-weight:700;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.div-table-header-cell.checkbox-column input[type=checkbox]:indeterminate{background-color:var(--dt-primary);border-color:var(--dt-primary)}.div-table-row.selected{background-color:var(--dt-bg-selected)!important}.div-table-row.focused{background-color:var(--dt-bg-base);box-shadow:inset 3px 0 0 var(--dt-primary)}.div-table-row.focused:hover{background-color:var(--dt-primary-lighter)!important}.div-table-row.group-header.focused{background-color:var(--dt-bg-base)!important;box-shadow:inset 3px 0 0 var(--dt-primary)!important}.div-table-row.group-header.focused:hover{background-color:var(--dt-bg-hover)!important}.div-table-row.group-header{background:var(--dt-bg-base);border-bottom:1px solid var(--dt-border-row);border-top:1px solid var(--dt-border-row);box-shadow:none;color:var(--dt-text-secondary);font-weight:400;isolation:isolate;position:sticky;top:0;z-index:9}.div-table-row.group-header:first-of-type{border-top:none}.div-table-row.group-header:hover{background-color:var(--dt-bg-hover)}.div-table-row.group-header:first-of-type{box-shadow:0 2px 8px var(--dt-shadow-heavy)}.div-table-row.group-header .div-table-cell span{font-weight:600}.div-table-row.group-header .checkbox-column{align-items:center;display:flex;justify-content:center}.div-table-row.group-header .checkbox-column input[type=checkbox]{accent-color:var(--dt-primary);cursor:pointer;height:15px;width:15px}.div-table-row.group-header .checkbox-column input[type=checkbox]:indeterminate{background-color:var(--dt-primary)}.group-toggle,.group-toggle-all{align-items:center;border-radius:3px;cursor:pointer;display:inline-flex;font-size:.9em;justify-content:center;min-height:20px;min-width:20px;padding:2px;transform:rotate(90deg);transition:transform .2s ease}.group-toggle-all.collapsed,.group-toggle.collapsed{transform:rotate(0deg)}.group-toggle-all{font-size:1em;font-weight:700;margin-right:6px}.group-toggle-all:hover,.group-toggle:hover{background-color:var(--dt-shadow);opacity:.7}.div-table-cell.grouped-column{color:var(--dt-text-disabled);font-style:italic}.div-table-cell.composite-column{align-items:flex-start;display:flex;flex-direction:column;gap:2px;padding:6px 12px;white-space:normal}.composite-sub{color:var(--dt-text-muted);line-height:1.2}.div-table-cell.composite-cell{align-items:stretch;display:flex;flex-direction:column;gap:0;padding:8px 12px}.composite-sub-cell{align-items:center;display:flex;min-width:0;overflow:hidden}.composite-sub-cell:first-child{margin-bottom:4px}.composite-sub-cell:not(:first-child){color:var(--dt-text-muted)}.div-table-header-cell.composite-header{flex-direction:column;gap:4px;justify-content:flex-start;padding:8px 12px}.composite-sub-header{border-radius:4px;cursor:pointer;min-width:0;padding:0;transition:background-color .2s ease;user-select:none;width:100%}.composite-sub-header:first-child{color:var(--dt-text-primary);font-weight:600;margin-bottom:4px}.composite-sub-header:hover{background-color:var(--dt-bg-disabled)}.composite-toggle{cursor:pointer;display:inline-block;font-size:.9em;transition:transform .2s ease;user-select:none}.composite-toggle:hover{opacity:.7}.div-table-row.group-collapsed{display:none}.col-fixed-narrow{grid-column:span 1;max-width:80px;min-width:60px}.col-fixed-medium{grid-column:span 1;max-width:140px;min-width:100px}.col-flexible-small{flex:1;grid-column:span 1;min-width:120px}.col-flexible-medium{flex:2;grid-column:span 2;min-width:150px}.col-flexible-large{flex:3;grid-column:span 3;min-width:200px}.div-table-header.grid-5-cols,.div-table-row.grid-5-cols{grid-template-columns:40px 1fr 100px 200px 100px}.div-table-header.grid-4-cols,.div-table-row.grid-4-cols{grid-template-columns:40px 2fr 200px 100px}.div-table-header,.div-table-row{grid-template-columns:repeat(auto-fit,minmax(100px,1fr))}@media (max-width:768px){.div-table-toolbar{align-items:stretch;flex-direction:column;gap:8px}.query-inputfield{max-width:100%;width:100%}.div-table-cell.hidden-mobile,.div-table-header-cell.hidden-mobile{display:none}.div-table-header.grid-4-cols,.div-table-header.grid-5-cols,.div-table-row.grid-4-cols,.div-table-row.grid-5-cols{grid-template-columns:40px 2fr 1fr}}@media (max-width:480px){.div-table-cell.hidden-small,.div-table-header-cell.hidden-small{display:none}.div-table-header.grid-4-cols,.div-table-header.grid-5-cols,.div-table-row.grid-4-cols,.div-table-row.grid-5-cols{grid-template-columns:40px 1fr}}.div-table-widget.no-checkboxes .checkbox-column{display:none}.div-table-widget.no-checkboxes .div-table-header.grid-5-cols,.div-table-widget.no-checkboxes .div-table-row.grid-5-cols{grid-template-columns:1fr 2fr 2fr 1fr}.div-table-widget.no-checkboxes .div-table-header.grid-4-cols,.div-table-widget.no-checkboxes .div-table-row.grid-4-cols{grid-template-columns:2fr 2fr 1fr}.div-table-body::-webkit-scrollbar{width:8px}.div-table-body::-webkit-scrollbar-track{background:var(--dt-scrollbar-track);border-radius:4px}.div-table-body::-webkit-scrollbar-thumb{background:var(--dt-scrollbar-thumb);border-radius:4px}.div-table-body::-webkit-scrollbar-thumb:hover{background:var(--dt-scrollbar-thumb-hover)}.div-table-empty{color:var(--dt-text-disabled)}.div-table-empty,.div-table-loading{align-items:center;display:flex;font-style:italic;justify-content:center;min-height:200px}.div-table-loading{color:var(--dt-text-light);position:relative}.div-table-loading:before{animation:spin 1s linear infinite;border-top:2px solid var(--dt-spinner-track);border:2px solid var(--dt-spinner-track);border-radius:50%;border-top-color:var(--dt-spinner-active);content:"";height:20px;margin-right:10px;width:20px}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.error-indicator{align-items:center;background:var(--dt-error-bg);border:1px solid var(--dt-error-border);border-radius:3px;color:var(--dt-error-text);display:none;font-size:14px;gap:10px;justify-content:center;margin:10px 0;padding:15px}.div-table-row.loading-placeholder{background:var(--dt-group-bg);border-bottom:1px solid var(--dt-border-row);cursor:default;pointer-events:none}.div-table-row.loading-placeholder:hover{background:var(--dt-group-bg)!important}.div-table-cell.loading-cell{align-items:center;display:flex;padding:8px 12px}.loading-shimmer-content{animation:loading-shimmer 1.5s infinite;background:linear-gradient(90deg,var(--dt-skeleton-base) 25%,var(--dt-skeleton-shine) 50%,var(--dt-skeleton-base) 75%);background-size:200% 100%;border-radius:4px;height:16px}.retry-button{align-items:stretch;background:var(--dt-error);border:none;border-radius:4px;color:var(--dt-text-inverse);flex-direction:column;gap:0;padding:8px 12px}.div-table-cell.composite-cell .composite-sub-cell{align-items:flex-start}.retry-button:hover{background:var(--dt-error-hover)}.retry-button:active{background:var(--dt-error-active)}.div-table-container.has-fixed-columns{display:flex;flex-direction:column;overflow:hidden}.div-table-columns-wrapper{display:flex;flex:1;min-height:0;overflow:hidden}.div-table-fixed-section{background:var(--dt-bg-base);border-right:1px solid var(--dt-border-light);display:flex;flex:0 0 auto;flex-direction:column;z-index:5}.div-table-fixed-section.has-scroll-shadow{box-shadow:2px 0 8px var(--dt-shadow)}.div-table-scroll-section{display:flex;flex:1 1 auto;flex-direction:column;min-width:0;overflow:hidden}.div-table-fixed-header{display:grid;z-index:11}.div-table-fixed-header,.div-table-scroll-header{box-sizing:border-box;flex-shrink:0;position:relative}.div-table-scroll-header{overflow-x:scroll;overflow-y:hidden;scrollbar-width:none;z-index:10;-ms-overflow-style:none}.div-table-scroll-header::-webkit-scrollbar{display:none}.div-table-scroll-header-inner{display:grid;min-width:100%;width:max-content}.div-table-fixed-body{flex:1;min-height:0;overflow-x:hidden;overflow-y:auto}.div-table-fixed-body::-webkit-scrollbar{display:none}.div-table-fixed-body{-ms-overflow-style:none;scrollbar-width:none}.div-table-scroll-body{flex:1;min-height:0;overflow:auto;overflow-x:overlay;overflow-y:overlay}@supports (scrollbar-gutter:stable){.div-table-scroll-body{overflow-x:auto;overflow-y:auto}.div-table-fixed-body,.div-table-scroll-body{scrollbar-gutter:stable}}.div-table-fixed-row,.div-table-scroll-row{align-items:flex-start;box-sizing:border-box;min-height:40px}.div-table-fixed-row,.div-table-scroll-row{background:var(--dt-bg-base);display:grid}.div-table-row.hover,.div-table-row:hover{background-color:var(--dt-bg-hover)}.div-table-fixed-row.selected,.div-table-scroll-row.selected{background-color:var(--dt-bg-selected)!important}.div-table-fixed-row.focused,.div-table-scroll-row.focused{background-color:var(--dt-bg-base);box-shadow:inset 3px 0 0 var(--dt-primary)}.div-table-fixed-row.focused.hover,.div-table-fixed-row.focused:hover,.div-table-scroll-row.focused.hover,.div-table-scroll-row.focused:hover{background-color:var(--dt-primary-lighter)!important}.div-table-fixed-row.group-header,.div-table-scroll-row.group-header{background:var(--dt-bg-base);border-bottom:1px solid var(--dt-border-row);border-top:1px solid var(--dt-border-row);position:sticky;top:0;z-index:4}.div-table-fixed-row.group-header.focused,.div-table-scroll-row.group-header.focused{background-color:var(--dt-bg-base)!important;box-shadow:inset 3px 0 0 var(--dt-primary)!important}.div-table-scroll-section .div-table-cell{overflow:visible;text-overflow:clip;white-space:nowrap}.div-table-scroll-section .div-table-header-cell,.div-table-scroll-section .header-left-content{overflow:visible}.div-table-scroll-section .header-left-content>span{overflow:visible;text-overflow:clip;white-space:nowrap}.div-table-scroll-row{min-width:100%;width:max-content}@media (max-width:768px){.div-table-container.has-fixed-columns{display:flex;flex-direction:column}.div-table-columns-wrapper{flex-direction:column}.div-table-fixed-section{border-bottom:1px solid var(--dt-border-light);border-right:none;box-shadow:0 2px 8px var(--dt-shadow);flex:0 0 auto}.div-table-scroll-section{flex:1 1 auto}}.div-table-row.summary-row{background-color:var(--dt-bg-base);border-bottom:2px solid var(--dt-border-dark);font-weight:600;min-height:32px}.div-table-row.header-summary{background-color:var(--dt-bg-summary);border-bottom:1px solid var(--dt-summary-border);position:sticky;top:0;z-index:2}.div-table-row.group-summary{border-bottom:1px solid var(--dt-summary-border);font-size:.95em;font-weight:500}.div-table-cell.summary-cell{color:var(--dt-text-secondary);padding:8px 12px}.aggregate-value{color:var(--dt-text-primary);font-variant-numeric:tabular-nums;font-weight:700}.div-table-row.summary-row:hover{background-color:var(--dt-bg-summary)}.div-table-fixed-row.summary-row{background-color:var(--dt-bg-base);min-height:32px}.div-table-fixed-row.header-summary{background-color:var(--dt-bg-summary)}.div-table-cell.summary-cell:empty{min-height:1em}