Skip to content

Commit cc06da1

Browse files
committed
side chat: make default shift+enter/button to reply to most recent thread instead of making a new one
- this code sucks but I'm tired and this is important - I saw a dozen examples of students frustrated and confused by the existing chat reply implementation; I hope this helps!
1 parent 55d09a2 commit cc06da1

File tree

3 files changed

+68
-26
lines changed

3 files changed

+68
-26
lines changed

src/packages/frontend/chat/chat-log.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
cmp,
2727
hoursToTimeIntervalHuman,
2828
parse_hashtags,
29+
plural,
2930
search_match,
3031
search_split,
3132
} from "@cocalc/util/misc";
@@ -41,10 +42,16 @@ interface Props {
4142
path: string;
4243
mode: Mode;
4344
scrollToBottomRef?: MutableRefObject<(force?: boolean) => void>;
45+
setLastVisible?: (x: Date | null) => void;
4446
}
4547

46-
export function ChatLog(props: Readonly<Props>) {
47-
const { project_id, path, scrollToBottomRef, mode } = props;
48+
export function ChatLog({
49+
project_id,
50+
path,
51+
scrollToBottomRef,
52+
mode,
53+
setLastVisible,
54+
}: Props) {
4855
const actions: ChatActions = useActions(project_id, path);
4956
const messages = useRedux(["messages"], project_id, path) as ChatMessages;
5057
const fontSize = useRedux(["font_size"], project_id, path);
@@ -92,6 +99,16 @@ export function ChatLog(props: Readonly<Props>) {
9299
account_id,
93100
filterRecentH,
94101
);
102+
// TODO: This is an ugly hack because I'm tired and need to finish this.
103+
// The right solution would be to move this filtering to the store.
104+
// The timeout is because you can't update a component while rendering another one.
105+
setTimeout(() => {
106+
setLastVisible?.(
107+
dates.length == 0
108+
? null
109+
: new Date(parseFloat(dates[dates.length - 1])),
110+
);
111+
}, 1);
95112
return { dates, numFolded };
96113
}, [messages, search, project_id, path, filterRecentH]);
97114

@@ -366,9 +383,11 @@ function NotShowing({ num, search, filterRecentH }: NotShowingProps) {
366383
key="not_showing"
367384
message={
368385
<b>
369-
WARNING: Hiding {num} messages
386+
WARNING: Hiding {num} {plural(num, "message")}
370387
{search.trim()
371-
? ` that do not match search for '${search.trim()}'`
388+
? ` that ${
389+
num != 1 ? "do" : "does"
390+
} not match search for '${search.trim()}'`
372391
: ""}
373392
{timespan
374393
? ` ${

src/packages/frontend/chat/message.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ export default function Message(props: Readonly<Props>) {
688688
}}
689689
type="primary"
690690
>
691-
<Icon name="paper-plane" /> Send
691+
<Icon name="paper-plane" /> Send Reply
692692
</Button>
693693
<LLMCostEstimationChat
694694
llm_cost={llm_cost_reply}

src/packages/frontend/chat/side-chat.tsx

Lines changed: 44 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { Button, Flex, Tooltip } from "antd";
1+
import { Button, Flex, Space, Tooltip } from "antd";
22
import { debounce } from "lodash";
3-
import { CSSProperties, useCallback, useEffect, useRef } from "react";
4-
3+
import { CSSProperties, useCallback, useEffect, useRef, useState } from "react";
54
import {
65
redux,
76
useActions,
@@ -31,6 +30,7 @@ interface Props {
3130
export default function SideChat({ project_id, path, style }: Props) {
3231
const actions: ChatActions = useActions(project_id, path);
3332
const messages = useRedux(["messages"], project_id, path);
33+
const [lastVisible, setLastVisible] = useState<Date | null>(null);
3434
const input: string = useRedux(["input"], project_id, path);
3535
const search: string = useRedux(["search"], project_id, path);
3636
const addCollab: boolean = useRedux(["add_collab"], project_id, path);
@@ -55,11 +55,21 @@ export default function SideChat({ project_id, path, style }: Props) {
5555
markAsRead();
5656
}, []);
5757

58-
const sendChat = useCallback(() => {
59-
const input = submitMentionsRef.current?.();
60-
actions.send_chat({ input });
61-
scrollToBottomRef.current?.(true);
62-
}, [actions]);
58+
const sendChat = useCallback(
59+
(options?) => {
60+
const input = submitMentionsRef.current?.();
61+
actions.send_chat({ input, ...options });
62+
actions.delete_draft(0);
63+
scrollToBottomRef.current?.(true);
64+
setTimeout(() => {
65+
scrollToBottomRef.current?.(true);
66+
}, 10);
67+
setTimeout(() => {
68+
scrollToBottomRef.current?.(true);
69+
}, 1000);
70+
},
71+
[actions],
72+
);
6373

6474
if (messages == null) {
6575
return <Loading />;
@@ -155,25 +165,38 @@ export default function SideChat({ project_id, path, style }: Props) {
155165
path={path}
156166
scrollToBottomRef={scrollToBottomRef}
157167
mode={"sidechat"}
168+
setLastVisible={setLastVisible}
158169
/>
159170
</div>
160171

161172
<div>
162173
{input.trim() ? (
163174
<Flex vertical={false} align="center" justify="space-between">
164175
<Tooltip title="Send message (shift+enter)">
165-
<Button
166-
style={{ margin: "5px 0 5px 5px" }}
167-
onClick={() => {
168-
sendChat();
169-
user_activity("side_chat", "send_chat", "click");
170-
}}
171-
disabled={!input?.trim() || is_uploading}
172-
type="primary"
173-
>
174-
<Icon name="paper-plane" />
175-
Send
176-
</Button>
176+
<Space>
177+
{lastVisible && (
178+
<Button
179+
type="primary"
180+
onClick={() => {
181+
sendChat({ reply_to: new Date(lastVisible) });
182+
}}
183+
>
184+
Reply (shift+enter)
185+
</Button>
186+
)}
187+
<Button
188+
type={!lastVisible ? "primary" : undefined}
189+
style={{ margin: "5px 0 5px 5px" }}
190+
onClick={() => {
191+
sendChat();
192+
user_activity("side_chat", "send_chat", "click");
193+
}}
194+
disabled={!input?.trim() || is_uploading}
195+
>
196+
<Icon name="paper-plane" />
197+
Start New Conversation
198+
</Button>
199+
</Space>
177200
</Tooltip>
178201
<LLMCostEstimationChat
179202
compact
@@ -187,7 +210,7 @@ export default function SideChat({ project_id, path, style }: Props) {
187210
cacheId={`${path}${project_id}-new`}
188211
input={input}
189212
on_send={() => {
190-
sendChat();
213+
sendChat(lastVisible ? { reply_to: lastVisible } : undefined);
191214
user_activity("side_chat", "send_chat", "keyboard");
192215
}}
193216
style={{ height: INPUT_HEIGHT }}

0 commit comments

Comments
 (0)