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/frontend/compute/detailed-state.tsx
Views: 687
1
import { Progress, Tooltip } from "antd";
2
import { Icon, TimeAgo } from "@cocalc/frontend/components";
3
import { capitalize } from "@cocalc/util/misc";
4
import { DisplayImage } from "./select-image";
5
import ShowError from "@cocalc/frontend/components/error";
6
import { setDetailedState } from "./api";
7
import SyncButton from "./sync-button";
8
9
const SPEC = {
10
compute: {
11
icon: "server",
12
label: "Compute",
13
tip: "Jupyter kernel and terminal software environment",
14
},
15
filesystem: {
16
icon: "files",
17
label: "Filesystem",
18
tip: "Service that manages mounting and syncing the /home/user filesystem",
19
},
20
"filesystem-sync": {
21
icon: "sync",
22
label: "Sync",
23
// no tip on purpose since button provides tip
24
},
25
"filesystem-cache": {
26
icon: "disk-round",
27
label: "Cache",
28
tip: "Cache frequently read files from project on compute server",
29
},
30
"filesystem-network": {
31
icon: "network-wired",
32
label: "Mount",
33
tip: "Network mounted /home/user filesystem",
34
},
35
vm: {
36
icon: "desktop",
37
label: "Virtual Machine",
38
tip: "Underlying virtual machine on which the compute server containers are running",
39
},
40
install: {
41
icon: "cloud-dev",
42
label: "Install",
43
tip: "Install Docker, Nodejs, and CoCalc software on the compute server",
44
},
45
};
46
47
// order the components
48
const COMPONENTS = [
49
"filesystem-sync",
50
"compute",
51
"vm",
52
"filesystem",
53
"filesystem-cache",
54
"filesystem-network",
55
"install",
56
];
57
58
export default function DetailedState({
59
id,
60
project_id,
61
detailed_state,
62
color,
63
configuration,
64
}) {
65
if (!detailed_state) {
66
return null;
67
}
68
const v: JSX.Element[] = [];
69
for (const name of COMPONENTS) {
70
if (detailed_state[name]) {
71
v.push(
72
<State
73
id={id}
74
project_id={project_id}
75
key={name}
76
name={name}
77
configuration={configuration}
78
{...detailed_state[name]}
79
/>,
80
);
81
}
82
}
83
for (const name in detailed_state) {
84
if (!COMPONENTS.includes(name)) {
85
v.push(
86
<State
87
id={id}
88
project_id={project_id}
89
key={name}
90
name={name}
91
configuration={configuration}
92
{...detailed_state[name]}
93
/>,
94
);
95
}
96
}
97
return (
98
<div style={{ borderTop: `1px solid ${color}`, marginTop: "10px" }}>
99
{v}
100
</div>
101
);
102
}
103
104
function toLabel(name: string) {
105
if (!name) return "";
106
return name
107
.split("-")
108
.map((x) => capitalize(x))
109
.join(" ");
110
}
111
112
function State({
113
name,
114
state,
115
time,
116
expire,
117
progress,
118
extra,
119
configuration,
120
project_id,
121
id,
122
}) {
123
const expired = expire && expire < Date.now();
124
let label;
125
if (name == "filesystem-sync") {
126
let disabled = false;
127
if (configuration?.excludeFromSync != null) {
128
if (
129
configuration.excludeFromSync.includes("~") ||
130
configuration.excludeFromSync.includes(".")
131
) {
132
disabled = true;
133
}
134
}
135
label = (
136
<SyncButton
137
disabled={disabled}
138
size="small"
139
compute_server_id={id}
140
project_id={project_id}
141
time={time}
142
syncing={
143
!extra &&
144
progress <
145
80 /* 80 because the last per for read cache is not sync and sometimes gets stuck */
146
}
147
/>
148
);
149
} else if (name == "compute") {
150
label = <DisplayImage configuration={configuration} />;
151
} else if (SPEC[name]?.label) {
152
label = SPEC[name].label;
153
} else {
154
label = toLabel(name);
155
}
156
157
return (
158
<div
159
style={{
160
borderBottom: "1px solid #ddd",
161
height: "24px",
162
overflow: "hidden",
163
whiteSpace: "nowrap",
164
}}
165
>
166
<div style={{ display: "flex" }}>
167
<Tooltip title={SPEC[name]?.tip}>
168
<div
169
style={{
170
flex: 1,
171
color: expired ? "#aaa" : undefined,
172
}}
173
>
174
{name != "compute" && name != "filesystem-sync" && (
175
<>
176
<Icon
177
name={SPEC[name]?.icon ?? "cube"}
178
style={{ marginRight: "5px" }}
179
/>{" "}
180
</>
181
)}
182
{label}
183
</div>
184
</Tooltip>
185
{!expired && (
186
<>
187
<div style={{ flex: 1 }}>
188
{!expired && <Progress percent={progress ?? 0} size="small" />}
189
</div>
190
<div style={{ flex: 1, textAlign: "center" }}>
191
{state == "ready" ? (
192
"Ready"
193
) : (
194
<Tooltip title={toLabel(state)}>
195
<Icon name="run" />
196
</Tooltip>
197
)}
198
</div>
199
<div
200
style={{
201
flex: 1,
202
textAlign: "center",
203
height: "30px",
204
overflow: "auto",
205
}}
206
>
207
{/* only show time when at least a minute in past to avoid annoying flicker */}
208
{(time ?? 0) < Date.now() - 60 * 1000 && <TimeAgo date={time} />}
209
</div>
210
</>
211
)}
212
</div>
213
{extra && (
214
<div
215
style={{
216
display: "flex",
217
}}
218
>
219
<div style={{ flex: 0.1 }} />
220
<div style={{ flex: 0.9 }}>
221
{state == "error" ? (
222
<ShowError
223
style={{
224
marginBottom: "10px",
225
position: "absolute",
226
maxWidth: "400px",
227
zIndex: 1,
228
}}
229
error={extra}
230
setError={() => {
231
setDetailedState({
232
id,
233
project_id,
234
name,
235
extra: "",
236
state: "ready",
237
});
238
}}
239
/>
240
) : (
241
extra
242
)}
243
</div>
244
</div>
245
)}
246
</div>
247
);
248
}
249
250