mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	
							parent
							
								
									c978ed6c6b
								
							
						
					
					
						commit
						7c00b760f8
					
				| @ -0,0 +1,50 @@ | |||||||
|  | import { Dialogue } from 'component/common/Dialogue/Dialogue'; | ||||||
|  | import React from 'react'; | ||||||
|  | import { formatUnknownError } from 'utils/formatUnknownError'; | ||||||
|  | import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi'; | ||||||
|  | import useProjects from 'hooks/api/getters/useProjects/useProjects'; | ||||||
|  | import useToast from 'hooks/useToast'; | ||||||
|  | 
 | ||||||
|  | interface IDeleteProjectDialogueProps { | ||||||
|  |     project: string; | ||||||
|  |     open: boolean; | ||||||
|  |     onClose?: () => void; | ||||||
|  |     onSuccess?: () => void; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const DeleteProjectDialogue = ({ | ||||||
|  |     open, | ||||||
|  |     onClose, | ||||||
|  |     project, | ||||||
|  |     onSuccess, | ||||||
|  | }: IDeleteProjectDialogueProps) => { | ||||||
|  |     const { deleteProject } = useProjectApi(); | ||||||
|  |     const { refetch: refetchProjectOverview } = useProjects(); | ||||||
|  |     const { setToastData, setToastApiError } = useToast(); | ||||||
|  | 
 | ||||||
|  |     const onClick = async (e: React.SyntheticEvent) => { | ||||||
|  |         e.preventDefault(); | ||||||
|  |         try { | ||||||
|  |             await deleteProject(project); | ||||||
|  |             refetchProjectOverview(); | ||||||
|  |             setToastData({ | ||||||
|  |                 title: 'Deleted project', | ||||||
|  |                 type: 'success', | ||||||
|  |                 text: 'Successfully deleted project', | ||||||
|  |             }); | ||||||
|  |             onSuccess?.(); | ||||||
|  |         } catch (ex: unknown) { | ||||||
|  |             setToastApiError(formatUnknownError(ex)); | ||||||
|  |         } | ||||||
|  |         onClose?.(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |         <Dialogue | ||||||
|  |             open={open} | ||||||
|  |             onClick={onClick} | ||||||
|  |             onClose={onClose} | ||||||
|  |             title="Really delete project" | ||||||
|  |         /> | ||||||
|  |     ); | ||||||
|  | }; | ||||||
| @ -18,7 +18,7 @@ export const useStyles = makeStyles()(theme => ({ | |||||||
|         marginBottom: '1rem', |         marginBottom: '1rem', | ||||||
|     }, |     }, | ||||||
|     innerContainer: { |     innerContainer: { | ||||||
|         padding: '1rem 2rem', |         padding: '1.25rem 2rem', | ||||||
|         display: 'flex', |         display: 'flex', | ||||||
|         alignItems: 'center', |         alignItems: 'center', | ||||||
|     }, |     }, | ||||||
|  | |||||||
| @ -4,21 +4,44 @@ import useLoading from 'hooks/useLoading'; | |||||||
| import ApiError from 'component/common/ApiError/ApiError'; | import ApiError from 'component/common/ApiError/ApiError'; | ||||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||||
| import { useStyles } from './Project.styles'; | import { useStyles } from './Project.styles'; | ||||||
| import { Tab, Tabs } from '@mui/material'; | import { styled, Tab, Tabs } from '@mui/material'; | ||||||
| import { Edit } from '@mui/icons-material'; | import { Delete, Edit } from '@mui/icons-material'; | ||||||
| import useToast from 'hooks/useToast'; | import useToast from 'hooks/useToast'; | ||||||
| import useQueryParams from 'hooks/useQueryParams'; | import useQueryParams from 'hooks/useQueryParams'; | ||||||
| import { useEffect } from 'react'; | import { useEffect, useState } from 'react'; | ||||||
| import { ProjectAccess } from '../ProjectAccess/ProjectAccess'; | import { ProjectAccess } from '../ProjectAccess/ProjectAccess'; | ||||||
| import ProjectEnvironment from '../ProjectEnvironment/ProjectEnvironment'; | import ProjectEnvironment from '../ProjectEnvironment/ProjectEnvironment'; | ||||||
| import { ProjectFeaturesArchive } from './ProjectFeaturesArchive/ProjectFeaturesArchive'; | import { ProjectFeaturesArchive } from './ProjectFeaturesArchive/ProjectFeaturesArchive'; | ||||||
| import ProjectOverview from './ProjectOverview'; | import ProjectOverview from './ProjectOverview'; | ||||||
| import ProjectHealth from './ProjectHealth/ProjectHealth'; | import ProjectHealth from './ProjectHealth/ProjectHealth'; | ||||||
| import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton'; | import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton'; | ||||||
| import { UPDATE_PROJECT } from 'component/providers/AccessProvider/permissions'; | import { | ||||||
|  |     DELETE_PROJECT, | ||||||
|  |     UPDATE_PROJECT, | ||||||
|  | } from 'component/providers/AccessProvider/permissions'; | ||||||
| import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; | import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; | ||||||
| import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; | import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; | ||||||
| import { Routes, Route, useLocation } from 'react-router-dom'; | import { Routes, Route, useLocation } from 'react-router-dom'; | ||||||
|  | import { DeleteProjectDialogue } from './DeleteProject/DeleteProjectDialogue'; | ||||||
|  | 
 | ||||||
|  | const StyledDiv = styled('div')(() => ({ | ||||||
|  |     display: 'flex', | ||||||
|  | })); | ||||||
|  | 
 | ||||||
|  | const StyledName = styled('div')(({ theme }) => ({ | ||||||
|  |     overflow: 'hidden', | ||||||
|  |     textOverflow: 'ellipsis', | ||||||
|  |     whiteSpace: 'nowrap', | ||||||
|  |     paddingBottom: theme.spacing(2), | ||||||
|  | })); | ||||||
|  | 
 | ||||||
|  | const StyledTitle = styled('span')(({ theme }) => ({ | ||||||
|  |     fontSize: theme.fontSizes.smallBody, | ||||||
|  |     fontWeight: 'normal', | ||||||
|  | })); | ||||||
|  | const StyledText = styled(StyledTitle)(({ theme }) => ({ | ||||||
|  |     color: theme.palette.grey[800], | ||||||
|  | })); | ||||||
| 
 | 
 | ||||||
| const Project = () => { | const Project = () => { | ||||||
|     const projectId = useRequiredPathParam('projectId'); |     const projectId = useRequiredPathParam('projectId'); | ||||||
| @ -33,6 +56,8 @@ const Project = () => { | |||||||
|     const basePath = `/projects/${projectId}`; |     const basePath = `/projects/${projectId}`; | ||||||
|     const projectName = project?.name || projectId; |     const projectName = project?.name || projectId; | ||||||
| 
 | 
 | ||||||
|  |     const [showDelDialog, setShowDelDialog] = useState(false); | ||||||
|  | 
 | ||||||
|     const tabs = [ |     const tabs = [ | ||||||
|         { |         { | ||||||
|             title: 'Overview', |             title: 'Overview', | ||||||
| @ -85,13 +110,37 @@ const Project = () => { | |||||||
|             <div className={styles.header}> |             <div className={styles.header}> | ||||||
|                 <div className={styles.innerContainer}> |                 <div className={styles.innerContainer}> | ||||||
|                     <h2 className={styles.title}> |                     <h2 className={styles.title}> | ||||||
|                         <div className={styles.titleText} data-loading> |                         <div> | ||||||
|                             {projectName} |                             <StyledName data-loading>{projectName}</StyledName> | ||||||
|  |                             <ConditionallyRender | ||||||
|  |                                 condition={Boolean(project.description)} | ||||||
|  |                                 show={ | ||||||
|  |                                     <StyledDiv> | ||||||
|  |                                         <StyledTitle data-loading> | ||||||
|  |                                             Description:  | ||||||
|  |                                         </StyledTitle> | ||||||
|  |                                         <StyledText data-loading> | ||||||
|  |                                             {project.description} | ||||||
|  |                                         </StyledText> | ||||||
|  |                                     </StyledDiv> | ||||||
|  |                                 } | ||||||
|  |                             /> | ||||||
|  |                             <StyledDiv> | ||||||
|  |                                 <StyledTitle data-loading> | ||||||
|  |                                     projectId:  | ||||||
|  |                                 </StyledTitle> | ||||||
|  |                                 <StyledText data-loading> | ||||||
|  |                                     {projectId} | ||||||
|  |                                 </StyledText> | ||||||
|  |                             </StyledDiv> | ||||||
|                         </div> |                         </div> | ||||||
|  |                         <StyledDiv> | ||||||
|                             <PermissionIconButton |                             <PermissionIconButton | ||||||
|                                 permission={UPDATE_PROJECT} |                                 permission={UPDATE_PROJECT} | ||||||
|                                 projectId={projectId} |                                 projectId={projectId} | ||||||
|                             sx={{ visibility: isOss() ? 'hidden' : 'visible' }} |                                 sx={{ | ||||||
|  |                                     visibility: isOss() ? 'hidden' : 'visible', | ||||||
|  |                                 }} | ||||||
|                                 onClick={() => |                                 onClick={() => | ||||||
|                                     navigate(`/projects/${projectId}/edit`) |                                     navigate(`/projects/${projectId}/edit`) | ||||||
|                                 } |                                 } | ||||||
| @ -100,6 +149,21 @@ const Project = () => { | |||||||
|                             > |                             > | ||||||
|                                 <Edit /> |                                 <Edit /> | ||||||
|                             </PermissionIconButton> |                             </PermissionIconButton> | ||||||
|  |                             <PermissionIconButton | ||||||
|  |                                 permission={DELETE_PROJECT} | ||||||
|  |                                 projectId={projectId} | ||||||
|  |                                 sx={{ | ||||||
|  |                                     visibility: isOss() ? 'hidden' : 'visible', | ||||||
|  |                                 }} | ||||||
|  |                                 onClick={() => { | ||||||
|  |                                     setShowDelDialog(true); | ||||||
|  |                                 }} | ||||||
|  |                                 tooltipProps={{ title: 'Delete project' }} | ||||||
|  |                                 data-loading | ||||||
|  |                             > | ||||||
|  |                                 <Delete /> | ||||||
|  |                             </PermissionIconButton> | ||||||
|  |                         </StyledDiv> | ||||||
|                     </h2> |                     </h2> | ||||||
|                 </div> |                 </div> | ||||||
|                 <ConditionallyRender |                 <ConditionallyRender | ||||||
| @ -132,6 +196,16 @@ const Project = () => { | |||||||
|                     </Tabs> |                     </Tabs> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|  |             <DeleteProjectDialogue | ||||||
|  |                 project={projectId} | ||||||
|  |                 open={showDelDialog} | ||||||
|  |                 onClose={() => { | ||||||
|  |                     setShowDelDialog(false); | ||||||
|  |                 }} | ||||||
|  |                 onSuccess={() => { | ||||||
|  |                     navigate('/projects'); | ||||||
|  |                 }} | ||||||
|  |             /> | ||||||
|             <Routes> |             <Routes> | ||||||
|                 <Route path="health" element={<ProjectHealth />} /> |                 <Route path="health" element={<ProjectHealth />} /> | ||||||
|                 <Route path="access/*" element={<ProjectAccess />} /> |                 <Route path="access/*" element={<ProjectAccess />} /> | ||||||
|  | |||||||
| @ -32,6 +32,7 @@ export const useStyles = makeStyles()(theme => ({ | |||||||
|         boxOrient: 'vertical', |         boxOrient: 'vertical', | ||||||
|         textOverflow: 'ellipsis', |         textOverflow: 'ellipsis', | ||||||
|         overflow: 'hidden', |         overflow: 'hidden', | ||||||
|  |         alignItems: 'flex-start', | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|     projectIcon: { |     projectIcon: { | ||||||
|  | |||||||
| @ -4,21 +4,17 @@ import MoreVertIcon from '@mui/icons-material/MoreVert'; | |||||||
| import { ReactComponent as ProjectIcon } from 'assets/icons/projectIcon.svg'; | import { ReactComponent as ProjectIcon } from 'assets/icons/projectIcon.svg'; | ||||||
| import React, { useState, SyntheticEvent, useContext } from 'react'; | import React, { useState, SyntheticEvent, useContext } from 'react'; | ||||||
| import { useNavigate } from 'react-router-dom'; | import { useNavigate } from 'react-router-dom'; | ||||||
| import { Dialogue } from 'component/common/Dialogue/Dialogue'; |  | ||||||
| import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi'; |  | ||||||
| import useProjects from 'hooks/api/getters/useProjects/useProjects'; |  | ||||||
| import { Delete, Edit } from '@mui/icons-material'; | import { Delete, Edit } from '@mui/icons-material'; | ||||||
| import { getProjectEditPath } from 'utils/routePathHelpers'; | import { getProjectEditPath } from 'utils/routePathHelpers'; | ||||||
| import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton'; | import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton'; | ||||||
| import useToast from 'hooks/useToast'; |  | ||||||
| import { | import { | ||||||
|     UPDATE_PROJECT, |     UPDATE_PROJECT, | ||||||
|     DELETE_PROJECT, |     DELETE_PROJECT, | ||||||
| } from 'component/providers/AccessProvider/permissions'; | } from 'component/providers/AccessProvider/permissions'; | ||||||
| import { formatUnknownError } from 'utils/formatUnknownError'; |  | ||||||
| import AccessContext from 'contexts/AccessContext'; | import AccessContext from 'contexts/AccessContext'; | ||||||
| import { DEFAULT_PROJECT_ID } from 'hooks/api/getters/useDefaultProject/useDefaultProjectId'; | import { DEFAULT_PROJECT_ID } from 'hooks/api/getters/useDefaultProject/useDefaultProjectId'; | ||||||
| import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; | import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; | ||||||
|  | import { DeleteProjectDialogue } from '../Project/DeleteProject/DeleteProjectDialogue'; | ||||||
| 
 | 
 | ||||||
| interface IProjectCardProps { | interface IProjectCardProps { | ||||||
|     name: string; |     name: string; | ||||||
| @ -40,36 +36,15 @@ export const ProjectCard = ({ | |||||||
|     const { classes } = useStyles(); |     const { classes } = useStyles(); | ||||||
|     const { hasAccess } = useContext(AccessContext); |     const { hasAccess } = useContext(AccessContext); | ||||||
|     const { isOss } = useUiConfig(); |     const { isOss } = useUiConfig(); | ||||||
|     const { refetch: refetchProjectOverview } = useProjects(); |  | ||||||
|     const [anchorEl, setAnchorEl] = useState(null); |     const [anchorEl, setAnchorEl] = useState(null); | ||||||
|     const [showDelDialog, setShowDelDialog] = useState(false); |     const [showDelDialog, setShowDelDialog] = useState(false); | ||||||
|     const { deleteProject } = useProjectApi(); |  | ||||||
|     const navigate = useNavigate(); |     const navigate = useNavigate(); | ||||||
|     const { setToastData, setToastApiError } = useToast(); |  | ||||||
| 
 |  | ||||||
|     // @ts-expect-error
 |     // @ts-expect-error
 | ||||||
|     const handleClick = e => { |     const handleClick = e => { | ||||||
|         e.preventDefault(); |         e.preventDefault(); | ||||||
|         setAnchorEl(e.currentTarget); |         setAnchorEl(e.currentTarget); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     const onRemoveProject = async (e: React.SyntheticEvent) => { |  | ||||||
|         e.preventDefault(); |  | ||||||
|         try { |  | ||||||
|             await deleteProject(id); |  | ||||||
|             refetchProjectOverview(); |  | ||||||
|             setToastData({ |  | ||||||
|                 title: 'Deleted project', |  | ||||||
|                 type: 'success', |  | ||||||
|                 text: 'Successfully deleted project', |  | ||||||
|             }); |  | ||||||
|         } catch (e: unknown) { |  | ||||||
|             setToastApiError(formatUnknownError(e)); |  | ||||||
|         } |  | ||||||
|         setShowDelDialog(false); |  | ||||||
|         setAnchorEl(null); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     const canDeleteProject = |     const canDeleteProject = | ||||||
|         hasAccess(DELETE_PROJECT, id) && id !== DEFAULT_PROJECT_ID; |         hasAccess(DELETE_PROJECT, id) && id !== DEFAULT_PROJECT_ID; | ||||||
| 
 | 
 | ||||||
| @ -152,15 +127,13 @@ export const ProjectCard = ({ | |||||||
|                     <p data-loading>members</p> |                     <p data-loading>members</p> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
|             <Dialogue |             <DeleteProjectDialogue | ||||||
|  |                 project={id} | ||||||
|                 open={showDelDialog} |                 open={showDelDialog} | ||||||
|                 onClick={onRemoveProject} |                 onClose={() => { | ||||||
|                 onClose={event => { |  | ||||||
|                     event.preventDefault(); |  | ||||||
|                     setAnchorEl(null); |                     setAnchorEl(null); | ||||||
|                     setShowDelDialog(false); |                     setShowDelDialog(false); | ||||||
|                 }} |                 }} | ||||||
|                 title="Really delete project" |  | ||||||
|             /> |             /> | ||||||
|         </Card> |         </Card> | ||||||
|     ); |     ); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user