@smartnet360/svelte-components 0.0.11 → 0.0.12
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/antenna-pattern/components/AntennaControls.svelte +424 -0
- package/dist/apps/antenna-pattern/components/AntennaControls.svelte.d.ts +16 -0
- package/dist/apps/antenna-pattern/components/AntennaDataDropdown.svelte +62 -0
- package/dist/apps/antenna-pattern/components/AntennaDataDropdown.svelte.d.ts +18 -0
- package/dist/apps/antenna-pattern/components/AntennaDiagrams.svelte +339 -0
- package/dist/apps/antenna-pattern/components/AntennaDiagrams.svelte.d.ts +3 -0
- package/dist/apps/antenna-pattern/components/AntennaSettingsModal.svelte +299 -0
- package/dist/apps/antenna-pattern/components/AntennaSettingsModal.svelte.d.ts +24 -0
- package/dist/apps/antenna-pattern/components/DbNotification.svelte +67 -0
- package/dist/apps/antenna-pattern/components/DbNotification.svelte.d.ts +18 -0
- package/dist/apps/antenna-pattern/components/JsonImporter.svelte +116 -0
- package/dist/apps/antenna-pattern/components/JsonImporter.svelte.d.ts +18 -0
- package/dist/apps/antenna-pattern/components/MSIConverter.svelte +209 -0
- package/dist/apps/antenna-pattern/components/MSIConverter.svelte.d.ts +18 -0
- package/dist/apps/antenna-pattern/components/PlotlyRadarChart.svelte +252 -0
- package/dist/apps/antenna-pattern/components/PlotlyRadarChart.svelte.d.ts +22 -0
- package/dist/apps/antenna-pattern/db.d.ts +24 -0
- package/dist/apps/antenna-pattern/db.js +15 -0
- package/dist/apps/antenna-pattern/helpers/plotly-utils.d.ts +54 -0
- package/dist/apps/antenna-pattern/helpers/plotly-utils.js +324 -0
- package/dist/apps/antenna-pattern/index.d.ts +15 -0
- package/dist/apps/antenna-pattern/index.js +19 -0
- package/dist/apps/antenna-pattern/stores/antennas.d.ts +5 -0
- package/dist/apps/antenna-pattern/stores/antennas.js +14 -0
- package/dist/apps/antenna-pattern/stores/db-status.d.ts +28 -0
- package/dist/apps/antenna-pattern/stores/db-status.js +34 -0
- package/dist/apps/antenna-pattern/utils/db-utils.d.ts +9 -0
- package/dist/apps/antenna-pattern/utils/db-utils.js +180 -0
- package/dist/apps/antenna-pattern/utils/init-db.d.ts +2 -0
- package/dist/apps/antenna-pattern/utils/init-db.js +95 -0
- package/dist/apps/antenna-pattern/utils/msi-parser.d.ts +3 -0
- package/dist/apps/antenna-pattern/utils/msi-parser.js +197 -0
- package/dist/apps/antenna-pattern/utils/plotly-chart-utils.d.ts +101 -0
- package/dist/apps/antenna-pattern/utils/plotly-chart-utils.js +152 -0
- package/dist/apps/index.d.ts +1 -0
- package/dist/apps/index.js +6 -0
- package/dist/{Charts → core/Charts}/ChartComponent.svelte +131 -39
- package/dist/{Charts → core/Charts}/charts.model.d.ts +1 -1
- package/dist/{Desktop → core/Desktop}/GridRenderer.svelte +1 -1
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +6 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -2
- package/package.json +6 -2
- /package/dist/{Charts → core/Charts}/ChartCard.svelte +0 -0
- /package/dist/{Charts → core/Charts}/ChartCard.svelte.d.ts +0 -0
- /package/dist/{Charts → core/Charts}/ChartComponent.svelte.d.ts +0 -0
- /package/dist/{Charts → core/Charts}/adapt.d.ts +0 -0
- /package/dist/{Charts → core/Charts}/adapt.js +0 -0
- /package/dist/{Charts → core/Charts}/charts.model.js +0 -0
- /package/dist/{Charts → core/Charts}/data-utils.d.ts +0 -0
- /package/dist/{Charts → core/Charts}/data-utils.js +0 -0
- /package/dist/{Charts → core/Charts}/index.d.ts +0 -0
- /package/dist/{Charts → core/Charts}/index.js +0 -0
- /package/dist/{Charts → core/Charts}/plotly.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/Desktop.svelte +0 -0
- /package/dist/{Desktop → core/Desktop}/Desktop.svelte.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/Grid/Half.svelte +0 -0
- /package/dist/{Desktop → core/Desktop}/Grid/Half.svelte.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/Grid/Quarter.svelte +0 -0
- /package/dist/{Desktop → core/Desktop}/Grid/Quarter.svelte.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/Grid/ResizeHandle.svelte +0 -0
- /package/dist/{Desktop → core/Desktop}/Grid/ResizeHandle.svelte.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/Grid/index.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/Grid/index.js +0 -0
- /package/dist/{Desktop → core/Desktop}/Grid/resizeStore.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/Grid/resizeStore.js +0 -0
- /package/dist/{Desktop → core/Desktop}/GridRenderer.svelte.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/GridSelector/ComponentPalette.svelte +0 -0
- /package/dist/{Desktop → core/Desktop}/GridSelector/ComponentPalette.svelte.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/GridSelector/ConfigurationPanel.svelte +0 -0
- /package/dist/{Desktop → core/Desktop}/GridSelector/ConfigurationPanel.svelte.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/GridSelector/GridSelector.svelte +0 -0
- /package/dist/{Desktop → core/Desktop}/GridSelector/GridSelector.svelte.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/GridSelector/LayoutPicker.svelte +0 -0
- /package/dist/{Desktop → core/Desktop}/GridSelector/LayoutPicker.svelte.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/GridSelector/LayoutPreview.svelte +0 -0
- /package/dist/{Desktop → core/Desktop}/GridSelector/LayoutPreview.svelte.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/GridSelector/index.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/GridSelector/index.js +0 -0
- /package/dist/{Desktop → core/Desktop}/GridViewer.svelte +0 -0
- /package/dist/{Desktop → core/Desktop}/GridViewer.svelte.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/gridLayouts.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/gridLayouts.js +0 -0
- /package/dist/{Desktop → core/Desktop}/index.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/index.js +0 -0
- /package/dist/{Desktop → core/Desktop}/launchHelpers.d.ts +0 -0
- /package/dist/{Desktop → core/Desktop}/launchHelpers.js +0 -0
@@ -0,0 +1,339 @@
|
|
1
|
+
<svelte:options runes={true} />
|
2
|
+
|
3
|
+
<script lang="ts">
|
4
|
+
import { onMount } from 'svelte';
|
5
|
+
import { browser } from '$app/environment';
|
6
|
+
import { loadAntennas } from '../utils/db-utils';
|
7
|
+
import type { Antenna } from '../db';
|
8
|
+
import AntennaControls from './AntennaControls.svelte';
|
9
|
+
import AntennaSettingsModal from './AntennaSettingsModal.svelte';
|
10
|
+
import {
|
11
|
+
createAntennaChartData,
|
12
|
+
createChartLayout,
|
13
|
+
createChartConfig,
|
14
|
+
generateChartTitle,
|
15
|
+
type PlotlyTraceData
|
16
|
+
} from '../utils/plotly-chart-utils';
|
17
|
+
|
18
|
+
let Plotly: any;
|
19
|
+
let chartDiv = $state<HTMLDivElement>();
|
20
|
+
let antennas = $state<Antenna[]>([]);
|
21
|
+
let selectedAntenna = $state<Antenna | null>(null);
|
22
|
+
let selectedAntenna2 = $state<Antenna | null>(null);
|
23
|
+
let chartInitialized = $state(false);
|
24
|
+
|
25
|
+
// External Bootstrap slider values
|
26
|
+
let ant1ElectricalTilt = $state(0);
|
27
|
+
let ant2ElectricalTilt = $state(0);
|
28
|
+
let ant1MechanicalTilt = $state(0);
|
29
|
+
let ant2MechanicalTilt = $state(0);
|
30
|
+
|
31
|
+
// Viewing mode and pattern visibility
|
32
|
+
let viewMode = $state<'single' | 'compare'>('single');
|
33
|
+
let patternType = $state<'horizontal' | 'vertical'>('vertical');
|
34
|
+
|
35
|
+
// Settings modal state
|
36
|
+
let showSettingsModal = $state(false);
|
37
|
+
|
38
|
+
// Available tilt options (will be set from antenna data)
|
39
|
+
let availableElectricalTilts = $state<string[]>(['0', '2', '4', '6', '8']);
|
40
|
+
|
41
|
+
// Handle antenna selection from controls
|
42
|
+
function handleAntenna1Change(antenna: Antenna | null) {
|
43
|
+
selectedAntenna = antenna;
|
44
|
+
if (antenna) {
|
45
|
+
// Update available electrical tilts based on selected antenna
|
46
|
+
availableElectricalTilts = antenna.tilt ?
|
47
|
+
antenna.tilt.split(',').map(t => t.trim()) :
|
48
|
+
['0', '2', '4', '6', '8'];
|
49
|
+
ant1ElectricalTilt = 0;
|
50
|
+
ant1MechanicalTilt = 0;
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
function handleAntenna2Change(antenna: Antenna | null) {
|
55
|
+
selectedAntenna2 = antenna;
|
56
|
+
if (antenna) {
|
57
|
+
ant2ElectricalTilt = 0;
|
58
|
+
ant2MechanicalTilt = 0;
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
// Handle electrical tilt changes from controls
|
63
|
+
function handleTilt1Change(tilt: number) {
|
64
|
+
ant1ElectricalTilt = tilt;
|
65
|
+
}
|
66
|
+
|
67
|
+
function handleTilt2Change(tilt: number) {
|
68
|
+
ant2ElectricalTilt = tilt;
|
69
|
+
}
|
70
|
+
|
71
|
+
// Handle mechanical tilt changes from controls
|
72
|
+
function handleMechTilt1Change(tilt: number) {
|
73
|
+
ant1MechanicalTilt = tilt;
|
74
|
+
}
|
75
|
+
|
76
|
+
function handleMechTilt2Change(tilt: number) {
|
77
|
+
ant2MechanicalTilt = tilt;
|
78
|
+
}
|
79
|
+
|
80
|
+
// Handle settings modal
|
81
|
+
function openSettings() {
|
82
|
+
showSettingsModal = true;
|
83
|
+
}
|
84
|
+
|
85
|
+
function closeSettings() {
|
86
|
+
showSettingsModal = false;
|
87
|
+
}
|
88
|
+
|
89
|
+
// Handle data refresh from settings modal
|
90
|
+
async function handleDataRefresh() {
|
91
|
+
try {
|
92
|
+
antennas = await loadAntennas();
|
93
|
+
|
94
|
+
// Reinitialize antenna selections after data refresh
|
95
|
+
if (antennas.length > 0) {
|
96
|
+
selectedAntenna = antennas[0];
|
97
|
+
if (antennas.length > 1) {
|
98
|
+
selectedAntenna2 = antennas[1];
|
99
|
+
} else {
|
100
|
+
selectedAntenna2 = antennas[0];
|
101
|
+
}
|
102
|
+
|
103
|
+
// Reset tilt values
|
104
|
+
ant1ElectricalTilt = 0;
|
105
|
+
ant1MechanicalTilt = 0;
|
106
|
+
ant2ElectricalTilt = 0;
|
107
|
+
ant2MechanicalTilt = 0;
|
108
|
+
|
109
|
+
// Update chart if initialized
|
110
|
+
if (chartInitialized) {
|
111
|
+
await updateChart();
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
console.log('Data refreshed from settings modal');
|
116
|
+
} catch (error) {
|
117
|
+
console.error('Failed to refresh data:', error);
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
// Watch for slider changes and update chart
|
122
|
+
$effect(() => {
|
123
|
+
if (chartInitialized) {
|
124
|
+
updateChart();
|
125
|
+
}
|
126
|
+
});
|
127
|
+
|
128
|
+
onMount(async () => {
|
129
|
+
if (browser) {
|
130
|
+
try {
|
131
|
+
// Load Plotly and antenna data
|
132
|
+
Plotly = await import('plotly.js-dist-min');
|
133
|
+
antennas = await loadAntennas();
|
134
|
+
|
135
|
+
if (antennas.length > 0) {
|
136
|
+
// Set default antenna selection for antenna 1
|
137
|
+
selectedAntenna = antennas[0];
|
138
|
+
if (selectedAntenna.tilt) {
|
139
|
+
availableElectricalTilts = selectedAntenna.tilt.split(',').map(t => t.trim());
|
140
|
+
}
|
141
|
+
|
142
|
+
// Set default antenna selection for antenna 2 (for compare mode)
|
143
|
+
if (antennas.length > 1) {
|
144
|
+
selectedAntenna2 = antennas[1];
|
145
|
+
} else {
|
146
|
+
selectedAntenna2 = antennas[0]; // Use same antenna if only one available
|
147
|
+
}
|
148
|
+
|
149
|
+
await initializeChart();
|
150
|
+
}
|
151
|
+
} catch (error) {
|
152
|
+
console.error('Failed to initialize:', error);
|
153
|
+
}
|
154
|
+
}
|
155
|
+
});
|
156
|
+
|
157
|
+
async function initializeChart() {
|
158
|
+
if (!Plotly || !chartDiv) return;
|
159
|
+
|
160
|
+
const data = createAntennaChartData(
|
161
|
+
selectedAntenna,
|
162
|
+
selectedAntenna2,
|
163
|
+
viewMode,
|
164
|
+
patternType === 'horizontal',
|
165
|
+
patternType === 'vertical',
|
166
|
+
ant1ElectricalTilt,
|
167
|
+
ant1MechanicalTilt,
|
168
|
+
ant2ElectricalTilt,
|
169
|
+
ant2MechanicalTilt
|
170
|
+
);
|
171
|
+
const title = generateChartTitle(viewMode, selectedAntenna, selectedAntenna2);
|
172
|
+
const layout = createChartLayout(title);
|
173
|
+
const config = createChartConfig();
|
174
|
+
|
175
|
+
try {
|
176
|
+
await Plotly.newPlot(chartDiv, data, layout, config);
|
177
|
+
chartInitialized = true;
|
178
|
+
console.log('Chart initialized with antenna controls');
|
179
|
+
} catch (error) {
|
180
|
+
console.error('Failed to create chart:', error);
|
181
|
+
}
|
182
|
+
}
|
183
|
+
|
184
|
+
async function updateChart() {
|
185
|
+
if (!Plotly || !chartDiv || !chartInitialized) return;
|
186
|
+
|
187
|
+
try {
|
188
|
+
const data = createAntennaChartData(
|
189
|
+
selectedAntenna,
|
190
|
+
selectedAntenna2,
|
191
|
+
viewMode,
|
192
|
+
patternType === 'horizontal',
|
193
|
+
patternType === 'vertical',
|
194
|
+
ant1ElectricalTilt,
|
195
|
+
ant1MechanicalTilt,
|
196
|
+
ant2ElectricalTilt,
|
197
|
+
ant2MechanicalTilt
|
198
|
+
);
|
199
|
+
const title = generateChartTitle(viewMode, selectedAntenna, selectedAntenna2);
|
200
|
+
await Plotly.react(chartDiv, data, createChartLayout(title));
|
201
|
+
} catch (error) {
|
202
|
+
console.error('Failed to update chart:', error);
|
203
|
+
}
|
204
|
+
}
|
205
|
+
</script>
|
206
|
+
|
207
|
+
<div class="container-fluid mt-4">
|
208
|
+
|
209
|
+
|
210
|
+
<!-- Viewing Mode and Pattern Visibility Controls -->
|
211
|
+
<div class="row mb-4">
|
212
|
+
<div class="col-md-4">
|
213
|
+
<div class="form-label">Viewing Mode:</div>
|
214
|
+
<div class="btn-group w-100" role="group" aria-label="Viewing mode selection">
|
215
|
+
<input
|
216
|
+
type="radio"
|
217
|
+
class="btn-check"
|
218
|
+
id="singleMode"
|
219
|
+
bind:group={viewMode}
|
220
|
+
value="single"
|
221
|
+
>
|
222
|
+
<label class="btn btn-outline-primary" for="singleMode">Single Antenna</label>
|
223
|
+
|
224
|
+
<input
|
225
|
+
type="radio"
|
226
|
+
class="btn-check"
|
227
|
+
id="compareMode"
|
228
|
+
bind:group={viewMode}
|
229
|
+
value="compare"
|
230
|
+
>
|
231
|
+
<label class="btn btn-outline-primary" for="compareMode">Compare</label>
|
232
|
+
</div>
|
233
|
+
</div>
|
234
|
+
|
235
|
+
<div class="col-md-4">
|
236
|
+
<div class="form-label">Pattern Type:</div>
|
237
|
+
<div class="btn-group w-100" role="group" aria-label="Pattern type selection">
|
238
|
+
<input
|
239
|
+
type="radio"
|
240
|
+
class="btn-check"
|
241
|
+
id="horizontalPattern"
|
242
|
+
bind:group={patternType}
|
243
|
+
value="horizontal"
|
244
|
+
>
|
245
|
+
<label class="btn btn-outline-primary" for="horizontalPattern">Horizontal</label>
|
246
|
+
|
247
|
+
<input
|
248
|
+
type="radio"
|
249
|
+
class="btn-check"
|
250
|
+
id="verticalPattern"
|
251
|
+
bind:group={patternType}
|
252
|
+
value="vertical"
|
253
|
+
>
|
254
|
+
<label class="btn btn-outline-primary" for="verticalPattern">Vertical</label>
|
255
|
+
</div>
|
256
|
+
</div>
|
257
|
+
|
258
|
+
<div class="col-md-4">
|
259
|
+
<div class="form-label">Actions:</div>
|
260
|
+
<button
|
261
|
+
type="button"
|
262
|
+
class="btn btn-outline-secondary w-100"
|
263
|
+
onclick={openSettings}
|
264
|
+
title="Settings"
|
265
|
+
>
|
266
|
+
<i class="bi bi-gear"></i> Settings
|
267
|
+
</button>
|
268
|
+
</div>
|
269
|
+
</div>
|
270
|
+
|
271
|
+
<div class="row">
|
272
|
+
<!-- Left Column - Antenna 1 Controls -->
|
273
|
+
<div class="col-md-3">
|
274
|
+
<AntennaControls
|
275
|
+
antennas={antennas}
|
276
|
+
selectedAntenna={selectedAntenna}
|
277
|
+
antennaNumber={1}
|
278
|
+
electricalTiltIndex={ant1ElectricalTilt}
|
279
|
+
mechanicalTilt={ant1MechanicalTilt}
|
280
|
+
colorTheme="primary"
|
281
|
+
onAntennaChange={handleAntenna1Change}
|
282
|
+
onElectricalTiltChange={handleTilt1Change}
|
283
|
+
onMechanicalTiltChange={handleMechTilt1Change}
|
284
|
+
/>
|
285
|
+
</div>
|
286
|
+
|
287
|
+
<!-- Center Column - Chart (always centered) -->
|
288
|
+
<div class="col-md-6">
|
289
|
+
<div class="card">
|
290
|
+
<div class="card-body p-1">
|
291
|
+
<div bind:this={chartDiv} style="height: 700px;"></div>
|
292
|
+
</div>
|
293
|
+
</div>
|
294
|
+
</div>
|
295
|
+
|
296
|
+
<!-- Right Column - Antenna 2 Controls (only in compare mode) -->
|
297
|
+
<div class="col-md-3">
|
298
|
+
{#if viewMode === 'compare'}
|
299
|
+
<AntennaControls
|
300
|
+
antennas={antennas}
|
301
|
+
selectedAntenna={selectedAntenna2}
|
302
|
+
antennaNumber={2}
|
303
|
+
electricalTiltIndex={ant2ElectricalTilt}
|
304
|
+
mechanicalTilt={ant2MechanicalTilt}
|
305
|
+
colorTheme="warning"
|
306
|
+
onAntennaChange={handleAntenna2Change}
|
307
|
+
onElectricalTiltChange={handleTilt2Change}
|
308
|
+
onMechanicalTiltChange={handleMechTilt2Change}
|
309
|
+
/>
|
310
|
+
{:else}
|
311
|
+
<!-- Empty space to keep chart centered in single mode -->
|
312
|
+
<div></div>
|
313
|
+
{/if}
|
314
|
+
</div>
|
315
|
+
</div>
|
316
|
+
|
317
|
+
|
318
|
+
</div>
|
319
|
+
|
320
|
+
<!-- Settings Modal -->
|
321
|
+
<AntennaSettingsModal
|
322
|
+
show={showSettingsModal}
|
323
|
+
onClose={closeSettings}
|
324
|
+
on:dataRefresh={handleDataRefresh}
|
325
|
+
/>
|
326
|
+
|
327
|
+
<style>
|
328
|
+
/* Chart container */
|
329
|
+
:global(.plotly .plot-container) {
|
330
|
+
border-radius: 8px !important;
|
331
|
+
}
|
332
|
+
|
333
|
+
/* Main chart card styling */
|
334
|
+
.card {
|
335
|
+
border: none;
|
336
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
337
|
+
border-radius: 12px;
|
338
|
+
}
|
339
|
+
</style>
|
@@ -0,0 +1,299 @@
|
|
1
|
+
<svelte:options runes={true} />
|
2
|
+
|
3
|
+
<script lang="ts">
|
4
|
+
import { createEventDispatcher } from 'svelte';
|
5
|
+
import JsonImporter from './JsonImporter.svelte';
|
6
|
+
import MSIConverter from './MSIConverter.svelte';
|
7
|
+
import DbNotification from './DbNotification.svelte';
|
8
|
+
import { exportAntennas, clearAllAntennas } from '../utils/db-utils';
|
9
|
+
import { dbStatus } from '../stores/db-status';
|
10
|
+
|
11
|
+
interface Props {
|
12
|
+
show: boolean;
|
13
|
+
onClose: () => void;
|
14
|
+
}
|
15
|
+
|
16
|
+
let { show, onClose }: Props = $props();
|
17
|
+
|
18
|
+
const dispatch = createEventDispatcher();
|
19
|
+
|
20
|
+
let activeTab = $state<'import' | 'export' | 'manage' | 'msi'>('import');
|
21
|
+
let showClearConfirm = $state(false);
|
22
|
+
|
23
|
+
// Handle data refresh after import operations
|
24
|
+
function handleDataRefresh() {
|
25
|
+
dispatch('dataRefresh');
|
26
|
+
}
|
27
|
+
|
28
|
+
// Export data as JSON
|
29
|
+
async function handleExport() {
|
30
|
+
try {
|
31
|
+
await exportAntennas();
|
32
|
+
console.log('Data exported successfully');
|
33
|
+
} catch (error) {
|
34
|
+
console.error('Export failed:', error);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
// Clear all data with confirmation
|
39
|
+
async function handleClearData() {
|
40
|
+
if (!showClearConfirm) {
|
41
|
+
showClearConfirm = true;
|
42
|
+
return;
|
43
|
+
}
|
44
|
+
|
45
|
+
try {
|
46
|
+
await clearAllAntennas();
|
47
|
+
showClearConfirm = false;
|
48
|
+
handleDataRefresh();
|
49
|
+
console.log('All data cleared successfully');
|
50
|
+
} catch (error) {
|
51
|
+
console.error('Clear data failed:', error);
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
function cancelClear() {
|
56
|
+
showClearConfirm = false;
|
57
|
+
}
|
58
|
+
</script>
|
59
|
+
|
60
|
+
<!-- Modal -->
|
61
|
+
{#if show}
|
62
|
+
<!-- Modal backdrop -->
|
63
|
+
<div class="modal-backdrop fade show"></div>
|
64
|
+
|
65
|
+
<!-- Modal dialog -->
|
66
|
+
<div class="modal fade show d-block" tabindex="-1" role="dialog">
|
67
|
+
<div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable" role="document">
|
68
|
+
<div class="modal-content">
|
69
|
+
<!-- Modal Header -->
|
70
|
+
<div class="modal-header border-bottom">
|
71
|
+
<h4 class="modal-title">
|
72
|
+
<i class="bi bi-gear me-2"></i>
|
73
|
+
Antenna Data Management
|
74
|
+
</h4>
|
75
|
+
<button
|
76
|
+
type="button"
|
77
|
+
class="btn-close"
|
78
|
+
onclick={onClose}
|
79
|
+
aria-label="Close"
|
80
|
+
></button>
|
81
|
+
</div>
|
82
|
+
|
83
|
+
<!-- Modal Body -->
|
84
|
+
<div class="modal-body p-0">
|
85
|
+
<!-- Tab Navigation -->
|
86
|
+
<div class="border-bottom">
|
87
|
+
<div class="nav nav-tabs">
|
88
|
+
<button
|
89
|
+
class="nav-link {activeTab === 'import' ? 'active' : ''}"
|
90
|
+
type="button"
|
91
|
+
onclick={() => activeTab = 'import'}
|
92
|
+
>
|
93
|
+
<i class="bi bi-upload me-2"></i>Import JSON
|
94
|
+
</button>
|
95
|
+
<button
|
96
|
+
class="nav-link {activeTab === 'msi' ? 'active' : ''}"
|
97
|
+
type="button"
|
98
|
+
onclick={() => activeTab = 'msi'}
|
99
|
+
>
|
100
|
+
<i class="bi bi-file-earmark-text me-2"></i>Import MSI
|
101
|
+
</button>
|
102
|
+
<button
|
103
|
+
class="nav-link {activeTab === 'export' ? 'active' : ''}"
|
104
|
+
type="button"
|
105
|
+
onclick={() => activeTab = 'export'}
|
106
|
+
>
|
107
|
+
<i class="bi bi-download me-2"></i>Export Data
|
108
|
+
</button>
|
109
|
+
<button
|
110
|
+
class="nav-link {activeTab === 'manage' ? 'active' : ''}"
|
111
|
+
type="button"
|
112
|
+
onclick={() => activeTab = 'manage'}
|
113
|
+
>
|
114
|
+
<i class="bi bi-trash me-2"></i>Manage Data
|
115
|
+
</button>
|
116
|
+
</div>
|
117
|
+
</div>
|
118
|
+
|
119
|
+
<!-- Tab Content -->
|
120
|
+
<div class="tab-content p-4">
|
121
|
+
|
122
|
+
<!-- Import JSON Tab -->
|
123
|
+
{#if activeTab === 'import'}
|
124
|
+
<div class="tab-pane fade show active">
|
125
|
+
<div class="row">
|
126
|
+
<div class="col-12">
|
127
|
+
<h5 class="mb-3">Import Antenna Data from JSON</h5>
|
128
|
+
<JsonImporter on:dataRefresh={handleDataRefresh} />
|
129
|
+
</div>
|
130
|
+
</div>
|
131
|
+
</div>
|
132
|
+
{/if}
|
133
|
+
|
134
|
+
<!-- Import MSI Tab -->
|
135
|
+
{#if activeTab === 'msi'}
|
136
|
+
<div class="tab-pane fade show active">
|
137
|
+
<div class="row">
|
138
|
+
<div class="col-12">
|
139
|
+
<h5 class="mb-3">Import MSI Pattern Files</h5>
|
140
|
+
|
141
|
+
<MSIConverter on:dataRefresh={handleDataRefresh} />
|
142
|
+
</div>
|
143
|
+
</div>
|
144
|
+
</div>
|
145
|
+
{/if}
|
146
|
+
|
147
|
+
<!-- Export Data Tab -->
|
148
|
+
{#if activeTab === 'export'}
|
149
|
+
<div class="tab-pane fade show active">
|
150
|
+
<div class="row">
|
151
|
+
<div class="col-12">
|
152
|
+
<h5 class="mb-3">Export Antenna Data</h5>
|
153
|
+
|
154
|
+
<div class="card border-success">
|
155
|
+
<div class="card-body text-center">
|
156
|
+
<i class="bi bi-download text-success" style="font-size: 3rem;"></i>
|
157
|
+
<h6 class="mt-3 mb-3">Download Data Backup</h6>
|
158
|
+
<p class="text-muted mb-4">
|
159
|
+
Export all antenna patterns and metadata as a JSON file.
|
160
|
+
</p>
|
161
|
+
<button
|
162
|
+
type="button"
|
163
|
+
class="btn btn-success btn-lg"
|
164
|
+
onclick={handleExport}
|
165
|
+
>
|
166
|
+
<i class="bi bi-download me-2"></i>
|
167
|
+
Export JSON File
|
168
|
+
</button>
|
169
|
+
</div>
|
170
|
+
</div>
|
171
|
+
</div>
|
172
|
+
</div>
|
173
|
+
</div>
|
174
|
+
{/if}
|
175
|
+
|
176
|
+
<!-- Manage Data Tab -->
|
177
|
+
{#if activeTab === 'manage'}
|
178
|
+
<div class="tab-pane fade show active">
|
179
|
+
<div class="row">
|
180
|
+
<div class="col-12">
|
181
|
+
<h5 class="mb-3">Manage Database</h5>
|
182
|
+
|
183
|
+
|
184
|
+
<!-- Database Status -->
|
185
|
+
<div class="card border-info mb-4">
|
186
|
+
<div class="card-body">
|
187
|
+
<h6 class="card-title">
|
188
|
+
<i class="bi bi-info-circle me-2"></i>Database Status
|
189
|
+
</h6>
|
190
|
+
<DbNotification />
|
191
|
+
</div>
|
192
|
+
</div>
|
193
|
+
|
194
|
+
<!-- Clear Data Section -->
|
195
|
+
<div class="card border-danger">
|
196
|
+
<div class="card-body">
|
197
|
+
<h6 class="card-title text-danger">
|
198
|
+
<i class="bi bi-exclamation-triangle me-2"></i>Danger Zone
|
199
|
+
</h6>
|
200
|
+
<p class="text-muted mb-3">
|
201
|
+
Permanently delete all antenna data from the database. This action cannot be undone.
|
202
|
+
</p>
|
203
|
+
|
204
|
+
{#if !showClearConfirm}
|
205
|
+
<button
|
206
|
+
type="button"
|
207
|
+
class="btn btn-outline-danger"
|
208
|
+
onclick={handleClearData}
|
209
|
+
>
|
210
|
+
<i class="bi bi-trash me-2"></i>
|
211
|
+
Clear All Data
|
212
|
+
</button>
|
213
|
+
{:else}
|
214
|
+
<div class="alert alert-danger" role="alert">
|
215
|
+
<strong>Are you sure?</strong> This will permanently delete all antenna data.
|
216
|
+
</div>
|
217
|
+
<div class="d-flex gap-2">
|
218
|
+
<button
|
219
|
+
type="button"
|
220
|
+
class="btn btn-danger"
|
221
|
+
onclick={handleClearData}
|
222
|
+
>
|
223
|
+
<i class="bi bi-trash me-2"></i>
|
224
|
+
Yes, Delete All Data
|
225
|
+
</button>
|
226
|
+
<button
|
227
|
+
type="button"
|
228
|
+
class="btn btn-secondary"
|
229
|
+
onclick={cancelClear}
|
230
|
+
>
|
231
|
+
Cancel
|
232
|
+
</button>
|
233
|
+
</div>
|
234
|
+
{/if}
|
235
|
+
</div>
|
236
|
+
</div>
|
237
|
+
</div>
|
238
|
+
</div>
|
239
|
+
</div>
|
240
|
+
{/if}
|
241
|
+
|
242
|
+
</div>
|
243
|
+
</div>
|
244
|
+
|
245
|
+
<!-- Modal Footer -->
|
246
|
+
<div class="modal-footer border-top">
|
247
|
+
<button
|
248
|
+
type="button"
|
249
|
+
class="btn btn-secondary"
|
250
|
+
onclick={onClose}
|
251
|
+
>
|
252
|
+
Close
|
253
|
+
</button>
|
254
|
+
</div>
|
255
|
+
</div>
|
256
|
+
</div>
|
257
|
+
</div>
|
258
|
+
{/if}
|
259
|
+
|
260
|
+
<style>
|
261
|
+
.modal {
|
262
|
+
background-color: rgba(0, 0, 0, 0.5);
|
263
|
+
}
|
264
|
+
|
265
|
+
.modal-xl {
|
266
|
+
max-width: 1140px;
|
267
|
+
}
|
268
|
+
|
269
|
+
.nav-tabs {
|
270
|
+
border-bottom: 1px solid #dee2e6;
|
271
|
+
}
|
272
|
+
|
273
|
+
.nav-tabs .nav-link {
|
274
|
+
border: none;
|
275
|
+
border-bottom: 3px solid transparent;
|
276
|
+
background: none;
|
277
|
+
color: #6c757d;
|
278
|
+
padding: 1rem 1.5rem;
|
279
|
+
}
|
280
|
+
|
281
|
+
.nav-tabs .nav-link:hover {
|
282
|
+
border-bottom-color: #e9ecef;
|
283
|
+
color: #495057;
|
284
|
+
}
|
285
|
+
|
286
|
+
.nav-tabs .nav-link.active {
|
287
|
+
color: #0d6efd;
|
288
|
+
border-bottom-color: #0d6efd;
|
289
|
+
background: none;
|
290
|
+
}
|
291
|
+
|
292
|
+
.card {
|
293
|
+
transition: box-shadow 0.15s ease-in-out;
|
294
|
+
}
|
295
|
+
|
296
|
+
.card:hover {
|
297
|
+
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
|
298
|
+
}
|
299
|
+
</style>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
interface Props {
|
2
|
+
show: boolean;
|
3
|
+
onClose: () => void;
|
4
|
+
}
|
5
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
6
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
7
|
+
$$bindings?: Bindings;
|
8
|
+
} & Exports;
|
9
|
+
(internal: unknown, props: Props & {
|
10
|
+
$$events?: Events;
|
11
|
+
$$slots?: Slots;
|
12
|
+
}): Exports & {
|
13
|
+
$set?: any;
|
14
|
+
$on?: any;
|
15
|
+
};
|
16
|
+
z_$$bindings?: Bindings;
|
17
|
+
}
|
18
|
+
declare const AntennaSettingsModal: $$__sveltets_2_IsomorphicComponent<Props, {
|
19
|
+
dataRefresh: CustomEvent<any>;
|
20
|
+
} & {
|
21
|
+
[evt: string]: CustomEvent<any>;
|
22
|
+
}, {}, {}, "">;
|
23
|
+
type AntennaSettingsModal = InstanceType<typeof AntennaSettingsModal>;
|
24
|
+
export default AntennaSettingsModal;
|