Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List cluster delete #231

Merged
merged 5 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions components/button/button.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ export const ErrorButton = styled(Button)`
&:hover {
background-color: ${({ theme }) => theme.colors.fireBrick};
}

${({ disabled }) =>
disabled &&
`
background-color: ${LIGHT_GREY} !important;
border-color: ${EXCLUSIVE_PLUM} !important;
color: ${EXCLUSIVE_PLUM} !important;
cursor: not-allowed !important;
`}
`;

export const InfoButton = styled(Button)`
Expand Down
5 changes: 4 additions & 1 deletion components/clusterTable/clusterTable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Story } from '@storybook/react';

import { ClusterStatus, ClusterType } from '../../types/provision';
import { InstallationType } from '../../types/redux';
import { noop } from '../../utils/noop';

import { ClusterTable, ClusterInfo } from './clusterTable';

Expand Down Expand Up @@ -79,6 +80,8 @@ const clusters: ClusterInfo[] = [
},
];

const DefaultTemplate: Story = (args) => <ClusterTable clusters={clusters} {...args} />;
const DefaultTemplate: Story = (args) => (
<ClusterTable clusters={clusters} {...args} onMenuOpenClose={noop} onDeleteCluster={noop} />
);

export const Default = DefaultTemplate.bind({});
36 changes: 35 additions & 1 deletion components/clusterTable/clusterTable.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,24 @@ import {
IconButton,
iconButtonClasses,
typographyClasses,
Box,
} from '@mui/material';

import Typography from '../typography';
import Tag from '../tag';
import { PASTEL_LIGHT_BLUE, SALTBOX_BLUE, VOLCANIC_SAND } from '../../constants/colors';
import { CHEFS_HAT, PASTEL_LIGHT_BLUE, SALTBOX_BLUE, VOLCANIC_SAND } from '../../constants/colors';

export const Menu = styled(Box)`
position: absolute;
bottom: -40px;
left: -110px;
width: 160px;
background-color: white;
border: 1px solid ${CHEFS_HAT};
border-radius: 8px;
box-shadow: 0px 2px 4px 0px rgba(100, 116, 139, 0.25);
z-index: 1;
`;

export const StyledIconButton = muiStyled(IconButton)(() => ({
[`&.${iconButtonClasses.root}`]: {
Expand All @@ -28,9 +41,17 @@ export const StyledTableBody = muiStyled(TableBody)(() => ({
boxShadow: `0 0 0 2px ${PASTEL_LIGHT_BLUE}`,
},
}));

export const StyledTableCell = muiStyled(TableCell)(() => ({
[`&.${tableCellClasses.root}`]: {
border: 0,
backgroundColor: 'white',
},
}));

export const StyledHeaderCell = muiStyled(StyledTableCell)(() => ({
[`&.${tableCellClasses.root}`]: {
backgroundColor: 'transparent',
},
}));

Expand All @@ -41,6 +62,19 @@ export const StyledTag = styled(Tag)`
export const StyledTableRow = muiStyled(TableRow)(() => ({
[`&.${tableRowClasses.root}`]: {
border: 0,
height: 'fit-content',
},
['&:first-child td:first-child']: {
borderTopLeftRadius: '20px',
},
['&:first-child td:last-child']: {
borderTopRightRadius: '20px',
},
['&:last-child td:first-child']: {
borderBottomLeftRadius: '20px',
},
['&:last-child td:last-child']: {
borderBottomRightRadius: '20px',
},
}));

Expand Down
154 changes: 111 additions & 43 deletions components/clusterTable/clusterTable.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import React, { useState, FunctionComponent, ComponentPropsWithoutRef } from 'react';
import React, {
useState,
FunctionComponent,
ComponentPropsWithoutRef,
useCallback,
useRef,
} from 'react';
import Table from '@mui/material/Table';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import { Box, Collapse, IconButton } from '@mui/material';
import { Box, Collapse, IconButton, List, ListItem, ListItemButton } from '@mui/material';
import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
Expand All @@ -15,9 +21,11 @@ import civoLogo from '../../assets/civo_logo.svg';
import digitalOceanLogo from '../../assets/digital_ocean_logo.svg';
import vultrLogo from '../../assets/vultr_logo.svg';
import { CLUSTER_TAG_CONFIG } from '../../constants';
import { DODGER_BLUE, ROCK_BLUE } from '../../constants/colors';
import { Cluster, ClusterType } from '../../types/provision';
import { DODGER_BLUE, FIRE_BRICK, ROCK_BLUE } from '../../constants/colors';
import { Cluster, ClusterStatus, ClusterType } from '../../types/provision';
import { InstallationType } from '../../types/redux';
import Typography from '../../components/typography';
import { useOnClickOutside } from '../../hooks/useOnClickOutside';

import {
StyledTableRow,
Expand All @@ -27,6 +35,8 @@ import {
StyledIconButton,
StyledTableHeading,
StyledCellText,
Menu,
StyledHeaderCell,
} from './clusterTable.styled';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -55,17 +65,29 @@ export type ClusterInfo = Pick<
instanceSize?: string;
};

const ClusterRow: FunctionComponent<ClusterInfo> = ({
clusterName,
type,
cloudProvider,
cloudRegion,
creationDate = '',
gitUser: createdBy,
status,
nodes,
type ClusterRowProps = ClusterInfo & {
onMenuOpenClose: (clusterName?: string) => void;
onDeleteCluster: () => void;
};

const ClusterRow: FunctionComponent<ClusterRowProps> = ({
onDeleteCluster,
onMenuOpenClose,
...rest
}) => {
const {
clusterName,
type,
cloudProvider,
cloudRegion,
creationDate = '',
gitUser: createdBy,
status,
nodes,
} = rest;

const [open, setOpen] = useState(false);
const [menuOpen, setMenuOpen] = useState(false);

const cloudLogoSrc = CLOUD_LOGO_OPTIONS[cloudProvider];
const { iconLabel, iconType, bgColor } = CLUSTER_TAG_CONFIG[status ?? 'draft'];
Expand All @@ -74,10 +96,21 @@ const ClusterRow: FunctionComponent<ClusterInfo> = ({
// placeholder for now. new field yet to be implemented
const nodeCount = nodes ?? 2;

const handleMenu = useCallback(() => {
setMenuOpen(!menuOpen);
onMenuOpenClose(!menuOpen ? clusterName : undefined);
}, [menuOpen, onMenuOpenClose, clusterName]);

const buttonRef = useRef(null);

useOnClickOutside(buttonRef, () => setMenuOpen(false));

return (
<>
<StyledTableRow
sx={{ '&:hover td:first-child button': { opacity: 1, pointerEvents: 'all' } }}
sx={{
'&:hover td:first-child button': { opacity: 1, pointerEvents: 'all' },
}}
>
<StyledTableCell align="right" style={{ width: '50px' }}>
<StyledIconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
Expand Down Expand Up @@ -116,60 +149,95 @@ const ClusterRow: FunctionComponent<ClusterInfo> = ({
<StyledTableCell>
<StyledTag text={iconLabel} bgColor={bgColor} icon={iconType} />
</StyledTableCell>
<StyledTableCell>
<IconButton aria-label="more info">
<StyledTableCell style={{ position: 'relative' }}>
<IconButton
aria-label="more info"
onClick={handleMenu}
ref={buttonRef}
disabled={status === ClusterStatus.DELETED}
>
<MoreHorizIcon />
</IconButton>
{menuOpen && (
<Menu>
<List>
<ListItem disablePadding>
<ListItemButton onClick={onDeleteCluster}>
<Typography variant="body2" style={{ color: `${FIRE_BRICK}` }}>
Delete cluster
</Typography>
</ListItemButton>
</ListItem>
</List>
</Menu>
)}
</StyledTableCell>
</StyledTableRow>
<StyledTableRow>
<StyledTableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box sx={{ margin: 1, height: '100px' }}>TBD</Box>
</Collapse>
</StyledTableCell>
</StyledTableRow>
{open && (
<StyledTableRow>
<StyledTableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box sx={{ margin: 1, height: '100px' }}>TBD</Box>
</Collapse>
</StyledTableCell>
</StyledTableRow>
)}
</>
);
};

interface ClusterTableProps extends ComponentPropsWithoutRef<'div'> {
clusters: ClusterInfo[];
onDeleteCluster: () => void;
onMenuOpenClose: (clusterName?: string) => void;
}

export const ClusterTable: FunctionComponent<ClusterTableProps> = ({ clusters, ...rest }) => (
<TableContainer style={{ display: 'flex' }} {...rest}>
<Table aria-label="collapsible table" sx={{ borderCollapse: 'collapse', margin: '5px' }}>
export const ClusterTable: FunctionComponent<ClusterTableProps> = ({
clusters,
onDeleteCluster,
onMenuOpenClose,
...rest
}) => (
<TableContainer style={{ display: 'flex', height: '100%' }} {...rest}>
<Table
aria-label="collapsible table"
sx={{ borderCollapse: 'collapse', margin: '5px', height: 'fit-content' }}
>
<TableHead>
<StyledTableRow>
<StyledTableCell />
<StyledTableCell>
<StyledHeaderCell />
<StyledHeaderCell>
<StyledTableHeading variant="labelMedium">Name</StyledTableHeading>
</StyledTableCell>
<StyledTableCell>
</StyledHeaderCell>
<StyledHeaderCell>
<StyledTableHeading variant="labelMedium">Cloud</StyledTableHeading>
</StyledTableCell>
<StyledTableCell>
</StyledHeaderCell>
<StyledHeaderCell>
<StyledTableHeading variant="labelMedium">Region</StyledTableHeading>
</StyledTableCell>
<StyledTableCell>
</StyledHeaderCell>
<StyledHeaderCell>
<StyledTableHeading variant="labelMedium">Nodes</StyledTableHeading>
</StyledTableCell>
<StyledTableCell>
</StyledHeaderCell>
<StyledHeaderCell>
<StyledTableHeading variant="labelMedium">Created</StyledTableHeading>
</StyledTableCell>
<StyledTableCell>
</StyledHeaderCell>
<StyledHeaderCell>
<StyledTableHeading variant="labelMedium">Created by</StyledTableHeading>
</StyledTableCell>
<StyledTableCell>
</StyledHeaderCell>
<StyledHeaderCell>
<StyledTableHeading variant="labelMedium">Status</StyledTableHeading>
</StyledTableCell>
<StyledTableCell />
</StyledHeaderCell>
<StyledHeaderCell />
</StyledTableRow>
</TableHead>
<StyledTableBody>
{clusters.map((cluster) => (
<ClusterRow key={cluster.clusterName} {...cluster} />
<ClusterRow
key={cluster.clusterName}
{...cluster}
onDeleteCluster={onDeleteCluster}
onMenuOpenClose={onMenuOpenClose}
/>
))}
</StyledTableBody>
</Table>
Expand Down
Loading