@smartnet360/svelte-components 0.0.134 → 0.0.136

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.
Files changed (43) hide show
  1. package/dist/core/CellHistory/CellHistoryPanel.svelte +178 -0
  2. package/dist/core/CellHistory/CellHistoryPanel.svelte.d.ts +4 -0
  3. package/dist/core/CellHistory/column-config.d.ts +26 -0
  4. package/dist/core/CellHistory/column-config.js +120 -0
  5. package/dist/core/CellHistory/index.d.ts +9 -0
  6. package/dist/core/CellHistory/index.js +10 -0
  7. package/dist/core/CellHistory/transformers.d.ts +16 -0
  8. package/dist/core/CellHistory/transformers.js +76 -0
  9. package/dist/core/CellHistory/types.d.ts +54 -0
  10. package/dist/core/CellHistory/types.js +6 -0
  11. package/dist/core/{CellTable → CellTableV2}/CellTable.svelte +7 -3
  12. package/dist/core/{CellTable → CellTableV2}/CellTable.svelte.d.ts +3 -0
  13. package/dist/core/{CellTable → CellTableV2}/CellTablePanel.svelte +87 -235
  14. package/dist/core/{CellTable → CellTableV2}/CellTablePanel.svelte.d.ts +16 -2
  15. package/dist/core/{CellTable → CellTableV2}/CellTableToolbar.svelte +0 -1
  16. package/dist/core/{CellTable → CellTableV2}/column-config.d.ts +11 -30
  17. package/dist/core/{CellTable → CellTableV2}/column-config.js +21 -220
  18. package/dist/core/CellTableV2/composables/index.d.ts +12 -0
  19. package/dist/core/CellTableV2/composables/index.js +9 -0
  20. package/dist/core/CellTableV2/composables/useColumnVisibility.svelte.d.ts +45 -0
  21. package/dist/core/CellTableV2/composables/useColumnVisibility.svelte.js +98 -0
  22. package/dist/core/CellTableV2/composables/usePersistence.svelte.d.ts +28 -0
  23. package/dist/core/CellTableV2/composables/usePersistence.svelte.js +101 -0
  24. package/dist/core/CellTableV2/composables/useScrollSpy.svelte.d.ts +44 -0
  25. package/dist/core/CellTableV2/composables/useScrollSpy.svelte.js +91 -0
  26. package/dist/core/CellTableV2/index.d.ts +12 -0
  27. package/dist/core/CellTableV2/index.js +14 -0
  28. package/dist/core/{CellTable → CellTableV2}/types.d.ts +3 -3
  29. package/dist/core/index.d.ts +2 -1
  30. package/dist/core/index.js +3 -1
  31. package/package.json +1 -1
  32. package/dist/core/CellTable/CellHistoryDemo.svelte +0 -240
  33. package/dist/core/CellTable/CellHistoryDemo.svelte.d.ts +0 -3
  34. package/dist/core/CellTable/CellTableDemo.svelte +0 -336
  35. package/dist/core/CellTable/CellTableDemo.svelte.d.ts +0 -3
  36. package/dist/core/CellTable/history-api-helper.d.ts +0 -79
  37. package/dist/core/CellTable/history-api-helper.js +0 -83
  38. package/dist/core/CellTable/index.d.ts +0 -15
  39. package/dist/core/CellTable/index.js +0 -20
  40. /package/dist/core/{CellTable → CellTableV2}/CellTableToolbar.svelte.d.ts +0 -0
  41. /package/dist/core/{CellTable → CellTableV2}/ColumnPicker.svelte +0 -0
  42. /package/dist/core/{CellTable → CellTableV2}/ColumnPicker.svelte.d.ts +0 -0
  43. /package/dist/core/{CellTable → CellTableV2}/types.js +0 -0
@@ -1,8 +1,18 @@
1
1
  <script lang="ts">
