@smartnet360/svelte-components 0.0.58 → 0.0.60
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/map-v2/demo/demo-cells.d.ts +4 -3
- package/dist/map-v2/demo/demo-cells.js +85 -67
- package/dist/map-v2/features/cells/controls/CellFilterControl.svelte +26 -0
- package/dist/map-v2/features/cells/layers/CellsLayer.svelte +57 -10
- package/dist/map-v2/features/cells/utils/cellTree.js +68 -11
- package/package.json +1 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Demo Cell Data
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 100 sites across San Francisco Bay Area
|
|
5
|
+
* Each site has 3 sectors (azimuths: 0°, 120°, 240°)
|
|
5
6
|
* Each sector has 12 cells (all tech-band combinations)
|
|
6
|
-
* Total:
|
|
7
|
+
* Total: 100 sites × 3 sectors × 12 tech-bands = 3,600 cells
|
|
7
8
|
*/
|
|
8
9
|
import type { Cell } from '../features/cells/types';
|
|
9
10
|
/**
|
|
10
|
-
* Generate demo cells: 3 sectors × 12 tech-bands =
|
|
11
|
+
* Generate demo cells: 100 sites × 3 sectors × 12 tech-bands = 3,600 cells
|
|
11
12
|
*/
|
|
12
13
|
export declare const demoCells: Cell[];
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Demo Cell Data
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 100 sites across San Francisco Bay Area
|
|
5
|
+
* Each site has 3 sectors (azimuths: 0°, 120°, 240°)
|
|
5
6
|
* Each sector has 12 cells (all tech-band combinations)
|
|
6
|
-
* Total:
|
|
7
|
+
* Total: 100 sites × 3 sectors × 12 tech-bands = 3,600 cells
|
|
7
8
|
*/
|
|
8
|
-
//
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
9
|
+
// Base location: San Francisco
|
|
10
|
+
const BASE_LAT = 37.7749;
|
|
11
|
+
const BASE_LNG = -122.4194;
|
|
12
|
+
// Grid parameters for distributing sites
|
|
13
|
+
const NUM_SITES = 1;
|
|
14
|
+
const GRID_SIZE = 10; // 10×10 grid
|
|
15
|
+
const LAT_SPACING = 0.01; // ~1.1 km spacing
|
|
16
|
+
const LNG_SPACING = 0.015; // ~1.1 km spacing (adjusted for longitude)
|
|
12
17
|
// Standard beamwidth for sectors
|
|
13
18
|
const BEAMWIDTH = 65;
|
|
14
19
|
// Cell tech-band definitions with proper fband format
|
|
@@ -46,69 +51,82 @@ const STATUSES = [
|
|
|
46
51
|
'On_Air'
|
|
47
52
|
];
|
|
48
53
|
/**
|
|
49
|
-
* Generate demo cells: 3 sectors × 12 tech-bands =
|
|
54
|
+
* Generate demo cells: 100 sites × 3 sectors × 12 tech-bands = 3,600 cells
|
|
50
55
|
*/
|
|
51
56
|
export const demoCells = [];
|
|
52
57
|
let cellCounter = 1;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
58
|
+
// Generate sites in a grid pattern
|
|
59
|
+
for (let siteIndex = 0; siteIndex < NUM_SITES; siteIndex++) {
|
|
60
|
+
const row = Math.floor(siteIndex / GRID_SIZE);
|
|
61
|
+
const col = siteIndex % GRID_SIZE;
|
|
62
|
+
// Calculate site position (centered grid around base location)
|
|
63
|
+
const siteLat = BASE_LAT + (row - GRID_SIZE / 2) * LAT_SPACING;
|
|
64
|
+
const siteLng = BASE_LNG + (col - GRID_SIZE / 2) * LNG_SPACING;
|
|
65
|
+
const siteId = `DEMO-SITE-${String(siteIndex + 1).padStart(3, '0')}`;
|
|
66
|
+
// Generate 3 sectors per site
|
|
67
|
+
AZIMUTHS.forEach((azimuth, sectorIndex) => {
|
|
68
|
+
// Generate 12 tech-bands per sector
|
|
69
|
+
TECH_BANDS.forEach((techBand, techIndex) => {
|
|
70
|
+
const cellId = `CELL-${String(cellCounter).padStart(4, '0')}`;
|
|
71
|
+
const status = STATUSES[techIndex];
|
|
72
|
+
demoCells.push({
|
|
73
|
+
// Core properties
|
|
74
|
+
id: cellId,
|
|
75
|
+
txId: `TX-${String(cellCounter).padStart(4, '0')}`,
|
|
76
|
+
cellID: cellId,
|
|
77
|
+
cellID2G: techBand.tech === '2G' ? cellId : '',
|
|
78
|
+
cellName: `${siteId} ${techBand.tech}${techBand.band} S${sectorIndex + 1}`,
|
|
79
|
+
siteId: siteId,
|
|
80
|
+
tech: techBand.tech,
|
|
81
|
+
fband: techBand.fband,
|
|
82
|
+
frq: techBand.band,
|
|
83
|
+
type: 'MACRO',
|
|
84
|
+
status: status,
|
|
85
|
+
onAirDate: '2024-01-15',
|
|
86
|
+
// 2G specific
|
|
87
|
+
bcch: techBand.tech === '2G' ? 100 + techIndex : 0,
|
|
88
|
+
ctrlid: techBand.tech === '2G' ? `CTRL-${cellId}` : '',
|
|
89
|
+
// 4G specific
|
|
90
|
+
dlEarfn: techBand.tech === '4G' ? 6200 + techIndex * 100 : 0,
|
|
91
|
+
// Physical properties
|
|
92
|
+
antenna: 'DEMO-ANTENNA-MODEL',
|
|
93
|
+
azimuth: azimuth,
|
|
94
|
+
height: 30, // 30 meters antenna height
|
|
95
|
+
electricalTilt: '3',
|
|
96
|
+
beamwidth: BEAMWIDTH,
|
|
97
|
+
latitude: siteLat,
|
|
98
|
+
longitude: siteLng,
|
|
99
|
+
dx: 0,
|
|
100
|
+
dy: 0,
|
|
101
|
+
siteLatitude: siteLat,
|
|
102
|
+
siteLongitude: siteLng,
|
|
103
|
+
// Planning
|
|
104
|
+
comment: `Demo ${techBand.tech} ${techBand.band} cell at azimuth ${azimuth}°`,
|
|
105
|
+
planner: 'Demo User',
|
|
106
|
+
// Atoll properties
|
|
107
|
+
atollETP: 43.0,
|
|
108
|
+
atollPW: 20.0,
|
|
109
|
+
atollRS: 500.0 + (techBand.band === '700' ? 200 : 0), // Lower freq = longer range
|
|
110
|
+
atollBW: parseFloat(techBand.band) / 100, // Simplified bandwidth
|
|
111
|
+
// Network properties
|
|
112
|
+
cellId3: `${cellId}-3G`,
|
|
113
|
+
nwtP1: 20,
|
|
114
|
+
nwtP2: 40,
|
|
115
|
+
pci1: (cellCounter % 504), // Physical Cell ID for LTE
|
|
116
|
+
nwtRS: 450.0,
|
|
117
|
+
nwtBW: 10.0,
|
|
118
|
+
// Other
|
|
119
|
+
other: {
|
|
120
|
+
demoCell: true,
|
|
121
|
+
siteNumber: siteIndex + 1,
|
|
122
|
+
sector: sectorIndex + 1,
|
|
123
|
+
techBandKey: `${techBand.tech}_${techBand.band}`,
|
|
124
|
+
gridPosition: { row, col }
|
|
125
|
+
},
|
|
126
|
+
customSubgroup: `Sector-${sectorIndex + 1}`
|
|
127
|
+
});
|
|
128
|
+
cellCounter++;
|
|
110
129
|
});
|
|
111
|
-
cellCounter++;
|
|
112
130
|
});
|
|
113
|
-
}
|
|
114
|
-
console.log(`Generated ${demoCells.length} demo cells across ${AZIMUTHS.length} sectors`);
|
|
131
|
+
}
|
|
132
|
+
console.log(`Generated ${demoCells.length} demo cells across ${NUM_SITES} sites (${AZIMUTHS.length} sectors × ${TECH_BANDS.length} tech-bands per site)`);
|
|
@@ -56,10 +56,36 @@
|
|
|
56
56
|
let level1 = $state<Exclude<CellGroupingField, 'none'>>(store.groupingConfig.level1);
|
|
57
57
|
let level2 = $state<CellGroupingField>(store.groupingConfig.level2);
|
|
58
58
|
|
|
59
|
+
// Track config for localStorage invalidation
|
|
60
|
+
const STORAGE_CONFIG_KEY = 'cellular-cell-filter:config';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Check if grouping config has changed and clear localStorage if needed
|
|
64
|
+
*/
|
|
65
|
+
function validateStoredConfig() {
|
|
66
|
+
const storedConfigStr = localStorage.getItem(STORAGE_CONFIG_KEY);
|
|
67
|
+
const currentConfig = `${level1}:${level2}`;
|
|
68
|
+
|
|
69
|
+
if (storedConfigStr !== currentConfig) {
|
|
70
|
+
console.log('CellFilterControl: Config changed, clearing tree state', {
|
|
71
|
+
stored: storedConfigStr,
|
|
72
|
+
current: currentConfig
|
|
73
|
+
});
|
|
74
|
+
// Clear tree state from localStorage
|
|
75
|
+
localStorage.removeItem('cellular-cell-filter:checked');
|
|
76
|
+
localStorage.removeItem('cellular-cell-filter:expanded');
|
|
77
|
+
// Save new config
|
|
78
|
+
localStorage.setItem(STORAGE_CONFIG_KEY, currentConfig);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
59
82
|
// Rebuild tree when grouping config or cells change
|
|
60
83
|
function rebuildTree() {
|
|
61
84
|
if (store.cells.length === 0) return;
|
|
62
85
|
|
|
86
|
+
// Validate and clear stale localStorage
|
|
87
|
+
validateStoredConfig();
|
|
88
|
+
|
|
63
89
|
console.log('CellFilterControl: Building tree with config:', { level1, level2 });
|
|
64
90
|
|
|
65
91
|
const treeNodes = buildCellTree(
|
|
@@ -34,12 +34,28 @@
|
|
|
34
34
|
|
|
35
35
|
let map = $state<MapboxMap | null>(null);
|
|
36
36
|
let mounted = $state(false);
|
|
37
|
+
let viewportUpdateTimer: ReturnType<typeof setTimeout> | null = null;
|
|
38
|
+
let viewportVersion = $state(0); // Increment this to force $effect re-run on viewport changes
|
|
37
39
|
|
|
38
|
-
//
|
|
39
|
-
function
|
|
40
|
+
// Viewport change handler (pan/zoom/move) with debouncing
|
|
41
|
+
function handleMoveEnd() {
|
|
40
42
|
if (!map) return;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
|
|
44
|
+
// Clear any existing timer
|
|
45
|
+
if (viewportUpdateTimer) {
|
|
46
|
+
clearTimeout(viewportUpdateTimer);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Debounce: wait 200ms after last move event before re-rendering
|
|
50
|
+
viewportUpdateTimer = setTimeout(() => {
|
|
51
|
+
if (!map) return;
|
|
52
|
+
const newZoom = map.getZoom();
|
|
53
|
+
console.log('CellsLayer: Viewport changed (zoom/pan), updating to zoom:', newZoom);
|
|
54
|
+
// Update zoom if changed
|
|
55
|
+
store.setCurrentZoom(newZoom);
|
|
56
|
+
// Force $effect to re-run by incrementing version (triggers on pan without zoom change)
|
|
57
|
+
viewportVersion++;
|
|
58
|
+
}, 200);
|
|
43
59
|
}
|
|
44
60
|
|
|
45
61
|
onMount(() => {
|
|
@@ -55,8 +71,8 @@
|
|
|
55
71
|
// Set initial zoom
|
|
56
72
|
store.setCurrentZoom(mapInstance.getZoom());
|
|
57
73
|
|
|
58
|
-
// Listen to zoom
|
|
59
|
-
mapInstance.on('
|
|
74
|
+
// Listen to viewport changes (pan + zoom, debounced)
|
|
75
|
+
mapInstance.on('moveend', handleMoveEnd);
|
|
60
76
|
}
|
|
61
77
|
});
|
|
62
78
|
|
|
@@ -68,7 +84,12 @@
|
|
|
68
84
|
onDestroy(() => {
|
|
69
85
|
if (!map) return;
|
|
70
86
|
|
|
71
|
-
|
|
87
|
+
// Clean up timer
|
|
88
|
+
if (viewportUpdateTimer) {
|
|
89
|
+
clearTimeout(viewportUpdateTimer);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
map.off('moveend', handleMoveEnd);
|
|
72
93
|
|
|
73
94
|
// Clean up layers and source
|
|
74
95
|
if (map.getLayer(LINE_LAYER_ID)) {
|
|
@@ -84,13 +105,17 @@
|
|
|
84
105
|
|
|
85
106
|
// Reactive: Update GeoJSON when cells/zoom/filters/settings change
|
|
86
107
|
$effect(() => {
|
|
108
|
+
// Track viewportVersion to force re-run on pan (even without zoom change)
|
|
109
|
+
viewportVersion;
|
|
110
|
+
|
|
87
111
|
console.log('CellsLayer $effect triggered:', {
|
|
88
112
|
mounted,
|
|
89
113
|
hasMap: !!map,
|
|
90
114
|
showCells: store.showCells,
|
|
91
115
|
filteredCellsCount: store.filteredCells.length,
|
|
92
116
|
currentZoom: store.currentZoom,
|
|
93
|
-
baseRadius: store.baseRadius
|
|
117
|
+
baseRadius: store.baseRadius,
|
|
118
|
+
viewportVersion
|
|
94
119
|
});
|
|
95
120
|
|
|
96
121
|
if (!mounted || !map || !store.showCells) {
|
|
@@ -110,9 +135,31 @@
|
|
|
110
135
|
return;
|
|
111
136
|
}
|
|
112
137
|
|
|
113
|
-
//
|
|
138
|
+
// Filter cells by viewport bounds (only render visible cells)
|
|
139
|
+
const bounds = map.getBounds();
|
|
140
|
+
if (!bounds) {
|
|
141
|
+
console.warn('CellsLayer: Cannot get map bounds, skipping viewport filter');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const visibleCells = store.filteredCells.filter(cell =>
|
|
146
|
+
bounds.contains([cell.longitude, cell.latitude])
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
console.log('CellsLayer: Viewport filtering:', {
|
|
150
|
+
totalFiltered: store.filteredCells.length,
|
|
151
|
+
visibleInViewport: visibleCells.length,
|
|
152
|
+
bounds: {
|
|
153
|
+
north: bounds.getNorth(),
|
|
154
|
+
south: bounds.getSouth(),
|
|
155
|
+
east: bounds.getEast(),
|
|
156
|
+
west: bounds.getWest()
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Generate GeoJSON from visible cells only
|
|
114
161
|
const geoJSON = cellsToGeoJSON(
|
|
115
|
-
|
|
162
|
+
visibleCells,
|
|
116
163
|
store.currentZoom,
|
|
117
164
|
store.baseRadius,
|
|
118
165
|
store.groupColorMap
|
|
@@ -71,12 +71,22 @@ function generateNodeId(field, value, parentId) {
|
|
|
71
71
|
*/
|
|
72
72
|
export function buildCellTree(cells, config, colorMap) {
|
|
73
73
|
const { level1, level2 } = config;
|
|
74
|
+
console.log('=== buildCellTree START ===');
|
|
75
|
+
console.log('Config:', { level1, level2 });
|
|
76
|
+
console.log('Total cells:', cells.length);
|
|
74
77
|
// If level2 is 'none', create flat 2-level tree
|
|
75
78
|
if (level2 === 'none') {
|
|
76
|
-
|
|
79
|
+
console.log('Building flat tree (2-level)');
|
|
80
|
+
const tree = buildFlatTree(cells, level1, colorMap);
|
|
81
|
+
console.log('Flat tree built, root children:', tree.children?.length);
|
|
82
|
+
return tree;
|
|
77
83
|
}
|
|
78
84
|
// Otherwise, create nested 3-level tree
|
|
79
|
-
|
|
85
|
+
console.log('Building nested tree (3-level)');
|
|
86
|
+
const tree = buildNestedTree(cells, level1, level2, colorMap);
|
|
87
|
+
console.log('Nested tree built, root children:', tree.children?.length);
|
|
88
|
+
console.log('=== buildCellTree END ===');
|
|
89
|
+
return tree;
|
|
80
90
|
}
|
|
81
91
|
/**
|
|
82
92
|
* Build flat 2-level tree (Root → Level1 groups)
|
|
@@ -97,6 +107,8 @@ function buildFlatTree(cells, level1, colorMap) {
|
|
|
97
107
|
const children = sortedGroups.map(([value, groupCells]) => {
|
|
98
108
|
const nodeId = generateNodeId(level1, value);
|
|
99
109
|
const color = colorMap?.get(nodeId);
|
|
110
|
+
const cellIds = groupCells.map((c) => c.id);
|
|
111
|
+
console.log(` Flat tree node: id="${nodeId}", cells=${cellIds.length}, cellIds sample:`, cellIds.slice(0, 3));
|
|
100
112
|
return {
|
|
101
113
|
id: nodeId,
|
|
102
114
|
label: getGroupLabel(level1, value, groupCells.length),
|
|
@@ -106,7 +118,7 @@ function buildFlatTree(cells, level1, colorMap) {
|
|
|
106
118
|
type: 'leafGroup',
|
|
107
119
|
groupingField: level1,
|
|
108
120
|
groupingValue: value,
|
|
109
|
-
cellIds
|
|
121
|
+
cellIds,
|
|
110
122
|
color
|
|
111
123
|
}
|
|
112
124
|
};
|
|
@@ -149,6 +161,8 @@ function buildNestedTree(cells, level1, level2, colorMap) {
|
|
|
149
161
|
const level2Children = sortedLevel2.map(([value2, groupCells]) => {
|
|
150
162
|
const nodeId = generateNodeId(level2, value2, parentId);
|
|
151
163
|
const color = colorMap?.get(nodeId);
|
|
164
|
+
const cellIds = groupCells.map((c) => c.id);
|
|
165
|
+
console.log(` Nested tree leaf: id="${nodeId}", cells=${cellIds.length}, cellIds sample:`, cellIds.slice(0, 3));
|
|
152
166
|
return {
|
|
153
167
|
id: nodeId,
|
|
154
168
|
label: getGroupLabel(level2, value2, groupCells.length),
|
|
@@ -160,13 +174,14 @@ function buildNestedTree(cells, level1, level2, colorMap) {
|
|
|
160
174
|
groupingValue: value2,
|
|
161
175
|
parentGroupingField: level1,
|
|
162
176
|
parentGroupingValue: value1,
|
|
163
|
-
cellIds
|
|
177
|
+
cellIds,
|
|
164
178
|
color
|
|
165
179
|
}
|
|
166
180
|
};
|
|
167
181
|
});
|
|
168
182
|
// Calculate total cells in this level1 group
|
|
169
183
|
const totalCells = Array.from(level2Groups.values()).flat().length;
|
|
184
|
+
console.log(` Nested tree parent: id="${parentId}", totalCells=${totalCells}, children=${level2Children.length}`);
|
|
170
185
|
return {
|
|
171
186
|
id: parentId,
|
|
172
187
|
label: getGroupLabel(level1, value1, totalCells),
|
|
@@ -197,30 +212,72 @@ function buildNestedTree(cells, level1, level2, colorMap) {
|
|
|
197
212
|
* @returns Filtered array of cells
|
|
198
213
|
*/
|
|
199
214
|
export function getFilteredCells(checkedPaths, allCells) {
|
|
215
|
+
console.log('=== getFilteredCells START ===');
|
|
216
|
+
console.log('Checked paths:', Array.from(checkedPaths));
|
|
217
|
+
console.log('Total cells:', allCells.length);
|
|
200
218
|
// If root is checked (or no specific filters), return all cells
|
|
201
219
|
if (checkedPaths.has('root') && checkedPaths.size === 1) {
|
|
220
|
+
console.log('Root only checked, returning all cells');
|
|
202
221
|
return allCells;
|
|
203
222
|
}
|
|
223
|
+
// Sample first 3 cells for detailed logging
|
|
224
|
+
const sampleSize = 3;
|
|
225
|
+
let processedCount = 0;
|
|
204
226
|
// Filter cells that match any of the checked paths
|
|
205
227
|
const filtered = allCells.filter((cell) => {
|
|
228
|
+
const shouldLog = processedCount < sampleSize;
|
|
229
|
+
if (shouldLog) {
|
|
230
|
+
console.log(`\n--- Sample Cell ${processedCount + 1}: ${cell.id} ---`);
|
|
231
|
+
console.log(` Properties: tech="${cell.tech}", frq="${cell.frq}", status="${cell.status}"`);
|
|
232
|
+
}
|
|
206
233
|
// Check if this cell belongs to any checked path
|
|
207
|
-
|
|
234
|
+
const matched = Array.from(checkedPaths).some((path) => {
|
|
208
235
|
// Match cell properties against path segments
|
|
209
|
-
if (path === 'root')
|
|
236
|
+
if (path === 'root') {
|
|
237
|
+
if (shouldLog)
|
|
238
|
+
console.log(` Path "root": MATCH`);
|
|
210
239
|
return true;
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
240
|
+
}
|
|
241
|
+
// Parse path and filter out "root" prefix and deduplicate consecutive segments
|
|
242
|
+
const allSegments = path.split(':');
|
|
243
|
+
// Remove "root" and deduplicate consecutive segments
|
|
244
|
+
const segments = [];
|
|
245
|
+
let prevSegment = '';
|
|
246
|
+
for (const segment of allSegments) {
|
|
247
|
+
if (segment !== 'root' && segment !== prevSegment) {
|
|
248
|
+
segments.push(segment);
|
|
249
|
+
prevSegment = segment;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (shouldLog) {
|
|
253
|
+
console.log(` Checking path "${path}" (raw: [${allSegments.join(', ')}], filtered: [${segments.join(', ')}])`);
|
|
254
|
+
}
|
|
255
|
+
// Match filtered segments against cell properties
|
|
256
|
+
const segmentMatches = segments.every((segment) => {
|
|
257
|
+
const matches = (cell.tech === segment ||
|
|
216
258
|
cell.frq === segment ||
|
|
217
259
|
cell.status === segment ||
|
|
218
260
|
cell.siteId === segment ||
|
|
219
261
|
cell.customSubgroup === segment ||
|
|
220
262
|
cell.type === segment ||
|
|
221
263
|
cell.planner === segment);
|
|
264
|
+
if (shouldLog) {
|
|
265
|
+
console.log(` Segment "${segment}": ${matches ? '✓ MATCH' : '✗ NO MATCH'}`);
|
|
266
|
+
}
|
|
267
|
+
return matches;
|
|
222
268
|
});
|
|
269
|
+
if (shouldLog) {
|
|
270
|
+
console.log(` Path "${path}": ${segmentMatches ? '✓ MATCHED' : '✗ NOT MATCHED'}`);
|
|
271
|
+
}
|
|
272
|
+
return segmentMatches;
|
|
223
273
|
});
|
|
274
|
+
if (shouldLog) {
|
|
275
|
+
console.log(` Final result: ${matched ? '✓ INCLUDE' : '✗ EXCLUDE'}`);
|
|
276
|
+
}
|
|
277
|
+
processedCount++;
|
|
278
|
+
return matched;
|
|
224
279
|
});
|
|
280
|
+
console.log(`\nFiltered result: ${filtered.length} of ${allCells.length} cells`);
|
|
281
|
+
console.log('=== getFilteredCells END ===\n');
|
|
225
282
|
return filtered;
|
|
226
283
|
}
|