@smartnet360/svelte-components 0.0.102 → 0.0.104

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 (85) hide show
  1. package/dist/apps/antenna-pattern/index.d.ts +1 -0
  2. package/dist/apps/antenna-pattern/index.js +1 -0
  3. package/dist/apps/antenna-pattern/utils/load-static-antennas.d.ts +17 -0
  4. package/dist/apps/antenna-pattern/utils/load-static-antennas.js +83 -0
  5. package/dist/apps/site-check/SiteCheck.svelte +13 -81
  6. package/dist/apps/site-check/SiteCheckControls.svelte +0 -7
  7. package/dist/apps/site-check/helper.js +0 -33
  8. package/dist/apps/site-check/transforms.js +15 -65
  9. package/dist/core/CellTable/CellTable.svelte +456 -0
  10. package/dist/core/CellTable/CellTable.svelte.d.ts +27 -0
  11. package/dist/core/CellTable/CellTablePanel.svelte +211 -0
  12. package/dist/core/CellTable/CellTablePanel.svelte.d.ts +49 -0
  13. package/dist/core/CellTable/CellTableToolbar.svelte +218 -0
  14. package/dist/core/CellTable/CellTableToolbar.svelte.d.ts +32 -0
  15. package/dist/core/CellTable/column-config.d.ts +63 -0
  16. package/dist/core/CellTable/column-config.js +465 -0
  17. package/dist/core/CellTable/index.d.ts +10 -0
  18. package/dist/core/CellTable/index.js +11 -0
  19. package/dist/core/CellTable/types.d.ts +166 -0
  20. package/dist/core/CellTable/types.js +6 -0
  21. package/dist/core/Charts/ChartCard.svelte +118 -31
  22. package/dist/core/Charts/ChartCard.svelte.d.ts +2 -0
  23. package/dist/core/Charts/ChartComponent.svelte +8 -31
  24. package/dist/core/Charts/data-processor.js +1 -19
  25. package/dist/core/CoverageMap/ai/AITools.d.ts +117 -0
  26. package/dist/core/CoverageMap/ai/AITools.js +380 -0
  27. package/dist/core/CoverageMap/core/CoverageCalculator.d.ts +138 -0
  28. package/dist/core/CoverageMap/core/CoverageCalculator.js +375 -0
  29. package/dist/core/CoverageMap/core/GridCalculator.d.ts +115 -0
  30. package/dist/core/CoverageMap/core/GridCalculator.js +484 -0
  31. package/dist/core/CoverageMap/core/PathLossModels.d.ts +253 -0
  32. package/dist/core/CoverageMap/core/PathLossModels.js +380 -0
  33. package/dist/core/CoverageMap/core/SignalProcessor.d.ts +288 -0
  34. package/dist/core/CoverageMap/core/SignalProcessor.js +424 -0
  35. package/dist/core/CoverageMap/data/AntennaStore.d.ts +165 -0
  36. package/dist/core/CoverageMap/data/AntennaStore.js +327 -0
  37. package/dist/core/CoverageMap/data/SiteStore.d.ts +155 -0
  38. package/dist/core/CoverageMap/data/SiteStore.js +355 -0
  39. package/dist/core/CoverageMap/index.d.ts +74 -0
  40. package/dist/core/CoverageMap/index.js +103 -0
  41. package/dist/core/CoverageMap/types.d.ts +252 -0
  42. package/dist/core/CoverageMap/types.js +7 -0
  43. package/dist/core/CoverageMap/utils/geoUtils.d.ts +223 -0
  44. package/dist/core/CoverageMap/utils/geoUtils.js +374 -0
  45. package/dist/core/CoverageMap/utils/rfUtils.d.ts +329 -0
  46. package/dist/core/CoverageMap/utils/rfUtils.js +434 -0
  47. package/dist/core/CoverageMap/visualization/ColorSchemes.d.ts +149 -0
  48. package/dist/core/CoverageMap/visualization/ColorSchemes.js +377 -0
  49. package/dist/core/TreeView/index.d.ts +4 -4
  50. package/dist/core/TreeView/index.js +5 -5
  51. package/dist/core/TreeView/tree-utils.d.ts +12 -0
  52. package/dist/core/TreeView/tree-utils.js +115 -6
  53. package/dist/core/TreeView/tree.store.svelte.d.ts +94 -0
  54. package/dist/core/TreeView/tree.store.svelte.js +274 -0
  55. package/dist/core/index.d.ts +1 -0
  56. package/dist/core/index.js +2 -0
  57. package/dist/map-v2/features/cells/controls/CellFilterControl.svelte +16 -27
  58. package/dist/map-v2/features/repeaters/controls/RepeaterFilterControl.svelte +33 -42
  59. package/dist/map-v2/features/sites/controls/SiteFilterControl.svelte +12 -19
  60. package/dist/map-v3/core/components/Map.svelte +4 -0
  61. package/dist/map-v3/core/stores/map.store.svelte.js +2 -0
  62. package/dist/map-v3/features/cells/components/CellFilterControl.svelte +24 -30
  63. package/dist/map-v3/features/coverage/index.d.ts +12 -0
  64. package/dist/map-v3/features/coverage/index.js +16 -0
  65. package/dist/map-v3/features/coverage/layers/CoverageLayer.svelte +198 -0
  66. package/dist/map-v3/features/coverage/layers/CoverageLayer.svelte.d.ts +10 -0
  67. package/dist/map-v3/features/coverage/logic/coloring.d.ts +28 -0
  68. package/dist/map-v3/features/coverage/logic/coloring.js +77 -0
  69. package/dist/map-v3/features/coverage/logic/geometry.d.ts +33 -0
  70. package/dist/map-v3/features/coverage/logic/geometry.js +112 -0
  71. package/dist/map-v3/features/coverage/stores/coverage.data.svelte.d.ts +46 -0
  72. package/dist/map-v3/features/coverage/stores/coverage.data.svelte.js +95 -0
  73. package/dist/map-v3/features/coverage/stores/coverage.display.svelte.d.ts +33 -0
  74. package/dist/map-v3/features/coverage/stores/coverage.display.svelte.js +90 -0
  75. package/dist/map-v3/features/coverage/types.d.ts +52 -0
  76. package/dist/map-v3/features/coverage/types.js +7 -0
  77. package/dist/map-v3/features/repeaters/components/RepeaterFilterControl.svelte +14 -20
  78. package/dist/map-v3/features/sites/components/SiteFilterControl.svelte +23 -33
  79. package/dist/map-v3/index.d.ts +4 -0
  80. package/dist/map-v3/index.js +5 -0
  81. package/package.json +4 -3
  82. package/dist/apps/site-check/transforms-old.d.ts +0 -56
  83. package/dist/apps/site-check/transforms-old.js +0 -273
  84. package/dist/core/TreeView/tree.store.d.ts +0 -10
  85. package/dist/core/TreeView/tree.store.js +0 -320
