@lobehub/lobehub 2.0.0-next.285 → 2.0.0-next.286

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 CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 2.0.0-next.286](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.285...v2.0.0-next.286)
6
+
7
+ <sup>Released on **2026-01-14**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Prevent auto navigation to profile when clicking topic.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Prevent auto navigation to profile when clicking topic, closes [#11500](https://github.com/lobehub/lobe-chat/issues/11500) ([1e03005](https://github.com/lobehub/lobe-chat/commit/1e03005))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
5
30
  ## [Version 2.0.0-next.285](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.284...v2.0.0-next.285)
6
31
 
7
32
  <sup>Released on **2026-01-14**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "fixes": [
5
+ "Prevent auto navigation to profile when clicking topic."
6
+ ]
7
+ },
8
+ "date": "2026-01-14",
9
+ "version": "2.0.0-next.286"
10
+ },
2
11
  {
3
12
  "children": {
4
13
  "features": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.0-next.285",
3
+ "version": "2.0.0-next.286",
4
4
  "description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -4,6 +4,3 @@ export * from './llm';
4
4
  export * from './url';
5
5
 
6
6
  export const ENABLE_BUSINESS_FEATURES = false;
7
- export const ENABLE_TOPIC_LINK_SHARE =
8
- ENABLE_BUSINESS_FEATURES ||
9
- (process.env.NODE_ENV === 'development' && !!process.env.NEXT_PUBLIC_ENABLE_TOPIC_LINK_SHARE);
@@ -9,7 +9,8 @@ import { useAgentStore } from '@/store/agent';
9
9
  const AddButton = memo(() => {
10
10
  const navigate = useNavigate();
11
11
  const createAgent = useAgentStore((s) => s.createAgent);
12
- const { mutate, isValidating } = useActionSWR('agent.createAgent', async () => {
12
+ // Use a unique SWR key to avoid conflicts with useCreateMenuItems which uses 'agent.createAgent'
13
+ const { mutate, isValidating } = useActionSWR('agent.createAgentFromWelcome', async () => {
13
14
  const result = await createAgent({});
14
15
  navigate(`/agent/${result.agentId}/profile`);
15
16
  return result;
@@ -1,6 +1,5 @@
1
1
  'use client';
2
2
 
3
- import { ENABLE_TOPIC_LINK_SHARE } from '@lobechat/business-const';
4
3
  import { ActionIcon } from '@lobehub/ui';
5
4
  import { Share2 } from 'lucide-react';
6
5
  import dynamic from 'next/dynamic';
@@ -10,6 +9,8 @@ import { useTranslation } from 'react-i18next';
10
9
  import { DESKTOP_HEADER_ICON_SIZE, MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
11
10
  import { useWorkspaceModal } from '@/hooks/useWorkspaceModal';
12
11
  import { useChatStore } from '@/store/chat';
12
+ import { useServerConfigStore } from '@/store/serverConfig';
13
+ import { serverConfigSelectors } from '@/store/serverConfig/selectors';
13
14
 
14
15
  const ShareModal = dynamic(() => import('@/features/ShareModal'));
15
16
  const SharePopover = dynamic(() => import('@/features/SharePopover'));
@@ -24,6 +25,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
24
25
  const [isModalOpen, setIsModalOpen] = useWorkspaceModal(open, setOpen);
25
26
  const { t } = useTranslation('common');
26
27
  const activeTopicId = useChatStore((s) => s.activeTopicId);
28
+ const enableTopicLinkShare = useServerConfigStore(serverConfigSelectors.enableBusinessFeatures);
27
29
 
28
30
  // Hide share button when no topic exists (no messages sent yet)
29
31
  if (!activeTopicId) return null;
@@ -31,7 +33,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
31
33
  const iconButton = (
32
34
  <ActionIcon
33
35
  icon={Share2}
34
- onClick={ENABLE_TOPIC_LINK_SHARE ? undefined : () => setIsModalOpen(true)}
36
+ onClick={enableTopicLinkShare ? undefined : () => setIsModalOpen(true)}
35
37
  size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE}
36
38
  title={t('share')}
37
39
  tooltipProps={{
@@ -42,7 +44,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
42
44
 
43
45
  return (
44
46
  <>
45
- {ENABLE_TOPIC_LINK_SHARE ? (
47
+ {enableTopicLinkShare ? (
46
48
  <SharePopover onOpenModal={() => setIsModalOpen(true)}>{iconButton}</SharePopover>
47
49
  ) : (
48
50
  iconButton
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { SOCIAL_URL } from '@lobechat/business-const';
3
+ import { BRANDING_PROVIDER, SOCIAL_URL } from '@lobechat/business-const';
4
4
  import { Flexbox, Icon, Tabs } from '@lobehub/ui';
5
5
  import { createStaticStyles } from 'antd-style';
6
6
  import { BookOpenIcon, BrainCircuitIcon, ListIcon } from 'lucide-react';
@@ -38,27 +38,36 @@ const Nav = memo<NavProps>(({ mobile, setActiveTab, activeTab = ProviderNavKey.O
38
38
  const { t } = useTranslation('discover');
39
39
  const { identifier } = useDetailContext();
40
40
 
41
+ // Hide Guide tab for branding provider as it doesn't have integration docs
42
+ const showGuideTab = identifier !== BRANDING_PROVIDER;
43
+
44
+ const items = [
45
+ {
46
+ icon: <Icon icon={BookOpenIcon} size={16} />,
47
+ key: ProviderNavKey.Overview,
48
+ label: t('providers.details.overview.title'),
49
+ },
50
+ ...(showGuideTab
51
+ ? [
52
+ {
53
+ icon: <Icon icon={BrainCircuitIcon} size={16} />,
54
+ key: ProviderNavKey.Guide,
55
+ label: t('providers.details.guide.title'),
56
+ },
57
+ ]
58
+ : []),
59
+ {
60
+ icon: <Icon icon={ListIcon} size={16} />,
61
+ key: ProviderNavKey.Related,
62
+ label: t('providers.details.related.title'),
63
+ },
64
+ ];
65
+
41
66
  const nav = (
42
67
  <Tabs
43
68
  activeKey={activeTab}
44
69
  compact={mobile}
45
- items={[
46
- {
47
- icon: <Icon icon={BookOpenIcon} size={16} />,
48
- key: ProviderNavKey.Overview,
49
- label: t('providers.details.overview.title'),
50
- },
51
- {
52
- icon: <Icon icon={BrainCircuitIcon} size={16} />,
53
- key: ProviderNavKey.Guide,
54
- label: t('providers.details.guide.title'),
55
- },
56
- {
57
- icon: <Icon icon={ListIcon} size={16} />,
58
- key: ProviderNavKey.Related,
59
- label: t('providers.details.related.title'),
60
- },
61
- ]}
70
+ items={items}
62
71
  onChange={(key) => setActiveTab?.(key as ProviderNavKey)}
63
72
  />
64
73
  );
@@ -1,6 +1,5 @@
1
1
  'use client';
2
2
 
3
- import { ENABLE_TOPIC_LINK_SHARE } from '@lobechat/business-const';
4
3
  import { ActionIcon } from '@lobehub/ui';
5
4
  import { Share2 } from 'lucide-react';
6
5
  import dynamic from 'next/dynamic';
@@ -10,6 +9,8 @@ import { useTranslation } from 'react-i18next';
10
9
  import { DESKTOP_HEADER_ICON_SIZE, MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
11
10
  import { useWorkspaceModal } from '@/hooks/useWorkspaceModal';
12
11
  import { useChatStore } from '@/store/chat';
12
+ import { useServerConfigStore } from '@/store/serverConfig';
13
+ import { serverConfigSelectors } from '@/store/serverConfig/selectors';
13
14
 
14
15
  const ShareModal = dynamic(() => import('@/features/ShareModal'));
15
16
  const SharePopover = dynamic(() => import('@/features/SharePopover'));
@@ -24,6 +25,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
24
25
  const [isModalOpen, setIsModalOpen] = useWorkspaceModal(open, setOpen);
25
26
  const { t } = useTranslation('common');
26
27
  const activeTopicId = useChatStore((s) => s.activeTopicId);
28
+ const enableTopicLinkShare = useServerConfigStore(serverConfigSelectors.enableBusinessFeatures);
27
29
 
28
30
  // Hide share button when no topic exists (no messages sent yet)
29
31
  if (!activeTopicId) return null;
@@ -31,7 +33,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
31
33
  const iconButton = (
32
34
  <ActionIcon
33
35
  icon={Share2}
34
- onClick={ENABLE_TOPIC_LINK_SHARE ? undefined : () => setIsModalOpen(true)}
36
+ onClick={enableTopicLinkShare ? undefined : () => setIsModalOpen(true)}
35
37
  size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE}
36
38
  title={t('share')}
37
39
  tooltipProps={{
@@ -42,7 +44,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
42
44
 
43
45
  return (
44
46
  <>
45
- {ENABLE_TOPIC_LINK_SHARE ? (
47
+ {enableTopicLinkShare ? (
46
48
  <SharePopover onOpenModal={() => setIsModalOpen(true)}>{iconButton}</SharePopover>
47
49
  ) : (
48
50
  iconButton
@@ -1,21 +1,16 @@
1
1
  import { createStaticStyles } from 'antd-style';
2
2
 
3
3
  export const styles = createStaticStyles(({ css, cssVar }) => ({
4
-
5
-
6
- // Divider 样式
7
- divider: css`
4
+ // Divider 样式
5
+ divider: css`
8
6
  height: 24px;
9
7
  `,
10
8
 
11
-
12
-
13
-
14
- // 内层容器 - 深色模式
15
- innerContainerDark: css`
9
+ // 内层容器 - 深色模式
10
+ innerContainerDark: css`
16
11
  position: relative;
17
12
 
18
- overflow: hidden;
13
+ overflow: hidden auto;
19
14
 
20
15
  border: 1px solid ${cssVar.colorBorderSecondary};
21
16
  border-radius: ${cssVar.borderRadius};
@@ -23,14 +18,11 @@ innerContainerDark: css`
23
18
  background: ${cssVar.colorBgContainer};
24
19
  `,
25
20
 
26
-
27
-
28
-
29
- // 内层容器 - 浅色模式
30
- innerContainerLight: css`
21
+ // 内层容器 - 浅色模式
22
+ innerContainerLight: css`
31
23
  position: relative;
32
24
 
33
- overflow: hidden;
25
+ overflow: hidden auto;
34
26
 
35
27
  border: 1px solid ${cssVar.colorBorder};
36
28
  border-radius: ${cssVar.borderRadius};
@@ -38,10 +30,8 @@ innerContainerLight: css`
38
30
  background: ${cssVar.colorBgContainer};
39
31
  `,
40
32
 
41
-
42
-
43
- // 外层容器
44
- outerContainer: css`
33
+ // 外层容器
34
+ outerContainer: css`
45
35
  position: relative;
46
36
  `,
47
37
  }));
@@ -84,6 +84,31 @@ describe('SettingsAction', () => {
84
84
  expect.any(AbortSignal),
85
85
  );
86
86
  });
87
+
88
+ it('should include field in diffs when user resets it to default value', async () => {
89
+ const { result } = renderHook(() => useUserStore());
90
+
91
+ // First, set memory.enabled to false (non-default value)
92
+ await act(async () => {
93
+ await result.current.setSettings({ memory: { enabled: false } });
94
+ });
95
+
96
+ expect(userService.updateUserSettings).toHaveBeenLastCalledWith(
97
+ expect.objectContaining({ memory: { enabled: false } }),
98
+ expect.any(AbortSignal),
99
+ );
100
+
101
+ // Then, reset memory.enabled back to true (default value)
102
+ // This should still include memory in the diffs to override the previously saved value
103
+ await act(async () => {
104
+ await result.current.setSettings({ memory: { enabled: true } });
105
+ });
106
+
107
+ expect(userService.updateUserSettings).toHaveBeenLastCalledWith(
108
+ expect.objectContaining({ memory: { enabled: true } }),
109
+ expect.any(AbortSignal),
110
+ );
111
+ });
87
112
  });
88
113
 
89
114
  describe('updateDefaultAgent', () => {
@@ -103,6 +103,17 @@ export const createSettingsSlice: StateCreator<
103
103
  if (isEqual(prevSetting, nextSettings)) return;
104
104
 
105
105
  const diffs = difference(nextSettings, defaultSettings);
106
+
107
+ // When user resets a field to default value, we need to explicitly include it in diffs
108
+ // to override the previously saved non-default value in the backend
109
+ const changedFields = difference(nextSettings, prevSetting);
110
+ for (const key of Object.keys(changedFields)) {
111
+ // Only handle fields that were previously set by user (exist in prevSetting)
112
+ if (key in prevSetting && !(key in diffs)) {
113
+ (diffs as any)[key] = (nextSettings as any)[key];
114
+ }
115
+ }
116
+
106
117
  set({ settings: diffs }, false, 'optimistic_updateSettings');
107
118
 
108
119
  const abortController = get().internal_createSignal();