Skip to content

Commit cdbe1de

Browse files
committed
Merge remote-tracking branch 'origin/master' into store-onprem-price
2 parents 1246267 + 6d53422 commit cdbe1de

File tree

14 files changed

+323
-260
lines changed

14 files changed

+323
-260
lines changed

src/packages/frontend/chat/actions.ts

Lines changed: 44 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import {
3939
toOllamaModel,
4040
type LanguageModel,
4141
} from "@cocalc/util/db-schema/llm-utils";
42-
import { cmp, isValidUUID, parse_hashtags, uuid } from "@cocalc/util/misc";
42+
import { cmp, isValidUUID, uuid } from "@cocalc/util/misc";
4343
import { reuseInFlight } from "@cocalc/util/reuse-in-flight";
4444
import { getSortedDates, getUserName } from "./chat-log";
4545
import { message_to_markdown } from "./message";
@@ -51,7 +51,6 @@ import {
5151
Feedback,
5252
MessageHistory,
5353
} from "./types";
54-
import { getSelectedHashtagsSearch } from "./utils";
5554
import { history_path } from "@cocalc/util/misc";
5655

5756
const MAX_CHATSTREAM = 10;
@@ -193,7 +192,7 @@ export class ChatActions extends Actions<ChatState> {
193192
});
194193
}
195194

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

211210
this.syncdb.commit();
212211

213-
if (folded && msgIndex != null) {
214-
this.scrollToBottom(msgIndex);
212+
if (folded && messageIndex != null) {
213+
this.scrollToBottom(messageIndex);
215214
}
216215
}
217216

@@ -294,40 +293,44 @@ export class ChatActions extends Actions<ChatState> {
294293
// For replies search find full threads not individual messages.
295294
this.setState({
296295
input: "",
297-
search: "",
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-
});
304-
}
305-
this.ensureDraftStartsWithHashtags(false);
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({
@@ -621,38 +624,6 @@ export class ChatActions extends Actions<ChatState> {
621624
? selectedHashtags.delete(tag)
622625
: selectedHashtags.set(tag, state);
623626
this.setState({ selectedHashtags });
624-
this.ensureDraftStartsWithHashtags(true);
625-
}
626-
627-
private ensureDraftStartsWithHashtags(commit: boolean = false): void {
628-
if (this.syncdb == null || this.store == null) return;
629-
// set draft input to match selected hashtags, if any.
630-
const hashtags = this.store.get("selectedHashtags");
631-
if (hashtags == null) return;
632-
const { selectedHashtagsSearch } = getSelectedHashtagsSearch(hashtags);
633-
let input = this.store.get("input");
634-
const prefix = selectedHashtagsSearch.trim() + " ";
635-
if (input.startsWith(prefix)) {
636-
return;
637-
}
638-
const v = parse_hashtags(input);
639-
if (v.length > 0) {
640-
input = input.slice(v[v.length - 1][1]);
641-
}
642-
643-
input = prefix + input;
644-
this.setState({ input });
645-
const sender_id = this.redux.getStore("account").get_account_id();
646-
this.syncdb.set({
647-
event: "draft",
648-
active: Date.now(),
649-
sender_id,
650-
input,
651-
date: 0,
652-
});
653-
if (commit) {
654-
this.syncdb.commit();
655-
}
656627
}
657628

658629
public help() {
@@ -1131,6 +1102,14 @@ export class ChatActions extends Actions<ChatState> {
11311102
foreground_project: true,
11321103
});
11331104
};
1105+
1106+
clearAllFilters = () => {
1107+
this.setState({
1108+
search: "",
1109+
selectedHashtags: immutableMap(),
1110+
filterRecentH: 0,
1111+
});
1112+
};
11341113
}
11351114