@@ -14,3 +14,4 @@ export * from './utils/db-utils';
14
14
  export * from './utils/init-db';
15
15
  export * from './utils/msi-parser';
16
16
  export * from './utils/plotly-chart-utils';
17
+ export * from './utils/load-static-antennas';
@@ -19,3 +19,4 @@ export * from './utils/db-utils';
19
19
  export * from './utils/init-db';
20
20
  export * from './utils/msi-parser';
21
21
  export * from './utils/plotly-chart-utils';
22
+ export * from './utils/load-static-antennas';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Load antennas from static/antennas folder via fetch
3
+ * This is a helper for loading pre-bundled antenna files without user interaction
4
+ */
5
+ import type { Antenna } from '../db';
6
+ /**
7
+ * Load and parse all static antenna files
8
+ */
9
+ export declare function loadStaticAntennas(): Promise<Antenna[]>;
10
+ /**
11
+ * Load static antennas and save to database
12
+ */
13
+ export declare function importStaticAntennas(): Promise<{
14
+ success: boolean;
15
+ count: number;
16
+ error?: string;
17
+ }>;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Load antennas from static/antennas folder via fetch
3
+ * This is a helper for loading pre-bundled antenna files without user interaction
4
+ */
5
+ import { parseMSIFile } from './msi-parser';
6
+ import { saveAntennas } from './db-utils';
7
+ const STATIC_ANTENNA_FILES = [
8
+ 'ADU4515R17v06_0699_X_CO_M45_03T_Lr1.msi',
9
+ 'ADU4515R17v06_0699_X_CO_M45_04T_Lr1.msi',
10
+ 'ADU4515R17v06_0699_X_CO_M45_05T_Lr1.msi',
11
+ 'ADU4515R17v06_0699_X_CO_M45_06T_Lr1.msi',
12
+ 'ADU4515R17v06_0699_X_CO_M45_07T_Lr1.msi',
13
+ 'ADU4515R17v06_0699_X_CO_M45_08T_Lr1.msi',
14
+ 'ADU4515R17v06_0699_X_CO_M45_09T_Lr1.msi',
15
+ 'ADU4515R17v06_0699_X_CO_M45_10T_Lr1.msi',
16
+ 'ADU4515R17v06_0699_X_CO_M45_11T_Lr1.msi',
17
+ 'ADU4515R17v06_0699_X_CO_M45_12T_Lr1.msi'
18
+ ];
19
+ /**
20
+ * Load and parse all static antenna files
21
+ */
22
+ export async function loadStaticAntennas() {
23
+ const antennas = [];
24
+ console.log(`[loadStaticAntennas] Starting to load ${STATIC_ANTENNA_FILES.length} antenna files...`);
25
+ for (const filename of STATIC_ANTENNA_FILES) {
26
+ try {
27
+ // Fetch the file from static folder
28
+ const url = `/antennas/${filename}`;
29
+ console.log(`[loadStaticAntennas] Fetching: ${url}`);
30
+ const response = await fetch(url);
31
+ if (!response.ok) {
32
+ console.warn(`[loadStaticAntennas] Failed to fetch ${filename}: ${response.status} ${response.statusText}`);
33
+ continue;
34
+ }
35
+ // Convert to File object for parser
36
+ const blob = await response.blob();
37
+ const file = new File([blob], filename, { type: 'text/plain' });
38
+ console.log(`[loadStaticAntennas] Parsing ${filename}...`);
39
+ // Parse the MSI file
40
+ const antenna = await parseMSIFile(file);
41
+ antenna.sourcePath = `static/antennas/${filename}`;
42
+ antennas.push(antenna);
43
+ console.log(`[loadStaticAntennas] ✓ Loaded: ${antenna.name} (${antenna.frequency} MHz, tilt: ${antenna.tilt}°)`);
44
+ }
45
+ catch (error) {
46
+ console.error(`[loadStaticAntennas] Error parsing ${filename}:`, error);
47
+ }
48
+ }
49
+ console.log(`[loadStaticAntennas] Completed. Loaded ${antennas.length}/${STATIC_ANTENNA_FILES.length} antennas`);
50
+ return antennas;
51
+ }
52
+ /**
53
+ * Load static antennas and save to database
54
+ */
55
+ export async function importStaticAntennas() {
56
+ try {
57
+ console.log('[importStaticAntennas] Starting import process...');
58
+ const antennas = await loadStaticAntennas();
59
+ if (antennas.length === 0) {
60
+ console.error('[importStaticAntennas] No antennas were successfully loaded');
61
+ return {
62
+ success: false,
63
+ count: 0,
64
+ error: 'No antennas were successfully loaded'
65
+ };
66
+ }
67
+ console.log(`[importStaticAntennas] Saving ${antennas.length} antennas to database...`);
68
+ await saveAntennas(antennas);
69
+ console.log(`[importStaticAntennas] ✓ Successfully saved ${antennas.length} antennas to database`);
70
+ return {
71
+ success: true,
72
+ count: antennas.length
73
+ };
74
+ }
75
+ catch (error) {
76
+ console.error('[importStaticAntennas] Failed to import static antennas:', error);
77
+ return {
78
+ success: false,
79
+ count: 0,
80
+ error: error instanceof Error ? error.message : 'Unknown error'
81
+ };
82
+ }
83
+ }
@@ -5,7 +5,6 @@
5
5
  import { ChartComponent, type Layout, type CellStylingConfig } from '../../core/Charts';
