UNPKG

@kinvolk/headlamp-plugin

Version:

The needed infrastructure for building Headlamp plugins.

92 lines (91 loc) 6.23 kB
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 Chip from '@mui/material/Chip'; import Dialog from '@mui/material/Dialog'; import DialogActions from '@mui/material/DialogActions'; import DialogContent from '@mui/material/DialogContent'; import DialogTitle from '@mui/material/DialogTitle'; import List from '@mui/material/List'; import ListItemButton from '@mui/material/ListItemButton'; import ListItemText from '@mui/material/ListItemText'; import Radio from '@mui/material/Radio'; import Typography from '@mui/material/Typography'; import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { DateLabel } from '../Label'; /** * RollbackDialog component that shows revision history and allows * the user to select a specific revision to rollback to. */ export default function RollbackDialog(props) { const { open, resourceKind, resourceName, getRevisionHistory, onClose, onConfirm } = props; const { t } = useTranslation(['translation']); const [revisions, setRevisions] = useState([]); const [selectedRevision, setSelectedRevision] = useState(undefined); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); useEffect(() => { if (!open) { return; } let isActive = true; // eslint-disable-next-line react-hooks/set-state-in-effect setLoading(true); setError(null); setSelectedRevision(undefined); getRevisionHistory() .then(history => { if (!isActive) { return; } setRevisions(history); const nonCurrent = history.filter(r => !r.isCurrent); if (nonCurrent.length > 0) { setSelectedRevision(nonCurrent[0].revision); } setLoading(false); }) .catch(err => { if (!isActive) { return; } setError(err instanceof Error ? err.message : String(err)); setLoading(false); }); return () => { isActive = false; }; }, [open, getRevisionHistory]); function handleConfirm() { onConfirm(selectedRevision); } const hasPreviousRevisions = revisions.filter(r => !r.isCurrent).length > 0; return (_jsxs(Dialog, { open: open, onClose: onClose, maxWidth: "sm", fullWidth: true, children: [_jsx(DialogTitle, { children: t('translation|Rollback {{ kind }}', { kind: resourceKind }) }), _jsxs(DialogContent, { children: [loading && (_jsx(Typography, { variant: "body2", color: "text.secondary", sx: { py: 2 }, children: t('translation|Loading revision history…') })), error && (_jsx(Typography, { variant: "body2", color: "error", sx: { py: 2 }, children: t('translation|Failed to load revision history: {{ error }}', { error }) })), !loading && !error && (_jsxs(_Fragment, { children: [_jsx(Typography, { variant: "body2", sx: { mb: 2 }, children: t('translation|Select a revision to rollback "{{ name }}" to. This will replace the current pod template with the one from the selected revision.', { name: resourceName }) }), !hasPreviousRevisions ? (_jsx(Typography, { variant: "body2", color: "text.secondary", children: t('translation|No previous revisions available to rollback to.') })) : (_jsx(List, { sx: { maxHeight: 320, overflow: 'auto' }, children: revisions.map(rev => (_jsxs(ListItemButton, { selected: selectedRevision === rev.revision, onClick: () => { if (!rev.isCurrent) { setSelectedRevision(rev.revision); } }, disabled: rev.isCurrent, sx: { borderRadius: 1, mb: 0.5, border: '1px solid', borderColor: selectedRevision === rev.revision ? 'primary.main' : 'divider', }, children: [_jsx(Radio, { checked: selectedRevision === rev.revision, disabled: rev.isCurrent, size: "small", sx: { mr: 1 } }), _jsx(ListItemText, { primary: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [_jsx(Typography, { variant: "body2", fontWeight: "medium", children: t('translation|Revision {{ revision }}', { revision: rev.revision, }) }), rev.isCurrent && (_jsx(Chip, { label: t('translation|Current'), size: "small", color: "primary", variant: "outlined" }))] }), secondary: _jsxs(Box, { component: "span", children: [_jsx(Typography, { variant: "caption", color: "text.secondary", component: "span", children: _jsx(DateLabel, { date: rev.createdAt }) }), rev.images.length > 0 && (_jsx(Typography, { variant: "caption", color: "text.secondary", component: "span", sx: { display: 'block' }, children: rev.images.map((img, i) => (_jsx(Box, { component: "span", sx: { display: 'block' }, children: img }, i))) }))] }) })] }, rev.revision))) }))] }))] }), _jsxs(DialogActions, { children: [_jsx(Button, { onClick: onClose, children: t('translation|Cancel') }), _jsx(Button, { onClick: handleConfirm, variant: "contained", color: "primary", disabled: !hasPreviousRevisions || selectedRevision === undefined || loading, children: t('translation|Rollback') })] })] })); }