UNPKG

@kinvolk/headlamp-plugin

Version:

The needed infrastructure for building Headlamp plugins.

110 lines (109 loc) 5.99 kB
import { jsx as _jsx, Fragment as _Fragment, 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 Badge from '@mui/material/Badge'; import Box from '@mui/material/Box'; import Checkbox from '@mui/material/Checkbox'; import Chip from '@mui/material/Chip'; import CircularProgress from '@mui/material/CircularProgress'; import Popover from '@mui/material/Popover'; import Stack from '@mui/material/Stack'; import { styled } from '@mui/material/styles'; import Typography from '@mui/material/Typography'; import { alpha } from '@mui/system/colorManipulator'; import { memo, useState } from 'react'; import { getFlatSources } from './GraphSources'; const Node = styled('div')(() => ({ display: 'flex', flexDirection: 'column', })); const NodeHeader = styled('div')(({ theme }) => ({ display: 'flex', flexDirection: 'row', alignItems: 'center', borderRadius: theme.spacing(1), paddingLeft: theme.spacing(0.5), paddingRight: theme.spacing(0.5), paddingTop: theme.spacing(0.5), paddingBottom: theme.spacing(0.5), ':hover': { background: theme.palette.action.hover, }, ':active': { background: alpha(theme.palette.action.active, theme.palette.action.activatedOpacity), }, })); /** * Component that displays a Source and allows to check or uncheck it * and its' descendants * * @returns */ function GraphSourceView({ source, sourceData, selection, toggleSelection, }) { const [isActive, setIsActive] = useState(false); const hasChildren = 'sources' in source; const isSelected = (source) => 'sources' in source ? source.sources.every(s => isSelected(s)) : selection.has(source.id); const isChecked = isSelected(source); const intermediate = 'sources' in source && getFlatSources(source.sources).some(s => isSelected(s)) && !isChecked; const data = sourceData.get(source.id); const check = (_jsxs(_Fragment, { children: [_jsx(Box, { mr: 1, display: "flex", children: _jsx(Badge, { badgeContent: isChecked ? data?.nodes?.length : undefined, overlap: "circular", children: _jsx(Box, { width: hasChildren ? '24px' : '24px', height: hasChildren ? '24px' : '24px', children: source.icon }) }) }), _jsx(Typography, { variant: "subtitle2", children: source.label }), !('sources' in source) && isChecked && !data && _jsx(CircularProgress, {}), _jsx(Checkbox, { sx: () => ({ marginLeft: 'auto' }), checked: isChecked, indeterminate: intermediate, onClick: e => { e.stopPropagation(); toggleSelection(source); }, onKeyDown: e => { if (e.key === 'Enter' || e.key === ' ') { e.stopPropagation(); e.preventDefault(); toggleSelection(source); } } })] })); if (!('sources' in source)) { return (_jsx(Node, { onClick: () => { toggleSelection(source); }, children: _jsx(NodeHeader, { children: check }) })); } return (_jsxs(Node, { children: [_jsxs(NodeHeader, { role: "button", tabIndex: 0, onClick: () => setIsActive(!isActive), onKeyDown: e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setIsActive(!isActive); } }, children: [_jsx(Icon, { icon: isActive ? 'mdi:chevron-down' : 'mdi:chevron-right', width: 18, height: 18, style: { flexShrink: 0 } }), check] }), _jsx(Stack, { ml: 3, children: isActive && source.sources?.map(source => (_jsx(GraphSourceView, { source: source, selection: selection, toggleSelection: toggleSelection, sourceData: sourceData }, source.id))) })] })); } export const GraphSourcesView = memo(({ sources, sourceData, selectedSources, toggleSource }) => { const [anchorEl, setAnchorEl] = useState(null); const selected = sources.filter(source => { const isSelected = selectedSources.has(source.id); return 'sources' in source ? getFlatSources(source.sources).some(it => selectedSources.has(it.id)) : isSelected; }); const selectedText = selected.length > 2 ? `${selected[0].label}, ${selected[1].label}, +${selected.length - 2}` : selected.map(it => it.label).join(', '); return (_jsxs(_Fragment, { children: [_jsx(Chip, { label: _jsxs(Stack, { direction: "row", gap: 1, alignItems: "center", children: [_jsx(Icon, { icon: "mdi:filter" }), " ", selectedText, ' '] }), color: "primary", variant: 'filled', onClick: e => setAnchorEl(e.currentTarget), sx: { lineHeight: '1', } }), _jsx(Popover, { elevation: 4, anchorOrigin: { vertical: 'bottom', horizontal: 'left', }, onClose: () => setAnchorEl(null), anchorEl: anchorEl, open: Boolean(anchorEl), children: _jsx(Box, { sx: { display: 'flex', flexDirection: 'column', width: 'fit-content', minWidth: '350px', padding: 1.5, }, children: sources.map((source, index) => (_jsx(GraphSourceView, { source: source, selection: selectedSources, toggleSelection: toggleSource, sourceData: sourceData }, index))) }) })] })); });