Skip to content

Commit b41f5d4

Browse files
authored
Merge pull request #1660 from Mai-with-u/dev
Dev
2 parents 2c14fd8 + 05052ba commit b41f5d4

30 files changed

Lines changed: 507 additions & 113 deletions

dashboard/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "maibot-dashboard",
33
"private": true,
4-
"version": "1.0.9",
4+
"version": "1.0.10",
55
"type": "module",
66
"main": "./out/main/index.js",
77
"scripts": {

dashboard/src/lib/plugin-api/marketplace.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ interface PluginApiResponse {
2121
id: string
2222
manifest: {
2323
manifest_version: number
24+
id?: string
2425
name: string
2526
version: string
2627
description: string
@@ -56,6 +57,7 @@ function normalizePluginManifest(manifest: PluginApiResponse['manifest']): Plugi
5657

5758
return {
5859
manifest_version: manifest.manifest_version || 1,
60+
id: manifest.id,
5961
name: manifest.name,
6062
version: manifest.version,
6163
description: manifest.description || '',
@@ -104,18 +106,23 @@ export async function fetchPluginList(): Promise<ApiResponse<PluginInfo[]>> {
104106

105107
const pluginList = data
106108
.filter(item => {
107-
if (!item?.id || !item?.manifest) {
109+
if (!item?.manifest) {
108110
console.warn('跳过无效插件数据:', item)
109111
return false
110112
}
113+
const pluginId = item.manifest.id || item.id
114+
if (!pluginId) {
115+
console.warn('跳过缺少 ID 的插件:', item)
116+
return false
117+
}
111118
if (!item.manifest.name || !item.manifest.version) {
112119
console.warn('跳过缺少必需字段的插件:', item.id)
113120
return false
114121
}
115122
return true
116123
})
117124
.map((item) => ({
118-
id: item.id,
125+
id: item.manifest.id || item.id,
119126
manifest: normalizePluginManifest(item.manifest),
120127
downloads: 0,
121128
rating: 0,

dashboard/src/lib/plugin-api/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export interface InstalledPlugin {
2525
id: string
2626
manifest: {
2727
manifest_version: number
28+
id?: string
2829
name: string
2930
version: string
3031
description: string

dashboard/src/lib/version.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* 修改此处的版本号后,所有展示版本的地方都会自动更新
66
*/
77

8-
export const APP_VERSION = '1.0.9'
8+
export const APP_VERSION = '1.0.10'
99
export const APP_NAME = 'MaiBot Dashboard'
1010
export const APP_FULL_NAME = `${APP_NAME} v${APP_VERSION}`
1111

dashboard/src/routes/plugin-detail.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,21 +104,23 @@ export function PluginDetailPage() {
104104
}
105105

106106
const pluginList = JSON.parse(result.data)
107-
const foundPlugin = pluginList.find((p: any) => p.id === search.pluginId)
107+
const foundPlugin = pluginList.find((p: any) => (p.manifest?.id || p.id) === search.pluginId)
108108

109109
if (!foundPlugin) {
110110
throw new Error('未找到该插件')
111111
}
112112

113113
const rawManifest = foundPlugin.manifest || {}
114+
const pluginId = rawManifest.id || foundPlugin.id
114115
const repositoryUrl = rawManifest.repository_url || rawManifest.urls?.repository
115116
const homepageUrl = rawManifest.homepage_url || rawManifest.urls?.homepage
116117

117118
// 转换为 PluginInfo 格式
118119
const pluginInfo: PluginInfo = {
119-
id: foundPlugin.id,
120+
id: pluginId,
120121
manifest: {
121122
...rawManifest,
123+
id: pluginId,
122124
homepage_url: homepageUrl,
123125
repository_url: repositoryUrl,
124126
default_locale: rawManifest.default_locale || rawManifest.i18n?.default_locale || 'zh-CN',
@@ -170,8 +172,8 @@ export function PluginDetailPage() {
170172
return
171173
}
172174

173-
setIsInstalled(checkPluginInstalled(search.pluginId, installedPlugins.data))
174-
setInstalledVersion(getInstalledPluginVersion(search.pluginId, installedPlugins.data))
175+
setIsInstalled(checkPluginInstalled(pluginId, installedPlugins.data))
176+
setInstalledVersion(getInstalledPluginVersion(pluginId, installedPlugins.data))
175177
} catch (err) {
176178
setError(err instanceof Error ? err.message : '加载失败')
177179
} finally {
@@ -196,7 +198,7 @@ export function PluginDetailPage() {
196198
// 如果插件已安装,优先尝试从本地读取 README
197199
if (isInstalled && search.pluginId) {
198200
try {
199-
const localResponse = await fetchWithAuth(`/api/webui/plugins/local-readme/${search.pluginId}`)
201+
const localResponse = await fetchWithAuth(`/api/webui/plugins/local-readme/${plugin.id}`)
200202

201203
if (localResponse.ok) {
202204
const localResult = await localResponse.json()

dashboard/src/routes/plugins/InstalledTab.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export function InstalledTab({
6767
})
6868

6969
return (
70-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
70+
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-5">
7171
{filteredPlugins.map((plugin) => (
7272
<PluginCard
7373
key={plugin.id}

dashboard/src/routes/plugins/MarketplaceTab.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export function MarketplaceTab({
6868
})
6969

7070
return (
71-
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
71+
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-5">
7272
{filteredPlugins.map((plugin) => (
7373
<PluginCard
7474
key={plugin.id}

dashboard/src/routes/plugins/PluginCard.tsx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ export function PluginCard({
4444
key={plugin.id}
4545
className="flex flex-col hover:shadow-lg transition-shadow h-full"
4646
>
47-
<CardHeader>
48-
<div className="flex items-start justify-between gap-2">
49-
<CardTitle className="text-xl">{plugin.manifest?.name || plugin.id}</CardTitle>
50-
<div className="flex flex-col gap-1">
47+
<CardHeader className="p-5 pb-3">
48+
<div className="flex items-start justify-between gap-3">
49+
<CardTitle className="text-lg leading-snug">{plugin.manifest?.name || plugin.id}</CardTitle>
50+
<div className="flex flex-col items-end gap-1 shrink-0">
5151
{plugin.manifest?.categories && plugin.manifest.categories[0] && (
5252
<Badge variant="secondary" className="text-xs whitespace-nowrap">
5353
{CATEGORY_NAMES[plugin.manifest.categories[0]] || plugin.manifest.categories[0]}
@@ -56,18 +56,18 @@ export function PluginCard({
5656
{getStatusBadge(plugin)}
5757
</div>
5858
</div>
59-
<CardDescription className="line-clamp-2">{plugin.manifest?.description || '无描述'}</CardDescription>
59+
<CardDescription className="line-clamp-2 text-sm leading-snug">{plugin.manifest?.description || '无描述'}</CardDescription>
6060
</CardHeader>
61-
<CardContent className="flex-1">
62-
<div className="space-y-3">
61+
<CardContent className="px-5 pb-3">
62+
<div className="space-y-2.5">
6363
{/* 统计信息 */}
64-
<div className="flex items-center gap-4 text-sm text-muted-foreground">
64+
<div className="flex items-center gap-3 text-sm text-muted-foreground">
6565
<div className="flex items-center gap-1">
66-
<Download className="h-4 w-4" />
66+
<Download className="h-3.5 w-3.5" />
6767
<span>{(pluginStats[plugin.id]?.downloads ?? plugin.downloads ?? 0).toLocaleString()}</span>
6868
</div>
6969
<div className="flex items-center gap-1">
70-
<Star className="h-4 w-4 fill-yellow-400 text-yellow-400" />
70+
<Star className="h-3.5 w-3.5 fill-yellow-400 text-yellow-400" />
7171
<span>{(pluginStats[plugin.id]?.rating ?? plugin.rating ?? 0).toFixed(1)}</span>
7272
</div>
7373
</div>
@@ -85,7 +85,7 @@ export function PluginCard({
8585
)}
8686
</div>
8787
{/* 版本和作者 */}
88-
<div className="text-xs text-muted-foreground pt-2 border-t space-y-1">
88+
<div className="text-xs text-muted-foreground pt-2.5 border-t space-y-1">
8989
<div>v{plugin.manifest?.version || 'unknown'} · {plugin.manifest?.author?.name || 'Unknown'}</div>
9090
{/* 支持版本 */}
9191
{plugin.manifest?.host_application && (
@@ -103,7 +103,7 @@ export function PluginCard({
103103
</div>
104104
</div>
105105
</CardContent>
106-
<CardFooter className="pt-4">
106+
<CardFooter className="px-5 pt-2 pb-5">
107107
<div className="flex items-center justify-end gap-2 w-full">
108108
<Button
109109
variant="outline"
@@ -169,7 +169,7 @@ export function PluginCard({
169169
(loadProgress.stage === 'loading' || loadProgress.stage === 'success' || loadProgress.stage === 'error') &&
170170
loadProgress.operation !== 'fetch' &&
171171
loadProgress.plugin_id === plugin.id && (
172-
<div className="px-6 pb-4 -mt-2">
172+
<div className="px-5 pb-5 -mt-1">
173173
<div className={`space-y-2 p-3 rounded-lg border ${
174174
loadProgress.stage === 'success'
175175
? 'bg-green-50 dark:bg-green-950/20 border-green-200 dark:border-green-900'

dashboard/src/routes/plugins/index.tsx

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ export function PluginsPage() {
4848
function PluginsPageContent() {
4949
const navigate = useNavigate()
5050
const { triggerRestart, isRestarting } = useRestart()
51+
const [restartNoticeVisible, setRestartNoticeVisible] = useState(
52+
() => localStorage.getItem('plugins-restart-notice-dismissed') !== 'true'
53+
)
5154
const [searchQuery, setSearchQuery] = useState('')
5255
const [categoryFilter, setCategoryFilter] = useState('all')
5356
const [activeTab, setActiveTab] = useState('all') // all | installed | updates
@@ -67,6 +70,11 @@ function PluginsPageContent() {
6770

6871
const { toast } = useToast()
6972

73+
const dismissRestartNotice = () => {
74+
localStorage.setItem('plugins-restart-notice-dismissed', 'true')
75+
setRestartNoticeVisible(false)
76+
}
77+
7078
// 加载插件统计数据
7179
const loadPluginStats = async (pluginList: PluginInfo[]) => {
7280
const statsPromises = pluginList.map(async (plugin) => {
@@ -220,6 +228,7 @@ function PluginsPageContent() {
220228
id: installedPlugin.id,
221229
manifest: {
222230
manifest_version: installedPlugin.manifest.manifest_version || 1,
231+
id: installedPlugin.manifest.id || installedPlugin.id,
223232
name: installedPlugin.manifest.name,
224233
version: installedPlugin.manifest.version,
225234
description: installedPlugin.manifest.description || '',
@@ -704,16 +713,23 @@ function PluginsPageContent() {
704713
</div>
705714

706715
{/* 安装提示 */}
707-
<Card className="border-blue-200 bg-blue-50 dark:bg-blue-950/20 dark:border-blue-900">
708-
<CardContent className="py-3">
709-
<div className="flex items-center gap-2">
710-
<Info className="h-4 w-4 text-blue-600 flex-shrink-0" />
711-
<p className="text-sm text-blue-800 dark:text-blue-200">
712-
安装、卸载或更新插件后,需要<span className="font-semibold">重启麦麦</span>才能使更改生效
713-
</p>
714-
</div>
715-
</CardContent>
716-
</Card>
716+
{restartNoticeVisible && (
717+
<Card className="border-blue-200 bg-blue-50 dark:bg-blue-950/20 dark:border-blue-900">
718+
<CardContent className="py-3">
719+
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
720+
<div className="flex items-center gap-2">
721+
<Info className="h-4 w-4 text-blue-600 flex-shrink-0" />
722+
<p className="text-sm text-blue-800 dark:text-blue-200">
723+
安装、卸载或更新插件后,部分插件需要<span className="font-semibold">重启麦麦</span>才能生效
724+
</p>
725+
</div>
726+
<Button type="button" variant="outline" size="sm" onClick={dismissRestartNotice}>
727+
我知道了
728+
</Button>
729+
</div>
730+
</CardContent>
731+
</Card>
732+
)}
717733

718734
{/* Git 状态警告 */}
719735
{gitStatus && !gitStatus.installed && (

dashboard/src/routes/reasoning-process.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react'
22
import {
33
Clock,
44
Code2,
5+
Copy,
56
FileCode2,
67
FileText,
78
RefreshCw,
@@ -10,6 +11,7 @@ import {
1011

1112
import { Badge } from '@/components/ui/badge'
1213
import { Button } from '@/components/ui/button'
14+
import { useToast } from '@/hooks/use-toast'
1315
import { Input } from '@/components/ui/input'
1416
import { ScrollArea } from '@/components/ui/scroll-area'
1517
import {
@@ -49,6 +51,7 @@ function formatSize(size: number): string {
4951
}
5052

5153
export function ReasoningProcessPage() {
54+
const { toast } = useToast()
5255
const [items, setItems] = useState<ReasoningPromptFile[]>([])
5356
const [stages, setStages] = useState<string[]>([])
5457
const [sessions, setSessions] = useState<string[]>([])
@@ -165,6 +168,31 @@ export function ReasoningProcessPage() {
165168
setPage(1)
166169
}
167170

171+
async function handleCopyPrompt() {
172+
if (!textContent || contentLoading) {
173+
toast({
174+
title: '暂无可复制内容',
175+
description: '请先选择一条包含 txt 的 prompt 记录',
176+
variant: 'destructive',
177+
})
178+
return
179+
}
180+
181+
try {
182+
await navigator.clipboard.writeText(textContent)
183+
toast({
184+
title: '已复制完整 Prompt',
185+
description: selected ? `${selected.stage}/${selected.session_id}/${selected.stem}` : undefined,
186+
})
187+
} catch (err) {
188+
toast({
189+
title: '复制失败',
190+
description: err instanceof Error ? err.message : '请手动选择文本复制',
191+
variant: 'destructive',
192+
})
193+
}
194+
}
195+
168196
return (
169197
<div className="flex h-full min-h-0 flex-col gap-3 overflow-hidden p-3 lg:p-4">
170198
<div className="flex flex-col gap-2 lg:flex-row lg:items-center lg:justify-between">
@@ -328,6 +356,17 @@ export function ReasoningProcessPage() {
328356
</div>
329357
{selected && (
330358
<div className="flex items-center gap-2 text-xs text-muted-foreground">
359+
<Button
360+
variant="outline"
361+
size="sm"
362+
className="h-8 gap-1.5"
363+
onClick={handleCopyPrompt}
364+
disabled={!selected.text_path || contentLoading || !textContent}
365+
title="复制完整 Prompt"
366+
>
367+
<Copy className="h-3.5 w-3.5" />
368+
复制
369+
</Button>
331370
{selected.text_path && (
332371
<span className="inline-flex items-center gap-1">
333372
<FileText className="h-3.5 w-3.5" />

0 commit comments

Comments
 (0)