@smartnet360/svelte-components 0.0.133 → 0.0.135

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 (40) 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/CellHistoryDemo.svelte +1 -0
  12. package/dist/core/CellTable/CellTable.svelte +7 -5
  13. package/dist/core/CellTable/CellTablePanel.svelte +82 -14
  14. package/dist/core/CellTable/CellTablePanel.svelte.d.ts +2 -0
  15. package/dist/core/CellTable/column-config.js +46 -58
  16. package/dist/core/CellTableV2/CellTable.svelte +601 -0
  17. package/dist/core/CellTableV2/CellTable.svelte.d.ts +43 -0
  18. package/dist/core/CellTableV2/CellTablePanel.svelte +685 -0
  19. package/dist/core/CellTableV2/CellTablePanel.svelte.d.ts +98 -0
  20. package/dist/core/CellTableV2/CellTableToolbar.svelte +322 -0
  21. package/dist/core/CellTableV2/CellTableToolbar.svelte.d.ts +59 -0
  22. package/dist/core/CellTableV2/ColumnPicker.svelte +214 -0
  23. package/dist/core/CellTableV2/ColumnPicker.svelte.d.ts +26 -0
  24. package/dist/core/CellTableV2/column-config.d.ts +120 -0
  25. package/dist/core/CellTableV2/column-config.js +671 -0
  26. package/dist/core/CellTableV2/composables/index.d.ts +12 -0
  27. package/dist/core/CellTableV2/composables/index.js +9 -0
  28. package/dist/core/CellTableV2/composables/useColumnVisibility.svelte.d.ts +45 -0
  29. package/dist/core/CellTableV2/composables/useColumnVisibility.svelte.js +98 -0
  30. package/dist/core/CellTableV2/composables/usePersistence.svelte.d.ts +28 -0
  31. package/dist/core/CellTableV2/composables/usePersistence.svelte.js +101 -0
  32. package/dist/core/CellTableV2/composables/useScrollSpy.svelte.d.ts +44 -0
  33. package/dist/core/CellTableV2/composables/useScrollSpy.svelte.js +91 -0
  34. package/dist/core/CellTableV2/index.d.ts +12 -0
  35. package/dist/core/CellTableV2/index.js +14 -0
  36. package/dist/core/CellTableV2/types.d.ts +172 -0
  37. package/dist/core/CellTableV2/types.js +6 -0
  38. package/dist/core/index.d.ts +2 -0
  39. package/dist/core/index.js +5 -0
  40. package/package.json +1 -1
