refactor(dashboard): migrate plugin-api HTTP functions to ApiResponse pattern

- Migrate 14 HTTP functions in plugin-api.ts to return ApiResponse<T>
  - fetchPluginList, checkGitStatus, getMaimaiVersion
  - getInstalledPlugins, installPlugin, uninstallPlugin, updatePlugin
  - getPluginConfigSchema, getPluginConfig, getPluginConfigRaw
  - updatePluginConfig, updatePluginConfigRaw, resetPluginConfig, togglePlugin
- Update 3 caller files to handle ApiResponse pattern:
  - plugins.tsx: 5 function calls updated
  - plugin-config.tsx: 5 function calls updated
  - plugin-detail.tsx: 5 function calls updated
- All callers now check .success before accessing .data
- Preserve WebSocket and utility functions unchanged
- Build verification: npm run build succeeds with 0 errors
This commit is contained in:
DrSmoothl
2026-03-01 18:06:25 +08:00
parent d4bfc9591c
commit dc7e037582
4 changed files with 446 additions and 269 deletions

View File

@@ -1,6 +1,8 @@
import { fetchWithAuth, getAuthHeaders } from '@/lib/fetch-with-auth' import type { ApiResponse } from '@/types/api'
import type { PluginInfo } from '@/types/plugin' import type { PluginInfo } from '@/types/plugin'
import { fetchWithAuth, getAuthHeaders } from '@/lib/fetch-with-auth'
import { parseResponse } from './api-helpers'
import { createReconnectingWebSocket } from './ws-utils' import { createReconnectingWebSocket } from './ws-utils'
/** /**
@@ -106,12 +108,9 @@ interface PluginApiResponse {
/** /**
* 从远程获取插件列表(通过后端代理避免 CORS * 从远程获取插件列表(通过后端代理避免 CORS
*/ */
export async function fetchPluginList(): Promise<PluginInfo[]> { export async function fetchPluginList(): Promise<ApiResponse<PluginInfo[]>> {
try {
// 通过后端 API 获取 Raw 文件
const response = await fetchWithAuth('/api/webui/plugins/fetch-raw', { const response = await fetchWithAuth('/api/webui/plugins/fetch-raw', {
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
owner: PLUGIN_REPO_OWNER, owner: PLUGIN_REPO_OWNER,
repo: PLUGIN_REPO_NAME, repo: PLUGIN_REPO_NAME,
@@ -120,23 +119,24 @@ export async function fetchPluginList(): Promise<PluginInfo[]> {
}) })
}) })
if (!response.ok) { const apiResult = await parseResponse<{ success: boolean; data: string; error?: string }>(response)
throw new Error(`HTTP error! status: ${response.status}`)
if (!apiResult.success) {
return apiResult
} }
const result = await response.json() const result = apiResult.data
// 检查后端返回的结果
if (!result.success || !result.data) { if (!result.success || !result.data) {
throw new Error(result.error || '获取插件列表失败') return {
success: false,
error: result.error || '获取插件列表失败'
}
} }
const data: PluginApiResponse[] = JSON.parse(result.data) const data: PluginApiResponse[] = JSON.parse(result.data)
// 转换为 PluginInfo 格式,并过滤掉无效数据
const pluginList = data const pluginList = data
.filter(item => { .filter(item => {
// 验证必需字段
if (!item?.id || !item?.manifest) { if (!item?.id || !item?.manifest) {
console.warn('跳过无效插件数据:', item) console.warn('跳过无效插件数据:', item)
return false return false
@@ -164,7 +164,6 @@ export async function fetchPluginList(): Promise<PluginInfo[]> {
default_locale: item.manifest.default_locale || 'zh-CN', default_locale: item.manifest.default_locale || 'zh-CN',
locales_path: item.manifest.locales_path, locales_path: item.manifest.locales_path,
}, },
// 默认值,这些信息可能需要从其他 API 获取
downloads: 0, downloads: 0,
rating: 0, rating: 0,
review_count: 0, review_count: 0,
@@ -173,57 +172,54 @@ export async function fetchPluginList(): Promise<PluginInfo[]> {
updated_at: new Date().toISOString(), updated_at: new Date().toISOString(),
})) }))
return pluginList return {
} catch (error) { success: true,
console.error('Failed to fetch plugin list:', error) data: pluginList
throw error
} }
} }
/** /**
* 检查本机 Git 安装状态 * 检查本机 Git 安装状态
*/ */
export async function checkGitStatus(): Promise<GitStatus> { export async function checkGitStatus(): Promise<ApiResponse<GitStatus>> {
try {
const response = await fetchWithAuth('/api/webui/plugins/git-status') const response = await fetchWithAuth('/api/webui/plugins/git-status')
if (!response.ok) { const apiResult = await parseResponse<GitStatus>(response)
throw new Error(`HTTP error! status: ${response.status}`)
}
return await response.json() if (!apiResult.success) {
} catch (error) {
console.error('Failed to check Git status:', error)
// 返回未安装状态
return { return {
success: true,
data: {
installed: false, installed: false,
error: '无法检测 Git 安装状态' error: '无法检测 Git 安装状态'
} }
} }
}
return apiResult
} }
/** /**
* 获取麦麦版本信息 * 获取麦麦版本信息
*/ */
export async function getMaimaiVersion(): Promise<MaimaiVersion> { export async function getMaimaiVersion(): Promise<ApiResponse<MaimaiVersion>> {
try {
const response = await fetchWithAuth('/api/webui/plugins/version') const response = await fetchWithAuth('/api/webui/plugins/version')
if (!response.ok) { const apiResult = await parseResponse<MaimaiVersion>(response)
throw new Error(`HTTP error! status: ${response.status}`)
}
return await response.json() if (!apiResult.success) {
} catch (error) {
console.error('Failed to get Maimai version:', error)
// 返回默认版本
return { return {
success: true,
data: {
version: '0.0.0', version: '0.0.0',
version_major: 0, version_major: 0,
version_minor: 0, version_minor: 0,
version_patch: 0 version_patch: 0
} }
} }
}
return apiResult
} }
/** /**
@@ -318,26 +314,31 @@ export async function connectPluginProgressWebSocket(
/** /**
* 获取已安装插件列表 * 获取已安装插件列表
*/ */
export async function getInstalledPlugins(): Promise<InstalledPlugin[]> { export async function getInstalledPlugins(): Promise<ApiResponse<InstalledPlugin[]>> {
try {
const response = await fetchWithAuth('/api/webui/plugins/installed', { const response = await fetchWithAuth('/api/webui/plugins/installed', {
headers: getAuthHeaders() headers: getAuthHeaders()
}) })
if (!response.ok) { const apiResult = await parseResponse<{ success: boolean; plugins?: InstalledPlugin[]; message?: string }>(response)
throw new Error(`HTTP error! status: ${response.status}`)
if (!apiResult.success) {
return {
success: true,
data: []
}
} }
const result = await response.json() const result = apiResult.data
if (!result.success) { if (!result.success) {
throw new Error(result.message || '获取已安装插件列表失败') return {
success: true,
data: []
}
} }
return result.plugins || [] return {
} catch (error) { success: true,
console.error('Failed to get installed plugins:', error) data: result.plugins || []
return []
} }
} }
@@ -363,10 +364,9 @@ export function getInstalledPluginVersion(pluginId: string, installedPlugins: In
/** /**
* 安装插件 * 安装插件
*/ */
export async function installPlugin(pluginId: string, repositoryUrl: string, branch: string = 'main'): Promise<{ success: boolean; message: string }> { export async function installPlugin(pluginId: string, repositoryUrl: string, branch: string = 'main'): Promise<ApiResponse<{ success: boolean; message: string }>> {
const response = await fetchWithAuth('/api/webui/plugins/install', { const response = await fetchWithAuth('/api/webui/plugins/install', {
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
plugin_id: pluginId, plugin_id: pluginId,
repository_url: repositoryUrl, repository_url: repositoryUrl,
@@ -374,41 +374,29 @@ export async function installPlugin(pluginId: string, repositoryUrl: string, bra
}) })
}) })
if (!response.ok) { return await parseResponse<{ success: boolean; message: string }>(response)
const error = await response.json()
throw new Error(error.detail || '安装失败')
}
return await response.json()
} }
/** /**
* 卸载插件 * 卸载插件
*/ */
export async function uninstallPlugin(pluginId: string): Promise<{ success: boolean; message: string }> { export async function uninstallPlugin(pluginId: string): Promise<ApiResponse<{ success: boolean; message: string }>> {
const response = await fetchWithAuth('/api/webui/plugins/uninstall', { const response = await fetchWithAuth('/api/webui/plugins/uninstall', {
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
plugin_id: pluginId plugin_id: pluginId
}) })
}) })
if (!response.ok) { return await parseResponse<{ success: boolean; message: string }>(response)
const error = await response.json()
throw new Error(error.detail || '卸载失败')
}
return await response.json()
} }
/** /**
* 更新插件 * 更新插件
*/ */
export async function updatePlugin(pluginId: string, repositoryUrl: string, branch: string = 'main'): Promise<{ success: boolean; message: string; old_version: string; new_version: string }> { export async function updatePlugin(pluginId: string, repositoryUrl: string, branch: string = 'main'): Promise<ApiResponse<{ success: boolean; message: string; old_version: string; new_version: string }>> {
const response = await fetchWithAuth('/api/webui/plugins/update', { const response = await fetchWithAuth('/api/webui/plugins/update', {
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
plugin_id: pluginId, plugin_id: pluginId,
repository_url: repositoryUrl, repository_url: repositoryUrl,
@@ -416,12 +404,7 @@ export async function updatePlugin(pluginId: string, repositoryUrl: string, bran
}) })
}) })
if (!response.ok) { return await parseResponse<{ success: boolean; message: string; old_version: string; new_version: string }>(response)
const error = await response.json()
throw new Error(error.detail || '更新失败')
}
return await response.json()
} }
@@ -525,82 +508,85 @@ export interface PluginConfigSchema {
/** /**
* 获取插件配置 Schema * 获取插件配置 Schema
*/ */
export async function getPluginConfigSchema(pluginId: string): Promise<PluginConfigSchema> { export async function getPluginConfigSchema(pluginId: string): Promise<ApiResponse<PluginConfigSchema>> {
const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}/schema`, { const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}/schema`, {
headers: getAuthHeaders() headers: getAuthHeaders()
}) })
if (!response.ok) { const apiResult = await parseResponse<{ success: boolean; schema?: PluginConfigSchema; message?: string }>(response)
const text = await response.text()
try { if (!apiResult.success) {
const error = JSON.parse(text) return apiResult
throw new Error(error.detail || '获取配置 Schema 失败') }
} catch {
throw new Error(`获取配置 Schema 失败 (${response.status})`) const result = apiResult.data
if (!result.success || !result.schema) {
return {
success: false,
error: result.message || '获取配置 Schema 失败'
} }
} }
const result = await response.json() return {
success: true,
if (!result.success) { data: result.schema
throw new Error(result.message || '获取配置 Schema 失败')
} }
return result.schema
} }
/** /**
* 获取插件当前配置值 * 获取插件当前配置值
*/ */
export async function getPluginConfig(pluginId: string): Promise<Record<string, unknown>> { export async function getPluginConfig(pluginId: string): Promise<ApiResponse<Record<string, unknown>>> {
const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}`, { const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}`, {
headers: getAuthHeaders() headers: getAuthHeaders()
}) })
if (!response.ok) { const apiResult = await parseResponse<{ success: boolean; config?: Record<string, unknown>; message?: string }>(response)
const text = await response.text()
try { if (!apiResult.success) {
const error = JSON.parse(text) return apiResult
throw new Error(error.detail || '获取配置失败') }
} catch {
throw new Error(`获取配置失败 (${response.status})`) const result = apiResult.data
if (!result.success || !result.config) {
return {
success: false,
error: result.message || '获取配置失败'
} }
} }
const result = await response.json() return {
success: true,
if (!result.success) { data: result.config
throw new Error(result.message || '获取配置失败')
} }
return result.config
} }
/** /**
* 获取插件原始 TOML 配置 * 获取插件原始 TOML 配置
*/ */
export async function getPluginConfigRaw(pluginId: string): Promise<string> { export async function getPluginConfigRaw(pluginId: string): Promise<ApiResponse<string>> {
const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}/raw`, { const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}/raw`, {
headers: getAuthHeaders() headers: getAuthHeaders()
}) })
if (!response.ok) { const apiResult = await parseResponse<{ success: boolean; config?: string; message?: string }>(response)
const text = await response.text()
try { if (!apiResult.success) {
const error = JSON.parse(text) return apiResult
throw new Error(error.detail || '获取配置失败') }
} catch {
throw new Error(`获取配置失败 (${response.status})`) const result = apiResult.data
if (!result.success || !result.config) {
return {
success: false,
error: result.message || '获取配置失败'
} }
} }
const result = await response.json() return {
success: true,
if (!result.success) { data: result.config
throw new Error(result.message || '获取配置失败')
} }
return result.config
} }
/** /**
@@ -609,19 +595,14 @@ export async function getPluginConfigRaw(pluginId: string): Promise<string> {
export async function updatePluginConfig( export async function updatePluginConfig(
pluginId: string, pluginId: string,
config: Record<string, unknown> config: Record<string, unknown>
): Promise<{ success: boolean; message: string; note?: string }> { ): Promise<ApiResponse<{ success: boolean; message: string; note?: string }>> {
const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}`, { const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}`, {
method: 'PUT', method: 'PUT',
headers: getAuthHeaders(), headers: getAuthHeaders(),
body: JSON.stringify({ config }) body: JSON.stringify({ config })
}) })
if (!response.ok) { return await parseResponse<{ success: boolean; message: string; note?: string }>(response)
const error = await response.json()
throw new Error(error.detail || '保存配置失败')
}
return await response.json()
} }
/** /**
@@ -630,19 +611,14 @@ export async function updatePluginConfig(
export async function updatePluginConfigRaw( export async function updatePluginConfigRaw(
pluginId: string, pluginId: string,
configToml: string configToml: string
): Promise<{ success: boolean; message: string; note?: string }> { ): Promise<ApiResponse<{ success: boolean; message: string; note?: string }>> {
const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}/raw`, { const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}/raw`, {
method: 'PUT', method: 'PUT',
headers: getAuthHeaders(), headers: getAuthHeaders(),
body: JSON.stringify({ config: configToml }) body: JSON.stringify({ config: configToml })
}) })
if (!response.ok) { return await parseResponse<{ success: boolean; message: string; note?: string }>(response)
const error = await response.json()
throw new Error(error.detail || '保存配置失败')
}
return await response.json()
} }
/** /**
@@ -650,18 +626,13 @@ export async function updatePluginConfigRaw(
*/ */
export async function resetPluginConfig( export async function resetPluginConfig(
pluginId: string pluginId: string
): Promise<{ success: boolean; message: string; backup?: string }> { ): Promise<ApiResponse<{ success: boolean; message: string; backup?: string }>> {
const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}/reset`, { const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}/reset`, {
method: 'POST', method: 'POST',
headers: getAuthHeaders() headers: getAuthHeaders()
}) })
if (!response.ok) { return await parseResponse<{ success: boolean; message: string; backup?: string }>(response)
const error = await response.json()
throw new Error(error.detail || '重置配置失败')
}
return await response.json()
} }
/** /**
@@ -669,16 +640,11 @@ export async function resetPluginConfig(
*/ */
export async function togglePlugin( export async function togglePlugin(
pluginId: string pluginId: string
): Promise<{ success: boolean; enabled: boolean; message: string; note?: string }> { ): Promise<ApiResponse<{ success: boolean; enabled: boolean; message: string; note?: string }>> {
const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}/toggle`, { const response = await fetchWithAuth(`/api/webui/plugins/config/${pluginId}/toggle`, {
method: 'POST', method: 'POST',
headers: getAuthHeaders() headers: getAuthHeaders()
}) })
if (!response.ok) { return await parseResponse<{ success: boolean; enabled: boolean; message: string; note?: string }>(response)
const error = await response.json()
throw new Error(error.detail || '切换状态失败')
}
return await response.json()
} }

View File

@@ -341,16 +341,44 @@ function PluginConfigEditor({ plugin, onBack }: PluginConfigEditorProps) {
const loadConfig = useCallback(async () => { const loadConfig = useCallback(async () => {
setLoading(true) setLoading(true)
try { try {
const [schemaData, configData, rawConfigData] = await Promise.all([ const [schemaResult, configResult, rawResult] = await Promise.all([
getPluginConfigSchema(plugin.id), getPluginConfigSchema(plugin.id),
getPluginConfig(plugin.id), getPluginConfig(plugin.id),
getPluginConfigRaw(plugin.id) getPluginConfigRaw(plugin.id)
]) ])
setSchema(schemaData)
setConfig(configData) if (!schemaResult.success) {
setOriginalConfig(JSON.parse(JSON.stringify(configData))) toast({
setSourceCode(rawConfigData) title: '加载配置架构失败',
setOriginalSourceCode(rawConfigData) description: schemaResult.error,
variant: 'destructive'
})
return
}
if (!configResult.success) {
toast({
title: '加载配置数据失败',
description: configResult.error,
variant: 'destructive'
})
return
}
if (!rawResult.success) {
toast({
title: '加载原始配置失败',
description: rawResult.error,
variant: 'destructive'
})
return
}
setSchema(schemaResult.data)
setConfig(configResult.data)
setOriginalConfig(JSON.parse(JSON.stringify(configResult.data)))
setSourceCode(rawResult.data)
setOriginalSourceCode(rawResult.data)
} catch (error) { } catch (error) {
toast({ toast({
title: '加载配置失败', title: '加载配置失败',
@@ -433,7 +461,15 @@ function PluginConfigEditor({ plugin, onBack }: PluginConfigEditorProps) {
// 重置配置 // 重置配置
const handleReset = async () => { const handleReset = async () => {
try { try {
await resetPluginConfig(plugin.id) const resetResult = await resetPluginConfig(plugin.id)
if (!resetResult.success) {
toast({
title: '重置失败',
description: resetResult.error,
variant: 'destructive'
})
return
}
toast({ toast({
title: '配置已重置', title: '配置已重置',
description: '下次加载插件时将使用默认配置' description: '下次加载插件时将使用默认配置'
@@ -452,10 +488,18 @@ function PluginConfigEditor({ plugin, onBack }: PluginConfigEditorProps) {
// 切换启用状态 // 切换启用状态
const handleToggle = async () => { const handleToggle = async () => {
try { try {
const result = await togglePlugin(plugin.id) const toggleResult = await togglePlugin(plugin.id)
if (!toggleResult.success) {
toast({ toast({
title: result.message, title: '切换失败',
description: result.note description: toggleResult.error,
variant: 'destructive'
})
return
}
toast({
title: toggleResult.data.message,
description: toggleResult.data.note
}) })
loadConfig() loadConfig()
} catch (error) { } catch (error) {
@@ -723,8 +767,16 @@ function PluginConfigPageContent() {
const loadPlugins = async () => { const loadPlugins = async () => {
setLoading(true) setLoading(true)
try { try {
const data = await getInstalledPlugins() const installedResult = await getInstalledPlugins()
setPlugins(data) if (!installedResult.success) {
toast({
title: '加载插件列表失败',
description: installedResult.error,
variant: 'destructive'
})
return
}
setPlugins(installedResult.data)
} catch (error) { } catch (error) {
toast({ toast({
title: '加载插件列表失败', title: '加载插件列表失败',

View File

@@ -131,10 +131,37 @@ export function PluginDetailPage() {
getInstalledPlugins(), getInstalledPlugins(),
]) ])
setGitStatus(gitStatusResult) if (!gitStatusResult.success) {
setMaimaiVersion(versionResult) toast({
setIsInstalled(checkPluginInstalled(search.pluginId, installedPlugins)) title: 'Git 状态检查失败',
setInstalledVersion(getInstalledPluginVersion(search.pluginId, installedPlugins)) description: gitStatusResult.error,
variant: 'destructive',
})
} else {
setGitStatus(gitStatusResult.data)
}
if (!versionResult.success) {
toast({
title: '版本获取失败',
description: versionResult.error,
variant: 'destructive',
})
} else {
setMaimaiVersion(versionResult.data)
}
if (!installedPlugins.success) {
toast({
title: '获取已安装插件失败',
description: installedPlugins.error,
variant: 'destructive',
})
return
}
setIsInstalled(checkPluginInstalled(search.pluginId, installedPlugins.data))
setInstalledVersion(getInstalledPluginVersion(search.pluginId, installedPlugins.data))
} catch (err) { } catch (err) {
setError(err instanceof Error ? err.message : '加载失败') setError(err instanceof Error ? err.message : '加载失败')
} finally { } finally {
@@ -243,7 +270,16 @@ export function PluginDetailPage() {
try { try {
setOperating(true) setOperating(true)
await installPlugin(plugin.id, plugin.manifest.repository_url || '', 'main') const installResult = await installPlugin(plugin.id, plugin.manifest.repository_url || '', 'main')
if (!installResult.success) {
toast({
title: '安装失败',
description: installResult.error,
variant: 'destructive',
})
return
}
// 记录下载统计 // 记录下载统计
recordPluginDownload(plugin.id).catch((err) => { recordPluginDownload(plugin.id).catch((err) => {
@@ -256,9 +292,17 @@ export function PluginDetailPage() {
}) })
// 重新加载安装状态 // 重新加载安装状态
const installedPlugins = await getInstalledPlugins() const installedPluginsResult = await getInstalledPlugins()
setIsInstalled(checkPluginInstalled(plugin.id, installedPlugins)) if (!installedPluginsResult.success) {
setInstalledVersion(getInstalledPluginVersion(plugin.id, installedPlugins)) toast({
title: '获取已安装插件失败',
description: installedPluginsResult.error,
variant: 'destructive',
})
return
}
setIsInstalled(checkPluginInstalled(plugin.id, installedPluginsResult.data))
setInstalledVersion(getInstalledPluginVersion(plugin.id, installedPluginsResult.data))
} catch (error) { } catch (error) {
toast({ toast({
title: '安装失败', title: '安装失败',
@@ -277,7 +321,16 @@ export function PluginDetailPage() {
try { try {
setOperating(true) setOperating(true)
await uninstallPlugin(plugin.id) const uninstallResult = await uninstallPlugin(plugin.id)
if (!uninstallResult.success) {
toast({
title: '卸载失败',
description: uninstallResult.error,
variant: 'destructive',
})
return
}
toast({ toast({
title: '卸载成功', title: '卸载成功',
@@ -285,9 +338,17 @@ export function PluginDetailPage() {
}) })
// 重新加载安装状态 // 重新加载安装状态
const installedPlugins = await getInstalledPlugins() const installedPluginsResult = await getInstalledPlugins()
setIsInstalled(checkPluginInstalled(plugin.id, installedPlugins)) if (!installedPluginsResult.success) {
setInstalledVersion(getInstalledPluginVersion(plugin.id, installedPlugins)) toast({
title: '获取已安装插件失败',
description: installedPluginsResult.error,
variant: 'destructive',
})
return
}
setIsInstalled(checkPluginInstalled(plugin.id, installedPluginsResult.data))
setInstalledVersion(getInstalledPluginVersion(plugin.id, installedPluginsResult.data))
} catch (error) { } catch (error) {
toast({ toast({
title: '卸载失败', title: '卸载失败',
@@ -306,17 +367,34 @@ export function PluginDetailPage() {
try { try {
setOperating(true) setOperating(true)
const result = await updatePlugin(plugin.id, plugin.manifest.repository_url || '', 'main') const updateResult = await updatePlugin(plugin.id, plugin.manifest.repository_url || '', 'main')
if (!updateResult.success) {
toast({
title: '更新失败',
description: updateResult.error,
variant: 'destructive',
})
return
}
toast({ toast({
title: '更新成功', title: '更新成功',
description: `${plugin.manifest.name} 已从 ${result.old_version} 更新到 ${result.new_version}`, description: `${plugin.manifest.name} 已从 ${updateResult.data.old_version} 更新到 ${updateResult.data.new_version}`,
}) })
// 重新加载安装状态 // 重新加载安装状态
const installedPlugins = await getInstalledPlugins() const installedPluginsResult = await getInstalledPlugins()
setIsInstalled(checkPluginInstalled(plugin.id, installedPlugins)) if (!installedPluginsResult.success) {
setInstalledVersion(getInstalledPluginVersion(plugin.id, installedPlugins)) toast({
title: '获取已安装插件失败',
description: installedPluginsResult.error,
variant: 'destructive',
})
return
}
setIsInstalled(checkPluginInstalled(plugin.id, installedPluginsResult.data))
setInstalledVersion(getInstalledPluginVersion(plugin.id, installedPluginsResult.data))
} catch (error) { } catch (error) {
toast({ toast({
title: '更新失败', title: '更新失败',

View File

@@ -180,34 +180,71 @@ function PluginsPageContent() {
// 3. 检查 Git 状态 // 3. 检查 Git 状态
if (!isUnmounted) { if (!isUnmounted) {
const status = await checkGitStatus() const statusResult = await checkGitStatus()
setGitStatus(status) if (!statusResult.success) {
if (!status.installed) {
toast({ toast({
title: 'Git 未安装', title: 'Git 状态检查失败',
description: status.error || '请先安装 Git 才能使用插件安装功能', description: statusResult.error,
variant: 'destructive', variant: 'destructive',
}) })
setGitStatus({ installed: false, error: statusResult.error })
} else {
setGitStatus(statusResult.data)
if (!statusResult.data.installed) {
toast({
title: 'Git 未安装',
description: statusResult.data.error || '请先安装 Git 才能使用插件安装功能',
variant: 'destructive',
})
}
} }
} }
// 4. 获取麦麦版本 // 4. 获取麦麦版本
if (!isUnmounted) { if (!isUnmounted) {
const version = await getMaimaiVersion() const versionResult = await getMaimaiVersion()
setMaimaiVersion(version) if (!versionResult.success) {
toast({
title: '版本获取失败',
description: versionResult.error,
variant: 'destructive',
})
} else {
setMaimaiVersion(versionResult.data)
}
} }
// 5. 加载插件列表(包含已安装信息) // 5. 加载插件列表(包含已安装信息)
if (!isUnmounted) { if (!isUnmounted) {
try { try {
setLoading(true) setLoading(true)
setError(null) setError(null)
const data = await fetchPluginList() const apiResult = await fetchPluginList()
if (!apiResult.success) {
if (!isUnmounted) {
setError(apiResult.error)
toast({
title: '加载失败',
description: apiResult.error,
variant: 'destructive',
})
}
return
}
const data = apiResult.data
if (!isUnmounted) { if (!isUnmounted) {
// 获取已安装插件列表 // 获取已安装插件列表
const installed = await getInstalledPlugins() const installedResult = await getInstalledPlugins()
if (!installedResult.success) {
toast({
title: '获取已安装插件失败',
description: installedResult.error,
variant: 'destructive',
})
return
}
const installed = installedResult.data
setInstalledPlugins(installed) setInstalledPlugins(installed)
// 将已安装信息合并到插件数据中 // 将已安装信息合并到插件数据中
@@ -261,16 +298,6 @@ function PluginsPageContent() {
// 6. 加载所有插件的统计数据 // 6. 加载所有插件的统计数据
loadPluginStats(mergedData) loadPluginStats(mergedData)
} }
} catch (err) {
if (!isUnmounted) {
const errorMessage = err instanceof Error ? err.message : '加载插件列表失败'
setError(errorMessage)
toast({
title: '加载失败',
description: errorMessage,
variant: 'destructive',
})
}
} finally { } finally {
if (!isUnmounted) { if (!isUnmounted) {
setLoading(false) setLoading(false)
@@ -463,12 +490,21 @@ function PluginsPageContent() {
try { try {
setInstallDialogOpen(false) setInstallDialogOpen(false)
await installPlugin( const installResult = await installPlugin(
installingPlugin.id, installingPlugin.id,
installingPlugin.manifest.repository_url || '', installingPlugin.manifest.repository_url || '',
branch branch
) )
if (!installResult.success) {
toast({
title: '安装失败',
description: installResult.error,
variant: 'destructive',
})
return
}
// 记录下载统计 // 记录下载统计
recordPluginDownload(installingPlugin.id).catch(err => { recordPluginDownload(installingPlugin.id).catch(err => {
console.warn('Failed to record download:', err) console.warn('Failed to record download:', err)
@@ -480,7 +516,16 @@ function PluginsPageContent() {
}) })
// 重新加载已安装插件列表 // 重新加载已安装插件列表
const installed = await getInstalledPlugins() const installedResult = await getInstalledPlugins()
if (!installedResult.success) {
toast({
title: '获取已安装插件失败',
description: installedResult.error,
variant: 'destructive',
})
return
}
const installed = installedResult.data
setInstalledPlugins(installed) setInstalledPlugins(installed)
// 重新合并已安装信息到插件列表 // 重新合并已安装信息到插件列表
@@ -513,7 +558,16 @@ function PluginsPageContent() {
// 卸载插件处理 // 卸载插件处理
const handleUninstall = async (plugin: PluginInfo) => { const handleUninstall = async (plugin: PluginInfo) => {
try { try {
await uninstallPlugin(plugin.id) const uninstallResult = await uninstallPlugin(plugin.id)
if (!uninstallResult.success) {
toast({
title: '卸载失败',
description: uninstallResult.error,
variant: 'destructive',
})
return
}
toast({ toast({
title: '卸载成功', title: '卸载成功',
@@ -521,7 +575,16 @@ function PluginsPageContent() {
}) })
// 重新加载已安装插件列表 // 重新加载已安装插件列表
const installed = await getInstalledPlugins() const installedResult = await getInstalledPlugins()
if (!installedResult.success) {
toast({
title: '获取已安装插件失败',
description: installedResult.error,
variant: 'destructive',
})
return
}
const installed = installedResult.data
setInstalledPlugins(installed) setInstalledPlugins(installed)
// 重新合并已安装信息到插件列表 // 重新合并已安装信息到插件列表
@@ -561,19 +624,37 @@ function PluginsPageContent() {
} }
try { try {
const result = await updatePlugin( const updateResult = await updatePlugin(
plugin.id, plugin.id,
plugin.manifest.repository_url || '', plugin.manifest.repository_url || '',
'main' 'main'
) )
if (!updateResult.success) {
toast({
title: '更新失败',
description: updateResult.error,
variant: 'destructive',
})
return
}
toast({ toast({
title: '更新成功', title: '更新成功',
description: `${plugin.manifest.name} 已从 ${result.old_version} 更新到 ${result.new_version}`, description: `${plugin.manifest.name} 已从 ${updateResult.data.old_version} 更新到 ${updateResult.data.new_version}`,
}) })
// 重新加载已安装插件列表 // 重新加载已安装插件列表
const installed = await getInstalledPlugins() const installedResult = await getInstalledPlugins()
if (!installedResult.success) {
toast({
title: '获取已安装插件失败',
description: installedResult.error,
variant: 'destructive',
})
return
}
const installed = installedResult.data
setInstalledPlugins(installed) setInstalledPlugins(installed)
// 重新合并已安装信息到插件列表 // 重新合并已安装信息到插件列表