mirror of
https://github.com/lobehub/lobehub
synced 2026-04-21 09:37:28 +00:00
🐛 fix(desktop): repo-type detection for submodule/worktree + chat & sidebar polish (#13978)
* 🐛 fix(desktop): detect repo type for submodule and worktree directories Route detectRepoType through resolveGitDir so directories where `.git` is a pointer file (submodules, worktrees) are correctly identified as git/github repos instead of falling back to the plain folder icon. Fixes LOBE-7373 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(desktop): reprobe repo type for stale recent-dir entries The recents picker rendered `entry.repoType` directly from localStorage, so any submodule/worktree entry cached while `detectRepoType` still returned `undefined` stayed stuck on the folder icon even after the main-process fix. Wrap each row icon in a component that calls `useRepoType`, which re-probes missing entries and backfills the cache. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(chat-input): clear autocomplete hint on IME start to prevent freeze Dispatch KEY_ESCAPE_COMMAND on compositionstart so the autocomplete plugin removes PlaceholderInline/PlaceholderBlock nodes before the IME begins composing. Composing next to those placeholder nodes caused the editor to freeze during pinyin input with a visible hint. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ♻️ refactor(topic-sidebar): split project grouping into ByProjectMode Extracts project-specific group rendering from ByTimeMode into its own ByProjectMode folder, with a shared GroupedAccordion container. Project groups get a folder-icon column aligned with the topic item layout and a "new topic in {directory}" action. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(desktop): read config via commondir for linked worktrees `resolveGitDir` returns `.git/worktrees/<name>/` for linked worktrees — that dir has its own `HEAD` but no `config`, so `detectRepoType` still returned `undefined` and worktrees missed the repo icon. Resolve the `commondir` pointer first so `config` is read from the shared gitdir. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
46df77ac3f
commit
8240e8685d
13 changed files with 255 additions and 86 deletions
|
|
@ -247,9 +247,10 @@ export default class SystemController extends ControllerModule {
|
|||
|
||||
@IpcMethod()
|
||||
async detectRepoType(dirPath: string): Promise<'git' | 'github' | undefined> {
|
||||
const gitConfigPath = path.join(dirPath, '.git', 'config');
|
||||
const commonDir = await this.resolveCommonGitDir(dirPath);
|
||||
if (!commonDir) return undefined;
|
||||
try {
|
||||
const config = await readFile(gitConfigPath, 'utf8');
|
||||
const config = await readFile(path.join(commonDir, 'config'), 'utf8');
|
||||
if (config.includes('github.com')) return 'github';
|
||||
return 'git';
|
||||
} catch {
|
||||
|
|
@ -460,6 +461,24 @@ export default class SystemController extends ControllerModule {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the common git dir — where shared state like `config` and
|
||||
* `packed-refs` lives. For linked worktrees, `resolveGitDir` returns
|
||||
* `.git/worktrees/<name>/` which has its own `HEAD` but no `config`;
|
||||
* the `commondir` pointer inside it resolves to the main repo's gitdir.
|
||||
*/
|
||||
private async resolveCommonGitDir(dirPath: string): Promise<string | undefined> {
|
||||
const gitDir = await this.resolveGitDir(dirPath);
|
||||
if (!gitDir) return undefined;
|
||||
try {
|
||||
const commondir = (await readFile(path.join(gitDir, 'commondir'), 'utf8')).trim();
|
||||
if (!commondir) return gitDir;
|
||||
return path.isAbsolute(commondir) ? commondir : path.resolve(gitDir, commondir);
|
||||
} catch {
|
||||
return gitDir;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the actual `.git` directory for a working tree.
|
||||
* Supports both standard layouts and worktree pointer files (`.git` as a regular file).
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"actions.addNewTopic": "Start New Topic",
|
||||
"actions.addNewTopicInProject": "Start new topic in {{directory}}",
|
||||
"actions.autoRename": "Smart Rename",
|
||||
"actions.confirmRemoveAll": "You are about to delete all topics. This action cannot be undone.",
|
||||
"actions.confirmRemoveTopic": "You are about to delete this topic. This action cannot be undone.",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"actions.addNewTopic": "开启新话题",
|
||||
"actions.addNewTopicInProject": "在 {{directory}} 中开启新话题",
|
||||
"actions.autoRename": "智能重命名",
|
||||
"actions.confirmRemoveAll": "您即将删除所有话题,此操作无法撤销。",
|
||||
"actions.confirmRemoveTopic": "您即将删除此话题,此操作无法撤销。",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { Editor, FloatMenu, useEditorState } from '@lobehub/editor/react';
|
|||
import { combineKeys } from '@lobehub/ui';
|
||||
import { css, cx } from 'antd-style';
|
||||
import Fuse from 'fuse.js';
|
||||
import { KEY_ESCAPE_COMMAND } from 'lexical';
|
||||
import { memo, type ReactNode, useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { useHotkeysContext } from 'react-hotkeys-hook';
|
||||
|
||||
|
|
@ -300,13 +301,23 @@ const InputEditor = memo<{ defaultRows?: number; placeholder?: ReactNode }>(
|
|||
minHeight: defaultRows > 1 ? defaultRows * 23 : undefined,
|
||||
}}
|
||||
onCompositionEnd={({ event }) => compositionProps.onCompositionEnd(event)}
|
||||
onCompositionStart={({ event }) => compositionProps.onCompositionStart(event)}
|
||||
onBlur={() => {
|
||||
disableScope(HotkeyEnum.AddUserMessage);
|
||||
}}
|
||||
onChange={() => {
|
||||
updateMarkdownContent();
|
||||
}}
|
||||
onCompositionStart={({ event }) => {
|
||||
compositionProps.onCompositionStart(event);
|
||||
// Clear autocomplete placeholder nodes before IME composition starts —
|
||||
// composing next to placeholder inline nodes freezes the editor.
|
||||
if (isAutoCompleteEnabled) {
|
||||
editor?.dispatchCommand(
|
||||
KEY_ESCAPE_COMMAND,
|
||||
new KeyboardEvent('keydown', { key: 'Escape' }),
|
||||
);
|
||||
}
|
||||
}}
|
||||
onContextMenu={async ({ event: e, editor }) => {
|
||||
if (isDesktop) {
|
||||
e.preventDefault();
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { useChatStore } from '@/store/chat';
|
|||
import { topicSelectors } from '@/store/chat/selectors';
|
||||
|
||||
import { addRecentDir, getRecentDirs, type RecentDirEntry, removeRecentDir } from './recentDirs';
|
||||
import { useRepoType } from './useRepoType';
|
||||
|
||||
const styles = createStaticStyles(({ css }) => ({
|
||||
chooseFolderItem: css`
|
||||
|
|
@ -103,6 +104,15 @@ const renderDirIcon = (repoType?: 'git' | 'github'): ReactNode => {
|
|||
);
|
||||
};
|
||||
|
||||
// Backfills `repoType` for entries cached before detection supported submodule /
|
||||
// worktree layouts — `useRepoType` probes and updates the recents cache.
|
||||
const RecentDirIcon = memo<{ entry: RecentDirEntry }>(({ entry }) => {
|
||||
const probed = useRepoType(entry.path);
|
||||
return <>{renderDirIcon(entry.repoType ?? probed)}</>;
|
||||
});
|
||||
|
||||
RecentDirIcon.displayName = 'RecentDirIcon';
|
||||
|
||||
interface WorkingDirectoryContentProps {
|
||||
agentId: string;
|
||||
onClose?: () => void;
|
||||
|
|
@ -223,7 +233,7 @@ const WorkingDirectoryContent = memo<WorkingDirectoryContentProps>(({ agentId, o
|
|||
key={entry.path}
|
||||
onClick={() => selectDir(entry)}
|
||||
>
|
||||
{renderDirIcon(entry.repoType)}
|
||||
<RecentDirIcon entry={entry} />
|
||||
<Flexbox flex={1} style={{ minWidth: 0 }}>
|
||||
<div className={styles.dirName}>{getDirName(entry.path)}</div>
|
||||
<div className={styles.dirPath}>{entry.path}</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
export default {
|
||||
'actions.addNewTopic': 'Start New Topic',
|
||||
'actions.addNewTopicInProject': 'Start new topic in {{directory}}',
|
||||
'actions.autoRename': 'Smart Rename',
|
||||
'actions.confirmRemoveAll': 'You are about to delete all topics. This action cannot be undone.',
|
||||
'actions.confirmRemoveTopic': 'You are about to delete this topic. This action cannot be undone.',
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { useUserStore } from '@/store/user';
|
|||
import { preferenceSelectors } from '@/store/user/selectors';
|
||||
|
||||
import AllTopicsDrawer from '../AllTopicsDrawer';
|
||||
import ByProjectMode from '../TopicListContent/ByProjectMode';
|
||||
import ByTimeMode from '../TopicListContent/ByTimeMode';
|
||||
import FlatMode from '../TopicListContent/FlatMode';
|
||||
|
||||
|
|
@ -48,7 +49,13 @@ const TopicList = memo(() => {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
{topicGroupMode === 'flat' ? <FlatMode /> : <ByTimeMode />}
|
||||
{topicGroupMode === 'flat' ? (
|
||||
<FlatMode />
|
||||
) : topicGroupMode === 'byProject' ? (
|
||||
<ByProjectMode />
|
||||
) : (
|
||||
<ByTimeMode />
|
||||
)}
|
||||
<AllTopicsDrawer open={allTopicsDrawerOpen} onClose={closeAllTopicsDrawer} />
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
import { AccordionItem, ActionIcon, Center, Flexbox, Icon, Text } from '@lobehub/ui';
|
||||
import { cssVar } from 'antd-style';
|
||||
import { FolderClosedIcon, PlusIcon } from 'lucide-react';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { isDesktop } from '@/const/version';
|
||||
import { useAgentStore } from '@/store/agent';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
|
||||
import TopicItem from '../../List/Item';
|
||||
import { type GroupItemComponentProps } from '../GroupedAccordion';
|
||||
|
||||
const PROJECT_GROUP_PREFIX = 'project:';
|
||||
|
||||
const GroupItem = memo<GroupItemComponentProps>(({ group, activeTopicId, activeThreadId }) => {
|
||||
const { t } = useTranslation('topic');
|
||||
const { id, title, children } = group;
|
||||
|
||||
const workingDirectory = useMemo(
|
||||
() => (id.startsWith(PROJECT_GROUP_PREFIX) ? id.slice(PROJECT_GROUP_PREFIX.length) : undefined),
|
||||
[id],
|
||||
);
|
||||
|
||||
const handleAddTopic = useCallback(async () => {
|
||||
if (!workingDirectory) return;
|
||||
const agentId = useAgentStore.getState().activeAgentId;
|
||||
if (agentId) {
|
||||
await useAgentStore.getState().updateAgentRuntimeEnvConfigById(agentId, { workingDirectory });
|
||||
}
|
||||
useChatStore.getState().switchTopic(null, { skipRefreshMessage: true });
|
||||
}, [workingDirectory]);
|
||||
|
||||
const canAddTopic = isDesktop && !!workingDirectory;
|
||||
|
||||
return (
|
||||
<AccordionItem
|
||||
itemKey={id}
|
||||
paddingBlock={4}
|
||||
paddingInline={4}
|
||||
action={
|
||||
canAddTopic ? (
|
||||
<ActionIcon
|
||||
icon={PlusIcon}
|
||||
size={'small'}
|
||||
title={t('actions.addNewTopicInProject', { directory: title })}
|
||||
tooltipProps={{ placement: 'right' }}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
void handleAddTopic();
|
||||
}}
|
||||
/>
|
||||
) : undefined
|
||||
}
|
||||
title={
|
||||
<Flexbox horizontal align="center" gap={8} height={24} style={{ overflow: 'hidden' }}>
|
||||
<Center flex={'none'} height={24} width={28}>
|
||||
<Icon
|
||||
color={cssVar.colorTextSecondary}
|
||||
icon={FolderClosedIcon}
|
||||
size={{ size: 15, strokeWidth: 1.5 }}
|
||||
/>
|
||||
</Center>
|
||||
<Text ellipsis fontSize={14} style={{ flex: 1 }} type={'secondary'}>
|
||||
{title}
|
||||
</Text>
|
||||
</Flexbox>
|
||||
}
|
||||
>
|
||||
<Flexbox gap={1} paddingBlock={1}>
|
||||
{children.map((topic) => (
|
||||
<TopicItem
|
||||
active={activeTopicId === topic.id}
|
||||
fav={topic.favorite}
|
||||
id={topic.id}
|
||||
key={topic.id}
|
||||
metadata={topic.metadata}
|
||||
threadId={activeThreadId}
|
||||
title={topic.title}
|
||||
/>
|
||||
))}
|
||||
</Flexbox>
|
||||
</AccordionItem>
|
||||
);
|
||||
});
|
||||
|
||||
export default GroupItem;
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
'use client';
|
||||
|
||||
import { memo } from 'react';
|
||||
|
||||
import GroupedAccordion from '../GroupedAccordion';
|
||||
import GroupItem from './GroupItem';
|
||||
|
||||
const ByProjectMode = memo(() => <GroupedAccordion GroupItem={GroupItem} />);
|
||||
|
||||
ByProjectMode.displayName = 'ByProjectMode';
|
||||
|
||||
export default ByProjectMode;
|
||||
|
|
@ -3,20 +3,13 @@ import dayjs from 'dayjs';
|
|||
import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { type GroupedTopic } from '@/types/topic';
|
||||
|
||||
import TopicItem from '../../List/Item';
|
||||
import { type GroupItemComponentProps } from '../GroupedAccordion';
|
||||
|
||||
const preformat = (id: string) =>
|
||||
id.startsWith('20') ? (id.includes('-') ? dayjs(id).format('MMMM') : id) : undefined;
|
||||
|
||||
interface GroupItemProps {
|
||||
activeThreadId?: string;
|
||||
activeTopicId?: string;
|
||||
group: GroupedTopic;
|
||||
}
|
||||
|
||||
const GroupItem = memo<GroupItemProps>(({ group, activeTopicId, activeThreadId }) => {
|
||||
const GroupItem = memo<GroupItemComponentProps>(({ group, activeTopicId, activeThreadId }) => {
|
||||
const { t } = useTranslation('topic');
|
||||
const { id, title, children } = group;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,79 +1,11 @@
|
|||
'use client';
|
||||
|
||||
import { Accordion, Flexbox } from '@lobehub/ui';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { MoreHorizontal } from 'lucide-react';
|
||||
import { memo, useEffect, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import NavItem from '@/features/NavPanel/components/NavItem';
|
||||
import SkeletonList from '@/features/NavPanel/components/SkeletonList';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
import { topicSelectors } from '@/store/chat/selectors';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { systemStatusSelectors } from '@/store/global/selectors';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { preferenceSelectors } from '@/store/user/selectors';
|
||||
import { memo } from 'react';
|
||||
|
||||
import GroupedAccordion from '../GroupedAccordion';
|
||||
import GroupItem from './GroupItem';
|
||||
|
||||
const ByTimeMode = memo(() => {
|
||||
const { t } = useTranslation('topic');
|
||||
const topicPageSize = useGlobalStore(systemStatusSelectors.topicPageSize);
|
||||
const topicSortBy = useUserStore(preferenceSelectors.topicSortBy);
|
||||
const topicGroupMode = useUserStore(preferenceSelectors.topicGroupMode);
|
||||
|
||||
const [hasMore, isExpandingPageSize, openAllTopicsDrawer] = useChatStore((s) => [
|
||||
topicSelectors.hasMoreTopics(s),
|
||||
topicSelectors.isExpandingPageSize(s),
|
||||
s.openAllTopicsDrawer,
|
||||
]);
|
||||
const [activeTopicId, activeThreadId] = useChatStore((s) => [s.activeTopicId, s.activeThreadId]);
|
||||
|
||||
const groupSelector = useMemo(
|
||||
() => topicSelectors.groupedTopicsForSidebar(topicPageSize, topicSortBy, topicGroupMode),
|
||||
[topicPageSize, topicSortBy, topicGroupMode],
|
||||
);
|
||||
const groupTopics = useChatStore(groupSelector, isEqual);
|
||||
|
||||
const [topicGroupKeys, updateSystemStatus] = useGlobalStore((s) => [
|
||||
systemStatusSelectors.topicGroupKeys(s),
|
||||
s.updateSystemStatus,
|
||||
]);
|
||||
|
||||
// Reset expanded keys when grouping changes so all groups start expanded
|
||||
useEffect(() => {
|
||||
updateSystemStatus({ expandTopicGroupKeys: undefined });
|
||||
}, [topicSortBy, topicGroupMode, updateSystemStatus]);
|
||||
|
||||
const expandedKeys = useMemo(() => {
|
||||
return topicGroupKeys || groupTopics.map((group) => group.id);
|
||||
}, [topicGroupKeys, groupTopics]);
|
||||
|
||||
return (
|
||||
<Flexbox gap={2}>
|
||||
{/* Grouped topics */}
|
||||
<Accordion
|
||||
expandedKeys={expandedKeys}
|
||||
gap={2}
|
||||
onExpandedChange={(keys) => updateSystemStatus({ expandTopicGroupKeys: keys as any })}
|
||||
>
|
||||
{groupTopics.map((group) => (
|
||||
<GroupItem
|
||||
activeThreadId={activeThreadId}
|
||||
activeTopicId={activeTopicId}
|
||||
group={group}
|
||||
key={group.id}
|
||||
/>
|
||||
))}
|
||||
</Accordion>
|
||||
{isExpandingPageSize && <SkeletonList rows={3} />}
|
||||
{hasMore && !isExpandingPageSize && (
|
||||
<NavItem icon={MoreHorizontal} title={t('loadMore')} onClick={openAllTopicsDrawer} />
|
||||
)}
|
||||
</Flexbox>
|
||||
);
|
||||
});
|
||||
const ByTimeMode = memo(() => <GroupedAccordion GroupItem={GroupItem} />);
|
||||
|
||||
ByTimeMode.displayName = 'ByTimeMode';
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
'use client';
|
||||
|
||||
import { Accordion, Flexbox } from '@lobehub/ui';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { MoreHorizontal } from 'lucide-react';
|
||||
import { type ComponentType, memo, useEffect, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import NavItem from '@/features/NavPanel/components/NavItem';
|
||||
import SkeletonList from '@/features/NavPanel/components/SkeletonList';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
import { topicSelectors } from '@/store/chat/selectors';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { systemStatusSelectors } from '@/store/global/selectors';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { preferenceSelectors } from '@/store/user/selectors';
|
||||
import { type GroupedTopic } from '@/types/topic';
|
||||
|
||||
export interface GroupItemComponentProps {
|
||||
activeThreadId?: string;
|
||||
activeTopicId?: string;
|
||||
group: GroupedTopic;
|
||||
}
|
||||
|
||||
interface GroupedAccordionProps {
|
||||
GroupItem: ComponentType<GroupItemComponentProps>;
|
||||
}
|
||||
|
||||
const GroupedAccordion = memo<GroupedAccordionProps>(({ GroupItem }) => {
|
||||
const { t } = useTranslation('topic');
|
||||
const topicPageSize = useGlobalStore(systemStatusSelectors.topicPageSize);
|
||||
const topicSortBy = useUserStore(preferenceSelectors.topicSortBy);
|
||||
const topicGroupMode = useUserStore(preferenceSelectors.topicGroupMode);
|
||||
|
||||
const [hasMore, isExpandingPageSize, openAllTopicsDrawer] = useChatStore((s) => [
|
||||
topicSelectors.hasMoreTopics(s),
|
||||
topicSelectors.isExpandingPageSize(s),
|
||||
s.openAllTopicsDrawer,
|
||||
]);
|
||||
const [activeTopicId, activeThreadId] = useChatStore((s) => [s.activeTopicId, s.activeThreadId]);
|
||||
|
||||
const groupSelector = useMemo(
|
||||
() => topicSelectors.groupedTopicsForSidebar(topicPageSize, topicSortBy, topicGroupMode),
|
||||
[topicPageSize, topicSortBy, topicGroupMode],
|
||||
);
|
||||
const groupTopics = useChatStore(groupSelector, isEqual);
|
||||
|
||||
const [topicGroupKeys, updateSystemStatus] = useGlobalStore((s) => [
|
||||
systemStatusSelectors.topicGroupKeys(s),
|
||||
s.updateSystemStatus,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
updateSystemStatus({ expandTopicGroupKeys: undefined });
|
||||
}, [topicSortBy, topicGroupMode, updateSystemStatus]);
|
||||
|
||||
const expandedKeys = useMemo(
|
||||
() => topicGroupKeys || groupTopics.map((group) => group.id),
|
||||
[topicGroupKeys, groupTopics],
|
||||
);
|
||||
|
||||
return (
|
||||
<Flexbox gap={2}>
|
||||
<Accordion
|
||||
expandedKeys={expandedKeys}
|
||||
gap={2}
|
||||
onExpandedChange={(keys) => updateSystemStatus({ expandTopicGroupKeys: keys as any })}
|
||||
>
|
||||
{groupTopics.map((group) => (
|
||||
<GroupItem
|
||||
activeThreadId={activeThreadId}
|
||||
activeTopicId={activeTopicId}
|
||||
group={group}
|
||||
key={group.id}
|
||||
/>
|
||||
))}
|
||||
</Accordion>
|
||||
{isExpandingPageSize && <SkeletonList rows={3} />}
|
||||
{hasMore && !isExpandingPageSize && (
|
||||
<NavItem icon={MoreHorizontal} title={t('loadMore')} onClick={openAllTopicsDrawer} />
|
||||
)}
|
||||
</Flexbox>
|
||||
);
|
||||
});
|
||||
|
||||
GroupedAccordion.displayName = 'GroupedAccordion';
|
||||
|
||||
export default GroupedAccordion;
|
||||
|
|
@ -13,6 +13,7 @@ import { topicSelectors } from '@/store/chat/selectors';
|
|||
import { useUserStore } from '@/store/user';
|
||||
import { preferenceSelectors } from '@/store/user/selectors';
|
||||
|
||||
import ByProjectMode from './ByProjectMode';
|
||||
import ByTimeMode from './ByTimeMode';
|
||||
import FlatMode from './FlatMode';
|
||||
import SearchResult from './SearchResult';
|
||||
|
|
@ -46,7 +47,13 @@ const TopicListContent = memo(() => {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
{topicGroupMode === 'flat' ? <FlatMode /> : <ByTimeMode />}
|
||||
{topicGroupMode === 'flat' ? (
|
||||
<FlatMode />
|
||||
) : topicGroupMode === 'byProject' ? (
|
||||
<ByProjectMode />
|
||||
) : (
|
||||
<ByTimeMode />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue