diff --git a/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCard.tsx b/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCard.tsx index f66d0e8821..02196145fd 100644 --- a/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCard.tsx +++ b/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCard.tsx @@ -1,21 +1,15 @@ -import { Box, Card, styled } from '@mui/material'; +import { styled } from '@mui/material'; import type { IGroup } from 'interfaces/group'; -import { Link, useNavigate } from 'react-router-dom'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import { Badge } from 'component/common/Badge/Badge'; -import { GroupCardActions } from './GroupCardActions/GroupCardActions'; -import TopicOutlinedIcon from '@mui/icons-material/TopicOutlined'; +import { Link } from 'react-router-dom'; +import { GroupCardActions } from './GroupCardActions'; import { RoleBadge } from 'component/common/RoleBadge/RoleBadge'; import { useScimSettings } from 'hooks/api/getters/useScimSettings/useScimSettings'; -import { - AvatarComponent, - AvatarGroup, -} from 'component/common/AvatarGroup/AvatarGroup'; import GroupsIcon from '@mui/icons-material/GroupsOutlined'; import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext'; import { Highlighter } from 'component/common/Highlighter/Highlighter'; import { Truncator } from 'component/common/Truncator/Truncator'; -import { TooltipLink } from 'component/common/TooltipLink/TooltipLink'; +import { Card } from 'component/common/Card/Card'; +import { GroupCardFooter } from './GroupCardFooter'; const StyledCardLink = styled(Link)(({ theme }) => ({ color: 'inherit', @@ -27,54 +21,6 @@ const StyledCardLink = styled(Link)(({ theme }) => ({ pointer: 'cursor', })); -const StyledCard = styled(Card)(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - justifyContent: 'space-between', - height: '100%', - boxShadow: 'none', - border: `1px solid ${theme.palette.divider}`, - [theme.breakpoints.down('sm')]: { - justifyContent: 'center', - }, - transition: 'background-color 0.2s ease-in-out', - backgroundColor: theme.palette.background.default, - '&:hover': { - backgroundColor: theme.palette.neutral.light, - }, - borderRadius: theme.shape.borderRadiusMedium, -})); - -const StyledCardBody = styled(Box)(({ theme }) => ({ - padding: theme.spacing(2), - display: 'flex', - flexFlow: 'column', - height: '100%', - position: 'relative', -})); - -const StyledCardBodyHeader = styled('div')(({ theme }) => ({ - display: 'flex', - gap: theme.spacing(1), - width: '100%', - alignItems: 'center', - justifyContent: 'space-between', -})); - -const StyledCardIconContainer = styled(Box)(({ theme }) => ({ - display: 'grid', - placeItems: 'center', - padding: theme.spacing(0.5), - alignSelf: 'baseline', - backgroundColor: theme.palette.secondary.light, - color: theme.palette.primary.main, - borderRadius: theme.shape.borderRadiusMedium, - '& > svg': { - height: theme.spacing(2), - width: theme.spacing(2), - }, -})); - const StyledCardTitle = styled('h3')(({ theme }) => ({ margin: 0, marginRight: 'auto', @@ -83,47 +29,6 @@ const StyledCardTitle = styled('h3')(({ theme }) => ({ lineHeight: '1.2', })); -const StyledCardDescription = styled('p')(({ theme }) => ({ - color: theme.palette.text.secondary, - fontSize: theme.fontSizes.smallBody, - marginTop: theme.spacing(2), -})); - -const StyledCardFooter = styled(Box)(({ theme }) => ({ - padding: theme.spacing(0, 2), - display: 'flex', - background: theme.palette.envAccordion.expanded, - boxShadow: theme.boxShadows.accordionFooter, - alignItems: 'center', - justifyContent: 'space-between', - borderTop: `1px solid ${theme.palette.divider}`, - minHeight: theme.spacing(6.25), -})); - -const StyledCardFooterSpan = styled('span')(({ theme }) => ({ - fontSize: theme.fontSizes.smallerBody, - color: theme.palette.text.secondary, - textWrap: 'nowrap', -})); - -const StyledAvatarComponent = styled(AvatarComponent)(({ theme }) => ({ - height: theme.spacing(2.5), - width: theme.spacing(2.5), - marginLeft: theme.spacing(-0.75), -})); - -const StyledProjectsTooltip = styled(Box)(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(1), - maxWidth: theme.spacing(25), -})); - -const StyledProjectBadge = styled(Badge)({ - cursor: 'pointer', - overflowWrap: 'anywhere', -}); - interface IGroupCardProps { group: IGroup; onEditUsers: (group: IGroup) => void; @@ -135,115 +40,48 @@ export const GroupCard = ({ onEditUsers, onRemoveGroup, }: IGroupCardProps) => { - const navigate = useNavigate(); - const { searchQuery } = useSearchHighlightContext(); const { settings: { enabled: scimEnabled }, } = useScimSettings(); + const isScimGroup = scimEnabled && Boolean(group.scimId); - return ( + const title = ( + + {group.name} + + ); + + const headerActions = ( <> - - - - - - - - - - {group.name} - - - - } - /> - onEditUsers(group)} - onRemove={() => onRemoveGroup(group)} - isScimGroup={isScimGroup} - /> - - - - {group.description} - - - } - /> - - - 0} - show={ - - } - elseShow={ - - This group has no users - - } - /> - 0} - show={ - - {group.projects.map((project) => ( - { - e.preventDefault(); - navigate( - `/projects/${project}/settings/access`, - ); - }} - color='secondary' - icon={} - > - {project} - - ))} - - } - > - - {group.projects.length} project - {group.projects.length !== 1 && 's'} - - - } - /> - - - + {group.rootRole && } + onEditUsers(group)} + onRemove={() => onRemoveGroup(group)} + isScimGroup={isScimGroup} + /> ); + + const body = group.description && ( + + {group.description} + + ); + + return ( + + } + headerActions={headerActions} + footer={} + > + {body} + + + ); }; diff --git a/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardActions/GroupCardActions.tsx b/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardActions.tsx similarity index 100% rename from frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardActions/GroupCardActions.tsx rename to frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardActions.tsx diff --git a/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardAvatars/GroupPopover/GroupPopover.tsx b/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardAvatars/GroupPopover/GroupPopover.tsx deleted file mode 100644 index bf028b1c00..0000000000 --- a/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardAvatars/GroupPopover/GroupPopover.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { Popover, styled } from '@mui/material'; -import type { IGroupUser } from 'interfaces/group'; - -const StyledPopover = styled(Popover)(({ theme }) => ({ - pointerEvents: 'none', - '.MuiPaper-root': { - padding: theme.spacing(2), - }, -})); - -const StyledName = styled('div')(({ theme }) => ({ - color: theme.palette.text.secondary, - fontSize: theme.fontSizes.smallBody, - marginTop: theme.spacing(1), -})); - -interface IGroupPopoverProps { - user: Partial | undefined; - - open: boolean; - anchorEl: HTMLElement | null; - - onPopoverClose(event: React.MouseEvent): void; -} - -export const GroupPopover = ({ - user, - open, - anchorEl, - onPopoverClose, -}: IGroupPopoverProps) => { - return ( - - {user?.name || user?.username} -
{user?.description || user?.email}
-
- ); -}; diff --git a/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardFooter.tsx b/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardFooter.tsx new file mode 100644 index 0000000000..52813abe29 --- /dev/null +++ b/frontend/src/component/admin/groups/GroupsList/GroupCard/GroupCardFooter.tsx @@ -0,0 +1,78 @@ +import type { IGroup } from 'interfaces/group'; +import { Badge } from 'component/common/Badge/Badge'; +import TopicOutlinedIcon from '@mui/icons-material/TopicOutlined'; +import { + AvatarComponent, + AvatarGroup, +} from 'component/common/AvatarGroup/AvatarGroup'; +import { TooltipLink } from 'component/common/TooltipLink/TooltipLink'; +import { Box, styled } from '@mui/material'; +import { useNavigate } from 'react-router-dom'; + +const StyledAvatarComponent = styled(AvatarComponent)(({ theme }) => ({ + height: theme.spacing(2.5), + width: theme.spacing(2.5), + marginLeft: theme.spacing(-0.75), +})); + +const StyledProjectsTooltip = styled(Box)(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + gap: theme.spacing(1), + maxWidth: theme.spacing(25), +})); + +const StyledProjectBadge = styled(Badge)({ + cursor: 'pointer', + overflowWrap: 'anywhere', +}); + +interface IGroupCardFooterProps { + group: IGroup; +} + +export const GroupCardFooter = ({ group }: IGroupCardFooterProps) => { + const navigate = useNavigate(); + + return ( + <> + {group.users.length > 0 ? ( + + ) : ( + This group has no users + )} + {group.projects.length > 0 && ( + + {group.projects.map((project) => ( + { + e.preventDefault(); + navigate( + `/projects/${project}/settings/access`, + ); + }} + color='secondary' + icon={} + > + {project} + + ))} + + } + > + + {group.projects.length} project + {group.projects.length !== 1 && 's'} + + + )} + + ); +}; diff --git a/frontend/src/component/common/Card/Card.tsx b/frontend/src/component/common/Card/Card.tsx new file mode 100644 index 0000000000..5870ab7f46 --- /dev/null +++ b/frontend/src/component/common/Card/Card.tsx @@ -0,0 +1,112 @@ +import { styled, Card as MUICard, Box } from '@mui/material'; + +const StyledCard = styled(MUICard)(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-between', + height: '100%', + boxShadow: 'none', + border: `1px solid ${theme.palette.divider}`, + [theme.breakpoints.down('sm')]: { + justifyContent: 'center', + }, + transition: 'background-color 0.2s ease-in-out', + backgroundColor: theme.palette.background.default, + '&:hover': { + backgroundColor: theme.palette.neutral.light, + }, + borderRadius: theme.shape.borderRadiusMedium, +})); + +const StyledCardBody = styled(Box)(({ theme }) => ({ + padding: theme.spacing(2), + display: 'flex', + flexFlow: 'column', + height: '100%', + position: 'relative', +})); + +const StyledCardBodyHeader = styled(Box)(({ theme }) => ({ + display: 'flex', + gap: theme.spacing(1), + width: '100%', + alignItems: 'center', + justifyContent: 'space-between', + fontWeight: theme.typography.fontWeightRegular, + fontSize: theme.typography.body1.fontSize, + lineHeight: '1.2', +})); + +const StyledCardIconContainer = styled(Box)(({ theme }) => ({ + display: 'grid', + placeItems: 'center', + padding: theme.spacing(0.5), + alignSelf: 'baseline', + backgroundColor: theme.palette.secondary.light, + color: theme.palette.primary.main, + borderRadius: theme.shape.borderRadiusMedium, + '& > svg': { + height: theme.spacing(2), + width: theme.spacing(2), + }, +})); + +const StyledCardActions = styled(Box)(({ theme }) => ({ + display: 'flex', + gap: theme.spacing(1), + marginLeft: 'auto', +})); + +const StyledCardBodyContent = styled(Box)(({ theme }) => ({ + color: theme.palette.text.secondary, + fontSize: theme.fontSizes.smallBody, + marginTop: theme.spacing(2), +})); + +const StyledCardFooter = styled(Box)(({ theme }) => ({ + padding: theme.spacing(0, 2), + display: 'flex', + background: theme.palette.envAccordion.expanded, + boxShadow: theme.boxShadows.accordionFooter, + alignItems: 'center', + justifyContent: 'space-between', + borderTop: `1px solid ${theme.palette.divider}`, + minHeight: theme.spacing(6.25), + fontSize: theme.fontSizes.smallerBody, + color: theme.palette.text.secondary, + textWrap: 'nowrap', +})); + +interface ICardProps { + icon?: React.ReactNode; + title?: React.ReactNode; + headerActions?: React.ReactNode; + footer?: React.ReactNode; + children?: React.ReactNode; +} + +export const Card = ({ + icon, + title, + headerActions, + footer, + children, +}: ICardProps) => ( + + + + {icon && ( + {icon} + )} + {title} + {headerActions && ( + {headerActions} + )} + + {children && ( + {children} + )} + + {footer && {footer}} + +); diff --git a/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard.tsx b/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard.tsx deleted file mode 100644 index 00a658b5a1..0000000000 --- a/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import type { IReleasePlanTemplate } from 'interfaces/releasePlans'; -import { ReactComponent as ReleaseTemplateIcon } from 'assets/img/releaseTemplates.svg'; -import { styled, Typography } from '@mui/material'; -import { ReleasePlanTemplateCardMenu } from './ReleasePlanTemplateCardMenu'; -import { useNavigate } from 'react-router-dom'; -import { UserAvatar } from 'component/common/UserAvatar/UserAvatar'; -import useUserInfo from 'hooks/api/getters/useUserInfo/useUserInfo'; - -const StyledTemplateCard = styled('aside')(({ theme }) => ({ - height: '100%', - cursor: 'pointer', - '&:hover': { - transition: 'background-color 0.2s ease-in-out', - backgroundColor: theme.palette.neutral.light, - }, - overflow: 'hidden', -})); - -const TemplateCardHeader = styled('div')(({ theme }) => ({ - backgroundColor: theme.palette.primary.main, - padding: theme.spacing(2.5), - borderTopLeftRadius: theme.shape.borderRadiusLarge, - borderTopRightRadius: theme.shape.borderRadiusLarge, -})); - -const TemplateCardBody = styled('div')(({ theme }) => ({ - padding: theme.spacing(1.25), - border: `1px solid ${theme.palette.divider}`, - borderRadius: theme.shape.borderRadiusLarge, - borderTop: 'none', - borderTopLeftRadius: 0, - borderTopRightRadius: 0, - display: 'flex', - flexDirection: 'column', -})); - -const StyledCenter = styled('div')(({ theme }) => ({ - textAlign: 'center', -})); - -const StyledDiv = styled('div')(({ theme }) => ({ - display: 'flex', -})); - -const StyledCreatedBy = styled(Typography)(({ theme }) => ({ - color: theme.palette.text.secondary, - fontSize: theme.fontSizes.smallBody, - display: 'flex', - alignItems: 'center', - marginRight: 'auto', - gap: theme.spacing(1), -})); - -const StyledCreatedByAvatar = styled(UserAvatar)(({ theme }) => ({ - width: theme.spacing(3), - height: theme.spacing(3), -})); - -const StyledMenu = styled('div')(({ theme }) => ({ - marginLeft: theme.spacing(1), - marginTop: theme.spacing(-1), - marginBottom: theme.spacing(-1), - marginRight: theme.spacing(-1), - display: 'flex', - alignItems: 'center', -})); - -export const ReleasePlanTemplateCard = ({ - template, -}: { template: IReleasePlanTemplate }) => { - const navigate = useNavigate(); - const onClick = () => { - navigate(`/release-management/edit/${template.id}`); - }; - const { user: createdBy } = useUserInfo(`${template.createdByUserId}`); - - return ( - - - - - - - -
{template.name}
- - - Created by - - { - e.preventDefault(); - e.stopPropagation(); - }} - > - - - -
-
- ); -}; diff --git a/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCard.tsx b/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCard.tsx new file mode 100644 index 0000000000..ba7d32e0ae --- /dev/null +++ b/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCard.tsx @@ -0,0 +1,55 @@ +import type { IReleasePlanTemplate } from 'interfaces/releasePlans'; +import { ReactComponent as ReleaseTemplateIcon } from 'assets/img/releaseTemplates.svg'; +import { styled } from '@mui/material'; +import { Link } from 'react-router-dom'; +import { Card } from 'component/common/Card/Card'; +import { Truncator } from 'component/common/Truncator/Truncator'; +import { ReleasePlanTemplateCardActions } from './ReleasePlanTemplateCardActions'; +import { ReleasePlanTemplateCardFooter } from './ReleasePlanTemplateCardFooter'; + +const StyledCardLink = styled(Link)(({ theme }) => ({ + color: 'inherit', + textDecoration: 'none', + border: 'none', + padding: '0', + background: 'transparent', + fontFamily: theme.typography.fontFamily, + pointer: 'cursor', +})); + +const StyledCardTitle = styled('h3')(({ theme }) => ({ + margin: 0, + marginRight: 'auto', + fontWeight: theme.typography.fontWeightRegular, + fontSize: theme.typography.body1.fontSize, + lineHeight: '1.2', +})); + +export const ReleasePlanTemplateCard = ({ + template, +}: { template: IReleasePlanTemplate }) => ( + + } + title={ + + {template.name} + + } + headerActions={ + + } + footer={} + > + {template.description && ( + + {template.description} + + )} + + +); diff --git a/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCardActions.tsx b/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCardActions.tsx new file mode 100644 index 0000000000..00913ff12f --- /dev/null +++ b/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCardActions.tsx @@ -0,0 +1,138 @@ +import { useCallback, useState } from 'react'; +import { + IconButton, + Tooltip, + MenuItem, + ListItemText, + styled, + Popover, + MenuList, + ListItemIcon, + Typography, +} from '@mui/material'; +import MoreVertIcon from '@mui/icons-material/MoreVert'; +import type { IReleasePlanTemplate } from 'interfaces/releasePlans'; +import { useReleasePlanTemplatesApi } from 'hooks/api/actions/useReleasePlanTemplatesApi/useReleasePlanTemplatesApi'; +import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplates'; +import useToast from 'hooks/useToast'; +import { formatUnknownError } from 'utils/formatUnknownError'; +import { TemplateDeleteDialog } from '../TemplateDeleteDialog'; +import EditIcon from '@mui/icons-material/Edit'; +import DeleteIcon from '@mui/icons-material/Delete'; +import { Link } from 'react-router-dom'; + +const StyledActions = styled('div')(({ theme }) => ({ + margin: theme.spacing(-1), + marginLeft: theme.spacing(-0.5), + display: 'flex', + justifyContent: 'center', + alignItems: 'center', +})); + +const StyledPopover = styled(Popover)(({ theme }) => ({ + borderRadius: theme.shape.borderRadiusLarge, + padding: theme.spacing(1, 1.5), +})); + +export const ReleasePlanTemplateCardActions = ({ + template, +}: { template: IReleasePlanTemplate }) => { + const [anchorEl, setAnchorEl] = useState(null); + const { deleteReleasePlanTemplate } = useReleasePlanTemplatesApi(); + const { refetch } = useReleasePlanTemplates(); + const { setToastData, setToastApiError } = useToast(); + const [deleteOpen, setDeleteOpen] = useState(false); + const deleteReleasePlan = useCallback(async () => { + try { + await deleteReleasePlanTemplate(template.id); + refetch(); + setToastData({ + type: 'success', + text: 'Release plan template deleted', + }); + } catch (error: unknown) { + setToastApiError(formatUnknownError(error)); + } + }, [setToastApiError, refetch, setToastData, deleteReleasePlanTemplate]); + + const open = Boolean(anchorEl); + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; + + const id = `release-plan-template-${template.id}-actions`; + const menuId = `${id}-menu`; + + return ( + { + e.preventDefault(); + e.stopPropagation(); + }} + > + + + + + + + + + + + + + + Edit template + + + + { + setDeleteOpen(true); + handleClose(); + }} + > + + + + + + Delete template + + + + + + + + ); +}; diff --git a/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCardFooter.tsx b/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCardFooter.tsx new file mode 100644 index 0000000000..bfb29eb346 --- /dev/null +++ b/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCard/ReleasePlanTemplateCardFooter.tsx @@ -0,0 +1,60 @@ +import type { IReleasePlanTemplate } from 'interfaces/releasePlans'; +import { Box, styled } from '@mui/material'; +import useUserInfo from 'hooks/api/getters/useUserInfo/useUserInfo'; +import theme from 'themes/theme'; +import { AvatarComponent } from 'component/common/AvatarGroup/AvatarGroup'; + +const StyledFooter = styled(Box)({ + display: 'flex', + alignItems: 'center', + gap: theme.spacing(1), +}); + +const StyledAvatar = styled(AvatarComponent)(({ theme }) => ({ + height: theme.spacing(3.5), + width: theme.spacing(3.5), + marginLeft: 0, +})); + +const StyledContainer = styled(Box)({ + display: 'flex', + flexDirection: 'column', +}); + +const StyledValue = styled('div')(({ theme }) => ({ + fontSize: theme.fontSizes.smallBody, + lineHeight: 1, + lineClamp: `1`, + WebkitLineClamp: 1, + display: '-webkit-box', + boxOrient: 'vertical', + textOverflow: 'ellipsis', + overflow: 'hidden', + alignItems: 'flex-start', + WebkitBoxOrient: 'vertical', + wordBreak: 'break-word', + maxWidth: '100%', + color: theme.palette.text.primary, +})); + +interface IReleasePlanTemplateCardFooterProps { + template: IReleasePlanTemplate; +} + +export const ReleasePlanTemplateCardFooter = ({ + template, +}: IReleasePlanTemplateCardFooterProps) => { + const { user: createdBy } = useUserInfo(`${template.createdByUserId}`); + + return ( + + + + Created by + + {createdBy.name || createdBy.username || createdBy.email} + + + + ); +}; diff --git a/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCardMenu.tsx b/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCardMenu.tsx deleted file mode 100644 index 2955cae0b3..0000000000 --- a/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateCardMenu.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { useCallback, useState } from 'react'; -import { - IconButton, - Tooltip, - Menu, - MenuItem, - ListItemText, -} from '@mui/material'; -import MoreVertIcon from '@mui/icons-material/MoreVert'; -import type { IReleasePlanTemplate } from 'interfaces/releasePlans'; -import { useReleasePlanTemplatesApi } from 'hooks/api/actions/useReleasePlanTemplatesApi/useReleasePlanTemplatesApi'; -import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplates'; -import useToast from 'hooks/useToast'; -import { formatUnknownError } from 'utils/formatUnknownError'; -import { TemplateDeleteDialog } from './TemplateDeleteDialog'; - -export const ReleasePlanTemplateCardMenu = ({ - template, - onClick, -}: { template: IReleasePlanTemplate; onClick: () => void }) => { - const [isMenuOpen, setIsMenuOpen] = useState(false); - const [anchorEl, setAnchorEl] = useState(null); - const { deleteReleasePlanTemplate } = useReleasePlanTemplatesApi(); - const { refetch } = useReleasePlanTemplates(); - const { setToastData, setToastApiError } = useToast(); - const [deleteOpen, setDeleteOpen] = useState(false); - const deleteReleasePlan = useCallback(async () => { - try { - await deleteReleasePlanTemplate(template.id); - refetch(); - setToastData({ - type: 'success', - text: 'Release plan template deleted', - }); - } catch (error: unknown) { - setToastApiError(formatUnknownError(error)); - } - }, [setToastApiError, refetch, setToastData, deleteReleasePlanTemplate]); - - const closeMenu = () => { - setIsMenuOpen(false); - setAnchorEl(null); - }; - - const handleMenuClick = (event: React.SyntheticEvent) => { - event.stopPropagation(); - if (isMenuOpen) { - closeMenu(); - } else { - setAnchorEl(event.currentTarget); - setIsMenuOpen(true); - } - }; - - return ( - <> - - - - - - - { - onClick(); - }} - > - Edit template - - { - setDeleteOpen(true); - closeMenu(); - }} - > - Delete template - - - - - ); -}; diff --git a/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateList.tsx b/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateList.tsx index 9ae7c1093c..767cec5dee 100644 --- a/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateList.tsx +++ b/frontend/src/component/releases/ReleaseManagement/ReleasePlanTemplateList.tsx @@ -1,5 +1,5 @@ import { Grid } from '@mui/material'; -import { ReleasePlanTemplateCard } from './ReleasePlanTemplateCard'; +import { ReleasePlanTemplateCard } from './ReleasePlanTemplateCard/ReleasePlanTemplateCard'; import type { IReleasePlanTemplate } from 'interfaces/releasePlans'; interface ITemplateList {