@lobehub/chat 0.142.4 → 0.142.5
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 +26 -0
- package/package.json +1 -1
- package/src/app/chat/(mobile)/mobile/page.tsx +2 -0
- package/src/app/chat/components/SessionHydration/index.tsx +1 -6
- package/src/app/chat/features/SessionListContent/Inbox/index.tsx +4 -11
- package/src/app/chat/features/SessionListContent/List/index.tsx +2 -14
- package/src/app/home/Redirect.tsx +0 -4
- package/src/app/settings/_layout/Desktop/index.tsx +1 -1
- package/src/app/welcome/features/Banner/index.tsx +1 -3
- package/src/hooks/useIsMobile.ts +2 -1
- package/src/store/session/slices/session/action.test.ts +0 -35
- package/src/store/session/slices/session/action.ts +8 -21
- package/src/store/session/slices/session/initialState.ts +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.142.5](https://github.com/lobehub/lobe-chat/compare/v0.142.4...v0.142.5)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-03-26**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: Fix mobile click, fix mobile click issue.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **misc**: Fix mobile click ([3775b28](https://github.com/lobehub/lobe-chat/commit/3775b28))
|
|
21
|
+
- **misc**: Fix mobile click issue, closes [#1744](https://github.com/lobehub/lobe-chat/issues/1744) ([a6b1234](https://github.com/lobehub/lobe-chat/commit/a6b1234))
|
|
22
|
+
|
|
23
|
+
</details>
|
|
24
|
+
|
|
25
|
+
<div align="right">
|
|
26
|
+
|
|
27
|
+
[](#readme-top)
|
|
28
|
+
|
|
29
|
+
</div>
|
|
30
|
+
|
|
5
31
|
### [Version 0.142.4](https://github.com/lobehub/lobe-chat/compare/v0.142.3...v0.142.4)
|
|
6
32
|
|
|
7
33
|
<sup>Released on **2024-03-26**</sup>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.142.
|
|
3
|
+
"version": "0.142.5",
|
|
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",
|
|
@@ -7,6 +7,7 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
7
7
|
import Conversation from '@/features/Conversation';
|
|
8
8
|
import { useSessionStore } from '@/store/session';
|
|
9
9
|
|
|
10
|
+
import SessionHydration from '../../components/SessionHydration';
|
|
10
11
|
import TelemetryNotification from '../../features/TelemetryNotification';
|
|
11
12
|
import ChatInput from '../features/ChatInput';
|
|
12
13
|
import ChatHeader from './ChatHeader';
|
|
@@ -27,6 +28,7 @@ const Chat = memo(() => {
|
|
|
27
28
|
<TopicList />
|
|
28
29
|
<TelemetryNotification mobile />
|
|
29
30
|
</Flexbox>
|
|
31
|
+
<SessionHydration />
|
|
30
32
|
</>
|
|
31
33
|
);
|
|
32
34
|
});
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useResponsive } from 'antd-style';
|
|
4
|
-
import { useRouter } from 'next/navigation';
|
|
5
4
|
import { useQueryState } from 'nuqs';
|
|
6
|
-
import { parseAsString } from 'nuqs/
|
|
5
|
+
import { parseAsString } from 'nuqs/server';
|
|
7
6
|
import { memo, useEffect } from 'react';
|
|
8
7
|
import { createStoreUpdater } from 'zustand-utils';
|
|
9
8
|
|
|
@@ -16,10 +15,6 @@ const SessionHydration = memo(() => {
|
|
|
16
15
|
const { mobile } = useResponsive();
|
|
17
16
|
useStoreUpdater('isMobile', mobile);
|
|
18
17
|
|
|
19
|
-
const router = useRouter();
|
|
20
|
-
// TODO: 后续可以把 router 从 useSessionStore 移除
|
|
21
|
-
useStoreUpdater('router', router);
|
|
22
|
-
|
|
23
18
|
// two-way bindings the url and session store
|
|
24
19
|
const [session, setSession] = useQueryState(
|
|
25
20
|
'session',
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useResponsive } from 'antd-style';
|
|
2
1
|
import Link from 'next/link';
|
|
3
2
|
import { memo } from 'react';
|
|
4
3
|
import { useTranslation } from 'react-i18next';
|
|
@@ -6,24 +5,18 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
5
|
import { DEFAULT_INBOX_AVATAR } from '@/const/meta';
|
|
7
6
|
import { INBOX_SESSION_ID } from '@/const/session';
|
|
8
7
|
import { SESSION_CHAT_URL } from '@/const/url';
|
|
8
|
+
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
9
9
|
import { useSessionStore } from '@/store/session';
|
|
10
10
|
|
|
11
11
|
import ListItem from '../ListItem';
|
|
12
12
|
|
|
13
13
|
const Inbox = memo(() => {
|
|
14
14
|
const { t } = useTranslation('chat');
|
|
15
|
-
const
|
|
16
|
-
const
|
|
15
|
+
const mobile = useIsMobile();
|
|
16
|
+
const activeId = useSessionStore((s) => s.activeId);
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
|
-
<Link
|
|
20
|
-
aria-label={t('inbox.title')}
|
|
21
|
-
href={SESSION_CHAT_URL(INBOX_SESSION_ID, mobile)}
|
|
22
|
-
onClick={(e) => {
|
|
23
|
-
e.preventDefault();
|
|
24
|
-
switchSession(INBOX_SESSION_ID);
|
|
25
|
-
}}
|
|
26
|
-
>
|
|
19
|
+
<Link aria-label={t('inbox.title')} href={SESSION_CHAT_URL(INBOX_SESSION_ID, mobile)}>
|
|
27
20
|
<ListItem
|
|
28
21
|
active={activeId === INBOX_SESSION_ID}
|
|
29
22
|
avatar={DEFAULT_INBOX_AVATAR}
|
|
@@ -24,11 +24,7 @@ interface SessionListProps {
|
|
|
24
24
|
showAddButton?: boolean;
|
|
25
25
|
}
|
|
26
26
|
const SessionList = memo<SessionListProps>(({ dataSource, groupId, showAddButton = true }) => {
|
|
27
|
-
const
|
|
28
|
-
s.activeSession,
|
|
29
|
-
s.switchSession,
|
|
30
|
-
sessionSelectors.isSessionListInit(s),
|
|
31
|
-
]);
|
|
27
|
+
const isInit = useSessionStore((s) => sessionSelectors.isSessionListInit(s));
|
|
32
28
|
const { styles } = useStyles();
|
|
33
29
|
|
|
34
30
|
const { mobile } = useResponsive();
|
|
@@ -38,15 +34,7 @@ const SessionList = memo<SessionListProps>(({ dataSource, groupId, showAddButton
|
|
|
38
34
|
) : dataSource.length > 0 ? (
|
|
39
35
|
dataSource.map(({ id }) => (
|
|
40
36
|
<LazyLoad className={styles} key={id}>
|
|
41
|
-
<Link
|
|
42
|
-
aria-label={id}
|
|
43
|
-
href={SESSION_CHAT_URL(id, mobile)}
|
|
44
|
-
onClick={(e) => {
|
|
45
|
-
e.preventDefault();
|
|
46
|
-
if (mobile) switchSession(id);
|
|
47
|
-
else activeSession(id);
|
|
48
|
-
}}
|
|
49
|
-
>
|
|
37
|
+
<Link aria-label={id} href={SESSION_CHAT_URL(id, mobile)}>
|
|
50
38
|
<SessionItem id={id} />
|
|
51
39
|
</Link>
|
|
52
40
|
</LazyLoad>
|
|
@@ -5,7 +5,6 @@ import { memo, useEffect } from 'react';
|
|
|
5
5
|
|
|
6
6
|
import { messageService } from '@/services/message';
|
|
7
7
|
import { sessionService } from '@/services/session';
|
|
8
|
-
import { useSessionStore } from '@/store/session';
|
|
9
8
|
|
|
10
9
|
const checkHasConversation = async () => {
|
|
11
10
|
const hasMessages = await messageService.hasMessages();
|
|
@@ -15,14 +14,11 @@ const checkHasConversation = async () => {
|
|
|
15
14
|
|
|
16
15
|
const Redirect = memo(() => {
|
|
17
16
|
const router = useRouter();
|
|
18
|
-
const [switchSession] = useSessionStore((s) => [s.switchSession]);
|
|
19
17
|
|
|
20
18
|
useEffect(() => {
|
|
21
19
|
checkHasConversation().then((hasData) => {
|
|
22
20
|
if (hasData) {
|
|
23
21
|
router.replace('/chat');
|
|
24
|
-
|
|
25
|
-
switchSession();
|
|
26
22
|
} else {
|
|
27
23
|
router.replace('/welcome');
|
|
28
24
|
}
|
|
@@ -14,7 +14,7 @@ const Desktop = memo<PropsWithChildren>(({ children }) => (
|
|
|
14
14
|
<SideBar />
|
|
15
15
|
<Flexbox flex={1} height={'100%'} style={{ position: 'relative' }}>
|
|
16
16
|
<Header />
|
|
17
|
-
<Flexbox align={'center'} flex={1} padding={24} style={{
|
|
17
|
+
<Flexbox align={'center'} flex={1} padding={24} style={{ overflowY: 'scroll' }}>
|
|
18
18
|
<SafeSpacing />
|
|
19
19
|
<Center gap={16} width={'100%'}>
|
|
20
20
|
{children}
|
|
@@ -10,7 +10,6 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
10
10
|
|
|
11
11
|
import DataImporter from '@/features/DataImporter';
|
|
12
12
|
import { useGlobalStore } from '@/store/global';
|
|
13
|
-
import { useSessionStore } from '@/store/session';
|
|
14
13
|
|
|
15
14
|
import Hero from './Hero';
|
|
16
15
|
import { useStyles } from './style';
|
|
@@ -19,7 +18,6 @@ const Banner = memo<{ mobile?: boolean }>(({ mobile }) => {
|
|
|
19
18
|
const { t } = useTranslation('welcome');
|
|
20
19
|
const router = useRouter();
|
|
21
20
|
const { styles } = useStyles();
|
|
22
|
-
const [switchSession] = useSessionStore((s) => [s.switchSession]);
|
|
23
21
|
const [switchBackToChat, isMobile] = useGlobalStore((s) => [s.switchBackToChat, s.isMobile]);
|
|
24
22
|
|
|
25
23
|
return (
|
|
@@ -36,7 +34,7 @@ const Banner = memo<{ mobile?: boolean }>(({ mobile }) => {
|
|
|
36
34
|
>
|
|
37
35
|
<DataImporter
|
|
38
36
|
onFinishImport={() => {
|
|
39
|
-
|
|
37
|
+
router.push('/chat');
|
|
40
38
|
}}
|
|
41
39
|
>
|
|
42
40
|
<Button block={mobile} size={'large'}>
|
package/src/hooks/useIsMobile.ts
CHANGED
|
@@ -31,9 +31,6 @@ beforeEach(() => {
|
|
|
31
31
|
vi.clearAllMocks();
|
|
32
32
|
useSessionStore.setState({
|
|
33
33
|
refreshSessions: mockRefresh,
|
|
34
|
-
router: {
|
|
35
|
-
push: mockRouterPush,
|
|
36
|
-
} as unknown as AppRouterInstance,
|
|
37
34
|
});
|
|
38
35
|
});
|
|
39
36
|
|
|
@@ -72,9 +69,6 @@ describe('SessionAction', () => {
|
|
|
72
69
|
expect(call[1]).toMatchObject({ config: { displayMode: 'docs' } });
|
|
73
70
|
|
|
74
71
|
expect(createdSessionId).toBe(newSessionId);
|
|
75
|
-
expect(mockRouterPush).toHaveBeenCalledWith(
|
|
76
|
-
SESSION_CHAT_URL(newSessionId, result.current.isMobile),
|
|
77
|
-
);
|
|
78
72
|
});
|
|
79
73
|
|
|
80
74
|
it('should create a new session but not switch to it if isSwitchSession is false', async () => {
|
|
@@ -131,35 +125,6 @@ describe('SessionAction', () => {
|
|
|
131
125
|
});
|
|
132
126
|
});
|
|
133
127
|
|
|
134
|
-
describe('switchSession', () => {
|
|
135
|
-
it('should switch to the provided session id', async () => {
|
|
136
|
-
const { result } = renderHook(() => useSessionStore());
|
|
137
|
-
const sessionId = 'session-id';
|
|
138
|
-
|
|
139
|
-
act(() => {
|
|
140
|
-
result.current.switchSession(sessionId);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
expect(result.current.activeId).toBe(sessionId);
|
|
144
|
-
expect(mockRouterPush).toHaveBeenCalledWith(
|
|
145
|
-
SESSION_CHAT_URL(sessionId, result.current.isMobile),
|
|
146
|
-
);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('should switch to the inbox session id if none is provided', async () => {
|
|
150
|
-
const { result } = renderHook(() => useSessionStore());
|
|
151
|
-
|
|
152
|
-
act(() => {
|
|
153
|
-
result.current.switchSession();
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
expect(result.current.activeId).toBe(INBOX_SESSION_ID);
|
|
157
|
-
expect(mockRouterPush).toHaveBeenCalledWith(
|
|
158
|
-
SESSION_CHAT_URL(INBOX_SESSION_ID, result.current.isMobile),
|
|
159
|
-
);
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
128
|
describe('activeSession', () => {
|
|
164
129
|
it('should set the provided session id as active', async () => {
|
|
165
130
|
const { result } = renderHook(() => useSessionStore());
|
|
@@ -5,7 +5,6 @@ import { DeepPartial } from 'utility-types';
|
|
|
5
5
|
import { StateCreator } from 'zustand/vanilla';
|
|
6
6
|
|
|
7
7
|
import { INBOX_SESSION_ID } from '@/const/session';
|
|
8
|
-
import { SESSION_CHAT_URL } from '@/const/url';
|
|
9
8
|
import { useClientDataSWR } from '@/libs/swr';
|
|
10
9
|
import { sessionService } from '@/services/session';
|
|
11
10
|
import { useGlobalStore } from '@/store/global';
|
|
@@ -56,10 +55,6 @@ export interface SessionAction {
|
|
|
56
55
|
* @param id - sessionId
|
|
57
56
|
*/
|
|
58
57
|
removeSession: (id: string) => void;
|
|
59
|
-
/**
|
|
60
|
-
* switch session url
|
|
61
|
-
*/
|
|
62
|
-
switchSession: (sessionId?: string) => void;
|
|
63
58
|
/**
|
|
64
59
|
* A custom hook that uses SWR to fetch sessions data.
|
|
65
60
|
*/
|
|
@@ -86,9 +81,9 @@ export const createSessionSlice: StateCreator<
|
|
|
86
81
|
},
|
|
87
82
|
|
|
88
83
|
createSession: async (agent, isSwitchSession = true) => {
|
|
89
|
-
const {
|
|
84
|
+
const { activeSession, refreshSessions } = get();
|
|
90
85
|
|
|
91
|
-
//
|
|
86
|
+
// merge the defaultAgent in settings
|
|
92
87
|
const defaultAgent = merge(
|
|
93
88
|
initLobeSession,
|
|
94
89
|
settingsSelectors.defaultAgent(useGlobalStore.getState()),
|
|
@@ -99,14 +94,14 @@ export const createSessionSlice: StateCreator<
|
|
|
99
94
|
const id = await sessionService.createNewSession(LobeSessionType.Agent, newSession);
|
|
100
95
|
await refreshSessions();
|
|
101
96
|
|
|
102
|
-
//
|
|
103
|
-
if (isSwitchSession)
|
|
97
|
+
// Whether to goto to the new session after creation, the default is to switch to
|
|
98
|
+
if (isSwitchSession) activeSession(id);
|
|
104
99
|
|
|
105
100
|
return id;
|
|
106
101
|
},
|
|
107
102
|
|
|
108
103
|
duplicateSession: async (id) => {
|
|
109
|
-
const {
|
|
104
|
+
const { activeSession, refreshSessions } = get();
|
|
110
105
|
const session = sessionSelectors.getSessionById(id)(get());
|
|
111
106
|
|
|
112
107
|
if (!session) return;
|
|
@@ -123,7 +118,7 @@ export const createSessionSlice: StateCreator<
|
|
|
123
118
|
}
|
|
124
119
|
|
|
125
120
|
await refreshSessions();
|
|
126
|
-
|
|
121
|
+
activeSession(newId);
|
|
127
122
|
},
|
|
128
123
|
|
|
129
124
|
pinSession: async (sessionId, pinned) => {
|
|
@@ -140,20 +135,12 @@ export const createSessionSlice: StateCreator<
|
|
|
140
135
|
await sessionService.removeSession(sessionId);
|
|
141
136
|
await get().refreshSessions();
|
|
142
137
|
|
|
138
|
+
// If the active session deleted, switch to the inbox session
|
|
143
139
|
if (sessionId === get().activeId) {
|
|
144
|
-
get().
|
|
140
|
+
get().activeSession(INBOX_SESSION_ID);
|
|
145
141
|
}
|
|
146
142
|
},
|
|
147
143
|
|
|
148
|
-
switchSession: (sessionId = INBOX_SESSION_ID) => {
|
|
149
|
-
const { isMobile, router } = get();
|
|
150
|
-
|
|
151
|
-
get().activeSession(sessionId);
|
|
152
|
-
|
|
153
|
-
// TODO: 后续可以把 router 移除
|
|
154
|
-
router?.push(SESSION_CHAT_URL(sessionId, isMobile));
|
|
155
|
-
},
|
|
156
|
-
|
|
157
144
|
useFetchSessions: () =>
|
|
158
145
|
useClientDataSWR<ChatSessionList>(FETCH_SESSIONS_KEY, sessionService.getSessionsWithGroup, {
|
|
159
146
|
onSuccess: (data) => {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';
|
|
2
|
-
|
|
3
1
|
import { DEFAULT_AGENT_META } from '@/const/meta';
|
|
4
2
|
import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
|
|
5
3
|
import { CustomSessionGroup, LobeAgentSession, LobeSessionType } from '@/types/session';
|
|
@@ -25,11 +23,6 @@ export interface SessionState {
|
|
|
25
23
|
isSearching: boolean;
|
|
26
24
|
isSessionsFirstFetchFinished: boolean;
|
|
27
25
|
pinnedSessions: LobeAgentSession[];
|
|
28
|
-
/**
|
|
29
|
-
* 后续看看是否可以将 router 部分的逻辑移出去
|
|
30
|
-
* @deprecated
|
|
31
|
-
*/
|
|
32
|
-
router?: AppRouterInstance;
|
|
33
26
|
searchKeywords: string;
|
|
34
27
|
searchSessions: LobeAgentSession[];
|
|
35
28
|
/**
|