@lobehub/lobehub 2.0.0-next.343 → 2.0.0-next.345
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/.cursor/rules/i18n.mdc +1 -1
- package/.cursor/rules/modal-imperative.mdc +162 -0
- package/.cursor/rules/rules-index.mdc +1 -0
- package/.env.example +0 -14
- package/.eslintrc.js +8 -1
- package/CHANGELOG.md +66 -0
- package/Dockerfile +3 -13
- package/README.md +3 -5
- package/README.zh-CN.md +3 -5
- package/changelog/v1.json +24 -0
- package/docs/self-hosting/advanced/auth/clerk-to-betterauth.mdx +11 -42
- package/docs/self-hosting/advanced/auth/clerk-to-betterauth.zh-CN.mdx +10 -41
- package/e2e/src/support/webServer.ts +2 -0
- package/locales/ar/error.json +0 -4
- package/locales/bg-BG/error.json +0 -4
- package/locales/de-DE/error.json +0 -4
- package/locales/en-US/error.json +0 -4
- package/locales/es-ES/error.json +0 -4
- package/locales/fa-IR/error.json +0 -4
- package/locales/fr-FR/error.json +0 -4
- package/locales/it-IT/error.json +0 -4
- package/locales/ja-JP/error.json +0 -4
- package/locales/ko-KR/error.json +0 -4
- package/locales/nl-NL/error.json +0 -4
- package/locales/pl-PL/error.json +0 -4
- package/locales/pt-BR/error.json +0 -4
- package/locales/ru-RU/error.json +0 -4
- package/locales/tr-TR/error.json +0 -4
- package/locales/vi-VN/error.json +0 -4
- package/locales/zh-CN/error.json +0 -4
- package/locales/zh-TW/error.json +0 -4
- package/package.json +7 -9
- package/packages/builtin-agents/package.json +2 -0
- package/packages/builtin-agents/src/agents/agent-builder/index.ts +4 -2
- package/packages/builtin-agents/src/agents/group-agent-builder/index.ts +4 -2
- package/packages/builtin-agents/src/agents/page-agent/index.ts +5 -2
- package/packages/builtin-tool-cloud-sandbox/src/ExecutionRuntime/index.ts +161 -12
- package/packages/context-engine/src/engine/messages/MessagesEngine.ts +9 -9
- package/packages/context-engine/src/providers/GroupContextInjector.ts +19 -33
- package/packages/context-engine/src/providers/__tests__/GroupContextInjector.test.ts +79 -43
- package/packages/context-engine/src/providers/__tests__/__snapshots__/GroupContextInjector.test.ts.snap +5 -15
- package/packages/database/src/repositories/userMemory/__tests__/UserMemoryTopicRepository.test.ts +24 -3
- package/packages/model-bank/src/modelProviders/comfyui.ts +0 -1
- package/packages/model-bank/src/modelProviders/fal.ts +0 -1
- package/packages/types/src/fetch.ts +1 -2
- package/packages/utils/src/server/__tests__/auth.test.ts +0 -47
- package/packages/utils/src/server/auth.ts +1 -9
- package/scripts/_shared/checkDeprecatedClerkEnv.js +42 -0
- package/scripts/changelogWorkflow/buildStaticChangelog.ts +2 -1
- package/scripts/clerk-to-betterauth/_internal/types.ts +53 -20
- package/scripts/clerk-to-betterauth/export-clerk-users-with-api.ts +43 -36
- package/scripts/countEnWord.ts +1 -1
- package/scripts/electronWorkflow/modifiers/appCode.mts +2 -131
- package/scripts/i18nWorkflow/protectedPatterns.ts +1 -2
- package/scripts/prebuild.mts +10 -8
- package/scripts/serverLauncher/startServer.js +23 -5
- package/src/app/(backend)/middleware/auth/index.test.ts +8 -4
- package/src/app/(backend)/middleware/auth/index.ts +0 -15
- package/src/app/(backend)/middleware/auth/utils.test.ts +0 -28
- package/src/app/(backend)/middleware/auth/utils.ts +2 -17
- package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +3 -51
- package/src/app/(backend)/webapi/models/[provider]/route.test.ts +8 -4
- package/src/app/[variants]/(auth)/next-auth/signin/AuthSignInBox.tsx +7 -6
- package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -16
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/index.tsx +1 -1
- package/src/app/[variants]/(main)/home/features/InputArea/SkillInstallBanner.tsx +13 -13
- package/src/app/[variants]/(main)/home/features/RecentPage/Item.tsx +2 -2
- package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +3 -21
- package/src/app/[variants]/(main)/settings/profile/features/AvatarRow.tsx +1 -2
- package/src/app/[variants]/(main)/settings/security/index.tsx +1 -22
- package/src/app/[variants]/(main)/settings/skill/features/KlavisSkillItem.tsx +12 -14
- package/src/app/[variants]/(main)/settings/skill/features/LobehubSkillItem.tsx +8 -14
- package/src/app/[variants]/(main)/settings/skill/index.tsx +7 -5
- package/src/app/[variants]/(mobile)/me/(home)/__tests__/UserBanner.test.tsx +2 -35
- package/src/app/[variants]/(mobile)/me/(home)/__tests__/useCategory.test.tsx +0 -20
- package/src/app/[variants]/(mobile)/me/(home)/features/UserBanner.tsx +1 -2
- package/src/app/[variants]/(mobile)/me/profile/features/Category.tsx +3 -13
- package/src/app/[variants]/(mobile)/settings/_layout/Header.tsx +2 -3
- package/src/app/[variants]/share/t/[id]/_layout/index.tsx +1 -1
- package/src/app/[variants]/share/t/[id]/index.tsx +1 -1
- package/src/app/robots.tsx +1 -1
- package/src/envs/auth.ts +2 -27
- package/src/envs/llm.ts +2 -2
- package/src/features/AgentSetting/AgentPlugin/index.tsx +9 -12
- package/src/features/ChatInput/ActionBar/Tools/index.tsx +7 -5
- package/src/features/ChatMiniMap/utils.ts +1 -1
- package/src/features/CommandMenu/SearchResults.tsx +1 -1
- package/src/features/Conversation/ChatList/components/AutoScroll/DebugInspector.tsx +166 -0
- package/src/features/Conversation/ChatList/components/AutoScroll/index.tsx +86 -0
- package/src/features/Conversation/ChatList/components/VirtualizedList.tsx +11 -17
- package/src/features/Conversation/Messages/AgentCouncil/components/AutoScrollShadow.tsx +25 -14
- package/src/features/Conversation/Messages/AgentCouncil/components/CouncilMember.tsx +1 -1
- package/src/features/IntegrationDetailModal/IntegrationDetailContent.tsx +305 -0
- package/src/features/IntegrationDetailModal/index.tsx +21 -283
- package/src/features/MCPPluginDetail/Deployment/index.tsx +1 -1
- package/src/features/MCPPluginDetail/Schema/Prompts.tsx +1 -1
- package/src/features/MCPPluginDetail/Schema/Tools.tsx +1 -1
- package/src/features/ProfileEditor/AgentTool.tsx +14 -20
- package/src/features/ResourceManager/components/Explorer/MasonryView/MasonryFileItem/NoteFileItem.tsx +1 -1
- package/src/features/SkillStore/LobeHubList/index.tsx +50 -87
- package/src/features/SkillStore/Search/index.tsx +1 -1
- package/src/features/SkillStore/{Content.tsx → SkillStoreContent.tsx} +3 -8
- package/src/features/SkillStore/index.tsx +15 -33
- package/src/features/User/UserPanel/PanelContent.tsx +0 -8
- package/src/features/User/__tests__/PanelContent.test.tsx +1 -35
- package/src/features/User/__tests__/UserAvatar.test.tsx +30 -57
- package/src/features/User/__tests__/useMenu.test.tsx +2 -43
- package/src/layout/AuthProvider/index.tsx +0 -5
- package/src/libs/next/config/define-config.ts +6 -0
- package/src/libs/next/proxy/createRouteMatcher.test.ts +121 -0
- package/src/libs/next/proxy/createRouteMatcher.ts +18 -0
- package/src/libs/next/proxy/define-config.ts +4 -53
- package/src/libs/next-auth/adapter/index.ts +1 -2
- package/src/libs/oidc-provider/provider.test.ts +5 -316
- package/src/libs/trpc/lambda/context.test.ts +0 -13
- package/src/libs/trpc/lambda/context.ts +3 -22
- package/src/libs/trpc/middleware/userAuth.ts +2 -4
- package/src/libs/trusted-client/getSessionUser.ts +2 -17
- package/src/locales/default/error.ts +0 -6
- package/src/locales/default/index.ts +0 -2
- package/src/proxy.ts +0 -1
- package/src/server/routers/lambda/__tests__/user.test.ts +0 -71
- package/src/server/routers/lambda/user.ts +6 -63
- package/src/server/services/changelog/index.test.ts +3 -2
- package/src/server/services/changelog/index.ts +1 -1
- package/src/server/services/user/index.ts +0 -83
- package/src/services/chat/index.ts +1 -2
- package/src/services/chat/mecha/agentConfigResolver.test.ts +43 -0
- package/src/services/chat/mecha/agentConfigResolver.ts +3 -1
- package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +58 -14
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +10 -2
- package/src/store/user/slices/auth/action.test.ts +1 -81
- package/src/store/user/slices/auth/action.ts +3 -28
- package/src/store/user/slices/auth/initialState.ts +1 -18
- package/src/store/user/slices/auth/selectors.test.ts +2 -127
- package/src/store/user/slices/auth/selectors.ts +1 -21
- package/src/utils/errorResponse.ts +1 -4
- package/src/utils/markdownToTxt.ts +20 -0
- package/locales/ar/clerk.json +0 -545
- package/locales/bg-BG/clerk.json +0 -545
- package/locales/de-DE/clerk.json +0 -545
- package/locales/en-US/clerk.json +0 -545
- package/locales/es-ES/clerk.json +0 -545
- package/locales/fa-IR/clerk.json +0 -545
- package/locales/fr-FR/clerk.json +0 -545
- package/locales/it-IT/clerk.json +0 -545
- package/locales/ja-JP/clerk.json +0 -545
- package/locales/ko-KR/clerk.json +0 -545
- package/locales/nl-NL/clerk.json +0 -545
- package/locales/pl-PL/clerk.json +0 -545
- package/locales/pt-BR/clerk.json +0 -545
- package/locales/ru-RU/clerk.json +0 -545
- package/locales/tr-TR/clerk.json +0 -545
- package/locales/vi-VN/clerk.json +0 -545
- package/locales/zh-CN/clerk.json +0 -545
- package/locales/zh-TW/clerk.json +0 -545
- package/src/app/(backend)/api/webhooks/clerk/__tests__/fixtures/createUser.json +0 -73
- package/src/app/(backend)/api/webhooks/clerk/route.ts +0 -95
- package/src/app/(backend)/api/webhooks/clerk/validateRequest.ts +0 -22
- package/src/app/[variants]/(auth)/login/[[...login]]/page.tsx +0 -27
- package/src/app/[variants]/(main)/settings/security/features/ClerkProfile.tsx +0 -67
- package/src/features/Conversation/ChatList/components/AutoScroll.tsx +0 -25
- package/src/layout/AuthProvider/Clerk/UserUpdater.tsx +0 -40
- package/src/layout/AuthProvider/Clerk/index.tsx +0 -54
- package/src/layout/AuthProvider/Clerk/useAppearance.ts +0 -133
- package/src/libs/clerk-auth/index.test.ts +0 -216
- package/src/libs/clerk-auth/index.ts +0 -80
- package/src/locales/default/clerk.ts +0 -677
- package/src/server/services/user/index.test.ts +0 -220
|
@@ -18,7 +18,7 @@ import KlavisServerItem from '@/features/ChatInput/ActionBar/Tools/KlavisServerI
|
|
|
18
18
|
import LobehubSkillServerItem from '@/features/ChatInput/ActionBar/Tools/LobehubSkillServerItem';
|
|
19
19
|
import ToolItem from '@/features/ChatInput/ActionBar/Tools/ToolItem';
|
|
20
20
|
import ActionDropdown from '@/features/ChatInput/ActionBar/components/ActionDropdown';
|
|
21
|
-
import
|
|
21
|
+
import { createSkillStoreModal } from '@/features/SkillStore';
|
|
22
22
|
import { useCheckPluginsIsInstalled } from '@/hooks/useCheckPluginsIsInstalled';
|
|
23
23
|
import { useFetchInstalledPlugins } from '@/hooks/useFetchInstalledPlugins';
|
|
24
24
|
import { useAgentStore } from '@/store/agent';
|
|
@@ -157,8 +157,6 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
157
157
|
const allLobehubSkillServers = useToolStore(lobehubSkillStoreSelectors.getServers, isEqual);
|
|
158
158
|
const isLobehubSkillEnabled = useServerConfigStore(serverConfigSelectors.enableLobehubSkill);
|
|
159
159
|
|
|
160
|
-
// Plugin store modal state
|
|
161
|
-
const [modalOpen, setModalOpen] = useState(false);
|
|
162
160
|
const [updating, setUpdating] = useState(false);
|
|
163
161
|
|
|
164
162
|
// Tab state for dual-column layout
|
|
@@ -423,7 +421,7 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
423
421
|
key: 'plugin-store',
|
|
424
422
|
label: t('tools.plugins.store'),
|
|
425
423
|
onClick: () => {
|
|
426
|
-
|
|
424
|
+
createSkillStoreModal();
|
|
427
425
|
},
|
|
428
426
|
},
|
|
429
427
|
],
|
|
@@ -556,20 +554,7 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
556
554
|
<>
|
|
557
555
|
{/* Plugin Selector and Tags */}
|
|
558
556
|
<Flexbox align="center" gap={8} horizontal wrap={'wrap'}>
|
|
559
|
-
{/* Second Row: Selected Plugins as Tags */}
|
|
560
|
-
{allEnabledTools.map((pluginId) => {
|
|
561
|
-
return (
|
|
562
|
-
<PluginTag
|
|
563
|
-
key={pluginId}
|
|
564
|
-
onRemove={handleRemovePlugin(pluginId)}
|
|
565
|
-
pluginId={pluginId}
|
|
566
|
-
showDesktopOnlyLabel={filterAvailableInWeb}
|
|
567
|
-
useAllMetaList={useAllMetaList}
|
|
568
|
-
/>
|
|
569
|
-
);
|
|
570
|
-
})}
|
|
571
557
|
{/* Plugin Selector Dropdown - Using Action component pattern */}
|
|
572
|
-
|
|
573
558
|
<Suspense fallback={button}>
|
|
574
559
|
<ActionDropdown
|
|
575
560
|
maxHeight={500}
|
|
@@ -622,10 +607,19 @@ const AgentTool = memo<AgentToolProps>(
|
|
|
622
607
|
{button}
|
|
623
608
|
</ActionDropdown>
|
|
624
609
|
</Suspense>
|
|
610
|
+
{/* Selected Plugins as Tags */}
|
|
611
|
+
{allEnabledTools.map((pluginId) => {
|
|
612
|
+
return (
|
|
613
|
+
<PluginTag
|
|
614
|
+
key={pluginId}
|
|
615
|
+
onRemove={handleRemovePlugin(pluginId)}
|
|
616
|
+
pluginId={pluginId}
|
|
617
|
+
showDesktopOnlyLabel={filterAvailableInWeb}
|
|
618
|
+
useAllMetaList={useAllMetaList}
|
|
619
|
+
/>
|
|
620
|
+
);
|
|
621
|
+
})}
|
|
625
622
|
</Flexbox>
|
|
626
|
-
|
|
627
|
-
{/* PluginStore Modal - rendered outside Flexbox to avoid event interference */}
|
|
628
|
-
{modalOpen && <SkillStore open={modalOpen} setOpen={setModalOpen} />}
|
|
629
623
|
</>
|
|
630
624
|
);
|
|
631
625
|
},
|
|
@@ -2,7 +2,6 @@ import { Button, Tooltip } from '@lobehub/ui';
|
|
|
2
2
|
import { createStaticStyles, cx } from 'antd-style';
|
|
3
3
|
import { isNull } from 'es-toolkit/compat';
|
|
4
4
|
import { FileBoxIcon } from 'lucide-react';
|
|
5
|
-
import markdownToTxt from 'markdown-to-txt';
|
|
6
5
|
import { memo } from 'react';
|
|
7
6
|
import { useTranslation } from 'react-i18next';
|
|
8
7
|
|
|
@@ -10,6 +9,7 @@ import FileIcon from '@/components/FileIcon';
|
|
|
10
9
|
import { fileManagerSelectors, useFileStore } from '@/store/file';
|
|
11
10
|
import { type AsyncTaskStatus, type IAsyncTaskError } from '@/types/asyncTask';
|
|
12
11
|
import { isChunkingUnsupported } from '@/utils/isChunkingUnsupported';
|
|
12
|
+
import markdownToTxt from '@/utils/markdownToTxt';
|
|
13
13
|
|
|
14
14
|
import ChunksBadge from '../../ListView/ListItem/ChunkTag';
|
|
15
15
|
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
import { KLAVIS_SERVER_TYPES, LOBEHUB_SKILL_PROVIDERS } from '@lobechat/const';
|
|
4
4
|
import { createStaticStyles } from 'antd-style';
|
|
5
5
|
import isEqual from 'fast-deep-equal';
|
|
6
|
-
import
|
|
7
|
-
import { memo, useMemo, useState } from 'react';
|
|
6
|
+
import { memo, useCallback, useMemo } from 'react';
|
|
8
7
|
|
|
9
|
-
import
|
|
8
|
+
import { createIntegrationDetailModal } from '@/features/IntegrationDetailModal';
|
|
10
9
|
import { serverConfigSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
11
10
|
import { useToolStore } from '@/store/tool';
|
|
12
11
|
import { klavisStoreSelectors, lobehubSkillStoreSelectors } from '@/store/tool/selectors';
|
|
@@ -15,7 +14,6 @@ import { LobehubSkillStatus } from '@/store/tool/slices/lobehubSkillStore/types'
|
|
|
15
14
|
|
|
16
15
|
import Empty from '../Empty';
|
|
17
16
|
import Item from './Item';
|
|
18
|
-
import { useSkillConnect } from './useSkillConnect';
|
|
19
17
|
|
|
20
18
|
const styles = createStaticStyles(({ css }) => ({
|
|
21
19
|
grid: css`
|
|
@@ -36,40 +34,7 @@ interface LobeHubListProps {
|
|
|
36
34
|
keywords: string;
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
interface DetailState {
|
|
40
|
-
identifier: string;
|
|
41
|
-
serverName?: Klavis.McpServerName;
|
|
42
|
-
type: 'klavis' | 'lobehub';
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
interface DetailModalWithConnectProps {
|
|
46
|
-
detailState: DetailState;
|
|
47
|
-
onClose: () => void;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const DetailModalWithConnect = memo<DetailModalWithConnectProps>(({ detailState, onClose }) => {
|
|
51
|
-
const { handleConnect, isConnecting } = useSkillConnect({
|
|
52
|
-
identifier: detailState.identifier,
|
|
53
|
-
serverName: detailState.serverName,
|
|
54
|
-
type: detailState.type,
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<IntegrationDetailModal
|
|
59
|
-
identifier={detailState.identifier}
|
|
60
|
-
isConnecting={isConnecting}
|
|
61
|
-
onClose={onClose}
|
|
62
|
-
onConnect={handleConnect}
|
|
63
|
-
open
|
|
64
|
-
type={detailState.type}
|
|
65
|
-
/>
|
|
66
|
-
);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
DetailModalWithConnect.displayName = 'DetailModalWithConnect';
|
|
70
|
-
|
|
71
37
|
export const LobeHubList = memo<LobeHubListProps>(({ keywords }) => {
|
|
72
|
-
const [detailState, setDetailState] = useState<DetailState | null>(null);
|
|
73
38
|
|
|
74
39
|
const isLobehubSkillEnabled = useServerConfigStore(serverConfigSelectors.enableLobehubSkill);
|
|
75
40
|
const isKlavisEnabled = useServerConfigStore(serverConfigSelectors.enableKlavis);
|
|
@@ -84,13 +49,19 @@ export const LobeHubList = memo<LobeHubListProps>(({ keywords }) => {
|
|
|
84
49
|
useFetchLobehubSkillConnections(isLobehubSkillEnabled);
|
|
85
50
|
useFetchUserKlavisServers(isKlavisEnabled);
|
|
86
51
|
|
|
87
|
-
const getLobehubSkillServerByProvider = (
|
|
88
|
-
|
|
89
|
-
|
|
52
|
+
const getLobehubSkillServerByProvider = useCallback(
|
|
53
|
+
(providerId: string) => {
|
|
54
|
+
return allLobehubSkillServers.find((server) => server.identifier === providerId);
|
|
55
|
+
},
|
|
56
|
+
[allLobehubSkillServers],
|
|
57
|
+
);
|
|
90
58
|
|
|
91
|
-
const getKlavisServerByIdentifier = (
|
|
92
|
-
|
|
93
|
-
|
|
59
|
+
const getKlavisServerByIdentifier = useCallback(
|
|
60
|
+
(identifier: string) => {
|
|
61
|
+
return allKlavisServers.find((server) => server.identifier === identifier);
|
|
62
|
+
},
|
|
63
|
+
[allKlavisServers],
|
|
64
|
+
);
|
|
94
65
|
|
|
95
66
|
const filteredItems = useMemo(() => {
|
|
96
67
|
const items: Array<
|
|
@@ -127,57 +98,49 @@ export const LobeHubList = memo<LobeHubListProps>(({ keywords }) => {
|
|
|
127
98
|
if (filteredItems.length === 0) return <Empty search={hasSearchKeywords} />;
|
|
128
99
|
|
|
129
100
|
return (
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const isConnected = server?.status === LobehubSkillStatus.CONNECTED;
|
|
136
|
-
return (
|
|
137
|
-
<Item
|
|
138
|
-
description={item.provider.description}
|
|
139
|
-
icon={item.provider.icon}
|
|
140
|
-
identifier={item.provider.id}
|
|
141
|
-
isConnected={isConnected}
|
|
142
|
-
key={item.provider.id}
|
|
143
|
-
label={item.provider.label}
|
|
144
|
-
onOpenDetail={() =>
|
|
145
|
-
setDetailState({ identifier: item.provider.id, type: 'lobehub' })
|
|
146
|
-
}
|
|
147
|
-
type="lobehub"
|
|
148
|
-
/>
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
const server = getKlavisServerByIdentifier(item.serverType.identifier);
|
|
152
|
-
const isConnected = server?.status === KlavisServerStatus.CONNECTED;
|
|
101
|
+
<div className={styles.grid}>
|
|
102
|
+
{filteredItems.map((item) => {
|
|
103
|
+
if (item.type === 'lobehub') {
|
|
104
|
+
const server = getLobehubSkillServerByProvider(item.provider.id);
|
|
105
|
+
const isConnected = server?.status === LobehubSkillStatus.CONNECTED;
|
|
153
106
|
return (
|
|
154
107
|
<Item
|
|
155
|
-
description={item.
|
|
156
|
-
icon={item.
|
|
157
|
-
identifier={item.
|
|
108
|
+
description={item.provider.description}
|
|
109
|
+
icon={item.provider.icon}
|
|
110
|
+
identifier={item.provider.id}
|
|
158
111
|
isConnected={isConnected}
|
|
159
|
-
key={item.
|
|
160
|
-
label={item.
|
|
112
|
+
key={item.provider.id}
|
|
113
|
+
label={item.provider.label}
|
|
161
114
|
onOpenDetail={() =>
|
|
162
|
-
|
|
163
|
-
identifier: item.serverType.identifier,
|
|
164
|
-
serverName: item.serverType.serverName,
|
|
165
|
-
type: 'klavis',
|
|
166
|
-
})
|
|
115
|
+
createIntegrationDetailModal({ identifier: item.provider.id, type: 'lobehub' })
|
|
167
116
|
}
|
|
168
|
-
|
|
169
|
-
type="klavis"
|
|
117
|
+
type="lobehub"
|
|
170
118
|
/>
|
|
171
119
|
);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
120
|
+
}
|
|
121
|
+
const server = getKlavisServerByIdentifier(item.serverType.identifier);
|
|
122
|
+
const isConnected = server?.status === KlavisServerStatus.CONNECTED;
|
|
123
|
+
return (
|
|
124
|
+
<Item
|
|
125
|
+
description={item.serverType.description}
|
|
126
|
+
icon={item.serverType.icon}
|
|
127
|
+
identifier={item.serverType.identifier}
|
|
128
|
+
isConnected={isConnected}
|
|
129
|
+
key={item.serverType.identifier}
|
|
130
|
+
label={item.serverType.label}
|
|
131
|
+
onOpenDetail={() =>
|
|
132
|
+
createIntegrationDetailModal({
|
|
133
|
+
identifier: item.serverType.identifier,
|
|
134
|
+
serverName: item.serverType.serverName,
|
|
135
|
+
type: 'klavis',
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
serverName={item.serverType.serverName}
|
|
139
|
+
type="klavis"
|
|
140
|
+
/>
|
|
141
|
+
);
|
|
142
|
+
})}
|
|
143
|
+
</div>
|
|
181
144
|
);
|
|
182
145
|
});
|
|
183
146
|
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import { Flexbox, Segmented } from '@lobehub/ui';
|
|
4
4
|
import { type SegmentedOptions } from 'antd/es/segmented';
|
|
5
|
-
import {
|
|
5
|
+
import { useState } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
|
|
8
8
|
import AddSkillButton from './AddSkillButton';
|
|
9
|
-
|
|
10
9
|
import CommunityList from './CommunityList';
|
|
11
10
|
import LobeHubList from './LobeHubList';
|
|
12
11
|
import Search from './Search';
|
|
@@ -16,7 +15,7 @@ export enum SkillStoreTab {
|
|
|
16
15
|
LobeHub = 'lobehub',
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
export const
|
|
18
|
+
export const SkillStoreContent = () => {
|
|
20
19
|
const { t } = useTranslation('setting');
|
|
21
20
|
const [activeTab, setActiveTab] = useState<SkillStoreTab>(SkillStoreTab.LobeHub);
|
|
22
21
|
const [lobehubKeywords, setLobehubKeywords] = useState('');
|
|
@@ -52,8 +51,4 @@ export const Content = memo(() => {
|
|
|
52
51
|
</Flexbox>
|
|
53
52
|
</Flexbox>
|
|
54
53
|
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
Content.displayName = 'SkillStoreContent';
|
|
58
|
-
|
|
59
|
-
export default Content;
|
|
54
|
+
};
|
|
@@ -1,37 +1,19 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { createModal } from '@lobehub/ui';
|
|
4
|
+
import { t } from 'i18next';
|
|
6
5
|
|
|
7
|
-
import
|
|
6
|
+
import { SkillStoreContent } from './SkillStoreContent';
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
footer={null}
|
|
22
|
-
onCancel={() => setOpen(false)}
|
|
23
|
-
open={open}
|
|
24
|
-
styles={{
|
|
25
|
-
body: { overflow: 'hidden', padding: 0 },
|
|
26
|
-
}}
|
|
27
|
-
title={t('skillStore.title')}
|
|
28
|
-
width={'min(80%, 800px)'}
|
|
29
|
-
>
|
|
30
|
-
<Content />
|
|
31
|
-
</Modal>
|
|
32
|
-
);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
SkillStore.displayName = 'SkillStore';
|
|
36
|
-
|
|
37
|
-
export default SkillStore;
|
|
8
|
+
export const createSkillStoreModal = () =>
|
|
9
|
+
createModal({
|
|
10
|
+
allowFullscreen: true,
|
|
11
|
+
children: <SkillStoreContent />,
|
|
12
|
+
destroyOnHidden: false,
|
|
13
|
+
footer: null,
|
|
14
|
+
styles: {
|
|
15
|
+
body: { overflow: 'hidden', padding: 0 },
|
|
16
|
+
},
|
|
17
|
+
title: t('skillStore.title', { ns: 'setting' }),
|
|
18
|
+
width: 'min(80%, 800px)',
|
|
19
|
+
});
|
|
@@ -10,8 +10,6 @@ import BusinessPanelContent from '@/business/client/features/User/BusinessPanelC
|
|
|
10
10
|
import BrandWatermark from '@/components/BrandWatermark';
|
|
11
11
|
import Menu from '@/components/Menu';
|
|
12
12
|
import { isDesktop } from '@/const/version';
|
|
13
|
-
import { enableBetterAuth, enableNextAuth } from '@/envs/auth';
|
|
14
|
-
import { useRouter } from '@/libs/next/navigation';
|
|
15
13
|
import { useUserStore } from '@/store/user';
|
|
16
14
|
import { authSelectors } from '@/store/user/selectors';
|
|
17
15
|
|
|
@@ -22,8 +20,6 @@ import LangButton from './LangButton';
|
|
|
22
20
|
import { useMenu } from './useMenu';
|
|
23
21
|
|
|
24
22
|
const PanelContent = memo<{ closePopover: () => void }>(({ closePopover }) => {
|
|
25
|
-
const router = useRouter();
|
|
26
|
-
|
|
27
23
|
const isLoginWithAuth = useUserStore(authSelectors.isLoginWithAuth);
|
|
28
24
|
const [openSignIn, signOut] = useUserStore((s) => [s.openLogin, s.logout]);
|
|
29
25
|
const { mainItems, logoutItems } = useMenu();
|
|
@@ -52,10 +48,6 @@ const PanelContent = memo<{ closePopover: () => void }>(({ closePopover }) => {
|
|
|
52
48
|
|
|
53
49
|
signOut();
|
|
54
50
|
closePopover();
|
|
55
|
-
// NextAuth and Better Auth handle redirect in their own signOut methods
|
|
56
|
-
if (enableNextAuth || enableBetterAuth) return;
|
|
57
|
-
// Clerk uses /login page
|
|
58
|
-
router.push('/login');
|
|
59
51
|
};
|
|
60
52
|
|
|
61
53
|
return (
|
|
@@ -68,19 +68,11 @@ vi.mock('@/const/version', () => ({
|
|
|
68
68
|
}));
|
|
69
69
|
|
|
70
70
|
// Use vi.hoisted to ensure variables exist before vi.mock factory executes
|
|
71
|
-
const {
|
|
72
|
-
enableAuth: { value: true },
|
|
73
|
-
enableClerk: { value: false },
|
|
71
|
+
const { enableNextAuth } = vi.hoisted(() => ({
|
|
74
72
|
enableNextAuth: { value: false },
|
|
75
73
|
}));
|
|
76
74
|
|
|
77
75
|
vi.mock('@/envs/auth', () => ({
|
|
78
|
-
get enableAuth() {
|
|
79
|
-
return enableAuth.value;
|
|
80
|
-
},
|
|
81
|
-
get enableClerk() {
|
|
82
|
-
return enableClerk.value;
|
|
83
|
-
},
|
|
84
76
|
get enableNextAuth() {
|
|
85
77
|
return enableNextAuth.value;
|
|
86
78
|
},
|
|
@@ -140,32 +132,6 @@ describe('PanelContent', () => {
|
|
|
140
132
|
});
|
|
141
133
|
});
|
|
142
134
|
|
|
143
|
-
describe('disable auth', () => {
|
|
144
|
-
it('should render UserInfo', () => {
|
|
145
|
-
act(() => {
|
|
146
|
-
useUserStore.setState({ isSignedIn: true });
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
renderWithRouter(<PanelContent closePopover={closePopover} />);
|
|
150
|
-
|
|
151
|
-
expect(screen.getByText('Mocked UserInfo')).toBeInTheDocument();
|
|
152
|
-
expect(screen.getByText('Mocked DataStatistics')).toBeInTheDocument();
|
|
153
|
-
expect(screen.queryByText('Mocked SignInBlock')).not.toBeInTheDocument();
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('should render BrandWatermark when disable auth', () => {
|
|
157
|
-
enableAuth.value = false;
|
|
158
|
-
|
|
159
|
-
act(() => {
|
|
160
|
-
useUserStore.setState({ isSignedIn: false });
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
renderWithRouter(<PanelContent closePopover={closePopover} />);
|
|
164
|
-
|
|
165
|
-
expect(screen.getByText('Mocked BrandWatermark')).toBeInTheDocument();
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
|
|
169
135
|
it('should render Menu with main items', () => {
|
|
170
136
|
renderWithRouter(<PanelContent closePopover={closePopover} />);
|
|
171
137
|
|
|
@@ -10,87 +10,60 @@ import UserAvatar from '../UserAvatar';
|
|
|
10
10
|
vi.mock('zustand/traditional');
|
|
11
11
|
|
|
12
12
|
// Use vi.hoisted to ensure variables exist before vi.mock factory executes
|
|
13
|
-
const {
|
|
14
|
-
enableAuth: { value: true },
|
|
15
|
-
enableClerk: { value: false },
|
|
13
|
+
const { enableNextAuth } = vi.hoisted(() => ({
|
|
16
14
|
enableNextAuth: { value: false },
|
|
17
15
|
}));
|
|
18
16
|
|
|
19
17
|
vi.mock('@/envs/auth', () => ({
|
|
20
|
-
get enableAuth() {
|
|
21
|
-
return enableAuth.value;
|
|
22
|
-
},
|
|
23
|
-
get enableClerk() {
|
|
24
|
-
return enableClerk.value;
|
|
25
|
-
},
|
|
26
18
|
get enableNextAuth() {
|
|
27
19
|
return enableNextAuth.value;
|
|
28
20
|
},
|
|
29
21
|
}));
|
|
30
22
|
|
|
31
23
|
afterEach(() => {
|
|
32
|
-
enableAuth.value = true;
|
|
33
|
-
enableClerk.value = false;
|
|
34
24
|
enableNextAuth.value = false;
|
|
35
25
|
});
|
|
36
26
|
|
|
37
27
|
describe('UserAvatar', () => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
isSignedIn: true,
|
|
47
|
-
user: { avatar: mockAvatar, id: 'abc', username: mockUsername },
|
|
48
|
-
});
|
|
28
|
+
it('should show the username and avatar are displayed when the user is logged in', async () => {
|
|
29
|
+
const mockAvatar = 'https://example.com/avatar.png';
|
|
30
|
+
const mockUsername = 'teeeeeestuser';
|
|
31
|
+
|
|
32
|
+
act(() => {
|
|
33
|
+
useUserStore.setState({
|
|
34
|
+
isSignedIn: true,
|
|
35
|
+
user: { avatar: mockAvatar, id: 'abc', username: mockUsername },
|
|
49
36
|
});
|
|
50
|
-
|
|
51
|
-
render(<UserAvatar />);
|
|
52
|
-
|
|
53
|
-
expect(screen.getByAltText(mockUsername)).toBeInTheDocument();
|
|
54
|
-
expect(screen.getByAltText(mockUsername)).toHaveAttribute('src', mockAvatar);
|
|
55
37
|
});
|
|
56
38
|
|
|
57
|
-
|
|
58
|
-
const mockUsername = 'testuser';
|
|
39
|
+
render(<UserAvatar />);
|
|
59
40
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
isSignedIn: true,
|
|
64
|
-
user: { id: 'bbb', username: mockUsername },
|
|
65
|
-
});
|
|
66
|
-
});
|
|
41
|
+
expect(screen.getByAltText(mockUsername)).toBeInTheDocument();
|
|
42
|
+
expect(screen.getByAltText(mockUsername)).toHaveAttribute('src', mockAvatar);
|
|
43
|
+
});
|
|
67
44
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
expect(screen.getByText('TE')).toBeInTheDocument();
|
|
71
|
-
});
|
|
45
|
+
it('should show default avatar when the user is logged in but have no custom avatar', () => {
|
|
46
|
+
const mockUsername = 'testuser';
|
|
72
47
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
48
|
+
act(() => {
|
|
49
|
+
useUserStore.setState({
|
|
50
|
+
isSignedIn: true,
|
|
51
|
+
user: { id: 'bbb', username: mockUsername },
|
|
76
52
|
});
|
|
77
|
-
|
|
78
|
-
render(<UserAvatar />);
|
|
79
|
-
expect(screen.getByAltText(BRANDING_NAME)).toBeInTheDocument();
|
|
80
|
-
expect(screen.getByAltText(BRANDING_NAME)).toHaveAttribute('src', DEFAULT_USER_AVATAR_URL);
|
|
81
53
|
});
|
|
82
|
-
});
|
|
83
54
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
useUserStore.setState({ enableAuth: () => false, isSignedIn: false, user: undefined });
|
|
89
|
-
});
|
|
55
|
+
render(<UserAvatar />);
|
|
56
|
+
// When user has no avatar url, <Avatar /> falls back to initials rendering (not an <img />)
|
|
57
|
+
expect(screen.getByText('TE')).toBeInTheDocument();
|
|
58
|
+
});
|
|
90
59
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
60
|
+
it('should show LobeChat and default avatar when the user is not logged in', () => {
|
|
61
|
+
act(() => {
|
|
62
|
+
useUserStore.setState({ isSignedIn: false, user: undefined });
|
|
94
63
|
});
|
|
64
|
+
|
|
65
|
+
render(<UserAvatar />);
|
|
66
|
+
expect(screen.getByAltText(BRANDING_NAME)).toBeInTheDocument();
|
|
67
|
+
expect(screen.getByAltText(BRANDING_NAME)).toHaveAttribute('src', DEFAULT_USER_AVATAR_URL);
|
|
95
68
|
});
|
|
96
69
|
});
|
|
@@ -48,33 +48,11 @@ vi.mock('./useNewVersion', () => ({
|
|
|
48
48
|
useNewVersion: vi.fn(() => false),
|
|
49
49
|
}));
|
|
50
50
|
|
|
51
|
-
// Use vi.hoisted to ensure variables exist before vi.mock factory executes
|
|
52
|
-
const { enableAuth, enableClerk } = vi.hoisted(() => ({
|
|
53
|
-
enableAuth: { value: true },
|
|
54
|
-
enableClerk: { value: true },
|
|
55
|
-
}));
|
|
56
|
-
|
|
57
|
-
vi.mock('@/envs/auth', () => ({
|
|
58
|
-
get enableAuth() {
|
|
59
|
-
return enableAuth.value;
|
|
60
|
-
},
|
|
61
|
-
get enableClerk() {
|
|
62
|
-
return enableClerk.value;
|
|
63
|
-
},
|
|
64
|
-
}));
|
|
65
|
-
|
|
66
|
-
afterEach(() => {
|
|
67
|
-
enableAuth.value = true;
|
|
68
|
-
enableClerk.value = true;
|
|
69
|
-
});
|
|
70
|
-
|
|
71
51
|
describe('useMenu', () => {
|
|
72
52
|
it('should provide correct menu items when user is logged in with auth', () => {
|
|
73
53
|
act(() => {
|
|
74
|
-
useUserStore.setState({ isSignedIn: true
|
|
54
|
+
useUserStore.setState({ isSignedIn: true });
|
|
75
55
|
});
|
|
76
|
-
enableAuth.value = true;
|
|
77
|
-
enableClerk.value = false;
|
|
78
56
|
|
|
79
57
|
const { result } = renderHook(() => useMenu(), { wrapper });
|
|
80
58
|
|
|
@@ -88,29 +66,10 @@ describe('useMenu', () => {
|
|
|
88
66
|
});
|
|
89
67
|
});
|
|
90
68
|
|
|
91
|
-
it('should provide correct menu items when user is logged in without auth', () => {
|
|
92
|
-
act(() => {
|
|
93
|
-
useUserStore.setState({ isSignedIn: false, enableAuth: () => false });
|
|
94
|
-
});
|
|
95
|
-
enableAuth.value = false;
|
|
96
|
-
|
|
97
|
-
const { result } = renderHook(() => useMenu(), { wrapper });
|
|
98
|
-
|
|
99
|
-
act(() => {
|
|
100
|
-
const { mainItems, logoutItems } = result.current;
|
|
101
|
-
// When not logged in (isLogin = false), these items should not be shown
|
|
102
|
-
// isLogin checks isSignedIn, so with isSignedIn: false, isLogin should be false
|
|
103
|
-
expect(mainItems?.some((item) => item?.key === 'setting')).toBe(false);
|
|
104
|
-
expect(mainItems?.some((item) => item?.key === 'import')).toBe(false);
|
|
105
|
-
expect(logoutItems.some((item) => item?.key === 'logout')).toBe(false);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
69
|
it('should provide correct menu items when user is not logged in', () => {
|
|
110
70
|
act(() => {
|
|
111
|
-
useUserStore.setState({ isSignedIn: false
|
|
71
|
+
useUserStore.setState({ isSignedIn: false });
|
|
112
72
|
});
|
|
113
|
-
enableAuth.value = true;
|
|
114
73
|
|
|
115
74
|
const { result } = renderHook(() => useMenu(), { wrapper });
|
|
116
75
|
|
|
@@ -4,7 +4,6 @@ import { type PropsWithChildren } from 'react';
|
|
|
4
4
|
import { authEnv } from '@/envs/auth';
|
|
5
5
|
|
|
6
6
|
import BetterAuth from './BetterAuth';
|
|
7
|
-
import Clerk from './Clerk';
|
|
8
7
|
import Desktop from './Desktop';
|
|
9
8
|
import NextAuth from './NextAuth';
|
|
10
9
|
import NoAuth from './NoAuth';
|
|
@@ -14,10 +13,6 @@ const AuthProvider = ({ children }: PropsWithChildren) => {
|
|
|
14
13
|
return <Desktop>{children}</Desktop>;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
if (authEnv.NEXT_PUBLIC_ENABLE_CLERK_AUTH) {
|
|
18
|
-
return <Clerk>{children}</Clerk>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
16
|
if (authEnv.NEXT_PUBLIC_ENABLE_BETTER_AUTH) {
|
|
22
17
|
return <BetterAuth>{children}</BetterAuth>;
|
|
23
18
|
}
|
|
@@ -313,6 +313,12 @@ export function defineConfig(config: CustomNextConfig) {
|
|
|
313
313
|
permanent: true,
|
|
314
314
|
source: '/chat',
|
|
315
315
|
},
|
|
316
|
+
// Redirect old Clerk login route to Better Auth signin
|
|
317
|
+
{
|
|
318
|
+
destination: '/signin',
|
|
319
|
+
permanent: true,
|
|
320
|
+
source: '/login',
|
|
321
|
+
},
|
|
316
322
|
...(config.redirects ?? []),
|
|
317
323
|
],
|
|
318
324
|
|