2
+ /**
3
+ * CellTablePanel V2 - Composable-based Cell Table Panel
4
+ *
5
+ * Uses composables for reusable logic:
6
+ * - usePersistence: localStorage read/write
7
+ * - useColumnVisibility: column preset and visibility management
8
+ * - useScrollSpy: group navigation
9
+ */
2
10
  import type { Snippet } from 'svelte';
11
+ import type { ColumnDefinition } from 'tabulator-tables';
3
12
  import CellTable from './CellTable.svelte';
4
13
  import CellTableToolbar from './CellTableToolbar.svelte';
5
14
  import { getColumnMetadata, getPresetVisibleFields, DEFAULT_TECH_COLORS, DEFAULT_STATUS_COLORS, FBAND_COLORS } from './column-config';
15
+ import type { ColumnMetadataOptions } from './column-config';
6
16
  import type {
7
17
  CellData,
8
18
  CellTableGroupField,
@@ -16,6 +26,9 @@
16
26
  StatusColorMap,
17
27
  GroupOption
18
28
  } from './types';
29
+ import { usePersistence } from './composables/usePersistence.svelte';
30
+ import { useColumnVisibility } from './composables/useColumnVisibility.svelte';
31
+ import { useScrollSpy } from './composables/useScrollSpy.svelte';
19
32
 
20
33
  interface Props {
21
34
  /** Cell data array to display */
@@ -26,6 +39,10 @@
26
39
  groupOptions?: GroupOption[];
27
40
  /** Initial column preset */
28
41
  columnPreset?: ColumnPreset;
42
+ /** Custom column definitions (overrides columnPreset when provided) */
43
+ customColumns?: ColumnDefinition[];
44
+ /** Column metadata filter options */
45
+ columnMetadataOptions?: ColumnMetadataOptions;
29
46
  /** Enable row selection */
30
47
  selectable?: boolean;
31
48
  /** Enable multi-row selection */
@@ -52,7 +69,7 @@
52
69
  showDetailsSidebar?: boolean;
53
70
  /** Sidebar width in pixels */
54
71
  sidebarWidth?: number;
55
- /** Persist settings (groupBy, visibleColumns) to localStorage */
72
+ /** Persist settings to localStorage */
56
73
  persistSettings?: boolean;
57
74
  /** Storage key prefix for persisted settings */
58
75
  storageKey?: string;
@@ -84,7 +101,9 @@
84
101
  cells = [],
85
102
  groupBy = $bindable('none'),
86
103
  groupOptions,
87
- columnPreset = $bindable('default'),
104
+ columnPreset: initialPreset = 'default',
105
+ customColumns,
106
+ columnMetadataOptions,
88
107
  selectable = true,
89
108
  multiSelect = true,
90
109
  height = '100%',
@@ -99,7 +118,7 @@
99
118
  showDetailsSidebar = false,
100
119
  sidebarWidth = 320,
101
120
  persistSettings = true,
102
- storageKey = 'cell-table',
121
+ storageKey = 'cell-table-v2',
103
122
  persistLayout = true,
104
123
  showScrollSpy = false,
105
124
  tableRef = $bindable(null),
@@ -113,122 +132,28 @@
113
132
  contextMenu
114
133
  }: Props = $props();
115
134
 
116
- // Context menu state
117
- let contextMenuVisible = $state(false);
118
- let contextMenuRow: CellData | null = $state(null);
119
- let contextMenuPosition = $state({ x: 0, y: 0 });
120
-
121
- // Storage keys
122
- const STORAGE_KEY_GROUP = `${storageKey}-groupBy`;
123
- const STORAGE_KEY_FILTERS = `${storageKey}-filtersVisible`;
124
- const STORAGE_KEY_SCROLLSPY = `${storageKey}-scrollSpyEnabled`;
125
- const STORAGE_KEY_PRESET = `${storageKey}-columnPreset`;
135
+ // ========== Composables ==========
126
136
 
