@svadmin/ui 0.38.2 → 0.38.5
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 +8 -4
- package/dist/app.theme.css +8 -4
- package/dist/components/AICommandBar.svelte +16 -15
- package/dist/components/AboutSettings.svelte +12 -11
- package/dist/components/AdminApp.svelte +144 -70
- package/dist/components/AdminApp.svelte.d.ts +6 -3
- package/dist/components/ApiSettings.svelte +19 -16
- package/dist/components/AppearanceSettings.svelte +18 -16
- package/dist/components/AuditLogDrawer.svelte +6 -3
- package/dist/components/AuditLogViewer.svelte +18 -15
- package/dist/components/Authenticated.svelte +4 -4
- package/dist/components/AutoForm.svelte +19 -16
- package/dist/components/AutoSaveIndicator.svelte +7 -5
- package/dist/components/AutoTable.svelte +85 -71
- package/dist/components/AutoTable.svelte.d.ts +1 -1
- package/dist/components/Breadcrumbs.svelte +17 -13
- package/dist/components/CancelTaskButton.svelte +5 -2
- package/dist/components/CatchAllNavigate.svelte +3 -3
- package/dist/components/ChatDialog.svelte +22 -19
- package/dist/components/ComboboxField.svelte +6 -4
- package/dist/components/CommandPalette.svelte +20 -20
- package/dist/components/ConfigErrorScreen.svelte +12 -10
- package/dist/components/ConfirmDialog.svelte +6 -4
- package/dist/components/CreatePage.svelte +4 -2
- package/dist/components/DevTools.svelte +11 -9
- package/dist/components/DrawerForm.svelte +5 -2
- package/dist/components/EditPage.svelte +8 -5
- package/dist/components/EmptyState.svelte +5 -3
- package/dist/components/ErrorBoundary.svelte +5 -3
- package/dist/components/ErrorComponent.svelte +6 -4
- package/dist/components/ErrorPage.svelte +12 -10
- package/dist/components/FieldRenderer.svelte +17 -15
- package/dist/components/ForgotPasswordPage.svelte +22 -19
- package/dist/components/Header.svelte +7 -4
- package/dist/components/InfiniteList.svelte +6 -3
- package/dist/components/IntegrationsSettings.svelte +9 -6
- package/dist/components/KeyboardShortcuts.svelte +4 -2
- package/dist/components/Layout.svelte +12 -13
- package/dist/components/LazyPage.svelte +47 -0
- package/dist/components/LazyPage.svelte.d.ts +14 -0
- package/dist/components/ListPage.svelte +8 -5
- package/dist/components/LoginPage.svelte +24 -22
- package/dist/components/MarkdownRenderer.svelte +89 -35
- package/dist/components/ModalForm.svelte +4 -2
- package/dist/components/NavigateToResource.svelte +3 -3
- package/dist/components/NotificationsSettings.svelte +26 -24
- package/dist/components/PasswordInput.svelte +4 -2
- package/dist/components/PermissionMatrix.svelte +15 -12
- package/dist/components/ProfilePage.svelte +23 -21
- package/dist/components/RegisterPage.svelte +21 -19
- package/dist/components/ResourceOperationsPage.svelte +3 -2
- package/dist/components/RetryTaskButton.svelte +5 -2
- package/dist/components/RolesSettings.svelte +10 -8
- package/dist/components/SecuritySettings.svelte +26 -23
- package/dist/components/SettingsPage.svelte +14 -11
- package/dist/components/ShowPage.svelte +9 -7
- package/dist/components/Sidebar.svelte +36 -28
- package/dist/components/SidebarItem.svelte +4 -4
- package/dist/components/SidebarItem.svelte.d.ts +1 -1
- package/dist/components/StepsForm.svelte +11 -8
- package/dist/components/TaskDetails.svelte +14 -11
- package/dist/components/TaskList.svelte +14 -11
- package/dist/components/TaskQueueDrawer.svelte +34 -32
- package/dist/components/TaskStatusBadge.svelte +5 -2
- package/dist/components/Toast.svelte +18 -4
- package/dist/components/TooltipButton.svelte +25 -3
- package/dist/components/TwoFactorAuthPage.svelte +26 -24
- package/dist/components/UndoableNotification.svelte +5 -2
- package/dist/components/UpdatePasswordPage.svelte +18 -15
- package/dist/components/VirtualTable.svelte +0 -4
- package/dist/components/account/CompanyProfilePage.svelte +13 -11
- package/dist/components/account/GetStartedPage.svelte +15 -13
- package/dist/components/account/ImportMembersPage.svelte +14 -12
- package/dist/components/account/MembersStarterPage.svelte +10 -8
- package/dist/components/account/SecurityLogPage.svelte +24 -22
- package/dist/components/account/SettingsEnterprisePage.svelte +6 -4
- package/dist/components/account/SettingsPlainPage.svelte +14 -12
- package/dist/components/account/SettingsSidebarPage.svelte +11 -9
- package/dist/components/account/TeamMembersPage.svelte +10 -8
- package/dist/components/buttons/CloneButton.svelte +4 -2
- package/dist/components/buttons/CreateButton.svelte +4 -2
- package/dist/components/buttons/DeleteButton.svelte +6 -4
- package/dist/components/buttons/EditButton.svelte +4 -2
- package/dist/components/buttons/ExportButton.svelte +4 -2
- package/dist/components/buttons/ImportButton.svelte +4 -2
- package/dist/components/buttons/RefreshButton.svelte +4 -2
- package/dist/components/buttons/SaveButton.svelte +4 -2
- package/dist/components/buttons/ShowButton.svelte +4 -2
- package/dist/components/fieldComponentMap.js +0 -3
- package/dist/components/fields/ArrayField.svelte +6 -4
- package/dist/components/fields/JsonField.svelte +5 -3
- package/dist/components/fields/RelationField.svelte +3 -3
- package/dist/components/fields/RichTextField.svelte +4 -2
- package/dist/components/network/TeamCrewTablePage.svelte +18 -16
- package/dist/components/network/UserCardsNFTPage.svelte +11 -9
- package/dist/components/profile/ActivityTimeline.svelte +10 -8
- package/dist/components/profile/ProfileCard.svelte +13 -11
- package/dist/components/profile/ProjectsGrid.svelte +7 -5
- package/dist/components/profile/PublicProfilePage.svelte +18 -16
- package/dist/components/profile/TeamsShowcase.svelte +7 -5
- package/dist/components/toast-host.svelte.d.ts +5 -0
- package/dist/components/toast-host.svelte.js +21 -0
- package/dist/components/ui/command/command-dialog.svelte +29 -13
- package/dist/components/ui/command/command-dialog.svelte.d.ts +4 -3
- package/dist/components/ui/command/command-empty.svelte +18 -0
- package/dist/components/ui/command/command-empty.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-group.svelte +41 -0
- package/dist/components/ui/command/command-group.svelte.d.ts +8 -0
- package/dist/components/ui/command/command-input.svelte +23 -0
- package/dist/components/ui/command/command-input.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-item.svelte +43 -0
- package/dist/components/ui/command/command-item.svelte.d.ts +11 -0
- package/dist/components/ui/command/command-list.svelte +18 -0
- package/dist/components/ui/command/command-list.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-loading.svelte +12 -0
- package/dist/components/ui/command/command-loading.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-separator.svelte +23 -0
- package/dist/components/ui/command/command-separator.svelte.d.ts +7 -0
- package/dist/components/ui/command/command.svelte +26 -0
- package/dist/components/ui/command/command.svelte.d.ts +4 -0
- package/dist/components/ui/command/index.d.ts +55 -2
- package/dist/components/ui/command/index.js +21 -2
- package/dist/components/ui/sheet/sheet-content.svelte +1 -4
- package/dist/components/ui/sheet/sheet-content.svelte.d.ts +1 -3
- package/dist/components/ui/tabs/tabs-content.svelte +6 -2
- package/dist/components/ui/tabs/tabs-context.svelte.d.ts +5 -0
- package/dist/components/ui/tabs/tabs-context.svelte.js +2 -0
- package/dist/components/ui/tabs/tabs-trigger.svelte +49 -4
- package/dist/components/ui/tabs/tabs.svelte +12 -1
- package/dist/components/ui/tooltip/index.d.ts +4 -1
- package/dist/components/ui/tooltip/index.js +3 -1
- package/dist/components/ui/tooltip/tooltip-content.svelte +308 -35
- package/dist/components/ui/tooltip/tooltip-content.svelte.d.ts +42 -3
- package/dist/components/ui/tooltip/tooltip-context.svelte.d.ts +37 -0
- package/dist/components/ui/tooltip/tooltip-context.svelte.js +220 -0
- package/dist/components/ui/tooltip/tooltip-layer-registry.svelte.d.ts +11 -0
- package/dist/components/ui/tooltip/tooltip-layer-registry.svelte.js +93 -0
- package/dist/components/ui/tooltip/tooltip-trigger.svelte +56 -3
- package/dist/components/ui/tooltip/tooltip-trigger.svelte.d.ts +23 -2
- package/dist/components/ui/tooltip/tooltip.svelte +63 -3
- package/dist/components/ui/tooltip/tooltip.svelte.d.ts +23 -2
- package/dist/router-state.svelte.d.ts +13 -0
- package/dist/router-state.svelte.js +72 -37
- package/package.json +13 -11
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
type ColumnVisibilityState,
|
|
11
11
|
type ExpandedState,
|
|
12
12
|
} from '@tanstack/svelte-table';
|
|
13
|
-
import type { Updater } from '@tanstack/table-core';
|
|
13
|
+
import type { Column, Header, TableFeatures, Updater } from '@tanstack/table-core';
|
|
14
14
|
import {
|
|
15
15
|
column_getCanSort,
|
|
16
16
|
column_getIsSorted,
|
|
@@ -31,12 +31,19 @@
|
|
|
31
31
|
cell_getValue,
|
|
32
32
|
} from '@tanstack/table-core/static-functions';
|
|
33
33
|
|
|
34
|
-
import { useList, useDelete, useDeleteMany, getResource, notify } from '@svadmin/core';
|
|
35
|
-
import type {
|
|
36
|
-
|
|
34
|
+
import { captureAdminContext, useList, useDelete, useDeleteMany, getResource, notify } from '@svadmin/core';
|
|
35
|
+
import type {
|
|
36
|
+
BaseRecord,
|
|
37
|
+
FieldDefinition,
|
|
38
|
+
Filter,
|
|
39
|
+
LogicalFilter,
|
|
40
|
+
Pagination as PaginationState,
|
|
41
|
+
Sort,
|
|
42
|
+
} from '@svadmin/core';
|
|
37
43
|
import { useCan, getAccessControlProvider } from '@svadmin/core';
|
|
38
44
|
import { readURLState, writeURLState } from '@svadmin/core';
|
|
39
|
-
import {
|
|
45
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
46
|
+
|
|
40
47
|
import { fade } from 'svelte/transition';
|
|
41
48
|
import { Button } from './ui/button/index.js';
|
|
42
49
|
import { Input } from './ui/input/index.js';
|
|
@@ -50,7 +57,7 @@
|
|
|
50
57
|
import * as ContextMenu from './ui/context-menu/index.js';
|
|
51
58
|
import {
|
|
52
59
|
Plus, Pencil, Trash2,
|
|
53
|
-
Search, Download,
|
|
60
|
+
Search, Download, ChevronDown, ChevronUp, SlidersHorizontal, Filter as FilterIcon,
|
|
54
61
|
Eye, Copy
|
|
55
62
|
} from '@lucide/svelte';
|
|
56
63
|
import ConfirmDialog from './ConfirmDialog.svelte';
|
|
@@ -59,6 +66,8 @@
|
|
|
59
66
|
import DraggableHeader from './DraggableHeader.svelte';
|
|
60
67
|
import type { Snippet } from 'svelte';
|
|
61
68
|
|
|
69
|
+
const i18n = useTranslation();
|
|
70
|
+
|
|
62
71
|
// ─── Props with Snippet composability ─────────────────────────
|
|
63
72
|
interface Props {
|
|
64
73
|
resourceName: string;
|
|
@@ -96,12 +105,13 @@
|
|
|
96
105
|
pagination: externalPagination,
|
|
97
106
|
sorters: externalSorters,
|
|
98
107
|
}: Props = $props();
|
|
108
|
+
const adminContext = captureAdminContext();
|
|
99
109
|
|
|
100
110
|
const resource = $derived(getResource(resourceName));
|
|
101
111
|
const primaryKey = $derived(resource.primaryKey ?? 'id');
|
|
102
112
|
|
|
103
113
|
// ─── URL state + server-side state ────────────────────────────
|
|
104
|
-
const urlState = readURLState();
|
|
114
|
+
const urlState = readURLState(adminContext);
|
|
105
115
|
|
|
106
116
|
// Snapshot resource values for initial state (untrack to avoid reactive tracking)
|
|
107
117
|
const storedPageSize = typeof window !== 'undefined' ? parseInt(localStorage.getItem('svadmin-default-page-size') ?? '', 10) : NaN;
|
|
@@ -142,7 +152,7 @@
|
|
|
142
152
|
sortField: sorters[0]?.field,
|
|
143
153
|
sortOrder: sorters[0]?.order,
|
|
144
154
|
search: searchText || undefined,
|
|
145
|
-
});
|
|
155
|
+
}, adminContext);
|
|
146
156
|
});
|
|
147
157
|
|
|
148
158
|
// ─── Build active filters with search ─────────────────────────
|
|
@@ -156,14 +166,15 @@
|
|
|
156
166
|
if (searchableFields.length === 1) {
|
|
157
167
|
result.push({ field: searchableFields[0].key, operator: 'contains', value: searchText });
|
|
158
168
|
} else {
|
|
159
|
-
|
|
169
|
+
const searchFilter: LogicalFilter = {
|
|
160
170
|
operator: 'or',
|
|
161
171
|
value: searchableFields.map(f => ({
|
|
162
172
|
field: f.key,
|
|
163
173
|
operator: 'contains',
|
|
164
174
|
value: searchText
|
|
165
175
|
}))
|
|
166
|
-
}
|
|
176
|
+
};
|
|
177
|
+
result.push(searchFilter);
|
|
167
178
|
}
|
|
168
179
|
}
|
|
169
180
|
for (const [key, value] of Object.entries(filterValues)) {
|
|
@@ -353,7 +364,7 @@
|
|
|
353
364
|
resource.fields.filter(f => f.showInList !== false)
|
|
354
365
|
);
|
|
355
366
|
|
|
356
|
-
const columns = $derived<ColumnDef<
|
|
367
|
+
const columns = $derived<ColumnDef<TableFeatures, BaseRecord, unknown>[]>([
|
|
357
368
|
// Selection column
|
|
358
369
|
...(selectable && (canDelete || batchActions) ? [{
|
|
359
370
|
id: '_select',
|
|
@@ -361,7 +372,7 @@
|
|
|
361
372
|
cell: () => '',
|
|
362
373
|
size: 40,
|
|
363
374
|
enableSorting: false,
|
|
364
|
-
} satisfies ColumnDef<
|
|
375
|
+
} satisfies ColumnDef<TableFeatures, BaseRecord, unknown>] : []),
|
|
365
376
|
// Expand column
|
|
366
377
|
...(expandedRowRender ? [{
|
|
367
378
|
id: '_expand',
|
|
@@ -369,9 +380,9 @@
|
|
|
369
380
|
cell: () => '',
|
|
370
381
|
size: 40,
|
|
371
382
|
enableSorting: false,
|
|
372
|
-
} satisfies ColumnDef<
|
|
383
|
+
} satisfies ColumnDef<TableFeatures, BaseRecord, unknown>] : []),
|
|
373
384
|
// Data columns
|
|
374
|
-
...visibleFields.map((field): ColumnDef<
|
|
385
|
+
...visibleFields.map((field): ColumnDef<TableFeatures, BaseRecord, unknown> => ({
|
|
375
386
|
id: field.key,
|
|
376
387
|
accessorKey: field.key,
|
|
377
388
|
header: () => field.label,
|
|
@@ -380,7 +391,7 @@
|
|
|
380
391
|
// Actions column
|
|
381
392
|
{
|
|
382
393
|
id: '_actions',
|
|
383
|
-
header: () => t('common.actions'),
|
|
394
|
+
header: () => i18n.t('common.actions'),
|
|
384
395
|
cell: () => '',
|
|
385
396
|
size: 100,
|
|
386
397
|
enableSorting: false,
|
|
@@ -388,23 +399,26 @@
|
|
|
388
399
|
]);
|
|
389
400
|
|
|
390
401
|
// ─── Create TanStack Table ────────────────────────────────────
|
|
391
|
-
const tbl = createTable(
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
402
|
+
const tbl = createTable(
|
|
403
|
+
{
|
|
404
|
+
get data() { return query.data?.data ?? []; },
|
|
405
|
+
get columns() { return columns; },
|
|
406
|
+
getCoreRowModel: createCoreRowModel(),
|
|
407
|
+
manualPagination: true,
|
|
408
|
+
manualSorting: true,
|
|
409
|
+
getRowId: (row: BaseRecord) => String(row[primaryKey]),
|
|
410
|
+
atoms: {
|
|
411
|
+
sorting: sortingAtom,
|
|
412
|
+
columnVisibility: columnVisibilityAtom,
|
|
413
|
+
rowSelection: rowSelectionAtom,
|
|
414
|
+
expanded: expandedAtom,
|
|
415
|
+
columnOrder: columnOrderAtom,
|
|
416
|
+
},
|
|
417
|
+
get enableRowSelection() { return selectable && (canDelete || batchActions); },
|
|
418
|
+
get enableExpanding() { return !!expandedRowRender; },
|
|
404
419
|
},
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
});
|
|
420
|
+
() => undefined,
|
|
421
|
+
);
|
|
408
422
|
|
|
409
423
|
const selectedCount = $derived(Object.keys(rowSelection).length);
|
|
410
424
|
const totalPages = $derived(Math.ceil((query.data?.total ?? 0) / (pagination.pageSize ?? 10)));
|
|
@@ -433,7 +447,7 @@
|
|
|
433
447
|
let confirmAction = $state<() => void>(() => {});
|
|
434
448
|
|
|
435
449
|
function confirmDelete(id: string | number) {
|
|
436
|
-
confirmMessage = t('common.deleteConfirm');
|
|
450
|
+
confirmMessage = i18n.t('common.deleteConfirm');
|
|
437
451
|
confirmAction = async () => {
|
|
438
452
|
await deleteMutation.mutateAsync({ id, resource: resourceName });
|
|
439
453
|
confirmOpen = false;
|
|
@@ -443,13 +457,13 @@
|
|
|
443
457
|
|
|
444
458
|
function confirmBatchDelete() {
|
|
445
459
|
const ids = Object.keys(rowSelection);
|
|
446
|
-
confirmMessage = t('common.batchDeleteConfirm', { count: ids.length });
|
|
460
|
+
confirmMessage = i18n.t('common.batchDeleteConfirm', { count: ids.length });
|
|
447
461
|
confirmAction = async () => {
|
|
448
462
|
try {
|
|
449
463
|
await deleteManyMutation.mutateAsync({ ids, resource: resourceName });
|
|
450
|
-
notify({ type: 'success', message: t('common.batchDeleteSuccess', { count: ids.length }) });
|
|
464
|
+
notify({ type: 'success', message: i18n.t('common.batchDeleteSuccess', { count: ids.length }) });
|
|
451
465
|
} catch {
|
|
452
|
-
notify({ type: 'error', message: t('common.batchDeletePartialFail', { failed: 1, total: ids.length }) });
|
|
466
|
+
notify({ type: 'error', message: i18n.t('common.batchDeletePartialFail', { failed: 1, total: ids.length }) });
|
|
453
467
|
}
|
|
454
468
|
rowSelection = {};
|
|
455
469
|
confirmOpen = false;
|
|
@@ -491,7 +505,7 @@
|
|
|
491
505
|
<div class="flex flex-wrap items-center gap-2">
|
|
492
506
|
{#if canExport}
|
|
493
507
|
<Button variant="outline" size="sm" onclick={exportCSV}>
|
|
494
|
-
<Download class="h-4 w-4" data-icon="inline-start" /> {t('common.export')}
|
|
508
|
+
<Download class="h-4 w-4" data-icon="inline-start" /> {i18n.t('common.export')}
|
|
495
509
|
</Button>
|
|
496
510
|
{/if}
|
|
497
511
|
{#if selectedCount > 0 && canDelete}
|
|
@@ -501,7 +515,7 @@
|
|
|
501
515
|
class="h-9 whitespace-nowrap"
|
|
502
516
|
onclick={confirmBatchDelete}
|
|
503
517
|
>
|
|
504
|
-
<Trash2 class="h-4 w-4" data-icon="inline-start" /> {t('common.batchDelete', { count: selectedCount })}
|
|
518
|
+
<Trash2 class="h-4 w-4" data-icon="inline-start" /> {i18n.t('common.batchDelete', { count: selectedCount })}
|
|
505
519
|
</Button>
|
|
506
520
|
{/if}
|
|
507
521
|
|
|
@@ -514,12 +528,12 @@
|
|
|
514
528
|
<DropdownMenu.Trigger>
|
|
515
529
|
{#snippet child({ props })}
|
|
516
530
|
<Button variant="outline" size="sm" {...props}>
|
|
517
|
-
<SlidersHorizontal class="h-4 w-4" data-icon="inline-start" /> {t('common.columns') || 'Columns'}
|
|
531
|
+
<SlidersHorizontal class="h-4 w-4" data-icon="inline-start" /> {i18n.t('common.columns') || 'Columns'}
|
|
518
532
|
</Button>
|
|
519
533
|
{/snippet}
|
|
520
534
|
</DropdownMenu.Trigger>
|
|
521
535
|
<DropdownMenu.Content align="end" class="w-48">
|
|
522
|
-
{#each table_getAllLeafColumns(tbl).filter((
|
|
536
|
+
{#each table_getAllLeafColumns(tbl).filter((column: Column<TableFeatures, BaseRecord, unknown>) => !column.id.startsWith('_')) as column, _i (_i)}
|
|
523
537
|
<DropdownMenu.CheckboxItem
|
|
524
538
|
checked={column_getIsVisible(column)}
|
|
525
539
|
onCheckedChange={(v) => column_toggleVisibility(column, !!v)}
|
|
@@ -533,8 +547,8 @@
|
|
|
533
547
|
{@render headerActions()}
|
|
534
548
|
{/if}
|
|
535
549
|
{#if canCreate}
|
|
536
|
-
<Button onclick={() => navigate(`/${resourceName}/create`)}>
|
|
537
|
-
<Plus class="h-4 w-4" data-icon="inline-start" /> {t('common.create')}
|
|
550
|
+
<Button onclick={() => adminContext.navigate(`/${resourceName}/create`)}>
|
|
551
|
+
<Plus class="h-4 w-4" data-icon="inline-start" /> {i18n.t('common.create')}
|
|
538
552
|
</Button>
|
|
539
553
|
{/if}
|
|
540
554
|
</div>
|
|
@@ -549,7 +563,7 @@
|
|
|
549
563
|
type="text"
|
|
550
564
|
bind:value={searchText}
|
|
551
565
|
oninput={() => { pagination = { ...pagination, current: 1 }; }}
|
|
552
|
-
placeholder={t('common.search')}
|
|
566
|
+
placeholder={i18n.t('common.search')}
|
|
553
567
|
class="pl-10 h-9"
|
|
554
568
|
/>
|
|
555
569
|
</div>
|
|
@@ -561,7 +575,7 @@
|
|
|
561
575
|
{#snippet child({ props })}
|
|
562
576
|
<Button variant="outline" size="sm" class="h-9 px-3" {...props}>
|
|
563
577
|
<FilterIcon class="h-4 w-4" data-icon="inline-start" />
|
|
564
|
-
{t('common.filter')}
|
|
578
|
+
{i18n.t('common.filter')}
|
|
565
579
|
{#if activeFilterCount > 0}
|
|
566
580
|
<Badge variant="secondary" class="ml-1 h-5 min-w-5 px-1">{activeFilterCount}</Badge>
|
|
567
581
|
{/if}
|
|
@@ -570,7 +584,7 @@
|
|
|
570
584
|
</Popover.Trigger>
|
|
571
585
|
<Popover.Content class="w-80">
|
|
572
586
|
<div class="space-y-3">
|
|
573
|
-
<h4 class="font-medium text-sm">{t('common.filter')}</h4>
|
|
587
|
+
<h4 class="font-medium text-sm">{i18n.t('common.filter')}</h4>
|
|
574
588
|
{#each filterableFields as field, _i (_i)}
|
|
575
589
|
<div class="space-y-1">
|
|
576
590
|
<label class="text-xs text-muted-foreground" for="filter-{field.key}">{field.label}</label>
|
|
@@ -581,7 +595,7 @@
|
|
|
581
595
|
value={filterValues[field.key] ?? ''}
|
|
582
596
|
onchange={(e) => filterValues[field.key] = (e.currentTarget as HTMLSelectElement).value}
|
|
583
597
|
>
|
|
584
|
-
<option value="">{t('common.all')}</option>
|
|
598
|
+
<option value="">{i18n.t('common.all')}</option>
|
|
585
599
|
{#each field.options as opt, _i (_i)}
|
|
586
600
|
<option value={opt.value}>{opt.label}</option>
|
|
587
601
|
{/each}
|
|
@@ -600,13 +614,13 @@
|
|
|
600
614
|
{/each}
|
|
601
615
|
<div class="flex gap-2 pt-2">
|
|
602
616
|
<Button size="sm" class="flex-1" onclick={() => { pagination = { ...pagination, current: 1 }; }}>
|
|
603
|
-
{t('common.confirm')}
|
|
617
|
+
{i18n.t('common.confirm')}
|
|
604
618
|
</Button>
|
|
605
619
|
<Button variant="outline" size="sm" onclick={() => {
|
|
606
620
|
filterValues = {};
|
|
607
621
|
pagination = { ...pagination, current: 1 };
|
|
608
622
|
}}>
|
|
609
|
-
{t('common.reset')}
|
|
623
|
+
{i18n.t('common.reset')}
|
|
610
624
|
</Button>
|
|
611
625
|
</div>
|
|
612
626
|
</div>
|
|
@@ -616,7 +630,7 @@
|
|
|
616
630
|
</div>
|
|
617
631
|
|
|
618
632
|
<!-- Table (TanStack-powered) -->
|
|
619
|
-
<div class="rounded-[24px] bg-card/80 backdrop-blur-3xl shadow-[0_8px_30px_rgb(0,0,0,0.04)] overflow-hidden ring-1 ring-border/30" role="region" aria-label="{resource.label} {t('common.list')}">
|
|
633
|
+
<div class="rounded-[24px] bg-card/80 backdrop-blur-3xl shadow-[0_8px_30px_rgb(0,0,0,0.04)] overflow-hidden ring-1 ring-border/30" role="region" aria-label="{resource.label} {i18n.t('common.list')}">
|
|
620
634
|
{#if query.isLoading}
|
|
621
635
|
<div class="p-4 space-y-3">
|
|
622
636
|
<div class="flex gap-4 mb-2">
|
|
@@ -634,7 +648,7 @@
|
|
|
634
648
|
</div>
|
|
635
649
|
{:else if query.error}
|
|
636
650
|
<div class="flex h-64 items-center justify-center text-destructive text-sm">
|
|
637
|
-
{t('common.loadFailed', { message: (query.error as Error).message })}
|
|
651
|
+
{i18n.t('common.loadFailed', { message: (query.error as Error).message })}
|
|
638
652
|
</div>
|
|
639
653
|
{:else}
|
|
640
654
|
<div in:fade={{ duration: 150 }}>
|
|
@@ -644,9 +658,9 @@
|
|
|
644
658
|
<Table.Header>
|
|
645
659
|
{#each table_getHeaderGroups(tbl) as headerGroup, _i (_i)}
|
|
646
660
|
<DraggableHeader
|
|
647
|
-
columns={headerGroup.headers.map((
|
|
661
|
+
columns={headerGroup.headers.map((header: Header<TableFeatures, BaseRecord, unknown>) => ({ id: header.column.id, header }))}
|
|
648
662
|
resourceName={resourceName}
|
|
649
|
-
onReorder={(newOrder) => { columnOrder = newOrder.map((
|
|
663
|
+
onReorder={(newOrder) => { columnOrder = newOrder.map((column) => column.id); }}
|
|
650
664
|
>
|
|
651
665
|
{#snippet header(col, _index, dragProps)}
|
|
652
666
|
{@const header = col.header as typeof headerGroup.headers[0]}
|
|
@@ -663,7 +677,7 @@
|
|
|
663
677
|
{:else if header.id === '_expand'}
|
|
664
678
|
<!-- empty -->
|
|
665
679
|
{:else if header.id === '_actions'}
|
|
666
|
-
<span class="text-right block">{t('common.actions')}</span>
|
|
680
|
+
<span class="text-right block">{i18n.t('common.actions')}</span>
|
|
667
681
|
{:else if column_getCanSort(header.column)}
|
|
668
682
|
<Button
|
|
669
683
|
variant="ghost"
|
|
@@ -703,7 +717,7 @@
|
|
|
703
717
|
onCheckedChange={() => row_toggleSelected(row)}
|
|
704
718
|
/>
|
|
705
719
|
{:else if cell.column.id === '_expand'}
|
|
706
|
-
<TooltipButton tooltip={row_getIsExpanded(row) ? t('common.collapse') : t('common.expand')} variant="ghost" size="icon" class="h-7 w-7" onclick={() => row_toggleExpanded(row)}>
|
|
720
|
+
<TooltipButton tooltip={row_getIsExpanded(row) ? i18n.t('common.collapse') : i18n.t('common.expand')} variant="ghost" size="icon" class="h-7 w-7" onclick={() => row_toggleExpanded(row)}>
|
|
707
721
|
{#if row_getIsExpanded(row)}
|
|
708
722
|
<ChevronUp class="h-4 w-4" />
|
|
709
723
|
{:else}
|
|
@@ -716,12 +730,12 @@
|
|
|
716
730
|
{@render rowActions({ record, id })}
|
|
717
731
|
{:else}
|
|
718
732
|
{#if canEdit}
|
|
719
|
-
<TooltipButton tooltip={t('common.edit')} variant="ghost" size="icon-sm" onclick={() => navigate(`/${resourceName}/edit/${id}`)}>
|
|
733
|
+
<TooltipButton tooltip={i18n.t('common.edit')} variant="ghost" size="icon-sm" onclick={() => adminContext.navigate(`/${resourceName}/edit/${id}`)}>
|
|
720
734
|
<Pencil class="h-4 w-4" />
|
|
721
735
|
</TooltipButton>
|
|
722
736
|
{/if}
|
|
723
737
|
{#if canDelete}
|
|
724
|
-
<TooltipButton tooltip={t('common.delete')} variant="ghost" size="icon-sm" onclick={() => confirmDelete(id)} class="hover:text-destructive">
|
|
738
|
+
<TooltipButton tooltip={i18n.t('common.delete')} variant="ghost" size="icon-sm" onclick={() => confirmDelete(id)} class="hover:text-destructive">
|
|
725
739
|
<Trash2 class="h-4 w-4" />
|
|
726
740
|
</TooltipButton>
|
|
727
741
|
{/if}
|
|
@@ -767,20 +781,20 @@
|
|
|
767
781
|
</ContextMenu.Trigger>
|
|
768
782
|
<ContextMenu.Content class="w-48">
|
|
769
783
|
{#if canEdit}
|
|
770
|
-
<ContextMenu.Item onclick={() => navigate(`/${resourceName}/edit/${id}`)} class="gap-2">
|
|
771
|
-
<Pencil class="h-4 w-4" /> {t('common.edit')}
|
|
784
|
+
<ContextMenu.Item onclick={() => adminContext.navigate(`/${resourceName}/edit/${id}`)} class="gap-2">
|
|
785
|
+
<Pencil class="h-4 w-4" /> {i18n.t('common.edit')}
|
|
772
786
|
</ContextMenu.Item>
|
|
773
787
|
{/if}
|
|
774
|
-
<ContextMenu.Item onclick={() => navigate(`/${resourceName}/show/${id}`)} class="gap-2">
|
|
775
|
-
<Eye class="h-4 w-4" /> {t('common.detail')}
|
|
788
|
+
<ContextMenu.Item onclick={() => adminContext.navigate(`/${resourceName}/show/${id}`)} class="gap-2">
|
|
789
|
+
<Eye class="h-4 w-4" /> {i18n.t('common.detail')}
|
|
776
790
|
</ContextMenu.Item>
|
|
777
791
|
<ContextMenu.Item onclick={() => navigator.clipboard?.writeText(String(id))} class="gap-2">
|
|
778
|
-
<Copy class="h-4 w-4" /> {t('common.copyId')}
|
|
792
|
+
<Copy class="h-4 w-4" /> {i18n.t('common.copyId')}
|
|
779
793
|
</ContextMenu.Item>
|
|
780
794
|
{#if canDelete}
|
|
781
795
|
<ContextMenu.Separator />
|
|
782
796
|
<ContextMenu.Item onclick={() => confirmDelete(id)} class="gap-2 text-destructive">
|
|
783
|
-
<Trash2 class="h-4 w-4" /> {t('common.delete')}
|
|
797
|
+
<Trash2 class="h-4 w-4" /> {i18n.t('common.delete')}
|
|
784
798
|
</ContextMenu.Item>
|
|
785
799
|
{/if}
|
|
786
800
|
</ContextMenu.Content>
|
|
@@ -802,12 +816,12 @@
|
|
|
802
816
|
<svg class="h-16 w-16 text-muted-foreground/30 mb-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor">
|
|
803
817
|
<path stroke-linecap="round" stroke-linejoin="round" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
|
|
804
818
|
</svg>
|
|
805
|
-
<p class="text-sm font-medium text-muted-foreground mb-1">{t('common.noData')}</p>
|
|
806
|
-
<p class="text-xs text-muted-foreground/60 mb-4">{t('common.noDataHint') || 'Get started by creating your first record.'}</p>
|
|
819
|
+
<p class="text-sm font-medium text-muted-foreground mb-1">{i18n.t('common.noData')}</p>
|
|
820
|
+
<p class="text-xs text-muted-foreground/60 mb-4">{i18n.t('common.noDataHint') || 'Get started by creating your first record.'}</p>
|
|
807
821
|
{#if canCreate}
|
|
808
|
-
<Button variant="outline" size="sm" class="gap-2" onclick={() => navigate(`/${resourceName}/create`)}>
|
|
822
|
+
<Button variant="outline" size="sm" class="gap-2" onclick={() => adminContext.navigate(`/${resourceName}/create`)}>
|
|
809
823
|
<Plus class="h-3.5 w-3.5" />
|
|
810
|
-
{t('common.create')}
|
|
824
|
+
{i18n.t('common.create')}
|
|
811
825
|
</Button>
|
|
812
826
|
{/if}
|
|
813
827
|
</div>
|
|
@@ -843,15 +857,15 @@
|
|
|
843
857
|
{@render rowActions({ record, id })}
|
|
844
858
|
{:else}
|
|
845
859
|
{#if canEdit}
|
|
846
|
-
<TooltipButton tooltip={t('common.edit')} variant="ghost" size="icon-sm" onclick={() => navigate(`/${resourceName}/edit/${id}`)}>
|
|
860
|
+
<TooltipButton tooltip={i18n.t('common.edit')} variant="ghost" size="icon-sm" onclick={() => adminContext.navigate(`/${resourceName}/edit/${id}`)}>
|
|
847
861
|
<Pencil class="h-4 w-4" />
|
|
848
862
|
</TooltipButton>
|
|
849
863
|
{/if}
|
|
850
|
-
<TooltipButton tooltip={t('common.detail')} variant="ghost" size="icon-sm" onclick={() => navigate(`/${resourceName}/show/${id}`)}>
|
|
864
|
+
<TooltipButton tooltip={i18n.t('common.detail')} variant="ghost" size="icon-sm" onclick={() => adminContext.navigate(`/${resourceName}/show/${id}`)}>
|
|
851
865
|
<Eye class="h-4 w-4" />
|
|
852
866
|
</TooltipButton>
|
|
853
867
|
{#if canDelete}
|
|
854
|
-
<TooltipButton tooltip={t('common.delete')} variant="ghost" size="icon-sm" onclick={() => confirmDelete(id)} class="hover:text-destructive">
|
|
868
|
+
<TooltipButton tooltip={i18n.t('common.delete')} variant="ghost" size="icon-sm" onclick={() => confirmDelete(id)} class="hover:text-destructive">
|
|
855
869
|
<Trash2 class="h-4 w-4" />
|
|
856
870
|
</TooltipButton>
|
|
857
871
|
{/if}
|
|
@@ -895,7 +909,7 @@
|
|
|
895
909
|
{#if emptyState}
|
|
896
910
|
{@render emptyState()}
|
|
897
911
|
{:else}
|
|
898
|
-
{t('common.noData')}
|
|
912
|
+
{i18n.t('common.noData')}
|
|
899
913
|
{/if}
|
|
900
914
|
</div>
|
|
901
915
|
{/each}
|
|
@@ -908,7 +922,7 @@
|
|
|
908
922
|
{#if totalPages > 0}
|
|
909
923
|
<div class="flex flex-col sm:flex-row items-center justify-between gap-2 text-sm text-muted-foreground">
|
|
910
924
|
<div class="flex items-center gap-2">
|
|
911
|
-
<span>{t('common.total', { total: query.data?.total ?? 0 })}</span>
|
|
925
|
+
<span>{i18n.t('common.total', { total: query.data?.total ?? 0 })}</span>
|
|
912
926
|
<select
|
|
913
927
|
class="h-8 w-[70px] px-1 py-1 flex items-center justify-between rounded-md border border-input bg-background text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
914
928
|
value={String(pagination.pageSize ?? 10)}
|
|
@@ -962,7 +976,7 @@
|
|
|
962
976
|
<ConfirmDialog
|
|
963
977
|
open={confirmOpen}
|
|
964
978
|
message={confirmMessage}
|
|
965
|
-
confirmText={t('common.delete')}
|
|
979
|
+
confirmText={i18n.t('common.delete')}
|
|
966
980
|
onconfirm={confirmAction}
|
|
967
981
|
oncancel={() => { confirmOpen = false; }}
|
|
968
982
|
/>
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
import { getResources } from '@svadmin/core';
|
|
2
|
+
import { captureAdminContext, getResources } from '@svadmin/core';
|
|
4
3
|
import { getPath } from '../router-state.svelte.js';
|
|
5
|
-
import {
|
|
6
|
-
|
|
4
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
5
|
+
|
|
7
6
|
import * as Breadcrumb from './ui/breadcrumb/index.js';
|
|
8
7
|
|
|
8
|
+
const i18n = useTranslation();
|
|
9
|
+
|
|
10
|
+
const adminContext = captureAdminContext();
|
|
9
11
|
const resources = $derived((() => { try { return getResources(); } catch { return []; } })());
|
|
10
12
|
|
|
11
13
|
interface Crumb { label: string; href: string; }
|
|
12
14
|
|
|
13
15
|
const crumbs = $derived.by(() => {
|
|
14
|
-
const result: Crumb[] = [{ label: t('common.home') ?? 'Home', href: formatLink('/') }];
|
|
16
|
+
const result: Crumb[] = [{ label: i18n.t('common.home') ?? 'Home', href: adminContext.formatLink('/') }];
|
|
15
17
|
const path = getPath().replace(/^\//, '');
|
|
16
18
|
if (path === '') return result;
|
|
17
19
|
|
|
@@ -25,21 +27,23 @@
|
|
|
25
27
|
currentPath += `/${seg}`;
|
|
26
28
|
|
|
27
29
|
if (resourceNames.includes(seg)) {
|
|
28
|
-
const res = resources.find(r => r.name === seg)
|
|
29
|
-
|
|
30
|
+
const res = resources.find(r => r.name === seg);
|
|
31
|
+
if (res) {
|
|
32
|
+
result.push({ label: res.label, href: adminContext.formatLink(currentPath) });
|
|
33
|
+
}
|
|
30
34
|
} else if (seg === 'create') {
|
|
31
|
-
result.push({ label: t('common.create') ?? 'Create', href: formatLink(currentPath) });
|
|
35
|
+
result.push({ label: i18n.t('common.create') ?? 'Create', href: adminContext.formatLink(currentPath) });
|
|
32
36
|
} else if (['edit', 'show', 'clone'].includes(seg) && segments[i+1]) {
|
|
33
|
-
const actionLabel = seg === 'edit' ? (t('common.edit') ?? 'Edit') :
|
|
34
|
-
seg === 'show' ? (t('common.detail') ?? 'Details') :
|
|
35
|
-
(t('common.clone') ?? 'Clone');
|
|
37
|
+
const actionLabel = seg === 'edit' ? (i18n.t('common.edit') ?? 'Edit') :
|
|
38
|
+
seg === 'show' ? (i18n.t('common.detail') ?? 'Details') :
|
|
39
|
+
(i18n.t('common.clone') ?? 'Clone');
|
|
36
40
|
const id = segments[i+1];
|
|
37
41
|
currentPath += `/${id}`; // advance path by id
|
|
38
|
-
result.push({ label: `${actionLabel} #${id}`, href: formatLink(currentPath) });
|
|
42
|
+
result.push({ label: `${actionLabel} #${id}`, href: adminContext.formatLink(currentPath) });
|
|
39
43
|
i++; // skip next segment since we consumed the id
|
|
40
44
|
} else if (i > 0 && resourceNames.includes(segments[i-1])) {
|
|
41
45
|
// This is a parent ID (e.g. /teams/123/users) and we are not an action
|
|
42
|
-
result.push({ label: `#${seg}`, href: formatLink(currentPath) });
|
|
46
|
+
result.push({ label: `#${seg}`, href: adminContext.formatLink(currentPath) });
|
|
43
47
|
}
|
|
44
48
|
}
|
|
45
49
|
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getTaskProvider } from '@svadmin/core';
|
|
3
3
|
import { useQueryClient } from '@tanstack/svelte-query';
|
|
4
|
-
import {
|
|
4
|
+
import { useTranslation } from '@svadmin/core/i18n';
|
|
5
|
+
|
|
5
6
|
import { Button } from './ui/button/index.js';
|
|
6
7
|
import { Loader2, Ban } from '@lucide/svelte';
|
|
7
8
|
|
|
9
|
+
const i18n = useTranslation();
|
|
10
|
+
|
|
8
11
|
let {
|
|
9
12
|
taskId,
|
|
10
13
|
taskProvider = getTaskProvider({ optional: true }),
|
|
@@ -55,6 +58,6 @@
|
|
|
55
58
|
{#if children}
|
|
56
59
|
{@render children()}
|
|
57
60
|
{:else}
|
|
58
|
-
{t('common.cancel')}
|
|
61
|
+
{i18n.t('common.cancel')}
|
|
59
62
|
{/if}
|
|
60
63
|
</Button>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { useIsAuthenticated } from '@svadmin/core';
|
|
3
|
-
import { navigate } from '@svadmin/core/router';
|
|
2
|
+
import { captureAdminContext, useIsAuthenticated } from '@svadmin/core';
|
|
4
3
|
import NavigateToResource from './NavigateToResource.svelte';
|
|
5
4
|
|
|
5
|
+
const adminContext = captureAdminContext();
|
|
6
6
|
const auth = useIsAuthenticated();
|
|
7
7
|
|
|
8
8
|
$effect(() => {
|
|
9
9
|
if (!auth.isLoading && !auth.isAuthenticated) {
|
|
10
|
-
navigate('/login');
|
|
10
|
+
adminContext.navigate('/login');
|
|
11
11
|
}
|
|
12
12
|
});
|
|
13
13
|
</script>
|