mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-20 23:22:05 +08:00
feat(navigation): migrate to TanStack Router and enhance navigation structure
- Replaced react-router with TanStack Router for improved routing capabilities. - Updated navigation logic across various components to utilize the new navigation API. - Refactored App.tsx to integrate AppShell as the main routing component, removing the deprecated Router. - Enhanced navigation methods to support search parameters, improving URL handling for settings and provider navigation. These changes streamline the routing architecture, enhancing the overall user experience and maintainability of the application.
This commit is contained in:
parent
5ad5bd537b
commit
b9a56fcec1
@ -7,15 +7,13 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|||||||
import { Provider } from 'react-redux'
|
import { Provider } from 'react-redux'
|
||||||
import { PersistGate } from 'redux-persist/integration/react'
|
import { PersistGate } from 'redux-persist/integration/react'
|
||||||
|
|
||||||
// TODO: 新路由系统入口,迁移完成后启用
|
import { AppShell } from './components/layout/AppShell'
|
||||||
// import { AppShell } from './components/layout/AppShell'
|
|
||||||
import TopViewContainer from './components/TopView'
|
import TopViewContainer from './components/TopView'
|
||||||
import AntdProvider from './context/AntdProvider'
|
import AntdProvider from './context/AntdProvider'
|
||||||
import { CodeStyleProvider } from './context/CodeStyleProvider'
|
import { CodeStyleProvider } from './context/CodeStyleProvider'
|
||||||
import { NotificationProvider } from './context/NotificationProvider'
|
import { NotificationProvider } from './context/NotificationProvider'
|
||||||
import StyleSheetManager from './context/StyleSheetManager'
|
import StyleSheetManager from './context/StyleSheetManager'
|
||||||
import { ThemeProvider } from './context/ThemeProvider'
|
import { ThemeProvider } from './context/ThemeProvider'
|
||||||
import Router from './Router'
|
|
||||||
|
|
||||||
const logger = loggerService.withContext('App.tsx')
|
const logger = loggerService.withContext('App.tsx')
|
||||||
|
|
||||||
@ -44,8 +42,7 @@ function App(): React.ReactElement {
|
|||||||
<CodeStyleProvider>
|
<CodeStyleProvider>
|
||||||
<PersistGate loading={null} persistor={persistor}>
|
<PersistGate loading={null} persistor={persistor}>
|
||||||
<TopViewContainer>
|
<TopViewContainer>
|
||||||
{/* TODO: 迁移完成后切换到 <AppShell /> */}
|
<AppShell />
|
||||||
<Router />
|
|
||||||
</TopViewContainer>
|
</TopViewContainer>
|
||||||
</PersistGate>
|
</PersistGate>
|
||||||
</CodeStyleProvider>
|
</CodeStyleProvider>
|
||||||
|
|||||||
@ -1,67 +0,0 @@
|
|||||||
import '@renderer/databases'
|
|
||||||
|
|
||||||
import type { FC } from 'react'
|
|
||||||
import { useMemo } from 'react'
|
|
||||||
import { HashRouter, Route, Routes } from 'react-router-dom'
|
|
||||||
|
|
||||||
import Sidebar from './components/app/Sidebar'
|
|
||||||
import { ErrorBoundary } from './components/ErrorBoundary'
|
|
||||||
import TabsContainer from './components/Tab/TabContainer'
|
|
||||||
import NavigationHandler from './handler/NavigationHandler'
|
|
||||||
import { useNavbarPosition } from './hooks/useNavbar'
|
|
||||||
import CodeToolsPage from './pages/code/CodeToolsPage'
|
|
||||||
import FilesPage from './pages/files/FilesPage'
|
|
||||||
import HomePage from './pages/home/HomePage'
|
|
||||||
import KnowledgePage from './pages/knowledge/KnowledgePage'
|
|
||||||
import LaunchpadPage from './pages/launchpad/LaunchpadPage'
|
|
||||||
import MinAppPage from './pages/minapps/MinAppPage'
|
|
||||||
import MinAppsPage from './pages/minapps/MinAppsPage'
|
|
||||||
import NotesPage from './pages/notes/NotesPage'
|
|
||||||
import PaintingsRoutePage from './pages/paintings/PaintingsRoutePage'
|
|
||||||
import SettingsPage from './pages/settings/SettingsPage'
|
|
||||||
import AssistantPresetsPage from './pages/store/assistants/presets/AssistantPresetsPage'
|
|
||||||
import TranslatePage from './pages/translate/TranslatePage'
|
|
||||||
|
|
||||||
const Router: FC = () => {
|
|
||||||
const { navbarPosition } = useNavbarPosition()
|
|
||||||
|
|
||||||
const routes = useMemo(() => {
|
|
||||||
return (
|
|
||||||
<ErrorBoundary>
|
|
||||||
<Routes>
|
|
||||||
<Route path="/" element={<HomePage />} />
|
|
||||||
<Route path="/store" element={<AssistantPresetsPage />} />
|
|
||||||
<Route path="/paintings/*" element={<PaintingsRoutePage />} />
|
|
||||||
<Route path="/translate" element={<TranslatePage />} />
|
|
||||||
<Route path="/files" element={<FilesPage />} />
|
|
||||||
<Route path="/notes" element={<NotesPage />} />
|
|
||||||
<Route path="/knowledge" element={<KnowledgePage />} />
|
|
||||||
<Route path="/apps/:appId" element={<MinAppPage />} />
|
|
||||||
<Route path="/apps" element={<MinAppsPage />} />
|
|
||||||
<Route path="/code" element={<CodeToolsPage />} />
|
|
||||||
<Route path="/settings/*" element={<SettingsPage />} />
|
|
||||||
<Route path="/launchpad" element={<LaunchpadPage />} />
|
|
||||||
</Routes>
|
|
||||||
</ErrorBoundary>
|
|
||||||
)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
if (navbarPosition === 'left') {
|
|
||||||
return (
|
|
||||||
<HashRouter>
|
|
||||||
<Sidebar />
|
|
||||||
{routes}
|
|
||||||
<NavigationHandler />
|
|
||||||
</HashRouter>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<HashRouter>
|
|
||||||
<NavigationHandler />
|
|
||||||
<TabsContainer>{routes}</TabsContainer>
|
|
||||||
</HashRouter>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Router
|
|
||||||
@ -30,13 +30,13 @@ export const FreeTrialModelTag: FC<Props> = ({ model, showLabel = true }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onSelectProvider = () => {
|
const onSelectProvider = () => {
|
||||||
NavigationService.navigate!(`/settings/provider?id=${providerId}`)
|
NavigationService.navigate!({ to: `/settings/provider`, search: { id: providerId } })
|
||||||
}
|
}
|
||||||
|
|
||||||
const onNavigateProvider = (e: MouseEvent) => {
|
const onNavigateProvider = (e: MouseEvent) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
SelectModelPopup.hide()
|
SelectModelPopup.hide()
|
||||||
NavigationService.navigate!(`/settings/provider?id=${providerId}`)
|
NavigationService.navigate?.({ to: '/settings/provider', search: { id: providerId } })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!showLabel) {
|
if (!showLabel) {
|
||||||
|
|||||||
@ -6,11 +6,11 @@ import { useMinappPopup } from '@renderer/hooks/useMinappPopup'
|
|||||||
import { useMinapps } from '@renderer/hooks/useMinapps'
|
import { useMinapps } from '@renderer/hooks/useMinapps'
|
||||||
import { useNavbarPosition } from '@renderer/hooks/useNavbar'
|
import { useNavbarPosition } from '@renderer/hooks/useNavbar'
|
||||||
import type { MinAppType } from '@renderer/types'
|
import type { MinAppType } from '@renderer/types'
|
||||||
|
import { useNavigate } from '@tanstack/react-router'
|
||||||
import type { MenuProps } from 'antd'
|
import type { MenuProps } from 'antd'
|
||||||
import { Dropdown } from 'antd'
|
import { Dropdown } from 'antd'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -47,7 +47,7 @@ const MinApp: FC<Props> = ({ app, onClick, size = 60, isLast }) => {
|
|||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
if (isTopNavbar) {
|
if (isTopNavbar) {
|
||||||
// 顶部导航栏:导航到小程序页面
|
// 顶部导航栏:导航到小程序页面
|
||||||
navigate(`/apps/${app.id}`)
|
navigate({ to: `/apps/${app.id}` })
|
||||||
} else {
|
} else {
|
||||||
// 侧边导航栏:保持原有弹窗行为
|
// 侧边导航栏:保持原有弹窗行为
|
||||||
openMinappKeepAlive(app)
|
openMinappKeepAlive(app)
|
||||||
|
|||||||
@ -3,9 +3,9 @@ import WebviewContainer from '@renderer/components/MinApp/WebviewContainer'
|
|||||||
import { useMinapps } from '@renderer/hooks/useMinapps'
|
import { useMinapps } from '@renderer/hooks/useMinapps'
|
||||||
import { useNavbarPosition } from '@renderer/hooks/useNavbar'
|
import { useNavbarPosition } from '@renderer/hooks/useNavbar'
|
||||||
import { getWebviewLoaded, setWebviewLoaded } from '@renderer/utils/webviewStateManager'
|
import { getWebviewLoaded, setWebviewLoaded } from '@renderer/utils/webviewStateManager'
|
||||||
|
import { useLocation } from '@tanstack/react-router'
|
||||||
import type { WebviewTag } from 'electron'
|
import type { WebviewTag } from 'electron'
|
||||||
import React, { useEffect, useRef } from 'react'
|
import React, { useEffect, useRef } from 'react'
|
||||||
import { useLocation } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -193,7 +193,7 @@ const PopupContainer: React.FC<Props> = ({ model, filter: baseFilter, showTagFil
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
resolve(undefined)
|
resolve(undefined)
|
||||||
window.navigate(`/settings/provider?id=${p.id}`)
|
window.navigate({ to: '/settings/provider', search: { id: p.id } })
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import { addTab, removeTab, setActiveTab, setTabs } from '@renderer/store/tabs'
|
|||||||
import type { MinAppType } from '@renderer/types'
|
import type { MinAppType } from '@renderer/types'
|
||||||
import { classNames } from '@renderer/utils'
|
import { classNames } from '@renderer/utils'
|
||||||
import { ThemeMode } from '@shared/data/preference/preferenceTypes'
|
import { ThemeMode } from '@shared/data/preference/preferenceTypes'
|
||||||
|
import { useLocation, useNavigate } from '@tanstack/react-router'
|
||||||
import type { LRUCache } from 'lru-cache'
|
import type { LRUCache } from 'lru-cache'
|
||||||
import {
|
import {
|
||||||
FileSearch,
|
FileSearch,
|
||||||
@ -37,7 +38,6 @@ import {
|
|||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { useCallback, useEffect, useMemo } from 'react'
|
import { useCallback, useEffect, useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import MinAppIcon from '../Icons/MinAppIcon'
|
import MinAppIcon from '../Icons/MinAppIcon'
|
||||||
@ -203,17 +203,17 @@ const TabsContainer: React.FC<TabsContainerProps> = ({ children }) => {
|
|||||||
|
|
||||||
const handleAddTab = () => {
|
const handleAddTab = () => {
|
||||||
hideMinappPopup()
|
hideMinappPopup()
|
||||||
navigate('/launchpad')
|
navigate({ to: '/launchpad' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSettingsClick = () => {
|
const handleSettingsClick = () => {
|
||||||
hideMinappPopup()
|
hideMinappPopup()
|
||||||
navigate(lastSettingsPath)
|
navigate({ to: lastSettingsPath })
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleTabClick = (tab: Tab) => {
|
const handleTabClick = (tab: Tab) => {
|
||||||
hideMinappPopup()
|
hideMinappPopup()
|
||||||
navigate(tab.path)
|
navigate({ to: tab.path })
|
||||||
}
|
}
|
||||||
|
|
||||||
const visibleTabs = useMemo(() => tabs.filter((tab) => !specialTabs.includes(tab.id)), [tabs])
|
const visibleTabs = useMemo(() => tabs.filter((tab) => !specialTabs.includes(tab.id)), [tabs])
|
||||||
|
|||||||
@ -30,9 +30,9 @@ import {
|
|||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
import { useTabs } from '../../hooks/useTabs'
|
||||||
import UserPopup from '../Popups/UserPopup'
|
import UserPopup from '../Popups/UserPopup'
|
||||||
import { SidebarOpenedMinappTabs, SidebarPinnedApps } from './PinnedMinapps'
|
import { SidebarOpenedMinappTabs, SidebarPinnedApps } from './PinnedMinapps'
|
||||||
|
|
||||||
@ -40,9 +40,11 @@ const Sidebar: FC = () => {
|
|||||||
const { hideMinappPopup } = useMinappPopup()
|
const { hideMinappPopup } = useMinappPopup()
|
||||||
const { pinned, minappShow } = useMinapps()
|
const { pinned, minappShow } = useMinapps()
|
||||||
const [visibleSidebarIcons] = usePreference('ui.sidebar.icons.visible')
|
const [visibleSidebarIcons] = usePreference('ui.sidebar.icons.visible')
|
||||||
|
const { tabs, activeTabId, updateTab } = useTabs()
|
||||||
|
|
||||||
const { pathname } = useLocation()
|
// 获取当前 Tab 的 URL 作为 pathname
|
||||||
const navigate = useNavigate()
|
const activeTab = tabs.find((t) => t.id === activeTabId)
|
||||||
|
const pathname = activeTab?.url || '/'
|
||||||
|
|
||||||
const { theme, settedTheme, toggleTheme } = useTheme()
|
const { theme, settedTheme, toggleTheme } = useTheme()
|
||||||
const avatar = useAvatar()
|
const avatar = useAvatar()
|
||||||
@ -54,9 +56,12 @@ const Sidebar: FC = () => {
|
|||||||
|
|
||||||
const showPinnedApps = pinned.length > 0 && visibleSidebarIcons.includes('minapp')
|
const showPinnedApps = pinned.length > 0 && visibleSidebarIcons.includes('minapp')
|
||||||
|
|
||||||
|
// 在当前 Tab 内跳转
|
||||||
const to = async (path: string) => {
|
const to = async (path: string) => {
|
||||||
await modelGenerating()
|
await modelGenerating()
|
||||||
navigate(path)
|
if (activeTabId) {
|
||||||
|
updateTab(activeTabId, { url: path })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isFullscreen = useFullscreen()
|
const isFullscreen = useFullscreen()
|
||||||
@ -121,14 +126,16 @@ const Sidebar: FC = () => {
|
|||||||
const MainMenus: FC = () => {
|
const MainMenus: FC = () => {
|
||||||
const { hideMinappPopup } = useMinappPopup()
|
const { hideMinappPopup } = useMinappPopup()
|
||||||
const { minappShow } = useMinapps()
|
const { minappShow } = useMinapps()
|
||||||
|
const { tabs, activeTabId, updateTab } = useTabs()
|
||||||
|
|
||||||
|
// 获取当前 Tab 的 URL 作为 pathname
|
||||||
|
const activeTab = tabs.find((t) => t.id === activeTabId)
|
||||||
|
const pathname = activeTab?.url || '/'
|
||||||
|
|
||||||
const { pathname } = useLocation()
|
|
||||||
const [visibleSidebarIcons] = usePreference('ui.sidebar.icons.visible')
|
const [visibleSidebarIcons] = usePreference('ui.sidebar.icons.visible')
|
||||||
const { defaultPaintingProvider } = useSettings()
|
const { defaultPaintingProvider } = useSettings()
|
||||||
const navigate = useNavigate()
|
|
||||||
const { theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
|
|
||||||
const isRoute = (path: string): string => (pathname === path && !minappShow ? 'active' : '')
|
|
||||||
const isRoutes = (path: string): string => (pathname.startsWith(path) && !minappShow ? 'active' : '')
|
const isRoutes = (path: string): string => (pathname.startsWith(path) && !minappShow ? 'active' : '')
|
||||||
|
|
||||||
const iconMap = {
|
const iconMap = {
|
||||||
@ -144,7 +151,7 @@ const MainMenus: FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pathMap = {
|
const pathMap = {
|
||||||
assistants: '/',
|
assistants: '/chat',
|
||||||
store: '/store',
|
store: '/store',
|
||||||
paintings: `/paintings/${defaultPaintingProvider}`,
|
paintings: `/paintings/${defaultPaintingProvider}`,
|
||||||
translate: '/translate',
|
translate: '/translate',
|
||||||
@ -155,17 +162,24 @@ const MainMenus: FC = () => {
|
|||||||
notes: '/notes'
|
notes: '/notes'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 在当前 Tab 内跳转
|
||||||
|
const to = async (path: string) => {
|
||||||
|
await modelGenerating()
|
||||||
|
if (activeTabId) {
|
||||||
|
updateTab(activeTabId, { url: path })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return visibleSidebarIcons.map((icon) => {
|
return visibleSidebarIcons.map((icon) => {
|
||||||
const path = pathMap[icon]
|
const path = pathMap[icon]
|
||||||
const isActive = path === '/' ? isRoute(path) : isRoutes(path)
|
const isActive = isRoutes(path)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip key={icon} placement="right" content={getSidebarIconLabel(icon)} delay={800}>
|
<Tooltip key={icon} placement="right" content={getSidebarIconLabel(icon)} delay={800}>
|
||||||
<StyledLink
|
<StyledLink
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
hideMinappPopup()
|
hideMinappPopup()
|
||||||
await modelGenerating()
|
await to(path)
|
||||||
navigate(path)
|
|
||||||
}}>
|
}}>
|
||||||
<Icon theme={theme} className={isActive}>
|
<Icon theme={theme} className={isActive}>
|
||||||
{iconMap[icon]}
|
{iconMap[icon]}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import '@renderer/databases'
|
||||||
|
|
||||||
import { cn, Tabs, TabsList, TabsTrigger } from '@cherrystudio/ui'
|
import { cn, Tabs, TabsList, TabsTrigger } from '@cherrystudio/ui'
|
||||||
import { Plus, X } from 'lucide-react'
|
import { Plus, X } from 'lucide-react'
|
||||||
import { Activity } from 'react'
|
import { Activity } from 'react'
|
||||||
@ -31,7 +33,7 @@ export const AppShell = () => {
|
|||||||
id: uuid(),
|
id: uuid(),
|
||||||
type: 'route',
|
type: 'route',
|
||||||
url: '/',
|
url: '/',
|
||||||
title: 'New Tab',
|
title: 'New Tab'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
src/renderer/src/env.d.ts
vendored
4
src/renderer/src/env.d.ts
vendored
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
import type { PermissionUpdate } from '@anthropic-ai/claude-agent-sdk'
|
import type { PermissionUpdate } from '@anthropic-ai/claude-agent-sdk'
|
||||||
import type { ToastUtilities } from '@cherrystudio/ui'
|
import type { ToastUtilities } from '@cherrystudio/ui'
|
||||||
|
import type { UseNavigateResult } from '@tanstack/react-router'
|
||||||
import type { HookAPI } from 'antd/es/modal/useModal'
|
import type { HookAPI } from 'antd/es/modal/useModal'
|
||||||
import type { NavigateFunction } from 'react-router-dom'
|
|
||||||
|
|
||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
VITE_RENDERER_INTEGRATED_MODEL: string
|
VITE_RENDERER_INTEGRATED_MODEL: string
|
||||||
@ -18,7 +18,7 @@ declare global {
|
|||||||
root: HTMLElement
|
root: HTMLElement
|
||||||
modal: HookAPI
|
modal: HookAPI
|
||||||
store: any
|
store: any
|
||||||
navigate: NavigateFunction
|
navigate: UseNavigateResult<string>
|
||||||
toast: ToastUtilities
|
toast: ToastUtilities
|
||||||
agentTools: {
|
agentTools: {
|
||||||
respondToPermission: (payload: {
|
respondToPermission: (payload: {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { useAppSelector } from '@renderer/store'
|
import { useAppSelector } from '@renderer/store'
|
||||||
import { IpcChannel } from '@shared/IpcChannel'
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
|
import { useLocation, useNavigate } from '@tanstack/react-router'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useHotkeys } from 'react-hotkeys-hook'
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
|
||||||
|
|
||||||
const NavigationHandler: React.FC = () => {
|
const NavigationHandler: React.FC = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
@ -17,7 +17,7 @@ const NavigationHandler: React.FC = () => {
|
|||||||
if (location.pathname.startsWith('/settings')) {
|
if (location.pathname.startsWith('/settings')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
navigate('/settings/provider')
|
navigate({ to: '/settings/provider' })
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
splitKey: '!',
|
splitKey: '!',
|
||||||
@ -30,7 +30,7 @@ const NavigationHandler: React.FC = () => {
|
|||||||
// Listen for navigate to About page event from macOS menu
|
// Listen for navigate to About page event from macOS menu
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleNavigateToAbout = () => {
|
const handleNavigateToAbout = () => {
|
||||||
navigate('/settings/about')
|
navigate({ to: '/settings/about' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeListener = window.electron.ipcRenderer.on(IpcChannel.Windows_NavigateToAbout, handleNavigateToAbout)
|
const removeListener = window.electron.ipcRenderer.on(IpcChannel.Windows_NavigateToAbout, handleNavigateToAbout)
|
||||||
|
|||||||
@ -64,7 +64,7 @@ export function useAppInit() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.api.getDataPathFromArgs().then((dataPath) => {
|
window.api.getDataPathFromArgs().then((dataPath) => {
|
||||||
if (dataPath) {
|
if (dataPath) {
|
||||||
window.navigate('/settings/data', { replace: true })
|
window.navigate({ to: '/settings/data', replace: true })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|||||||
@ -13,8 +13,8 @@ window.electron.ipcRenderer.on(IpcChannel.Mcp_ServersChanged, (_event, servers)
|
|||||||
|
|
||||||
window.electron.ipcRenderer.on(IpcChannel.Mcp_AddServer, (_event, server: MCPServer) => {
|
window.electron.ipcRenderer.on(IpcChannel.Mcp_AddServer, (_event, server: MCPServer) => {
|
||||||
store.dispatch(addMCPServer(server))
|
store.dispatch(addMCPServer(server))
|
||||||
NavigationService.navigate?.('/settings/mcp')
|
NavigationService.navigate?.({ to: '/settings/mcp' })
|
||||||
NavigationService.navigate?.(`/settings/mcp/settings/${encodeURIComponent(server.id)}`)
|
NavigationService.navigate?.({ to: `/settings/mcp/settings/${encodeURIComponent(server.id)}` })
|
||||||
})
|
})
|
||||||
|
|
||||||
const selectMcpServers = (state: RootState) => state.mcp.servers
|
const selectMcpServers = (state: RootState) => state.mcp.servers
|
||||||
|
|||||||
@ -186,7 +186,7 @@ export const useMinappPopup = () => {
|
|||||||
|
|
||||||
// Then navigate to the app tab using NavigationService
|
// Then navigate to the app tab using NavigationService
|
||||||
if (NavigationService.navigate) {
|
if (NavigationService.navigate) {
|
||||||
NavigationService.navigate(`/apps/${config.id}`)
|
NavigationService.navigate({ to: `/apps/${config.id}` })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// For side navbar, use the traditional popup system
|
// For side navbar, use the traditional popup system
|
||||||
|
|||||||
@ -19,12 +19,12 @@ import { getClaudeSupportedProviders } from '@renderer/utils/provider'
|
|||||||
import type { TerminalConfig } from '@shared/config/constant'
|
import type { TerminalConfig } from '@shared/config/constant'
|
||||||
import { codeTools, terminalApps } from '@shared/config/constant'
|
import { codeTools, terminalApps } from '@shared/config/constant'
|
||||||
import { isSiliconAnthropicCompatibleModel } from '@shared/config/providers'
|
import { isSiliconAnthropicCompatibleModel } from '@shared/config/providers'
|
||||||
|
import { Link } from '@tanstack/react-router'
|
||||||
import { Alert, Checkbox, Input, Popover, Select, Space } from 'antd'
|
import { Alert, Checkbox, Input, Popover, Select, Space } from 'antd'
|
||||||
import { ArrowUpRight, Download, FolderOpen, HelpCircle, Terminal, X } from 'lucide-react'
|
import { ArrowUpRight, Download, FolderOpen, HelpCircle, Terminal, X } from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Link } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@ -11,9 +11,9 @@ import { getTopicById } from '@renderer/hooks/useTopic'
|
|||||||
import { getAssistantById } from '@renderer/services/AssistantService'
|
import { getAssistantById } from '@renderer/services/AssistantService'
|
||||||
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
import { EVENT_NAMES, EventEmitter } from '@renderer/services/EventService'
|
||||||
import { locateToMessage } from '@renderer/services/MessagesService'
|
import { locateToMessage } from '@renderer/services/MessagesService'
|
||||||
import NavigationService from '@renderer/services/NavigationService'
|
|
||||||
import type { Topic } from '@renderer/types'
|
import type { Topic } from '@renderer/types'
|
||||||
import { classNames, runAsyncFunction } from '@renderer/utils'
|
import { classNames, runAsyncFunction } from '@renderer/utils'
|
||||||
|
import { useNavigate } from '@tanstack/react-router'
|
||||||
import { Divider, Empty } from 'antd'
|
import { Divider, Empty } from 'antd'
|
||||||
import { t } from 'i18next'
|
import { t } from 'i18next'
|
||||||
import { Forward } from 'lucide-react'
|
import { Forward } from 'lucide-react'
|
||||||
@ -27,7 +27,8 @@ interface Props extends React.HTMLAttributes<HTMLDivElement> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TopicMessages: FC<Props> = ({ topic: _topic, ...props }) => {
|
const TopicMessages: FC<Props> = ({ topic: _topic, ...props }) => {
|
||||||
const navigate = NavigationService.navigate!
|
const navigate = useNavigate()
|
||||||
|
|
||||||
const { handleScroll, containerRef } = useScrollPosition('TopicMessages')
|
const { handleScroll, containerRef } = useScrollPosition('TopicMessages')
|
||||||
const [messageStyle] = usePreference('chat.message.style')
|
const [messageStyle] = usePreference('chat.message.style')
|
||||||
const { setTimeoutTimer } = useTimer()
|
const { setTimeoutTimer } = useTimer()
|
||||||
@ -53,7 +54,7 @@ const TopicMessages: FC<Props> = ({ topic: _topic, ...props }) => {
|
|||||||
await modelGenerating()
|
await modelGenerating()
|
||||||
SearchPopup.hide()
|
SearchPopup.hide()
|
||||||
const assistant = getAssistantById(topic.assistantId)
|
const assistant = getAssistantById(topic.assistantId)
|
||||||
navigate('/', { state: { assistant, topic } })
|
navigate({ to: '/chat', search: { assistantId: assistant?.id, topicId: topic.id } })
|
||||||
setTimeoutTimer('onContinueChat', () => EventEmitter.emit(EVENT_NAMES.SHOW_TOPIC_SIDEBAR), 100)
|
setTimeoutTimer('onContinueChat', () => EventEmitter.emit(EVENT_NAMES.SHOW_TOPIC_SIDEBAR), 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,11 +10,11 @@ import { newMessagesActions } from '@renderer/store/newMessage'
|
|||||||
import { setActiveAgentId, setActiveTopicOrSessionAction } from '@renderer/store/runtime'
|
import { setActiveAgentId, setActiveTopicOrSessionAction } from '@renderer/store/runtime'
|
||||||
import type { Assistant, Topic } from '@renderer/types'
|
import type { Assistant, Topic } from '@renderer/types'
|
||||||
import { MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH, SECOND_MIN_WINDOW_WIDTH } from '@shared/config/constant'
|
import { MIN_WINDOW_HEIGHT, MIN_WINDOW_WIDTH, SECOND_MIN_WINDOW_WIDTH } from '@shared/config/constant'
|
||||||
|
import { useNavigate, useSearch } from '@tanstack/react-router'
|
||||||
import { AnimatePresence, motion } from 'motion/react'
|
import { AnimatePresence, motion } from 'motion/react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { startTransition, useCallback, useEffect, useState } from 'react'
|
import { startTransition, useCallback, useEffect, useState } from 'react'
|
||||||
import { useDispatch } from 'react-redux'
|
import { useDispatch } from 'react-redux'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import Chat from './Chat'
|
import Chat from './Chat'
|
||||||
@ -31,13 +31,23 @@ const HomePage: FC = () => {
|
|||||||
// Initialize agent session hook
|
// Initialize agent session hook
|
||||||
useAgentSessionInitializer()
|
useAgentSessionInitializer()
|
||||||
|
|
||||||
const location = useLocation()
|
const search = useSearch({ strict: false }) as { assistantId?: string; topicId?: string }
|
||||||
const state = location.state
|
|
||||||
|
// 根据 search params 中的 ID 查找对应的 assistant
|
||||||
|
const assistantFromSearch = search.assistantId
|
||||||
|
? assistants.find((a) => a.id === search.assistantId)
|
||||||
|
: undefined
|
||||||
|
|
||||||
const [activeAssistant, _setActiveAssistant] = useState<Assistant>(
|
const [activeAssistant, _setActiveAssistant] = useState<Assistant>(
|
||||||
state?.assistant || _activeAssistant || assistants[0]
|
assistantFromSearch || _activeAssistant || assistants[0]
|
||||||
)
|
)
|
||||||
const { activeTopic, setActiveTopic: _setActiveTopic } = useActiveTopic(activeAssistant?.id ?? '', state?.topic)
|
|
||||||
|
// 根据 search params 中的 topicId 查找对应的 topic
|
||||||
|
const topicFromSearch = search.topicId
|
||||||
|
? activeAssistant?.topics?.find((t) => t.id === search.topicId)
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
const { activeTopic, setActiveTopic: _setActiveTopic } = useActiveTopic(activeAssistant?.id ?? '', topicFromSearch)
|
||||||
const [showAssistants] = usePreference('assistant.tab.show')
|
const [showAssistants] = usePreference('assistant.tab.show')
|
||||||
const [showTopics] = usePreference('topic.tab.show')
|
const [showTopics] = usePreference('topic.tab.show')
|
||||||
const [topicPosition] = usePreference('topic.position')
|
const [topicPosition] = usePreference('topic.position')
|
||||||
@ -80,10 +90,10 @@ const HomePage: FC = () => {
|
|||||||
}, [navigate])
|
}, [navigate])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
state?.assistant && setActiveAssistant(state?.assistant)
|
assistantFromSearch && setActiveAssistant(assistantFromSearch)
|
||||||
state?.topic && setActiveTopic(state?.topic)
|
topicFromSearch && setActiveTopic(topicFromSearch)
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [state])
|
}, [search.assistantId, search.topicId])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const canMinimize = topicPosition == 'left' ? !showAssistants : !showAssistants && !showTopics
|
const canMinimize = topicPosition == 'left' ? !showAssistants : !showAssistants && !showTopics
|
||||||
|
|||||||
@ -5,11 +5,11 @@ import { QuickPanelReservedSymbol, useQuickPanel } from '@renderer/components/Qu
|
|||||||
import type { ToolQuickPanelApi } from '@renderer/pages/home/Inputbar/types'
|
import type { ToolQuickPanelApi } from '@renderer/pages/home/Inputbar/types'
|
||||||
import { useAppSelector } from '@renderer/store'
|
import { useAppSelector } from '@renderer/store'
|
||||||
import type { KnowledgeBase } from '@renderer/types'
|
import type { KnowledgeBase } from '@renderer/types'
|
||||||
|
import { useNavigate } from '@tanstack/react-router'
|
||||||
import { CircleX, FileSearch, Plus } from 'lucide-react'
|
import { CircleX, FileSearch, Plus } from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { memo, useCallback, useEffect, useMemo, useRef } from 'react'
|
import { memo, useCallback, useEffect, useMemo, useRef } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
quickPanel: ToolQuickPanelApi
|
quickPanel: ToolQuickPanelApi
|
||||||
@ -54,7 +54,7 @@ const KnowledgeBaseButton: FC<Props> = ({ quickPanel, selectedBases, onSelect, d
|
|||||||
items.push({
|
items.push({
|
||||||
label: t('knowledge.add.title') + '...',
|
label: t('knowledge.add.title') + '...',
|
||||||
icon: <Plus />,
|
icon: <Plus />,
|
||||||
action: () => navigate('/knowledge'),
|
action: () => navigate({ to: '/knowledge' }),
|
||||||
isSelected: false
|
isSelected: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -12,12 +12,12 @@ import { EventEmitter } from '@renderer/services/EventService'
|
|||||||
import type { MCPPrompt, MCPResource, MCPServer } from '@renderer/types'
|
import type { MCPPrompt, MCPResource, MCPServer } from '@renderer/types'
|
||||||
import { isToolUseModeFunction } from '@renderer/utils/assistant'
|
import { isToolUseModeFunction } from '@renderer/utils/assistant'
|
||||||
import { isGeminiWebSearchProvider, isSupportUrlContextProvider } from '@renderer/utils/provider'
|
import { isGeminiWebSearchProvider, isSupportUrlContextProvider } from '@renderer/utils/provider'
|
||||||
|
import { useNavigate } from '@tanstack/react-router'
|
||||||
import { Form, Input } from 'antd'
|
import { Form, Input } from 'antd'
|
||||||
import { CircleX, Hammer, Plus } from 'lucide-react'
|
import { CircleX, Hammer, Plus } from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
assistantId: string
|
assistantId: string
|
||||||
@ -205,7 +205,7 @@ const MCPToolsButton: FC<Props> = ({ quickPanel, setInputValue, resizeTextArea,
|
|||||||
newList.push({
|
newList.push({
|
||||||
label: t('settings.mcp.addServer.label') + '...',
|
label: t('settings.mcp.addServer.label') + '...',
|
||||||
icon: <Plus />,
|
icon: <Plus />,
|
||||||
action: () => navigate('/settings/mcp')
|
action: () => navigate({ to: '/settings/mcp' })
|
||||||
})
|
})
|
||||||
|
|
||||||
newList.unshift({
|
newList.unshift({
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { getModelUniqId } from '@renderer/services/ModelService'
|
|||||||
import type { FileType, Model } from '@renderer/types'
|
import type { FileType, Model } from '@renderer/types'
|
||||||
import { FileTypes } from '@renderer/types'
|
import { FileTypes } from '@renderer/types'
|
||||||
import { getFancyProviderName } from '@renderer/utils'
|
import { getFancyProviderName } from '@renderer/utils'
|
||||||
|
import { useNavigate } from '@tanstack/react-router'
|
||||||
import { Avatar } from 'antd'
|
import { Avatar } from 'antd'
|
||||||
import { useLiveQuery } from 'dexie-react-hooks'
|
import { useLiveQuery } from 'dexie-react-hooks'
|
||||||
import { first, sortBy } from 'lodash'
|
import { first, sortBy } from 'lodash'
|
||||||
@ -16,7 +17,6 @@ import { AtSign, CircleX, Plus } from 'lucide-react'
|
|||||||
import type React from 'react'
|
import type React from 'react'
|
||||||
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
export type MentionTriggerInfo = { type: 'input' | 'button'; position?: number; originalText?: string }
|
export type MentionTriggerInfo = { type: 'input' | 'button'; position?: number; originalText?: string }
|
||||||
@ -194,7 +194,7 @@ export const useMentionModelsPanel = (params: Params, role: 'button' | 'manager'
|
|||||||
items.push({
|
items.push({
|
||||||
label: t('settings.models.add.add_model') + '...',
|
label: t('settings.models.add.add_model') + '...',
|
||||||
icon: <Plus />,
|
icon: <Plus />,
|
||||||
action: () => navigate('/settings/provider'),
|
action: () => navigate({ to: '/settings/provider' }),
|
||||||
isSelected: false
|
isSelected: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import CodeViewer from '@renderer/components/CodeViewer'
|
|||||||
import { useCodeStyle } from '@renderer/context/CodeStyleProvider'
|
import { useCodeStyle } from '@renderer/context/CodeStyleProvider'
|
||||||
import { useTimer } from '@renderer/hooks/useTimer'
|
import { useTimer } from '@renderer/hooks/useTimer'
|
||||||
import { getHttpMessageLabel, getProviderLabel } from '@renderer/i18n/label'
|
import { getHttpMessageLabel, getProviderLabel } from '@renderer/i18n/label'
|
||||||
import { getProviderById } from '@renderer/services/ProviderService'
|
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
import { removeBlocksThunk } from '@renderer/store/thunk/messageThunk'
|
import { removeBlocksThunk } from '@renderer/store/thunk/messageThunk'
|
||||||
import type { SerializedAiSdkError, SerializedAiSdkErrorUnion, SerializedError } from '@renderer/types/error'
|
import type { SerializedAiSdkError, SerializedAiSdkErrorUnion, SerializedError } from '@renderer/types/error'
|
||||||
@ -33,10 +32,10 @@ import {
|
|||||||
} from '@renderer/types/error'
|
} from '@renderer/types/error'
|
||||||
import type { ErrorMessageBlock, Message } from '@renderer/types/newMessage'
|
import type { ErrorMessageBlock, Message } from '@renderer/types/newMessage'
|
||||||
import { formatAiSdkError, formatError, safeToString } from '@renderer/utils/error'
|
import { formatAiSdkError, formatError, safeToString } from '@renderer/utils/error'
|
||||||
|
import { Link } from '@tanstack/react-router'
|
||||||
import { Alert as AntdAlert, Modal } from 'antd'
|
import { Alert as AntdAlert, Modal } from 'antd'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { Trans, useTranslation } from 'react-i18next'
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
import { Link } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
const HTTP_ERROR_CODES = [400, 401, 403, 404, 429, 500, 502, 503, 504]
|
const HTTP_ERROR_CODES = [400, 401, 403, 404, 429, 500, 502, 503, 504]
|
||||||
@ -71,8 +70,8 @@ const ErrorMessage: React.FC<{ block: ErrorMessageBlock }> = ({ block }) => {
|
|||||||
provider: (
|
provider: (
|
||||||
<Link
|
<Link
|
||||||
style={{ color: 'var(--color-link)' }}
|
style={{ color: 'var(--color-link)' }}
|
||||||
to={`/settings/provider`}
|
to="/settings/provider"
|
||||||
state={{ provider: getProviderById(providerId) }}
|
search={{ id: providerId }}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import styled from 'styled-components'
|
|||||||
|
|
||||||
import AssistantsDrawer from './components/AssistantsDrawer'
|
import AssistantsDrawer from './components/AssistantsDrawer'
|
||||||
import UpdateAppButton from './components/UpdateAppButton'
|
import UpdateAppButton from './components/UpdateAppButton'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
activeAssistant: Assistant
|
activeAssistant: Assistant
|
||||||
activeTopic: Topic
|
activeTopic: Topic
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import App from '@renderer/components/MinApp/MinApp'
|
import App from '@renderer/components/MinApp/MinApp'
|
||||||
import { useMinapps } from '@renderer/hooks/useMinapps'
|
import { useMinapps } from '@renderer/hooks/useMinapps'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
import { useSettings } from '@renderer/hooks/useSettings'
|
||||||
|
import { useNavigate } from '@tanstack/react-router'
|
||||||
import { Code, FileSearch, Folder, Languages, LayoutGrid, NotepadText, Palette, Sparkle } from 'lucide-react'
|
import { Code, FileSearch, Folder, Languages, LayoutGrid, NotepadText, Palette, Sparkle } from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
const LaunchpadPage: FC = () => {
|
const LaunchpadPage: FC = () => {
|
||||||
@ -87,7 +87,7 @@ const LaunchpadPage: FC = () => {
|
|||||||
<SectionTitle>{t('launchpad.apps')}</SectionTitle>
|
<SectionTitle>{t('launchpad.apps')}</SectionTitle>
|
||||||
<Grid>
|
<Grid>
|
||||||
{appMenuItems.map((item) => (
|
{appMenuItems.map((item) => (
|
||||||
<AppIcon key={item.path} onClick={() => navigate(item.path)}>
|
<AppIcon key={item.path} onClick={() => navigate({ to: item.path })}>
|
||||||
<IconContainer>
|
<IconContainer>
|
||||||
<IconWrapper bgColor={item.bgColor}>{item.icon}</IconWrapper>
|
<IconWrapper bgColor={item.bgColor}>{item.icon}</IconWrapper>
|
||||||
</IconContainer>
|
</IconContainer>
|
||||||
|
|||||||
@ -6,10 +6,10 @@ import { useMinapps } from '@renderer/hooks/useMinapps'
|
|||||||
import { useNavbarPosition } from '@renderer/hooks/useNavbar'
|
import { useNavbarPosition } from '@renderer/hooks/useNavbar'
|
||||||
import TabsService from '@renderer/services/TabsService'
|
import TabsService from '@renderer/services/TabsService'
|
||||||
import { getWebviewLoaded, onWebviewStateChange, setWebviewLoaded } from '@renderer/utils/webviewStateManager'
|
import { getWebviewLoaded, onWebviewStateChange, setWebviewLoaded } from '@renderer/utils/webviewStateManager'
|
||||||
|
import { useNavigate, useParams } from '@tanstack/react-router'
|
||||||
import type { WebviewTag } from 'electron'
|
import type { WebviewTag } from 'electron'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useNavigate, useParams } from 'react-router-dom'
|
|
||||||
import BeatLoader from 'react-spinners/BeatLoader'
|
import BeatLoader from 'react-spinners/BeatLoader'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ import WebviewSearch from './components/WebviewSearch'
|
|||||||
const logger = loggerService.withContext('MinAppPage')
|
const logger = loggerService.withContext('MinAppPage')
|
||||||
|
|
||||||
const MinAppPage: FC = () => {
|
const MinAppPage: FC = () => {
|
||||||
const { appId } = useParams<{ appId: string }>()
|
const { appId } = useParams({ strict: false }) as { appId: string }
|
||||||
const { isTopNavbar } = useNavbarPosition()
|
const { isTopNavbar } = useNavbarPosition()
|
||||||
const { openMinappKeepAlive, minAppsCache } = useMinappPopup()
|
const { openMinappKeepAlive, minAppsCache } = useMinappPopup()
|
||||||
const { minapps } = useMinapps()
|
const { minapps } = useMinapps()
|
||||||
@ -64,7 +64,7 @@ const MinAppPage: FC = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// If app not found, redirect to apps list
|
// If app not found, redirect to apps list
|
||||||
if (!app) {
|
if (!app) {
|
||||||
navigate('/apps')
|
navigate({ to: '/apps' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ const MinAppPage: FC = () => {
|
|||||||
// Only check once and only if we haven't already redirected
|
// Only check once and only if we haven't already redirected
|
||||||
if (!initialIsTopNavbar.current && !hasRedirected.current) {
|
if (!initialIsTopNavbar.current && !hasRedirected.current) {
|
||||||
hasRedirected.current = true
|
hasRedirected.current = true
|
||||||
navigate('/apps')
|
navigate({ to: '/apps' })
|
||||||
// Open popup after navigation
|
// Open popup after navigation
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
openMinappKeepAlive(app)
|
openMinappKeepAlive(app)
|
||||||
|
|||||||
@ -15,11 +15,11 @@ import { isDev } from '@renderer/config/constant'
|
|||||||
import { DEFAULT_MIN_APPS } from '@renderer/config/minapps'
|
import { DEFAULT_MIN_APPS } from '@renderer/config/minapps'
|
||||||
import { useMinapps } from '@renderer/hooks/useMinapps'
|
import { useMinapps } from '@renderer/hooks/useMinapps'
|
||||||
import type { MinAppType } from '@renderer/types'
|
import type { MinAppType } from '@renderer/types'
|
||||||
|
import { useNavigate } from '@tanstack/react-router'
|
||||||
import type { WebviewTag } from 'electron'
|
import type { WebviewTag } from 'electron'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
const logger = loggerService.withContext('MinimalToolbar')
|
const logger = loggerService.withContext('MinimalToolbar')
|
||||||
@ -213,7 +213,7 @@ const MinimalToolbar: FC<Props> = ({ app, webviewRef, currentUrl, onReload, onOp
|
|||||||
}, [app.id, webviewRef, scheduleNavigationUpdate])
|
}, [app.id, webviewRef, scheduleNavigationUpdate])
|
||||||
|
|
||||||
const handleMinimize = useCallback(() => {
|
const handleMinimize = useCallback(() => {
|
||||||
navigate('/apps')
|
navigate({ to: '/apps' })
|
||||||
}, [navigate])
|
}, [navigate])
|
||||||
|
|
||||||
const handleTogglePin = useCallback(() => {
|
const handleTogglePin = useCallback(() => {
|
||||||
|
|||||||
@ -19,12 +19,12 @@ import { translateText } from '@renderer/services/TranslateService'
|
|||||||
import type { FileMetadata } from '@renderer/types'
|
import type { FileMetadata } from '@renderer/types'
|
||||||
import type { PaintingAction, PaintingsState } from '@renderer/types'
|
import type { PaintingAction, PaintingsState } from '@renderer/types'
|
||||||
import { getErrorMessage, uuid } from '@renderer/utils'
|
import { getErrorMessage, uuid } from '@renderer/utils'
|
||||||
|
import { useLocation, useNavigate } from '@tanstack/react-router'
|
||||||
import { Input, InputNumber, Radio, Segmented, Select, Slider, Upload } from 'antd'
|
import { Input, InputNumber, Radio, Segmented, Select, Slider, Upload } from 'antd'
|
||||||
import TextArea from 'antd/es/input/TextArea'
|
import TextArea from 'antd/es/input/TextArea'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import SendMessageButton from '../home/Inputbar/SendMessageButton'
|
import SendMessageButton from '../home/Inputbar/SendMessageButton'
|
||||||
@ -667,7 +667,7 @@ const AihubmixPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
const handleProviderChange = (providerId: string) => {
|
const handleProviderChange = (providerId: string) => {
|
||||||
const routeName = location.pathname.split('/').pop()
|
const routeName = location.pathname.split('/').pop()
|
||||||
if (providerId !== routeName) {
|
if (providerId !== routeName) {
|
||||||
navigate('../' + providerId, { replace: true })
|
navigate({ to: '../' + providerId, replace: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,13 +11,13 @@ import { useAllProviders } from '@renderer/hooks/useProvider'
|
|||||||
import FileManager from '@renderer/services/FileManager'
|
import FileManager from '@renderer/services/FileManager'
|
||||||
import type { FileMetadata } from '@renderer/types'
|
import type { FileMetadata } from '@renderer/types'
|
||||||
import { convertToBase64, uuid } from '@renderer/utils'
|
import { convertToBase64, uuid } from '@renderer/utils'
|
||||||
|
import { useLocation, useNavigate } from '@tanstack/react-router'
|
||||||
import type { DmxapiPainting } from '@types'
|
import type { DmxapiPainting } from '@types'
|
||||||
import { Input, InputNumber, Segmented, Select } from 'antd'
|
import { Input, InputNumber, Segmented, Select } from 'antd'
|
||||||
import TextArea from 'antd/es/input/TextArea'
|
import TextArea from 'antd/es/input/TextArea'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React, { useEffect, useRef, useState } from 'react'
|
import React, { useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import { generationModeType } from '../../types'
|
import { generationModeType } from '../../types'
|
||||||
@ -640,7 +640,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
const handleProviderChange = (providerId: string) => {
|
const handleProviderChange = (providerId: string) => {
|
||||||
const routeName = location.pathname.split('/').pop()
|
const routeName = location.pathname.split('/').pop()
|
||||||
if (providerId !== routeName) {
|
if (providerId !== routeName) {
|
||||||
navigate('../' + providerId, { replace: true })
|
navigate({ to: '../' + providerId, replace: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,13 +29,13 @@ import type { PaintingAction, PaintingsState } from '@renderer/types'
|
|||||||
import type { FileMetadata } from '@renderer/types'
|
import type { FileMetadata } from '@renderer/types'
|
||||||
import { getErrorMessage, uuid } from '@renderer/utils'
|
import { getErrorMessage, uuid } from '@renderer/utils'
|
||||||
import { isNewApiProvider } from '@renderer/utils/provider'
|
import { isNewApiProvider } from '@renderer/utils/provider'
|
||||||
|
import { useLocation, useNavigate } from '@tanstack/react-router'
|
||||||
import { Empty, InputNumber, Segmented, Select, Upload } from 'antd'
|
import { Empty, InputNumber, Segmented, Select, Upload } from 'antd'
|
||||||
import TextArea from 'antd/es/input/TextArea'
|
import TextArea from 'antd/es/input/TextArea'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import SendMessageButton from '../home/Inputbar/SendMessageButton'
|
import SendMessageButton from '../home/Inputbar/SendMessageButton'
|
||||||
@ -436,7 +436,7 @@ const NewApiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
const handleProviderChange = (providerId: string) => {
|
const handleProviderChange = (providerId: string) => {
|
||||||
const routeName = location.pathname.split('/').pop()
|
const routeName = location.pathname.split('/').pop()
|
||||||
if (providerId !== routeName) {
|
if (providerId !== routeName) {
|
||||||
navigate('../' + providerId, { replace: true })
|
navigate({ to: '../' + providerId, replace: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,7 +463,7 @@ const NewApiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
|
|
||||||
// 当 modelOptions 为空时,引导用户跳转到 Provider 设置页面,新增 image-generation 端点模型
|
// 当 modelOptions 为空时,引导用户跳转到 Provider 设置页面,新增 image-generation 端点模型
|
||||||
const handleShowAddModelPopup = () => {
|
const handleShowAddModelPopup = () => {
|
||||||
navigate(`/settings/provider?id=${newApiProvider.id}`)
|
navigate({ to: `/settings/provider?id=${newApiProvider.id}` })
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -15,13 +15,13 @@ import FileManager from '@renderer/services/FileManager'
|
|||||||
import { translateText } from '@renderer/services/TranslateService'
|
import { translateText } from '@renderer/services/TranslateService'
|
||||||
import type { FileMetadata, OvmsPainting } from '@renderer/types'
|
import type { FileMetadata, OvmsPainting } from '@renderer/types'
|
||||||
import { getErrorMessage, uuid } from '@renderer/utils'
|
import { getErrorMessage, uuid } from '@renderer/utils'
|
||||||
|
import { useLocation, useNavigate } from '@tanstack/react-router'
|
||||||
import { Avatar, Input, InputNumber, Select, Slider } from 'antd'
|
import { Avatar, Input, InputNumber, Select, Slider } from 'antd'
|
||||||
import TextArea from 'antd/es/input/TextArea'
|
import TextArea from 'antd/es/input/TextArea'
|
||||||
import { Info } from 'lucide-react'
|
import { Info } from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import SendMessageButton from '../home/Inputbar/SendMessageButton'
|
import SendMessageButton from '../home/Inputbar/SendMessageButton'
|
||||||
@ -330,7 +330,7 @@ const OvmsPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
const handleProviderChange = (providerId: string) => {
|
const handleProviderChange = (providerId: string) => {
|
||||||
const routeName = location.pathname.split('/').pop()
|
const routeName = location.pathname.split('/').pop()
|
||||||
if (providerId !== routeName) {
|
if (providerId !== routeName) {
|
||||||
navigate('../' + providerId, { replace: true })
|
navigate({ to: '../' + providerId, replace: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,9 +5,9 @@ import { setDefaultPaintingProvider } from '@renderer/store/settings'
|
|||||||
import { updateTab } from '@renderer/store/tabs'
|
import { updateTab } from '@renderer/store/tabs'
|
||||||
import type { PaintingProvider, SystemProviderId } from '@renderer/types'
|
import type { PaintingProvider, SystemProviderId } from '@renderer/types'
|
||||||
import { isNewApiProvider } from '@renderer/utils/provider'
|
import { isNewApiProvider } from '@renderer/utils/provider'
|
||||||
|
import { useParams } from '@tanstack/react-router'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
import { Route, Routes, useParams } from 'react-router-dom'
|
|
||||||
|
|
||||||
import AihubmixPage from './AihubmixPage'
|
import AihubmixPage from './AihubmixPage'
|
||||||
import DmxapiPage from './DmxapiPage'
|
import DmxapiPage from './DmxapiPage'
|
||||||
@ -22,8 +22,8 @@ const logger = loggerService.withContext('PaintingsRoutePage')
|
|||||||
const BASE_OPTIONS: SystemProviderId[] = ['zhipu', 'aihubmix', 'silicon', 'dmxapi', 'tokenflux', 'ovms']
|
const BASE_OPTIONS: SystemProviderId[] = ['zhipu', 'aihubmix', 'silicon', 'dmxapi', 'tokenflux', 'ovms']
|
||||||
|
|
||||||
const PaintingsRoutePage: FC = () => {
|
const PaintingsRoutePage: FC = () => {
|
||||||
const params = useParams()
|
const params = useParams({ strict: false }) as { _splat?: string }
|
||||||
const provider = params['*']
|
const provider = params._splat
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const providers = useAllProviders()
|
const providers = useAllProviders()
|
||||||
const [ovmsStatus, setOvmsStatus] = useState<'not-installed' | 'not-running' | 'running'>('not-running')
|
const [ovmsStatus, setOvmsStatus] = useState<'not-installed' | 'not-running' | 'running'>('not-running')
|
||||||
@ -49,22 +49,34 @@ const PaintingsRoutePage: FC = () => {
|
|||||||
}
|
}
|
||||||
}, [provider, dispatch, validOptions])
|
}, [provider, dispatch, validOptions])
|
||||||
|
|
||||||
return (
|
// 根据 provider 渲染对应的页面
|
||||||
<Routes>
|
const renderPage = () => {
|
||||||
<Route path="*" element={<NewApiPage Options={validOptions} />} />
|
switch (provider) {
|
||||||
<Route path="/zhipu" element={<ZhipuPage Options={validOptions} />} />
|
case 'zhipu':
|
||||||
<Route path="/aihubmix" element={<AihubmixPage Options={validOptions} />} />
|
return <ZhipuPage Options={validOptions} />
|
||||||
<Route path="/silicon" element={<SiliconPage Options={validOptions} />} />
|
case 'aihubmix':
|
||||||
<Route path="/dmxapi" element={<DmxapiPage Options={validOptions} />} />
|
return <AihubmixPage Options={validOptions} />
|
||||||
<Route path="/tokenflux" element={<TokenFluxPage Options={validOptions} />} />
|
case 'silicon':
|
||||||
<Route path="/ovms" element={<OvmsPage Options={validOptions} />} />
|
return <SiliconPage Options={validOptions} />
|
||||||
<Route path="/new-api" element={<NewApiPage Options={validOptions} />} />
|
case 'dmxapi':
|
||||||
{/* new-api family providers are mounted dynamically below */}
|
return <DmxapiPage Options={validOptions} />
|
||||||
{newApiProviders.map((p) => (
|
case 'tokenflux':
|
||||||
<Route key={p.id} path={`/${p.id}`} element={<NewApiPage Options={validOptions} />} />
|
return <TokenFluxPage Options={validOptions} />
|
||||||
))}
|
case 'ovms':
|
||||||
</Routes>
|
return <OvmsPage Options={validOptions} />
|
||||||
)
|
case 'new-api':
|
||||||
|
return <NewApiPage Options={validOptions} />
|
||||||
|
default:
|
||||||
|
// 检查是否是 new-api 家族的 provider
|
||||||
|
if (provider && newApiProviders.some((p) => p.id === provider)) {
|
||||||
|
return <NewApiPage Options={validOptions} />
|
||||||
|
}
|
||||||
|
// 默认页面
|
||||||
|
return <NewApiPage Options={validOptions} />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PaintingsRoutePage
|
export default PaintingsRoutePage
|
||||||
|
|||||||
@ -23,12 +23,12 @@ import FileManager from '@renderer/services/FileManager'
|
|||||||
import { translateText } from '@renderer/services/TranslateService'
|
import { translateText } from '@renderer/services/TranslateService'
|
||||||
import type { FileMetadata, Painting } from '@renderer/types'
|
import type { FileMetadata, Painting } from '@renderer/types'
|
||||||
import { getErrorMessage, uuid } from '@renderer/utils'
|
import { getErrorMessage, uuid } from '@renderer/utils'
|
||||||
|
import { useLocation, useNavigate } from '@tanstack/react-router'
|
||||||
import { Input, InputNumber, Radio, Select, Slider } from 'antd'
|
import { Input, InputNumber, Radio, Select, Slider } from 'antd'
|
||||||
import TextArea from 'antd/es/input/TextArea'
|
import TextArea from 'antd/es/input/TextArea'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import SendMessageButton from '../home/Inputbar/SendMessageButton'
|
import SendMessageButton from '../home/Inputbar/SendMessageButton'
|
||||||
@ -333,7 +333,7 @@ const SiliconPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
const handleProviderChange = (providerId: string) => {
|
const handleProviderChange = (providerId: string) => {
|
||||||
const routeName = location.pathname.split('/').pop()
|
const routeName = location.pathname.split('/').pop()
|
||||||
if (providerId !== routeName) {
|
if (providerId !== routeName) {
|
||||||
navigate('../' + providerId, { replace: true })
|
navigate({ to: '../' + providerId, replace: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,12 +15,12 @@ import FileManager from '@renderer/services/FileManager'
|
|||||||
import { translateText } from '@renderer/services/TranslateService'
|
import { translateText } from '@renderer/services/TranslateService'
|
||||||
import type { TokenFluxPainting } from '@renderer/types'
|
import type { TokenFluxPainting } from '@renderer/types'
|
||||||
import { getErrorMessage, uuid } from '@renderer/utils'
|
import { getErrorMessage, uuid } from '@renderer/utils'
|
||||||
|
import { useLocation, useNavigate } from '@tanstack/react-router'
|
||||||
import { Select } from 'antd'
|
import { Select } from 'antd'
|
||||||
import TextArea from 'antd/es/input/TextArea'
|
import TextArea from 'antd/es/input/TextArea'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import SendMessageButton from '../home/Inputbar/SendMessageButton'
|
import SendMessageButton from '../home/Inputbar/SendMessageButton'
|
||||||
@ -268,7 +268,7 @@ const TokenFluxPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
const handleProviderChange = (providerId: string) => {
|
const handleProviderChange = (providerId: string) => {
|
||||||
const routeName = location.pathname.split('/').pop()
|
const routeName = location.pathname.split('/').pop()
|
||||||
if (providerId !== routeName) {
|
if (providerId !== routeName) {
|
||||||
navigate('../' + providerId, { replace: true })
|
navigate({ to: '../' + providerId, replace: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,12 +12,12 @@ import { usePaintings } from '@renderer/hooks/usePaintings'
|
|||||||
import { useAllProviders } from '@renderer/hooks/useProvider'
|
import { useAllProviders } from '@renderer/hooks/useProvider'
|
||||||
import FileManager from '@renderer/services/FileManager'
|
import FileManager from '@renderer/services/FileManager'
|
||||||
import { getErrorMessage, uuid } from '@renderer/utils'
|
import { getErrorMessage, uuid } from '@renderer/utils'
|
||||||
|
import { useLocation, useNavigate } from '@tanstack/react-router'
|
||||||
import { InputNumber, Radio, Select } from 'antd'
|
import { InputNumber, Radio, Select } from 'antd'
|
||||||
import TextArea from 'antd/es/input/TextArea'
|
import TextArea from 'antd/es/input/TextArea'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import SendMessageButton from '../home/Inputbar/SendMessageButton'
|
import SendMessageButton from '../home/Inputbar/SendMessageButton'
|
||||||
@ -260,7 +260,7 @@ const ZhipuPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
const handleProviderChange = (providerId: string) => {
|
const handleProviderChange = (providerId: string) => {
|
||||||
const routeName = location.pathname.split('/').pop()
|
const routeName = location.pathname.split('/').pop()
|
||||||
if (providerId !== routeName) {
|
if (providerId !== routeName) {
|
||||||
navigate('../' + providerId, { replace: true })
|
navigate({ to: '../' + providerId, replace: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ export function checkProviderEnabled(provider: Provider, t: TFunction): Promise<
|
|||||||
closable: true,
|
closable: true,
|
||||||
okText: t('common.go_to_settings'),
|
okText: t('common.go_to_settings'),
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
window.navigate?.(`/settings/provider?id=${provider.id}`)
|
window.navigate?.({ to: `/settings/provider`, search: { id: provider.id } })
|
||||||
reject('Provider disabled')
|
reject('Provider disabled')
|
||||||
},
|
},
|
||||||
onCancel: () => reject('Provider disabled')
|
onCancel: () => reject('Provider disabled')
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import i18n from '@renderer/i18n'
|
|||||||
// import { setUpdateState as setAppUpdateState } from '@renderer/store/runtime'
|
// import { setUpdateState as setAppUpdateState } from '@renderer/store/runtime'
|
||||||
import { runAsyncFunction } from '@renderer/utils'
|
import { runAsyncFunction } from '@renderer/utils'
|
||||||
import { ThemeMode, UpgradeChannel } from '@shared/data/preference/preferenceTypes'
|
import { ThemeMode, UpgradeChannel } from '@shared/data/preference/preferenceTypes'
|
||||||
|
import { Link } from '@tanstack/react-router'
|
||||||
import { Avatar, Progress, Radio, Row, Tag } from 'antd'
|
import { Avatar, Progress, Radio, Row, Tag } from 'antd'
|
||||||
import { debounce } from 'lodash'
|
import { debounce } from 'lodash'
|
||||||
import { Bug, Building2, Github, Globe, Mail, Rss } from 'lucide-react'
|
import { Bug, Building2, Github, Globe, Mail, Rss } from 'lucide-react'
|
||||||
@ -21,7 +22,6 @@ import type { FC } from 'react'
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import Markdown from 'react-markdown'
|
import Markdown from 'react-markdown'
|
||||||
import { Link } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import { SettingContainer, SettingDivider, SettingGroup, SettingRow, SettingTitle } from '.'
|
import { SettingContainer, SettingDivider, SettingGroup, SettingRow, SettingTitle } from '.'
|
||||||
|
|||||||
@ -3,11 +3,11 @@ import { Center, ColFlex } from '@cherrystudio/ui'
|
|||||||
import { Button } from '@cherrystudio/ui'
|
import { Button } from '@cherrystudio/ui'
|
||||||
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
import { useAppDispatch, useAppSelector } from '@renderer/store'
|
||||||
import { setIsBunInstalled, setIsUvInstalled } from '@renderer/store/mcp'
|
import { setIsBunInstalled, setIsUvInstalled } from '@renderer/store/mcp'
|
||||||
|
import { useNavigate } from '@tanstack/react-router'
|
||||||
import { Alert } from 'antd'
|
import { Alert } from 'antd'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import { SettingDescription, SettingRow, SettingSubtitle } from '..'
|
import { SettingDescription, SettingRow, SettingSubtitle } from '..'
|
||||||
@ -87,7 +87,7 @@ const InstallNpxUv: FC<Props> = ({ mini = false }) => {
|
|||||||
<Button
|
<Button
|
||||||
className="nodrag rounded-full"
|
className="nodrag rounded-full"
|
||||||
variant={installed ? 'default' : 'destructive'}
|
variant={installed ? 'default' : 'destructive'}
|
||||||
onClick={() => navigate('/settings/mcp/mcp-install')}
|
onClick={() => navigate({ to: '/settings/mcp/mcp-install' })}
|
||||||
size="icon">
|
size="icon">
|
||||||
{installed ? <CheckCircleOutlined /> : <WarningOutlined />}
|
{installed ? <CheckCircleOutlined /> : <WarningOutlined />}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -9,12 +9,12 @@ import { useMCPServerTrust } from '@renderer/hooks/useMCPServerTrust'
|
|||||||
import type { MCPServer } from '@renderer/types'
|
import type { MCPServer } from '@renderer/types'
|
||||||
import { formatMcpError } from '@renderer/utils/error'
|
import { formatMcpError } from '@renderer/utils/error'
|
||||||
import { matchKeywordsInString } from '@renderer/utils/match'
|
import { matchKeywordsInString } from '@renderer/utils/match'
|
||||||
|
import { useNavigate } from '@tanstack/react-router'
|
||||||
import { Button, Dropdown, Empty } from 'antd'
|
import { Button, Dropdown, Empty } from 'antd'
|
||||||
import { Plus } from 'lucide-react'
|
import { Plus } from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { startTransition, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
import { startTransition, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import { SettingTitle } from '..'
|
import { SettingTitle } from '..'
|
||||||
@ -115,7 +115,7 @@ const McpServersList: FC = () => {
|
|||||||
isActive: false
|
isActive: false
|
||||||
}
|
}
|
||||||
addMCPServer(newServer)
|
addMCPServer(newServer)
|
||||||
navigate(`/settings/mcp/settings/${encodeURIComponent(newServer.id)}`)
|
navigate({ to: `/settings/mcp/settings/${encodeURIComponent(newServer.id)}` })
|
||||||
window.toast.success(t('settings.mcp.addSuccess'))
|
window.toast.success(t('settings.mcp.addSuccess'))
|
||||||
}, [addMCPServer, navigate, t])
|
}, [addMCPServer, navigate, t])
|
||||||
|
|
||||||
@ -260,7 +260,7 @@ const McpServersList: FC = () => {
|
|||||||
isLoading={loadingServerIds.has(server.id)}
|
isLoading={loadingServerIds.has(server.id)}
|
||||||
onToggle={async (active) => await handleToggleActive(server, active)}
|
onToggle={async (active) => await handleToggleActive(server, active)}
|
||||||
onDelete={() => onDeleteMcpServer(server)}
|
onDelete={() => onDeleteMcpServer(server)}
|
||||||
onEdit={() => navigate(`/settings/mcp/settings/${encodeURIComponent(server.id)}`)}
|
onEdit={() => navigate({ to: `/settings/mcp/settings/${encodeURIComponent(server.id)}` })}
|
||||||
onOpenUrl={(url) => window.open(url, '_blank')}
|
onOpenUrl={(url) => window.open(url, '_blank')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -11,13 +11,13 @@ import MCPDescription from '@renderer/pages/settings/MCPSettings/McpDescription'
|
|||||||
import type { MCPPrompt, MCPResource, MCPServer, MCPTool } from '@renderer/types'
|
import type { MCPPrompt, MCPResource, MCPServer, MCPTool } from '@renderer/types'
|
||||||
import { parseKeyValueString } from '@renderer/utils/env'
|
import { parseKeyValueString } from '@renderer/utils/env'
|
||||||
import { formatMcpError } from '@renderer/utils/error'
|
import { formatMcpError } from '@renderer/utils/error'
|
||||||
|
import { useNavigate, useParams } from '@tanstack/react-router'
|
||||||
import type { TabsProps } from 'antd'
|
import type { TabsProps } from 'antd'
|
||||||
import { Badge, Form, Input, Radio, Select, Tabs } from 'antd'
|
import { Badge, Form, Input, Radio, Select, Tabs } from 'antd'
|
||||||
import TextArea from 'antd/es/input/TextArea'
|
import TextArea from 'antd/es/input/TextArea'
|
||||||
import { ChevronDown, SaveIcon } from 'lucide-react'
|
import { ChevronDown, SaveIcon } from 'lucide-react'
|
||||||
import React, { useCallback, useEffect, useState } from 'react'
|
import React, { useCallback, useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate, useParams } from 'react-router'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import { SettingContainer, SettingDivider, SettingGroup, SettingTitle } from '..'
|
import { SettingContainer, SettingDivider, SettingGroup, SettingTitle } from '..'
|
||||||
@ -68,7 +68,8 @@ type TabKey = 'settings' | 'description' | 'tools' | 'prompts' | 'resources'
|
|||||||
|
|
||||||
const McpSettings: React.FC = () => {
|
const McpSettings: React.FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { serverId } = useParams<{ serverId: string }>()
|
const params = useParams({ strict: false }) as { serverId?: string }
|
||||||
|
const serverId = params.serverId
|
||||||
const decodedServerId = serverId ? decodeURIComponent(serverId) : ''
|
const decodedServerId = serverId ? decodeURIComponent(serverId) : ''
|
||||||
const server = useMCPServer(decodedServerId).server as MCPServer
|
const server = useMCPServer(decodedServerId).server as MCPServer
|
||||||
const { deleteMCPServer, updateMCPServer } = useMCPServers()
|
const { deleteMCPServer, updateMCPServer } = useMCPServers()
|
||||||
@ -376,7 +377,7 @@ const McpSettings: React.FC = () => {
|
|||||||
await window.api.mcp.removeServer(server)
|
await window.api.mcp.removeServer(server)
|
||||||
deleteMCPServer(server.id)
|
deleteMCPServer(server.id)
|
||||||
window.toast.success(t('settings.mcp.deleteSuccess'))
|
window.toast.success(t('settings.mcp.deleteSuccess'))
|
||||||
navigate('/settings/mcp')
|
navigate({ to: '/settings/mcp' })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|||||||
@ -8,30 +8,17 @@ import TokenFluxProviderLogo from '@renderer/assets/images/providers/tokenflux.p
|
|||||||
import DividerWithText from '@renderer/components/DividerWithText'
|
import DividerWithText from '@renderer/components/DividerWithText'
|
||||||
import ListItem from '@renderer/components/ListItem'
|
import ListItem from '@renderer/components/ListItem'
|
||||||
import Scrollbar from '@renderer/components/Scrollbar'
|
import Scrollbar from '@renderer/components/Scrollbar'
|
||||||
import { useTheme } from '@renderer/context/ThemeProvider'
|
import { Link, Outlet, useLocation, useNavigate } from '@tanstack/react-router'
|
||||||
import { useMCPServers } from '@renderer/hooks/useMCPServers'
|
|
||||||
import { Button, Flex } from 'antd'
|
import { Button, Flex } from 'antd'
|
||||||
import { FolderCog, Package, ShoppingBag } from 'lucide-react'
|
import { FolderCog, Package, ShoppingBag } from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router'
|
|
||||||
import { Link } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import { SettingContainer } from '..'
|
|
||||||
import BuiltinMCPServerList from './BuiltinMCPServerList'
|
|
||||||
import InstallNpxUv from './InstallNpxUv'
|
|
||||||
import McpMarketList from './McpMarketList'
|
|
||||||
import ProviderDetail from './McpProviderSettings'
|
|
||||||
import McpServersList from './McpServersList'
|
|
||||||
import McpSettings from './McpSettings'
|
|
||||||
import NpxSearch from './NpxSearch'
|
|
||||||
import { providers } from './providers/config'
|
import { providers } from './providers/config'
|
||||||
|
|
||||||
const MCPSettings: FC = () => {
|
const MCPSettings: FC = () => {
|
||||||
const { theme } = useTheme()
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { mcpServers } = useMCPServers()
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
|
||||||
@ -84,7 +71,7 @@ const MCPSettings: FC = () => {
|
|||||||
<ListItem
|
<ListItem
|
||||||
title={t('settings.mcp.servers', 'MCP Servers')}
|
title={t('settings.mcp.servers', 'MCP Servers')}
|
||||||
active={activeView === 'servers'}
|
active={activeView === 'servers'}
|
||||||
onClick={() => navigate('/settings/mcp/servers')}
|
onClick={() => navigate({ to: '/settings/mcp/servers' })}
|
||||||
icon={<FolderCog size={18} />}
|
icon={<FolderCog size={18} />}
|
||||||
titleStyle={{ fontWeight: 500 }}
|
titleStyle={{ fontWeight: 500 }}
|
||||||
/>
|
/>
|
||||||
@ -92,14 +79,14 @@ const MCPSettings: FC = () => {
|
|||||||
<ListItem
|
<ListItem
|
||||||
title={t('settings.mcp.builtinServers', 'Built-in Servers')}
|
title={t('settings.mcp.builtinServers', 'Built-in Servers')}
|
||||||
active={activeView === 'builtin'}
|
active={activeView === 'builtin'}
|
||||||
onClick={() => navigate('/settings/mcp/builtin')}
|
onClick={() => navigate({ to: '/settings/mcp/builtin' })}
|
||||||
icon={<Package size={18} />}
|
icon={<Package size={18} />}
|
||||||
titleStyle={{ fontWeight: 500 }}
|
titleStyle={{ fontWeight: 500 }}
|
||||||
/>
|
/>
|
||||||
<ListItem
|
<ListItem
|
||||||
title={t('settings.mcp.marketplaces', 'Marketplaces')}
|
title={t('settings.mcp.marketplaces', 'Marketplaces')}
|
||||||
active={activeView === 'marketplaces'}
|
active={activeView === 'marketplaces'}
|
||||||
onClick={() => navigate('/settings/mcp/marketplaces')}
|
onClick={() => navigate({ to: '/settings/mcp/marketplaces' })}
|
||||||
icon={<ShoppingBag size={18} />}
|
icon={<ShoppingBag size={18} />}
|
||||||
titleStyle={{ fontWeight: 500 }}
|
titleStyle={{ fontWeight: 500 }}
|
||||||
/>
|
/>
|
||||||
@ -109,7 +96,7 @@ const MCPSettings: FC = () => {
|
|||||||
key={provider.key}
|
key={provider.key}
|
||||||
title={provider.name}
|
title={provider.name}
|
||||||
active={activeView === provider.key}
|
active={activeView === provider.key}
|
||||||
onClick={() => navigate(`/settings/mcp/${provider.key}`)}
|
onClick={() => navigate({ to: `/settings/mcp/${provider.key}` })}
|
||||||
icon={providerIcons[provider.key] || <FolderCog size={16} />}
|
icon={providerIcons[provider.key] || <FolderCog size={16} />}
|
||||||
titleStyle={{ fontWeight: 500 }}
|
titleStyle={{ fontWeight: 500 }}
|
||||||
/>
|
/>
|
||||||
@ -125,50 +112,7 @@ const MCPSettings: FC = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
</BackButtonContainer>
|
</BackButtonContainer>
|
||||||
)}
|
)}
|
||||||
<Routes>
|
<Outlet />
|
||||||
<Route index element={<Navigate to="servers" replace />} />
|
|
||||||
<Route path="servers" element={<McpServersList />} />
|
|
||||||
<Route path="settings/:serverId" element={<McpSettings />} />
|
|
||||||
<Route
|
|
||||||
path="npx-search"
|
|
||||||
element={
|
|
||||||
<SettingContainer theme={theme}>
|
|
||||||
<NpxSearch />
|
|
||||||
</SettingContainer>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="mcp-install"
|
|
||||||
element={
|
|
||||||
<SettingContainer style={{ backgroundColor: 'inherit' }}>
|
|
||||||
<InstallNpxUv />
|
|
||||||
</SettingContainer>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="builtin"
|
|
||||||
element={
|
|
||||||
<ContentWrapper>
|
|
||||||
<BuiltinMCPServerList />
|
|
||||||
</ContentWrapper>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Route
|
|
||||||
path="marketplaces"
|
|
||||||
element={
|
|
||||||
<ContentWrapper>
|
|
||||||
<McpMarketList />
|
|
||||||
</ContentWrapper>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{providers.map((provider) => (
|
|
||||||
<Route
|
|
||||||
key={provider.key}
|
|
||||||
path={provider.key}
|
|
||||||
element={<ProviderDetail provider={provider} existingServers={mcpServers} />}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Routes>
|
|
||||||
</RightContainer>
|
</RightContainer>
|
||||||
</MainContainer>
|
</MainContainer>
|
||||||
</Container>
|
</Container>
|
||||||
@ -212,12 +156,6 @@ const ProviderIcon = styled.img`
|
|||||||
background-color: var(--color-background-soft);
|
background-color: var(--color-background-soft);
|
||||||
`
|
`
|
||||||
|
|
||||||
const ContentWrapper = styled.div`
|
|
||||||
padding: 20px;
|
|
||||||
overflow-y: auto;
|
|
||||||
height: 100%;
|
|
||||||
`
|
|
||||||
|
|
||||||
const BackButtonContainer = styled.div`
|
const BackButtonContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@ -14,13 +14,13 @@ import ImageStorage from '@renderer/services/ImageStorage'
|
|||||||
import type { Provider, ProviderType } from '@renderer/types'
|
import type { Provider, ProviderType } from '@renderer/types'
|
||||||
import { isSystemProvider } from '@renderer/types'
|
import { isSystemProvider } from '@renderer/types'
|
||||||
import { getFancyProviderName, matchKeywordsInModel, matchKeywordsInProvider, uuid } from '@renderer/utils'
|
import { getFancyProviderName, matchKeywordsInModel, matchKeywordsInProvider, uuid } from '@renderer/utils'
|
||||||
|
import { useLocation, useNavigate, useSearch } from '@tanstack/react-router'
|
||||||
import type { MenuProps } from 'antd'
|
import type { MenuProps } from 'antd'
|
||||||
import { Dropdown, Input, Tag } from 'antd'
|
import { Dropdown, Input, Tag } from 'antd'
|
||||||
import { GripVertical, PlusIcon, Search, UserPen } from 'lucide-react'
|
import { GripVertical, PlusIcon, Search, UserPen } from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { startTransition, useCallback, useEffect, useRef, useState } from 'react'
|
import { startTransition, useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useSearchParams } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import AddProviderPopup from './AddProviderPopup'
|
import AddProviderPopup from './AddProviderPopup'
|
||||||
@ -35,7 +35,9 @@ const systemType = await window.api.system.getDeviceType()
|
|||||||
const cpuName = await window.api.system.getCpuName()
|
const cpuName = await window.api.system.getCpuName()
|
||||||
|
|
||||||
const ProviderList: FC = () => {
|
const ProviderList: FC = () => {
|
||||||
const [searchParams, setSearchParams] = useSearchParams()
|
const search = useSearch({ strict: false }) as Record<string, string | undefined>
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const location = useLocation()
|
||||||
const providers = useAllProviders()
|
const providers = useAllProviders()
|
||||||
const { updateProviders, addProvider, removeProvider, updateProvider } = useProviders()
|
const { updateProviders, addProvider, removeProvider, updateProvider } = useProviders()
|
||||||
const { setTimeoutTimer } = useTimer()
|
const { setTimeoutTimer } = useTimer()
|
||||||
@ -72,8 +74,8 @@ const ProviderList: FC = () => {
|
|||||||
}, [providers])
|
}, [providers])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (searchParams.get('id')) {
|
if (search.id) {
|
||||||
const providerId = searchParams.get('id')
|
const providerId = search.id
|
||||||
const provider = providers.find((p) => p.id === providerId)
|
const provider = providers.find((p) => p.id === providerId)
|
||||||
if (provider) {
|
if (provider) {
|
||||||
setSelectedProvider(provider)
|
setSelectedProvider(provider)
|
||||||
@ -89,10 +91,17 @@ const ProviderList: FC = () => {
|
|||||||
} else {
|
} else {
|
||||||
setSelectedProvider(providers[0])
|
setSelectedProvider(providers[0])
|
||||||
}
|
}
|
||||||
searchParams.delete('id')
|
// 清除 id 参数
|
||||||
setSearchParams(searchParams)
|
navigate({
|
||||||
|
to: location.pathname,
|
||||||
|
search: (prev) => {
|
||||||
|
const { id: _, ...rest } = prev as Record<string, unknown>
|
||||||
|
return rest
|
||||||
|
},
|
||||||
|
replace: true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}, [providers, searchParams, setSearchParams, setSelectedProvider, setTimeoutTimer])
|
}, [providers, search.id, navigate, location.pathname, setSelectedProvider, setTimeoutTimer])
|
||||||
|
|
||||||
// Handle provider add key from URL schema
|
// Handle provider add key from URL schema
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -106,7 +115,7 @@ const ProviderList: FC = () => {
|
|||||||
const { id } = data
|
const { id } = data
|
||||||
|
|
||||||
const { updatedProvider, isNew, displayName } = await UrlSchemaInfoPopup.show(data)
|
const { updatedProvider, isNew, displayName } = await UrlSchemaInfoPopup.show(data)
|
||||||
window.navigate(`/settings/provider?id=${id}`)
|
navigate({ to: '/settings/provider', search: { id } })
|
||||||
|
|
||||||
if (!updatedProvider) {
|
if (!updatedProvider) {
|
||||||
return
|
return
|
||||||
@ -123,7 +132,7 @@ const ProviderList: FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查 URL 参数
|
// 检查 URL 参数
|
||||||
const addProviderData = searchParams.get('addProviderData')
|
const addProviderData = search.addProviderData
|
||||||
if (!addProviderData) {
|
if (!addProviderData) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -132,17 +141,17 @@ const ProviderList: FC = () => {
|
|||||||
const { id, apiKey: newApiKey, baseUrl, type, name } = JSON.parse(addProviderData)
|
const { id, apiKey: newApiKey, baseUrl, type, name } = JSON.parse(addProviderData)
|
||||||
if (!id || !newApiKey || !baseUrl) {
|
if (!id || !newApiKey || !baseUrl) {
|
||||||
window.toast.error(t('settings.models.provider_key_add_failed_by_invalid_data'))
|
window.toast.error(t('settings.models.provider_key_add_failed_by_invalid_data'))
|
||||||
window.navigate('/settings/provider')
|
navigate({ to: '/settings/provider' })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
handleProviderAddKey({ id, apiKey: newApiKey, baseUrl, type, name })
|
handleProviderAddKey({ id, apiKey: newApiKey, baseUrl, type, name })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
window.toast.error(t('settings.models.provider_key_add_failed_by_invalid_data'))
|
window.toast.error(t('settings.models.provider_key_add_failed_by_invalid_data'))
|
||||||
window.navigate('/settings/provider')
|
navigate({ to: '/settings/provider' })
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [searchParams])
|
}, [search.addProviderData])
|
||||||
|
|
||||||
const onAddProvider = async () => {
|
const onAddProvider = async () => {
|
||||||
const { name: providerName, type, logo } = await AddProviderPopup.show()
|
const { name: providerName, type, logo } = await AddProviderPopup.show()
|
||||||
|
|||||||
@ -6,12 +6,12 @@ import { useTheme } from '@renderer/context/ThemeProvider'
|
|||||||
import { getSelectionDescriptionLabel } from '@renderer/i18n/label'
|
import { getSelectionDescriptionLabel } from '@renderer/i18n/label'
|
||||||
import SelectionToolbar from '@renderer/windows/selection/toolbar/SelectionToolbar'
|
import SelectionToolbar from '@renderer/windows/selection/toolbar/SelectionToolbar'
|
||||||
import type { SelectionFilterMode, SelectionTriggerMode } from '@shared/data/preference/preferenceTypes'
|
import type { SelectionFilterMode, SelectionTriggerMode } from '@shared/data/preference/preferenceTypes'
|
||||||
|
import { Link } from '@tanstack/react-router'
|
||||||
import { Row, Slider } from 'antd'
|
import { Row, Slider } from 'antd'
|
||||||
import { CircleHelp, Edit2 } from 'lucide-react'
|
import { CircleHelp, Edit2 } from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Link } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { GlobalOutlined } from '@ant-design/icons'
|
import { GlobalOutlined } from '@ant-design/icons'
|
||||||
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
|
import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
|
||||||
import Scrollbar from '@renderer/components/Scrollbar'
|
import Scrollbar from '@renderer/components/Scrollbar'
|
||||||
import ModelSettings from '@renderer/pages/settings/ModelSettings/ModelSettings'
|
import { Link, Outlet, useLocation } from '@tanstack/react-router'
|
||||||
import { Divider as AntDivider } from 'antd'
|
import { Divider as AntDivider } from 'antd'
|
||||||
import {
|
import {
|
||||||
Brain,
|
Brain,
|
||||||
@ -22,27 +22,11 @@ import {
|
|||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Link, Route, Routes, useLocation } from 'react-router-dom'
|
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
import AboutSettings from './AboutSettings'
|
|
||||||
import DataSettings from './DataSettings/DataSettings'
|
|
||||||
import DisplaySettings from './DisplaySettings/DisplaySettings'
|
|
||||||
import DocProcessSettings from './DocProcessSettings'
|
|
||||||
import GeneralSettings from './GeneralSettings'
|
|
||||||
import MCPSettings from './MCPSettings'
|
|
||||||
import MemorySettings from './MemorySettings'
|
|
||||||
import NotesSettings from './NotesSettings'
|
|
||||||
import { ProviderList } from './ProviderSettings'
|
|
||||||
import QuickAssistantSettings from './QuickAssistantSettings'
|
|
||||||
import QuickPhraseSettings from './QuickPhraseSettings'
|
|
||||||
import SelectionAssistantSettings from './SelectionAssistantSettings/SelectionAssistantSettings'
|
|
||||||
import ShortcutSettings from './ShortcutSettings'
|
|
||||||
import { ApiServerSettings } from './ToolSettings/ApiServerSettings'
|
|
||||||
import WebSearchSettings from './WebSearchSettings'
|
|
||||||
|
|
||||||
const SettingsPage: FC = () => {
|
const SettingsPage: FC = () => {
|
||||||
const { pathname } = useLocation()
|
const location = useLocation()
|
||||||
|
const { pathname } = location
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const isRoute = (path: string): string => (pathname.startsWith(path) ? 'active' : '')
|
const isRoute = (path: string): string => (pathname.startsWith(path) ? 'active' : '')
|
||||||
@ -156,24 +140,7 @@ const SettingsPage: FC = () => {
|
|||||||
</MenuItemLink>
|
</MenuItemLink>
|
||||||
</SettingMenus>
|
</SettingMenus>
|
||||||
<SettingContent>
|
<SettingContent>
|
||||||
<Routes>
|
<Outlet />
|
||||||
<Route path="provider" element={<ProviderList />} />
|
|
||||||
<Route path="model" element={<ModelSettings />} />
|
|
||||||
<Route path="websearch" element={<WebSearchSettings />} />
|
|
||||||
<Route path="api-server" element={<ApiServerSettings />} />
|
|
||||||
<Route path="docprocess" element={<DocProcessSettings />} />
|
|
||||||
<Route path="quickphrase" element={<QuickPhraseSettings />} />
|
|
||||||
<Route path="mcp/*" element={<MCPSettings />} />
|
|
||||||
<Route path="memory" element={<MemorySettings />} />
|
|
||||||
<Route path="general/*" element={<GeneralSettings />} />
|
|
||||||
<Route path="display" element={<DisplaySettings />} />
|
|
||||||
<Route path="shortcut" element={<ShortcutSettings />} />
|
|
||||||
<Route path="quickAssistant" element={<QuickAssistantSettings />} />
|
|
||||||
<Route path="selectionAssistant" element={<SelectionAssistantSettings />} />
|
|
||||||
<Route path="data" element={<DataSettings />} />
|
|
||||||
<Route path="notes" element={<NotesSettings />} />
|
|
||||||
<Route path="about" element={<AboutSettings />} />
|
|
||||||
</Routes>
|
|
||||||
</SettingContent>
|
</SettingContent>
|
||||||
</ContentContainer>
|
</ContentContainer>
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@ -9,48 +9,510 @@
|
|||||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
||||||
|
|
||||||
import { Route as rootRouteImport } from './routes/__root'
|
import { Route as rootRouteImport } from './routes/__root'
|
||||||
|
import { Route as TranslateRouteImport } from './routes/translate'
|
||||||
|
import { Route as StoreRouteImport } from './routes/store'
|
||||||
import { Route as SettingsRouteImport } from './routes/settings'
|
import { Route as SettingsRouteImport } from './routes/settings'
|
||||||
|
import { Route as NotesRouteImport } from './routes/notes'
|
||||||
|
import { Route as KnowledgeRouteImport } from './routes/knowledge'
|
||||||
|
import { Route as FilesRouteImport } from './routes/files'
|
||||||
|
import { Route as CodeRouteImport } from './routes/code'
|
||||||
|
import { Route as ChatRouteImport } from './routes/chat'
|
||||||
import { Route as IndexRouteImport } from './routes/index'
|
import { Route as IndexRouteImport } from './routes/index'
|
||||||
|
import { Route as SettingsIndexRouteImport } from './routes/settings/index'
|
||||||
|
import { Route as PaintingsIndexRouteImport } from './routes/paintings/index'
|
||||||
|
import { Route as AppsIndexRouteImport } from './routes/apps/index'
|
||||||
|
import { Route as SettingsWebsearchRouteImport } from './routes/settings/websearch'
|
||||||
|
import { Route as SettingsShortcutRouteImport } from './routes/settings/shortcut'
|
||||||
|
import { Route as SettingsSelectionAssistantRouteImport } from './routes/settings/selectionAssistant'
|
||||||
|
import { Route as SettingsQuickphraseRouteImport } from './routes/settings/quickphrase'
|
||||||
|
import { Route as SettingsQuickAssistantRouteImport } from './routes/settings/quickAssistant'
|
||||||
|
import { Route as SettingsProviderRouteImport } from './routes/settings/provider'
|
||||||
|
import { Route as SettingsNotesRouteImport } from './routes/settings/notes'
|
||||||
|
import { Route as SettingsModelRouteImport } from './routes/settings/model'
|
||||||
|
import { Route as SettingsMemoryRouteImport } from './routes/settings/memory'
|
||||||
|
import { Route as SettingsMcpRouteImport } from './routes/settings/mcp'
|
||||||
|
import { Route as SettingsGeneralRouteImport } from './routes/settings/general'
|
||||||
|
import { Route as SettingsDocprocessRouteImport } from './routes/settings/docprocess'
|
||||||
|
import { Route as SettingsDisplayRouteImport } from './routes/settings/display'
|
||||||
|
import { Route as SettingsDataRouteImport } from './routes/settings/data'
|
||||||
|
import { Route as SettingsApiServerRouteImport } from './routes/settings/api-server'
|
||||||
|
import { Route as SettingsAboutRouteImport } from './routes/settings/about'
|
||||||
|
import { Route as PaintingsSplatRouteImport } from './routes/paintings/$'
|
||||||
|
import { Route as AppsAppIdRouteImport } from './routes/apps/$appId'
|
||||||
|
import { Route as SettingsMcpIndexRouteImport } from './routes/settings/mcp/index'
|
||||||
|
import { Route as SettingsMcpServersRouteImport } from './routes/settings/mcp/servers'
|
||||||
|
import { Route as SettingsMcpNpxSearchRouteImport } from './routes/settings/mcp/npx-search'
|
||||||
|
import { Route as SettingsMcpMcpInstallRouteImport } from './routes/settings/mcp/mcp-install'
|
||||||
|
import { Route as SettingsMcpMarketplacesRouteImport } from './routes/settings/mcp/marketplaces'
|
||||||
|
import { Route as SettingsMcpBuiltinRouteImport } from './routes/settings/mcp/builtin'
|
||||||
|
import { Route as SettingsMcpSplatRouteImport } from './routes/settings/mcp/$'
|
||||||
|
import { Route as SettingsMcpSettingsServerIdRouteImport } from './routes/settings/mcp/settings.$serverId'
|
||||||
|
|
||||||
|
const TranslateRoute = TranslateRouteImport.update({
|
||||||
|
id: '/translate',
|
||||||
|
path: '/translate',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
const StoreRoute = StoreRouteImport.update({
|
||||||
|
id: '/store',
|
||||||
|
path: '/store',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
const SettingsRoute = SettingsRouteImport.update({
|
const SettingsRoute = SettingsRouteImport.update({
|
||||||
id: '/settings',
|
id: '/settings',
|
||||||
path: '/settings',
|
path: '/settings',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
|
const NotesRoute = NotesRouteImport.update({
|
||||||
|
id: '/notes',
|
||||||
|
path: '/notes',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
const KnowledgeRoute = KnowledgeRouteImport.update({
|
||||||
|
id: '/knowledge',
|
||||||
|
path: '/knowledge',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
const FilesRoute = FilesRouteImport.update({
|
||||||
|
id: '/files',
|
||||||
|
path: '/files',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
const CodeRoute = CodeRouteImport.update({
|
||||||
|
id: '/code',
|
||||||
|
path: '/code',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
const ChatRoute = ChatRouteImport.update({
|
||||||
|
id: '/chat',
|
||||||
|
path: '/chat',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
const IndexRoute = IndexRouteImport.update({
|
const IndexRoute = IndexRouteImport.update({
|
||||||
id: '/',
|
id: '/',
|
||||||
path: '/',
|
path: '/',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
|
const SettingsIndexRoute = SettingsIndexRouteImport.update({
|
||||||
|
id: '/',
|
||||||
|
path: '/',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const PaintingsIndexRoute = PaintingsIndexRouteImport.update({
|
||||||
|
id: '/paintings/',
|
||||||
|
path: '/paintings/',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
const AppsIndexRoute = AppsIndexRouteImport.update({
|
||||||
|
id: '/apps/',
|
||||||
|
path: '/apps/',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
const SettingsWebsearchRoute = SettingsWebsearchRouteImport.update({
|
||||||
|
id: '/websearch',
|
||||||
|
path: '/websearch',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsShortcutRoute = SettingsShortcutRouteImport.update({
|
||||||
|
id: '/shortcut',
|
||||||
|
path: '/shortcut',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsSelectionAssistantRoute =
|
||||||
|
SettingsSelectionAssistantRouteImport.update({
|
||||||
|
id: '/selectionAssistant',
|
||||||
|
path: '/selectionAssistant',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsQuickphraseRoute = SettingsQuickphraseRouteImport.update({
|
||||||
|
id: '/quickphrase',
|
||||||
|
path: '/quickphrase',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsQuickAssistantRoute = SettingsQuickAssistantRouteImport.update({
|
||||||
|
id: '/quickAssistant',
|
||||||
|
path: '/quickAssistant',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsProviderRoute = SettingsProviderRouteImport.update({
|
||||||
|
id: '/provider',
|
||||||
|
path: '/provider',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsNotesRoute = SettingsNotesRouteImport.update({
|
||||||
|
id: '/notes',
|
||||||
|
path: '/notes',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsModelRoute = SettingsModelRouteImport.update({
|
||||||
|
id: '/model',
|
||||||
|
path: '/model',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsMemoryRoute = SettingsMemoryRouteImport.update({
|
||||||
|
id: '/memory',
|
||||||
|
path: '/memory',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsMcpRoute = SettingsMcpRouteImport.update({
|
||||||
|
id: '/mcp',
|
||||||
|
path: '/mcp',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsGeneralRoute = SettingsGeneralRouteImport.update({
|
||||||
|
id: '/general',
|
||||||
|
path: '/general',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsDocprocessRoute = SettingsDocprocessRouteImport.update({
|
||||||
|
id: '/docprocess',
|
||||||
|
path: '/docprocess',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsDisplayRoute = SettingsDisplayRouteImport.update({
|
||||||
|
id: '/display',
|
||||||
|
path: '/display',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsDataRoute = SettingsDataRouteImport.update({
|
||||||
|
id: '/data',
|
||||||
|
path: '/data',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsApiServerRoute = SettingsApiServerRouteImport.update({
|
||||||
|
id: '/api-server',
|
||||||
|
path: '/api-server',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsAboutRoute = SettingsAboutRouteImport.update({
|
||||||
|
id: '/about',
|
||||||
|
path: '/about',
|
||||||
|
getParentRoute: () => SettingsRoute,
|
||||||
|
} as any)
|
||||||
|
const PaintingsSplatRoute = PaintingsSplatRouteImport.update({
|
||||||
|
id: '/paintings/$',
|
||||||
|
path: '/paintings/$',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
const AppsAppIdRoute = AppsAppIdRouteImport.update({
|
||||||
|
id: '/apps/$appId',
|
||||||
|
path: '/apps/$appId',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
const SettingsMcpIndexRoute = SettingsMcpIndexRouteImport.update({
|
||||||
|
id: '/',
|
||||||
|
path: '/',
|
||||||
|
getParentRoute: () => SettingsMcpRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsMcpServersRoute = SettingsMcpServersRouteImport.update({
|
||||||
|
id: '/servers',
|
||||||
|
path: '/servers',
|
||||||
|
getParentRoute: () => SettingsMcpRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsMcpNpxSearchRoute = SettingsMcpNpxSearchRouteImport.update({
|
||||||
|
id: '/npx-search',
|
||||||
|
path: '/npx-search',
|
||||||
|
getParentRoute: () => SettingsMcpRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsMcpMcpInstallRoute = SettingsMcpMcpInstallRouteImport.update({
|
||||||
|
id: '/mcp-install',
|
||||||
|
path: '/mcp-install',
|
||||||
|
getParentRoute: () => SettingsMcpRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsMcpMarketplacesRoute = SettingsMcpMarketplacesRouteImport.update({
|
||||||
|
id: '/marketplaces',
|
||||||
|
path: '/marketplaces',
|
||||||
|
getParentRoute: () => SettingsMcpRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsMcpBuiltinRoute = SettingsMcpBuiltinRouteImport.update({
|
||||||
|
id: '/builtin',
|
||||||
|
path: '/builtin',
|
||||||
|
getParentRoute: () => SettingsMcpRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsMcpSplatRoute = SettingsMcpSplatRouteImport.update({
|
||||||
|
id: '/$',
|
||||||
|
path: '/$',
|
||||||
|
getParentRoute: () => SettingsMcpRoute,
|
||||||
|
} as any)
|
||||||
|
const SettingsMcpSettingsServerIdRoute =
|
||||||
|
SettingsMcpSettingsServerIdRouteImport.update({
|
||||||
|
id: '/settings/$serverId',
|
||||||
|
path: '/settings/$serverId',
|
||||||
|
getParentRoute: () => SettingsMcpRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/settings': typeof SettingsRoute
|
'/chat': typeof ChatRoute
|
||||||
|
'/code': typeof CodeRoute
|
||||||
|
'/files': typeof FilesRoute
|
||||||
|
'/knowledge': typeof KnowledgeRoute
|
||||||
|
'/notes': typeof NotesRoute
|
||||||
|
'/settings': typeof SettingsRouteWithChildren
|
||||||
|
'/store': typeof StoreRoute
|
||||||
|
'/translate': typeof TranslateRoute
|
||||||
|
'/apps/$appId': typeof AppsAppIdRoute
|
||||||
|
'/paintings/$': typeof PaintingsSplatRoute
|
||||||
|
'/settings/about': typeof SettingsAboutRoute
|
||||||
|
'/settings/api-server': typeof SettingsApiServerRoute
|
||||||
|
'/settings/data': typeof SettingsDataRoute
|
||||||
|
'/settings/display': typeof SettingsDisplayRoute
|
||||||
|
'/settings/docprocess': typeof SettingsDocprocessRoute
|
||||||
|
'/settings/general': typeof SettingsGeneralRoute
|
||||||
|
'/settings/mcp': typeof SettingsMcpRouteWithChildren
|
||||||
|
'/settings/memory': typeof SettingsMemoryRoute
|
||||||
|
'/settings/model': typeof SettingsModelRoute
|
||||||
|
'/settings/notes': typeof SettingsNotesRoute
|
||||||
|
'/settings/provider': typeof SettingsProviderRoute
|
||||||
|
'/settings/quickAssistant': typeof SettingsQuickAssistantRoute
|
||||||
|
'/settings/quickphrase': typeof SettingsQuickphraseRoute
|
||||||
|
'/settings/selectionAssistant': typeof SettingsSelectionAssistantRoute
|
||||||
|
'/settings/shortcut': typeof SettingsShortcutRoute
|
||||||
|
'/settings/websearch': typeof SettingsWebsearchRoute
|
||||||
|
'/apps': typeof AppsIndexRoute
|
||||||
|
'/paintings': typeof PaintingsIndexRoute
|
||||||
|
'/settings/': typeof SettingsIndexRoute
|
||||||
|
'/settings/mcp/$': typeof SettingsMcpSplatRoute
|
||||||
|
'/settings/mcp/builtin': typeof SettingsMcpBuiltinRoute
|
||||||
|
'/settings/mcp/marketplaces': typeof SettingsMcpMarketplacesRoute
|
||||||
|
'/settings/mcp/mcp-install': typeof SettingsMcpMcpInstallRoute
|
||||||
|
'/settings/mcp/npx-search': typeof SettingsMcpNpxSearchRoute
|
||||||
|
'/settings/mcp/servers': typeof SettingsMcpServersRoute
|
||||||
|
'/settings/mcp/': typeof SettingsMcpIndexRoute
|
||||||
|
'/settings/mcp/settings/$serverId': typeof SettingsMcpSettingsServerIdRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/settings': typeof SettingsRoute
|
'/chat': typeof ChatRoute
|
||||||
|
'/code': typeof CodeRoute
|
||||||
|
'/files': typeof FilesRoute
|
||||||
|
'/knowledge': typeof KnowledgeRoute
|
||||||
|
'/notes': typeof NotesRoute
|
||||||
|
'/store': typeof StoreRoute
|
||||||
|
'/translate': typeof TranslateRoute
|
||||||
|
'/apps/$appId': typeof AppsAppIdRoute
|
||||||
|
'/paintings/$': typeof PaintingsSplatRoute
|
||||||
|
'/settings/about': typeof SettingsAboutRoute
|
||||||
|
'/settings/api-server': typeof SettingsApiServerRoute
|
||||||
|
'/settings/data': typeof SettingsDataRoute
|
||||||
|
'/settings/display': typeof SettingsDisplayRoute
|
||||||
|
'/settings/docprocess': typeof SettingsDocprocessRoute
|
||||||
|
'/settings/general': typeof SettingsGeneralRoute
|
||||||
|
'/settings/memory': typeof SettingsMemoryRoute
|
||||||
|
'/settings/model': typeof SettingsModelRoute
|
||||||
|
'/settings/notes': typeof SettingsNotesRoute
|
||||||
|
'/settings/provider': typeof SettingsProviderRoute
|
||||||
|
'/settings/quickAssistant': typeof SettingsQuickAssistantRoute
|
||||||
|
'/settings/quickphrase': typeof SettingsQuickphraseRoute
|
||||||
|
'/settings/selectionAssistant': typeof SettingsSelectionAssistantRoute
|
||||||
|
'/settings/shortcut': typeof SettingsShortcutRoute
|
||||||
|
'/settings/websearch': typeof SettingsWebsearchRoute
|
||||||
|
'/apps': typeof AppsIndexRoute
|
||||||
|
'/paintings': typeof PaintingsIndexRoute
|
||||||
|
'/settings': typeof SettingsIndexRoute
|
||||||
|
'/settings/mcp/$': typeof SettingsMcpSplatRoute
|
||||||
|
'/settings/mcp/builtin': typeof SettingsMcpBuiltinRoute
|
||||||
|
'/settings/mcp/marketplaces': typeof SettingsMcpMarketplacesRoute
|
||||||
|
'/settings/mcp/mcp-install': typeof SettingsMcpMcpInstallRoute
|
||||||
|
'/settings/mcp/npx-search': typeof SettingsMcpNpxSearchRoute
|
||||||
|
'/settings/mcp/servers': typeof SettingsMcpServersRoute
|
||||||
|
'/settings/mcp': typeof SettingsMcpIndexRoute
|
||||||
|
'/settings/mcp/settings/$serverId': typeof SettingsMcpSettingsServerIdRoute
|
||||||
}
|
}
|
||||||
export interface FileRoutesById {
|
export interface FileRoutesById {
|
||||||
__root__: typeof rootRouteImport
|
__root__: typeof rootRouteImport
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/settings': typeof SettingsRoute
|
'/chat': typeof ChatRoute
|
||||||
|
'/code': typeof CodeRoute
|
||||||
|
'/files': typeof FilesRoute
|
||||||
|
'/knowledge': typeof KnowledgeRoute
|
||||||
|
'/notes': typeof NotesRoute
|
||||||
|
'/settings': typeof SettingsRouteWithChildren
|
||||||
|
'/store': typeof StoreRoute
|
||||||
|
'/translate': typeof TranslateRoute
|
||||||
|
'/apps/$appId': typeof AppsAppIdRoute
|
||||||
|
'/paintings/$': typeof PaintingsSplatRoute
|
||||||
|
'/settings/about': typeof SettingsAboutRoute
|
||||||
|
'/settings/api-server': typeof SettingsApiServerRoute
|
||||||
|
'/settings/data': typeof SettingsDataRoute
|
||||||
|
'/settings/display': typeof SettingsDisplayRoute
|
||||||
|
'/settings/docprocess': typeof SettingsDocprocessRoute
|
||||||
|
'/settings/general': typeof SettingsGeneralRoute
|
||||||
|
'/settings/mcp': typeof SettingsMcpRouteWithChildren
|
||||||
|
'/settings/memory': typeof SettingsMemoryRoute
|
||||||
|
'/settings/model': typeof SettingsModelRoute
|
||||||
|
'/settings/notes': typeof SettingsNotesRoute
|
||||||
|
'/settings/provider': typeof SettingsProviderRoute
|
||||||
|
'/settings/quickAssistant': typeof SettingsQuickAssistantRoute
|
||||||
|
'/settings/quickphrase': typeof SettingsQuickphraseRoute
|
||||||
|
'/settings/selectionAssistant': typeof SettingsSelectionAssistantRoute
|
||||||
|
'/settings/shortcut': typeof SettingsShortcutRoute
|
||||||
|
'/settings/websearch': typeof SettingsWebsearchRoute
|
||||||
|
'/apps/': typeof AppsIndexRoute
|
||||||
|
'/paintings/': typeof PaintingsIndexRoute
|
||||||
|
'/settings/': typeof SettingsIndexRoute
|
||||||
|
'/settings/mcp/$': typeof SettingsMcpSplatRoute
|
||||||
|
'/settings/mcp/builtin': typeof SettingsMcpBuiltinRoute
|
||||||
|
'/settings/mcp/marketplaces': typeof SettingsMcpMarketplacesRoute
|
||||||
|
'/settings/mcp/mcp-install': typeof SettingsMcpMcpInstallRoute
|
||||||
|
'/settings/mcp/npx-search': typeof SettingsMcpNpxSearchRoute
|
||||||
|
'/settings/mcp/servers': typeof SettingsMcpServersRoute
|
||||||
|
'/settings/mcp/': typeof SettingsMcpIndexRoute
|
||||||
|
'/settings/mcp/settings/$serverId': typeof SettingsMcpSettingsServerIdRoute
|
||||||
}
|
}
|
||||||
export interface FileRouteTypes {
|
export interface FileRouteTypes {
|
||||||
fileRoutesByFullPath: FileRoutesByFullPath
|
fileRoutesByFullPath: FileRoutesByFullPath
|
||||||
fullPaths: '/' | '/settings'
|
fullPaths:
|
||||||
|
| '/'
|
||||||
|
| '/chat'
|
||||||
|
| '/code'
|
||||||
|
| '/files'
|
||||||
|
| '/knowledge'
|
||||||
|
| '/notes'
|
||||||
|
| '/settings'
|
||||||
|
| '/store'
|
||||||
|
| '/translate'
|
||||||
|
| '/apps/$appId'
|
||||||
|
| '/paintings/$'
|
||||||
|
| '/settings/about'
|
||||||
|
| '/settings/api-server'
|
||||||
|
| '/settings/data'
|
||||||
|
| '/settings/display'
|
||||||
|
| '/settings/docprocess'
|
||||||
|
| '/settings/general'
|
||||||
|
| '/settings/mcp'
|
||||||
|
| '/settings/memory'
|
||||||
|
| '/settings/model'
|
||||||
|
| '/settings/notes'
|
||||||
|
| '/settings/provider'
|
||||||
|
| '/settings/quickAssistant'
|
||||||
|
| '/settings/quickphrase'
|
||||||
|
| '/settings/selectionAssistant'
|
||||||
|
| '/settings/shortcut'
|
||||||
|
| '/settings/websearch'
|
||||||
|
| '/apps'
|
||||||
|
| '/paintings'
|
||||||
|
| '/settings/'
|
||||||
|
| '/settings/mcp/$'
|
||||||
|
| '/settings/mcp/builtin'
|
||||||
|
| '/settings/mcp/marketplaces'
|
||||||
|
| '/settings/mcp/mcp-install'
|
||||||
|
| '/settings/mcp/npx-search'
|
||||||
|
| '/settings/mcp/servers'
|
||||||
|
| '/settings/mcp/'
|
||||||
|
| '/settings/mcp/settings/$serverId'
|
||||||
fileRoutesByTo: FileRoutesByTo
|
fileRoutesByTo: FileRoutesByTo
|
||||||
to: '/' | '/settings'
|
to:
|
||||||
id: '__root__' | '/' | '/settings'
|
| '/'
|
||||||
|
| '/chat'
|
||||||
|
| '/code'
|
||||||
|
| '/files'
|
||||||
|
| '/knowledge'
|
||||||
|
| '/notes'
|
||||||
|
| '/store'
|
||||||
|
| '/translate'
|
||||||
|
| '/apps/$appId'
|
||||||
|
| '/paintings/$'
|
||||||
|
| '/settings/about'
|
||||||
|
| '/settings/api-server'
|
||||||
|
| '/settings/data'
|
||||||
|
| '/settings/display'
|
||||||
|
| '/settings/docprocess'
|
||||||
|
| '/settings/general'
|
||||||
|
| '/settings/memory'
|
||||||
|
| '/settings/model'
|
||||||
|
| '/settings/notes'
|
||||||
|
| '/settings/provider'
|
||||||
|
| '/settings/quickAssistant'
|
||||||
|
| '/settings/quickphrase'
|
||||||
|
| '/settings/selectionAssistant'
|
||||||
|
| '/settings/shortcut'
|
||||||
|
| '/settings/websearch'
|
||||||
|
| '/apps'
|
||||||
|
| '/paintings'
|
||||||
|
| '/settings'
|
||||||
|
| '/settings/mcp/$'
|
||||||
|
| '/settings/mcp/builtin'
|
||||||
|
| '/settings/mcp/marketplaces'
|
||||||
|
| '/settings/mcp/mcp-install'
|
||||||
|
| '/settings/mcp/npx-search'
|
||||||
|
| '/settings/mcp/servers'
|
||||||
|
| '/settings/mcp'
|
||||||
|
| '/settings/mcp/settings/$serverId'
|
||||||
|
id:
|
||||||
|
| '__root__'
|
||||||
|
| '/'
|
||||||
|
| '/chat'
|
||||||
|
| '/code'
|
||||||
|
| '/files'
|
||||||
|
| '/knowledge'
|
||||||
|
| '/notes'
|
||||||
|
| '/settings'
|
||||||
|
| '/store'
|
||||||
|
| '/translate'
|
||||||
|
| '/apps/$appId'
|
||||||
|
| '/paintings/$'
|
||||||
|
| '/settings/about'
|
||||||
|
| '/settings/api-server'
|
||||||
|
| '/settings/data'
|
||||||
|
| '/settings/display'
|
||||||
|
| '/settings/docprocess'
|
||||||
|
| '/settings/general'
|
||||||
|
| '/settings/mcp'
|
||||||
|
| '/settings/memory'
|
||||||
|
| '/settings/model'
|
||||||
|
| '/settings/notes'
|
||||||
|
| '/settings/provider'
|
||||||
|
| '/settings/quickAssistant'
|
||||||
|
| '/settings/quickphrase'
|
||||||
|
| '/settings/selectionAssistant'
|
||||||
|
| '/settings/shortcut'
|
||||||
|
| '/settings/websearch'
|
||||||
|
| '/apps/'
|
||||||
|
| '/paintings/'
|
||||||
|
| '/settings/'
|
||||||
|
| '/settings/mcp/$'
|
||||||
|
| '/settings/mcp/builtin'
|
||||||
|
| '/settings/mcp/marketplaces'
|
||||||
|
| '/settings/mcp/mcp-install'
|
||||||
|
| '/settings/mcp/npx-search'
|
||||||
|
| '/settings/mcp/servers'
|
||||||
|
| '/settings/mcp/'
|
||||||
|
| '/settings/mcp/settings/$serverId'
|
||||||
fileRoutesById: FileRoutesById
|
fileRoutesById: FileRoutesById
|
||||||
}
|
}
|
||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
IndexRoute: typeof IndexRoute
|
IndexRoute: typeof IndexRoute
|
||||||
SettingsRoute: typeof SettingsRoute
|
ChatRoute: typeof ChatRoute
|
||||||
|
CodeRoute: typeof CodeRoute
|
||||||
|
FilesRoute: typeof FilesRoute
|
||||||
|
KnowledgeRoute: typeof KnowledgeRoute
|
||||||
|
NotesRoute: typeof NotesRoute
|
||||||
|
SettingsRoute: typeof SettingsRouteWithChildren
|
||||||
|
StoreRoute: typeof StoreRoute
|
||||||
|
TranslateRoute: typeof TranslateRoute
|
||||||
|
AppsAppIdRoute: typeof AppsAppIdRoute
|
||||||
|
PaintingsSplatRoute: typeof PaintingsSplatRoute
|
||||||
|
AppsIndexRoute: typeof AppsIndexRoute
|
||||||
|
PaintingsIndexRoute: typeof PaintingsIndexRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@tanstack/react-router' {
|
declare module '@tanstack/react-router' {
|
||||||
interface FileRoutesByPath {
|
interface FileRoutesByPath {
|
||||||
|
'/translate': {
|
||||||
|
id: '/translate'
|
||||||
|
path: '/translate'
|
||||||
|
fullPath: '/translate'
|
||||||
|
preLoaderRoute: typeof TranslateRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
'/store': {
|
||||||
|
id: '/store'
|
||||||
|
path: '/store'
|
||||||
|
fullPath: '/store'
|
||||||
|
preLoaderRoute: typeof StoreRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
'/settings': {
|
'/settings': {
|
||||||
id: '/settings'
|
id: '/settings'
|
||||||
path: '/settings'
|
path: '/settings'
|
||||||
@ -58,6 +520,41 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof SettingsRouteImport
|
preLoaderRoute: typeof SettingsRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
|
'/notes': {
|
||||||
|
id: '/notes'
|
||||||
|
path: '/notes'
|
||||||
|
fullPath: '/notes'
|
||||||
|
preLoaderRoute: typeof NotesRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
'/knowledge': {
|
||||||
|
id: '/knowledge'
|
||||||
|
path: '/knowledge'
|
||||||
|
fullPath: '/knowledge'
|
||||||
|
preLoaderRoute: typeof KnowledgeRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
'/files': {
|
||||||
|
id: '/files'
|
||||||
|
path: '/files'
|
||||||
|
fullPath: '/files'
|
||||||
|
preLoaderRoute: typeof FilesRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
'/code': {
|
||||||
|
id: '/code'
|
||||||
|
path: '/code'
|
||||||
|
fullPath: '/code'
|
||||||
|
preLoaderRoute: typeof CodeRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
'/chat': {
|
||||||
|
id: '/chat'
|
||||||
|
path: '/chat'
|
||||||
|
fullPath: '/chat'
|
||||||
|
preLoaderRoute: typeof ChatRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
'/': {
|
'/': {
|
||||||
id: '/'
|
id: '/'
|
||||||
path: '/'
|
path: '/'
|
||||||
@ -65,12 +562,296 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof IndexRouteImport
|
preLoaderRoute: typeof IndexRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
|
'/settings/': {
|
||||||
|
id: '/settings/'
|
||||||
|
path: '/'
|
||||||
|
fullPath: '/settings/'
|
||||||
|
preLoaderRoute: typeof SettingsIndexRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/paintings/': {
|
||||||
|
id: '/paintings/'
|
||||||
|
path: '/paintings'
|
||||||
|
fullPath: '/paintings'
|
||||||
|
preLoaderRoute: typeof PaintingsIndexRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
'/apps/': {
|
||||||
|
id: '/apps/'
|
||||||
|
path: '/apps'
|
||||||
|
fullPath: '/apps'
|
||||||
|
preLoaderRoute: typeof AppsIndexRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
'/settings/websearch': {
|
||||||
|
id: '/settings/websearch'
|
||||||
|
path: '/websearch'
|
||||||
|
fullPath: '/settings/websearch'
|
||||||
|
preLoaderRoute: typeof SettingsWebsearchRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/shortcut': {
|
||||||
|
id: '/settings/shortcut'
|
||||||
|
path: '/shortcut'
|
||||||
|
fullPath: '/settings/shortcut'
|
||||||
|
preLoaderRoute: typeof SettingsShortcutRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/selectionAssistant': {
|
||||||
|
id: '/settings/selectionAssistant'
|
||||||
|
path: '/selectionAssistant'
|
||||||
|
fullPath: '/settings/selectionAssistant'
|
||||||
|
preLoaderRoute: typeof SettingsSelectionAssistantRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/quickphrase': {
|
||||||
|
id: '/settings/quickphrase'
|
||||||
|
path: '/quickphrase'
|
||||||
|
fullPath: '/settings/quickphrase'
|
||||||
|
preLoaderRoute: typeof SettingsQuickphraseRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/quickAssistant': {
|
||||||
|
id: '/settings/quickAssistant'
|
||||||
|
path: '/quickAssistant'
|
||||||
|
fullPath: '/settings/quickAssistant'
|
||||||
|
preLoaderRoute: typeof SettingsQuickAssistantRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/provider': {
|
||||||
|
id: '/settings/provider'
|
||||||
|
path: '/provider'
|
||||||
|
fullPath: '/settings/provider'
|
||||||
|
preLoaderRoute: typeof SettingsProviderRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/notes': {
|
||||||
|
id: '/settings/notes'
|
||||||
|
path: '/notes'
|
||||||
|
fullPath: '/settings/notes'
|
||||||
|
preLoaderRoute: typeof SettingsNotesRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/model': {
|
||||||
|
id: '/settings/model'
|
||||||
|
path: '/model'
|
||||||
|
fullPath: '/settings/model'
|
||||||
|
preLoaderRoute: typeof SettingsModelRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/memory': {
|
||||||
|
id: '/settings/memory'
|
||||||
|
path: '/memory'
|
||||||
|
fullPath: '/settings/memory'
|
||||||
|
preLoaderRoute: typeof SettingsMemoryRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/mcp': {
|
||||||
|
id: '/settings/mcp'
|
||||||
|
path: '/mcp'
|
||||||
|
fullPath: '/settings/mcp'
|
||||||
|
preLoaderRoute: typeof SettingsMcpRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/general': {
|
||||||
|
id: '/settings/general'
|
||||||
|
path: '/general'
|
||||||
|
fullPath: '/settings/general'
|
||||||
|
preLoaderRoute: typeof SettingsGeneralRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/docprocess': {
|
||||||
|
id: '/settings/docprocess'
|
||||||
|
path: '/docprocess'
|
||||||
|
fullPath: '/settings/docprocess'
|
||||||
|
preLoaderRoute: typeof SettingsDocprocessRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/display': {
|
||||||
|
id: '/settings/display'
|
||||||
|
path: '/display'
|
||||||
|
fullPath: '/settings/display'
|
||||||
|
preLoaderRoute: typeof SettingsDisplayRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/data': {
|
||||||
|
id: '/settings/data'
|
||||||
|
path: '/data'
|
||||||
|
fullPath: '/settings/data'
|
||||||
|
preLoaderRoute: typeof SettingsDataRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/api-server': {
|
||||||
|
id: '/settings/api-server'
|
||||||
|
path: '/api-server'
|
||||||
|
fullPath: '/settings/api-server'
|
||||||
|
preLoaderRoute: typeof SettingsApiServerRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/settings/about': {
|
||||||
|
id: '/settings/about'
|
||||||
|
path: '/about'
|
||||||
|
fullPath: '/settings/about'
|
||||||
|
preLoaderRoute: typeof SettingsAboutRouteImport
|
||||||
|
parentRoute: typeof SettingsRoute
|
||||||
|
}
|
||||||
|
'/paintings/$': {
|
||||||
|
id: '/paintings/$'
|
||||||
|
path: '/paintings/$'
|
||||||
|
fullPath: '/paintings/$'
|
||||||
|
preLoaderRoute: typeof PaintingsSplatRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
'/apps/$appId': {
|
||||||
|
id: '/apps/$appId'
|
||||||
|
path: '/apps/$appId'
|
||||||
|
fullPath: '/apps/$appId'
|
||||||
|
preLoaderRoute: typeof AppsAppIdRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
'/settings/mcp/': {
|
||||||
|
id: '/settings/mcp/'
|
||||||
|
path: '/'
|
||||||
|
fullPath: '/settings/mcp/'
|
||||||
|
preLoaderRoute: typeof SettingsMcpIndexRouteImport
|
||||||
|
parentRoute: typeof SettingsMcpRoute
|
||||||
|
}
|
||||||
|
'/settings/mcp/servers': {
|
||||||
|
id: '/settings/mcp/servers'
|
||||||
|
path: '/servers'
|
||||||
|
fullPath: '/settings/mcp/servers'
|
||||||
|
preLoaderRoute: typeof SettingsMcpServersRouteImport
|
||||||
|
parentRoute: typeof SettingsMcpRoute
|
||||||
|
}
|
||||||
|
'/settings/mcp/npx-search': {
|
||||||
|
id: '/settings/mcp/npx-search'
|
||||||
|
path: '/npx-search'
|
||||||
|
fullPath: '/settings/mcp/npx-search'
|
||||||
|
preLoaderRoute: typeof SettingsMcpNpxSearchRouteImport
|
||||||
|
parentRoute: typeof SettingsMcpRoute
|
||||||
|
}
|
||||||
|
'/settings/mcp/mcp-install': {
|
||||||
|
id: '/settings/mcp/mcp-install'
|
||||||
|
path: '/mcp-install'
|
||||||
|
fullPath: '/settings/mcp/mcp-install'
|
||||||
|
preLoaderRoute: typeof SettingsMcpMcpInstallRouteImport
|
||||||
|
parentRoute: typeof SettingsMcpRoute
|
||||||
|
}
|
||||||
|
'/settings/mcp/marketplaces': {
|
||||||
|
id: '/settings/mcp/marketplaces'
|
||||||
|
path: '/marketplaces'
|
||||||
|
fullPath: '/settings/mcp/marketplaces'
|
||||||
|
preLoaderRoute: typeof SettingsMcpMarketplacesRouteImport
|
||||||
|
parentRoute: typeof SettingsMcpRoute
|
||||||
|
}
|
||||||
|
'/settings/mcp/builtin': {
|
||||||
|
id: '/settings/mcp/builtin'
|
||||||
|
path: '/builtin'
|
||||||
|
fullPath: '/settings/mcp/builtin'
|
||||||
|
preLoaderRoute: typeof SettingsMcpBuiltinRouteImport
|
||||||
|
parentRoute: typeof SettingsMcpRoute
|
||||||
|
}
|
||||||
|
'/settings/mcp/$': {
|
||||||
|
id: '/settings/mcp/$'
|
||||||
|
path: '/$'
|
||||||
|
fullPath: '/settings/mcp/$'
|
||||||
|
preLoaderRoute: typeof SettingsMcpSplatRouteImport
|
||||||
|
parentRoute: typeof SettingsMcpRoute
|
||||||
|
}
|
||||||
|
'/settings/mcp/settings/$serverId': {
|
||||||
|
id: '/settings/mcp/settings/$serverId'
|
||||||
|
path: '/settings/$serverId'
|
||||||
|
fullPath: '/settings/mcp/settings/$serverId'
|
||||||
|
preLoaderRoute: typeof SettingsMcpSettingsServerIdRouteImport
|
||||||
|
parentRoute: typeof SettingsMcpRoute
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SettingsMcpRouteChildren {
|
||||||
|
SettingsMcpSplatRoute: typeof SettingsMcpSplatRoute
|
||||||
|
SettingsMcpBuiltinRoute: typeof SettingsMcpBuiltinRoute
|
||||||
|
SettingsMcpMarketplacesRoute: typeof SettingsMcpMarketplacesRoute
|
||||||
|
SettingsMcpMcpInstallRoute: typeof SettingsMcpMcpInstallRoute
|
||||||
|
SettingsMcpNpxSearchRoute: typeof SettingsMcpNpxSearchRoute
|
||||||
|
SettingsMcpServersRoute: typeof SettingsMcpServersRoute
|
||||||
|
SettingsMcpIndexRoute: typeof SettingsMcpIndexRoute
|
||||||
|
SettingsMcpSettingsServerIdRoute: typeof SettingsMcpSettingsServerIdRoute
|
||||||
|
}
|
||||||
|
|
||||||
|
const SettingsMcpRouteChildren: SettingsMcpRouteChildren = {
|
||||||
|
SettingsMcpSplatRoute: SettingsMcpSplatRoute,
|
||||||
|
SettingsMcpBuiltinRoute: SettingsMcpBuiltinRoute,
|
||||||
|
SettingsMcpMarketplacesRoute: SettingsMcpMarketplacesRoute,
|
||||||
|
SettingsMcpMcpInstallRoute: SettingsMcpMcpInstallRoute,
|
||||||
|
SettingsMcpNpxSearchRoute: SettingsMcpNpxSearchRoute,
|
||||||
|
SettingsMcpServersRoute: SettingsMcpServersRoute,
|
||||||
|
SettingsMcpIndexRoute: SettingsMcpIndexRoute,
|
||||||
|
SettingsMcpSettingsServerIdRoute: SettingsMcpSettingsServerIdRoute,
|
||||||
|
}
|
||||||
|
|
||||||
|
const SettingsMcpRouteWithChildren = SettingsMcpRoute._addFileChildren(
|
||||||
|
SettingsMcpRouteChildren,
|
||||||
|
)
|
||||||
|
|
||||||
|
interface SettingsRouteChildren {
|
||||||
|
SettingsAboutRoute: typeof SettingsAboutRoute
|
||||||
|
SettingsApiServerRoute: typeof SettingsApiServerRoute
|
||||||
|
SettingsDataRoute: typeof SettingsDataRoute
|
||||||
|
SettingsDisplayRoute: typeof SettingsDisplayRoute
|
||||||
|
SettingsDocprocessRoute: typeof SettingsDocprocessRoute
|
||||||
|
SettingsGeneralRoute: typeof SettingsGeneralRoute
|
||||||
|
SettingsMcpRoute: typeof SettingsMcpRouteWithChildren
|
||||||
|
SettingsMemoryRoute: typeof SettingsMemoryRoute
|
||||||
|
SettingsModelRoute: typeof SettingsModelRoute
|
||||||
|
SettingsNotesRoute: typeof SettingsNotesRoute
|
||||||
|
SettingsProviderRoute: typeof SettingsProviderRoute
|
||||||
|
SettingsQuickAssistantRoute: typeof SettingsQuickAssistantRoute
|
||||||
|
SettingsQuickphraseRoute: typeof SettingsQuickphraseRoute
|
||||||
|
SettingsSelectionAssistantRoute: typeof SettingsSelectionAssistantRoute
|
||||||
|
SettingsShortcutRoute: typeof SettingsShortcutRoute
|
||||||
|
SettingsWebsearchRoute: typeof SettingsWebsearchRoute
|
||||||
|
SettingsIndexRoute: typeof SettingsIndexRoute
|
||||||
|
}
|
||||||
|
|
||||||
|
const SettingsRouteChildren: SettingsRouteChildren = {
|
||||||
|
SettingsAboutRoute: SettingsAboutRoute,
|
||||||
|
SettingsApiServerRoute: SettingsApiServerRoute,
|
||||||
|
SettingsDataRoute: SettingsDataRoute,
|
||||||
|
SettingsDisplayRoute: SettingsDisplayRoute,
|
||||||
|
SettingsDocprocessRoute: SettingsDocprocessRoute,
|
||||||
|
SettingsGeneralRoute: SettingsGeneralRoute,
|
||||||
|
SettingsMcpRoute: SettingsMcpRouteWithChildren,
|
||||||
|
SettingsMemoryRoute: SettingsMemoryRoute,
|
||||||
|
SettingsModelRoute: SettingsModelRoute,
|
||||||
|
SettingsNotesRoute: SettingsNotesRoute,
|
||||||
|
SettingsProviderRoute: SettingsProviderRoute,
|
||||||
|
SettingsQuickAssistantRoute: SettingsQuickAssistantRoute,
|
||||||
|
SettingsQuickphraseRoute: SettingsQuickphraseRoute,
|
||||||
|
SettingsSelectionAssistantRoute: SettingsSelectionAssistantRoute,
|
||||||
|
SettingsShortcutRoute: SettingsShortcutRoute,
|
||||||
|
SettingsWebsearchRoute: SettingsWebsearchRoute,
|
||||||
|
SettingsIndexRoute: SettingsIndexRoute,
|
||||||
|
}
|
||||||
|
|
||||||
|
const SettingsRouteWithChildren = SettingsRoute._addFileChildren(
|
||||||
|
SettingsRouteChildren,
|
||||||
|
)
|
||||||
|
|
||||||
const rootRouteChildren: RootRouteChildren = {
|
const rootRouteChildren: RootRouteChildren = {
|
||||||
IndexRoute: IndexRoute,
|
IndexRoute: IndexRoute,
|
||||||
SettingsRoute: SettingsRoute,
|
ChatRoute: ChatRoute,
|
||||||
|
CodeRoute: CodeRoute,
|
||||||
|
FilesRoute: FilesRoute,
|
||||||
|
KnowledgeRoute: KnowledgeRoute,
|
||||||
|
NotesRoute: NotesRoute,
|
||||||
|
SettingsRoute: SettingsRouteWithChildren,
|
||||||
|
StoreRoute: StoreRoute,
|
||||||
|
TranslateRoute: TranslateRoute,
|
||||||
|
AppsAppIdRoute: AppsAppIdRoute,
|
||||||
|
PaintingsSplatRoute: PaintingsSplatRoute,
|
||||||
|
AppsIndexRoute: AppsIndexRoute,
|
||||||
|
PaintingsIndexRoute: PaintingsIndexRoute,
|
||||||
}
|
}
|
||||||
export const routeTree = rootRouteImport
|
export const routeTree = rootRouteImport
|
||||||
._addFileChildren(rootRouteChildren)
|
._addFileChildren(rootRouteChildren)
|
||||||
|
|||||||
@ -23,9 +23,9 @@ import {
|
|||||||
} from '@renderer/utils/messageUtils/create'
|
} from '@renderer/utils/messageUtils/create'
|
||||||
import { filterContextMessages } from '@renderer/utils/messageUtils/filters'
|
import { filterContextMessages } from '@renderer/utils/messageUtils/filters'
|
||||||
import { getMainTextContent } from '@renderer/utils/messageUtils/find'
|
import { getMainTextContent } from '@renderer/utils/messageUtils/find'
|
||||||
|
import type { UseNavigateResult } from '@tanstack/react-router'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { t } from 'i18next'
|
import { t } from 'i18next'
|
||||||
import type { NavigateFunction } from 'react-router'
|
|
||||||
|
|
||||||
import { getAssistantById, getAssistantProvider, getDefaultModel } from './AssistantService'
|
import { getAssistantById, getAssistantProvider, getDefaultModel } from './AssistantService'
|
||||||
import { EVENT_NAMES, EventEmitter } from './EventService'
|
import { EVENT_NAMES, EventEmitter } from './EventService'
|
||||||
@ -68,14 +68,14 @@ export function deleteMessageFiles(message: Message) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function locateToMessage(navigate: NavigateFunction, message: Message) {
|
export async function locateToMessage(navigate: UseNavigateResult<string>, message: Message) {
|
||||||
await modelGenerating()
|
await modelGenerating()
|
||||||
|
|
||||||
SearchPopup.hide()
|
SearchPopup.hide()
|
||||||
const assistant = getAssistantById(message.assistantId)
|
const assistant = getAssistantById(message.assistantId)
|
||||||
const topic = await getTopicById(message.topicId)
|
const topic = await getTopicById(message.topicId)
|
||||||
|
|
||||||
navigate('/', { state: { assistant, topic } })
|
navigate({ to: '/chat', search: { assistantId: assistant?.id, topicId: topic?.id } })
|
||||||
|
|
||||||
setTimeout(() => EventEmitter.emit(EVENT_NAMES.SHOW_TOPIC_SIDEBAR), 0)
|
setTimeout(() => EventEmitter.emit(EVENT_NAMES.SHOW_TOPIC_SIDEBAR), 0)
|
||||||
setTimeout(() => EventEmitter.emit(EVENT_NAMES.LOCATE_MESSAGE + ':' + message.id), 300)
|
setTimeout(() => EventEmitter.emit(EVENT_NAMES.LOCATE_MESSAGE + ':' + message.id), 300)
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
import type { NavigateFunction } from 'react-router-dom'
|
import type { UseNavigateResult } from '@tanstack/react-router'
|
||||||
|
|
||||||
|
// Tab 导航服务 - 用于在非 React 组件中进行路由导航
|
||||||
interface INavigationService {
|
interface INavigationService {
|
||||||
navigate: NavigateFunction | null
|
navigate: UseNavigateResult<string> | null
|
||||||
setNavigate: (navigateFunc: NavigateFunction) => void
|
setNavigate: (navigateFunc: UseNavigateResult<string>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const NavigationService: INavigationService = {
|
const NavigationService: INavigationService = {
|
||||||
navigate: null,
|
navigate: null,
|
||||||
|
|
||||||
setNavigate: (navigateFunc: NavigateFunction): void => {
|
setNavigate: (navigateFunc: UseNavigateResult<string>): void => {
|
||||||
NavigationService.navigate = navigateFunc
|
NavigationService.navigate = navigateFunc
|
||||||
window.navigate = NavigationService.navigate
|
window.navigate = NavigationService.navigate
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,12 +55,12 @@ class TabsService {
|
|||||||
|
|
||||||
// 使用 NavigationService 导航到新的标签页
|
// 使用 NavigationService 导航到新的标签页
|
||||||
if (NavigationService.navigate) {
|
if (NavigationService.navigate) {
|
||||||
NavigationService.navigate(lastTab.path)
|
NavigationService.navigate({ to: lastTab.path })
|
||||||
} else {
|
} else {
|
||||||
logger.warn('Navigation service not ready, will navigate on next render')
|
logger.warn('Navigation service not ready, will navigate on next render')
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (NavigationService.navigate) {
|
if (NavigationService.navigate) {
|
||||||
NavigationService.navigate(lastTab.path)
|
NavigationService.navigate({ to: lastTab.path })
|
||||||
}
|
}
|
||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
@ -133,7 +133,7 @@ class TabsService {
|
|||||||
|
|
||||||
// 导航到对应页面
|
// 导航到对应页面
|
||||||
if (NavigationService.navigate) {
|
if (NavigationService.navigate) {
|
||||||
NavigationService.navigate(tab.path)
|
NavigationService.navigate({ to: tab.path })
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user