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/project/listing.tsx
Views: 687
1
/*
2
Show directory in a project based on cached information
3
in the database.
4
*/
5
6
import { useEffect } from "react";
7
import useDatabase from "lib/hooks/database";
8
import { Alert, Card, Table } from "antd";
9
import Loading from "components/share/loading";
10
import editURL from "lib/share/edit-url";
11
import { cmp } from "@cocalc/util/cmp";
12
import { filename_extension } from "@cocalc/util/misc";
13
import A from "components/misc/A";
14
import { join } from "path";
15
import { file_associations } from "@cocalc/frontend/file-associations";
16
import { Icon } from "@cocalc/frontend/components/icon";
17
import { human_readable_size, plural } from "@cocalc/util/misc";
18
19
interface Props {
20
project_id: string;
21
path: string;
22
title?: string; // optional title of the project to show at top
23
update?: any; // change to force an update of the listing.
24
sort?: "time" | "size" | "name";
25
}
26
27
function getQuery(project_id, path) {
28
return {
29
listings: { project_id, path, listing: null },
30
};
31
}
32
33
export default function Listing({
34
project_id,
35
path,
36
title,
37
update,
38
sort,
39
}: Props) {
40
const { error, value, loading, query } = useDatabase(
41
getQuery(project_id, path)
42
);
43
useEffect(() => {
44
// update the listing whenever "update" changes.
45
query(getQuery(project_id, path));
46
}, [update, project_id, path]);
47
return (
48
<div>
49
{loading && <Loading />}
50
{error && <Alert type="error" message={error} showIcon />}
51
{!loading && !error && (
52
<FileList
53
listing={value.listings?.listing ?? []}
54
project_id={project_id}
55
path={path}
56
title={title}
57
sort={sort}
58
/>
59
)}
60
</div>
61
);
62
}
63
64
interface Entry {
65
name: string;
66
size: number;
67
mtime: number;
68
isdir?: boolean;
69
}
70
71
interface FileListProps {
72
project_id: string;
73
path: string;
74
title?: string;
75
listing: Entry[];
76
sort?: "time" | "size" | "name";
77
}
78
79
function FileList({ listing, project_id, path, title, sort }: FileListProps) {
80
let c;
81
if (sort == "time") {
82
c = (a, b) => cmp(b.mtime, a.mtime);
83
} else if (sort == "size") {
84
c = (a, b) => cmp(a.size, b.size);
85
} else {
86
c = (a, b) => cmp(a.name.toLowerCase(), b.name.toLowerCase());
87
}
88
const dataSource = listing
89
.filter((entry) => !entry.name.startsWith("."))
90
.sort(c);
91
92
const columns = [
93
{
94
title: "Type",
95
dataIndex: "isdir",
96
key: "isdir",
97
render: (isdir, entry) => (
98
<>
99
<Icon
100
name={
101
isdir
102
? "folder"
103
: file_associations[filename_extension(entry.name)]?.icon ??
104
file_associations[""]?.icon
105
}
106
/>
107
{isdir && <Icon name="caret-right" />}
108
</>
109
),
110
},
111
{
112
title: "Name",
113
dataIndex: "name",
114
key: "name",
115
render: (_, entry) => (
116
<A
117
href={editURL({ project_id, path: join(path, entry.name) })}
118
external
119
>
120
{entry.name}
121
</A>
122
),
123
},
124
{
125
title: "Date Modified",
126
dataIndex: "mtime",
127
key: "mtime",
128
render: (mtime) => <>{new Date(mtime * 1000).toLocaleString()}</>,
129
},
130
{
131
title: "Size",
132
dataIndex: "size",
133
key: "size",
134
render: (size, { isdir }) =>
135
isdir ? `${size} ${plural(size, "item")}` : human_readable_size(size),
136
},
137
];
138
139
return (
140
<Card
141
style={{ boxShadow:"4px 4px 2px #ddd" }}
142
title={
143
title ? (
144
<div>
145
Title: <A
146
external
147
href={editURL({
148
type: "collaborator",
149
project_id,
150
})}
151
>
152
{title}
153
</A>
154
</div>
155
) : (
156
"Directory Listing"
157
)
158
}
159
>
160
<div style={{ fontSize: "11pt", marginBottom: "10px" }}>
161
{path ? path : "Home Directory"}
162
</div>
163
<Table
164
dataSource={dataSource}
165
columns={columns}
166
style={{ width: "100%" }}
167
pagination={{ hideOnSinglePage: true }}
168
rowKey="name"
169
/>
170
</Card>
171
);
172
}
173
174