CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/next/components/support/recent-files.tsx
Views: 687
1
/*
2
Note: The TreeSelect component we use below has numerous accessibility
3
issues, which are being tracked upstream:
4
5
https://github.com/ant-design/ant-design/issues/22343
6
7
This component significantly degrades our lighthouse accessibility
8
score for this page.
9
*/
10
11
import { ReactNode, useEffect, useState } from "react";
12
import useAPI from "lib/hooks/api";
13
import Loading from "components/share/loading";
14
import { Alert, TreeSelect } from "antd";
15
import { Placeholder } from "./util";
16
17
interface Node {
18
title: ReactNode;
19
value: string;
20
children?: Node[];
21
}
22
23
interface Props {
24
interval?: string; // postgreSQL interval, e.g., "1 day"
25
onChange?: (value: { project_id: string; path?: string }[]) => void;
26
}
27
28
export default function RecentFiles({ interval, onChange }: Props) {
29
const { result, error } = useAPI("file-access", {
30
interval: interval ?? "1 day",
31
});
32
const [treeData, setTreeData] = useState<Node[]>([]);
33
34
useEffect(() => {
35
if (!result) return;
36
37
// organize the files by project:
38
const projects: {
39
[project_id: string]: {
40
path: string;
41
title: string;
42
project_id: string;
43
}[];
44
} = {};
45
for (const file of result.files ?? []) {
46
if (projects[file.project_id] == null) {
47
projects[file.project_id] = [file];
48
} else {
49
projects[file.project_id].push(file);
50
}
51
}
52
53
const treeData: Node[] = [];
54
for (const project_id in projects) {
55
const files = projects[project_id];
56
if (files.length == 0) continue;
57
const children: Node[] = [];
58
treeData.push({
59
title: (
60
<>
61
Project: <b>{files[0].title}</b>
62
</>
63
),
64
value: files[0].project_id,
65
children,
66
});
67
for (const file of files) {
68
children.push({
69
title: file.path,
70
value: file.project_id + file.path,
71
});
72
}
73
}
74
75
setTreeData(treeData);
76
}, [result]);
77
78
return (
79
<div>
80
{error && <Alert type="error" message={error} />}
81
{result == null ? (
82
<Loading />
83
) : (
84
<>
85
<TreeSelect
86
style={{ width: "100%" }}
87
treeData={treeData}
88
placeholder={
89
<Placeholder>Search for relevant files...</Placeholder>
90
}
91
allowClear
92
multiple
93
treeDefaultExpandAll={true}
94
showSearch
95
dropdownStyle={{ maxHeight: 400, overflow: "auto" }}
96
onChange={(selected: string[]) => {
97
if (!onChange) return;
98
const v: { project_id: string; path?: string }[] = [];
99
for (const value of selected) {
100
const project_id = value.slice(0, 36);
101
if (value.length <= 36) {
102
v.push({ project_id });
103
} else {
104
const path = value.slice(36);
105
v.push({ project_id, path });
106
}
107
}
108
onChange(v);
109
}}
110
/>
111
</>
112
)}
113
</div>
114
);
115
}
116
117