lobehub / lobe-chat

🤯 Lobe Chat - an open-source, modern-design AI chat framework. Supports Multi AI Providers( OpenAI / Claude 3 / Gemini / Ollama / Azure / DeepSeek), Knowledge Base (file upload / knowledge management / RAG ), Multi-Modals (Vision/TTS) and plugin system. One-click FREE deployment of your private ChatGPT/ Claude application.
https://chat-preview.lobehub.com
Other
44.5k stars 9.98k forks source link

[Request] Option to disable message deletion confirmation #3934

Open Rekkertt opened 2 months ago

Rekkertt commented 2 months ago

🥰 Feature Description

When I want to clean some of my history I need to confirm everytime which I find annoying.

Confirmation

🧐 Proposed Solution

Option to control if you want confirmation before deleting a conversation.

📝 Additional Information

No response

lobehubbot commented 2 months ago

👀 @Rekkertt

Thank you for raising an issue. We will investigate into the matter and get back to you as soon as possible. Please make sure you have given us as much context as possible.\ 非常感谢您提交 issue。我们会尽快调查此事,并尽快回复您。 请确保您已经提供了尽可能多的背景信息。

dosubot[bot] commented 2 months ago

Hey @Rekkertt! 👋 I'm here to assist you with any bugs, questions, or contributions while you wait for a human maintainer. Let's tackle this together!

To add an option to disable the message deletion confirmation dialog, you can introduce a configuration setting that controls whether the confirmation dialog should be shown. Here is how you can modify the existing code to include this option:

  1. Add a new configuration setting in your configuration service.
  2. Modify the onClick handler for the delete action to check this setting before showing the confirmation dialog.

Here's the updated code:

import { ActionIcon, Icon } from '@lobehub/ui';
import { App, Dropdown } from 'antd';
import { createStyles } from 'antd-style';
import { ItemType } from 'antd/es/menu/interface';
import isEqual from 'fast-deep-equal';
import {
  Check,
  HardDriveDownload,
  ListTree,
  LucideCopy,
  LucidePlus,
  MoreVertical,
  Pin,
  PinOff,
  Trash,
} from 'lucide-react';
import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next';

import { isServerMode } from '@/const/version';
import { configService } from '@/services/config';
import { useSessionStore } from '@/store/session';
import { sessionHelpers } from '@/store/session/helpers';
import { sessionGroupSelectors, sessionSelectors } from '@/store/session/selectors';
import { SessionDefaultGroup } from '@/types/session';

const useStyles = createStyles(({ css }) => ({
  modalRoot: css`
    z-index: 2000;
  `,
}));

interface ActionProps {
  group: string | undefined;
  id: string;
  openCreateGroupModal: () => void;
  setOpen: (open: boolean) => void;
}

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

  const sessionCustomGroups = useSessionStore(sessionGroupSelectors.sessionGroupItems, isEqual);
  const [pin, removeSession, pinSession, duplicateSession, updateSessionGroup] = useSessionStore(
    (s) => {
      const session = sessionSelectors.getSessionById(id)(s);
      return [
        sessionHelpers.getSessionPinned(session),
        s.removeSession,
        s.pinSession,
        s.duplicateSession,
        s.updateSessionGroupId,
      ];
    },
  );

  const { modal, message } = App.useApp();

  const isDefault = group === SessionDefaultGroup.Default;
  // const hasDivider = !isDefault || Object.keys(sessionByGroup).length > 0;
