@smartnet360/svelte-components 0.0.110 → 0.0.112
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/dist/core/CellTable/CellTable.svelte +7 -10
- package/dist/core/CellTable/CellTableDemo.svelte +44 -0
- package/dist/core/CellTable/CellTablePanel.svelte +106 -11
- package/dist/core/CellTable/CellTablePanel.svelte.d.ts +6 -0
- package/dist/core/CellTable/CellTableToolbar.svelte +2 -1
- package/dist/core/CellTable/column-config.d.ts +8 -0
- package/dist/core/CellTable/column-config.js +100 -27
- package/dist/core/CellTable/types.d.ts +2 -1
- package/dist/shared/demo/cell-types.d.ts +2 -2
- package/package.json +1 -1
|
@@ -190,21 +190,18 @@
|
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
// Track previous values to avoid unnecessary updates
|
|
193
|
-
let
|
|
194
|
-
let prevCellsFirstId: string | null = null;
|
|
193
|
+
let prevCellsRef: unknown[] | null = null;
|
|
195
194
|
let prevGroupBy: string | null = null;
|
|
196
195
|
let prevColumnPreset: string | null = null;
|
|
197
196
|
|
|
198
|
-
// Update table data when cells
|
|
197
|
+
// Update table data when cells change (reference comparison)
|
|
199
198
|
$effect(() => {
|
|
200
|
-
|
|
201
|
-
const
|
|
199
|
+
// Track the cells array reference to detect any change
|
|
200
|
+
const currentRef = sortedCells;
|
|
202
201
|
|
|
203
|
-
//
|
|
204
|
-
if (isInitialized && table &&
|
|
205
|
-
|
|
206
|
-
prevCellsLength = currentLength;
|
|
207
|
-
prevCellsFirstId = currentFirstId;
|
|
202
|
+
// Update if reference changed (new array assignment)
|
|
203
|
+
if (isInitialized && table && currentRef !== prevCellsRef) {
|
|
204
|
+
prevCellsRef = currentRef;
|
|
208
205
|
table.replaceData(sortedCells);
|
|
209
206
|
ondatachange?.({
|
|
210
207
|
type: 'load',
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
let groupBy: CellTableGroupField = $state('none');
|
|
11
11
|
let columnPreset: ColumnPreset = $state('default');
|
|
12
|
+
let searchTerm = $state('');
|
|
12
13
|
|
|
13
14
|
function handleSelectionChange(event: RowSelectionEvent) {
|
|
14
15
|
console.log('Selection changed:', event.ids);
|
|
@@ -17,6 +18,28 @@
|
|
|
17
18
|
function regenerateData() {
|
|
18
19
|
demoCells = generateCellsFromPreset(datasetSize);
|
|
19
20
|
}
|
|
21
|
+
|
|
22
|
+
function handleSearch() {
|
|
23
|
+
const term = searchTerm.trim().toLowerCase();
|
|
24
|
+
if (!term) {
|
|
25
|
+
// Reset to full dataset
|
|
26
|
+
demoCells = generateCellsFromPreset(datasetSize);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// Filter by siteId (case-insensitive, partial match)
|
|
30
|
+
const allCells = generateCellsFromPreset(datasetSize);
|
|
31
|
+
demoCells = allCells.filter(cell =>
|
|
32
|
+
cell.siteId.toLowerCase().includes(term) ||
|
|
33
|
+
cell.cellName.toLowerCase().includes(term)
|
|
34
|
+
);
|
|
35
|
+
console.log(`Search "${term}": found ${demoCells.length} cells`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function handleSearchKeydown(event: KeyboardEvent) {
|
|
39
|
+
if (event.key === 'Enter') {
|
|
40
|
+
handleSearch();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
20
43
|
</script>
|
|
21
44
|
|
|
22
45
|
<div class="cell-table-page vh-100 d-flex flex-column">
|
|
@@ -55,6 +78,27 @@
|
|
|
55
78
|
title="Cell Data"
|
|
56
79
|
onselectionchange={handleSelectionChange}
|
|
57
80
|
>
|
|
81
|
+
{#snippet headerSearch()}
|
|
82
|
+
<div class="input-group input-group-sm" style="width: 180px;">
|
|
83
|
+
<input
|
|
84
|
+
type="text"
|
|
85
|
+
class="form-control"
|
|
86
|
+
placeholder="Search site or cell..."
|
|
87
|
+
bind:value={searchTerm}
|
|
88
|
+
onkeydown={handleSearchKeydown}
|
|
89
|
+
/>
|
|
90
|
+
<button
|
|
91
|
+
class="btn btn-outline-primary"
|
|
92
|
+
type="button"
|
|
93
|
+
onclick={handleSearch}
|
|
94
|
+
title="Search"
|
|
95
|
+
aria-label="Search"
|
|
96
|
+
>
|
|
97
|
+
<i class="bi bi-search"></i>
|
|
98
|
+
</button>
|
|
99
|
+
</div>
|
|
100
|
+
{/snippet}
|
|
101
|
+
|
|
58
102
|
{#snippet footer({ selectedRows, selectedCount })}
|
|
59
103
|
<div class="d-flex align-items-center justify-content-between">
|
|
60
104
|
<span class="text-muted small">
|
|
@@ -2,7 +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
|
+
import { getColumnMetadata, getPresetVisibleFields, DEFAULT_TECH_COLORS, DEFAULT_STATUS_COLORS, FBAND_COLORS } from './column-config';
|
|
6
6
|
import type {
|
|
7
7
|
CellData,
|
|
8
8
|
CellTableGroupField,
|
|
@@ -44,6 +44,10 @@
|
|
|
44
44
|
showDetailsSidebar?: boolean;
|
|
45
45
|
/** Sidebar width in pixels */
|
|
46
46
|
sidebarWidth?: number;
|
|
47
|
+
/** Persist settings (groupBy, visibleColumns) to localStorage */
|
|
48
|
+
persistSettings?: boolean;
|
|
49
|
+
/** Storage key prefix for persisted settings */
|
|
50
|
+
storageKey?: string;
|
|
47
51
|
/** Bindable reference to table methods */
|
|
48
52
|
tableRef?: { redraw: () => void } | null;
|
|
49
53
|
/** Row selection change event */
|
|
@@ -52,6 +56,8 @@
|
|
|
52
56
|
onrowclick?: (event: RowClickEvent) => void;
|
|
53
57
|
/** Row double-click event */
|
|
54
58
|
onrowdblclick?: (event: RowDblClickEvent) => void;
|
|
59
|
+
/** Custom header search slot (appears next to title) */
|
|
60
|
+
headerSearch?: Snippet;
|
|
55
61
|
/** Custom header actions slot */
|
|
56
62
|
headerActions?: Snippet;
|
|
57
63
|
/** Custom footer slot */
|
|
@@ -75,15 +81,81 @@
|
|
|
75
81
|
title = 'Cell Data',
|
|
76
82
|
showDetailsSidebar = false,
|
|
77
83
|
sidebarWidth = 320,
|
|
84
|
+
persistSettings = true,
|
|
85
|
+
storageKey = 'cell-table',
|
|
78
86
|
tableRef = $bindable(null),
|
|
79
87
|
onselectionchange,
|
|
80
88
|
onrowclick,
|
|
81
89
|
onrowdblclick,
|
|
90
|
+
headerSearch,
|
|
82
91
|
headerActions,
|
|
83
92
|
footer,
|
|
84
93
|
detailsContent
|
|
85
94
|
}: Props = $props();
|
|
86
95
|
|
|
96
|
+
// Storage keys
|
|
97
|
+
const STORAGE_KEY_GROUP = `${storageKey}-groupBy`;
|
|
98
|
+
const STORAGE_KEY_COLUMNS = `${storageKey}-visibleColumns`;
|
|
99
|
+
const STORAGE_KEY_FILTERS = `${storageKey}-filtersVisible`;
|
|
100
|
+
|
|
101
|
+
// Load persisted settings
|
|
102
|
+
function loadPersistedSettings() {
|
|
103
|
+
if (!persistSettings || typeof localStorage === 'undefined') return { columns: null, filtersVisible: true };
|
|
104
|
+
|
|
105
|
+
let columns: string[] | null = null;
|
|
106
|
+
let filters = true;
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const savedGroup = localStorage.getItem(STORAGE_KEY_GROUP);
|
|
110
|
+
if (savedGroup) {
|
|
111
|
+
groupBy = savedGroup as CellTableGroupField;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const savedColumns = localStorage.getItem(STORAGE_KEY_COLUMNS);
|
|
115
|
+
if (savedColumns) {
|
|
116
|
+
columns = JSON.parse(savedColumns) as string[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const savedFilters = localStorage.getItem(STORAGE_KEY_FILTERS);
|
|
120
|
+
if (savedFilters !== null) {
|
|
121
|
+
filters = savedFilters === 'true';
|
|
122
|
+
}
|
|
123
|
+
} catch (e) {
|
|
124
|
+
console.warn('Failed to load CellTable settings:', e);
|
|
125
|
+
}
|
|
126
|
+
return { columns, filtersVisible: filters };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Save group setting
|
|
130
|
+
function saveGroupSetting(group: CellTableGroupField) {
|
|
131
|
+
if (!persistSettings || typeof localStorage === 'undefined') return;
|
|
132
|
+
try {
|
|
133
|
+
localStorage.setItem(STORAGE_KEY_GROUP, group);
|
|
134
|
+
} catch (e) {
|
|
135
|
+
console.warn('Failed to save group setting:', e);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Save column visibility
|
|
140
|
+
function saveColumnVisibility(columns: string[]) {
|
|
141
|
+
if (!persistSettings || typeof localStorage === 'undefined') return;
|
|
142
|
+
try {
|
|
143
|
+
localStorage.setItem(STORAGE_KEY_COLUMNS, JSON.stringify(columns));
|
|
144
|
+
} catch (e) {
|
|
145
|
+
console.warn('Failed to save column visibility:', e);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Save filter visibility
|
|
150
|
+
function saveFilterVisibility(visible: boolean) {
|
|
151
|
+
if (!persistSettings || typeof localStorage === 'undefined') return;
|
|
152
|
+
try {
|
|
153
|
+
localStorage.setItem(STORAGE_KEY_FILTERS, String(visible));
|
|
154
|
+
} catch (e) {
|
|
155
|
+
console.warn('Failed to save filter visibility:', e);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
87
159
|
let cellTable: CellTable;
|
|
88
160
|
let selectedCount = $state(0);
|
|
89
161
|
let selectedRows = $state<CellData[]>([]);
|
|
@@ -91,13 +163,16 @@
|
|
|
91
163
|
let sidebarOpen = $state(false);
|
|
92
164
|
let clickedCell: CellData | null = $state(null);
|
|
93
165
|
let tableRefSet = false;
|
|
94
|
-
let filtersVisible = $state(true);
|
|
95
166
|
|
|
96
167
|
// Column visibility management
|
|
97
168
|
const columnMeta = getColumnMetadata();
|
|
98
|
-
|
|
169
|
+
|
|
170
|
+
// Initialize from storage or defaults
|
|
171
|
+
const persistedSettings = loadPersistedSettings();
|
|
172
|
+
let filtersVisible = $state(persistedSettings.filtersVisible);
|
|
173
|
+
let visibleColumns = $state<string[]>(persistedSettings.columns ?? getPresetVisibleFields(columnPreset));
|
|
99
174
|
|
|
100
|
-
// Update visible columns when preset changes
|
|
175
|
+
// Update visible columns when preset changes (but not from storage load)
|
|
101
176
|
$effect(() => {
|
|
102
177
|
visibleColumns = getPresetVisibleFields(columnPreset);
|
|
103
178
|
});
|
|
@@ -109,6 +184,10 @@
|
|
|
109
184
|
tableRef = {
|
|
110
185
|
redraw: () => cellTable?.redraw()
|
|
111
186
|
};
|
|
187
|
+
// Apply persisted filter visibility after table is ready
|
|
188
|
+
if (!filtersVisible) {
|
|
189
|
+
setTimeout(() => cellTable?.toggleHeaderFilters(false), 100);
|
|
190
|
+
}
|
|
112
191
|
}
|
|
113
192
|
});
|
|
114
193
|
|
|
@@ -133,6 +212,7 @@
|
|
|
133
212
|
|
|
134
213
|
function handleGroupChange(group: CellTableGroupField) {
|
|
135
214
|
groupBy = group;
|
|
215
|
+
saveGroupSetting(group);
|
|
136
216
|
}
|
|
137
217
|
|
|
138
218
|
function handlePresetChange(preset: ColumnPreset) {
|
|
@@ -162,6 +242,7 @@
|
|
|
162
242
|
function handleToggleFilters() {
|
|
163
243
|
filtersVisible = !filtersVisible;
|
|
164
244
|
cellTable?.toggleHeaderFilters(filtersVisible);
|
|
245
|
+
saveFilterVisibility(filtersVisible);
|
|
165
246
|
}
|
|
166
247
|
|
|
167
248
|
function handleColumnVisibilityChange(field: string, visible: boolean) {
|
|
@@ -174,6 +255,7 @@
|
|
|
174
255
|
visibleColumns = visibleColumns.filter(f => f !== field);
|
|
175
256
|
cellTable?.hideColumn(field);
|
|
176
257
|
}
|
|
258
|
+
saveColumnVisibility(visibleColumns);
|
|
177
259
|
}
|
|
178
260
|
|
|
179
261
|
function handleResetColumns() {
|
|
@@ -187,6 +269,14 @@
|
|
|
187
269
|
cellTable?.hideColumn(col.field);
|
|
188
270
|
}
|
|
189
271
|
});
|
|
272
|
+
// Clear persisted column visibility (use preset defaults)
|
|
273
|
+
if (persistSettings && typeof localStorage !== 'undefined') {
|
|
274
|
+
try {
|
|
275
|
+
localStorage.removeItem(STORAGE_KEY_COLUMNS);
|
|
276
|
+
} catch (e) {
|
|
277
|
+
console.warn('Failed to clear column visibility:', e);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
190
280
|
}
|
|
191
281
|
|
|
192
282
|
function toggleSidebar() {
|
|
@@ -225,10 +315,15 @@
|
|
|
225
315
|
<div class="cell-table-panel d-flex flex-column" style:height>
|
|
226
316
|
<!-- Header -->
|
|
227
317
|
<div class="panel-header d-flex align-items-center justify-content-between px-3 py-2 bg-body-secondary border-bottom">
|
|
228
|
-
<
|
|
229
|
-
<
|
|
230
|
-
|
|
231
|
-
|
|
318
|
+
<div class="d-flex align-items-center gap-3">
|
|
319
|
+
<h6 class="mb-0 d-flex align-items-center gap-2">
|
|
320
|
+
<i class="bi bi-table text-primary"></i>
|
|
321
|
+
{title}
|
|
322
|
+
</h6>
|
|
323
|
+
{#if headerSearch}
|
|
324
|
+
{@render headerSearch()}
|
|
325
|
+
{/if}
|
|
326
|
+
</div>
|
|
232
327
|
<div class="d-flex align-items-center gap-2">
|
|
233
328
|
{#if headerActions}
|
|
234
329
|
<div class="header-actions">
|
|
@@ -334,12 +429,12 @@
|
|
|
334
429
|
|
|
335
430
|
<dt class="col-5 text-muted">Technology</dt>
|
|
336
431
|
<dd class="col-7">
|
|
337
|
-
<span class="badge
|
|
432
|
+
<span class="badge" style="background-color: {techColors?.[clickedCell.tech] ?? DEFAULT_TECH_COLORS[clickedCell.tech] ?? '#6c757d'}; color: white;">{clickedCell.tech}</span>
|
|
338
433
|
</dd>
|
|
339
434
|
|
|
340
435
|
<dt class="col-5 text-muted">Band</dt>
|
|
341
436
|
<dd class="col-7">
|
|
342
|
-
<span class="badge
|
|
437
|
+
<span class="badge" style="background-color: {FBAND_COLORS[clickedCell.fband] ?? '#6c757d'}; color: white;">{clickedCell.fband}</span>
|
|
343
438
|
</dd>
|
|
344
439
|
|
|
345
440
|
<dt class="col-5 text-muted">Frequency</dt>
|
|
@@ -347,7 +442,7 @@
|
|
|
347
442
|
|
|
348
443
|
<dt class="col-5 text-muted">Status</dt>
|
|
349
444
|
<dd class="col-7">
|
|
350
|
-
<span class="badge
|
|
445
|
+
<span class="badge" style="background-color: {statusColors?.[clickedCell.status] ?? DEFAULT_STATUS_COLORS[clickedCell.status] ?? '#6c757d'}; color: white;">{clickedCell.status.replace(/_/g, ' ')}</span>
|
|
351
446
|
</dd>
|
|
352
447
|
|
|
353
448
|
<dt class="col-12 text-muted mt-2 mb-1 border-top pt-2">Physical</dt>
|
|
@@ -29,6 +29,10 @@ interface Props {
|
|
|
29
29
|
showDetailsSidebar?: boolean;
|
|
30
30
|
/** Sidebar width in pixels */
|
|
31
31
|
sidebarWidth?: number;
|
|
32
|
+
/** Persist settings (groupBy, visibleColumns) to localStorage */
|
|
33
|
+
persistSettings?: boolean;
|
|
34
|
+
/** Storage key prefix for persisted settings */
|
|
35
|
+
storageKey?: string;
|
|
32
36
|
/** Bindable reference to table methods */
|
|
33
37
|
tableRef?: {
|
|
34
38
|
redraw: () => void;
|
|
@@ -39,6 +43,8 @@ interface Props {
|
|
|
39
43
|
onrowclick?: (event: RowClickEvent) => void;
|
|
40
44
|
/** Row double-click event */
|
|
41
45
|
onrowdblclick?: (event: RowDblClickEvent) => void;
|
|
46
|
+
/** Custom header search slot (appears next to title) */
|
|
47
|
+
headerSearch?: Snippet;
|
|
42
48
|
/** Custom header actions slot */
|
|
43
49
|
headerActions?: Snippet;
|
|
44
50
|
/** Custom footer slot */
|
|
@@ -87,7 +87,8 @@
|
|
|
87
87
|
{ value: 'full', label: 'All Columns' },
|
|
88
88
|
{ value: 'physical', label: 'Physical' },
|
|
89
89
|
{ value: 'network', label: 'Network' },
|
|
90
|
-
{ value: 'planning', label: 'Planning' }
|
|
90
|
+
{ value: 'planning', label: 'Planning' },
|
|
91
|
+
{ value: 'compare', label: 'Compare (Atoll/Nwt)' }
|
|
91
92
|
];
|
|
92
93
|
|
|
93
94
|
function handleGroupChange(e: Event) {
|
|
@@ -53,6 +53,14 @@ export declare function azimuthFormatter(cell: CellComponent): string;
|
|
|
53
53
|
* Height formatter with meter unit
|
|
54
54
|
*/
|
|
55
55
|
export declare function heightFormatter(cell: CellComponent): string;
|
|
56
|
+
/**
|
|
57
|
+
* Comparison formatter for Atoll vs Network values
|
|
58
|
+
* Shows both values side by side with color coding:
|
|
59
|
+
* - Green: values match exactly
|
|
60
|
+
* - Red: values don't match
|
|
61
|
+
* - Gray: one or both values missing
|
|
62
|
+
*/
|
|
63
|
+
export declare function createCompareFormatter(atollField: string, nwtField: string): (cell: CellComponent) => string;
|
|
56
64
|
/**
|
|
57
65
|
* Custom sorter for fband - extracts numeric portion and sorts numerically
|
|
58
66
|
* Examples: LTE700 → 700, GSM900 → 900, LTE1800 → 1800, 5G-3500 → 3500
|
|
@@ -53,12 +53,13 @@ export const FBAND_COLORS = {
|
|
|
53
53
|
* Column groups for different presets
|
|
54
54
|
*/
|
|
55
55
|
export const COLUMN_GROUPS = {
|
|
56
|
-
core: ['
|
|
56
|
+
core: ['siteId', 'txId', 'cellName', 'tech', 'fband', 'status'],
|
|
57
57
|
physical: ['antenna', 'azimuth', 'height', 'electricalTilt', 'beamwidth'],
|
|
58
|
-
network: ['dlEarfn', 'bcch', 'pci1', 'cellId3', '
|
|
58
|
+
network: ['dlEarfn', 'bcch', 'pci1', 'cellId3', 'nwtET', 'nwtPW', 'nwtRS', 'nwtBW'],
|
|
59
59
|
planning: ['planner', 'comment', 'onAirDate', 'type'],
|
|
60
|
-
atoll: ['
|
|
60
|
+
atoll: ['atollET', 'atollPW', 'atollRS', 'atollBW'],
|
|
61
61
|
position: ['latitude', 'longitude', 'siteLatitude', 'siteLongitude', 'dx', 'dy'],
|
|
62
|
+
compare: ['compareET', 'comparePW', 'compareRS', 'compareBW'],
|
|
62
63
|
};
|
|
63
64
|
/**
|
|
64
65
|
* Create a technology badge formatter
|
|
@@ -131,6 +132,40 @@ export function heightFormatter(cell) {
|
|
|
131
132
|
return '';
|
|
132
133
|
return `${value}m`;
|
|
133
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
|
+
}
|
|
134
169
|
/**
|
|
135
170
|
* Custom sorter for fband - extracts numeric portion and sorts numerically
|
|
136
171
|
* Examples: LTE700 → 700, GSM900 → 900, LTE1800 → 1800, 5G-3500 → 3500
|
|
@@ -178,24 +213,26 @@ export function getAllColumns(techColors = DEFAULT_TECH_COLORS, statusColors = D
|
|
|
178
213
|
const headerFilterParams = headerFilters ? { headerFilter: 'input' } : {};
|
|
179
214
|
const selectHeaderFilter = headerFilters ? { headerFilter: 'list', headerFilterParams: { valuesLookup: true } } : {};
|
|
180
215
|
return [
|
|
181
|
-
// Core columns
|
|
216
|
+
// Core columns - siteId, txId, cellName first (frozen)
|
|
182
217
|
{
|
|
183
|
-
title: 'ID',
|
|
184
|
-
field: '
|
|
218
|
+
title: 'Site ID',
|
|
219
|
+
field: 'siteId',
|
|
185
220
|
width: 120,
|
|
186
221
|
frozen: true,
|
|
187
222
|
...headerFilterParams,
|
|
188
223
|
},
|
|
189
224
|
{
|
|
190
|
-
title: '
|
|
191
|
-
field: '
|
|
192
|
-
width:
|
|
225
|
+
title: 'TX ID',
|
|
226
|
+
field: 'txId',
|
|
227
|
+
width: 100,
|
|
228
|
+
frozen: true,
|
|
193
229
|
...headerFilterParams,
|
|
194
230
|
},
|
|
195
231
|
{
|
|
196
|
-
title: '
|
|
197
|
-
field: '
|
|
198
|
-
width:
|
|
232
|
+
title: 'Cell Name',
|
|
233
|
+
field: 'cellName',
|
|
234
|
+
width: 150,
|
|
235
|
+
frozen: true,
|
|
199
236
|
...headerFilterParams,
|
|
200
237
|
},
|
|
201
238
|
{
|
|
@@ -318,12 +355,6 @@ export function getAllColumns(techColors = DEFAULT_TECH_COLORS, statusColors = D
|
|
|
318
355
|
width: 100,
|
|
319
356
|
...headerFilterParams,
|
|
320
357
|
},
|
|
321
|
-
{
|
|
322
|
-
title: 'TX ID',
|
|
323
|
-
field: 'txId',
|
|
324
|
-
width: 100,
|
|
325
|
-
...headerFilterParams,
|
|
326
|
-
},
|
|
327
358
|
{
|
|
328
359
|
title: 'Ctrl ID',
|
|
329
360
|
field: 'ctrlid',
|
|
@@ -360,8 +391,8 @@ export function getAllColumns(techColors = DEFAULT_TECH_COLORS, statusColors = D
|
|
|
360
391
|
},
|
|
361
392
|
// Atoll columns
|
|
362
393
|
{
|
|
363
|
-
title: 'Atoll
|
|
364
|
-
field: '
|
|
394
|
+
title: 'Atoll ET',
|
|
395
|
+
field: 'atollET',
|
|
365
396
|
width: 90,
|
|
366
397
|
hozAlign: 'right',
|
|
367
398
|
formatter: numberFormatter(1),
|
|
@@ -391,6 +422,39 @@ export function getAllColumns(techColors = DEFAULT_TECH_COLORS, statusColors = D
|
|
|
391
422
|
formatter: numberFormatter(1),
|
|
392
423
|
...headerFilterParams,
|
|
393
424
|
},
|
|
425
|
+
// Compare columns (Atoll vs Network)
|
|
426
|
+
{
|
|
427
|
+
title: 'Δ ET',
|
|
428
|
+
field: 'compareET',
|
|
429
|
+
width: 110,
|
|
430
|
+
hozAlign: 'center',
|
|
431
|
+
formatter: createCompareFormatter('atollET', 'nwtET'),
|
|
432
|
+
headerTooltip: 'Atoll ET | Network ET',
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
title: 'Δ PW',
|
|
436
|
+
field: 'comparePW',
|
|
437
|
+
width: 110,
|
|
438
|
+
hozAlign: 'center',
|
|
439
|
+
formatter: createCompareFormatter('atollPW', 'nwtPW'),
|
|
440
|
+
headerTooltip: 'Atoll PW | Network PW',
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
title: 'Δ RS',
|
|
444
|
+
field: 'compareRS',
|
|
445
|
+
width: 110,
|
|
446
|
+
hozAlign: 'center',
|
|
447
|
+
formatter: createCompareFormatter('atollRS', 'nwtRS'),
|
|
448
|
+
headerTooltip: 'Atoll RS | Network RS',
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
title: 'Δ BW',
|
|
452
|
+
field: 'compareBW',
|
|
453
|
+
width: 110,
|
|
454
|
+
hozAlign: 'center',
|
|
455
|
+
formatter: createCompareFormatter('atollBW', 'nwtBW'),
|
|
456
|
+
headerTooltip: 'Atoll BW | Network BW',
|
|
457
|
+
},
|
|
394
458
|
// Position columns
|
|
395
459
|
{
|
|
396
460
|
title: 'Latitude',
|
|
@@ -469,7 +533,7 @@ export function getColumnsForPreset(preset, techColors = DEFAULT_TECH_COLORS, st
|
|
|
469
533
|
let visibleFields;
|
|
470
534
|
switch (preset) {
|
|
471
535
|
case 'compact':
|
|
472
|
-
visibleFields = ['
|
|
536
|
+
visibleFields = ['siteId', 'txId', 'cellName', 'tech', 'fband', 'status'];
|
|
473
537
|
break;
|
|
474
538
|
case 'full':
|
|
475
539
|
return allColumns;
|
|
@@ -482,10 +546,13 @@ export function getColumnsForPreset(preset, techColors = DEFAULT_TECH_COLORS, st
|
|
|
482
546
|
case 'planning':
|
|
483
547
|
visibleFields = [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.planning];
|
|
484
548
|
break;
|
|
549
|
+
case 'compare':
|
|
550
|
+
visibleFields = [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.compare];
|
|
551
|
+
break;
|
|
485
552
|
case 'default':
|
|
486
553
|
default:
|
|
487
554
|
visibleFields = [
|
|
488
|
-
'
|
|
555
|
+
'siteId', 'txId', 'cellName', 'tech', 'fband', 'frq', 'status',
|
|
489
556
|
'azimuth', 'height', 'antenna'
|
|
490
557
|
];
|
|
491
558
|
}
|
|
@@ -517,9 +584,9 @@ export function getGroupHeaderFormatter(groupField) {
|
|
|
517
584
|
export function getColumnMetadata() {
|
|
518
585
|
return [
|
|
519
586
|
// Core
|
|
520
|
-
{ field: 'id', title: 'ID', group: 'Core' },
|
|
521
|
-
{ field: 'cellName', title: 'Cell Name', group: 'Core' },
|
|
522
587
|
{ field: 'siteId', title: 'Site ID', group: 'Core' },
|
|
588
|
+
{ field: 'txId', title: 'TX ID', group: 'Core' },
|
|
589
|
+
{ field: 'cellName', title: 'Cell Name', group: 'Core' },
|
|
523
590
|
{ field: 'tech', title: 'Technology', group: 'Core' },
|
|
524
591
|
{ field: 'fband', title: 'Band', group: 'Core' },
|
|
525
592
|
{ field: 'frq', title: 'Frequency', group: 'Core' },
|
|
@@ -539,7 +606,6 @@ export function getColumnMetadata() {
|
|
|
539
606
|
{ field: 'rru', title: 'RRU', group: 'Network' },
|
|
540
607
|
{ field: 'cellID', title: 'Cell ID', group: 'Network' },
|
|
541
608
|
{ field: 'cellId2G', title: 'Cell ID 2G', group: 'Network' },
|
|
542
|
-
{ field: 'txId', title: 'TX ID', group: 'Network' },
|
|
543
609
|
{ field: 'ctrlid', title: 'Ctrl ID', group: 'Network' },
|
|
544
610
|
{ field: 'nwtET', title: 'NWT ET', group: 'Network' },
|
|
545
611
|
{ field: 'nwtPW', title: 'NWT PW', group: 'Network' },
|
|
@@ -550,6 +616,11 @@ export function getColumnMetadata() {
|
|
|
550
616
|
{ field: 'atollPW', title: 'Atoll PW', group: 'Atoll' },
|
|
551
617
|
{ field: 'atollRS', title: 'Atoll RS', group: 'Atoll' },
|
|
552
618
|
{ field: 'atollBW', title: 'Atoll BW', group: 'Atoll' },
|
|
619
|
+
// Compare (Atoll vs Network)
|
|
620
|
+
{ field: 'compareET', title: 'Δ ET', group: 'Compare' },
|
|
621
|
+
{ field: 'comparePW', title: 'Δ PW', group: 'Compare' },
|
|
622
|
+
{ field: 'compareRS', title: 'Δ RS', group: 'Compare' },
|
|
623
|
+
{ field: 'compareBW', title: 'Δ BW', group: 'Compare' },
|
|
553
624
|
// Position
|
|
554
625
|
{ field: 'latitude', title: 'Latitude', group: 'Position' },
|
|
555
626
|
{ field: 'longitude', title: 'Longitude', group: 'Position' },
|
|
@@ -569,7 +640,7 @@ export function getColumnMetadata() {
|
|
|
569
640
|
export function getPresetVisibleFields(preset) {
|
|
570
641
|
switch (preset) {
|
|
571
642
|
case 'compact':
|
|
572
|
-
return ['
|
|
643
|
+
return ['siteId', 'txId', 'cellName', 'tech', 'fband', 'status'];
|
|
573
644
|
case 'full':
|
|
574
645
|
return getColumnMetadata().map(c => c.field);
|
|
575
646
|
case 'physical':
|
|
@@ -578,8 +649,10 @@ export function getPresetVisibleFields(preset) {
|
|
|
578
649
|
return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.network];
|
|
579
650
|
case 'planning':
|
|
580
651
|
return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.planning];
|
|
652
|
+
case 'compare':
|
|
653
|
+
return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.compare];
|
|
581
654
|
case 'default':
|
|
582
655
|
default:
|
|
583
|
-
return ['
|
|
656
|
+
return ['siteId', 'txId', 'cellName', 'tech', 'fband', 'frq', 'status', 'azimuth', 'height', 'antenna'];
|
|
584
657
|
}
|
|
585
658
|
}
|
|
@@ -16,7 +16,7 @@ export type CellTableGroupField = CellGroupingField | 'none';
|
|
|
16
16
|
/**
|
|
17
17
|
* Column preset configurations
|
|
18
18
|
*/
|
|
19
|
-
export type ColumnPreset = 'default' | 'compact' | 'full' | 'physical' | 'network' | 'planning';
|
|
19
|
+
export type ColumnPreset = 'default' | 'compact' | 'full' | 'physical' | 'network' | 'planning' | 'compare';
|
|
20
20
|
/**
|
|
21
21
|
* Column visibility configuration
|
|
22
22
|
*/
|
|
@@ -122,4 +122,5 @@ export interface ColumnGroups {
|
|
|
122
122
|
planning: string[];
|
|
123
123
|
atoll: string[];
|
|
124
124
|
position: string[];
|
|
125
|
+
compare: string[];
|
|
125
126
|
}
|
|
@@ -39,12 +39,12 @@ export interface Cell {
|
|
|
39
39
|
atollPW?: number;
|
|
40
40
|
atollRS?: number;
|
|
41
41
|
atollBW?: number;
|
|
42
|
-
rru: string;
|
|
43
42
|
nwtET?: number;
|
|
44
43
|
nwtPW?: number;
|
|
45
|
-
pci?: number;
|
|
46
44
|
nwtRS?: number;
|
|
47
45
|
nwtBW?: number;
|
|
46
|
+
pci?: number;
|
|
47
|
+
rru: string;
|
|
48
48
|
other?: Record<string, unknown>;
|
|
49
49
|
customSubgroup: string;
|
|
50
50
|
}
|