127
- // Per-preset column visibility storage key
128
- function getColumnsStorageKey(preset: ColumnPreset): string {
129
- return `${storageKey}-visibleColumns-${preset}`;
130
- }
131
-
132
- // Load persisted settings
133
- function loadPersistedSettings() {
134
- if (!persistSettings || typeof localStorage === 'undefined') return { filtersVisible: true, scrollSpyEnabled: showScrollSpy, preset: null };
135
-
136
- let filters = true;
137
- let scrollSpy = showScrollSpy;
138
- let preset: ColumnPreset | null = null;
139
-
140
- try {
141
- const savedGroup = localStorage.getItem(STORAGE_KEY_GROUP);
142
- if (savedGroup) {
143
- groupBy = savedGroup as CellTableGroupField;
144
- }
145
-
146
- const savedPreset = localStorage.getItem(STORAGE_KEY_PRESET);
147
- if (savedPreset) {
148
- preset = savedPreset as ColumnPreset;
149
- }
150
-
151
- const savedFilters = localStorage.getItem(STORAGE_KEY_FILTERS);
152
- if (savedFilters !== null) {
153
- filters = savedFilters === 'true';
154
- }
155
-
156
- const savedScrollSpy = localStorage.getItem(STORAGE_KEY_SCROLLSPY);
157
- if (savedScrollSpy !== null) {
158
- scrollSpy = savedScrollSpy === 'true';
159
- }
160
- } catch (e) {
161
- console.warn('Failed to load CellTable settings:', e);
162
- }
163
- return { filtersVisible: filters, scrollSpyEnabled: scrollSpy, preset };
164
- }
137
+ // Persistence utilities
138
+ const persistence = usePersistence({ storageKey, enabled: persistSettings });
165
139
 
166
- // Load columns for a specific preset
167
- function loadColumnsForPreset(preset: ColumnPreset): string[] {
168
- if (!persistSettings || typeof localStorage === 'undefined') {
169
- return getPresetVisibleFields(preset);
170
- }
171
- try {
172
- const saved = localStorage.getItem(getColumnsStorageKey(preset));
173
- if (saved) {
174
- return JSON.parse(saved) as string[];
175
- }
176
- } catch (e) {
177
- console.warn('Failed to load columns for preset:', e);
178
- }
179
- return getPresetVisibleFields(preset);
180
- }
181
-
182
- // Save group setting
183
- function saveGroupSetting(group: CellTableGroupField) {
184
- if (!persistSettings || typeof localStorage === 'undefined') return;
185
- try {
186
- localStorage.setItem(STORAGE_KEY_GROUP, group);
187
- } catch (e) {
188
- console.warn('Failed to save group setting:', e);
189
- }
190
- }
191
-
192
- // Save column visibility for current preset
193
- function saveColumnVisibility(columns: string[]) {
194
- if (!persistSettings || typeof localStorage === 'undefined') return;
195
- try {
196
- localStorage.setItem(getColumnsStorageKey(columnPreset), JSON.stringify(columns));
197
- } catch (e) {
198
- console.warn('Failed to save column visibility:', e);
199
- }
200
- }
201
-
202
- // Save filter visibility
203
- function saveFilterVisibility(visible: boolean) {
204
- if (!persistSettings || typeof localStorage === 'undefined') return;
205
- try {
206
- localStorage.setItem(STORAGE_KEY_FILTERS, String(visible));
207
- } catch (e) {
208
- console.warn('Failed to save filter visibility:', e);
209
- }
210
- }
211
-
212
- // Save scrollspy state
213
- function saveScrollSpyState(enabled: boolean) {
214
- if (!persistSettings || typeof localStorage === 'undefined') return;
215
- try {
216
- localStorage.setItem(STORAGE_KEY_SCROLLSPY, String(enabled));
217
- } catch (e) {
218
- console.warn('Failed to save scrollspy state:', e);
219
- }
220
- }
221
-
222
- // Save column preset
223
- function savePreset(preset: ColumnPreset) {
224
- if (!persistSettings || typeof localStorage === 'undefined') return;
225
- try {
226
- localStorage.setItem(STORAGE_KEY_PRESET, preset);
227
- } catch (e) {
228
- console.warn('Failed to save preset:', e);
229
- }
230
- }
140
+ // Column visibility management
141
+ const columnVis = useColumnVisibility({
142
+ storageKey,
143
+ columnMeta: getColumnMetadata(columnMetadataOptions),
144
+ initialPreset,
145
+ persistSettings
146
+ });
147
+
148
+ // ScrollSpy navigation
149
+ const scrollSpy = useScrollSpy({
150
+ storageKey,
151
+ initialEnabled: showScrollSpy,
152
+ persistSettings
153
+ });
231
154
 
