import { cx } from '@emotion/css'; import { Checkbox, Icon, IconButton, LoadingPlaceholder, useStyles2, useTheme2, FadeTransition } from '@grafana/ui'; import React, { useCallback, useEffect, useState } from 'react'; import getStyles from './styles'; import { EntryType, Row, RowGroup } from './types'; interface NestedRowsProps { rows: RowGroup; level: number; selectedRows: RowGroup; requestNestedRows: (row: Row) => Promise; onRowSelectedChange: (row: Row, selected: boolean) => void; } const NestedRows: React.FC = ({ rows, selectedRows, level, requestNestedRows, onRowSelectedChange, }) => ( <> {Object.keys(rows).map((rowId) => ( ))} ); interface NestedRowProps { row: Row; level: number; selectedRows: RowGroup; requestNestedRows: (row: Row) => Promise; onRowSelectedChange: (row: Row, selected: boolean) => void; } const NestedRow: React.FC = ({ row, selectedRows, level, requestNestedRows, onRowSelectedChange }) => { const styles = useStyles2(getStyles); const isSelected = !!selectedRows[row.id]; const isDisabled = Object.keys(selectedRows).length > 0 && !isSelected; const initialOpenStatus = row.type === EntryType.Collection ? 'open' : 'closed'; const [openStatus, setOpenStatus] = useState<'open' | 'closed' | 'loading'>(initialOpenStatus); const isOpen = openStatus === 'open'; const onRowToggleCollapse = async () => { if (openStatus === 'open') { setOpenStatus('closed'); return; } setOpenStatus('loading'); await requestNestedRows(row); setOpenStatus('open'); }; // opens the resource group on load of component if there was a previously saved selection useEffect(() => { const selectedRow = Object.keys(selectedRows).map((rowId) => selectedRows[rowId])[0]; const isSelectedResourceGroup = selectedRow && selectedRow.resourceGroupName && row.name === selectedRow.resourceGroupName; if (isSelectedResourceGroup) { setOpenStatus('open'); } }, [selectedRows, row]); return ( <> {row.typeLabel} {row.location ?? '-'} {isOpen && row.children && Object.keys(row.children).length > 0 && ( )} ); }; interface EntryIconProps { entry: Row; isOpen: boolean; } const EntryIcon: React.FC = ({ isOpen, entry: { type } }) => { switch (type) { case EntryType.Collection: return ; case EntryType.SubCollection: return ; case EntryType.Resource: return ; default: return null; } }; interface NestedEntryProps { level: number; entry: Row; isSelected: boolean; isOpen: boolean; isDisabled: boolean; onToggleCollapse: (row: Row) => void; onSelectedChange: (row: Row, selected: boolean) => void; } const NestedEntry: React.FC = ({ entry, isSelected, isDisabled, isOpen, level, onToggleCollapse, onSelectedChange, }) => { const theme = useTheme2(); const styles = useStyles2(getStyles); const hasChildren = !!entry.children; const isSelectable = entry.type === EntryType.Resource; const handleToggleCollapse = useCallback(() => { onToggleCollapse(entry); }, [onToggleCollapse, entry]); const handleSelectedChanged = useCallback( (ev: React.ChangeEvent) => { const isSelected = ev.target.checked; onSelectedChange(entry, isSelected); }, [entry, onSelectedChange] ); return (
{/* When groups are selectable, I *think* we will want to show a 2-wide space instead of the collapse button for leaf rows that have no children to get them to align */} {hasChildren && ( )} {isSelectable && } {entry.name}
); }; export default NestedRows;