6
6
  import { buildTreeNodes, filterChartData, transformChartData, type CellTrafficRecord, defaultCellStyling, type TreeGroupingConfig, type TreeGroupField, type ColorDimension, defaultTreeGrouping } from './index';
7
7
  import { expandLayoutForCells } from './helper';
8
- import { log } from '../../core/logger';
9
8
  import type {ChartMarker, Mode } from '../../index.js';
10
9
  import { checkHealth } from '../../core/FeatureRegistry';
11
10
  import SiteCheckControls from './SiteCheckControls.svelte';
@@ -52,24 +51,16 @@
52
51
 
53
52
  // Rebuild tree whenever treeGrouping, singleRootSelect, or singleLevel1Select changes
54
53
  $effect(() => {
55
-
56
- log('🔄 Rebuilding tree with grouping', { treeGrouping, singleRootSelect, singleLevel1Select });
57
-
58
54
  // Clear any existing localStorage data to prevent stale state
59
55
  // This includes both tree state AND chart settings to avoid cell mismatches
60
56
  if (typeof window !== 'undefined') {
61
57
  localStorage.removeItem('site-check:treeState');
62
58
  localStorage.removeItem('charts:globalControls');
63
- log('🧹 Cleared localStorage: tree state and chart settings');
64
59
  }
65
60
 
66
61
  // Build tree nodes from raw data with custom grouping
67
62
  const treeNodes = buildTreeNodes(rawData, treeGrouping);
68
- log('🌲 Tree Nodes Built', {
69
- nodeCount: treeNodes.length,
70
- firstNode: treeNodes[0],
71
- grouping: treeGrouping
72
- });
63
+
73
64
  if(!isHealthy) {
74
65
  return;
75
66
  }
@@ -82,57 +73,24 @@
82
73
  singleRootSelect, // Pass single root select mode
83
74
  singleLevel1Select // Pass single Level 1 select mode
84
75
  });