@@ -0,0 +1,671 @@
1
+ /**
2
+ * CellTable - Column Configuration
3
+ *
4
+ * Defines column definitions, presets, and formatters for the cell table
5
+ */
6
+ /**
7
+ * Default technology colors (Bootstrap-aligned)
8
+ * 2G: Yellow, 4G: Purple, 5G: Green
9
+ */
10
+ export const DEFAULT_TECH_COLORS = {
11
+ '2G': '#ffc107', // Yellow
12
+ '3G': '#0d6efd', // primary blue
13
+ '4G': '#9333ea', // Purple
14
+ '5G': '#22c55e', // Green
15
+ 'LTE': '#9333ea', // Purple (same as 4G)
16
+ 'NR': '#22c55e', // Green (same as 5G)
17
+ };
18
+ /**
19
+ * Default status colors (Bootstrap-aligned)
20
+ */
21
+ export const DEFAULT_STATUS_COLORS = {
22
+ 'On_Air': '#198754', // success green
23
+ 'On_Air_UNDER_CONSTRUCTION': '#4ce207ff', // warning yellow
24
+ 'On_Air_Locked': '#e04001ff', // info cyan
25
+ 'RF_Plan_Ready': '#e69603ff', // primary blue
26
+ 'Re-Planned_RF_Plan_Ready': '#c1a342ff', // purple
27
+ 'Tavlati_RF_Plan_Ready': '#25ddfdff', // orange
28
+ };
29
+ /**
30
+ * Frequency band colors
31
+ * GSM: Yellow shades (darker = higher freq)
32
+ * LTE: Purple shades (darker = higher freq)
33
+ * 5G: Green shades (stronger = higher freq)
34
+ */
35
+ export const FBAND_COLORS = {
36
+ // GSM - Yellow shades (900 lighter, 1800 darker)
37
+ 'GSM900': '#ffc107', // Light yellow
38
+ 'GSM1800': '#cc9a06', // Darker yellow/gold
39
+ // LTE - Purple shades (700 lightest → 2600 darkest)
40
+ 'LTE700': '#d8b4fe', // Light purple
41
+ 'LTE800': '#c084fc', //
42
+ 'LTE900': '#a855f7', //
43
+ 'LTE1800': '#9333ea', //
44
+ 'LTE2100': '#7e22ce', //
45
+ 'LTE2600': '#6b21a8', // Dark purple
46
+ // 5G - Green shades (700 lighter → 3500 stronger)
47
+ '5G-700': '#86efac', // Light green
48
+ '5G-2100': '#22c55e', // Medium green
49
+ '5G-3500': '#15803d', // Strong/dark green
50
+ 'NR3500': '#15803d', // Same as 5G-3500
51
+ };
52
+ /**
53
+ * Column groups for different presets
54
+ */
55
+ export const COLUMN_GROUPS = {
56
+ core: ['siteId', 'txId', 'cellName', 'tech', 'fband', 'status'],
57
+ physical: ['antenna', 'azimuth', 'height', 'beamwidth'],
58
+ network: ['nwET', 'nwPW', 'nwRS', 'nwBW', 'dlEarfn', 'bcch', 'pci', 'rru', 'cellID', 'cellId2G', 'ctrlid'],
59
+ planning: ['planner', 'comment', 'onAirDate'],
60
+ atoll: ['atollET', 'atollMT', 'atollPW', 'atollRS', 'atollBW'],
61
+ position: ['latitude', 'longitude', 'siteLatitude', 'siteLongitude', 'dx', 'dy'],
62
+ compare: ['compareET', 'comparePW', 'compareRS', 'compareBW'],
63
+ };
64
+ /**
65
+ * Create a technology badge formatter
66
+ */
67
+ export function createTechFormatter(colors = DEFAULT_TECH_COLORS) {
68
+ return (cell) => {
69
+ const value = cell.getValue();
70
+ const color = colors[value] || '#6c757d';
71
+ return `<span class="badge" style="background-color: ${color}; color: white;">${value}</span>`;
72
+ };
73
+ }
74
+ /**
75
+ * Create a status badge formatter
76
+ */
77
+ export function createStatusFormatter(colors = DEFAULT_STATUS_COLORS) {
78
+ return (cell) => {
79
+ const value = cell.getValue();
80
+ const color = colors[value] || '#6c757d';
81
+ const displayValue = value.replace(/_/g, ' ');
82
+ return `<span class="badge" style="background-color: ${color}; color: white; font-size: 0.7rem;">${displayValue}</span>`;
83
+ };
84
+ }
85
+ /**
86
+ * Create an fband badge formatter
87
+ */
88
+ export function createFbandFormatter() {
89
+ return (cell) => {
90
+ const value = cell.getValue();
91
+ const color = FBAND_COLORS[value] || '#6c757d';
92
+ return `<span class="badge" style="background-color: ${color}; color: white;">${value}</span>`;
93
+ };
94
+ }
95
+ /**
96
+ * Number formatter with fixed decimals
97
+ */
98
+ export function numberFormatter(decimals = 2) {
99
+ return (cell) => {
100
+ const value = cell.getValue();
101
+ if (value === null || value === undefined || value === '')
102
+ return '';
103
+ const num = Number(value);
104
+ return isNaN(num) ? String(value) : num.toFixed(decimals);
105
+ };
106
+ }
107
+ /**
108
+ * Coordinate formatter (lat/lng)
109
+ */
110
+ export function coordinateFormatter(cell) {
111
+ const value = cell.getValue();
112
+ if (value === null || value === undefined || value === '')
113
+ return '';
114
+ const num = Number(value);
115
+ return isNaN(num) ? String(value) : num.toFixed(6);
116
+ }
117
+ /**
118
+ * Azimuth formatter with degree symbol
119
+ */
120
+ export function azimuthFormatter(cell) {
121
+ const value = cell.getValue();
122
+ if (value === null || value === undefined || value === '')
123
+ return '';
124
+ return `${value}°`;
125
+ }
126
+ /**
127
+ * Height formatter with meter unit
128
+ */
129
+ export function heightFormatter(cell) {
130
+ const value = cell.getValue();
131
+ if (value === null || value === undefined || value === '')
132
+ return '';
133
+ return `${value}m`;
134
+ }
135
+ /**
136
+ * Comparison formatter for Atoll vs Network values
137
+ * Shows both values side by side with color coding:
138
+ * - Green: values match exactly
139
+ * - Red: values don't match
140
+ * - Gray: one or both values missing
141
+ */
142
+ export function createCompareFormatter(atollField, nwtField) {
143
+ return (cell) => {
144
+ const row = cell.getRow().getData();
145
+ const atollVal = row[atollField];
146
+ const nwtVal = row[nwtField];
147
+ const atollStr = atollVal !== null && atollVal !== undefined ? String(atollVal) : '-';
148
+ const nwtStr = nwtVal !== null && nwtVal !== undefined ? String(nwtVal) : '-';
149
+ // Determine match status
150
+ const atollMissing = atollVal === null || atollVal === undefined;
151
+ const nwtMissing = nwtVal === null || nwtVal === undefined;
152
+ let bgColor;
153
+ let textColor = 'white';
154
+ if (atollMissing || nwtMissing) {
155
+ // One or both missing - gray
156
+ bgColor = '#6c757d';
157
+ }
158
+ else if (atollVal === nwtVal) {
159
+ // Exact match - green
160
+ bgColor = '#198754';
161
+ }
162
+ else {
163
+ // Mismatch - red
164
+ bgColor = '#dc3545';
165
+ }
166
+ return `<span class="badge" style="background-color: ${bgColor}; color: ${textColor}; font-size: 0.75rem; font-weight: normal;">${atollStr} | ${nwtStr}</span>`;
167
+ };
168
+ }
169
+ /**
170
+ * Custom sorter for fband - extracts numeric portion and sorts numerically
171
+ * Examples: LTE700 → 700, GSM900 → 900, LTE1800 → 1800, 5G-3500 → 3500
172
+ */
173
+ export function fbandSorter(a, b) {
174
+ const numA = parseInt(a.replace(/\D/g, ''), 10) || 0;
175
+ const numB = parseInt(b.replace(/\D/g, ''), 10) || 0;
176
+ return numA - numB;
177
+ }
178
+ /**
179
+ * Custom sorter for cellName - sorts by the 5th character (sector digit)
180
+ * Example: 10001 → '1', 10002 → '2', 10003 → '3'
181
+ */
182
+ export function cellNameSectorSorter(a, b) {
183
+ const charA = a.charAt(4) || '0';
184
+ const charB = b.charAt(4) || '0';
185
+ return charA.localeCompare(charB);
186
+ }
187
+ /**
188
+ * Combined multi-level sorter for cell data
189
+ * Sort order: tech (asc) → fband by numeric value (asc) → cellName by 5th digit (asc)
190
+ */
191
+ export function cellDataSorter(a, b) {
192
+ // 1. Sort by tech (string comparison)
193
+ const techA = String(a.tech || '');
194
+ const techB = String(b.tech || '');
195
+ const techCompare = techA.localeCompare(techB);
196
+ if (techCompare !== 0)
197
+ return techCompare;
198
+ // 2. Sort by fband (numeric extraction)
199
+ const fbandA = String(a.fband || '');
200
+ const fbandB = String(b.fband || '');
201
+ const fbandCompare = fbandSorter(fbandA, fbandB);
202
+ if (fbandCompare !== 0)
203
+ return fbandCompare;
204
+ // 3. Sort by cellName 5th character (sector)
205
+ const cellNameA = String(a.cellName || '');
206
+ const cellNameB = String(b.cellName || '');
207
+ return cellNameSectorSorter(cellNameA, cellNameB);
208
+ }
209
+ /**
210
+ * Get all column definitions
211
+ */
212
+ export function getAllColumns(techColors = DEFAULT_TECH_COLORS, statusColors = DEFAULT_STATUS_COLORS, headerFilters = true) {
213
+ const headerFilterParams = headerFilters ? { headerFilter: 'input' } : {};
214
+ const selectHeaderFilter = headerFilters ? { headerFilter: 'list', headerFilterParams: { valuesLookup: true } } : {};
215
+ return [
216
+ // Core columns - siteId, txId, cellName first (frozen)
217
+ {
218
+ title: 'Site ID',
219
+ field: 'siteId',
220
+ width: 120,
221
+ frozen: true,
222
+ ...headerFilterParams,
223
+ },
224
+ {
225
+ title: 'TX ID',
226
+ field: 'txId',
227
+ width: 100,
228
+ frozen: true,
229
+ ...headerFilterParams,
230
+ },
231
+ {
232
+ title: 'Cell Name',
233
+ field: 'cellName',
234
+ width: 150,
235
+ frozen: true,
236
+ ...headerFilterParams,
237
+ },
238
+ {
239
+ title: 'Tech',
240
+ field: 'tech',
241
+ width: 80,
242
+ hozAlign: 'center',
243
+ formatter: createTechFormatter(techColors),
244
+ ...selectHeaderFilter,
245
+ },
246
+ {
247
+ title: 'Band',
248
+ field: 'fband',
249
+ width: 100,
250
+ hozAlign: 'center',
251
+ formatter: createFbandFormatter(),
252
+ ...selectHeaderFilter,
253
+ },
254
+ {
255
+ title: 'Freq',
256
+ field: 'frq',
257
+ width: 80,
258
+ hozAlign: 'center',
259
+ ...selectHeaderFilter,
260
+ },
261
+ {
262
+ title: 'Status',
263
+ field: 'status',
264
+ width: 180,
265
+ formatter: createStatusFormatter(statusColors),
266
+ ...selectHeaderFilter,
267
+ },
268
+ {
269
+ title: 'On Air Date',
270
+ field: 'onAirDate',
271
+ width: 120,
272
+ ...headerFilterParams,
273
+ },
274
+ // Physical columns
275
+ {
276
+ title: 'Antenna',
277
+ field: 'antenna',
278
+ width: 150,
279
+ ...headerFilterParams,
280
+ },
281
+ {
282
+ title: 'Azimuth',
283
+ field: 'azimuth',
284
+ width: 90,
285
+ hozAlign: 'right',
286
+ formatter: azimuthFormatter,
287
+ ...headerFilterParams,
288
+ },
289
+ {
290
+ title: 'Height',
291
+ field: 'height',
292
+ width: 80,
293
+ hozAlign: 'right',
294
+ formatter: heightFormatter,
295
+ ...headerFilterParams,
296
+ },
297
+ {
298
+ title: 'Beamwidth',
299
+ field: 'beamwidth',
300
+ width: 100,
301
+ hozAlign: 'right',
302
+ formatter: azimuthFormatter,
303
+ ...headerFilterParams,
304
+ },
305
+ // Network columns
306
+ {
307
+ title: 'DL EARFCN',
308
+ field: 'dlEarfn',
309
+ width: 100,
310
+ hozAlign: 'right',
311
+ ...headerFilterParams,
312
+ },
313
+ {
314
+ title: 'BCCH',
315
+ field: 'bcch',
316
+ width: 80,
317
+ hozAlign: 'right',
318
+ ...headerFilterParams,
319
+ },
320
+ {
321
+ title: 'PCI',
322
+ field: 'pci',
323
+ width: 80,
324
+ hozAlign: 'right',
325
+ ...headerFilterParams,
326
+ },
327
+ {
328
+ title: 'Cell ID',
329
+ field: 'cellID',
330
+ width: 100,
331
+ ...headerFilterParams,
332
+ },
333
+ {
334
+ title: 'Cell ID 2G',
335
+ field: 'cellID2G',
336
+ width: 100,
337
+ ...headerFilterParams,
338
+ },
339
+ {
340
+ title: 'Ctrl ID',
341
+ field: 'ctrlid',
342
+ width: 100,
343
+ ...headerFilterParams,
344
+ },
345
+ {
346
+ title: 'RRU',
347
+ field: 'rru',
348
+ width: 100,
349
+ ...headerFilterParams,
350
+ },
351
+ {
352
+ title: 'NW ET',
353
+ field: 'nwET',
354
+ width: 80,
355
+ hozAlign: 'right',
356
+ formatter: numberFormatter(1),
357
+ ...headerFilterParams,
358
+ },
359
+ {
360
+ title: 'NW PW',
361
+ field: 'nwPW',
362
+ width: 80,
363
+ hozAlign: 'right',
364
+ formatter: numberFormatter(1),
365
+ ...headerFilterParams,
366
+ },
367
+ {
368
+ title: 'NW RS',
369
+ field: 'nwRS',
370
+ width: 80,
371
+ hozAlign: 'right',
372
+ ...headerFilterParams,
373
+ },
374
+ {
375
+ title: 'NW BW',
376
+ field: 'nwBW',
377
+ width: 80,
378
+ hozAlign: 'right',
379
+ ...headerFilterParams,
380
+ },
381
+ // Atoll columns
382
+ {
383
+ title: 'Atoll ET',
384
+ field: 'atollET',
385
+ width: 90,
386
+ hozAlign: 'right',
387
+ formatter: numberFormatter(1),
388
+ ...headerFilterParams,
389
+ },
390
+ {
391
+ title: 'Atoll MT',
392
+ field: 'atollMT',
393
+ width: 90,
394
+ hozAlign: 'right',
395
+ formatter: numberFormatter(1),
396
+ ...headerFilterParams,
397
+ },
398
+ {
399
+ title: 'Atoll PW',
400
+ field: 'atollPW',
401
+ width: 90,
402
+ hozAlign: 'right',
403
+ formatter: numberFormatter(1),
404
+ ...headerFilterParams,
405
+ },
406
+ {
407
+ title: 'Atoll RS',
408
+ field: 'atollRS',
409
+ width: 90,
410
+ hozAlign: 'right',
411
+ formatter: numberFormatter(1),
412
+ ...headerFilterParams,
413
+ },
414
+ {
415
+ title: 'Atoll BW',
416
+ field: 'atollBW',
417
+ width: 90,
418
+ hozAlign: 'right',
419
+ formatter: numberFormatter(1),
420
+ ...headerFilterParams,
421
+ },
422
+ // Compare columns (Atoll vs Network)
423
+ {
424
+ title: 'Δ ET',
425
+ field: 'compareET',
426
+ width: 110,
427
+ hozAlign: 'center',
428
+ formatter: createCompareFormatter('atollET', 'nwET'),
429
+ headerTooltip: 'Atoll ET | Network ET',
430
+ },
431
+ {
432
+ title: 'Δ PW',
433
+ field: 'comparePW',
434
+ width: 110,
435
+ hozAlign: 'center',
436
+ formatter: createCompareFormatter('atollPW', 'nwPW'),
437
+ headerTooltip: 'Atoll PW | Network PW',
438
+ },
439
+ {
440
+ title: 'Δ RS',
441
+ field: 'compareRS',
442
+ width: 110,
443
+ hozAlign: 'center',
444
+ formatter: createCompareFormatter('atollRS', 'nwRS'),
445
+ headerTooltip: 'Atoll RS | Network RS',
446
+ },
447
+ {
448
+ title: 'Δ BW',
449
+ field: 'compareBW',
450
+ width: 110,
451
+ hozAlign: 'center',
452
+ formatter: createCompareFormatter('atollBW', 'nwBW'),
453
+ headerTooltip: 'Atoll BW | Network BW',
454
+ },
455
+ // Position columns
456
+ {
457
+ title: 'Latitude',
458
+ field: 'latitude',
459
+ width: 120,
460
+ hozAlign: 'right',
461
+ formatter: coordinateFormatter,
462
+ ...headerFilterParams,
463
+ },
464
+ {
465
+ title: 'Longitude',
466
+ field: 'longitude',
467
+ width: 120,
468
+ hozAlign: 'right',
469
+ formatter: coordinateFormatter,
470
+ ...headerFilterParams,
471
+ },
472
+ {
473
+ title: 'Site Lat',
474
+ field: 'siteLatitude',
475
+ width: 120,
476
+ hozAlign: 'right',
477
+ formatter: coordinateFormatter,
478
+ ...headerFilterParams,
479
+ },
480
+ {
481
+ title: 'Site Lng',
482
+ field: 'siteLongitude',
483
+ width: 120,
484
+ hozAlign: 'right',
485
+ formatter: coordinateFormatter,
486
+ ...headerFilterParams,
487
+ },
488
+ {
489
+ title: 'DX',
490
+ field: 'dx',
491
+ width: 80,
492
+ hozAlign: 'right',
493
+ formatter: numberFormatter(2),
494
+ ...headerFilterParams,
495
+ },
496
+ {
497
+ title: 'DY',
498
+ field: 'dy',
499
+ width: 80,
500
+ hozAlign: 'right',
501
+ formatter: numberFormatter(2),
502
+ ...headerFilterParams,
503
+ },
504
+ // Planning columns
505
+ {
506
+ title: 'Planner',
507
+ field: 'planner',
508
+ width: 120,
509
+ ...headerFilterParams,
510
+ },
511
+ {
512
+ title: 'Comment',
513
+ field: 'comment',
514
+ width: 200,
515
+ ...headerFilterParams,
516
+ },
517
+ {
518
+ title: 'Subgroup',
519
+ field: 'customSubgroup',
520
+ width: 120,
521
+ ...headerFilterParams,
522
+ },
523
+ ];
524
+ }
525
+ /**
526
+ * Get columns for a specific preset
527
+ */
528
+ export function getColumnsForPreset(preset, techColors = DEFAULT_TECH_COLORS, statusColors = DEFAULT_STATUS_COLORS, headerFilters = true) {
529
+ const allColumns = getAllColumns(techColors, statusColors, headerFilters);
530
+ let visibleFields;
531
+ switch (preset) {
532
+ case 'compact':
533
+ visibleFields = ['siteId', 'txId', 'cellName', 'tech', 'fband', 'status'];
534
+ break;
535
+ case 'full':
536
+ return allColumns;
537
+ case 'physical':
538
+ visibleFields = [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.physical];
539
+ break;
540
+ case 'network':
541
+ visibleFields = [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.network];
542
+ break;
543
+ case 'planning':
544
+ visibleFields = [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.planning];
545
+ break;
546
+ case 'compare':
547
+ visibleFields = [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.compare];
548
+ break;
549
+ case 'default':
550
+ default:
551
+ visibleFields = [
552
+ 'siteId', 'txId', 'cellName', 'tech', 'fband', 'frq', 'status',
553
+ 'azimuth', 'height', 'antenna'
554
+ ];
555
+ }
556
+ return allColumns.filter(col => visibleFields.includes(col.field));
557
+ }
558
+ /**
559
+ * Get group header formatter for a specific field
560
+ */
561
+ export function getGroupHeaderFormatter(groupField) {
562
+ return (value, count) => {
563
+ const displayValue = String(value).replace(/_/g, ' ');
564
+ let color = '#6c757d';
565
+ if (groupField === 'tech') {
566
+ color = DEFAULT_TECH_COLORS[String(value)] || color;
567
+ }
568
+ else if (groupField === 'fband') {
569
+ color = FBAND_COLORS[String(value)] || color;
570
+ }
571
+ else if (groupField === 'status') {
572
+ color = DEFAULT_STATUS_COLORS[String(value)] || color;
573
+ }
574
+ return `<span class="badge me-2" style="background-color: ${color}; color: white;">${displayValue}</span>
575
+ <span class="text-muted">(${count} cell${count !== 1 ? 's' : ''})</span>`;
576
+ };
577
+ }
578
+ /**
579
+ * Get column metadata for the column picker UI
580
+ * @param options Filter options for including/excluding column groups
581
+ */
582
+ export function getColumnMetadata(options) {
583
+ const allColumns = [
584
+ // Core
585
+ { field: 'siteId', title: 'Site ID', group: 'Core' },
586
+ { field: 'txId', title: 'TX ID', group: 'Core' },
587
+ { field: 'cellName', title: 'Cell Name', group: 'Core' },
588
+ { field: 'tech', title: 'Technology', group: 'Core' },
589
+ { field: 'fband', title: 'Band', group: 'Core' },
590
+ { field: 'frq', title: 'Frequency', group: 'Core' },
591
+ { field: 'status', title: 'Status', group: 'Core' },
592
+ { field: 'onAirDate', title: 'On Air Date', group: 'Core' },
593
+ // Antenna Physical
594
+ { field: 'antenna', title: 'Antenna', group: 'Antenna Physical' },
595
+ { field: 'azimuth', title: 'Azimuth', group: 'Antenna Physical' },
596
+ { field: 'height', title: 'Height', group: 'Antenna Physical' },
597
+ { field: 'beamwidth', title: 'Beamwidth', group: 'Antenna Physical' },
598
+ { field: 'atollMT', title: 'Atoll MT', group: 'Atoll' },
599
+ // Atoll antenna settings
600
+ { field: 'atollET', title: 'Atoll ET', group: 'Atoll' },
601
+ { field: 'atollPW', title: 'Atoll PW', group: 'Atoll' },
602
+ { field: 'atollRS', title: 'Atoll RS', group: 'Atoll' },
603
+ { field: 'atollBW', title: 'Atoll BW', group: 'Atoll' },
604
+ // Network antena settings
605
+ { field: 'nwET', title: 'NW ET', group: 'Network' },
606
+ { field: 'nwPW', title: 'NW PW', group: 'Network' },
607
+ { field: 'nwRS', title: 'NW RS', group: 'Network' },
608
+ { field: 'nwBW', title: 'NW BW', group: 'Network' },
609
+ // Compare (Atoll vs Network)
610
+ { field: 'compareET', title: 'Δ ET', group: 'Compare' },
611
+ { field: 'comparePW', title: 'Δ PW', group: 'Compare' },
612
+ { field: 'compareRS', title: 'Δ RS', group: 'Compare' },
613
+ { field: 'compareBW', title: 'Δ BW', group: 'Compare' },
614
+ // Network settings
615
+ { field: 'dlEarfn', title: 'DL EARFCN', group: 'Network' },
616
+ { field: 'bcch', title: 'BCCH', group: 'Network' },
617
+ { field: 'pci', title: 'PCI', group: 'Network' },
618
+ { field: 'rru', title: 'RRU', group: 'Network' },
619
+ { field: 'cellID', title: 'Cell ID', group: 'Network' },
620
+ { field: 'cellId2G', title: 'Cell ID 2G', group: 'Network' },
621
+ { field: 'ctrlid', title: 'Ctrl ID', group: 'Network' },
622
+ // Position
623
+ // { field: 'latitude', title: 'Latitude', group: 'Position' },
624
+ // { field: 'longitude', title: 'Longitude', group: 'Position' },
625
+ // { field: 'siteLatitude', title: 'Site Latitude', group: 'Position' },
626
+ // { field: 'siteLongitude', title: 'Site Longitude', group: 'Position' },
627
+ // { field: 'dx', title: 'DX', group: 'Position' },
628
+ // { field: 'dy', title: 'DY', group: 'Position' },
629
+ // Planning
630
+ { field: 'planner', title: 'Planner', group: 'Planning' },
631
+ { field: 'comment', title: 'Comment', group: 'Planning' },
632
+ // { field: 'customSubgroup', title: 'Subgroup', group: 'Planning' },
633
+ ];
634
+ // Apply filtering if options provided
635
+ const { include, exclude } = options ?? {};
636
+ return allColumns.filter(col => {
637
+ // If include is specified, only include those groups
638
+ if (include && include.length > 0) {
639
+ if (!include.includes(col.group)) {
640
+ return false;
641
+ }
642
+ }
643
+ // Apply exclude filter
644
+ if (exclude && exclude.includes(col.group)) {
645
+ return false;
646
+ }
647
+ return true;
648
+ });
649
+ }
650
+ /**
651
+ * Get default visible columns for a preset
652
+ */
653
+ export function getPresetVisibleFields(preset) {
654
+ switch (preset) {
655
+ case 'compact':
656
+ return ['siteId', 'txId', 'cellName', 'tech', 'fband', 'status'];
657
+ case 'full':
658
+ return getColumnMetadata().map(c => c.field);
659
+ case 'physical':
660
+ return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.physical];
661
+ case 'network':
662
+ return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.network];
663
+ case 'planning':
664
+ return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.planning];
665
+ case 'compare':
666
+ return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.compare];
667
+ case 'default':
668
+ default:
669
+ return ['siteId', 'txId', 'cellName', 'tech', 'fband', 'frq', 'status', 'azimuth', 'height', 'antenna'];
670
+ }
671
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * CellTableV2 Composables
3
+ *
4
+ * Reusable logic hooks for cell table functionality.
5
+ * These composables use Svelte 5 runes and can be shared across different panel types.
6
+ */
7
+ export { usePersistence } from './usePersistence.svelte';
8
+ export type { UsePersistenceOptions, UsePersistenceReturn } from './usePersistence.svelte';
9
+ export { useColumnVisibility } from './useColumnVisibility.svelte';
10
+ export type { UseColumnVisibilityOptions, UseColumnVisibilityReturn } from './useColumnVisibility.svelte';
11
+ export { useScrollSpy } from './useScrollSpy.svelte';
12
+ export type { UseScrollSpyOptions, UseScrollSpyReturn, ScrollSpyGroup, CellTableRef } from './useScrollSpy.svelte';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * CellTableV2 Composables
3
+ *
4
+ * Reusable logic hooks for cell table functionality.
5
+ * These composables use Svelte 5 runes and can be shared across different panel types.
6
+ */
7
+ export { usePersistence } from './usePersistence.svelte';
8
+ export { useColumnVisibility } from './useColumnVisibility.svelte';
9
+ export { useScrollSpy } from './useScrollSpy.svelte';