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/landing/software-libraries.tsx
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2022 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { Divider, Input, Table } from "antd";
7
import { debounce } from "lodash";
8
import { useMemo, useState } from "react";
9
10
import { Paragraph, Text } from "components/misc";
11
import A from "components/misc/A";
12
import { getLibaries } from "lib/landing/get-libraries";
13
import {
14
ComputeComponents,
15
ComputeInventory,
16
Item,
17
LanguageName,
18
SoftwareSpec,
19
} from "lib/landing/types";
20
21
// check if the string is a URL
22
function isURL(url?: string) {
23
return url && url.match(/^(http|https):\/\//);
24
}
25
26
export function renderName(name, record) {
27
const url = record.url;
28
return (
29
<div>
30
<b>{isURL(url) ? <A href={url}>{name}</A> : name}</b>
31
<br />
32
{record.summary}
33
</div>
34
);
35
}
36
37
type Columns = {
38
width: string;
39
title: string;
40
key: string;
41
dataIndex: string;
42
render?: typeof renderName;
43
}[];
44
interface Props {
45
timestamp: string;
46
libWidthPct?: number;
47
spec: SoftwareSpec[LanguageName];
48
inventory: ComputeInventory[LanguageName];
49
components: ComputeComponents[LanguageName];
50
}
51
52
export default function SoftwareLibraries(props: Props) {
53
const { spec, inventory, components, libWidthPct = 60, timestamp } = props;
54
const dataSource = getLibaries(spec, inventory, components);
55
const [search, setSearch] = useState<string>("");
56
const onChange = useMemo(
57
() =>
58
debounce((e) => {
59
setSearch(e.target.value);
60
}, 500),
61
[]
62
);
63
64
let data: Item[];
65
if (!search) {
66
data = dataSource;
67
} else {
68
const s = search.toLowerCase();
69
data = [];
70
for (const x of dataSource) {
71
if (x.search.includes(s)) {
72
data.push(x);
73
}
74
}
75
}
76
77
const columns = useMemo((): Columns => {
78
const envs = Object.entries(spec);
79
const width = (100 - libWidthPct) / envs.length;
80
81
const columns: Columns = [
82
{
83
width: `${libWidthPct}%`,
84
title: "Library",
85
key: "library",
86
dataIndex: "name",
87
render: renderName,
88
},
89
];
90
91
for (const [name, val] of envs) {
92
columns.push({
93
width: `${width}%`,
94
title: val.name,
95
key: name,
96
dataIndex: name,
97
});
98
}
99
100
return columns;
101
}, [libWidthPct]);
102
103
return (
104
<div>
105
<h2>Showing {data.length} libraries</h2>
106
<Input.Search
107
style={{ padding: "0 30px 15px 0", width: "50%", minWidth: "300px" }}
108
placeholder="Search..."
109
allowClear
110
onChange={onChange}
111
onPressEnter={(e) => setSearch((e.target as any).value)}
112
/>
113
<div style={{ overflowX: "auto", width: "100%" }}>
114
<Table
115
columns={columns}
116
bordered
117
pagination={false}
118
rowKey={"index"}
119
dataSource={data}
120
/>
121
</div>
122
<SoftwareSpecTimestamp timestamp={timestamp} />
123
</div>
124
);
125
}
126
127
export function SoftwareSpecTimestamp({ timestamp }: { timestamp: string }) {
128
return (
129
<>
130
<Divider />
131
<Paragraph style={{ textAlign: "center" }}>
132
<Text type="secondary">
133
This information was collected at {timestamp}.
134
</Text>
135
</Paragraph>
136
</>
137
);
138
}
139
140