@lobehub/chat 0.31.0 → 0.32.0

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 CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 0.32.0](https://github.com/lobehub/lobe-chat/compare/v0.31.0...v0.32.0)
6
+
7
+ <sup>Released on **2023-07-30**</sup>
8
+
9
+ #### ✨ Features
10
+
11
+ - **misc**: 支持会话置顶.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's improved
19
+
20
+ - **misc**: 支持会话置顶, closes [#32](https://github.com/lobehub/lobe-chat/issues/32) ([fc44b5d](https://github.com/lobehub/lobe-chat/commit/fc44b5d))
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
+
5
30
  ## [Version 0.31.0](https://github.com/lobehub/lobe-chat/compare/v0.30.1...v0.31.0)
6
31
 
7
32
  <sup>Released on **2023-07-30**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "Lobe Chat is an open-source chatbot client using LangChain, Typescript and Next.js",
5
5
  "keywords": [
6
6
  "chatbot",
@@ -19,10 +19,9 @@ interface SessionItemProps {
19
19
  active?: boolean;
20
20
  id: string;
21
21
  loading?: boolean;
22
- pin?: boolean;
23
22
  }
24
23
 
25
- const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pin }) => {
24
+ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading }) => {
26
25
  const ref = useRef(null);
27
26
  const isHovering = useHover(ref);
28
27
 
@@ -33,6 +32,7 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
33
32
  const [defaultModel] = useSettings((s) => [s.settings.model], shallow);
34
33
 
35
34
  const [
35
+ pin,
36
36
  title,
37
37
  description,
38
38
  systemRole,
@@ -42,11 +42,13 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
42
42
  model,
43
43
  chatLength,
44
44
  removeSession,
45
+ pinSession,
45
46
  ] = useSessionStore((s) => {
46
47
  const session = sessionSelectors.getSessionById(id)(s);
47
48
  const meta = session.meta;
48
49
  const systemRole = session.config.systemRole;
49
50
  return [
51
+ session.pinned,
50
52
  agentSelectors.getTitle(meta),
51
53
  meta.description,
52
54
  systemRole,
@@ -56,6 +58,7 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
56
58
  session.config.model,
57
59
  chatSelectors.currentChats(s).length,
58
60
  s.removeSession,
61
+ s.pinSession,
59
62
  ];
60
63
  }, shallow);
61
64
 
@@ -66,8 +69,9 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
66
69
  icon: <Icon icon={pin ? PinOff : Pin} />,
67
70
  key: 'pin',
68
71
  label: t(pin ? 'pinOff' : 'pin'),
69
- // TODO: 动作绑定
70
- onClick: () => {},
72
+ onClick: () => {
73
+ pinSession(id, !pin);
74
+ },
71
75
  },
72
76
  {
73
77
  children: [
@@ -154,7 +158,16 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
154
158
  style={{ color: theme.colorText }}
155
159
  title={title}
156
160
  />
157
- <Dropdown arrow={false} menu={{ items }} trigger={['click']}>
161
+ <Dropdown
162
+ arrow={false}
163
+ menu={{
164
+ items,
165
+ onClick: ({ domEvent }) => {
166
+ domEvent.stopPropagation();
167
+ },
168
+ }}
169
+ trigger={['click']}
170
+ >
158
171
  <ActionIcon
159
172
  className="session-remove"
160
173
  icon={MoreVertical}
@@ -31,6 +31,11 @@ export interface SessionAction {
31
31
  */
32
32
  importSessions: (sessions: LobeSessions) => void;
33
33
 
34
+ /**
35
+ * 置顶会话
36
+ * @param sessionId
37
+ */
38
+ pinSession: (sessionId: string, pinned?: boolean) => void;
34
39
  /**
35
40
  * 生成压缩后的消息
36
41
  * @returns 压缩后的消息
@@ -42,12 +47,13 @@ export interface SessionAction {
42
47
  * @returns void
43
48
  */
44
49
  removeSession: (sessionId: string) => void;
50
+
45
51
  /**
46
52
  * @title 切换会话
47
53
  * @param sessionId - 会话索引
48
54
  * @returns void
49
55
  */
50
- switchSession: (sessionId?: string | 'new') => Promise<void>;
56
+ switchSession: (sessionId?: string) => Promise<void>;
51
57
  }
52
58
 
53
59
  export const createSessionSlice: StateCreator<
@@ -104,6 +110,19 @@ export const createSessionSlice: StateCreator<
104
110
  }),
