1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

feat: UI stub for adding dependent features (#4814)

This commit is contained in:
Mateusz Kwasniewski 2023-09-22 11:26:45 +02:00 committed by GitHub
parent d28e7e5a69
commit b4742df8be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 6 deletions

View File

@ -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>
);
};

View File

@ -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>

View File

@ -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,
};
};

View File

@ -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;
}; };

View File

@ -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'],
}); });
}); });

View File

@ -44,6 +44,7 @@ process.nextTick(async () => {
privateProjects: true, privateProjects: true,
accessOverview: true, accessOverview: true,
datadogJsonTemplate: true, datadogJsonTemplate: true,
dependentFeatures: true,
}, },
}, },
authentication: { authentication: {