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/row-entry.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 humanizeList from "humanize-list";
7
import { CopyToClipBoard } from "@cocalc/frontend/components";
8
import { SERVER_SETTINGS_ENV_PREFIX } from "@cocalc/util/consts";
9
import { ConfigValid, RowType } from "@cocalc/util/db-schema/site-defaults";
10
import { version } from "@cocalc/util/smc-version";
11
import { ON_PREM_DEFAULT_QUOTAS, upgrades } from "@cocalc/util/upgrade-spec";
12
import { JsonEditor } from "../json-editor";
13
import { RowEntryInner, testIsInvalid } from "./row-entry-inner";
14
import { IsReadonly } from "./types";
15
16
const MAX_UPGRADES = upgrades.max_per_project;
17
18
const FIELD_DEFAULTS = {
19
default_quotas: ON_PREM_DEFAULT_QUOTAS,
20
max_upgrades: MAX_UPGRADES,
21
} as const;
22
23
export interface RowEntryInnerProps {
24
name: string;
25
value: string; // value is the rawValue (a string)
26
valid?: ConfigValid;
27
password: boolean;
28
multiline?: number;
29
isReadonly: IsReadonly | null;
30
onChangeEntry: (name: string, value: string) => void;
31
clearable?: boolean;
32
update: () => void;
33
}
34
35
interface RowEntryProps extends RowEntryInnerProps {
36
displayed_val?: string; // the processed rawValue
37
hint?: JSX.Element;
38
rowType?: RowType;
39
onJsonEntryChange: (name: string, value?: string) => void;
40
onChangeEntry: (name: string, value: string) => void;
41
}
42
43
export function RowEntry({
44
name,
45
value,
46
password,
47
displayed_val,
48
valid,
49
hint,
50
rowType,
51
multiline,
52
isReadonly,
53
onJsonEntryChange,
54
onChangeEntry,
55
clearable,
56
update,
57
}: RowEntryProps) {
58
if (isReadonly == null) return null; // typescript
59
60
function ReadOnly({ readonly }) {
61
if (readonly) {
62
return (
63
<>
64
Value controlled via{" "}
65
<code>
66
${SERVER_SETTINGS_ENV_PREFIX}_{name.toUpperCase()}
67
</code>
68
.
69
</>
70
);
71
} else {
72
return null;
73
}
74
}
75
76
if (rowType == "header") {
77
return <div />;
78
} else {
79
switch (name) {
80
case "default_quotas":
81
case "max_upgrades":
82
const ro: boolean = isReadonly[name];
83
return (
84
<>
85
<JsonEntry
86
name={name}
87
data={value}
88
readonly={ro}
89
onJsonEntryChange={onJsonEntryChange}
90
/>
91
<ReadOnly readonly={ro} />
92
</>
93
);
94
default:
95
const is_valid = !testIsInvalid(value, valid);
96
return (
97
<div>
98
<RowEntryInner
99
name={name}
100
value={value}
101
valid={valid}
102
password={password}
103
multiline={multiline}
104
onChangeEntry={onChangeEntry}
105
isReadonly={isReadonly}
106
clearable={clearable}
107
update={update}
108
/>
109
<div style={{ fontSize: "90%", display: "inlineBlock" }}>
110
{!Array.isArray(value) &&
111
name === "version_recommended_browser" ? (
112
<VersionHint value={value} />
113
) : undefined}
114
{hint}
115
<ReadOnly readonly={isReadonly[name]} />
116
{displayed_val != null && (
117
<span>
118
{" "}
119
{is_valid ? "Interpreted as" : "Invalid:"}{" "}
120
<code>{displayed_val}</code>.{" "}
121
</span>
122
)}
123
{valid != null && Array.isArray(valid) && (
124
<span>Valid values: {humanizeList(valid)}.</span>
125
)}
126
</div>
127
</div>
128
);
129
}
130
}
131
}
132
133
function VersionHint({ value }: { value: string }) {
134
let error;
135
if (new Date(parseInt(value) * 1000) > new Date()) {
136
error = (
137
<div
138
style={{
139
background: "red",
140
color: "white",
141
margin: "15px",
142
padding: "15px",
143
}}
144
>
145
INVALID version - it is in the future!!
146
</div>
147
);
148
} else {
149
error = undefined;
150
}
151
return (
152
<div style={{ marginTop: "15px", color: "#666" }}>
153
Your browser version:{" "}
154
<CopyToClipBoard
155
style={{
156
display: "inline-block",
157
width: "50ex",
158
margin: 0,
159
}}
160
value={`${version}`}
161
/>{" "}
162
{error}
163
</div>
164
);
165
}
166
167
// This is specific to on-premises kubernetes setups.
168
// The production site works differently.
169
// TODO: make this a more sophisticated data editor.
170
function JsonEntry({ name, data, readonly, onJsonEntryChange }) {
171
const jval = JSON.parse(data ?? "{}") ?? {};
172
const dflt = FIELD_DEFAULTS[name];
173
const quotas = { ...dflt, ...jval };
174
const value = JSON.stringify(quotas);
175
return (
176
<JsonEditor
177
value={value}
178
readonly={readonly}
179
rows={10}
180
onSave={(value) => onJsonEntryChange(name, value)}
181
/>
182
);
183
}
184
185