@kinvolk/headlamp-plugin
Version:
The needed infrastructure for building Headlamp plugins.
90 lines (89 loc) • 4.98 kB
JavaScript
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 Box from '@mui/material/Box';
import Chip from '@mui/material/Chip';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Typography from '@mui/material/Typography';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { DateLabel } from '../Label';
import SectionBox from '../SectionBox';
/**
* Helper to extract revision history from a resource that supports it.
*/
function getRevisionHistoryFn(resource) {
if ('getRevisionHistory' in resource && typeof resource.getRevisionHistory === 'function') {
return () => resource.getRevisionHistory();
}
return undefined;
}
/**
* RevisionHistorySection shows a table of revision history for rollbackable resources.
* Displays revision number, creation date, container images, and current status.
*
* This is added as an extraSection on Deployment, DaemonSet, and StatefulSet details pages.
*/
export default function RevisionHistorySection(props) {
const { resource } = props;
const { t } = useTranslation(['translation']);
const [revisions, setRevisions] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const getHistory = getRevisionHistoryFn(resource);
useEffect(() => {
const historyGetter = getRevisionHistoryFn(resource);
let isActive = true;
if (!historyGetter) {
setRevisions([]);
setError(null);
setLoading(false);
return () => {
isActive = false;
};
}
setLoading(true);
setError(null);
historyGetter()
.then(history => {
if (!isActive) {
return;
}
setRevisions(history);
setLoading(false);
})
.catch(err => {
if (!isActive) {
return;
}
setError(err instanceof Error ? err.message : String(err));
setLoading(false);
});
return () => {
isActive = false;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [resource?.metadata?.uid, resource?.metadata?.resourceVersion]);
if (!getHistory) {
return null;
}
return (_jsxs(SectionBox, { title: t('translation|Revision History'), 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 && revisions.length === 0 && (_jsx(Typography, { variant: "body2", color: "text.secondary", sx: { py: 2 }, children: t('translation|No revision history available.') })), !loading && !error && revisions.length > 0 && (_jsx(TableContainer, { children: _jsxs(Table, { size: "small", children: [_jsx(TableHead, { children: _jsxs(TableRow, { children: [_jsx(TableCell, { children: t('translation|Revision') }), _jsx(TableCell, { children: t('translation|Created') }), _jsx(TableCell, { children: t('translation|Images') }), _jsx(TableCell, { children: t('translation|Status') })] }) }), _jsx(TableBody, { children: revisions.map(rev => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(Typography, { variant: "body2", children: rev.revision }) }), _jsx(TableCell, { children: _jsx(DateLabel, { date: rev.createdAt }) }), _jsx(TableCell, { children: _jsx(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 0.5 }, children: rev.images.map((img, i) => (_jsx(Typography, { variant: "body2", sx: { fontFamily: 'monospace' }, children: img }, i))) }) }), _jsx(TableCell, { children: rev.isCurrent ? (_jsx(Chip, { label: t('translation|Current'), size: "small", color: "primary", variant: "outlined" })) : (_jsx(Typography, { variant: "body2", color: "text.secondary", children: t('translation|Previous') })) })] }, rev.revision))) })] }) }))] }));
}