@smartnet360/svelte-components 0.0.22 → 0.0.23

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 (36) hide show
  1. package/dist/apps/antenna-pattern/utils/msi-parser.js +18 -1
  2. package/dist/cellular/CellularChartsView.svelte +293 -0
  3. package/dist/cellular/CellularChartsView.svelte.d.ts +7 -0
  4. package/dist/cellular/HierarchicalTree.svelte +469 -0
  5. package/dist/cellular/HierarchicalTree.svelte.d.ts +9 -0
  6. package/dist/cellular/SiteTree.svelte +286 -0
  7. package/dist/cellular/SiteTree.svelte.d.ts +11 -0
  8. package/dist/cellular/cellular-transforms.d.ts +25 -0
  9. package/dist/cellular/cellular-transforms.js +129 -0
  10. package/dist/cellular/cellular.model.d.ts +63 -0
  11. package/dist/cellular/cellular.model.js +6 -0
  12. package/dist/cellular/index.d.ts +11 -0
  13. package/dist/cellular/index.js +11 -0
  14. package/dist/cellular/mock-cellular-data.d.ts +13 -0
  15. package/dist/cellular/mock-cellular-data.js +241 -0
  16. package/dist/core/TreeChartView/TreeChartView.svelte +208 -0
  17. package/dist/core/TreeChartView/TreeChartView.svelte.d.ts +42 -0
  18. package/dist/core/TreeChartView/index.d.ts +7 -0
  19. package/dist/core/TreeChartView/index.js +7 -0
  20. package/dist/core/TreeView/TreeNode.svelte +173 -0
  21. package/dist/core/TreeView/TreeNode.svelte.d.ts +10 -0
  22. package/dist/core/TreeView/TreeView.svelte +163 -0
  23. package/dist/core/TreeView/TreeView.svelte.d.ts +10 -0
  24. package/dist/core/TreeView/index.d.ts +48 -0
  25. package/dist/core/TreeView/index.js +50 -0
  26. package/dist/core/TreeView/tree-utils.d.ts +56 -0
  27. package/dist/core/TreeView/tree-utils.js +194 -0
  28. package/dist/core/TreeView/tree.model.d.ts +104 -0
  29. package/dist/core/TreeView/tree.model.js +5 -0
  30. package/dist/core/TreeView/tree.store.d.ts +10 -0
  31. package/dist/core/TreeView/tree.store.js +225 -0
  32. package/dist/core/index.d.ts +2 -0
  33. package/dist/core/index.js +4 -0
  34. package/dist/index.d.ts +1 -0
  35. package/dist/index.js +3 -1
  36. package/package.json +1 -1
@@ -92,7 +92,24 @@ export async function parseMSIFile(file) {
92
92
  }
93
93
  }
94
94
  else if (trimmedLine.startsWith('COMMENT ')) {
95
- result.comment = trimmedLine.substring(8).trim();
95
+ const commentText = trimmedLine.substring(8).trim();
96
+ result.comment = commentText;
97
+ // Extract tilt from comment if not already set from filename
98
+ if (!filenameMetadata.tilt_from_filename && !result.tilt) {
99
+ // Look for patterns like "Lever position 2 deg" or "Lever position 2deg"
100
+ const leverMatch = commentText.match(/Lever position\s+(\d+)\s*deg/i);
101
+ if (leverMatch) {
102
+ result.tilt = leverMatch[1];
103
+ }
104
+ // Alternative patterns: "tilt: 2 deg", "2 deg tilt", "mechanical tilt 2", etc.
105
+ // if (!result.tilt) {
106
+ // const tiltMatch = commentText.match(/(?:tilt|mechanical|electrical)[\s:]+(\d+)(?:\s*deg)?/i) ||
107
+ // commentText.match(/(\d+)\s*deg(?:ree)?s?\s+(?:tilt|mechanical|electrical)/i);
108
+ // if (tiltMatch) {
109
+ // result.tilt = tiltMatch[1];
110
+ // }
111
+ // }
112
+ }
96
113
  }
