@smartnet360/svelte-components 0.0.115 → 0.0.116

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.
@@ -10,6 +10,7 @@
10
10
  RowSelectionEvent,
11
11
  RowClickEvent,
12
12
  RowDblClickEvent,
13
+ RowContextMenuEvent,
13
14
  DataChangeEvent
14
15
  } from './types';
15
16
  import {
@@ -34,6 +35,8 @@
34
35
  onrowclick?: (event: RowClickEvent) => void;
35
36
  /** Row double-click event */
36
37
  onrowdblclick?: (event: RowDblClickEvent) => void;
38
+ /** Row context menu (right-click) event */
39
+ onrowcontextmenu?: (event: RowContextMenuEvent) => void;
37
40
  /** Data change event (filter, sort, etc.) */
38
41
  ondatachange?: (event: DataChangeEvent) => void;
39
42
  }
@@ -58,6 +61,7 @@
58
61
  onselectionchange,
59
62
  onrowclick,
60
63
  onrowdblclick,
64
+ onrowcontextmenu,
61
65
  ondatachange
62
66
  }: Props = $props();
63
67
 
@@ -152,6 +156,16 @@
152
156
  }
153
157
  });
154
158
 
159
+ table.on('rowContext', (e, row) => {
160
+ if (onrowcontextmenu) {
161
+ (e as MouseEvent).preventDefault();
162
+ onrowcontextmenu({
163
+ row: (row as RowComponent).getData() as CellData,
164
+ event: e as MouseEvent
165
+ });
166
+ }
167
+ });
168
+
155
169
  table.on('rowSelectionChanged', (data, rows) => {
156
170
  if (onselectionchange) {
157
171
  const cellData = data as CellData[];
@@ -1,6 +1,6 @@
1
1
  import { TabulatorFull as Tabulator } from 'tabulator-tables';
2
2
  import 'tabulator-tables/dist/css/tabulator_bootstrap5.min.css';
3
- import type { CellTableProps, CellData, RowSelectionEvent, RowClickEvent, RowDblClickEvent, DataChangeEvent } from './types';
3
+ import type { CellTableProps, CellData, RowSelectionEvent, RowClickEvent, RowDblClickEvent, RowContextMenuEvent, DataChangeEvent } from './types';
4
4
  interface Props extends CellTableProps {
5
5
  /** Row selection change event */
6
6
  onselectionchange?: (event: RowSelectionEvent) => void;
@@ -8,6 +8,8 @@ interface Props extends CellTableProps {
8
8
  onrowclick?: (event: RowClickEvent) => void;
9
9
  /** Row double-click event */
10
10
  onrowdblclick?: (event: RowDblClickEvent) => void;
11
+ /** Row context menu (right-click) event */
12
+ onrowcontextmenu?: (event: RowContextMenuEvent) => void;
11
13
  /** Data change event (filter, sort, etc.) */
12
14
  ondatachange?: (event: DataChangeEvent) => void;
13
15
  }
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import CellTablePanel from './CellTablePanel.svelte';
3
- import type { CellTableGroupField, ColumnPreset, RowSelectionEvent } from './types';
3
+ import type { CellTableGroupField, ColumnPreset, RowSelectionEvent, CellData } from './types';
4
4
  import { generateCellsFromPreset, getGeneratorInfo, type GeneratorPreset } from '../../shared/demo';
5
5
 
6
6
  let datasetSize: GeneratorPreset = $state('small');
@@ -42,6 +42,29 @@
42
42
  console.log('Selection changed:', event.ids);
43
43
  }
44
44
 
45
+ // Context menu action handlers
46
+ function handleViewCell(cell: CellData) {
47
+ console.log('View cell:', cell.id, cell.cellName);
48
+ alert(`Viewing cell: ${cell.cellName}`);
49
+ }
50
+
51
+ function handleEditCell(cell: CellData) {
52
+ console.log('Edit cell:', cell.id, cell.cellName);
53
+ alert(`Edit cell: ${cell.cellName}`);
54
+ }
55
+
56
+ function handleDeleteCell(cell: CellData) {
57
+ console.log('Delete cell:', cell.id, cell.cellName);
58
+ if (confirm(`Delete cell ${cell.cellName}?`)) {
59
+ demoCells = demoCells.filter(c => c.id !== cell.id);
60
+ }
61
+ }
62
+
63
+ function handleShowOnMap(cell: CellData) {
64
+ console.log('Show on map:', cell.latitude, cell.longitude);
65
+ alert(`Show on map: ${cell.cellName}\nLat: ${cell.latitude}\nLon: ${cell.longitude}`);
66
+ }
67
+
45
68
  function regenerateData() {
46
69
  demoCells = generateCellsFromPreset(datasetSize);
47
70
  }
@@ -242,6 +265,28 @@
242
265
  </div>
243
266
  </div>
244
267
  {/snippet}
268
+
269
+ {#snippet contextMenu({ row, closeMenu })}
270
+ <div class="dropdown-menu show shadow-lg" style="min-width: 180px;">
271
+ <h6 class="dropdown-header text-truncate" style="max-width: 200px;">
272
+ <i class="bi bi-broadcast me-1"></i>{row.cellName}
273
+ </h6>
274
+ <div class="dropdown-divider"></div>
275
+ <button class="dropdown-item" onclick={() => { handleViewCell(row); closeMenu(); }}>
276
+ <i class="bi bi-eye me-2 text-primary"></i>View Details
277
+ </button>
278
+ <button class="dropdown-item" onclick={() => { handleEditCell(row); closeMenu(); }}>
279
+ <i class="bi bi-pencil me-2 text-warning"></i>Edit Cell
280
+ </button>
281
+ <button class="dropdown-item" onclick={() => { handleShowOnMap(row); closeMenu(); }}>
282
+ <i class="bi bi-geo-alt me-2 text-info"></i>Show on Map
283
+ </button>
284
+ <div class="dropdown-divider"></div>
285
+ <button class="dropdown-item text-danger" onclick={() => { handleDeleteCell(row); closeMenu(); }}>
286
+ <i class="bi bi-trash me-2"></i>Delete Cell
287
+ </button>
288
+ </div>
289
+ {/snippet}
245
290
  </CellTablePanel>
246
291
  </div>
247
292
  </div>
@@ -10,6 +10,7 @@
10
10
  RowSelectionEvent,
11
11
  RowClickEvent,
12
12
  RowDblClickEvent,
13
+ RowContextMenuEvent,
13
14
  DataChangeEvent,
14
15
  TechColorMap,
15
16
  StatusColorMap
@@ -68,6 +69,8 @@
68
69
  footer?: Snippet<[{ selectedRows: CellData[]; selectedCount: number }]>;
69
70
  /** Custom details sidebar content */
70
71
  detailsContent?: Snippet<[{ cell: CellData | null; closeSidebar: () => void }]>;
72
+ /** Custom context menu content (right-click on row) */
73
+ contextMenu?: Snippet<[{ row: CellData; closeMenu: () => void }]>;
71
74
  }
72
75
 
73
76
  let {
@@ -96,9 +99,15 @@
96
99
  headerSearch,
97
100
  headerActions,
98
101
  footer,
99
- detailsContent
102
+ detailsContent,
103
+ contextMenu
100
104
  }: Props = $props();
101
105
 
106
+ // Context menu state
107
+ let contextMenuVisible = $state(false);
108
+ let contextMenuRow: CellData | null = $state(null);
109
+ let contextMenuPosition = $state({ x: 0, y: 0 });
110
+
102
111
  // Storage keys
103
112
  const STORAGE_KEY_GROUP = `${storageKey}-groupBy`;
104
113
  const STORAGE_KEY_COLUMNS = `${storageKey}-visibleColumns`;
@@ -239,6 +248,26 @@
239
248
  updateScrollSpyGroups();
240
249
  }
241
250
 
251
+ function handleRowContextMenu(event: RowContextMenuEvent) {
252
+ if (contextMenu) {
253
+ contextMenuRow = event.row;
254
+ contextMenuPosition = { x: event.event.clientX, y: event.event.clientY };
255
+ contextMenuVisible = true;
256
+ }
257
+ }
258
+
259
+ function closeContextMenu() {
260
+ contextMenuVisible = false;
261
+ contextMenuRow = null;
262
+ }
263
+
264
+ function handleClickOutside(event: MouseEvent) {
265
+ const target = event.target as HTMLElement;
266
+ if (!target.closest('.context-menu-container')) {
267
+ closeContextMenu();
268
+ }
269
+ }
270
+
242
271
  function updateScrollSpyGroups() {
243
272
  if (scrollSpyEnabled && groupBy !== 'none') {
244
273
  // Small delay to ensure table has updated
@@ -477,6 +506,7 @@
477
506
  onselectionchange={handleSelectionChange}
478
507
  ondatachange={handleDataChange}
479
508
  onrowclick={handleRowClick}
509
+ onrowcontextmenu={handleRowContextMenu}
480
510
  {onrowdblclick}
481
511
  />
482
512
  </div>
@@ -617,8 +647,21 @@
617
647
  {@render footer({ selectedRows, selectedCount })}
618
648
  </div>
619
649
  {/if}
650
+
651
+ <!-- Context Menu (portal-like, fixed position) -->
652
+ {#if contextMenuVisible && contextMenuRow && contextMenu}
653
+ <div
654
+ class="context-menu-container"
655
+ style="position: fixed; left: {contextMenuPosition.x}px; top: {contextMenuPosition.y}px; z-index: 1050;"
656
+ >
657
+ {@render contextMenu({ row: contextMenuRow, closeMenu: closeContextMenu })}
658
+ </div>
659
+ {/if}
620
660
  </div>
621
661
 
662
+ <!-- Click outside handler -->
663
+ <svelte:window onclick={contextMenuVisible ? handleClickOutside : undefined} />
664
+
622
665
  <style>
623
666
  .cell-table-panel {
624
667
  background-color: var(--bs-body-bg, #fff);
@@ -694,4 +737,20 @@
694
737
  .scrollspy-badge:active {
695
738
  transform: translateY(0);
696
739
  }
740
+
741
+ /* Context menu styling */
742
+ .context-menu-container {
743
+ animation: contextMenuFadeIn 0.1s ease-out;
744
+ }
745
+
746
+ @keyframes contextMenuFadeIn {
747
+ from {
748
+ opacity: 0;
749
+ transform: scale(0.95);
750
+ }
751
+ to {
752
+ opacity: 1;
753
+ transform: scale(1);
754
+ }
755
+ }
697
756
  </style>
@@ -61,6 +61,11 @@ interface Props {
61
61
  cell: CellData | null;
62
62
  closeSidebar: () => void;
63
63
  }]>;
64
+ /** Custom context menu content (right-click on row) */
65
+ contextMenu?: Snippet<[{
66
+ row: CellData;
67
+ closeMenu: () => void;
68
+ }]>;
64
69
  }
65
70
  declare const CellTablePanel: import("svelte").Component<Props, {
66
71
  getSelectedRows: () => CellData[];
@@ -100,7 +100,8 @@
100
100
  { value: 'physical', label: 'Physical' },
101
101
  { value: 'network', label: 'Network' },
102
102
  { value: 'planning', label: 'Planning' },
103
- { value: 'compare', label: 'Compare (Atoll/Nwt)' }
103
+ { value: 'compare', label: 'Compare (Atoll/NW)' },
104
+ { value: 'kpi', label: 'KPI Trends' }
104
105
  ];
105
106
 
106
107
  function handleGroupChange(e: Event) {
@@ -61,6 +61,23 @@ export declare function heightFormatter(cell: CellComponent): string;
61
61
  * - Gray: one or both values missing
62
62
  */
63
63
  export declare function createCompareFormatter(atollField: string, nwtField: string): (cell: CellComponent) => string;
64
+ /**
65
+ * Creates a sparkline SVG formatter for KPI time-series data
66
+ * Renders a mini line chart showing trend over time
67
+ *
68
+ * @param options Configuration for the sparkline
69
+ */
70
+ export interface SparklineOptions {
71
+ width?: number;
72
+ height?: number;
73
+ lineColor?: string;
74
+ fillColor?: string;
75
+ showDots?: boolean;
76
+ showLastValue?: boolean;
77
+ unit?: string;
78
+ decimals?: number;
79
+ }
80
+ export declare function createSparklineFormatter(options?: SparklineOptions): (cell: CellComponent) => string;
64
81
  /**
65
82
  * Custom sorter for fband - extracts numeric portion and sorts numerically
66
83
  * Examples: LTE700 → 700, GSM900 → 900, LTE1800 → 1800, 5G-3500 → 3500
@@ -60,6 +60,7 @@ export const COLUMN_GROUPS = {
60
60
  atoll: ['atollET', 'atollPW', 'atollRS', 'atollBW'],
61
61
  position: ['latitude', 'longitude', 'siteLatitude', 'siteLongitude', 'dx', 'dy'],
62
62
  compare: ['compareET', 'comparePW', 'compareRS', 'compareBW'],
63
+ kpi: ['kpiTraffic', 'kpiThroughput', 'kpiAvailability', 'kpiSuccessRate'],
63
64
  };
64
65
  /**
65
66
  * Create a technology badge formatter
@@ -166,6 +167,55 @@ export function createCompareFormatter(atollField, nwtField) {
166
167
  return `<span class="badge" style="background-color: ${bgColor}; color: ${textColor}; font-size: 0.75rem; font-weight: normal;">${atollStr} | ${nwtStr}</span>`;
167
168
  };
168
169
  }
170
+ export function createSparklineFormatter(options = {}) {
171
+ const { width = 80, height = 24, lineColor = '#0d6efd', fillColor = 'rgba(13,110,253,0.2)', showDots = false, showLastValue = true, unit = '', decimals = 1 } = options;
172
+ return (cell) => {
173
+ const data = cell.getValue();
174
+ if (!data || !Array.isArray(data) || data.length === 0) {
175
+ return '<span class="text-muted">—</span>';
176
+ }
177
+ const values = data.filter(v => typeof v === 'number' && !isNaN(v));
178
+ if (values.length === 0) {
179
+ return '<span class="text-muted">—</span>';
180
+ }
181
+ const min = Math.min(...values);
182
+ const max = Math.max(...values);
183
+ const range = max - min || 1;
184
+ const padding = 2;
185
+ const chartWidth = showLastValue ? width - 35 : width - 4;
186
+ const chartHeight = height - 4;
187
+ // Generate SVG path
188
+ const points = values.map((v, i) => {
189
+ const x = padding + (i / (values.length - 1 || 1)) * (chartWidth - padding * 2);
190
+ const y = padding + (1 - (v - min) / range) * (chartHeight - padding * 2);
191
+ return { x, y, v };
192
+ });
193
+ // Line path
194
+ const linePath = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x.toFixed(1)} ${p.y.toFixed(1)}`).join(' ');
195
+ // Fill path (closed polygon)
196
+ const fillPath = `${linePath} L ${points[points.length - 1].x.toFixed(1)} ${chartHeight - padding} L ${padding} ${chartHeight - padding} Z`;
197
+ // Dots
198
+ const dots = showDots
199
+ ? points.map(p => `<circle cx="${p.x.toFixed(1)}" cy="${p.y.toFixed(1)}" r="1.5" fill="${lineColor}"/>`).join('')
200
+ : '';
201
+ // Last value text
202
+ const lastValue = values[values.length - 1];
203
+ const valueText = showLastValue
204
+ ? `<text x="${width - 2}" y="${height / 2 + 4}" text-anchor="end" font-size="10" fill="#333">${lastValue.toFixed(decimals)}${unit}</text>`
205
+ : '';
206
+ // Trend indicator (comparing last vs first)
207
+ const trend = values.length > 1 ? values[values.length - 1] - values[0] : 0;
208
+ const trendColor = trend >= 0 ? '#198754' : '#dc3545';
209
+ return `
210
+ <svg width="${width}" height="${height}" style="vertical-align: middle;">
211
+ <path d="${fillPath}" fill="${fillColor}" />
212
+ <path d="${linePath}" fill="none" stroke="${lineColor}" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
213
+ ${dots}
214
+ ${valueText}
215
+ </svg>
216
+ `.trim().replace(/\s+/g, ' ');
217
+ };
218
+ }
169
219
  /**
170
220
  * Custom sorter for fband - extracts numeric portion and sorts numerically
171
221
  * Examples: LTE700 → 700, GSM900 → 900, LTE1800 → 1800, 5G-3500 → 3500
@@ -455,6 +505,63 @@ export function getAllColumns(techColors = DEFAULT_TECH_COLORS, statusColors = D
455
505
  formatter: createCompareFormatter('atollBW', 'nwBW'),
456
506
  headerTooltip: 'Atoll BW | Network BW',
457
507
  },
508
+ // KPI Sparkline columns
509
+ {
510
+ title: 'Traffic',
511
+ field: 'kpiTraffic',
512
+ width: 120,
513
+ hozAlign: 'center',
514
+ formatter: createSparklineFormatter({
515
+ unit: '',
516
+ lineColor: '#0d6efd',
517
+ fillColor: 'rgba(13,110,253,0.15)',
518
+ decimals: 0
519
+ }),
520
+ headerTooltip: 'Traffic volume trend (GB)',
521
+ headerSort: false,
522
+ },
523
+ {
524
+ title: 'Throughput',
525
+ field: 'kpiThroughput',
526
+ width: 120,
527
+ hozAlign: 'center',
528
+ formatter: createSparklineFormatter({
529
+ unit: '',
530
+ lineColor: '#6f42c1',
531
+ fillColor: 'rgba(111,66,193,0.15)',
532
+ decimals: 1
533
+ }),
534
+ headerTooltip: 'Throughput trend (Mbps)',
535
+ headerSort: false,
536
+ },
537
+ {
538
+ title: 'Avail %',
539
+ field: 'kpiAvailability',
540
+ width: 120,
541
+ hozAlign: 'center',
542
+ formatter: createSparklineFormatter({
543
+ unit: '%',
544
+ lineColor: '#198754',
545
+ fillColor: 'rgba(25,135,84,0.15)',
546
+ decimals: 1
547
+ }),
548
+ headerTooltip: 'Availability trend (%)',
549
+ headerSort: false,
550
+ },
551
+ {
552
+ title: 'Success %',
553
+ field: 'kpiSuccessRate',
554
+ width: 120,
555
+ hozAlign: 'center',
556
+ formatter: createSparklineFormatter({
557
+ unit: '%',
558
+ lineColor: '#fd7e14',
559
+ fillColor: 'rgba(253,126,20,0.15)',
560
+ decimals: 1
561
+ }),
562
+ headerTooltip: 'Success rate trend (%)',
563
+ headerSort: false,
564
+ },
458
565
  // Position columns
459
566
  {
460
567
  title: 'Latitude',
@@ -549,6 +656,9 @@ export function getColumnsForPreset(preset, techColors = DEFAULT_TECH_COLORS, st
549
656
  case 'compare':
550
657
  visibleFields = [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.compare];
551
658
  break;
659
+ case 'kpi':
660
+ visibleFields = [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.kpi];
661
+ break;
552
662
  case 'default':
553
663
  default:
554
664
  visibleFields = [
@@ -621,6 +731,11 @@ export function getColumnMetadata() {
621
731
  { field: 'comparePW', title: 'Δ PW', group: 'Compare' },
622
732
  { field: 'compareRS', title: 'Δ RS', group: 'Compare' },
623
733
  { field: 'compareBW', title: 'Δ BW', group: 'Compare' },
734
+ // KPI Trends
735
+ { field: 'kpiTraffic', title: 'Traffic', group: 'KPI' },
736
+ { field: 'kpiThroughput', title: 'Throughput', group: 'KPI' },
737
+ { field: 'kpiAvailability', title: 'Availability', group: 'KPI' },
738
+ { field: 'kpiSuccessRate', title: 'Success Rate', group: 'KPI' },
624
739
  // Position
625
740
  { field: 'latitude', title: 'Latitude', group: 'Position' },
626
741
  { field: 'longitude', title: 'Longitude', group: 'Position' },
@@ -651,6 +766,8 @@ export function getPresetVisibleFields(preset) {
651
766
  return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.planning];
652
767
  case 'compare':
653
768
  return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.compare];
769
+ case 'kpi':
770
+ return [...COLUMN_GROUPS.core, ...COLUMN_GROUPS.kpi];
654
771
  case 'default':
655
772
  default:
656
773
  return ['siteId', 'txId', 'cellName', 'tech', 'fband', 'frq', 'status', 'azimuth', 'height', 'antenna'];
@@ -9,5 +9,5 @@ export { default as CellTablePanel } from './CellTablePanel.svelte';
9
9
  export { default as CellTableDemo } from './CellTableDemo.svelte';
10
10
  export { default as ColumnPicker } from './ColumnPicker.svelte';
11
11
  export { generateCells, generateCellsFromPreset, getGeneratorInfo, GENERATOR_PRESETS, type CellGeneratorConfig, type GeneratorPreset } from '../../shared/demo';
12
- export type { CellData, CellTableGroupField, ColumnPreset, ColumnVisibility, TechColorMap, StatusColorMap, CellTableProps, RowSelectionEvent, RowClickEvent, RowDblClickEvent, DataChangeEvent, CellTableColumn, ColumnGroups } from './types';
12
+ export type { CellData, CellTableGroupField, ColumnPreset, ColumnVisibility, TechColorMap, StatusColorMap, CellTableProps, RowSelectionEvent, RowClickEvent, RowDblClickEvent, RowContextMenuEvent, DataChangeEvent, CellTableColumn, ColumnGroups } from './types';
13
13
  export { DEFAULT_TECH_COLORS, DEFAULT_STATUS_COLORS, FBAND_COLORS, COLUMN_GROUPS, getAllColumns, getColumnsForPreset, getGroupHeaderFormatter, getColumnMetadata, getPresetVisibleFields, fbandSorter, cellNameSectorSorter, cellDataSorter, createTechFormatter, createStatusFormatter, createFbandFormatter, numberFormatter, coordinateFormatter, azimuthFormatter, heightFormatter, type ColumnMeta } from './column-config';
@@ -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' | 'compare';
19
+ export type ColumnPreset = 'default' | 'compact' | 'full' | 'physical' | 'network' | 'planning' | 'compare' | 'kpi';
20
20
  /**
21
21
  * Column visibility configuration
22
22
  */
@@ -93,6 +93,13 @@ export interface RowDblClickEvent {
93
93
  row: CellData;
94
94
  event: MouseEvent;
95
95
  }
96
+ /**
97
+ * Row context menu (right-click) event data
98
+ */
99
+ export interface RowContextMenuEvent {
100
+ row: CellData;
101
+ event: MouseEvent;
102
+ }
96
103
  /**
97
104
  * Data change event data
98
105
  */
@@ -123,4 +130,5 @@ export interface ColumnGroups {
123
130
  atoll: string[];
124
131
  position: string[];
125
132
  compare: string[];
133
+ kpi: string[];
126
134
  }
@@ -4,6 +4,21 @@
4
4
  * Generates realistic cell network data with configurable parameters.
5
5
  * Supports density zones, multiple technologies, and various site configurations.
6
6
  */
7
+ /**
8
+ * Generate mock KPI time-series data
9
+ * Creates an array of values with realistic variation
10
+ */
11
+ function generateMockKpiData(days, min, max, random) {
12
+ const data = [];
13
+ let current = min + random() * (max - min);
14
+ for (let i = 0; i < days; i++) {
15
+ // Add some realistic variation (±10%)
16
+ const variation = (random() - 0.5) * 0.2 * (max - min);
17
+ current = Math.max(min, Math.min(max, current + variation));
18
+ data.push(Math.round(current * 10) / 10);
19
+ }
20
+ return data;
21
+ }
7
22
  /**
8
23
  * Preset configurations
9
24
  */
@@ -211,6 +226,11 @@ export function generateCells(config) {
211
226
  pci: cellCounter % 504,
212
227
  nwRS: 450.0,
213
228
  nwBW: 10.0,
229
+ // KPI time-series mock data (7 days)
230
+ kpiTraffic: generateMockKpiData(7, 50, 200, random),
231
+ kpiThroughput: generateMockKpiData(7, 20, 80, random),
232
+ kpiAvailability: generateMockKpiData(7, 95, 100, random),
233
+ kpiSuccessRate: generateMockKpiData(7, 90, 100, random),
214
234
  other: {
215
235
  city: ['Tehran', 'Shiraz', 'Isfahan', 'Mashhad', 'Tabriz'][siteNum % 5],
216
236
  bcc: bandIndex % 8,
@@ -45,6 +45,10 @@ export interface Cell {
45
45
  nwBW?: number;
46
46
  pci?: number;
47
47
  rru: string;
48
+ kpiTraffic?: number[];
49
+ kpiThroughput?: number[];
50
+ kpiAvailability?: number[];
51
+ kpiSuccessRate?: number[];
48
52
  other?: Record<string, unknown>;
49
53
  customSubgroup: string;
50
54
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartnet360/svelte-components",
3
- "version": "0.0.115",
3
+ "version": "0.0.116",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",