@allbluecn/admin-app 0.2.6 → 0.3.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 +16 -12
- package/src/components/admin/admin-user-menu.tsx +2 -4
- package/src/components/admin/developer-log.tsx +3 -5
- package/src/components/ai-memory/memory-facts-panel.tsx +383 -0
- package/src/components/ai-prompts/preview-panel.tsx +165 -0
- package/src/components/ai-prompts/prompt-editor.tsx +328 -0
- package/src/components/ai-prompts/prompt-table.tsx +141 -0
- package/src/components/ai-prompts/prompt-utils.ts +124 -0
- package/src/components/ai-prompts/section-editor.tsx +135 -0
- package/src/components/ai-prompts/variable-panel.tsx +128 -0
- package/src/components/ai-prompts/version-history.tsx +157 -0
- package/src/components/ai-provider/provider-form.tsx +6 -10
- package/src/components/ai-provider/provider-table.tsx +33 -13
- package/src/components/auth/admin-login-form.tsx +1 -1
- package/src/components/component/component-form-dialog.tsx +4 -4
- package/src/components/component/component-import-dialog.tsx +2 -2
- package/src/components/dependency/changelog-dialog.tsx +2 -4
- package/src/components/dependency/columns.tsx +4 -8
- package/src/components/dependency/dependency-table.tsx +2 -2
- package/src/components/dependency/edit-dialog.tsx +7 -11
- package/src/components/invitations/invitations-page.tsx +4 -8
- package/src/components/knowledge-public/bookmark-form-dialog.tsx +1 -1
- package/src/components/knowledge-public/compliance-form-dialog.tsx +1 -1
- package/src/components/knowledge-public/legal-form-dialog.tsx +2 -2
- package/src/components/layout/sidebar-02/app-sidebar.tsx +17 -9
- package/src/components/layout/sidebar-02/nav-main.tsx +6 -14
- package/src/components/layout/sidebar-02/nav-notifications.tsx +3 -7
- package/src/components/magicui/rainbow-button.tsx +2 -2
- package/src/components/market/columns.tsx +2 -4
- package/src/components/market/market-app-form.tsx +2 -2
- package/src/components/market/market-app-list.tsx +1 -1
- package/src/components/oauth-providers/provider-page.tsx +1 -1
- package/src/components/ui/alert-dialog.tsx +28 -57
- package/src/components/ui/alert.tsx +3 -4
- package/src/components/ui/avatar.tsx +5 -28
- package/src/components/ui/badge.tsx +19 -34
- package/src/components/ui/button.tsx +14 -41
- package/src/components/ui/card.tsx +6 -24
- package/src/components/ui/checkbox.tsx +4 -26
- package/src/components/ui/collapsible.tsx +6 -37
- package/src/components/ui/dialog.tsx +30 -60
- package/src/components/ui/dropdown-menu.tsx +118 -137
- package/src/components/ui/field.tsx +8 -27
- package/src/components/ui/input-group.tsx +13 -26
- package/src/components/ui/input.tsx +4 -21
- package/src/components/ui/label.tsx +3 -27
- package/src/components/ui/pagination.tsx +17 -31
- package/src/components/ui/select.tsx +101 -76
- package/src/components/ui/separator.tsx +4 -27
- package/src/components/ui/sheet.tsx +29 -58
- package/src/components/ui/sidebar.tsx +119 -117
- package/src/components/ui/skeleton.tsx +1 -18
- package/src/components/ui/switch.tsx +5 -24
- package/src/components/ui/table.tsx +1 -19
- package/src/components/ui/textarea.tsx +2 -20
- package/src/components/ui/toast.tsx +282 -0
- package/src/components/ui/tooltip.tsx +34 -45
- package/src/components/user/settings-activity-log.tsx +1 -1
- package/src/components/user/user-create-dialog.tsx +2 -2
- package/src/components/user/user-filters.tsx +2 -2
- package/src/hooks/use-mobile.ts +0 -17
- package/src/lib/pacer.ts +21 -0
- package/src/lib/utils.ts +1 -23
- package/src/paraglide/README.md +1 -1
- package/src/paraglide/messages/_index.js +95 -0
- package/src/paraglide/messages/admin_ai_memory_action_clearuser1.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_action_query.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_clear_cancel.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_clear_confirm_action.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_clear_confirm_description.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_clear_confirm_title.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_columns_actions.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_columns_content.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_columns_createdat1.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_columns_threadid1.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_delete_cancel.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_delete_confirm_action.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_delete_confirm_description.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_delete_confirm_title.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_empty.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_emptyhint1.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_error_nouserid2.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_error_query.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_error_title.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_form_user.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_page_description.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_page_title.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_placeholder_user.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_stat_count.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_stat_lastwrite1.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_toast_cleared.js +30 -0
- package/src/paraglide/messages/admin_ai_memory_toast_deleted.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_active.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_back.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_badge_protected.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_cache_hint.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_columns_active.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_columns_key.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_columns_name.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_columns_protected.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_columns_updatedat1.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_columns_version.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_description.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_description_placeholder.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_edit.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_name.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_name_placeholder.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_note_placeholder.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_page_description.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_page_title.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_preview_empty.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_preview_generating.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_preview_hint.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_preview_nocontent1.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_preview_placeholder.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_preview_section.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_preview_title.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_protected_hint.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_rollback.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_rollback_confirm_action.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_rollback_confirm_description.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_rollback_confirm_title.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_save.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_section_add.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_section_id.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_section_movedown1.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_section_moveup1.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_section_order.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_section_remove.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_section_template_placeholder.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_sections_empty.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_sections_hint.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_sections_title.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_toast_activated.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_toast_failed.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_toast_protected_locked.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_toast_rolled_back.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_toast_save_failed.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_toast_saved.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_variable_add.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_variable_declarehint1.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_variable_description_placeholder.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_variable_name_placeholder.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_variable_remove.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_variable_undeclared.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_variables_empty.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_variables_title.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_versions_current.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_versions_empty.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_versions_hint.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_versions_nonote1.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_versions_title.js +30 -0
- package/src/paraglide/messages/admin_ai_prompts_versions_unknowncreator1.js +30 -0
- package/src/paraglide/messages/admin_ai_table_seedfromseed2.js +30 -0
- package/src/paraglide/messages/admin_ai_table_toast_seedcreated1.js +30 -0
- package/src/paraglide/messages/admin_ai_table_toast_seedfailed1.js +30 -0
- package/src/paraglide/messages/admin_ai_table_toast_seednonew2.js +30 -0
- package/src/paraglide/messages/common_monitoring_aiusage_sandbox1.js +30 -0
- package/src/paraglide/messages/common_monitoring_aiusage_sandboxvalue2.js +30 -0
- package/src/paraglide/messages/common_nav_aiprompts1.js +30 -0
- package/src/routeTree.gen.ts +101 -0
- package/src/routes/__root.tsx +2 -2
- package/src/{components/ui/sonner.tsx → routes/_nav/ai-memory/route.lazy.tsx} +24 -16
- package/src/routes/_nav/ai-memory/route.tsx +31 -0
- package/src/routes/_nav/ai-prompts/$key/route.lazy.tsx +32 -0
- package/src/routes/_nav/ai-prompts/$key/route.tsx +37 -0
- package/src/routes/_nav/ai-prompts/index/route.lazy.tsx +47 -0
- package/src/routes/_nav/ai-prompts/route.lazy.tsx +26 -0
- package/src/routes/_nav/ai-prompts/route.tsx +31 -0
- package/src/routes/_nav/compliance/route.lazy.tsx +2 -4
- package/src/routes/_nav/components/route.lazy.tsx +1 -1
- package/src/routes/_nav/knowledge-public/bookmarks/route.lazy.tsx +1 -1
- package/src/routes/_nav/knowledge-public/compliance/route.lazy.tsx +1 -1
- package/src/routes/_nav/knowledge-public/legal/route.lazy.tsx +1 -1
- package/src/routes/_nav/licenses/$licenseId/route.lazy.tsx +1 -1
- package/src/routes/_nav/monitoring/ai-usage/route.lazy.tsx +10 -1
- package/src/routes/_nav/monitoring/errors/route.lazy.tsx +1 -1
- package/src/routes/_nav/monitoring/health/route.lazy.tsx +1 -1
- package/src/routes/_nav/monitoring/logs/route.lazy.tsx +1 -1
- package/src/routes/_nav/monitoring/metrics/route.lazy.tsx +1 -1
- package/src/routes/_nav/monitoring/sentry/route.lazy.tsx +1 -1
- package/src/routes/_nav/permissions/route.lazy.tsx +2 -2
- package/src/routes/_nav/sso/route.lazy.tsx +1 -1
- package/src/routes/_nav/users/$userId/route.lazy.tsx +3 -3
- package/src/routes/setup/route.lazy.tsx +1 -1
- package/src/server/__tests__/prompt-defaults.test.ts +139 -0
- package/src/server/admin-ai-usage.ts +22 -4
- package/src/server/ai-memory/store.ts +103 -0
- package/src/server/serverFns/ai-memory/clear.ts +31 -0
- package/src/server/serverFns/ai-memory/delete.ts +31 -0
- package/src/server/serverFns/ai-memory/list-users.ts +40 -0
- package/src/server/serverFns/ai-memory/list.ts +54 -0
- package/src/server/serverFns/ai-prompts/activate.ts +53 -0
- package/src/server/serverFns/ai-prompts/get.ts +74 -0
- package/src/server/serverFns/ai-prompts/list.ts +55 -0
- package/src/server/serverFns/ai-prompts/preview.ts +66 -0
- package/src/server/serverFns/ai-prompts/prompt-defaults.ts +63 -0
- package/src/server/serverFns/ai-prompts/prompt-schemas.ts +47 -0
- package/src/server/serverFns/ai-prompts/rollback.ts +86 -0
- package/src/server/serverFns/ai-prompts/save.ts +129 -0
- package/src/server/serverFns/ai-provider/seed-from-seed.ts +64 -0
- package/src/styles/globals.css +92 -77
- package/src/components/layout/sidebar-02/logo.tsx +0 -40
- package/src/components/layout/sidebar-02/team-switcher.tsx +0 -106
- package/src/components/providers/theme-toggle.tsx +0 -59
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// AllBlue - 理想之海
|
|
3
|
+
// Copyright (C) 2026 AllBlue Contributors
|
|
4
|
+
//
|
|
5
|
+
// This program is free software: you can redistribute it and/or modify
|
|
6
|
+
// it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
// (at your option) any later version.
|
|
9
|
+
//
|
|
10
|
+
// This program is distributed in the hope that it will be useful,
|
|
11
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
// GNU Affero General Public License for more details.
|
|
14
|
+
//
|
|
15
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
// apps/admin/src/components/ai-prompts/section-editor.tsx
|
|
19
|
+
import { ArrowDown, ArrowUp, Plus, Trash2 } from "lucide-react"
|
|
20
|
+
|
|
21
|
+
import { m } from "@/paraglide/messages.js"
|
|
22
|
+
import { Button } from "@/components/ui/button"
|
|
23
|
+
import { Input } from "@/components/ui/input"
|
|
24
|
+
import { Textarea } from "@/components/ui/textarea"
|
|
25
|
+
import {
|
|
26
|
+
appendSection,
|
|
27
|
+
moveSection,
|
|
28
|
+
removeSection,
|
|
29
|
+
type PromptSectionDTO,
|
|
30
|
+
} from "./prompt-utils"
|
|
31
|
+
|
|
32
|
+
interface SectionEditorProps {
|
|
33
|
+
sections: PromptSectionDTO[]
|
|
34
|
+
onChange: (sections: PromptSectionDTO[]) => void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function SectionEditor({ sections, onChange }: SectionEditorProps) {
|
|
38
|
+
return (
|
|
39
|
+
<div className="space-y-3">
|
|
40
|
+
{sections.length === 0 && (
|
|
41
|
+
<p className="text-sm text-muted-foreground">
|
|
42
|
+
{m["admin-ai_prompts_sections_empty"]()}
|
|
43
|
+
</p>
|
|
44
|
+
)}
|
|
45
|
+
|
|
46
|
+
{sections.map((section, index) => (
|
|
47
|
+
<div
|
|
48
|
+
key={section.id}
|
|
49
|
+
className="rounded-md border border-border p-3 space-y-3"
|
|
50
|
+
>
|
|
51
|
+
<div className="flex items-center gap-2">
|
|
52
|
+
<span className="text-sm font-medium shrink-0">
|
|
53
|
+
{m["admin-ai_prompts_section_id"]()}
|
|
54
|
+
</span>
|
|
55
|
+
<span className="font-mono text-xs text-muted-foreground truncate">
|
|
56
|
+
{section.id}
|
|
57
|
+
</span>
|
|
58
|
+
<span className="flex-1" />
|
|
59
|
+
<Button
|
|
60
|
+
type="button"
|
|
61
|
+
variant="ghost"
|
|
62
|
+
size="icon-xs"
|
|
63
|
+
className="shrink-0"
|
|
64
|
+
disabled={index === 0}
|
|
65
|
+
onClick={() => onChange(moveSection(sections, index, -1))}
|
|
66
|
+
aria-label={m["admin-ai_prompts_section_moveUp"]()}
|
|
67
|
+
>
|
|
68
|
+
<ArrowUp />
|
|
69
|
+
</Button>
|
|
70
|
+
<Button
|
|
71
|
+
type="button"
|
|
72
|
+
variant="ghost"
|
|
73
|
+
size="icon-xs"
|
|
74
|
+
className="shrink-0"
|
|
75
|
+
disabled={index === sections.length - 1}
|
|
76
|
+
onClick={() => onChange(moveSection(sections, index, 1))}
|
|
77
|
+
aria-label={m["admin-ai_prompts_section_moveDown"]()}
|
|
78
|
+
>
|
|
79
|
+
<ArrowDown />
|
|
80
|
+
</Button>
|
|
81
|
+
<Button
|
|
82
|
+
type="button"
|
|
83
|
+
variant="ghost"
|
|
84
|
+
size="icon-xs"
|
|
85
|
+
className="shrink-0 text-destructive hover:text-destructive"
|
|
86
|
+
disabled={sections.length === 1}
|
|
87
|
+
onClick={() => onChange(removeSection(sections, index))}
|
|
88
|
+
aria-label={m["admin-ai_prompts_section_remove"]()}
|
|
89
|
+
>
|
|
90
|
+
<Trash2 />
|
|
91
|
+
</Button>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div className="flex items-center gap-3">
|
|
95
|
+
<div className="flex items-center gap-2 shrink-0">
|
|
96
|
+
<span className="text-sm text-muted-foreground">
|
|
97
|
+
{m["admin-ai_prompts_section_order"]()}
|
|
98
|
+
</span>
|
|
99
|
+
<Input
|
|
100
|
+
type="number"
|
|
101
|
+
min={1}
|
|
102
|
+
className="w-16 h-7"
|
|
103
|
+
value={section.order}
|
|
104
|
+
readOnly
|
|
105
|
+
tabIndex={-1}
|
|
106
|
+
/>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<Textarea
|
|
111
|
+
className="font-mono text-sm min-h-24 resize-y"
|
|
112
|
+
value={section.template}
|
|
113
|
+
placeholder={m["admin-ai_prompts_section_template_placeholder"]({ placeholder: "{{name}}" })}
|
|
114
|
+
onChange={(e) => {
|
|
115
|
+
const next = sections.slice()
|
|
116
|
+
next[index] = { ...section, template: e.target.value }
|
|
117
|
+
onChange(next)
|
|
118
|
+
}}
|
|
119
|
+
/>
|
|
120
|
+
</div>
|
|
121
|
+
))}
|
|
122
|
+
|
|
123
|
+
<Button
|
|
124
|
+
type="button"
|
|
125
|
+
variant="outline"
|
|
126
|
+
size="sm"
|
|
127
|
+
className="w-full"
|
|
128
|
+
onClick={() => onChange(appendSection(sections))}
|
|
129
|
+
>
|
|
130
|
+
<Plus />
|
|
131
|
+
{m["admin-ai_prompts_section_add"]()}
|
|
132
|
+
</Button>
|
|
133
|
+
</div>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// AllBlue - 理想之海
|
|
3
|
+
// Copyright (C) 2026 AllBlue Contributors
|
|
4
|
+
//
|
|
5
|
+
// This program is free software: you can redistribute it and/or modify
|
|
6
|
+
// it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
// (at your option) any later version.
|
|
9
|
+
//
|
|
10
|
+
// This program is distributed in the hope that it will be useful,
|
|
11
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
// GNU Affero General Public License for more details.
|
|
14
|
+
//
|
|
15
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
// apps/admin/src/components/ai-prompts/variable-panel.tsx
|
|
19
|
+
import { AlertTriangle, Plus, Trash2 } from "lucide-react"
|
|
20
|
+
|
|
21
|
+
import { m } from "@/paraglide/messages.js"
|
|
22
|
+
import { Button } from "@/components/ui/button"
|
|
23
|
+
import { Input } from "@/components/ui/input"
|
|
24
|
+
import {
|
|
25
|
+
addVariable,
|
|
26
|
+
removeVariable,
|
|
27
|
+
type PromptVariableDTO,
|
|
28
|
+
} from "./prompt-utils"
|
|
29
|
+
|
|
30
|
+
interface VariablePanelProps {
|
|
31
|
+
variables: PromptVariableDTO[]
|
|
32
|
+
onChange: (variables: PromptVariableDTO[]) => void
|
|
33
|
+
usedVariables: string[]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function VariablePanel({
|
|
37
|
+
variables,
|
|
38
|
+
onChange,
|
|
39
|
+
usedVariables,
|
|
40
|
+
}: VariablePanelProps) {
|
|
41
|
+
const declared = new Set(variables.map((v) => v.name).filter(Boolean))
|
|
42
|
+
const undeclared = usedVariables.filter((name) => !declared.has(name))
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className="space-y-3">
|
|
46
|
+
{variables.length === 0 && undeclared.length === 0 && (
|
|
47
|
+
<p className="text-sm text-muted-foreground">
|
|
48
|
+
{m["admin-ai_prompts_variables_empty"]()}
|
|
49
|
+
</p>
|
|
50
|
+
)}
|
|
51
|
+
|
|
52
|
+
{variables.map((variable, index) => (
|
|
53
|
+
<div
|
|
54
|
+
key={index}
|
|
55
|
+
title={variable.description || undefined}
|
|
56
|
+
className="flex items-center gap-2 rounded-md border border-border p-2"
|
|
57
|
+
>
|
|
58
|
+
<Input
|
|
59
|
+
className="font-mono text-sm flex-1 h-7"
|
|
60
|
+
value={variable.name}
|
|
61
|
+
placeholder={m["admin-ai_prompts_variable_name_placeholder"]()}
|
|
62
|
+
onChange={(e) => {
|
|
63
|
+
const next = variables.slice()
|
|
64
|
+
next[index] = { ...variable, name: e.target.value }
|
|
65
|
+
onChange(next)
|
|
66
|
+
}}
|
|
67
|
+
/>
|
|
68
|
+
<Input
|
|
69
|
+
className="flex-1 h-7"
|
|
70
|
+
value={variable.description}
|
|
71
|
+
placeholder={m["admin-ai_prompts_variable_description_placeholder"]()}
|
|
72
|
+
onChange={(e) => {
|
|
73
|
+
const next = variables.slice()
|
|
74
|
+
next[index] = { ...variable, description: e.target.value }
|
|
75
|
+
onChange(next)
|
|
76
|
+
}}
|
|
77
|
+
/>
|
|
78
|
+
<Button
|
|
79
|
+
type="button"
|
|
80
|
+
variant="ghost"
|
|
81
|
+
size="icon-xs"
|
|
82
|
+
className="shrink-0 text-destructive hover:text-destructive"
|
|
83
|
+
onClick={() => onChange(removeVariable(variables, index))}
|
|
84
|
+
aria-label={m["admin-ai_prompts_variable_remove"]()}
|
|
85
|
+
>
|
|
86
|
+
<Trash2 />
|
|
87
|
+
</Button>
|
|
88
|
+
</div>
|
|
89
|
+
))}
|
|
90
|
+
|
|
91
|
+
<Button
|
|
92
|
+
type="button"
|
|
93
|
+
variant="outline"
|
|
94
|
+
size="sm"
|
|
95
|
+
className="w-full"
|
|
96
|
+
onClick={() => onChange(addVariable(variables))}
|
|
97
|
+
>
|
|
98
|
+
<Plus />
|
|
99
|
+
{m["admin-ai_prompts_variable_add"]()}
|
|
100
|
+
</Button>
|
|
101
|
+
|
|
102
|
+
{undeclared.length > 0 && (
|
|
103
|
+
<div className="rounded-md border border-amber-500/40 bg-amber-500/5 p-3 space-y-2">
|
|
104
|
+
<div className="flex items-center gap-2 text-sm text-amber-600 dark:text-amber-400">
|
|
105
|
+
<AlertTriangle className="size-4 shrink-0" />
|
|
106
|
+
<span>{m["admin-ai_prompts_variable_undeclared"]()}</span>
|
|
107
|
+
</div>
|
|
108
|
+
<div className="flex flex-wrap gap-1.5">
|
|
109
|
+
{undeclared.map((name) => (
|
|
110
|
+
<button
|
|
111
|
+
key={name}
|
|
112
|
+
type="button"
|
|
113
|
+
onClick={() =>
|
|
114
|
+
onChange(addVariable([...variables, { name, description: "" }]))
|
|
115
|
+
}
|
|
116
|
+
className="inline-flex items-center gap-1 rounded border border-amber-500/40 bg-background px-1.5 py-0.5 font-mono text-xs text-amber-600 hover:bg-amber-500/10 dark:text-amber-400"
|
|
117
|
+
title={m["admin-ai_prompts_variable_declareHint"]({ name })}
|
|
118
|
+
>
|
|
119
|
+
<Plus className="size-3" />
|
|
120
|
+
{name}
|
|
121
|
+
</button>
|
|
122
|
+
))}
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
// AllBlue - 理想之海
|
|
3
|
+
// Copyright (C) 2026 AllBlue Contributors
|
|
4
|
+
//
|
|
5
|
+
// This program is free software: you can redistribute it and/or modify
|
|
6
|
+
// it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
// (at your option) any later version.
|
|
9
|
+
//
|
|
10
|
+
// This program is distributed in the hope that it will be useful,
|
|
11
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
// GNU Affero General Public License for more details.
|
|
14
|
+
//
|
|
15
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
// apps/admin/src/components/ai-prompts/version-history.tsx
|
|
19
|
+
import { useState } from "react"
|
|
20
|
+
import { History, Loader2, RotateCcw } from "lucide-react"
|
|
21
|
+
import { formatTimestamp } from "@allbluecn/web-app/lib/datetime"
|
|
22
|
+
|
|
23
|
+
import { m } from "@/paraglide/messages.js"
|
|
24
|
+
import { Badge } from "@/components/ui/badge"
|
|
25
|
+
import { Button } from "@/components/ui/button"
|
|
26
|
+
import {
|
|
27
|
+
Collapsible,
|
|
28
|
+
CollapsibleContent,
|
|
29
|
+
CollapsibleTrigger,
|
|
30
|
+
} from "@/components/ui/collapsible"
|
|
31
|
+
import {
|
|
32
|
+
AlertDialog,
|
|
33
|
+
AlertDialogAction,
|
|
34
|
+
AlertDialogCancel,
|
|
35
|
+
AlertDialogContent,
|
|
36
|
+
AlertDialogDescription,
|
|
37
|
+
AlertDialogFooter,
|
|
38
|
+
AlertDialogHeader,
|
|
39
|
+
AlertDialogTitle,
|
|
40
|
+
} from "@/components/ui/alert-dialog"
|
|
41
|
+
import type { PromptVersionSummary } from "./prompt-utils"
|
|
42
|
+
|
|
43
|
+
interface VersionHistoryProps {
|
|
44
|
+
versions: PromptVersionSummary[]
|
|
45
|
+
currentVersion: number
|
|
46
|
+
onRollback: (version: number) => void
|
|
47
|
+
rollbackPending: boolean
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function VersionHistory({
|
|
51
|
+
versions,
|
|
52
|
+
currentVersion,
|
|
53
|
+
onRollback,
|
|
54
|
+
rollbackPending,
|
|
55
|
+
}: VersionHistoryProps) {
|
|
56
|
+
const [rollbackTarget, setRollbackTarget] = useState<number | null>(null)
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<Collapsible defaultOpen>
|
|
60
|
+
<CollapsibleTrigger className="flex w-full items-center gap-2 text-sm font-medium">
|
|
61
|
+
<History />
|
|
62
|
+
<span>{m["admin-ai_prompts_versions_title"]()}</span>
|
|
63
|
+
<Badge variant="secondary" className="ml-auto">
|
|
64
|
+
{versions.length}
|
|
65
|
+
</Badge>
|
|
66
|
+
</CollapsibleTrigger>
|
|
67
|
+
<CollapsibleContent className="pt-3 space-y-2">
|
|
68
|
+
<p className="text-xs text-muted-foreground">
|
|
69
|
+
{m["admin-ai_prompts_versions_hint"]()}
|
|
70
|
+
</p>
|
|
71
|
+
|
|
72
|
+
{versions.length === 0 && (
|
|
73
|
+
<p className="text-sm text-muted-foreground">
|
|
74
|
+
{m["admin-ai_prompts_versions_empty"]()}
|
|
75
|
+
</p>
|
|
76
|
+
)}
|
|
77
|
+
|
|
78
|
+
{versions.map((version) => {
|
|
79
|
+
const isCurrent = version.version >= currentVersion
|
|
80
|
+
return (
|
|
81
|
+
<div
|
|
82
|
+
key={version.id}
|
|
83
|
+
className="flex items-center gap-3 rounded-md border border-border p-2.5"
|
|
84
|
+
>
|
|
85
|
+
<Badge
|
|
86
|
+
variant={isCurrent ? "default" : "outline"}
|
|
87
|
+
className="font-mono shrink-0"
|
|
88
|
+
>
|
|
89
|
+
v{version.version}
|
|
90
|
+
</Badge>
|
|
91
|
+
<div className="flex-1 min-w-0">
|
|
92
|
+
<p className="text-sm truncate">
|
|
93
|
+
{version.note ||
|
|
94
|
+
m["admin-ai_prompts_versions_noNote"]()}
|
|
95
|
+
</p>
|
|
96
|
+
<p className="text-xs text-muted-foreground">
|
|
97
|
+
{version.createdBy ?? m["admin-ai_prompts_versions_unknownCreator"]()}
|
|
98
|
+
{" · "}
|
|
99
|
+
{formatTimestamp(version.createdAt)}
|
|
100
|
+
</p>
|
|
101
|
+
</div>
|
|
102
|
+
{isCurrent ? (
|
|
103
|
+
<span className="text-xs text-muted-foreground shrink-0">
|
|
104
|
+
{m["admin-ai_prompts_versions_current"]()}
|
|
105
|
+
</span>
|
|
106
|
+
) : (
|
|
107
|
+
<Button
|
|
108
|
+
type="button"
|
|
109
|
+
variant="outline"
|
|
110
|
+
size="sm"
|
|
111
|
+
className="shrink-0"
|
|
112
|
+
disabled={rollbackPending}
|
|
113
|
+
onClick={() => setRollbackTarget(version.version)}
|
|
114
|
+
>
|
|
115
|
+
{rollbackPending ? (
|
|
116
|
+
<Loader2 className="animate-spin" />
|
|
117
|
+
) : (
|
|
118
|
+
<RotateCcw />
|
|
119
|
+
)}
|
|
120
|
+
{m["admin-ai_prompts_rollback"]()}
|
|
121
|
+
</Button>
|
|
122
|
+
)}
|
|
123
|
+
</div>
|
|
124
|
+
)
|
|
125
|
+
})}
|
|
126
|
+
</CollapsibleContent>
|
|
127
|
+
|
|
128
|
+
<AlertDialog open={rollbackTarget !== null} onOpenChange={(open) => { if (!open) setRollbackTarget(null) }}>
|
|
129
|
+
<AlertDialogContent>
|
|
130
|
+
<AlertDialogHeader>
|
|
131
|
+
<AlertDialogTitle>
|
|
132
|
+
{m["admin-ai_prompts_rollback_confirm_title"]({
|
|
133
|
+
version: rollbackTarget ?? 0,
|
|
134
|
+
})}
|
|
135
|
+
</AlertDialogTitle>
|
|
136
|
+
<AlertDialogDescription>
|
|
137
|
+
{m["admin-ai_prompts_rollback_confirm_description"]({
|
|
138
|
+
version: rollbackTarget ?? 0,
|
|
139
|
+
})}
|
|
140
|
+
</AlertDialogDescription>
|
|
141
|
+
</AlertDialogHeader>
|
|
142
|
+
<AlertDialogFooter>
|
|
143
|
+
<AlertDialogCancel>{m.common_common_cancel()}</AlertDialogCancel>
|
|
144
|
+
<AlertDialogAction
|
|
145
|
+
disabled={rollbackPending}
|
|
146
|
+
onClick={() => {
|
|
147
|
+
if (rollbackTarget !== null) onRollback(rollbackTarget)
|
|
148
|
+
}}
|
|
149
|
+
>
|
|
150
|
+
{m["admin-ai_prompts_rollback_confirm_action"]()}
|
|
151
|
+
</AlertDialogAction>
|
|
152
|
+
</AlertDialogFooter>
|
|
153
|
+
</AlertDialogContent>
|
|
154
|
+
</AlertDialog>
|
|
155
|
+
</Collapsible>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
@@ -21,7 +21,7 @@ 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"
|
|
24
|
-
import { toast } from '@/components/ui/
|
|
24
|
+
import { toast } from '@/components/ui/toast'
|
|
25
25
|
import {
|
|
26
26
|
ADAPTER_KINDS,
|
|
27
27
|
PROVIDER_CATEGORIES,
|
|
@@ -142,11 +142,9 @@ export function ProviderForm({
|
|
|
142
142
|
return (
|
|
143
143
|
<div className="mx-auto w-3/5 space-y-6">
|
|
144
144
|
<div className="sticky top-0 z-20 flex items-center gap-2 border-b bg-background pt-6 pb-3">
|
|
145
|
-
<Button
|
|
146
|
-
<Link to="/ai-providers" aria-label="返回">
|
|
145
|
+
<Button render={<Link to="/ai-providers" aria-label="返回" />} variant="ghost" size="icon" nativeButton={false}>
|
|
147
146
|
<ArrowLeft className="size-4" />
|
|
148
|
-
</
|
|
149
|
-
</Button>
|
|
147
|
+
</Button>
|
|
150
148
|
<h2 className="text-lg font-semibold">
|
|
151
149
|
{mode === "create" ? m['admin-ai_form_addProvider']() : m['admin-ai_form_editProvider']()}
|
|
152
150
|
</h2>
|
|
@@ -230,7 +228,7 @@ export function ProviderForm({
|
|
|
230
228
|
</FieldContent>
|
|
231
229
|
<Select
|
|
232
230
|
value={values.category}
|
|
233
|
-
onValueChange={(v
|
|
231
|
+
onValueChange={(v) => patch({ category: (v ?? "") as ProviderCategory })}
|
|
234
232
|
>
|
|
235
233
|
<SelectTrigger className="w-40">
|
|
236
234
|
<SelectValue />
|
|
@@ -252,7 +250,7 @@ export function ProviderForm({
|
|
|
252
250
|
</FieldContent>
|
|
253
251
|
<Select
|
|
254
252
|
value={values.adapterKind}
|
|
255
|
-
onValueChange={(v
|
|
253
|
+
onValueChange={(v) => patch({ adapterKind: (v ?? "") as AdapterKind })}
|
|
256
254
|
>
|
|
257
255
|
<SelectTrigger className="w-60">
|
|
258
256
|
<SelectValue />
|
|
@@ -416,9 +414,7 @@ export function ProviderForm({
|
|
|
416
414
|
</FieldSet>
|
|
417
415
|
|
|
418
416
|
<div className="sticky bottom-0 z-20 flex items-center justify-end gap-3 border-t bg-background pt-6 pb-6">
|
|
419
|
-
<Button
|
|
420
|
-
<Link to="/ai-providers">{m.common_common_cancel()}</Link>
|
|
421
|
-
</Button>
|
|
417
|
+
<Button render={<Link to="/ai-providers" />} variant="outline" nativeButton={false}>{m.common_common_cancel()}</Button>
|
|
422
418
|
<Button onClick={handleSubmit} disabled={saveMutation.isPending}>
|
|
423
419
|
{saveMutation.isPending ? (
|
|
424
420
|
<Loader2 className="size-4 animate-spin" data-icon="inline-start" />
|
|
@@ -20,8 +20,8 @@ import { useState } from "react"
|
|
|
20
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
|
-
import { Edit, Plus, Trash2, Users } from "lucide-react"
|
|
24
|
-
import { toast } from '@/components/ui/
|
|
23
|
+
import { Edit, Plus, RefreshCw, Trash2, Users } from "lucide-react"
|
|
24
|
+
import { toast } from '@/components/ui/toast'
|
|
25
25
|
import { ADAPTER_KINDS, PROVIDER_BADGE_STYLES, type AiProviderRow } from "@allbluecn/kernel"
|
|
26
26
|
import { Button } from "@/components/ui/button"
|
|
27
27
|
import { Switch } from "@/components/ui/switch"
|
|
@@ -40,6 +40,7 @@ import { DataTable, type AdminColumnDef } from "@/components/data-table/data-tab
|
|
|
40
40
|
import { ProviderIcon } from "./provider-icon"
|
|
41
41
|
import { updateAiProviderAdminFn } from "@/server/serverFns/ai-provider/update"
|
|
42
42
|
import { deleteAiProviderAdminFn } from "@/server/serverFns/ai-provider/delete"
|
|
43
|
+
import { seedFromSeedFn } from "@/server/serverFns/ai-provider/seed-from-seed"
|
|
43
44
|
|
|
44
45
|
const ADAPTER_LABEL_MAP = new Map(ADAPTER_KINDS.map((k) => [k.value, k.label]))
|
|
45
46
|
|
|
@@ -71,6 +72,25 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
71
72
|
toast.error(err instanceof Error ? err.message : m['admin-ai_table_toast_deleteFailed']()),
|
|
72
73
|
})
|
|
73
74
|
|
|
75
|
+
const seedMutation = useMutation({
|
|
76
|
+
mutationFn: () => seedFromSeedFn({ data: {} }),
|
|
77
|
+
onSuccess: async (result: { created: string[]; skipped: string[] }) => {
|
|
78
|
+
if (result.created.length === 0) {
|
|
79
|
+
toast.info(m['admin-ai_table_toast_seedNoNew']())
|
|
80
|
+
} else {
|
|
81
|
+
toast.success(
|
|
82
|
+
m['admin-ai_table_toast_seedCreated']({
|
|
83
|
+
created: result.created.length,
|
|
84
|
+
skipped: result.skipped.length,
|
|
85
|
+
}),
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
await router.invalidate()
|
|
89
|
+
},
|
|
90
|
+
onError: (err) =>
|
|
91
|
+
toast.error(err instanceof Error ? err.message : m['admin-ai_table_toast_seedFailed']()),
|
|
92
|
+
})
|
|
93
|
+
|
|
74
94
|
const columns: AdminColumnDef<AiProviderRow>[] = [
|
|
75
95
|
{
|
|
76
96
|
accessorKey: "displayName",
|
|
@@ -171,15 +191,11 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
171
191
|
const canDelete = row.original.configCount === 0
|
|
172
192
|
return (
|
|
173
193
|
<div className="flex items-center gap-1">
|
|
174
|
-
<Button
|
|
175
|
-
|
|
176
|
-
to="/ai-providers/$id/edit"
|
|
177
|
-
params={{ id: row.original.id }}
|
|
178
|
-
>
|
|
194
|
+
<Button render={<Link to="/ai-providers/$id/edit"
|
|
195
|
+
params={{ id: row.original.id }} />} variant="ghost" size="sm" nativeButton={false}>
|
|
179
196
|
<Edit className="size-4" />
|
|
180
197
|
{m['admin-ai_table_edit']()}
|
|
181
|
-
</
|
|
182
|
-
</Button>
|
|
198
|
+
</Button>
|
|
183
199
|
{canDelete ? (
|
|
184
200
|
<Button
|
|
185
201
|
variant="ghost"
|
|
@@ -216,12 +232,16 @@ export function ProviderTable({ data }: { data: AiProviderRow[] }) {
|
|
|
216
232
|
{m['admin-ai_table_pageDescription']({ count: data.length })}
|
|
217
233
|
</p>
|
|
218
234
|
</div>
|
|
219
|
-
<
|
|
220
|
-
<
|
|
235
|
+
<div className="flex items-center gap-2">
|
|
236
|
+
<Button variant="outline" size="sm" onClick={() => seedMutation.mutate()} disabled={seedMutation.isPending}>
|
|
237
|
+
<RefreshCw className="size-4" />
|
|
238
|
+
{m['admin-ai_table_seedFromSeed']()}
|
|
239
|
+
</Button>
|
|
240
|
+
<Button render={<Link to="/ai-providers/new" />} nativeButton={false}>
|
|
221
241
|
<Plus className="size-4" />
|
|
222
242
|
{m['admin-ai_table_addProvider']()}
|
|
223
|
-
</
|
|
224
|
-
</
|
|
243
|
+
</Button>
|
|
244
|
+
</div>
|
|
225
245
|
</div>
|
|
226
246
|
<DataTable columns={columns} data={data} />
|
|
227
247
|
|
|
@@ -23,7 +23,7 @@ import { Button } from "@/components/ui/button";
|
|
|
23
23
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
24
24
|
import { Field, FieldLabel } from "@/components/ui/field";
|
|
25
25
|
import { Card, CardContent } from "@/components/ui/card";
|
|
26
|
-
import { toast } from '@/components/ui/
|
|
26
|
+
import { toast } from '@/components/ui/toast';
|
|
27
27
|
import { UserAvatar } from "@allbluecn/web-app/user-avatar";
|
|
28
28
|
import type { AvatarConfig, ShapeType } from "@allbluecn/kernel";
|
|
29
29
|
import { AuthLayout, AuthLayoutLeft, AuthLayoutRight } from "@/components/auth/auth-layout";
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
} from '@/components/ui/dialog'
|
|
39
39
|
import { getComponent, ComponentPreview } from '@allbluecn/web-app/prototype'
|
|
40
40
|
import { createComponentFn, updateComponentFn } from '@/server/serverFns/components/mutations'
|
|
41
|
-
import { toast } from '@/components/ui/
|
|
41
|
+
import { toast } from '@/components/ui/toast'
|
|
42
42
|
import type { ComponentItem } from './component-table'
|
|
43
43
|
|
|
44
44
|
const CATEGORY_KEYS = ['base', 'block', 'template'] as const
|
|
@@ -197,7 +197,7 @@ export function ComponentFormDialog({ open, onOpenChange, component, onSuccess }
|
|
|
197
197
|
<Input value={String(val)} onChange={(e: React.ChangeEvent<HTMLInputElement>) => setVal(e.target.value)} className="font-mono text-xs" />
|
|
198
198
|
</div>
|
|
199
199
|
) : prop.type === 'select' && prop.options ? (
|
|
200
|
-
<Select value={String(val)} onValueChange={setVal}>
|
|
200
|
+
<Select value={String(val)} onValueChange={(v) => setVal(v ?? "")}>
|
|
201
201
|
<SelectTrigger className="w-full"><SelectValue /></SelectTrigger>
|
|
202
202
|
<SelectContent>
|
|
203
203
|
{prop.options.map((o) => (
|
|
@@ -257,7 +257,7 @@ export function ComponentFormDialog({ open, onOpenChange, component, onSuccess }
|
|
|
257
257
|
|
|
258
258
|
<div className="space-y-1.5">
|
|
259
259
|
<Label>{m.common_component_form_category()}</Label>
|
|
260
|
-
<Select value={category} onValueChange={setCategory}>
|
|
260
|
+
<Select value={category} onValueChange={(v) => setCategory(v ?? "")}>
|
|
261
261
|
<SelectTrigger className="w-full">
|
|
262
262
|
<SelectValue />
|
|
263
263
|
</SelectTrigger>
|
|
@@ -271,7 +271,7 @@ export function ComponentFormDialog({ open, onOpenChange, component, onSuccess }
|
|
|
271
271
|
|
|
272
272
|
<div className="space-y-1.5">
|
|
273
273
|
<Label>{m.common_component_form_type()}</Label>
|
|
274
|
-
<Select value={type} onValueChange={setType}>
|
|
274
|
+
<Select value={type} onValueChange={(v) => setType(v ?? "")}>
|
|
275
275
|
<SelectTrigger className="w-full">
|
|
276
276
|
<SelectValue />
|
|
277
277
|
</SelectTrigger>
|
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
DialogTitle,
|
|
36
36
|
} from '@/components/ui/dialog'
|
|
37
37
|
import { importComponentFn } from '@/server/serverFns/components/import'
|
|
38
|
-
import { toast } from '@/components/ui/
|
|
38
|
+
import { toast } from '@/components/ui/toast'
|
|
39
39
|
import { Loader2, Sparkles } from 'lucide-react'
|
|
40
40
|
import { cn } from '@/lib/utils'
|
|
41
41
|
|
|
@@ -207,7 +207,7 @@ export function ComponentImportDialog({ open, onOpenChange, onSuccess }: Compone
|
|
|
207
207
|
</div>
|
|
208
208
|
<div className="space-y-1.5">
|
|
209
209
|
<Label>分类</Label>
|
|
210
|
-
<Select value={category} onValueChange={setCategory}>
|
|
210
|
+
<Select value={category} onValueChange={(v) => setCategory(v ?? "")}>
|
|
211
211
|
<SelectTrigger className="w-full">
|
|
212
212
|
<SelectValue />
|
|
213
213
|
</SelectTrigger>
|
|
@@ -40,12 +40,10 @@ export function ChangelogDialog({ row }: { row: ThirdPartyDependencyRow }) {
|
|
|
40
40
|
|
|
41
41
|
return (
|
|
42
42
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
43
|
-
<DialogTrigger
|
|
44
|
-
<Button size="sm" variant="ghost" className="h-7 gap-1 px-2" title={m.common_dependency_table_cell_viewChangelog()}>
|
|
43
|
+
<DialogTrigger render={<Button size="sm" variant="ghost" className="h-7 gap-1 px-2" title={m.common_dependency_table_cell_viewChangelog()} />}>
|
|
45
44
|
<FileText className="size-3.5" />
|
|
46
45
|
<span className="text-xs">{m.common_dependency_table_cell_changelogBtn()}</span>
|
|
47
|
-
</
|
|
48
|
-
</DialogTrigger>
|
|
46
|
+
</DialogTrigger>
|
|
49
47
|
<DialogContent className="max-h-[85vh] w-200 max-w-4xl overflow-hidden p-0">
|
|
50
48
|
<DialogHeader className="border-b px-5 py-3">
|
|
51
49
|
<div className="flex items-center justify-between gap-2 pr-6">
|
|
@@ -128,11 +128,9 @@ export function getDependencyColumns(opts: ColumnOpts): ColumnDef<typeof depende
|
|
|
128
128
|
if (!desc) return <span className="text-xs text-muted-foreground">—</span>
|
|
129
129
|
return (
|
|
130
130
|
<Tooltip>
|
|
131
|
-
<TooltipTrigger
|
|
132
|
-
<span className="line-clamp-2 max-w-[280px] text-xs text-muted-foreground">
|
|
131
|
+
<TooltipTrigger render={<span className="line-clamp-2 max-w-[280px] text-xs text-muted-foreground" />}>
|
|
133
132
|
{desc}
|
|
134
|
-
</
|
|
135
|
-
</TooltipTrigger>
|
|
133
|
+
</TooltipTrigger>
|
|
136
134
|
<TooltipContent className="max-w-sm">{desc}</TooltipContent>
|
|
137
135
|
</Tooltip>
|
|
138
136
|
)
|
|
@@ -156,11 +154,9 @@ export function getDependencyColumns(opts: ColumnOpts): ColumnDef<typeof depende
|
|
|
156
154
|
if (r.usages.length > 1) {
|
|
157
155
|
return (
|
|
158
156
|
<Tooltip>
|
|
159
|
-
<TooltipTrigger
|
|
160
|
-
<span className="cursor-help border-b border-dashed border-muted-foreground/50">
|
|
157
|
+
<TooltipTrigger render={<span className="cursor-help border-b border-dashed border-muted-foreground/50" />}>
|
|
161
158
|
{r.currentVersion}
|
|
162
|
-
</
|
|
163
|
-
</TooltipTrigger>
|
|
159
|
+
</TooltipTrigger>
|
|
164
160
|
<TooltipContent>
|
|
165
161
|
<div className="space-y-0.5 text-xs">
|
|
166
162
|
{r.usages.map((u) => (
|