Merge branch 'dev' of https://github.com/Mai-with-u/MaiBot into dev
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "maibot-dashboard",
|
"name": "maibot-dashboard",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* 修改此处的版本号后,所有展示版本的地方都会自动更新
|
* 修改此处的版本号后,所有展示版本的地方都会自动更新
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const APP_VERSION = '1.0.1'
|
export const APP_VERSION = '1.0.2'
|
||||||
export const APP_NAME = 'MaiBot Dashboard'
|
export const APP_NAME = 'MaiBot Dashboard'
|
||||||
export const APP_FULL_NAME = `${APP_NAME} v${APP_VERSION}`
|
export const APP_FULL_NAME = `${APP_NAME} v${APP_VERSION}`
|
||||||
|
|
||||||
|
|||||||
@@ -85,11 +85,11 @@ const modelConfigRoute = createRoute({
|
|||||||
component: lazyRouteComponent(() => import('./routes/config/model'), 'ModelConfigPage'),
|
component: lazyRouteComponent(() => import('./routes/config/model'), 'ModelConfigPage'),
|
||||||
})
|
})
|
||||||
|
|
||||||
// 配置路由 - 麦麦适配器配置
|
// 配置路由 - 麦麦适配器配置(已停用,引导跳转到插件配置;旧实现保留在 ./routes/config/adapter)
|
||||||
const adapterConfigRoute = createRoute({
|
const adapterConfigRoute = createRoute({
|
||||||
getParentRoute: () => protectedRoute,
|
getParentRoute: () => protectedRoute,
|
||||||
path: '/config/adapter',
|
path: '/config/adapter',
|
||||||
component: lazyRouteComponent(() => import('./routes/config/adapter'), 'AdapterConfigPage'),
|
component: lazyRouteComponent(() => import('./routes/config/adapter-disabled'), 'AdapterConfigPage'),
|
||||||
})
|
})
|
||||||
|
|
||||||
// 资源管理路由 - 表情包管理
|
// 资源管理路由 - 表情包管理
|
||||||
|
|||||||
60
dashboard/src/routes/config/adapter-disabled.tsx
Normal file
60
dashboard/src/routes/config/adapter-disabled.tsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { Link } from '@tanstack/react-router'
|
||||||
|
import { ArrowRight, Info } from 'lucide-react'
|
||||||
|
|
||||||
|
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from '@/components/ui/card'
|
||||||
|
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 麦麦适配器配置 —— 禁用页
|
||||||
|
*
|
||||||
|
* 原页面({@link import('./adapter').AdapterConfigPage})的能力已迁移至
|
||||||
|
* 「插件配置」中的对应适配器插件。这里保留路由占位并引导用户跳转,
|
||||||
|
* 避免误用旧的 TOML 直接编辑路径。
|
||||||
|
*/
|
||||||
|
export function AdapterConfigPage() {
|
||||||
|
return (
|
||||||
|
<ScrollArea className="h-full">
|
||||||
|
<div className="mx-auto w-full max-w-3xl space-y-4 p-4 sm:space-y-6 sm:p-6">
|
||||||
|
<div>
|
||||||
|
<h1 className="text-2xl font-bold sm:text-3xl">麦麦适配器配置</h1>
|
||||||
|
<p className="text-muted-foreground mt-1 text-sm sm:mt-2 sm:text-base">
|
||||||
|
该界面已停用
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Alert>
|
||||||
|
<Info className="h-4 w-4" />
|
||||||
|
<AlertTitle>该配置入口已迁移</AlertTitle>
|
||||||
|
<AlertDescription>
|
||||||
|
适配器现已作为插件管理。请前往「插件配置」找到对应适配器插件(如 Napcat 适配器)进行配置。
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>请前往插件配置</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
在插件配置页面中,选择目标适配器插件即可修改其配置项。原适配器 TOML 直接编辑入口已停用,但相关代码与历史配置文件未被删除,可在需要时由开发者手动恢复。
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<Button asChild>
|
||||||
|
<Link to="/plugin-config">
|
||||||
|
打开插件配置
|
||||||
|
<ArrowRight className="ml-2 h-4 w-4" />
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ interface InstalledTabProps {
|
|||||||
checkPluginCompatibility: (plugin: PluginInfo) => boolean
|
checkPluginCompatibility: (plugin: PluginInfo) => boolean
|
||||||
needsUpdate: (plugin: PluginInfo) => boolean
|
needsUpdate: (plugin: PluginInfo) => boolean
|
||||||
getStatusBadge: (plugin: PluginInfo) => React.JSX.Element | null
|
getStatusBadge: (plugin: PluginInfo) => React.JSX.Element | null
|
||||||
|
getIncompatibleReason: (plugin: PluginInfo) => string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InstalledTab({
|
export function InstalledTab({
|
||||||
@@ -33,6 +34,7 @@ export function InstalledTab({
|
|||||||
checkPluginCompatibility,
|
checkPluginCompatibility,
|
||||||
needsUpdate,
|
needsUpdate,
|
||||||
getStatusBadge,
|
getStatusBadge,
|
||||||
|
getIncompatibleReason,
|
||||||
}: InstalledTabProps) {
|
}: InstalledTabProps) {
|
||||||
// 过滤已安装插件
|
// 过滤已安装插件
|
||||||
const filteredPlugins = plugins.filter(plugin => {
|
const filteredPlugins = plugins.filter(plugin => {
|
||||||
@@ -80,6 +82,7 @@ export function InstalledTab({
|
|||||||
checkPluginCompatibility={checkPluginCompatibility}
|
checkPluginCompatibility={checkPluginCompatibility}
|
||||||
needsUpdate={needsUpdate}
|
needsUpdate={needsUpdate}
|
||||||
getStatusBadge={getStatusBadge}
|
getStatusBadge={getStatusBadge}
|
||||||
|
getIncompatibleReason={getIncompatibleReason}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ interface MarketplaceTabProps {
|
|||||||
checkPluginCompatibility: (plugin: PluginInfo) => boolean
|
checkPluginCompatibility: (plugin: PluginInfo) => boolean
|
||||||
needsUpdate: (plugin: PluginInfo) => boolean
|
needsUpdate: (plugin: PluginInfo) => boolean
|
||||||
getStatusBadge: (plugin: PluginInfo) => React.JSX.Element | null
|
getStatusBadge: (plugin: PluginInfo) => React.JSX.Element | null
|
||||||
|
getIncompatibleReason: (plugin: PluginInfo) => string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MarketplaceTab({
|
export function MarketplaceTab({
|
||||||
@@ -33,6 +34,7 @@ export function MarketplaceTab({
|
|||||||
checkPluginCompatibility,
|
checkPluginCompatibility,
|
||||||
needsUpdate,
|
needsUpdate,
|
||||||
getStatusBadge,
|
getStatusBadge,
|
||||||
|
getIncompatibleReason,
|
||||||
}: MarketplaceTabProps) {
|
}: MarketplaceTabProps) {
|
||||||
// 过滤插件
|
// 过滤插件
|
||||||
const filteredPlugins = plugins.filter(plugin => {
|
const filteredPlugins = plugins.filter(plugin => {
|
||||||
@@ -76,6 +78,7 @@ export function MarketplaceTab({
|
|||||||
checkPluginCompatibility={checkPluginCompatibility}
|
checkPluginCompatibility={checkPluginCompatibility}
|
||||||
needsUpdate={needsUpdate}
|
needsUpdate={needsUpdate}
|
||||||
getStatusBadge={getStatusBadge}
|
getStatusBadge={getStatusBadge}
|
||||||
|
getIncompatibleReason={getIncompatibleReason}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ interface PluginCardProps {
|
|||||||
checkPluginCompatibility: (plugin: PluginInfo) => boolean
|
checkPluginCompatibility: (plugin: PluginInfo) => boolean
|
||||||
needsUpdate: (plugin: PluginInfo) => boolean
|
needsUpdate: (plugin: PluginInfo) => boolean
|
||||||
getStatusBadge: (plugin: PluginInfo) => React.JSX.Element | null
|
getStatusBadge: (plugin: PluginInfo) => React.JSX.Element | null
|
||||||
|
getIncompatibleReason: (plugin: PluginInfo) => string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PluginCard({
|
export function PluginCard({
|
||||||
@@ -34,6 +35,7 @@ export function PluginCard({
|
|||||||
checkPluginCompatibility,
|
checkPluginCompatibility,
|
||||||
needsUpdate,
|
needsUpdate,
|
||||||
getStatusBadge,
|
getStatusBadge,
|
||||||
|
getIncompatibleReason,
|
||||||
}: PluginCardProps) {
|
}: PluginCardProps) {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
@@ -114,8 +116,14 @@ export function PluginCard({
|
|||||||
needsUpdate(plugin) ? (
|
needsUpdate(plugin) ? (
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
disabled={!gitStatus?.installed}
|
disabled={!gitStatus?.installed || (maimaiVersion !== null && !checkPluginCompatibility(plugin))}
|
||||||
title={!gitStatus?.installed ? 'Git 未安装' : undefined}
|
title={
|
||||||
|
!gitStatus?.installed
|
||||||
|
? 'Git 未安装'
|
||||||
|
: (maimaiVersion !== null && !checkPluginCompatibility(plugin))
|
||||||
|
? (getIncompatibleReason(plugin) ?? '插件与当前麦麦版本不兼容')
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
onClick={() => onUpdate(plugin)}
|
onClick={() => onUpdate(plugin)}
|
||||||
>
|
>
|
||||||
<RefreshCw className="h-4 w-4 mr-1" />
|
<RefreshCw className="h-4 w-4 mr-1" />
|
||||||
@@ -145,7 +153,7 @@ export function PluginCard({
|
|||||||
!gitStatus?.installed
|
!gitStatus?.installed
|
||||||
? 'Git 未安装'
|
? 'Git 未安装'
|
||||||
: (maimaiVersion !== null && !checkPluginCompatibility(plugin))
|
: (maimaiVersion !== null && !checkPluginCompatibility(plugin))
|
||||||
? `不兼容当前版本 (需要 ${plugin.manifest?.host_application?.min_version || '未知'}${plugin.manifest?.host_application?.max_version ? ` - ${plugin.manifest.host_application.max_version}` : '+'},当前 ${maimaiVersion?.version})`
|
? (getIncompatibleReason(plugin) ?? '插件与当前麦麦版本不兼容')
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
onClick={() => onInstall(plugin)}
|
onClick={() => onInstall(plugin)}
|
||||||
|
|||||||
@@ -268,8 +268,8 @@ function PluginsPageContent() {
|
|||||||
|
|
||||||
// 获取插件状态徽章
|
// 获取插件状态徽章
|
||||||
const getStatusBadge = (plugin: PluginInfo) => {
|
const getStatusBadge = (plugin: PluginInfo) => {
|
||||||
// 优先显示兼容性状态
|
// 优先显示兼容性状态(已安装但不兼容也需要提示,避免用户误以为可继续更新)
|
||||||
if (!plugin.installed && maimaiVersion && !checkPluginCompatibility(plugin)) {
|
if (maimaiVersion && !checkPluginCompatibility(plugin)) {
|
||||||
return (
|
return (
|
||||||
<Badge variant="destructive" className="gap-1">
|
<Badge variant="destructive" className="gap-1">
|
||||||
<AlertCircle className="h-3 w-3" />
|
<AlertCircle className="h-3 w-3" />
|
||||||
@@ -317,8 +317,19 @@ function PluginsPageContent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查插件兼容性
|
// 检查插件兼容性
|
||||||
|
// 规则:
|
||||||
|
// 1. manifest_version === 1 的插件在麦麦 >= 1.0.0 时一律视为不兼容(旧 manifest 已不再被宿主接受);
|
||||||
|
// 2. 否则若声明了 host_application 范围,则按版本范围判定。
|
||||||
const checkPluginCompatibility = (plugin: PluginInfo): boolean => {
|
const checkPluginCompatibility = (plugin: PluginInfo): boolean => {
|
||||||
if (!maimaiVersion || !plugin.manifest?.host_application) return true
|
if (!maimaiVersion) return true
|
||||||
|
|
||||||
|
// manifest v1 在 1.0.0+ 麦麦上不再兼容
|
||||||
|
const manifestVersion = plugin.manifest?.manifest_version ?? 1
|
||||||
|
if (manifestVersion <= 1 && maimaiVersion.version_major >= 1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!plugin.manifest?.host_application) return true
|
||||||
|
|
||||||
return isPluginCompatible(
|
return isPluginCompatible(
|
||||||
plugin.manifest.host_application.min_version,
|
plugin.manifest.host_application.min_version,
|
||||||
@@ -327,11 +338,35 @@ function PluginsPageContent() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 不兼容原因(用于 UI 提示)
|
||||||
|
const getIncompatibleReason = (plugin: PluginInfo): string | null => {
|
||||||
|
if (!maimaiVersion) return null
|
||||||
|
const manifestVersion = plugin.manifest?.manifest_version ?? 1
|
||||||
|
if (manifestVersion <= 1 && maimaiVersion.version_major >= 1) {
|
||||||
|
return `该插件使用旧版 manifest (v${manifestVersion}),已不被麦麦 ${maimaiVersion.version} 支持`
|
||||||
|
}
|
||||||
|
if (plugin.manifest?.host_application && !isPluginCompatible(
|
||||||
|
plugin.manifest.host_application.min_version,
|
||||||
|
plugin.manifest.host_application.max_version,
|
||||||
|
maimaiVersion
|
||||||
|
)) {
|
||||||
|
const min = plugin.manifest.host_application.min_version || '未知'
|
||||||
|
const max = plugin.manifest.host_application.max_version
|
||||||
|
const range = max ? `${min} - ${max}` : `${min}+`
|
||||||
|
return `不兼容当前版本 (需要 ${range},当前 ${maimaiVersion.version})`
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否需要更新(市场版本比已安装版本新)
|
// 检查是否需要更新(市场版本比已安装版本新)
|
||||||
const needsUpdate = (plugin: PluginInfo): boolean => {
|
const needsUpdate = (plugin: PluginInfo): boolean => {
|
||||||
if (!plugin.installed || !plugin.installed_version || !plugin.manifest?.version) {
|
if (!plugin.installed || !plugin.installed_version || !plugin.manifest?.version) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
// 不兼容的插件不允许更新
|
||||||
|
if (!checkPluginCompatibility(plugin)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
const installedVer = plugin.installed_version.trim()
|
const installedVer = plugin.installed_version.trim()
|
||||||
const marketVer = plugin.manifest.version.trim()
|
const marketVer = plugin.manifest.version.trim()
|
||||||
@@ -368,7 +403,7 @@ function PluginsPageContent() {
|
|||||||
if (maimaiVersion && !checkPluginCompatibility(plugin)) {
|
if (maimaiVersion && !checkPluginCompatibility(plugin)) {
|
||||||
toast({
|
toast({
|
||||||
title: '无法安装',
|
title: '无法安装',
|
||||||
description: '插件与当前麦麦版本不兼容',
|
description: getIncompatibleReason(plugin) ?? '插件与当前麦麦版本不兼容',
|
||||||
variant: 'destructive',
|
variant: 'destructive',
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -526,6 +561,16 @@ function PluginsPageContent() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 不兼容的插件不允许更新
|
||||||
|
if (maimaiVersion && !checkPluginCompatibility(plugin)) {
|
||||||
|
toast({
|
||||||
|
title: '无法更新',
|
||||||
|
description: getIncompatibleReason(plugin) ?? '插件与当前麦麦版本不兼容',
|
||||||
|
variant: 'destructive',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const updateResult = await updatePlugin(
|
const updateResult = await updatePlugin(
|
||||||
plugin.id,
|
plugin.id,
|
||||||
@@ -833,6 +878,7 @@ function PluginsPageContent() {
|
|||||||
checkPluginCompatibility={checkPluginCompatibility}
|
checkPluginCompatibility={checkPluginCompatibility}
|
||||||
needsUpdate={needsUpdate}
|
needsUpdate={needsUpdate}
|
||||||
getStatusBadge={getStatusBadge}
|
getStatusBadge={getStatusBadge}
|
||||||
|
getIncompatibleReason={getIncompatibleReason}
|
||||||
/>
|
/>
|
||||||
) : activeTab === 'installed' ? (
|
) : activeTab === 'installed' ? (
|
||||||
<InstalledTab
|
<InstalledTab
|
||||||
@@ -850,6 +896,7 @@ function PluginsPageContent() {
|
|||||||
checkPluginCompatibility={checkPluginCompatibility}
|
checkPluginCompatibility={checkPluginCompatibility}
|
||||||
needsUpdate={needsUpdate}
|
needsUpdate={needsUpdate}
|
||||||
getStatusBadge={getStatusBadge}
|
getStatusBadge={getStatusBadge}
|
||||||
|
getIncompatibleReason={getIncompatibleReason}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ dependencies = [
|
|||||||
"json-repair>=0.47.6",
|
"json-repair>=0.47.6",
|
||||||
"maim-message>=0.6.2",
|
"maim-message>=0.6.2",
|
||||||
"maibot-dashboard==1.0.1.dev2026050251",
|
"maibot-dashboard==1.0.1.dev2026050251",
|
||||||
"maibot-plugin-sdk>=2.3.0",
|
"maibot-plugin-sdk>=2.4.0",
|
||||||
"matplotlib>=3.10.5",
|
"matplotlib>=3.10.5",
|
||||||
"mcp",
|
"mcp",
|
||||||
"msgpack>=1.1.2",
|
"msgpack>=1.1.2",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ httpx
|
|||||||
jieba>=0.42.1
|
jieba>=0.42.1
|
||||||
json-repair>=0.47.6
|
json-repair>=0.47.6
|
||||||
maim-message>=0.6.2
|
maim-message>=0.6.2
|
||||||
maibot-plugin-sdk>=1.2.3,<2.0.0
|
maibot-plugin-sdk>=2.4.0
|
||||||
mcp
|
mcp
|
||||||
msgpack>=1.1.2
|
msgpack>=1.1.2
|
||||||
numpy>=2.2.6
|
numpy>=2.2.6
|
||||||
|
|||||||
Reference in New Issue
Block a user