Skip to content

Commit be70ef5

Browse files
committed
frontend: add node shell
Fixes headlamp-k8s#996 Signed-off-by: farodin91 <github@jan-jansen.net>
1 parent b52f766 commit be70ef5

File tree

19 files changed

+431
-146
lines changed

19 files changed

+431
-146
lines changed

frontend/src/components/App/Settings/SettingsCluster.tsx

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import React from 'react';
66
import { useTranslation } from 'react-i18next';
77
import { useDispatch } from 'react-redux';
88
import { useHistory } from 'react-router-dom';
9-
import helpers, { ClusterSettings } from '../../../helpers';
9+
import helpers, { ClusterSettings, DEFAULT_NODE_SHELL_LINUX_IMAGE } from '../../../helpers';
1010
import { useCluster, useClustersConf } from '../../../lib/k8s';
1111
import { deleteCluster } from '../../../lib/k8s/apiProxy';
1212
import { setConfig } from '../../../redux/configSlice';
@@ -53,6 +53,7 @@ export default function SettingsCluster() {
5353
const { t } = useTranslation(['translation']);
5454
const [defaultNamespace, setDefaultNamespace] = React.useState('default');
5555
const [userDefaultNamespace, setUserDefaultNamespace] = React.useState('');
56+
const [nodeShellLinuxImage, setNodeShellLinuxImage] = React.useState('');
5657
const [newAllowedNamespace, setNewAllowedNamespace] = React.useState('');
5758
const [clusterSettings, setClusterSettings] = React.useState<ClusterSettings | null>(null);
5859
const classes = useStyles();
@@ -127,10 +128,32 @@ export default function SettingsCluster() {
127128
};
128129
}, [userDefaultNamespace]);
129130

131+
React.useEffect(() => {
132+
let timeoutHandle: NodeJS.Timeout | null = null;
133+
134+
if (isEditingNodeShellLinuxImage()) {
135+
// We store the node shell image after a timeout.
136+
timeoutHandle = setTimeout(() => {
137+
storeNewNodeShellLinuxImage(nodeShellLinuxImage);
138+
}, 1000);
139+
}
140+
141+
return () => {
142+
if (timeoutHandle) {
143+
clearTimeout(timeoutHandle);
144+
timeoutHandle = null;
145+
}
146+
};
147+
}, [nodeShellLinuxImage]);
148+
130149
function isEditingDefaultNamespace() {
131150
return clusterSettings?.defaultNamespace !== userDefaultNamespace;
132151
}
133152

153+
function isEditingNodeShellLinuxImage() {
154+
return clusterSettings?.nodeShellLinuxImage !== nodeShellLinuxImage;
155+
}
156+
134157
if (!cluster) {
135158
return null;
136159
}
@@ -163,6 +186,14 @@ export default function SettingsCluster() {
163186
});
164187
}
165188

189+
function storeNewNodeShellLinuxImage(image: string) {
190+
setClusterSettings((settings: ClusterSettings | null) => {
191+
const newSettings = { ...(settings || {}) };
192+
newSettings.nodeShellLinuxImage = image;
193+
return newSettings;
194+
});
195+
}
196+
166197
const isValidDefaultNamespace = isValidNamespaceFormat(userDefaultNamespace);
167198
const isValidNewAllowedNamespace = isValidNamespaceFormat(newAllowedNamespace);
168199
const invalidNamespaceMessage = t(
@@ -295,6 +326,35 @@ export default function SettingsCluster() {
295326
</>
296327
),
297328
},
329+
{
330+
name: t('translation|Node Shell Linux Image'),
331+
value: (
332+
<TextField
333+
onChange={event => {
334+
let value = event.target.value;
335+
value = value.replace(' ', '');
336+
setNodeShellLinuxImage(value);
337+
}}
338+
value={nodeShellLinuxImage}
339+
placeholder={DEFAULT_NODE_SHELL_LINUX_IMAGE}
340+
helperText={t(
341+
'translation|The default image is used for dropping a shell into a node (when not specified directly).'
342+
)}
343+
InputProps={{
344+
endAdornment: isEditingNodeShellLinuxImage() ? (
345+
<Icon
346+
width={24}
347+
color={theme.palette.text.secondary}
348+
icon="mdi:progress-check"
349+
/>
350+
) : (
351+
<Icon width={24} icon="mdi:check-bold" />
352+
),
353+
className: classes.input,
354+
}}
355+
/>
356+
),
357+
},
298358
]}
299359
/>
300360
</SectionBox>

0 commit comments

Comments
 (0)