155
+ // ========== Local State ==========
156
+
232
157
  let cellTable: CellTable;
233
158
  let selectedCount = $state(0);
234
159
  let selectedRows = $state<CellData[]>([]);
@@ -236,50 +161,28 @@
236
161
  let sidebarOpen = $state(false);
237
162
  let clickedCell: CellData | null = $state(null);
238
163
  let tableRefSet = false;
239
-
240
- // Column visibility management
241
- const columnMeta = getColumnMetadata();
164
+ let filtersVisible = $state(persistence.load('filtersVisible', true));
242
165
 
243
- // Initialize from storage or defaults
244
- const persistedSettings = loadPersistedSettings();
245
- let filtersVisible = $state(persistedSettings.filtersVisible);
246
-
247
- // Apply persisted preset if available
248
- if (persistedSettings.preset) {
249
- columnPreset = persistedSettings.preset;
166
+ // Context menu state
167
+ let contextMenuVisible = $state(false);
168
+ let contextMenuRow: CellData | null = $state(null);
169
+ let contextMenuPosition = $state({ x: 0, y: 0 });
170
+
171
+ // Load initial groupBy from persistence
172
+ const savedGroupBy = persistence.loadString('groupBy', groupBy);
173
+ if (savedGroupBy && savedGroupBy !== groupBy) {
174
+ groupBy = savedGroupBy as CellTableGroupField;
250
175
  }
251
-
252
- // Load columns for the current preset (with any saved customizations)
253
- let visibleColumns = $state<string[]>(loadColumnsForPreset(columnPreset));
254
-
255
- // ScrollSpy state - initialize from persisted settings
256
- let scrollSpyGroups = $state<{ key: string; count: number }[]>([]);
257
- let scrollSpyEnabled = $state(persistedSettings.scrollSpyEnabled);
258
176
 
259
- // Track preset changes to load per-preset columns
260
- let prevPreset: ColumnPreset | null = columnPreset;
177
+ // ========== Effects ==========
261
178
 
262
- // Apply column visibility to Tabulator
263
- function applyColumnVisibility(columns: string[]) {
264
- if (!cellTable) return;
265
- columnMeta.forEach(col => {
266
- if (columns.includes(col.field)) {
267
- cellTable.showColumn(col.field);
268
- } else {
269
- cellTable.hideColumn(col.field);
270
- }
271
- });
272
- }
179
+ // Track preset changes to apply column visibility
180
+ let prevPreset: ColumnPreset | null = columnVis.columnPreset;
273
181
 
274
- // Update visible columns when preset changes - load saved customizations for that preset
275
182
  $effect(() => {
276
- if (columnPreset !== prevPreset) {
277
- prevPreset = columnPreset;
278
- // Load saved columns for this preset (or preset defaults if none saved)
279
- const newColumns = loadColumnsForPreset(columnPreset);
280
- visibleColumns = newColumns;
281
- // Apply to Tabulator
282
- applyColumnVisibility(newColumns);
183
+ if (columnVis.columnPreset !== prevPreset) {
184
+ prevPreset = columnVis.columnPreset;
185
+ columnVis.applyToTable(cellTable);
283
186
  }
284
187
  });
285
188
 
@@ -291,7 +194,7 @@
291
194
  redraw: () => cellTable?.redraw()
292
195
  };
293
196
  // Apply persisted column visibility after table is ready
294
- setTimeout(() => applyColumnVisibility(visibleColumns), 100);
197
+ setTimeout(() => columnVis.applyToTable(cellTable), 100);
295
198
  // Apply persisted filter visibility after table is ready
296
199
  if (!filtersVisible) {
297
200
  setTimeout(() => cellTable?.toggleHeaderFilters(false), 100);
@@ -299,6 +202,8 @@
299
202
  }
300
203
  });