97
114
  else if (trimmedLine.startsWith('HORIZONTAL ')) {
98
115
  currentSection = 'horizontal';
@@ -0,0 +1,293 @@
1
+ <svelte:options runes={true} />
2
+
3
+ <script lang="ts">
4
+ import type { CellularSite, CellLine } from './cellular.model.js';
5
+ import type { Layout } from '../core/Charts/charts.model.js';
6
+ import type { TreeNode } from '../core/TreeView/tree.model.js';
7
+ import ChartComponent from '../core/Charts/ChartComponent.svelte';
8
+ import { TreeView, createTreeStore } from '../core/TreeView';
9
+ import { getBandColor, getBandLabel } from './mock-cellular-data.js';
10
+
11
+ interface Props {
12
+ sites: CellularSite[];
13
+ }
14
+
15
+ let { sites }: Props = $props();
16
+
17
+ // Transform cellular sites to TreeNode structure
18
+ let treeNodes = $derived.by((): TreeNode[] => {
19
+ return sites.map(site => ({
20
+ id: site.siteId,
21
+ label: site.siteName,
22
+ icon: '📡',
23
+ defaultExpanded: false,
24
+ defaultChecked: true, // Explicitly set
25
+ children: site.sectors.map(sector => ({
26
+ id: sector.sectorId, // Just the sector ID, not full path
27
+ label: sector.sectorName,
28
+ icon: '📶',
29
+ defaultExpanded: false,
30
+ defaultChecked: true, // Explicitly set
31
+ children: sector.cells.map(cell => ({
32
+ id: String(cell.band), // Just the band number
33
+ label: getBandLabel(cell.band),
34
+ icon: '📻',
35
+ defaultChecked: true, // Explicitly set
36
+ metadata: {
37
+ band: cell.band,
38
+ color: getBandColor(cell.band)
39
+ }
40
+ }))
41
+ }))
42
+ }));
43
+ });
44
+
45
+ // Create tree store with persistence
46
+ let treeStore = $derived(
47
+ createTreeStore({
48
+ nodes: treeNodes,
49
+ namespace: 'cellular-sites',
50
+ persistState: true, // Re-enabled - state will be saved/restored
51
+ defaultExpandAll: false,
52
+ showIndeterminate: true
53
+ })
54
+ );
55
+
56
+ // Flatten sites into cell lines
57
+ let cellLines = $derived.by((): CellLine[] => {
58
+ const lines: CellLine[] = [];
59
+
60
+ sites.forEach(site => {
61
+ site.sectors.forEach(sector => {
62
+ sector.cells.forEach(cell => {
63
+ // Path construction matches tree-utils.ts flattenTree logic
64
+ // Root: "siteId"
65
+ // Level 1: "siteId:sectorId"
66
+ // Level 2: "siteId:sectorId:band"
67
+ const cellKey = `${site.siteId}:${sector.sectorId}:${cell.band}`;
68
+
69
+ // Check visibility from tree store
70
+ const isVisible = $treeStore.state.checkedPaths.has(cellKey);
71
+
72
+ lines.push({
73
+ siteId: site.siteId,
74
+ siteName: site.siteName,
75
+ sectorId: sector.sectorId,
76
+ sectorName: sector.sectorName,
77
+ cellId: cell.cellId,
78
+ band: cell.band,
79
+ label: `${site.siteName} - ${sector.sectorName} - ${getBandLabel(cell.band)}`,
80
+ color: getBandColor(cell.band),
81
+ kpis: cell.kpis,
82
+ visible: isVisible
83
+ });
84
+ });
85
+ });
86
+ });
87
+
88
+ return lines;
89
+ });
90
+
91
+ // Filter visible cell lines for chart display
92
+ let visibleCellLines = $derived(cellLines.filter(line => line.visible));
93
+
94
+ // Transform cell lines into chart data format
95
+ let chartData = $derived.by(() => {
96
+ const data: any[] = [];
97
+
98
+ visibleCellLines.forEach(line => {
99
+ // Create one row per timestamp with all KPI values
100
+ const timestamps = new Set(line.kpis.throughput.map(kpi => kpi.timestamp));
101
+
102
+ timestamps.forEach(timestamp => {
103
+ const throughputPoint = line.kpis.throughput.find(kpi => kpi.timestamp === timestamp);
104
+ const taPoint = line.kpis.timingAdvance.find(kpi => kpi.timestamp === timestamp);
105
+
106
+ if (throughputPoint && taPoint) {
107
+ data.push({
108
+ TIMESTAMP: timestamp,
109
+ [`DL_THROUGHPUT_${line.cellId}`]: throughputPoint.value,
110
+ [`AVG_TA_${line.cellId}`]: taPoint.value,
111
+ _cellId: line.cellId,
112
+ _label: line.label,
113
+ _color: line.color
114
+ });
115
+ }
116
+ });
117
+ });
118
+
119
+ return data;
120
+ });
121
+
122
+ // Chart layout configuration - dynamically build KPIs from visible cells
123
+ let chartLayout = $derived.by((): Layout => {
124
+ const throughputKPIs = visibleCellLines.map(line => ({
125
+ rawName: `DL_THROUGHPUT_${line.cellId}`,
126
+ name: line.label,
127
+ scale: 'absolute' as const,
128
+ unit: 'Mbps',
129
+ color: line.color
130
+ }));
131
+
132
+ const taKPIs = visibleCellLines.map(line => ({
133
+ rawName: `AVG_TA_${line.cellId}`,
134
+ name: line.label,
135
+ scale: 'absolute' as const,
136
+ unit: 'μs',
137
+ color: line.color
138
+ }));
139
+
140
+ return {
141
+ layoutName: 'Cellular KPIs',
142
+ sections: [
143
+ {
144
+ id: 'kpis',
145
+ title: 'KPIs',
146
+ grid: '2x2',
147
+ charts: [
148
+ {
149
+ title: 'Downlink Throughput',
150
+ yLeft: throughputKPIs,
151
+ yRight: []
152
+ },
153
+ {
154
+ title: 'Average Timing Advance',
155
+ yLeft: taKPIs,
156
+ yRight: []
157
+ }
158
+ ]
159
+ }
160
+ ]
161
+ };
162
+ });
163
+ </script>
164
+
165
+ <div class="cellular-charts-view">
166
+ <!-- Left: Site Tree -->
167
+ <aside class="site-selector">
168
+ <TreeView store={$treeStore} showControls={true} height="100%" />
169
+ </aside>
170
+
171
+ <!-- Right: Charts -->
172
+ <main class="charts-area">
173
+ <div class="charts-header">
174
+ <h5 class="mb-0">Cellular Network KPIs</h5>
175
+ <div class="stats">
176
+ <span class="badge bg-primary">
177
+ {visibleCellLines.length} of {cellLines.length} cells visible
178
+ </span>
179
+ </div>
180
+ </div>
181
+ <div class="charts-container">
182
+ {#if visibleCellLines.length === 0}
183
+ <div class="empty-state">
184
+ <div class="empty-state-content">
185
+ <i class="bi bi-info-circle" style="font-size: 3rem; color: #6c757d;"></i>
186
+ <h4 class="mt-3">No Cells Selected</h4>
187
+ <p class="text-muted">
188
+ Select one or more cells from the tree on the left to display KPI charts.
189
+ </p>
190
+ </div>
191
+ </div>
192
+ {:else}
193
+ <ChartComponent
194
+ layout={chartLayout}
195
+ data={chartData}
196
+ mode="tabs"
197
+ showGlobalControls={true}
198
+ enableAdaptation={true}
199
+ />
200
+ {/if}
201
+ </div>
202
+ </main>
203
+ </div>
204
+
205
+ <style>
206
+ .cellular-charts-view {
207
+ width: 100%;
208
+ height: 100%;
209
+ display: flex;
210
+ gap: 0;
211
+ background-color: #fff;
212
+ }
213
+
214
+ .site-selector {
215
+ width: 300px;
216
+ flex-shrink: 0;
217
+ height: 100%;
218
+ overflow: hidden;
219
+ }
220
+
221
+ .charts-area {
222
+ flex: 1;
223
+ display: flex;
224
+ flex-direction: column;
225
+ min-width: 0;
226
+ height: 100%;
227
+ }
228
+
229
+ .charts-header {
230
+ padding: 1rem;
231
+ border-bottom: 1px solid #dee2e6;
232
+ background-color: #f8f9fa;
233
+ display: flex;
234
+ justify-content: space-between;
235
+ align-items: center;
236
+ flex-shrink: 0;
237
+ }
238
+
239
+ .charts-header h5 {
240
+ margin: 0;
241
+ color: #495057;
242
+ }
243
+
244
+ .stats {
245
+ display: flex;
246
+ gap: 0.5rem;
247
+ }
248
+
249
+ .charts-container {
250
+ flex: 1;
251
+ min-height: 0;
252
+ overflow: hidden;
253
+ }
254
+
255
+ .empty-state {
256
+ display: flex;
257
+ align-items: center;
258
+ justify-content: center;
259
+ height: 100%;
260
+ width: 100%;
261
+ }
262
+
263
+ .empty-state-content {
264
+ text-align: center;
265
+ max-width: 400px;
266
+ padding: 2rem;
267
+ }
268
+
269
+ .empty-state-content h4 {
270
+ color: #495057;
271
+ margin-bottom: 0.5rem;
272
+ }
273
+
274
+ /* Responsive layout */
275
+ @media (max-width: 992px) {
276
+ .site-selector {
277
+ width: 250px;
278
+ }
279
+ }
280
+
281
+ @media (max-width: 768px) {
282
+ .cellular-charts-view {
283
+ flex-direction: column;
284
+ }
285
+
286
+ .site-selector {
287
+ width: 100%;
288
+ height: 300px;
289
+ border-right: none;
290
+ border-bottom: 1px solid #dee2e6;
291
+ }
292
+ }
293
+ </style>
@@ -0,0 +1,7 @@
1
+ import type { CellularSite } from './cellular.model.js';
2
+ interface Props {
3
+ sites: CellularSite[];
4
+ }
5
+ declare const CellularChartsView: import("svelte").Component<Props, {}, "">;
6
+ type CellularChartsView = ReturnType<typeof CellularChartsView>;
7
+ export default CellularChartsView;