85
- log('✅ Tree Store Created', {
86
- namespace: 'site-check',
87
- grouping: treeGrouping,
88
- singleRootSelect,
89
- singleLevel1Select
90
- });
91
76
  });
92
77
 
93
78
  // Derive chart data from tree selection
94
79
  let filteredData = $derived.by(() => {
95
80
  if (!treeStore) return [];
96
- const storeValue = $treeStore;
97
- if (!storeValue) return [];
98
- const filtered = filterChartData(rawData, storeValue.state.checkedPaths);
99
- log('🔍 Filtered Data:', {
100
- totalRaw: rawData.length,
101
- checkedPaths: Array.from(storeValue.state.checkedPaths),
102
- filteredCount: filtered.length,
103
- cells: Array.from(new Set(filtered.map(r => r.cellName)))
104
- });
105
- return filtered;
81
+ return filterChartData(rawData, treeStore.state.checkedPaths);
106
82
  });
107
83
 
108
84
  // Transform data using base metrics from layout
109
85
  let chartData = $derived.by(() => {
110
- const transformed = transformChartData(filteredData, baseMetrics);
111
- log('📊 Chart Data:', {
112
- filteredRows: filteredData.length,
113
- transformedRows: transformed.length,
114
- baseMetrics,
115
- sampleRow: transformed[0],
116
- columns: transformed[0] ? Object.keys(transformed[0]) : []
117
- });
118
- return transformed;
86
+ return transformChartData(filteredData, baseMetrics);
119
87
  });
120
88
 
121
89
  // Expand layout based on selected cells and chosen base layout
