UNPKG

@kinvolk/headlamp-plugin

Version:

The needed infrastructure for building Headlamp plugins.

130 lines (129 loc) 6.38 kB
import { jsx as _jsx, jsxs as _jsxs } 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 { Icon } from '@iconify/react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import { useTheme } from '@mui/material/styles'; import Typography from '@mui/material/Typography'; import { useTranslation } from 'react-i18next'; import { generatePath, useHistory } from 'react-router-dom'; import { formatClusterPathParam } from '../../../lib/cluster'; import { getClusterPrefixedPath } from '../../../lib/util'; import Link from '../../common/Link'; import Table from '../../common/Table'; import ClusterContextMenu from './ClusterContextMenu'; import { MULTI_HOME_ENABLED } from './config'; /** * ClusterStatus component displays the status of a cluster. * It shows an icon and a message indicating whether the cluster is active, unknown, or has an error. * * @param {Object} props - The component props. * @param {ApiError|null} [props.error] - The error object if there is an error with the cluster. */ function ClusterStatus({ error }) { const { t } = useTranslation(['translation']); const theme = useTheme(); const stateUnknown = error === undefined; const hasReachError = error && error.status !== 401 && error.status !== 403; return (_jsx(Box, { width: "fit-content", children: _jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "center", children: [hasReachError ? (_jsx(Icon, { icon: "mdi:cloud-off", width: 16, color: theme.palette.home.status.error })) : stateUnknown ? (_jsx(Icon, { icon: "mdi:cloud-question", width: 16, color: theme.palette.home.status.unknown })) : (_jsx(Icon, { icon: "mdi:cloud-check-variant", width: 16, color: theme.palette.home.status.success })), _jsx(Typography, { variant: "body2", style: { marginLeft: theme.spacing(1), color: hasReachError ? theme.palette.home.status.error : !stateUnknown ? theme.palette.home.status.success : undefined, }, children: hasReachError ? error.message : stateUnknown ? '⋯' : t('translation|Active') })] }) })); } /** * ClusterTable component displays a table of clusters with their status, origin, and version. */ export default function ClusterTable({ customNameClusters, versions, errors, clusters, warningLabels, }) { const history = useHistory(); const { t } = useTranslation(['translation']); /** * Gets the origin of a cluster. * * @param cluster * @returns A description of where the cluster is picked up from: dynamic, in-cluster, or from a kubeconfig file. */ function getOrigin(cluster) { if (cluster.meta_data?.source === 'kubeconfig') { const kubeconfigPath = process.env.KUBECONFIG ?? '~/.kube/config'; return `Kubeconfig: ${kubeconfigPath}`; } else if (cluster.meta_data?.source === 'dynamic_cluster') { return t('translation|Plugin'); } else if (cluster.meta_data?.source === 'in_cluster') { return t('translation|In-cluster'); } return 'Unknown'; } const viewClusters = t('View Clusters'); return (_jsx(Table, { columns: [ { id: 'name', header: t('Name'), accessorKey: 'name', Cell: ({ row: { original } }) => (_jsx(Link, { routeName: "cluster", params: { cluster: original.name }, children: original.name })), }, { header: t('Origin'), accessorFn: cluster => getOrigin(cluster), Cell: ({ row: { original } }) => (_jsx(Typography, { variant: "body2", children: getOrigin((clusters || {})[original.name]) })), }, { header: t('Status'), accessorFn: cluster => errors[cluster.name] === null ? 'Active' : errors[cluster.name]?.message, Cell: ({ row: { original } }) => _jsx(ClusterStatus, { error: errors[original.name] }), }, { header: t('Warnings'), accessorFn: cluster => warningLabels[cluster.name] }, { header: t('glossary|Kubernetes Version'), accessorFn: ({ name }) => versions[name]?.gitVersion || '⋯', }, { header: '', muiTableBodyCellProps: { align: 'right', }, accessorFn: cluster => errors[cluster.name] === null ? 'Active' : errors[cluster.name]?.message, Cell: ({ row: { original: cluster } }) => { return _jsx(ClusterContextMenu, { cluster: cluster }); }, }, ], data: Object.values(customNameClusters), enableRowSelection: MULTI_HOME_ENABLED ? row => { // Only allow selection if the cluster is working return !errors[row.original.name]; } : false, initialState: { sorting: [{ id: 'name', desc: false }], }, muiToolbarAlertBannerProps: { sx: theme => ({ background: theme.palette.background.muted, }), }, renderToolbarAlertBannerContent: ({ table }) => (_jsx(Button, { variant: "contained", sx: { marginLeft: 1, }, onClick: () => { history.push({ pathname: generatePath(getClusterPrefixedPath(), { cluster: formatClusterPathParam(table.getSelectedRowModel().rows.map(it => it.original.name)), }), }); }, children: viewClusters })) })); }