@lobehub/chat 1.49.0 → 1.49.2

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 (31) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/package.json +2 -2
  4. package/src/app/(main)/_layout/Mobile/index.tsx +2 -2
  5. package/src/app/(main)/chat/_layout/Mobile.tsx +2 -2
  6. package/src/app/(main)/discover/features/StoreSearchBar.tsx +3 -5
  7. package/src/app/(main)/discover/features/useNav.tsx +3 -3
  8. package/src/app/(main)/discover/search/_layout/Mobile/Header.tsx +2 -2
  9. package/src/app/(main)/files/(content)/_layout/Mobile.tsx +2 -2
  10. package/src/app/(main)/profile/@category/features/CategoryContent.tsx +5 -10
  11. package/src/app/(main)/repos/[id]/_layout/Mobile.tsx +2 -2
  12. package/src/app/(main)/settings/@category/features/CategoryContent.tsx +3 -10
  13. package/src/app/@modal/chat/(.)settings/modal/features/CategoryContent.tsx +2 -3
  14. package/src/app/@modal/chat/(.)settings/modal/layout.tsx +2 -2
  15. package/src/app/@modal/chat/(.)settings/modal/page.tsx +3 -2
  16. package/src/components/DataStyleModal/index.tsx +3 -1
  17. package/src/components/withSuspense.tsx +8 -0
  18. package/src/features/AgentSetting/AgentTTS/index.tsx +2 -2
  19. package/src/features/InitClientDB/EnableModal.tsx +9 -1
  20. package/src/hooks/useActiveTabKey.ts +3 -3
  21. package/src/hooks/useChatSettingsTab.ts +12 -0
  22. package/src/hooks/useDiscoverTab.ts +12 -0
  23. package/src/hooks/useQueryRoute.test.ts +6 -4
  24. package/src/hooks/useQueryRoute.ts +4 -3
  25. package/src/hooks/useSettingsTab.ts +12 -0
  26. package/src/hooks/useShowMobileWorkspace.ts +7 -0
  27. package/src/hooks/useWorkspaceModal.tsx +2 -2
  28. package/src/layout/GlobalProvider/ReactScan.tsx +3 -1
  29. package/src/middleware.ts +4 -0
  30. package/src/hooks/useQuery.test.ts +0 -19
  31. package/src/hooks/useQuery.ts +0 -8
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.49.2](https://github.com/lobehub/lobe-chat/compare/v1.49.1...v1.49.2)
6
+
7
+ <sup>Released on **2025-01-27**</sup>
8
+
9
+ #### ♻ Code Refactoring
10
+
11
+ - **misc**: Remove use query.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Code refactoring
19
+
20
+ - **misc**: Remove use query, closes [#5604](https://github.com/lobehub/lobe-chat/issues/5604) ([58c60de](https://github.com/lobehub/lobe-chat/commit/58c60de))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ### [Version 1.49.1](https://github.com/lobehub/lobe-chat/compare/v1.49.0...v1.49.1)
31
+
32
+ <sup>Released on **2025-01-27**</sup>
33
+
34
+ #### ♻ Code Refactoring
35
+
36
+ - **misc**: UseMobileWorkspace use nqus to replace useQuery.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### Code refactoring
44
+
45
+ - **misc**: UseMobileWorkspace use nqus to replace useQuery, closes [#5603](https://github.com/lobehub/lobe-chat/issues/5603) ([70e5272](https://github.com/lobehub/lobe-chat/commit/70e5272))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ## [Version 1.49.0](https://github.com/lobehub/lobe-chat/compare/v1.48.4...v1.49.0)
6
56
 
7
57
  <sup>Released on **2025-01-27**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,22 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "improvements": [
5
+ "Remove use query."
6
+ ]
7
+ },
8
+ "date": "2025-01-27",
9
+ "version": "1.49.2"
10
+ },
11
+ {
12
+ "children": {
13
+ "improvements": [
14
+ "UseMobileWorkspace use nqus to replace useQuery."
15
+ ]
16
+ },
17
+ "date": "2025-01-27",
18
+ "version": "1.49.1"
19
+ },
2
20
  {
3
21
  "children": {
4
22
  "features": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.49.0",
3
+ "version": "1.49.2",
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",
@@ -129,7 +129,7 @@
129
129
  "@lobehub/chat-plugins-gateway": "^1.9.0",
130
130
  "@lobehub/icons": "^1.61.1",
131
131
  "@lobehub/tts": "^1.28.0",
132
- "@lobehub/ui": "^1.164.2",
132
+ "@lobehub/ui": "^1.164.8",
133
133
  "@neondatabase/serverless": "^0.10.4",
134
134
  "@next/third-parties": "^15.1.4",
135
135
  "@react-spring/web": "^9.7.5",
@@ -5,7 +5,7 @@ import { usePathname } from 'next/navigation';
5
5
  import qs from 'query-string';
6
6
  import { PropsWithChildren, memo } from 'react';
7
7
 
8
- import { useQuery } from '@/hooks/useQuery';
8
+ import { useShowMobileWorkspace } from '@/hooks/useShowMobileWorkspace';
9
9
  import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
10
10
 
11
11
  import NavBar from './NavBar';
@@ -22,7 +22,7 @@ const MOBILE_NAV_ROUTES = new Set([
22
22
  ]);
23
23
 
24
24
  const Layout = memo(({ children }: PropsWithChildren) => {
25
- const { showMobileWorkspace } = useQuery();
25
+ const showMobileWorkspace = useShowMobileWorkspace();
26
26
  const pathname = usePathname();
27
27
  const { url } = qs.parseUrl(pathname);
28
28
  const showNav = !showMobileWorkspace && MOBILE_NAV_ROUTES.has(url);
@@ -5,7 +5,7 @@ import { Suspense, memo } from 'react';
5
5
  import { Flexbox } from 'react-layout-kit';
6
6
 
7
7
  import InitClientDB from '@/features/InitClientDB';
8
- import { useQuery } from '@/hooks/useQuery';
8
+ import { useShowMobileWorkspace } from '@/hooks/useShowMobileWorkspace';
9
9
 
10
10
  import { LayoutProps } from './type';
11
11
 
@@ -18,7 +18,7 @@ const useStyles = createStyles(({ css, token }) => ({
18
18
  }));
19
19
 
20
20
  const Layout = memo<LayoutProps>(({ children, session }) => {
21
- const { showMobileWorkspace } = useQuery();
21
+ const showMobileWorkspace = useShowMobileWorkspace();
22
22
  const { styles } = useStyles();
23
23
 
24
24
  return (
@@ -8,7 +8,6 @@ import { memo, useEffect, useState } from 'react';
8
8
  import { useTranslation } from 'react-i18next';
9
9
  import urlJoin from 'url-join';
10
10
 
11
- import { useQuery } from '@/hooks/useQuery';
12
11
  import { useQueryRoute } from '@/hooks/useQueryRoute';
13
12
  import { DiscoverTab } from '@/types/discover';
14
13
 
@@ -32,9 +31,8 @@ interface StoreSearchBarProps extends SearchBarProps {
32
31
  const StoreSearchBar = memo<StoreSearchBarProps>(({ mobile, onBlur, onFocus, ...rest }) => {
33
32
  const [active, setActive] = useState(false);
34
33
  const pathname = usePathname();
35
- const { q } = useQuery();
36
34
  const { activeKey } = useNav();
37
- const [searchKey, setSearchKey] = useQueryState('q');
35
+ const [searchKey, setSearchKey] = useQueryState('q', { clearOnDefault: true, defaultValue: '' });
38
36
 
39
37
  const { t } = useTranslation('discover');
40
38
  const { cx, styles } = useStyles();
@@ -45,8 +43,8 @@ const StoreSearchBar = memo<StoreSearchBarProps>(({ mobile, onBlur, onFocus, ...
45
43
  useEffect(() => {
46
44
  if (!pathname.includes('/discover/search')) return;
47
45
  // 使用 useQueryState 时,当 handleSearch 为空时无法回跳
48
- if (!q) router.push(urlJoin('/discover', activeType), { query: {}, replace: true });
49
- }, [q, pathname, activeType]);
46
+ if (!searchKey) router.push(urlJoin('/discover', activeType), { query: {}, replace: true });
47
+ }, [searchKey, pathname, activeType]);
50
48
 
51
49
  const handleSearch = (value: string) => {
52
50
  router.push('/discover/search', { query: { q: value, type: activeType } });
@@ -6,19 +6,19 @@ import { useTranslation } from 'react-i18next';
6
6
  import urlJoin from 'url-join';
7
7
 
8
8
  import type { MenuProps } from '@/components/Menu';
9
- import { useQuery } from '@/hooks/useQuery';
9
+ import { useDiscoverTab } from '@/hooks/useDiscoverTab';
10
10
  import { DiscoverTab } from '@/types/discover';
11
11
 
12
12
  export const useNav = () => {
13
13
  const pathname = usePathname();
14
- const { type } = useQuery();
14
+ const type = useDiscoverTab();
15
15
  const { t } = useTranslation('discover');
16
16
  const iconSize = { fontSize: 16 };
17
17
 
18
18
  const activeKey = useMemo(() => {
19
19
  for (const value of Object.values(DiscoverTab)) {
20
20
  if (pathname === '/discover/search') {
21
- return (type as DiscoverTab) || DiscoverTab.Assistants;
21
+ return type;
22
22
  } else if (pathname.includes(urlJoin('/discover', value))) {
23
23
  return value;
24
24
  }
@@ -5,14 +5,14 @@ import { useRouter } from 'next/navigation';
5
5
  import { memo } from 'react';
6
6
  import urlJoin from 'url-join';
7
7
 
8
- import { useQuery } from '@/hooks/useQuery';
8
+ import { useDiscoverTab } from '@/hooks/useDiscoverTab';
9
9
  import { mobileHeaderSticky } from '@/styles/mobileHeader';
10
10
 
11
11
  import StoreSearchBar from '../../../features/StoreSearchBar';
12
12
 
13
13
  const Header = memo(() => {
14
14
  const router = useRouter();
15
- const { type = 'assistants' } = useQuery();
15
+ const type = useDiscoverTab();
16
16
 
17
17
  return (
18
18
  <MobileNavBar
@@ -4,7 +4,7 @@ import { createStyles } from 'antd-style';
4
4
  import { memo } from 'react';
5
5
  import { Flexbox } from 'react-layout-kit';
6
6
 
7
- import { useQuery } from '@/hooks/useQuery';
7
+ import { useShowMobileWorkspace } from '@/hooks/useShowMobileWorkspace';
8
8
 
9
9
  import { LayoutProps } from './type';
10
10
 
@@ -17,7 +17,7 @@ const useStyles = createStyles(({ css, token }) => ({
17
17
  }));
18
18
 
19
19
  const Layout = memo<LayoutProps>(({ children, menu }) => {
20
- const { showMobileWorkspace } = useQuery();
20
+ const showMobileWorkspace = useShowMobileWorkspace();
21
21
  const { styles } = useStyles();
22
22
 
23
23
  return (
@@ -5,15 +5,13 @@ import urlJoin from 'url-join';
5
5
 
6
6
  import Menu from '@/components/Menu';
7
7
  import { useActiveSettingsKey } from '@/hooks/useActiveTabKey';
8
- import { useQuery } from '@/hooks/useQuery';
9
8
  import { useQueryRoute } from '@/hooks/useQueryRoute';
10
- import { ProfileTabs, SettingsTabs } from '@/store/global/initialState';
9
+ import { ProfileTabs } from '@/store/global/initialState';
11
10
 
12
11
  import { useCategory } from '../../hooks/useCategory';
13
12
 
14
- const CategoryContent = memo<{ modal?: boolean }>(({ modal }) => {
13
+ const CategoryContent = memo(() => {
15
14
  const activeTab = useActiveSettingsKey();
16
- const { tab = SettingsTabs.Common } = useQuery();
17
15
  const cateItems = useCategory();
18
16
  const router = useQueryRoute();
19
17
 
@@ -22,14 +20,11 @@ const CategoryContent = memo<{ modal?: boolean }>(({ modal }) => {
22
20
  items={cateItems}
23
21
  onClick={({ key }) => {
24
22
  const activeKey = key === ProfileTabs.Profile ? '/' : key;
25
- if (modal) {
26
- router.replace('/profile/modal', { query: { tab: activeKey } });
27
- } else {
28
- router.push(urlJoin('/profile', activeKey));
29
- }
23
+
24
+ router.push(urlJoin('/profile', activeKey));
30
25
  }}
31
26
  selectable
32
- selectedKeys={[modal ? tab : (activeTab as any)]}
27
+ selectedKeys={[activeTab]}
33
28
  variant={'compact'}
34
29
  />
35
30
  );
@@ -4,7 +4,7 @@ import { createStyles } from 'antd-style';
4
4
  import { memo } from 'react';
5
5
  import { Flexbox } from 'react-layout-kit';
6
6
 
7
- import { useQuery } from '@/hooks/useQuery';
7
+ import { useShowMobileWorkspace } from '@/hooks/useShowMobileWorkspace';
8
8
 
9
9
  import { LayoutProps } from './type';
10
10
 
@@ -17,7 +17,7 @@ const useStyles = createStyles(({ css, token }) => ({
17
17
  }));
18
18
 
19
19
  const Layout = memo<LayoutProps>(({ children, menu }) => {
20
- const { showMobileWorkspace } = useQuery();
20
+ const showMobileWorkspace = useShowMobileWorkspace();
21
21
  const { styles } = useStyles();
22
22
 
23
23
  return (
@@ -5,15 +5,12 @@ import urlJoin from 'url-join';
5
5
 
6
6
  import Menu from '@/components/Menu';
7
7
  import { useActiveSettingsKey } from '@/hooks/useActiveTabKey';
8
- import { useQuery } from '@/hooks/useQuery';
9
8
  import { useQueryRoute } from '@/hooks/useQueryRoute';
10
- import { SettingsTabs } from '@/store/global/initialState';
11
9
 
12
10
  import { useCategory } from '../../hooks/useCategory';
13
11
 
14
- const CategoryContent = memo<{ modal?: boolean }>(({ modal }) => {
12
+ const CategoryContent = memo(() => {
15
13
  const activeTab = useActiveSettingsKey();
16
- const { tab = SettingsTabs.Common } = useQuery();
17
14
  const cateItems = useCategory();
18
15
  const router = useQueryRoute();
19
16
 
@@ -21,14 +18,10 @@ const CategoryContent = memo<{ modal?: boolean }>(({ modal }) => {
21
18
  <Menu
22
19
  items={cateItems}
23
20
  onClick={({ key }) => {
24
- if (modal) {
25
- router.replace('/settings/modal', { query: { tab: key } });
26
- } else {
27
- router.push(urlJoin('/settings', key));
28
- }
21
+ router.push(urlJoin('/settings', key));
29
22
  }}
30
23
  selectable
31
- selectedKeys={[modal ? tab : (activeTab as any)]}
24
+ selectedKeys={[activeTab]}
32
25
  variant={'compact'}
33
26
  />
34
27
  );
@@ -5,15 +5,14 @@ import { Flexbox } from 'react-layout-kit';
5
5
 
6
6
  import HeaderContent from '@/app/(main)/chat/settings/features/HeaderContent';
7
7
  import Menu from '@/components/Menu';
8
- import { useQuery } from '@/hooks/useQuery';
8
+ import { useChatSettingsTab } from '@/hooks/useChatSettingsTab';
9
9
  import { useQueryRoute } from '@/hooks/useQueryRoute';
10
- import { ChatSettingsTabs } from '@/store/global/initialState';
11
10
 
12
11
  import { useCategory } from './useCategory';
13
12
 
14
13
  const CategoryContent = memo(() => {
15
14
  const cateItems = useCategory();
16
- const { tab = ChatSettingsTabs.Meta } = useQuery();
15
+ const tab = useChatSettingsTab();
17
16
  const router = useQueryRoute();
18
17
 
19
18
  return (
@@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next';
9
9
  import ModalLayout from '@/app/@modal/_layout/ModalLayout';
10
10
  import StoreUpdater from '@/features/AgentSetting/StoreUpdater';
11
11
  import { Provider, createStore } from '@/features/AgentSetting/store';
12
- import { useQuery } from '@/hooks/useQuery';
12
+ import { useChatSettingsTab } from '@/hooks/useChatSettingsTab';
13
13
  import { useAgentStore } from '@/store/agent';
14
14
  import { agentSelectors } from '@/store/agent/slices/chat';
15
15
  import { ChatSettingsTabs } from '@/store/global/initialState';
@@ -24,7 +24,7 @@ const CategoryContent = dynamic(() => import('./features/CategoryContent'), {
24
24
  });
25
25
 
26
26
  const Layout = memo<PropsWithChildren>(({ children }) => {
27
- const { tab = ChatSettingsTabs.Meta } = useQuery();
27
+ const tab = useChatSettingsTab();
28
28
  const { t } = useTranslation('setting');
29
29
  const id = useSessionStore((s) => s.activeId);
30
30
  const config = useAgentStore(agentSelectors.currentAgentConfig, isEqual);
@@ -2,7 +2,7 @@
2
2
 
3
3
  import dynamic from 'next/dynamic';
4
4
 
5
- import { useQuery } from '@/hooks/useQuery';
5
+ import { useChatSettingsTab } from '@/hooks/useChatSettingsTab';
6
6
  import { ChatSettingsTabs } from '@/store/global/initialState';
7
7
 
8
8
  import Skeleton from './loading';
@@ -37,7 +37,8 @@ const AgentTTS = dynamic(() => import('@/features/AgentSetting/AgentTTS'), { loa
37
37
  */
38
38
 
39
39
  const Page = () => {
40
- const { tab = ChatSettingsTabs.Meta } = useQuery();
40
+ const tab = useChatSettingsTab();
41
+
41
42
  return (
42
43
  <>
43
44
  {tab === ChatSettingsTabs.Meta && <AgentMeta />}
@@ -26,6 +26,7 @@ const useStyles = createStyles(({ css, token, prefixCls, isDarkMode }) => ({
26
26
 
27
27
  interface DataStyleModalProps {
28
28
  children: ReactNode;
29
+ height?: number | string;
29
30
  icon: LucideIcon;
30
31
  onOpenChange?: (open: boolean) => void;
31
32
  open: boolean;
@@ -34,7 +35,7 @@ interface DataStyleModalProps {
34
35
  }
35
36
 
36
37
  const DataStyleModal = memo<DataStyleModalProps>(
37
- ({ icon, onOpenChange, title, open, children, width = 550 }) => {
38
+ ({ icon, onOpenChange, title, open, children, width = 550, height }) => {
38
39
  const { styles } = useStyles();
39
40
 
40
41
  return (
@@ -46,6 +47,7 @@ const DataStyleModal = memo<DataStyleModalProps>(
46
47
  }}
47
48
  closable={false}
48
49
  footer={null}
50
+ height={height}
49
51
  open={open}
50
52
  title={
51
53
  <Flexbox gap={8} horizontal>
@@ -0,0 +1,8 @@
1
+ import { ComponentType, Suspense } from 'react';
2
+
3
+ // @ts-ignore
4
+ export const withSuspense: <T>(Comp: T) => T = (Component: ComponentType<any>) => (props: any) => (
5
+ <Suspense>
6
+ <Component {...props} />
7
+ </Suspense>
8
+ );
@@ -28,8 +28,8 @@ const AgentTTS = memo(() => {
28
28
  return (all?: boolean) => new VoiceList(all ? undefined : locale);
29
29
  });
30
30
  const [showAllLocaleVoice, ttsService, updateConfig] = useStore((s) => [
31
- s.config.tts.showAllLocaleVoice,
32
- s.config.tts.ttsService,
31
+ s.config.tts?.showAllLocaleVoice,
32
+ s.config.tts?.ttsService,
33
33
  s.setAgentConfig,
34
34
  ]);
35
35
 
@@ -8,6 +8,7 @@ import { Center, Flexbox } from 'react-layout-kit';
8
8
 
9
9
  import DataStyleModal from '@/components/DataStyleModal';
10
10
  import { useGlobalStore } from '@/store/global';
11
+ import { useServerConfigStore } from '@/store/serverConfig';
11
12
 
12
13
  import PGliteIcon from './PGliteIcon';
13
14
 
@@ -56,6 +57,8 @@ interface EnableClientDBModalProps {
56
57
  const EnableClientDBModal = memo<EnableClientDBModalProps>(({ open }) => {
57
58
  const { t } = useTranslation('common');
58
59
  const { styles } = useStyles();
60
+ const isMobile = useServerConfigStore((s) => s.isMobile);
61
+
59
62
  const markPgliteEnabled = useGlobalStore((s) => s.markPgliteEnabled);
60
63
  const features = [
61
64
  {
@@ -76,7 +79,12 @@ const EnableClientDBModal = memo<EnableClientDBModalProps>(({ open }) => {
76
79
  ];
77
80
 
78
81
  return (
79
- <DataStyleModal icon={CpuIcon} open={open} title={t('clientDB.modal.title')}>
82
+ <DataStyleModal
83
+ height={isMobile ? '80vh' : undefined}
84
+ icon={CpuIcon}
85
+ open={open}
86
+ title={t('clientDB.modal.title')}
87
+ >
80
88
  <Center gap={48}>
81
89
  <Flexbox>
82
90
  <Flexbox className={styles.intro} style={{ textAlign: 'center' }} width={460}>
@@ -1,6 +1,6 @@
1
1
  import { usePathname } from 'next/navigation';
2
+ import { useQueryState } from 'nuqs';
2
3
 
3
- import { useQuery } from '@/hooks/useQuery';
4
4
  import { ProfileTabs, SettingsTabs, SidebarTabKey } from '@/store/global/initialState';
5
5
 
6
6
  /**
@@ -17,7 +17,7 @@ export const useActiveTabKey = () => {
17
17
  */
18
18
  export const useActiveSettingsKey = () => {
19
19
  const pathname = usePathname();
20
- const { tab } = useQuery();
20
+ const [tab] = useQueryState('tab');
21
21
 
22
22
  const tabs = pathname.split('/').at(-1);
23
23
 
@@ -33,7 +33,7 @@ export const useActiveSettingsKey = () => {
33
33
  */
34
34
  export const useActiveProfileKey = () => {
35
35
  const pathname = usePathname();
36
- const { tab } = useQuery();
36
+ const [tab] = useQueryState('tab');
37
37
 
38
38
  const tabs = pathname.split('/').at(-1);
39
39
 
@@ -0,0 +1,12 @@
1
+ import { useQueryState } from 'nuqs';
2
+
3
+ import { ChatSettingsTabs } from '@/store/global/initialState';
4
+
5
+ export const useChatSettingsTab = () => {
6
+ const [type] = useQueryState('tab', {
7
+ clearOnDefault: true,
8
+ defaultValue: ChatSettingsTabs.Meta,
9
+ });
10
+
11
+ return type as ChatSettingsTabs;
12
+ };
@@ -0,0 +1,12 @@
1
+ import { useQueryState } from 'nuqs';
2
+
3
+ import { DiscoverTab } from '@/types/discover';
4
+
5
+ export const useDiscoverTab = () => {
6
+ const [type] = useQueryState('type', {
7
+ clearOnDefault: true,
8
+ defaultValue: DiscoverTab.Assistants,
9
+ });
10
+
11
+ return type as DiscoverTab;
12
+ };
@@ -1,5 +1,5 @@
1
1
  import { renderHook } from '@testing-library/react';
2
- import { describe, expect, it, vi } from 'vitest';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
3
 
4
4
  import { useQueryRoute } from './useQueryRoute';
5
5
 
@@ -10,13 +10,15 @@ vi.mock('next/navigation', () => ({
10
10
  replace: vi.fn((href) => href),
11
11
  })),
12
12
  }));
13
- vi.mock('@/hooks/useQuery', () => ({
14
- useQuery: vi.fn(() => ({ foo: 'bar' })),
15
- }));
13
+
16
14
  vi.mock('@/utils/env', () => ({
17
15
  isOnServerSide: false,
18
16
  }));
19
17
 
18
+ beforeEach(() => {
19
+ location.search = 'foo=bar';
20
+ });
21
+
20
22
  describe('useQueryRoute', () => {
21
23
  it('should generate correct href without hash and replace', () => {
22
24
  const { result } = renderHook(() =>
@@ -2,7 +2,6 @@ import { useRouter } from 'next/navigation';
2
2
  import qs, { type ParsedQuery } from 'query-string';
3
3
  import { useMemo } from 'react';
4
4
 
5
- import { useQuery } from '@/hooks/useQuery';
6
5
  import { isOnServerSide } from '@/utils/env';
7
6
 
8
7
  interface QueryRouteOptions {
@@ -30,17 +29,19 @@ const genHref = ({ hash, replace, url, prevQuery = {}, query = {} }: GenHrefOpti
30
29
 
31
30
  export const useQueryRoute = () => {
32
31
  const router = useRouter();
33
- const prevQuery = useQuery();
34
32
 
35
33
  return useMemo(
36
34
  () => ({
37
35
  push: (url: string, options: QueryRouteOptions = {}) => {
36
+ const prevQuery = qs.parse(window.location.search);
37
+
38
38
  return router.push(genHref({ prevQuery, url, ...options }));
39
39
  },
40
40
  replace: (url: string, options: QueryRouteOptions = {}) => {
41
+ const prevQuery = qs.parse(window.location.search);
41
42
  return router.replace(genHref({ prevQuery, url, ...options }));
42
43
  },
43
44
  }),
44
- [prevQuery],
45
+ [],
45
46
  );
46
47
  };
@@ -0,0 +1,12 @@
1
+ import { useQueryState } from 'nuqs';
2
+
3
+ import { SettingsTabs } from '@/store/global/initialState';
4
+
5
+ export const useSettingsTab = () => {
6
+ const [type] = useQueryState('tab', {
7
+ clearOnDefault: true,
8
+ defaultValue: SettingsTabs.Common,
9
+ });
10
+
11
+ return type as SettingsTabs;
12
+ };
@@ -0,0 +1,7 @@
1
+ import { parseAsBoolean, useQueryState } from 'nuqs';
2
+
3
+ export const useShowMobileWorkspace = () => {
4
+ const [showMobileWorkspace] = useQueryState('showMobileWorkspace', parseAsBoolean);
5
+
6
+ return showMobileWorkspace;
7
+ };
@@ -1,7 +1,7 @@
1
1
  import { useEffect } from 'react';
2
2
  import useMergeState from 'use-merge-value';
3
3
 
4
- import { useQuery } from '@/hooks/useQuery';
4
+ import { useShowMobileWorkspace } from '@/hooks/useShowMobileWorkspace';
5
5
  import { useServerConfigStore } from '@/store/serverConfig';
6
6
 
7
7
  export const useWorkspaceModal = (
@@ -9,7 +9,7 @@ export const useWorkspaceModal = (
9
9
  onChange?: (v: boolean) => void,
10
10
  ): [boolean, (v: boolean) => void] => {
11
11
  const mobile = useServerConfigStore((s) => s.isMobile);
12
- const { showMobileWorkspace } = useQuery();
12
+ const showMobileWorkspace = useShowMobileWorkspace();
13
13
  const [isModalOpen, setIsModalOpen] = useMergeState(false, {
14
14
  defaultValue: false,
15
15
  onChange,
@@ -4,6 +4,8 @@ import { useSearchParams } from 'next/navigation';
4
4
  import Script from 'next/script';
5
5
  import React, { memo } from 'react';
6
6
 
7
+ import { withSuspense } from '@/components/withSuspense';
8
+
7
9
  const ReactScan = memo(() => {
8
10
  const searchParams = useSearchParams();
9
11
 
@@ -12,4 +14,4 @@ const ReactScan = memo(() => {
12
14
  return !!debug && <Script src="https://unpkg.com/react-scan/dist/auto.global.js" />;
13
15
  });
14
16
 
15
- export default ReactScan;
17
+ export default withSuspense(ReactScan);
package/src/middleware.ts CHANGED
@@ -12,8 +12,12 @@ export const config = {
12
12
  '/(api|trpc|webapi)(.*)',
13
13
  // include the /
14
14
  '/',
15
+ '/discover',
16
+ '/discover(.*)',
17
+ '/chat',
15
18
  '/chat(.*)',
16
19
  '/settings(.*)',
20
+ '/files',
17
21
  '/files(.*)',
18
22
  '/repos(.*)',
19
23
  // ↓ cloud ↓
@@ -1,19 +0,0 @@
1
- import { renderHook } from '@testing-library/react';
2
- import { describe, expect, it, vi } from 'vitest';
3
-
4
- import { useQuery } from './useQuery';
5
-
6
- // Mocks
7
- vi.mock('next/navigation', () => ({
8
- useSearchParams: vi.fn(() => 'baz=qux&foo=bar'),
9
- }));
10
-
11
- describe('useQuery', () => {
12
- it('should parse query', () => {
13
- const { result } = renderHook(() => useQuery());
14
- expect(result.current).toEqual({
15
- baz: 'qux',
16
- foo: 'bar',
17
- });
18
- });
19
- });
@@ -1,8 +0,0 @@
1
- import { useSearchParams } from 'next/navigation';
2
- import qs from 'query-string';
3
- import { useMemo } from 'react';
4
-
5
- export const useQuery = () => {
6
- const rawQuery = useSearchParams();
7
- return useMemo(() => qs.parse(rawQuery.toString()), [rawQuery]);
8
- };