mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: delete features FE (#3350)
This commit is contained in:
		
							parent
							
								
									8a03e5526c
								
							
						
					
					
						commit
						076768215e
					
				| @ -1,12 +1,16 @@ | |||||||
| import { FC } from 'react'; | import { FC, useState } from 'react'; | ||||||
| import { Button } from '@mui/material'; | import { Button } from '@mui/material'; | ||||||
| import { Undo } from '@mui/icons-material'; | import { Undo } from '@mui/icons-material'; | ||||||
| import { UPDATE_FEATURE } from 'component/providers/AccessProvider/permissions'; | import { | ||||||
|  |     DELETE_FEATURE, | ||||||
|  |     UPDATE_FEATURE, | ||||||
|  | } from 'component/providers/AccessProvider/permissions'; | ||||||
| import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC'; | import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC'; | ||||||
| import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi'; | import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi'; | ||||||
| import { formatUnknownError } from 'utils/formatUnknownError'; | import { formatUnknownError } from 'utils/formatUnknownError'; | ||||||
| import { useFeaturesArchive } from 'hooks/api/getters/useFeaturesArchive/useFeaturesArchive'; | import { useFeaturesArchive } from 'hooks/api/getters/useFeaturesArchive/useFeaturesArchive'; | ||||||
| import useToast from 'hooks/useToast'; | import useToast from 'hooks/useToast'; | ||||||
|  | import { ArchivedFeatureDeleteConfirm } from './ArchivedFeatureActionCell/ArchivedFeatureDeleteConfirm/ArchivedFeatureDeleteConfirm'; | ||||||
| 
 | 
 | ||||||
| interface IArchiveBatchActionsProps { | interface IArchiveBatchActionsProps { | ||||||
|     selectedIds: string[]; |     selectedIds: string[]; | ||||||
| @ -20,6 +24,7 @@ export const ArchiveBatchActions: FC<IArchiveBatchActionsProps> = ({ | |||||||
|     const { reviveFeatures } = useProjectApi(); |     const { reviveFeatures } = useProjectApi(); | ||||||
|     const { setToastData, setToastApiError } = useToast(); |     const { setToastData, setToastApiError } = useToast(); | ||||||
|     const { refetchArchived } = useFeaturesArchive(projectId); |     const { refetchArchived } = useFeaturesArchive(projectId); | ||||||
|  |     const [deleteModalOpen, setDeleteModalOpen] = useState(false); | ||||||
| 
 | 
 | ||||||
|     const onRevive = async () => { |     const onRevive = async () => { | ||||||
|         try { |         try { | ||||||
| @ -34,6 +39,10 @@ export const ArchiveBatchActions: FC<IArchiveBatchActionsProps> = ({ | |||||||
|             setToastApiError(formatUnknownError(error)); |             setToastApiError(formatUnknownError(error)); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  | 
 | ||||||
|  |     const onDelete = async () => { | ||||||
|  |         setDeleteModalOpen(true); | ||||||
|  |     }; | ||||||
|     return ( |     return ( | ||||||
|         <> |         <> | ||||||
|             <PermissionHOC projectId={projectId} permission={UPDATE_FEATURE}> |             <PermissionHOC projectId={projectId} permission={UPDATE_FEATURE}> | ||||||
| @ -49,6 +58,26 @@ export const ArchiveBatchActions: FC<IArchiveBatchActionsProps> = ({ | |||||||
|                     </Button> |                     </Button> | ||||||
|                 )} |                 )} | ||||||
|             </PermissionHOC> |             </PermissionHOC> | ||||||
|  |             <PermissionHOC projectId={projectId} permission={DELETE_FEATURE}> | ||||||
|  |                 {({ hasAccess }) => ( | ||||||
|  |                     <Button | ||||||
|  |                         disabled={!hasAccess} | ||||||
|  |                         startIcon={<Undo />} | ||||||
|  |                         variant="outlined" | ||||||
|  |                         size="small" | ||||||
|  |                         onClick={onDelete} | ||||||
|  |                     > | ||||||
|  |                         Delete | ||||||
|  |                     </Button> | ||||||
|  |                 )} | ||||||
|  |             </PermissionHOC> | ||||||
|  |             <ArchivedFeatureDeleteConfirm | ||||||
|  |                 deletedFeatures={selectedIds} | ||||||
|  |                 projectId={projectId} | ||||||
|  |                 open={deleteModalOpen} | ||||||
|  |                 setOpen={setDeleteModalOpen} | ||||||
|  |                 refetch={refetchArchived} | ||||||
|  |             /> | ||||||
|         </> |         </> | ||||||
|     ); |     ); | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -341,7 +341,8 @@ export const ArchiveTable = ({ | |||||||
|                 )} |                 )} | ||||||
|             /> |             /> | ||||||
|             <ArchivedFeatureDeleteConfirm |             <ArchivedFeatureDeleteConfirm | ||||||
|                 deletedFeature={deletedFeature} |                 deletedFeatures={[deletedFeature?.name!]} | ||||||
|  |                 projectId={projectId!} | ||||||
|                 open={deleteModalOpen} |                 open={deleteModalOpen} | ||||||
|                 setOpen={setDeleteModalOpen} |                 setOpen={setDeleteModalOpen} | ||||||
|                 refetch={refetch} |                 refetch={refetch} | ||||||
|  | |||||||
| @ -2,13 +2,13 @@ import { Alert, styled } from '@mui/material'; | |||||||
| import React, { useState } from 'react'; | import React, { useState } from 'react'; | ||||||
| import { Dialogue } from 'component/common/Dialogue/Dialogue'; | import { Dialogue } from 'component/common/Dialogue/Dialogue'; | ||||||
| import Input from 'component/common/Input/Input'; | import Input from 'component/common/Input/Input'; | ||||||
| import { IFeatureToggle } from 'interfaces/featureToggle'; |  | ||||||
| import { formatUnknownError } from 'utils/formatUnknownError'; | import { formatUnknownError } from 'utils/formatUnknownError'; | ||||||
| import { useFeatureArchiveApi } from 'hooks/api/actions/useFeatureArchiveApi/useReviveFeatureApi'; |  | ||||||
| import useToast from 'hooks/useToast'; | import useToast from 'hooks/useToast'; | ||||||
|  | import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi'; | ||||||
| 
 | 
 | ||||||
| interface IArchivedFeatureDeleteConfirmProps { | interface IArchivedFeatureDeleteConfirmProps { | ||||||
|     deletedFeature?: IFeatureToggle; |     deletedFeatures: string[]; | ||||||
|  |     projectId: string; | ||||||
|     open: boolean; |     open: boolean; | ||||||
|     setOpen: React.Dispatch<React.SetStateAction<boolean>>; |     setOpen: React.Dispatch<React.SetStateAction<boolean>>; | ||||||
|     refetch: () => void; |     refetch: () => void; | ||||||
| @ -23,27 +23,32 @@ const StyledFormInput = styled(Input)(({ theme }) => ({ | |||||||
|     width: '100%', |     width: '100%', | ||||||
| })); | })); | ||||||
| 
 | 
 | ||||||
|  | const confirmationText = 'I want to delete'; | ||||||
|  | 
 | ||||||
| export const ArchivedFeatureDeleteConfirm = ({ | export const ArchivedFeatureDeleteConfirm = ({ | ||||||
|     deletedFeature, |     deletedFeatures, | ||||||
|  |     projectId, | ||||||
|     open, |     open, | ||||||
|     setOpen, |     setOpen, | ||||||
|     refetch, |     refetch, | ||||||
| }: IArchivedFeatureDeleteConfirmProps) => { | }: IArchivedFeatureDeleteConfirmProps) => { | ||||||
|     const [confirmName, setConfirmName] = useState(''); |     const [confirmName, setConfirmName] = useState(''); | ||||||
|     const { setToastData, setToastApiError } = useToast(); |     const { setToastData, setToastApiError } = useToast(); | ||||||
|     const { deleteFeature } = useFeatureArchiveApi(); |     const { deleteFeatures } = useProjectApi(); | ||||||
| 
 | 
 | ||||||
|     const onDeleteFeatureToggle = async () => { |     const onDeleteFeatureToggle = async () => { | ||||||
|         try { |         try { | ||||||
|             if (!deletedFeature) { |             if (deletedFeatures.length === 0) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             await deleteFeature(deletedFeature.name); |             await deleteFeatures(projectId, deletedFeatures); | ||||||
|             await refetch(); |             await refetch(); | ||||||
|             setToastData({ |             setToastData({ | ||||||
|                 type: 'success', |                 type: 'success', | ||||||
|                 title: 'Feature toggle deleted', |                 title: 'Feature toggles deleted', | ||||||
|                 text: `You have successfully deleted the ${deletedFeature.name} feature toggle.`, |                 text: `You have successfully deleted following features toggles: ${deletedFeatures.join( | ||||||
|  |                     ', ' | ||||||
|  |                 )}.`,
 | ||||||
|             }); |             }); | ||||||
|         } catch (error: unknown) { |         } catch (error: unknown) { | ||||||
|             setToastApiError(formatUnknownError(error)); |             setToastApiError(formatUnknownError(error)); | ||||||
| @ -61,13 +66,13 @@ export const ArchivedFeatureDeleteConfirm = ({ | |||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
|         <Dialogue |         <Dialogue | ||||||
|             title="Delete feature toggle?" |             title="Delete feature toggles?" | ||||||
|             open={open} |             open={open} | ||||||
|             primaryButtonText="Delete feature toggle" |             primaryButtonText="Delete feature toggles" | ||||||
|             secondaryButtonText="Cancel" |             secondaryButtonText="Cancel" | ||||||
|             onClick={onDeleteFeatureToggle} |             onClick={onDeleteFeatureToggle} | ||||||
|             onClose={clearModal} |             onClose={clearModal} | ||||||
|             disabledPrimaryButton={deletedFeature?.name !== confirmName} |             disabledPrimaryButton={confirmationText !== confirmName} | ||||||
|             formId={formId} |             formId={formId} | ||||||
|         > |         > | ||||||
|             <Alert severity="warning"> |             <Alert severity="warning"> | ||||||
| @ -78,8 +83,9 @@ export const ArchivedFeatureDeleteConfirm = ({ | |||||||
|             </Alert> |             </Alert> | ||||||
| 
 | 
 | ||||||
|             <StyledDeleteParagraph> |             <StyledDeleteParagraph> | ||||||
|                 In order to delete this feature toggle, please enter its name in |                 In order to delete feature toggles, please enter the following | ||||||
|                 the text field below: <strong>{deletedFeature?.name}</strong> |                 confirmation text in the text field below:{' '} | ||||||
|  |                 <strong>I want to delete</strong> | ||||||
|             </StyledDeleteParagraph> |             </StyledDeleteParagraph> | ||||||
| 
 | 
 | ||||||
|             <form id={formId}> |             <form id={formId}> | ||||||
| @ -89,8 +95,8 @@ export const ArchivedFeatureDeleteConfirm = ({ | |||||||
|                         setConfirmName(e.currentTarget.value); |                         setConfirmName(e.currentTarget.value); | ||||||
|                     }} |                     }} | ||||||
|                     value={confirmName} |                     value={confirmName} | ||||||
|                     placeholder="<feature toggle name>" |                     placeholder="<deletion confirmation>" | ||||||
|                     label="Feature toggle name" |                     label="Deletetion confirmation" | ||||||
|                 /> |                 /> | ||||||
|             </form> |             </form> | ||||||
|         </Dialogue> |         </Dialogue> | ||||||
|  | |||||||
| @ -223,6 +223,16 @@ const useProjectApi = () => { | |||||||
|         return makeRequest(req.caller, req.id); |         return makeRequest(req.caller, req.id); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     const deleteFeatures = async (projectId: string, featureIds: string[]) => { | ||||||
|  |         const path = `api/admin/projects/${projectId}/delete`; | ||||||
|  |         const req = createRequest(path, { | ||||||
|  |             method: 'POST', | ||||||
|  |             body: JSON.stringify({ features: featureIds }), | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         return makeRequest(req.caller, req.id); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     const staleFeatures = async ( |     const staleFeatures = async ( | ||||||
|         projectId: string, |         projectId: string, | ||||||
|         featureIds: string[], |         featureIds: string[], | ||||||
| @ -257,6 +267,7 @@ const useProjectApi = () => { | |||||||
|         archiveFeatures, |         archiveFeatures, | ||||||
|         reviveFeatures, |         reviveFeatures, | ||||||
|         staleFeatures, |         staleFeatures, | ||||||
|  |         deleteFeatures, | ||||||
|         searchProjectUser, |         searchProjectUser, | ||||||
|         errors, |         errors, | ||||||
|         loading, |         loading, | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user