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