forked from XiaoMo/ChatGPT-Next-Web
feat: #499 revert delete session
This commit is contained in:
parent
806587c8ea
commit
5952064362
@ -12,7 +12,7 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: rgb(51, 51, 51);
|
color: var(--black);
|
||||||
|
|
||||||
&[disabled] {
|
&[disabled] {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
|
@ -59,6 +59,7 @@ export function ChatList() {
|
|||||||
state.removeSession,
|
state.removeSession,
|
||||||
state.moveSession,
|
state.moveSession,
|
||||||
]);
|
]);
|
||||||
|
const chatStore = useChatStore();
|
||||||
|
|
||||||
const onDragEnd: OnDragEndResponder = (result) => {
|
const onDragEnd: OnDragEndResponder = (result) => {
|
||||||
const { destination, source } = result;
|
const { destination, source } = result;
|
||||||
@ -95,10 +96,7 @@ export function ChatList() {
|
|||||||
index={i}
|
index={i}
|
||||||
selected={i === selectedIndex}
|
selected={i === selectedIndex}
|
||||||
onClick={() => selectSession(i)}
|
onClick={() => selectSession(i)}
|
||||||
onDelete={() =>
|
onDelete={chatStore.deleteSession}
|
||||||
(!isMobileScreen() || confirm(Locale.Home.DeleteChat)) &&
|
|
||||||
removeSession(i)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{provided.placeholder}
|
{provided.placeholder}
|
||||||
|
@ -93,6 +93,7 @@ function _Home() {
|
|||||||
state.removeSession,
|
state.removeSession,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
const chatStore = useChatStore();
|
||||||
const loading = !useHasHydrated();
|
const loading = !useHasHydrated();
|
||||||
const [showSideBar, setShowSideBar] = useState(true);
|
const [showSideBar, setShowSideBar] = useState(true);
|
||||||
|
|
||||||
@ -142,11 +143,7 @@ function _Home() {
|
|||||||
<div className={styles["sidebar-action"] + " " + styles.mobile}>
|
<div className={styles["sidebar-action"] + " " + styles.mobile}>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={<CloseIcon />}
|
icon={<CloseIcon />}
|
||||||
onClick={() => {
|
onClick={chatStore.deleteSession}
|
||||||
if (confirm(Locale.Home.DeleteChat)) {
|
|
||||||
removeSession(currentIndex);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles["sidebar-action"]}>
|
<div className={styles["sidebar-action"]}>
|
||||||
|
@ -135,9 +135,25 @@
|
|||||||
box-shadow: var(--card-shadow);
|
box-shadow: var(--card-shadow);
|
||||||
border: var(--border-in-light);
|
border: var(--border-in-light);
|
||||||
color: var(--black);
|
color: var(--black);
|
||||||
padding: 10px 30px;
|
padding: 10px 20px;
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.toast-action {
|
||||||
|
padding-left: 20px;
|
||||||
|
color: var(--primary);
|
||||||
|
opacity: 0.8;
|
||||||
|
border: 0;
|
||||||
|
background: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: inherit;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,17 +110,37 @@ export function showModal(props: ModalProps) {
|
|||||||
root.render(<Modal {...props} onClose={closeModal}></Modal>);
|
root.render(<Modal {...props} onClose={closeModal}></Modal>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ToastProps = { content: string };
|
export type ToastProps = {
|
||||||
|
content: string;
|
||||||
|
action?: {
|
||||||
|
text: string;
|
||||||
|
onClick: () => void;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export function Toast(props: ToastProps) {
|
export function Toast(props: ToastProps) {
|
||||||
return (
|
return (
|
||||||
<div className={styles["toast-container"]}>
|
<div className={styles["toast-container"]}>
|
||||||
<div className={styles["toast-content"]}>{props.content}</div>
|
<div className={styles["toast-content"]}>
|
||||||
|
<span>{props.content}</span>
|
||||||
|
{props.action && (
|
||||||
|
<button
|
||||||
|
onClick={props.action.onClick}
|
||||||
|
className={styles["toast-action"]}
|
||||||
|
>
|
||||||
|
{props.action.text}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showToast(content: string, delay = 3000) {
|
export function showToast(
|
||||||
|
content: string,
|
||||||
|
action?: ToastProps["action"],
|
||||||
|
delay = 3000,
|
||||||
|
) {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.className = styles.show;
|
div.className = styles.show;
|
||||||
document.body.appendChild(div);
|
document.body.appendChild(div);
|
||||||
@ -139,7 +159,7 @@ export function showToast(content: string, delay = 3000) {
|
|||||||
close();
|
close();
|
||||||
}, delay);
|
}, delay);
|
||||||
|
|
||||||
root.render(<Toast content={content} />);
|
root.render(<Toast content={content} action={action} />);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type InputProps = React.HTMLProps<HTMLTextAreaElement> & {
|
export type InputProps = React.HTMLProps<HTMLTextAreaElement> & {
|
||||||
|
@ -47,6 +47,8 @@ const cn = {
|
|||||||
Home: {
|
Home: {
|
||||||
NewChat: "新的聊天",
|
NewChat: "新的聊天",
|
||||||
DeleteChat: "确认删除选中的对话?",
|
DeleteChat: "确认删除选中的对话?",
|
||||||
|
DeleteToast: "已删除会话",
|
||||||
|
Revert: "撤销",
|
||||||
},
|
},
|
||||||
Settings: {
|
Settings: {
|
||||||
Title: "设置",
|
Title: "设置",
|
||||||
|
@ -50,6 +50,8 @@ const en: LocaleType = {
|
|||||||
Home: {
|
Home: {
|
||||||
NewChat: "New Chat",
|
NewChat: "New Chat",
|
||||||
DeleteChat: "Confirm to delete the selected conversation?",
|
DeleteChat: "Confirm to delete the selected conversation?",
|
||||||
|
DeleteToast: "Chat Deleted",
|
||||||
|
Revert: "Revert",
|
||||||
},
|
},
|
||||||
Settings: {
|
Settings: {
|
||||||
Title: "Settings",
|
Title: "Settings",
|
||||||
|
@ -50,6 +50,8 @@ const es: LocaleType = {
|
|||||||
Home: {
|
Home: {
|
||||||
NewChat: "Nuevo chat",
|
NewChat: "Nuevo chat",
|
||||||
DeleteChat: "¿Confirmar eliminación de la conversación seleccionada?",
|
DeleteChat: "¿Confirmar eliminación de la conversación seleccionada?",
|
||||||
|
DeleteToast: "Chat Deleted",
|
||||||
|
Revert: "Revert",
|
||||||
},
|
},
|
||||||
Settings: {
|
Settings: {
|
||||||
Title: "Configuración",
|
Title: "Configuración",
|
||||||
|
@ -50,6 +50,8 @@ const it: LocaleType = {
|
|||||||
Home: {
|
Home: {
|
||||||
NewChat: "Nuova Chat",
|
NewChat: "Nuova Chat",
|
||||||
DeleteChat: "Confermare la cancellazione della conversazione selezionata?",
|
DeleteChat: "Confermare la cancellazione della conversazione selezionata?",
|
||||||
|
DeleteToast: "Chat Deleted",
|
||||||
|
Revert: "Revert",
|
||||||
},
|
},
|
||||||
Settings: {
|
Settings: {
|
||||||
Title: "Impostazioni",
|
Title: "Impostazioni",
|
||||||
|
@ -48,6 +48,8 @@ const tw: LocaleType = {
|
|||||||
Home: {
|
Home: {
|
||||||
NewChat: "新的對話",
|
NewChat: "新的對話",
|
||||||
DeleteChat: "確定要刪除選取的對話嗎?",
|
DeleteChat: "確定要刪除選取的對話嗎?",
|
||||||
|
DeleteToast: "已刪除對話",
|
||||||
|
Revert: "撤銷",
|
||||||
},
|
},
|
||||||
Settings: {
|
Settings: {
|
||||||
Title: "設定",
|
Title: "設定",
|
||||||
|
@ -7,9 +7,10 @@ import {
|
|||||||
requestChatStream,
|
requestChatStream,
|
||||||
requestWithPrompt,
|
requestWithPrompt,
|
||||||
} from "../requests";
|
} from "../requests";
|
||||||
import { trimTopic } from "../utils";
|
import { isMobileScreen, trimTopic } from "../utils";
|
||||||
|
|
||||||
import Locale from "../locales";
|
import Locale from "../locales";
|
||||||
|
import { showToast } from "../components/ui-lib";
|
||||||
|
|
||||||
export type Message = ChatCompletionResponseMessage & {
|
export type Message = ChatCompletionResponseMessage & {
|
||||||
date: string;
|
date: string;
|
||||||
@ -204,6 +205,7 @@ interface ChatStore {
|
|||||||
moveSession: (from: number, to: number) => void;
|
moveSession: (from: number, to: number) => void;
|
||||||
selectSession: (index: number) => void;
|
selectSession: (index: number) => void;
|
||||||
newSession: () => void;
|
newSession: () => void;
|
||||||
|
deleteSession: () => void;
|
||||||
currentSession: () => ChatSession;
|
currentSession: () => ChatSession;
|
||||||
onNewMessage: (message: Message) => void;
|
onNewMessage: (message: Message) => void;
|
||||||
onUserInput: (content: string) => Promise<void>;
|
onUserInput: (content: string) => Promise<void>;
|
||||||
@ -324,6 +326,26 @@ export const useChatStore = create<ChatStore>()(
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
deleteSession() {
|
||||||
|
const deletedSession = get().currentSession();
|
||||||
|
const index = get().currentSessionIndex;
|
||||||
|
const isLastSession = get().sessions.length === 1;
|
||||||
|
if (!isMobileScreen() || confirm(Locale.Home.DeleteChat)) {
|
||||||
|
get().removeSession(index);
|
||||||
|
}
|
||||||
|
showToast(Locale.Home.DeleteToast, {
|
||||||
|
text: Locale.Home.Revert,
|
||||||
|
onClick() {
|
||||||
|
set((state) => ({
|
||||||
|
sessions: state.sessions
|
||||||
|
.slice(0, index)
|
||||||
|
.concat([deletedSession])
|
||||||
|
.concat(state.sessions.slice(index + Number(isLastSession))),
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
currentSession() {
|
currentSession() {
|
||||||
let index = get().currentSessionIndex;
|
let index = get().currentSessionIndex;
|
||||||
const sessions = get().sessions;
|
const sessions = get().sessions;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user