@smartnet360/svelte-components 0.0.142 → 0.0.144
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-tools/components/AntennaControls.svelte +14 -6
- package/dist/apps/antenna-tools/components/AntennaTools.svelte +6 -5
- package/dist/core/Auth/auth.svelte.js +72 -39
- package/dist/core/Auth/config.d.ts +1 -0
- package/dist/core/Auth/config.js +3 -4
- package/dist/map-v3/demo/DemoMap.svelte +3 -1
- package/dist/map-v3/features/custom/components/CustomCellSetManager.svelte +205 -14
- package/dist/map-v3/features/custom/components/CustomCellSetManager.svelte.d.ts +3 -0
- package/dist/map-v3/features/custom/components/ServerSetBrowser.svelte +398 -0
- package/dist/map-v3/features/custom/components/ServerSetBrowser.svelte.d.ts +22 -0
- package/dist/map-v3/features/custom/components/index.d.ts +1 -0
- package/dist/map-v3/features/custom/components/index.js +1 -0
- package/dist/map-v3/features/custom/db/custom-sets-api.d.ts +65 -0
- package/dist/map-v3/features/custom/db/custom-sets-api.js +220 -0
- package/dist/map-v3/features/custom/db/custom-sets-repository.d.ts +77 -0
- package/dist/map-v3/features/custom/db/custom-sets-repository.js +195 -0
- package/dist/map-v3/features/custom/db/index.d.ts +10 -0
- package/dist/map-v3/features/custom/db/index.js +9 -0
- package/dist/map-v3/features/custom/db/schema.sql +102 -0
- package/dist/map-v3/features/custom/db/types.d.ts +95 -0
- package/dist/map-v3/features/custom/db/types.js +95 -0
- package/dist/map-v3/features/custom/index.d.ts +2 -0
- package/dist/map-v3/features/custom/index.js +2 -0
- package/dist/map-v3/features/custom/logic/csv-parser.d.ts +12 -1
- package/dist/map-v3/features/custom/logic/csv-parser.js +54 -16
- package/dist/map-v3/features/custom/logic/tree-adapter.js +5 -3
- package/dist/map-v3/features/custom/stores/custom-cell-sets.svelte.d.ts +5 -1
- package/dist/map-v3/features/custom/stores/custom-cell-sets.svelte.js +6 -3
- package/dist/shared/csv-import/ColumnMapper.svelte +194 -0
- package/dist/shared/csv-import/ColumnMapper.svelte.d.ts +22 -0
- package/dist/shared/csv-import/column-detector.d.ts +58 -0
- package/dist/shared/csv-import/column-detector.js +228 -0
- package/dist/shared/csv-import/index.d.ts +10 -0
- package/dist/shared/csv-import/index.js +12 -0
- package/dist/shared/csv-import/types.d.ts +67 -0
- package/dist/shared/csv-import/types.js +70 -0
- package/package.json +1 -1
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Server Set Browser
|
|
4
|
+
*
|
|
5
|
+
* Modal component for browsing, loading, and deleting shared custom sets from the server.
|
|
6
|
+
* Shows a list of available sets with load/delete actions.
|
|
7
|
+
* Prompts user for overwrite/skip when loading a set with conflicting name.
|
|
8
|
+
*/
|
|
9
|
+
import type { CustomSetsApiClient } from '../db/custom-sets-api';
|
|
10
|
+
import type { CustomSetListItem } from '../db/types';
|
|
11
|
+
import type { CustomCellSet } from '../types';
|
|
12
|
+
import type { CustomCellSetsStore } from '../stores/custom-cell-sets.svelte';
|
|
13
|
+
|
|
14
|
+
interface Props {
|
|
15
|
+
/** API client for server operations */
|
|
16
|
+
apiClient: CustomSetsApiClient;
|
|
17
|
+
/** Local sets store for importing */
|
|
18
|
+
setsStore: CustomCellSetsStore;
|
|
19
|
+
/** Whether the modal is visible */
|
|
20
|
+
show: boolean;
|
|
21
|
+
/** Called when modal should close */
|
|
22
|
+
onclose: () => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let {
|
|
26
|
+
apiClient,
|
|
27
|
+
setsStore,
|
|
28
|
+
show,
|
|
29
|
+
onclose
|
|
30
|
+
}: Props = $props();
|
|
31
|
+
|
|
32
|
+
// State
|
|
33
|
+
let loading = $state(true);
|
|
34
|
+
let serverSets = $state<CustomSetListItem[]>([]);
|
|
35
|
+
let error = $state('');
|
|
36
|
+
let searchQuery = $state('');
|
|
37
|
+
|
|
38
|
+
// Loading/action state
|
|
39
|
+
let loadingSetId = $state<string | null>(null);
|
|
40
|
+
let deletingSetId = $state<string | null>(null);
|
|
41
|
+
|
|
42
|
+
// Conflict resolution modal
|
|
43
|
+
let conflictSet = $state<CustomSetListItem | null>(null);
|
|
44
|
+
let conflictLocalSet = $state<CustomCellSet | null>(null);
|
|
45
|
+
let loadedSetData = $state<CustomCellSet | null>(null);
|
|
46
|
+
|
|
47
|
+
// Filtered sets based on search
|
|
48
|
+
let filteredSets = $derived.by(() => {
|
|
49
|
+
if (!searchQuery.trim()) return serverSets;
|
|
50
|
+
const query = searchQuery.toLowerCase();
|
|
51
|
+
return serverSets.filter(s =>
|
|
52
|
+
s.name.toLowerCase().includes(query) ||
|
|
53
|
+
s.created_by.toLowerCase().includes(query)
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Load sets when modal opens
|
|
58
|
+
$effect(() => {
|
|
59
|
+
if (show) {
|
|
60
|
+
loadServerSets();
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
async function loadServerSets() {
|
|
65
|
+
loading = true;
|
|
66
|
+
error = '';
|
|
67
|
+
|
|
68
|
+
const result = await apiClient.listSets();
|
|
69
|
+
|
|
70
|
+
if (result.success && result.data) {
|
|
71
|
+
serverSets = result.data;
|
|
72
|
+
} else {
|
|
73
|
+
error = result.error || 'Failed to load sets from server';
|
|
74
|
+
serverSets = [];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
loading = false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function handleLoad(set: CustomSetListItem) {
|
|
81
|
+
loadingSetId = set.id;
|
|
82
|
+
error = '';
|
|
83
|
+
|
|
84
|
+
// Fetch full set data
|
|
85
|
+
const result = await apiClient.getSet(set.id);
|
|
86
|
+
|
|
87
|
+
if (!result.success || !result.data) {
|
|
88
|
+
error = result.error || 'Failed to load set';
|
|
89
|
+
loadingSetId = null;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Check for name conflict with local sets
|
|
94
|
+
const existingLocal = setsStore.sets.find(s => s.name === result.data!.name);
|
|
95
|
+
|
|
96
|
+
if (existingLocal) {
|
|
97
|
+
// Show conflict resolution modal
|
|
98
|
+
conflictSet = set;
|
|
99
|
+
conflictLocalSet = existingLocal;
|
|
100
|
+
loadedSetData = result.data;
|
|
101
|
+
loadingSetId = null;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// No conflict - import directly
|
|
106
|
+
importSetToStore(result.data);
|
|
107
|
+
loadingSetId = null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function handleConflictOverwrite() {
|
|
111
|
+
if (!loadedSetData || !conflictLocalSet) return;
|
|
112
|
+
|
|
113
|
+
// Remove existing local set
|
|
114
|
+
setsStore.removeSet(conflictLocalSet.id);
|
|
115
|
+
|
|
116
|
+
// Import the new one
|
|
117
|
+
importSetToStore(loadedSetData);
|
|
118
|
+
|
|
119
|
+
// Clear conflict state
|
|
120
|
+
conflictSet = null;
|
|
121
|
+
conflictLocalSet = null;
|
|
122
|
+
loadedSetData = null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function handleConflictSkip() {
|
|
126
|
+
// Just clear the conflict state
|
|
127
|
+
conflictSet = null;
|
|
128
|
+
conflictLocalSet = null;
|
|
129
|
+
loadedSetData = null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function importSetToStore(set: CustomCellSet) {
|
|
133
|
+
// Create import result format from set
|
|
134
|
+
const importResult = {
|
|
135
|
+
cells: set.cells,
|
|
136
|
+
unmatchedTxIds: set.unmatchedTxIds,
|
|
137
|
+
groups: set.groups,
|
|
138
|
+
extraColumns: set.extraColumns,
|
|
139
|
+
totalRows: set.cells.length,
|
|
140
|
+
cellCount: set.cells.filter(c => c.geometry === 'cell').length,
|
|
141
|
+
pointCount: set.cells.filter(c => c.geometry === 'point').length
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// Create the set in local store
|
|
145
|
+
const newSet = setsStore.createSet(set.name, importResult);
|
|
146
|
+
|
|
147
|
+
// Apply styling from loaded set
|
|
148
|
+
setsStore.updateSetSettings(newSet.id, {
|
|
149
|
+
baseSize: set.baseSize,
|
|
150
|
+
pointSize: set.pointSize,
|
|
151
|
+
opacity: set.opacity,
|
|
152
|
+
defaultColor: set.defaultColor
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Apply group colors
|
|
156
|
+
for (const [group, color] of Object.entries(set.groupColors)) {
|
|
157
|
+
setsStore.setGroupColor(newSet.id, group, color);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function handleDelete(set: CustomSetListItem) {
|
|
162
|
+
if (!confirm(`Delete "${set.name}" from server? This cannot be undone.`)) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
deletingSetId = set.id;
|
|
167
|
+
error = '';
|
|
168
|
+
|
|
169
|
+
const result = await apiClient.deleteSet(set.id);
|
|
170
|
+
|
|
171
|
+
if (result.success) {
|
|
172
|
+
// Remove from local list
|
|
173
|
+
serverSets = serverSets.filter(s => s.id !== set.id);
|
|
174
|
+
} else {
|
|
175
|
+
error = result.error || 'Failed to delete set';
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
deletingSetId = null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function formatDate(dateStr: string): string {
|
|
182
|
+
try {
|
|
183
|
+
const date = new Date(dateStr);
|
|
184
|
+
return date.toLocaleDateString(undefined, {
|
|
185
|
+
year: 'numeric',
|
|
186
|
+
month: 'short',
|
|
187
|
+
day: 'numeric'
|
|
188
|
+
});
|
|
189
|
+
} catch {
|
|
190
|
+
return dateStr;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function getItemSummary(set: CustomSetListItem): string {
|
|
195
|
+
const parts: string[] = [];
|
|
196
|
+
if (set.cellCount && set.cellCount > 0) {
|
|
197
|
+
parts.push(`${set.cellCount} cells`);
|
|
198
|
+
}
|
|
199
|
+
if (set.pointCount && set.pointCount > 0) {
|
|
200
|
+
parts.push(`${set.pointCount} points`);
|
|
201
|
+
}
|
|
202
|
+
return parts.join(', ') || 'No items';
|
|
203
|
+
}
|
|
204
|
+
</script>
|
|
205
|
+
|
|
206
|
+
{#if show}
|
|
207
|
+
<div class="modal fade show d-block" tabindex="-1" style="background: rgba(0,0,0,0.5);">
|
|
208
|
+
<div class="modal-dialog modal-dialog-centered modal-lg">
|
|
209
|
+
<div class="modal-content">
|
|
210
|
+
<div class="modal-header py-2">
|
|
211
|
+
<h6 class="modal-title">
|
|
212
|
+
<i class="bi bi-cloud-download me-2"></i>
|
|
213
|
+
Load from Server
|
|
214
|
+
</h6>
|
|
215
|
+
<button type="button" class="btn-close" onclick={onclose} aria-label="Close"></button>
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<div class="modal-body p-0">
|
|
219
|
+
<!-- Search bar -->
|
|
220
|
+
<div class="p-2 border-bottom">
|
|
221
|
+
<div class="input-group input-group-sm">
|
|
222
|
+
<span class="input-group-text">
|
|
223
|
+
<i class="bi bi-search"></i>
|
|
224
|
+
</span>
|
|
225
|
+
<input
|
|
226
|
+
type="text"
|
|
227
|
+
class="form-control"
|
|
228
|
+
placeholder="Search sets..."
|
|
229
|
+
bind:value={searchQuery}
|
|
230
|
+
/>
|
|
231
|
+
{#if searchQuery}
|
|
232
|
+
<button
|
|
233
|
+
class="btn btn-outline-secondary"
|
|
234
|
+
type="button"
|
|
235
|
+
onclick={() => searchQuery = ''}
|
|
236
|
+
aria-label="Clear search"
|
|
237
|
+
>
|
|
238
|
+
<i class="bi bi-x"></i>
|
|
239
|
+
</button>
|
|
240
|
+
{/if}
|
|
241
|
+
<button
|
|
242
|
+
class="btn btn-outline-secondary"
|
|
243
|
+
type="button"
|
|
244
|
+
onclick={loadServerSets}
|
|
245
|
+
disabled={loading}
|
|
246
|
+
title="Refresh"
|
|
247
|
+
aria-label="Refresh list"
|
|
248
|
+
>
|
|
249
|
+
<i class="bi bi-arrow-clockwise" class:spin={loading}></i>
|
|
250
|
+
</button>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
<!-- Error message -->
|
|
255
|
+
{#if error}
|
|
256
|
+
<div class="alert alert-danger m-2 py-2 small">
|
|
257
|
+
<i class="bi bi-exclamation-triangle me-1"></i>
|
|
258
|
+
{error}
|
|
259
|
+
</div>
|
|
260
|
+
{/if}
|
|
261
|
+
|
|
262
|
+
<!-- Loading state -->
|
|
263
|
+
{#if loading}
|
|
264
|
+
<div class="text-center p-4">
|
|
265
|
+
<div class="spinner-border spinner-border-sm text-primary" role="status">
|
|
266
|
+
<span class="visually-hidden">Loading...</span>
|
|
267
|
+
</div>
|
|
268
|
+
<p class="text-muted small mt-2 mb-0">Loading sets from server...</p>
|
|
269
|
+
</div>
|
|
270
|
+
{:else if filteredSets.length === 0}
|
|
271
|
+
<div class="text-center p-4">
|
|
272
|
+
<i class="bi bi-inbox fs-1 text-muted"></i>
|
|
273
|
+
<p class="text-muted small mt-2 mb-0">
|
|
274
|
+
{searchQuery ? 'No sets match your search' : 'No shared sets available'}
|
|
275
|
+
</p>
|
|
276
|
+
</div>
|
|
277
|
+
{:else}
|
|
278
|
+
<!-- Sets list -->
|
|
279
|
+
<div class="sets-list" style="max-height: 400px; overflow-y: auto;">
|
|
280
|
+
{#each filteredSets as set (set.id)}
|
|
281
|
+
<div class="set-row d-flex align-items-center px-3 py-2 border-bottom">
|
|
282
|
+
<div class="flex-grow-1" style="min-width: 0;">
|
|
283
|
+
<div class="fw-medium text-truncate">{set.name}</div>
|
|
284
|
+
<div class="small text-muted">
|
|
285
|
+
{getItemSummary(set)}
|
|
286
|
+
{#if set.groups && set.groups.length > 0}
|
|
287
|
+
<span class="mx-1">·</span>
|
|
288
|
+
{set.groups.length} groups
|
|
289
|
+
{/if}
|
|
290
|
+
</div>
|
|
291
|
+
<div class="small text-muted">
|
|
292
|
+
<i class="bi bi-person me-1"></i>{set.created_by}
|
|
293
|
+
<span class="mx-1">·</span>
|
|
294
|
+
<i class="bi bi-calendar me-1"></i>{formatDate(set.updated_at)}
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
<div class="d-flex gap-1 ms-2">
|
|
298
|
+
<button
|
|
299
|
+
class="btn btn-sm btn-outline-primary"
|
|
300
|
+
onclick={() => handleLoad(set)}
|
|
301
|
+
disabled={loadingSetId === set.id}
|
|
302
|
+
title="Load this set"
|
|
303
|
+
aria-label="Load this set"
|
|
304
|
+
>
|
|
305
|
+
{#if loadingSetId === set.id}
|
|
306
|
+
<span class="spinner-border spinner-border-sm" role="status"></span>
|
|
307
|
+
{:else}
|
|
308
|
+
<i class="bi bi-download"></i>
|
|
309
|
+
{/if}
|
|
310
|
+
</button>
|
|
311
|
+
<button
|
|
312
|
+
class="btn btn-sm btn-outline-danger"
|
|
313
|
+
onclick={() => handleDelete(set)}
|
|
314
|
+
disabled={deletingSetId === set.id}
|
|
315
|
+
title="Delete from server"
|
|
316
|
+
aria-label="Delete from server"
|
|
317
|
+
>
|
|
318
|
+
{#if deletingSetId === set.id}
|
|
319
|
+
<span class="spinner-border spinner-border-sm" role="status"></span>
|
|
320
|
+
{:else}
|
|
321
|
+
<i class="bi bi-trash"></i>
|
|
322
|
+
{/if}
|
|
323
|
+
</button>
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
{/each}
|
|
327
|
+
</div>
|
|
328
|
+
{/if}
|
|
329
|
+
</div>
|
|
330
|
+
|
|
331
|
+
<div class="modal-footer py-2">
|
|
332
|
+
<small class="text-muted me-auto">
|
|
333
|
+
{filteredSets.length} set{filteredSets.length !== 1 ? 's' : ''} available
|
|
334
|
+
</small>
|
|
335
|
+
<button type="button" class="btn btn-secondary btn-sm" onclick={onclose}>
|
|
336
|
+
Close
|
|
337
|
+
</button>
|
|
338
|
+
</div>
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
</div>
|
|
342
|
+
{/if}
|
|
343
|
+
|
|
344
|
+
<!-- Conflict Resolution Modal -->
|
|
345
|
+
{#if conflictSet && conflictLocalSet}
|
|
346
|
+
<div class="modal fade show d-block" tabindex="-1" style="background: rgba(0,0,0,0.6); z-index: 2001;">
|
|
347
|
+
<div class="modal-dialog modal-dialog-centered">
|
|
348
|
+
<div class="modal-content">
|
|
349
|
+
<div class="modal-header py-2 bg-warning-subtle">
|
|
350
|
+
<h6 class="modal-title">
|
|
351
|
+
<i class="bi bi-exclamation-triangle me-2"></i>
|
|
352
|
+
Name Conflict
|
|
353
|
+
</h6>
|
|
354
|
+
</div>
|
|
355
|
+
<div class="modal-body">
|
|
356
|
+
<p>
|
|
357
|
+
A set named <strong>"{conflictSet.name}"</strong> already exists locally.
|
|
358
|
+
</p>
|
|
359
|
+
<p class="text-muted small mb-0">
|
|
360
|
+
What would you like to do?
|
|
361
|
+
</p>
|
|
362
|
+
</div>
|
|
363
|
+
<div class="modal-footer py-2">
|
|
364
|
+
<button type="button" class="btn btn-secondary btn-sm" onclick={handleConflictSkip}>
|
|
365
|
+
Skip
|
|
366
|
+
</button>
|
|
367
|
+
<button type="button" class="btn btn-warning btn-sm" onclick={handleConflictOverwrite}>
|
|
368
|
+
<i class="bi bi-arrow-repeat me-1"></i>
|
|
369
|
+
Overwrite Local
|
|
370
|
+
</button>
|
|
371
|
+
</div>
|
|
372
|
+
</div>
|
|
373
|
+
</div>
|
|
374
|
+
</div>
|
|
375
|
+
{/if}
|
|
376
|
+
|
|
377
|
+
<style>
|
|
378
|
+
.modal {
|
|
379
|
+
z-index: 2000;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.set-row {
|
|
383
|
+
transition: background-color 0.15s ease;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.set-row:hover {
|
|
387
|
+
background-color: rgba(0, 0, 0, 0.02);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.spin {
|
|
391
|
+
animation: spin 1s linear infinite;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
@keyframes spin {
|
|
395
|
+
from { transform: rotate(0deg); }
|
|
396
|
+
to { transform: rotate(360deg); }
|
|
397
|
+
}
|
|
398
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Set Browser
|
|
3
|
+
*
|
|
4
|
+
* Modal component for browsing, loading, and deleting shared custom sets from the server.
|
|
5
|
+
* Shows a list of available sets with load/delete actions.
|
|
6
|
+
* Prompts user for overwrite/skip when loading a set with conflicting name.
|
|
7
|
+
*/
|
|
8
|
+
import type { CustomSetsApiClient } from '../db/custom-sets-api';
|
|
9
|
+
import type { CustomCellSetsStore } from '../stores/custom-cell-sets.svelte';
|
|
10
|
+
interface Props {
|
|
11
|
+
/** API client for server operations */
|
|
12
|
+
apiClient: CustomSetsApiClient;
|
|
13
|
+
/** Local sets store for importing */
|
|
14
|
+
setsStore: CustomCellSetsStore;
|
|
15
|
+
/** Whether the modal is visible */
|
|
16
|
+
show: boolean;
|
|
17
|
+
/** Called when modal should close */
|
|
18
|
+
onclose: () => void;
|
|
19
|
+
}
|
|
20
|
+
declare const ServerSetBrowser: import("svelte").Component<Props, {}, "">;
|
|
21
|
+
type ServerSetBrowser = ReturnType<typeof ServerSetBrowser>;
|
|
22
|
+
export default ServerSetBrowser;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom Feature - API Client
|
|
3
|
+
*
|
|
4
|
+
* Client-side service for interacting with custom cell sets API.
|
|
5
|
+
* Designed to work with any backend that implements the expected endpoints.
|
|
6
|
+
*
|
|
7
|
+
* Usage in consuming app:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const api = new CustomSetsApiClient('/api/custom-sets');
|
|
10
|
+
* const sets = await api.listSets();
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
import type { CustomSetListItem, ApiResponse } from './types';
|
|
14
|
+
import type { CustomCellSet } from '../types';
|
|
15
|
+
/**
|
|
16
|
+
* API client for custom cell sets
|
|
17
|
+
* Provides CRUD operations against a REST API endpoint
|
|
18
|
+
*/
|
|
19
|
+
export declare class CustomSetsApiClient {
|
|
20
|
+
private baseUrl;
|
|
21
|
+
private headers;
|
|
22
|
+
/**
|
|
23
|
+
* Create a new API client
|
|
24
|
+
* @param baseUrl Base URL for the API (e.g., '/api/custom-sets')
|
|
25
|
+
* @param headers Optional additional headers (e.g., auth tokens)
|
|
26
|
+
*/
|
|
27
|
+
constructor(baseUrl: string, headers?: Record<string, string>);
|
|
28
|
+
/**
|
|
29
|
+
* Update headers (e.g., after auth token refresh)
|
|
30
|
+
*/
|
|
31
|
+
setHeaders(headers: Record<string, string>): void;
|
|
32
|
+
/**
|
|
33
|
+
* List all available sets (lightweight, no cell data)
|
|
34
|
+
*/
|
|
35
|
+
listSets(): Promise<ApiResponse<CustomSetListItem[]>>;
|
|
36
|
+
/**
|
|
37
|
+
* Get a single set by ID (full data including cells)
|
|
38
|
+
*/
|
|
39
|
+
getSet(id: string): Promise<ApiResponse<CustomCellSet>>;
|
|
40
|
+
/**
|
|
41
|
+
* Save a set to the server (create or update)
|
|
42
|
+
* @param set The CustomCellSet to save
|
|
43
|
+
* @param id Optional ID for update (omit for create)
|
|
44
|
+
*/
|
|
45
|
+
saveSet(set: CustomCellSet, id?: string): Promise<ApiResponse<{
|
|
46
|
+
id: string;
|
|
47
|
+
}>>;
|
|
48
|
+
/**
|
|
49
|
+
* Delete a set from the server
|
|
50
|
+
*/
|
|
51
|
+
deleteSet(id: string): Promise<ApiResponse<void>>;
|
|
52
|
+
/**
|
|
53
|
+
* Check if a set with the given name exists
|
|
54
|
+
*/
|
|
55
|
+
checkNameExists(name: string): Promise<ApiResponse<{
|
|
56
|
+
exists: boolean;
|
|
57
|
+
id?: string;
|
|
58
|
+
}>>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Factory function to create API client
|
|
62
|
+
* @param baseUrl API endpoint base URL
|
|
63
|
+
* @param headers Optional headers (e.g., auth tokens)
|
|
64
|
+
*/
|
|
65
|
+
export declare function createCustomSetsApi(baseUrl: string, headers?: Record<string, string>): CustomSetsApiClient;
|