|
1 |
| -/* |
2 |
| - * This file is part of CoCalc: Copyright © 2020 Sagemath, Inc. |
3 |
| - * License: MS-RSL – see LICENSE.md for details |
4 |
| - */ |
5 |
| - |
6 |
| -/* |
7 |
| -Full text search that is better than a simple filter. |
8 |
| -*/ |
9 |
| - |
10 |
| -import { useFrameContext } from "@cocalc/frontend/frame-editors/frame-tree/frame-context"; |
11 |
| -import type { EditorDescription } from "@cocalc/frontend/frame-editors/frame-tree/types"; |
12 |
| -import { Card, Input } from "antd"; |
13 |
| -import { path_split, separate_file_extension, set } from "@cocalc/util/misc"; |
14 |
| -import { useEffect, useMemo, useState } from "react"; |
15 |
| -import { throttle } from "lodash"; |
16 |
| -import useSearchIndex from "./use-search-index"; |
17 |
| -import ShowError from "@cocalc/frontend/components/error"; |
18 | 1 | import StaticMarkdown from "@cocalc/frontend/editors/slate/static-markdown";
|
19 | 2 | import { TimeAgo } from "@cocalc/frontend/components";
|
20 |
| -import { useEditorRedux } from "@cocalc/frontend/app-framework"; |
21 |
| -import type { ChatState } from "@cocalc/frontend/chat/store"; |
22 |
| - |
23 |
| -interface Props { |
24 |
| - font_size: number; |
25 |
| - desc; |
26 |
| -} |
27 |
| - |
28 |
| -function Search({ font_size, desc }: Props) { |
29 |
| - const { project_id, path, actions, id } = useFrameContext(); |
30 |
| - const useEditor = useEditorRedux<ChatState>({ project_id, path }); |
31 |
| - const messages = useEditor("messages"); |
32 |
| - const [indexedMessages, setIndexedMessages] = useState<any>(messages); |
33 |
| - const [search, setSearch] = useState<string>(desc.get("data-search") ?? ""); |
34 |
| - const [result, setResult] = useState<any>(null); |
35 |
| - const saveSearch = useMemo( |
36 |
| - () => |
37 |
| - throttle((search) => { |
38 |
| - if (!actions.isClosed()) { |
39 |
| - actions.set_frame_data({ id, search }); |
40 |
| - } |
41 |
| - }, 250), |
42 |
| - [project_id, path], |
43 |
| - ); |
44 |
| - |
45 |
| - const { error, setError, index, doRefresh, fragmentKey } = useSearchIndex(); |
46 |
| - |
47 |
| - useEffect(() => { |
48 |
| - if (index == null) { |
49 |
| - return; |
50 |
| - } |
51 |
| - if (!search.trim()) { |
52 |
| - setResult([]); |
53 |
| - return; |
54 |
| - } |
55 |
| - (async () => { |
56 |
| - const result = await index.search({ term: search }); |
57 |
| - setResult(result); |
58 |
| - })(); |
59 |
| - }, [search, index]); |
60 |
| - |
61 |
| - useEffect(() => { |
62 |
| - if (indexedMessages != messages) { |
63 |
| - setIndexedMessages(messages); |
64 |
| - doRefresh(); |
65 |
| - } |
66 |
| - }, [messages]); |
| 3 | +import { createSearchEditor } from "@cocalc/frontend/frame-editors/generic/search"; |
67 | 4 |
|
| 5 | +function Preview({ id, content }) { |
68 | 6 | return (
|
69 |
| - <div className="smc-vfill"> |
70 |
| - <Card |
71 |
| - title={ |
72 |
| - <> |
73 |
| - Search Chatroom{" "} |
74 |
| - {separate_file_extension(path_split(path).tail).name} |
75 |
| - </> |
76 |
| - } |
77 |
| - style={{ fontSize: font_size }} |
78 |
| - > |
79 |
| - <ShowError |
80 |
| - error={error} |
81 |
| - setError={setError} |
82 |
| - style={{ marginBottom: "15px" }} |
83 |
| - /> |
84 |
| - <Input.Search |
85 |
| - autoFocus |
86 |
| - allowClear |
87 |
| - placeholder="Search messages..." |
88 |
| - value={search} |
89 |
| - onChange={(e) => { |
90 |
| - const search = e.target.value ?? ""; |
91 |
| - setSearch(search); |
92 |
| - saveSearch(search); |
93 |
| - }} |
94 |
| - /> |
95 |
| - </Card> |
96 |
| - <div className="smc-vfill"> |
97 |
| - <div style={{ overflow: "auto", padding: "15px" }}> |
98 |
| - {result?.hits?.map((hit) => ( |
99 |
| - <SearchResult key={hit.id} hit={hit} actions={actions} fragmentKey={fragmentKey} /> |
100 |
| - ))} |
101 |
| - {result?.hits == null && search?.trim() && <div>No hits</div>} |
102 |
| - </div> |
103 |
| - </div> |
104 |
| - </div> |
105 |
| - ); |
106 |
| -} |
107 |
| - |
108 |
| -function SearchResult({ hit, actions, fragmentKey }) { |
109 |
| - const { document } = hit; |
110 |
| - return ( |
111 |
| - <div |
112 |
| - style={{ |
113 |
| - cursor: "pointer", |
114 |
| - margin: "10px 0", |
115 |
| - padding: "5px", |
116 |
| - border: "1px solid #ccc", |
117 |
| - background: "#f8f8f8", |
118 |
| - borderRadius: "5px", |
119 |
| - maxHeight: "100px", |
120 |
| - overflow: "hidden", |
121 |
| - }} |
122 |
| - onClick={() => { |
123 |
| - actions.gotoFragment({ [fragmentKey]: document.id }); |
124 |
| - }} |
125 |
| - > |
126 |
| - <TimeAgo style={{ float: "right", color: "#888" }} date={parseFloat(document.id)} /> |
| 7 | + <> |
| 8 | + <TimeAgo |
| 9 | + style={{ float: "right", color: "#888" }} |
| 10 | + date={parseFloat(id)} |
| 11 | + /> |
127 | 12 | <StaticMarkdown
|
128 |
| - value={document.content} |
| 13 | + value={content} |
129 | 14 | style={{ marginBottom: "-10px" /* account for <p> */ }}
|
130 | 15 | />
|
131 |
| - </div> |
| 16 | + </> |
132 | 17 | );
|
133 | 18 | }
|
134 | 19 |
|
135 |
| -export const search = { |
136 |
| - type: "search", |
137 |
| - short: "Search", |
138 |
| - name: "Search", |
139 |
| - icon: "comment", |
140 |
| - commands: set(["decrease_font_size", "increase_font_size"]), |
141 |
| - component: Search, |
142 |
| -} as EditorDescription; |
| 20 | +export const search = createSearchEditor({ Preview }); |
0 commit comments