@kinvolk/headlamp-plugin
Version:
The needed infrastructure for building Headlamp plugins.
98 lines (97 loc) • 5.7 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/*
* Copyright 2025 The Kubernetes Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import Link from '@mui/material/Link';
import Snackbar from '@mui/material/Snackbar';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import React from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { generatePath, useHistory } from 'react-router-dom';
import { setToken } from '../../lib/auth';
import { getCluster, getClusterPrefixedPath } from '../../lib/cluster';
import { useClustersConf } from '../../lib/k8s';
import { testAuth } from '../../lib/k8s/apiProxy';
import { ClusterDialog } from '../cluster/Chooser';
import { DialogTitle } from '../common/Dialog';
import HeadlampLink from '../common/Link';
export default function AuthToken() {
const history = useHistory();
const clusterConf = useClustersConf();
const [token, setToken] = React.useState('');
const [showError, setShowError] = React.useState(false);
const clusters = useClustersConf();
const { t } = useTranslation();
function onAuthClicked() {
loginWithToken(token).then(code => {
// If successful, redirect.
if (code === 200) {
history.replace(generatePath(getClusterPrefixedPath(), {
cluster: getCluster(),
}));
}
else {
setToken('');
setShowError(true);
}
});
}
return (_jsx(PureAuthToken, { onCancel: () => history.replace('/'), title: Object.keys(clusterConf || {}).length > 1
? t('Authentication: {{ clusterName }}', { clusterName: getCluster() })
: t('Authentication'), token: token, showError: showError, showActions: Object.keys(clusters || {}).length > 1, onChangeToken: (event) => setToken(event.target.value), onAuthClicked: onAuthClicked, onCloseError: () => {
setShowError(false);
} }));
}
export function PureAuthToken({ title, token, showActions, showError, onCancel, onAuthClicked, onChangeToken, onCloseError, }) {
const { t } = useTranslation();
const cluster = getCluster();
const focusedRef = React.useCallback((node) => {
if (node !== null) {
// node.setAttribute('tabindex', '-1');
node.focus();
}
}, []);
function onClose() {
// Do nothing because we're not supposed to close on backdrop click
}
return (_jsxs(Box, { component: "main", children: [_jsxs(ClusterDialog, { useCover: true, onClose: onClose, "aria-labelledby": "authtoken-dialog-title", children: [_jsx(DialogTitle, { id: "authtoken-dialog-title", children: title }), _jsxs(DialogContent, { children: [_jsx(DialogContentText, { children: _jsx(Trans, { t: t, children: "Please paste your authentication token." }) }), _jsx(TextField, { margin: "dense", id: "token", label: t('ID token'), type: "password", size: "small", variant: "outlined", value: token, onChange: onChangeToken, fullWidth: true, ref: focusedRef })] }), _jsxs(DialogActions, { children: [_jsx(Box, { ml: 2, children: _jsx(Typography, { variant: "body2", color: "textSecondary", children: _jsxs(Trans, { t: t, children: ["Check out how to generate a", _jsx(Link, { style: { cursor: 'pointer', marginLeft: '0.4rem' }, target: "_blank", href: "https://headlamp.dev/docs/latest/installation/#create-a-service-account-token", children: "service account token" }), "."] }) }) }), _jsx("div", { style: { flex: '1 0 0' } })] }), _jsx(Box, { overflow: "hidden", textAlign: "center", children: _jsx(HeadlampLink, { routeName: "settingsCluster", params: { clusterID: cluster || '' }, children: t('translation|Cluster settings') }) }), _jsxs(DialogActions, { children: [showActions && (_jsxs(_Fragment, { children: [_jsx(Button, { onClick: onCancel, color: "secondary", variant: "contained", children: t('translation|Cancel') }), _jsx("div", { style: { flex: '1 0 0' } })] })), _jsx(Button, { onClick: onAuthClicked, color: "primary", variant: "contained", children: t('translation|Authenticate') })] })] }), _jsx(Snackbar, { anchorOrigin: {
vertical: 'bottom',
horizontal: 'center',
}, open: showError, autoHideDuration: 5000, onClose: onCloseError, ContentProps: {
'aria-describedby': 'message-id',
}, message: _jsx("span", { id: "message-id", children: t('translation|Error authenticating') }) })] }));
}
async function loginWithToken(token) {
try {
const cluster = getCluster();
if (!cluster) {
// Expectation failed.
return 417;
}
setToken(cluster, token);
await testAuth();
return 200;
}
catch (err) {
console.error(err);
return err.status;
}
}