@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.
Files changed (64) hide show
  1. package/dist/component-registry.svelte.js +1 -0
  2. package/dist/components/AICommandBar.svelte +3 -3
  3. package/dist/components/AboutSettings.svelte +2 -2
  4. package/dist/components/AdminApp.svelte +2 -3
  5. package/dist/components/AnomalyBadge.svelte +1 -1
  6. package/dist/components/AppearanceSettings.svelte +5 -6
  7. package/dist/components/AuditLogDrawer.svelte +1 -1
  8. package/dist/components/AuditLogViewer.svelte +1 -1
  9. package/dist/components/AutoForm.svelte +5 -4
  10. package/dist/components/AutoTable.svelte +126 -57
  11. package/dist/components/Breadcrumbs.svelte +1 -0
  12. package/dist/components/ChatDialog.svelte +5 -4
  13. package/dist/components/ComboboxField.svelte +3 -3
  14. package/dist/components/CommandPalette.svelte +3 -3
  15. package/dist/components/CopilotPanel.svelte +2 -2
  16. package/dist/components/CreatePage.svelte +0 -1
  17. package/dist/components/DevTools.svelte +4 -3
  18. package/dist/components/DraggableHeader.svelte +2 -1
  19. package/dist/components/EditPage.svelte +1 -1
  20. package/dist/components/EmptyState.svelte +1 -1
  21. package/dist/components/FieldRenderer.svelte +7 -6
  22. package/dist/components/Header.svelte +1 -0
  23. package/dist/components/InferencerPanel.svelte +4 -3
  24. package/dist/components/InfiniteList.svelte +3 -4
  25. package/dist/components/KeyboardShortcuts.svelte +3 -3
  26. package/dist/components/Layout.svelte +5 -5
  27. package/dist/components/MarkdownRenderer.svelte +3 -5
  28. package/dist/components/ModalForm.svelte +1 -3
  29. package/dist/components/PageSkeleton.svelte +4 -4
  30. package/dist/components/PasswordInput.svelte +1 -2
  31. package/dist/components/PermissionMatrix.svelte +5 -5
  32. package/dist/components/ProfilePage.svelte +1 -1
  33. package/dist/components/RolesSettings.svelte +1 -2
  34. package/dist/components/SettingsPage.svelte +4 -5
  35. package/dist/components/ShowPage.svelte +4 -6
  36. package/dist/components/Sidebar.svelte +12 -11
  37. package/dist/components/SidebarItem.svelte +1 -2
  38. package/dist/components/StepsForm.svelte +1 -1
  39. package/dist/components/TaskList.svelte +1 -1
  40. package/dist/components/TaskQueueDrawer.svelte +2 -1
  41. package/dist/components/TenantSwitcher.svelte +1 -2
  42. package/dist/components/Toast.svelte +1 -0
  43. package/dist/components/TooltipButton.svelte +1 -0
  44. package/dist/components/VirtualTable.svelte +1 -1
  45. package/dist/components/VoiceInput.svelte +1 -0
  46. package/dist/components/buttons/ImportButton.svelte +1 -1
  47. package/dist/components/buttons/ListButton.svelte +1 -1
  48. package/dist/components/charts/BarChart.svelte +1 -1
  49. package/dist/components/charts/LineChart.svelte +3 -3
  50. package/dist/components/charts/PieChart.svelte +2 -2
  51. package/dist/components/fieldComponentMap.js +2 -1
  52. package/dist/components/fields/ArrayField.svelte +1 -1
  53. package/dist/components/fields/MarkdownField.svelte +1 -0
  54. package/dist/components/fields/MultiSelectField.svelte +1 -1
  55. package/dist/components/fields/TagField.svelte +1 -1
  56. package/dist/components/ui/alert/index.js +1 -0
  57. package/dist/components/ui/badge/index.js +1 -0
  58. package/dist/components/ui/button/button.svelte +1 -0
  59. package/dist/components/ui/button/index.js +1 -0
  60. package/dist/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +1 -0
  61. package/dist/components/ui/dropdown-menu/dropdown-menu.svelte +1 -1
  62. package/dist/components/ui/sheet/sheet.svelte +1 -0
  63. package/dist/components/ui/tabs/tabs.svelte +1 -0
  64. package/package.json +13 -13
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1
2
  /**
2
3
  * Component Registry — Svelte Context-based DI for component injection.
3
4
  *
@@ -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, Send } from '@lucide/svelte';
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, getAuthProvider, createHashRouterProvider, configureTheme } from '@svadmin/core';
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, getComponentRegistry, type ComponentRegistry } from '../component-registry.svelte.js';
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, AlertTriangle } from '@lucide/svelte';
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, getResolvedTheme, getColorThemes, getColorTheme, setColorTheme, getColorPresets } from '@svadmin/core';
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)!.push(f);
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
- row_getAllVisibleCells,
28
+ row_getVisibleCells,
28
29
  row_getIsExpanded,
29
30
  row_toggleExpanded,
30
31
  cell_getValue,
31
- } from '@tanstack/svelte-table/static-functions';
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<{ current: number; pageSize: number }>(untrack(() => externalPagination ?? {
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 pagination; },
186
- get sorters() { return sorters; },
187
- get filters() { return activeFilters; },
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
- state: {
301
- get sorting() { return sorting; },
302
- get columnVisibility() { return columnVisibility; },
303
- get rowSelection() { return rowSelection; },
304
- get expanded() { return expanded; },
305
- get columnOrder() { return columnOrder; },
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, index, dragProps)}
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 row_getAllVisibleCells(row) as cell}
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={row_getAllVisibleCells(row).length}>
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,4 +1,5 @@
1
1
  <script lang="ts">
2
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
3
  import { getResources } from '@svadmin/core';
3
4
  import { getPath } from '../router-state.svelte.js';
4
5
  import { formatLink } from '@svadmin/core/router';
@@ -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, AgentEvent } from '@svadmin/core';
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, ShieldCheck, ShieldX, Wrench, LayoutDashboard } from '@lucide/svelte';
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, Bot, Sparkles } from '@lucide/svelte';
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, ChevronRight, Check, RefreshCcw } from '@lucide/svelte';
4
- import { fade, slide } from 'svelte/transition';
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,6 +1,5 @@
1
1
  <script lang="ts">
2
2
  import { getResource } from '@svadmin/core';
3
- import { navigate } from '@svadmin/core/router';
4
3
  import { t } from '@svadmin/core/i18n';
5
4
  import type { Snippet } from 'svelte';
6
5
  import PageHeader from './PageHeader.svelte';
@@ -1,10 +1,10 @@
1
1
  <script lang="ts">
2
- import { fly, scale } from 'svelte/transition';
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>