@svadmin/ui 0.37.0 → 0.38.1
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 +42 -88
- package/dist/components/AdminApp.svelte +38 -35
- package/dist/components/CanAccess.svelte +3 -2
- package/dist/components/CanAccess.svelte.d.ts +1 -0
- package/dist/components/CreateInferencer.svelte +13 -0
- package/dist/components/CreateInferencer.svelte.d.ts +7 -0
- package/dist/components/EditInferencer.svelte +21 -0
- package/dist/components/EditInferencer.svelte.d.ts +9 -0
- package/dist/components/Header.svelte +4 -4
- package/dist/components/Layout.svelte +26 -13
- package/dist/components/ListInferencer.svelte +14 -0
- package/dist/components/ListInferencer.svelte.d.ts +7 -0
- package/dist/components/ResourceInferencer.svelte +28 -0
- package/dist/components/ResourceInferencer.svelte.d.ts +7 -0
- package/dist/components/ResourceOperationsPage.svelte +168 -21
- package/dist/components/ResourceOperationsPage.svelte.d.ts +2 -0
- package/dist/components/SettingsPage.svelte +3 -2
- package/dist/components/ShowInferencer.svelte +21 -0
- package/dist/components/ShowInferencer.svelte.d.ts +9 -0
- package/dist/components/ShowPage.svelte +2 -2
- package/dist/components/ShowPage.svelte.d.ts +1 -0
- package/dist/components/Sidebar.svelte +101 -104
- package/dist/components/Sidebar.svelte.d.ts +0 -1
- package/dist/components/SidebarItem.svelte +114 -52
- package/dist/components/StepsForm.svelte +2 -1
- package/dist/components/UndoableNotification.svelte +2 -1
- package/dist/components/account/TeamMembersPage.svelte +9 -3
- package/dist/components/buttons/CloneButton.svelte +10 -2
- package/dist/components/buttons/CloneButton.svelte.d.ts +2 -4
- package/dist/components/buttons/CreateButton.svelte +9 -2
- package/dist/components/buttons/CreateButton.svelte.d.ts +2 -4
- package/dist/components/buttons/DeleteButton.svelte +10 -2
- package/dist/components/buttons/DeleteButton.svelte.d.ts +2 -4
- package/dist/components/buttons/EditButton.svelte +10 -2
- package/dist/components/buttons/EditButton.svelte.d.ts +2 -4
- package/dist/components/buttons/ExportButton.svelte +9 -2
- package/dist/components/buttons/ExportButton.svelte.d.ts +2 -4
- package/dist/components/buttons/ImportButton.svelte +9 -2
- package/dist/components/buttons/ImportButton.svelte.d.ts +2 -4
- package/dist/components/buttons/ShowButton.svelte +10 -2
- package/dist/components/buttons/ShowButton.svelte.d.ts +2 -4
- package/dist/components/buttons/access-control.d.ts +7 -0
- package/dist/components/buttons/access-control.js +5 -0
- package/dist/components/ui/sheet/sheet.svelte +3 -3
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/router-state.svelte.js +15 -0
- package/package.json +2 -2
|
@@ -25,6 +25,17 @@
|
|
|
25
25
|
badge?: string;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
type WorkspaceStyle =
|
|
29
|
+
| 'inventory'
|
|
30
|
+
| 'operations'
|
|
31
|
+
| 'people'
|
|
32
|
+
| 'calendar'
|
|
33
|
+
| 'communications'
|
|
34
|
+
| 'crm'
|
|
35
|
+
| 'property'
|
|
36
|
+
| 'ai'
|
|
37
|
+
| 'store';
|
|
38
|
+
|
|
28
39
|
interface Props {
|
|
29
40
|
resourceName: string;
|
|
30
41
|
eyebrow: string;
|
|
@@ -39,6 +50,7 @@
|
|
|
39
50
|
tableDescription?: string;
|
|
40
51
|
emptyLanesText?: string;
|
|
41
52
|
highlightsLabel?: string;
|
|
53
|
+
workspaceStyle?: WorkspaceStyle;
|
|
42
54
|
}
|
|
43
55
|
|
|
44
56
|
let {
|
|
@@ -55,11 +67,12 @@
|
|
|
55
67
|
tableDescription,
|
|
56
68
|
emptyLanesText = 'No grouped records yet.',
|
|
57
69
|
highlightsLabel = 'Focus queue',
|
|
70
|
+
workspaceStyle = 'operations',
|
|
58
71
|
}: Props = $props();
|
|
59
72
|
</script>
|
|
60
73
|
|
|
61
|
-
<div class="space-y-6" data-svadmin-resource-operations={resourceName}>
|
|
62
|
-
<section class="
|
|
74
|
+
<div class="space-y-6" data-svadmin-resource-operations={resourceName} data-svadmin-workspace-style={workspaceStyle}>
|
|
75
|
+
<section class="space-y-5 border-b border-border/60 pb-5" data-svadmin-ops-hero>
|
|
63
76
|
<div class="min-w-0 py-1">
|
|
64
77
|
<Badge>{eyebrow}</Badge>
|
|
65
78
|
<div class="flex items-start gap-4">
|
|
@@ -78,7 +91,7 @@
|
|
|
78
91
|
</Button>
|
|
79
92
|
</div>
|
|
80
93
|
|
|
81
|
-
<div class="grid gap-4 md:grid-cols-3">
|
|
94
|
+
<div class="grid min-w-0 gap-4 md:grid-cols-3">
|
|
82
95
|
{#each metrics as metric (metric.label)}
|
|
83
96
|
<Card.Root data-svadmin-metric-card>
|
|
84
97
|
<Card.Content class="p-5">
|
|
@@ -93,8 +106,8 @@
|
|
|
93
106
|
</div>
|
|
94
107
|
</section>
|
|
95
108
|
|
|
96
|
-
<div class="grid gap-4
|
|
97
|
-
<div class="
|
|
109
|
+
<div class="grid min-w-0 gap-4">
|
|
110
|
+
<div class="grid min-w-0 gap-4 {workspaceStyle !== 'ai' && workspaceStyle !== 'communications' ? 'xl:grid-cols-2' : ''}">
|
|
98
111
|
<Card.Root data-svadmin-panel-card>
|
|
99
112
|
<Card.Header>
|
|
100
113
|
<Card.Title>{tableLabel}</Card.Title>
|
|
@@ -120,27 +133,161 @@
|
|
|
120
133
|
</Card.Root>
|
|
121
134
|
|
|
122
135
|
{#if highlights.length > 0}
|
|
123
|
-
<Card.Root data-svadmin-panel-card>
|
|
136
|
+
<Card.Root data-svadmin-panel-card data-svadmin-workbench={workspaceStyle}>
|
|
124
137
|
<Card.Header>
|
|
125
138
|
<Card.Title>{highlightsLabel}</Card.Title>
|
|
126
139
|
</Card.Header>
|
|
127
|
-
<Card.Content
|
|
128
|
-
{#
|
|
129
|
-
<div class="
|
|
130
|
-
<div class="
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
140
|
+
<Card.Content>
|
|
141
|
+
{#if workspaceStyle === 'ai'}
|
|
142
|
+
<div class="grid gap-3 lg:grid-cols-[0.9fr_1.1fr]">
|
|
143
|
+
<div class="space-y-2">
|
|
144
|
+
{#each lanes as lane (lane.label)}
|
|
145
|
+
<div class="rounded-lg border bg-muted/30 px-3 py-2">
|
|
146
|
+
<div class="flex items-center justify-between gap-3">
|
|
147
|
+
<span class="text-sm font-medium">{lane.label}</span>
|
|
148
|
+
<Badge variant="outline">{lane.value}</Badge>
|
|
149
|
+
</div>
|
|
150
|
+
{#if lane.hint}
|
|
151
|
+
<p class="mt-1 text-xs text-muted-foreground">{lane.hint}</p>
|
|
152
|
+
{/if}
|
|
153
|
+
</div>
|
|
154
|
+
{/each}
|
|
155
|
+
</div>
|
|
156
|
+
<div class="space-y-3">
|
|
157
|
+
{#each highlights as item (item.title)}
|
|
158
|
+
<div class="rounded-2xl rounded-tl-sm border bg-card px-4 py-3">
|
|
159
|
+
<div class="flex items-center justify-between gap-3">
|
|
160
|
+
<p class="font-medium">{item.title}</p>
|
|
161
|
+
{#if item.badge}
|
|
162
|
+
<Badge>{item.badge}</Badge>
|
|
163
|
+
{/if}
|
|
164
|
+
</div>
|
|
165
|
+
{#if item.description}
|
|
166
|
+
<p class="mt-2 text-sm text-muted-foreground">{item.description}</p>
|
|
167
|
+
{/if}
|
|
168
|
+
{#if item.meta}
|
|
169
|
+
<p class="mt-2 text-xs font-medium text-primary">{item.meta}</p>
|
|
170
|
+
{/if}
|
|
171
|
+
</div>
|
|
172
|
+
{/each}
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
{:else if workspaceStyle === 'communications'}
|
|
176
|
+
<div class="grid gap-4 lg:grid-cols-[0.82fr_1.18fr]">
|
|
177
|
+
<div class="space-y-2">
|
|
178
|
+
{#each lanes as lane (lane.label)}
|
|
179
|
+
<div class="flex items-center justify-between rounded-lg border bg-muted/25 px-3 py-2">
|
|
180
|
+
<div>
|
|
181
|
+
<p class="text-sm font-medium">{lane.label}</p>
|
|
182
|
+
{#if lane.hint}
|
|
183
|
+
<p class="text-xs text-muted-foreground">{lane.hint}</p>
|
|
184
|
+
{/if}
|
|
185
|
+
</div>
|
|
186
|
+
<Badge variant="outline">{lane.value}</Badge>
|
|
187
|
+
</div>
|
|
188
|
+
{/each}
|
|
189
|
+
</div>
|
|
190
|
+
<div class="divide-y rounded-lg border">
|
|
191
|
+
{#each highlights as item (item.title)}
|
|
192
|
+
<div class="px-4 py-3">
|
|
193
|
+
<div class="flex items-center justify-between gap-3">
|
|
194
|
+
<p class="font-medium">{item.title}</p>
|
|
195
|
+
{#if item.badge}
|
|
196
|
+
<Badge>{item.badge}</Badge>
|
|
197
|
+
{/if}
|
|
198
|
+
</div>
|
|
199
|
+
{#if item.description}
|
|
200
|
+
<p class="mt-1 text-xs text-muted-foreground">{item.description}</p>
|
|
201
|
+
{/if}
|
|
202
|
+
{#if item.meta}
|
|
203
|
+
<p class="mt-2 text-xs font-medium text-primary">{item.meta}</p>
|
|
204
|
+
{/if}
|
|
205
|
+
</div>
|
|
206
|
+
{/each}
|
|
135
207
|
</div>
|
|
136
|
-
{#if item.description}
|
|
137
|
-
<p class="mt-1 text-xs text-muted-foreground">{item.description}</p>
|
|
138
|
-
{/if}
|
|
139
|
-
{#if item.meta}
|
|
140
|
-
<p class="mt-2 text-xs font-medium text-primary">{item.meta}</p>
|
|
141
|
-
{/if}
|
|
142
208
|
</div>
|
|
143
|
-
{
|
|
209
|
+
{:else if workspaceStyle === 'crm'}
|
|
210
|
+
<div class="grid gap-3 md:grid-cols-3">
|
|
211
|
+
{#each lanes as lane (lane.label)}
|
|
212
|
+
<div class="rounded-lg border bg-muted/25 p-3">
|
|
213
|
+
<div class="flex items-center justify-between gap-3">
|
|
214
|
+
<p class="text-sm font-semibold">{lane.label}</p>
|
|
215
|
+
<Badge variant="outline">{lane.value}</Badge>
|
|
216
|
+
</div>
|
|
217
|
+
{#if lane.hint}
|
|
218
|
+
<p class="mt-2 text-xs text-muted-foreground">{lane.hint}</p>
|
|
219
|
+
{/if}
|
|
220
|
+
</div>
|
|
221
|
+
{/each}
|
|
222
|
+
</div>
|
|
223
|
+
<div class="mt-4 grid gap-3">
|
|
224
|
+
{#each highlights as item (item.title)}
|
|
225
|
+
<div class="rounded-lg border-l-4 border-l-primary bg-muted/20 px-4 py-3">
|
|
226
|
+
<div class="flex items-center justify-between gap-3">
|
|
227
|
+
<p class="font-medium">{item.title}</p>
|
|
228
|
+
{#if item.badge}
|
|
229
|
+
<Badge>{item.badge}</Badge>
|
|
230
|
+
{/if}
|
|
231
|
+
</div>
|
|
232
|
+
{#if item.description}
|
|
233
|
+
<p class="mt-1 text-xs text-muted-foreground">{item.description}</p>
|
|
234
|
+
{/if}
|
|
235
|
+
{#if item.meta}
|
|
236
|
+
<p class="mt-2 text-xs font-medium text-primary">{item.meta}</p>
|
|
237
|
+
{/if}
|
|
238
|
+
</div>
|
|
239
|
+
{/each}
|
|
240
|
+
</div>
|
|
241
|
+
{:else if workspaceStyle === 'property' || workspaceStyle === 'store'}
|
|
242
|
+
<div class="grid gap-3 md:grid-cols-2">
|
|
243
|
+
{#each highlights as item (item.title)}
|
|
244
|
+
<div class="rounded-xl border bg-gradient-to-br from-muted/45 to-background p-4">
|
|
245
|
+
<div class="flex items-center justify-between gap-3">
|
|
246
|
+
<p class="font-medium">{item.title}</p>
|
|
247
|
+
{#if item.badge}
|
|
248
|
+
<Badge>{item.badge}</Badge>
|
|
249
|
+
{/if}
|
|
250
|
+
</div>
|
|
251
|
+
{#if item.description}
|
|
252
|
+
<p class="mt-2 text-sm text-muted-foreground">{item.description}</p>
|
|
253
|
+
{/if}
|
|
254
|
+
{#if item.meta}
|
|
255
|
+
<p class="mt-3 text-xs font-semibold text-primary">{item.meta}</p>
|
|
256
|
+
{/if}
|
|
257
|
+
</div>
|
|
258
|
+
{/each}
|
|
259
|
+
{#each lanes as lane (lane.label)}
|
|
260
|
+
<div class="rounded-xl border bg-card p-4">
|
|
261
|
+
<div class="flex items-center justify-between gap-3">
|
|
262
|
+
<p class="font-medium">{lane.label}</p>
|
|
263
|
+
<Badge variant="outline">{lane.value}</Badge>
|
|
264
|
+
</div>
|
|
265
|
+
{#if lane.hint}
|
|
266
|
+
<p class="mt-2 text-xs text-muted-foreground">{lane.hint}</p>
|
|
267
|
+
{/if}
|
|
268
|
+
</div>
|
|
269
|
+
{/each}
|
|
270
|
+
</div>
|
|
271
|
+
{:else}
|
|
272
|
+
<div class="space-y-3">
|
|
273
|
+
{#each highlights as item (item.title)}
|
|
274
|
+
<div class="py-3">
|
|
275
|
+
<div class="flex items-center justify-between gap-3">
|
|
276
|
+
<p class="font-medium">{item.title}</p>
|
|
277
|
+
{#if item.badge}
|
|
278
|
+
<Badge>{item.badge}</Badge>
|
|
279
|
+
{/if}
|
|
280
|
+
</div>
|
|
281
|
+
{#if item.description}
|
|
282
|
+
<p class="mt-1 text-xs text-muted-foreground">{item.description}</p>
|
|
283
|
+
{/if}
|
|
284
|
+
{#if item.meta}
|
|
285
|
+
<p class="mt-2 text-xs font-medium text-primary">{item.meta}</p>
|
|
286
|
+
{/if}
|
|
287
|
+
</div>
|
|
288
|
+
{/each}
|
|
289
|
+
</div>
|
|
290
|
+
{/if}
|
|
144
291
|
</Card.Content>
|
|
145
292
|
</Card.Root>
|
|
146
293
|
{/if}
|
|
@@ -15,6 +15,7 @@ interface HighlightItem {
|
|
|
15
15
|
meta?: string;
|
|
16
16
|
badge?: string;
|
|
17
17
|
}
|
|
18
|
+
type WorkspaceStyle = 'inventory' | 'operations' | 'people' | 'calendar' | 'communications' | 'crm' | 'property' | 'ai' | 'store';
|
|
18
19
|
interface Props {
|
|
19
20
|
resourceName: string;
|
|
20
21
|
eyebrow: string;
|
|
@@ -31,6 +32,7 @@ interface Props {
|
|
|
31
32
|
tableDescription?: string;
|
|
32
33
|
emptyLanesText?: string;
|
|
33
34
|
highlightsLabel?: string;
|
|
35
|
+
workspaceStyle?: WorkspaceStyle;
|
|
34
36
|
}
|
|
35
37
|
declare const ResourceOperationsPage: Component<Props, {}, "">;
|
|
36
38
|
type ResourceOperationsPage = ReturnType<typeof ResourceOperationsPage>;
|
|
@@ -95,8 +95,9 @@
|
|
|
95
95
|
let activeKey = $derived.by(() => {
|
|
96
96
|
const tab = getParams().tab;
|
|
97
97
|
if (!tab) return "profile";
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
const alias = tab === "api-keys" ? "api" : tab;
|
|
99
|
+
if (sectionKeys.has(alias)) return alias;
|
|
100
|
+
return content ? alias : "profile";
|
|
100
101
|
});
|
|
101
102
|
|
|
102
103
|
// Default redirect to profile
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// ShowInferencer — 基于资源定义零配置渲染详情页
|
|
3
|
+
// 从 URL 自动提取 :id 参数
|
|
4
|
+
import ShowPage from './ShowPage.svelte';
|
|
5
|
+
import { useParsed } from '@svadmin/core';
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
resourceName: string;
|
|
9
|
+
/** 可选:显式指定 id,默认从 URL 解析 */
|
|
10
|
+
id?: string | number;
|
|
11
|
+
class?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let { resourceName, id, class: className = '' }: Props = $props();
|
|
15
|
+
const parsed = useParsed();
|
|
16
|
+
const resolvedId = $derived(id ?? parsed.id ?? '');
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
{#if resolvedId}
|
|
20
|
+
<ShowPage {resourceName} id={resolvedId} class={className} />
|
|
21
|
+
{/if}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
resourceName: string;
|
|
3
|
+
/** 可选:显式指定 id,默认从 URL 解析 */
|
|
4
|
+
id?: string | number;
|
|
5
|
+
class?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const ShowInferencer: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type ShowInferencer = ReturnType<typeof ShowInferencer>;
|
|
9
|
+
export default ShowInferencer;
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import CloneButton from './buttons/CloneButton.svelte';
|
|
13
13
|
import RefreshButton from './buttons/RefreshButton.svelte';
|
|
14
14
|
|
|
15
|
-
let { resourceName, id } = $props<{ resourceName: string; id: string | number }>();
|
|
15
|
+
let { resourceName, id, class: className = '' } = $props<{ resourceName: string; id: string | number; class?: string }>();
|
|
16
16
|
|
|
17
17
|
const resource = $derived(getResource(resourceName));
|
|
18
18
|
const showFields = $derived(resource.fields.filter(f => f.showInShow !== false));
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
const query = useShow({ get resource() { return resourceName; }, get id() { return id; } });
|
|
21
21
|
</script>
|
|
22
22
|
|
|
23
|
-
<div class="space-y-6">
|
|
23
|
+
<div class="space-y-6 {className}">
|
|
24
24
|
<PageHeader title="{resource.label} {t('common.detail')}">
|
|
25
25
|
{#snippet actions()}
|
|
26
26
|
<ListButton resource={resourceName} hideText />
|