@lobehub/chat 0.110.3 → 0.110.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 CHANGED
@@ -2,6 +2,48 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.110.5](https://github.com/lobehub/lobe-chat/compare/v0.110.4...v0.110.5)
6
+
7
+ <sup>Released on **2023-12-10**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Fix setting plugin i18n.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Fix setting plugin i18n, closes [#606](https://github.com/lobehub/lobe-chat/issues/606) ([4e18ebf](https://github.com/lobehub/lobe-chat/commit/4e18ebf))
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 0.110.4](https://github.com/lobehub/lobe-chat/compare/v0.110.3...v0.110.4)
31
+
32
+ <sup>Released on **2023-12-08**</sup>
33
+
34
+ <br/>
35
+
36
+ <details>
37
+ <summary><kbd>Improvements and Fixes</kbd></summary>
38
+
39
+ </details>
40
+
41
+ <div align="right">
42
+
43
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
44
+
45
+ </div>
46
+
5
47
  ### [Version 0.110.3](https://github.com/lobehub/lobe-chat/compare/v0.110.2...v0.110.3)
6
48
 
7
49
  <sup>Released on **2023-12-08**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.110.3",
3
+ "version": "0.110.5",
4
4
  "description": "An open-source, extensible (Function Calling), high-performance chatbot framework. It supports one-click free deployment of your private ChatGPT/LLM web application",
5
5
  "keywords": [
6
6
  "chatbot",
@@ -144,7 +144,7 @@
144
144
  "@types/ua-parser-js": "^0.7",
145
145
  "@types/uuid": "^9",
146
146
  "@umijs/lint": "^4",
147
- "@vitest/coverage-v8": "^1",
147
+ "@vitest/coverage-v8": "0.34.6",
148
148
  "commitlint": "^18",
149
149
  "consola": "^3",
150
150
  "dpdm": "^3",
@@ -162,7 +162,7 @@
162
162
  "stylelint": "^15",
163
163
  "ts-node": "^10",
164
164
  "typescript": "^5",
165
- "vitest": "^1"
165
+ "vitest": "0.34.6"
166
166
  },
167
167
  "publishConfig": {
168
168
  "access": "public",
@@ -1,6 +1,6 @@
1
1
  import { ActionIcon, ChatInputArea, ChatSendButton } from '@lobehub/ui';
2
2
  import { Maximize2, Minimize2 } from 'lucide-react';
3
- import { memo } from 'react';
3
+ import { memo, useCallback, useMemo } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
 
6
6
  import ActionBar from '@/app/chat/features/ChatInput/ActionBar';
@@ -27,50 +27,64 @@ const ChatInputDesktopLayout = memo(() => {
27
27
  canUpload,
28
28
  } = useChatInput();
29
29
 
30
+ const handleSizeChange = useCallback(
31
+ (_: any, size: any) => {
32
+ if (!size) return;
33
+ updatePreference({
34
+ inputHeight: typeof size.height === 'string' ? Number.parseInt(size.height) : size.height,
35
+ });
36
+ },
37
+ [updatePreference],
38
+ );
39
+
40
+ const buttonAddons = useMemo(
41
+ () => (
42
+ <ChatSendButton
43
+ leftAddons={canUpload && <LocalFiles />}
44
+ loading={loading}
45
+ onSend={onSend}
46
+ onStop={onStop}
47
+ rightAddons={<SaveTopic />}
48
+ texts={{
49
+ send: t('send'),
50
+ stop: t('stop'),
51
+ warp: t('warp'),
52
+ }}
53
+ />
54
+ ),
55
+ [canUpload, loading, onSend, onStop, t],
56
+ );
57
+
58
+ const topAddons = useMemo(
59
+ () => (
60
+ <ActionBar
61
+ rightAreaEndRender={
62
+ <ActionIcon
63
+ icon={expand ? Minimize2 : Maximize2}
64
+ onClick={() => {
65
+ setExpand(!expand);
66
+ }}
67
+ />
68
+ }
69
+ />
70
+ ),
71
+ [expand],
72
+ );
73
+
30
74
  return (
31
75
  <>
32
76
  {canUpload && <DragUpload />}
33
77
  <ChatInputArea
34
- bottomAddons={
35
- <ChatSendButton
36
- leftAddons={canUpload && <LocalFiles />}
37
- loading={loading}
38
- onSend={onSend}
39
- onStop={onStop}
40
- rightAddons={<SaveTopic />}
41
- texts={{
42
- send: t('send'),
43
- stop: t('stop'),
44
- warp: t('warp'),
45
- }}
46
- />
47
- }
78
+ bottomAddons={buttonAddons}
48
79
  expand={expand}
49
80
  heights={{ headerHeight: HEADER_HEIGHT, inputHeight, minHeight: CHAT_TEXTAREA_HEIGHT }}
50
81
  loading={loading}
51
82
  onInput={onInput}
52
83
  onSend={onSend}
53
- onSizeChange={(_, size) => {
54
- if (!size) return;
55
- updatePreference({
56
- inputHeight:
57
- typeof size.height === 'string' ? Number.parseInt(size.height) : size.height,
58
- });
59
- }}
84
+ onSizeChange={handleSizeChange}
60
85
  placeholder={t('sendPlaceholder')}
61
86
  ref={ref}
62
- topAddons={
63
- <ActionBar
64
- rightAreaEndRender={
65
- <ActionIcon
66
- icon={expand ? Minimize2 : Maximize2}
67
- onClick={() => {
68
- setExpand(!expand);
69
- }}
70
- />
71
- }
72
- />
73
- }
87
+ topAddons={topAddons}
74
88
  value={value}
75
89
  />
76
90
  </>
@@ -1,5 +1,5 @@
1
1
  import { TextAreaRef } from 'antd/es/input/TextArea';
2
- import { useRef, useState } from 'react';
2
+ import { useCallback, useRef, useState } from 'react';
3
3
 
4
4
  import { useChatStore } from '@/store/chat';
5
5
  import { useGlobalStore } from '@/store/global';
@@ -24,17 +24,19 @@ export const useChatInput = () => {
24
24
  s.stopGenerateMessage,
25
25
  ]);
26
26
 
27
+ const handleSend = useCallback(() => {
28
+ setExpand(false);
29
+ ref?.current?.blur();
30
+ onSend();
31
+ }, [onSend]);
32
+
27
33
  return {
28
34
  canUpload,
29
35
  expand,
30
36
  inputHeight,
31
37
  loading,
32
38
  onInput,
33
- onSend: () => {
34
- setExpand(false);
35
- ref?.current?.blur();
36
- onSend();
37
- },
39
+ onSend: handleSend,
38
40
  onStop,
39
41
  ref,
40
42
  setExpand,
@@ -27,7 +27,7 @@ const AgentPlugin = memo(() => {
27
27
  s.toggleAgentPlugin,
28
28
  ]);
29
29
 
30
- const installedPlugins = useToolStore(pluginSelectors.installedPlugins, isEqual);
30
+ const installedPlugins = useToolStore(pluginSelectors.installedPluginMetaList, isEqual);
31
31
  const useFetchInstalledPlugins = useToolStore((s) => s.useFetchInstalledPlugins);
32
32
 
33
33
  const { isLoading } = useFetchInstalledPlugins();
@@ -36,7 +36,7 @@ const AgentPlugin = memo(() => {
36
36
 
37
37
  // =========== Plugin List =========== //
38
38
 
39
- const list = installedPlugins.map(({ identifier, type, manifest: { meta } = {} }) => {
39
+ const list = installedPlugins.map(({ identifier, type, meta }) => {
40
40
  const isCustomPlugin = type === 'customPlugin';
41
41
 
42
42
  return {
@@ -7,7 +7,7 @@ import { pluginSelectors } from './selectors';
7
7
 
8
8
  const mockState = {
9
9
  ...initialState,
10
- pluginManifestLoading: {
10
+ pluginInstallLoading: {
11
11
  'plugin-1': false,
12
12
  'plugin-2': true,
13
13
  },
@@ -139,4 +139,73 @@ describe('pluginSelectors', () => {
139
139
  expect(result).toBe(true);
140
140
  });
141
141
  });
142
+
143
+ describe('isPluginInstalled', () => {
144
+ it('should return true if the plugin is installed', () => {
145
+ const result = pluginSelectors.isPluginInstalled('plugin-1')(mockState);
146
+ expect(result).toBe(true);
147
+ });
148
+
149
+ it('should return false if the plugin is not installed', () => {
150
+ const result = pluginSelectors.isPluginInstalled('non-installed-plugin')(mockState);
151
+ expect(result).toBe(false);
152
+ });
153
+ });
154
+
155
+ describe('getInstalledPluginById', () => {
156
+ it('should return the installed plugin by id', () => {
157
+ const result = pluginSelectors.getInstalledPluginById('plugin-1')(mockState);
158
+ expect(result).toEqual(mockState.installedPlugins[0]);
159
+ });
160
+
161
+ it('should return undefined if the plugin is not installed', () => {
162
+ const result = pluginSelectors.getInstalledPluginById('non-installed-plugin')(mockState);
163
+ expect(result).toBeUndefined();
164
+ });
165
+ });
166
+
167
+ describe('getPluginManifestLoadingStatus', () => {
168
+ it('should return "loading" if the plugin manifest is being loaded', () => {
169
+ const result = pluginSelectors.getPluginManifestLoadingStatus('plugin-2')(mockState);
170
+ expect(result).toBe('loading');
171
+ });
172
+
173
+ it('should return "error" if the plugin manifest is not found', () => {
174
+ const result =
175
+ pluginSelectors.getPluginManifestLoadingStatus('non-existing-plugin')(mockState);
176
+ expect(result).toBe('error');
177
+ });
178
+
179
+ it('should return "success" if the plugin manifest is loaded', () => {
180
+ const result = pluginSelectors.getPluginManifestLoadingStatus('plugin-1')(mockState);
181
+ expect(result).toBe('success');
182
+ });
183
+ });
184
+
185
+ describe('storeAndInstallPluginsIdList', () => {
186
+ it('should return a list of unique plugin identifiers from both installed and store lists', () => {
187
+ const result = pluginSelectors.storeAndInstallPluginsIdList(mockState);
188
+ expect(result).toEqual(['plugin-1', 'plugin-2']);
189
+ });
190
+ });
191
+
192
+ describe('installedPluginManifestList', () => {
193
+ it('should return a list of manifests for installed plugins', () => {
194
+ const result = pluginSelectors.installedPluginManifestList(mockState);
195
+ const expectedManifests = mockState.installedPlugins.map((p) => p.manifest);
196
+ expect(result).toEqual(expectedManifests);
197
+ });
198
+ });
199
+
200
+ describe('installedPluginMetaList', () => {
201
+ it('should return a list of meta information for installed plugins', () => {
202
+ const result = pluginSelectors.installedPluginMetaList(mockState);
203
+ const expectedMetaList = mockState.installedPlugins.map((p) => ({
204
+ identifier: p.identifier,
205
+ meta: pluginSelectors.getPluginMetaById(p.identifier)(mockState),
206
+ type: p.type,
207
+ }));
208
+ expect(result).toEqual(expectedMetaList);
209
+ });
210
+ });
142
211
  });
@@ -63,6 +63,7 @@ const installedPluginMetaList = (s: ToolStoreState) =>
63
63
  installedPlugins(s).map((p) => ({
64
64
  identifier: p.identifier,
65
65
  meta: getPluginMetaById(p.identifier)(s),
66
+ type: p.type,
66
67
  }));
67
68
 
68
69
  const isPluginHasUI = (id: string) => (s: ToolStoreState) => {