11361115
export function getRootMessage(

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

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,31 @@ Render all the messages in the chat.
88
*/
99

1010
import { Alert } from "antd";
11-
import { List, Set as immutableSet } from "immutable";
11+
import { Set as immutableSet } from "immutable";
1212
import { MutableRefObject, useEffect, useMemo, useRef } from "react";
1313
import { Virtuoso, VirtuosoHandle } from "react-virtuoso";
1414
import { chatBotName, isChatBot } from "@cocalc/frontend/account/chatbot";
1515
import {
16-
TypedMap,
1716
useActions,
1817
useRedux,
1918
useTypedRedux,
2019
} from "@cocalc/frontend/app-framework";
2120
import { VisibleMDLG } from "@cocalc/frontend/components";
2221
import useVirtuosoScrollHook from "@cocalc/frontend/components/virtuoso-scroll-hook";
2322
import { HashtagBar } from "@cocalc/frontend/editors/task-editor/hashtag-bar";
24-
import { webapp_client } from "@cocalc/frontend/webapp-client";
2523
import {
2624
cmp,
2725
hoursToTimeIntervalHuman,
2826
parse_hashtags,
2927
plural,
30-
search_match,
31-
search_split,
3228
} from "@cocalc/util/misc";
3329
import { ChatActions, getRootMessage } from "./actions";
3430
import Composing from "./composing";
3531
import Message from "./message";
36-
import { ChatMessageTyped, ChatMessages, MessageHistory, Mode } from "./types";
32+
import type { ChatMessageTyped, ChatMessages, Mode } from "./types";
3733
import { getSelectedHashtagsSearch, newest_content } from "./utils";
3834
import { DivTempHeight } from "@cocalc/frontend/jupyter/cell-list";
35+
import { filterMessages } from "./filter-messages";
3936

4037
interface Props {
4138
project_id: string; // used to render links more effectively
@@ -231,20 +228,11 @@ function isPrevMessageSender(
231228
);
232229
}
233230

234-
// NOTE: I removed search including send name, since that would
235-
// be slower and of questionable value.
236-
function searchMatches(message: ChatMessageTyped, searchTerms): boolean {
237-
const first = message.get("history", List()).first() as
238-
| TypedMap<MessageHistory>
239-
| undefined;
240-
if (first == null) return false;
241-
return search_match(first.get("content", ""), searchTerms);
242-
}
243-
244231
function isThread(messages: ChatMessages, message: ChatMessageTyped) {
245232
if (message.get("reply_to") != null) {
246233
return true;
247234
}
235+
248236
// TODO/WARNING!!! This is a linear search
249237
// through all messages to decide if a message is the root of a thread.
250238
// This is VERY BAD and must to be redone at some point, since we call isThread
@@ -253,9 +241,8 @@ function isThread(messages: ChatMessages, message: ChatMessageTyped) {
253241
// use a proper data structure (or even a cache) to track this once
254242
// and for all. It's more complicated but everything needs to be at
255243
// most O(n).
256-
return messages.some(
257-
(m) => m.get("reply_to") === message.get("date").toISOString(),
258-
);
244+
const s = message.get("date").toISOString();
245+
return messages.some((m) => m.get("reply_to") === s);
259246
}
260247

261248
function isFolded(
@@ -282,21 +269,11 @@ export function getSortedDates(
282269
): { dates: string[]; numFolded: number } {
283270
let numFolded = 0;
284271
let m = messages;
285-
if (m == null) return { dates: [], numFolded: 0 };
286-
287-
if (search) {
288-
const searchTerms = search_split(search);
289-
m = m.filter((message) => searchMatches(message, searchTerms));
272+
if (m == null) {
273+
return { dates: [], numFolded: 0 };
290274
}
291275

292-
if (typeof filterRecentH === "number" && filterRecentH > 0) {
293-
const now = webapp_client.server_time().getTime();
294-
const cutoff = now - filterRecentH * 1000 * 60 * 60;
295-
m = m.filter((msg) => {
296-
const date = msg.get("date").getTime();
297-
return date >= cutoff;
298-
});
299-
}
276+
m = filterMessages({ messages: m, filter: search, filterRecentH });
300277

301278
const v: [date: number, reply_to: number | undefined][] = [];
302279
for (const [date, message] of m) {
@@ -383,7 +360,7 @@ function NotShowing({ num, search, filterRecentH }: NotShowingProps) {
383360
key="not_showing"
384361
message={
385362
<b>
386-
WARNING: Hiding {num} {plural(num, "message")}
363+
WARNING: Hiding {num} {plural(num, "messages")}
387364
{search.trim()
388365
? ` that ${
389366
num != 1 ? "do" : "does"
@@ -406,7 +383,6 @@ export function MessageList({
406383
account_id,
407384
virtuosoRef,
408385
sortedDates,
409-
search,
410386
user_map,
411387
project_id,
412388
path,
@@ -461,10 +437,7 @@ export function MessageList({
461437
}
462438

463439
const is_thread = isThread(messages, message);
464-
// if we search for a message, we treat all threads as unfolded
465-
const force_unfold = !!search;
466-
const is_folded =
467-
!force_unfold && isFolded(messages, message, account_id);
440+
const is_folded = isFolded(messages, message, account_id);
468441
const is_thread_body = message.get("reply_to") != null;
469442
const h = virtuosoHeightsRef.current[index];
470443

@@ -484,7 +457,6 @@ export function MessageList({
484457
actions={actions}
485458
is_thread={is_thread}
486459
is_folded={is_folded}
487-
force_unfold={force_unfold}
488460
is_thread_body={is_thread_body}
489461
is_prev_sender={isPrevMessageSender(
490462
index,

0 commit comments

Comments
 (0)