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/admin/site-settings/render-row.tsx
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import { Alert, Button, Popover } from "antd";
7
import { CSSProperties } from "react";
8
import { Icon, LabeledRow, Markdown } from "@cocalc/frontend/components";
9
import StaticMarkdown from "@cocalc/frontend/editors/slate/static-markdown";
10
import { Config, RowType, Tag } from "@cocalc/util/db-schema/site-defaults";
11
import { COLORS } from "@cocalc/util/theme";
12
import { Data, IsReadonly } from "./types";
13
import { RowEntry } from "./row-entry";
14
import { RefreshImagesButton } from "@cocalc/frontend/compute/select-version";
15
16
interface RenderRowProps {
17
name: string;
18
conf: Config;
19
data: Data | null;
20
update: () => void;
21
isReadonly: IsReadonly | null;
22
onChangeEntry: (name: string, value: string) => void;
23
onJsonEntryChange: (name: string, value: string) => void;
24
filterStr: string;
25
filterTag: Tag | null;
26
isModified: (name: string) => boolean;
27
isHeader: boolean;
28
saveSingleSetting: (name: string) => void;
29
}
30
31
export function RenderRow({
32
name,
33
conf,
34
data,
35
update,
36
isReadonly,
37
onChangeEntry,
38
onJsonEntryChange,
39
filterStr,
40
filterTag,
41
isModified,
42
isHeader,
43
saveSingleSetting,
44
}: RenderRowProps) {
45
if (data == null) return null;
46
47
// if tags are used, we're strictly filtering by them
48
if (filterTag) {
49
if (!conf.tags) return null;
50
if (!conf.tags.includes(filterTag)) {
51
return null;
52
}
53
}
54
// otherwise we're (additionally) filtering by the search string
55
if (filterStr) {
56
const { tags, name: title, desc } = conf;
57
const f = filterStr.toLowerCase();
58
const match_any_tag = tags && tags.includes(f as any);
59
const x = [name, title, desc]
60
.join(" ")
61
.toLowerCase()
62
.replace(/-/g, " ")
63
.replace(/_/g, " ");
64
if (!x.includes(f) && !match_any_tag) {
65
return null;
66
}
67
}
68
if (conf.cocalc_only) {
69
if (!document.location.host.endsWith("cocalc.com")) {
70
return null;
71
}
72
}
73
// don't show certain fields, i.e. where show evals to false
74
if (typeof conf.show == "function" && !conf.show(data)) {
75
return null;
76
}
77
78
const rawValue = data[name] ?? conf.default;
79
const rowType: RowType = conf.type ?? "setting";
80
81
// fallbacks: to_display? → to_val? → undefined
82
const parsed_value: string | undefined =
83
typeof conf.to_display == "function"
84
? `${conf.to_display(rawValue)}`
85
: typeof conf.to_val == "function"
86
? `${conf.to_val(rawValue, data)}`
87
: undefined;
88
89
// not currently supported.
90
// const clearable = conf.clearable ?? false;
91
92
const label = (
93
<div style={{ paddingRight: "15px" }}>
94
<strong>{conf.name}</strong> <RowHelp help={conf.help} />
95
<br />
96
<StaticMarkdown style={{ color: COLORS.GRAY_M }} value={conf.desc} />
97
</div>
98
);
99
100
const hint = <RowHint conf={conf} rawValue={rawValue} />;
101
102
let style = { marginTop: "15px", paddingLeft: "10px" } as CSSProperties;
103
// indent optional fields
104
if (typeof conf.show == "function" && rowType == "setting") {
105
style = {
106
...style,
107
borderLeft: `2px solid ${COLORS.GRAY}`,
108
marginLeft: "0px",
109
marginTop: "0px",
110
} as CSSProperties;
111
}
112
113
function renderRowExtra() {
114
if (isHeader) return null;
115
const modified = isModified(name);
116
return (
117
<Button
118
type={modified ? "primary" : "default"}
119
disabled={!modified}
120
size="middle"
121
icon={<Icon name="save" />}
122
onClick={() => saveSingleSetting(name)}
123
/>
124
);
125
}
126
127
return (
128
<LabeledRow
129
label={label}
130
key={name}
131
style={style}
132
label_cols={6}
133
extra={renderRowExtra()}
134
>
135
<RowEntry
136
name={name}
137
value={rawValue}
138
password={conf.password ?? false}
139
displayed_val={parsed_value}
140
valid={conf.valid}
141
hint={hint}
142
rowType={rowType}
143
multiline={conf.multiline}
144
isReadonly={isReadonly}
145
onJsonEntryChange={onJsonEntryChange}
146
onChangeEntry={onChangeEntry}
147
clearable={conf.clearable}
148
update={update}
149
/>
150
{name == "compute_servers_images_spec_url" && (
151
<div>
152
<RefreshImagesButton />
153
<Alert
154
showIcon
155
style={{ margin: "15px" }}
156
type="info"
157
message="Click the above button after updating the images spec URL to clear the cache."
158
/>
159
</div>
160
)}
161
</LabeledRow>
162
);
163
}
164
165
function RowHint({ conf, rawValue }: { conf: Config; rawValue: string }) {
166
if (typeof conf.hint == "function") {
167
return <Markdown value={conf.hint(rawValue)} />;
168
} else {
169
return null;
170
}
171
}
172
173
function RowHelp({ help }: { help?: string }) {
174
if (typeof help !== "string") return null;
175
return (
176
<Popover
177
content={
178
<StaticMarkdown
179
className={"admin-site-setting-popover-help"}
180
style={{ fontSize: "90%" }}
181
value={help}
182
/>
183
}
184
trigger={["hover", "click"]}
185
placement="right"
186
overlayStyle={{ maxWidth: "500px" }}
187
>
188
<Icon style={{ color: COLORS.GRAY }} name="question-circle" />
189
</Popover>
190
);
191
}
192
193