Skip to content

Commit ca48b4c

Browse files
committed
fix #7748 -- chat: finish changing chat filtering to be on the thread level, rather than each message
1 parent 88dbf97 commit ca48b4c

File tree

5 files changed

+65
-48
lines changed

5 files changed

+65
-48
lines changed

src/packages/frontend/chat/actions.ts

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ export class ChatActions extends Actions<ChatState> {
192192
});
193193
}
194194

195-
public foldThread(reply_to: Date, msgIndex: number) {
195+
public foldThread(reply_to: Date, messageIndex?: number) {
196196
if (this.syncdb == null) return;
197197
const account_id = this.redux.getStore("account").get_account_id();
198198
const cur = this.syncdb.get_one({ event: "chat", date: reply_to });
@@ -209,8 +209,8 @@ export class ChatActions extends Actions<ChatState> {
209209

210210
this.syncdb.commit();
211211

212-
if (folded && msgIndex != null) {
213-
this.scrollToBottom(msgIndex);
212+
if (folded && messageIndex != null) {
213+
this.scrollToBottom(messageIndex);
214214
}
215215
}
216216

@@ -293,41 +293,44 @@ export class ChatActions extends Actions<ChatState> {
293293
// For replies search find full threads not individual messages.
294294
this.setState({
295295
input: "",
296-
search: "",
297-
selectedHashtags: immutableMap(),
298296
});
297+
this.clearAllFilters();
299298
} else {
300-
// TODO: but until we improve search to be by thread (instead of by message), do this:
301-
this.setState({
302-
search: "",
303-
selectedHashtags: immutableMap(),
304-
});
305-
}
306-
307-
if (this.store != null) {
308-
const project_id = this.store?.get("project_id");
309-
const path = this.store?.get("path");
310-
// set notification saying that we sent an actual chat
311-
let action;
299+
// when replying we make sure that the thread is expanded, since otherwise
300+
// our reply won't be visible
301+
const messages = this.store.get("messages");
312302
if (
313-
noNotification ||
314-
mentionsLanguageModel(input) ||
315-
this.isLanguageModelThread(reply_to)
303+
messages
304+
?.getIn([`${reply_to.valueOf()}`, "folding"])
305+
?.includes(sender_id)
316306
) {
317-
// Note: don't mark it is a chat if it is with chatgpt,
318-
// since no point in notifying all collabs of this.
319-
action = "edit";
320-
} else {
321-
action = "chat";
307+
this.foldThread(reply_to);
322308
}
323-
webapp_client.mark_file({
324-
project_id,
325-
path,
326-
action,
327-
ttl: 10000,
328-
});
329-
track("send_chat", { project_id, path });
330309
}
310+
311+
const project_id = this.store?.get("project_id");
312+
const path = this.store?.get("path");
313+
// set notification saying that we sent an actual chat
314+
let action;
315+
if (
316+
noNotification ||
317+
mentionsLanguageModel(input) ||
318+
this.isLanguageModelThread(reply_to)
319+
) {
320+
// Note: don't mark it is a chat if it is with chatgpt,
321+
// since no point in notifying all collabs of this.
322+
action = "edit";
323+
} else {
324+
action = "chat";
325+
}
326+
webapp_client.mark_file({
327+
project_id,
328+
path,
329+
action,
330+
ttl: 10000,
331+
});
332+
track("send_chat", { project_id, path });
333+
331334
this.save_to_disk();
332335
(async () => {
333336
await this.processLLM({
@@ -1099,6 +1102,14 @@ export class ChatActions extends Actions<ChatState> {
10991102
foreground_project: true,
11001103
});
11011104
};
1105+
1106+
clearAllFilters = () => {
1107+
this.setState({
1108+
search: "",
1109+
selectedHashtags: immutableMap(),
1110+
filterRecentH: 0,
1111+
});
1112+
};
11021113
}
11031114

11041115
export function getRootMessage(

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

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ function isThread(messages: ChatMessages, message: ChatMessageTyped) {
232232
if (message.get("reply_to") != null) {
233233
return true;
234234
}
235+
235236
// TODO/WARNING!!! This is a linear search
236237
// through all messages to decide if a message is the root of a thread.
237238
// This is VERY BAD and must to be redone at some point, since we call isThread
@@ -240,9 +241,8 @@ function isThread(messages: ChatMessages, message: ChatMessageTyped) {
240241
// use a proper data structure (or even a cache) to track this once
241242
// and for all. It's more complicated but everything needs to be at
242243
// most O(n).
243-
return messages.some(
244-
(m) => m.get("reply_to") === message.get("date").toISOString(),
245-
);
244+
const s = message.get("date").toISOString();
245+
return messages.some((m) => m.get("reply_to") === s);
246246
}
247247

248248
function isFolded(
@@ -383,7 +383,6 @@ export function MessageList({
383383
account_id,
384384
virtuosoRef,
385385
sortedDates,
386-
search,
387386
user_map,
388387
project_id,
389388
path,
@@ -438,10 +437,7 @@ export function MessageList({
438437
}
439438

440439
const is_thread = isThread(messages, message);
441-
// if we search for a message, we treat all threads as unfolded
442-
const force_unfold = !!search;
443-
const is_folded =
444-
!force_unfold && isFolded(messages, message, account_id);
440+
const is_folded = isFolded(messages, message, account_id);
445441
const is_thread_body = message.get("reply_to") != null;
446442
const h = virtuosoHeightsRef.current[index];
447443

@@ -461,7 +457,6 @@ export function MessageList({
461457
actions={actions}
462458
is_thread={is_thread}
463459
is_folded={is_folded}
464-
force_unfold={force_unfold}
465460
is_thread_body={is_thread_body}
466461
is_prev_sender={isPrevMessageSender(
467462
index,

src/packages/frontend/chat/filter-messages.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,36 @@ export function filterMessages({
2020
filter?: string;
2121
filterRecentH?: number;
2222
}) {
23+
let messages0 = messages;
2324
if (filter) {
2425
const searchTerms = search_split(filter);
25-
messages = messages.filter((message) =>
26+
messages0 = messages0.filter((message) =>
2627
searchMatches(message, searchTerms),
2728
);
2829
}
2930

3031
if (typeof filterRecentH === "number" && filterRecentH > 0) {
3132
const now = webapp_client.server_time().getTime();
3233
const cutoff = now - filterRecentH * 1000 * 60 * 60;
33-
messages = messages.filter((msg) => {
34-
const date = msg.get("date").getTime();
34+
messages0 = messages0.filter((message) => {
35+
const date = message.get("date").getTime();
3536
return date >= cutoff;
3637
});
3738
}
3839

39-
return messages;
40+
if (messages0.size == 0) {
41+
// nothing matches
42+
return messages0;
43+
}
44+
45+
// Next, we expand to include all threads containing any matching messages.
46+
// First find the roots of all matching threads:
47+
const roots = new Set<string>();
48+
for (const [_, message] of messages0) {
49+
roots.add(message.get("reply_to") ?? message.get("date").toISOString());
50+
}
51+
// Return all messages in these threads
52+
return messages.filter((message) => roots.has(message.get("reply_to") ?? message.get("date").toISOString()));
4053
}
4154

4255
// NOTE: I removed search including send name, since that would

src/packages/frontend/chat/message.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,13 @@ interface Props {
122122
is_thread?: boolean; // if true, there is a thread starting in a reply_to message
123123
is_folded?: boolean; // if true, only show the reply_to root message
124124
is_thread_body: boolean;
125-
force_unfold?: boolean; // if true, all threads are temporarily forced to be unfolded
126125

127126
llm_cost_reply?: [number, number] | null;
128127
}
129128

130129
export default function Message(props: Readonly<Props>) {
131130
const {
132131
is_folded,
133-
force_unfold,
134132
is_thread_body,
135133
is_thread,
136134
llm_cost_reply,
@@ -882,7 +880,6 @@ export default function Message(props: Readonly<Props>) {
882880
<Button
883881
type="text"
884882
style={style}
885-
disabled={force_unfold}
886883
onClick={() =>
887884
props.actions?.foldThread(message.get("date"), props.index)
888885
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ export default function SideChat({ project_id, path, style }: Props) {
212212
on_send={() => {
213213
sendChat(lastVisible ? { reply_to: lastVisible } : undefined);
214214
user_activity("side_chat", "send_chat", "keyboard");
215+
actions?.clearAllFilters();
215216
}}
216217
style={{ height: INPUT_HEIGHT }}
217218
height={INPUT_HEIGHT}

0 commit comments

Comments
 (0)