105
111
  });
106
112
  },
113
+ // genShareUrl: () => {
114
+ // const session = sessionSelectors.currentSession(get());
115
+ // if (!session) return '';
116
+ //
117
+ // const agent = session.config;
118
+ // return genShareMessagesUrl(session.chats, agent.systemRole);
119
+ // },
120
+ pinSession: (sessionId, pinned) => {
121
+ const nextValue = typeof pinned === 'boolean' ? pinned : !get().sessions[sessionId].pinned;
122
+
123
+ get().dispatchSession({ id: sessionId, pinned: nextValue, type: 'toggleSessionPinned' });
124
+ },
125
+
107
126
  removeSession: (sessionId) => {
108
127
  get().dispatchSession({ id: sessionId, type: 'removeSession' });
109
128
 
@@ -122,11 +141,4 @@ export const createSessionSlice: StateCreator<
122
141
  // 新会话
123
142
  await Router.push(`/chat/${sessionId}`);
124
143
  },
125
- // genShareUrl: () => {
126
- // const session = sessionSelectors.currentSession(get());
127
- // if (!session) return '';
128
- //
129
- // const agent = session.config;
130
- // return genShareMessagesUrl(session.chats, agent.systemRole);
131
- // },
132
144
  });
@@ -63,6 +63,11 @@ interface UpdateSessionAgentConfig {
63
63
  id: string;
64
64
  type: 'updateSessionConfig';
65
65
  }
66
+ interface ToggleSessionPinned {
67
+ id: string;
68
+ pinned: boolean;
69
+ type: 'toggleSessionPinned';
70
+ }
66
71
 
67
72
  export type SessionDispatch =
68
73
  | AddSession
@@ -70,7 +75,8 @@ export type SessionDispatch =
70
75
  | RemoveSession
71
76
  | UpdateSessionMeta
72
77
  | UpdateSessionAgentConfig
73
- | UpdateSessionTopic;
78
+ | UpdateSessionTopic
79
+ | ToggleSessionPinned;
74
80
 
75
81
  export const sessionsReducer = (state: LobeSessions, payload: SessionDispatch): LobeSessions => {
76
82
  switch (payload.type) {
@@ -89,6 +95,16 @@ export const sessionsReducer = (state: LobeSessions, payload: SessionDispatch):
89
95
  });
90
96
  }
91
97
 
98
+ case 'toggleSessionPinned': {
99
+ return produce(state, (draft) => {
100
+ const { pinned, id } = payload;
101
+ const session = draft[id];
102
+ if (!session) return;
103
+
104
+ session.pinned = pinned;
105
+ });
106
+ }
107
+
92
108
  case 'updateSessionMeta': {
93
109
  return produce(state, (draft) => {
94
110
  const chat = draft[payload.id];
@@ -21,8 +21,19 @@ export const sessionList = (s: SessionStore) => {
21
21
  .map((c) => c.content)
22
22
  .join(''),
23
23
  ]);
24
-
25
- return Object.values(filterChats).sort((a, b) => (b.updateAt || 0) - (a.updateAt || 0));
24
+ // 先按照 `pinned` 字段进行排序,置顶的会排在前面。然后,根据 `updateAt` 字段进行倒序排序。
25
+ return Object.values(filterChats).sort((a, b) => {
26
+ if (a.pinned && !b.pinned) {
27
+ return -1;
28
+ }
29
+ if (!a.pinned && b.pinned) {
30
+ return 1;
31
+ }
32
+ if (a.updateAt && b.updateAt) {
33
+ return b.updateAt - a.updateAt;
34
+ }
35
+ return 0;
36
+ });
26
37
  };
27
38
 
28
39
  export const getSessionById =
@@ -19,6 +19,13 @@ interface LobeSessionBase extends BaseDataModel {
19
19
  * 聊天记录
20
20
  */
21
21
  chats: ChatMessageMap;
22
+ /**
23
+ * 置顶
24
+ */
25
+ pinned?: boolean;
26
+ /**
27
+ * 主题
28
+ */
22
29
  topics?: ChatTopicMap;
23
30
  /**
24
31
  * 每个会话的类别