UNPKG

@kinvolk/headlamp-plugin

Version:

The needed infrastructure for building Headlamp plugins.

152 lines (151 loc) 6.43 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 { useTranslation } from 'react-i18next'; import Job from '../../lib/k8s/job'; import { formatDuration } from '../../lib/util'; import { useNamespaces } from '../../redux/filterSlice'; import { CreateResourceButton } from '../common'; import { StatusLabel } from '../common/Label'; import ResourceListView from '../common/Resource/ResourceListView'; import LightTooltip from '../common/Tooltip/TooltipLight'; export function makeJobStatusValue(job) { if (!job?.status?.conditions) { return '-'; } const conditionOptions = ['Failed', 'Complete', 'Suspended']; const condition = job.status.conditions.find(({ status, type }) => conditionOptions.includes(type) && status === 'True'); if (!condition) { return '-'; } return condition.type; } export function makeJobStatusLabel(job) { if (!job?.status?.conditions) { return null; } const conditionOptions = { Failed: { status: 'error', icon: 'mdi:alert-outline', }, Complete: { status: 'success', icon: 'mdi:check-bold', }, Suspended: { status: '', icon: 'mdi:pause', }, }; const condition = job.status.conditions.find(({ status, type }) => type in conditionOptions && status === 'True'); if (!condition) { return null; } const tooltip = ''; const conditionInfo = conditionOptions[condition.type || 'Suspended']; return (_jsx(LightTooltip, { title: tooltip, interactive: true, children: _jsx(Box, { display: "inline", children: _jsxs(StatusLabel, { status: conditionInfo.status, children: [_jsx(Icon, { "aria-label": "hidden", icon: conditionInfo.icon, width: "1.2rem", height: "1.2rem" }), condition.type] }) }) })); } export default function JobsList() { const { items: jobs, errors } = Job.useList({ namespace: useNamespaces() }); return _jsx(JobsListRenderer, { jobs: jobs, errors: errors, reflectTableInURL: true }); } export function JobsListRenderer(props) { const { jobs, errors, hideColumns = [], reflectTableInURL = 'jobs', noNamespaceFilter, enableRowActions, enableRowSelection, hideCreateButton, } = props; const { t } = useTranslation(['glossary', 'translation']); function getCompletions(job) { return `${job.spec.completions}/${job.spec.parallelism}`; } function sortByCompletions(job1, job2) { const parallelismSorted = job1.spec.parallelism - job2.spec.parallelism; if (parallelismSorted === 0) { return job1.spec.completions - job2.spec.completions; } return parallelismSorted; } return (_jsx(ResourceListView, { title: t('Jobs'), headerProps: { noNamespaceFilter, titleSideActions: hideCreateButton ? [] : [_jsx(CreateResourceButton, { resourceClass: Job }, "create-job-button")], }, hideColumns: hideColumns, errors: errors, columns: [ 'name', 'namespace', 'cluster', { id: 'completions', label: t('Completions'), gridTemplate: 'min-content', disableFiltering: true, getValue: job => getCompletions(job), sort: sortByCompletions, }, { id: 'conditions', label: t('translation|Conditions'), filterVariant: 'multi-select', gridTemplate: 'min-content', getValue: job => makeJobStatusValue(job), render: job => makeJobStatusLabel(job), }, { id: 'duration', label: t('translation|Duration'), gridTemplate: 'min-content', getValue: job => { const duration = job.getDuration(); if (duration > 0) { return formatDuration(duration, { format: 'mini' }); } return '-'; }, sort: (job1, job2) => job1.getDuration() - job2.getDuration(), }, { id: 'containers', label: t('Containers'), getValue: job => job .getContainers() .map(c => c.name) .join(''), render: job => { const containerNames = job.getContainers().map((c) => c.name); const containerTooltip = containerNames.join('\n'); const containerText = containerNames.join(', '); return (_jsx(LightTooltip, { title: containerTooltip, interactive: true, children: containerText })); }, }, { id: 'images', label: t('Images'), gridTemplate: 'auto', getValue: job => job .getContainers() .map(c => c.image) .join(''), render: job => { const containerImages = job.getContainers().map((c) => c.image); const containerTooltip = containerImages.join('\n'); const containerText = containerImages.join(', '); return (_jsx(LightTooltip, { title: containerTooltip, interactive: true, children: containerText })); }, }, 'labels', 'age', ], data: jobs, reflectInURL: reflectTableInURL, id: "headlamp-jobs", enableRowActions: enableRowActions, enableRowSelection: enableRowSelection })); }