Skip to content

Commit

Permalink
feat: support edit message and delete message (#51) and improve worki…
Browse files Browse the repository at this point in the history
…ng state
  • Loading branch information
zmh-program committed Jan 29, 2024
1 parent a3a9e5a commit fc391d2
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 44 deletions.
17 changes: 4 additions & 13 deletions app/src/api/conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ export class Conversation {
const idx = ev.index ?? -1;

if (this.isValidIndex(idx)) {
delete this.data[idx];
this.data.splice(idx, 1);

this.sendRemoveEvent(idx);
this.triggerCallback();
}
Expand Down Expand Up @@ -116,21 +117,11 @@ export class Conversation {
}

public sendEditEvent(id: number, message: string) {
this.sendEvent(
"edit",
JSON.stringify({
message: `${id}:${message}`,
}),
);
this.sendEvent("edit", `${id}:${message}`);
}

public sendRemoveEvent(id: number) {
this.sendEvent(
"remove",
JSON.stringify({
message: `${id}`,
}),
);
this.sendEvent("remove", id.toString());
}

public sendShareEvent(refer: string) {
Expand Down
4 changes: 4 additions & 0 deletions app/src/assets/main.less
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ strong {
display: flex;
flex-direction: row;
align-items: center;

&.gold {
color: hsl(var(--gold));
}
}

.flex-dialog {
Expand Down
2 changes: 1 addition & 1 deletion app/src/assets/pages/home.less
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@
transition: 0.2s;
opacity: 0;
border: 1px solid var(--border);
outline: 0;
outline: none;

&:hover {
color: hsl(var(--text));
Expand Down
58 changes: 49 additions & 9 deletions app/src/components/EditorProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useTranslation } from "react-i18next";
import "@/assets/common/editor.less";
import { Textarea } from "./ui/textarea.tsx";
import Markdown from "./Markdown.tsx";
import { useEffect, useRef, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import { Toggle } from "./ui/toggle.tsx";
import { mobile } from "@/utils/device.ts";
import { Button } from "./ui/button.tsx";
Expand All @@ -22,9 +22,25 @@ type RichEditorProps = {
value: string;
onChange: (value: string) => void;
maxLength?: number;

open?: boolean;
setOpen?: (open: boolean) => void;
children?: React.ReactNode;

submittable?: boolean;
onSubmit?: (value: string) => void;
closeOnSubmit?: boolean;
};

function RichEditor({ value, onChange, maxLength }: RichEditorProps) {
function RichEditor({
value,
onChange,
maxLength,
submittable,
onSubmit,
setOpen,
closeOnSubmit,
}: RichEditorProps) {
const { t } = useTranslation();
const input = useRef(null);
const [openPreview, setOpenPreview] = useState(!mobile);
Expand Down Expand Up @@ -113,7 +129,7 @@ function RichEditor({ value, onChange, maxLength }: RichEditorProps) {
>
{openInput && (
<Textarea
placeholder={t("chat.placeholder")}
placeholder={t("chat.placeholder-raw")}
value={value}
className={`editor-input`}
id={`editor`}
Expand All @@ -127,6 +143,26 @@ function RichEditor({ value, onChange, maxLength }: RichEditorProps) {
)}
</div>
</div>
{submittable && (
<div className={`editor-footer mt-2 flex flex-row`}>
<Button
variant={`outline`}
className={`ml-auto mr-2`}
onClick={() => setOpen?.(false)}
>
{t("cancel")}
</Button>
<Button
variant={`default`}
onClick={() => {
onSubmit?.(value);
(closeOnSubmit ?? true) && setOpen?.(false);
}}
>
{t("submit")}
</Button>
</div>
)}
</div>
);
}
Expand All @@ -136,12 +172,16 @@ function EditorProvider(props: RichEditorProps) {

return (
<>
<Dialog>
<DialogTrigger asChild>
<ChatAction text={t("editor")}>
<Maximize className={`h-4 w-4`} />
</ChatAction>
</DialogTrigger>
<Dialog open={props.open} onOpenChange={props.setOpen}>
{!props.setOpen && (
<DialogTrigger asChild>
{props.children ?? (
<ChatAction text={t("editor")}>
<Maximize className={`h-4 w-4`} />
</ChatAction>
)}
</DialogTrigger>
)}
<DialogContent className={`editor-dialog flex-dialog`}>
<DialogHeader>
<DialogTitle>{t("edit")}</DialogTitle>
Expand Down
35 changes: 30 additions & 5 deletions app/src/components/Message.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Message } from "@/api/types.ts";
import Markdown from "@/components/Markdown.tsx";
import {
CalendarCheck2,
CircleSlash,
Cloud,
CloudFog,
Expand All @@ -17,7 +18,7 @@ import {
import { filterMessage } from "@/utils/processor.ts";
import { copyClipboard, saveAsFile, useInputValue } from "@/utils/dom.ts";
import { useTranslation } from "react-i18next";
import { Ref, useMemo, useRef } from "react";
import { Ref, useMemo, useRef, useState } from "react";
import {
DropdownMenu,
DropdownMenuContent,
Expand All @@ -26,6 +27,7 @@ import {
} from "@/components/ui/dropdown-menu.tsx";
import { cn } from "@/components/ui/lib/utils.ts";
import Tips from "@/components/Tips.tsx";
import EditorProvider from "@/components/EditorProvider.tsx";

type MessageProps = {
index: number;
Expand Down Expand Up @@ -68,8 +70,18 @@ function MessageQuota({ message }: MessageQuotaProps) {
return (
message.quota &&
message.quota !== 0 && (
<Tips classNamePopup={`icon-tooltip justify-center`} trigger={trigger}>
<CloudFog className={`h-4 w-4 mr-2`} />
<Tips
classNamePopup={cn(
"icon-tooltip justify-center",
message.plan && "gold",
)}
trigger={trigger}
>
{message.plan ? (
<CalendarCheck2 className={`h-4 w-4 mr-2`} />
) : (
<CloudFog className={`h-4 w-4 mr-2`} />
)}
<p>{message.quota.toFixed(6)}</p>
</Tips>
)
Expand All @@ -80,13 +92,24 @@ function MessageContent({ message, end, index, onEvent }: MessageProps) {
const { t } = useTranslation();
const isAssistant = message.role === "assistant";

const [open, setOpen] = useState(false);
const [editedMessage, setEditedMessage] = useState<string | undefined>("");

return (
<div
className={cn(
"content-wrapper",
isAssistant ? "flex-row" : "flex-row-reverse",
)}
>
<EditorProvider
submittable={true}
onSubmit={(value) => onEvent && onEvent("edit", index, value)}
open={open}
setOpen={setOpen}
value={editedMessage ?? ""}
onChange={setEditedMessage}
/>
<div className={`message-content`}>
{message.content.length ? (
<Markdown children={message.content} />
Expand Down Expand Up @@ -135,11 +158,13 @@ function MessageContent({ message, end, index, onEvent }: MessageProps) {
<MousePointerSquare className={`h-4 w-4 mr-1.5`} />
{t("message.use")}
</DropdownMenuItem>
<DropdownMenuItem>
<DropdownMenuItem onClick={() => setOpen(true)}>
<PencilLine className={`h-4 w-4 mr-1.5`} />
{t("message.edit")}
</DropdownMenuItem>
<DropdownMenuItem>
<DropdownMenuItem
onClick={() => onEvent && onEvent("remove", index)}
>
<Trash className={`h-4 w-4 mr-1.5`} />
{t("message.remove")}
</DropdownMenuItem>
Expand Down
9 changes: 1 addition & 8 deletions app/src/components/home/ChatInterface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ import { chatEvent } from "@/events/chat.ts";
import { addEventListeners } from "@/utils/dom.ts";

type ChatInterfaceProps = {
setWorking?: (working: boolean) => void;
setTarget: (target: HTMLDivElement | null) => void;
};

function ChatInterface({ setTarget, setWorking }: ChatInterfaceProps) {
function ChatInterface({ setTarget }: ChatInterfaceProps) {
const ref = React.useRef(null);
const messages: Message[] = useSelector(selectMessages);
const current: number = useSelector(selectCurrent);
Expand All @@ -29,12 +28,6 @@ function ChatInterface({ setTarget, setWorking }: ChatInterfaceProps) {
[messages],
);

useEffect(() => {
const end = messages[messages.length - 1].end;
const working = messages.length > 0 && !(end === undefined ? true : end);
setWorking?.(working);
}, [messages]);

useEffect(() => {
if (!ref.current) return;
const el = ref.current as HTMLDivElement;
Expand Down
8 changes: 7 additions & 1 deletion app/src/components/home/ChatSpace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
} from "@/components/ui/dialog.tsx";
import { getLanguage } from "@/i18n.ts";
import { selectAuthenticated } from "@/store/auth.ts";
import { docsEndpoint, useDeeptrain } from "@/conf/env.ts";
import { appLogo, docsEndpoint, useDeeptrain } from "@/conf/env.ts";

function ChatSpace() {
const [open, setOpen] = useState(false);
Expand All @@ -32,6 +32,12 @@ function ChatSpace() {

return (
<div className={`chat-product`}>
<img
src={appLogo}
className={`chat-logo h-20 w-20 translate-y-[-2rem]`}
alt={``}
/>

{useDeeptrain && (
<Button variant={`outline`} onClick={() => setOpen(true)}>
<Users2 className={`h-4 w-4 mr-1.5`} />
Expand Down
7 changes: 7 additions & 0 deletions app/src/components/home/ChatWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ type InterfaceProps = {
function Interface(props: InterfaceProps) {
const messages = useSelector(selectMessages);

useEffect(() => {
const end =
messages.length > 0 && (messages[messages.length - 1].end ?? true);
const working = messages.length > 0 && !end;
props.setWorking?.(working);
}, [messages]);

return messages.length > 0 ? <ChatInterface {...props} /> : <ChatSpace />;
}

Expand Down
1 change: 1 addition & 0 deletions app/src/components/home/ConversationSegment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ function ConversationSegment({
}}
>
<DropdownMenuTrigger
className={`outline-none`}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/home/assemblies/ChatInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function ChatInput({
onValueChange(e.target.value);
setMemory("history", e.target.value);
}}
placeholder={t("chat.placeholder")}
placeholder={sender ? t("chat.placeholder-enter") : t("chat.placeholder")}
onKeyDown={async (e) => {
if (e.key === "Enter") {
if (sender || e.ctrlKey) {
Expand Down
3 changes: 3 additions & 0 deletions app/src/resources/i18n/cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"upward": "上移",
"downward": "下移",
"save": "保存",
"submit": "提交",
"announcement": "站点公告",
"i-know": "我已知晓",
"auth": {
Expand Down Expand Up @@ -125,6 +126,8 @@
"web": "联网搜索",
"web-aria": "切换网络搜索功能",
"placeholder": "写点什么... (Ctrl+Enter 发送)",
"placeholder-enter": "写点什么... (Enter 发送)",
"placeholder-raw": "写点什么...",
"recall": "历史复原",
"recall-desc": "检测到您上次有未发送的消息,已经为您恢复。",
"recall-cancel": "取消"
Expand Down
7 changes: 5 additions & 2 deletions app/src/resources/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@
"placeholder": "Write something... (Ctrl+Enter to send)",
"recall": "History Recall",
"recall-desc": "Detected that you have unsent messages last time, has been restored for you.",
"recall-cancel": "Cancel"
"recall-cancel": "Cancel",
"placeholder-enter": "Write something... (Enter to send)",
"placeholder-raw": "Write something..."
},
"message": {
"copy": "Copy Message",
Expand Down Expand Up @@ -617,5 +619,6 @@
"downward": "Move down",
"save": "Save",
"announcement": "Site Announcement",
"i-know": "Yes, I understand."
"i-know": "Yes, I understand.",
"submit": "Send"
}
7 changes: 5 additions & 2 deletions app/src/resources/i18n/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@
"placeholder": "何か書いてください... ( Ctrl + Enterで送信)",
"recall": "履歴の回復",
"recall-desc": "最後に未送信のメッセージが検出され、復元されました。",
"recall-cancel": "キャンセル"
"recall-cancel": "キャンセル",
"placeholder-enter": "何か書いてください... (送信するにはEnterキーを押してください)",
"placeholder-raw": "何か書いてください..."
},
"message": {
"copy": "メッセージをコピー",
Expand Down Expand Up @@ -617,5 +619,6 @@
"downward": "下へ移動",
"save": "保存",
"announcement": "サイトのお知らせ",
"i-know": "私は知っています"
"i-know": "私は知っています",
"submit": "提出"
}
7 changes: 5 additions & 2 deletions app/src/resources/i18n/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@
"placeholder": "Напишите что-нибудь... (Ctrl+Enter для отправки)",
"recall": "История",
"recall-desc": "Обнаружено, что у вас есть неотправленные сообщения в прошлый раз, они были восстановлены для вас.",
"recall-cancel": "Отмена"
"recall-cancel": "Отмена",
"placeholder-enter": "Напишите что-нибудь... (Введите, чтобы отправить)",
"placeholder-raw": "Напишите что-нибудь..."
},
"message": {
"copy": "Копировать сообщение",
Expand Down Expand Up @@ -617,5 +619,6 @@
"downward": "Ниже",
"save": "Сохранить",
"announcement": "Объявление о площадке",
"i-know": "Мне известно о"
"i-know": "Мне известно о",
"submit": "передавать"
}

0 comments on commit fc391d2

Please sign in to comment.