mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: add limit warning for feature flags (#7556)
This PR adds the Limit component to the feature flag creation form. At the limit: ![image](https://github.com/Unleash/unleash/assets/17786332/86f17565-5c75-4265-8e3b-5200222345ec) Approaching the limit: ![image](https://github.com/Unleash/unleash/assets/17786332/af041d78-fcd3-4aa6-b415-9738cbfbae1b) Below the limit threshold (no change): ![image](https://github.com/Unleash/unleash/assets/17786332/79ddc3ee-6e52-44d3-8d0b-0ebae90707a7)
This commit is contained in:
parent
5ed4ccc981
commit
8f8ff13cc5
@ -28,50 +28,66 @@ const setupApi = ({
|
||||
});
|
||||
};
|
||||
|
||||
test("should allow you to create feature flags when you're below the global limit", async () => {
|
||||
setupApi({ flagLimit: 3, flagCount: 2 });
|
||||
describe('button states', () => {
|
||||
test("should allow you to create feature flags when you're below the global limit", async () => {
|
||||
setupApi({ flagLimit: 3, flagCount: 2 });
|
||||
|
||||
render(
|
||||
<Routes>
|
||||
<Route
|
||||
path='/projects/:projectId/create-toggle'
|
||||
element={<CreateFeature />}
|
||||
/>
|
||||
</Routes>,
|
||||
{
|
||||
route: '/projects/default/create-toggle',
|
||||
permissions: [{ permission: CREATE_FEATURE }],
|
||||
},
|
||||
);
|
||||
render(
|
||||
<Routes>
|
||||
<Route
|
||||
path='/projects/:projectId/create-toggle'
|
||||
element={<CreateFeature />}
|
||||
/>
|
||||
</Routes>,
|
||||
{
|
||||
route: '/projects/default/create-toggle',
|
||||
permissions: [{ permission: CREATE_FEATURE }],
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(async () => {
|
||||
const button = await screen.findByRole('button', {
|
||||
name: /create feature flag/i,
|
||||
});
|
||||
expect(button).not.toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
test("should not allow you to create API tokens when you're at the global limit", async () => {
|
||||
setupApi({ flagLimit: 3, flagCount: 3 });
|
||||
|
||||
render(
|
||||
<Routes>
|
||||
<Route
|
||||
path='/projects/:projectId/create-toggle'
|
||||
element={<CreateFeature />}
|
||||
/>
|
||||
</Routes>,
|
||||
{
|
||||
route: '/projects/default/create-toggle',
|
||||
permissions: [{ permission: CREATE_FEATURE }],
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(async () => {
|
||||
const button = await screen.findByRole('button', {
|
||||
name: /create feature flag/i,
|
||||
await waitFor(() => {
|
||||
expect(button).not.toBeDisabled();
|
||||
});
|
||||
expect(button).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('limit component', () => {
|
||||
test('should show limit reached info', async () => {
|
||||
setupApi({ flagLimit: 1, flagCount: 1 });
|
||||
render(
|
||||
<Routes>
|
||||
<Route
|
||||
path='/projects/:projectId/create-toggle'
|
||||
element={<CreateFeature />}
|
||||
/>
|
||||
</Routes>,
|
||||
{
|
||||
route: '/projects/default/create-toggle',
|
||||
permissions: [{ permission: CREATE_FEATURE }],
|
||||
},
|
||||
);
|
||||
|
||||
await screen.findByText('You have reached the limit for feature flags');
|
||||
});
|
||||
|
||||
test('should show approaching limit info', async () => {
|
||||
setupApi({ flagLimit: 10, flagCount: 9 });
|
||||
render(
|
||||
<Routes>
|
||||
<Route
|
||||
path='/projects/:projectId/create-toggle'
|
||||
element={<CreateFeature />}
|
||||
/>
|
||||
</Routes>,
|
||||
{
|
||||
route: '/projects/default/create-toggle',
|
||||
permissions: [{ permission: CREATE_FEATURE }],
|
||||
},
|
||||
);
|
||||
|
||||
await screen.findByText('You are nearing the limit for feature flags');
|
||||
});
|
||||
});
|
||||
|
@ -19,6 +19,7 @@ import useProjectOverview, {
|
||||
} from 'hooks/api/getters/useProjectOverview/useProjectOverview';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import { useGlobalFeatureSearch } from '../FeatureToggleList/useGlobalFeatureSearch';
|
||||
import { Limit } from 'component/common/Limit/Limit';
|
||||
|
||||
const StyledAlert = styled(Alert)(({ theme }) => ({
|
||||
marginBottom: theme.spacing(2),
|
||||
@ -106,6 +107,8 @@ const CreateFeature = () => {
|
||||
const { total: totalFlags, loading: loadingTotalFlagCount } =
|
||||
useGlobalFeatureSearch();
|
||||
|
||||
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||
|
||||
const { globalFlagLimitReached, projectFlagLimitReached, limitMessage } =
|
||||
useFlagLimits({
|
||||
global: {
|
||||
@ -196,6 +199,18 @@ const CreateFeature = () => {
|
||||
mode='Create'
|
||||
clearErrors={clearErrors}
|
||||
featureNaming={projectInfo.featureNaming}
|
||||
Limit={
|
||||
<ConditionallyRender
|
||||
condition={resourceLimitsEnabled}
|
||||
show={
|
||||
<Limit
|
||||
name='feature flags'
|
||||
limit={uiConfig.resourceLimits.featureFlags}
|
||||
currentValue={totalFlags ?? 0}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<CreateButton
|
||||
name='feature flag'
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
type Theme,
|
||||
Typography,
|
||||
Link,
|
||||
Box,
|
||||
} from '@mui/material';
|
||||
import FeatureTypeSelect from '../FeatureView/FeatureSettings/FeatureSettingsMetadata/FeatureTypeSelect/FeatureTypeSelect';
|
||||
import { CF_DESC_ID, CF_NAME_ID, CF_TYPE_ID } from 'utils/testIds';
|
||||
@ -43,6 +44,7 @@ interface IFeatureToggleForm {
|
||||
mode: 'Create' | 'Edit';
|
||||
clearErrors: () => void;
|
||||
children?: React.ReactNode;
|
||||
Limit?: React.ReactNode;
|
||||
}
|
||||
|
||||
const StyledForm = styled('form')({
|
||||
@ -79,7 +81,6 @@ const StyledTypeDescription = styled('p')(({ theme }) => ({
|
||||
}));
|
||||
|
||||
const StyledButtonContainer = styled('div')({
|
||||
marginTop: 'auto',
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
});
|
||||
@ -98,6 +99,12 @@ const styledTypography = (theme: Theme) => ({
|
||||
margin: theme.spacing(1, 0),
|
||||
});
|
||||
|
||||
const LimitContainer = styled(Box)(({ theme }) => ({
|
||||
'&:has(*)': {
|
||||
marginBottom: theme.spacing(2),
|
||||
},
|
||||
}));
|
||||
|
||||
const FeatureForm: React.FC<IFeatureToggleForm> = ({
|
||||
children,
|
||||
type,
|
||||
@ -117,6 +124,7 @@ const FeatureForm: React.FC<IFeatureToggleForm> = ({
|
||||
errors,
|
||||
mode,
|
||||
clearErrors,
|
||||
Limit,
|
||||
}) => {
|
||||
const { featureTypes } = useFeatureTypes();
|
||||
const navigate = useNavigate();
|
||||
@ -256,6 +264,7 @@ const FeatureForm: React.FC<IFeatureToggleForm> = ({
|
||||
/>
|
||||
</StyledRow>
|
||||
</StyledFormControl>
|
||||
<LimitContainer>{Limit}</LimitContainer>
|
||||
<StyledButtonContainer>
|
||||
{children}
|
||||
<StyledCancelButton onClick={handleCancel}>
|
||||
|
Loading…
Reference in New Issue
Block a user