const items = useMemo(
    () =>
      (
        [
          {
            icon: <Icon icon={pin ? PinOff : Pin} />,
            key: 'pin',
            label: t(pin ? 'pinOff' : 'pin'),
            onClick: () => {
              pinSession(id, !pin);
            },
          },
          {
            icon: <Icon icon={LucideCopy} />,
            key: 'duplicate',
            label: t('duplicate', { ns: 'common' }),
            onClick: ({ domEvent }) => {
              domEvent.stopPropagation();
duplicateSession(id);
            },
          },
          {
            type: 'divider',
          },
          {
            children: [
              ...sessionCustomGroups.map(({ id: groupId, name }) => ({
                icon: group === groupId ? <Icon icon={Check} /> : <div />,
                key: groupId,
                label: name,
                onClick: () => {
                  updateSessionGroup(id, groupId);
                },
              })),
              {
                icon: isDefault ? <Icon icon={Check} /> : <div />,
                key: 'defaultList',
                label: t('defaultList'),
                onClick: () => {
                  updateSessionGroup(id, SessionDefaultGroup.Default);
                },
              },
              {
                type: 'divider',
              },
              {
                icon: <Icon icon={LucidePlus} />,
                key: 'createGroup',
                label: <div>{t('sessionGroup.createGroup')}</div>,
                onClick: ({ domEvent }) => {
                  domEvent.stopPropagation();
                  openCreateGroupModal();
                },
              },
            ],
            icon: <Icon icon={ListTree} />,
            key: 'moveGroup',
            label: t('sessionGroup.moveGroup'),
          },
          {
            type: 'divider',
          },
          isServerMode
            ? undefined
            : {
                children: [
                  {
                    key: 'agent',
                    label: t('exportType.agent', { ns: 'common' }),
                    onClick: () => {
                      configService.exportSingleAgent(id);
                    },
                  },
                  {
                    key: 'agentWithMessage',
                    label: t('exportType.agentWithMessage', { ns: 'common' }),
                    onClick: () => {
                      configService.exportSingleSession(id);
                    },
                  },
                ],
icon: <Icon icon={HardDriveDownload} />,
                key: 'export',
                label: t('export', { ns: 'common' }),
              },
          {
            danger: true,
            icon: <Icon icon={Trash} />,
            key: 'delete',
            label: t('delete', { ns: 'common' }),
            onClick: ({ domEvent }) => {
              domEvent.stopPropagation();
              const showConfirmation = configService.get('showDeleteConfirmation', true);
              if (showConfirmation) {
                modal.confirm({
                  centered: true,
                  okButtonProps: { danger: true },
                  onOk: async () => {
                    await removeSession(id);
                    message.success(t('confirmRemoveSessionSuccess'));
                  },
                  rootClassName: styles.modalRoot,
                  title: t('confirmRemoveSessionItemAlert'),
                });
              } else {
                removeSession(id);
                message.success(t('confirmRemoveSessionSuccess'));
              }
            },
          },
        ] as ItemType[]
      ).filter(Boolean),
    [id, pin],
  );
return (
    <Dropdown
      arrow={false}
      menu={{
        items,
        onClick: ({ domEvent }) => {
          domEvent.stopPropagation();
        },
      }}
      onOpenChange={setOpen}
      trigger={['click']}
    >
      <ActionIcon
        icon={MoreVertical}
        size={{
          blockSize: 28,
          fontSize: 16,
        }}
      />
    </Dropdown>
  );
});

export default Actions;

In this code, configService.get('showDeleteConfirmation', true) is used to check if the confirmation dialog should be shown. If the setting is true, the confirmation dialog is displayed; otherwise, the session is deleted immediately. You will need to ensure that configService has the appropriate method to get this configuration setting sup>[[1]](https://github.com/lobehub/lobe-chat/blob/main/src/app/(main)/chat/@session/features/SessionListContent/List/Item/Actions.tsx)</sup.

To continue talking to Dosu, mention @dosu.

Lostsite commented 2 months ago

Please keep this conformation, to avoid miss click.

sxjeru commented 2 months ago

May consider temporarily turning off secondary confirmation when messages are deleted continuously.

Rekkertt commented 2 months ago

> Please keep this conformation, to avoid miss click.

I mean an extra option for those who want to disable it or something similair like sxjeru suggested.

arvinxx commented 2 months ago

I perfer to support multi select and then delete