Skip to content

Commit

Permalink
✨ feat: 支持渲染 manifest 中的 settings
Browse files Browse the repository at this point in the history
  • Loading branch information
arvinxx committed Aug 24, 2023
1 parent 0551d45 commit 1185300
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 59 deletions.
30 changes: 30 additions & 0 deletions src/features/AgentSetting/AgentPlugin/PluginSettingRender.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// import { Input } from '@lobehub/ui';
import { Input, InputNumber, Switch } from 'antd';
import { memo } from 'react';

interface PluginSettingsProps {
format?: string;
props?: any;
type?: 'string' | 'number' | 'boolean';
}

const PluginSettingRender = memo<PluginSettingsProps>(({ type, format, props }) => {
switch (type) {
case 'string': {
switch (format) {
case 'password': {
return <Input.Password {...props} />;
}
}
return <Input {...props} />;
}
case 'number': {
return <InputNumber {...props} />;
}
case 'boolean': {
return <Switch {...props} />;
}
}
});

export default PluginSettingRender;
158 changes: 99 additions & 59 deletions src/features/AgentSetting/AgentPlugin/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { Avatar, Form, ItemGroup } from '@lobehub/ui';
import { Avatar, Form, ItemGroup, Markdown } from '@lobehub/ui';
import { Skeleton, Switch } from 'antd';
import { createStyles } from 'antd-style';
import isEqual from 'fast-deep-equal';
import { ToyBrick } from 'lucide-react';
import { memo, useMemo } from 'react';
import { LucideStore, ToyBrick } from 'lucide-react';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';

import { FORM_STYLE } from '@/const/layoutTokens';
import { usePluginStore } from '@/store/plugin';
import { AgentAction } from '@/store/session/slices/agentConfig';
import { useSessionStore } from '@/store/session';
import { AgentAction, agentSelectors } from '@/store/session/slices/agentConfig';
import { LobeAgentConfig } from '@/types/session';

const useStyles = createStyles(({ css }) => ({
import PluginSettingRender from './PluginSettingRender';

const useStyles = createStyles(({ css, token }) => ({
avatar: css`
.ant-skeleton-header {
padding-right: 0;
Expand All @@ -26,6 +29,11 @@ const useStyles = createStyles(({ css }) => ({
margin-block-start: 12px !important;
}
`,
md: css`
p {
color: ${token.colorTextDescription};
}
`,
}));

export interface AgentPluginProps {
Expand All @@ -41,67 +49,99 @@ const AgentPlugin = memo<AgentPluginProps>(({ config, updateConfig }) => {
s.fetchPluginManifest,
]);
const pluginManifestLoading = usePluginStore((s) => s.pluginManifestLoading, isEqual);
const pluginManifestMap = usePluginStore((s) => s.pluginManifestMap, isEqual);
const { data } = useFetchPluginList();

const plugin: ItemGroup = useMemo(() => {
let children;
const plugins = useSessionStore(agentSelectors.currentAgentPlugins);

const loadingItem = {
avatar: (
<Skeleton
active
avatar={{ size: 40 }}
className={styles.avatar}
paragraph={false}
title={false}
/>
),
label: (
<Skeleton
active
avatar={false}
paragraph={{ className: styles.label, style: { marginBottom: 0 } }}
style={{ width: 300 }}
title={false}
/>
),
};
const loadingItem = {
avatar: (
<Skeleton
active
avatar={{ size: 40 }}
className={styles.avatar}
paragraph={false}
title={false}
/>
),
label: (
<Skeleton
active
avatar={false}
paragraph={{ className: styles.label, style: { marginBottom: 0 } }}
style={{ width: 300 }}
title={false}
/>
),
};

children = !data
? [loadingItem, loadingItem, loadingItem]
: data.plugins.map((item) => ({
avatar: <Avatar avatar={item.meta.avatar} />,
children: (
<Switch
checked={
// 如果在加载中,说明激活了
pluginManifestLoading[item.identifier] || !config.plugins
? false
: config.plugins.includes(item.identifier)
const children = !data
? [loadingItem, loadingItem, loadingItem]
: data.plugins.map(({ identifier, meta }) => ({
avatar: <Avatar avatar={meta.avatar} />,
children: (
<Switch
checked={
// 如果在加载中,说明激活了
pluginManifestLoading[identifier] || !config.plugins
? false
: config.plugins.includes(identifier)
}
loading={pluginManifestLoading[identifier]}
onChange={(checked) => {
updateConfig(identifier, checked);
if (checked) {
fetchPluginManifest(identifier);
}
loading={pluginManifestLoading[item.identifier]}
onChange={(checked) => {
updateConfig(item.identifier, checked);
if (checked) {
fetchPluginManifest(item.identifier);
}
}}
/>
),
desc: item.meta?.description,
label: t(`plugins.${item.identifier}` as any, { ns: 'plugin' }),
minWidth: undefined,
tag: item.identifier,
}));
}}
/>
),
desc: meta?.description,
label: meta.title,
minWidth: undefined,
tag: identifier,
}));

const pluginsConfig = !data
? []
: (plugins
.map((identifier) => {
const item = data.plugins.find((i) => i.identifier === identifier);

if (!item) return null;
const manifest = pluginManifestMap[identifier];

if (!manifest.settings) return null;

return {
children,
icon: ToyBrick,
title: t('settingPlugin.title'),
};
}, [config, data?.plugins, pluginManifestLoading]);
return {
// children: [],
children: Object.entries(manifest.settings.properties).map(([name, i]) => ({
children: <PluginSettingRender format={i.format} type={i.type as any} />,
desc: i.description && <Markdown className={styles.md}>{i.description}</Markdown>,
label: i.title,
name,
tag: name,
})),
icon: ToyBrick,
// icon: <Avatar avatar={item.meta.avatar} />,
title: t('settingPlugin.config', { id: item.meta.title || item.identifier }),
};
})
.filter(Boolean) as unknown as ItemGroup[]);

return <Form items={[plugin]} {...FORM_STYLE} />;
return (
<Form
items={[
{
children,
icon: LucideStore,
title: t('settingPlugin.title'),
},
...pluginsConfig,
]}
{...FORM_STYLE}
/>
);
});

export default AgentPlugin;
1 change: 1 addition & 0 deletions src/locales/default/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export default {
},
},
settingPlugin: {
config: '{{id}} 插件配置',
title: '插件列表',
},
settingSystem: {
Expand Down

0 comments on commit 1185300

Please sign in to comment.