122
90
  let chartLayout = $derived.by(() => {
123
91
  // Pass cellStyling, treeGrouping, colorDimension, and useSectorLineStyles - helper will decide per-section whether to use styling,
124
92
  // and generate appropriate labels based on grouping, colors based on colorDimension, and line styles based on useSectorLineStyles
125
- const expanded = expandLayoutForCells(selectedBaseLayout, filteredData, treeGrouping, colorDimension, useSectorLineStyles, cellStyling);
126
- log('📐 Chart Layout:', {
127
- layoutName: selectedBaseLayout.layoutName,
128
- layoutDefaultColors: selectedBaseLayout.useDefaultChartColors ?? false,
129
- sectionsCount: expanded.sections.length,
130
- totalCharts: expanded.sections.reduce((sum, s) => sum + s.charts.length, 0),
131
- firstSection: expanded.sections[0],
132
- grouping: treeGrouping,
133
- colorDimension
134
- });
135
- return expanded;
93
+ return expandLayoutForCells(selectedBaseLayout, filteredData, treeGrouping, colorDimension, useSectorLineStyles, cellStyling);
136
94
  });
137
95
 
138
96
  let totalRecords = $derived(rawData.length);
@@ -140,14 +98,10 @@
140
98
 
141
99
  // Compute simple stats
142
100
  let totalCells = $derived.by(() => {
143
- const count = new Set(filteredData.map((r) => r.cellName)).size;
144
- log('📱 Total Cells:', count);
145
- return count;
101
+ return new Set(filteredData.map((r) => r.cellName)).size;
146
102
  });
147
103
  let totalSites = $derived.by(() => {
148
- const count = new Set(filteredData.map((r) => r.siteName)).size;
149
- log('📡 Total Sites:', count);
150
- return count;
104
+ return new Set(filteredData.map((r) => r.siteName)).size;
151
105
  });
152
106
 
153
107
  // Detect cell technology (LTE vs NR) for single-cell layout selection
@@ -157,45 +111,23 @@
157
111
  const cell = filteredData[0];
158
112
  const band = cell?.band?.toUpperCase() || '';
159
113
 
160
- if (band.startsWith('LTE')) {
161
- log('📡 Detected Technology: LTE', { band });
162
- return 'LTE';
163
- }
164
- if (band.startsWith('NR') || band.startsWith('5G')) {
165
- log('📡 Detected Technology: NR', { band });
166
- return 'NR';
167
- }
168
-
169
- log('📡 Detected Technology: UNKNOWN', { band });
114
+ if (band.startsWith('LTE')) return 'LTE';
115
+ if (band.startsWith('NR') || band.startsWith('5G')) return 'NR';
170
116
  return 'UNKNOWN';
171
117
  });
172
118
 
173
119
  // Select appropriate layout based on cell count and technology
174
120
  let selectedBaseLayout = $derived.by(() => {
175
121
  // Multiple cells → always use multi-cell layout
176
- if (totalCells !== 1) {
177
- log('📐 Layout Selection: Multi-cell (count=' + totalCells + ')');
178
- return multiCellLayout;
179
- }
122
+ if (totalCells !== 1) return multiCellLayout;
180
123
 
181
124
  // Single LTE cell → use LTE layout if available, otherwise fallback
182
- if (cellTechnology === 'LTE' && singleLteLayout) {
183
- log('📐 Layout Selection: Single LTE (optimized)');
184
- return singleLteLayout;
185
- }
125
+ if (cellTechnology === 'LTE' && singleLteLayout) return singleLteLayout;
186
126
 
187
127
  // Single NR cell → use NR layout if available, otherwise fallback
188
- if (cellTechnology === 'NR' && singleNrLayout) {
189
- log('📐 Layout Selection: Single NR (optimized)');
190
- return singleNrLayout;
191
- }
128
+ if (cellTechnology === 'NR' && singleNrLayout) return singleNrLayout;
192
129
 
193
130
  // Fallback to multi-cell layout for single cells (works fine)
194
- log('📐 Layout Selection: Multi-cell (fallback for single cell)', {
195
- technology: cellTechnology,
196
- lteLayout: !!singleLteLayout,
197
- nrLayout: !!singleNrLayout
198
- });
199
131
  return multiCellLayout;
200
132
  });
