UNPKG

@kinvolk/headlamp-plugin

Version:

The needed infrastructure for building Headlamp plugins.

101 lines (100 loc) 4.14 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 Link from '@mui/material/Link'; import Typography from '@mui/material/Typography'; import React from 'react'; import { useTranslation } from 'react-i18next'; const A8R_ICON_MAP = { description: { icon: 'mdi:information-outline', labelKey: 'Description' }, owner: { icon: 'mdi:account', labelKey: 'Owner' }, dependencies: { icon: 'mdi:sitemap', labelKey: 'Dependencies' }, chat: { icon: 'mdi:chat', labelKey: 'Chat' }, bugs: { icon: 'mdi:bug', labelKey: 'Bugs' }, logs: { icon: 'mdi:chart-timeline-variant', labelKey: 'Logs' }, documentation: { icon: 'mdi:book-open-page-variant', labelKey: 'Documentation' }, repository: { icon: 'mdi:github', labelKey: 'Repository' }, support: { icon: 'mdi:help-circle', labelKey: 'Support' }, runbook: { icon: 'mdi:script-text', labelKey: 'Runbook' }, incidents: { icon: 'mdi:alert-circle', labelKey: 'Incidents' }, uptime: { icon: 'mdi:check-circle', labelKey: 'Uptime' }, performance: { icon: 'mdi:speedometer', labelKey: 'Performance' }, }; const PREFERRED_ORDER = [ 'description', 'owner', 'dependencies', 'chat', 'documentation', 'repository', 'logs', 'bugs', 'support', 'runbook', 'incidents', 'uptime', 'performance', ]; function isValidHttpUrl(value) { try { const url = new URL(value); return url.protocol === 'http:' || url.protocol === 'https:'; } catch { return false; } } /** * Parses Kubernetes resource annotations and extracts a8r.io metadata items. * * Filters annotations starting with 'a8r.io/', maps them to display-friendly * metadata items with icons and labels, and sorts by preferred display order. * * @param annotations - Key-value pairs of Kubernetes annotations (defaults to empty object) * @returns Array of parsed metadata items sorted by preferred display order */ export function getA8RMetadata(annotations = {}) { return Object.entries(annotations) .filter(([key]) => key.startsWith('a8r.io/')) .map(([key, value]) => { const shortKey = key.replace('a8r.io/', ''); const meta = A8R_ICON_MAP[shortKey]; if (!meta) return null; return { key: shortKey, labelKey: meta.labelKey, value, icon: meta.icon, isLink: isValidHttpUrl(value), }; }) .filter((v) => Boolean(v)) .sort((a, b) => { const ai = PREFERRED_ORDER.indexOf(a.key); const bi = PREFERRED_ORDER.indexOf(b.key); return (ai === -1 ? 999 : ai) - (bi === -1 ? 999 : bi); }); } export default function A8RInfo({ annotations }) { const { t } = useTranslation(['glossary', 'translation']); const metadata = React.useMemo(() => getA8RMetadata(annotations), [annotations]); if (metadata.length === 0) return null; return (_jsx(Box, { display: "flex", flexDirection: "column", gap: 1.5, children: metadata.map(item => (_jsxs(Box, { display: "flex", alignItems: "center", children: [_jsx(Icon, { icon: item.icon, width: "20", style: { marginRight: 8 } }), _jsxs(Typography, { variant: "body2", children: [_jsxs("strong", { children: [t(item.labelKey), ":"] }), ' ', item.isLink ? (_jsx(Link, { href: item.value, target: "_blank", rel: "noopener noreferrer", children: item.value })) : (item.value)] })] }, item.key))) })); }