@lobehub/chat 0.58.0 → 0.59.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 +26 -0
- package/package.json +1 -1
- package/src/features/AgentSetting/AgentPlugin/index.tsx +4 -4
- package/src/locales/default/common.ts +1 -0
- package/src/pages/chat/features/Conversation/ChatList/Error/Plugin/PluginSettings.tsx +7 -5
- package/src/pages/chat/features/Conversation/ChatList/Plugins/CustomRender.tsx +6 -4
- package/src/pages/chat/features/Header/PluginTag.tsx +40 -14
- package/src/store/plugin/helpers.ts +26 -0
- package/src/store/plugin/index.ts +1 -0
- package/src/store/plugin/selectors.ts +30 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 0.59.0](https://github.com/lobehub/lobe-chat/compare/v0.58.0...v0.59.0)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-08-26**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **misc**: 支持展示插件插件状态, 支持插件 i18n 模式展示.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **misc**: 支持展示插件插件状态 ([7e916ac](https://github.com/lobehub/lobe-chat/commit/7e916ac))
|
|
21
|
+
- **misc**: 支持插件 i18n 模式展示 ([8614734](https://github.com/lobehub/lobe-chat/commit/8614734))
|
|
22
|
+
|
|
23
|
+
</details>
|
|
24
|
+
|
|
25
|
+
<div align="right">
|
|
26
|
+
|
|
27
|
+
[](#readme-top)
|
|
28
|
+
|
|
29
|
+
</div>
|
|
30
|
+
|
|
5
31
|
## [Version 0.58.0](https://github.com/lobehub/lobe-chat/compare/v0.57.0...v0.58.0)
|
|
6
32
|
|
|
7
33
|
<sup>Released on **2023-08-26**</sup>
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
9
9
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
10
10
|
import { transformPluginSettings } from '@/features/PluginSettings';
|
|
11
11
|
import PluginSettingRender from '@/features/PluginSettings/PluginSettingRender';
|
|
12
|
-
import { usePluginStore } from '@/store/plugin';
|
|
12
|
+
import { pluginHelpers, usePluginStore } from '@/store/plugin';
|
|
13
13
|
import { useSessionStore } from '@/store/session';
|
|
14
14
|
import { AgentAction, agentSelectors } from '@/store/session/slices/agentConfig';
|
|
15
15
|
import { LobeAgentConfig } from '@/types/session';
|
|
@@ -98,8 +98,8 @@ const AgentPlugin = memo<AgentPluginProps>(({ config, updateConfig }) => {
|
|
|
98
98
|
}}
|
|
99
99
|
/>
|
|
100
100
|
),
|
|
101
|
-
desc: meta
|
|
102
|
-
label: meta
|
|
101
|
+
desc: pluginHelpers.getPluginDesc(meta),
|
|
102
|
+
label: pluginHelpers.getPluginTitle(meta),
|
|
103
103
|
minWidth: undefined,
|
|
104
104
|
tag: identifier,
|
|
105
105
|
}));
|
|
@@ -131,7 +131,7 @@ const AgentPlugin = memo<AgentPluginProps>(({ config, updateConfig }) => {
|
|
|
131
131
|
desc: item.desc && <Markdown className={styles.md}>{item.desc}</Markdown>,
|
|
132
132
|
})),
|
|
133
133
|
icon: ToyBrick,
|
|
134
|
-
title: t('settingPlugin.config', { id: item.meta
|
|
134
|
+
title: t('settingPlugin.config', { id: pluginHelpers.getPluginTitle(item.meta) }),
|
|
135
135
|
};
|
|
136
136
|
})
|
|
137
137
|
.filter(Boolean) as unknown as ItemGroup[]);
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Avatar } from '@lobehub/ui';
|
|
2
2
|
import { Button, Divider } from 'antd';
|
|
3
3
|
import { useTheme } from 'antd-style';
|
|
4
|
+
import isEqual from 'fast-deep-equal';
|
|
4
5
|
import { memo } from 'react';
|
|
5
6
|
import { useTranslation } from 'react-i18next';
|
|
6
7
|
import { Center, Flexbox } from 'react-layout-kit';
|
|
7
8
|
|
|
8
9
|
import PluginSettingsConfig from '@/features/PluginSettings';
|
|
9
|
-
import { pluginSelectors, usePluginStore } from '@/store/plugin';
|
|
10
|
+
import { pluginHelpers, pluginSelectors, usePluginStore } from '@/store/plugin';
|
|
10
11
|
import { useSessionStore } from '@/store/session';
|
|
11
12
|
|
|
12
13
|
import { ErrorActionContainer, useStyles } from '../style';
|
|
@@ -22,20 +23,21 @@ const PluginSettings = memo<PluginSettingsProps>(({ id, pluginIdentifier }) => {
|
|
|
22
23
|
const { t } = useTranslation('error');
|
|
23
24
|
const theme = useTheme();
|
|
24
25
|
const [resend, deleteMessage] = useSessionStore((s) => [s.resendMessage, s.deleteMessage]);
|
|
25
|
-
|
|
26
|
-
const
|
|
26
|
+
|
|
27
|
+
const plugin = usePluginStore(pluginSelectors.getPluginMetaById(pluginIdentifier), isEqual);
|
|
28
|
+
const manifest = usePluginStore(pluginSelectors.getPluginManifestById(pluginIdentifier), isEqual);
|
|
27
29
|
|
|
28
30
|
return (
|
|
29
31
|
<ErrorActionContainer>
|
|
30
32
|
<Center gap={16} style={{ maxWidth: 400 }}>
|
|
31
33
|
<Avatar
|
|
32
|
-
avatar={plugin?.meta
|
|
34
|
+
avatar={pluginHelpers.getPluginAvatar(plugin?.meta) || '⚙️'}
|
|
33
35
|
background={theme.colorFillContent}
|
|
34
36
|
gap={12}
|
|
35
37
|
size={80}
|
|
36
38
|
/>
|
|
37
39
|
<Flexbox style={{ fontSize: 20 }}>
|
|
38
|
-
{t('pluginSettings.title', { name: plugin?.meta
|
|
40
|
+
{t('pluginSettings.title', { name: pluginHelpers.getPluginTitle(plugin?.meta) })}
|
|
39
41
|
</Flexbox>
|
|
40
42
|
<Flexbox className={styles.desc}>{t('pluginSettings.desc')}</Flexbox>
|
|
41
43
|
<Divider style={{ margin: '0 16px' }} />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PluginRender, PluginRenderProps } from '@lobehub/chat-plugin-sdk';
|
|
2
2
|
import { Skeleton } from 'antd';
|
|
3
|
-
import { memo, useState } from 'react';
|
|
3
|
+
import { memo, useEffect, useState } from 'react';
|
|
4
4
|
|
|
5
5
|
import { system } from './dynamticLoader';
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ interface CustomRenderProps extends PluginRenderProps {
|
|
|
10
10
|
const CustomRender = memo<CustomRenderProps>(({ url, ...props }) => {
|
|
11
11
|
const [component, setComp] = useState<PluginRender | null>(null);
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
useEffect(() => {
|
|
14
14
|
system
|
|
15
15
|
.import(url)
|
|
16
16
|
.then((module1) => {
|
|
@@ -21,12 +21,14 @@ const CustomRender = memo<CustomRenderProps>(({ url, ...props }) => {
|
|
|
21
21
|
setComp(null);
|
|
22
22
|
console.error(error);
|
|
23
23
|
});
|
|
24
|
+
}, [url]);
|
|
24
25
|
|
|
26
|
+
if (!component) {
|
|
25
27
|
return <Skeleton active style={{ width: 300 }} />;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
const
|
|
30
|
+
const Render = component;
|
|
29
31
|
|
|
30
|
-
return <
|
|
32
|
+
return <Render {...props} />;
|
|
31
33
|
});
|
|
32
34
|
export default CustomRender;
|
|
@@ -1,33 +1,59 @@
|
|
|
1
|
-
import { Avatar, Icon, Tag } from '@lobehub/ui';
|
|
1
|
+
import { ActionIcon, Avatar, Icon, Tag } from '@lobehub/ui';
|
|
2
2
|
import type { MenuProps } from 'antd';
|
|
3
|
-
import { Dropdown } from 'antd';
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
3
|
+
import { Badge, Dropdown } from 'antd';
|
|
4
|
+
import isEqual from 'fast-deep-equal';
|
|
5
|
+
import { LucideRotateCw, LucideToyBrick } from 'lucide-react';
|
|
6
|
+
import { memo, useMemo } from 'react';
|
|
6
7
|
import { useTranslation } from 'react-i18next';
|
|
8
|
+
import { Flexbox } from 'react-layout-kit';
|
|
7
9
|
|
|
8
|
-
import { usePluginStore } from '@/store/plugin';
|
|
10
|
+
import { pluginHelpers, pluginSelectors, usePluginStore } from '@/store/plugin';
|
|
11
|
+
|
|
12
|
+
const PluginStatus = memo<{ id: string; title?: string }>(({ title, id }) => {
|
|
13
|
+
const { t } = useTranslation('common');
|
|
14
|
+
const status = usePluginStore(pluginSelectors.getPluginManifestLoadingStatus(id));
|
|
15
|
+
|
|
16
|
+
const renderStatus = useMemo(() => {
|
|
17
|
+
switch (status) {
|
|
18
|
+
case 'loading': {
|
|
19
|
+
return <Badge color={'blue'} status={'processing'} />;
|
|
20
|
+
}
|
|
21
|
+
case 'error': {
|
|
22
|
+
return <ActionIcon icon={LucideRotateCw} size={'small'} title={t('retry')} />;
|
|
23
|
+
}
|
|
24
|
+
case 'success': {
|
|
25
|
+
return <Badge status={status} />;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}, [status]);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Flexbox gap={12} horizontal justify={'space-between'}>
|
|
32
|
+
{title} {renderStatus}
|
|
33
|
+
</Flexbox>
|
|
34
|
+
);
|
|
35
|
+
});
|
|
9
36
|
|
|
10
37
|
export interface PluginTagProps {
|
|
11
38
|
plugins: string[];
|
|
12
39
|
}
|
|
13
40
|
|
|
14
41
|
const PluginTag = memo<PluginTagProps>(({ plugins }) => {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
const list = usePluginStore((s) => s.pluginList);
|
|
42
|
+
const list = usePluginStore(pluginSelectors.displayPluginList);
|
|
43
|
+
const displayPlugin = usePluginStore(pluginSelectors.getPluginMetaById(plugins[0]), isEqual);
|
|
18
44
|
|
|
19
45
|
if (plugins.length === 0) return null;
|
|
20
46
|
|
|
21
47
|
const items: MenuProps['items'] = plugins.map((id) => {
|
|
22
|
-
const item = list
|
|
48
|
+
const item = list.find((i) => i.identifier === id);
|
|
49
|
+
|
|
23
50
|
return {
|
|
24
|
-
icon:
|
|
25
|
-
<Avatar avatar={item?.meta.avatar} size={24} style={{ marginLeft: -6, marginRight: 2 }} />
|
|
26
|
-
),
|
|
51
|
+
icon: <Avatar avatar={item?.avatar} size={24} style={{ marginLeft: -6, marginRight: 2 }} />,
|
|
27
52
|
key: id,
|
|
28
|
-
label:
|
|
53
|
+
label: <PluginStatus id={id} title={item?.title} />,
|
|
29
54
|
};
|
|
30
55
|
});
|
|
56
|
+
|
|
31
57
|
const count = plugins.length;
|
|
32
58
|
|
|
33
59
|
return (
|
|
@@ -35,7 +61,7 @@ const PluginTag = memo<PluginTagProps>(({ plugins }) => {
|
|
|
35
61
|
<div>
|
|
36
62
|
<Tag>
|
|
37
63
|
{<Icon icon={LucideToyBrick} />}
|
|
38
|
-
{
|
|
64
|
+
{pluginHelpers.getPluginTitle(displayPlugin?.meta)}
|
|
39
65
|
{count > 1 && <div>({plugins.length - 1}+)</div>}
|
|
40
66
|
</Tag>
|
|
41
67
|
</div>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { LobeChatPluginMeta } from '@lobehub/chat-plugin-sdk';
|
|
2
|
+
import i18n from 'i18next';
|
|
3
|
+
|
|
4
|
+
const getI18nValue = (value: string | Record<string, string> | undefined) => {
|
|
5
|
+
if (!value) return;
|
|
6
|
+
|
|
7
|
+
if (typeof value === 'string') return value;
|
|
8
|
+
|
|
9
|
+
if (value[i18n.language]) return value[i18n.language];
|
|
10
|
+
|
|
11
|
+
return Object.values(value)[0];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const getPluginFormList = (pluginList: LobeChatPluginMeta[], id: string) =>
|
|
15
|
+
pluginList?.find((p) => p.identifier === id);
|
|
16
|
+
|
|
17
|
+
const getPluginTitle = (meta?: LobeChatPluginMeta['meta']) => getI18nValue(meta?.title);
|
|
18
|
+
const getPluginDesc = (meta?: LobeChatPluginMeta['meta']) => getI18nValue(meta?.description);
|
|
19
|
+
const getPluginAvatar = (meta?: LobeChatPluginMeta['meta']) => meta?.avatar;
|
|
20
|
+
|
|
21
|
+
export const pluginHelpers = {
|
|
22
|
+
getPluginAvatar,
|
|
23
|
+
getPluginDesc,
|
|
24
|
+
getPluginFormList,
|
|
25
|
+
getPluginTitle,
|
|
26
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PLUGIN_SCHEMA_SEPARATOR } from '@/const/plugin';
|
|
2
|
+
import { pluginHelpers } from '@/store/plugin/helpers';
|
|
2
3
|
|
|
3
4
|
import { PluginStoreState } from './initialState';
|
|
4
5
|
|
|
@@ -23,13 +24,38 @@ const enabledSchema =
|
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
const getPluginMetaById = (id: string) => (s: PluginStoreState) =>
|
|
26
|
-
s.pluginList
|
|
27
|
+
pluginHelpers.getPluginFormList(s.pluginList, id);
|
|
27
28
|
|
|
28
|
-
const
|
|
29
|
-
|
|
29
|
+
const getPluginManifestById = (id: string) => (s: PluginStoreState) => s.pluginManifestMap[id];
|
|
30
|
+
const getPluginSettingsById = (id: string) => (s: PluginStoreState) => s.pluginsSettings[id];
|
|
31
|
+
|
|
32
|
+
// 获取插件 manifest 加载状态
|
|
33
|
+
const getPluginManifestLoadingStatus = (id: string) => (s: PluginStoreState) => {
|
|
34
|
+
const manifest = getPluginManifestById(id);
|
|
35
|
+
|
|
36
|
+
if (s.pluginManifestLoading[id]) return 'loading';
|
|
37
|
+
|
|
38
|
+
if (!manifest) return 'error';
|
|
39
|
+
|
|
40
|
+
if (!!manifest) return 'success';
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const displayPluginList = (s: PluginStoreState) =>
|
|
44
|
+
s.pluginList.map((p) => ({
|
|
45
|
+
author: p.author,
|
|
46
|
+
avatar: p.meta?.avatar,
|
|
47
|
+
createAt: p.createAt,
|
|
48
|
+
desc: pluginHelpers.getPluginDesc(p.meta),
|
|
49
|
+
homepage: p.homepage,
|
|
50
|
+
identifier: p.identifier,
|
|
51
|
+
title: pluginHelpers.getPluginTitle(p.meta),
|
|
52
|
+
}));
|
|
30
53
|
|
|
31
54
|
export const pluginSelectors = {
|
|
55
|
+
displayPluginList,
|
|
32
56
|
enabledSchema,
|
|
33
|
-
|
|
57
|
+
getPluginManifestById,
|
|
58
|
+
getPluginManifestLoadingStatus,
|
|
34
59
|
getPluginMetaById,
|
|
60
|
+
getPluginSettingsById,
|
|
35
61
|
};
|