301
204
 
205
+ // ========== Event Handlers ==========
206
+
302
207
  function handleSelectionChange(event: RowSelectionEvent) {
303
208
  selectedCount = event.rows.length;
304
209
  selectedRows = event.rows;
@@ -317,7 +222,9 @@
317
222
  function handleDataChange(event: DataChangeEvent) {
318
223
  filteredCount = event.filteredCount;
319
224
  // Update scrollspy groups when data changes
320
- updateScrollSpyGroups();
225
+ if (scrollSpy.enabled && groupBy !== 'none') {
226
+ setTimeout(() => scrollSpy.updateGroups(cellTable), 50);
227
+ }
321
228
  }
322
229
 
323
230
  function handleRowContextMenu(event: RowContextMenuEvent) {
@@ -340,43 +247,28 @@
340
247
  }
341
248
  }
342
249
 
343
- function updateScrollSpyGroups() {
344
- if (scrollSpyEnabled && groupBy !== 'none') {
345
- // Small delay to ensure table has updated
346
- setTimeout(() => {
347
- scrollSpyGroups = cellTable?.getGroups() ?? [];
348
- }, 50);
349
- } else {
350
- scrollSpyGroups = [];
351
- }
352
- }
353
-
354
250
  function handleScrollToGroup(key: string) {
355
- cellTable?.scrollToGroup(key);
251
+ scrollSpy.scrollToGroup(cellTable, key);
356
252
  }
357
253
 
