@svadmin/ui 0.88.1 → 0.92.0
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/app.css +4 -0
- package/dist/app.theme.css +4 -0
- package/dist/component-registry.svelte.d.ts +2 -2
- package/dist/components/AboutSettings.svelte +23 -4
- package/dist/components/AdminApp.svelte +6 -4
- package/dist/components/AdminApp.svelte.d.ts +3 -3
- package/dist/components/ApiSettings.svelte +43 -27
- package/dist/components/ApprovalActionCard.svelte +8 -9
- package/dist/components/ApprovalCenter.svelte +24 -5
- package/dist/components/AuditLogViewer.svelte +2 -2
- package/dist/components/AutoComplete.svelte +610 -0
- package/dist/components/AutoComplete.svelte.d.ts +25 -0
- package/dist/components/AutoForm.svelte +265 -18
- package/dist/components/AutoForm.svelte.d.ts +19 -2
- package/dist/components/AutoTable.svelte +141 -36
- package/dist/components/AutoTable.svelte.d.ts +8 -0
- package/dist/components/BatchActionBar.svelte +42 -14
- package/dist/components/BatchActionBar.svelte.d.ts +5 -0
- package/dist/components/BoundRecordDetailDrawer.svelte +5 -3
- package/dist/components/CancelTaskButton.svelte +14 -1
- package/dist/components/Cascader.svelte +412 -53
- package/dist/components/Cascader.svelte.d.ts +7 -1
- package/dist/components/ColorPicker.svelte +1 -1
- package/dist/components/ColorPicker.svelte.d.ts +1 -1
- package/dist/components/ComboboxField.svelte +270 -34
- package/dist/components/ComboboxField.svelte.d.ts +4 -0
- package/dist/components/CommandPalette.svelte +4 -4
- package/dist/components/DashboardView.svelte +73 -7
- package/dist/components/DashboardView.svelte.d.ts +3 -1
- package/dist/components/DateRangeInput.svelte +8 -1
- package/dist/components/DetailWorkspaceAsyncSection.svelte +107 -0
- package/dist/components/DetailWorkspaceAsyncSection.svelte.d.ts +36 -0
- package/dist/components/DetailWorkspaceSections.svelte +233 -0
- package/dist/components/DetailWorkspaceSections.svelte.d.ts +9 -0
- package/dist/components/DrawerForm.svelte +78 -9
- package/dist/components/DrawerForm.svelte.d.ts +3 -3
- package/dist/components/ErrorBoundary.svelte +1 -1
- package/dist/components/ErrorComponent.svelte +19 -6
- package/dist/components/ErrorComponent.svelte.d.ts +1 -0
- package/dist/components/ErrorSummary.svelte +9 -4
- package/dist/components/FieldRenderer.svelte +203 -90
- package/dist/components/FieldRenderer.svelte.d.ts +16 -1
- package/dist/components/FileUpload.svelte +116 -51
- package/dist/components/FileUpload.svelte.d.ts +7 -27
- package/dist/components/FileUploadField.svelte +170 -0
- package/dist/components/FileUploadField.svelte.d.ts +21 -0
- package/dist/components/FilterBuilder.svelte +13 -7
- package/dist/components/FilterCollectionInput.svelte +9 -7
- package/dist/components/FilterCollectionInput.svelte.d.ts +3 -0
- package/dist/components/ForgotPasswordPage.svelte +1 -1
- package/dist/components/Header.svelte +1 -1
- package/dist/components/ImportWizard.svelte +197 -28
- package/dist/components/ImportWizard.svelte.d.ts +5 -1
- package/dist/components/InferencerPanel.svelte +4 -2
- package/dist/components/InfiniteList.svelte +52 -9
- package/dist/components/JsonSchemaForm.svelte +237 -42
- package/dist/components/JsonSchemaForm.svelte.d.ts +10 -3
- package/dist/components/KanbanBoard.svelte +43 -7
- package/dist/components/KanbanBoard.svelte.d.ts +2 -2
- package/dist/components/Layout.svelte +1 -1
- package/dist/components/LoginPage.svelte +1 -1
- package/dist/components/MetricStrip.svelte +8 -3
- package/dist/components/MetricStrip.svelte.d.ts +1 -0
- package/dist/components/ModalForm.svelte +85 -9
- package/dist/components/ModalForm.svelte.d.ts +3 -3
- package/dist/components/MoneyInput.svelte +5 -3
- package/dist/components/MoneyInput.svelte.d.ts +4 -2
- package/dist/components/MultiTabKeepAlive.svelte +502 -43
- package/dist/components/MultiTabKeepAlive.svelte.d.ts +40 -6
- package/dist/components/NotificationsSettings.svelte +10 -10
- package/dist/components/NumberInput.svelte +5 -3
- package/dist/components/NumberInput.svelte.d.ts +4 -2
- package/dist/components/NumericInput.svelte +277 -25
- package/dist/components/NumericInput.svelte.d.ts +3 -1
- package/dist/components/PercentInput.svelte +5 -3
- package/dist/components/PercentInput.svelte.d.ts +4 -2
- package/dist/components/PermissionMatrix.svelte +44 -8
- package/dist/components/PermissionMatrix.svelte.d.ts +1 -0
- package/dist/components/ProfilePage.svelte +38 -13
- package/dist/components/RadioGroup.svelte +203 -4
- package/dist/components/RadioGroup.svelte.d.ts +1 -1
- package/dist/components/Rate.svelte +3 -3
- package/dist/components/Rate.svelte.d.ts +2 -2
- package/dist/components/RecordDetailDrawer.svelte +1 -1
- package/dist/components/RecordDetailDrawer.svelte.d.ts +1 -1
- package/dist/components/RegisterPage.svelte +1 -1
- package/dist/components/RelationPicker.svelte +39 -11
- package/dist/components/ResourceAccessGuard.svelte +7 -2
- package/dist/components/RetryTaskButton.svelte +14 -1
- package/dist/components/RolesSettings.svelte +74 -28
- package/dist/components/SecuritySettings.svelte +66 -51
- package/dist/components/SegmentedControl.svelte +4 -2
- package/dist/components/SegmentedControl.svelte.d.ts +1 -1
- package/dist/components/Sidebar.svelte +1 -1
- package/dist/components/StepsForm.svelte +62 -10
- package/dist/components/StepsForm.svelte.d.ts +4 -2
- package/dist/components/SvadminLogo.svelte +1 -0
- package/dist/components/SvarDataGrid.svelte +42 -24
- package/dist/components/SvarDataGrid.svelte.d.ts +10 -10
- package/dist/components/SvarResourceRead.svelte +2 -0
- package/dist/components/SvarResourceTableView.svelte +4 -2
- package/dist/components/TagsInput.svelte +3 -3
- package/dist/components/TagsInput.svelte.d.ts +2 -2
- package/dist/components/TaskDetails.svelte +22 -16
- package/dist/components/TaskDetails.svelte.d.ts +1 -1
- package/dist/components/TaskList.svelte +57 -15
- package/dist/components/TaskQueueDrawer.svelte +54 -34
- package/dist/components/Toast.svelte +13 -2
- package/dist/components/Transfer.svelte +67 -5
- package/dist/components/Transfer.svelte.d.ts +4 -0
- package/dist/components/TreeSelect.svelte +337 -77
- package/dist/components/TreeSelect.svelte.d.ts +4 -0
- package/dist/components/TreeTable.svelte +6 -1
- package/dist/components/TwoFactorAuthPage.svelte +8 -4
- package/dist/components/UpdatePasswordPage.svelte +1 -1
- package/dist/components/VersionDiffViewer.svelte +9 -7
- package/dist/components/account/CompanyProfilePage.svelte +13 -12
- package/dist/components/account/MemberDirectory.svelte +14 -10
- package/dist/components/account/SettingsEnterprisePage.svelte +18 -18
- package/dist/components/content/AuditTimeline.svelte +8 -6
- package/dist/components/content/DataState.svelte +1 -1
- package/dist/components/content/FileList.svelte +44 -13
- package/dist/components/content/FileList.svelte.d.ts +4 -2
- package/dist/components/content/FileListRow.svelte +87 -0
- package/dist/components/content/FileListRow.svelte.d.ts +11 -0
- package/dist/components/content/ImportDropzone.svelte +109 -12
- package/dist/components/content/ImportDropzone.svelte.d.ts +1 -0
- package/dist/components/content/IntegrationCard.svelte +3 -3
- package/dist/components/content/IntegrationCard.svelte.d.ts +2 -0
- package/dist/components/content/MediaThumbnail.svelte +6 -2
- package/dist/components/detail-workspace.d.ts +60 -0
- package/dist/components/detail-workspace.js +3 -0
- package/dist/components/enterprise/json-schema-form.d.ts +1 -1
- package/dist/components/enterprise/recursive-schema-form.d.ts +15 -1
- package/dist/components/enterprise/recursive-schema-form.js +288 -14
- package/dist/components/enterprise/schema-form-references.d.ts +14 -0
- package/dist/components/enterprise/schema-form-references.js +316 -0
- package/dist/components/fields/ArrayField.svelte +178 -14
- package/dist/components/fields/ArrayField.svelte.d.ts +17 -3
- package/dist/components/fields/array-field-metadata.d.ts +4 -0
- package/dist/components/fields/array-field-metadata.js +36 -0
- package/dist/components/file-upload-reference.d.ts +11 -0
- package/dist/components/file-upload-reference.js +50 -0
- package/dist/components/file-upload-types.d.ts +32 -0
- package/dist/components/file-upload-types.js +1 -0
- package/dist/components/form-contract.upload-type-fixture.svelte +108 -0
- package/dist/components/form-contract.upload-type-fixture.svelte.d.ts +18 -0
- package/dist/components/json-schema-form-state.d.ts +19 -0
- package/dist/components/list-deletion.svelte.js +6 -1
- package/dist/components/list-state.svelte.d.ts +12 -1
- package/dist/components/list-state.svelte.js +56 -16
- package/dist/components/numeric-format.d.ts +44 -0
- package/dist/components/numeric-format.js +198 -0
- package/dist/components/record-detail.svelte.js +2 -0
- package/dist/components/saved-list-views.d.ts +9 -2
- package/dist/components/saved-list-views.js +42 -11
- package/dist/components/saved-list-views.svelte.d.ts +3 -0
- package/dist/components/saved-list-views.svelte.js +56 -7
- package/dist/components/task-action.svelte.d.ts +1 -0
- package/dist/components/task-action.svelte.js +55 -3
- package/dist/components/task-utils.d.ts +1 -0
- package/dist/components/task-utils.js +18 -0
- package/dist/components/ui/input/input.svelte +1 -1
- package/dist/components/ui/input/input.svelte.d.ts +1 -1
- package/dist/components/ui/sheet/sheet.svelte +4 -1
- package/dist/components/version-history.d.ts +14 -0
- package/dist/components/version-history.js +32 -0
- package/dist/components/workspace-tab-state.d.ts +78 -0
- package/dist/components/workspace-tab-state.js +587 -0
- package/dist/index.d.ts +13 -1
- package/dist/index.js +4 -0
- package/package.json +5 -5
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
import * as Card from './ui/card/index.js';
|
|
19
19
|
import TaskList from './TaskList.svelte';
|
|
20
20
|
import TaskDetails from './TaskDetails.svelte';
|
|
21
|
+
import DataState from './content/DataState.svelte';
|
|
21
22
|
import {
|
|
22
23
|
isTaskActive,
|
|
24
|
+
formatTaskDate,
|
|
23
25
|
resolveTaskCreatedAt,
|
|
24
26
|
resolveTaskMessage,
|
|
25
27
|
resolveTaskTitle,
|
|
@@ -57,6 +59,9 @@
|
|
|
57
59
|
let mounted = true;
|
|
58
60
|
onDestroy(() => { mounted = false; submitAttempt = null; });
|
|
59
61
|
const activeTaskProvider = $derived(taskProvider ?? context.taskProvider);
|
|
62
|
+
const canListTasks = $derived(typeof activeTaskProvider?.list === 'function');
|
|
63
|
+
const canListDlq = $derived(typeof activeTaskProvider?.listDlq === 'function');
|
|
64
|
+
const canListCurrentTab = $derived(activeTab === 'dlq' ? canListDlq : canListTasks);
|
|
60
65
|
const taskScope = $derived({
|
|
61
66
|
provider: activeTaskProvider,
|
|
62
67
|
tenant: context.tenantCacheKey?.__svadminTenant,
|
|
@@ -99,12 +104,13 @@
|
|
|
99
104
|
const resolvedTitle = $derived(title ?? i18n.t('task.drawerTitle'));
|
|
100
105
|
|
|
101
106
|
const taskQuery = useTaskList(definedReactiveOptions({
|
|
107
|
+
errorNotification: false,
|
|
102
108
|
get taskProvider() {
|
|
103
109
|
return activeTaskProvider;
|
|
104
110
|
},
|
|
105
111
|
get queryOptions() {
|
|
106
112
|
return {
|
|
107
|
-
enabled:
|
|
113
|
+
enabled: canListTasks,
|
|
108
114
|
refetchInterval: refreshInterval,
|
|
109
115
|
refetchIntervalInBackground: true,
|
|
110
116
|
};
|
|
@@ -112,6 +118,7 @@
|
|
|
112
118
|
}));
|
|
113
119
|
|
|
114
120
|
const dlqQuery = useTaskList(definedReactiveOptions({
|
|
121
|
+
errorNotification: false,
|
|
115
122
|
get dlq() {
|
|
116
123
|
return true;
|
|
117
124
|
},
|
|
@@ -120,7 +127,7 @@
|
|
|
120
127
|
},
|
|
121
128
|
get queryOptions() {
|
|
122
129
|
return {
|
|
123
|
-
enabled:
|
|
130
|
+
enabled: canListDlq,
|
|
124
131
|
refetchInterval: refreshInterval,
|
|
125
132
|
refetchIntervalInBackground: true,
|
|
126
133
|
};
|
|
@@ -129,8 +136,9 @@
|
|
|
129
136
|
|
|
130
137
|
const submitTask = useSubmitTask();
|
|
131
138
|
|
|
132
|
-
const allTasks = $derived(taskQuery.data?.data ?? []);
|
|
133
|
-
const dlqTasks = $derived(dlqQuery.data?.data ?? []);
|
|
139
|
+
const allTasks = $derived(canListTasks ? taskQuery.data?.data ?? [] : []);
|
|
140
|
+
const dlqTasks = $derived(canListDlq ? dlqQuery.data?.data ?? [] : []);
|
|
141
|
+
const currentQuery = $derived(activeTab === 'dlq' ? dlqQuery : taskQuery);
|
|
134
142
|
|
|
135
143
|
const availableStatuses = $derived.by(() => {
|
|
136
144
|
const source = activeTab === 'dlq' ? dlqTasks : allTasks;
|
|
@@ -189,12 +197,6 @@
|
|
|
189
197
|
}
|
|
190
198
|
});
|
|
191
199
|
|
|
192
|
-
function formatTime(value: unknown) {
|
|
193
|
-
if (typeof value !== 'string' || !value) return '—';
|
|
194
|
-
const date = new Date(value);
|
|
195
|
-
if (Number.isNaN(date.getTime())) return '—';
|
|
196
|
-
return date.toLocaleString();
|
|
197
|
-
}
|
|
198
200
|
|
|
199
201
|
function resetSubmitForm() {
|
|
200
202
|
submitTaskName = '';
|
|
@@ -247,23 +249,24 @@
|
|
|
247
249
|
submitOpen = false;
|
|
248
250
|
resetSubmitForm();
|
|
249
251
|
await Promise.allSettled([
|
|
250
|
-
taskQuery.refetch?.(),
|
|
251
|
-
dlqQuery.refetch?.(),
|
|
252
|
+
...(canListTasks ? [taskQuery.refetch?.()] : []),
|
|
253
|
+
...(canListDlq ? [dlqQuery.refetch?.()] : []),
|
|
252
254
|
]);
|
|
253
|
-
} catch
|
|
255
|
+
} catch {
|
|
254
256
|
if (!current()) return;
|
|
255
|
-
submitError =
|
|
257
|
+
submitError = i18n.t('task.submitFailed');
|
|
256
258
|
} finally {
|
|
257
259
|
if (submitAttempt === attempt) submitAttempt = null;
|
|
258
260
|
}
|
|
259
261
|
}
|
|
260
262
|
|
|
261
263
|
async function refreshCurrentTab() {
|
|
264
|
+
if (!canListCurrentTab || currentQuery.isFetching) return;
|
|
262
265
|
if (activeTab === 'dlq') {
|
|
263
|
-
await dlqQuery.refetch?.();
|
|
266
|
+
await dlqQuery.refetch?.({ cancelRefetch: false });
|
|
264
267
|
return;
|
|
265
268
|
}
|
|
266
|
-
await taskQuery.refetch?.();
|
|
269
|
+
await taskQuery.refetch?.({ cancelRefetch: false });
|
|
267
270
|
}
|
|
268
271
|
</script>
|
|
269
272
|
|
|
@@ -298,9 +301,11 @@
|
|
|
298
301
|
<div class="svadmin-u-60fbb7713999 svadmin-u-1eb5c6df38c1 svadmin-u-3960ffc248d9 svadmin-u-77a2a20e90d4">
|
|
299
302
|
<ListTodo class="svadmin-u-cd0d9c512cdc svadmin-u-72470489ff4e svadmin-u-bfa603190748" />
|
|
300
303
|
<h2 class="svadmin-u-fc7473ca09eb svadmin-u-e83a7042bc91">{resolvedTitle}</h2>
|
|
301
|
-
|
|
304
|
+
{#if canListTasks}
|
|
305
|
+
<Badge variant="secondary" class="svadmin-u-359090c2d529">{i18n.t('task.activeCount', { count: runningCount })}</Badge>
|
|
306
|
+
{/if}
|
|
302
307
|
{#if allTasks[0] && resolveTaskCreatedAt(allTasks[0])}
|
|
303
|
-
<span class="svadmin-u-359090c2d529 svadmin-u-bfa603190748">{i18n.t('task.lastQueuedAt', { time:
|
|
308
|
+
<span class="svadmin-u-359090c2d529 svadmin-u-bfa603190748">{i18n.t('task.lastQueuedAt', { time: formatTaskDate(resolveTaskCreatedAt(allTasks[0]), i18n.locale) })}</span>
|
|
304
309
|
{/if}
|
|
305
310
|
</div>
|
|
306
311
|
</div>
|
|
@@ -319,16 +324,20 @@
|
|
|
319
324
|
<Tabs.List class="svadmin-u-52083e7da442 svadmin-u-5f22e64f2282 svadmin-u-ca6bcd4b6f3f svadmin-u-18049387f0af svadmin-u-b00f43c30c2b svadmin-u-eb6a3cef9686">
|
|
320
325
|
<Tabs.Trigger value="tasks" active={activeTab === 'tasks'} onclick={() => activeTab = 'tasks'}>
|
|
321
326
|
{i18n.t('task.tabTasks')}
|
|
322
|
-
|
|
327
|
+
{#if canListTasks}
|
|
328
|
+
<Badge variant="outline" class="svadmin-u-f58b02572ab2 svadmin-u-1dc571a3609f">{taskQuery.data?.total ?? allTasks.length}</Badge>
|
|
329
|
+
{/if}
|
|
323
330
|
</Tabs.Trigger>
|
|
324
331
|
<Tabs.Trigger value="dlq" active={activeTab === 'dlq'} onclick={() => activeTab = 'dlq'}>
|
|
325
332
|
{i18n.t('task.tabDlq')}
|
|
326
|
-
|
|
333
|
+
{#if canListDlq}
|
|
334
|
+
<Badge variant="outline" class="svadmin-u-f58b02572ab2 svadmin-u-1dc571a3609f">{dlqQuery.data?.total ?? dlqTasks.length}</Badge>
|
|
335
|
+
{/if}
|
|
327
336
|
</Tabs.Trigger>
|
|
328
337
|
</Tabs.List>
|
|
329
338
|
</Tabs.Root>
|
|
330
339
|
<div class="svadmin-u-fb56d9cff341 svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-77a2a20e90d4">
|
|
331
|
-
<Button variant="outline" size="sm" onclick={() => void refreshCurrentTab()}>
|
|
340
|
+
<Button variant="outline" size="sm" disabled={!canListCurrentTab || currentQuery.isFetching} onclick={() => void refreshCurrentTab()}>
|
|
332
341
|
<RefreshCw class="svadmin-u-82cc6c6581cd svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c" />
|
|
333
342
|
{i18n.t('common.refresh')}
|
|
334
343
|
</Button>
|
|
@@ -345,16 +354,17 @@
|
|
|
345
354
|
<Input
|
|
346
355
|
class="svadmin-u-9e83b2412bc9"
|
|
347
356
|
placeholder={i18n.t('task.searchPlaceholder')}
|
|
357
|
+
disabled={!canListCurrentTab}
|
|
348
358
|
bind:value={searchQuery}
|
|
349
359
|
/>
|
|
350
360
|
</div>
|
|
351
|
-
<Select bind:value={statusFilter} aria-label={i18n.t('task.statusFilterLabel')}>
|
|
361
|
+
<Select bind:value={statusFilter} disabled={!canListCurrentTab} aria-label={i18n.t('task.statusFilterLabel')}>
|
|
352
362
|
<option value="all">{i18n.t('task.statusAll')}</option>
|
|
353
363
|
{#each availableStatuses as status, _i (_i)}
|
|
354
364
|
<option value={status}>{status}</option>
|
|
355
365
|
{/each}
|
|
356
366
|
</Select>
|
|
357
|
-
<Select bind:value={autoRefresh} aria-label={i18n.t('task.autoRefreshLabel')}>
|
|
367
|
+
<Select bind:value={autoRefresh} disabled={!canListCurrentTab} aria-label={i18n.t('task.autoRefreshLabel')}>
|
|
358
368
|
<option value="0">{i18n.t('task.refreshOff')}</option>
|
|
359
369
|
<option value="5000">{i18n.t('task.refresh5s')}</option>
|
|
360
370
|
<option value="15000">{i18n.t('task.refresh15s')}</option>
|
|
@@ -400,22 +410,32 @@
|
|
|
400
410
|
</Card.Root>
|
|
401
411
|
{/if}
|
|
402
412
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
+
{#if !canListCurrentTab}
|
|
414
|
+
<DataState state="error" title={i18n.t('common.configRequired')}
|
|
415
|
+
description={i18n.t(activeTab === 'dlq' ? 'task.dlqUnavailable' : 'task.listUnavailable')} />
|
|
416
|
+
{:else if currentQuery.isError}
|
|
417
|
+
<DataState state="error" description={i18n.t('task.fetchListFailed')}
|
|
418
|
+
{...definedOptions({ retry: currentQuery.isFetching ? undefined : () => { void refreshCurrentTab(); } })} />
|
|
419
|
+
{:else if currentQuery.isLoading}
|
|
420
|
+
<DataState state="loading" loadingLabel={i18n.t('task.loadingList')} />
|
|
421
|
+
{:else}
|
|
422
|
+
<TaskList
|
|
423
|
+
tasks={filteredTasks}
|
|
424
|
+
taskProvider={activeTaskProvider}
|
|
425
|
+
dlq={activeTab === 'dlq'}
|
|
426
|
+
title={activeTab === 'dlq' ? i18n.t('task.dlqTitle') : i18n.t('task.listTitle')}
|
|
427
|
+
emptyText={activeTab === 'dlq' ? i18n.t('task.noDlq') : i18n.t('task.noTasks')}
|
|
428
|
+
onSelect={(task) => {
|
|
429
|
+
selectedTaskId = task.id;
|
|
430
|
+
}}
|
|
431
|
+
/>
|
|
432
|
+
{/if}
|
|
413
433
|
</div>
|
|
414
434
|
</div>
|
|
415
435
|
|
|
416
436
|
<div class="svadmin-u-fb7302e5364d svadmin-u-73fc3fb18ceb svadmin-u-8a25a995eb8e">
|
|
417
437
|
<div class="svadmin-u-8e63407b5ceb">
|
|
418
|
-
{#if selectedTaskId}
|
|
438
|
+
{#if canListCurrentTab && selectedTaskId && !currentQuery.isError && !currentQuery.isLoading}
|
|
419
439
|
<TaskDetails
|
|
420
440
|
taskId={selectedTaskId}
|
|
421
441
|
taskProvider={activeTaskProvider}
|
|
@@ -16,14 +16,25 @@
|
|
|
16
16
|
import UndoableNotification from './UndoableNotification.svelte';
|
|
17
17
|
|
|
18
18
|
let host = $state<ToastHostRegistration | null>(null);
|
|
19
|
+
let sheetOpen = $state(false);
|
|
19
20
|
const isActiveHost = $derived(host?.isActive() ?? false);
|
|
20
21
|
const theme = $derived(getResolvedTheme() === 'dark' ? 'dark' : 'light');
|
|
22
|
+
const toastPosition = $derived<'top-right' | 'bottom-left'>(sheetOpen ? 'bottom-left' : 'top-right');
|
|
21
23
|
|
|
22
24
|
onMount(() => {
|
|
25
|
+
const syncSheetState = (): void => {
|
|
26
|
+
sheetOpen = document.querySelector('.svadmin-sheet-panel') !== null;
|
|
27
|
+
};
|
|
28
|
+
syncSheetState();
|
|
29
|
+
const sheetObserver = new MutationObserver(syncSheetState);
|
|
30
|
+
sheetObserver.observe(document.body, { childList: true, subtree: true });
|
|
23
31
|
const registration = registerToastHost();
|
|
24
32
|
host = registration;
|
|
25
33
|
|
|
26
|
-
return () =>
|
|
34
|
+
return () => {
|
|
35
|
+
sheetObserver.disconnect();
|
|
36
|
+
registration.unregister();
|
|
37
|
+
};
|
|
27
38
|
});
|
|
28
39
|
|
|
29
40
|
$effect(() => {
|
|
@@ -55,7 +66,7 @@
|
|
|
55
66
|
});
|
|
56
67
|
|
|
57
68
|
const toasterProps = $derived({
|
|
58
|
-
position:
|
|
69
|
+
position: toastPosition,
|
|
59
70
|
richColors: true,
|
|
60
71
|
closeButton: true,
|
|
61
72
|
expand: false,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { SvelteSet } from 'svelte/reactivity';
|
|
3
3
|
import type { Snippet } from 'svelte';
|
|
4
|
+
import { untrack } from 'svelte';
|
|
4
5
|
import { ChevronRight, ChevronLeft, ChevronsRight, ChevronsLeft, Search } from '@lucide/svelte';
|
|
5
6
|
import { cn } from '../utils.js';
|
|
6
7
|
import { Checkbox } from './ui/checkbox/index.js';
|
|
@@ -18,6 +19,10 @@
|
|
|
18
19
|
const i18n = useTranslation();
|
|
19
20
|
|
|
20
21
|
interface Props {
|
|
22
|
+
id?: string;
|
|
23
|
+
labelledby?: string;
|
|
24
|
+
describedby?: string;
|
|
25
|
+
invalid?: boolean;
|
|
21
26
|
dataSource?: TransferItem[];
|
|
22
27
|
targetKeys?: (string | number)[];
|
|
23
28
|
titles?: [string, string];
|
|
@@ -33,6 +38,10 @@
|
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
let {
|
|
41
|
+
id,
|
|
42
|
+
labelledby,
|
|
43
|
+
describedby,
|
|
44
|
+
invalid = false,
|
|
36
45
|
dataSource = [],
|
|
37
46
|
targetKeys = $bindable([]),
|
|
38
47
|
titles = ['源列表', '目标列表'],
|
|
@@ -45,6 +54,7 @@
|
|
|
45
54
|
|
|
46
55
|
let leftSearch = $state('');
|
|
47
56
|
let rightSearch = $state('');
|
|
57
|
+
let observedSearchable = $state(untrack(() => searchable));
|
|
48
58
|
|
|
49
59
|
const leftSelected = new SvelteSet<string | number>();
|
|
50
60
|
const rightSelected = new SvelteSet<string | number>();
|
|
@@ -59,6 +69,28 @@
|
|
|
59
69
|
dataSource.filter((item) => targetKeySet.has(item.key))
|
|
60
70
|
);
|
|
61
71
|
|
|
72
|
+
$effect.pre(() => {
|
|
73
|
+
const leftKeys = new Set(
|
|
74
|
+
leftDataSource.filter((item) => !item.disabled).map((item) => item.key)
|
|
75
|
+
);
|
|
76
|
+
const rightKeys = new Set(
|
|
77
|
+
rightDataSource.filter((item) => !item.disabled).map((item) => item.key)
|
|
78
|
+
);
|
|
79
|
+
for (const key of leftSelected) {
|
|
80
|
+
if (!leftKeys.has(key)) leftSelected.delete(key);
|
|
81
|
+
}
|
|
82
|
+
for (const key of rightSelected) {
|
|
83
|
+
if (!rightKeys.has(key)) rightSelected.delete(key);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
$effect.pre(() => {
|
|
88
|
+
if (observedSearchable === searchable) return;
|
|
89
|
+
observedSearchable = searchable;
|
|
90
|
+
leftSearch = '';
|
|
91
|
+
rightSearch = '';
|
|
92
|
+
});
|
|
93
|
+
|
|
62
94
|
const filteredLeft = $derived(
|
|
63
95
|
leftDataSource.filter((item) => {
|
|
64
96
|
if (!leftSearch.trim()) return true;
|
|
@@ -76,16 +108,19 @@
|
|
|
76
108
|
);
|
|
77
109
|
|
|
78
110
|
function toggleLeftSelect(key: string | number) {
|
|
111
|
+
if (disabled || !leftDataSource.some(item => item.key === key && !item.disabled)) return;
|
|
79
112
|
if (leftSelected.has(key)) leftSelected.delete(key);
|
|
80
113
|
else leftSelected.add(key);
|
|
81
114
|
}
|
|
82
115
|
|
|
83
116
|
function toggleRightSelect(key: string | number) {
|
|
117
|
+
if (disabled || !rightDataSource.some(item => item.key === key && !item.disabled)) return;
|
|
84
118
|
if (rightSelected.has(key)) rightSelected.delete(key);
|
|
85
119
|
else rightSelected.add(key);
|
|
86
120
|
}
|
|
87
121
|
|
|
88
122
|
function toggleAllLeft() {
|
|
123
|
+
if (disabled) return;
|
|
89
124
|
const selectable = filteredLeft.filter((i) => !i.disabled);
|
|
90
125
|
const allSelected = selectable.length > 0 && selectable.every((i) => leftSelected.has(i.key));
|
|
91
126
|
if (allSelected) {
|
|
@@ -96,6 +131,7 @@
|
|
|
96
131
|
}
|
|
97
132
|
|
|
98
133
|
function toggleAllRight() {
|
|
134
|
+
if (disabled) return;
|
|
99
135
|
const selectable = filteredRight.filter((i) => !i.disabled);
|
|
100
136
|
const allSelected = selectable.length > 0 && selectable.every((i) => rightSelected.has(i.key));
|
|
101
137
|
if (allSelected) {
|
|
@@ -154,13 +190,24 @@
|
|
|
154
190
|
}
|
|
155
191
|
</script>
|
|
156
192
|
|
|
157
|
-
<div
|
|
193
|
+
<div
|
|
194
|
+
id={id}
|
|
195
|
+
role="group"
|
|
196
|
+
aria-labelledby={labelledby}
|
|
197
|
+
aria-label={labelledby ? undefined : titles.join(' / ')}
|
|
198
|
+
aria-describedby={describedby}
|
|
199
|
+
aria-disabled={disabled || undefined}
|
|
200
|
+
data-invalid={invalid || undefined}
|
|
201
|
+
class={cn('svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed svadmin-u-020ba687fa12 svadmin-u-3960ffc248d9 svadmin-u-1004c0c3954c svadmin-u-6da6a3c3f741', className)}
|
|
202
|
+
data-testid="transfer"
|
|
203
|
+
>
|
|
158
204
|
<!-- Left Panel -->
|
|
159
205
|
<div class="svadmin-u-36e579c0b41c svadmin-u-6da6a3c3f741 svadmin-u-5f22e64f2282 svadmin-u-ca6bcd4b6f3f svadmin-u-18049387f0af svadmin-u-cd0ad9a56558 svadmin-u-cef5b893cf23 svadmin-u-60fbb7713999 svadmin-u-8dddea0773ed svadmin-u-ff4a6777f1bc">
|
|
160
206
|
<div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-8ef2268efbbc svadmin-u-65fdbade2025 svadmin-u-c9ed8c5f79ae svadmin-u-0e17f2bd9074 svadmin-u-03b4dd7f172b svadmin-u-2859c861d7de">
|
|
161
207
|
<div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-77a2a20e90d4">
|
|
162
208
|
<Checkbox
|
|
163
|
-
|
|
209
|
+
aria-label={titles[0]}
|
|
210
|
+
checked={filteredLeft.some((i) => !i.disabled) && filteredLeft.filter((i) => !i.disabled).every((i) => leftSelected.has(i.key))}
|
|
164
211
|
disabled={disabled || filteredLeft.filter((i) => !i.disabled).length === 0}
|
|
165
212
|
onCheckedChange={toggleAllLeft}
|
|
166
213
|
/>
|
|
@@ -177,6 +224,7 @@
|
|
|
177
224
|
<Search class="svadmin-u-da4dbfbc4fdc svadmin-u-ecfeb742a3f3 svadmin-u-7a470f4c9b28 svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c svadmin-u-bfa603190748" />
|
|
178
225
|
<Input
|
|
179
226
|
type="text"
|
|
227
|
+
aria-label={titles[0]}
|
|
180
228
|
bind:value={leftSearch}
|
|
181
229
|
placeholder={i18n.t('common.search', undefined) ?? '搜索...'}
|
|
182
230
|
class="svadmin-u-ed8a5df7b2fb svadmin-u-e4af885410fe svadmin-u-aa2c13a5e1b4 svadmin-u-359090c2d529"
|
|
@@ -191,7 +239,8 @@
|
|
|
191
239
|
{@const selected = leftSelected.has(item.key)}
|
|
192
240
|
<div
|
|
193
241
|
role="button"
|
|
194
|
-
tabindex=
|
|
242
|
+
tabindex={disabled || item.disabled ? -1 : 0}
|
|
243
|
+
aria-disabled={disabled || item.disabled || undefined}
|
|
195
244
|
class={cn(
|
|
196
245
|
'svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-77a2a20e90d4 svadmin-u-421ac2be5045 svadmin-u-0b91436debbd svadmin-u-ec0091ee009b svadmin-u-359090c2d529 svadmin-u-ceb69a6b0e5f svadmin-u-34516836730d svadmin-u-7f6912283f11',
|
|
197
246
|
selected ? 'svadmin-u-375dc44df6e9 svadmin-u-20aaf08a7ed1 svadmin-u-2689f3958069' : 'svadmin-u-39f703dbe296 svadmin-u-d4108abe6359',
|
|
@@ -206,8 +255,13 @@
|
|
|
206
255
|
}}
|
|
207
256
|
>
|
|
208
257
|
<Checkbox
|
|
258
|
+
aria-label={item.title}
|
|
209
259
|
checked={selected}
|
|
210
260
|
disabled={disabled || item.disabled}
|
|
261
|
+
onclick={(event) => event.stopPropagation()}
|
|
262
|
+
onkeydown={(event) => {
|
|
263
|
+
if (event.key === 'Enter' || event.key === ' ') event.stopPropagation();
|
|
264
|
+
}}
|
|
211
265
|
onCheckedChange={() => toggleLeftSelect(item.key)}
|
|
212
266
|
/>
|
|
213
267
|
<div class="svadmin-u-7e0b7cdf1a94 svadmin-u-36e579c0b41c">
|
|
@@ -281,7 +335,8 @@
|
|
|
281
335
|
<div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-8ef2268efbbc svadmin-u-65fdbade2025 svadmin-u-c9ed8c5f79ae svadmin-u-0e17f2bd9074 svadmin-u-03b4dd7f172b svadmin-u-2859c861d7de">
|
|
282
336
|
<div class="svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-77a2a20e90d4">
|
|
283
337
|
<Checkbox
|
|
284
|
-
|
|
338
|
+
aria-label={titles[1]}
|
|
339
|
+
checked={filteredRight.some((i) => !i.disabled) && filteredRight.filter((i) => !i.disabled).every((i) => rightSelected.has(i.key))}
|
|
285
340
|
disabled={disabled || filteredRight.filter((i) => !i.disabled).length === 0}
|
|
286
341
|
onCheckedChange={toggleAllRight}
|
|
287
342
|
/>
|
|
@@ -298,6 +353,7 @@
|
|
|
298
353
|
<Search class="svadmin-u-da4dbfbc4fdc svadmin-u-ecfeb742a3f3 svadmin-u-7a470f4c9b28 svadmin-u-7fc7f732bf7e svadmin-u-bf600f8e029c svadmin-u-bfa603190748" />
|
|
299
354
|
<Input
|
|
300
355
|
type="text"
|
|
356
|
+
aria-label={titles[1]}
|
|
301
357
|
bind:value={rightSearch}
|
|
302
358
|
placeholder={i18n.t('common.search', undefined) ?? '搜索...'}
|
|
303
359
|
class="svadmin-u-ed8a5df7b2fb svadmin-u-e4af885410fe svadmin-u-aa2c13a5e1b4 svadmin-u-359090c2d529"
|
|
@@ -312,7 +368,8 @@
|
|
|
312
368
|
{@const selected = rightSelected.has(item.key)}
|
|
313
369
|
<div
|
|
314
370
|
role="button"
|
|
315
|
-
tabindex=
|
|
371
|
+
tabindex={disabled || item.disabled ? -1 : 0}
|
|
372
|
+
aria-disabled={disabled || item.disabled || undefined}
|
|
316
373
|
class={cn(
|
|
317
374
|
'svadmin-u-60fbb7713999 svadmin-u-3960ffc248d9 svadmin-u-77a2a20e90d4 svadmin-u-421ac2be5045 svadmin-u-0b91436debbd svadmin-u-ec0091ee009b svadmin-u-359090c2d529 svadmin-u-ceb69a6b0e5f svadmin-u-34516836730d svadmin-u-7f6912283f11',
|
|
318
375
|
selected ? 'svadmin-u-375dc44df6e9 svadmin-u-20aaf08a7ed1 svadmin-u-2689f3958069' : 'svadmin-u-39f703dbe296 svadmin-u-d4108abe6359',
|
|
@@ -327,8 +384,13 @@
|
|
|
327
384
|
}}
|
|
328
385
|
>
|
|
329
386
|
<Checkbox
|
|
387
|
+
aria-label={item.title}
|
|
330
388
|
checked={selected}
|
|
331
389
|
disabled={disabled || item.disabled}
|
|
390
|
+
onclick={(event) => event.stopPropagation()}
|
|
391
|
+
onkeydown={(event) => {
|
|
392
|
+
if (event.key === 'Enter' || event.key === ' ') event.stopPropagation();
|
|
393
|
+
}}
|
|
332
394
|
onCheckedChange={() => toggleRightSelect(item.key)}
|
|
333
395
|
/>
|
|
334
396
|
<div class="svadmin-u-7e0b7cdf1a94 svadmin-u-36e579c0b41c">
|
|
@@ -6,6 +6,10 @@ export interface TransferItem {
|
|
|
6
6
|
disabled?: boolean;
|
|
7
7
|
}
|
|
8
8
|
interface Props {
|
|
9
|
+
id?: string;
|
|
10
|
+
labelledby?: string;
|
|
11
|
+
describedby?: string;
|
|
12
|
+
invalid?: boolean;
|
|
9
13
|
dataSource?: TransferItem[];
|
|
10
14
|
targetKeys?: (string | number)[];
|
|
11
15
|
titles?: [string, string];
|