@lobehub/chat 1.97.7 → 1.97.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/changelog/v1.json +5 -0
  3. package/package.json +2 -2
  4. package/src/app/[variants]/(main)/discover/(detail)/assistant/[...slugs]/features/Details/Nav.tsx +4 -3
  5. package/src/app/[variants]/(main)/discover/(detail)/features/MakedownRender.tsx +3 -0
  6. package/src/app/[variants]/(main)/discover/(detail)/features/Toc/useToc.tsx +9 -2
  7. package/src/app/[variants]/(main)/discover/(detail)/model/[...slugs]/features/Details/Nav.tsx +4 -2
  8. package/src/app/[variants]/(main)/discover/(detail)/provider/[...slugs]/features/Details/Nav.tsx +4 -2
  9. package/src/app/[variants]/(main)/discover/(list)/features/SortButton/index.tsx +1 -0
  10. package/src/app/[variants]/(main)/files/(content)/@modal/(.)[id]/page.tsx +2 -0
  11. package/src/app/[variants]/(main)/files/[id]/page.tsx +2 -0
  12. package/src/app/[variants]/(main)/repos/[id]/Client.tsx +29 -0
  13. package/src/app/[variants]/(main)/repos/[id]/features/Menu/Head/index.tsx +12 -4
  14. package/src/app/[variants]/(main)/repos/[id]/features/Menu/Menu/index.tsx +4 -1
  15. package/src/app/[variants]/(main)/repos/[id]/features/Menu/index.tsx +8 -8
  16. package/src/app/[variants]/(main)/repos/[id]/layout.tsx +2 -0
  17. package/src/app/[variants]/(main)/repos/[id]/page.tsx +2 -22
  18. package/src/app/[variants]/(main)/repos/loading.tsx +3 -0
  19. package/src/app/[variants]/(main)/settings/agent/AgentMenu/Menu.tsx +17 -0
  20. package/src/app/[variants]/(main)/settings/agent/AgentMenu/index.tsx +12 -8
  21. package/src/app/[variants]/(main)/settings/agent/page.tsx +15 -1
  22. package/src/app/[variants]/(main)/settings/provider/(detail)/[id]/ClientMode.tsx +16 -4
  23. package/src/app/[variants]/(main)/settings/provider/(detail)/[id]/page.tsx +2 -30
  24. package/src/app/[variants]/(main)/settings/provider/layout.tsx +0 -2
  25. package/src/components/NProgress/index.tsx +11 -7
  26. package/src/features/ChatInput/ActionBar/STT/common.tsx +1 -0
  27. package/src/features/KnowledgeBaseModal/CreateNew/CreateForm.tsx +5 -1
  28. package/src/features/MCPPluginDetail/Schema/Prompts.tsx +4 -2
  29. package/src/features/MCPPluginDetail/Schema/Tools.tsx +4 -2
  30. package/src/features/MCPPluginDetail/Score/GithubBadge/index.tsx +2 -0
  31. package/src/features/ModelSelect/index.tsx +3 -1
  32. package/src/features/ModelSwitchPanel/index.tsx +1 -0
  33. package/src/services/aiProvider/type.ts +2 -1
  34. package/src/store/knowledgeBase/slices/crud/action.ts +21 -4
  35. package/src/store/knowledgeBase/slices/crud/initialState.ts +4 -0
  36. package/src/store/knowledgeBase/slices/crud/selectors.ts +7 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.97.8](https://github.com/lobehub/lobe-chat/compare/v1.97.7...v1.97.8)
6
+
7
+ <sup>Released on **2025-07-10**</sup>
8
+
9
+ <br/>
10
+
11
+ <details>
12
+ <summary><kbd>Improvements and Fixes</kbd></summary>
13
+
14
+ </details>
15
+
16
+ <div align="right">
17
+
18
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
19
+
20
+ </div>
21
+
5
22
  ### [Version 1.97.7](https://github.com/lobehub/lobe-chat/compare/v1.97.6...v1.97.7)
6
23
 
7
24
  <sup>Released on **2025-07-10**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,9 @@
1
1
  [
2
+ {
3
+ "children": {},
4
+ "date": "2025-07-10",
5
+ "version": "1.97.8"
6
+ },
2
7
  {
3
8
  "children": {
4
9
  "improvements": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.97.7",
3
+ "version": "1.97.8",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -171,7 +171,7 @@
171
171
  "@xterm/xterm": "^5.5.0",
172
172
  "ahooks": "^3.8.5",
173
173
  "ai": "^3.4.33",
174
- "antd": "5.26.2",
174
+ "antd": "^5.26.4",
175
175
  "antd-style": "^3.7.1",
176
176
  "brotli-wasm": "^3.0.1",
177
177
  "chroma-js": "^3.1.2",
@@ -28,12 +28,13 @@ const useStyles = createStyles(({ css, token }) => {
28
28
  `,
29
29
  };
30
30
  });
31
-
32
- const Nav = memo<{
31
+ interface NavProps {
33
32
  activeTab?: AssistantNavKey;
34
33
  mobile?: boolean;
35
34
  setActiveTab?: (tab: AssistantNavKey) => void;
36
- }>(({ mobile, setActiveTab, activeTab = AssistantNavKey.Overview }) => {
35
+ }
36
+
37
+ const Nav = memo<NavProps>(({ mobile, setActiveTab, activeTab = AssistantNavKey.Overview }) => {
37
38
  const { t } = useTranslation('discover');
38
39
  const { pluginCount, knowledgeCount, identifier } = useDetailContext();
39
40
  const { styles } = useStyles();
@@ -13,6 +13,7 @@ const MarkdownRender = memo<{ children?: string }>(({ children }) => {
13
13
  <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
14
14
  </Center>
15
15
  );
16
+
16
17
  return (
17
18
  <Markdown
18
19
  allowHtml
@@ -29,6 +30,8 @@ const MarkdownRender = memo<{ children?: string }>(({ children }) => {
29
30
  h5: H5,
30
31
  img: ({ src, ...rest }: { src: string }) => {
31
32
  if (src.includes('glama.ai')) return;
33
+
34
+ // eslint-disable-next-line @next/next/no-img-element
32
35
  if (src && src.startsWith('http')) return <img src={src} {...rest} />;
33
36
  return;
34
37
  },
@@ -4,12 +4,19 @@ import { AnchorProps } from 'antd';
4
4
  import { unionBy } from 'lodash-es';
5
5
  import { FC, PropsWithChildren, createContext, useContext, useState } from 'react';
6
6
 
7
- const TocContext = createContext<{
7
+ interface TocState {
8
8
  isLoading: boolean;
9
9
  setFinished: () => void;
10
10
  setToc: (data: any) => void;
11
11
  toc?: AnchorProps['items'];
12
- }>({ isLoading: true, setFinished: () => {}, setToc: () => {}, toc: [] });
12
+ }
13
+
14
+ const TocContext = createContext<TocState>({
15
+ isLoading: true,
16
+ setFinished: () => {},
17
+ setToc: () => {},
18
+ toc: [],
19
+ });
13
20
 
14
21
  export interface TOCItem {
15
22
  href: string;
@@ -26,11 +26,13 @@ const useStyles = createStyles(({ css, token }) => {
26
26
  };
27
27
  });
28
28
 
29
- const Nav = memo<{
29
+ interface NavProps {
30
30
  activeTab?: ModelNavKey;
31
31
  mobile?: boolean;
32
32
  setActiveTab?: (tab: ModelNavKey) => void;
33
- }>(({ mobile, setActiveTab, activeTab = ModelNavKey.Overview }) => {
33
+ }
34
+
35
+ const Nav = memo<NavProps>(({ mobile, setActiveTab, activeTab = ModelNavKey.Overview }) => {
34
36
  const { t } = useTranslation('discover');
35
37
  const { styles } = useStyles();
36
38
 
@@ -29,11 +29,13 @@ const useStyles = createStyles(({ css, token }) => {
29
29
  };
30
30
  });
31
31
 
32
- const Nav = memo<{
32
+ interface NavProps {
33
33
  activeTab?: ProviderNavKey;
34
34
  mobile?: boolean;
35
35
  setActiveTab?: (tab: ProviderNavKey) => void;
36
- }>(({ mobile, setActiveTab, activeTab = ProviderNavKey.Overview }) => {
36
+ }
37
+
38
+ const Nav = memo<NavProps>(({ mobile, setActiveTab, activeTab = ProviderNavKey.Overview }) => {
37
39
  const { t } = useTranslation('discover');
38
40
  const { identifier } = useDetailContext();
39
41
  const { styles } = useStyles();
@@ -167,6 +167,7 @@ const SortButton = memo(() => {
167
167
  return (
168
168
  <Dropdown
169
169
  menu={{
170
+ // @ts-expect-error 等待 antd 修复
170
171
  activeKey: activeItem.key,
171
172
  items: items as DropdownMenuItemType[],
172
173
  onClick: ({ key }) => handleSort(key),
@@ -15,3 +15,5 @@ const Page = async (props: PagePropsWithId) => {
15
15
  };
16
16
 
17
17
  export default Page;
18
+
19
+ export const dynamic = 'force-static';
@@ -39,3 +39,5 @@ const FilePage = async (props: PagePropsWithId) => {
39
39
  };
40
40
 
41
41
  export default FilePage;
42
+
43
+ export const dynamic = 'force-static';
@@ -0,0 +1,29 @@
1
+ 'use client';
2
+
3
+ import { memo } from 'react';
4
+ import { Flexbox } from 'react-layout-kit';
5
+
6
+ import FileManager from '@/features/FileManager';
7
+ import FilePanel from '@/features/FileSidePanel';
8
+ import { knowledgeBaseSelectors, useKnowledgeBaseStore } from '@/store/knowledgeBase';
9
+
10
+ import Menu from './features/Menu';
11
+ import { useKnowledgeBaseItem } from './hooks/useKnowledgeItem';
12
+
13
+ const RepoClientPage = memo<{ id: string }>(({ id }) => {
14
+ useKnowledgeBaseItem(id);
15
+ const name = useKnowledgeBaseStore(knowledgeBaseSelectors.getKnowledgeBaseNameById(id));
16
+
17
+ return (
18
+ <>
19
+ <FilePanel>
20
+ <Menu id={id} />
21
+ </FilePanel>
22
+ <Flexbox flex={1} style={{ overflow: 'hidden', position: 'relative' }}>
23
+ <FileManager knowledgeBaseId={id} title={name} />
24
+ </Flexbox>
25
+ </>
26
+ );
27
+ });
28
+
29
+ export default RepoClientPage;
@@ -1,13 +1,17 @@
1
1
  'use client';
2
2
 
3
3
  import { Text } from '@lobehub/ui';
4
+ import { Skeleton } from 'antd';
4
5
  import { memo } from 'react';
5
6
  import { Center, Flexbox } from 'react-layout-kit';
6
7
 
7
8
  import GoBack from '@/components/GoBack';
8
9
  import RepoIcon from '@/components/RepoIcon';
10
+ import { knowledgeBaseSelectors, useKnowledgeBaseStore } from '@/store/knowledgeBase';
11
+
12
+ const Head = memo<{ id: string }>(({ id }) => {
13
+ const name = useKnowledgeBaseStore(knowledgeBaseSelectors.getKnowledgeBaseNameById(id));
9
14
 
10
- const Head = memo<{ name?: string }>(({ name }) => {
11
15
  return (
12
16
  <Flexbox gap={8}>
13
17
  <GoBack href={'/files'} />
@@ -16,9 +20,13 @@ const Head = memo<{ name?: string }>(({ name }) => {
16
20
  <RepoIcon />
17
21
  </Center>
18
22
 
19
- <Text ellipsis strong style={{ fontSize: 16 }}>
20
- {name}
21
- </Text>
23
+ {!name ? (
24
+ <Skeleton active paragraph={false} title={{ style: { marginBottom: 0 }, width: 80 }} />
25
+ ) : (
26
+ <Text ellipsis strong style={{ fontSize: 16 }}>
27
+ {name}
28
+ </Text>
29
+ )}
22
30
  </Flexbox>
23
31
  </Flexbox>
24
32
  );
@@ -10,12 +10,15 @@ import { Flexbox } from 'react-layout-kit';
10
10
 
11
11
  import Menu from '@/components/Menu';
12
12
  import type { MenuProps } from '@/components/Menu';
13
+ import { useKnowledgeBaseStore } from '@/store/knowledgeBase';
13
14
  import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
14
15
 
15
- const FileMenu = memo<{ id: string }>(({ id }) => {
16
+ const FileMenu = memo(() => {
16
17
  const { t } = useTranslation('knowledgeBase');
17
18
  const pathname = usePathname();
18
19
  const { enableRAGEval } = useServerConfigStore(featureFlagsSelectors);
20
+ const id = useKnowledgeBaseStore((s) => s.activeKnowledgeBaseId);
21
+
19
22
  const [activeKey, setActiveKey] = useState(
20
23
  pathname.startsWith(`/repos/${id}/evals`) ? 'eval' : 'files',
21
24
  );
@@ -4,14 +4,14 @@ import { Flexbox } from 'react-layout-kit';
4
4
  import Head from './Head';
5
5
  import Menu from './Menu';
6
6
 
7
- type Props = { id: string; name: string };
8
-
9
- const ComposeMenu = memo<Props>(({ id, name }) => (
10
- <Flexbox gap={16} height={'100%'} paddingInline={12} style={{ paddingTop: 12 }}>
11
- <Head name={name} />
12
- <Menu id={id} />
13
- </Flexbox>
14
- ));
7
+ const ComposeMenu = memo<{ id: string }>(({ id }) => {
8
+ return (
9
+ <Flexbox gap={16} height={'100%'} paddingInline={12} style={{ paddingTop: 12 }}>
10
+ <Head id={id} />
11
+ <Menu />
12
+ </Flexbox>
13
+ );
14
+ });
15
15
 
16
16
  ComposeMenu.displayName = 'ComposeMenu';
17
17
 
@@ -9,3 +9,5 @@ const Layout = ServerLayout<LayoutProps>({ Desktop, Mobile });
9
9
  Layout.displayName = 'RepoLayout';
10
10
 
11
11
  export default (props: LayoutProps) => <Layout {...props} />;
12
+
13
+ export const dynamic = 'force-static';
@@ -1,29 +1,9 @@
1
- import { redirect } from 'next/navigation';
2
- import { Flexbox } from 'react-layout-kit';
3
-
4
- import { KnowledgeBaseModel } from '@/database/models/knowledgeBase';
5
- import { getServerDB } from '@/database/server';
6
- import FileManager from '@/features/FileManager';
7
- import FilePanel from '@/features/FileSidePanel';
8
1
  import { PagePropsWithId } from '@/types/next';
9
2
 
10
- import Menu from './features/Menu';
3
+ import Client from './Client';
11
4
 
12
5
  export default async (props: PagePropsWithId) => {
13
6
  const params = await props.params;
14
7
 
15
- const serverDB = await getServerDB();
16
- const item = await KnowledgeBaseModel.findById(serverDB, params.id);
17
- if (!item) return redirect('/repos');
18
-
19
- return (
20
- <>
21
- <FilePanel>
22
- <Menu id={params.id} name={item.name} />
23
- </FilePanel>
24
- <Flexbox flex={1} style={{ overflow: 'hidden', position: 'relative' }}>
25
- <FileManager knowledgeBaseId={params.id} title={item.name} />
26
- </Flexbox>
27
- </>
28
- );
8
+ return <Client id={params.id} />;
29
9
  };
@@ -0,0 +1,3 @@
1
+ import Loading from '@/components/Loading/BrandTextLoading';
2
+
3
+ export default () => <Loading />;
@@ -0,0 +1,17 @@
1
+ 'use client';
2
+
3
+ import { useQueryState } from 'nuqs';
4
+ import { memo } from 'react';
5
+
6
+ import { AgentCategory } from '@/features/AgentSetting';
7
+ import { ChatSettingsTabs } from '@/store/global/initialState';
8
+
9
+ const Menu = memo(() => {
10
+ const [tab, setTab] = useQueryState('tab', {
11
+ defaultValue: ChatSettingsTabs.Prompt,
12
+ });
13
+
14
+ return <AgentCategory setTab={setTab} tab={tab} />;
15
+ });
16
+
17
+ export default Menu;
@@ -1,14 +1,13 @@
1
1
  'use client';
2
2
 
3
3
  import { Alert } from '@lobehub/ui';
4
+ import { Skeleton } from 'antd';
4
5
  import { useTheme } from 'antd-style';
5
- import { useQueryState } from 'nuqs';
6
- import { memo } from 'react';
6
+ import { Suspense, memo } from 'react';
7
7
  import { useTranslation } from 'react-i18next';
8
8
  import { Flexbox } from 'react-layout-kit';
9
9
 
10
- import { AgentCategory } from '@/features/AgentSetting';
11
- import { ChatSettingsTabs } from '@/store/global/initialState';
10
+ import Menu from './Menu';
12
11
 
13
12
  interface ProviderMenuProps {
14
13
  mobile?: boolean;
@@ -16,9 +15,6 @@ interface ProviderMenuProps {
16
15
  const ProviderMenu = memo(({ mobile }: ProviderMenuProps) => {
17
16
  const theme = useTheme();
18
17
  const { t } = useTranslation('setting');
19
- const [tab, setTab] = useQueryState('tab', {
20
- defaultValue: ChatSettingsTabs.Prompt,
21
- });
22
18
 
23
19
  const width = mobile ? undefined : 260;
24
20
  return (
@@ -41,7 +37,15 @@ const ProviderMenu = memo(({ mobile }: ProviderMenuProps) => {
41
37
  }}
42
38
  variant={'filled'}
43
39
  />
44
- <AgentCategory setTab={setTab} tab={tab} />
40
+ <Suspense
41
+ fallback={
42
+ <Flexbox gap={4} paddingBlock={8} paddingInline={8}>
43
+ <Skeleton active paragraph={{ rows: 4 }} title={false} />
44
+ </Flexbox>
45
+ }
46
+ >
47
+ <Menu />
48
+ </Suspense>
45
49
  </Flexbox>
46
50
  );
47
51
  });
@@ -1,8 +1,13 @@
1
+ import { Skeleton } from 'antd';
2
+ import { Suspense } from 'react';
3
+
1
4
  import { metadataModule } from '@/server/metadata';
2
5
  import { translation } from '@/server/translation';
3
6
  import { DynamicLayoutProps } from '@/types/next';
4
7
  import { RouteVariants } from '@/utils/server/routeVariants';
5
8
 
9
+ import Page from './index';
10
+
6
11
  export const generateMetadata = async (props: DynamicLayoutProps) => {
7
12
  const locale = await RouteVariants.getLocale(props);
8
13
  const { t } = await translation('setting', locale);
@@ -12,4 +17,13 @@ export const generateMetadata = async (props: DynamicLayoutProps) => {
12
17
  url: '/settings/agent',
13
18
  });
14
19
  };
15
- export { default } from './index';
20
+
21
+ export default () => {
22
+ return (
23
+ <Suspense fallback={<Skeleton active paragraph={{ rows: 5 }} title={false} />}>
24
+ <Page />
25
+ </Suspense>
26
+ );
27
+ };
28
+
29
+ export const dynamic = 'force-static';
@@ -1,22 +1,34 @@
1
1
  'use client';
2
2
 
3
- import { memo } from 'react';
3
+ import { useRouter } from 'next/navigation';
4
+ import { memo, useEffect } from 'react';
4
5
  import { Flexbox } from 'react-layout-kit';
5
- import useSWR from 'swr';
6
6
 
7
+ import Loading from '@/components/Loading/BrandTextLoading';
8
+ import { useClientDataSWR } from '@/libs/swr';
7
9
  import { aiProviderService } from '@/services/aiProvider';
8
10
 
9
11
  import ModelList from '../../features/ModelList';
10
12
  import ProviderConfig from '../../features/ProviderConfig';
11
13
 
12
14
  const ClientMode = memo<{ id: string }>(({ id }) => {
13
- const { data, isLoading } = useSWR('get-client-provider', () =>
15
+ const { data, isLoading } = useClientDataSWR('get-client-provider', () =>
14
16
  aiProviderService.getAiProviderById(id),
15
17
  );
16
18
 
19
+ const router = useRouter();
20
+
21
+ useEffect(() => {
22
+ if (!isLoading && !data?.id) {
23
+ router.push('/settings/provider');
24
+ }
25
+ }, [isLoading, data]);
26
+
27
+ if (isLoading || !data || !data.id) return <Loading />;
28
+
17
29
  return (
18
30
  <Flexbox gap={24} paddingBlock={8}>
19
- {!isLoading && data && <ProviderConfig {...data} />}
31
+ <ProviderConfig {...data} id={id} name={data.name || ''} />
20
32
  <ModelList id={id} />
21
33
  </Flexbox>
22
34
  );
@@ -1,14 +1,5 @@
1
- import { redirect } from 'next/navigation';
2
-
3
1
  import { DEFAULT_MODEL_PROVIDER_LIST } from '@/config/modelProviders';
4
- import { isDesktop, isServerMode } from '@/const/version';
5
- import { AiInfraRepos } from '@/database/repositories/aiInfra';
6
- import { serverDB } from '@/database/server';
7
- import { getServerGlobalConfig } from '@/server/globalConfig';
8
- import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
9
2
  import { PagePropsWithId } from '@/types/next';
10
- import { ProviderConfig } from '@/types/user/settings';
11
- import { getUserAuth } from '@/utils/server/auth';
12
3
 
13
4
  import ClientMode from './ClientMode';
14
5
  import ProviderDetail from './index';
@@ -20,28 +11,9 @@ const Page = async (props: PagePropsWithId) => {
20
11
  // if builtin provider
21
12
  if (!!builtinProviderCard) return <ProviderDetail source={'builtin'} {...builtinProviderCard} />;
22
13
 
23
- // if user custom provider
24
- if (!isDesktop && isServerMode) {
25
- const { userId } = await getUserAuth();
26
-
27
- const { aiProvider } = await getServerGlobalConfig();
28
- const aiInfraRepos = new AiInfraRepos(
29
- serverDB,
30
- userId!,
31
- aiProvider as Record<string, ProviderConfig>,
32
- );
33
-
34
- const userCard = await aiInfraRepos.getAiProviderDetail(
35
- params.id,
36
- KeyVaultsGateKeeper.getUserKeyVaults,
37
- );
38
-
39
- if (!userCard) return redirect('/settings/provider');
40
-
41
- return <ProviderDetail {...userCard} />;
42
- }
43
-
44
14
  return <ClientMode id={params.id} />;
45
15
  };
46
16
 
47
17
  export default Page;
18
+
19
+ export const dynamic = 'force-static';
@@ -19,5 +19,3 @@ const ProviderSettingsLayout = ({ children, ...res }: PropsWithChildren) => {
19
19
  ProviderSettingsLayout.displayName = 'ProviderSettingsLayout';
20
20
 
21
21
  export default ProviderSettingsLayout;
22
-
23
- export const dynamic = 'auto';
@@ -4,16 +4,20 @@ import { useTheme } from 'antd-style';
4
4
  import NextTopLoader from 'nextjs-toploader';
5
5
  import { memo } from 'react';
6
6
 
7
+ import { isDesktop } from '@/const/version';
8
+
7
9
  const NProgress = memo(() => {
8
10
  const theme = useTheme();
9
11
  return (
10
- <NextTopLoader
11
- color={theme.colorText}
12
- height={2}
13
- shadow={false}
14
- showSpinner={false}
15
- zIndex={1000}
16
- />
12
+ !isDesktop && (
13
+ <NextTopLoader
14
+ color={theme.colorText}
15
+ height={2}
16
+ shadow={false}
17
+ showSpinner={false}
18
+ zIndex={1000}
19
+ />
20
+ )
17
21
  );
18
22
  });
19
23
 
@@ -51,6 +51,7 @@ const CommonSTT = memo<{
51
51
  return (
52
52
  <Dropdown
53
53
  menu={{
54
+ // @ts-expect-error 等待 antd 修复
54
55
  activeKey: 'time',
55
56
  items: [
56
57
  {
@@ -1,4 +1,5 @@
1
1
  import { Button, Form, Input, TextArea } from '@lobehub/ui';
2
+ import { useRouter } from 'next/navigation';
2
3
  import { memo, useState } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
4
5
 
@@ -13,14 +14,17 @@ const CreateForm = memo<CreateFormProps>(({ onClose }) => {
13
14
  const { t } = useTranslation('knowledgeBase');
14
15
  const [loading, setLoading] = useState(false);
15
16
  const createNewKnowledgeBase = useKnowledgeBaseStore((s) => s.createNewKnowledgeBase);
17
+ const router = useRouter();
16
18
 
17
19
  const onFinish = async (values: CreateKnowledgeBaseParams) => {
18
20
  setLoading(true);
19
21
 
20
22
  try {
21
- await createNewKnowledgeBase(values);
23
+ const id = await createNewKnowledgeBase(values);
22
24
  setLoading(false);
23
25
  onClose?.();
26
+
27
+ router.push(`/repos/${id}`);
24
28
  } catch (e) {
25
29
  console.error(e);
26
30
  setLoading(false);
@@ -14,11 +14,13 @@ import { useDetailContext } from '../DetailProvider';
14
14
  import { useStyles } from './style';
15
15
  import { ModeType } from './types';
16
16
 
17
- const Prompts = memo<{
17
+ interface PromptsProps {
18
18
  activeKey?: string[];
19
19
  mode?: ModeType;
20
20
  setActiveKey?: (key: string[]) => void;
21
- }>(({ mode, activeKey = [], setActiveKey }) => {
21
+ }
22
+
23
+ const Prompts = memo<PromptsProps>(({ mode, activeKey = [], setActiveKey }) => {
22
24
  const { t } = useTranslation('discover');
23
25
  const { prompts } = useDetailContext();
24
26
  const { styles, theme } = useStyles();
@@ -14,11 +14,13 @@ import { useDetailContext } from '../DetailProvider';
14
14
  import { useStyles } from './style';
15
15
  import { ModeType } from './types';
16
16
 
17
- const Tools = memo<{
17
+ interface ToolsProps {
18
18
  activeKey?: string[];
19
19
  mode?: ModeType;
20
20
  setActiveKey?: (key: string[]) => void;
21
- }>(({ mode, activeKey = [], setActiveKey }) => {
21
+ }
22
+
23
+ const Tools = memo<ToolsProps>(({ mode, activeKey = [], setActiveKey }) => {
22
24
  const { t } = useTranslation('discover');
23
25
  const { tools } = useDetailContext();
24
26
  const { styles, theme } = useStyles();
@@ -59,6 +59,7 @@ const GithubBadge = memo(() => {
59
59
  <Snippet language={'md'} style={{ fontSize: 12 }} variant={'outlined'}>
60
60
  {badgeLite}
61
61
  </Snippet>
62
+ {/* eslint-disable-next-line @next/next/no-img-element */}
62
63
  <img
63
64
  alt="MCP Badge"
64
65
  height={selectedStyle === 'for-the-badge' ? 28 : 20}
@@ -74,6 +75,7 @@ const GithubBadge = memo(() => {
74
75
  <Snippet language={'md'} style={{ fontSize: 12 }} variant={'outlined'}>
75
76
  {badge}
76
77
  </Snippet>
78
+ {/* eslint-disable-next-line @next/next/no-img-element */}
77
79
  <img alt="MCP Badge" src={styledBadgeFullUrl} />
78
80
  </>
79
81
  );
@@ -69,13 +69,15 @@ const ModelSelect = memo<ModelSelectProps>(({ value, onChange, showAbility = tru
69
69
  return (
70
70
  <Select
71
71
  className={styles.select}
72
+ classNames={{
73
+ popup: { root: styles.popup },
74
+ }}
72
75
  defaultValue={`${value?.provider}/${value?.model}`}
73
76
  onChange={(value, option) => {
74
77
  const model = value.split('/').slice(1).join('/');
75
78
  onChange?.({ model, provider: (option as unknown as ModelOption).provider });
76
79
  }}
77
80
  options={options}
78
- popupClassName={styles.popup}
79
81
  popupMatchSelectWidth={false}
80
82
  value={`${value?.provider}/${value?.model}`}
81
83
  />
@@ -141,6 +141,7 @@ const ModelSwitchPanel = memo<IProps>(({ children, onOpenChange, open }) => {
141
141
  return (
142
142
  <ActionDropdown
143
143
  menu={{
144
+ // @ts-expect-error 等待 antd 修复
144
145
  activeKey: menuKey(provider, model),
145
146
  className: styles.menu,
146
147
  items,
@@ -1,4 +1,5 @@
1
1
  import {
2
+ AiProviderDetailItem,
2
3
  AiProviderRuntimeState,
3
4
  AiProviderSortMap,
4
5
  CreateAiProviderParams,
@@ -10,7 +11,7 @@ export interface IAiProviderService {
10
11
 
11
12
  deleteAiProvider: (id: string) => Promise<any>;
12
13
 
13
- getAiProviderById: (id: string) => Promise<any>;
14
+ getAiProviderById: (id: string) => Promise<AiProviderDetailItem | undefined>;
14
15
 
15
16
  getAiProviderList: () => Promise<any>;
16
17
 
@@ -10,7 +10,7 @@ const FETCH_KNOWLEDGE_BASE_LIST_KEY = 'FETCH_KNOWLEDGE_BASE';
10
10
  const FETCH_KNOWLEDGE_BASE_ITEM_KEY = 'FETCH_KNOWLEDGE_BASE_ITEM';
11
11
 
12
12
  export interface KnowledgeBaseCrudAction {
13
- createNewKnowledgeBase: (params: CreateKnowledgeBaseParams) => Promise<void>;
13
+ createNewKnowledgeBase: (params: CreateKnowledgeBaseParams) => Promise<string>;
14
14
  internal_toggleKnowledgeBaseLoading: (id: string, loading: boolean) => void;
15
15
  refreshKnowledgeBaseList: () => Promise<void>;
16
16
 
@@ -28,8 +28,11 @@ export const createCrudSlice: StateCreator<
28
28
  KnowledgeBaseCrudAction
29
29
  > = (set, get) => ({
30
30
  createNewKnowledgeBase: async (params) => {
31
- await knowledgeBaseService.createKnowledgeBase(params);
31
+ const id = await knowledgeBaseService.createKnowledgeBase(params);
32
+
32
33
  await get().refreshKnowledgeBaseList();
34
+
35
+ return id;
33
36
  },
34
37
  internal_toggleKnowledgeBaseLoading: (id, loading) => {
35
38
  set(
@@ -58,8 +61,22 @@ export const createCrudSlice: StateCreator<
58
61
  },
59
62
 
60
63
  useFetchKnowledgeBaseItem: (id) =>
61
- useClientDataSWR<KnowledgeBaseItem | undefined>([FETCH_KNOWLEDGE_BASE_ITEM_KEY, id], () =>
62
- knowledgeBaseService.getKnowledgeBaseById(id),
64
+ useClientDataSWR<KnowledgeBaseItem | undefined>(
65
+ [FETCH_KNOWLEDGE_BASE_ITEM_KEY, id],
66
+ () => knowledgeBaseService.getKnowledgeBaseById(id),
67
+ {
68
+ onSuccess: (item) => {
69
+ if (!item) return;
70
+
71
+ set({
72
+ activeKnowledgeBaseId: id,
73
+ activeKnowledgeBaseItems: {
74
+ ...get().activeKnowledgeBaseItems,
75
+ [id]: item,
76
+ },
77
+ });
78
+ },
79
+ },
63
80
  ),
64
81
 
65
82
  useFetchKnowledgeBaseList: (params = {}) =>
@@ -1,5 +1,8 @@
1
+ import { KnowledgeBaseItem } from '@/types/knowledgeBase';
2
+
1
3
  export interface KnowledgeBaseState {
2
4
  activeKnowledgeBaseId: string | null;
5
+ activeKnowledgeBaseItems: Record<string, KnowledgeBaseItem>;
3
6
  initKnowledgeBaseList: boolean;
4
7
  knowledgeBaseLoadingIds: string[];
5
8
  knowledgeBaseRenamingId?: string | null;
@@ -7,6 +10,7 @@ export interface KnowledgeBaseState {
7
10
 
8
11
  export const initialKnowledgeBaseState: KnowledgeBaseState = {
9
12
  activeKnowledgeBaseId: null,
13
+ activeKnowledgeBaseItems: {},
10
14
  initKnowledgeBaseList: false,
11
15
  knowledgeBaseLoadingIds: [],
12
16
  };
@@ -2,6 +2,13 @@ import { KnowledgeBaseStoreState } from '@/store/knowledgeBase/initialState';
2
2
 
3
3
  const activeKnowledgeBaseId = (s: KnowledgeBaseStoreState) => s.activeKnowledgeBaseId;
4
4
 
5
+ const getKnowledgeBaseById = (id: string) => (s: KnowledgeBaseStoreState) =>
6
+ s.activeKnowledgeBaseItems[id];
7
+
8
+ const getKnowledgeBaseNameById = (id: string) => (s: KnowledgeBaseStoreState) =>
9
+ getKnowledgeBaseById(id)(s)?.name;
10
+
5
11
  export const knowledgeBaseSelectors = {
6
12
  activeKnowledgeBaseId,
13
+ getKnowledgeBaseNameById,
7
14
  };