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 { FeatureOverviewSidePanel } from 'component/feature/FeatureView/FeatureOverview/FeatureOverviewSidePanel/FeatureOverviewSidePanel'; | ||||||
| import { useHiddenEnvironments } from 'hooks/useHiddenEnvironments'; | import { useHiddenEnvironments } from 'hooks/useHiddenEnvironments'; | ||||||
| import { styled } from '@mui/material'; | 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 }) => ({ | const StyledContainer = styled('div')(({ theme }) => ({ | ||||||
|     display: 'flex', |     display: 'flex', | ||||||
| @ -39,6 +42,7 @@ const FeatureOverview = () => { | |||||||
|         useHiddenEnvironments(); |         useHiddenEnvironments(); | ||||||
|     const onSidebarClose = () => navigate(featurePath); |     const onSidebarClose = () => navigate(featurePath); | ||||||
|     usePageTitle(featureId); |     usePageTitle(featureId); | ||||||
|  |     const dependentFeatures = useUiFlag('dependentFeatures'); | ||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
|         <StyledContainer> |         <StyledContainer> | ||||||
| @ -50,6 +54,16 @@ const FeatureOverview = () => { | |||||||
|                 /> |                 /> | ||||||
|             </div> |             </div> | ||||||
|             <StyledMainContent> |             <StyledMainContent> | ||||||
|  |                 <ConditionallyRender | ||||||
|  |                     condition={dependentFeatures} | ||||||
|  |                     show={ | ||||||
|  |                         <AddDependency | ||||||
|  |                             projectId={projectId} | ||||||
|  |                             featureId={featureId} | ||||||
|  |                         /> | ||||||
|  |                     } | ||||||
|  |                 /> | ||||||
|  | 
 | ||||||
|                 <FeatureOverviewEnvironments /> |                 <FeatureOverviewEnvironments /> | ||||||
|             </StyledMainContent> |             </StyledMainContent> | ||||||
|             <Routes> |             <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; |     variantTypeNumber?: boolean; | ||||||
|     privateProjects?: boolean; |     privateProjects?: boolean; | ||||||
|     accessOverview?: boolean; |     accessOverview?: boolean; | ||||||
|  |     dependentFeatures?: boolean; | ||||||
|     [key: string]: boolean | Variant | undefined; |     [key: string]: boolean | Variant | undefined; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -32,13 +32,13 @@ afterAll(async () => { | |||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const addFeatureDependency = async ( | const addFeatureDependency = async ( | ||||||
|     parentFeature: string, |     childFeature: string, | ||||||
|     payload: CreateDependentFeatureSchema, |     payload: CreateDependentFeatureSchema, | ||||||
|     expectedCode = 200, |     expectedCode = 200, | ||||||
| ) => { | ) => { | ||||||
|     return app.request |     return app.request | ||||||
|         .post( |         .post( | ||||||
|             `/api/admin/projects/default/features/${parentFeature}/dependencies`, |             `/api/admin/projects/default/features/${childFeature}/dependencies`, | ||||||
|         ) |         ) | ||||||
|         .send(payload) |         .send(payload) | ||||||
|         .expect(expectedCode); |         .expect(expectedCode); | ||||||
| @ -51,13 +51,13 @@ test('should add feature dependency', async () => { | |||||||
|     await app.createFeature(child); |     await app.createFeature(child); | ||||||
| 
 | 
 | ||||||
|     // save explicit enabled and variants
 |     // save explicit enabled and variants
 | ||||||
|     await addFeatureDependency(parent, { |     await addFeatureDependency(child, { | ||||||
|         feature: child, |         feature: parent, | ||||||
|         enabled: false, |         enabled: false, | ||||||
|     }); |     }); | ||||||
|     // overwrite with implicit enabled: true and variants
 |     // overwrite with implicit enabled: true and variants
 | ||||||
|     await addFeatureDependency(parent, { |     await addFeatureDependency(child, { | ||||||
|         feature: child, |         feature: parent, | ||||||
|         variants: ['variantB'], |         variants: ['variantB'], | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -44,6 +44,7 @@ process.nextTick(async () => { | |||||||
|                         privateProjects: true, |                         privateProjects: true, | ||||||
|                         accessOverview: true, |                         accessOverview: true, | ||||||
|                         datadogJsonTemplate: true, |                         datadogJsonTemplate: true, | ||||||
|  |                         dependentFeatures: true, | ||||||
|                     }, |                     }, | ||||||
|                 }, |                 }, | ||||||
|                 authentication: { |                 authentication: { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user