@lobehub/chat 0.63.2 → 0.64.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 +62 -0
- package/package.json +1 -1
- package/src/components/EmojiPicker/index.tsx +13 -5
- package/src/const/url.ts +1 -1
- package/src/features/AgentSetting/AgentMeta/index.tsx +1 -1
- package/src/features/AgentSetting/AgentPlugin/LocalPluginItem.tsx +72 -0
- package/src/features/AgentSetting/AgentPlugin/MarketList.tsx +160 -0
- package/src/features/AgentSetting/AgentPlugin/PluginSettings.tsx +76 -0
- package/src/features/AgentSetting/AgentPlugin/index.tsx +8 -143
- package/src/features/PluginDevModal/ManifestForm.tsx +96 -0
- package/src/features/PluginDevModal/MetaForm.tsx +90 -0
- package/src/features/PluginDevModal/PluginPreview.tsx +36 -0
- package/src/features/PluginDevModal/index.tsx +153 -0
- package/src/locales/default/error.ts +2 -0
- package/src/locales/default/plugin.ts +79 -3
- package/src/locales/default/setting.ts +3 -0
- package/src/pages/chat/features/Conversation/ChatList/Error/index.tsx +2 -1
- package/src/pages/chat/features/Conversation/ChatList/Plugins/FunctionCall.tsx +7 -4
- package/src/pages/chat/features/Conversation/ChatList/Plugins/PluginMessage.tsx +27 -33
- package/src/services/plugin.ts +6 -3
- package/src/store/plugin/action.ts +23 -2
- package/src/store/plugin/initialState.ts +17 -1
- package/src/store/plugin/reducers/devPluginList.ts +56 -0
- package/src/store/plugin/selectors.ts +9 -2
- package/src/store/plugin/store.ts +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,68 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 0.64.0](https://github.com/lobehub/lobe-chat/compare/v0.63.3...v0.64.0)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-08-29**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **misc**: Remove no need i18n.
|
|
12
|
+
|
|
13
|
+
#### ✨ Features
|
|
14
|
+
|
|
15
|
+
- **misc**: 增加自定义插件的增删改配置功能, 完善自定义插件表单的校验逻辑, 支持本地插件侧的请求与错误呈现, 新增插件配置 Dev 弹窗, 绑定本地插件的增删改逻辑.
|
|
16
|
+
|
|
17
|
+
<br/>
|
|
18
|
+
|
|
19
|
+
<details>
|
|
20
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
21
|
+
|
|
22
|
+
#### Code refactoring
|
|
23
|
+
|
|
24
|
+
- **misc**: Remove no need i18n ([808a86a](https://github.com/lobehub/lobe-chat/commit/808a86a))
|
|
25
|
+
|
|
26
|
+
#### What's improved
|
|
27
|
+
|
|
28
|
+
- **misc**: 增加自定义插件的增删改配置功能 ([faba081](https://github.com/lobehub/lobe-chat/commit/faba081))
|
|
29
|
+
- **misc**: 完善自定义插件表单的校验逻辑 ([4e1fd28](https://github.com/lobehub/lobe-chat/commit/4e1fd28))
|
|
30
|
+
- **misc**: 支持本地插件侧的请求与错误呈现 ([7e2b39a](https://github.com/lobehub/lobe-chat/commit/7e2b39a))
|
|
31
|
+
- **misc**: 新增插件配置 Dev 弹窗 ([20269b7](https://github.com/lobehub/lobe-chat/commit/20269b7))
|
|
32
|
+
- **misc**: 绑定本地插件的增删改逻辑 ([902e7ed](https://github.com/lobehub/lobe-chat/commit/902e7ed))
|
|
33
|
+
|
|
34
|
+
</details>
|
|
35
|
+
|
|
36
|
+
<div align="right">
|
|
37
|
+
|
|
38
|
+
[](#readme-top)
|
|
39
|
+
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
### [Version 0.63.3](https://github.com/lobehub/lobe-chat/compare/v0.63.2...v0.63.3)
|
|
43
|
+
|
|
44
|
+
<sup>Released on **2023-08-28**</sup>
|
|
45
|
+
|
|
46
|
+
#### ♻ Code Refactoring
|
|
47
|
+
|
|
48
|
+
- **misc**: Refactor with new market url.
|
|
49
|
+
|
|
50
|
+
<br/>
|
|
51
|
+
|
|
52
|
+
<details>
|
|
53
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
54
|
+
|
|
55
|
+
#### Code refactoring
|
|
56
|
+
|
|
57
|
+
- **misc**: Refactor with new market url, closes [#123](https://github.com/lobehub/lobe-chat/issues/123) ([34a88f8](https://github.com/lobehub/lobe-chat/commit/34a88f8))
|
|
58
|
+
|
|
59
|
+
</details>
|
|
60
|
+
|
|
61
|
+
<div align="right">
|
|
62
|
+
|
|
63
|
+
[](#readme-top)
|
|
64
|
+
|
|
65
|
+
</div>
|
|
66
|
+
|
|
5
67
|
### [Version 0.63.2](https://github.com/lobehub/lobe-chat/compare/v0.63.1...v0.63.2)
|
|
6
68
|
|
|
7
69
|
<sup>Released on **2023-08-27**</sup>
|
package/package.json
CHANGED
|
@@ -4,21 +4,29 @@ import Picker from '@emoji-mart/react';
|
|
|
4
4
|
import { Avatar } from '@lobehub/ui';
|
|
5
5
|
import { Popover } from 'antd';
|
|
6
6
|
import { memo } from 'react';
|
|
7
|
+
import useMergeState from 'use-merge-value';
|
|
7
8
|
|
|
8
9
|
import { DEFAULT_AVATAR, DEFAULT_BACKGROUND_COLOR } from '@/const/meta';
|
|
9
10
|
|
|
10
11
|
import { useStyles } from './style';
|
|
11
12
|
|
|
12
13
|
export interface EmojiPickerProps {
|
|
13
|
-
avatar?: string;
|
|
14
14
|
backgroundColor?: string;
|
|
15
|
-
|
|
15
|
+
defaultAvatar?: string;
|
|
16
|
+
onChange?: (emoji: string) => void;
|
|
17
|
+
value?: string;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
const EmojiPicker = memo<EmojiPickerProps>(
|
|
19
|
-
({
|
|
21
|
+
({ value, defaultAvatar, backgroundColor = DEFAULT_BACKGROUND_COLOR, onChange }) => {
|
|
20
22
|
const { styles } = useStyles();
|
|
21
23
|
|
|
24
|
+
const [ava, setAva] = useMergeState(DEFAULT_AVATAR, {
|
|
25
|
+
defaultValue: defaultAvatar,
|
|
26
|
+
onChange,
|
|
27
|
+
value,
|
|
28
|
+
});
|
|
29
|
+
|
|
22
30
|
return (
|
|
23
31
|
<Popover
|
|
24
32
|
content={
|
|
@@ -27,7 +35,7 @@ const EmojiPicker = memo<EmojiPickerProps>(
|
|
|
27
35
|
data={data}
|
|
28
36
|
i18n={i18n}
|
|
29
37
|
locale={'zh'}
|
|
30
|
-
onEmojiSelect={(e: any) =>
|
|
38
|
+
onEmojiSelect={(e: any) => setAva(e.native)}
|
|
31
39
|
skinTonePosition={'none'}
|
|
32
40
|
theme={'auto'}
|
|
33
41
|
/>
|
|
@@ -38,7 +46,7 @@ const EmojiPicker = memo<EmojiPickerProps>(
|
|
|
38
46
|
trigger={'click'}
|
|
39
47
|
>
|
|
40
48
|
<div className={styles.avatar} style={{ width: 'fit-content' }}>
|
|
41
|
-
<Avatar avatar={
|
|
49
|
+
<Avatar avatar={ava} background={backgroundColor} size={44} />
|
|
42
50
|
</div>
|
|
43
51
|
</Popover>
|
|
44
52
|
);
|
package/src/const/url.ts
CHANGED
|
@@ -7,4 +7,4 @@ export const FEEDBACK = pkg.bugs.url;
|
|
|
7
7
|
export const DISCORD = 'https://discord.gg/AYFPHvv2jT';
|
|
8
8
|
|
|
9
9
|
export const PLUGINS_INDEX_URL =
|
|
10
|
-
process.env.PLUGINS_INDEX_URL ?? 'https://chat-plugins
|
|
10
|
+
process.env.PLUGINS_INDEX_URL ?? 'https://chat-plugins.lobehub.com';
|
|
@@ -63,9 +63,9 @@ const AgentMeta = memo(() => {
|
|
|
63
63
|
{
|
|
64
64
|
children: (
|
|
65
65
|
<EmojiPicker
|
|
66
|
-
avatar={meta.avatar}
|
|
67
66
|
backgroundColor={meta.backgroundColor}
|
|
68
67
|
onChange={(avatar) => updateMeta({ avatar })}
|
|
68
|
+
value={meta.avatar}
|
|
69
69
|
/>
|
|
70
70
|
),
|
|
71
71
|
label: t('settingAgent.avatar.title'),
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Button, Switch } from 'antd';
|
|
2
|
+
import isEqual from 'fast-deep-equal';
|
|
3
|
+
import { memo, useState } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
|
6
|
+
import DevModal from 'src/features/PluginDevModal';
|
|
7
|
+
|
|
8
|
+
import { pluginSelectors, usePluginStore } from '@/store/plugin';
|
|
9
|
+
|
|
10
|
+
import { useStore } from '../store';
|
|
11
|
+
|
|
12
|
+
const MarketList = memo<{ id: string }>(({ id }) => {
|
|
13
|
+
const { t } = useTranslation('plugin');
|
|
14
|
+
|
|
15
|
+
const [showModal, setModal] = useState(false);
|
|
16
|
+
|
|
17
|
+
const updateConfig = useStore((s) => s.toggleAgentPlugin);
|
|
18
|
+
const [plugins, hasPlugin] = useStore((s) => [s.config.plugins || [], !!s.config.plugins]);
|
|
19
|
+
|
|
20
|
+
const [useFetchPluginList, fetchPluginManifest, dispatchDevPluginList] = usePluginStore((s) => [
|
|
21
|
+
s.useFetchPluginList,
|
|
22
|
+
s.fetchPluginManifest,
|
|
23
|
+
s.dispatchDevPluginList,
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
const pluginManifestLoading = usePluginStore((s) => s.pluginManifestLoading, isEqual);
|
|
27
|
+
const devPlugin = usePluginStore(pluginSelectors.getDevPluginById(id), isEqual);
|
|
28
|
+
|
|
29
|
+
useFetchPluginList();
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<>
|
|
33
|
+
<DevModal
|
|
34
|
+
onDelete={() => {
|
|
35
|
+
dispatchDevPluginList({ id, type: 'deleteItem' });
|
|
36
|
+
}}
|
|
37
|
+
onOpenChange={setModal}
|
|
38
|
+
onSave={(value) => {
|
|
39
|
+
dispatchDevPluginList({ id, plugin: value, type: 'updateItem' });
|
|
40
|
+
}}
|
|
41
|
+
open={showModal}
|
|
42
|
+
showDelete
|
|
43
|
+
value={devPlugin}
|
|
44
|
+
/>
|
|
45
|
+
|
|
46
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
47
|
+
<Switch
|
|
48
|
+
checked={
|
|
49
|
+
// 如果在加载中,说明激活了
|
|
50
|
+
pluginManifestLoading[id] || !hasPlugin ? false : plugins.includes(id)
|
|
51
|
+
}
|
|
52
|
+
loading={pluginManifestLoading[id]}
|
|
53
|
+
onChange={(checked) => {
|
|
54
|
+
updateConfig(id);
|
|
55
|
+
if (checked) {
|
|
56
|
+
fetchPluginManifest(id);
|
|
57
|
+
}
|
|
58
|
+
}}
|
|
59
|
+
/>
|
|
60
|
+
<Button
|
|
61
|
+
onClick={() => {
|
|
62
|
+
setModal(true);
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
{t('list.item.local.config')}
|
|
66
|
+
</Button>
|
|
67
|
+
</Flexbox>
|
|
68
|
+
</>
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
export default MarketList;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { Avatar, Form, Icon, Tooltip } from '@lobehub/ui';
|
|
2
|
+
import { Button, Skeleton, Switch, Tag } from 'antd';
|
|
3
|
+
import { createStyles } from 'antd-style';
|
|
4
|
+
import isEqual from 'fast-deep-equal';
|
|
5
|
+
import { LucideBlocks, LucideStore } from 'lucide-react';
|
|
6
|
+
import { memo, useState } from 'react';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
import { Flexbox } from 'react-layout-kit';
|
|
9
|
+
import DevModal from 'src/features/PluginDevModal';
|
|
10
|
+
|
|
11
|
+
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
12
|
+
import { pluginHelpers, usePluginStore } from '@/store/plugin';
|
|
13
|
+
|
|
14
|
+
import { useStore } from '../store';
|
|
15
|
+
import LocalPluginItem from './LocalPluginItem';
|
|
16
|
+
|
|
17
|
+
const useStyles = createStyles(({ css }) => ({
|
|
18
|
+
avatar: css`
|
|
19
|
+
.ant-skeleton-header {
|
|
20
|
+
padding-right: 0;
|
|
21
|
+
}
|
|
22
|
+
`,
|
|
23
|
+
label: css`
|
|
24
|
+
li {
|
|
25
|
+
height: 14px !important;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
li + li {
|
|
29
|
+
margin-block-start: 12px !important;
|
|
30
|
+
}
|
|
31
|
+
`,
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
const MarketList = memo(() => {
|
|
35
|
+
const { t } = useTranslation('setting');
|
|
36
|
+
const { styles } = useStyles();
|
|
37
|
+
|
|
38
|
+
const [showModal, setModal] = useState(false);
|
|
39
|
+
|
|
40
|
+
// useEffect(() => {
|
|
41
|
+
// setModal(true);
|
|
42
|
+
// }, []);
|
|
43
|
+
|
|
44
|
+
const updateConfig = useStore((s) => s.toggleAgentPlugin);
|
|
45
|
+
const [plugins, hasPlugin] = useStore((s) => [s.config.plugins || [], !!s.config.plugins]);
|
|
46
|
+
|
|
47
|
+
const [useFetchPluginList, fetchPluginManifest, saveToDevList, updateNewDevPlugin] =
|
|
48
|
+
usePluginStore((s) => [
|
|
49
|
+
s.useFetchPluginList,
|
|
50
|
+
s.fetchPluginManifest,
|
|
51
|
+
s.saveToDevList,
|
|
52
|
+
s.updateNewDevPlugin,
|
|
53
|
+
]);
|
|
54
|
+
const pluginManifestLoading = usePluginStore((s) => s.pluginManifestLoading, isEqual);
|
|
55
|
+
const pluginList = usePluginStore((s) => s.pluginList, isEqual);
|
|
56
|
+
const devPluginList = usePluginStore((s) => s.devPluginList, isEqual);
|
|
57
|
+
|
|
58
|
+
useFetchPluginList();
|
|
59
|
+
|
|
60
|
+
const loadingItem = {
|
|
61
|
+
avatar: (
|
|
62
|
+
<Skeleton
|
|
63
|
+
active
|
|
64
|
+
avatar={{ size: 40 }}
|
|
65
|
+
className={styles.avatar}
|
|
66
|
+
paragraph={false}
|
|
67
|
+
title={false}
|
|
68
|
+
/>
|
|
69
|
+
),
|
|
70
|
+
label: (
|
|
71
|
+
<Skeleton
|
|
72
|
+
active
|
|
73
|
+
avatar={false}
|
|
74
|
+
paragraph={{ className: styles.label, style: { marginBottom: 0 } }}
|
|
75
|
+
style={{ width: 300 }}
|
|
76
|
+
title={false}
|
|
77
|
+
/>
|
|
78
|
+
),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const loadingList = [loadingItem, loadingItem, loadingItem];
|
|
82
|
+
|
|
83
|
+
const isEmpty = pluginList.length === 0;
|
|
84
|
+
|
|
85
|
+
const list = pluginList.map(({ identifier, meta }) => ({
|
|
86
|
+
avatar: <Avatar avatar={meta.avatar} />,
|
|
87
|
+
children: (
|
|
88
|
+
<Switch
|
|
89
|
+
checked={
|
|
90
|
+
// 如果在加载中,说明激活了
|
|
91
|
+
pluginManifestLoading[identifier] || !hasPlugin ? false : plugins.includes(identifier)
|
|
92
|
+
}
|
|
93
|
+
loading={pluginManifestLoading[identifier]}
|
|
94
|
+
onChange={(checked) => {
|
|
95
|
+
updateConfig(identifier);
|
|
96
|
+
if (checked) {
|
|
97
|
+
fetchPluginManifest(identifier);
|
|
98
|
+
}
|
|
99
|
+
}}
|
|
100
|
+
/>
|
|
101
|
+
),
|
|
102
|
+
desc: pluginHelpers.getPluginDesc(meta),
|
|
103
|
+
label: pluginHelpers.getPluginTitle(meta),
|
|
104
|
+
minWidth: undefined,
|
|
105
|
+
tag: identifier,
|
|
106
|
+
}));
|
|
107
|
+
|
|
108
|
+
const devList = devPluginList.map(({ identifier, meta }) => ({
|
|
109
|
+
avatar: <Avatar avatar={pluginHelpers.getPluginAvatar(meta) || '🧩'} />,
|
|
110
|
+
children: <LocalPluginItem id={identifier} />,
|
|
111
|
+
desc: pluginHelpers.getPluginDesc(meta),
|
|
112
|
+
label: (
|
|
113
|
+
<Flexbox align={'center'} gap={8} horizontal>
|
|
114
|
+
{pluginHelpers.getPluginTitle(meta)}
|
|
115
|
+
<Tag bordered={false} color={'gold'}>
|
|
116
|
+
{t('list.item.local.title', { ns: 'plugin' })}
|
|
117
|
+
</Tag>
|
|
118
|
+
</Flexbox>
|
|
119
|
+
),
|
|
120
|
+
minWidth: undefined,
|
|
121
|
+
tag: identifier,
|
|
122
|
+
}));
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<>
|
|
126
|
+
<DevModal
|
|
127
|
+
onOpenChange={setModal}
|
|
128
|
+
onSave={saveToDevList}
|
|
129
|
+
onValueChange={updateNewDevPlugin}
|
|
130
|
+
open={showModal}
|
|
131
|
+
/>
|
|
132
|
+
<Form
|
|
133
|
+
items={[
|
|
134
|
+
{
|
|
135
|
+
children: isEmpty ? loadingList : [...devList, ...list],
|
|
136
|
+
extra: (
|
|
137
|
+
<Tooltip title={t('settingPlugin.addTooltip')}>
|
|
138
|
+
<Button
|
|
139
|
+
icon={<Icon icon={LucideBlocks} />}
|
|
140
|
+
onClick={(e) => {
|
|
141
|
+
e.stopPropagation();
|
|
142
|
+
setModal(true);
|
|
143
|
+
}}
|
|
144
|
+
size={'small'}
|
|
145
|
+
>
|
|
146
|
+
{t('settingPlugin.add')}
|
|
147
|
+
</Button>
|
|
148
|
+
</Tooltip>
|
|
149
|
+
),
|
|
150
|
+
icon: LucideStore,
|
|
151
|
+
title: t('settingPlugin.title'),
|
|
152
|
+
},
|
|
153
|
+
]}
|
|
154
|
+
{...FORM_STYLE}
|
|
155
|
+
/>{' '}
|
|
156
|
+
</>
|
|
157
|
+
);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
export default MarketList;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Form, ItemGroup, Markdown } from '@lobehub/ui';
|
|
2
|
+
import { createStyles } from 'antd-style';
|
|
3
|
+
import isEqual from 'fast-deep-equal';
|
|
4
|
+
import { ToyBrick } from 'lucide-react';
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
|
|
8
|
+
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
9
|
+
import { transformPluginSettings } from '@/features/PluginSettings';
|
|
10
|
+
import PluginSettingRender from '@/features/PluginSettings/PluginSettingRender';
|
|
11
|
+
import { pluginHelpers, pluginSelectors, usePluginStore } from '@/store/plugin';
|
|
12
|
+
|
|
13
|
+
import { useStore } from '../store';
|
|
14
|
+
|
|
15
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
16
|
+
md: css`
|
|
17
|
+
p {
|
|
18
|
+
color: ${token.colorTextDescription};
|
|
19
|
+
}
|
|
20
|
+
`,
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
const PluginSettings = memo(() => {
|
|
24
|
+
const { t } = useTranslation('setting');
|
|
25
|
+
const { styles } = useStyles();
|
|
26
|
+
|
|
27
|
+
const [plugins] = useStore((s) => [s.config.plugins || [], !!s.config.plugins]);
|
|
28
|
+
|
|
29
|
+
const [useFetchPluginList, updatePluginSettings] = usePluginStore((s) => [
|
|
30
|
+
s.useFetchPluginList,
|
|
31
|
+
s.updatePluginSettings,
|
|
32
|
+
]);
|
|
33
|
+
const pluginList = usePluginStore(pluginSelectors.pluginList);
|
|
34
|
+
|
|
35
|
+
const pluginManifestMap = usePluginStore((s) => s.pluginManifestMap, isEqual);
|
|
36
|
+
const pluginsSettings = usePluginStore((s) => s.pluginsSettings, isEqual);
|
|
37
|
+
useFetchPluginList();
|
|
38
|
+
|
|
39
|
+
const isEmpty = pluginList.length === 0;
|
|
40
|
+
|
|
41
|
+
const pluginsConfig = isEmpty
|
|
42
|
+
? []
|
|
43
|
+
: (plugins
|
|
44
|
+
.map((identifier) => {
|
|
45
|
+
const item = pluginList.find((i) => i.identifier === identifier);
|
|
46
|
+
|
|
47
|
+
if (!item) return null;
|
|
48
|
+
const manifest = pluginManifestMap[identifier];
|
|
49
|
+
|
|
50
|
+
if (!manifest?.settings) return null;
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
children: transformPluginSettings(manifest.settings).map((item) => ({
|
|
54
|
+
...item,
|
|
55
|
+
children: (
|
|
56
|
+
<PluginSettingRender
|
|
57
|
+
defaultValue={pluginsSettings[identifier]?.[item.name]}
|
|
58
|
+
format={item.format}
|
|
59
|
+
onChange={(value) => {
|
|
60
|
+
updatePluginSettings(identifier, { [item.name]: value });
|
|
61
|
+
}}
|
|
62
|
+
type={item.type as any}
|
|
63
|
+
/>
|
|
64
|
+
),
|
|
65
|
+
desc: item.desc && <Markdown className={styles.md}>{item.desc}</Markdown>,
|
|
66
|
+
})),
|
|
67
|
+
icon: ToyBrick,
|
|
68
|
+
title: t('settingPlugin.config', { id: pluginHelpers.getPluginTitle(item.meta) }),
|
|
69
|
+
};
|
|
70
|
+
})
|
|
71
|
+
.filter(Boolean) as unknown as ItemGroup[]);
|
|
72
|
+
|
|
73
|
+
return <Form items={pluginsConfig} {...FORM_STYLE} />;
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
export default PluginSettings;
|
|
@@ -1,148 +1,13 @@
|
|
|
1
|
-
import { Avatar, Form, ItemGroup, Markdown } from '@lobehub/ui';
|
|
2
|
-
import { Skeleton, Switch } from 'antd';
|
|
3
|
-
import { createStyles } from 'antd-style';
|
|
4
|
-
import isEqual from 'fast-deep-equal';
|
|
5
|
-
import { LucideStore, ToyBrick } from 'lucide-react';
|
|
6
1
|
import { memo } from 'react';
|
|
7
|
-
import { useTranslation } from 'react-i18next';
|
|
8
2
|
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import PluginSettingRender from '@/features/PluginSettings/PluginSettingRender';
|
|
12
|
-
import { pluginHelpers, usePluginStore } from '@/store/plugin';
|
|
3
|
+
import MarketList from './MarketList';
|
|
4
|
+
import PluginSettings from './PluginSettings';
|
|
13
5
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
`,
|
|
22
|
-
label: css`
|
|
23
|
-
li {
|
|
24
|
-
height: 14px !important;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
li + li {
|
|
28
|
-
margin-block-start: 12px !important;
|
|
29
|
-
}
|
|
30
|
-
`,
|
|
31
|
-
md: css`
|
|
32
|
-
p {
|
|
33
|
-
color: ${token.colorTextDescription};
|
|
34
|
-
}
|
|
35
|
-
`,
|
|
36
|
-
}));
|
|
37
|
-
|
|
38
|
-
const AgentPlugin = memo(() => {
|
|
39
|
-
const { t } = useTranslation('setting');
|
|
40
|
-
const { styles } = useStyles();
|
|
41
|
-
|
|
42
|
-
const updateConfig = useStore((s) => s.toggleAgentPlugin);
|
|
43
|
-
const [plugins, hasPlugin] = useStore((s) => [s.config.plugins || [], !!s.config.plugins]);
|
|
44
|
-
|
|
45
|
-
const [useFetchPluginList, fetchPluginManifest, updatePluginSettings] = usePluginStore((s) => [
|
|
46
|
-
s.useFetchPluginList,
|
|
47
|
-
s.fetchPluginManifest,
|
|
48
|
-
s.updatePluginSettings,
|
|
49
|
-
]);
|
|
50
|
-
const pluginManifestLoading = usePluginStore((s) => s.pluginManifestLoading, isEqual);
|
|
51
|
-
const pluginManifestMap = usePluginStore((s) => s.pluginManifestMap, isEqual);
|
|
52
|
-
const pluginsSettings = usePluginStore((s) => s.pluginsSettings, isEqual);
|
|
53
|
-
const { data } = useFetchPluginList();
|
|
54
|
-
|
|
55
|
-
const loadingItem = {
|
|
56
|
-
avatar: (
|
|
57
|
-
<Skeleton
|
|
58
|
-
active
|
|
59
|
-
avatar={{ size: 40 }}
|
|
60
|
-
className={styles.avatar}
|
|
61
|
-
paragraph={false}
|
|
62
|
-
title={false}
|
|
63
|
-
/>
|
|
64
|
-
),
|
|
65
|
-
label: (
|
|
66
|
-
<Skeleton
|
|
67
|
-
active
|
|
68
|
-
avatar={false}
|
|
69
|
-
paragraph={{ className: styles.label, style: { marginBottom: 0 } }}
|
|
70
|
-
style={{ width: 300 }}
|
|
71
|
-
title={false}
|
|
72
|
-
/>
|
|
73
|
-
),
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const children = !data
|
|
77
|
-
? [loadingItem, loadingItem, loadingItem]
|
|
78
|
-
: data.plugins.map(({ identifier, meta }) => ({
|
|
79
|
-
avatar: <Avatar avatar={meta.avatar} />,
|
|
80
|
-
children: (
|
|
81
|
-
<Switch
|
|
82
|
-
checked={
|
|
83
|
-
// 如果在加载中,说明激活了
|
|
84
|
-
pluginManifestLoading[identifier] || !hasPlugin ? false : plugins.includes(identifier)
|
|
85
|
-
}
|
|
86
|
-
loading={pluginManifestLoading[identifier]}
|
|
87
|
-
onChange={(checked) => {
|
|
88
|
-
updateConfig(identifier);
|
|
89
|
-
if (checked) {
|
|
90
|
-
fetchPluginManifest(identifier);
|
|
91
|
-
}
|
|
92
|
-
}}
|
|
93
|
-
/>
|
|
94
|
-
),
|
|
95
|
-
desc: pluginHelpers.getPluginDesc(meta),
|
|
96
|
-
label: pluginHelpers.getPluginTitle(meta),
|
|
97
|
-
minWidth: undefined,
|
|
98
|
-
tag: identifier,
|
|
99
|
-
}));
|
|
100
|
-
|
|
101
|
-
const pluginsConfig = !data
|
|
102
|
-
? []
|
|
103
|
-
: (plugins
|
|
104
|
-
.map((identifier) => {
|
|
105
|
-
const item = data.plugins.find((i) => i.identifier === identifier);
|
|
106
|
-
|
|
107
|
-
if (!item) return null;
|
|
108
|
-
const manifest = pluginManifestMap[identifier];
|
|
109
|
-
|
|
110
|
-
if (!manifest?.settings) return null;
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
children: transformPluginSettings(manifest.settings).map((item) => ({
|
|
114
|
-
...item,
|
|
115
|
-
children: (
|
|
116
|
-
<PluginSettingRender
|
|
117
|
-
defaultValue={pluginsSettings[identifier]?.[item.name]}
|
|
118
|
-
format={item.format}
|
|
119
|
-
onChange={(value) => {
|
|
120
|
-
updatePluginSettings(identifier, { [item.name]: value });
|
|
121
|
-
}}
|
|
122
|
-
type={item.type as any}
|
|
123
|
-
/>
|
|
124
|
-
),
|
|
125
|
-
desc: item.desc && <Markdown className={styles.md}>{item.desc}</Markdown>,
|
|
126
|
-
})),
|
|
127
|
-
icon: ToyBrick,
|
|
128
|
-
title: t('settingPlugin.config', { id: pluginHelpers.getPluginTitle(item.meta) }),
|
|
129
|
-
};
|
|
130
|
-
})
|
|
131
|
-
.filter(Boolean) as unknown as ItemGroup[]);
|
|
132
|
-
|
|
133
|
-
return (
|
|
134
|
-
<Form
|
|
135
|
-
items={[
|
|
136
|
-
{
|
|
137
|
-
children,
|
|
138
|
-
icon: LucideStore,
|
|
139
|
-
title: t('settingPlugin.title'),
|
|
140
|
-
},
|
|
141
|
-
...pluginsConfig,
|
|
142
|
-
]}
|
|
143
|
-
{...FORM_STYLE}
|
|
144
|
-
/>
|
|
145
|
-
);
|
|
146
|
-
});
|
|
6
|
+
const AgentPlugin = memo(() => (
|
|
7
|
+
<>
|
|
8
|
+
<MarketList />
|
|
9
|
+
<PluginSettings />
|
|
10
|
+
</>
|
|
11
|
+
));
|
|
147
12
|
|
|
148
13
|
export default AgentPlugin;
|