201
133
  </script>
@@ -210,7 +142,7 @@
210
142
  {colorDimension}
211
143
  {singleRootSelect}
212
144
  {singleLevel1Select}
213
- treeStore={$treeStore}
145
+ {treeStore}
214
146
  {showGroupingSelector}
215
147
  {onSearch}
216
148
  {searchPlaceholder}
@@ -223,7 +155,7 @@
223
155
  <!-- Tree View -->
224
156
  <div class="flex-grow-1" style="min-height: 0; overflow: hidden;">
225
157
  {#if treeStore}
226
- <TreeView store={$treeStore!} showControls={true} showIndeterminate={true} height="100%" />
158
+ <TreeView store={treeStore} showControls={true} showIndeterminate={true} height="100%" />
227
159
  {/if}
228
160
  </div>
229
161
  </div>
@@ -1,7 +1,6 @@
1
1
  <svelte:options runes={true} />
2
2
 
3
3
  <script lang="ts">
4
- import { log } from '../../core/logger';
5
4
  import type { TreeGroupingConfig, TreeGroupField, ColorDimension } from './index';
6
5
 
7
6
  interface Props {
@@ -68,7 +67,6 @@
68
67
  function handleSearch() {
69
68
  if (onSearch) {
70
69
  onSearch(searchTerm);
71
- log('🔍 Search triggered:', searchTerm);
72
70
  }
73
71
  }
74
72
 
@@ -76,7 +74,6 @@
76
74
  searchTerm = '';
77
75
  if (onSearch) {
78
76
  onSearch('');
79
- log('🧹 Search cleared');
80
77
  }
81
78
  }
82
79
 
@@ -100,12 +97,10 @@
100
97
 
101
98
  function handleColorDimensionChange(dimension: ColorDimension) {
102
99
  onColorDimensionChange?.(dimension);
103
- log('🎨 Color dimension changed:', dimension);
104
100
  }
105
101
 
106
102
  function handleSingleRootSelectChange(enabled: boolean) {
107
103
  onSingleRootSelectChange?.(enabled);
108
- log('🔘 Single root select mode:', enabled);
109
104
 
110
105
  // When enabling single root mode, uncheck all roots except the first one
111
106
  if (enabled && treeStore) {
@@ -115,7 +110,6 @@
115
110
  store.state.checkedPaths.has(path)
116
111
  );
117
112
  if (checkedRoots.length > 1) {
118
- log('🔘 Multiple roots selected, keeping only first one:', checkedRoots[0]);
119
113
  for (let i = 1; i < checkedRoots.length; i++) {
120
114
  store.toggle(checkedRoots[i]);
121
115
  }
@@ -126,7 +120,6 @@
126
120
 
127
121
  function handleSingleLevel1SelectChange(enabled: boolean) {
128
122
  onSingleLevel1SelectChange?.(enabled);
129
- log('🔘 Single Level 1 select mode:', enabled);
130
123
  }
131
124
  </script>
132
125
 
@@ -103,36 +103,3 @@ export function extractBaseMetrics(layout) {
103
103
  });
104
104
  return Array.from(metrics);
105
105
  }
106
- /**
107
- * Get a distinct color for each cell line
108
- * Uses a predefined color palette with good contrast
109
- */
110
- function getColorForIndex(index) {
111
- const colors = [
112
- '#0d6efd', // Blue
113
- '#198754', // Green
114
- '#dc3545', // Red
115
- '#ffc107', // Yellow
116
- '#0dcaf0', // Cyan
117
- '#6f42c1', // Purple
118
- '#fd7e14', // Orange
119
- '#20c997', // Teal
120
- '#d63384', // Pink
121
- '#6610f2', // Indigo
122
- '#17a2b8', // Info
123
- '#28a745', // Success
124
- '#e83e8c', // Magenta
125
- '#6c757d', // Gray
126
- '#007bff', // Primary
127
- '#28a745', // Green variant
128
- '#17a2b8', // Cyan variant
129
- '#ffc107', // Amber
130
- '#dc3545', // Danger
131
- '#343a40', // Dark
132
- '#6c757d', // Secondary
133
- '#fd7e14', // Orange variant
134
- '#20c997', // Teal variant
135
- '#6f42c1' // Violet
136
- ];
137
- return colors[index % colors.length];
138
- }
@@ -2,7 +2,6 @@
2
2
  * Data Transforms for Site Check Component
3
3
  * Converts raw CSV data to TreeView nodes and Chart configurations
4
4
  */
5
- import { log } from '../../core/logger';
6
5
  /**
7
6
  * Generate a deterministic, production-safe stackgroup ID
8
7
  * This function ensures stackgroups are:
@@ -37,16 +36,17 @@ export function createStackGroupId(value, mode) {
37
36
  export function assignStackGroups(kpis, cells, mode) {
38
37
  // Create a mapping of cellName → metadata for quick lookup
39
38
  const cellMetadata = new Map(cells);
40
- return kpis.map(kpi => {
39
+ // Track missing cells for aggregated warning
40
+ const missingCells = [];
41
+ const result = kpis.map(kpi => {
41
42
  // Extract cellName from the rawName (format: "METRIC_CELLNAME")
42
43
  const cellName = kpi.rawName.split('_').slice(1).join('_');
43
44
  const record = cellMetadata.get(cellName);
44
45
  if (!record) {
45
- // Fallback if cell not found - use default stackgroup
46
- log('⚠️ Cell not found for KPI, using default stackgroup', {
47
- kpiRawName: kpi.rawName,
48
- cellName
49
- });
46
+ // Track missing cell for aggregated warning
47
+ if (!missingCells.includes(cellName)) {
48
+ missingCells.push(cellName);
49
+ }
50
50
  return {
51
51
  ...kpi,
52
52
  stackGroup: createStackGroupId(null, mode)
@@ -77,18 +77,16 @@ export function assignStackGroups(kpis, cells, mode) {
77
77
  }
78
78
  // Create deterministic stackgroup ID
79
79
  const stackGroup = createStackGroupId(groupValue, mode);
80
- log('📊 Assigned stackgroup', {
81
- kpiName: kpi.name,
82
- cellName,
83
- mode,
84
- groupValue,
85
- stackGroup
86
- });
87
80
  return {
88
81
  ...kpi,
89
82
  stackGroup
90
83
  };
91
84
  });
85
+ // Log aggregated warning if any cells were missing
86
+ if (missingCells.length > 0) {
87
+ console.warn(`[SiteCheck] ${missingCells.length} cells not found for KPIs, using default stackgroup. Cells: ${missingCells.slice(0, 5).join(', ')}${missingCells.length > 5 ? ` (+${missingCells.length - 5} more)` : ''}`);
88
+ }
89
+ return result;
92
90
  }
93
91
  /**
94
92
  * Band frequency mapping for consistent ordering
@@ -155,11 +153,6 @@ export function sortCellsByBandFrequency(items) {
155
153
  * @param grouping - Tree grouping configuration (defaults to Site → Azimuth → Cell)
156
154
  */
157
155
  export function buildTreeNodes(data, grouping = { level0: 'site', level1: 'azimuth' }) {
158
- log('🔄 Building tree nodes', {
159
- recordCount: data.length,
160
- grouping,
161
- treeDepth: grouping.level1 === null ? 2 : 3
162
- });
163
156
  // Check if this is a 2-level tree (no level1)
164
157
  if (grouping.level1 === null) {
165
158
  return build2LevelTree(data, grouping);
@@ -237,11 +230,6 @@ export function buildTreeNodes(data, grouping = { level0: 'site', level1: 'azimu
237
230
  });
238
231
  treeNodes.push(level0Node);
239
232
  });
240
- log('✅ Tree nodes built', {
241
- totalNodes: treeNodes.length,
242
- grouping,
243
- sampleNode: treeNodes[0]?.label
244
- });
245
233
  return treeNodes;
246
234
  }
