mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-27 13:29:15 +07:00
🐛 fix: prevent auto navigation to profile when clicking topic (#11500)
This commit is contained in:
@@ -4,6 +4,3 @@ export * from './llm';
|
||||
export * from './url';
|
||||
|
||||
export const ENABLE_BUSINESS_FEATURES = false;
|
||||
export const ENABLE_TOPIC_LINK_SHARE =
|
||||
ENABLE_BUSINESS_FEATURES ||
|
||||
(process.env.NODE_ENV === 'development' && !!process.env.NEXT_PUBLIC_ENABLE_TOPIC_LINK_SHARE);
|
||||
|
||||
@@ -9,7 +9,8 @@ import { useAgentStore } from '@/store/agent';
|
||||
const AddButton = memo(() => {
|
||||
const navigate = useNavigate();
|
||||
const createAgent = useAgentStore((s) => s.createAgent);
|
||||
const { mutate, isValidating } = useActionSWR('agent.createAgent', async () => {
|
||||
// Use a unique SWR key to avoid conflicts with useCreateMenuItems which uses 'agent.createAgent'
|
||||
const { mutate, isValidating } = useActionSWR('agent.createAgentFromWelcome', async () => {
|
||||
const result = await createAgent({});
|
||||
navigate(`/agent/${result.agentId}/profile`);
|
||||
return result;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { ENABLE_TOPIC_LINK_SHARE } from '@lobechat/business-const';
|
||||
import { ActionIcon } from '@lobehub/ui';
|
||||
import { Share2 } from 'lucide-react';
|
||||
import dynamic from 'next/dynamic';
|
||||
@@ -10,6 +9,8 @@ import { useTranslation } from 'react-i18next';
|
||||
import { DESKTOP_HEADER_ICON_SIZE, MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
|
||||
import { useWorkspaceModal } from '@/hooks/useWorkspaceModal';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
import { useServerConfigStore } from '@/store/serverConfig';
|
||||
import { serverConfigSelectors } from '@/store/serverConfig/selectors';
|
||||
|
||||
const ShareModal = dynamic(() => import('@/features/ShareModal'));
|
||||
const SharePopover = dynamic(() => import('@/features/SharePopover'));
|
||||
@@ -24,6 +25,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
|
||||
const [isModalOpen, setIsModalOpen] = useWorkspaceModal(open, setOpen);
|
||||
const { t } = useTranslation('common');
|
||||
const activeTopicId = useChatStore((s) => s.activeTopicId);
|
||||
const enableTopicLinkShare = useServerConfigStore(serverConfigSelectors.enableBusinessFeatures);
|
||||
|
||||
// Hide share button when no topic exists (no messages sent yet)
|
||||
if (!activeTopicId) return null;
|
||||
@@ -31,7 +33,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
|
||||
const iconButton = (
|
||||
<ActionIcon
|
||||
icon={Share2}
|
||||
onClick={ENABLE_TOPIC_LINK_SHARE ? undefined : () => setIsModalOpen(true)}
|
||||
onClick={enableTopicLinkShare ? undefined : () => setIsModalOpen(true)}
|
||||
size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE}
|
||||
title={t('share')}
|
||||
tooltipProps={{
|
||||
@@ -42,7 +44,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{ENABLE_TOPIC_LINK_SHARE ? (
|
||||
{enableTopicLinkShare ? (
|
||||
<SharePopover onOpenModal={() => setIsModalOpen(true)}>{iconButton}</SharePopover>
|
||||
) : (
|
||||
iconButton
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { SOCIAL_URL } from '@lobechat/business-const';
|
||||
import { BRANDING_PROVIDER, SOCIAL_URL } from '@lobechat/business-const';
|
||||
import { Flexbox, Icon, Tabs } from '@lobehub/ui';
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
import { BookOpenIcon, BrainCircuitIcon, ListIcon } from 'lucide-react';
|
||||
@@ -38,27 +38,36 @@ const Nav = memo<NavProps>(({ mobile, setActiveTab, activeTab = ProviderNavKey.O
|
||||
const { t } = useTranslation('discover');
|
||||
const { identifier } = useDetailContext();
|
||||
|
||||
// Hide Guide tab for branding provider as it doesn't have integration docs
|
||||
const showGuideTab = identifier !== BRANDING_PROVIDER;
|
||||
|
||||
const items = [
|
||||
{
|
||||
icon: <Icon icon={BookOpenIcon} size={16} />,
|
||||
key: ProviderNavKey.Overview,
|
||||
label: t('providers.details.overview.title'),
|
||||
},
|
||||
...(showGuideTab
|
||||
? [
|
||||
{
|
||||
icon: <Icon icon={BrainCircuitIcon} size={16} />,
|
||||
key: ProviderNavKey.Guide,
|
||||
label: t('providers.details.guide.title'),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
icon: <Icon icon={ListIcon} size={16} />,
|
||||
key: ProviderNavKey.Related,
|
||||
label: t('providers.details.related.title'),
|
||||
},
|
||||
];
|
||||
|
||||
const nav = (
|
||||
<Tabs
|
||||
activeKey={activeTab}
|
||||
compact={mobile}
|
||||
items={[
|
||||
{
|
||||
icon: <Icon icon={BookOpenIcon} size={16} />,
|
||||
key: ProviderNavKey.Overview,
|
||||
label: t('providers.details.overview.title'),
|
||||
},
|
||||
{
|
||||
icon: <Icon icon={BrainCircuitIcon} size={16} />,
|
||||
key: ProviderNavKey.Guide,
|
||||
label: t('providers.details.guide.title'),
|
||||
},
|
||||
{
|
||||
icon: <Icon icon={ListIcon} size={16} />,
|
||||
key: ProviderNavKey.Related,
|
||||
label: t('providers.details.related.title'),
|
||||
},
|
||||
]}
|
||||
items={items}
|
||||
onChange={(key) => setActiveTab?.(key as ProviderNavKey)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { ENABLE_TOPIC_LINK_SHARE } from '@lobechat/business-const';
|
||||
import { ActionIcon } from '@lobehub/ui';
|
||||
import { Share2 } from 'lucide-react';
|
||||
import dynamic from 'next/dynamic';
|
||||
@@ -10,6 +9,8 @@ import { useTranslation } from 'react-i18next';
|
||||
import { DESKTOP_HEADER_ICON_SIZE, MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
|
||||
import { useWorkspaceModal } from '@/hooks/useWorkspaceModal';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
import { useServerConfigStore } from '@/store/serverConfig';
|
||||
import { serverConfigSelectors } from '@/store/serverConfig/selectors';
|
||||
|
||||
const ShareModal = dynamic(() => import('@/features/ShareModal'));
|
||||
const SharePopover = dynamic(() => import('@/features/SharePopover'));
|
||||
@@ -24,6 +25,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
|
||||
const [isModalOpen, setIsModalOpen] = useWorkspaceModal(open, setOpen);
|
||||
const { t } = useTranslation('common');
|
||||
const activeTopicId = useChatStore((s) => s.activeTopicId);
|
||||
const enableTopicLinkShare = useServerConfigStore(serverConfigSelectors.enableBusinessFeatures);
|
||||
|
||||
// Hide share button when no topic exists (no messages sent yet)
|
||||
if (!activeTopicId) return null;
|
||||
@@ -31,7 +33,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
|
||||
const iconButton = (
|
||||
<ActionIcon
|
||||
icon={Share2}
|
||||
onClick={ENABLE_TOPIC_LINK_SHARE ? undefined : () => setIsModalOpen(true)}
|
||||
onClick={enableTopicLinkShare ? undefined : () => setIsModalOpen(true)}
|
||||
size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE}
|
||||
title={t('share')}
|
||||
tooltipProps={{
|
||||
@@ -42,7 +44,7 @@ const ShareButton = memo<ShareButtonProps>(({ mobile, setOpen, open }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{ENABLE_TOPIC_LINK_SHARE ? (
|
||||
{enableTopicLinkShare ? (
|
||||
<SharePopover onOpenModal={() => setIsModalOpen(true)}>{iconButton}</SharePopover>
|
||||
) : (
|
||||
iconButton
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
import { createStaticStyles } from 'antd-style';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
|
||||
|
||||
// Divider 样式
|
||||
divider: css`
|
||||
// Divider 样式
|
||||
divider: css`
|
||||
height: 24px;
|
||||
`,
|
||||
|
||||
|
||||
|
||||
|
||||
// 内层容器 - 深色模式
|
||||
innerContainerDark: css`
|
||||
// 内层容器 - 深色模式
|
||||
innerContainerDark: css`
|
||||
position: relative;
|
||||
|
||||
overflow: hidden;
|
||||
overflow: hidden auto;
|
||||
|
||||
border: 1px solid ${cssVar.colorBorderSecondary};
|
||||
border-radius: ${cssVar.borderRadius};
|
||||
@@ -23,14 +18,11 @@ innerContainerDark: css`
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
|
||||
|
||||
|
||||
|
||||
// 内层容器 - 浅色模式
|
||||
innerContainerLight: css`
|
||||
// 内层容器 - 浅色模式
|
||||
innerContainerLight: css`
|
||||
position: relative;
|
||||
|
||||
overflow: hidden;
|
||||
overflow: hidden auto;
|
||||
|
||||
border: 1px solid ${cssVar.colorBorder};
|
||||
border-radius: ${cssVar.borderRadius};
|
||||
@@ -38,10 +30,8 @@ innerContainerLight: css`
|
||||
background: ${cssVar.colorBgContainer};
|
||||
`,
|
||||
|
||||
|
||||
|
||||
// 外层容器
|
||||
outerContainer: css`
|
||||
// 外层容器
|
||||
outerContainer: css`
|
||||
position: relative;
|
||||
`,
|
||||
}));
|
||||
|
||||
@@ -84,6 +84,31 @@ describe('SettingsAction', () => {
|
||||
expect.any(AbortSignal),
|
||||
);
|
||||
});
|
||||
|
||||
it('should include field in diffs when user resets it to default value', async () => {
|
||||
const { result } = renderHook(() => useUserStore());
|
||||
|
||||
// First, set memory.enabled to false (non-default value)
|
||||
await act(async () => {
|
||||
await result.current.setSettings({ memory: { enabled: false } });
|
||||
});
|
||||
|
||||
expect(userService.updateUserSettings).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ memory: { enabled: false } }),
|
||||
expect.any(AbortSignal),
|
||||
);
|
||||
|
||||
// Then, reset memory.enabled back to true (default value)
|
||||
// This should still include memory in the diffs to override the previously saved value
|
||||
await act(async () => {
|
||||
await result.current.setSettings({ memory: { enabled: true } });
|
||||
});
|
||||
|
||||
expect(userService.updateUserSettings).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ memory: { enabled: true } }),
|
||||
expect.any(AbortSignal),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateDefaultAgent', () => {
|
||||
|
||||
@@ -103,6 +103,17 @@ export const createSettingsSlice: StateCreator<
|
||||
if (isEqual(prevSetting, nextSettings)) return;
|
||||
|
||||
const diffs = difference(nextSettings, defaultSettings);
|
||||
|
||||
// When user resets a field to default value, we need to explicitly include it in diffs
|
||||
// to override the previously saved non-default value in the backend
|
||||
const changedFields = difference(nextSettings, prevSetting);
|
||||
for (const key of Object.keys(changedFields)) {
|
||||
// Only handle fields that were previously set by user (exist in prevSetting)
|
||||
if (key in prevSetting && !(key in diffs)) {
|
||||
(diffs as any)[key] = (nextSettings as any)[key];
|
||||
}
|
||||
}
|
||||
|
||||
set({ settings: diffs }, false, 'optimistic_updateSettings');
|
||||
|
||||
const abortController = get().internal_createSignal();
|
||||
|
||||
Reference in New Issue
Block a user