@smartnet360/svelte-components 0.0.60 → 0.0.62

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.
@@ -64,13 +64,9 @@
64
64
  */
65
65
  function validateStoredConfig() {
66
66
  const storedConfigStr = localStorage.getItem(STORAGE_CONFIG_KEY);
67
- const currentConfig = `${level1}:${level2}`;
67
+ const currentConfig = `${level1}:${level2}:${store.includePlannedCells}`;
68
68
 
69
69
  if (storedConfigStr !== currentConfig) {
70
- console.log('CellFilterControl: Config changed, clearing tree state', {
71
- stored: storedConfigStr,
72
- current: currentConfig
73
- });
74
70
  // Clear tree state from localStorage
75
71
  localStorage.removeItem('cellular-cell-filter:checked');
76
72
  localStorage.removeItem('cellular-cell-filter:expanded');
@@ -81,15 +77,13 @@
81
77
 
82
78
  // Rebuild tree when grouping config or cells change
83
79
  function rebuildTree() {
84
- if (store.cells.length === 0) return;
80
+ if (store.cellsFilteredByStatus.length === 0) return;
85
81
 
86
82
  // Validate and clear stale localStorage
87
83
  validateStoredConfig();
88
84
 
89
- console.log('CellFilterControl: Building tree with config:', { level1, level2 });
90
-
91
85
  const treeNodes = buildCellTree(
92
- store.cells,
86
+ store.cellsFilteredByStatus, // Use filtered cells, not all cells
93
87
  { level1, level2 },
94
88
  store.groupColorMap
95
89
  );
@@ -102,18 +96,14 @@
102
96
  defaultExpandAll: false
103
97
  });
104
98
 
105
- console.log('CellFilterControl: Tree store created');
106
-
107
99
  // Subscribe to tree changes and update filtered cells
108
100
  if (treeStore) {
109
101
  const unsub = treeStore.subscribe((treeValue: TreeStoreValue) => {
110
102
  const checkedPaths = treeValue.getCheckedPaths();
111
- console.log('TreeStore updated, checked paths:', checkedPaths.length);
112
103
 
113
104
  // Convert string[] to Set<string>
114
105
  const checkedPathsSet = new Set(checkedPaths);
115
- const newFilteredCells = getFilteredCells(checkedPathsSet, store.cells);
116
- console.log('Filtered cells count:', newFilteredCells.length, 'of', store.cells.length);
106
+ const newFilteredCells = getFilteredCells(checkedPathsSet, store.cellsFilteredByStatus); // Use filtered cells
117
107
 
118
108
  // Update the cell store directly
119
109
  store.setFilteredCells(newFilteredCells);
@@ -124,10 +114,17 @@
124
114
  }
125
115
 
126
116
  onMount(() => {
127
- console.log('CellFilterControl: Mounted with', store.cells.length, 'cells');
128
117
  rebuildTree();
129
118
  });
130
119
 
120
+ // Handle includePlannedCells checkbox change
121
+ function handleIncludePlannedChange(event: Event) {
122
+ const target = event.currentTarget as HTMLInputElement;
123
+ store.setIncludePlannedCells(target.checked);
124
+ // Rebuild tree with new filtered cells
125
+ rebuildTree();
126
+ }
127
+
131
128
  // Handle grouping config changes
132
129
  function handleLevel1Change(event: Event) {
133
130
  const target = event.currentTarget as HTMLSelectElement;
@@ -170,34 +167,57 @@
170
167
 
171
168
  <MapControl {position} {title} collapsible={true} {initiallyCollapsed}>
172
169
  <div class="cell-filter-control">
170
+ <!-- Status Filter Checkbox -->
171
+ <div class="mb-3">
172
+ <div class="form-check">
173
+ <input
174
+ type="checkbox"
175
+ class="form-check-input"
176
+ id="includePlanned"
177
+ checked={store.includePlannedCells}
178
+ onchange={handleIncludePlannedChange}
179
+ />
180
+ <label class="form-check-label small" for="includePlanned">
181
+ Include Planned Cells
182
+ <span class="text-muted ms-1">
183
+ ({store.includePlannedCells ? 'All cells' : 'On Air only'})
184
+ </span>
185
+ </label>
186
+ </div>
187
+ </div>
188
+
173
189
  <!-- Grouping Configuration -->
174
190
  <div class="grouping-config">
175
- <div class="mb-2">
176
- <label for="level1-select" class="form-label small mb-1">Level 1 Grouping</label>
177
- <select
178
- id="level1-select"
179
- class="form-select form-select-sm"
180
- value={level1}
181
- onchange={handleLevel1Change}
182
- >
183
- {#each GROUPING_OPTIONS as option}
184
- <option value={option}>{FIELD_LABELS[option]}</option>
185
- {/each}
186
- </select>
187
- </div>
188
-
189
- <div class="mb-3">
190
- <label for="level2-select" class="form-label small mb-1">Level 2 Grouping</label>
191
- <select
192
- id="level2-select"
193
- class="form-select form-select-sm"
194
- value={level2}
195
- onchange={handleLevel2Change}
196
- >
197
- {#each LEVEL2_OPTIONS as option}
198
- <option value={option}>{FIELD_LABELS[option]}</option>
199
- {/each}
200
- </select>
191
+ <div class="row g-2 mb-3">
192
+ <!-- Level 1 Grouping -->
193
+ <div class="col-6">
194
+ <label for="level1-select" class="form-label small mb-1">Level 1</label>
195
+ <select
196
+ id="level1-select"
197
+ class="form-select form-select-sm"
198
+ value={level1}
199
+ onchange={handleLevel1Change}
200
+ >
201
+ {#each GROUPING_OPTIONS as option}
202
+ <option value={option}>{FIELD_LABELS[option]}</option>
203
+ {/each}
204
+ </select>
205
+ </div>
206
+
207
+ <!-- Level 2 Grouping -->
208
+ <div class="col-6">
209
+ <label for="level2-select" class="form-label small mb-1">Level 2</label>
210
+ <select
211
+ id="level2-select"
212
+ class="form-select form-select-sm"
213
+ value={level2}
214
+ onchange={handleLevel2Change}
215
+ >
216
+ {#each LEVEL2_OPTIONS as option}
217
+ <option value={option}>{FIELD_LABELS[option]}</option>
218
+ {/each}
219
+ </select>
220
+ </div>
201
221
  </div>
202
222
  </div>
203
223
 
@@ -234,8 +254,7 @@
234
254
 
235
255
  <style>
236
256
  .cell-filter-control {
237
- min-width: 280px;
238
- max-width: 320px;
257
+ width: 100%;
239
258
  }
240
259
 
241
260
  .grouping-config {
@@ -8,6 +8,7 @@ import type { Cell, CellStatus, CellStatusStyle, CellTreeConfig } from '../types
8
8
  export interface CellStoreValue {
9
9
  cells: Cell[];
10
10
  filteredCells: Cell[];
11
+ includePlannedCells: boolean;
11
12
  showCells: boolean;
12
13
  lineWidth: number;
13
14
  fillOpacity: number;
@@ -19,8 +20,10 @@ export interface CellStoreValue {
19
20
  }
20
21
  export interface CellStoreContext {
21
22
  readonly cells: Cell[];
23
+ readonly cellsFilteredByStatus: Cell[];
22
24
  readonly filteredCells: Cell[];
23
25
  readonly showCells: boolean;
26
+ readonly includePlannedCells: boolean;
24
27
  readonly lineWidth: number;
25
28
  readonly fillOpacity: number;
26
29
  readonly baseRadius: number;
@@ -28,6 +31,7 @@ export interface CellStoreContext {
28
31
  readonly groupingConfig: CellTreeConfig;
29
32
  readonly groupColorMap: Map<string, string>;
30
33
  setFilteredCells(cells: Cell[]): void;
34
+ setIncludePlannedCells(value: boolean): void;
31
35
  setShowCells(value: boolean): void;
32
36
  setLineWidth(value: number): void;
33
37
  setFillOpacity(value: number): void;
@@ -48,6 +48,7 @@ export function createCellStoreContext(cells) {
48
48
  let state = $state({
49
49
  cells,
50
50
  filteredCells: cells,
51
+ includePlannedCells: persistedSettings.includePlannedCells ?? false, // Default: On Air only
51
52
  showCells: persistedSettings.showCells ?? true,
52
53
  lineWidth: persistedSettings.lineWidth ?? 2,
53
54
  fillOpacity: persistedSettings.fillOpacity ?? 0.6,
@@ -57,6 +58,12 @@ export function createCellStoreContext(cells) {
57
58
  groupColorMap: initialColorMap,
58
59
  currentZoom: 12 // Default zoom
59
60
  });
61
+ // Derived: Filter cells by status based on includePlannedCells flag
62
+ // IMPORTANT: This is a pure $derived - it only READS from state, never writes
63
+ let cellsFilteredByStatus = $derived(state.includePlannedCells
64
+ ? state.cells // Include all cells
65
+ : state.cells.filter(cell => cell.status.startsWith('On_Air')) // Only On Air cells
66
+ );
60
67
  // Auto-save settings when they change
61
68
  $effect(() => {
62
69
  // Convert Map to plain object for serialization
@@ -66,6 +73,7 @@ export function createCellStoreContext(cells) {
66
73
  });
67
74
  const settings = {
68
75
  showCells: state.showCells,
76
+ includePlannedCells: state.includePlannedCells,
69
77
  lineWidth: state.lineWidth,
70
78
  fillOpacity: state.fillOpacity,
71
79
  baseRadius: state.baseRadius,
@@ -79,8 +87,12 @@ export function createCellStoreContext(cells) {
79
87
  // Bindable properties with getters/setters
80
88
  get cells() { return state.cells; },
81
89
  set cells(value) { state.cells = value; },
90
+ // Derived readonly property - filtered by status
91
+ get cellsFilteredByStatus() { return cellsFilteredByStatus; },
82
92
  get filteredCells() { return state.filteredCells; },
83
93
  set filteredCells(value) { state.filteredCells = value; },
94
+ get includePlannedCells() { return state.includePlannedCells; },
95
+ set includePlannedCells(value) { state.includePlannedCells = value; },
84
96
  get showCells() { return state.showCells; },
85
97
  set showCells(value) { state.showCells = value; },
86
98
  get lineWidth() { return state.lineWidth; },
@@ -97,6 +109,9 @@ export function createCellStoreContext(cells) {
97
109
  setFilteredCells(cells) {
98
110
  state.filteredCells = cells;
99
111
  },
112
+ setIncludePlannedCells(value) {
113
+ state.includePlannedCells = value;
114
+ },
100
115
  setShowCells(value) {
101
116
  state.showCells = value;
102
117
  },
@@ -24,7 +24,7 @@ import * as turf from '@turf/turf';
24
24
  * 64 // 64 points
25
25
  * );
26
26
  */
27
- export function createArcPolygon(center, azimuth, beamwidth, radius, steps = 64) {
27
+ export function createArcPolygon(center, azimuth, beamwidth, radius, steps = 6) {
28
28
  // Convert radius from meters to kilometers for Turf
29
29
  const radiusKm = radius / 1000;
30
30
  // Calculate start and end bearings for the arc
@@ -71,22 +71,12 @@ 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);
77
74
  // If level2 is 'none', create flat 2-level tree
78
75
  if (level2 === 'none') {
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;
76
+ return buildFlatTree(cells, level1, colorMap);
83
77
  }
84
78
  // Otherwise, create nested 3-level tree
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;
79
+ return buildNestedTree(cells, level1, level2, colorMap);
90
80
  }
91
81
  /**
92
82
  * Build flat 2-level tree (Root → Level1 groups)
@@ -162,7 +152,6 @@ function buildNestedTree(cells, level1, level2, colorMap) {
162
152
  const nodeId = generateNodeId(level2, value2, parentId);
163
153
  const color = colorMap?.get(nodeId);
164
154
  const cellIds = groupCells.map((c) => c.id);
165
- console.log(` Nested tree leaf: id="${nodeId}", cells=${cellIds.length}, cellIds sample:`, cellIds.slice(0, 3));
166
155
  return {
167
156
  id: nodeId,
168
157
  label: getGroupLabel(level2, value2, groupCells.length),
@@ -181,7 +170,6 @@ function buildNestedTree(cells, level1, level2, colorMap) {
181
170
  });
182
171
  // Calculate total cells in this level1 group
183
172
  const totalCells = Array.from(level2Groups.values()).flat().length;
184
- console.log(` Nested tree parent: id="${parentId}", totalCells=${totalCells}, children=${level2Children.length}`);
185
173
  return {
186
174
  id: parentId,
187
175
  label: getGroupLabel(level1, value1, totalCells),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartnet360/svelte-components",
3
- "version": "0.0.60",
3
+ "version": "0.0.62",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",