Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/next/components/project/listing.tsx
Views: 687
/*1Show directory in a project based on cached information2in the database.3*/45import { useEffect } from "react";6import useDatabase from "lib/hooks/database";7import { Alert, Card, Table } from "antd";8import Loading from "components/share/loading";9import editURL from "lib/share/edit-url";10import { cmp } from "@cocalc/util/cmp";11import { filename_extension } from "@cocalc/util/misc";12import A from "components/misc/A";13import { join } from "path";14import { file_associations } from "@cocalc/frontend/file-associations";15import { Icon } from "@cocalc/frontend/components/icon";16import { human_readable_size, plural } from "@cocalc/util/misc";1718interface Props {19project_id: string;20path: string;21title?: string; // optional title of the project to show at top22update?: any; // change to force an update of the listing.23sort?: "time" | "size" | "name";24}2526function getQuery(project_id, path) {27return {28listings: { project_id, path, listing: null },29};30}3132export default function Listing({33project_id,34path,35title,36update,37sort,38}: Props) {39const { error, value, loading, query } = useDatabase(40getQuery(project_id, path)41);42useEffect(() => {43// update the listing whenever "update" changes.44query(getQuery(project_id, path));45}, [update, project_id, path]);46return (47<div>48{loading && <Loading />}49{error && <Alert type="error" message={error} showIcon />}50{!loading && !error && (51<FileList52listing={value.listings?.listing ?? []}53project_id={project_id}54path={path}55title={title}56sort={sort}57/>58)}59</div>60);61}6263interface Entry {64name: string;65size: number;66mtime: number;67isdir?: boolean;68}6970interface FileListProps {71project_id: string;72path: string;73title?: string;74listing: Entry[];75sort?: "time" | "size" | "name";76}7778function FileList({ listing, project_id, path, title, sort }: FileListProps) {79let c;80if (sort == "time") {81c = (a, b) => cmp(b.mtime, a.mtime);82} else if (sort == "size") {83c = (a, b) => cmp(a.size, b.size);84} else {85c = (a, b) => cmp(a.name.toLowerCase(), b.name.toLowerCase());86}87const dataSource = listing88.filter((entry) => !entry.name.startsWith("."))89.sort(c);9091const columns = [92{93title: "Type",94dataIndex: "isdir",95key: "isdir",96render: (isdir, entry) => (97<>98<Icon99name={100isdir101? "folder"102: file_associations[filename_extension(entry.name)]?.icon ??103file_associations[""]?.icon104}105/>106{isdir && <Icon name="caret-right" />}107</>108),109},110{111title: "Name",112dataIndex: "name",113key: "name",114render: (_, entry) => (115<A116href={editURL({ project_id, path: join(path, entry.name) })}117external118>119{entry.name}120</A>121),122},123{124title: "Date Modified",125dataIndex: "mtime",126key: "mtime",127render: (mtime) => <>{new Date(mtime * 1000).toLocaleString()}</>,128},129{130title: "Size",131dataIndex: "size",132key: "size",133render: (size, { isdir }) =>134isdir ? `${size} ${plural(size, "item")}` : human_readable_size(size),135},136];137138return (139<Card140style={{ boxShadow:"4px 4px 2px #ddd" }}141title={142title ? (143<div>144Title: <A145external146href={editURL({147type: "collaborator",148project_id,149})}150>151{title}152</A>153</div>154) : (155"Directory Listing"156)157}158>159<div style={{ fontSize: "11pt", marginBottom: "10px" }}>160{path ? path : "Home Directory"}161</div>162<Table163dataSource={dataSource}164columns={columns}165style={{ width: "100%" }}166pagination={{ hideOnSinglePage: true }}167rowKey="name"168/>169</Card>170);171}172173174