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