@lobehub/chat 0.151.7 → 0.151.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.
- package/CHANGELOG.md +25 -0
- package/package.json +1 -1
- package/src/{layout/DefaultLayout/Desktop/SideBar → app/(main)/@nav/_layout/Desktop}/index.tsx +9 -6
- package/src/app/(main)/@nav/_layout/Mobile.tsx +71 -0
- package/src/app/(main)/@nav/default.tsx +10 -0
- package/src/app/(main)/_layout/Desktop.tsx +33 -0
- package/src/app/(main)/_layout/Mobile.tsx +24 -0
- package/src/app/(main)/_layout/type.ts +6 -0
- package/src/app/(main)/chat/(mobile)/features/ChatInput/index.tsx +1 -1
- package/src/app/(main)/chat/(mobile)/index.tsx +4 -3
- package/src/app/(main)/chat/(mobile)/mobile/ChatHeader/index.tsx +1 -0
- package/src/app/(main)/chat/(mobile)/mobile/page.tsx +6 -9
- package/src/app/(main)/chat/settings/(mobile)/index.tsx +4 -3
- package/src/app/(main)/error.tsx +5 -0
- package/src/app/(main)/layout.tsx +11 -0
- package/src/app/(main)/market/_layout/Mobile/index.tsx +6 -8
- package/src/app/(main)/market/features/AgentSearchBar/index.tsx +15 -12
- package/src/app/(main)/not-found.tsx +3 -0
- package/src/app/(main)/settings/_layout/Mobile/index.tsx +3 -3
- package/src/app/layout.tsx +1 -4
- package/src/app/page.tsx +2 -0
- package/src/components/404/index.tsx +4 -2
- package/src/components/Error/index.tsx +5 -3
- package/src/components/server/MobileNavLayout.tsx +60 -0
- package/src/components/server/ServerLayout.tsx +6 -7
- package/src/database/client/models/__tests__/sessionGroup.test.ts +18 -0
- package/src/features/Conversation/index.tsx +3 -3
- package/src/styles/mobileHeader.ts +1 -0
- package/src/layout/DefaultLayout/Desktop/index.tsx +0 -32
- package/src/layout/DefaultLayout/Mobile/index.tsx +0 -59
- package/src/layout/DefaultLayout/index.ts +0 -2
- package/src/layout/routes/Desktop.tsx +0 -18
- package/src/layout/routes/Mobile.tsx +0 -24
- package/src/layout/routes/index.tsx +0 -8
- /package/src/{layout/DefaultLayout/Desktop/SideBar → app/(main)/@nav/_layout/Desktop}/Avatar.tsx +0 -0
- /package/src/{layout/DefaultLayout/Desktop/SideBar → app/(main)/@nav/_layout/Desktop}/BottomActions.tsx +0 -0
- /package/src/{layout/DefaultLayout/Desktop/SideBar → app/(main)/@nav/_layout/Desktop}/TopActions.tsx +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.151.8](https://github.com/lobehub/lobe-chat/compare/v0.151.7...v0.151.8)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-04-30**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **misc**: Move NavBar to `[@nav](https://github.com/nav)` slot route.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Code refactoring
|
|
19
|
+
|
|
20
|
+
- **misc**: Move NavBar to `[@nav](https://github.com/nav)` slot route, closes [#2306](https://github.com/lobehub/lobe-chat/issues/2306) ([aee7231](https://github.com/lobehub/lobe-chat/commit/aee7231))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
### [Version 0.151.7](https://github.com/lobehub/lobe-chat/compare/v0.151.6...v0.151.7)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2024-04-30**</sup>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.151.
|
|
3
|
+
"version": "0.151.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",
|
package/src/{layout/DefaultLayout/Desktop/SideBar → app/(main)/@nav/_layout/Desktop}/index.tsx
RENAMED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
1
3
|
import { SideNav } from '@lobehub/ui';
|
|
2
4
|
import { memo } from 'react';
|
|
3
5
|
|
|
4
|
-
import {
|
|
6
|
+
import { useActiveTabKey } from '@/hooks/useActiveTabKey';
|
|
5
7
|
|
|
6
8
|
import Avatar from './Avatar';
|
|
7
9
|
import BottomActions from './BottomActions';
|
|
8
10
|
import TopActions from './TopActions';
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
sidebarKey
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export default memo<Props>(({ sidebarKey }) => {
|
|
12
|
+
const Nav = memo(() => {
|
|
13
|
+
const sidebarKey = useActiveTabKey();
|
|
15
14
|
return (
|
|
16
15
|
<SideNav
|
|
17
16
|
avatar={<Avatar />}
|
|
@@ -21,3 +20,7 @@ export default memo<Props>(({ sidebarKey }) => {
|
|
|
21
20
|
/>
|
|
22
21
|
);
|
|
23
22
|
});
|
|
23
|
+
|
|
24
|
+
Nav.displayName = 'DesktopNav';
|
|
25
|
+
|
|
26
|
+
export default Nav;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Icon, MobileTabBar, type MobileTabBarProps } from '@lobehub/ui';
|
|
4
|
+
import { createStyles } from 'antd-style';
|
|
5
|
+
import { Bot, MessageSquare, User } from 'lucide-react';
|
|
6
|
+
import { useRouter } from 'next/navigation';
|
|
7
|
+
import { rgba } from 'polished';
|
|
8
|
+
import { memo, useMemo } from 'react';
|
|
9
|
+
import { useTranslation } from 'react-i18next';
|
|
10
|
+
|
|
11
|
+
import { useActiveTabKey } from '@/hooks/useActiveTabKey';
|
|
12
|
+
import { SidebarTabKey } from '@/store/global/initialState';
|
|
13
|
+
|
|
14
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
15
|
+
active: css`
|
|
16
|
+
svg {
|
|
17
|
+
fill: ${rgba(token.colorPrimary, 0.33)};
|
|
18
|
+
}
|
|
19
|
+
`,
|
|
20
|
+
container: css`
|
|
21
|
+
position: fixed;
|
|
22
|
+
z-index: 100;
|
|
23
|
+
right: 0;
|
|
24
|
+
bottom: 0;
|
|
25
|
+
left: 0;
|
|
26
|
+
`,
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
const Nav = memo(() => {
|
|
30
|
+
const { t } = useTranslation('common');
|
|
31
|
+
const { styles } = useStyles();
|
|
32
|
+
const activeKey = useActiveTabKey();
|
|
33
|
+
const router = useRouter();
|
|
34
|
+
const items: MobileTabBarProps['items'] = useMemo(
|
|
35
|
+
() => [
|
|
36
|
+
{
|
|
37
|
+
icon: (active) => (
|
|
38
|
+
<Icon className={active ? styles.active : undefined} icon={MessageSquare} />
|
|
39
|
+
),
|
|
40
|
+
key: SidebarTabKey.Chat,
|
|
41
|
+
onClick: () => {
|
|
42
|
+
router.push('/chat');
|
|
43
|
+
},
|
|
44
|
+
title: t('tab.chat'),
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
icon: (active) => <Icon className={active ? styles.active : undefined} icon={Bot} />,
|
|
48
|
+
key: SidebarTabKey.Market,
|
|
49
|
+
onClick: () => {
|
|
50
|
+
router.push('/market');
|
|
51
|
+
},
|
|
52
|
+
title: t('tab.market'),
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
icon: (active) => <Icon className={active ? styles.active : undefined} icon={User} />,
|
|
56
|
+
key: SidebarTabKey.Setting,
|
|
57
|
+
onClick: () => {
|
|
58
|
+
router.push('/settings');
|
|
59
|
+
},
|
|
60
|
+
title: t('tab.setting'),
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
[t],
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
return <MobileTabBar activeKey={activeKey} className={styles.container} items={items} safeArea />;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
Nav.displayName = 'MobileNav';
|
|
70
|
+
|
|
71
|
+
export default Nav;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useTheme } from 'antd-style';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
|
6
|
+
|
|
7
|
+
import { useIsPWA } from '@/hooks/useIsPWA';
|
|
8
|
+
|
|
9
|
+
import { LayoutProps } from './type';
|
|
10
|
+
|
|
11
|
+
const Layout = memo<LayoutProps>(({ children, nav }) => {
|
|
12
|
+
const isPWA = useIsPWA();
|
|
13
|
+
const theme = useTheme();
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Flexbox
|
|
17
|
+
height={'100%'}
|
|
18
|
+
horizontal
|
|
19
|
+
style={{
|
|
20
|
+
borderTop: isPWA ? `1px solid ${theme.colorBorder}` : undefined,
|
|
21
|
+
position: 'relative',
|
|
22
|
+
}}
|
|
23
|
+
width={'100%'}
|
|
24
|
+
>
|
|
25
|
+
{nav}
|
|
26
|
+
{children}
|
|
27
|
+
</Flexbox>
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
Layout.displayName = 'DesktopMainLayout';
|
|
32
|
+
|
|
33
|
+
export default Layout;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { usePathname } from 'next/navigation';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
|
|
6
|
+
import { LayoutProps } from './type';
|
|
7
|
+
|
|
8
|
+
const MOBILE_IGNORE_NAV_ROUTES = ['/settings/', '/chat/'];
|
|
9
|
+
|
|
10
|
+
const Layout = memo(({ children, nav }: LayoutProps) => {
|
|
11
|
+
const pathname = usePathname();
|
|
12
|
+
const hideNav = MOBILE_IGNORE_NAV_ROUTES.some((path) => pathname.startsWith(path));
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
{children}
|
|
17
|
+
{!hideNav && nav}
|
|
18
|
+
</>
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
Layout.displayName = 'MobileMainLayout';
|
|
23
|
+
|
|
24
|
+
export default Layout;
|
|
@@ -27,7 +27,7 @@ const ChatInputMobileLayout = memo(() => {
|
|
|
27
27
|
setExpand={setExpand}
|
|
28
28
|
style={{
|
|
29
29
|
background: `linear-gradient(to bottom, ${theme.colorFillQuaternary}, transparent)`,
|
|
30
|
-
width: '
|
|
30
|
+
width: '100%',
|
|
31
31
|
}}
|
|
32
32
|
textAreaLeftAddons={<STT mobile />}
|
|
33
33
|
textAreaRightAddons={
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import { useRouter } from 'next/navigation';
|
|
4
4
|
import { memo, useEffect } from 'react';
|
|
5
5
|
|
|
6
|
+
import MobileContentLayout from '@/components/server/MobileNavLayout';
|
|
7
|
+
|
|
6
8
|
import SessionHeader from './features/SessionHeader';
|
|
7
9
|
import SessionList from './features/SessionList';
|
|
8
10
|
|
|
@@ -15,10 +17,9 @@ const ChatMobilePage = memo(() => {
|
|
|
15
17
|
}, []);
|
|
16
18
|
|
|
17
19
|
return (
|
|
18
|
-
|
|
19
|
-
<SessionHeader />
|
|
20
|
+
<MobileContentLayout header={<SessionHeader />} withNav>
|
|
20
21
|
<SessionList />
|
|
21
|
-
|
|
22
|
+
</MobileContentLayout>
|
|
22
23
|
);
|
|
23
24
|
});
|
|
24
25
|
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import dynamic from 'next/dynamic';
|
|
4
4
|
import { memo } from 'react';
|
|
5
|
-
import { Flexbox } from 'react-layout-kit';
|
|
6
5
|
|
|
6
|
+
import MobileContentLayout from '@/components/server/MobileNavLayout';
|
|
7
7
|
import Conversation from '@/features/Conversation';
|
|
8
8
|
|
|
9
9
|
import SessionHydration from '../../components/SessionHydration';
|
|
@@ -15,15 +15,12 @@ const TopicList = dynamic(() => import('../features/TopicList'));
|
|
|
15
15
|
|
|
16
16
|
const Chat = memo(() => {
|
|
17
17
|
return (
|
|
18
|
-
|
|
19
|
-
<
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
<TopicList />
|
|
23
|
-
<TelemetryNotification mobile />
|
|
24
|
-
</Flexbox>
|
|
18
|
+
<MobileContentLayout header={<ChatHeader />}>
|
|
19
|
+
<Conversation chatInput={<ChatInput />} mobile />
|
|
20
|
+
<TopicList />
|
|
21
|
+
<TelemetryNotification mobile />
|
|
25
22
|
<SessionHydration />
|
|
26
|
-
|
|
23
|
+
</MobileContentLayout>
|
|
27
24
|
);
|
|
28
25
|
});
|
|
29
26
|
export default Chat;
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
import { memo } from 'react';
|
|
4
4
|
|
|
5
|
+
import MobileContentLayout from '@/components/server/MobileNavLayout';
|
|
6
|
+
|
|
5
7
|
import EditPage from '../features/EditPage';
|
|
6
8
|
import Header from './Header';
|
|
7
9
|
|
|
8
10
|
const ChatSettings = memo(() => (
|
|
9
|
-
|
|
10
|
-
<Header />
|
|
11
|
+
<MobileContentLayout header={<Header />} withNav={false}>
|
|
11
12
|
<EditPage />
|
|
12
|
-
|
|
13
|
+
</MobileContentLayout>
|
|
13
14
|
));
|
|
14
15
|
|
|
15
16
|
export default ChatSettings;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import ServerLayout from '@/components/server/ServerLayout';
|
|
2
|
+
|
|
3
|
+
import Desktop from './_layout/Desktop';
|
|
4
|
+
import Mobile from './_layout/Mobile';
|
|
5
|
+
import { LayoutProps } from './_layout/type';
|
|
6
|
+
|
|
7
|
+
const MainLayout = ServerLayout<LayoutProps>({ Desktop, Mobile });
|
|
8
|
+
|
|
9
|
+
MainLayout.displayName = 'MainLayout';
|
|
10
|
+
|
|
11
|
+
export default MainLayout;
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { PropsWithChildren } from 'react';
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
import MobileContentLayout from '@/components/server/MobileNavLayout';
|
|
3
4
|
|
|
4
5
|
import AgentSearchBar from '../../features/AgentSearchBar';
|
|
5
6
|
import Header from './Header';
|
|
6
7
|
|
|
7
8
|
const MobileLayout = ({ children }: PropsWithChildren) => {
|
|
8
9
|
return (
|
|
9
|
-
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
{children}
|
|
14
|
-
</Flexbox>
|
|
15
|
-
</>
|
|
10
|
+
<MobileContentLayout gap={16} header={<Header />} style={{ paddingInline: 16 }} withNav>
|
|
11
|
+
<AgentSearchBar mobile />
|
|
12
|
+
{children}
|
|
13
|
+
</MobileContentLayout>
|
|
16
14
|
);
|
|
17
15
|
};
|
|
18
16
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { SearchBar } from '@lobehub/ui';
|
|
4
4
|
import { memo, useCallback, useState } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { Flexbox } from 'react-layout-kit';
|
|
6
7
|
|
|
7
8
|
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
8
9
|
import { useMarketStore } from '@/store/market';
|
|
@@ -19,18 +20,20 @@ const AgentSearchBar = memo<{ mobile?: boolean }>(({ mobile: controlledMobile })
|
|
|
19
20
|
}, [value, setKeywords]);
|
|
20
21
|
|
|
21
22
|
return (
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
<Flexbox flex={'none'} paddingBlock={mobile ? 8 : 0}>
|
|
24
|
+
<SearchBar
|
|
25
|
+
allowClear
|
|
26
|
+
enableShortKey={!mobile}
|
|
27
|
+
onChange={(e) => setValue(e.target.value)}
|
|
28
|
+
onPressEnter={handleSearch}
|
|
29
|
+
onSubmit={handleSearch}
|
|
30
|
+
placeholder={t('search.placeholder')}
|
|
31
|
+
shortKey={'k'}
|
|
32
|
+
spotlight={!mobile}
|
|
33
|
+
type={mobile ? 'block' : 'ghost'}
|
|
34
|
+
value={value}
|
|
35
|
+
/>
|
|
36
|
+
</Flexbox>
|
|
34
37
|
);
|
|
35
38
|
});
|
|
36
39
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { PropsWithChildren } from 'react';
|
|
4
4
|
|
|
5
|
+
import MobileContentLayout from '@/components/server/MobileNavLayout';
|
|
5
6
|
import { useIsSubSlug } from '@/hooks/useIsSubSlug';
|
|
6
7
|
|
|
7
8
|
import SubSettingHeader from './SubSettingHeader';
|
|
@@ -11,10 +12,9 @@ const MobileLayout = ({ children }: PropsWithChildren) => {
|
|
|
11
12
|
|
|
12
13
|
if (isSubPath)
|
|
13
14
|
return (
|
|
14
|
-
|
|
15
|
-
<SubSettingHeader />
|
|
15
|
+
<MobileContentLayout header={<SubSettingHeader />} withNav={false}>
|
|
16
16
|
{children}
|
|
17
|
-
|
|
17
|
+
</MobileContentLayout>
|
|
18
18
|
);
|
|
19
19
|
|
|
20
20
|
return children;
|
package/src/app/layout.tsx
CHANGED
|
@@ -8,7 +8,6 @@ import Analytics from '@/components/Analytics';
|
|
|
8
8
|
import { DEFAULT_LANG, LOBE_LOCALE_COOKIE } from '@/const/locale';
|
|
9
9
|
import AuthProvider from '@/layout/AuthProvider';
|
|
10
10
|
import GlobalProvider from '@/layout/GlobalProvider';
|
|
11
|
-
import LayoutRoutes from '@/layout/routes';
|
|
12
11
|
import { isMobileDevice } from '@/utils/responsive';
|
|
13
12
|
|
|
14
13
|
const RootLayout = async ({ children }: PropsWithChildren) => {
|
|
@@ -21,9 +20,7 @@ const RootLayout = async ({ children }: PropsWithChildren) => {
|
|
|
21
20
|
<html dir={direction} lang={lang?.value || DEFAULT_LANG} suppressHydrationWarning>
|
|
22
21
|
<body>
|
|
23
22
|
<GlobalProvider>
|
|
24
|
-
<AuthProvider>
|
|
25
|
-
<LayoutRoutes>{children}</LayoutRoutes>
|
|
26
|
-
</AuthProvider>
|
|
23
|
+
<AuthProvider>{children}</AuthProvider>
|
|
27
24
|
</GlobalProvider>
|
|
28
25
|
<Analytics />
|
|
29
26
|
<SpeedInsights />
|
package/src/app/page.tsx
CHANGED
|
@@ -9,7 +9,7 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
9
9
|
|
|
10
10
|
import { MAX_WIDTH } from '@/const/layoutTokens';
|
|
11
11
|
|
|
12
|
-
const
|
|
12
|
+
const NotFound = memo(() => {
|
|
13
13
|
const { t } = useTranslation('error');
|
|
14
14
|
return (
|
|
15
15
|
<Flexbox align={'center'} justify={'center'} style={{ height: '100%', width: '100%' }}>
|
|
@@ -38,4 +38,6 @@ const Page404 = memo(() => {
|
|
|
38
38
|
);
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
NotFound.displayName = 'NotFound';
|
|
42
|
+
|
|
43
|
+
export default NotFound;
|
|
@@ -11,12 +11,12 @@ import { MAX_WIDTH } from '@/const/layoutTokens';
|
|
|
11
11
|
|
|
12
12
|
import { type ErrorType, sentryCaptureException } from './sentryCaptureException';
|
|
13
13
|
|
|
14
|
-
interface
|
|
14
|
+
interface ErrorCaptureProps {
|
|
15
15
|
error: ErrorType;
|
|
16
16
|
reset: () => void;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
const
|
|
19
|
+
const ErrorCapture = memo<ErrorCaptureProps>(({ reset, error }) => {
|
|
20
20
|
const { t } = useTranslation('error');
|
|
21
21
|
|
|
22
22
|
useLayoutEffect(() => {
|
|
@@ -53,4 +53,6 @@ const PageError = memo<PageErrorProps>(({ reset, error }) => {
|
|
|
53
53
|
);
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
ErrorCapture.displayName = 'ErrorCapture';
|
|
57
|
+
|
|
58
|
+
export default ErrorCapture;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { Flexbox, type FlexboxProps } from 'react-layout-kit';
|
|
3
|
+
|
|
4
|
+
interface MobileContentLayoutProps extends FlexboxProps {
|
|
5
|
+
header?: ReactNode;
|
|
6
|
+
withNav?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const MobileContentLayout = ({
|
|
10
|
+
children,
|
|
11
|
+
withNav,
|
|
12
|
+
style,
|
|
13
|
+
header,
|
|
14
|
+
...rest
|
|
15
|
+
}: MobileContentLayoutProps) => {
|
|
16
|
+
const content = (
|
|
17
|
+
<Flexbox
|
|
18
|
+
height="100%"
|
|
19
|
+
style={{
|
|
20
|
+
overflowX: 'hidden',
|
|
21
|
+
overflowY: 'auto',
|
|
22
|
+
position: 'relative',
|
|
23
|
+
...style,
|
|
24
|
+
// TabNav Height
|
|
25
|
+
paddingBottom: withNav ? 48 : style?.paddingBottom,
|
|
26
|
+
}}
|
|
27
|
+
width="100%"
|
|
28
|
+
{...rest}
|
|
29
|
+
>
|
|
30
|
+
{children}
|
|
31
|
+
</Flexbox>
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
if (!header) return content;
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Flexbox height={'100%'} style={{ overflow: 'hidden', position: 'relative' }} width={'100%'}>
|
|
38
|
+
{header}
|
|
39
|
+
<Flexbox
|
|
40
|
+
height="100%"
|
|
41
|
+
style={{
|
|
42
|
+
overflowX: 'hidden',
|
|
43
|
+
overflowY: 'auto',
|
|
44
|
+
position: 'relative',
|
|
45
|
+
...style,
|
|
46
|
+
// TabNav Height
|
|
47
|
+
paddingBottom: withNav ? 48 : style?.paddingBottom,
|
|
48
|
+
}}
|
|
49
|
+
width="100%"
|
|
50
|
+
{...rest}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
</Flexbox>
|
|
54
|
+
</Flexbox>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
MobileContentLayout.displayName = 'MobileContentLayout';
|
|
59
|
+
|
|
60
|
+
export default MobileContentLayout;
|
|
@@ -2,17 +2,16 @@ import { FC, PropsWithChildren } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { isMobileDevice } from '@/utils/responsive';
|
|
4
4
|
|
|
5
|
-
interface ServerLayoutProps {
|
|
6
|
-
Desktop: FC<
|
|
7
|
-
Mobile: FC<
|
|
5
|
+
interface ServerLayoutProps<T> {
|
|
6
|
+
Desktop: FC<T>;
|
|
7
|
+
Mobile: FC<T>;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
const ServerLayout =
|
|
11
|
-
({ Desktop, Mobile }: ServerLayoutProps) =>
|
|
12
|
-
(
|
|
11
|
+
<T extends PropsWithChildren>({ Desktop, Mobile }: ServerLayoutProps<T>): FC<T> =>
|
|
12
|
+
(props: T) => {
|
|
13
13
|
const mobile = isMobileDevice();
|
|
14
|
-
|
|
15
|
-
return mobile ? <Mobile>{children}</Mobile> : <Desktop>{children}</Desktop>;
|
|
14
|
+
return mobile ? <Mobile {...props} /> : <Desktop {...props} />;
|
|
16
15
|
};
|
|
17
16
|
|
|
18
17
|
ServerLayout.displayName = 'ServerLayout';
|
|
@@ -89,6 +89,16 @@ describe('SessionGroupModel', () => {
|
|
|
89
89
|
expect(session.group).not.toEqual(createdGroup.id);
|
|
90
90
|
});
|
|
91
91
|
});
|
|
92
|
+
it('should update associated sessions to default group when a session group is deleted', async () => {
|
|
93
|
+
const createdGroup = await SessionGroupModel.create(
|
|
94
|
+
sessionGroupData.name,
|
|
95
|
+
sessionGroupData.sort,
|
|
96
|
+
);
|
|
97
|
+
const sessionId = await SessionModel.create('agent', {}, createdGroup.id);
|
|
98
|
+
await SessionGroupModel.delete(createdGroup.id);
|
|
99
|
+
const updatedSession = await SessionModel.findById(sessionId.id);
|
|
100
|
+
expect(updatedSession.group).toEqual('default');
|
|
101
|
+
});
|
|
92
102
|
});
|
|
93
103
|
|
|
94
104
|
describe('query', () => {
|
|
@@ -153,6 +163,14 @@ describe('SessionGroupModel', () => {
|
|
|
153
163
|
expect(fetchedGroups[0].id).toEqual(group2.id);
|
|
154
164
|
expect(fetchedGroups[1].id).toEqual(group1.id);
|
|
155
165
|
});
|
|
166
|
+
|
|
167
|
+
it('should sort session groups correctly when only b has a sort value', async () => {
|
|
168
|
+
const groupA = await SessionGroupModel.create('groupA'); // sort undefined
|
|
169
|
+
const groupB = await SessionGroupModel.create('groupB', 1); // sort defined
|
|
170
|
+
const fetchedGroups = await SessionGroupModel.query();
|
|
171
|
+
expect(fetchedGroups[0].id).toEqual(groupB.id);
|
|
172
|
+
expect(fetchedGroups[1].id).toEqual(groupA.id);
|
|
173
|
+
});
|
|
156
174
|
});
|
|
157
175
|
|
|
158
176
|
describe('updateOrder', () => {
|
|
@@ -9,14 +9,13 @@ import SkeletonList from './components/SkeletonList';
|
|
|
9
9
|
const ChatList = lazy(() => import('./components/VirtualizedList'));
|
|
10
10
|
|
|
11
11
|
const useStyles = createStyles(
|
|
12
|
-
({ css, responsive
|
|
12
|
+
({ css, responsive }) => css`
|
|
13
13
|
position: relative;
|
|
14
14
|
overflow-y: auto;
|
|
15
15
|
height: 100%;
|
|
16
16
|
|
|
17
17
|
${responsive.mobile} {
|
|
18
|
-
|
|
19
|
-
width: 100vw;
|
|
18
|
+
width: 100%;
|
|
20
19
|
}
|
|
21
20
|
`,
|
|
22
21
|
);
|
|
@@ -32,6 +31,7 @@ const Conversation = memo<ConversationProps>(({ chatInput, mobile }) => {
|
|
|
32
31
|
return (
|
|
33
32
|
<Flexbox
|
|
34
33
|
flex={1}
|
|
34
|
+
height={'100%'}
|
|
35
35
|
// `relative` is required, ChatInput's absolute position needs it
|
|
36
36
|
style={{ position: 'relative' }}
|
|
37
37
|
>
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useTheme } from 'antd-style';
|
|
4
|
-
import { PropsWithChildren, memo } from 'react';
|
|
5
|
-
import { Flexbox } from 'react-layout-kit';
|
|
6
|
-
|
|
7
|
-
import ClientResponsiveLayout from '@/components/client/ClientResponsiveLayout';
|
|
8
|
-
import { useActiveTabKey } from '@/hooks/useActiveTabKey';
|
|
9
|
-
import { useIsPWA } from '@/hooks/useIsPWA';
|
|
10
|
-
|
|
11
|
-
import SideBar from './SideBar';
|
|
12
|
-
|
|
13
|
-
const Desktop = memo<PropsWithChildren>(({ children }) => {
|
|
14
|
-
const isPWA = useIsPWA();
|
|
15
|
-
const theme = useTheme();
|
|
16
|
-
|
|
17
|
-
const sidebarKey = useActiveTabKey();
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<Flexbox
|
|
21
|
-
height={'100%'}
|
|
22
|
-
horizontal
|
|
23
|
-
style={isPWA ? { borderTop: `1px solid ${theme.colorBorder}` } : {}}
|
|
24
|
-
width={'100%'}
|
|
25
|
-
>
|
|
26
|
-
<SideBar sidebarKey={sidebarKey} />
|
|
27
|
-
{children}
|
|
28
|
-
</Flexbox>
|
|
29
|
-
);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
export default ClientResponsiveLayout({ Desktop, Mobile: () => import('../Mobile') });
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { type MobileNavBarTitleProps } from '@lobehub/ui';
|
|
4
|
-
import { createStyles } from 'antd-style';
|
|
5
|
-
import dynamic from 'next/dynamic';
|
|
6
|
-
import { CSSProperties, PropsWithChildren, memo } from 'react';
|
|
7
|
-
import { Flexbox } from 'react-layout-kit';
|
|
8
|
-
|
|
9
|
-
import SafeSpacing from '@/components/SafeSpacing';
|
|
10
|
-
import { SidebarTabKey } from '@/store/global/initialState';
|
|
11
|
-
|
|
12
|
-
const MobileTabBar = dynamic(() => import('@/features/MobileTabBar'));
|
|
13
|
-
|
|
14
|
-
const useStyles = createStyles(({ css, cx, stylish }) => ({
|
|
15
|
-
container: cx(
|
|
16
|
-
stylish.noScrollbar,
|
|
17
|
-
css`
|
|
18
|
-
position: relative;
|
|
19
|
-
overflow: hidden auto;
|
|
20
|
-
width: 100vw;
|
|
21
|
-
height: 100%;
|
|
22
|
-
`,
|
|
23
|
-
),
|
|
24
|
-
mobileTabBar: css`
|
|
25
|
-
position: fixed;
|
|
26
|
-
z-index: 100;
|
|
27
|
-
right: 0;
|
|
28
|
-
bottom: 0;
|
|
29
|
-
left: 0;
|
|
30
|
-
`,
|
|
31
|
-
}));
|
|
32
|
-
|
|
33
|
-
interface AppMobileLayoutProps extends PropsWithChildren {
|
|
34
|
-
className?: string;
|
|
35
|
-
showTabBar?: boolean;
|
|
36
|
-
style?: CSSProperties;
|
|
37
|
-
tabBarKey?: SidebarTabKey;
|
|
38
|
-
title?: MobileNavBarTitleProps;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const AppLayoutMobile = memo<AppMobileLayoutProps>(
|
|
42
|
-
({ children, showTabBar, tabBarKey, style, className }) => {
|
|
43
|
-
const { styles, cx } = useStyles();
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<Flexbox className={cx(styles.container, className)} style={style}>
|
|
47
|
-
{children}
|
|
48
|
-
{showTabBar && (
|
|
49
|
-
<>
|
|
50
|
-
<SafeSpacing mobile position={'bottom'} />
|
|
51
|
-
<MobileTabBar className={styles.mobileTabBar} tabBarKey={tabBarKey} />
|
|
52
|
-
</>
|
|
53
|
-
)}
|
|
54
|
-
</Flexbox>
|
|
55
|
-
);
|
|
56
|
-
},
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
export default AppLayoutMobile;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { usePathname } from 'next/navigation';
|
|
4
|
-
import { PropsWithChildren, memo } from 'react';
|
|
5
|
-
|
|
6
|
-
import { DefaultLayoutDesktop } from '@/layout/DefaultLayout';
|
|
7
|
-
|
|
8
|
-
const defaultLayoutRoutes = new Set(['/']);
|
|
9
|
-
|
|
10
|
-
const DesktopLayout = memo<PropsWithChildren>(({ children }) => {
|
|
11
|
-
const pathname = usePathname();
|
|
12
|
-
|
|
13
|
-
if (defaultLayoutRoutes.has(pathname)) return children;
|
|
14
|
-
|
|
15
|
-
return <DefaultLayoutDesktop>{children}</DefaultLayoutDesktop>;
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
export default DesktopLayout;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { usePathname } from 'next/navigation';
|
|
4
|
-
import { PropsWithChildren, memo } from 'react';
|
|
5
|
-
|
|
6
|
-
import { useActiveTabKey } from '@/hooks/useActiveTabKey';
|
|
7
|
-
import { useIsSubSlug } from '@/hooks/useIsSubSlug';
|
|
8
|
-
import { DefaultLayoutMobile } from '@/layout/DefaultLayout';
|
|
9
|
-
|
|
10
|
-
const MobileLayout = memo<PropsWithChildren>(({ children }) => {
|
|
11
|
-
const pathname = usePathname();
|
|
12
|
-
const tabBarKey = useActiveTabKey();
|
|
13
|
-
const isSubPath = useIsSubSlug();
|
|
14
|
-
|
|
15
|
-
if (pathname === '/') return children;
|
|
16
|
-
|
|
17
|
-
return (
|
|
18
|
-
<DefaultLayoutMobile showTabBar={!isSubPath} tabBarKey={tabBarKey}>
|
|
19
|
-
{children}
|
|
20
|
-
</DefaultLayoutMobile>
|
|
21
|
-
);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
export default MobileLayout;
|
/package/src/{layout/DefaultLayout/Desktop/SideBar → app/(main)/@nav/_layout/Desktop}/Avatar.tsx
RENAMED
|
File without changes
|
|
File without changes
|
/package/src/{layout/DefaultLayout/Desktop/SideBar → app/(main)/@nav/_layout/Desktop}/TopActions.tsx
RENAMED
|
File without changes
|