mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: UI stub for adding dependent features (#4814)
This commit is contained in:
		
							parent
							
								
									d28e7e5a69
								
							
						
					
					
						commit
						b4742df8be
					
				| @ -0,0 +1,60 @@ | ||||
| import { Box, styled } from '@mui/material'; | ||||
| import { trim } from '../../common/util'; | ||||
| import React, { FC, useState } from 'react'; | ||||
| import Input from '../../common/Input/Input'; | ||||
| import { CREATE_FEATURE } from '../../providers/AccessProvider/permissions'; | ||||
| import PermissionButton from '../../common/PermissionButton/PermissionButton'; | ||||
| import { useDependentFeaturesApi } from 'hooks/api/actions/useDependentFeaturesApi/useDependentFeaturesApi'; | ||||
| 
 | ||||
| const StyledForm = styled('form')({}); | ||||
| 
 | ||||
| const StyledInputDescription = styled('p')(({ theme }) => ({ | ||||
|     marginBottom: theme.spacing(1), | ||||
| })); | ||||
| 
 | ||||
| const StyledInput = styled(Input)(({ theme }) => ({ | ||||
|     marginBottom: theme.spacing(2), | ||||
| })); | ||||
| 
 | ||||
| interface IAddDependencyProps { | ||||
|     projectId: string; | ||||
|     featureId: string; | ||||
| } | ||||
| export const AddDependency: FC<IAddDependencyProps> = ({ | ||||
|     projectId, | ||||
|     featureId, | ||||
| }) => { | ||||
|     const [parent, setParent] = useState(''); | ||||
|     const { addDependency } = useDependentFeaturesApi(); | ||||
| 
 | ||||
|     return ( | ||||
|         <StyledForm | ||||
|             onSubmit={() => { | ||||
|                 addDependency(featureId, { feature: parent }); | ||||
|             }} | ||||
|         > | ||||
|             <StyledInputDescription> | ||||
|                 What feature do you want to depend on? | ||||
|             </StyledInputDescription> | ||||
|             <Box sx={{ display: 'flex', gap: 1 }}> | ||||
|                 <StyledInput | ||||
|                     autoFocus | ||||
|                     label="Dependency" | ||||
|                     id="dependency-feature" | ||||
|                     value={parent} | ||||
|                     onChange={e => setParent(trim(e.target.value))} | ||||
|                 /> | ||||
|                 <PermissionButton | ||||
|                     permission={CREATE_FEATURE} | ||||
|                     projectId={projectId} | ||||
|                     onClick={() => { | ||||
|                         addDependency(featureId, { feature: parent }); | ||||
|                     }} | ||||
|                     variant={'outlined'} | ||||
|                 > | ||||
|                     Add{' '} | ||||
|                 </PermissionButton> | ||||
|             </Box> | ||||
|         </StyledForm> | ||||
|     ); | ||||
| }; | ||||
| @ -12,6 +12,9 @@ import { usePageTitle } from 'hooks/usePageTitle'; | ||||
| import { FeatureOverviewSidePanel } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanel'; | ||||
| import { useHiddenEnvironments } from 'hooks/useHiddenEnvironments'; | ||||
| import { styled } from '@mui/material'; | ||||
| import { AddDependency } from '../../Dependencies/AddDependency'; | ||||
| import { useUiFlag } from 'hooks/useUiFlag'; | ||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||
| 
 | ||||
| const StyledContainer = styled('div')(({ theme }) => ({ | ||||
|     display: 'flex', | ||||
| @ -39,6 +42,7 @@ const FeatureOverview = () => { | ||||
|         useHiddenEnvironments(); | ||||
|     const onSidebarClose = () => navigate(featurePath); | ||||
|     usePageTitle(featureId); | ||||
|     const dependentFeatures = useUiFlag('dependentFeatures'); | ||||
| 
 | ||||
|     return ( | ||||
|         <StyledContainer> | ||||
| @ -50,6 +54,16 @@ const FeatureOverview = () => { | ||||
|                 /> | ||||
|             </div> | ||||
|             <StyledMainContent> | ||||
|                 <ConditionallyRender | ||||
|                     condition={dependentFeatures} | ||||
|                     show={ | ||||
|                         <AddDependency | ||||
|                             projectId={projectId} | ||||
|                             featureId={featureId} | ||||
|                         /> | ||||
|                     } | ||||
|                 /> | ||||
| 
 | ||||
|                 <FeatureOverviewEnvironments /> | ||||
|             </StyledMainContent> | ||||
|             <Routes> | ||||
|  | ||||
| @ -0,0 +1,35 @@ | ||||
| import useAPI from '../useApi/useApi'; | ||||
| 
 | ||||
| // TODO: generate from orval
 | ||||
| interface IParentFeaturePayload { | ||||
|     feature: string; | ||||
| } | ||||
| export const useDependentFeaturesApi = () => { | ||||
|     const { makeRequest, createRequest, errors, loading } = useAPI({ | ||||
|         propagateErrors: true, | ||||
|     }); | ||||
| 
 | ||||
|     const addDependency = async ( | ||||
|         childFeature: string, | ||||
|         parentFeaturePayload: IParentFeaturePayload | ||||
|     ) => { | ||||
|         const req = createRequest( | ||||
|             `/api/admin/projects/default/features/${childFeature}/dependencies`, | ||||
|             { | ||||
|                 method: 'POST', | ||||
|                 body: JSON.stringify(parentFeaturePayload), | ||||
|             } | ||||
|         ); | ||||
|         try { | ||||
|             await makeRequest(req.caller, req.id); | ||||
|         } catch (e) { | ||||
|             throw e; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     return { | ||||
|         addDependency, | ||||
|         errors, | ||||
|         loading, | ||||
|     }; | ||||
| }; | ||||
| @ -65,6 +65,7 @@ export type UiFlags = { | ||||
|     variantTypeNumber?: boolean; | ||||
|     privateProjects?: boolean; | ||||
|     accessOverview?: boolean; | ||||
|     dependentFeatures?: boolean; | ||||
|     [key: string]: boolean | Variant | undefined; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -32,13 +32,13 @@ afterAll(async () => { | ||||
| }); | ||||
| 
 | ||||
| const addFeatureDependency = async ( | ||||
|     parentFeature: string, | ||||
|     childFeature: string, | ||||
|     payload: CreateDependentFeatureSchema, | ||||
|     expectedCode = 200, | ||||
| ) => { | ||||
|     return app.request | ||||
|         .post( | ||||
|             `/api/admin/projects/default/features/${parentFeature}/dependencies`, | ||||
|             `/api/admin/projects/default/features/${childFeature}/dependencies`, | ||||
|         ) | ||||
|         .send(payload) | ||||
|         .expect(expectedCode); | ||||
| @ -51,13 +51,13 @@ test('should add feature dependency', async () => { | ||||
|     await app.createFeature(child); | ||||
| 
 | ||||
|     // save explicit enabled and variants
 | ||||
|     await addFeatureDependency(parent, { | ||||
|         feature: child, | ||||
|     await addFeatureDependency(child, { | ||||
|         feature: parent, | ||||
|         enabled: false, | ||||
|     }); | ||||
|     // overwrite with implicit enabled: true and variants
 | ||||
|     await addFeatureDependency(parent, { | ||||
|         feature: child, | ||||
|     await addFeatureDependency(child, { | ||||
|         feature: parent, | ||||
|         variants: ['variantB'], | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| @ -44,6 +44,7 @@ process.nextTick(async () => { | ||||
|                         privateProjects: true, | ||||
|                         accessOverview: true, | ||||
|                         datadogJsonTemplate: true, | ||||
|                         dependentFeatures: true, | ||||
|                     }, | ||||
|                 }, | ||||
|                 authentication: { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user