|
@@ -19,6 +19,7 @@ import { useTranslation } from "react-i18next";
|
|
|
|
|
|
import VisibleKey from "../VisibleKey";
|
|
import VisibleKey from "../VisibleKey";
|
|
import { Chat } from "@/components/Assistant/types";
|
|
import { Chat } from "@/components/Assistant/types";
|
|
|
|
+import NoDataImage from "../NoDataImage";
|
|
|
|
|
|
dayjs.extend(isSameOrAfter);
|
|
dayjs.extend(isSameOrAfter);
|
|
|
|
|
|
@@ -158,7 +159,7 @@ const HistoryList: FC<HistoryListProps> = (props) => {
|
|
ref={listRef}
|
|
ref={listRef}
|
|
id={id}
|
|
id={id}
|
|
className={clsx(
|
|
className={clsx(
|
|
- "h-full overflow-auto px-3 py-2 text-sm bg-[#F3F4F6] dark:bg-[#1F2937]"
|
|
|
|
|
|
+ "flex flex-col h-full overflow-auto px-3 py-2 text-sm bg-[#F3F4F6] dark:bg-[#1F2937]"
|
|
)}
|
|
)}
|
|
>
|
|
>
|
|
<div className="flex gap-1 children:h-8">
|
|
<div className="flex gap-1 children:h-8">
|
|
@@ -197,194 +198,202 @@ const HistoryList: FC<HistoryListProps> = (props) => {
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
- <div className="mt-6">
|
|
|
|
- {Object.entries(sortedList).map(([label, list]) => {
|
|
|
|
- return (
|
|
|
|
- <div key={label}>
|
|
|
|
- <span className="text-xs text-[#999] px-3">{t(label)}</span>
|
|
|
|
-
|
|
|
|
- <ul>
|
|
|
|
- {list.map((item) => {
|
|
|
|
- const { _id, _source } = item;
|
|
|
|
-
|
|
|
|
- const isActive = _id === active?._id;
|
|
|
|
- const title = _source?.title ?? _id;
|
|
|
|
-
|
|
|
|
- return (
|
|
|
|
- <li
|
|
|
|
- key={_id}
|
|
|
|
- id={_id}
|
|
|
|
- className={clsx(
|
|
|
|
- "flex items-center mt-1 h-10 rounded-lg cursor-pointer hover:bg-[#EDEDED] dark:hover:bg-[#353F4D] transition",
|
|
|
|
- {
|
|
|
|
- "!bg-[#E5E7EB] dark:!bg-[#2B3444]": isActive,
|
|
|
|
- }
|
|
|
|
- )}
|
|
|
|
- onClick={() => {
|
|
|
|
- if (!isActive) {
|
|
|
|
- setIsEdit(false);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- onSelect(item);
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- <div
|
|
|
|
- className={clsx("w-1 h-6 rounded-sm bg-[#0072FF]", {
|
|
|
|
- "opacity-0": _id !== active?._id,
|
|
|
|
- })}
|
|
|
|
- />
|
|
|
|
-
|
|
|
|
- <div className="flex-1 flex items-center justify-between gap-2 px-2 overflow-hidden">
|
|
|
|
- {isEdit && isActive ? (
|
|
|
|
- <Input
|
|
|
|
- autoFocus
|
|
|
|
- defaultValue={title}
|
|
|
|
- className="flex-1 -mx-px outline-none bg-transparent border border-[#0061FF] rounded-[4px]"
|
|
|
|
- onKeyDown={(event) => {
|
|
|
|
- if (event.key !== "Enter") return;
|
|
|
|
-
|
|
|
|
- onRename(item._id, event.currentTarget.value);
|
|
|
|
-
|
|
|
|
- setIsEdit(false);
|
|
|
|
- }}
|
|
|
|
- onBlur={(event) => {
|
|
|
|
- onRename(item._id, event.target.value);
|
|
|
|
-
|
|
|
|
|
|
+ {list.length > 0 ? (
|
|
|
|
+ <>
|
|
|
|
+ <div className="mt-6">
|
|
|
|
+ {Object.entries(sortedList).map(([label, list]) => {
|
|
|
|
+ return (
|
|
|
|
+ <div key={label}>
|
|
|
|
+ <span className="text-xs text-[#999] px-3">{t(label)}</span>
|
|
|
|
+
|
|
|
|
+ <ul>
|
|
|
|
+ {list.map((item) => {
|
|
|
|
+ const { _id, _source } = item;
|
|
|
|
+
|
|
|
|
+ const isActive = _id === active?._id;
|
|
|
|
+ const title = _source?.title ?? _id;
|
|
|
|
+
|
|
|
|
+ return (
|
|
|
|
+ <li
|
|
|
|
+ key={_id}
|
|
|
|
+ id={_id}
|
|
|
|
+ className={clsx(
|
|
|
|
+ "flex items-center mt-1 h-10 rounded-lg cursor-pointer hover:bg-[#EDEDED] dark:hover:bg-[#353F4D] transition",
|
|
|
|
+ {
|
|
|
|
+ "!bg-[#E5E7EB] dark:!bg-[#2B3444]": isActive,
|
|
|
|
+ }
|
|
|
|
+ )}
|
|
|
|
+ onClick={() => {
|
|
|
|
+ if (!isActive) {
|
|
setIsEdit(false);
|
|
setIsEdit(false);
|
|
- }}
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ onSelect(item);
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ <div
|
|
|
|
+ className={clsx("w-1 h-6 rounded-sm bg-[#0072FF]", {
|
|
|
|
+ "opacity-0": _id !== active?._id,
|
|
|
|
+ })}
|
|
/>
|
|
/>
|
|
- ) : (
|
|
|
|
- <span className="truncate">{title}</span>
|
|
|
|
- )}
|
|
|
|
-
|
|
|
|
- <div className="flex items-center gap-2">
|
|
|
|
- {isActive && !isEdit && (
|
|
|
|
- <VisibleKey
|
|
|
|
- shortcut="↑↓"
|
|
|
|
- rootClassName="w-6"
|
|
|
|
- shortcutClassName="w-6"
|
|
|
|
- />
|
|
|
|
- )}
|
|
|
|
|
|
|
|
- <Popover>
|
|
|
|
- {isActive && !isEdit && (
|
|
|
|
- <PopoverButton
|
|
|
|
- ref={moreButtonRef}
|
|
|
|
- className="flex gap-2"
|
|
|
|
- >
|
|
|
|
- <VisibleKey
|
|
|
|
- shortcut="O"
|
|
|
|
- onKeyPress={() => {
|
|
|
|
- moreButtonRef.current?.click();
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- <Ellipsis className="size-4 text-[#979797]" />
|
|
|
|
- </VisibleKey>
|
|
|
|
- </PopoverButton>
|
|
|
|
|
|
+ <div className="flex-1 flex items-center justify-between gap-2 px-2 overflow-hidden">
|
|
|
|
+ {isEdit && isActive ? (
|
|
|
|
+ <Input
|
|
|
|
+ autoFocus
|
|
|
|
+ defaultValue={title}
|
|
|
|
+ className="flex-1 -mx-px outline-none bg-transparent border border-[#0061FF] rounded-[4px]"
|
|
|
|
+ onKeyDown={(event) => {
|
|
|
|
+ if (event.key !== "Enter") return;
|
|
|
|
+
|
|
|
|
+ onRename(item._id, event.currentTarget.value);
|
|
|
|
+
|
|
|
|
+ setIsEdit(false);
|
|
|
|
+ }}
|
|
|
|
+ onBlur={(event) => {
|
|
|
|
+ onRename(item._id, event.target.value);
|
|
|
|
+
|
|
|
|
+ setIsEdit(false);
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
|
|
+ ) : (
|
|
|
|
+ <span className="truncate">{title}</span>
|
|
)}
|
|
)}
|
|
|
|
|
|
- <PopoverPanel
|
|
|
|
- anchor="bottom"
|
|
|
|
- className="flex flex-col rounded-lg shadow-md z-100 bg-white dark:bg-[#202126] p-1 border border-black/2 dark:border-white/10"
|
|
|
|
- onClick={(event) => {
|
|
|
|
- event.stopPropagation();
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- {menuItems.map((menuItem) => {
|
|
|
|
- const {
|
|
|
|
- label,
|
|
|
|
- icon: Icon,
|
|
|
|
- shortcut,
|
|
|
|
- iconColor,
|
|
|
|
- onClick,
|
|
|
|
- } = menuItem;
|
|
|
|
-
|
|
|
|
- return (
|
|
|
|
- <button
|
|
|
|
- key={label}
|
|
|
|
- className="flex items-center gap-2 px-3 py-2 text-sm rounded-md hover:bg-[#EDEDED] dark:hover:bg-[#2B2C31] transition"
|
|
|
|
- onClick={onClick}
|
|
|
|
|
|
+ <div className="flex items-center gap-2">
|
|
|
|
+ {isActive && !isEdit && (
|
|
|
|
+ <VisibleKey
|
|
|
|
+ shortcut="↑↓"
|
|
|
|
+ rootClassName="w-6"
|
|
|
|
+ shortcutClassName="w-6"
|
|
|
|
+ />
|
|
|
|
+ )}
|
|
|
|
+
|
|
|
|
+ <Popover>
|
|
|
|
+ {isActive && !isEdit && (
|
|
|
|
+ <PopoverButton
|
|
|
|
+ ref={moreButtonRef}
|
|
|
|
+ className="flex gap-2"
|
|
>
|
|
>
|
|
<VisibleKey
|
|
<VisibleKey
|
|
- shortcut={shortcut}
|
|
|
|
- onKeyPress={onClick}
|
|
|
|
|
|
+ shortcut="O"
|
|
|
|
+ onKeyPress={() => {
|
|
|
|
+ moreButtonRef.current?.click();
|
|
|
|
+ }}
|
|
>
|
|
>
|
|
- <Icon
|
|
|
|
- className="size-4"
|
|
|
|
- style={{
|
|
|
|
- color: iconColor,
|
|
|
|
- }}
|
|
|
|
- />
|
|
|
|
|
|
+ <Ellipsis className="size-4 text-[#979797]" />
|
|
</VisibleKey>
|
|
</VisibleKey>
|
|
-
|
|
|
|
- <span>{t(label)}</span>
|
|
|
|
- </button>
|
|
|
|
- );
|
|
|
|
- })}
|
|
|
|
- </PopoverPanel>
|
|
|
|
- </Popover>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </li>
|
|
|
|
- );
|
|
|
|
- })}
|
|
|
|
- </ul>
|
|
|
|
- </div>
|
|
|
|
- );
|
|
|
|
- })}
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <Dialog
|
|
|
|
- open={isOpen}
|
|
|
|
- onClose={() => setIsOpen(false)}
|
|
|
|
- className="relative z-1000"
|
|
|
|
- >
|
|
|
|
- <div
|
|
|
|
- id="headlessui-popover-panel:delete-history"
|
|
|
|
- className="fixed inset-0 flex items-center justify-center w-screen"
|
|
|
|
- >
|
|
|
|
- <DialogPanel className="flex flex-col justify-between w-[360px] h-[160px] p-3 text-[#333] dark:text-white/90 border border-[#e6e6e6] bg-white dark:bg-[#202126] dark:border-white/10 shadow-xl rounded-lg">
|
|
|
|
- <div className="flex flex-col gap-3">
|
|
|
|
- <DialogTitle className="text-base font-bold">
|
|
|
|
- {t("history_list.delete_modal.title")}
|
|
|
|
- </DialogTitle>
|
|
|
|
- <Description className="text-sm">
|
|
|
|
- {t("history_list.delete_modal.description", {
|
|
|
|
- replace: [active?._source?.title || active?._id],
|
|
|
|
- })}
|
|
|
|
- </Description>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <div className="flex gap-4 self-end">
|
|
|
|
- <VisibleKey
|
|
|
|
- shortcut="N"
|
|
|
|
- shortcutClassName="left-[unset] right-0"
|
|
|
|
- onKeyPress={() => setIsOpen(false)}
|
|
|
|
- >
|
|
|
|
- <button
|
|
|
|
- className="h-8 px-4 text-sm text-[#666666] bg-[#F8F9FA] dark:text-white dark:bg-[#202126] border border-[#E6E6E6] dark:border-white/10 rounded-lg"
|
|
|
|
- onClick={() => setIsOpen(false)}
|
|
|
|
- >
|
|
|
|
- {t("history_list.delete_modal.button.cancel")}
|
|
|
|
- </button>
|
|
|
|
- </VisibleKey>
|
|
|
|
-
|
|
|
|
- <VisibleKey
|
|
|
|
- shortcut="Y"
|
|
|
|
- shortcutClassName="left-[unset] right-0"
|
|
|
|
- onKeyPress={handleRemove}
|
|
|
|
- >
|
|
|
|
- <button
|
|
|
|
- className="h-8 px-4 text-sm text-white bg-[#EF4444] rounded-lg"
|
|
|
|
- onClick={handleRemove}
|
|
|
|
- >
|
|
|
|
- {t("history_list.delete_modal.button.delete")}
|
|
|
|
- </button>
|
|
|
|
- </VisibleKey>
|
|
|
|
|
|
+ </PopoverButton>
|
|
|
|
+ )}
|
|
|
|
+
|
|
|
|
+ <PopoverPanel
|
|
|
|
+ anchor="bottom"
|
|
|
|
+ className="flex flex-col rounded-lg shadow-md z-100 bg-white dark:bg-[#202126] p-1 border border-black/2 dark:border-white/10"
|
|
|
|
+ onClick={(event) => {
|
|
|
|
+ event.stopPropagation();
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ {menuItems.map((menuItem) => {
|
|
|
|
+ const {
|
|
|
|
+ label,
|
|
|
|
+ icon: Icon,
|
|
|
|
+ shortcut,
|
|
|
|
+ iconColor,
|
|
|
|
+ onClick,
|
|
|
|
+ } = menuItem;
|
|
|
|
+
|
|
|
|
+ return (
|
|
|
|
+ <button
|
|
|
|
+ key={label}
|
|
|
|
+ className="flex items-center gap-2 px-3 py-2 text-sm rounded-md hover:bg-[#EDEDED] dark:hover:bg-[#2B2C31] transition"
|
|
|
|
+ onClick={onClick}
|
|
|
|
+ >
|
|
|
|
+ <VisibleKey
|
|
|
|
+ shortcut={shortcut}
|
|
|
|
+ onKeyPress={onClick}
|
|
|
|
+ >
|
|
|
|
+ <Icon
|
|
|
|
+ className="size-4"
|
|
|
|
+ style={{
|
|
|
|
+ color: iconColor,
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
|
|
+ </VisibleKey>
|
|
|
|
+
|
|
|
|
+ <span>{t(label)}</span>
|
|
|
|
+ </button>
|
|
|
|
+ );
|
|
|
|
+ })}
|
|
|
|
+ </PopoverPanel>
|
|
|
|
+ </Popover>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </li>
|
|
|
|
+ );
|
|
|
|
+ })}
|
|
|
|
+ </ul>
|
|
|
|
+ </div>
|
|
|
|
+ );
|
|
|
|
+ })}
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <Dialog
|
|
|
|
+ open={isOpen}
|
|
|
|
+ onClose={() => setIsOpen(false)}
|
|
|
|
+ className="relative z-1000"
|
|
|
|
+ >
|
|
|
|
+ <div
|
|
|
|
+ id="headlessui-popover-panel:delete-history"
|
|
|
|
+ className="fixed inset-0 flex items-center justify-center w-screen"
|
|
|
|
+ >
|
|
|
|
+ <DialogPanel className="flex flex-col justify-between w-[360px] h-[160px] p-3 text-[#333] dark:text-white/90 border border-[#e6e6e6] bg-white dark:bg-[#202126] dark:border-white/10 shadow-xl rounded-lg">
|
|
|
|
+ <div className="flex flex-col gap-3">
|
|
|
|
+ <DialogTitle className="text-base font-bold">
|
|
|
|
+ {t("history_list.delete_modal.title")}
|
|
|
|
+ </DialogTitle>
|
|
|
|
+ <Description className="text-sm">
|
|
|
|
+ {t("history_list.delete_modal.description", {
|
|
|
|
+ replace: [active?._source?.title || active?._id],
|
|
|
|
+ })}
|
|
|
|
+ </Description>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <div className="flex gap-4 self-end">
|
|
|
|
+ <VisibleKey
|
|
|
|
+ shortcut="N"
|
|
|
|
+ shortcutClassName="left-[unset] right-0"
|
|
|
|
+ onKeyPress={() => setIsOpen(false)}
|
|
|
|
+ >
|
|
|
|
+ <button
|
|
|
|
+ className="h-8 px-4 text-sm text-[#666666] bg-[#F8F9FA] dark:text-white dark:bg-[#202126] border border-[#E6E6E6] dark:border-white/10 rounded-lg"
|
|
|
|
+ onClick={() => setIsOpen(false)}
|
|
|
|
+ >
|
|
|
|
+ {t("history_list.delete_modal.button.cancel")}
|
|
|
|
+ </button>
|
|
|
|
+ </VisibleKey>
|
|
|
|
+
|
|
|
|
+ <VisibleKey
|
|
|
|
+ shortcut="Y"
|
|
|
|
+ shortcutClassName="left-[unset] right-0"
|
|
|
|
+ onKeyPress={handleRemove}
|
|
|
|
+ >
|
|
|
|
+ <button
|
|
|
|
+ className="h-8 px-4 text-sm text-white bg-[#EF4444] rounded-lg"
|
|
|
|
+ onClick={handleRemove}
|
|
|
|
+ >
|
|
|
|
+ {t("history_list.delete_modal.button.delete")}
|
|
|
|
+ </button>
|
|
|
|
+ </VisibleKey>
|
|
|
|
+ </div>
|
|
|
|
+ </DialogPanel>
|
|
</div>
|
|
</div>
|
|
- </DialogPanel>
|
|
|
|
|
|
+ </Dialog>
|
|
|
|
+ </>
|
|
|
|
+ ) : (
|
|
|
|
+ <div className="flex items-center justify-center flex-1">
|
|
|
|
+ <NoDataImage />
|
|
</div>
|
|
</div>
|
|
- </Dialog>
|
|
|
|
|
|
+ )}
|
|
</div>
|
|
</div>
|
|
);
|
|
);
|
|
};
|
|
};
|