247
235
  /**
@@ -299,11 +287,6 @@ function build2LevelTree(data, grouping) {
299
287
  });
300
288
  treeNodes.push(level0Node);
301
289
  });
302
- log('✅ 2-level tree nodes built', {
303
- totalNodes: treeNodes.length,
304
- grouping: `${grouping.level0} → cell`,
305
- sampleNode: treeNodes[0]?.label
306
- });
307
290
  return treeNodes;
308
291
  }
309
292
  /**
@@ -351,14 +334,10 @@ function compareValues(a, b) {
351
334
  }
352
335
  /**
353
336
  * Get icon emoji based on band technology
337
+ * Currently disabled - returns empty string to keep tree labels clean
354
338
  */
355
- function getBandIcon(band) {
339
+ function getBandIcon(_band) {
356
340
  return '';
357
- if (band.startsWith('NR'))
358
- return '📶'; // 5G
359
- if (band.startsWith('LTE'))
360
- return '📱'; // 4G
361
- return '📡'; // Fallback
362
341
  }
363
342
  /**
364
343
  * Filter chart data based on selected tree paths
@@ -366,11 +345,6 @@ function getBandIcon(band) {
366
345
  * Handles both 2-level (level0:cellName) and 3-level (level0:level1:cellName) paths
367
346
  */
368
347
  export function filterChartData(data, checkedPaths) {
369
- log('🔄 Filtering chart data', {
370
- totalRecords: data.length,
371
- checkedPathsCount: checkedPaths.size,
372
- paths: Array.from(checkedPaths)
373
- });
374
348
  // Extract cell names from checked leaf paths
375
349
  const selectedCells = new Set();
376
350
  checkedPaths.forEach((path) => {
@@ -385,12 +359,7 @@ export function filterChartData(data, checkedPaths) {
385
359
  }
386
360
  });
387
361
  // Filter data to only include selected cells
388
- const filtered = data.filter((record) => selectedCells.has(record.cellName));
389
- log('✅ Filtered chart data', {
390
- selectedCells: Array.from(selectedCells),
391
- filteredCount: filtered.length
392
- });
393
- return filtered;
362
+ return data.filter((record) => selectedCells.has(record.cellName));
394
363
  }
395
364
  /**
396
365
  * Transform data for chart component consumption
@@ -401,10 +370,6 @@ export function filterChartData(data, checkedPaths) {
401
370
  * @param baseMetrics - Array of metric names to pivot (e.g., ['DL_GBYTES', 'UL_GBYTES'])
402
371
  */
403
372
  export function transformChartData(data, baseMetrics) {
404
- log('🔄 Transforming chart data', {
405
- rowCount: data.length,
406
- baseMetrics
407
- });
408
373
  // Group data by date
409
374
  const dateMap = new Map();
410
375
  data.forEach((record) => {
@@ -435,10 +400,6 @@ export function transformChartData(data, baseMetrics) {
435
400
  });
436
401
  // Sort by date
437
402
  pivotedData.sort((a, b) => a.TIMESTAMP.localeCompare(b.TIMESTAMP));
438
- log('✅ Chart data transformed', {
439
- outputRows: pivotedData.length,
440
- sampleColumns: pivotedData[0] ? Object.keys(pivotedData[0]) : []
441
- });
442
403
  return pivotedData;
443
404
  }
444
405
  /**
@@ -508,17 +469,6 @@ export function createStyledKPI(metricName, cellRecord, unit, grouping, colorDim
508
469
  ...(color && { color }),
509
470
  ...(lineStyle && { lineStyle })
510
471
  };
511
- log('🎨 Styled KPI created', {
512
- metricName,
513
- cellName,
514
- displayName,
515
- band,
516
- sector,
517
- azimuth,
518
- colorDimension,
519
- color,
520
- lineStyle
521
- });
522
472
  return kpi;
523
473
  }
524
474
  /**