Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ refactor: session group #1126

Merged
merged 2 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { ActionIcon, Icon } from '@lobehub/ui';
import { App, Dropdown, DropdownProps, MenuProps } from 'antd';
import { createStyles } from 'antd-style';
import isEqual from 'fast-deep-equal';
import { MoreVertical, PencilLine, Settings2, Trash } from 'lucide-react';
import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';

import { useGlobalStore } from '@/store/global';
import { groupHelpers } from '@/store/global/helpers';
import { settingsSelectors } from '@/store/global/selectors';
import { useSessionStore } from '@/store/session';

const useStyles = createStyles(({ css }) => ({
modalRoot: css`
Expand All @@ -25,8 +22,8 @@ const Actions = memo<ActionsProps>(({ id, openRenameModal, openConfigModal, onOp
const { t } = useTranslation('chat');
const { styles } = useStyles();
const { modal } = App.useApp();
const sessionCustomGroups = useGlobalStore(settingsSelectors.sessionCustomGroups, isEqual);
const updateCustomGroup = useGlobalStore((s) => s.updateCustomGroup);

const [removeSessionGroup] = useSessionStore((s) => [s.removeSessionGroup]);
const items: MenuProps['items'] = useMemo(
() => [
{
Expand Down Expand Up @@ -61,7 +58,7 @@ const Actions = memo<ActionsProps>(({ id, openRenameModal, openConfigModal, onOp
centered: true,
okButtonProps: { danger: true },
onOk: () => {
updateCustomGroup(groupHelpers.removeGroup(id, sessionCustomGroups));
removeSessionGroup(id);
},
rootClassName: styles.modalRoot,
title: t('sessionGroup.confirmRemoveGroupAlert'),
Expand Down
45 changes: 23 additions & 22 deletions src/app/chat/features/SessionListContent/DefaultMode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { memo, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';

import { useGlobalStore } from '@/store/global';
import { preferenceSelectors, settingsSelectors } from '@/store/global/selectors';
import { preferenceSelectors } from '@/store/global/selectors';
import { useSessionStore } from '@/store/session';
import { sessionSelectors } from '@/store/session/selectors';
import { SessionDefaultGroup } from '@/types/session';

import Actions from '../SessionListContent/CollapseGroup/Actions';
import CollapseGroup from './CollapseGroup';
Expand All @@ -16,35 +17,34 @@ import ConfigGroupModal from './Modals/ConfigGroupModal';
import RenameGroupModal from './Modals/RenameGroupModal';

const SessionListContent = memo(() => {
const { t } = useTranslation('chat');

const [activeGroupId, setActiveGroupId] = useState<string>();
const [renameGroupModalOpen, setRenameGroupModalOpen] = useState(false);
const [configGroupModalOpen, setConfigGroupModalOpen] = useState(false);
const { t } = useTranslation('chat');
const sessionCustomGroups = useGlobalStore(settingsSelectors.sessionCustomGroups, isEqual);
const sessionList =
useSessionStore(sessionSelectors.sessionList(sessionCustomGroups), isEqual) || {};

const [useFetchSessions] = useSessionStore((s) => [s.useFetchSessions]);
useFetchSessions();

const pinnedSessions = useSessionStore(sessionSelectors.pinnedSessions, isEqual);
const defaultSessions = useSessionStore(sessionSelectors.defaultSessions, isEqual);
const customSessionGroups = useSessionStore(sessionSelectors.customSessionGroups, isEqual);

const [sessionGroupKeys, updatePreference] = useGlobalStore((s) => [
preferenceSelectors.sessionGroupKeys(s),
s.updatePreference,
]);
const [ useFetchSessions] = useSessionStore((s) => [
s.useFetchSessions,
]);
useFetchSessions();


const items = useMemo(
() =>
[
sessionList.pinnedList?.length > 0 && {
children: <SessionList dataSource={sessionList.pinnedList} />,
key: 'pinned',
pinnedSessions.length > 0 && {
children: <SessionList dataSource={pinnedSessions} />,
key: SessionDefaultGroup.Pinned,
label: t('pin'),
},
...sessionCustomGroups.map(({ id, name }) => ({
children: sessionList.customList[id] && (
<SessionList dataSource={sessionList.customList[id]} />
),
...customSessionGroups.map(({ id, name, children }) => ({
children: <SessionList dataSource={children} />,
extra: (
<Actions
id={id}
Expand All @@ -59,12 +59,12 @@ const SessionListContent = memo(() => {
label: name,
})),
{
children: <SessionList dataSource={sessionList.defaultList} />,
key: 'defaultList',
children: <SessionList dataSource={defaultSessions} />,
key: SessionDefaultGroup.Default,
label: t('defaultList'),
},
].filter(Boolean) as CollapseProps['items'],
[sessionCustomGroups, sessionList],
[customSessionGroups, pinnedSessions, defaultSessions],
);

return (
Expand All @@ -74,8 +74,9 @@ const SessionListContent = memo(() => {
activeKey={sessionGroupKeys}
items={items}
onChange={(keys) => {
const sessionGroupKeys = typeof keys === 'string' ? [keys] : keys;
updatePreference({ sessionGroupKeys });
const expandSessionGroupKeys = typeof keys === 'string' ? [keys] : keys;

updatePreference({ expandSessionGroupKeys });
}}
/>
{activeGroupId && (
Expand Down
11 changes: 4 additions & 7 deletions src/app/chat/features/SessionListContent/List/Item/Actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';

import { configService } from '@/services/config';
import { useGlobalStore } from '@/store/global';
import { settingsSelectors } from '@/store/global/selectors';
import { useSessionStore } from '@/store/session';
import { sessionHelpers } from '@/store/session/helpers';
import { sessionSelectors } from '@/store/session/selectors';
import { sessionGroupSelectors, sessionSelectors } from '@/store/session/selectors';
import { SessionDefaultGroup } from '@/types/session';

const useStyles = createStyles(({ css }) => ({
Expand All @@ -38,11 +36,10 @@ interface ActionProps {
}

const Actions = memo<ActionProps>(({ group, id, openCreateGroupModal, setOpen }) => {
const { t } = useTranslation('chat');

const { styles } = useStyles();
const { t } = useTranslation('chat');

const sessionCustomGroups = useGlobalStore(settingsSelectors.sessionCustomGroups, isEqual);
const sessionCustomGroups = useSessionStore(sessionGroupSelectors.sessionGroupItems, isEqual);
const [pin, removeSession, pinSession, duplicateSession, updateSessionGroup] = useSessionStore(
(s) => {
const session = sessionSelectors.getSessionById(id)(s);
Expand All @@ -51,7 +48,7 @@ const Actions = memo<ActionProps>(({ group, id, openCreateGroupModal, setOpen })
s.removeSession,
s.pinSession,
s.duplicateSession,
s.updateSessionGroup,
s.updateSessionGroupId,
];
},
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import { ActionIcon, EditableText, SortableList } from '@lobehub/ui';
import { Popconfirm, message } from 'antd';
import { App, Popconfirm } from 'antd';
import { createStyles } from 'antd-style';
import isEqual from 'fast-deep-equal';
import { PencilLine, Trash } from 'lucide-react';
import { memo, useCallback, useState } from 'react';
import { memo, useState } from 'react';
import { useTranslation } from 'react-i18next';

import { useGlobalStore } from '@/store/global';
import { groupHelpers } from '@/store/global/helpers';
import { settingsSelectors } from '@/store/global/selectors';
import { useSessionStore } from '@/store/session';
import { SessionGroupItem } from '@/types/session';

const useStyles = createStyles(({ css }) => ({
Expand All @@ -26,22 +23,15 @@ const useStyles = createStyles(({ css }) => ({
}));

const GroupItem = memo<SessionGroupItem>(({ id, name }) => {
const [editing, setEditing] = useState(false);
const sessionCustomGroups = useGlobalStore(settingsSelectors.sessionCustomGroups, isEqual);
const updateCustomGroup = useGlobalStore((s) => s.updateCustomGroup);
const { t } = useTranslation('chat');
const { styles } = useStyles();
const { message } = App.useApp();

const handleRename = useCallback(
(input: string) => {
if (!input) return;
if (input.length === 0 || input.length > 20)
return message.warning(t('sessionGroup.tooLong'));
updateCustomGroup(groupHelpers.renameGroup(id, input, sessionCustomGroups));
message.success(t('sessionGroup.renameSuccess'));
},
[id, sessionCustomGroups],
);
const [editing, setEditing] = useState(false);
const [updateSessionGroupName, removeSessionGroup] = useSessionStore((s) => [
s.updateSessionGroupName,
s.removeSessionGroup,
]);

return (
<>
Expand All @@ -57,7 +47,7 @@ const GroupItem = memo<SessionGroupItem>(({ id, name }) => {
type: 'primary',
}}
onConfirm={() => {
updateCustomGroup(groupHelpers.removeGroup(id, sessionCustomGroups));
removeSessionGroup(id);
}}
title={t('sessionGroup.confirmRemoveGroupAlert')}
>
Expand All @@ -67,8 +57,14 @@ const GroupItem = memo<SessionGroupItem>(({ id, name }) => {
) : (
<EditableText
editing={editing}
onChangeEnd={(v) => {
if (name !== v) handleRename(v);
onChangeEnd={(input) => {
if (name !== input) {
if (!input) return;
if (input.length === 0 || input.length > 20)
return message.warning(t('sessionGroup.tooLong'));
updateSessionGroupName(id, input);
message.success(t('sessionGroup.renameSuccess'));
}
setEditing(false);
}}
onEditingChange={(e) => setEditing(e)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit';

import { useGlobalStore } from '@/store/global';
import { settingsSelectors } from '@/store/global/selectors';
import { useSessionStore } from '@/store/session';
import { sessionGroupSelectors } from '@/store/session/selectors';
import { SessionGroupItem } from '@/types/session';

import GroupItem from './GroupItem';
Expand All @@ -30,10 +30,10 @@ const useStyles = createStyles(({ css, token, stylish }) => ({
const ConfigGroupModal = memo<ModalProps>(({ open, onCancel }) => {
const { t } = useTranslation('chat');
const { styles } = useStyles();
const sessionCustomGroups = useGlobalStore(settingsSelectors.sessionCustomGroups, isEqual);
const [addCustomGroup, updateCustomGroup] = useGlobalStore((s) => [
s.addCustomGroup,
s.updateCustomGroup,
const sessionGroupItems = useSessionStore(sessionGroupSelectors.sessionGroupItems, isEqual);
const [addSessionGroup, updateSessionGroupSort] = useSessionStore((s) => [
s.addSessionGroup,
s.updateSessionGroupSort,
]);

return (
Expand All @@ -47,8 +47,10 @@ const ConfigGroupModal = memo<ModalProps>(({ open, onCancel }) => {
>
<Flexbox>
<SortableList
items={sessionCustomGroups}
onChange={(item: SessionGroupItem[]) => updateCustomGroup(item)}
items={sessionGroupItems}
onChange={(items: SessionGroupItem[]) => {
updateSessionGroupSort(items);
}}
renderItem={(item: SessionGroupItem) => (
<SortableList.Item
align={'center'}
Expand All @@ -65,7 +67,7 @@ const ConfigGroupModal = memo<ModalProps>(({ open, onCancel }) => {
<Button
block
icon={<Icon icon={Plus} />}
onClick={() => addCustomGroup(t('sessionGroup.newGroup'))}
onClick={() => addSessionGroup(t('sessionGroup.newGroup'))}
>
{t('sessionGroup.createGroup')}
</Button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Input, Modal, type ModalProps } from '@lobehub/ui';
import { message } from 'antd';
import isEqual from 'fast-deep-equal';
import { memo, useCallback, useState } from 'react';
import { App } from 'antd';
import { MouseEvent, memo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit';

import { useGlobalStore } from '@/store/global';
import { settingsSelectors } from '@/store/global/selectors';
import { useSessionStore } from '@/store/session';

interface CreateGroupModalProps extends ModalProps {
Expand All @@ -15,41 +14,46 @@ interface CreateGroupModalProps extends ModalProps {
const CreateGroupModal = memo<CreateGroupModalProps>(
({ id, open, onCancel }: CreateGroupModalProps) => {
const { t } = useTranslation('chat');
const sessionCustomGroups = useGlobalStore(settingsSelectors.sessionCustomGroups, isEqual);
const addCustomGroup = useGlobalStore((s) => s.addCustomGroup);
const updateSessionGroup = useSessionStore((s) => s.updateSessionGroup);
const [input, setInput] = useState('');

const handleSubmit = useCallback(
(e: any) => {
if (!input) return;
if (input.length === 0 || input.length > 20)
return message.warning(t('sessionGroup.tooLong'));

const groupId = addCustomGroup(input);
updateSessionGroup(id, groupId);
message.success(t('sessionGroup.createSuccess'));
onCancel?.(e);
},
[id, input, sessionCustomGroups],
);
const toggleExpandSessionGroup = useGlobalStore((s) => s.toggleExpandSessionGroup);
const { message } = App.useApp();
const [updateSessionGroup, addCustomGroup] = useSessionStore((s) => [
s.updateSessionGroupId,
s.addSessionGroup,
]);
const [input, setInput] = useState('');

return (
<div onClick={(e) => e.stopPropagation()}>
<Modal
allowFullscreen
centered
onCancel={onCancel}
onOk={handleSubmit}
onOk={async (e: MouseEvent<HTMLButtonElement>) => {
if (!input) return;

if (input.length === 0 || input.length > 20)
return message.warning(t('sessionGroup.tooLong'));

const groupId = await addCustomGroup(input);
await updateSessionGroup(id, groupId);
toggleExpandSessionGroup(groupId, true);

message.success(t('sessionGroup.createSuccess'));
onCancel?.(e);
}}
open={open}
title={t('sessionGroup.createGroup')}
width={400}
>
<Input
autoFocus
onChange={(e) => setInput(e.target.value)}
placeholder={t('sessionGroup.inputPlaceholder')}
value={input}
/>
<Flexbox paddingBlock={16}>
<Input
autoFocus
onChange={(e) => setInput(e.target.value)}
placeholder={t('sessionGroup.inputPlaceholder')}
value={input}
/>
</Flexbox>
</Modal>
</div>
);
Expand Down
Loading
Loading