@lobehub/lobehub 2.0.0-next.294 → 2.0.0-next.295
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/apps/desktop/src/main/__mocks__/node-mac-permissions.ts +0 -1
- package/apps/desktop/src/main/__mocks__/setup.ts +0 -1
- package/apps/desktop/src/main/controllers/__tests__/SystemCtr.test.ts +1 -4
- package/apps/desktop/tsconfig.json +4 -10
- package/changelog/v1.json +9 -0
- package/e2e/scripts/setup.ts +45 -32
- package/package.json +1 -1
- package/packages/database/src/models/__tests__/knowledgeBase.test.ts +1 -1
- package/packages/database/src/repositories/knowledge/index.ts +1 -4
- package/packages/types/src/discover/assistants.ts +2 -2
- package/scripts/migrate-spa-navigation.ts +129 -0
- package/src/app/(backend)/api/workflows/memory-user-memory/pipelines/chat-topic/process-topics/route.ts +112 -109
- package/src/app/(backend)/api/workflows/memory-user-memory/pipelines/chat-topic/process-user-topics/route.ts +125 -113
- package/src/app/(backend)/api/workflows/memory-user-memory/pipelines/chat-topic/process-users/route.ts +74 -65
- package/src/app/[variants]/(auth)/auth-error/page.tsx +1 -1
- package/src/app/[variants]/(auth)/login/[[...login]]/page.tsx +1 -1
- package/src/app/[variants]/(auth)/next-auth/error/AuthErrorPage.tsx +1 -1
- package/src/app/[variants]/(auth)/next-auth/signin/AuthSignInBox.tsx +1 -1
- package/src/app/[variants]/(auth)/oauth/callback/error/page.tsx +1 -1
- package/src/app/[variants]/(auth)/oauth/callback/success/page.tsx +1 -1
- package/src/app/[variants]/(auth)/oauth/consent/[uid]/page.tsx +1 -1
- package/src/app/[variants]/(auth)/reset-password/layout.tsx +1 -1
- package/src/app/[variants]/(auth)/reset-password/page.tsx +2 -2
- package/src/app/[variants]/(auth)/signin/layout.tsx +1 -1
- package/src/app/[variants]/(auth)/signin/useSignIn.ts +1 -1
- package/src/app/[variants]/(auth)/signup/[[...signup]]/BetterAuthSignUpForm.tsx +2 -2
- package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -1
- package/src/app/[variants]/(auth)/signup/[[...signup]]/useSignUp.tsx +1 -1
- package/src/app/[variants]/(auth)/verify-email/layout.tsx +1 -1
- package/src/app/[variants]/(auth)/verify-email/page.tsx +2 -2
- package/src/app/[variants]/(main)/_layout/index.tsx +1 -1
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Cron/CronTopicGroup.tsx +1 -1
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Header/AddTopicButon.tsx +1 -1
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Header/Nav.tsx +1 -1
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/AllTopicsDrawer/index.tsx +1 -1
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/hooks/useThreadNavigation.ts +1 -1
- package/src/app/[variants]/(main)/agent/_layout/Sidebar/Topic/hooks/useTopicNavigation.ts +1 -1
- package/src/app/[variants]/(main)/agent/features/TelemetryNotification.tsx +2 -3
- package/src/app/[variants]/(main)/community/(detail)/assistant/features/Details/Nav.tsx +9 -9
- package/src/app/[variants]/(main)/community/(detail)/assistant/features/Details/Versions/index.tsx +2 -3
- package/src/app/[variants]/(main)/community/(detail)/features/MakedownRender.tsx +1 -2
- package/src/app/[variants]/(main)/community/(detail)/features/ShareButton.tsx +2 -3
- package/src/app/[variants]/(main)/community/(detail)/features/Toc/Heading.tsx +2 -3
- package/src/app/[variants]/(main)/community/(detail)/mcp/features/Details/Versions/index.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/model/features/Details/Nav.tsx +12 -11
- package/src/app/[variants]/(main)/community/(detail)/model/features/Details/Parameter/ParameterItem.tsx +2 -3
- package/src/app/[variants]/(main)/community/(detail)/provider/features/Details/Nav.tsx +11 -10
- package/src/app/[variants]/(main)/community/(detail)/provider/features/Header.tsx +10 -9
- package/src/app/[variants]/(main)/community/(list)/(home)/index.tsx +1 -1
- package/src/app/[variants]/(main)/community/(list)/assistant/features/Category/useCategory.tsx +1 -1
- package/src/app/[variants]/(main)/community/(list)/features/SortButton/index.tsx +2 -3
- package/src/app/[variants]/(main)/community/_layout/Sidebar/Header/Nav.tsx +1 -1
- package/src/app/[variants]/(main)/community/features/CreateButton/Inner.tsx +1 -1
- package/src/app/[variants]/(main)/community/features/CreateButton/index.tsx +1 -1
- package/src/app/[variants]/(main)/community/features/Search.tsx +1 -2
- package/src/app/[variants]/(main)/community/features/Title.tsx +5 -5
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Header/Nav.tsx +1 -1
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/AllTopicsDrawer/index.tsx +1 -1
- package/src/app/[variants]/(main)/group/_layout/Sidebar/Topic/hooks/useThreadNavigation.ts +1 -1
- package/src/app/[variants]/(main)/group/features/Conversation/Header/ShareButton/index.tsx +1 -1
- package/src/app/[variants]/(main)/group/features/TelemetryNotification.tsx +2 -3
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/AllAgentsDrawer/index.tsx +1 -1
- package/src/app/[variants]/(main)/hooks/useActiveTabKey.ts +6 -11
- package/src/app/[variants]/(main)/image/NotSupportClient.tsx +4 -3
- package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/ImageUpload.tsx +1 -1
- package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/MultiImagesUpload/ImageManageModal.tsx +1 -1
- package/src/app/[variants]/(main)/image/_layout/ConfigPanel/components/MultiImagesUpload/index.tsx +1 -1
- package/src/app/[variants]/(main)/memory/(home)/features/RoleTagCloud/index.tsx +1 -1
- package/src/app/[variants]/(main)/memory/_layout/Sidebar/Header/Nav.tsx +1 -1
- package/src/app/[variants]/(main)/memory/features/SourceLink.tsx +1 -1
- package/src/app/[variants]/(main)/page/_layout/Body/AllPagesDrawer/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/about/features/ItemCard.tsx +2 -3
- package/src/app/[variants]/(main)/settings/about/features/ItemLink.tsx +2 -3
- package/src/app/[variants]/(main)/settings/about/features/Version.tsx +6 -7
- package/src/app/[variants]/(main)/settings/features/SettingsContent.tsx +1 -1
- package/src/app/[variants]/(main)/settings/features/UpgradeAlert.tsx +4 -4
- package/src/app/[variants]/(main)/settings/provider/(list)/Footer.tsx +2 -2
- package/src/app/[variants]/(main)/settings/provider/detail/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/provider/detail/ollama/CheckError.tsx +1 -1
- package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/index.tsx +12 -6
- package/src/app/[variants]/(main)/settings/security/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/stats/features/overview/ShareButton/ShareModal.tsx +1 -1
- package/src/app/[variants]/(main)/settings/stats/features/rankings/AssistantsRank.tsx +1 -1
- package/src/app/[variants]/(main)/settings/stats/features/rankings/TopicsRank.tsx +1 -1
- package/src/app/[variants]/(mobile)/_layout/index.tsx +1 -1
- package/src/app/[variants]/(mobile)/chat/settings/features/AgentInfoDescription/index.tsx +1 -1
- package/src/app/[variants]/(mobile)/chat/settings/features/SettingButton.tsx +1 -1
- package/src/app/[variants]/(mobile)/router/index.tsx +1 -1
- package/src/app/[variants]/page.tsx +1 -1
- package/src/app/[variants]/router/index.tsx +1 -1
- package/src/components/404/index.tsx +4 -4
- package/src/components/Analytics/index.tsx +1 -1
- package/src/components/BrandWatermark/index.tsx +4 -4
- package/src/components/Branding/ProductLogo/Custom.tsx +1 -1
- package/src/components/Error/index.tsx +3 -4
- package/src/components/GoBack/index.tsx +2 -2
- package/src/components/LabsModal/LabCard.tsx +1 -1
- package/src/components/Link.tsx +25 -5
- package/src/components/OllamaSetupGuide/index.tsx +5 -4
- package/src/components/WebFavicon/index.tsx +1 -1
- package/src/components/client/ClientResponsiveContent/index.tsx +1 -1
- package/src/components/client/ClientResponsiveLayout.tsx +1 -1
- package/src/components/mdx/Image.tsx +1 -1
- package/src/components/mdx/Link.tsx +26 -9
- package/src/features/AlertBanner/CloudBanner.tsx +2 -3
- package/src/features/ChatInput/ActionBar/Model/ControlsForm.tsx +8 -7
- package/src/features/ChatInput/ActionBar/Params/Controls.tsx +1 -3
- package/src/features/ChatInput/ActionBar/Token/index.tsx +1 -1
- package/src/features/ChatInput/Mobile/index.tsx +1 -1
- package/src/features/Conversation/ChatItem/components/MessageContent/index.tsx +1 -1
- package/src/features/Conversation/Error/OllamaBizError/index.tsx +1 -1
- package/src/features/Conversation/Error/OllamaSetupGuide/Desktop.tsx +1 -2
- package/src/features/Conversation/Error/index.tsx +1 -1
- package/src/features/Conversation/Messages/AssistantGroup/Tool/Actions/Settings.tsx +1 -1
- package/src/features/Conversation/Messages/AssistantGroup/Tool/index.tsx +1 -1
- package/src/features/Conversation/Messages/AssistantGroup/index.tsx +1 -1
- package/src/features/Conversation/Messages/Tool/Tool/index.tsx +1 -1
- package/src/features/Conversation/Messages/components/SearchGrounding.tsx +1 -1
- package/src/features/DataImporter/Error.tsx +3 -3
- package/src/features/DevPanel/CacheViewer/cacheProvider.tsx +2 -1
- package/src/features/DevPanel/MetadataViewer/Og.tsx +1 -1
- package/src/features/DevPanel/features/FloatPanel.tsx +1 -1
- package/src/features/DevPanel/features/Table/TooltipContent.tsx +3 -4
- package/src/features/DevPanel/index.tsx +1 -1
- package/src/features/EditorCanvas/InlineToolbar.tsx +1 -6
- package/src/features/FileViewer/NotSupport/index.tsx +2 -3
- package/src/features/Follow/index.tsx +8 -9
- package/src/features/LibraryModal/AddFilesToKnowledgeBase/SelectForm.tsx +2 -2
- package/src/features/MCP/Scores.tsx +1 -1
- package/src/features/MCPPluginDetail/Nav.tsx +8 -8
- package/src/features/MCPPluginDetail/Overview/TagList.tsx +1 -1
- package/src/features/MobileTabBar/index.tsx +2 -1
- package/src/features/OllamaSetupGuide/Desktop.tsx +1 -2
- package/src/features/PWAInstall/Install.tsx +1 -1
- package/src/features/PWAInstall/index.tsx +1 -1
- package/src/features/PluginStore/McpList/index.tsx +1 -1
- package/src/features/PluginStore/PluginList/Detail/Header.tsx +6 -6
- package/src/features/PluginsUI/Render/DefaultType/index.tsx +1 -1
- package/src/features/Portal/Artifacts/Body/Renderer/index.tsx +1 -1
- package/src/features/ResourceManager/components/ChunkDrawer/index.tsx +1 -1
- package/src/features/ResourceManager/components/Explorer/ListView/Skeleton.tsx +26 -26
- package/src/features/ResourceManager/components/Explorer/ToolBar/BatchActionsDropdown.tsx +147 -149
- package/src/features/ResourceManager/index.tsx +1 -1
- package/src/features/Setting/Footer.tsx +4 -5
- package/src/features/User/UserPanel/PanelContent.tsx +1 -1
- package/src/hooks/useActiveTabKey.ts +6 -3
- package/src/hooks/useIsSingleMode.test.ts +10 -24
- package/src/hooks/useIsSingleMode.ts +4 -2
- package/src/hooks/useIsSubSlug.ts +2 -1
- package/src/hooks/useQuery.ts +5 -5
- package/src/layout/GlobalProvider/AppTheme.tsx +2 -2
- package/src/layout/GlobalProvider/StyleRegistry.tsx +1 -1
- package/src/layout/GlobalProvider/useUserStateRedirect.ts +13 -25
- package/src/libs/next/Image.tsx +13 -0
- package/src/libs/next/Link.tsx +13 -0
- package/src/libs/next/dynamic.tsx +13 -0
- package/src/libs/next/index.ts +22 -0
- package/src/libs/next/navigation.ts +22 -0
- package/src/libs/router/Link.tsx +30 -0
- package/src/libs/router/index.ts +18 -0
- package/src/libs/router/navigation.ts +72 -0
- package/src/server/modules/AgentRuntime/AgentStateManager.ts +5 -1
- package/src/store/chat/slices/portal/selectors.test.ts +5 -15
- package/src/store/page/index.ts +1 -1
- package/src/store/page/slices/crud/index.ts +1 -1
- package/src/app/[variants]/(main)/hooks/usePathname.ts +0 -10
- package/src/app/[variants]/(main)/hooks/useQuery.ts +0 -12
- package/src/app/[variants]/(main)/hooks/useRouter.ts +0 -22
- package/src/app/[variants]/(main)/hooks/useSearchParams.ts +0 -11
|
@@ -29,168 +29,166 @@ interface BatchActionsDropdownProps {
|
|
|
29
29
|
selectCount: number;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
const BatchActionsDropdown = memo<BatchActionsDropdownProps>(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
label: t('header.actions.deleteLibrary', { ns: 'file' }),
|
|
57
|
-
onClick: async () => {
|
|
58
|
-
modal.confirm({
|
|
59
|
-
okButtonProps: {
|
|
60
|
-
danger: true,
|
|
61
|
-
},
|
|
62
|
-
onOk: async () => {
|
|
63
|
-
await onActionClick('deleteLibrary');
|
|
64
|
-
},
|
|
65
|
-
title: t('library.list.confirmRemoveLibrary', { ns: 'file' }),
|
|
66
|
-
});
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
return items;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Filter out current knowledge base and create submenu items
|
|
73
|
-
const availableKnowledgeBases = (knowledgeBases || []).filter((kb) => kb.id !== libraryId);
|
|
74
|
-
|
|
75
|
-
const addToKnowledgeBaseSubmenu: DropdownItem[] = availableKnowledgeBases.map((kb) => ({
|
|
76
|
-
disabled: selectCount === 0,
|
|
77
|
-
icon: <RepoIcon />,
|
|
78
|
-
key: `add-to-kb-${kb.id}`,
|
|
79
|
-
label: <span style={{ marginLeft: 8 }}>{kb.name}</span>,
|
|
32
|
+
const BatchActionsDropdown = memo<BatchActionsDropdownProps>(({ selectCount, onActionClick }) => {
|
|
33
|
+
const { t } = useTranslation(['components', 'common', 'file', 'knowledgeBase']);
|
|
34
|
+
const { modal, message } = App.useApp();
|
|
35
|
+
|
|
36
|
+
const [libraryId, selectedFileIds] = useResourceManagerStore((s) => [
|
|
37
|
+
s.libraryId,
|
|
38
|
+
s.selectedFileIds,
|
|
39
|
+
]);
|
|
40
|
+
const [useFetchKnowledgeBaseList, addFilesToKnowledgeBase] = useKnowledgeBaseStore((s) => [
|
|
41
|
+
s.useFetchKnowledgeBaseList,
|
|
42
|
+
s.addFilesToKnowledgeBase,
|
|
43
|
+
]);
|
|
44
|
+
const { data: knowledgeBases } = useFetchKnowledgeBaseList();
|
|
45
|
+
|
|
46
|
+
const menuItems = useMemo<DropdownItem[]>(() => {
|
|
47
|
+
const items: DropdownItem[] = [];
|
|
48
|
+
|
|
49
|
+
// Show delete library option only when in a knowledge base and no files selected
|
|
50
|
+
if (libraryId && selectCount === 0) {
|
|
51
|
+
items.push({
|
|
52
|
+
danger: true,
|
|
53
|
+
icon: <Icon icon={Trash2Icon} />,
|
|
54
|
+
key: 'deleteLibrary',
|
|
55
|
+
label: t('header.actions.deleteLibrary', { ns: 'file' }),
|
|
80
56
|
onClick: async () => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
)
|
|
89
|
-
}
|
|
90
|
-
console.error(e);
|
|
91
|
-
message.error(t('addToKnowledgeBase.error', { ns: 'knowledgeBase' }));
|
|
92
|
-
}
|
|
57
|
+
modal.confirm({
|
|
58
|
+
okButtonProps: {
|
|
59
|
+
danger: true,
|
|
60
|
+
},
|
|
61
|
+
onOk: async () => {
|
|
62
|
+
await onActionClick('deleteLibrary');
|
|
63
|
+
},
|
|
64
|
+
title: t('library.list.confirmRemoveLibrary', { ns: 'file' }),
|
|
65
|
+
});
|
|
93
66
|
},
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
67
|
+
});
|
|
68
|
+
return items;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Filter out current knowledge base and create submenu items
|
|
72
|
+
const availableKnowledgeBases = (knowledgeBases || []).filter((kb) => kb.id !== libraryId);
|
|
73
|
+
|
|
74
|
+
const addToKnowledgeBaseSubmenu: DropdownItem[] = availableKnowledgeBases.map((kb) => ({
|
|
75
|
+
disabled: selectCount === 0,
|
|
76
|
+
icon: <RepoIcon />,
|
|
77
|
+
key: `add-to-kb-${kb.id}`,
|
|
78
|
+
label: <span style={{ marginLeft: 8 }}>{kb.name}</span>,
|
|
79
|
+
onClick: async () => {
|
|
80
|
+
try {
|
|
81
|
+
await addFilesToKnowledgeBase(kb.id, selectedFileIds);
|
|
82
|
+
message.success(
|
|
83
|
+
t('addToKnowledgeBase.addSuccess', {
|
|
84
|
+
count: selectCount,
|
|
85
|
+
ns: 'knowledgeBase',
|
|
86
|
+
}),
|
|
87
|
+
);
|
|
88
|
+
} catch (e) {
|
|
89
|
+
console.error(e);
|
|
90
|
+
message.error(t('addToKnowledgeBase.error', { ns: 'knowledgeBase' }));
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
}));
|
|
117
94
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
95
|
+
if (libraryId) {
|
|
96
|
+
items.push({
|
|
97
|
+
disabled: selectCount === 0,
|
|
98
|
+
icon: <Icon icon={BookMinusIcon} />,
|
|
99
|
+
key: 'removeFromKnowledgeBase',
|
|
100
|
+
label: t('FileManager.actions.removeFromKnowledgeBase'),
|
|
101
|
+
onClick: () => {
|
|
102
|
+
modal.confirm({
|
|
103
|
+
okButtonProps: {
|
|
104
|
+
danger: true,
|
|
105
|
+
},
|
|
106
|
+
onOk: async () => {
|
|
107
|
+
await onActionClick('removeFromKnowledgeBase');
|
|
108
|
+
message.success(t('FileManager.actions.removeFromKnowledgeBaseSuccess'));
|
|
109
|
+
},
|
|
110
|
+
title: t('FileManager.actions.confirmRemoveFromKnowledgeBase', {
|
|
111
|
+
count: selectCount,
|
|
112
|
+
}),
|
|
125
113
|
});
|
|
126
|
-
}
|
|
127
|
-
}
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (availableKnowledgeBases.length > 0) {
|
|
128
118
|
items.push({
|
|
129
119
|
children: addToKnowledgeBaseSubmenu as any,
|
|
130
120
|
disabled: selectCount === 0,
|
|
131
121
|
icon: <Icon icon={BookPlusIcon} />,
|
|
132
|
-
key: '
|
|
133
|
-
label: t('FileManager.actions.
|
|
122
|
+
key: 'addToOtherKnowledgeBase',
|
|
123
|
+
label: t('FileManager.actions.addToOtherKnowledgeBase'),
|
|
134
124
|
});
|
|
135
125
|
}
|
|
136
|
-
|
|
137
|
-
items.push(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
126
|
+
} else if (availableKnowledgeBases.length > 0) {
|
|
127
|
+
items.push({
|
|
128
|
+
children: addToKnowledgeBaseSubmenu as any,
|
|
129
|
+
disabled: selectCount === 0,
|
|
130
|
+
icon: <Icon icon={BookPlusIcon} />,
|
|
131
|
+
key: 'addToKnowledgeBase',
|
|
132
|
+
label: t('FileManager.actions.addToKnowledgeBase'),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
items.push(
|
|
137
|
+
{
|
|
138
|
+
disabled: selectCount === 0,
|
|
139
|
+
icon: <Icon icon={FileBoxIcon} />,
|
|
140
|
+
key: 'batchChunking',
|
|
141
|
+
label: t('FileManager.actions.batchChunking'),
|
|
142
|
+
onClick: async () => {
|
|
143
|
+
await onActionClick('batchChunking');
|
|
149
144
|
},
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
type: 'divider',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
danger: true,
|
|
151
|
+
disabled: selectCount === 0,
|
|
152
|
+
icon: <Icon icon={Trash2Icon} />,
|
|
153
|
+
key: 'delete',
|
|
154
|
+
label: t('delete', { ns: 'common' }),
|
|
155
|
+
onClick: async () => {
|
|
156
|
+
modal.confirm({
|
|
157
|
+
okButtonProps: {
|
|
158
|
+
danger: true,
|
|
159
|
+
},
|
|
160
|
+
onOk: async () => {
|
|
161
|
+
await onActionClick('delete');
|
|
162
|
+
message.success(t('FileManager.actions.deleteSuccess'));
|
|
163
|
+
},
|
|
164
|
+
title: t('FileManager.actions.confirmDeleteMultiFiles', { count: selectCount }),
|
|
165
|
+
});
|
|
168
166
|
},
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return items;
|
|
172
|
-
}, [
|
|
173
|
-
libraryId,
|
|
174
|
-
selectCount,
|
|
175
|
-
selectedFileIds,
|
|
176
|
-
onActionClick,
|
|
177
|
-
addFilesToKnowledgeBase,
|
|
178
|
-
t,
|
|
179
|
-
modal,
|
|
180
|
-
message,
|
|
181
|
-
knowledgeBases,
|
|
182
|
-
]);
|
|
183
|
-
|
|
184
|
-
return (
|
|
185
|
-
<DropdownMenu items={menuItems} placement="bottomLeft">
|
|
186
|
-
<ActionIconWithChevron
|
|
187
|
-
icon={CircleEllipsisIcon}
|
|
188
|
-
title={t('FileManager.actions.batchActions', 'Batch actions')}
|
|
189
|
-
/>
|
|
190
|
-
</DropdownMenu>
|
|
167
|
+
},
|
|
191
168
|
);
|
|
192
|
-
|
|
193
|
-
|
|
169
|
+
|
|
170
|
+
return items;
|
|
171
|
+
}, [
|
|
172
|
+
libraryId,
|
|
173
|
+
selectCount,
|
|
174
|
+
selectedFileIds,
|
|
175
|
+
onActionClick,
|
|
176
|
+
addFilesToKnowledgeBase,
|
|
177
|
+
t,
|
|
178
|
+
modal,
|
|
179
|
+
message,
|
|
180
|
+
knowledgeBases,
|
|
181
|
+
]);
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<DropdownMenu items={menuItems} placement="bottomLeft">
|
|
185
|
+
<ActionIconWithChevron
|
|
186
|
+
icon={CircleEllipsisIcon}
|
|
187
|
+
title={t('FileManager.actions.batchActions', 'Batch actions')}
|
|
188
|
+
/>
|
|
189
|
+
</DropdownMenu>
|
|
190
|
+
);
|
|
191
|
+
});
|
|
194
192
|
|
|
195
193
|
BatchActionsDropdown.displayName = 'BatchActionsDropdown';
|
|
196
194
|
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
import { BRANDING_NAME } from '@lobechat/business-const';
|
|
4
4
|
import { Flexbox } from '@lobehub/ui';
|
|
5
5
|
import { createStyles, cssVar } from 'antd-style';
|
|
6
|
-
import dynamic from 'next/dynamic';
|
|
7
6
|
import { memo, useEffect } from 'react';
|
|
8
7
|
import { useSearchParams } from 'react-router-dom';
|
|
9
8
|
|
|
10
9
|
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
|
|
11
10
|
import { PageEditor } from '@/features/PageEditor';
|
|
11
|
+
import dynamic from '@/libs/next/dynamic';
|
|
12
12
|
import { documentService } from '@/services/document';
|
|
13
13
|
import { useFileStore } from '@/store/file';
|
|
14
14
|
import { documentSelectors } from '@/store/file/slices/document/selectors';
|
|
@@ -4,7 +4,6 @@ import { BRANDING_NAME } from '@lobechat/business-const';
|
|
|
4
4
|
import { Center, Flexbox, Icon } from '@lobehub/ui';
|
|
5
5
|
import { createStaticStyles } from 'antd-style';
|
|
6
6
|
import { MessageSquareHeart } from 'lucide-react';
|
|
7
|
-
import Link from 'next/link';
|
|
8
7
|
import { type PropsWithChildren, memo, useState } from 'react';
|
|
9
8
|
import { useTranslation } from 'react-i18next';
|
|
10
9
|
|
|
@@ -43,7 +42,7 @@ const Footer = memo<PropsWithChildren>(() => {
|
|
|
43
42
|
>
|
|
44
43
|
<div style={{ textAlign: 'center' }}>
|
|
45
44
|
<Icon icon={MessageSquareHeart} /> {`${t('footer.title')} `}
|
|
46
|
-
<
|
|
45
|
+
<a
|
|
47
46
|
aria-label={'star'}
|
|
48
47
|
href={GITHUB}
|
|
49
48
|
onClick={(e) => {
|
|
@@ -52,9 +51,9 @@ const Footer = memo<PropsWithChildren>(() => {
|
|
|
52
51
|
}}
|
|
53
52
|
>
|
|
54
53
|
{t('footer.action.star')}
|
|
55
|
-
</
|
|
54
|
+
</a>
|
|
56
55
|
{` ${t('footer.and')} `}
|
|
57
|
-
<
|
|
56
|
+
<a
|
|
58
57
|
aria-label={'feedback'}
|
|
59
58
|
href={GITHUB_ISSUES}
|
|
60
59
|
onClick={(e) => {
|
|
@@ -63,7 +62,7 @@ const Footer = memo<PropsWithChildren>(() => {
|
|
|
63
62
|
}}
|
|
64
63
|
>
|
|
65
64
|
{t('footer.action.feedback')}
|
|
66
|
-
</
|
|
65
|
+
</a>
|
|
67
66
|
{' !'}
|
|
68
67
|
</div>
|
|
69
68
|
</Center>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ENABLE_BUSINESS_FEATURES } from '@lobechat/business-const';
|
|
2
2
|
import { Flexbox } from '@lobehub/ui';
|
|
3
|
-
import { useRouter } from 'next/navigation';
|
|
3
|
+
import { useRouter } from '@/libs/next/navigation';
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
import { Link, useNavigate } from 'react-router-dom';
|
|
6
6
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { usePathname, useSearchParams } from '
|
|
1
|
+
import { usePathname , useSearchParams } from '@/libs/router/navigation';
|
|
2
2
|
|
|
3
3
|
import { ProfileTabs, SettingsTabs, SidebarTabKey } from '@/store/global/initialState';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Returns the active tab key (chat/market/settings/...)
|
|
7
|
+
* React Router version for SPA
|
|
7
8
|
*/
|
|
8
9
|
export const useActiveTabKey = () => {
|
|
9
10
|
const pathname = usePathname();
|
|
@@ -12,16 +13,18 @@ export const useActiveTabKey = () => {
|
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Returns the active setting page key (?active=common/sync/agent/...)
|
|
16
|
+
* React Router version for SPA
|
|
15
17
|
*/
|
|
16
18
|
export const useActiveSettingsKey = () => {
|
|
17
|
-
const
|
|
18
|
-
const tabs =
|
|
19
|
+
const [searchParams] = useSearchParams();
|
|
20
|
+
const tabs = searchParams.get('active');
|
|
19
21
|
if (!tabs) return SettingsTabs.Common;
|
|
20
22
|
return tabs as SettingsTabs;
|
|
21
23
|
};
|
|
22
24
|
|
|
23
25
|
/**
|
|
24
26
|
* Returns the active profile page key (profile/security/stats/...)
|
|
27
|
+
* React Router version for SPA
|
|
25
28
|
*/
|
|
26
29
|
export const useActiveProfileKey = () => {
|
|
27
30
|
const pathname = usePathname();
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import { renderHook } from '@testing-library/react';
|
|
2
|
-
import { ReadonlyURLSearchParams } from 'next/navigation';
|
|
3
2
|
import { describe, expect, it, vi } from 'vitest';
|
|
4
3
|
|
|
5
4
|
import { useIsSingleMode } from './useIsSingleMode';
|
|
6
5
|
|
|
7
|
-
// Mock
|
|
6
|
+
// Mock react-router-dom useSearchParams (via the wrapper hook)
|
|
8
7
|
const mockUseSearchParams = vi.hoisted(() => vi.fn());
|
|
9
|
-
vi.mock('
|
|
8
|
+
vi.mock('@/libs/router/navigation', () => ({
|
|
10
9
|
useSearchParams: mockUseSearchParams,
|
|
11
10
|
}));
|
|
12
11
|
|
|
13
12
|
describe('useIsSingleMode', () => {
|
|
14
|
-
|
|
15
13
|
it('should return false initially (during SSR)', () => {
|
|
16
|
-
const mockSearchParams =
|
|
17
|
-
|
|
18
|
-
} as unknown as ReadonlyURLSearchParams;
|
|
19
|
-
|
|
20
|
-
mockUseSearchParams.mockReturnValue(mockSearchParams);
|
|
14
|
+
const mockSearchParams = new URLSearchParams('mode=single');
|
|
15
|
+
mockUseSearchParams.mockReturnValue([mockSearchParams, vi.fn()]);
|
|
21
16
|
|
|
22
17
|
const { result } = renderHook(() => useIsSingleMode());
|
|
23
18
|
|
|
@@ -26,11 +21,8 @@ describe('useIsSingleMode', () => {
|
|
|
26
21
|
});
|
|
27
22
|
|
|
28
23
|
it('should return true when mode=single', () => {
|
|
29
|
-
const mockSearchParams =
|
|
30
|
-
|
|
31
|
-
} as unknown as ReadonlyURLSearchParams;
|
|
32
|
-
|
|
33
|
-
mockUseSearchParams.mockReturnValue(mockSearchParams);
|
|
24
|
+
const mockSearchParams = new URLSearchParams('mode=single');
|
|
25
|
+
mockUseSearchParams.mockReturnValue([mockSearchParams, vi.fn()]);
|
|
34
26
|
|
|
35
27
|
const { result } = renderHook(() => useIsSingleMode());
|
|
36
28
|
|
|
@@ -39,11 +31,8 @@ describe('useIsSingleMode', () => {
|
|
|
39
31
|
});
|
|
40
32
|
|
|
41
33
|
it('should return false when mode is not single', () => {
|
|
42
|
-
const mockSearchParams =
|
|
43
|
-
|
|
44
|
-
} as unknown as ReadonlyURLSearchParams;
|
|
45
|
-
|
|
46
|
-
mockUseSearchParams.mockReturnValue(mockSearchParams);
|
|
34
|
+
const mockSearchParams = new URLSearchParams('mode=normal');
|
|
35
|
+
mockUseSearchParams.mockReturnValue([mockSearchParams, vi.fn()]);
|
|
47
36
|
|
|
48
37
|
const { result } = renderHook(() => useIsSingleMode());
|
|
49
38
|
|
|
@@ -52,11 +41,8 @@ describe('useIsSingleMode', () => {
|
|
|
52
41
|
});
|
|
53
42
|
|
|
54
43
|
it('should return false when no mode parameter exists', () => {
|
|
55
|
-
const mockSearchParams =
|
|
56
|
-
|
|
57
|
-
} as unknown as ReadonlyURLSearchParams;
|
|
58
|
-
|
|
59
|
-
mockUseSearchParams.mockReturnValue(mockSearchParams);
|
|
44
|
+
const mockSearchParams = new URLSearchParams();
|
|
45
|
+
mockUseSearchParams.mockReturnValue([mockSearchParams, vi.fn()]);
|
|
60
46
|
|
|
61
47
|
const { result } = renderHook(() => useIsSingleMode());
|
|
62
48
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useSearchParams } from 'next/navigation';
|
|
4
3
|
import { useEffect, useState } from 'react';
|
|
5
4
|
|
|
5
|
+
import { useSearchParams } from '@/libs/router/navigation';
|
|
6
|
+
|
|
6
7
|
/**
|
|
7
8
|
* Hook to check if the current page is in single mode
|
|
8
9
|
* Single mode is used for standalone windows in desktop app
|
|
10
|
+
* React Router version for SPA
|
|
9
11
|
* @returns boolean indicating if the current page is in single mode
|
|
10
12
|
*/
|
|
11
13
|
export const useIsSingleMode = (): boolean => {
|
|
@@ -16,7 +18,7 @@ export const useIsSingleMode = (): boolean => {
|
|
|
16
18
|
setMounted(true);
|
|
17
19
|
}, []);
|
|
18
20
|
|
|
19
|
-
const searchParams = useSearchParams();
|
|
21
|
+
const [searchParams] = useSearchParams();
|
|
20
22
|
|
|
21
23
|
useEffect(() => {
|
|
22
24
|
if (mounted) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { usePathname } from '
|
|
1
|
+
import { usePathname } from '@/libs/router/navigation';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Returns true if the current path has a sub slug (`/chat/mobile` or `/chat/settings`)
|
|
5
|
+
* React Router version for SPA
|
|
5
6
|
*/
|
|
6
7
|
export const useIsSubSlug = () => {
|
|
7
8
|
const pathname = usePathname();
|
package/src/hooks/useQuery.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { useSearchParams } from 'next/navigation';
|
|
2
1
|
import qs from 'query-string';
|
|
3
2
|
import { useMemo } from 'react';
|
|
4
3
|
|
|
4
|
+
import { useSearchParams } from '@/libs/router/navigation';
|
|
5
|
+
|
|
5
6
|
/**
|
|
6
7
|
* Hook to get query parameters
|
|
7
|
-
*
|
|
8
|
-
* For React Router version, use useQuery from @/app/[variants]/(main)/hooks/useQuery
|
|
8
|
+
* React Router version for SPA
|
|
9
9
|
*/
|
|
10
10
|
export const useQuery = () => {
|
|
11
|
-
const
|
|
12
|
-
return useMemo(() => qs.parse(
|
|
11
|
+
const [searchParams] = useSearchParams();
|
|
12
|
+
return useMemo(() => qs.parse(searchParams.toString()), [searchParams]);
|
|
13
13
|
};
|
|
@@ -13,15 +13,15 @@ import { createStaticStyles, cx, useTheme } from 'antd-style';
|
|
|
13
13
|
import 'antd/dist/reset.css';
|
|
14
14
|
import { AppConfigContext } from 'antd/es/app/context';
|
|
15
15
|
import * as motion from 'motion/react-m';
|
|
16
|
-
import Image from 'next/image';
|
|
17
|
-
import Link from 'next/link';
|
|
18
16
|
import { type ReactNode, memo, useEffect, useMemo, useState } from 'react';
|
|
19
17
|
|
|
20
18
|
import AntdStaticMethods from '@/components/AntdStaticMethods';
|
|
19
|
+
import Link from '@/components/Link';
|
|
21
20
|
import { LOBE_THEME_NEUTRAL_COLOR, LOBE_THEME_PRIMARY_COLOR } from '@/const/theme';
|
|
22
21
|
import { isDesktop } from '@/const/version';
|
|
23
22
|
import { useIsDark } from '@/hooks/useIsDark';
|
|
24
23
|
import { getUILocaleAndResources } from '@/libs/getUILocaleAndResources';
|
|
24
|
+
import Image from '@/libs/next/Image';
|
|
25
25
|
import { useGlobalStore } from '@/store/global';
|
|
26
26
|
import { systemStatusSelectors } from '@/store/global/selectors';
|
|
27
27
|
import { useUserStore } from '@/store/user';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { StyleProvider } from 'antd-style';
|
|
4
|
-
import { useServerInsertedHTML } from 'next/navigation';
|
|
4
|
+
import { useServerInsertedHTML } from '@/libs/next/navigation';
|
|
5
5
|
import { type PropsWithChildren } from 'react';
|
|
6
6
|
|
|
7
7
|
import { isDesktop } from '@/const/version';
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { OFFICIAL_URL } from '@lobechat/const';
|
|
4
|
-
import { usePathname } from 'next/navigation';
|
|
5
4
|
import { useCallback } from 'react';
|
|
6
5
|
|
|
7
6
|
import { getDesktopOnboardingCompleted } from '@/app/[variants]/(desktop)/desktop-onboarding/storage';
|
|
@@ -11,20 +10,12 @@ import { useUserStore } from '@/store/user';
|
|
|
11
10
|
import { onboardingSelectors } from '@/store/user/selectors';
|
|
12
11
|
import type { UserInitializationState } from '@/types/user';
|
|
13
12
|
|
|
14
|
-
const redirectIfNotOn = (currentPath: string
|
|
15
|
-
if (!currentPath
|
|
13
|
+
const redirectIfNotOn = (currentPath: string, path: string) => {
|
|
14
|
+
if (!currentPath.startsWith(path)) {
|
|
16
15
|
window.location.href = path;
|
|
17
16
|
}
|
|
18
17
|
};
|
|
19
18
|
|
|
20
|
-
const useCurrentPathname = () => {
|
|
21
|
-
const pathname = usePathname();
|
|
22
|
-
return useCallback(() => {
|
|
23
|
-
if (typeof window === 'undefined') return pathname;
|
|
24
|
-
return window.location.pathname || pathname;
|
|
25
|
-
}, [pathname]);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
19
|
export const useDesktopUserStateRedirect = () => {
|
|
29
20
|
const dataSyncConfig = useElectronStore((s) => s.dataSyncConfig);
|
|
30
21
|
const logout = useUserStore((s) => s.logout);
|
|
@@ -69,25 +60,22 @@ export const useDesktopUserStateRedirect = () => {
|
|
|
69
60
|
);
|
|
70
61
|
};
|
|
71
62
|
|
|
72
|
-
export const useWebUserStateRedirect = (
|
|
73
|
-
useCallback(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
63
|
+
export const useWebUserStateRedirect = () =>
|
|
64
|
+
useCallback((state: UserInitializationState) => {
|
|
65
|
+
const pathname = window.location.pathname;
|
|
66
|
+
if (state.isInWaitList === true) {
|
|
67
|
+
redirectIfNotOn(pathname, '/waitlist');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
79
70
|
|
|
80
|
-
|
|
71
|
+
if (!onboardingSelectors.needsOnboarding(state)) return;
|
|
81
72
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
[getCurrentPathname],
|
|
85
|
-
);
|
|
73
|
+
redirectIfNotOn(pathname, '/onboarding');
|
|
74
|
+
}, []);
|
|
86
75
|
|
|
87
76
|
export const useUserStateRedirect = () => {
|
|
88
|
-
const getCurrentPathname = useCurrentPathname();
|
|
89
77
|
const desktopRedirect = useDesktopUserStateRedirect();
|
|
90
|
-
const webRedirect = useWebUserStateRedirect(
|
|
78
|
+
const webRedirect = useWebUserStateRedirect();
|
|
91
79
|
|
|
92
80
|
return useCallback(
|
|
93
81
|
(state: UserInitializationState) => {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image component wrapper for Next.js Image.
|
|
3
|
+
* This module provides a unified interface that can be easily replaced
|
|
4
|
+
* with a generic <img> or custom image component in the future.
|
|
5
|
+
*
|
|
6
|
+
* @see Phase 3.4: LOBE-2991
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Re-export the Image component
|
|
10
|
+
|
|
11
|
+
// Re-export types
|
|
12
|
+
export type { ImageProps, StaticImageData } from 'next/image';
|
|
13
|
+
export { default } from 'next/image';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Link component wrapper for Next.js Link.
|
|
3
|
+
* This module provides a unified interface that can be easily replaced
|
|
4
|
+
* with react-router-dom Link in the future.
|
|
5
|
+
*
|
|
6
|
+
* @see Phase 3.2: LOBE-2989
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Re-export the Link component
|
|
10
|
+
|
|
11
|
+
// Re-export the type for props
|
|
12
|
+
export type { LinkProps } from 'next/link';
|
|
13
|
+
export { default } from 'next/link';
|