feat: 更新 CodeEditor 组件,重构为懒加载并添加 CodeEditorImpl,优化导入路径
This commit is contained in:
@@ -6,7 +6,7 @@ import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
import tseslint from 'typescript-eslint'
|
||||
|
||||
export default tseslint.config(
|
||||
{ ignores: ['dist'] },
|
||||
{ ignores: ['dist', 'out'] },
|
||||
jsxA11y.flatConfigs.recommended,
|
||||
{
|
||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||
@@ -25,10 +25,7 @@ export default tseslint.config(
|
||||
acc[key] = 'warn'
|
||||
return acc
|
||||
}, {}),
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
|
||||
// 关闭或降级其他规则
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
@@ -37,4 +34,11 @@ export default tseslint.config(
|
||||
'jsx-a11y/no-autofocus': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.d.ts'],
|
||||
rules: {
|
||||
// Ambient global declarations use `var` in TypeScript declaration files.
|
||||
'no-var': 'off',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,19 +1,8 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import CodeMirror from '@uiw/react-codemirror'
|
||||
import { css } from '@codemirror/lang-css'
|
||||
import { json, jsonParseLinter } from '@codemirror/lang-json'
|
||||
import { linter } from '@codemirror/lint'
|
||||
import { python } from '@codemirror/lang-python'
|
||||
import { oneDark } from '@codemirror/theme-one-dark'
|
||||
import { EditorView } from '@codemirror/view'
|
||||
import { StreamLanguage } from '@codemirror/language'
|
||||
import { toml as tomlMode } from '@codemirror/legacy-modes/mode/toml'
|
||||
|
||||
import { useTheme } from '@/components/use-theme'
|
||||
import { lazy, Suspense } from 'react'
|
||||
|
||||
export type Language = 'python' | 'json' | 'toml' | 'css' | 'text'
|
||||
|
||||
interface CodeEditorProps {
|
||||
export interface CodeEditorProps {
|
||||
value: string
|
||||
|
||||
onChange?: (value: string) => void
|
||||
@@ -27,109 +16,38 @@ interface CodeEditorProps {
|
||||
className?: string
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const languageExtensions: Record<Language, any[]> = {
|
||||
python: [python()],
|
||||
json: [json(), linter(jsonParseLinter())],
|
||||
toml: [StreamLanguage.define(tomlMode)],
|
||||
css: [css()],
|
||||
text: [],
|
||||
}
|
||||
const CodeEditorImpl = lazy(() => import('./CodeEditorImpl'))
|
||||
|
||||
export function CodeEditor({
|
||||
value,
|
||||
onChange,
|
||||
language = 'text',
|
||||
readOnly = false,
|
||||
height = '400px',
|
||||
function CodeEditorFallback({
|
||||
height,
|
||||
minHeight,
|
||||
maxHeight,
|
||||
placeholder,
|
||||
theme,
|
||||
className = '',
|
||||
}: CodeEditorProps) {
|
||||
const [mounted, setMounted] = useState(false)
|
||||
const { resolvedTheme } = useTheme()
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true)
|
||||
}, [])
|
||||
|
||||
if (!mounted) {
|
||||
}: Pick<CodeEditorProps, 'height' | 'minHeight' | 'maxHeight' | 'className'>) {
|
||||
return (
|
||||
<div
|
||||
className={`rounded-md border bg-muted animate-pulse ${className}`}
|
||||
className={`bg-muted animate-pulse rounded-md border ${className}`}
|
||||
style={{ height, minHeight, maxHeight }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const extensions = [
|
||||
...(languageExtensions[language] || []),
|
||||
EditorView.lineWrapping,
|
||||
// 应用 JetBrains Mono 字体
|
||||
EditorView.theme({
|
||||
'&': {
|
||||
fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", "Monaco", monospace',
|
||||
},
|
||||
'.cm-content': {
|
||||
fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", "Monaco", monospace',
|
||||
},
|
||||
'.cm-gutters': {
|
||||
fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", "Monaco", monospace',
|
||||
},
|
||||
'.cm-scroller': {
|
||||
fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", "Monaco", monospace',
|
||||
},
|
||||
}),
|
||||
]
|
||||
|
||||
if (readOnly) {
|
||||
extensions.push(EditorView.editable.of(false))
|
||||
}
|
||||
|
||||
// 如果外部传了 theme prop 则使用,否则从 context 自动获取
|
||||
const effectiveTheme = theme ?? resolvedTheme
|
||||
export function CodeEditor(props: CodeEditorProps) {
|
||||
const { height = '400px', minHeight, maxHeight, className = '' } = props
|
||||
|
||||
return (
|
||||
<div className={`rounded-md overflow-hidden border custom-scrollbar ${className}`}>
|
||||
<CodeMirror
|
||||
value={value}
|
||||
<Suspense
|
||||
fallback={
|
||||
<CodeEditorFallback
|
||||
height={height}
|
||||
minHeight={minHeight}
|
||||
maxHeight={maxHeight}
|
||||
theme={effectiveTheme === 'dark' ? oneDark : undefined}
|
||||
extensions={extensions}
|
||||
onChange={onChange}
|
||||
placeholder={placeholder}
|
||||
basicSetup={{
|
||||
lineNumbers: true,
|
||||
highlightActiveLineGutter: true,
|
||||
highlightSpecialChars: true,
|
||||
history: true,
|
||||
foldGutter: true,
|
||||
drawSelection: true,
|
||||
dropCursor: true,
|
||||
allowMultipleSelections: true,
|
||||
indentOnInput: true,
|
||||
syntaxHighlighting: true,
|
||||
bracketMatching: true,
|
||||
closeBrackets: true,
|
||||
autocompletion: true,
|
||||
rectangularSelection: true,
|
||||
crosshairCursor: true,
|
||||
highlightActiveLine: true,
|
||||
highlightSelectionMatches: true,
|
||||
closeBracketsKeymap: true,
|
||||
defaultKeymap: true,
|
||||
searchKeymap: true,
|
||||
historyKeymap: true,
|
||||
foldKeymap: true,
|
||||
completionKeymap: true,
|
||||
lintKeymap: true,
|
||||
}}
|
||||
className={className}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<CodeEditorImpl {...props} />
|
||||
</Suspense>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
105
dashboard/src/components/CodeEditorImpl.tsx
Normal file
105
dashboard/src/components/CodeEditorImpl.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
import { css } from '@codemirror/lang-css'
|
||||
import { json, jsonParseLinter } from '@codemirror/lang-json'
|
||||
import { python } from '@codemirror/lang-python'
|
||||
import { StreamLanguage } from '@codemirror/language'
|
||||
import { toml as tomlMode } from '@codemirror/legacy-modes/mode/toml'
|
||||
import { linter } from '@codemirror/lint'
|
||||
import { oneDark } from '@codemirror/theme-one-dark'
|
||||
import { EditorView } from '@codemirror/view'
|
||||
import CodeMirror from '@uiw/react-codemirror'
|
||||
|
||||
import { useTheme } from '@/components/use-theme'
|
||||
|
||||
import type { CodeEditorProps, Language } from './CodeEditor'
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const languageExtensions: Record<Language, any[]> = {
|
||||
python: [python()],
|
||||
json: [json(), linter(jsonParseLinter())],
|
||||
toml: [StreamLanguage.define(tomlMode)],
|
||||
css: [css()],
|
||||
text: [],
|
||||
}
|
||||
|
||||
export default function CodeEditorImpl({
|
||||
value,
|
||||
onChange,
|
||||
language = 'text',
|
||||
readOnly = false,
|
||||
height = '400px',
|
||||
minHeight,
|
||||
maxHeight,
|
||||
placeholder,
|
||||
theme,
|
||||
className = '',
|
||||
}: CodeEditorProps) {
|
||||
const { resolvedTheme } = useTheme()
|
||||
|
||||
const extensions = [
|
||||
...(languageExtensions[language] || []),
|
||||
EditorView.lineWrapping,
|
||||
// 应用 JetBrains Mono 字体
|
||||
EditorView.theme({
|
||||
'&': {
|
||||
fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", "Monaco", monospace',
|
||||
},
|
||||
'.cm-content': {
|
||||
fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", "Monaco", monospace',
|
||||
},
|
||||
'.cm-gutters': {
|
||||
fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", "Monaco", monospace',
|
||||
},
|
||||
'.cm-scroller': {
|
||||
fontFamily: '"JetBrains Mono", "Fira Code", "Consolas", "Monaco", monospace',
|
||||
},
|
||||
}),
|
||||
]
|
||||
|
||||
if (readOnly) {
|
||||
extensions.push(EditorView.editable.of(false))
|
||||
}
|
||||
|
||||
// 如果外部传了 theme prop 则使用,否则从 context 自动获取
|
||||
const effectiveTheme = theme ?? resolvedTheme
|
||||
|
||||
return (
|
||||
<div className={`custom-scrollbar overflow-hidden rounded-md border ${className}`}>
|
||||
<CodeMirror
|
||||
value={value}
|
||||
height={height}
|
||||
minHeight={minHeight}
|
||||
maxHeight={maxHeight}
|
||||
theme={effectiveTheme === 'dark' ? oneDark : undefined}
|
||||
extensions={extensions}
|
||||
onChange={onChange}
|
||||
placeholder={placeholder}
|
||||
basicSetup={{
|
||||
lineNumbers: true,
|
||||
highlightActiveLineGutter: true,
|
||||
highlightSpecialChars: true,
|
||||
history: true,
|
||||
foldGutter: true,
|
||||
drawSelection: true,
|
||||
dropCursor: true,
|
||||
allowMultipleSelections: true,
|
||||
indentOnInput: true,
|
||||
syntaxHighlighting: true,
|
||||
bracketMatching: true,
|
||||
closeBrackets: true,
|
||||
autocompletion: true,
|
||||
rectangularSelection: true,
|
||||
crosshairCursor: true,
|
||||
highlightActiveLine: true,
|
||||
highlightSelectionMatches: true,
|
||||
closeBracketsKeymap: true,
|
||||
defaultKeymap: true,
|
||||
searchKeymap: true,
|
||||
historyKeymap: true,
|
||||
foldKeymap: true,
|
||||
completionKeymap: true,
|
||||
lintKeymap: true,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1443,6 +1443,7 @@ export function ExpressionReviewer({ open, onOpenChange }: ExpressionReviewerPro
|
||||
<div
|
||||
className="relative w-full max-w-md h-[400px] flex items-center justify-center"
|
||||
role="listbox"
|
||||
tabIndex={0}
|
||||
aria-label="待审核的表达方式"
|
||||
aria-activedescendant={quickExpressions[quickCurrentIndex] ? `quick-expr-${quickExpressions[quickCurrentIndex].id}` : undefined}
|
||||
>
|
||||
@@ -1561,14 +1562,14 @@ if (isCurrent) {
|
||||
</div>
|
||||
{/* 情景 */}
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">情景</label>
|
||||
<div className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">情景</div>
|
||||
<div className="p-3 bg-muted/30 rounded-lg border border-border/50">
|
||||
<p className="text-lg font-medium leading-relaxed">{expr.situation}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/* 风格 */}
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">风格</label>
|
||||
<div className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">风格</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{expr.style.split(/[,,]/).map((s, i) => (
|
||||
<Badge key={i} variant="secondary" className="font-normal">
|
||||
@@ -1614,14 +1615,14 @@ if (isCurrent) {
|
||||
</div>
|
||||
{/* 情景 */}
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">情景</label>
|
||||
<div className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">情景</div>
|
||||
<div className="p-3 bg-muted/30 rounded-lg border border-border/50">
|
||||
<p className="text-lg font-medium leading-relaxed">{expr.situation}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/* 风格 */}
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">风格</label>
|
||||
<div className="text-xs font-semibold text-muted-foreground uppercase tracking-wider">风格</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{expr.style.split(/[,,]/).map((s, i) => (
|
||||
<Badge key={i} variant="secondary" className="font-normal">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMemo, useState } from 'react'
|
||||
|
||||
import { ListFieldEditor } from '@/components'
|
||||
import { ListFieldEditor } from '@/components/ListFieldEditor'
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { Label } from '@/components/ui/label'
|
||||
|
||||
@@ -1,31 +1,13 @@
|
||||
import { createRootRoute, createRoute, createRouter, Outlet, redirect } from '@tanstack/react-router'
|
||||
import {
|
||||
createRootRoute,
|
||||
createRoute,
|
||||
createRouter,
|
||||
lazyRouteComponent,
|
||||
Outlet,
|
||||
redirect,
|
||||
} from '@tanstack/react-router'
|
||||
import { TanStackRouterDevtools } from '@tanstack/router-devtools'
|
||||
import { IndexPage } from './routes/index'
|
||||
import { SettingsPage } from './routes/settings'
|
||||
import { AuthPage } from './routes/auth'
|
||||
import { SetupPage } from './routes/setup'
|
||||
import { NotFoundPage } from './routes/404'
|
||||
import { BotConfigPage } from './routes/config/bot'
|
||||
import { ModelProviderConfigPage } from './routes/config/modelProvider'
|
||||
import { ModelConfigPage } from './routes/config/model'
|
||||
import { AdapterConfigPage } from './routes/config/adapter'
|
||||
import { EmojiManagementPage } from './routes/resource/emoji'
|
||||
import { ExpressionManagementPage } from './routes/resource/expression'
|
||||
import { JargonManagementPage } from './routes/resource/jargon'
|
||||
import { PersonManagementPage } from './routes/person'
|
||||
import { KnowledgeGraphPage } from './routes/resource/knowledge-graph'
|
||||
import { KnowledgeBasePage } from './routes/resource/knowledge-base'
|
||||
import { LogViewerPage } from './routes/logs'
|
||||
import { PlannerMonitorPage } from './routes/monitor'
|
||||
import { PluginsPage } from './routes/plugins'
|
||||
import { ModelPresetsPage } from './routes/model-presets'
|
||||
import { PluginConfigPage } from './routes/plugin-config'
|
||||
import { PluginMirrorsPage } from './routes/plugin-mirrors'
|
||||
import { PluginDetailPage } from './routes/plugin-detail'
|
||||
import { ChatPage } from './routes/chat/index'
|
||||
import { WebUIFeedbackSurveyPage, MaiBotFeedbackSurveyPage } from './routes/survey'
|
||||
import PackMarketPage from './routes/config/pack-market'
|
||||
import PackDetailPage from './routes/config/pack-detail'
|
||||
import { Layout } from './components/layout'
|
||||
import { checkAuth } from './hooks/use-auth'
|
||||
import { RouteErrorBoundary } from './components/error-boundary'
|
||||
@@ -50,14 +32,14 @@ const rootRoute = createRootRoute({
|
||||
const authRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: '/auth',
|
||||
component: AuthPage,
|
||||
component: lazyRouteComponent(() => import('./routes/auth'), 'AuthPage'),
|
||||
})
|
||||
|
||||
// 首次配置路由(无 Layout)
|
||||
const setupRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: '/setup',
|
||||
component: SetupPage,
|
||||
component: lazyRouteComponent(() => import('./routes/setup/index.tsx'), 'SetupPage'),
|
||||
})
|
||||
|
||||
// 受保护的路由 Root(带 Layout)
|
||||
@@ -76,168 +58,192 @@ const protectedRoute = createRoute({
|
||||
const indexRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/',
|
||||
component: IndexPage,
|
||||
component: lazyRouteComponent(() => import('./routes/index'), 'IndexPage'),
|
||||
})
|
||||
|
||||
// 配置路由 - 麦麦主程序配置
|
||||
const botConfigRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/config/bot',
|
||||
component: BotConfigPage,
|
||||
component: lazyRouteComponent(() => import('./routes/config/bot'), 'BotConfigPage'),
|
||||
})
|
||||
|
||||
// 配置路由 - 麦麦模型提供商配置
|
||||
const modelProviderConfigRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/config/modelProvider',
|
||||
component: ModelProviderConfigPage,
|
||||
component: lazyRouteComponent(
|
||||
() => import('./routes/config/modelProvider/index.tsx'),
|
||||
'ModelProviderConfigPage'
|
||||
),
|
||||
})
|
||||
|
||||
// 配置路由 - 麦麦模型配置
|
||||
const modelConfigRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/config/model',
|
||||
component: ModelConfigPage,
|
||||
component: lazyRouteComponent(() => import('./routes/config/model'), 'ModelConfigPage'),
|
||||
})
|
||||
|
||||
// 配置路由 - 麦麦适配器配置
|
||||
const adapterConfigRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/config/adapter',
|
||||
component: AdapterConfigPage,
|
||||
component: lazyRouteComponent(() => import('./routes/config/adapter'), 'AdapterConfigPage'),
|
||||
})
|
||||
|
||||
// 资源管理路由 - 表情包管理
|
||||
const emojiManagementRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/resource/emoji',
|
||||
component: EmojiManagementPage,
|
||||
component: lazyRouteComponent(
|
||||
() => import('./routes/resource/emoji/index.tsx'),
|
||||
'EmojiManagementPage'
|
||||
),
|
||||
})
|
||||
|
||||
// 资源管理路由 - 表达方式管理
|
||||
const expressionManagementRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/resource/expression',
|
||||
component: ExpressionManagementPage,
|
||||
component: lazyRouteComponent(
|
||||
() => import('./routes/resource/expression/index.tsx'),
|
||||
'ExpressionManagementPage'
|
||||
),
|
||||
})
|
||||
|
||||
// 资源管理路由 - 人物信息管理
|
||||
const personManagementRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/resource/person',
|
||||
component: PersonManagementPage,
|
||||
component: lazyRouteComponent(() => import('./routes/person'), 'PersonManagementPage'),
|
||||
})
|
||||
|
||||
// 资源管理路由 - 黑话管理
|
||||
const jargonManagementRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/resource/jargon',
|
||||
component: JargonManagementPage,
|
||||
component: lazyRouteComponent(
|
||||
() => import('./routes/resource/jargon/index.tsx'),
|
||||
'JargonManagementPage'
|
||||
),
|
||||
})
|
||||
|
||||
// 资源管理路由 - 知识库图谱可视化
|
||||
const knowledgeGraphRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/resource/knowledge-graph',
|
||||
component: KnowledgeGraphPage,
|
||||
component: lazyRouteComponent(
|
||||
() => import('./routes/resource/knowledge-graph/index.tsx'),
|
||||
'KnowledgeGraphPage'
|
||||
),
|
||||
})
|
||||
|
||||
// 资源管理路由 - 麦麦知识库管理
|
||||
const knowledgeBaseRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/resource/knowledge-base',
|
||||
component: KnowledgeBasePage,
|
||||
component: lazyRouteComponent(
|
||||
() => import('./routes/resource/knowledge-base'),
|
||||
'KnowledgeBasePage'
|
||||
),
|
||||
})
|
||||
|
||||
// 日志查看器路由
|
||||
const logsRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/logs',
|
||||
component: LogViewerPage,
|
||||
component: lazyRouteComponent(() => import('./routes/logs'), 'LogViewerPage'),
|
||||
})
|
||||
|
||||
// MaiSaka 聊天流监控路由
|
||||
const plannerMonitorRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/planner-monitor',
|
||||
component: PlannerMonitorPage,
|
||||
component: lazyRouteComponent(() => import('./routes/monitor/index.tsx'), 'PlannerMonitorPage'),
|
||||
})
|
||||
|
||||
// 本地聊天室路由
|
||||
const chatRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/chat',
|
||||
component: ChatPage,
|
||||
component: lazyRouteComponent(() => import('./routes/chat/index'), 'ChatPage'),
|
||||
})
|
||||
|
||||
// 插件市场路由
|
||||
const pluginsRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/plugins',
|
||||
component: PluginsPage,
|
||||
component: lazyRouteComponent(() => import('./routes/plugins/index'), 'PluginsPage'),
|
||||
})
|
||||
|
||||
// 插件详情路由
|
||||
const pluginDetailRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/plugin-detail',
|
||||
component: PluginDetailPage,
|
||||
component: lazyRouteComponent(() => import('./routes/plugin-detail'), 'PluginDetailPage'),
|
||||
})
|
||||
|
||||
// 模型分配预设市场路由
|
||||
const modelPresetsRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/model-presets',
|
||||
component: ModelPresetsPage,
|
||||
component: lazyRouteComponent(() => import('./routes/model-presets'), 'ModelPresetsPage'),
|
||||
})
|
||||
|
||||
// 插件配置路由
|
||||
const pluginConfigRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/plugin-config',
|
||||
component: PluginConfigPage,
|
||||
component: lazyRouteComponent(() => import('./routes/plugin-config'), 'PluginConfigPage'),
|
||||
})
|
||||
|
||||
// 插件镜像源配置路由
|
||||
const pluginMirrorsRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/plugin-mirrors',
|
||||
component: PluginMirrorsPage,
|
||||
component: lazyRouteComponent(() => import('./routes/plugin-mirrors'), 'PluginMirrorsPage'),
|
||||
})
|
||||
|
||||
// 设置页路由
|
||||
const settingsRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/settings',
|
||||
component: SettingsPage,
|
||||
component: lazyRouteComponent(() => import('./routes/settings/index.tsx'), 'SettingsPage'),
|
||||
})
|
||||
|
||||
// 配置模板市场路由
|
||||
const packMarketRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/config/pack-market',
|
||||
component: PackMarketPage,
|
||||
component: lazyRouteComponent(() => import('./routes/config/pack-market')),
|
||||
})
|
||||
|
||||
// 配置模板详情路由
|
||||
export const packDetailRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/config/pack-market/$packId',
|
||||
component: PackDetailPage,
|
||||
component: lazyRouteComponent(() => import('./routes/config/pack-detail')),
|
||||
})
|
||||
|
||||
// 问卷调查路由 - WebUI 反馈
|
||||
const webuiFeedbackSurveyRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/survey/webui-feedback',
|
||||
component: WebUIFeedbackSurveyPage,
|
||||
component: lazyRouteComponent(
|
||||
() => import('./routes/survey/webui-feedback'),
|
||||
'WebUIFeedbackSurveyPage'
|
||||
),
|
||||
})
|
||||
|
||||
// 问卷调查路由 - 麦麦体验反馈
|
||||
const maibotFeedbackSurveyRoute = createRoute({
|
||||
getParentRoute: () => protectedRoute,
|
||||
path: '/survey/maibot-feedback',
|
||||
component: MaiBotFeedbackSurveyPage,
|
||||
component: lazyRouteComponent(
|
||||
() => import('./routes/survey/maibot-feedback'),
|
||||
'MaiBotFeedbackSurveyPage'
|
||||
),
|
||||
})
|
||||
|
||||
// 404 路由
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { CodeEditor } from '@/components'
|
||||
import { CodeEditor } from '@/components/CodeEditor'
|
||||
import { DynamicConfigForm } from '@/components/dynamic-form'
|
||||
import { RestartOverlay } from '@/components/restart-overlay'
|
||||
import { useToast } from '@/hooks/use-toast'
|
||||
|
||||
@@ -12,7 +12,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
|
||||
import { ListFieldEditor } from '@/components/ListFieldEditor'
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
||||
import { CodeEditor } from '@/components'
|
||||
import { CodeEditor } from '@/components/CodeEditor'
|
||||
import { parse as parseToml } from 'smol-toml'
|
||||
import {
|
||||
Select,
|
||||
|
||||
@@ -37,8 +37,8 @@ import {
|
||||
type GitStatus,
|
||||
type MaimaiVersion,
|
||||
} from '@/lib/plugin-api'
|
||||
import { MarkdownRenderer } from '@/components/markdown-renderer'
|
||||
import { PluginStats } from '@/components/plugin-stats'
|
||||
import { MarkdownRenderer } from '@/components'
|
||||
import { recordPluginDownload } from '@/lib/plugin-stats'
|
||||
|
||||
// 分类名称映射
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
Upload,
|
||||
} from 'lucide-react'
|
||||
|
||||
import { CodeEditor } from '@/components'
|
||||
import { CodeEditor } from '@/components/CodeEditor'
|
||||
import { MemoryDeleteDialog } from '@/components/memory/MemoryDeleteDialog'
|
||||
import { MemoryConfigEditor } from '@/components/memory/MemoryConfigEditor'
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
||||
|
||||
@@ -171,10 +171,14 @@ export function NodeDetailDialog({
|
||||
</Button>
|
||||
{onDeleteEntity ? (
|
||||
<div className="flex flex-col items-end gap-2 rounded-lg border bg-background p-3">
|
||||
<label className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<Checkbox checked={includeParagraphs} onCheckedChange={(checked) => setIncludeParagraphs(Boolean(checked))} />
|
||||
删除该实体相关证据段落
|
||||
</label>
|
||||
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<Checkbox
|
||||
checked={includeParagraphs}
|
||||
onCheckedChange={(checked) => setIncludeParagraphs(Boolean(checked))}
|
||||
aria-label="删除该实体相关证据段落"
|
||||
/>
|
||||
<span>删除该实体相关证据段落</span>
|
||||
</div>
|
||||
<Button variant="outline" onClick={() => onDeleteEntity({ includeParagraphs })}>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
删除实体
|
||||
@@ -280,10 +284,14 @@ export function EdgeDetailDialog({
|
||||
</Button>
|
||||
{onDeleteEdgeGroup ? (
|
||||
<div className="flex flex-col items-end gap-2 rounded-lg border bg-background p-3">
|
||||
<label className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<Checkbox checked={includeParagraphs} onCheckedChange={(checked) => setIncludeParagraphs(Boolean(checked))} />
|
||||
同时删除支撑段落
|
||||
</label>
|
||||
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<Checkbox
|
||||
checked={includeParagraphs}
|
||||
onCheckedChange={(checked) => setIncludeParagraphs(Boolean(checked))}
|
||||
aria-label="同时删除支撑段落"
|
||||
/>
|
||||
<span>同时删除支撑段落</span>
|
||||
</div>
|
||||
<Button variant="outline" onClick={() => onDeleteEdgeGroup({ includeParagraphs })}>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
删除此关系组
|
||||
@@ -371,10 +379,14 @@ export function RelationDetailDialog({
|
||||
|
||||
{onDeleteRelation ? (
|
||||
<div className="rounded-lg border bg-background p-3">
|
||||
<label className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<Checkbox checked={includeParagraphs} onCheckedChange={(checked) => setIncludeParagraphs(Boolean(checked))} />
|
||||
同时删除支撑该关系的段落
|
||||
</label>
|
||||
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<Checkbox
|
||||
checked={includeParagraphs}
|
||||
onCheckedChange={(checked) => setIncludeParagraphs(Boolean(checked))}
|
||||
aria-label="同时删除支撑该关系的段落"
|
||||
/>
|
||||
<span>同时删除支撑该关系的段落</span>
|
||||
</div>
|
||||
<Button className="mt-3" variant="outline" onClick={() => onDeleteRelation(relation, includeParagraphs)}>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
删除这条关系
|
||||
|
||||
Reference in New Issue
Block a user