@smartnet360/svelte-components 0.0.104 → 0.0.106
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/README.md +75 -0
- package/dist/core/CellTable/CellTableDemo.svelte +101 -0
- package/dist/core/CellTable/CellTableDemo.svelte.d.ts +3 -0
- package/dist/core/CellTable/CellTablePanel.svelte +210 -25
- package/dist/core/CellTable/CellTablePanel.svelte.d.ts +15 -1
- package/dist/core/CellTable/index.d.ts +2 -0
- package/dist/core/CellTable/index.js +5 -0
- package/dist/core/CellTable/types.d.ts +5 -46
- package/dist/map-v3/demo/demo-cells.d.ts +14 -10
- package/dist/map-v3/demo/demo-cells.js +21 -244
- package/dist/map-v3/features/cells/types.d.ts +3 -54
- package/dist/map-v3/features/cells/types.js +2 -1
- package/dist/shared/demo/cell-generator.d.ts +73 -0
- package/dist/shared/demo/cell-generator.js +254 -0
- package/dist/shared/demo/cell-types.d.ts +62 -0
- package/dist/shared/demo/cell-types.js +6 -0
- package/dist/shared/demo/index.d.ts +7 -0
- package/dist/shared/demo/index.js +7 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# RF Tool Components
|
|
2
|
+
|
|
3
|
+
Private SvelteKit component library for RF planning and network visualization tools.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @smartnet360/svelte-components
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Components
|
|
12
|
+
|
|
13
|
+
### Core Components (`@smartnet360/svelte-components/core`)
|
|
14
|
+
|
|
15
|
+
| Component | Description |
|
|
16
|
+
|-----------|-------------|
|
|
17
|
+
| **Desktop** | Grid orchestrator for multi-panel layouts with component assignment |
|
|
18
|
+
| **Charts** | Plotly-based chart system with tabs/scrollspy modes |
|
|
19
|
+
| **CellTable** | Tabulator-based cell data table with grouping and filtering |
|
|
20
|
+
| **TreeView** | Hierarchical tree component for data navigation |
|
|
21
|
+
| **Settings** | Configuration panels and settings management |
|
|
22
|
+
| **CoverageMap** | Coverage visualization component |
|
|
23
|
+
|
|
24
|
+
### Map Components
|
|
25
|
+
|
|
26
|
+
| Package | Description |
|
|
27
|
+
|---------|-------------|
|
|
28
|
+
| **map-v2** | Legacy map implementation |
|
|
29
|
+
| **map-v3** | Current map implementation with cell/site features |
|
|
30
|
+
|
|
31
|
+
### Shared Utilities (`@smartnet360/svelte-components/shared`)
|
|
32
|
+
|
|
33
|
+
| Module | Description |
|
|
34
|
+
|--------|-------------|
|
|
35
|
+
| **demo** | Cell data generator with configurable presets (small/medium/large/xlarge) |
|
|
36
|
+
| **ResizableSplitPanel** | Draggable split panel component |
|
|
37
|
+
|
|
38
|
+
## Development
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Install dependencies
|
|
42
|
+
npm install
|
|
43
|
+
|
|
44
|
+
# Run dev server
|
|
45
|
+
npm run dev
|
|
46
|
+
|
|
47
|
+
# Type checking
|
|
48
|
+
npm run check
|
|
49
|
+
|
|
50
|
+
# Build library
|
|
51
|
+
npm run build
|
|
52
|
+
|
|
53
|
+
# Release (patch/minor/major)
|
|
54
|
+
npm run release:patch
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Demo Routes
|
|
58
|
+
|
|
59
|
+
Demo pages available at `/apps/demo/`:
|
|
60
|
+
- `/apps/demo/cell-table` - CellTable component
|
|
61
|
+
- `/apps/demo/charts` - Charts component
|
|
62
|
+
- `/apps/demo/desktop` - Desktop grid system
|
|
63
|
+
|
|
64
|
+
## Tech Stack
|
|
65
|
+
|
|
66
|
+
- **Svelte 5** with runes (`$state`, `$derived`, `$effect`)
|
|
67
|
+
- **SvelteKit** library mode
|
|
68
|
+
- **TypeScript** first
|
|
69
|
+
- **Bootstrap 5** for styling
|
|
70
|
+
- **Plotly.js** for charts
|
|
71
|
+
- **Tabulator** for data tables
|
|
72
|
+
|
|
73
|
+
## License
|
|
74
|
+
|
|
75
|
+
Private - SmartNet360
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CellTablePanel from './CellTablePanel.svelte';
|
|
3
|
+
import type { CellTableGroupField, ColumnPreset, RowSelectionEvent } from './types';
|
|
4
|
+
import { generateCellsFromPreset, getGeneratorInfo, type GeneratorPreset } from '../../shared/demo';
|
|
5
|
+
|
|
6
|
+
let datasetSize: GeneratorPreset = $state('small');
|
|
7
|
+
let demoCells = $state(generateCellsFromPreset('small'));
|
|
8
|
+
let dataInfo = $derived(getGeneratorInfo(demoCells));
|
|
9
|
+
|
|
10
|
+
let groupBy: CellTableGroupField = $state('none');
|
|
11
|
+
let columnPreset: ColumnPreset = $state('default');
|
|
12
|
+
|
|
13
|
+
function handleSelectionChange(event: RowSelectionEvent) {
|
|
14
|
+
console.log('Selection changed:', event.ids);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function regenerateData() {
|
|
18
|
+
demoCells = generateCellsFromPreset(datasetSize);
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<div class="cell-table-page vh-100 d-flex flex-column">
|
|
23
|
+
<!-- Simple header for demo controls only -->
|
|
24
|
+
<div class="demo-controls bg-light border-bottom px-3 py-2 d-flex align-items-center gap-3 flex-wrap">
|
|
25
|
+
<div class="input-group input-group-sm" style="width: auto;">
|
|
26
|
+
<span class="input-group-text">Dataset</span>
|
|
27
|
+
<select class="form-select" bind:value={datasetSize} onchange={regenerateData}>
|
|
28
|
+
<option value="small">Small (~300)</option>
|
|
29
|
+
<option value="medium">Medium (~3K)</option>
|
|
30
|
+
<option value="large">Large (~15K)</option>
|
|
31
|
+
<option value="xlarge">XLarge (~60K)</option>
|
|
32
|
+
</select>
|
|
33
|
+
</div>
|
|
34
|
+
<span class="badge bg-info">
|
|
35
|
+
{dataInfo.totalCells.toLocaleString()} cells | {dataInfo.totalSites} sites
|
|
36
|
+
</span>
|
|
37
|
+
<span class="badge bg-secondary d-none d-md-inline">
|
|
38
|
+
{Object.entries(dataInfo.techBreakdown).map(([k, v]) => `${k}: ${v}`).join(' | ')}
|
|
39
|
+
</span>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<!-- CellTablePanel with integrated sidebar -->
|
|
43
|
+
<div class="flex-grow-1 overflow-hidden">
|
|
44
|
+
<CellTablePanel
|
|
45
|
+
cells={demoCells}
|
|
46
|
+
bind:groupBy
|
|
47
|
+
bind:columnPreset
|
|
48
|
+
selectable={true}
|
|
49
|
+
multiSelect={true}
|
|
50
|
+
showToolbar={true}
|
|
51
|
+
showExport={true}
|
|
52
|
+
headerFilters={true}
|
|
53
|
+
showDetailsSidebar={true}
|
|
54
|
+
sidebarWidth={320}
|
|
55
|
+
title="Cell Data"
|
|
56
|
+
onselectionchange={handleSelectionChange}
|
|
57
|
+
>
|
|
58
|
+
{#snippet footer({ selectedRows, selectedCount })}
|
|
59
|
+
<div class="d-flex align-items-center justify-content-between">
|
|
60
|
+
<span class="text-muted small">
|
|
61
|
+
{#if selectedCount > 0}
|
|
62
|
+
{selectedCount} cell(s) selected
|
|
63
|
+
{:else}
|
|
64
|
+
Click a row to view details
|
|
65
|
+
{/if}
|
|
66
|
+
</span>
|
|
67
|
+
<div class="btn-group">
|
|
68
|
+
<button
|
|
69
|
+
type="button"
|
|
70
|
+
class="btn btn-sm btn-outline-primary"
|
|
71
|
+
disabled={selectedCount === 0}
|
|
72
|
+
onclick={() => console.log('Process:', selectedRows.map(r => r.id))}
|
|
73
|
+
>
|
|
74
|
+
<i class="bi bi-gear"></i>
|
|
75
|
+
<span class="d-none d-sm-inline ms-1">Process</span>
|
|
76
|
+
</button>
|
|
77
|
+
<button
|
|
78
|
+
type="button"
|
|
79
|
+
class="btn btn-sm btn-outline-secondary"
|
|
80
|
+
disabled={selectedCount === 0}
|
|
81
|
+
onclick={() => console.log('Export:', selectedRows.map(r => r.id))}
|
|
82
|
+
>
|
|
83
|
+
<i class="bi bi-download"></i>
|
|
84
|
+
<span class="d-none d-sm-inline ms-1">Export</span>
|
|
85
|
+
</button>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
{/snippet}
|
|
89
|
+
</CellTablePanel>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<style>
|
|
94
|
+
.cell-table-page {
|
|
95
|
+
background: var(--bs-body-bg, #f8f9fa);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.demo-controls {
|
|
99
|
+
flex-shrink: 0;
|
|
100
|
+
}
|
|
101
|
+
</style>
|
|
@@ -39,6 +39,12 @@
|
|
|
39
39
|
headerFilters?: boolean;
|
|
40
40
|
/** Panel title */
|
|
41
41
|
title?: string;
|
|
42
|
+
/** Show details sidebar */
|
|
43
|
+
showDetailsSidebar?: boolean;
|
|
44
|
+
/** Sidebar width in pixels */
|
|
45
|
+
sidebarWidth?: number;
|
|
46
|
+
/** Bindable reference to table methods */
|
|
47
|
+
tableRef?: { redraw: () => void } | null;
|
|
42
48
|
/** Row selection change event */
|
|
43
49
|
onselectionchange?: (event: RowSelectionEvent) => void;
|
|
44
50
|
/** Row click event */
|
|
@@ -49,6 +55,8 @@
|
|
|
49
55
|
headerActions?: Snippet;
|
|
50
56
|
/** Custom footer slot */
|
|
51
57
|
footer?: Snippet<[{ selectedRows: CellData[]; selectedCount: number }]>;
|
|
58
|
+
/** Custom details sidebar content */
|
|
59
|
+
detailsContent?: Snippet<[{ cell: CellData | null; closeSidebar: () => void }]>;
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
let {
|
|
@@ -64,17 +72,32 @@
|
|
|
64
72
|
statusColors,
|
|
65
73
|
headerFilters = true,
|
|
66
74
|
title = 'Cell Data',
|
|
75
|
+
showDetailsSidebar = false,
|
|
76
|
+
sidebarWidth = 320,
|
|
77
|
+
tableRef = $bindable(null),
|
|
67
78
|
onselectionchange,
|
|
68
79
|
onrowclick,
|
|
69
80
|
onrowdblclick,
|
|
70
81
|
headerActions,
|
|
71
|
-
footer
|
|
82
|
+
footer,
|
|
83
|
+
detailsContent
|
|
72
84
|
}: Props = $props();
|
|
73
85
|
|
|
74
86
|
let cellTable: CellTable;
|
|
75
87
|
let selectedCount = $state(0);
|
|
76
88
|
let selectedRows = $state<CellData[]>([]);
|
|
77
89
|
let filteredCount = $state(cells.length);
|
|
90
|
+
let sidebarOpen = $state(false);
|
|
91
|
+
let clickedCell: CellData | null = $state(null);
|
|
92
|
+
|
|
93
|
+
// Expose table methods via tableRef
|
|
94
|
+
$effect(() => {
|
|
95
|
+
if (cellTable) {
|
|
96
|
+
tableRef = {
|
|
97
|
+
redraw: () => cellTable?.redraw()
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
});
|
|
78
101
|
|
|
79
102
|
function handleSelectionChange(event: RowSelectionEvent) {
|
|
80
103
|
selectedCount = event.rows.length;
|
|
@@ -82,6 +105,15 @@
|
|
|
82
105
|
onselectionchange?.(event);
|
|
83
106
|
}
|
|
84
107
|
|
|
108
|
+
function handleRowClick(event: RowClickEvent) {
|
|
109
|
+
if (showDetailsSidebar) {
|
|
110
|
+
clickedCell = event.row;
|
|
111
|
+
sidebarOpen = true;
|
|
112
|
+
setTimeout(() => cellTable?.redraw(), 320);
|
|
113
|
+
}
|
|
114
|
+
onrowclick?.(event);
|
|
115
|
+
}
|
|
116
|
+
|
|
85
117
|
function handleDataChange(event: DataChangeEvent) {
|
|
86
118
|
filteredCount = event.filteredCount;
|
|
87
119
|
}
|
|
@@ -106,6 +138,16 @@
|
|
|
106
138
|
cellTable?.clearFilters();
|
|
107
139
|
}
|
|
108
140
|
|
|
141
|
+
function toggleSidebar() {
|
|
142
|
+
sidebarOpen = !sidebarOpen;
|
|
143
|
+
setTimeout(() => cellTable?.redraw(), 320);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function closeSidebar() {
|
|
147
|
+
sidebarOpen = false;
|
|
148
|
+
setTimeout(() => cellTable?.redraw(), 320);
|
|
149
|
+
}
|
|
150
|
+
|
|
109
151
|
// Expose table methods
|
|
110
152
|
export function getSelectedRows(): CellData[] {
|
|
111
153
|
return cellTable?.getSelectedRows() ?? [];
|
|
@@ -122,6 +164,11 @@
|
|
|
122
164
|
export function redraw(): void {
|
|
123
165
|
cellTable?.redraw();
|
|
124
166
|
}
|
|
167
|
+
|
|
168
|
+
export function openSidebar(): void {
|
|
169
|
+
sidebarOpen = true;
|
|
170
|
+
setTimeout(() => cellTable?.redraw(), 320);
|
|
171
|
+
}
|
|
125
172
|
</script>
|
|
126
173
|
|
|
127
174
|
<div class="cell-table-panel d-flex flex-column" style:height>
|
|
@@ -131,11 +178,24 @@
|
|
|
131
178
|
<i class="bi bi-table text-primary"></i>
|
|
132
179
|
{title}
|
|
133
180
|
</h6>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
181
|
+
<div class="d-flex align-items-center gap-2">
|
|
182
|
+
{#if headerActions}
|
|
183
|
+
<div class="header-actions">
|
|
184
|
+
{@render headerActions()}
|
|
185
|
+
</div>
|
|
186
|
+
{/if}
|
|
187
|
+
{#if showDetailsSidebar}
|
|
188
|
+
<button
|
|
189
|
+
class="btn btn-sm"
|
|
190
|
+
class:btn-outline-secondary={!sidebarOpen}
|
|
191
|
+
class:btn-secondary={sidebarOpen}
|
|
192
|
+
onclick={toggleSidebar}
|
|
193
|
+
title={sidebarOpen ? 'Hide details' : 'Show details'}
|
|
194
|
+
>
|
|
195
|
+
<i class="bi" class:bi-layout-sidebar-reverse={!sidebarOpen} class:bi-x-lg={sidebarOpen}></i>
|
|
196
|
+
</button>
|
|
197
|
+
{/if}
|
|
198
|
+
</div>
|
|
139
199
|
</div>
|
|
140
200
|
|
|
141
201
|
<!-- Toolbar -->
|
|
@@ -155,24 +215,132 @@
|
|
|
155
215
|
/>
|
|
156
216
|
{/if}
|
|
157
217
|
|
|
158
|
-
<!--
|
|
159
|
-
<div class="
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
218
|
+
<!-- Main content with optional sidebar -->
|
|
219
|
+
<div class="content-area d-flex flex-grow-1 overflow-hidden">
|
|
220
|
+
<!-- Table -->
|
|
221
|
+
<div class="table-wrapper flex-grow-1 overflow-hidden">
|
|
222
|
+
<CellTable
|
|
223
|
+
bind:this={cellTable}
|
|
224
|
+
{cells}
|
|
225
|
+
{groupBy}
|
|
226
|
+
{columnPreset}
|
|
227
|
+
{selectable}
|
|
228
|
+
{multiSelect}
|
|
229
|
+
height="100%"
|
|
230
|
+
{techColors}
|
|
231
|
+
{statusColors}
|
|
232
|
+
{headerFilters}
|
|
233
|
+
onselectionchange={handleSelectionChange}
|
|
234
|
+
ondatachange={handleDataChange}
|
|
235
|
+
onrowclick={handleRowClick}
|
|
236
|
+
{onrowdblclick}
|
|
237
|
+
/>
|
|
238
|
+
</div>
|
|
239
|
+
|
|
240
|
+
<!-- Details Sidebar -->
|
|
241
|
+
{#if showDetailsSidebar}
|
|
242
|
+
<aside
|
|
243
|
+
class="details-sidebar border-start bg-white overflow-auto"
|
|
244
|
+
class:open={sidebarOpen}
|
|
245
|
+
style:--sidebar-width="{sidebarWidth}px"
|
|
246
|
+
>
|
|
247
|
+
<div class="sidebar-content" style:width="{sidebarWidth}px">
|
|
248
|
+
<div class="d-flex align-items-center justify-content-between p-3 border-bottom bg-light sticky-top">
|
|
249
|
+
<h6 class="mb-0">
|
|
250
|
+
<i class="bi bi-info-circle text-primary"></i> Details
|
|
251
|
+
</h6>
|
|
252
|
+
<button
|
|
253
|
+
class="btn btn-sm btn-outline-secondary"
|
|
254
|
+
onclick={closeSidebar}
|
|
255
|
+
title="Close"
|
|
256
|
+
>
|
|
257
|
+
<i class="bi bi-x-lg"></i>
|
|
258
|
+
</button>
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
<div class="p-3">
|
|
262
|
+
{#if detailsContent}
|
|
263
|
+
{@render detailsContent({ cell: clickedCell, closeSidebar })}
|
|
264
|
+
{:else if clickedCell}
|
|
265
|
+
<!-- Default details view -->
|
|
266
|
+
<dl class="row mb-0 small">
|
|
267
|
+
<dt class="col-5 text-muted">ID</dt>
|
|
268
|
+
<dd class="col-7"><code class="text-primary">{clickedCell.id}</code></dd>
|
|
269
|
+
|
|
270
|
+
<dt class="col-5 text-muted">Cell Name</dt>
|
|
271
|
+
<dd class="col-7 fw-medium">{clickedCell.cellName}</dd>
|
|
272
|
+
|
|
273
|
+
<dt class="col-5 text-muted">Site</dt>
|
|
274
|
+
<dd class="col-7">{clickedCell.siteId}</dd>
|
|
275
|
+
|
|
276
|
+
<dt class="col-5 text-muted">Technology</dt>
|
|
277
|
+
<dd class="col-7">
|
|
278
|
+
<span class="badge bg-secondary">{clickedCell.tech}</span>
|
|
279
|
+
</dd>
|
|
280
|
+
|
|
281
|
+
<dt class="col-5 text-muted">Band</dt>
|
|
282
|
+
<dd class="col-7">
|
|
283
|
+
<span class="badge bg-info">{clickedCell.fband}</span>
|
|
284
|
+
</dd>
|
|
285
|
+
|
|
286
|
+
<dt class="col-5 text-muted">Frequency</dt>
|
|
287
|
+
<dd class="col-7">{clickedCell.frq} MHz</dd>
|
|
288
|
+
|
|
289
|
+
<dt class="col-5 text-muted">Status</dt>
|
|
290
|
+
<dd class="col-7">
|
|
291
|
+
<span class="badge bg-success">{clickedCell.status.replace(/_/g, ' ')}</span>
|
|
292
|
+
</dd>
|
|
293
|
+
|
|
294
|
+
<dt class="col-12 text-muted mt-2 mb-1 border-top pt-2">Physical</dt>
|
|
295
|
+
|
|
296
|
+
<dt class="col-5 text-muted">Azimuth</dt>
|
|
297
|
+
<dd class="col-7">{clickedCell.azimuth}°</dd>
|
|
298
|
+
|
|
299
|
+
<dt class="col-5 text-muted">Height</dt>
|
|
300
|
+
<dd class="col-7">{clickedCell.height}m</dd>
|
|
301
|
+
|
|
302
|
+
<dt class="col-5 text-muted">Beamwidth</dt>
|
|
303
|
+
<dd class="col-7">{clickedCell.beamwidth}°</dd>
|
|
304
|
+
|
|
305
|
+
<dt class="col-5 text-muted">E-Tilt</dt>
|
|
306
|
+
<dd class="col-7">{clickedCell.electricalTilt}°</dd>
|
|
307
|
+
|
|
308
|
+
<dt class="col-5 text-muted">Antenna</dt>
|
|
309
|
+
<dd class="col-7 text-truncate" title={clickedCell.antenna}>
|
|
310
|
+
{clickedCell.antenna}
|
|
311
|
+
</dd>
|
|
312
|
+
|
|
313
|
+
<dt class="col-12 text-muted mt-2 mb-1 border-top pt-2">Location</dt>
|
|
314
|
+
|
|
315
|
+
<dt class="col-5 text-muted">Latitude</dt>
|
|
316
|
+
<dd class="col-7">{clickedCell.latitude.toFixed(6)}</dd>
|
|
317
|
+
|
|
318
|
+
<dt class="col-5 text-muted">Longitude</dt>
|
|
319
|
+
<dd class="col-7">{clickedCell.longitude.toFixed(6)}</dd>
|
|
320
|
+
|
|
321
|
+
<dt class="col-12 text-muted mt-2 mb-1 border-top pt-2">Planning</dt>
|
|
322
|
+
|
|
323
|
+
<dt class="col-5 text-muted">Planner</dt>
|
|
324
|
+
<dd class="col-7">{clickedCell.planner}</dd>
|
|
325
|
+
|
|
326
|
+
<dt class="col-5 text-muted">On Air</dt>
|
|
327
|
+
<dd class="col-7">{clickedCell.onAirDate}</dd>
|
|
328
|
+
|
|
329
|
+
{#if clickedCell.comment}
|
|
330
|
+
<dt class="col-5 text-muted">Comment</dt>
|
|
331
|
+
<dd class="col-7 fst-italic">{clickedCell.comment}</dd>
|
|
332
|
+
{/if}
|
|
333
|
+
</dl>
|
|
334
|
+
{:else}
|
|
335
|
+
<div class="text-center text-muted py-5">
|
|
336
|
+
<i class="bi bi-hand-index fs-1 opacity-50"></i>
|
|
337
|
+
<p class="mt-2 mb-0">Click a row to see details</p>
|
|
338
|
+
</div>
|
|
339
|
+
{/if}
|
|
340
|
+
</div>
|
|
341
|
+
</div>
|
|
342
|
+
</aside>
|
|
343
|
+
{/if}
|
|
176
344
|
</div>
|
|
177
345
|
|
|
178
346
|
<!-- Footer -->
|
|
@@ -200,9 +368,26 @@
|
|
|
200
368
|
color: var(--bs-body-color, #212529);
|
|
201
369
|
}
|
|
202
370
|
|
|
371
|
+
.content-area {
|
|
372
|
+
min-height: 0;
|
|
373
|
+
}
|
|
374
|
+
|
|
203
375
|
.table-wrapper {
|
|
204
376
|
min-height: 0;
|
|
205
|
-
|
|
377
|
+
transition: all 0.3s ease;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.details-sidebar {
|
|
381
|
+
width: 0;
|
|
382
|
+
min-width: 0;
|
|
383
|
+
opacity: 0;
|
|
384
|
+
transition: width 0.3s ease, opacity 0.3s ease, min-width 0.3s ease;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.details-sidebar.open {
|
|
388
|
+
width: var(--sidebar-width, 320px);
|
|
389
|
+
min-width: var(--sidebar-width, 320px);
|
|
390
|
+
opacity: 1;
|
|
206
391
|
}
|
|
207
392
|
|
|
208
393
|
.panel-footer {
|
|
@@ -25,6 +25,14 @@ interface Props {
|
|
|
25
25
|
headerFilters?: boolean;
|
|
26
26
|
/** Panel title */
|
|
27
27
|
title?: string;
|
|
28
|
+
/** Show details sidebar */
|
|
29
|
+
showDetailsSidebar?: boolean;
|
|
30
|
+
/** Sidebar width in pixels */
|
|
31
|
+
sidebarWidth?: number;
|
|
32
|
+
/** Bindable reference to table methods */
|
|
33
|
+
tableRef?: {
|
|
34
|
+
redraw: () => void;
|
|
35
|
+
} | null;
|
|
28
36
|
/** Row selection change event */
|
|
29
37
|
onselectionchange?: (event: RowSelectionEvent) => void;
|
|
30
38
|
/** Row click event */
|
|
@@ -38,12 +46,18 @@ interface Props {
|
|
|
38
46
|
selectedRows: CellData[];
|
|
39
47
|
selectedCount: number;
|
|
40
48
|
}]>;
|
|
49
|
+
/** Custom details sidebar content */
|
|
50
|
+
detailsContent?: Snippet<[{
|
|
51
|
+
cell: CellData | null;
|
|
52
|
+
closeSidebar: () => void;
|
|
53
|
+
}]>;
|
|
41
54
|
}
|
|
42
55
|
declare const CellTablePanel: import("svelte").Component<Props, {
|
|
43
56
|
getSelectedRows: () => CellData[];
|
|
44
57
|
clearSelection: () => void;
|
|
45
58
|
scrollToRow: (id: string) => void;
|
|
46
59
|
redraw: () => void;
|
|
47
|
-
|
|
60
|
+
openSidebar: () => void;
|
|
61
|
+
}, "groupBy" | "columnPreset" | "tableRef">;
|
|
48
62
|
type CellTablePanel = ReturnType<typeof CellTablePanel>;
|
|
49
63
|
export default CellTablePanel;
|
|
@@ -6,5 +6,7 @@
|
|
|
6
6
|
export { default as CellTable } from './CellTable.svelte';
|
|
7
7
|
export { default as CellTableToolbar } from './CellTableToolbar.svelte';
|
|
8
8
|
export { default as CellTablePanel } from './CellTablePanel.svelte';
|
|
9
|
+
export { default as CellTableDemo } from './CellTableDemo.svelte';
|
|
10
|
+
export { generateCells, generateCellsFromPreset, getGeneratorInfo, GENERATOR_PRESETS, type CellGeneratorConfig, type GeneratorPreset } from '../../shared/demo';
|
|
9
11
|
export type { CellData, CellTableGroupField, ColumnPreset, ColumnVisibility, TechColorMap, StatusColorMap, CellTableProps, RowSelectionEvent, RowClickEvent, RowDblClickEvent, DataChangeEvent, CellTableColumn, ColumnGroups } from './types';
|
|
10
12
|
export { DEFAULT_TECH_COLORS, DEFAULT_STATUS_COLORS, FBAND_COLORS, COLUMN_GROUPS, getAllColumns, getColumnsForPreset, getGroupHeaderFormatter, createTechFormatter, createStatusFormatter, createFbandFormatter, numberFormatter, coordinateFormatter, azimuthFormatter, heightFormatter } from './column-config';
|
|
@@ -7,5 +7,10 @@
|
|
|
7
7
|
export { default as CellTable } from './CellTable.svelte';
|
|
8
8
|
export { default as CellTableToolbar } from './CellTableToolbar.svelte';
|
|
9
9
|
export { default as CellTablePanel } from './CellTablePanel.svelte';
|
|
10
|
+
export { default as CellTableDemo } from './CellTableDemo.svelte';
|
|
11
|
+
// Re-export shared demo data utilities for convenience
|
|
12
|
+
// Note: Cell type is NOT re-exported here to avoid conflicts with map-v2
|
|
13
|
+
// Import Cell from '$lib/shared/demo' or '@smartnet360/svelte-components' directly
|
|
14
|
+
export { generateCells, generateCellsFromPreset, getGeneratorInfo, GENERATOR_PRESETS } from '../../shared/demo';
|
|
10
15
|
// Configuration utilities
|
|
11
16
|
export { DEFAULT_TECH_COLORS, DEFAULT_STATUS_COLORS, FBAND_COLORS, COLUMN_GROUPS, getAllColumns, getColumnsForPreset, getGroupHeaderFormatter, createTechFormatter, createStatusFormatter, createFbandFormatter, numberFormatter, coordinateFormatter, azimuthFormatter, heightFormatter } from './column-config';
|
|
@@ -4,56 +4,15 @@
|
|
|
4
4
|
* Types for the Tabulator-based cell data table component
|
|
5
5
|
*/
|
|
6
6
|
import type { ColumnDefinition, Options } from 'tabulator-tables';
|
|
7
|
+
import type { Cell, CellGroupingField } from '../../shared/demo';
|
|
7
8
|
/**
|
|
8
|
-
* Cell data model -
|
|
9
|
-
* Imported from map-v3 cells feature for consistency
|
|
9
|
+
* Cell data model - re-exported from shared for convenience
|
|
10
10
|
*/
|
|
11
|
-
export
|
|
12
|
-
id: string;
|
|
13
|
-
txId: string;
|
|
14
|
-
cellID: string;
|
|
15
|
-
cellID2G: string;
|
|
16
|
-
cellName: string;
|
|
17
|
-
siteId: string;
|
|
18
|
-
tech: string;
|
|
19
|
-
fband: string;
|
|
20
|
-
frq: string;
|
|
21
|
-
type: string;
|
|
22
|
-
status: string;
|
|
23
|
-
onAirDate: string;
|
|
24
|
-
bcch: number;
|
|
25
|
-
ctrlid: string;
|
|
26
|
-
dlEarfn: number;
|
|
27
|
-
antenna: string;
|
|
28
|
-
azimuth: number;
|
|
29
|
-
height: number;
|
|
30
|
-
electricalTilt: string;
|
|
31
|
-
beamwidth: number;
|
|
32
|
-
latitude: number;
|
|
33
|
-
longitude: number;
|
|
34
|
-
dx: number;
|
|
35
|
-
dy: number;
|
|
36
|
-
siteLatitude: number;
|
|
37
|
-
siteLongitude: number;
|
|
38
|
-
comment: string;
|
|
39
|
-
planner: string;
|
|
40
|
-
atollETP: number;
|
|
41
|
-
atollPW: number;
|
|
42
|
-
atollRS: number;
|
|
43
|
-
atollBW: number;
|
|
44
|
-
cellId3: string;
|
|
45
|
-
nwtP1: number;
|
|
46
|
-
nwtP2: number;
|
|
47
|
-
pci1: number;
|
|
48
|
-
nwtRS: number;
|
|
49
|
-
nwtBW: number;
|
|
50
|
-
other?: Record<string, unknown>;
|
|
51
|
-
customSubgroup: string;
|
|
52
|
-
}
|
|
11
|
+
export type CellData = Cell;
|
|
53
12
|
/**
|
|
54
|
-
* Available grouping fields for the table
|
|
13
|
+
* Available grouping fields for the table - extends shared type with 'none' option
|
|
55
14
|
*/
|
|
56
|
-
export type CellTableGroupField =
|
|
15
|
+
export type CellTableGroupField = CellGroupingField | 'none';
|
|
57
16
|
/**
|
|
58
17
|
* Column preset configurations
|
|
59
18
|
*/
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Demo Cell Data
|
|
2
|
+
* Demo Cell Data - Map V3
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*
|
|
12
|
-
*
|
|
4
|
+
* Uses the shared cell generator to create demo data.
|
|
5
|
+
* Default: 2000 sites, ~60k cells across Budapest area.
|
|
6
|
+
*
|
|
7
|
+
* Structure:
|
|
8
|
+
* - CellName format: 7-digit numeric (e.g., "1000141")
|
|
9
|
+
* - Format: SSSS (site) + S (sector 1-3) + BB (band 41-51)
|
|
10
|
+
* - Site ID range: 1000-2999
|
|
11
|
+
* - Example Site 1000:
|
|
12
|
+
* - Sector 1 (0°): 1000141-1000151 (11 bands)
|
|
13
|
+
* - Sector 2 (120°): 1000241-1000251 (11 bands)
|
|
14
|
+
* - Sector 3 (240°): 1000341-1000351 (11 bands)
|
|
13
15
|
*/
|
|
16
|
+
import { type Cell } from '../../shared/demo';
|
|
14
17
|
export declare const demoCells: Cell[];
|
|
18
|
+
export type { Cell } from '../../shared/demo';
|