@smartnet360/svelte-components 0.0.21 → 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.
- package/dist/apps/antenna-pattern/utils/msi-parser.js +18 -1
- package/dist/cellular/CellularChartsView.svelte +293 -0
- package/dist/cellular/CellularChartsView.svelte.d.ts +7 -0
- package/dist/cellular/HierarchicalTree.svelte +469 -0
- package/dist/cellular/HierarchicalTree.svelte.d.ts +9 -0
- package/dist/cellular/SiteTree.svelte +286 -0
- package/dist/cellular/SiteTree.svelte.d.ts +11 -0
- package/dist/cellular/cellular-transforms.d.ts +25 -0
- package/dist/cellular/cellular-transforms.js +129 -0
- package/dist/cellular/cellular.model.d.ts +63 -0
- package/dist/cellular/cellular.model.js +6 -0
- package/dist/cellular/index.d.ts +11 -0
- package/dist/cellular/index.js +11 -0
- package/dist/cellular/mock-cellular-data.d.ts +13 -0
- package/dist/cellular/mock-cellular-data.js +241 -0
- package/dist/core/Charts/ChartCard.svelte +65 -16
- package/dist/core/Charts/ChartCard.svelte.d.ts +2 -0
- package/dist/core/Charts/ChartComponent.svelte +166 -34
- package/dist/core/Charts/ChartComponent.svelte.d.ts +1 -0
- package/dist/core/Charts/GlobalControls.svelte +188 -0
- package/dist/core/Charts/GlobalControls.svelte.d.ts +8 -0
- package/dist/core/Charts/charts.model.d.ts +7 -0
- package/dist/core/TreeChartView/TreeChartView.svelte +208 -0
- package/dist/core/TreeChartView/TreeChartView.svelte.d.ts +42 -0
- package/dist/core/TreeChartView/index.d.ts +7 -0
- package/dist/core/TreeChartView/index.js +7 -0
- package/dist/core/TreeView/TreeNode.svelte +173 -0
- package/dist/core/TreeView/TreeNode.svelte.d.ts +10 -0
- package/dist/core/TreeView/TreeView.svelte +163 -0
- package/dist/core/TreeView/TreeView.svelte.d.ts +10 -0
- package/dist/core/TreeView/index.d.ts +48 -0
- package/dist/core/TreeView/index.js +50 -0
- package/dist/core/TreeView/tree-utils.d.ts +56 -0
- package/dist/core/TreeView/tree-utils.js +194 -0
- package/dist/core/TreeView/tree.model.d.ts +104 -0
- package/dist/core/TreeView/tree.model.js +5 -0
- package/dist/core/TreeView/tree.store.d.ts +10 -0
- package/dist/core/TreeView/tree.store.js +225 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- 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
|
-
|
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;
|