From ec527cb09a33d40d4a2a8305244e4a918124ffa8 Mon Sep 17 00:00:00 2001 From: arvinxx Date: Sat, 2 Sep 2023 18:43:11 +0800 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor(plugin):=20?= =?UTF-8?q?=E9=87=8D=E6=9E=84=20plugin=20Store=20=E7=BB=84=E7=BB=87?= =?UTF-8?q?=E7=BB=93=E6=9E=84=EF=BC=8C=E4=BE=BF=E4=BA=8E=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E4=B8=8E=E8=BF=AD=E4=BB=A3=E7=BB=B4=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AgentPlugin/LocalPluginItem.tsx | 2 +- .../AgentSetting/AgentPlugin/MarketList.tsx | 20 +++++--- src/features/PluginDevModal/MetaForm.tsx | 8 +--- src/features/PluginDevModal/PluginPreview.tsx | 4 +- src/features/PluginDevModal/index.tsx | 11 +++-- src/store/plugin/initialState.ts | 39 ++-------------- src/store/plugin/selectors.ts | 4 +- .../plugin/slices/customPlugin/action.ts | 46 +++++++++++++++++++ src/store/plugin/slices/customPlugin/index.ts | 3 ++ .../slices/customPlugin/initialState.ts | 16 +++++++ .../reducers/customPluginList.ts} | 12 ++--- .../plugin/{ => slices/plugin}/action.ts | 24 +--------- src/store/plugin/slices/plugin/index.ts | 3 ++ .../plugin/slices/plugin/initialState.ts | 22 +++++++++ .../{ => slices/plugin}/reducers/manifest.ts | 0 src/store/plugin/store.ts | 10 ++-- src/types/plugin.ts | 9 +++- 17 files changed, 142 insertions(+), 91 deletions(-) create mode 100644 src/store/plugin/slices/customPlugin/action.ts create mode 100644 src/store/plugin/slices/customPlugin/index.ts create mode 100644 src/store/plugin/slices/customPlugin/initialState.ts rename src/store/plugin/{reducers/devPluginList.ts => slices/customPlugin/reducers/customPluginList.ts} (78%) rename src/store/plugin/{ => slices/plugin}/action.ts (80%) create mode 100644 src/store/plugin/slices/plugin/index.ts create mode 100644 src/store/plugin/slices/plugin/initialState.ts rename src/store/plugin/{ => slices/plugin}/reducers/manifest.ts (100%) diff --git a/src/features/AgentSetting/AgentPlugin/LocalPluginItem.tsx b/src/features/AgentSetting/AgentPlugin/LocalPluginItem.tsx index 2e33ea11bc5d5..fc196eb495c80 100644 --- a/src/features/AgentSetting/AgentPlugin/LocalPluginItem.tsx +++ b/src/features/AgentSetting/AgentPlugin/LocalPluginItem.tsx @@ -20,7 +20,7 @@ const MarketList = memo<{ id: string }>(({ id }) => { const [useFetchPluginList, fetchPluginManifest, dispatchDevPluginList] = usePluginStore((s) => [ s.useFetchPluginList, s.fetchPluginManifest, - s.dispatchDevPluginList, + s.dispatchCustomPluginList, ]); const pluginManifestLoading = usePluginStore((s) => s.pluginManifestLoading, isEqual); diff --git a/src/features/AgentSetting/AgentPlugin/MarketList.tsx b/src/features/AgentSetting/AgentPlugin/MarketList.tsx index 8df9752de2522..a85347eafb5b4 100644 --- a/src/features/AgentSetting/AgentPlugin/MarketList.tsx +++ b/src/features/AgentSetting/AgentPlugin/MarketList.tsx @@ -41,19 +41,22 @@ const MarketList = memo(() => { // setModal(true); // }, []); - const updateConfig = useStore((s) => s.toggleAgentPlugin); - const [plugins, hasPlugin] = useStore((s) => [s.config.plugins || [], !!s.config.plugins]); + const [plugins, hasPlugin, toggleAgentPlugin] = useStore((s) => [ + s.config.plugins || [], + !!s.config.plugins, + s.toggleAgentPlugin, + ]); const [useFetchPluginList, fetchPluginManifest, saveToDevList, updateNewDevPlugin] = usePluginStore((s) => [ s.useFetchPluginList, s.fetchPluginManifest, - s.saveToDevList, + s.saveToCustomPluginList, s.updateNewDevPlugin, ]); const pluginManifestLoading = usePluginStore((s) => s.pluginManifestLoading, isEqual); const pluginList = usePluginStore((s) => s.pluginList, isEqual); - const devPluginList = usePluginStore((s) => s.devPluginList, isEqual); + const devPluginList = usePluginStore((s) => s.customPluginList, isEqual); useFetchPluginList(); @@ -92,7 +95,7 @@ const MarketList = memo(() => { } loading={pluginManifestLoading[identifier]} onChange={(checked) => { - updateConfig(identifier); + toggleAgentPlugin(identifier); if (checked) { fetchPluginManifest(identifier); } @@ -125,7 +128,12 @@ const MarketList = memo(() => { <> { + // 先保存 + saveToDevList(devPlugin); + // 再开启 + toggleAgentPlugin(devPlugin.identifier); + }} onValueChange={updateNewDevPlugin} open={showModal} /> diff --git a/src/features/PluginDevModal/MetaForm.tsx b/src/features/PluginDevModal/MetaForm.tsx index 69813692d5478..edf006717a9aa 100644 --- a/src/features/PluginDevModal/MetaForm.tsx +++ b/src/features/PluginDevModal/MetaForm.tsx @@ -1,6 +1,6 @@ import { Form, FormItemProps, Input } from '@lobehub/ui'; import { FormInstance } from 'antd'; -import { memo, useEffect } from 'react'; +import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import EmojiPicker from '@/components/EmojiPicker'; @@ -12,12 +12,6 @@ const MetaForm = memo<{ form: FormInstance; mode?: 'edit' | 'create' }>(({ form, const { t } = useTranslation('plugin'); const [plugins] = usePluginStore((s) => [pluginSelectors.pluginList(s).map((i) => i.identifier)]); - useEffect(() => { - if (usePluginStore.getState().newDevPlugin) { - form.setFieldsValue(usePluginStore.getState().newDevPlugin); - } - }, []); - const configItem: FormItemProps[] = [ { children: , diff --git a/src/features/PluginDevModal/PluginPreview.tsx b/src/features/PluginDevModal/PluginPreview.tsx index 78f1bc9edfe62..4b104b71b0520 100644 --- a/src/features/PluginDevModal/PluginPreview.tsx +++ b/src/features/PluginDevModal/PluginPreview.tsx @@ -5,11 +5,11 @@ import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import { pluginHelpers } from '@/store/plugin'; -import { DevPlugin } from '@/store/plugin/initialState'; +import { CustomPlugin } from '@/types/plugin'; const PluginPreview = memo<{ form: FormInstance }>(({ form }) => { const { t } = useTranslation('plugin'); - const plugin: DevPlugin = AForm.useWatch([], form); + const plugin: CustomPlugin = AForm.useWatch([], form); const items = { avatar: , diff --git a/src/features/PluginDevModal/index.tsx b/src/features/PluginDevModal/index.tsx index 91e5f57b2958b..09b2164181cb5 100644 --- a/src/features/PluginDevModal/index.tsx +++ b/src/features/PluginDevModal/index.tsx @@ -7,7 +7,7 @@ import { memo, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; -import { DevPlugin } from '@/store/plugin/initialState'; +import { CustomPlugin } from '@/types/plugin'; import ManifestForm from './ManifestForm'; import MetaForm from './MetaForm'; @@ -29,10 +29,10 @@ interface DevModalProps { mode?: 'edit' | 'create'; onDelete?: () => void; onOpenChange: (open: boolean) => void; - onSave?: (value: DevPlugin) => void; - onValueChange?: (value: Partial) => void; + onSave?: (value: CustomPlugin) => void; + onValueChange?: (value: Partial) => void; open?: boolean; - value?: DevPlugin; + value?: CustomPlugin; } const DevModal = memo( @@ -92,13 +92,14 @@ const DevModal = memo( ); + return ( { onValueChange?.(form.getFieldsValue()); }} onFormFinish={(_, info) => { - onSave?.(info.values as DevPlugin); + onSave?.(info.values as CustomPlugin); message.success(t(isEditMode ? 'dev.updateSuccess' : 'dev.saveSuccess')); onOpenChange(false); }} diff --git a/src/store/plugin/initialState.ts b/src/store/plugin/initialState.ts index 8777a7c91e9e7..cd606f01d3ef6 100644 --- a/src/store/plugin/initialState.ts +++ b/src/store/plugin/initialState.ts @@ -1,38 +1,9 @@ -import { LobeChatPluginManifest, LobeChatPluginMeta } from '@lobehub/chat-plugin-sdk'; +import { CustomPluginState, initialCustomPluginState } from './slices/customPlugin'; +import { PluginState, initialPluginState } from './slices/plugin'; -import { PluginManifestMap } from '@/types/plugin'; - -export type PluginManifestLoadingState = Record; -export type PluginsSettings = Record; - -export interface DevPlugin extends LobeChatPluginMeta { - apiMode: 'openapi' | 'simple'; - enableSettings: boolean; - manifestConfig?: LobeChatPluginManifest; - manifestMode: 'local' | 'url'; -} - -export interface PluginStoreState { - devPluginList: DevPlugin[]; - manifestPrepared: boolean; - newDevPlugin: Partial; - pluginList: LobeChatPluginMeta[]; - pluginManifestLoading: PluginManifestLoadingState; - pluginManifestMap: PluginManifestMap; - pluginsSettings: PluginsSettings; -} -export const defaultDevPlugin: Partial = { - apiMode: 'simple', - enableSettings: false, - manifestMode: 'url', -}; +export type PluginStoreState = PluginState & CustomPluginState; export const initialState: PluginStoreState = { - devPluginList: [], - manifestPrepared: false, - newDevPlugin: defaultDevPlugin, - pluginList: [], - pluginManifestLoading: {}, - pluginManifestMap: {}, - pluginsSettings: {}, + ...initialPluginState, + ...initialCustomPluginState, }; diff --git a/src/store/plugin/selectors.ts b/src/store/plugin/selectors.ts index d7b5f7c477263..4b9d934864577 100644 --- a/src/store/plugin/selectors.ts +++ b/src/store/plugin/selectors.ts @@ -23,13 +23,13 @@ const enabledSchema = ); }; -const pluginList = (s: PluginStoreState) => [...s.pluginList, ...s.devPluginList]; +const pluginList = (s: PluginStoreState) => [...s.pluginList, ...s.customPluginList]; const getPluginMetaById = (id: string) => (s: PluginStoreState) => pluginHelpers.getPluginFormList(pluginList(s), id); const getDevPluginById = (id: string) => (s: PluginStoreState) => - s.devPluginList.find((i) => i.identifier === id); + s.customPluginList.find((i) => i.identifier === id); const getPluginManifestById = (id: string) => (s: PluginStoreState) => s.pluginManifestMap[id]; const getPluginSettingsById = (id: string) => (s: PluginStoreState) => s.pluginsSettings[id]; diff --git a/src/store/plugin/slices/customPlugin/action.ts b/src/store/plugin/slices/customPlugin/action.ts new file mode 100644 index 0000000000000..552bc5e0afa0f --- /dev/null +++ b/src/store/plugin/slices/customPlugin/action.ts @@ -0,0 +1,46 @@ +import { merge } from 'lodash-es'; +import { StateCreator } from 'zustand/vanilla'; + +import { CustomPlugin } from '@/types/plugin'; +import { setNamespace } from '@/utils/storeDebug'; + +import { PluginStore } from '../../store'; +import { defaultCustomPlugin } from './initialState'; +import { CustomPluginListDispatch, devPluginListReducer } from './reducers/customPluginList'; + +const t = setNamespace('customPlugin'); + +/** + * 代理行为接口 + */ +export interface CustomPluginAction { + dispatchCustomPluginList: (payload: CustomPluginListDispatch) => void; + saveToCustomPluginList: (value: CustomPlugin) => void; + updateNewDevPlugin: (value: Partial) => void; +} + +export const createCustomPluginSlice: StateCreator< + PluginStore, + [['zustand/devtools', never]], + [], + CustomPluginAction +> = (set, get) => ({ + dispatchCustomPluginList: (payload) => { + const { customPluginList } = get(); + + const nextList = devPluginListReducer(customPluginList, payload); + set({ customPluginList: nextList }, false, t('dispatchDevList', payload)); + }, + saveToCustomPluginList: (value) => { + get().dispatchCustomPluginList({ plugin: value, type: 'addItem' }); + set({ newCustomPlugin: defaultCustomPlugin }, false, t('saveToDevList')); + }, + + updateNewDevPlugin: (newCustomPlugin) => { + set( + { newCustomPlugin: merge({}, get().newCustomPlugin, newCustomPlugin) }, + false, + t('updateNewDevPlugin'), + ); + }, +}); diff --git a/src/store/plugin/slices/customPlugin/index.ts b/src/store/plugin/slices/customPlugin/index.ts new file mode 100644 index 0000000000000..1d9afcc4054da --- /dev/null +++ b/src/store/plugin/slices/customPlugin/index.ts @@ -0,0 +1,3 @@ +export * from './action'; +export * from './initialState'; +// export * from './selectors'; diff --git a/src/store/plugin/slices/customPlugin/initialState.ts b/src/store/plugin/slices/customPlugin/initialState.ts new file mode 100644 index 0000000000000..4bafb9897af3f --- /dev/null +++ b/src/store/plugin/slices/customPlugin/initialState.ts @@ -0,0 +1,16 @@ +import { CustomPlugin } from '@/types/plugin'; + +export interface CustomPluginState { + customPluginList: CustomPlugin[]; + newCustomPlugin: Partial; +} +export const defaultCustomPlugin: Partial = { + apiMode: 'simple', + enableSettings: false, + manifestMode: 'url', +}; + +export const initialCustomPluginState: CustomPluginState = { + customPluginList: [], + newCustomPlugin: defaultCustomPlugin, +}; diff --git a/src/store/plugin/reducers/devPluginList.ts b/src/store/plugin/slices/customPlugin/reducers/customPluginList.ts similarity index 78% rename from src/store/plugin/reducers/devPluginList.ts rename to src/store/plugin/slices/customPlugin/reducers/customPluginList.ts index c6e364c19f72a..e863f4f7f673c 100644 --- a/src/store/plugin/reducers/devPluginList.ts +++ b/src/store/plugin/slices/customPlugin/reducers/customPluginList.ts @@ -1,11 +1,11 @@ import { produce } from 'immer'; -import { DevPlugin } from '../initialState'; +import { CustomPlugin } from '@/types/plugin'; -export type DevListState = DevPlugin[]; +export type DevListState = CustomPlugin[]; export type AddPluginAction = { - plugin: DevPlugin; + plugin: CustomPlugin; type: 'addItem'; }; @@ -16,15 +16,15 @@ export type DeletePluginAction = { export type UpdatePluginAction = { id: string; - plugin: DevPlugin; + plugin: CustomPlugin; type: 'updateItem'; }; -export type DevListDispatch = AddPluginAction | DeletePluginAction | UpdatePluginAction; +export type CustomPluginListDispatch = AddPluginAction | DeletePluginAction | UpdatePluginAction; export const devPluginListReducer = ( state: DevListState, - payload: DevListDispatch, + payload: CustomPluginListDispatch, ): DevListState => { switch (payload.type) { case 'addItem': { diff --git a/src/store/plugin/action.ts b/src/store/plugin/slices/plugin/action.ts similarity index 80% rename from src/store/plugin/action.ts rename to src/store/plugin/slices/plugin/action.ts index b1f6ecf89d903..b4c751ea90354 100644 --- a/src/store/plugin/action.ts +++ b/src/store/plugin/slices/plugin/action.ts @@ -14,10 +14,8 @@ import { pluginSelectors } from '@/store/plugin/selectors'; import { LobeSessions } from '@/types/session'; import { setNamespace } from '@/utils/storeDebug'; -import { DevPlugin, defaultDevPlugin } from './initialState'; -import { DevListDispatch, devPluginListReducer } from './reducers/devPluginList'; +import { PluginStore } from '../../store'; import { PluginDispatch, pluginManifestReducer } from './reducers/manifest'; -import { PluginStore } from './store'; const t = setNamespace('plugin'); @@ -26,12 +24,9 @@ const t = setNamespace('plugin'); */ export interface PluginAction { checkLocalEnabledPlugins: (sessions: LobeSessions) => void; - dispatchDevPluginList: (payload: DevListDispatch) => void; dispatchPluginManifest: (payload: PluginDispatch) => void; fetchPluginManifest: (name: string) => Promise; - saveToDevList: (value: DevPlugin) => void; updateManifestLoadingState: (key: string, value: boolean | undefined) => void; - updateNewDevPlugin: (value: Partial) => void; updatePluginSettings: (id: string, settings: Partial) => void; useFetchPluginList: () => SWRResponse; } @@ -60,12 +55,6 @@ export const createPluginSlice: StateCreator< set({ manifestPrepared: true }, false, t('checkLocalEnabledPlugins')); }, - dispatchDevPluginList: (payload) => { - const { devPluginList } = get(); - - const nextList = devPluginListReducer(devPluginList, payload); - set({ devPluginList: nextList }, false, t('dispatchDevList', payload)); - }, dispatchPluginManifest: (payload) => { const { pluginManifestMap } = get(); const nextManifest = pluginManifestReducer(pluginManifestMap, payload); @@ -113,10 +102,6 @@ export const createPluginSlice: StateCreator< // 4. 存储 manifest 信息 get().dispatchPluginManifest({ id: plugin.identifier, plugin: data, type: 'addManifest' }); }, - saveToDevList: (value) => { - get().dispatchDevPluginList({ plugin: value, type: 'addItem' }); - set({ newDevPlugin: defaultDevPlugin }, false, t('saveToDevList')); - }, updateManifestLoadingState: (key, value) => { set( @@ -127,13 +112,6 @@ export const createPluginSlice: StateCreator< t('updateManifestLoadingState'), ); }, - updateNewDevPlugin: (newDevPlugin) => { - set( - { newDevPlugin: merge({}, get().newDevPlugin, newDevPlugin) }, - false, - t('updateNewDevPlugin'), - ); - }, updatePluginSettings: (id, settings) => { set( produce((draft) => { diff --git a/src/store/plugin/slices/plugin/index.ts b/src/store/plugin/slices/plugin/index.ts new file mode 100644 index 0000000000000..1d9afcc4054da --- /dev/null +++ b/src/store/plugin/slices/plugin/index.ts @@ -0,0 +1,3 @@ +export * from './action'; +export * from './initialState'; +// export * from './selectors'; diff --git a/src/store/plugin/slices/plugin/initialState.ts b/src/store/plugin/slices/plugin/initialState.ts new file mode 100644 index 0000000000000..4794dabea43fd --- /dev/null +++ b/src/store/plugin/slices/plugin/initialState.ts @@ -0,0 +1,22 @@ +import { LobeChatPluginMeta } from '@lobehub/chat-plugin-sdk'; + +import { PluginManifestMap } from '@/types/plugin'; + +export type PluginManifestLoadingState = Record; +export type PluginsSettings = Record; + +export interface PluginState { + manifestPrepared: boolean; + pluginList: LobeChatPluginMeta[]; + pluginManifestLoading: PluginManifestLoadingState; + pluginManifestMap: PluginManifestMap; + pluginsSettings: PluginsSettings; +} + +export const initialPluginState: PluginState = { + manifestPrepared: false, + pluginList: [], + pluginManifestLoading: {}, + pluginManifestMap: {}, + pluginsSettings: {}, +}; diff --git a/src/store/plugin/reducers/manifest.ts b/src/store/plugin/slices/plugin/reducers/manifest.ts similarity index 100% rename from src/store/plugin/reducers/manifest.ts rename to src/store/plugin/slices/plugin/reducers/manifest.ts diff --git a/src/store/plugin/store.ts b/src/store/plugin/store.ts index bb93acad76e23..9b5c4c9d7027d 100644 --- a/src/store/plugin/store.ts +++ b/src/store/plugin/store.ts @@ -5,23 +5,25 @@ import { StateCreator } from 'zustand/vanilla'; import { isDev } from '@/utils/env'; -import { PluginAction, createPluginSlice } from './action'; import { PluginStoreState, initialState } from './initialState'; +import { CustomPluginAction, createCustomPluginSlice } from './slices/customPlugin'; +import { PluginAction, createPluginSlice } from './slices/plugin'; // =============== 聚合 createStoreFn ============ // -export type PluginStore = PluginStoreState & PluginAction; +export type PluginStore = PluginStoreState & CustomPluginAction & PluginAction; const createStore: StateCreator = (...parameters) => ({ ...initialState, ...createPluginSlice(...parameters), + ...createCustomPluginSlice(...parameters), }); // =============== persist 本地缓存中间件配置 ============ // type SessionPersist = Pick< PluginStore, - 'pluginList' | 'pluginManifestMap' | 'pluginsSettings' | 'devPluginList' + 'pluginList' | 'pluginManifestMap' | 'pluginsSettings' | 'customPluginList' >; const storeName = 'LOBE_PLUGIN'; @@ -30,7 +32,7 @@ const persistOptions: PersistOptions = { name: storeName, partialize: (s) => ({ - devPluginList: s.devPluginList, + customPluginList: s.customPluginList, pluginList: s.pluginList, pluginManifestMap: s.pluginManifestMap, pluginsSettings: s.pluginsSettings, diff --git a/src/types/plugin.ts b/src/types/plugin.ts index 38e2639873a5d..4a20b4e1909e9 100644 --- a/src/types/plugin.ts +++ b/src/types/plugin.ts @@ -1,3 +1,10 @@ -import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk'; +import { LobeChatPluginManifest, LobeChatPluginMeta } from '@lobehub/chat-plugin-sdk'; export type PluginManifestMap = Record; + +export interface CustomPlugin extends LobeChatPluginMeta { + apiMode: 'openapi' | 'simple'; + enableSettings: boolean; + manifestConfig?: LobeChatPluginManifest; + manifestMode: 'local' | 'url'; +}