358
254
  function handleToggleScrollSpy() {
359
- scrollSpyEnabled = !scrollSpyEnabled;
360
- saveScrollSpyState(scrollSpyEnabled);
361
- if (scrollSpyEnabled && groupBy !== 'none') {
362
- updateScrollSpyGroups();
363
- } else {
364
- scrollSpyGroups = [];
255
+ scrollSpy.toggle();
256
+ if (scrollSpy.enabled && groupBy !== 'none') {
257
+ setTimeout(() => scrollSpy.updateGroups(cellTable), 100);
365
258
  }
366
259
  }
367
260
 
368
261
  function handleGroupChange(group: CellTableGroupField) {
369
262
  groupBy = group;
370
- saveGroupSetting(group);
263
+ persistence.saveString('groupBy', group);
371
264
  // Update scrollspy groups after grouping changes
372
- if (scrollSpyEnabled) {
373
- setTimeout(() => updateScrollSpyGroups(), 100);
265
+ if (scrollSpy.enabled) {
266
+ setTimeout(() => scrollSpy.updateGroups(cellTable), 100);
374
267
  }
375
268
  }
376
269
 
377
270
  function handlePresetChange(preset: ColumnPreset) {
378
- columnPreset = preset;
379
- savePreset(preset);
271
+ columnVis.setPreset(preset);
380
272
  }
381
273
 
382
274
  function handleExportCSV() {
@@ -402,41 +294,21 @@
402
294
  function handleToggleFilters() {
403
295
  filtersVisible = !filtersVisible;
404
296
  cellTable?.toggleHeaderFilters(filtersVisible);
405
- saveFilterVisibility(filtersVisible);
297
+ persistence.save('filtersVisible', filtersVisible);
406
298
  }
407
299
 
408
300
  function handleColumnVisibilityChange(field: string, visible: boolean) {
301
+ columnVis.toggleColumn(field, visible);
409
302
  if (visible) {
410
- if (!visibleColumns.includes(field)) {
411
- visibleColumns = [...visibleColumns, field];
412
- }
413
303
  cellTable?.showColumn(field);
414
304
  } else {
415
- visibleColumns = visibleColumns.filter(f => f !== field);
416
305
  cellTable?.hideColumn(field);
417
306
  }
418
- saveColumnVisibility(visibleColumns);
419
307
  }
420
308
 
421
309
  function handleResetColumns() {
422
- const defaultFields = getPresetVisibleFields(columnPreset);
423
- visibleColumns = defaultFields;
424
- // Show/hide columns to match preset
425
- columnMeta.forEach(col => {
426
- if (defaultFields.includes(col.field)) {
427
- cellTable?.showColumn(col.field);
428
- } else {
429
- cellTable?.hideColumn(col.field);
430
- }
431
- });
432
- // Clear persisted column visibility for this preset (use preset defaults)
433
- if (persistSettings && typeof localStorage !== 'undefined') {
434
- try {
435
- localStorage.removeItem(getColumnsStorageKey(columnPreset));
436
- } catch (e) {
437
- console.warn('Failed to clear column visibility:', e);
438
- }
439
- }
310
+ columnVis.resetToDefaults();
311
+ columnVis.applyToTable(cellTable);
440
312
  }
441
313
 
442
314
  function toggleSidebar() {
@@ -449,7 +321,8 @@
449
321
  setTimeout(() => cellTable?.redraw(), 320);
450
322
  }
451
323
 
452
- // Expose table methods
324
+ // ========== Public API ==========
325
+
453
326
  export function getSelectedRows(): CellData[] {
454
327
  return cellTable?.getSelectedRows() ?? [];
455
328
  }
@@ -497,6 +370,7 @@
497
370
  class:btn-secondary={sidebarOpen}
498
371
  onclick={toggleSidebar}
499
372
  title={sidebarOpen ? 'Hide details' : 'Show details'}
373
+ aria-label={sidebarOpen ? 'Hide details' : 'Show details'}
500
374
  >
501
375
  <i class="bi" class:bi-layout-sidebar-reverse={!sidebarOpen} class:bi-x-lg={sidebarOpen}></i>
502
376
  </button>
@@ -509,7 +383,7 @@
509
383
  <CellTableToolbar
510
384
  {groupBy}
511
385
  {groupOptions}
512
- {columnPreset}
386
+ columnPreset={columnVis.columnPreset}
513
387
  totalCount={cells.length}
514
388
  {filteredCount}
515
389
  {selectedCount}
@@ -525,23 +399,23 @@
525
399
  onexpandall={handleExpandAll}
526
400
  {filtersVisible}
527
401
  ontogglefilters={handleToggleFilters}
528
- {columnMeta}
529
- {visibleColumns}
402
+ columnMeta={columnVis.columnMeta}
403
+ visibleColumns={columnVis.visibleColumns}
530
404
  oncolumnvisibilitychange={handleColumnVisibilityChange}
531
405
  onresetcolumns={handleResetColumns}
532
- {scrollSpyEnabled}
406
+ scrollSpyEnabled={scrollSpy.enabled}
533
407
  showScrollSpyToggle={showScrollSpy}
534
408
  ontogglescrollspy={handleToggleScrollSpy}
535
409
  />
536
410
  {/if}
537
411
 
538
412
  <!-- ScrollSpy Navigation Bar -->
539
- {#if scrollSpyEnabled && groupBy !== 'none' && scrollSpyGroups.length > 0}
413
+ {#if scrollSpy.enabled && groupBy !== 'none' && scrollSpy.groups.length > 0}
540
414
  <div class="scrollspy-bar d-flex align-items-center gap-2 px-3 py-2 bg-body-tertiary border-bottom overflow-auto">
541
415
  <span class="text-muted small me-1">
542
416
  <i class="bi bi-signpost-split"></i> Jump to:
543
417
  </span>
544
- {#each scrollSpyGroups as group (group.key)}
418
+ {#each scrollSpy.groups as group (group.key)}
545
419
  {@const bgColor = groupBy === 'tech'
546
420
  ? (techColors?.[group.key] ?? DEFAULT_TECH_COLORS[group.key] ?? '#6c757d')
547
421
  : groupBy === 'fband'
@@ -571,7 +445,8 @@
571
445
  bind:this={cellTable}
572
446
  {cells}
573
447
  {groupBy}
574
- {columnPreset}
448
+ columnPreset={columnVis.columnPreset}
449
+ {customColumns}
575
450
  {selectable}
576
451
  {multiSelect}
577
452
  height="100%"
@@ -604,6 +479,7 @@
604
479
  class="btn btn-sm btn-outline-secondary"
605
480
  onclick={closeSidebar}
606
481
  title="Close"
482
+ aria-label="Close sidebar"
607
483
  >
608
484
  <i class="bi bi-x-lg"></i>
609
485
  </button>
@@ -681,30 +557,6 @@
681
557
  <dt class="col-5 text-muted">Comment</dt>
682
558
  <dd class="col-7 fst-italic">{clickedCell.comment}</dd>
683
559
  {/if}
684
-
685
- <!-- Dynamic Other Properties -->
686
- {#if clickedCell.other && Object.keys(clickedCell.other).length > 0}
687
- <dt class="col-12 text-muted mt-2 mb-1 border-top pt-2">Other</dt>
688
-
689
- {#each Object.entries(clickedCell.other) as [key, value]}
690
- <dt class="col-5 text-muted text-capitalize">{key.replace(/_/g, ' ')}</dt>
691
- <dd class="col-7">
692
- {#if value === null || value === undefined}
693
- <span class="text-muted fst-italic">—</span>
694
- {:else if typeof value === 'boolean'}
695
- <span class="badge" class:bg-success={value} class:bg-secondary={!value}>
696
- {value ? 'Yes' : 'No'}
697
- </span>
698
- {:else if typeof value === 'number'}
699
- <code>{value}</code>
700
- {:else if typeof value === 'object'}
701
- <code class="small text-break">{JSON.stringify(value)}</code>
702
- {:else}
703
- {String(value)}
704
- {/if}
705
- </dd>
706
- {/each}
707
- {/if}
708
560
  </dl>
709
561
  {:else}
710
562
  <div class="text-center text-muted py-5">
@@ -1,4 +1,14 @@
1
+ /**
2
+ * CellTablePanel V2 - Composable-based Cell Table Panel
3
+ *
4
+ * Uses composables for reusable logic:
5
+ * - usePersistence: localStorage read/write
6
+ * - useColumnVisibility: column preset and visibility management
7
+ * - useScrollSpy: group navigation
8
+ */
1
9
  import type { Snippet } from 'svelte';
10
+ import type { ColumnDefinition } from 'tabulator-tables';
11
+ import type { ColumnMetadataOptions } from './column-config';
2
12
  import type { CellData, CellTableGroupField, ColumnPreset, RowSelectionEvent, RowClickEvent, RowDblClickEvent, TechColorMap, StatusColorMap, GroupOption } from './types';
3
13
  interface Props {
4
14
  /** Cell data array to display */
@@ -9,6 +19,10 @@ interface Props {
9
19
  groupOptions?: GroupOption[];
10
20
  /** Initial column preset */
11
21
  columnPreset?: ColumnPreset;
22
+ /** Custom column definitions (overrides columnPreset when provided) */
23
+ customColumns?: ColumnDefinition[];
24
+ /** Column metadata filter options */
25
+ columnMetadataOptions?: ColumnMetadataOptions;
12
26
  /** Enable row selection */
13
27
  selectable?: boolean;
14
28
  /** Enable multi-row selection */
@@ -35,7 +49,7 @@ interface Props {
35
49
  showDetailsSidebar?: boolean;
36
50
  /** Sidebar width in pixels */
37
51
  sidebarWidth?: number;
38
- /** Persist settings (groupBy, visibleColumns) to localStorage */
52
+ /** Persist settings to localStorage */
39
53
  persistSettings?: boolean;
40
54
  /** Storage key prefix for persisted settings */
41
55
  storageKey?: string;
@@ -79,6 +93,6 @@ declare const CellTablePanel: import("svelte").Component<Props, {
79
93
  scrollToRow: (id: string) => void;
80
94
  redraw: () => void;
81
95
  openSidebar: () => void;
82
- }, "groupBy" | "columnPreset" | "tableRef">;
96
+ }, "groupBy" | "tableRef">;
83
97
  type CellTablePanel = ReturnType<typeof CellTablePanel>;
84
98
  export default CellTablePanel;
@@ -107,7 +107,6 @@
107
107
  { value: 'network', label: 'Network' },
108
108
  { value: 'planning', label: 'Planning' },
109
109
  { value: 'compare', label: 'Compare (Atoll/NW)' },
110
- { value: 'kpi', label: 'KPI Trends' }
111
110
  ];
112
111
 
113
112
  function handleGroupChange(e: Event) {
@@ -61,35 +61,6 @@ export declare function heightFormatter(cell: CellComponent): string;
61
61
  * - Gray: one or both values missing
62
62
  */
63
63
  export declare function createCompareFormatter(atollField: string, nwtField: string): (cell: CellComponent) => string;
64
- /**
65
- * Create a history change formatter for showing current vs previous values
66
- * Highlights changes in yellow/amber, unchanged values in muted style
67
- *
68
- * @param currentField - Field name for current value
69
- * @param prevField - Field name for previous value
70
- */
71
- export declare function createHistoryChangeFormatter(currentField: string, prevField: string): (cell: CellComponent) => string;
72
- /**
73
- * Format ISO date string to YYYY.MM.DD format for history display
74
- */
75
- export declare function historyDateFormatter(cell: CellComponent): string;
76
- /**
77
- * Creates a sparkline SVG formatter for KPI time-series data
78
- * Renders a mini line chart showing trend over time
79
- *
80
- * @param options Configuration for the sparkline
81
- */
82
- export interface SparklineOptions {
83
- width?: number;
84
- height?: number;
85
- lineColor?: string;
86
- fillColor?: string;
87
- showDots?: boolean;
88
- showLastValue?: boolean;
89
- unit?: string;
90
- decimals?: number;
91
- }
92
- export declare function createSparklineFormatter(options?: SparklineOptions): (cell: CellComponent) => string;
93
64
  /**
94
65
  * Custom sorter for fband - extracts numeric portion and sorts numerically
95
66
  * Examples: LTE700 → 700, GSM900 → 900, LTE1800 → 1800, 5G-3500 → 3500
@@ -129,10 +100,20 @@ export interface ColumnMeta {
129
100
  title: string;
130
101
  group: string;
131
102
  }
103
+ /**
104
+ * Options for filtering column metadata
105
+ */
106
+ export interface ColumnMetadataOptions {
107
+ /** Include only these groups (if specified, only these groups are included) */
108
+ include?: string[];
109
+ /** Exclude these groups (applied after include filter) */
110
+ exclude?: string[];
111
+ }
132
112
  /**
133
113
  * Get column metadata for the column picker UI
114
+ * @param options Filter options for including/excluding column groups
134
115
  */
135
- export declare function getColumnMetadata(): ColumnMeta[];
116
+ export declare function getColumnMetadata(options?: ColumnMetadataOptions): ColumnMeta[];
136
117
  /**
137
118
  * Get default visible columns for a preset
138
119
  */