@lobehub/chat 0.82.9 → 0.83.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 +25 -0
- package/locales/en_US/error.json +2 -1
- package/locales/en_US/plugin.json +1 -0
- package/locales/en_US/setting.json +2 -1
- package/locales/ru_RU/error.json +2 -1
- package/locales/ru_RU/plugin.json +1 -0
- package/locales/ru_RU/setting.json +2 -1
- package/locales/zh_CN/error.json +1 -0
- package/locales/zh_CN/plugin.json +2 -1
- package/locales/zh_CN/setting.json +2 -1
- package/locales/zh_TW/error.json +2 -1
- package/locales/zh_TW/plugin.json +1 -0
- package/locales/zh_TW/setting.json +2 -1
- package/package.json +6 -5
- package/src/app/chat/components/SessionList/List/Item/index.tsx +2 -2
- package/src/app/home/index.tsx +15 -11
- package/src/app/layout.tsx +4 -1
- package/src/app/settings/agent/Agent.tsx +3 -3
- package/src/app/settings/agent/index.tsx +1 -0
- package/src/app/settings/common/Common.tsx +109 -117
- package/src/app/settings/features/SideBar/List.tsx +11 -5
- package/src/app/settings/llm/LLM/index.tsx +2 -2
- package/src/config/client.ts +13 -0
- package/src/const/locale.ts +9 -0
- package/src/const/settings.ts +1 -1
- package/src/const/url.ts +1 -6
- package/src/helpers/export.ts +2 -2
- package/src/layout/GlobalLayout/Locale.tsx +44 -0
- package/src/layout/GlobalLayout/LocaleLoading.tsx +21 -0
- package/src/layout/GlobalLayout/StoreHydration.tsx +28 -0
- package/src/layout/GlobalLayout/index.tsx +29 -41
- package/src/locales/create.ts +43 -26
- package/src/locales/default/setting.ts +2 -1
- package/src/locales/options.ts +6 -5
- package/src/services/agentMarket.ts +6 -4
- package/src/services/pluginMarket.ts +2 -2
- package/src/store/global/hooks/useSwitchSettingsOnInit.ts +5 -2
- package/src/store/global/{selectors.test.ts → selectors/settings.test.ts} +11 -11
- package/src/store/global/selectors/settings.ts +44 -0
- package/src/store/global/selectors.ts +1 -36
- package/src/store/global/slices/common.ts +3 -4
- package/src/types/locale.ts +4 -0
- package/src/types/settings.ts +2 -2
- package/src/utils/env.ts +2 -0
- package/src/utils/responsive.ts +1 -1
- package/src/utils/switchLang.ts +5 -1
- package/src/layout/GlobalLayout/style.ts +0 -18
- /package/src/{components/AppTheme/index.tsx → layout/GlobalLayout/AppTheme.tsx} +0 -0
package/src/config/client.ts
CHANGED
|
@@ -21,6 +21,10 @@ declare global {
|
|
|
21
21
|
NEXT_PUBLIC_POSTHOG_KEY: string;
|
|
22
22
|
NEXT_PUBLIC_POSTHOG_HOST: string;
|
|
23
23
|
NEXT_PUBLIC_POSTHOG_DEBUG: string;
|
|
24
|
+
|
|
25
|
+
NEXT_PUBLIC_I18N_DEBUG: string;
|
|
26
|
+
NEXT_PUBLIC_I18N_DEBUG_BROWSER: string;
|
|
27
|
+
NEXT_PUBLIC_I18N_DEBUG_SERVER: string;
|
|
24
28
|
}
|
|
25
29
|
}
|
|
26
30
|
}
|
|
@@ -29,18 +33,27 @@ export const getClientConfig = () => ({
|
|
|
29
33
|
AGENTS_INDEX_URL: process.env.AGENTS_INDEX_URL,
|
|
30
34
|
PLUGINS_INDEX_URL: process.env.PLUGINS_INDEX_URL,
|
|
31
35
|
|
|
36
|
+
// Vercel Analytics
|
|
32
37
|
ANALYTICS_VERCEL: process.env.NEXT_PUBLIC_ANALYTICS_VERCEL !== '0',
|
|
33
38
|
VERCEL_DEBUG: process.env.NEXT_PUBLIC_VERCEL_DEBUG === '1',
|
|
34
39
|
|
|
40
|
+
// Plausible Analytics
|
|
35
41
|
ANALYTICS_PLAUSIBLE: process.env.NEXT_PUBLIC_ANALYTICS_PLAUSIBLE === '1',
|
|
36
42
|
PLAUSIBLE_DOMAIN: process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN,
|
|
37
43
|
|
|
44
|
+
// Mixpanel Analytics
|
|
38
45
|
ANALYTICS_MIXPANEL: process.env.NEXT_PUBLIC_ANALYTICS_MIXPANEL === '1',
|
|
39
46
|
MIXPANEL_PROJECT_TOKEN: process.env.NEXT_PUBLIC_MIXPANEL_PROJECT_TOKEN,
|
|
40
47
|
MIXPANEL_DEBUG: process.env.NEXT_PUBLIC_MIXPANEL_DEBUG === '1',
|
|
41
48
|
|
|
49
|
+
// Posthog Analytics
|
|
42
50
|
ANALYTICS_POSTHOG: process.env.NEXT_PUBLIC_ANALYTICS_POSTHOG === '1',
|
|
43
51
|
POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY,
|
|
44
52
|
POSTHOG_HOST: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
|
45
53
|
POSTHOG_DEBUG: process.env.NEXT_PUBLIC_POSTHOG_DEBUG === '1',
|
|
54
|
+
|
|
55
|
+
// i18n debug mode
|
|
56
|
+
I18N_DEBUG: process.env.NEXT_PUBLIC_I18N_DEBUG === '1',
|
|
57
|
+
I18N_DEBUG_BROWSER: process.env.NEXT_PUBLIC_I18N_DEBUG_BROWSER === '1',
|
|
58
|
+
I18N_DEBUG_SERVER: process.env.NEXT_PUBLIC_I18N_DEBUG_SERVER === '1',
|
|
46
59
|
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { localeOptions } from '@/locales/options';
|
|
2
|
+
import { Locales } from '@/locales/resources';
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_LANG = 'en-US';
|
|
5
|
+
export const LOBE_LOCALE_COOKIE = 'LOBE_LOCALE';
|
|
6
|
+
|
|
7
|
+
export const checkLang = (lang: Locales) => {
|
|
8
|
+
return lang === DEFAULT_LANG || !localeOptions.map((o) => o.value).includes(lang);
|
|
9
|
+
};
|
package/src/const/settings.ts
CHANGED
package/src/const/url.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import urlJoin from 'url-join';
|
|
2
2
|
|
|
3
3
|
import { getClientConfig } from '@/config/client';
|
|
4
|
-
import { localeOptions } from '@/locales/options';
|
|
5
4
|
import { Locales } from '@/locales/resources';
|
|
6
5
|
|
|
7
6
|
import pkg from '../../package.json';
|
|
7
|
+
import { DEFAULT_LANG, checkLang } from './locale';
|
|
8
8
|
import { INBOX_SESSION_ID } from './session';
|
|
9
9
|
|
|
10
10
|
export const GITHUB = pkg.homepage;
|
|
@@ -16,11 +16,6 @@ export const DISCORD = 'https://discord.gg/AYFPHvv2jT';
|
|
|
16
16
|
export const PLUGINS_INDEX_URL =
|
|
17
17
|
getClientConfig().PLUGINS_INDEX_URL ?? 'https://chat-plugins.lobehub.com';
|
|
18
18
|
|
|
19
|
-
export const DEFAULT_LANG = 'en-US';
|
|
20
|
-
|
|
21
|
-
export const checkLang = (lang: Locales) => {
|
|
22
|
-
return lang === DEFAULT_LANG || !localeOptions.map((o) => o.value).includes(lang);
|
|
23
|
-
};
|
|
24
19
|
export const getPluginIndexJSON = (lang: Locales = DEFAULT_LANG, baseUrl = PLUGINS_INDEX_URL) => {
|
|
25
20
|
if (checkLang(lang)) return baseUrl;
|
|
26
21
|
|
package/src/helpers/export.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { settingsSelectors, useGlobalStore } from '@/store/global';
|
|
2
2
|
import { useSessionStore } from '@/store/session';
|
|
3
3
|
import { sessionSelectors } from '@/store/session/selectors';
|
|
4
4
|
import { createConfigFile, exportConfigFile } from '@/utils/config';
|
|
@@ -6,7 +6,7 @@ import { createConfigFile, exportConfigFile } from '@/utils/config';
|
|
|
6
6
|
const getSessions = () => sessionSelectors.exportSessions(useSessionStore.getState());
|
|
7
7
|
const getSession = (id: string) => sessionSelectors.getSessionById(id)(useSessionStore.getState());
|
|
8
8
|
|
|
9
|
-
const getSettings = () =>
|
|
9
|
+
const getSettings = () => settingsSelectors.exportSettings(useGlobalStore.getState());
|
|
10
10
|
|
|
11
11
|
// ============= 导出所有角色 ============= //
|
|
12
12
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ConfigProvider } from 'antd';
|
|
2
|
+
import Zh_CN from 'antd/locale/zh_CN';
|
|
3
|
+
import { PropsWithChildren, memo, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
import { createI18nNext } from '@/locales/create';
|
|
6
|
+
import { useOnFinishHydrationGlobal } from '@/store/global';
|
|
7
|
+
import { isOnServerSide } from '@/utils/env';
|
|
8
|
+
import { switchLang } from '@/utils/switchLang';
|
|
9
|
+
|
|
10
|
+
interface LocaleLayoutProps extends PropsWithChildren {
|
|
11
|
+
lang?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const InnerLocale = memo<LocaleLayoutProps>(({ children, lang }) => {
|
|
15
|
+
const [i18n] = useState(createI18nNext(lang));
|
|
16
|
+
|
|
17
|
+
// if run on server side, init i18n instance everytime
|
|
18
|
+
if (isOnServerSide) {
|
|
19
|
+
i18n.init();
|
|
20
|
+
} else {
|
|
21
|
+
// if on browser side, init i18n instance only once
|
|
22
|
+
if (!i18n.instance.isInitialized)
|
|
23
|
+
// console.log('locale', lang);
|
|
24
|
+
i18n.init().then(() => {
|
|
25
|
+
// console.log('inited.');
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
useOnFinishHydrationGlobal((s) => {
|
|
30
|
+
if (s.settings.language === 'auto') {
|
|
31
|
+
switchLang('auto');
|
|
32
|
+
}
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
35
|
+
return <ConfigProvider locale={Zh_CN}>{children}</ConfigProvider>;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// const Locale = memo<LocaleLayoutProps>((props) => (
|
|
39
|
+
// <Suspense fallback={<Loading />}>
|
|
40
|
+
// <InnerLocale {...props} />
|
|
41
|
+
// </Suspense>
|
|
42
|
+
// ));
|
|
43
|
+
|
|
44
|
+
export default InnerLocale;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Icon } from '@lobehub/ui';
|
|
2
|
+
import { Loader2 } from 'lucide-react';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { Center } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
const Loading = memo(() => (
|
|
7
|
+
<div
|
|
8
|
+
style={{
|
|
9
|
+
backdropFilter: 'blur(3px)',
|
|
10
|
+
height: '100vh',
|
|
11
|
+
width: '100vw',
|
|
12
|
+
zIndex: 100,
|
|
13
|
+
}}
|
|
14
|
+
>
|
|
15
|
+
<Center flex={1} gap={12} width={'100%'}>
|
|
16
|
+
<Icon icon={Loader2} spin />
|
|
17
|
+
</Center>
|
|
18
|
+
</div>
|
|
19
|
+
));
|
|
20
|
+
|
|
21
|
+
export default Loading;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useRouter } from 'next/navigation';
|
|
2
|
+
import { memo, useEffect } from 'react';
|
|
3
|
+
|
|
4
|
+
import { useGlobalStore } from '@/store/global';
|
|
5
|
+
import { usePluginStore } from '@/store/plugin';
|
|
6
|
+
import { useOnFinishHydrationSession, useSessionStore } from '@/store/session';
|
|
7
|
+
|
|
8
|
+
const StoreHydration = memo(() => {
|
|
9
|
+
const router = useRouter();
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
// refs: https://github.com/pmndrs/zustand/blob/main/docs/integrations/persisting-store-data.md#hashydrated
|
|
13
|
+
useSessionStore.persist.rehydrate();
|
|
14
|
+
useGlobalStore.persist.rehydrate();
|
|
15
|
+
usePluginStore.persist.rehydrate();
|
|
16
|
+
}, []);
|
|
17
|
+
|
|
18
|
+
useOnFinishHydrationSession((s, store) => {
|
|
19
|
+
usePluginStore.getState().checkLocalEnabledPlugins(s.sessions);
|
|
20
|
+
|
|
21
|
+
// add router instance to store
|
|
22
|
+
store.setState({ router });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return null;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export default StoreHydration;
|
|
@@ -1,56 +1,44 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { App
|
|
3
|
+
import { App } from 'antd';
|
|
4
|
+
import { createStyles } from 'antd-style';
|
|
4
5
|
import 'antd/dist/reset.css';
|
|
5
|
-
import
|
|
6
|
-
import { useRouter } from 'next/navigation';
|
|
7
|
-
import { PropsWithChildren, memo, useEffect } from 'react';
|
|
6
|
+
import { PropsWithChildren, memo } from 'react';
|
|
8
7
|
|
|
9
|
-
import AppTheme, { AppThemeProps } from '
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import { usePluginStore } from '@/store/plugin';
|
|
13
|
-
import { useOnFinishHydrationSession, useSessionStore } from '@/store/session';
|
|
14
|
-
import { switchLang } from '@/utils/switchLang';
|
|
8
|
+
import AppTheme, { AppThemeProps } from './AppTheme';
|
|
9
|
+
import Locale from './Locale';
|
|
10
|
+
import StoreHydration from './StoreHydration';
|
|
15
11
|
|
|
16
|
-
|
|
12
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
13
|
+
bg: css`
|
|
14
|
+
overflow-y: scroll;
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
align-items: center;
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
height: 100%;
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const router = useRouter();
|
|
24
|
-
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
// refs: https://github.com/pmndrs/zustand/blob/main/docs/integrations/persisting-store-data.md#hashydrated
|
|
27
|
-
useSessionStore.persist.rehydrate();
|
|
28
|
-
useGlobalStore.persist.rehydrate();
|
|
29
|
-
usePluginStore.persist.rehydrate();
|
|
30
|
-
}, []);
|
|
31
|
-
|
|
32
|
-
useOnFinishHydrationGlobal((state) => {
|
|
33
|
-
i18n.then(() => switchLang(state.settings.language));
|
|
34
|
-
});
|
|
21
|
+
background: ${token.colorBgLayout};
|
|
22
|
+
`,
|
|
23
|
+
}));
|
|
35
24
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// add router instance to store
|
|
40
|
-
store.setState({ router });
|
|
41
|
-
});
|
|
25
|
+
const Container = memo<PropsWithChildren>(({ children }) => {
|
|
26
|
+
const { styles } = useStyles();
|
|
42
27
|
|
|
43
|
-
return
|
|
44
|
-
<ConfigProvider locale={Zh_CN}>
|
|
45
|
-
<App className={styles.bg}>{children}</App>
|
|
46
|
-
</ConfigProvider>
|
|
47
|
-
);
|
|
28
|
+
return <App className={styles.bg}>{children}</App>;
|
|
48
29
|
});
|
|
49
30
|
|
|
50
|
-
|
|
31
|
+
interface GlobalLayoutProps extends AppThemeProps {
|
|
32
|
+
defaultLang?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const GlobalLayout = ({ children, defaultLang, ...theme }: GlobalLayoutProps) => (
|
|
51
36
|
<AppTheme {...theme}>
|
|
52
|
-
<
|
|
37
|
+
<Locale lang={defaultLang}>
|
|
38
|
+
<StoreHydration />
|
|
39
|
+
<Container>{children}</Container>
|
|
40
|
+
</Locale>
|
|
53
41
|
</AppTheme>
|
|
54
42
|
);
|
|
55
43
|
|
|
56
|
-
export default
|
|
44
|
+
export default GlobalLayout;
|
package/src/locales/create.ts
CHANGED
|
@@ -1,36 +1,53 @@
|
|
|
1
1
|
import i18n from 'i18next';
|
|
2
2
|
import LanguageDetector from 'i18next-browser-languagedetector';
|
|
3
|
-
import { isArray } from 'lodash-es';
|
|
4
3
|
import { initReactI18next } from 'react-i18next';
|
|
5
4
|
|
|
5
|
+
import { getClientConfig } from '@/config/client';
|
|
6
|
+
import { DEFAULT_LANG, LOBE_LOCALE_COOKIE } from '@/const/locale';
|
|
7
|
+
import resources from '@/locales/resources';
|
|
6
8
|
import type { Namespaces } from '@/types/locale';
|
|
9
|
+
import { isOnServerSide } from '@/utils/env';
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
const { I18N_DEBUG, I18N_DEBUG_BROWSER, I18N_DEBUG_SERVER } = getClientConfig();
|
|
12
|
+
const debugMode = I18N_DEBUG ?? isOnServerSide ? I18N_DEBUG_SERVER : I18N_DEBUG_BROWSER;
|
|
9
13
|
|
|
10
|
-
const
|
|
14
|
+
export const createI18nNext = (lang?: string) => {
|
|
15
|
+
const ns: Namespaces[] = [
|
|
16
|
+
'error',
|
|
17
|
+
'common',
|
|
18
|
+
'empty',
|
|
19
|
+
'error',
|
|
20
|
+
'market',
|
|
21
|
+
'plugin',
|
|
22
|
+
'setting',
|
|
23
|
+
'welcome',
|
|
24
|
+
];
|
|
11
25
|
|
|
12
|
-
|
|
13
|
-
|
|
26
|
+
const instance = i18n.use(initReactI18next).use(LanguageDetector);
|
|
27
|
+
// not find a good way to handle suspense loading
|
|
28
|
+
// .use(
|
|
29
|
+
// resourcesToBackend(
|
|
30
|
+
// isDev ? resources : (lng: string, ns: string) => import(`../../locales/${lng}/${ns}.json`),
|
|
31
|
+
// ),
|
|
32
|
+
// )
|
|
14
33
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
resources,
|
|
35
|
-
});
|
|
34
|
+
return {
|
|
35
|
+
init: () =>
|
|
36
|
+
instance.init({
|
|
37
|
+
debug: debugMode,
|
|
38
|
+
defaultNS: ['error', 'common'],
|
|
39
|
+
detection: {
|
|
40
|
+
caches: ['cookie'],
|
|
41
|
+
lookupCookie: LOBE_LOCALE_COOKIE,
|
|
42
|
+
},
|
|
43
|
+
fallbackLng: DEFAULT_LANG,
|
|
44
|
+
interpolation: {
|
|
45
|
+
escapeValue: false,
|
|
46
|
+
},
|
|
47
|
+
lng: lang,
|
|
48
|
+
ns,
|
|
49
|
+
resources,
|
|
50
|
+
}),
|
|
51
|
+
instance,
|
|
52
|
+
};
|
|
36
53
|
};
|
package/src/locales/options.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import type { SelectProps } from 'antd';
|
|
2
1
|
|
|
3
2
|
import type { Locales } from '@/types/locale';
|
|
4
3
|
|
|
5
|
-
type LocaleOptions =
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
type LocaleOptions = {
|
|
5
|
+
label: string;
|
|
6
|
+
value: Locales;
|
|
7
|
+
}[];
|
|
9
8
|
|
|
10
9
|
export const localeOptions: LocaleOptions = [
|
|
11
10
|
{
|
|
@@ -25,3 +24,5 @@ export const localeOptions: LocaleOptions = [
|
|
|
25
24
|
value: 'ru-RU',
|
|
26
25
|
},
|
|
27
26
|
] as LocaleOptions;
|
|
27
|
+
|
|
28
|
+
export const supportLangs: string[] = localeOptions.map((i) => i.value);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useGlobalStore } from '@/store/global';
|
|
1
|
+
import { getAgentJSON } from '@/const/url';
|
|
2
|
+
import { settingsSelectors, useGlobalStore } from '@/store/global';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* 请求助手列表
|
|
6
6
|
*/
|
|
7
7
|
export const getAgentList = async () => {
|
|
8
|
-
const res = await fetch(
|
|
8
|
+
const res = await fetch(settingsSelectors.currentLanguage(useGlobalStore.getState()));
|
|
9
9
|
|
|
10
10
|
return res.json();
|
|
11
11
|
};
|
|
@@ -15,7 +15,9 @@ export const getAgentList = async () => {
|
|
|
15
15
|
*/
|
|
16
16
|
export const getAgentManifest = async (identifier?: string) => {
|
|
17
17
|
if (!identifier) return;
|
|
18
|
-
const res = await fetch(
|
|
18
|
+
const res = await fetch(
|
|
19
|
+
getAgentJSON(identifier, settingsSelectors.currentLanguage(useGlobalStore.getState())),
|
|
20
|
+
);
|
|
19
21
|
|
|
20
22
|
return res.json();
|
|
21
23
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { getPluginIndexJSON } from '@/const/url';
|
|
2
|
-
import { useGlobalStore } from '@/store/global';
|
|
2
|
+
import { settingsSelectors, useGlobalStore } from '@/store/global';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* fetch Plugin Market List
|
|
6
6
|
*/
|
|
7
7
|
export const getPluginList = async () => {
|
|
8
|
-
const url = getPluginIndexJSON(useGlobalStore.getState()
|
|
8
|
+
const url = getPluginIndexJSON(settingsSelectors.currentLanguage(useGlobalStore.getState()));
|
|
9
9
|
|
|
10
10
|
const res = await fetch(url);
|
|
11
11
|
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import { useOnFinishHydrationGlobal } from '@/store/global';
|
|
2
|
+
|
|
1
3
|
import { SettingsTabs } from '../initialState';
|
|
2
|
-
import { useGlobalStore } from '../store';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* 切换设置侧边栏选项
|
|
6
7
|
*/
|
|
7
8
|
export const useSwitchSideBarOnInit = (key: SettingsTabs) => {
|
|
8
|
-
|
|
9
|
+
useOnFinishHydrationGlobal((store) => {
|
|
10
|
+
store.switchSettingTabs(key);
|
|
11
|
+
});
|
|
9
12
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { LanguageModel } from '@/types/llm';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { GlobalStore } from '../store';
|
|
4
|
+
import { settingsSelectors } from './settings';
|
|
5
5
|
|
|
6
|
-
describe('
|
|
6
|
+
describe('settingsSelectors', () => {
|
|
7
7
|
describe('currentSettings', () => {
|
|
8
8
|
it('should merge DEFAULT_SETTINGS and s.settings correctly', () => {
|
|
9
9
|
const s = {
|
|
@@ -36,7 +36,7 @@ describe('globalSelectors', () => {
|
|
|
36
36
|
},
|
|
37
37
|
} as unknown as GlobalStore;
|
|
38
38
|
|
|
39
|
-
const result =
|
|
39
|
+
const result = settingsSelectors.currentSettings(s);
|
|
40
40
|
|
|
41
41
|
expect(result).toEqual({
|
|
42
42
|
avatar: 'avatar.jpg',
|
|
@@ -93,7 +93,7 @@ describe('globalSelectors', () => {
|
|
|
93
93
|
// },
|
|
94
94
|
// };
|
|
95
95
|
//
|
|
96
|
-
// const result =
|
|
96
|
+
// const result = settingsSelectors.defaultAgent(s);
|
|
97
97
|
//
|
|
98
98
|
//
|
|
99
99
|
//
|
|
@@ -114,9 +114,9 @@ describe('globalSelectors', () => {
|
|
|
114
114
|
// },
|
|
115
115
|
// };
|
|
116
116
|
//
|
|
117
|
-
// const result =
|
|
117
|
+
// const result = settingsSelectors.defaultAgentConfig(s);
|
|
118
118
|
//
|
|
119
|
-
// const defaultAgent =
|
|
119
|
+
// const defaultAgent = settingsSelectors.defaultAgent(s);
|
|
120
120
|
// const expected = merge({}, DEFAULT_AGENT_CONFIG, defaultAgent.config);
|
|
121
121
|
//
|
|
122
122
|
// expect(result).toEqual(expected);
|
|
@@ -136,9 +136,9 @@ describe('globalSelectors', () => {
|
|
|
136
136
|
// },
|
|
137
137
|
// };
|
|
138
138
|
//
|
|
139
|
-
// const result =
|
|
139
|
+
// const result = settingsSelectors.defaultAgentMeta(s);
|
|
140
140
|
//
|
|
141
|
-
// const defaultAgent =
|
|
141
|
+
// const defaultAgent = settingsSelectors.defaultAgent(s);
|
|
142
142
|
// const expected = merge({}, DEFAULT_AGENT_META, defaultAgent.meta);
|
|
143
143
|
//
|
|
144
144
|
// expect(result).toEqual(expected);
|
|
@@ -183,7 +183,7 @@ describe('globalSelectors', () => {
|
|
|
183
183
|
// },
|
|
184
184
|
// };
|
|
185
185
|
//
|
|
186
|
-
// const result =
|
|
186
|
+
// const result = settingsSelectors.exportSettings(s);
|
|
187
187
|
//
|
|
188
188
|
// const expected = {
|
|
189
189
|
// avatar: 'avatar.jpg',
|
|
@@ -255,7 +255,7 @@ describe('globalSelectors', () => {
|
|
|
255
255
|
// },
|
|
256
256
|
// };
|
|
257
257
|
//
|
|
258
|
-
// const result =
|
|
258
|
+
// const result = settingsSelectors.exportSettings(s);
|
|
259
259
|
//
|
|
260
260
|
// expect(result).toBeInstanceOf(GlobalSettings);
|
|
261
261
|
// });
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { DEFAULT_AGENT_META } from '@/const/meta';
|
|
2
|
+
import { DEFAULT_AGENT, DEFAULT_AGENT_CONFIG, DEFAULT_SETTINGS } from '@/const/settings';
|
|
3
|
+
import { Locales } from '@/locales/resources';
|
|
4
|
+
import { GlobalSettings } from '@/types/settings';
|
|
5
|
+
import { merge } from '@/utils/merge';
|
|
6
|
+
|
|
7
|
+
import { GlobalStore } from '../store';
|
|
8
|
+
|
|
9
|
+
const currentSettings = (s: GlobalStore) => merge(DEFAULT_SETTINGS, s.settings);
|
|
10
|
+
|
|
11
|
+
const defaultAgent = (s: GlobalStore) => merge(DEFAULT_AGENT, s.settings.defaultAgent);
|
|
12
|
+
|
|
13
|
+
const defaultAgentConfig = (s: GlobalStore) => merge(DEFAULT_AGENT_CONFIG, defaultAgent(s).config);
|
|
14
|
+
|
|
15
|
+
const defaultAgentMeta = (s: GlobalStore) => merge(DEFAULT_AGENT_META, defaultAgent(s).meta);
|
|
16
|
+
|
|
17
|
+
const openAIAPIKeySelectors = (s: GlobalStore) =>
|
|
18
|
+
s.settings.languageModel.openAI.OPENAI_API_KEY || s.settings.OPENAI_API_KEY;
|
|
19
|
+
|
|
20
|
+
export const exportSettings = (s: GlobalStore) => {
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
22
|
+
const { OPENAI_API_KEY: _, password: __, ...settings } = s.settings;
|
|
23
|
+
|
|
24
|
+
return settings as GlobalSettings;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const currentLanguage = (s: GlobalStore) => {
|
|
28
|
+
const locale = s.settings.language;
|
|
29
|
+
if (locale === 'auto') {
|
|
30
|
+
return navigator.language as Locales;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return locale;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const settingsSelectors = {
|
|
37
|
+
currentLanguage,
|
|
38
|
+
currentSettings,
|
|
39
|
+
defaultAgent,
|
|
40
|
+
defaultAgentConfig,
|
|
41
|
+
defaultAgentMeta,
|
|
42
|
+
exportSettings,
|
|
43
|
+
openAIAPI: openAIAPIKeySelectors,
|
|
44
|
+
};
|
|
@@ -1,36 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { DEFAULT_AGENT, DEFAULT_AGENT_CONFIG, DEFAULT_SETTINGS } from '@/const/settings';
|
|
3
|
-
import { GlobalSettings } from '@/types/settings';
|
|
4
|
-
import { merge } from '@/utils/merge';
|
|
5
|
-
|
|
6
|
-
import { GlobalStore } from './store';
|
|
7
|
-
|
|
8
|
-
const currentSettings = (s: GlobalStore) => merge(DEFAULT_SETTINGS, s.settings);
|
|
9
|
-
|
|
10
|
-
const defaultAgent = (s: GlobalStore) => merge(DEFAULT_AGENT, s.settings.defaultAgent);
|
|
11
|
-
|
|
12
|
-
const defaultAgentConfig = (s: GlobalStore) => merge(DEFAULT_AGENT_CONFIG, defaultAgent(s).config);
|
|
13
|
-
|
|
14
|
-
const defaultAgentMeta = (s: GlobalStore) => merge(DEFAULT_AGENT_META, defaultAgent(s).meta);
|
|
15
|
-
|
|
16
|
-
const openAIAPIKeySelectors = (s: GlobalStore) =>
|
|
17
|
-
s.settings.languageModel.openAI.OPENAI_API_KEY || s.settings.OPENAI_API_KEY;
|
|
18
|
-
|
|
19
|
-
export const exportSettings = (s: GlobalStore) => {
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
21
|
-
const { OPENAI_API_KEY: _, password: __, ...settings } = s.settings;
|
|
22
|
-
|
|
23
|
-
return settings as GlobalSettings;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export const globalSelectors = {
|
|
27
|
-
currentSettings,
|
|
28
|
-
defaultAgent,
|
|
29
|
-
defaultAgentConfig,
|
|
30
|
-
defaultAgentMeta,
|
|
31
|
-
exportSettings,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export const settingsSelectors = {
|
|
35
|
-
openAIAPI: openAIAPIKeySelectors,
|
|
36
|
-
};
|
|
1
|
+
export * from './selectors/settings';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { produce } from 'immer';
|
|
2
|
-
import { merge } from 'lodash-es';
|
|
3
2
|
import type { StateCreator } from 'zustand/vanilla';
|
|
4
3
|
|
|
4
|
+
import { merge } from '@/utils/merge';
|
|
5
5
|
import { setNamespace } from '@/utils/storeDebug';
|
|
6
6
|
|
|
7
7
|
import type { GlobalPreference, GlobalState, Guide, SidebarTabKey } from '../initialState';
|
|
@@ -47,14 +47,13 @@ export const createCommonSlice: StateCreator<
|
|
|
47
47
|
},
|
|
48
48
|
updateGuideState: (guide) => {
|
|
49
49
|
const { updatePreference } = get();
|
|
50
|
-
const nextGuide = merge(
|
|
50
|
+
const nextGuide = merge(get().preference.guide, guide);
|
|
51
51
|
updatePreference({ guide: nextGuide });
|
|
52
52
|
},
|
|
53
|
-
|
|
54
53
|
updatePreference: (preference, action) => {
|
|
55
54
|
set(
|
|
56
55
|
produce((draft: GlobalState) => {
|
|
57
|
-
draft.preference = merge(
|
|
56
|
+
draft.preference = merge(draft.preference, preference);
|
|
58
57
|
}),
|
|
59
58
|
false,
|
|
60
59
|
action,
|
package/src/types/locale.ts
CHANGED
package/src/types/settings.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { NeutralColors, PrimaryColors } from '@lobehub/ui';
|
|
2
2
|
import type { ThemeMode } from 'antd-style';
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import { LocaleMode } from '@/types/locale';
|
|
5
5
|
import type { LobeAgentSession } from '@/types/session';
|
|
6
6
|
|
|
7
7
|
export interface GlobalBaseSettings {
|
|
@@ -36,7 +36,7 @@ export interface GlobalBaseSettings {
|
|
|
36
36
|
* @deprecated
|
|
37
37
|
*/
|
|
38
38
|
historyCount?: number;
|
|
39
|
-
language:
|
|
39
|
+
language: LocaleMode;
|
|
40
40
|
neutralColor?: NeutralColors;
|
|
41
41
|
password: string;
|
|
42
42
|
primaryColor?: PrimaryColors;
|
package/src/utils/env.ts
CHANGED