@smartnet360/svelte-components 0.0.105 → 0.0.107
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 +75 -0
- package/dist/core/CellTable/CellTable.svelte +87 -15
- package/dist/core/CellTable/CellTable.svelte.d.ts +6 -0
- package/dist/core/CellTable/CellTableDemo.svelte +83 -127
- package/dist/core/CellTable/CellTablePanel.svelte +293 -25
- package/dist/core/CellTable/CellTablePanel.svelte.d.ts +15 -1
- package/dist/core/CellTable/CellTableToolbar.svelte +71 -1
- package/dist/core/CellTable/CellTableToolbar.svelte.d.ts +17 -0
- package/dist/core/CellTable/ColumnPicker.svelte +214 -0
- package/dist/core/CellTable/ColumnPicker.svelte.d.ts +26 -0
- package/dist/core/CellTable/column-config.d.ts +16 -0
- package/dist/core/CellTable/column-config.js +72 -0
- package/dist/core/CellTable/index.d.ts +3 -2
- package/dist/core/CellTable/index.js +6 -3
- package/dist/core/CellTable/types.d.ts +5 -46
- package/dist/core/CoverageMap/data/SiteStore.js +2 -2
- package/dist/map-v3/demo/demo-cells.d.ts +14 -10
- package/dist/map-v3/demo/demo-cells.js +21 -244
- package/dist/map-v3/features/cells/types.d.ts +3 -54
- package/dist/map-v3/features/cells/types.js +2 -1
- package/dist/shared/demo/cell-generator.d.ts +73 -0
- package/dist/shared/demo/cell-generator.js +258 -0
- package/dist/shared/demo/cell-types.d.ts +62 -0
- package/dist/shared/demo/cell-types.js +6 -0
- package/dist/shared/demo/index.d.ts +7 -0
- package/dist/shared/demo/index.js +7 -0
- package/package.json +1 -1
- package/dist/core/CellTable/demo-data.d.ts +0 -5
- package/dist/core/CellTable/demo-data.js +0 -501
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import CellTable from './CellTable.svelte';
|
|
4
4
|
import CellTableToolbar from './CellTableToolbar.svelte';
|
|
5
|
+
import { getColumnMetadata, getPresetVisibleFields } from './column-config';
|
|
5
6
|
import type {
|
|
6
7
|
CellData,
|
|
7
8
|
CellTableGroupField,
|
|
@@ -39,6 +40,12 @@
|
|
|
39
40
|
headerFilters?: boolean;
|
|
40
41
|
/** Panel title */
|
|
41
42
|
title?: string;
|
|
43
|
+
/** Show details sidebar */
|
|
44
|
+
showDetailsSidebar?: boolean;
|
|
45
|
+
/** Sidebar width in pixels */
|
|
46
|
+
sidebarWidth?: number;
|
|
47
|
+
/** Bindable reference to table methods */
|
|
48
|
+
tableRef?: { redraw: () => void } | null;
|
|
42
49
|
/** Row selection change event */
|
|
43
50
|
onselectionchange?: (event: RowSelectionEvent) => void;
|
|
44
51
|
/** Row click event */
|
|
@@ -49,6 +56,8 @@
|
|
|
49
56
|
headerActions?: Snippet;
|
|
50
57
|
/** Custom footer slot */
|
|
51
58
|
footer?: Snippet<[{ selectedRows: CellData[]; selectedCount: number }]>;
|
|
59
|
+
/** Custom details sidebar content */
|
|
60
|
+
detailsContent?: Snippet<[{ cell: CellData | null; closeSidebar: () => void }]>;
|
|
52
61
|
}
|
|
53
62
|
|
|
54
63
|
let {
|
|
@@ -64,17 +73,44 @@
|
|
|
64
73
|
statusColors,
|
|
65
74
|
headerFilters = true,
|
|
66
75
|
title = 'Cell Data',
|
|
76
|
+
showDetailsSidebar = false,
|
|
77
|
+
sidebarWidth = 320,
|
|
78
|
+
tableRef = $bindable(null),
|
|
67
79
|
onselectionchange,
|
|
68
80
|
onrowclick,
|
|
69
81
|
onrowdblclick,
|
|
70
82
|
headerActions,
|
|
71
|
-
footer
|
|
83
|
+
footer,
|
|
84
|
+
detailsContent
|
|
72
85
|
}: Props = $props();
|
|
73
86
|
|
|
74
87
|
let cellTable: CellTable;
|
|
75
88
|
let selectedCount = $state(0);
|
|
76
89
|
let selectedRows = $state<CellData[]>([]);
|
|
77
90
|
let filteredCount = $state(cells.length);
|
|
91
|
+
let sidebarOpen = $state(false);
|
|
92
|
+
let clickedCell: CellData | null = $state(null);
|
|
93
|
+
let tableRefSet = false;
|
|
94
|
+
let filtersVisible = $state(true);
|
|
95
|
+
|
|
96
|
+
// Column visibility management
|
|
97
|
+
const columnMeta = getColumnMetadata();
|
|
98
|
+
let visibleColumns = $state<string[]>(getPresetVisibleFields(columnPreset));
|
|
99
|
+
|
|
100
|
+
// Update visible columns when preset changes
|
|
101
|
+
$effect(() => {
|
|
102
|
+
visibleColumns = getPresetVisibleFields(columnPreset);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Expose table methods via tableRef - only set once
|
|
106
|
+
$effect(() => {
|
|
107
|
+
if (cellTable && !tableRefSet) {
|
|
108
|
+
tableRefSet = true;
|
|
109
|
+
tableRef = {
|
|
110
|
+
redraw: () => cellTable?.redraw()
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
});
|
|
78
114
|
|
|
79
115
|
function handleSelectionChange(event: RowSelectionEvent) {
|
|
80
116
|
selectedCount = event.rows.length;
|
|
@@ -82,6 +118,15 @@
|
|
|
82
118
|
onselectionchange?.(event);
|
|
83
119
|
}
|
|
84
120
|
|
|
121
|
+
function handleRowClick(event: RowClickEvent) {
|
|
122
|
+
if (showDetailsSidebar) {
|
|
123
|
+
clickedCell = event.row;
|
|
124
|
+
sidebarOpen = true;
|
|
125
|
+
setTimeout(() => cellTable?.redraw(), 320);
|
|
126
|
+
}
|
|
127
|
+
onrowclick?.(event);
|
|
128
|
+
}
|
|
129
|
+
|
|
85
130
|
function handleDataChange(event: DataChangeEvent) {
|
|
86
131
|
filteredCount = event.filteredCount;
|
|
87
132
|
}
|
|
@@ -106,6 +151,54 @@
|
|
|
106
151
|
cellTable?.clearFilters();
|
|
107
152
|
}
|
|
108
153
|
|
|
154
|
+
function handleCollapseAll() {
|
|
155
|
+
cellTable?.collapseAll();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function handleExpandAll() {
|
|
159
|
+
cellTable?.expandAll();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function handleToggleFilters() {
|
|
163
|
+
filtersVisible = !filtersVisible;
|
|
164
|
+
cellTable?.toggleHeaderFilters(filtersVisible);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function handleColumnVisibilityChange(field: string, visible: boolean) {
|
|
168
|
+
if (visible) {
|
|
169
|
+
if (!visibleColumns.includes(field)) {
|
|
170
|
+
visibleColumns = [...visibleColumns, field];
|
|
171
|
+
}
|
|
172
|
+
cellTable?.showColumn(field);
|
|
173
|
+
} else {
|
|
174
|
+
visibleColumns = visibleColumns.filter(f => f !== field);
|
|
175
|
+
cellTable?.hideColumn(field);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function handleResetColumns() {
|
|
180
|
+
const defaultFields = getPresetVisibleFields(columnPreset);
|
|
181
|
+
visibleColumns = defaultFields;
|
|
182
|
+
// Show/hide columns to match preset
|
|
183
|
+
columnMeta.forEach(col => {
|
|
184
|
+
if (defaultFields.includes(col.field)) {
|
|
185
|
+
cellTable?.showColumn(col.field);
|
|
186
|
+
} else {
|
|
187
|
+
cellTable?.hideColumn(col.field);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function toggleSidebar() {
|
|
193
|
+
sidebarOpen = !sidebarOpen;
|
|
194
|
+
setTimeout(() => cellTable?.redraw(), 320);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function closeSidebar() {
|
|
198
|
+
sidebarOpen = false;
|
|
199
|
+
setTimeout(() => cellTable?.redraw(), 320);
|
|
200
|
+
}
|
|
201
|
+
|
|
109
202
|
// Expose table methods
|
|
110
203
|
export function getSelectedRows(): CellData[] {
|
|
111
204
|
return cellTable?.getSelectedRows() ?? [];
|
|
@@ -122,6 +215,11 @@
|
|
|
122
215
|
export function redraw(): void {
|
|
123
216
|
cellTable?.redraw();
|
|
124
217
|
}
|
|
218
|
+
|
|
219
|
+
export function openSidebar(): void {
|
|
220
|
+
sidebarOpen = true;
|
|
221
|
+
setTimeout(() => cellTable?.redraw(), 320);
|
|
222
|
+
}
|
|
125
223
|
</script>
|
|
126
224
|
|
|
127
225
|
<div class="cell-table-panel d-flex flex-column" style:height>
|
|
@@ -131,11 +229,24 @@
|
|
|
131
229
|
<i class="bi bi-table text-primary"></i>
|
|
132
230
|
{title}
|
|
133
231
|
</h6>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
232
|
+
<div class="d-flex align-items-center gap-2">
|
|
233
|
+
{#if headerActions}
|
|
234
|
+
<div class="header-actions">
|
|
235
|
+
{@render headerActions()}
|
|
236
|
+
</div>
|
|
237
|
+
{/if}
|
|
238
|
+
{#if showDetailsSidebar}
|
|
239
|
+
<button
|
|
240
|
+
class="btn btn-sm"
|
|
241
|
+
class:btn-outline-secondary={!sidebarOpen}
|
|
242
|
+
class:btn-secondary={sidebarOpen}
|
|
243
|
+
onclick={toggleSidebar}
|
|
244
|
+
title={sidebarOpen ? 'Hide details' : 'Show details'}
|
|
245
|
+
>
|
|
246
|
+
<i class="bi" class:bi-layout-sidebar-reverse={!sidebarOpen} class:bi-x-lg={sidebarOpen}></i>
|
|
247
|
+
</button>
|
|
248
|
+
{/if}
|
|
249
|
+
</div>
|
|
139
250
|
</div>
|
|
140
251
|
|
|
141
252
|
<!-- Toolbar -->
|
|
@@ -152,27 +263,167 @@
|
|
|
152
263
|
onexportcsv={handleExportCSV}
|
|
153
264
|
onexportjson={handleExportJSON}
|
|
154
265
|
onclearfilters={handleClearFilters}
|
|
266
|
+
oncollapseall={handleCollapseAll}
|
|
267
|
+
onexpandall={handleExpandAll}
|
|
268
|
+
{filtersVisible}
|
|
269
|
+
ontogglefilters={handleToggleFilters}
|
|
270
|
+
{columnMeta}
|
|
271
|
+
{visibleColumns}
|
|
272
|
+
oncolumnvisibilitychange={handleColumnVisibilityChange}
|
|
273
|
+
onresetcolumns={handleResetColumns}
|
|
155
274
|
/>
|
|
156
275
|
{/if}
|
|
157
276
|
|
|
158
|
-
<!--
|
|
159
|
-
<div class="
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
277
|
+
<!-- Main content with optional sidebar -->
|
|
278
|
+
<div class="content-area d-flex flex-grow-1 overflow-hidden">
|
|
279
|
+
<!-- Table -->
|
|
280
|
+
<div class="table-wrapper flex-grow-1 overflow-hidden">
|
|
281
|
+
<CellTable
|
|
282
|
+
bind:this={cellTable}
|
|
283
|
+
{cells}
|
|
284
|
+
{groupBy}
|
|
285
|
+
{columnPreset}
|
|
286
|
+
{selectable}
|
|
287
|
+
{multiSelect}
|
|
288
|
+
height="100%"
|
|
289
|
+
{techColors}
|
|
290
|
+
{statusColors}
|
|
291
|
+
{headerFilters}
|
|
292
|
+
onselectionchange={handleSelectionChange}
|
|
293
|
+
ondatachange={handleDataChange}
|
|
294
|
+
onrowclick={handleRowClick}
|
|
295
|
+
{onrowdblclick}
|
|
296
|
+
/>
|
|
297
|
+
</div>
|
|
298
|
+
|
|
299
|
+
<!-- Details Sidebar -->
|
|
300
|
+
{#if showDetailsSidebar}
|
|
301
|
+
<aside
|
|
302
|
+
class="details-sidebar border-start bg-white overflow-auto"
|
|
303
|
+
class:open={sidebarOpen}
|
|
304
|
+
style:--sidebar-width="{sidebarWidth}px"
|
|
305
|
+
>
|
|
306
|
+
<div class="sidebar-content" style:width="{sidebarWidth}px">
|
|
307
|
+
<div class="d-flex align-items-center justify-content-between p-3 border-bottom bg-light sticky-top">
|
|
308
|
+
<h6 class="mb-0">
|
|
309
|
+
<i class="bi bi-info-circle text-primary"></i> Details
|
|
310
|
+
</h6>
|
|
311
|
+
<button
|
|
312
|
+
class="btn btn-sm btn-outline-secondary"
|
|
313
|
+
onclick={closeSidebar}
|
|
314
|
+
title="Close"
|
|
315
|
+
>
|
|
316
|
+
<i class="bi bi-x-lg"></i>
|
|
317
|
+
</button>
|
|
318
|
+
</div>
|
|
319
|
+
|
|
320
|
+
<div class="p-3">
|
|
321
|
+
{#if detailsContent}
|
|
322
|
+
{@render detailsContent({ cell: clickedCell, closeSidebar })}
|
|
323
|
+
{:else if clickedCell}
|
|
324
|
+
<!-- Default details view -->
|
|
325
|
+
<dl class="row mb-0 small">
|
|
326
|
+
<dt class="col-5 text-muted">ID</dt>
|
|
327
|
+
<dd class="col-7"><code class="text-primary">{clickedCell.id}</code></dd>
|
|
328
|
+
|
|
329
|
+
<dt class="col-5 text-muted">Cell Name</dt>
|
|
330
|
+
<dd class="col-7 fw-medium">{clickedCell.cellName}</dd>
|
|
331
|
+
|
|
332
|
+
<dt class="col-5 text-muted">Site</dt>
|
|
333
|
+
<dd class="col-7">{clickedCell.siteId}</dd>
|
|
334
|
+
|
|
335
|
+
<dt class="col-5 text-muted">Technology</dt>
|
|
336
|
+
<dd class="col-7">
|
|
337
|
+
<span class="badge bg-secondary">{clickedCell.tech}</span>
|
|
338
|
+
</dd>
|
|
339
|
+
|
|
340
|
+
<dt class="col-5 text-muted">Band</dt>
|
|
341
|
+
<dd class="col-7">
|
|
342
|
+
<span class="badge bg-info">{clickedCell.fband}</span>
|
|
343
|
+
</dd>
|
|
344
|
+
|
|
345
|
+
<dt class="col-5 text-muted">Frequency</dt>
|
|
346
|
+
<dd class="col-7">{clickedCell.frq} MHz</dd>
|
|
347
|
+
|
|
348
|
+
<dt class="col-5 text-muted">Status</dt>
|
|
349
|
+
<dd class="col-7">
|
|
350
|
+
<span class="badge bg-success">{clickedCell.status.replace(/_/g, ' ')}</span>
|
|
351
|
+
</dd>
|
|
352
|
+
|
|
353
|
+
<dt class="col-12 text-muted mt-2 mb-1 border-top pt-2">Physical</dt>
|
|
354
|
+
|
|
355
|
+
<dt class="col-5 text-muted">Azimuth</dt>
|
|
356
|
+
<dd class="col-7">{clickedCell.azimuth}°</dd>
|
|
357
|
+
|
|
358
|
+
<dt class="col-5 text-muted">Height</dt>
|
|
359
|
+
<dd class="col-7">{clickedCell.height}m</dd>
|
|
360
|
+
|
|
361
|
+
<dt class="col-5 text-muted">Beamwidth</dt>
|
|
362
|
+
<dd class="col-7">{clickedCell.beamwidth}°</dd>
|
|
363
|
+
|
|
364
|
+
<dt class="col-5 text-muted">E-Tilt</dt>
|
|
365
|
+
<dd class="col-7">{clickedCell.electricalTilt}°</dd>
|
|
366
|
+
|
|
367
|
+
<dt class="col-5 text-muted">Antenna</dt>
|
|
368
|
+
<dd class="col-7 text-truncate" title={clickedCell.antenna}>
|
|
369
|
+
{clickedCell.antenna}
|
|
370
|
+
</dd>
|
|
371
|
+
|
|
372
|
+
<dt class="col-12 text-muted mt-2 mb-1 border-top pt-2">Location</dt>
|
|
373
|
+
|
|
374
|
+
<dt class="col-5 text-muted">Latitude</dt>
|
|
375
|
+
<dd class="col-7">{clickedCell.latitude.toFixed(6)}</dd>
|
|
376
|
+
|
|
377
|
+
<dt class="col-5 text-muted">Longitude</dt>
|
|
378
|
+
<dd class="col-7">{clickedCell.longitude.toFixed(6)}</dd>
|
|
379
|
+
|
|
380
|
+
<dt class="col-12 text-muted mt-2 mb-1 border-top pt-2">Planning</dt>
|
|
381
|
+
|
|
382
|
+
<dt class="col-5 text-muted">Planner</dt>
|
|
383
|
+
<dd class="col-7">{clickedCell.planner}</dd>
|
|
384
|
+
|
|
385
|
+
<dt class="col-5 text-muted">On Air</dt>
|
|
386
|
+
<dd class="col-7">{clickedCell.onAirDate}</dd>
|
|
387
|
+
|
|
388
|
+
{#if clickedCell.comment}
|
|
389
|
+
<dt class="col-5 text-muted">Comment</dt>
|
|
390
|
+
<dd class="col-7 fst-italic">{clickedCell.comment}</dd>
|
|
391
|
+
{/if}
|
|
392
|
+
|
|
393
|
+
<!-- Dynamic Other Properties -->
|
|
394
|
+
{#if clickedCell.other && Object.keys(clickedCell.other).length > 0}
|
|
395
|
+
<dt class="col-12 text-muted mt-2 mb-1 border-top pt-2">Other</dt>
|
|
396
|
+
|
|
397
|
+
{#each Object.entries(clickedCell.other) as [key, value]}
|
|
398
|
+
<dt class="col-5 text-muted text-capitalize">{key.replace(/_/g, ' ')}</dt>
|
|
399
|
+
<dd class="col-7">
|
|
400
|
+
{#if value === null || value === undefined}
|
|
401
|
+
<span class="text-muted fst-italic">—</span>
|
|
402
|
+
{:else if typeof value === 'boolean'}
|
|
403
|
+
<span class="badge" class:bg-success={value} class:bg-secondary={!value}>
|
|
404
|
+
{value ? 'Yes' : 'No'}
|
|
405
|
+
</span>
|
|
406
|
+
{:else if typeof value === 'number'}
|
|
407
|
+
<code>{value}</code>
|
|
408
|
+
{:else if typeof value === 'object'}
|
|
409
|
+
<code class="small text-break">{JSON.stringify(value)}</code>
|
|
410
|
+
{:else}
|
|
411
|
+
{String(value)}
|
|
412
|
+
{/if}
|
|
413
|
+
</dd>
|
|
414
|
+
{/each}
|
|
415
|
+
{/if}
|
|
416
|
+
</dl>
|
|
417
|
+
{:else}
|
|
418
|
+
<div class="text-center text-muted py-5">
|
|
419
|
+
<i class="bi bi-hand-index fs-1 opacity-50"></i>
|
|
420
|
+
<p class="mt-2 mb-0">Click a row to see details</p>
|
|
421
|
+
</div>
|
|
422
|
+
{/if}
|
|
423
|
+
</div>
|
|
424
|
+
</div>
|
|
425
|
+
</aside>
|
|
426
|
+
{/if}
|
|
176
427
|
</div>
|
|
177
428
|
|
|
178
429
|
<!-- Footer -->
|
|
@@ -200,9 +451,26 @@
|
|
|
200
451
|
color: var(--bs-body-color, #212529);
|
|
201
452
|
}
|
|
202
453
|
|
|
454
|
+
.content-area {
|
|
455
|
+
min-height: 0;
|
|
456
|
+
}
|
|
457
|
+
|
|
203
458
|
.table-wrapper {
|
|
204
459
|
min-height: 0;
|
|
205
|
-
|
|
460
|
+
transition: all 0.3s ease;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.details-sidebar {
|
|
464
|
+
width: 0;
|
|
465
|
+
min-width: 0;
|
|
466
|
+
opacity: 0;
|
|
467
|
+
transition: width 0.3s ease, opacity 0.3s ease, min-width 0.3s ease;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.details-sidebar.open {
|
|
471
|
+
width: var(--sidebar-width, 320px);
|
|
472
|
+
min-width: var(--sidebar-width, 320px);
|
|
473
|
+
opacity: 1;
|
|
206
474
|
}
|
|
207
475
|
|
|
208
476
|
.panel-footer {
|
|
@@ -25,6 +25,14 @@ interface Props {
|
|
|
25
25
|
headerFilters?: boolean;
|
|
26
26
|
/** Panel title */
|
|
27
27
|
title?: string;
|
|
28
|
+
/** Show details sidebar */
|
|
29
|
+
showDetailsSidebar?: boolean;
|
|
30
|
+
/** Sidebar width in pixels */
|
|
31
|
+
sidebarWidth?: number;
|
|
32
|
+
/** Bindable reference to table methods */
|
|
33
|
+
tableRef?: {
|
|
34
|
+
redraw: () => void;
|
|
35
|
+
} | null;
|
|
28
36
|
/** Row selection change event */
|
|
29
37
|
onselectionchange?: (event: RowSelectionEvent) => void;
|
|
30
38
|
/** Row click event */
|
|
@@ -38,12 +46,18 @@ interface Props {
|
|
|
38
46
|
selectedRows: CellData[];
|
|
39
47
|
selectedCount: number;
|
|
40
48
|
}]>;
|
|
49
|
+
/** Custom details sidebar content */
|
|
50
|
+
detailsContent?: Snippet<[{
|
|
51
|
+
cell: CellData | null;
|
|
52
|
+
closeSidebar: () => void;
|
|
53
|
+
}]>;
|
|
41
54
|
}
|
|
42
55
|
declare const CellTablePanel: import("svelte").Component<Props, {
|
|
43
56
|
getSelectedRows: () => CellData[];
|
|
44
57
|
clearSelection: () => void;
|
|
45
58
|
scrollToRow: (id: string) => void;
|
|
46
59
|
redraw: () => void;
|
|
47
|
-
|
|
60
|
+
openSidebar: () => void;
|
|
61
|
+
}, "groupBy" | "columnPreset" | "tableRef">;
|
|
48
62
|
type CellTablePanel = ReturnType<typeof CellTablePanel>;
|
|
49
63
|
export default CellTablePanel;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { CellTableGroupField, ColumnPreset } from './types';
|
|
3
|
+
import type { ColumnMeta } from './column-config';
|
|
4
|
+
import ColumnPicker from './ColumnPicker.svelte';
|
|
3
5
|
|
|
4
6
|
interface Props {
|
|
5
7
|
/** Current grouping field */
|
|
@@ -28,6 +30,22 @@
|
|
|
28
30
|
onexportjson?: () => void;
|
|
29
31
|
/** Clear filters event */
|
|
30
32
|
onclearfilters?: () => void;
|
|
33
|
+
/** Collapse all groups event */
|
|
34
|
+
oncollapseall?: () => void;
|
|
35
|
+
/** Expand all groups event */
|
|
36
|
+
onexpandall?: () => void;
|
|
37
|
+
/** Whether header filters are visible */
|
|
38
|
+
filtersVisible?: boolean;
|
|
39
|
+
/** Toggle filters event */
|
|
40
|
+
ontogglefilters?: () => void;
|
|
41
|
+
/** All available columns metadata */
|
|
42
|
+
columnMeta?: ColumnMeta[];
|
|
43
|
+
/** Currently visible column fields */
|
|
44
|
+
visibleColumns?: string[];
|
|
45
|
+
/** Column visibility change event */
|
|
46
|
+
oncolumnvisibilitychange?: (field: string, visible: boolean) => void;
|
|
47
|
+
/** Reset columns to preset default */
|
|
48
|
+
onresetcolumns?: () => void;
|
|
31
49
|
}
|
|
32
50
|
|
|
33
51
|
let {
|
|
@@ -43,7 +61,15 @@
|
|
|
43
61
|
onpresetchange,
|
|
44
62
|
onexportcsv,
|
|
45
63
|
onexportjson,
|
|
46
|
-
onclearfilters
|
|
64
|
+
onclearfilters,
|
|
65
|
+
oncollapseall,
|
|
66
|
+
onexpandall,
|
|
67
|
+
filtersVisible = true,
|
|
68
|
+
ontogglefilters,
|
|
69
|
+
columnMeta = [],
|
|
70
|
+
visibleColumns = [],
|
|
71
|
+
oncolumnvisibilitychange,
|
|
72
|
+
onresetcolumns
|
|
47
73
|
}: Props = $props();
|
|
48
74
|
|
|
49
75
|
const groupOptions: { value: CellTableGroupField; label: string }[] = [
|
|
@@ -107,6 +133,28 @@
|
|
|
107
133
|
<option value={option.value}>{option.label}</option>
|
|
108
134
|
{/each}
|
|
109
135
|
</select>
|
|
136
|
+
{#if groupBy !== 'none'}
|
|
137
|
+
<div class="btn-group ms-2">
|
|
138
|
+
<button
|
|
139
|
+
type="button"
|
|
140
|
+
class="btn btn-sm btn-outline-secondary"
|
|
141
|
+
onclick={oncollapseall}
|
|
142
|
+
title="Collapse all groups"
|
|
143
|
+
aria-label="Collapse all groups"
|
|
144
|
+
>
|
|
145
|
+
<i class="bi bi-chevron-contract"></i>
|
|
146
|
+
</button>
|
|
147
|
+
<button
|
|
148
|
+
type="button"
|
|
149
|
+
class="btn btn-sm btn-outline-secondary"
|
|
150
|
+
onclick={onexpandall}
|
|
151
|
+
title="Expand all groups"
|
|
152
|
+
aria-label="Expand all groups"
|
|
153
|
+
>
|
|
154
|
+
<i class="bi bi-chevron-expand"></i>
|
|
155
|
+
</button>
|
|
156
|
+
</div>
|
|
157
|
+
{/if}
|
|
110
158
|
</div>
|
|
111
159
|
{/if}
|
|
112
160
|
|
|
@@ -127,6 +175,15 @@
|
|
|
127
175
|
<option value={option.value}>{option.label}</option>
|
|
128
176
|
{/each}
|
|
129
177
|
</select>
|
|
178
|
+
{#if columnMeta.length > 0}
|
|
179
|
+
<ColumnPicker
|
|
180
|
+
columns={columnMeta}
|
|
181
|
+
{visibleColumns}
|
|
182
|
+
presetName={presetOptions.find(p => p.value === columnPreset)?.label ?? 'Default'}
|
|
183
|
+
onchange={oncolumnvisibilitychange}
|
|
184
|
+
onreset={onresetcolumns}
|
|
185
|
+
/>
|
|
186
|
+
{/if}
|
|
130
187
|
</div>
|
|
131
188
|
{/if}
|
|
132
189
|
|
|
@@ -134,6 +191,19 @@
|
|
|
134
191
|
|
|
135
192
|
<!-- Actions -->
|
|
136
193
|
<div class="toolbar-actions d-flex align-items-center gap-2">
|
|
194
|
+
{#if ontogglefilters}
|
|
195
|
+
<button
|
|
196
|
+
type="button"
|
|
197
|
+
class="btn btn-sm"
|
|
198
|
+
class:btn-outline-secondary={!filtersVisible}
|
|
199
|
+
class:btn-secondary={filtersVisible}
|
|
200
|
+
onclick={ontogglefilters}
|
|
201
|
+
title={filtersVisible ? 'Hide filters' : 'Show filters'}
|
|
202
|
+
aria-label={filtersVisible ? 'Hide filters' : 'Show filters'}
|
|
203
|
+
>
|
|
204
|
+
<i class="bi bi-funnel"></i>
|
|
205
|
+
</button>
|
|
206
|
+
{/if}
|
|
137
207
|
{#if onclearfilters}
|
|
138
208
|
<button
|
|
139
209
|
type="button"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CellTableGroupField, ColumnPreset } from './types';
|
|
2
|
+
import type { ColumnMeta } from './column-config';
|
|
2
3
|
interface Props {
|
|
3
4
|
/** Current grouping field */
|
|
4
5
|
groupBy?: CellTableGroupField;
|
|
@@ -26,6 +27,22 @@ interface Props {
|
|
|
26
27
|
onexportjson?: () => void;
|
|
27
28
|
/** Clear filters event */
|
|
28
29
|
onclearfilters?: () => void;
|
|
30
|
+
/** Collapse all groups event */
|
|
31
|
+
oncollapseall?: () => void;
|
|
32
|
+
/** Expand all groups event */
|
|
33
|
+
onexpandall?: () => void;
|
|
34
|
+
/** Whether header filters are visible */
|
|
35
|
+
filtersVisible?: boolean;
|
|
36
|
+
/** Toggle filters event */
|
|
37
|
+
ontogglefilters?: () => void;
|
|
38
|
+
/** All available columns metadata */
|
|
39
|
+
columnMeta?: ColumnMeta[];
|
|
40
|
+
/** Currently visible column fields */
|
|
41
|
+
visibleColumns?: string[];
|
|
42
|
+
/** Column visibility change event */
|
|
43
|
+
oncolumnvisibilitychange?: (field: string, visible: boolean) => void;
|
|
44
|
+
/** Reset columns to preset default */
|
|
45
|
+
onresetcolumns?: () => void;
|
|
29
46
|
}
|
|
30
47
|
declare const CellTableToolbar: import("svelte").Component<Props, {}, "">;
|
|
31
48
|
type CellTableToolbar = ReturnType<typeof CellTableToolbar>;
|