@allbluecn/admin-app 0.2.0 → 0.2.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/package.json +8 -8
- package/src/components/admin/admin-user-menu.tsx +12 -6
- package/src/components/admin/developer-log.tsx +42 -44
- package/src/components/ai-provider/model-list-editor.tsx +5 -4
- package/src/components/ai-provider/provider-form.tsx +63 -64
- package/src/components/ai-provider/provider-table.tsx +35 -36
- package/src/components/auth/admin-login-form.tsx +23 -24
- package/src/components/auth/oauth-section.tsx +3 -5
- package/src/components/auth/password-input.tsx +2 -3
- package/src/components/common/placeholder-page.tsx +2 -4
- package/src/components/component/component-form-dialog.tsx +48 -49
- package/src/components/component/component-import-dialog.tsx +5 -5
- package/src/components/component/component-table.tsx +13 -14
- package/src/components/data-table/data-table-pagination.tsx +4 -6
- package/src/components/data-table/table-detail-layout.tsx +2 -3
- package/src/components/dependency/changelog-dialog.tsx +3 -4
- package/src/components/dependency/columns.tsx +32 -24
- package/src/components/dependency/dependency-table.tsx +37 -29
- package/src/components/dependency/edit-dialog.tsx +24 -25
- package/src/components/knowledge-public/bookmark-form-dialog.tsx +7 -7
- package/src/components/knowledge-public/compliance-form-dialog.tsx +13 -13
- package/src/components/knowledge-public/legal-form-dialog.tsx +51 -46
- package/src/components/layout/sidebar-02/app-sidebar.tsx +33 -34
- package/src/components/layout/sidebar-02/nav-main.tsx +1 -1
- package/src/components/market/columns.tsx +20 -21
- package/src/components/market/market-app-form.tsx +45 -38
- package/src/components/market/market-app-list.tsx +16 -17
- package/src/components/monitoring/error-list.tsx +18 -19
- package/src/components/monitoring/health-cards.tsx +11 -13
- package/src/components/monitoring/metrics-stats.tsx +11 -12
- package/src/components/monitoring/request-log-table.tsx +8 -9
- package/src/components/ui/pagination.tsx +0 -2
- package/src/components/ui/sidebar.tsx +1 -1
- package/src/components/user/columns.tsx +9 -9
- package/src/components/user/settings-activity-log.tsx +39 -29
- package/src/components/user/settings-profile.tsx +36 -36
- package/src/components/user/user-create-dialog.tsx +4 -4
- package/src/components/user/user-filters.tsx +16 -18
- package/src/lib/i18n/config.ts +0 -32
- package/src/providers/index.tsx +6 -16
- package/src/routeTree.gen.ts +1199 -0
- package/src/routes/__root.tsx +9 -23
- package/src/routes/_nav/apps/route.lazy.tsx +2 -3
- package/src/routes/_nav/audit/route.lazy.tsx +10 -11
- package/src/routes/_nav/billing/invoices/route.lazy.tsx +6 -7
- package/src/routes/_nav/billing/route.lazy.tsx +3 -4
- package/src/routes/_nav/billing/subscriptions/$subscriptionId/route.lazy.tsx +16 -17
- package/src/routes/_nav/billing/subscriptions/route.lazy.tsx +9 -10
- package/src/routes/_nav/compliance/route.lazy.tsx +34 -35
- package/src/routes/_nav/components/route.lazy.tsx +6 -6
- package/src/routes/_nav/dashboard/route.lazy.tsx +3 -5
- package/src/routes/_nav/dependencies/route.lazy.tsx +7 -8
- package/src/routes/_nav/docs/route.lazy.tsx +2 -3
- package/src/routes/_nav/knowledge-public/bookmarks/route.lazy.tsx +40 -41
- package/src/routes/_nav/knowledge-public/compliance/route.lazy.tsx +32 -33
- package/src/routes/_nav/knowledge-public/legal/route.lazy.tsx +32 -33
- package/src/routes/_nav/licenses/$licenseId/route.lazy.tsx +24 -31
- package/src/routes/_nav/licenses/new/route.lazy.tsx +25 -26
- package/src/routes/_nav/licenses/route.lazy.tsx +17 -18
- package/src/routes/_nav/monitoring/ai-usage/route.lazy.tsx +26 -27
- package/src/routes/_nav/monitoring/errors/route.lazy.tsx +11 -12
- package/src/routes/_nav/monitoring/health/route.lazy.tsx +18 -20
- package/src/routes/_nav/monitoring/logs/route.lazy.tsx +12 -13
- package/src/routes/_nav/monitoring/metrics/route.lazy.tsx +13 -15
- package/src/routes/_nav/monitoring/overview/route.lazy.tsx +12 -13
- package/src/routes/_nav/monitoring/route.lazy.tsx +8 -9
- package/src/routes/_nav/monitoring/sentry/route.lazy.tsx +55 -57
- package/src/routes/_nav/permissions/route.lazy.tsx +48 -50
- package/src/routes/_nav/settings/route.lazy.tsx +2 -3
- package/src/routes/_nav/sso/route.lazy.tsx +20 -18
- package/src/routes/_nav/users/$userId/route.lazy.tsx +86 -82
- package/src/routes/_nav/users/route.lazy.tsx +4 -5
- package/src/routes/setup/route.lazy.tsx +15 -16
- package/src/start.ts +2 -2
- package/src/lib/i18n/client.ts +0 -32
- package/src/lib/i18n/locales/en/admin-ai.json +0 -128
- package/src/lib/i18n/locales/en/admin-billing.json +0 -56
- package/src/lib/i18n/locales/en/admin-users.json +0 -88
- package/src/lib/i18n/locales/en/common.json +0 -877
- package/src/lib/i18n/locales/en/enterprise.json +0 -208
- package/src/lib/i18n/locales/zh/admin-ai.json +0 -128
- package/src/lib/i18n/locales/zh/admin-billing.json +0 -56
- package/src/lib/i18n/locales/zh/admin-users.json +0 -88
- package/src/lib/i18n/locales/zh/common.json +0 -877
- package/src/lib/i18n/locales/zh/enterprise.json +0 -208
- package/src/lib/i18n/server.ts +0 -18
- package/src/lib/i18n/types.ts +0 -5
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
// apps/admin/src/components/ai-provider/provider-form.tsx
|
|
19
19
|
import { useState } from "react"
|
|
20
|
-
import {
|
|
20
|
+
import { m } from '@/paraglide/messages.js'
|
|
21
21
|
import { useMutation } from "@tanstack/react-query"
|
|
22
22
|
import { Link, useNavigate, useRouter } from "@tanstack/react-router"
|
|
23
23
|
import { ArrowLeft, Loader2, Save } from "lucide-react"
|
|
@@ -104,7 +104,6 @@ export function ProviderForm({
|
|
|
104
104
|
initial?: Partial<ProviderFormValues>
|
|
105
105
|
providerDbId?: string
|
|
106
106
|
}) {
|
|
107
|
-
const { t } = useTranslation('admin-ai')
|
|
108
107
|
const navigate = useNavigate()
|
|
109
108
|
const router = useRouter()
|
|
110
109
|
const [values, setValues] = useState<ProviderFormValues>({
|
|
@@ -126,17 +125,17 @@ export function ProviderForm({
|
|
|
126
125
|
})
|
|
127
126
|
},
|
|
128
127
|
onSuccess: async () => {
|
|
129
|
-
toast.success(mode === "create" ?
|
|
128
|
+
toast.success(mode === "create" ? m['admin-ai_form_toast_created']() : m['admin-ai_form_toast_updated']())
|
|
130
129
|
await router.invalidate()
|
|
131
130
|
navigate({ to: "/ai-providers" })
|
|
132
131
|
},
|
|
133
132
|
onError: (err) =>
|
|
134
|
-
toast.error(
|
|
133
|
+
toast.error(m['admin-ai_form_toast_saveFailed']({ error: err instanceof Error ? err.message : m.common_status_error() })),
|
|
135
134
|
})
|
|
136
135
|
|
|
137
136
|
function handleSubmit() {
|
|
138
|
-
if (!values.providerId.trim()) return toast.error(
|
|
139
|
-
if (!values.displayName.trim()) return toast.error(
|
|
137
|
+
if (!values.providerId.trim()) return toast.error(m['admin-ai_form_validation_providerIdRequired']())
|
|
138
|
+
if (!values.displayName.trim()) return toast.error(m['admin-ai_form_validation_displayNameRequired']())
|
|
140
139
|
saveMutation.mutate()
|
|
141
140
|
}
|
|
142
141
|
|
|
@@ -149,25 +148,25 @@ export function ProviderForm({
|
|
|
149
148
|
</Link>
|
|
150
149
|
</Button>
|
|
151
150
|
<h2 className="text-lg font-semibold">
|
|
152
|
-
{mode === "create" ?
|
|
151
|
+
{mode === "create" ? m['admin-ai_form_addProvider']() : m['admin-ai_form_editProvider']()}
|
|
153
152
|
</h2>
|
|
154
153
|
</div>
|
|
155
154
|
|
|
156
155
|
<FieldSet>
|
|
157
|
-
<FieldLegend>{
|
|
156
|
+
<FieldLegend>{m['admin-ai_form_basicInfo']()}</FieldLegend>
|
|
158
157
|
<FieldGroup>
|
|
159
158
|
<Field orientation="horizontal">
|
|
160
159
|
<FieldContent>
|
|
161
|
-
<FieldLabel>{
|
|
160
|
+
<FieldLabel>{m['admin-ai_form_providerId']()}</FieldLabel>
|
|
162
161
|
<FieldDescription>
|
|
163
|
-
{
|
|
164
|
-
{mode === "edit" && " " +
|
|
162
|
+
{m['admin-ai_form_providerIdDesc']()}
|
|
163
|
+
{mode === "edit" && " " + m['admin-ai_form_providerIdEditNote']()}
|
|
165
164
|
</FieldDescription>
|
|
166
165
|
</FieldContent>
|
|
167
166
|
<Input
|
|
168
167
|
value={values.providerId}
|
|
169
|
-
onChange={(e) => patch({ providerId: e.target.value })}
|
|
170
|
-
placeholder={
|
|
168
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => patch({ providerId: e.target.value })}
|
|
169
|
+
placeholder={m['admin-ai_form_providerIdPlaceholder']()}
|
|
171
170
|
disabled={mode === "edit"}
|
|
172
171
|
className="w-60 font-mono"
|
|
173
172
|
/>
|
|
@@ -175,8 +174,8 @@ export function ProviderForm({
|
|
|
175
174
|
|
|
176
175
|
<Field orientation="horizontal">
|
|
177
176
|
<FieldContent>
|
|
178
|
-
<FieldLabel>{
|
|
179
|
-
<FieldDescription>{
|
|
177
|
+
<FieldLabel>{m['admin-ai_form_preview']()}</FieldLabel>
|
|
178
|
+
<FieldDescription>{m['admin-ai_form_previewDesc']()}</FieldDescription>
|
|
180
179
|
</FieldContent>
|
|
181
180
|
<ProviderIcon
|
|
182
181
|
provider={{
|
|
@@ -189,36 +188,36 @@ export function ProviderForm({
|
|
|
189
188
|
|
|
190
189
|
<Field orientation="horizontal">
|
|
191
190
|
<FieldContent>
|
|
192
|
-
<FieldLabel>{
|
|
193
|
-
<FieldDescription>{
|
|
191
|
+
<FieldLabel>{m['admin-ai_form_displayName']()}</FieldLabel>
|
|
192
|
+
<FieldDescription>{m['admin-ai_form_displayNameDesc']()}</FieldDescription>
|
|
194
193
|
</FieldContent>
|
|
195
194
|
<Input
|
|
196
195
|
value={values.displayName}
|
|
197
|
-
onChange={(e) => patch({ displayName: e.target.value })}
|
|
196
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => patch({ displayName: e.target.value })}
|
|
198
197
|
className="w-60"
|
|
199
198
|
/>
|
|
200
199
|
</Field>
|
|
201
200
|
|
|
202
201
|
<Field orientation="horizontal">
|
|
203
202
|
<FieldContent>
|
|
204
|
-
<FieldLabel>{
|
|
205
|
-
<FieldDescription>{
|
|
203
|
+
<FieldLabel>{m['admin-ai_form_brandName']()}</FieldLabel>
|
|
204
|
+
<FieldDescription>{m['admin-ai_form_brandNameDesc']()}</FieldDescription>
|
|
206
205
|
</FieldContent>
|
|
207
206
|
<Input
|
|
208
207
|
value={values.brandName}
|
|
209
|
-
onChange={(e) => patch({ brandName: e.target.value })}
|
|
208
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => patch({ brandName: e.target.value })}
|
|
210
209
|
className="w-60"
|
|
211
210
|
/>
|
|
212
211
|
</Field>
|
|
213
212
|
|
|
214
213
|
<Field>
|
|
215
214
|
<FieldContent>
|
|
216
|
-
<FieldLabel>{
|
|
217
|
-
<FieldDescription>{
|
|
215
|
+
<FieldLabel>{m['admin-ai_form_description']()}</FieldLabel>
|
|
216
|
+
<FieldDescription>{m['admin-ai_form_descriptionDesc']()}</FieldDescription>
|
|
218
217
|
</FieldContent>
|
|
219
218
|
<Textarea
|
|
220
219
|
value={values.description}
|
|
221
|
-
onChange={(e) => patch({ description: e.target.value })}
|
|
220
|
+
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => patch({ description: e.target.value })}
|
|
222
221
|
rows={2}
|
|
223
222
|
/>
|
|
224
223
|
</Field>
|
|
@@ -227,11 +226,11 @@ export function ProviderForm({
|
|
|
227
226
|
|
|
228
227
|
<Field orientation="horizontal">
|
|
229
228
|
<FieldContent>
|
|
230
|
-
<FieldLabel>{
|
|
229
|
+
<FieldLabel>{m['admin-ai_form_category']()}</FieldLabel>
|
|
231
230
|
</FieldContent>
|
|
232
231
|
<Select
|
|
233
232
|
value={values.category}
|
|
234
|
-
onValueChange={(v) => patch({ category: v as ProviderCategory })}
|
|
233
|
+
onValueChange={(v: string) => patch({ category: v as ProviderCategory })}
|
|
235
234
|
>
|
|
236
235
|
<SelectTrigger className="w-40">
|
|
237
236
|
<SelectValue />
|
|
@@ -248,12 +247,12 @@ export function ProviderForm({
|
|
|
248
247
|
|
|
249
248
|
<Field orientation="horizontal">
|
|
250
249
|
<FieldContent>
|
|
251
|
-
<FieldLabel>{
|
|
252
|
-
<FieldDescription>{
|
|
250
|
+
<FieldLabel>{m['admin-ai_form_adapterKind']()}</FieldLabel>
|
|
251
|
+
<FieldDescription>{m['admin-ai_form_adapterKindDesc']()}</FieldDescription>
|
|
253
252
|
</FieldContent>
|
|
254
253
|
<Select
|
|
255
254
|
value={values.adapterKind}
|
|
256
|
-
onValueChange={(v) => patch({ adapterKind: v as AdapterKind })}
|
|
255
|
+
onValueChange={(v: string) => patch({ adapterKind: v as AdapterKind })}
|
|
257
256
|
>
|
|
258
257
|
<SelectTrigger className="w-60">
|
|
259
258
|
<SelectValue />
|
|
@@ -270,32 +269,32 @@ export function ProviderForm({
|
|
|
270
269
|
|
|
271
270
|
<Field orientation="horizontal">
|
|
272
271
|
<FieldContent>
|
|
273
|
-
<FieldLabel>{
|
|
274
|
-
<FieldDescription>{
|
|
272
|
+
<FieldLabel>{m['admin-ai_form_badge']()}</FieldLabel>
|
|
273
|
+
<FieldDescription>{m['admin-ai_form_badgeDesc']()}</FieldDescription>
|
|
275
274
|
</FieldContent>
|
|
276
275
|
<Input
|
|
277
276
|
value={values.badge}
|
|
278
|
-
onChange={(e) => patch({ badge: e.target.value })}
|
|
277
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => patch({ badge: e.target.value })}
|
|
279
278
|
className="w-40"
|
|
280
|
-
placeholder={
|
|
279
|
+
placeholder={m['admin-ai_form_badgePlaceholder']()}
|
|
281
280
|
/>
|
|
282
281
|
</Field>
|
|
283
282
|
|
|
284
283
|
<Field orientation="horizontal">
|
|
285
284
|
<FieldContent>
|
|
286
|
-
<FieldLabel>{
|
|
287
|
-
<FieldDescription>{
|
|
285
|
+
<FieldLabel>{m['admin-ai_form_brandColor']()}</FieldLabel>
|
|
286
|
+
<FieldDescription>{m['admin-ai_form_brandColorDesc']()}</FieldDescription>
|
|
288
287
|
</FieldContent>
|
|
289
288
|
<div className="flex items-center gap-2">
|
|
290
289
|
<input
|
|
291
290
|
type="color"
|
|
292
291
|
value={values.brandColor}
|
|
293
|
-
onChange={(e) => patch({ brandColor: e.target.value })}
|
|
292
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => patch({ brandColor: e.target.value })}
|
|
294
293
|
className="size-9 rounded border"
|
|
295
294
|
/>
|
|
296
295
|
<Input
|
|
297
296
|
value={values.brandColor}
|
|
298
|
-
onChange={(e) => patch({ brandColor: e.target.value })}
|
|
297
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => patch({ brandColor: e.target.value })}
|
|
299
298
|
className="w-28 font-mono"
|
|
300
299
|
/>
|
|
301
300
|
</div>
|
|
@@ -303,30 +302,30 @@ export function ProviderForm({
|
|
|
303
302
|
|
|
304
303
|
<Field orientation="horizontal">
|
|
305
304
|
<FieldContent>
|
|
306
|
-
<FieldLabel>{
|
|
307
|
-
<FieldDescription>{
|
|
305
|
+
<FieldLabel>{m['admin-ai_form_iconSlug']()}</FieldLabel>
|
|
306
|
+
<FieldDescription>{m['admin-ai_form_iconSlugDesc']()}</FieldDescription>
|
|
308
307
|
</FieldContent>
|
|
309
308
|
<Input
|
|
310
309
|
value={values.iconSlug}
|
|
311
|
-
onChange={(e) => patch({ iconSlug: e.target.value })}
|
|
310
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => patch({ iconSlug: e.target.value })}
|
|
312
311
|
className="w-60"
|
|
313
|
-
placeholder={
|
|
312
|
+
placeholder={m['admin-ai_form_iconSlugPlaceholder']()}
|
|
314
313
|
/>
|
|
315
314
|
</Field>
|
|
316
315
|
</FieldGroup>
|
|
317
316
|
</FieldSet>
|
|
318
317
|
|
|
319
318
|
<FieldSet>
|
|
320
|
-
<FieldLegend>{
|
|
319
|
+
<FieldLegend>{m['admin-ai_form_integrationConfig']()}</FieldLegend>
|
|
321
320
|
<FieldGroup>
|
|
322
321
|
<Field orientation="horizontal">
|
|
323
322
|
<FieldContent>
|
|
324
|
-
<FieldLabel>{
|
|
325
|
-
<FieldDescription>{
|
|
323
|
+
<FieldLabel>{m['admin-ai_form_defaultBaseUrl']()}</FieldLabel>
|
|
324
|
+
<FieldDescription>{m['admin-ai_form_defaultBaseUrlDesc']()}</FieldDescription>
|
|
326
325
|
</FieldContent>
|
|
327
326
|
<Input
|
|
328
327
|
value={values.defaultBaseUrl}
|
|
329
|
-
onChange={(e) => patch({ defaultBaseUrl: e.target.value })}
|
|
328
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => patch({ defaultBaseUrl: e.target.value })}
|
|
330
329
|
className="w-72"
|
|
331
330
|
placeholder="https://api.example.com/v1"
|
|
332
331
|
/>
|
|
@@ -334,11 +333,11 @@ export function ProviderForm({
|
|
|
334
333
|
|
|
335
334
|
<Field orientation="horizontal">
|
|
336
335
|
<FieldContent>
|
|
337
|
-
<FieldLabel>{
|
|
336
|
+
<FieldLabel>{m['admin-ai_form_keyUrl']()}</FieldLabel>
|
|
338
337
|
</FieldContent>
|
|
339
338
|
<Input
|
|
340
339
|
value={values.keyUrl}
|
|
341
|
-
|
|
340
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => patch({ keyUrl: e.target.value })}
|
|
342
341
|
className="w-72"
|
|
343
342
|
placeholder="https://..."
|
|
344
343
|
/>
|
|
@@ -346,11 +345,11 @@ export function ProviderForm({
|
|
|
346
345
|
|
|
347
346
|
<Field orientation="horizontal">
|
|
348
347
|
<FieldContent>
|
|
349
|
-
<FieldLabel>{
|
|
348
|
+
<FieldLabel>{m['admin-ai_form_docsUrl']()}</FieldLabel>
|
|
350
349
|
</FieldContent>
|
|
351
350
|
<Input
|
|
352
351
|
value={values.docsUrl}
|
|
353
|
-
onChange={(e) => patch({ docsUrl: e.target.value })}
|
|
352
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => patch({ docsUrl: e.target.value })}
|
|
354
353
|
className="w-72"
|
|
355
354
|
placeholder="https://..."
|
|
356
355
|
/>
|
|
@@ -358,11 +357,11 @@ export function ProviderForm({
|
|
|
358
357
|
|
|
359
358
|
<Field orientation="horizontal">
|
|
360
359
|
<FieldContent>
|
|
361
|
-
<FieldLabel>{
|
|
360
|
+
<FieldLabel>{m['admin-ai_form_apikeyPlaceholder']()}</FieldLabel>
|
|
362
361
|
</FieldContent>
|
|
363
362
|
<Input
|
|
364
363
|
value={values.keyPlaceholder}
|
|
365
|
-
onChange={(e) => patch({ keyPlaceholder: e.target.value })}
|
|
364
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => patch({ keyPlaceholder: e.target.value })}
|
|
366
365
|
className="w-60"
|
|
367
366
|
placeholder="sk-..."
|
|
368
367
|
/>
|
|
@@ -372,35 +371,35 @@ export function ProviderForm({
|
|
|
372
371
|
|
|
373
372
|
<Field orientation="horizontal">
|
|
374
373
|
<FieldContent>
|
|
375
|
-
<FieldLabel>{
|
|
376
|
-
<FieldDescription>{
|
|
374
|
+
<FieldLabel>{m['admin-ai_form_localDeploy']()}</FieldLabel>
|
|
375
|
+
<FieldDescription>{m['admin-ai_form_localDeployDesc']()}</FieldDescription>
|
|
377
376
|
</FieldContent>
|
|
378
377
|
<Switch
|
|
379
378
|
checked={values.isLocal}
|
|
380
|
-
onCheckedChange={(v) => patch({ isLocal: v })}
|
|
379
|
+
onCheckedChange={(v: boolean) => patch({ isLocal: v })}
|
|
381
380
|
/>
|
|
382
381
|
</Field>
|
|
383
382
|
|
|
384
383
|
<Field orientation="horizontal">
|
|
385
384
|
<FieldContent>
|
|
386
|
-
<FieldLabel>{
|
|
387
|
-
<FieldDescription>{
|
|
385
|
+
<FieldLabel>{m['admin-ai_form_platformEnabled']()}</FieldLabel>
|
|
386
|
+
<FieldDescription>{m['admin-ai_form_platformEnabledDesc']()}</FieldDescription>
|
|
388
387
|
</FieldContent>
|
|
389
388
|
<Switch
|
|
390
389
|
checked={values.enabled}
|
|
391
|
-
onCheckedChange={(v) => patch({ enabled: v })}
|
|
390
|
+
onCheckedChange={(v: boolean) => patch({ enabled: v })}
|
|
392
391
|
/>
|
|
393
392
|
</Field>
|
|
394
393
|
|
|
395
394
|
<Field orientation="horizontal">
|
|
396
395
|
<FieldContent>
|
|
397
|
-
<FieldLabel>{
|
|
398
|
-
<FieldDescription>{
|
|
396
|
+
<FieldLabel>{m['admin-ai_form_sortOrder']()}</FieldLabel>
|
|
397
|
+
<FieldDescription>{m['admin-ai_form_sortOrderDesc']()}</FieldDescription>
|
|
399
398
|
</FieldContent>
|
|
400
399
|
<Input
|
|
401
400
|
type="number"
|
|
402
401
|
value={values.sortOrder}
|
|
403
|
-
onChange={(e) => patch({ sortOrder: Number(e.target.value) })}
|
|
402
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) => patch({ sortOrder: Number(e.target.value) })}
|
|
404
403
|
className="w-24"
|
|
405
404
|
/>
|
|
406
405
|
</Field>
|
|
@@ -408,8 +407,8 @@ export function ProviderForm({
|
|
|
408
407
|
</FieldSet>
|
|
409
408
|
|
|
410
409
|
<FieldSet>
|
|
411
|
-
<FieldLegend>{
|
|
412
|
-
<FieldDescription>{
|
|
410
|
+
<FieldLegend>{m['admin-ai_form_modelList']()}</FieldLegend>
|
|
411
|
+
<FieldDescription>{m['admin-ai_form_modelListDesc']()}</FieldDescription>
|
|
413
412
|
<ModelListEditor
|
|
414
413
|
models={values.models}
|
|
415
414
|
onChange={(m) => patch({ models: m })}
|
|
@@ -418,7 +417,7 @@ export function ProviderForm({
|
|
|
418
417
|
|
|
419
418
|
<div className="sticky bottom-0 z-20 flex items-center justify-end gap-3 border-t bg-background pt-6 pb-6">
|
|
420
419
|
<Button asChild variant="outline">
|
|
421
|
-
<Link to="/ai-providers">{
|
|
420
|
+
<Link to="/ai-providers">{m.common_common_cancel()}</Link>
|
|
422
421
|
</Button>
|
|
423
422
|
<Button onClick={handleSubmit} disabled={saveMutation.isPending}>
|
|
424
423
|
{saveMutation.isPending ? (
|
|
@@ -426,7 +425,7 @@ export function ProviderForm({
|
|
|
426
425
|
) : (
|
|
427
426
|
<Save className="size-4" data-icon="inline-start" />
|
|
428
427
|
)}
|
|
429
|
-
{mode === "create" ?
|
|
428
|
+
{mode === "create" ? m.common_common_create() : m.common_button_save()}
|
|
430
429
|
</Button>
|
|
431
430
|
</div>
|
|
432
431
|
</div>
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
// apps/admin/src/components/ai-provider/provider-table.tsx
|
|
19
19
|
import { useState } from "react"
|
|
20
|
-
import {
|
|
20
|
+
import { m } from '@/paraglide/messages.js'
|
|
21
21
|
import { useMutation } from "@tanstack/react-query"
|
|
22
22
|
import { Link, useRouter } from "@tanstack/react-router"
|
|
23
23
|
import { Edit, Plus, Trash2, Users } from "lucide-react"
|
|
@@ -44,7 +44,6 @@ import { deleteAiProviderAdminFn } from "@/server/serverFns/ai-provider/delete"
|
|
|
44
44
|
const ADAPTER_LABEL_MAP = new Map(ADAPTER_KINDS.map((k) => [k.value, k.label]))
|
|
45
45
|
|
|
46
46
|
export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
47
|
-
const { t } = useTranslation('admin-ai')
|
|
48
47
|
const router = useRouter()
|
|
49
48
|
const [pendingDelete, setPendingDelete] = useState<AiProviderRow | null>(null)
|
|
50
49
|
|
|
@@ -54,29 +53,29 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
54
53
|
data: { id: vars.id, enabled: vars.enabled },
|
|
55
54
|
}),
|
|
56
55
|
onSuccess: async () => {
|
|
57
|
-
toast.success(
|
|
56
|
+
toast.success(m['admin-ai_table_toast_updated']())
|
|
58
57
|
await router.invalidate()
|
|
59
58
|
},
|
|
60
59
|
onError: (err) =>
|
|
61
|
-
toast.error(err instanceof Error ? err.message :
|
|
60
|
+
toast.error(err instanceof Error ? err.message : m.common_market_form_operationFailed()),
|
|
62
61
|
})
|
|
63
62
|
|
|
64
63
|
const deleteMutation = useMutation({
|
|
65
64
|
mutationFn: (id: string) => deleteAiProviderAdminFn({ data: { id } }),
|
|
66
65
|
onSuccess: async () => {
|
|
67
|
-
toast.success(
|
|
66
|
+
toast.success(m['admin-ai_table_toast_deleted']())
|
|
68
67
|
setPendingDelete(null)
|
|
69
68
|
await router.invalidate()
|
|
70
69
|
},
|
|
71
70
|
onError: (err) =>
|
|
72
|
-
toast.error(err instanceof Error ? err.message :
|
|
71
|
+
toast.error(err instanceof Error ? err.message : m['admin-ai_table_toast_deleteFailed']()),
|
|
73
72
|
})
|
|
74
73
|
|
|
75
74
|
const columns: AdminColumnDef<AiProviderRow>[] = [
|
|
76
75
|
{
|
|
77
76
|
accessorKey: "displayName",
|
|
78
|
-
header:
|
|
79
|
-
cell: ({ row }) => (
|
|
77
|
+
header: m['admin-ai_table_columns_provider'](),
|
|
78
|
+
cell: ({ row }: any) => (
|
|
80
79
|
<div className="flex items-center gap-3">
|
|
81
80
|
<ProviderIcon provider={row.original} size={36} />
|
|
82
81
|
<div>
|
|
@@ -90,8 +89,8 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
90
89
|
},
|
|
91
90
|
{
|
|
92
91
|
accessorKey: "adapterKind",
|
|
93
|
-
header:
|
|
94
|
-
cell: ({ row }) => (
|
|
92
|
+
header: m['admin-ai_table_columns_adapterKind'](),
|
|
93
|
+
cell: ({ row }: any) => (
|
|
95
94
|
<Badge variant="outline">
|
|
96
95
|
{ADAPTER_LABEL_MAP.get(row.original.adapterKind) ??
|
|
97
96
|
row.original.adapterKind}
|
|
@@ -100,15 +99,15 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
100
99
|
},
|
|
101
100
|
{
|
|
102
101
|
accessorKey: "category",
|
|
103
|
-
header:
|
|
104
|
-
cell: ({ row }) => (
|
|
102
|
+
header: m['admin-ai_table_columns_category'](),
|
|
103
|
+
cell: ({ row }: any) => (
|
|
105
104
|
<Badge variant="secondary">{row.original.category}</Badge>
|
|
106
105
|
),
|
|
107
106
|
},
|
|
108
107
|
{
|
|
109
108
|
accessorKey: "badge",
|
|
110
|
-
header:
|
|
111
|
-
cell: ({ row }) => {
|
|
109
|
+
header: m['admin-ai_table_columns_badge'](),
|
|
110
|
+
cell: ({ row }: any) => {
|
|
112
111
|
const b = row.original.badge
|
|
113
112
|
if (!b) return <span className="text-muted-foreground">—</span>
|
|
114
113
|
const style = PROVIDER_BADGE_STYLES[b] ?? "bg-muted text-muted-foreground"
|
|
@@ -121,8 +120,8 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
121
120
|
},
|
|
122
121
|
{
|
|
123
122
|
accessorKey: "models",
|
|
124
|
-
header:
|
|
125
|
-
cell: ({ row }) => (
|
|
123
|
+
header: m['admin-ai_table_columns_modelCount'](),
|
|
124
|
+
cell: ({ row }: any) => (
|
|
126
125
|
<span className="text-sm">
|
|
127
126
|
{Array.isArray(row.original.models) ? row.original.models.length : 0}
|
|
128
127
|
</span>
|
|
@@ -133,10 +132,10 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
133
132
|
header: () => (
|
|
134
133
|
<span className="inline-flex items-center gap-1">
|
|
135
134
|
<Users className="size-3.5" />
|
|
136
|
-
{
|
|
135
|
+
{m['admin-ai_table_columns_userConfigCount']()}
|
|
137
136
|
</span>
|
|
138
137
|
),
|
|
139
|
-
cell: ({ row }) => (
|
|
138
|
+
cell: ({ row }: any) => (
|
|
140
139
|
<span
|
|
141
140
|
className={
|
|
142
141
|
row.original.configCount > 0
|
|
@@ -150,25 +149,25 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
150
149
|
},
|
|
151
150
|
{
|
|
152
151
|
accessorKey: "enabled",
|
|
153
|
-
header:
|
|
154
|
-
cell: ({ row }) => (
|
|
152
|
+
header: m['admin-ai_table_columns_platformEnabled'](),
|
|
153
|
+
cell: ({ row }: any) => (
|
|
155
154
|
<Switch
|
|
156
155
|
checked={row.original.enabled}
|
|
157
|
-
onCheckedChange={(checked) =>
|
|
156
|
+
onCheckedChange={(checked: boolean) =>
|
|
158
157
|
toggleMutation.mutate({
|
|
159
158
|
id: row.original.id,
|
|
160
159
|
enabled: checked,
|
|
161
160
|
})
|
|
162
161
|
}
|
|
163
162
|
disabled={toggleMutation.isPending}
|
|
164
|
-
aria-label={
|
|
163
|
+
aria-label={m['admin-ai_table_enabledToggle']()}
|
|
165
164
|
/>
|
|
166
165
|
),
|
|
167
166
|
},
|
|
168
167
|
{
|
|
169
168
|
id: "actions",
|
|
170
|
-
header:
|
|
171
|
-
cell: ({ row }) => {
|
|
169
|
+
header: m['admin-ai_table_columns_actions'](),
|
|
170
|
+
cell: ({ row }: any) => {
|
|
172
171
|
const canDelete = row.original.configCount === 0
|
|
173
172
|
return (
|
|
174
173
|
<div className="flex items-center gap-1">
|
|
@@ -178,7 +177,7 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
178
177
|
params={{ id: row.original.id }}
|
|
179
178
|
>
|
|
180
179
|
<Edit className="size-4" />
|
|
181
|
-
{
|
|
180
|
+
{m['admin-ai_table_edit']()}
|
|
182
181
|
</Link>
|
|
183
182
|
</Button>
|
|
184
183
|
{canDelete ? (
|
|
@@ -189,17 +188,17 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
189
188
|
onClick={() => setPendingDelete(row.original)}
|
|
190
189
|
>
|
|
191
190
|
<Trash2 className="size-4" />
|
|
192
|
-
{
|
|
191
|
+
{m['admin-ai_table_delete']()}
|
|
193
192
|
</Button>
|
|
194
193
|
) : (
|
|
195
194
|
<Button
|
|
196
195
|
variant="ghost"
|
|
197
196
|
size="sm"
|
|
198
197
|
disabled
|
|
199
|
-
title={
|
|
198
|
+
title={m['admin-ai_table_deleteDisabled']({ count: row.original.configCount })}
|
|
200
199
|
>
|
|
201
200
|
<Trash2 className="size-4" />
|
|
202
|
-
{
|
|
201
|
+
{m['admin-ai_table_delete']()}
|
|
203
202
|
</Button>
|
|
204
203
|
)}
|
|
205
204
|
</div>
|
|
@@ -212,15 +211,15 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
212
211
|
<div className="space-y-4">
|
|
213
212
|
<div className="flex items-center justify-between">
|
|
214
213
|
<div>
|
|
215
|
-
<h2 className="text-lg font-semibold">{
|
|
214
|
+
<h2 className="text-lg font-semibold">{m['admin-ai_table_pageTitle']()}</h2>
|
|
216
215
|
<p className="text-sm text-muted-foreground">
|
|
217
|
-
{
|
|
216
|
+
{m['admin-ai_table_pageDescription']({ count: data.length })}
|
|
218
217
|
</p>
|
|
219
218
|
</div>
|
|
220
219
|
<Button asChild>
|
|
221
220
|
<Link to="/ai-providers/new">
|
|
222
221
|
<Plus className="size-4" />
|
|
223
|
-
{
|
|
222
|
+
{m['admin-ai_table_addProvider']()}
|
|
224
223
|
</Link>
|
|
225
224
|
</Button>
|
|
226
225
|
</div>
|
|
@@ -228,19 +227,19 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
228
227
|
|
|
229
228
|
<AlertDialog
|
|
230
229
|
open={!!pendingDelete}
|
|
231
|
-
onOpenChange={(open) => !open && setPendingDelete(null)}
|
|
230
|
+
onOpenChange={(open: boolean) => !open && setPendingDelete(null)}
|
|
232
231
|
>
|
|
233
232
|
<AlertDialogContent>
|
|
234
233
|
<AlertDialogHeader>
|
|
235
234
|
<AlertDialogTitle>
|
|
236
|
-
{
|
|
235
|
+
{m['admin-ai_table_deleteConfirm_title']({ name: pendingDelete?.displayName ?? '' })}
|
|
237
236
|
</AlertDialogTitle>
|
|
238
237
|
<AlertDialogDescription>
|
|
239
|
-
{
|
|
238
|
+
{m['admin-ai_table_deleteConfirm_description']()}
|
|
240
239
|
</AlertDialogDescription>
|
|
241
240
|
</AlertDialogHeader>
|
|
242
241
|
<AlertDialogFooter>
|
|
243
|
-
<AlertDialogCancel>{
|
|
242
|
+
<AlertDialogCancel>{m.common_common_cancel()}</AlertDialogCancel>
|
|
244
243
|
<AlertDialogAction
|
|
245
244
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
246
245
|
onClick={() =>
|
|
@@ -248,7 +247,7 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
248
247
|
}
|
|
249
248
|
disabled={deleteMutation.isPending}
|
|
250
249
|
>
|
|
251
|
-
{
|
|
250
|
+
{m['admin-ai_table_deleteConfirm_confirm']()}
|
|
252
251
|
</AlertDialogAction>
|
|
253
252
|
</AlertDialogFooter>
|
|
254
253
|
</AlertDialogContent>
|