@svadmin/ui 0.34.8 → 0.34.10
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/component-registry.svelte.js +1 -0
- package/dist/components/AICommandBar.svelte +3 -3
- package/dist/components/AboutSettings.svelte +2 -2
- package/dist/components/AdminApp.svelte +2 -3
- package/dist/components/AnomalyBadge.svelte +1 -1
- package/dist/components/AppearanceSettings.svelte +5 -6
- package/dist/components/AuditLogDrawer.svelte +1 -1
- package/dist/components/AuditLogViewer.svelte +1 -1
- package/dist/components/AutoForm.svelte +5 -4
- package/dist/components/AutoTable.svelte +126 -57
- package/dist/components/Breadcrumbs.svelte +1 -0
- package/dist/components/ChatDialog.svelte +5 -4
- package/dist/components/ComboboxField.svelte +3 -3
- package/dist/components/CommandPalette.svelte +3 -3
- package/dist/components/CopilotPanel.svelte +2 -2
- package/dist/components/CreatePage.svelte +0 -1
- package/dist/components/DevTools.svelte +4 -3
- package/dist/components/DraggableHeader.svelte +2 -1
- package/dist/components/EditPage.svelte +1 -1
- package/dist/components/EmptyState.svelte +1 -1
- package/dist/components/FieldRenderer.svelte +7 -6
- package/dist/components/Header.svelte +1 -0
- package/dist/components/InferencerPanel.svelte +4 -3
- package/dist/components/InfiniteList.svelte +3 -4
- package/dist/components/KeyboardShortcuts.svelte +3 -3
- package/dist/components/Layout.svelte +5 -5
- package/dist/components/MarkdownRenderer.svelte +3 -5
- package/dist/components/ModalForm.svelte +1 -3
- package/dist/components/PageSkeleton.svelte +4 -4
- package/dist/components/PasswordInput.svelte +1 -2
- package/dist/components/PermissionMatrix.svelte +5 -5
- package/dist/components/ProfilePage.svelte +1 -1
- package/dist/components/RolesSettings.svelte +1 -2
- package/dist/components/SettingsPage.svelte +4 -5
- package/dist/components/ShowPage.svelte +4 -6
- package/dist/components/Sidebar.svelte +12 -11
- package/dist/components/SidebarItem.svelte +1 -2
- package/dist/components/StepsForm.svelte +1 -1
- package/dist/components/TaskList.svelte +1 -1
- package/dist/components/TaskQueueDrawer.svelte +2 -1
- package/dist/components/TenantSwitcher.svelte +1 -2
- package/dist/components/Toast.svelte +1 -0
- package/dist/components/TooltipButton.svelte +1 -0
- package/dist/components/VirtualTable.svelte +1 -1
- package/dist/components/VoiceInput.svelte +1 -0
- package/dist/components/buttons/ImportButton.svelte +1 -1
- package/dist/components/buttons/ListButton.svelte +1 -1
- package/dist/components/charts/BarChart.svelte +1 -1
- package/dist/components/charts/LineChart.svelte +3 -3
- package/dist/components/charts/PieChart.svelte +2 -2
- package/dist/components/fieldComponentMap.js +2 -1
- package/dist/components/fields/ArrayField.svelte +1 -1
- package/dist/components/fields/MarkdownField.svelte +1 -0
- package/dist/components/fields/MultiSelectField.svelte +1 -1
- package/dist/components/fields/TagField.svelte +1 -1
- package/dist/components/ui/alert/index.js +1 -0
- package/dist/components/ui/badge/index.js +1 -0
- package/dist/components/ui/button/button.svelte +1 -0
- package/dist/components/ui/button/index.js +1 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +1 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu.svelte +1 -1
- package/dist/components/ui/sheet/sheet.svelte +1 -0
- package/dist/components/ui/tabs/tabs.svelte +1 -0
- package/package.json +13 -13
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { toggleTheme } from '@svadmin/core';
|
|
6
6
|
import { Command } from 'cmdk-sv';
|
|
7
7
|
import * as Dialog from './ui/dialog/index.js';
|
|
8
|
-
import { Search, LayoutDashboard, Plus, Sun, FileText, Sparkles, Loader2
|
|
8
|
+
import { Search, LayoutDashboard, Plus, Sun, FileText, Sparkles, Loader2 } from '@lucide/svelte';
|
|
9
9
|
import MarkdownRenderer from './MarkdownRenderer.svelte';
|
|
10
10
|
|
|
11
11
|
let { open = $bindable(false) } = $props<{ open?: boolean }>();
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
<LayoutDashboard class="h-4 w-4 text-muted-foreground" />
|
|
125
125
|
{t('common.home')}
|
|
126
126
|
</Command.Item>
|
|
127
|
-
{#each resources as r}
|
|
127
|
+
{#each resources as r, _i (_i)}
|
|
128
128
|
<Command.Item value={r.name} onSelect={() => act(() => navigate(`/${r.name}`))} class={itemClass}>
|
|
129
129
|
<FileText class="h-4 w-4 text-muted-foreground" />
|
|
130
130
|
{r.label}
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
|
|
137
137
|
<!-- Actions -->
|
|
138
138
|
<Command.Group heading={t('common.actions')}>
|
|
139
|
-
{#each resources as r}
|
|
139
|
+
{#each resources as r, _i (_i)}
|
|
140
140
|
<Command.Item value={`create-${r.name}`} onSelect={() => act(() => navigate(`/${r.name}/create`))} class={itemClass}>
|
|
141
141
|
<Plus class="h-4 w-4 text-muted-foreground" />
|
|
142
142
|
{t('common.create')} {r.label}
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
</Card.CardHeader>
|
|
47
47
|
<Card.CardContent>
|
|
48
48
|
<div class="flex flex-wrap gap-2">
|
|
49
|
-
{#each resources as resource}
|
|
49
|
+
{#each resources as resource, _i (_i)}
|
|
50
50
|
<Badge variant="outline" class="font-mono text-xs">{resource.name}</Badge>
|
|
51
51
|
{/each}
|
|
52
52
|
{#if resources.length === 0}
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
</Card.CardHeader>
|
|
67
67
|
<Card.CardContent>
|
|
68
68
|
<div class="flex flex-wrap gap-2">
|
|
69
|
-
{#each providerNames as name}
|
|
69
|
+
{#each providerNames as name, _i (_i)}
|
|
70
70
|
<Badge variant="outline" class="font-mono text-xs">{name}</Badge>
|
|
71
71
|
{/each}
|
|
72
72
|
</div>
|
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
import '../app.css';
|
|
4
4
|
import type { Snippet } from 'svelte';
|
|
5
5
|
import type { DataProvider, AuthProvider, ResourceDefinition, ThemeMode, RouterProvider, ThemeConfig, MenuItem, TaskProvider } from '@svadmin/core';
|
|
6
|
-
import { setDataProvider, setAuthProvider, setResources, setLocale, setTheme, setRouterProvider, setTaskProvider,
|
|
6
|
+
import { setDataProvider, setAuthProvider, setResources, setLocale, setTheme, setRouterProvider, setTaskProvider, createHashRouterProvider, configureTheme } from '@svadmin/core';
|
|
7
7
|
import { t } from '@svadmin/core/i18n';
|
|
8
8
|
import { navigate } from '@svadmin/core/router';
|
|
9
|
-
import { currentPath } from '@svadmin/core/router';
|
|
10
9
|
import { QueryClient, QueryClientProvider, type DefaultOptions } from '@tanstack/svelte-query';
|
|
11
|
-
import { setComponentRegistry,
|
|
10
|
+
import { setComponentRegistry, type ComponentRegistry } from '../component-registry.svelte.js';
|
|
12
11
|
import Layout from './Layout.svelte';
|
|
13
12
|
import AutoTable from './AutoTable.svelte';
|
|
14
13
|
import AutoForm from './AutoForm.svelte';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Badge } from './ui/badge/index.js';
|
|
3
|
-
import { TrendingUp, TrendingDown
|
|
3
|
+
import { TrendingUp, TrendingDown } from '@lucide/svelte';
|
|
4
4
|
import TooltipButton from './TooltipButton.svelte';
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { t } from '@svadmin/core/i18n';
|
|
3
|
-
import { getTheme, setTheme,
|
|
3
|
+
import { getTheme, setTheme, getColorTheme, setColorTheme, getColorPresets } from '@svadmin/core';
|
|
4
4
|
import { getLocale, setLocale, getAvailableLocales } from '@svadmin/core/i18n';
|
|
5
5
|
import * as Card from './ui/card/index.js';
|
|
6
|
-
import { Button } from './ui/button/index.js';
|
|
7
6
|
import { Sun, Moon, Monitor, Check } from '@lucide/svelte';
|
|
8
7
|
|
|
9
8
|
// Theme mode
|
|
@@ -67,7 +66,7 @@
|
|
|
67
66
|
</Card.CardHeader>
|
|
68
67
|
<Card.CardContent>
|
|
69
68
|
<div class="grid grid-cols-3 gap-3">
|
|
70
|
-
{#each themeOptions as opt}
|
|
69
|
+
{#each themeOptions as opt, _i (_i)}
|
|
71
70
|
{@const active = currentTheme === opt.value}
|
|
72
71
|
<button
|
|
73
72
|
class="relative flex flex-col items-center gap-2 rounded-xl border-2 p-4 transition-all duration-200
|
|
@@ -101,7 +100,7 @@
|
|
|
101
100
|
</Card.CardHeader>
|
|
102
101
|
<Card.CardContent>
|
|
103
102
|
<div class="flex flex-wrap gap-3">
|
|
104
|
-
{#each presets as preset}
|
|
103
|
+
{#each presets as preset, _i (_i)}
|
|
105
104
|
{@const active = currentColor === preset.name}
|
|
106
105
|
<button
|
|
107
106
|
class="group relative h-9 w-9 rounded-full transition-all duration-200 hover:scale-110
|
|
@@ -137,7 +136,7 @@
|
|
|
137
136
|
value={currentLocale}
|
|
138
137
|
onchange={(e) => setLocale((e.target as HTMLSelectElement).value)}
|
|
139
138
|
>
|
|
140
|
-
{#each availableLocales as loc}
|
|
139
|
+
{#each availableLocales as loc, _i (_i)}
|
|
141
140
|
<option value={loc}>{localeNames[loc] ?? loc}</option>
|
|
142
141
|
{/each}
|
|
143
142
|
</select>
|
|
@@ -172,7 +171,7 @@
|
|
|
172
171
|
<p class="text-sm font-medium text-foreground">{t('settings.defaultPageSize')}</p>
|
|
173
172
|
</div>
|
|
174
173
|
<div class="flex rounded-lg border border-input overflow-hidden">
|
|
175
|
-
{#each pageSizeOptions as size}
|
|
174
|
+
{#each pageSizeOptions as size, _i (_i)}
|
|
176
175
|
<button
|
|
177
176
|
class="px-3 py-1.5 text-xs font-mono font-medium transition-colors
|
|
178
177
|
{pageSize === size ? 'bg-primary text-primary-foreground' : 'bg-background text-muted-foreground hover:bg-accent'}"
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
</div>
|
|
69
69
|
{:else}
|
|
70
70
|
<div class="relative border-l border-border ml-3 pl-6 space-y-8">
|
|
71
|
-
{#each logs as log}
|
|
71
|
+
{#each logs as log, _i (_i)}
|
|
72
72
|
<div class="relative">
|
|
73
73
|
<span class="absolute -left-7 top-1 flex h-2 w-2 items-center justify-center rounded-full ring-4 ring-background {getActionColor(log.action)}"></span>
|
|
74
74
|
<div class="flex flex-col gap-1.5">
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
</Table.Row>
|
|
131
131
|
</Table.Header>
|
|
132
132
|
<Table.Body>
|
|
133
|
-
{#each filteredLogs as log}
|
|
133
|
+
{#each filteredLogs as log, _i (_i)}
|
|
134
134
|
<Table.Row class="border-0 even:bg-muted/20 hover:bg-muted/40 transition-colors">
|
|
135
135
|
<Table.Cell class="text-xs text-muted-foreground font-mono">
|
|
136
136
|
{formatDate(log.createdAt)}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
/* eslint-disable svelte/prefer-svelte-reactivity */
|
|
2
3
|
import { useForm, getResource, deriveValidator } from '@svadmin/core';
|
|
3
4
|
import { slide } from 'svelte/transition';
|
|
4
5
|
import type { FieldDefinition } from '@svadmin/core';
|
|
@@ -49,9 +50,9 @@
|
|
|
49
50
|
for (const f of formFields) {
|
|
50
51
|
const g = f.group ?? '';
|
|
51
52
|
if (!map.has(g)) { order.push(g); map.set(g, []); }
|
|
52
|
-
map.get(g)
|
|
53
|
+
(map.get(g) ?? []).push(f);
|
|
53
54
|
}
|
|
54
|
-
return order.map(g => ({ name: g, fields: map.get(g)
|
|
55
|
+
return order.map(g => ({ name: g, fields: map.get(g) ?? [] }));
|
|
55
56
|
})());
|
|
56
57
|
|
|
57
58
|
// ─── Default values from field metadata ───────────────────────────
|
|
@@ -161,7 +162,7 @@
|
|
|
161
162
|
{#if form.loading}
|
|
162
163
|
<div class="max-w-3xl space-y-6">
|
|
163
164
|
<div class="rounded-lg shadow-sm ring-1 ring-border/10 p-6 space-y-5">
|
|
164
|
-
{#each Array(4) as _}
|
|
165
|
+
{#each Array(4) as _, _i (_i)}
|
|
165
166
|
<div class="space-y-2">
|
|
166
167
|
<Skeleton class="h-4 w-24" />
|
|
167
168
|
<Skeleton class="h-10 w-full" />
|
|
@@ -181,7 +182,7 @@
|
|
|
181
182
|
{/if}
|
|
182
183
|
|
|
183
184
|
{#if hasGroups}
|
|
184
|
-
{#each groups as group}
|
|
185
|
+
{#each groups as group, _i (_i)}
|
|
185
186
|
<Card.Root class="border-border/40 shadow-sm">
|
|
186
187
|
{#if group.name}
|
|
187
188
|
<Card.Header>
|
|
@@ -10,6 +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
14
|
import {
|
|
14
15
|
column_getCanSort,
|
|
15
16
|
column_getIsSorted,
|
|
@@ -24,11 +25,11 @@
|
|
|
24
25
|
table_toggleAllRowsSelected,
|
|
25
26
|
row_getIsSelected,
|
|
26
27
|
row_toggleSelected,
|
|
27
|
-
|
|
28
|
+
row_getVisibleCells,
|
|
28
29
|
row_getIsExpanded,
|
|
29
30
|
row_toggleExpanded,
|
|
30
31
|
cell_getValue,
|
|
31
|
-
} from '@tanstack/
|
|
32
|
+
} from '@tanstack/table-core/static-functions';
|
|
32
33
|
|
|
33
34
|
import { useList, useDelete, useDeleteMany, getResource, notify } from '@svadmin/core';
|
|
34
35
|
import type { Pagination as PaginationState, Sort, Filter, FieldDefinition } from '@svadmin/core';
|
|
@@ -107,7 +108,7 @@
|
|
|
107
108
|
const initPageSize = untrack(() => resource.pageSize ?? (isNaN(storedPageSize) ? 10 : storedPageSize));
|
|
108
109
|
const initDefaultSort = untrack(() => resource.defaultSort);
|
|
109
110
|
|
|
110
|
-
let pagination = $state<
|
|
111
|
+
let pagination = $state<PaginationState>(untrack(() => externalPagination ?? {
|
|
111
112
|
current: urlState.page ?? 1,
|
|
112
113
|
pageSize: urlState.pageSize ?? initPageSize,
|
|
113
114
|
}));
|
|
@@ -173,6 +174,41 @@
|
|
|
173
174
|
return result;
|
|
174
175
|
});
|
|
175
176
|
|
|
177
|
+
function clonePlainValue(value: unknown): unknown {
|
|
178
|
+
if (Array.isArray(value)) return value.map(clonePlainValue);
|
|
179
|
+
if (value && typeof value === 'object') {
|
|
180
|
+
return Object.fromEntries(
|
|
181
|
+
Object.entries(value as Record<string, unknown>).map(([key, entry]) => [key, clonePlainValue(entry)])
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function cloneFilter(filter: Filter): Filter {
|
|
188
|
+
if ('field' in filter) {
|
|
189
|
+
return {
|
|
190
|
+
field: filter.field,
|
|
191
|
+
operator: filter.operator,
|
|
192
|
+
value: clonePlainValue(filter.value),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
operator: filter.operator,
|
|
197
|
+
value: filter.value.map(cloneFilter),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const queryPagination = $derived<PaginationState>({
|
|
202
|
+
current: pagination.current,
|
|
203
|
+
pageSize: pagination.pageSize,
|
|
204
|
+
mode: pagination.mode,
|
|
205
|
+
});
|
|
206
|
+
const querySorters = $derived<Sort[]>(sorters.map(sorter => ({
|
|
207
|
+
field: sorter.field,
|
|
208
|
+
order: sorter.order,
|
|
209
|
+
})));
|
|
210
|
+
const queryFilters = $derived<Filter[]>(activeFilters.map(cloneFilter));
|
|
211
|
+
|
|
176
212
|
$effect(() => {
|
|
177
213
|
if (Object.values(filterValues).some(v => v.trim())) {
|
|
178
214
|
pagination = { ...pagination, current: 1 };
|
|
@@ -182,9 +218,9 @@
|
|
|
182
218
|
// ─── Data fetching ────────────────────────────────────────────
|
|
183
219
|
const listResult = useList({
|
|
184
220
|
get resource() { return resourceName; },
|
|
185
|
-
get pagination() { return
|
|
186
|
-
get sorters() { return
|
|
187
|
-
get filters() { return
|
|
221
|
+
get pagination() { return queryPagination; },
|
|
222
|
+
get sorters() { return querySorters; },
|
|
223
|
+
get filters() { return queryFilters; },
|
|
188
224
|
});
|
|
189
225
|
const query = listResult;
|
|
190
226
|
const deleteResult = useDelete({ get resource() { return resourceName; } });
|
|
@@ -227,6 +263,68 @@
|
|
|
227
263
|
let expanded = $state.raw<ExpandedState>({});
|
|
228
264
|
let columnOrder = $state<string[]>([]);
|
|
229
265
|
|
|
266
|
+
function applyTableUpdater<T>(current: T, updater: Updater<T>): T {
|
|
267
|
+
return typeof updater === 'function' ? (updater as (old: T) => T)(current) : updater;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const tableSorting = $derived<SortingState>(sorting.map(sorter => ({
|
|
271
|
+
id: sorter.id,
|
|
272
|
+
desc: sorter.desc,
|
|
273
|
+
})));
|
|
274
|
+
const tableColumnVisibility = $derived<ColumnVisibilityState>({ ...columnVisibility });
|
|
275
|
+
const tableRowSelection = $derived<RowSelectionState>({ ...rowSelection });
|
|
276
|
+
const tableExpanded = $derived<ExpandedState>(expanded === true ? true : { ...expanded });
|
|
277
|
+
const tableColumnOrder = $derived<string[]>([...columnOrder]);
|
|
278
|
+
|
|
279
|
+
const sortingAtom = {
|
|
280
|
+
get: () => tableSorting,
|
|
281
|
+
set: (updater: Updater<SortingState>) => {
|
|
282
|
+
const nextSorting = applyTableUpdater(tableSorting, updater);
|
|
283
|
+
sorting = nextSorting;
|
|
284
|
+
|
|
285
|
+
const nextSorters: Sort[] = nextSorting.map((s) => ({
|
|
286
|
+
field: s.id,
|
|
287
|
+
order: s.desc ? 'desc' as const : 'asc' as const,
|
|
288
|
+
}));
|
|
289
|
+
|
|
290
|
+
if (JSON.stringify(nextSorters) !== JSON.stringify(sorters)) {
|
|
291
|
+
sorters = nextSorters;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if ((pagination.current ?? 1) !== 1) {
|
|
295
|
+
pagination = { ...pagination, current: 1 };
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const columnVisibilityAtom = {
|
|
301
|
+
get: () => tableColumnVisibility,
|
|
302
|
+
set: (updater: Updater<ColumnVisibilityState>) => {
|
|
303
|
+
columnVisibility = applyTableUpdater(tableColumnVisibility, updater);
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
const rowSelectionAtom = {
|
|
308
|
+
get: () => tableRowSelection,
|
|
309
|
+
set: (updater: Updater<RowSelectionState>) => {
|
|
310
|
+
rowSelection = applyTableUpdater(tableRowSelection, updater);
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const expandedAtom = {
|
|
315
|
+
get: () => tableExpanded,
|
|
316
|
+
set: (updater: Updater<ExpandedState>) => {
|
|
317
|
+
expanded = applyTableUpdater(tableExpanded, updater);
|
|
318
|
+
},
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const columnOrderAtom = {
|
|
322
|
+
get: () => tableColumnOrder,
|
|
323
|
+
set: (updater: Updater<string[]>) => {
|
|
324
|
+
columnOrder = applyTableUpdater(tableColumnOrder, updater);
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
|
|
230
328
|
// Persist column visibility to localStorage
|
|
231
329
|
$effect(() => {
|
|
232
330
|
const storageKey = `svadmin-columns-${resourceName}`;
|
|
@@ -297,41 +395,12 @@
|
|
|
297
395
|
manualPagination: true,
|
|
298
396
|
manualSorting: true,
|
|
299
397
|
getRowId: (row: any) => String(row[primaryKey]),
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
},
|
|
307
|
-
onSortingChange: (updater: any) => {
|
|
308
|
-
const nextSorting = typeof updater === 'function' ? updater(sorting) : updater;
|
|
309
|
-
sorting = nextSorting;
|
|
310
|
-
|
|
311
|
-
const nextSorters: Sort[] = nextSorting.map((s: any) => ({
|
|
312
|
-
field: s.id,
|
|
313
|
-
order: s.desc ? 'desc' as const : 'asc' as const,
|
|
314
|
-
}));
|
|
315
|
-
|
|
316
|
-
if (JSON.stringify(nextSorters) !== JSON.stringify(sorters)) {
|
|
317
|
-
sorters = nextSorters;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if ((pagination.current ?? 1) !== 1) {
|
|
321
|
-
pagination = { ...pagination, current: 1 };
|
|
322
|
-
}
|
|
323
|
-
},
|
|
324
|
-
onColumnVisibilityChange: (updater: any) => {
|
|
325
|
-
columnVisibility = typeof updater === 'function' ? updater(columnVisibility) : updater;
|
|
326
|
-
},
|
|
327
|
-
onRowSelectionChange: (updater: any) => {
|
|
328
|
-
rowSelection = typeof updater === 'function' ? updater(rowSelection) : updater;
|
|
329
|
-
},
|
|
330
|
-
onExpandedChange: (updater: any) => {
|
|
331
|
-
expanded = typeof updater === 'function' ? updater(expanded) : updater;
|
|
332
|
-
},
|
|
333
|
-
onColumnOrderChange: (updater: any) => {
|
|
334
|
-
columnOrder = typeof updater === 'function' ? updater(columnOrder) : updater;
|
|
398
|
+
atoms: {
|
|
399
|
+
sorting: sortingAtom,
|
|
400
|
+
columnVisibility: columnVisibilityAtom,
|
|
401
|
+
rowSelection: rowSelectionAtom,
|
|
402
|
+
expanded: expandedAtom,
|
|
403
|
+
columnOrder: columnOrderAtom,
|
|
335
404
|
},
|
|
336
405
|
get enableRowSelection() { return selectable && (canDelete || batchActions); },
|
|
337
406
|
get enableExpanding() { return !!expandedRowRender; },
|
|
@@ -450,7 +519,7 @@
|
|
|
450
519
|
{/snippet}
|
|
451
520
|
</DropdownMenu.Trigger>
|
|
452
521
|
<DropdownMenu.Content align="end" class="w-48">
|
|
453
|
-
{#each table_getAllLeafColumns(tbl).filter((c: any) => !c.id.startsWith('_')) as column}
|
|
522
|
+
{#each table_getAllLeafColumns(tbl).filter((c: any) => !c.id.startsWith('_')) as column, _i (_i)}
|
|
454
523
|
<DropdownMenu.CheckboxItem
|
|
455
524
|
checked={column_getIsVisible(column)}
|
|
456
525
|
onCheckedChange={(v) => column_toggleVisibility(column, !!v)}
|
|
@@ -502,7 +571,7 @@
|
|
|
502
571
|
<Popover.Content class="w-80">
|
|
503
572
|
<div class="space-y-3">
|
|
504
573
|
<h4 class="font-medium text-sm">{t('common.filter')}</h4>
|
|
505
|
-
{#each filterableFields as field}
|
|
574
|
+
{#each filterableFields as field, _i (_i)}
|
|
506
575
|
<div class="space-y-1">
|
|
507
576
|
<label class="text-xs text-muted-foreground" for="filter-{field.key}">{field.label}</label>
|
|
508
577
|
{#if field.type === 'select' && field.options}
|
|
@@ -513,7 +582,7 @@
|
|
|
513
582
|
onchange={(e) => filterValues[field.key] = (e.currentTarget as HTMLSelectElement).value}
|
|
514
583
|
>
|
|
515
584
|
<option value="">{t('common.all')}</option>
|
|
516
|
-
{#each field.options as opt}
|
|
585
|
+
{#each field.options as opt, _i (_i)}
|
|
517
586
|
<option value={opt.value}>{opt.label}</option>
|
|
518
587
|
{/each}
|
|
519
588
|
</select>
|
|
@@ -551,13 +620,13 @@
|
|
|
551
620
|
{#if query.isLoading}
|
|
552
621
|
<div class="p-4 space-y-3">
|
|
553
622
|
<div class="flex gap-4 mb-2">
|
|
554
|
-
{#each visibleFields.slice(0, 4) as _}
|
|
623
|
+
{#each visibleFields.slice(0, 4) as _, _i (_i)}
|
|
555
624
|
<Skeleton class="h-4 flex-1" />
|
|
556
625
|
{/each}
|
|
557
626
|
</div>
|
|
558
|
-
{#each Array(5) as _}
|
|
627
|
+
{#each Array(5) as _, _i (_i)}
|
|
559
628
|
<div class="flex gap-4">
|
|
560
|
-
{#each visibleFields.slice(0, 4) as __}
|
|
629
|
+
{#each visibleFields.slice(0, 4) as __, _i (_i)}
|
|
561
630
|
<Skeleton class="h-8 flex-1" />
|
|
562
631
|
{/each}
|
|
563
632
|
</div>
|
|
@@ -573,13 +642,13 @@
|
|
|
573
642
|
<div class="hidden md:block">
|
|
574
643
|
<Table.Root>
|
|
575
644
|
<Table.Header>
|
|
576
|
-
{#each table_getHeaderGroups(tbl) as headerGroup}
|
|
645
|
+
{#each table_getHeaderGroups(tbl) as headerGroup, _i (_i)}
|
|
577
646
|
<DraggableHeader
|
|
578
647
|
columns={headerGroup.headers.map((h: any) => ({ id: h.column.id, header: h }))}
|
|
579
648
|
resourceName={resourceName}
|
|
580
649
|
onReorder={(newOrder) => { columnOrder = newOrder.map((c: any) => c.id); }}
|
|
581
650
|
>
|
|
582
|
-
{#snippet header(col,
|
|
651
|
+
{#snippet header(col, _index, dragProps)}
|
|
583
652
|
{@const header = col.header as typeof headerGroup.headers[0]}
|
|
584
653
|
<Table.Head
|
|
585
654
|
{...dragProps}
|
|
@@ -619,14 +688,14 @@
|
|
|
619
688
|
{/each}
|
|
620
689
|
</Table.Header>
|
|
621
690
|
<Table.Body>
|
|
622
|
-
{#each table_getRowModel(tbl).rows as row}
|
|
691
|
+
{#each table_getRowModel(tbl).rows as row, _i (_i)}
|
|
623
692
|
{@const record = row.original}
|
|
624
693
|
{@const id = record[primaryKey] as string | number}
|
|
625
694
|
<ContextMenu.Root>
|
|
626
695
|
<ContextMenu.Trigger>
|
|
627
696
|
{#snippet child({ props })}
|
|
628
697
|
<Table.Row {...props} class="transition-all duration-300 border-b border-border/10 {row_getIsSelected(row) ? 'bg-primary/5' : 'hover:bg-muted/20'}">
|
|
629
|
-
{#each
|
|
698
|
+
{#each row_getVisibleCells(row) as cell, _i (_i)}
|
|
630
699
|
<Table.Cell>
|
|
631
700
|
{#if cell.column.id === '_select'}
|
|
632
701
|
<Checkbox
|
|
@@ -670,7 +739,7 @@
|
|
|
670
739
|
{new Date(cell_getValue(cell) as string).toLocaleDateString()}
|
|
671
740
|
{:else if field?.type === 'tags' && Array.isArray(cell_getValue(cell))}
|
|
672
741
|
<div class="flex flex-wrap gap-1">
|
|
673
|
-
{#each (cell_getValue(cell) as string[]).slice(0, 3) as tag}
|
|
742
|
+
{#each (cell_getValue(cell) as string[]).slice(0, 3) as tag, _i (_i)}
|
|
674
743
|
<Badge variant="secondary">{tag}</Badge>
|
|
675
744
|
{/each}
|
|
676
745
|
</div>
|
|
@@ -718,7 +787,7 @@
|
|
|
718
787
|
</ContextMenu.Root>
|
|
719
788
|
{#if expandedRowRender && row_getIsExpanded(row)}
|
|
720
789
|
<Table.Row class="bg-muted/10 border-b border-border/10 transition-all">
|
|
721
|
-
<Table.Cell colspan={
|
|
790
|
+
<Table.Cell colspan={row_getVisibleCells(row).length}>
|
|
722
791
|
{@render expandedRowRender({ record })}
|
|
723
792
|
</Table.Cell>
|
|
724
793
|
</Table.Row>
|
|
@@ -752,7 +821,7 @@
|
|
|
752
821
|
|
|
753
822
|
<!-- Mobile Card View (visible only on small screens) -->
|
|
754
823
|
<div class="md:hidden space-y-3 p-2">
|
|
755
|
-
{#each table_getRowModel(tbl).rows as row}
|
|
824
|
+
{#each table_getRowModel(tbl).rows as row, _i (_i)}
|
|
756
825
|
{@const record = row.original}
|
|
757
826
|
{@const id = record[primaryKey] as string | number}
|
|
758
827
|
<div
|
|
@@ -791,7 +860,7 @@
|
|
|
791
860
|
</div>
|
|
792
861
|
<!-- Card fields -->
|
|
793
862
|
<div class="space-y-2">
|
|
794
|
-
{#each visibleFields.slice(0, 6) as field}
|
|
863
|
+
{#each visibleFields.slice(0, 6) as field, _i (_i)}
|
|
795
864
|
{@const value = record[field.key]}
|
|
796
865
|
<div class="flex items-start justify-between gap-4">
|
|
797
866
|
<span class="text-xs font-medium text-muted-foreground shrink-0">{field.label}</span>
|
|
@@ -806,7 +875,7 @@
|
|
|
806
875
|
{new Date(value as string).toLocaleDateString()}
|
|
807
876
|
{:else if field.type === 'tags' && Array.isArray(value)}
|
|
808
877
|
<div class="flex flex-wrap gap-1 justify-end">
|
|
809
|
-
{#each (value as string[]).slice(0, 2) as tag}
|
|
878
|
+
{#each (value as string[]).slice(0, 2) as tag, _i (_i)}
|
|
810
879
|
<Badge variant="secondary" class="text-[10px]">{tag}</Badge>
|
|
811
880
|
{/each}
|
|
812
881
|
</div>
|
|
@@ -864,7 +933,7 @@
|
|
|
864
933
|
disabled={currentPage <= 1}
|
|
865
934
|
/>
|
|
866
935
|
</PaginationUI.Item>
|
|
867
|
-
{#each pages as page}
|
|
936
|
+
{#each pages as page, _i (_i)}
|
|
868
937
|
<PaginationUI.Item>
|
|
869
938
|
{#if page === '...'}
|
|
870
939
|
<PaginationUI.Ellipsis />
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
/* eslint-disable no-undef, svelte/no-at-html-tags */
|
|
2
3
|
import { getChatProvider, getChatContext, setChatContext, getAgentProvider, registerApproval, resolveApproval } from '@svadmin/core';
|
|
3
|
-
import type { ChatMessage, ChatAction
|
|
4
|
+
import type { ChatMessage, ChatAction } from '@svadmin/core';
|
|
4
5
|
import { t } from '@svadmin/core/i18n';
|
|
5
6
|
import { useParsed } from '@svadmin/core';
|
|
6
7
|
import { fly, fade, scale } from 'svelte/transition';
|
|
7
8
|
import { Button } from './ui/button/index.js';
|
|
8
9
|
import TooltipButton from './TooltipButton.svelte';
|
|
9
|
-
import { MessageCircle, X, Minus, Send, Loader2, Bot, Trash2
|
|
10
|
+
import { MessageCircle, X, Minus, Send, Loader2, Bot, Trash2 } from '@lucide/svelte';
|
|
10
11
|
|
|
11
12
|
interface Props {
|
|
12
13
|
/** localStorage key for chat history persistence. Set to '' to disable. */
|
|
@@ -508,7 +509,7 @@
|
|
|
508
509
|
{t('chat.welcomeDesc') || 'Ask me anything about your admin panel.'}
|
|
509
510
|
</p>
|
|
510
511
|
<div class="flex flex-col gap-2 w-full max-w-[240px]">
|
|
511
|
-
{#each suggestions as suggestion}
|
|
512
|
+
{#each suggestions as suggestion, _i (_i)}
|
|
512
513
|
<button
|
|
513
514
|
class="text-left text-xs px-3 py-2 rounded-lg border border-border hover:bg-accent hover:text-accent-foreground transition-colors cursor-pointer"
|
|
514
515
|
onclick={() => { inputValue = suggestion; }}
|
|
@@ -535,7 +536,7 @@
|
|
|
535
536
|
<!-- Action Buttons -->
|
|
536
537
|
{#if msg.actions && msg.actions.length > 0}
|
|
537
538
|
<div class="flex flex-wrap gap-1.5 mt-2 pt-2 border-t border-border/50">
|
|
538
|
-
{#each msg.actions as action}
|
|
539
|
+
{#each msg.actions as action, _i (_i)}
|
|
539
540
|
<Button
|
|
540
541
|
variant={action.variant ?? 'outline'}
|
|
541
542
|
size="sm"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
3
|
import { t } from '@svadmin/core/i18n';
|
|
3
4
|
import { useSelect } from '@svadmin/core';
|
|
4
5
|
import type { Filter } from '@svadmin/core';
|
|
5
6
|
import { Button } from './ui/button/index.js';
|
|
6
7
|
import TooltipButton from './TooltipButton.svelte';
|
|
7
|
-
import { Badge } from './ui/badge/index.js';
|
|
8
8
|
import { Command } from 'cmdk-sv';
|
|
9
9
|
import { Skeleton } from './ui/skeleton/index.js';
|
|
10
10
|
import { ChevronsUpDown, Check, X, Search } from '@lucide/svelte';
|
|
@@ -117,11 +117,11 @@
|
|
|
117
117
|
No results.
|
|
118
118
|
</Command.Empty>
|
|
119
119
|
{#if query.isLoading}
|
|
120
|
-
{#each Array(3) as _}
|
|
120
|
+
{#each Array(3) as _, _i (_i)}
|
|
121
121
|
<div class="px-2 py-1.5"><Skeleton class="h-5 w-full" /></div>
|
|
122
122
|
{/each}
|
|
123
123
|
{:else}
|
|
124
|
-
{#each (options as { label: string; value: string | number }[]) ?? [] as opt}
|
|
124
|
+
{#each (options as { label: string; value: string | number }[]) ?? [] as opt, _i (_i)}
|
|
125
125
|
<Command.Item
|
|
126
126
|
value={opt.label}
|
|
127
127
|
onSelect={() => handleSelect(opt.value)}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { toggleTheme } from '@svadmin/core';
|
|
6
6
|
import { Command } from 'cmdk-sv';
|
|
7
7
|
import * as Dialog from './ui/dialog/index.js';
|
|
8
|
-
import { Search, LayoutDashboard, Plus, Sun, FileText,
|
|
8
|
+
import { Search, LayoutDashboard, Plus, Sun, FileText, Sparkles } from '@lucide/svelte';
|
|
9
9
|
|
|
10
10
|
interface Props {
|
|
11
11
|
open?: boolean;
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
<LayoutDashboard class="h-4 w-4 text-muted-foreground" />
|
|
94
94
|
{t('common.home')}
|
|
95
95
|
</Command.Item>
|
|
96
|
-
{#each resources as r}
|
|
96
|
+
{#each resources as r, _i (_i)}
|
|
97
97
|
<Command.Item
|
|
98
98
|
value={r.name}
|
|
99
99
|
onSelect={() => act(() => navigate(`/${r.name}`))}
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
|
|
110
110
|
<!-- Actions -->
|
|
111
111
|
<Command.Group heading={t('common.actions')}>
|
|
112
|
-
{#each resources as r}
|
|
112
|
+
{#each resources as r, _i (_i)}
|
|
113
113
|
<Command.Item
|
|
114
114
|
value={"create-" + r.name}
|
|
115
115
|
onSelect={() => act(() => navigate(`/${r.name}/create`))}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getChatProvider, getChatContext } from '@svadmin/core';
|
|
3
|
-
import { Sparkles, X,
|
|
4
|
-
import {
|
|
3
|
+
import { Sparkles, X, Check, RefreshCcw } from '@lucide/svelte';
|
|
4
|
+
import { slide } from 'svelte/transition';
|
|
5
5
|
import { Button } from './ui/button/index.js';
|
|
6
6
|
import MarkdownRenderer from './MarkdownRenderer.svelte';
|
|
7
7
|
import TooltipButton from './TooltipButton.svelte';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
import { fly } from 'svelte/transition';
|
|
3
4
|
import { getResources } from '@svadmin/core';
|
|
4
5
|
import { getTheme, getColorTheme } from '@svadmin/core';
|
|
5
6
|
import { getLocale, t } from '@svadmin/core/i18n';
|
|
6
7
|
import { currentPath } from '@svadmin/core/router';
|
|
7
|
-
import { Button } from './ui/button/index.js';
|
|
8
8
|
import TooltipButton from './TooltipButton.svelte';
|
|
9
9
|
import * as Tabs from './ui/tabs/index.js';
|
|
10
10
|
import { Badge } from './ui/badge/index.js';
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
|
|
36
36
|
// Auto-trace state changes in dev mode via Svelte 5 $inspect
|
|
37
37
|
if ((import.meta as any).env?.DEV) {
|
|
38
|
+
// eslint-disable-next-line svelte/no-inspect
|
|
38
39
|
$inspect({ path, theme, colorTheme, locale, resourceCount: resources.length });
|
|
39
40
|
}
|
|
40
41
|
</script>
|
|
@@ -119,7 +120,7 @@
|
|
|
119
120
|
<!-- Resources -->
|
|
120
121
|
<div class="py-1">
|
|
121
122
|
<h4 class="text-[0.6875rem] font-bold uppercase tracking-widest text-muted-foreground mb-1 px-1">Resources ({resources.length})</h4>
|
|
122
|
-
{#each resources as r}
|
|
123
|
+
{#each resources as r, _i (_i)}
|
|
123
124
|
<div class="flex items-center justify-between px-1 py-0.5 rounded hover:bg-muted/50">
|
|
124
125
|
<span class="text-xs text-foreground">{r.name}</span>
|
|
125
126
|
<Badge variant="outline" class="font-mono text-[0.6875rem]">{r.fields.length} fields</Badge>
|