@smartnet360/svelte-components 0.0.83 → 0.0.85
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/site-check/SiteCheck.svelte +90 -36
- package/dist/apps/site-check/data-loader.d.ts +7 -3
- package/dist/apps/site-check/data-loader.js +2 -3
- package/dist/apps/site-check/helper.d.ts +3 -2
- package/dist/apps/site-check/helper.js +7 -5
- package/dist/apps/site-check/index.d.ts +1 -1
- package/dist/apps/site-check/transforms.d.ts +4 -2
- package/dist/apps/site-check/transforms.js +64 -19
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<script lang="ts">
|
|
4
4
|
import { TreeView, createTreeStore } from '../../core/TreeView';
|
|
5
5
|
import { ChartComponent, type Layout, type CellStylingConfig } from '../../core/Charts';
|
|
6
|
-
import { buildTreeNodes, filterChartData, transformChartData, type CellTrafficRecord, defaultCellStyling, type TreeGroupingConfig, defaultTreeGrouping } from './index';
|
|
6
|
+
import { buildTreeNodes, filterChartData, transformChartData, type CellTrafficRecord, defaultCellStyling, type TreeGroupingConfig, type TreeGroupField, type ColorDimension, defaultTreeGrouping } from './index';
|
|
7
7
|
import { expandLayoutForCells } from './helper';
|
|
8
8
|
import { log } from '../../core/logger';
|
|
9
9
|
import type {ChartMarker, Mode } from '../../index.js';
|
|
@@ -58,19 +58,39 @@
|
|
|
58
58
|
// Internal state for current grouping
|
|
59
59
|
let treeGrouping = $state<TreeGroupingConfig>(initialGrouping);
|
|
60
60
|
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
{
|
|
67
|
-
{
|
|
68
|
-
{
|
|
69
|
-
{
|
|
70
|
-
{ label: 'Azimuth → Cell (2-level)', value: { level0: 'azimuth', level1: null, level2: 'cell' } as TreeGroupingConfig },
|
|
61
|
+
// Color dimension state (defaults to 'band' for semantic RF characteristics)
|
|
62
|
+
let colorDimension = $state<ColorDimension>('band');
|
|
63
|
+
|
|
64
|
+
// Available field options for grouping levels
|
|
65
|
+
const fieldOptions: { value: TreeGroupField; label: string }[] = [
|
|
66
|
+
{ value: 'site', label: 'Site' },
|
|
67
|
+
{ value: 'band', label: 'Band' },
|
|
68
|
+
{ value: 'azimuth', label: 'Azimuth' },
|
|
69
|
+
{ value: 'sector', label: 'Sector' }
|
|
71
70
|
];
|
|
72
71
|
|
|
73
|
-
|
|
72
|
+
// Handlers for level changes
|
|
73
|
+
function handleLevel0Change(value: TreeGroupField) {
|
|
74
|
+
// Clear level1 if it conflicts with new level0
|
|
75
|
+
const newLevel1 = treeGrouping.level1 === value ? null : treeGrouping.level1;
|
|
76
|
+
treeGrouping = {
|
|
77
|
+
level0: value,
|
|
78
|
+
level1: newLevel1
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function handleLevel1Change(value: TreeGroupField | 'none') {
|
|
83
|
+
const newLevel1 = value === 'none' ? null : value;
|
|
84
|
+
treeGrouping = {
|
|
85
|
+
level0: treeGrouping.level0,
|
|
86
|
+
level1: newLevel1
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Get available options for level1 (exclude level0)
|
|
91
|
+
let availableLevel1Options = $derived.by(() => {
|
|
92
|
+
return fieldOptions.filter(opt => opt.value !== treeGrouping.level0);
|
|
93
|
+
}); let treeStore = $state<ReturnType<typeof createTreeStore> | null>(null);
|
|
74
94
|
|
|
75
95
|
// Rebuild tree whenever treeGrouping changes
|
|
76
96
|
$effect(() => {
|
|
@@ -137,16 +157,17 @@
|
|
|
137
157
|
|
|
138
158
|
// Expand layout based on selected cells and chosen base layout
|
|
139
159
|
let chartLayout = $derived.by(() => {
|
|
140
|
-
// Pass cellStyling and
|
|
141
|
-
// and generate appropriate labels based on grouping
|
|
142
|
-
const expanded = expandLayoutForCells(selectedBaseLayout, filteredData, treeGrouping, cellStyling);
|
|
160
|
+
// Pass cellStyling, treeGrouping, and colorDimension - helper will decide per-section whether to use styling,
|
|
161
|
+
// and generate appropriate labels based on grouping and colors based on colorDimension
|
|
162
|
+
const expanded = expandLayoutForCells(selectedBaseLayout, filteredData, treeGrouping, colorDimension, cellStyling);
|
|
143
163
|
log('📐 Chart Layout:', {
|
|
144
164
|
layoutName: selectedBaseLayout.layoutName,
|
|
145
165
|
layoutDefaultColors: selectedBaseLayout.useDefaultChartColors ?? false,
|
|
146
166
|
sectionsCount: expanded.sections.length,
|
|
147
167
|
totalCharts: expanded.sections.reduce((sum, s) => sum + s.charts.length, 0),
|
|
148
168
|
firstSection: expanded.sections[0],
|
|
149
|
-
grouping: treeGrouping
|
|
169
|
+
grouping: treeGrouping,
|
|
170
|
+
colorDimension
|
|
150
171
|
});
|
|
151
172
|
return expanded;
|
|
152
173
|
});
|
|
@@ -280,34 +301,67 @@
|
|
|
280
301
|
<i class="bi bi-search"></i>
|
|
281
302
|
</button>
|
|
282
303
|
</div>
|
|
283
|
-
|
|
284
|
-
|
|
304
|
+
</div>
|
|
305
|
+
{/if}
|
|
285
306
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
307
|
+
<!-- Grouping Selector -->
|
|
308
|
+
{#if showGroupingSelector}
|
|
309
|
+
<div class="p-3 border-bottom flex-shrink-0">
|
|
310
|
+
<div class="small fw-semibold mb-2">Tree Grouping</div>
|
|
311
|
+
|
|
312
|
+
<div class="row g-2 mb-2">
|
|
313
|
+
<!-- Level 0 (Mandatory) -->
|
|
314
|
+
<div class="col-4">
|
|
315
|
+
<label for="level0Select" class="form-label small mb-1">Level 0</label>
|
|
292
316
|
<select
|
|
293
|
-
id="
|
|
317
|
+
id="level0Select"
|
|
294
318
|
class="form-select form-select-sm"
|
|
319
|
+
value={treeGrouping.level0}
|
|
320
|
+
onchange={(e) => handleLevel0Change(e.currentTarget.value as TreeGroupField)}
|
|
321
|
+
>
|
|
322
|
+
{#each fieldOptions as option}
|
|
323
|
+
<option value={option.value}>{option.label}</option>
|
|
324
|
+
{/each}
|
|
325
|
+
</select>
|
|
326
|
+
</div>
|
|
327
|
+
|
|
328
|
+
<!-- Level 1 (Optional) -->
|
|
329
|
+
<div class="col-4">
|
|
330
|
+
<label for="level1Select" class="form-label small mb-1">Level 1</label>
|
|
331
|
+
<select
|
|
332
|
+
id="level1Select"
|
|
333
|
+
class="form-select form-select-sm"
|
|
334
|
+
value={treeGrouping.level1 ?? 'none'}
|
|
335
|
+
onchange={(e) => handleLevel1Change(e.currentTarget.value as TreeGroupField | 'none')}
|
|
336
|
+
>
|
|
337
|
+
<option value="none">None</option>
|
|
338
|
+
{#each availableLevel1Options as option}
|
|
339
|
+
<option value={option.value}>{option.label}</option>
|
|
340
|
+
{/each}
|
|
341
|
+
</select>
|
|
342
|
+
</div>
|
|
343
|
+
|
|
344
|
+
<!-- Color By -->
|
|
345
|
+
<div class="col-4">
|
|
346
|
+
<label for="colorDimensionSelect" class="form-label small mb-1">Color By</label>
|
|
347
|
+
<select
|
|
348
|
+
id="colorDimensionSelect"
|
|
349
|
+
class="form-select form-select-sm"
|
|
350
|
+
value={colorDimension}
|
|
295
351
|
onchange={(e) => {
|
|
296
|
-
|
|
297
|
-
|
|
352
|
+
colorDimension = e.currentTarget.value as ColorDimension;
|
|
353
|
+
log('🎨 Color dimension changed:', colorDimension);
|
|
298
354
|
}}
|
|
299
355
|
>
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
{preset.label}
|
|
303
|
-
</option>
|
|
304
|
-
{/each}
|
|
356
|
+
<option value="band">Band</option>
|
|
357
|
+
<option value="site">Site</option>
|
|
305
358
|
</select>
|
|
306
359
|
</div>
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
360
|
+
</div>
|
|
361
|
+
|
|
362
|
+
</div>
|
|
363
|
+
{/if}
|
|
364
|
+
{/if} <!-- Tree View -->
|
|
311
365
|
<div class="flex-grow-1" style="min-height: 0; overflow: hidden;">
|
|
312
366
|
{#if treeStore}
|
|
313
367
|
<TreeView store={$treeStore!} showControls={true} showIndeterminate={true} height="100%" />
|
|
@@ -15,19 +15,23 @@ export interface CellTrafficRecord {
|
|
|
15
15
|
* Tree grouping field types
|
|
16
16
|
*/
|
|
17
17
|
export type TreeGroupField = 'site' | 'azimuth' | 'band' | 'sector';
|
|
18
|
+
/**
|
|
19
|
+
* Color dimension types - determines which field is used for chart coloring
|
|
20
|
+
*/
|
|
21
|
+
export type ColorDimension = 'site' | 'band';
|
|
18
22
|
/**
|
|
19
23
|
* Configuration for tree hierarchy grouping
|
|
20
24
|
* Defines which fields appear at each level of the tree
|
|
21
|
-
*
|
|
25
|
+
* Cells are always the leaf nodes (implicit, not configured)
|
|
22
26
|
* - For 2-level tree: level0 → cell (set level1 to null)
|
|
27
|
+
* - For 3-level tree: level0 → level1 → cell
|
|
23
28
|
*/
|
|
24
29
|
export interface TreeGroupingConfig {
|
|
25
30
|
level0: TreeGroupField;
|
|
26
31
|
level1: TreeGroupField | null;
|
|
27
|
-
level2: 'cell';
|
|
28
32
|
}
|
|
29
33
|
/**
|
|
30
|
-
* Default tree grouping: Site →
|
|
34
|
+
* Default tree grouping: Site → Band → Cell (3-level)
|
|
31
35
|
*/
|
|
32
36
|
export declare const defaultTreeGrouping: TreeGroupingConfig;
|
|
33
37
|
/**
|
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
* Loads and parses cell_traffic_with_band.csv
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
* Default tree grouping: Site →
|
|
6
|
+
* Default tree grouping: Site → Band → Cell (3-level)
|
|
7
7
|
*/
|
|
8
8
|
export const defaultTreeGrouping = {
|
|
9
9
|
level0: 'site',
|
|
10
|
-
level1: '
|
|
11
|
-
level2: 'cell'
|
|
10
|
+
level1: 'band'
|
|
12
11
|
};
|
|
13
12
|
/**
|
|
14
13
|
* Load cell traffic data from CSV file
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Layout, CellStylingConfig } from '../../core/Charts';
|
|
2
|
-
import type { CellTrafficRecord, TreeGroupingConfig } from './';
|
|
2
|
+
import type { CellTrafficRecord, TreeGroupingConfig, ColorDimension } from './';
|
|
3
3
|
import { type StackGroupMode } from './transforms.js';
|
|
4
4
|
/**
|
|
5
5
|
* Expand base layout configuration with dynamic KPIs based on selected cells
|
|
@@ -8,11 +8,12 @@ import { type StackGroupMode } from './transforms.js';
|
|
|
8
8
|
* @param baseLayout - The base layout configuration from JSON
|
|
9
9
|
* @param data - Filtered cell traffic records for selected cells
|
|
10
10
|
* @param grouping - Current tree grouping configuration (determines label format)
|
|
11
|
+
* @param colorDimension - Which field to use for coloring (site or band)
|
|
11
12
|
* @param stylingConfig - Optional cell styling configuration (band colors, sector line styles)
|
|
12
13
|
* @param stackGroupMode - Optional stackgroup strategy for stacked charts (default: 'none' = single stack)
|
|
13
14
|
* @returns Expanded layout with cell-specific KPIs
|
|
14
15
|
*/
|
|
15
|
-
export declare function expandLayoutForCells(baseLayout: Layout, data: CellTrafficRecord[], grouping: TreeGroupingConfig, stylingConfig?: CellStylingConfig, stackGroupMode?: StackGroupMode): Layout;
|
|
16
|
+
export declare function expandLayoutForCells(baseLayout: Layout, data: CellTrafficRecord[], grouping: TreeGroupingConfig, colorDimension: ColorDimension, stylingConfig?: CellStylingConfig, stackGroupMode?: StackGroupMode): Layout;
|
|
16
17
|
/**
|
|
17
18
|
* Extract base metric names from a layout configuration
|
|
18
19
|
* Returns unique metric rawNames that need to be pivoted
|
|
@@ -6,11 +6,12 @@ import { createStyledKPI, sortCellsByBandFrequency, assignStackGroups } from './
|
|
|
6
6
|
* @param baseLayout - The base layout configuration from JSON
|
|
7
7
|
* @param data - Filtered cell traffic records for selected cells
|
|
8
8
|
* @param grouping - Current tree grouping configuration (determines label format)
|
|
9
|
+
* @param colorDimension - Which field to use for coloring (site or band)
|
|
9
10
|
* @param stylingConfig - Optional cell styling configuration (band colors, sector line styles)
|
|
10
11
|
* @param stackGroupMode - Optional stackgroup strategy for stacked charts (default: 'none' = single stack)
|
|
11
12
|
* @returns Expanded layout with cell-specific KPIs
|
|
12
13
|
*/
|
|
13
|
-
export function expandLayoutForCells(baseLayout, data, grouping, stylingConfig, stackGroupMode = 'none') {
|
|
14
|
+
export function expandLayoutForCells(baseLayout, data, grouping, colorDimension, stylingConfig, stackGroupMode = 'none') {
|
|
14
15
|
// Get unique cells and their metadata, sorted by band frequency
|
|
15
16
|
const cellMap = new Map();
|
|
16
17
|
data.forEach((record) => {
|
|
@@ -38,8 +39,8 @@ export function expandLayoutForCells(baseLayout, data, grouping, stylingConfig,
|
|
|
38
39
|
...section,
|
|
39
40
|
charts: section.charts.map((chart) => ({
|
|
40
41
|
...chart,
|
|
41
|
-
yLeft: expandKPIs(chart.yLeft, cells, grouping, effectiveStyling, stackGroupMode),
|
|
42
|
-
yRight: expandKPIs(chart.yRight, cells, grouping, effectiveStyling, stackGroupMode)
|
|
42
|
+
yLeft: expandKPIs(chart.yLeft, cells, grouping, colorDimension, effectiveStyling, stackGroupMode),
|
|
43
|
+
yRight: expandKPIs(chart.yRight, cells, grouping, colorDimension, effectiveStyling, stackGroupMode)
|
|
43
44
|
}))
|
|
44
45
|
};
|
|
45
46
|
})
|
|
@@ -54,17 +55,18 @@ export function expandLayoutForCells(baseLayout, data, grouping, stylingConfig,
|
|
|
54
55
|
* @param baseKPIs - Array of base KPIs from layout
|
|
55
56
|
* @param cells - Array of [cellName, record] tuples
|
|
56
57
|
* @param grouping - Current tree grouping configuration (determines label format)
|
|
58
|
+
* @param colorDimension - Which field to use for coloring (site or band)
|
|
57
59
|
* @param stylingConfig - Optional cell styling configuration
|
|
58
60
|
* @param stackGroupMode - Stackgroup strategy for this set of KPIs
|
|
59
61
|
* @returns Expanded array of KPIs (styled or default, with stackgroups assigned)
|
|
60
62
|
*/
|
|
61
|
-
function expandKPIs(baseKPIs, cells, grouping, stylingConfig, stackGroupMode = 'none') {
|
|
63
|
+
function expandKPIs(baseKPIs, cells, grouping, colorDimension, stylingConfig, stackGroupMode = 'none') {
|
|
62
64
|
let expandedKPIs = [];
|
|
63
65
|
baseKPIs.forEach((baseKPI) => {
|
|
64
66
|
cells.forEach(([cellName, record]) => {
|
|
65
67
|
if (stylingConfig) {
|
|
66
68
|
// Apply custom styling (band colors, sector line styles)
|
|
67
|
-
const styledKPI = createStyledKPI(baseKPI.rawName, record, baseKPI.unit, grouping, stylingConfig);
|
|
69
|
+
const styledKPI = createStyledKPI(baseKPI.rawName, record, baseKPI.unit, grouping, colorDimension, stylingConfig);
|
|
68
70
|
expandedKPIs.push({
|
|
69
71
|
...styledKPI,
|
|
70
72
|
stackGroup: undefined // Initialize for treeshake-safe property assignment
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Public API exports for cell traffic KPI visualization
|
|
4
4
|
*/
|
|
5
5
|
export { default as SiteCheck } from './SiteCheck.svelte';
|
|
6
|
-
export { loadCellTrafficData, getUniqueSites, getUniqueCells, groupDataByCell, defaultTreeGrouping, type CellTrafficRecord, type TreeGroupingConfig, type TreeGroupField } from './data-loader.js';
|
|
6
|
+
export { loadCellTrafficData, getUniqueSites, getUniqueCells, groupDataByCell, defaultTreeGrouping, type CellTrafficRecord, type TreeGroupingConfig, type TreeGroupField, type ColorDimension } from './data-loader.js';
|
|
7
7
|
export { buildTreeNodes, filterChartData, transformChartData, createStyledKPI, extractBandFromCell, getBandFrequency, sortCellsByBandFrequency, assignStackGroups, createStackGroupId, type StackGroupMode } from './transforms.js';
|
|
8
8
|
export { expandLayoutForCells, extractBaseMetrics } from './helper.js';
|
|
9
9
|
export { defaultCellStyling } from './default-cell-styling.js';
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { TreeNode } from '../../core/TreeView';
|
|
6
6
|
import type { KPI, CellStylingConfig } from '../../core/Charts';
|
|
7
|
-
import type { CellTrafficRecord, TreeGroupingConfig } from './data-loader';
|
|
7
|
+
import type { CellTrafficRecord, TreeGroupingConfig, ColorDimension } from './data-loader';
|
|
8
8
|
/**
|
|
9
9
|
* Stackgroup mode types for dynamic stacking strategies
|
|
10
10
|
*/
|
|
@@ -75,11 +75,13 @@ export declare function transformChartData(data: CellTrafficRecord[], baseMetric
|
|
|
75
75
|
/**
|
|
76
76
|
* Create a styled KPI with band colors and sector line styles
|
|
77
77
|
* Label format adapts to tree grouping configuration
|
|
78
|
+
* Color assignment adapts to colorDimension selection
|
|
78
79
|
* @param metricName - Base metric name (e.g., 'DL_GBYTES')
|
|
79
80
|
* @param cellRecord - Cell traffic record with metadata
|
|
80
81
|
* @param unit - Unit string (e.g., 'GB', '%')
|
|
81
82
|
* @param grouping - Current tree grouping configuration (determines label format)
|
|
83
|
+
* @param colorDimension - Which field to use for coloring (site or band)
|
|
82
84
|
* @param stylingConfig - Optional styling configuration
|
|
83
85
|
* @returns KPI with cell-specific styling applied
|
|
84
86
|
*/
|
|
85
|
-
export declare function createStyledKPI(metricName: string, cellRecord: CellTrafficRecord, unit: string, grouping: TreeGroupingConfig, stylingConfig?: CellStylingConfig): KPI;
|
|
87
|
+
export declare function createStyledKPI(metricName: string, cellRecord: CellTrafficRecord, unit: string, grouping: TreeGroupingConfig, colorDimension: ColorDimension, stylingConfig?: CellStylingConfig): KPI;
|
|
@@ -154,7 +154,7 @@ export function sortCellsByBandFrequency(items) {
|
|
|
154
154
|
* @param data - Cell traffic records
|
|
155
155
|
* @param grouping - Tree grouping configuration (defaults to Site → Azimuth → Cell)
|
|
156
156
|
*/
|
|
157
|
-
export function buildTreeNodes(data, grouping = { level0: 'site', level1: 'azimuth'
|
|
157
|
+
export function buildTreeNodes(data, grouping = { level0: 'site', level1: 'azimuth' }) {
|
|
158
158
|
log('🔄 Building tree nodes', {
|
|
159
159
|
recordCount: data.length,
|
|
160
160
|
grouping,
|
|
@@ -441,20 +441,60 @@ export function transformChartData(data, baseMetrics) {
|
|
|
441
441
|
});
|
|
442
442
|
return pivotedData;
|
|
443
443
|
}
|
|
444
|
+
/**
|
|
445
|
+
* Generate a consistent color for a site name using a hash function
|
|
446
|
+
* Same site will always get the same color
|
|
447
|
+
* @param siteName - Site name to generate color for
|
|
448
|
+
* @returns Hex color string
|
|
449
|
+
*/
|
|
450
|
+
function generateSiteColor(siteName) {
|
|
451
|
+
// Modern color palette for sites
|
|
452
|
+
const siteColors = [
|
|
453
|
+
'#3B82F6', // Blue
|
|
454
|
+
'#EF4444', // Red
|
|
455
|
+
'#10B981', // Emerald
|
|
456
|
+
'#F59E0B', // Amber
|
|
457
|
+
'#8B5CF6', // Violet
|
|
458
|
+
'#06B6D4', // Cyan
|
|
459
|
+
'#F97316', // Orange
|
|
460
|
+
'#84CC16', // Lime
|
|
461
|
+
'#EC4899', // Pink
|
|
462
|
+
'#14B8A6', // Teal
|
|
463
|
+
'#F43F5E', // Rose
|
|
464
|
+
'#A855F7' // Purple
|
|
465
|
+
];
|
|
466
|
+
// Simple hash function for consistent color assignment
|
|
467
|
+
let hash = 0;
|
|
468
|
+
for (let i = 0; i < siteName.length; i++) {
|
|
469
|
+
hash = siteName.charCodeAt(i) + ((hash << 5) - hash);
|
|
470
|
+
}
|
|
471
|
+
hash = Math.abs(hash);
|
|
472
|
+
return siteColors[hash % siteColors.length];
|
|
473
|
+
}
|
|
444
474
|
/**
|
|
445
475
|
* Create a styled KPI with band colors and sector line styles
|
|
446
476
|
* Label format adapts to tree grouping configuration
|
|
477
|
+
* Color assignment adapts to colorDimension selection
|
|
447
478
|
* @param metricName - Base metric name (e.g., 'DL_GBYTES')
|
|
448
479
|
* @param cellRecord - Cell traffic record with metadata
|
|
449
480
|
* @param unit - Unit string (e.g., 'GB', '%')
|
|
450
481
|
* @param grouping - Current tree grouping configuration (determines label format)
|
|
482
|
+
* @param colorDimension - Which field to use for coloring (site or band)
|
|
451
483
|
* @param stylingConfig - Optional styling configuration
|
|
452
484
|
* @returns KPI with cell-specific styling applied
|
|
453
485
|
*/
|
|
454
|
-
export function createStyledKPI(metricName, cellRecord, unit, grouping, stylingConfig) {
|
|
486
|
+
export function createStyledKPI(metricName, cellRecord, unit, grouping, colorDimension, stylingConfig) {
|
|
455
487
|
const { band, sector, azimuth, cellName, siteName } = cellRecord;
|
|
456
|
-
//
|
|
457
|
-
|
|
488
|
+
// Determine color based on colorDimension
|
|
489
|
+
let color;
|
|
490
|
+
if (colorDimension === 'band') {
|
|
491
|
+
// Get color from band colors config
|
|
492
|
+
color = stylingConfig?.bandColors?.[band];
|
|
493
|
+
}
|
|
494
|
+
else if (colorDimension === 'site') {
|
|
495
|
+
// Generate consistent color for site
|
|
496
|
+
color = generateSiteColor(siteName);
|
|
497
|
+
}
|
|
458
498
|
// Get line style from sector (if config provided)
|
|
459
499
|
const lineStyle = stylingConfig?.sectorLineStyles?.[sector.toString()];
|
|
460
500
|
// Generate label based on tree grouping configuration
|
|
@@ -475,6 +515,7 @@ export function createStyledKPI(metricName, cellRecord, unit, grouping, stylingC
|
|
|
475
515
|
band,
|
|
476
516
|
sector,
|
|
477
517
|
azimuth,
|
|
518
|
+
colorDimension,
|
|
478
519
|
color,
|
|
479
520
|
lineStyle
|
|
480
521
|
});
|
|
@@ -483,14 +524,18 @@ export function createStyledKPI(metricName, cellRecord, unit, grouping, stylingC
|
|
|
483
524
|
/**
|
|
484
525
|
* Generate adaptive label based on tree grouping configuration
|
|
485
526
|
* Label exactly matches the complete tree path shown in the tree view
|
|
527
|
+
* Only includes levels that are not null in the grouping config
|
|
486
528
|
* @param record - Cell traffic record with all metadata
|
|
487
529
|
* @param grouping - Current tree grouping configuration
|
|
488
|
-
* @returns Formatted label string matching complete tree hierarchy (
|
|
530
|
+
* @returns Formatted label string matching complete tree hierarchy (only non-null levels)
|
|
489
531
|
*/
|
|
490
532
|
function generateAdaptiveLabel(record, grouping) {
|
|
491
533
|
const { level0, level1 } = grouping;
|
|
492
534
|
// Helper to format field values exactly as shown in tree
|
|
493
535
|
const formatField = (field, value) => {
|
|
536
|
+
if (field === 'cell') {
|
|
537
|
+
return value; // Cell name as-is
|
|
538
|
+
}
|
|
494
539
|
switch (field) {
|
|
495
540
|
case 'azimuth':
|
|
496
541
|
return `${value}°`;
|
|
@@ -506,6 +551,9 @@ function generateAdaptiveLabel(record, grouping) {
|
|
|
506
551
|
};
|
|
507
552
|
// Get field values from record
|
|
508
553
|
const getFieldValue = (field) => {
|
|
554
|
+
if (field === 'cell') {
|
|
555
|
+
return record.cellName;
|
|
556
|
+
}
|
|
509
557
|
switch (field) {
|
|
510
558
|
case 'site':
|
|
511
559
|
return record.siteName;
|
|
@@ -517,19 +565,16 @@ function generateAdaptiveLabel(record, grouping) {
|
|
|
517
565
|
return record.sector;
|
|
518
566
|
}
|
|
519
567
|
};
|
|
520
|
-
// Build label
|
|
521
|
-
const
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
}
|
|
528
|
-
else {
|
|
529
|
-
// 3-level tree: level0 → level1 → cell
|
|
530
|
-
// Show: level0 → level1 → cellName (e.g., "SiteA → 120° → AB12141")
|
|
531
|
-
const level0Value = formatField(level0, getFieldValue(level0));
|
|
532
|
-
const level1Value = formatField(level1, getFieldValue(level1));
|
|
533
|
-
return `${level0Value}_${level1Value}_${cellLabel}`;
|
|
568
|
+
// Build label parts only for non-null levels
|
|
569
|
+
const parts = [];
|
|
570
|
+
// Level 0 is always present
|
|
571
|
+
parts.push(formatField(level0, getFieldValue(level0)));
|
|
572
|
+
// Level 1 (optional)
|
|
573
|
+
if (level1 !== null) {
|
|
574
|
+
parts.push(formatField(level1, getFieldValue(level1)));
|
|
534
575
|
}
|
|
576
|
+
// Cell is always the final leaf node
|
|
577
|
+
parts.push(record.cellName);
|
|
578
|
+
// Join with arrow separator
|
|
579
|
+
return parts.join(' → ');
|
|
535
580
|
}
|