mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
[Gitar] Cleaning up stale flag: resourceLimits with value true (#7964)
[![Gitar](https://raw.githubusercontent.com/gitarcode/.github/main/assets/gitar-banner.svg)](https://gitar.co) --- This automated PR was generated by [Gitar](https://gitar.co). View [docs](https://gitar.co/docs). --------- Co-authored-by: Gitar <noreply@gitar.co> Co-authored-by: Thomas Heartman <thomas@getunleash.io>
This commit is contained in:
parent
b0541a0af2
commit
4615ff40ce
@ -18,9 +18,6 @@ const server = testServerSetup();
|
||||
|
||||
const setupApi = (existingTokensCount: number) => {
|
||||
testServerRoute(server, '/api/admin/ui-config', {
|
||||
flags: {
|
||||
resourceLimits: true,
|
||||
},
|
||||
resourceLimits: {
|
||||
apiTokens: 1,
|
||||
},
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { styled } from '@mui/material';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
|
||||
import ApiTokenForm from '../ApiTokenForm/ApiTokenForm';
|
||||
import { CreateButton } from 'component/common/CreateButton/CreateButton';
|
||||
@ -37,16 +35,14 @@ const StyledLimit = styled(Limit)(({ theme }) => ({
|
||||
}));
|
||||
|
||||
const useApiTokenLimit = () => {
|
||||
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||
const { tokens, loading: loadingTokens } = useApiTokens();
|
||||
const { uiConfig, loading: loadingConfig } = useUiConfig();
|
||||
const apiTokensLimit = uiConfig.resourceLimits.apiTokens;
|
||||
|
||||
return {
|
||||
resourceLimitsEnabled,
|
||||
limit: apiTokensLimit,
|
||||
currentValue: tokens.length,
|
||||
limitReached: resourceLimitsEnabled && tokens.length >= apiTokensLimit,
|
||||
limitReached: tokens.length >= apiTokensLimit,
|
||||
loading: loadingConfig || loadingTokens,
|
||||
};
|
||||
};
|
||||
@ -58,7 +54,6 @@ export const CreateApiToken = ({ modal = false }: ICreateApiTokenProps) => {
|
||||
const [showConfirm, setShowConfirm] = useState(false);
|
||||
const [token, setToken] = useState('');
|
||||
const {
|
||||
resourceLimitsEnabled,
|
||||
limit,
|
||||
currentValue,
|
||||
limitReached,
|
||||
@ -176,16 +171,11 @@ export const CreateApiToken = ({ modal = false }: ICreateApiTokenProps) => {
|
||||
environment={environment}
|
||||
setEnvironment={setEnvironment}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={resourceLimitsEnabled}
|
||||
show={
|
||||
<StyledLimit
|
||||
name='API tokens'
|
||||
shortName='tokens'
|
||||
currentValue={currentValue}
|
||||
limit={limit}
|
||||
/>
|
||||
}
|
||||
<StyledLimit
|
||||
name='API tokens'
|
||||
shortName='tokens'
|
||||
currentValue={currentValue}
|
||||
limit={limit}
|
||||
/>
|
||||
</ApiTokenForm>
|
||||
<ConfirmToken
|
||||
|
@ -11,12 +11,7 @@ const setupApi = ({
|
||||
apiTokenLimit,
|
||||
}: { apiTokenCount: number; apiTokenLimit: number }) => {
|
||||
testServerRoute(server, '/api/admin/ui-config', {
|
||||
flags: {
|
||||
resourceLimits: true,
|
||||
},
|
||||
resourceLimits: {
|
||||
apiTokens: apiTokenLimit,
|
||||
},
|
||||
resourceLimits: { apiTokens: apiTokenLimit },
|
||||
});
|
||||
|
||||
testServerRoute(server, '/api/admin/api-tokens', {
|
||||
|
@ -3,7 +3,6 @@ import { CREATE_API_TOKEN_BUTTON } from 'utils/testIds';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import Add from '@mui/icons-material/Add';
|
||||
import { useApiTokens } from 'hooks/api/getters/useApiTokens/useApiTokens';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
interface ICreateApiTokenButton {
|
||||
path: string;
|
||||
@ -12,9 +11,7 @@ interface ICreateApiTokenButton {
|
||||
}
|
||||
|
||||
const useApiTokenLimit = (apiTokenLimit: number, apiTokenCount: number) => {
|
||||
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||
const limitReached =
|
||||
resourceLimitsEnabled && apiTokenCount >= apiTokenLimit;
|
||||
const limitReached = apiTokenCount >= apiTokenLimit;
|
||||
|
||||
return {
|
||||
limitReached,
|
||||
|
@ -6,15 +6,9 @@ import { FreeTextInput } from './FreeTextInput';
|
||||
const server = testServerSetup();
|
||||
|
||||
const LIMIT = 3;
|
||||
|
||||
const setupApi = () => {
|
||||
testServerRoute(server, '/api/admin/ui-config', {
|
||||
flags: {
|
||||
resourceLimits: true,
|
||||
},
|
||||
resourceLimits: {
|
||||
constraintValues: LIMIT,
|
||||
},
|
||||
resourceLimits: { constraintValues: LIMIT },
|
||||
});
|
||||
};
|
||||
|
||||
@ -126,8 +120,8 @@ test('should show limit reached indicator', async () => {
|
||||
<FreeTextInput
|
||||
error=''
|
||||
values={['1', '2', '3']}
|
||||
setValues={(newValues) => {}}
|
||||
setError={(newError: string) => {}}
|
||||
setValues={() => {}}
|
||||
setError={() => {}}
|
||||
removeValue={() => {}}
|
||||
/>,
|
||||
);
|
||||
|
@ -6,9 +6,7 @@ import type React from 'react';
|
||||
import { useState } from 'react';
|
||||
import { ConstraintFormHeader } from '../ConstraintFormHeader/ConstraintFormHeader';
|
||||
import { parseParameterStrings } from 'utils/parseParameter';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { Limit } from 'component/common/Limit/Limit';
|
||||
|
||||
interface IFreeTextInputProps {
|
||||
@ -72,7 +70,6 @@ export const FreeTextInput = ({
|
||||
}: IFreeTextInputProps) => {
|
||||
const [inputValues, setInputValues] = useState('');
|
||||
const { classes: styles } = useStyles();
|
||||
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||
const { uiConfig, loading } = useUiConfig();
|
||||
const constraintValuesLimit = uiConfig.resourceLimits.constraintValues;
|
||||
|
||||
@ -88,9 +85,7 @@ export const FreeTextInput = ({
|
||||
...values,
|
||||
...parseParameterStrings(inputValues),
|
||||
]);
|
||||
const limitReached = Boolean(
|
||||
resourceLimitsEnabled && newValues.length > constraintValuesLimit,
|
||||
);
|
||||
const limitReached = Boolean(newValues.length > constraintValuesLimit);
|
||||
|
||||
if (limitReached) {
|
||||
setError(
|
||||
@ -148,16 +143,11 @@ export const FreeTextInput = ({
|
||||
/>
|
||||
</div>
|
||||
<LimitContainer>
|
||||
<ConditionallyRender
|
||||
condition={resourceLimitsEnabled}
|
||||
show={
|
||||
<Limit
|
||||
name='single constraint values'
|
||||
shortName='values'
|
||||
currentValue={values.length}
|
||||
limit={constraintValuesLimit}
|
||||
/>
|
||||
}
|
||||
<Limit
|
||||
name='single constraint values'
|
||||
shortName='values'
|
||||
currentValue={values.length}
|
||||
limit={constraintValuesLimit}
|
||||
/>
|
||||
</LimitContainer>
|
||||
</>
|
||||
|
@ -7,14 +7,10 @@ import { ADMIN } from '../../providers/AccessProvider/permissions';
|
||||
const server = testServerSetup();
|
||||
|
||||
const setupApi = ({
|
||||
resourceLimits,
|
||||
limit,
|
||||
environments,
|
||||
}: { resourceLimits: boolean; limit: number; environments: number }) => {
|
||||
}: { limit: number; environments: number }) => {
|
||||
testServerRoute(server, '/api/admin/ui-config', {
|
||||
flags: {
|
||||
resourceLimits,
|
||||
},
|
||||
resourceLimits: {
|
||||
environments: limit,
|
||||
},
|
||||
@ -28,7 +24,7 @@ const setupApi = ({
|
||||
};
|
||||
|
||||
test('show limit reached info', async () => {
|
||||
setupApi({ environments: 1, limit: 1, resourceLimits: true });
|
||||
setupApi({ environments: 1, limit: 1 });
|
||||
render(<CreateEnvironment />, { permissions: [{ permission: ADMIN }] });
|
||||
|
||||
await screen.findByText('You have reached the limit for environments');
|
||||
@ -39,7 +35,7 @@ test('show limit reached info', async () => {
|
||||
});
|
||||
|
||||
test('show approaching limit info', async () => {
|
||||
setupApi({ environments: 9, limit: 10, resourceLimits: true });
|
||||
setupApi({ environments: 9, limit: 10 });
|
||||
render(<CreateEnvironment />, { permissions: [{ permission: ADMIN }] });
|
||||
|
||||
await screen.findByText('You are nearing the limit for environments');
|
||||
@ -48,10 +44,3 @@ test('show approaching limit info', async () => {
|
||||
});
|
||||
expect(createButton).toBeEnabled();
|
||||
});
|
||||
|
||||
test('show limit reached info - no resource limits component', async () => {
|
||||
setupApi({ environments: 1, limit: 1, resourceLimits: false });
|
||||
render(<CreateEnvironment />);
|
||||
|
||||
await screen.findByText('Go back');
|
||||
});
|
||||
|
@ -2,27 +2,20 @@ import { useNavigate } from 'react-router-dom';
|
||||
import useEnvironmentForm from '../hooks/useEnvironmentForm';
|
||||
import EnvironmentForm from '../EnvironmentForm/EnvironmentForm';
|
||||
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
|
||||
import { Alert } from '@mui/material';
|
||||
import { Button } from '@mui/material';
|
||||
import { CreateButton } from 'component/common/CreateButton/CreateButton';
|
||||
import useEnvironmentApi from 'hooks/api/actions/useEnvironmentApi/useEnvironmentApi';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import useToast from 'hooks/useToast';
|
||||
import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
|
||||
import usePermissions from 'hooks/api/getters/usePermissions/usePermissions';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
import { GO_BACK } from 'constants/navigate';
|
||||
import { Limit } from 'component/common/Limit/Limit';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
|
||||
const CreateEnvironment = () => {
|
||||
const { setToastApiError, setToastData } = useToast();
|
||||
const { uiConfig } = useUiConfig();
|
||||
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||
const environmentLimit = uiConfig.resourceLimits.environments;
|
||||
const navigate = useNavigate();
|
||||
const { environments } = useEnvironments();
|
||||
@ -73,13 +66,10 @@ const CreateEnvironment = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<ConditionallyRender
|
||||
condition={resourceLimitsEnabled || canCreateMoreEnvs}
|
||||
show={
|
||||
<FormTemplate
|
||||
loading={loading}
|
||||
title='Create environment'
|
||||
description='Environments allow you to manage your
|
||||
<FormTemplate
|
||||
loading={loading}
|
||||
title='Create environment'
|
||||
description='Environments allow you to manage your
|
||||
product lifecycle from local development
|
||||
through production. Your projects and
|
||||
feature flags are accessible in all your
|
||||
@ -89,66 +79,36 @@ const CreateEnvironment = () => {
|
||||
development or test environment without
|
||||
enabling the feature flag in the
|
||||
production environment.'
|
||||
documentationLink='https://docs.getunleash.io/reference/environments'
|
||||
documentationLinkLabel='Environments documentation'
|
||||
formatApiCode={formatApiCode}
|
||||
>
|
||||
<EnvironmentForm
|
||||
errors={errors}
|
||||
handleSubmit={handleSubmit}
|
||||
handleCancel={handleCancel}
|
||||
validateEnvironmentName={validateEnvironmentName}
|
||||
name={name}
|
||||
type={type}
|
||||
setName={setName}
|
||||
setType={setType}
|
||||
mode='Create'
|
||||
clearErrors={clearErrors}
|
||||
Limit={
|
||||
<ConditionallyRender
|
||||
condition={resourceLimitsEnabled}
|
||||
show={
|
||||
<Limit
|
||||
name='environments'
|
||||
limit={environmentLimit}
|
||||
currentValue={environments.length}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<CreateButton
|
||||
name='environment'
|
||||
permission={ADMIN}
|
||||
disabled={!canCreateMoreEnvs}
|
||||
/>
|
||||
</EnvironmentForm>
|
||||
</FormTemplate>
|
||||
}
|
||||
elseShow={
|
||||
<>
|
||||
<PageContent
|
||||
header={<PageHeader title='Create environment' />}
|
||||
>
|
||||
<Alert severity='error'>
|
||||
<p>
|
||||
Currently Unleash does not support more than{' '}
|
||||
{environmentLimit} environments. If you need
|
||||
more please reach out.
|
||||
</p>
|
||||
</Alert>
|
||||
<br />
|
||||
<Button
|
||||
onClick={handleCancel}
|
||||
variant='contained'
|
||||
color='primary'
|
||||
>
|
||||
Go back
|
||||
</Button>
|
||||
</PageContent>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
documentationLink='https://docs.getunleash.io/reference/environments'
|
||||
documentationLinkLabel='Environments documentation'
|
||||
formatApiCode={formatApiCode}
|
||||
>
|
||||
<EnvironmentForm
|
||||
errors={errors}
|
||||
handleSubmit={handleSubmit}
|
||||
handleCancel={handleCancel}
|
||||
validateEnvironmentName={validateEnvironmentName}
|
||||
name={name}
|
||||
type={type}
|
||||
setName={setName}
|
||||
setType={setType}
|
||||
mode='Create'
|
||||
clearErrors={clearErrors}
|
||||
Limit={
|
||||
<Limit
|
||||
name='environments'
|
||||
limit={environmentLimit}
|
||||
currentValue={environments.length}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<CreateButton
|
||||
name='environment'
|
||||
permission={ADMIN}
|
||||
disabled={!canCreateMoreEnvs}
|
||||
/>
|
||||
</EnvironmentForm>
|
||||
</FormTemplate>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -10,9 +10,6 @@ const LIMIT = 5;
|
||||
|
||||
const setupApi = () => {
|
||||
testServerRoute(server, '/api/admin/ui-config', {
|
||||
flags: {
|
||||
resourceLimits: true,
|
||||
},
|
||||
resourceLimits: {
|
||||
constraints: LIMIT,
|
||||
},
|
||||
|
@ -1,8 +1,7 @@
|
||||
import type React from 'react';
|
||||
import { forwardRef, type RefObject } from 'react';
|
||||
import { Box, Button, styled, Tooltip, Typography } from '@mui/material';
|
||||
import { Box, Button, styled, Typography } from '@mui/material';
|
||||
import Add from '@mui/icons-material/Add';
|
||||
import HelpOutline from '@mui/icons-material/HelpOutline';
|
||||
import type { IConstraint } from 'interfaces/strategy';
|
||||
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
@ -13,7 +12,6 @@ import {
|
||||
} from 'component/common/ConstraintAccordion/ConstraintAccordionList/ConstraintAccordionList';
|
||||
import { NewConstraintAccordionList } from 'component/common/NewConstraintAccordion/NewConstraintAccordionList/NewConstraintAccordionList';
|
||||
import { Limit } from 'component/common/Limit/Limit';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
|
||||
interface IConstraintAccordionListProps {
|
||||
@ -32,30 +30,6 @@ const StyledContainer = styled('div')({
|
||||
flexDirection: 'column',
|
||||
});
|
||||
|
||||
const StyledHelpWrapper = styled(Tooltip)(({ theme }) => ({
|
||||
marginLeft: theme.spacing(0.75),
|
||||
height: theme.spacing(1.5),
|
||||
}));
|
||||
|
||||
const StyledHelp = styled(HelpOutline)(({ theme }) => ({
|
||||
fill: theme.palette.action.active,
|
||||
[theme.breakpoints.down(860)]: {
|
||||
display: 'none',
|
||||
},
|
||||
}));
|
||||
|
||||
const StyledConstraintLabel = styled('p')(({ theme }) => ({
|
||||
marginBottom: theme.spacing(1),
|
||||
color: theme.palette.text.secondary,
|
||||
}));
|
||||
|
||||
const StyledAddCustomLabel = styled('div')(({ theme }) => ({
|
||||
marginTop: theme.spacing(1),
|
||||
marginBottom: theme.spacing(1),
|
||||
color: theme.palette.text.primary,
|
||||
display: 'flex',
|
||||
}));
|
||||
|
||||
const StyledHelpIconBox = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
@ -64,14 +38,11 @@ const StyledHelpIconBox = styled(Box)(({ theme }) => ({
|
||||
}));
|
||||
|
||||
const useConstraintLimit = (constraintsCount: number) => {
|
||||
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||
const { uiConfig } = useUiConfig();
|
||||
const constraintsLimit = uiConfig.resourceLimits?.constraints || 30;
|
||||
const limitReached =
|
||||
resourceLimitsEnabled && constraintsCount >= constraintsLimit;
|
||||
const limitReached = constraintsCount >= constraintsLimit;
|
||||
|
||||
return {
|
||||
resourceLimitsEnabled,
|
||||
limit: constraintsLimit,
|
||||
limitReached,
|
||||
};
|
||||
@ -80,93 +51,81 @@ const useConstraintLimit = (constraintsCount: number) => {
|
||||
export const FeatureStrategyConstraintAccordionList = forwardRef<
|
||||
IConstraintAccordionListRef | undefined,
|
||||
IConstraintAccordionListProps
|
||||
>(
|
||||
(
|
||||
{ constraints, setConstraints, showCreateButton, showLabel = true },
|
||||
ref,
|
||||
) => {
|
||||
const { onAdd, state, context } = useConstraintAccordionList(
|
||||
setConstraints,
|
||||
ref as RefObject<IConstraintAccordionListRef>,
|
||||
);
|
||||
const { resourceLimitsEnabled, limit, limitReached } =
|
||||
useConstraintLimit(constraints.length);
|
||||
>(({ constraints, setConstraints, showCreateButton }, ref) => {
|
||||
const { onAdd, state, context } = useConstraintAccordionList(
|
||||
setConstraints,
|
||||
ref as RefObject<IConstraintAccordionListRef>,
|
||||
);
|
||||
const { limit, limitReached } = useConstraintLimit(constraints.length);
|
||||
|
||||
if (context.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (context.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledContainer id={constraintAccordionListId}>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(showCreateButton && onAdd)}
|
||||
show={
|
||||
<div>
|
||||
<StyledHelpIconBox>
|
||||
<Typography>Constraints</Typography>
|
||||
<HelpIcon
|
||||
htmlTooltip
|
||||
tooltip={
|
||||
<Box>
|
||||
<Typography variant='body2'>
|
||||
Constraints are advanced
|
||||
targeting rules that you can use
|
||||
to enable a feature flag for a
|
||||
subset of your users. Read more
|
||||
about constraints{' '}
|
||||
<a
|
||||
href='https://docs.getunleash.io/reference/strategy-constraints'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
here
|
||||
</a>
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
</StyledHelpIconBox>
|
||||
<NewConstraintAccordionList
|
||||
ref={ref}
|
||||
setConstraints={setConstraints}
|
||||
constraints={constraints}
|
||||
state={state}
|
||||
return (
|
||||
<StyledContainer id={constraintAccordionListId}>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(showCreateButton && onAdd)}
|
||||
show={
|
||||
<div>
|
||||
<StyledHelpIconBox>
|
||||
<Typography>Constraints</Typography>
|
||||
<HelpIcon
|
||||
htmlTooltip
|
||||
tooltip={
|
||||
<Box>
|
||||
<Typography variant='body2'>
|
||||
Constraints are advanced targeting
|
||||
rules that you can use to enable a
|
||||
feature flag for a subset of your
|
||||
users. Read more about constraints{' '}
|
||||
<a
|
||||
href='https://docs.getunleash.io/reference/strategy-constraints'
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
here
|
||||
</a>
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
</StyledHelpIconBox>
|
||||
<NewConstraintAccordionList
|
||||
ref={ref}
|
||||
setConstraints={setConstraints}
|
||||
constraints={constraints}
|
||||
state={state}
|
||||
/>
|
||||
|
||||
<Box
|
||||
sx={(theme) => ({
|
||||
marginTop: theme.spacing(2),
|
||||
marginBottom: theme.spacing(2),
|
||||
})}
|
||||
>
|
||||
<ConditionallyRender
|
||||
condition={resourceLimitsEnabled}
|
||||
show={
|
||||
<Limit
|
||||
name='constraints in this strategy'
|
||||
shortName='constraints'
|
||||
currentValue={constraints.length}
|
||||
limit={limit}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
<Box
|
||||
sx={(theme) => ({
|
||||
marginTop: theme.spacing(2),
|
||||
marginBottom: theme.spacing(2),
|
||||
})}
|
||||
>
|
||||
<Limit
|
||||
name='constraints in this strategy'
|
||||
shortName='constraints'
|
||||
currentValue={constraints.length}
|
||||
limit={limit}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Button
|
||||
type='button'
|
||||
onClick={onAdd}
|
||||
startIcon={<Add />}
|
||||
variant='outlined'
|
||||
color='primary'
|
||||
data-testid='ADD_CONSTRAINT_BUTTON'
|
||||
disabled={Boolean(limitReached)}
|
||||
>
|
||||
Add constraint
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</StyledContainer>
|
||||
);
|
||||
},
|
||||
);
|
||||
<Button
|
||||
type='button'
|
||||
onClick={onAdd}
|
||||
startIcon={<Add />}
|
||||
variant='outlined'
|
||||
color='primary'
|
||||
data-testid='ADD_CONSTRAINT_BUTTON'
|
||||
disabled={Boolean(limitReached)}
|
||||
>
|
||||
Add constraint
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</StyledContainer>
|
||||
);
|
||||
});
|
||||
|
@ -36,21 +36,15 @@ import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
|
||||
import { useDefaultStrategy } from '../../../project/Project/ProjectSettings/ProjectDefaultStrategySettings/ProjectEnvironment/ProjectEnvironmentDefaultStrategy/EditDefaultStrategy';
|
||||
import { FeatureStrategyForm } from '../FeatureStrategyForm/FeatureStrategyForm';
|
||||
import { NewStrategyVariants } from 'component/feature/StrategyTypes/NewStrategyVariants';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import { Limit } from 'component/common/Limit/Limit';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
|
||||
const useStrategyLimit = (strategyCount: number) => {
|
||||
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||
const { uiConfig } = useUiConfig();
|
||||
const featureEnvironmentStrategiesLimit =
|
||||
uiConfig.resourceLimits?.featureEnvironmentStrategies || 100;
|
||||
const limitReached =
|
||||
resourceLimitsEnabled &&
|
||||
strategyCount >= featureEnvironmentStrategiesLimit;
|
||||
const limitReached = strategyCount >= featureEnvironmentStrategiesLimit;
|
||||
|
||||
return {
|
||||
resourceLimitsEnabled,
|
||||
limit: featureEnvironmentStrategiesLimit,
|
||||
limitReached,
|
||||
};
|
||||
@ -93,8 +87,7 @@ export const FeatureStrategyCreate = () => {
|
||||
(featureEnvironment) => featureEnvironment.name === environmentId,
|
||||
);
|
||||
const strategyCount = featureEnvironment?.strategies.length || 0;
|
||||
const { limit, limitReached, resourceLimitsEnabled } =
|
||||
useStrategyLimit(strategyCount);
|
||||
const { limit, limitReached } = useStrategyLimit(strategyCount);
|
||||
const ref = useRef<IFeatureToggle>(feature);
|
||||
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
|
||||
const { refetch: refetchChangeRequests } =
|
||||
@ -247,16 +240,11 @@ export const FeatureStrategyCreate = () => {
|
||||
/>
|
||||
}
|
||||
Limit={
|
||||
<ConditionallyRender
|
||||
condition={resourceLimitsEnabled}
|
||||
show={
|
||||
<Limit
|
||||
name='strategies in this environment'
|
||||
shortName='strategies'
|
||||
currentValue={strategyCount}
|
||||
limit={limit}
|
||||
/>
|
||||
}
|
||||
<Limit
|
||||
name='strategies in this environment'
|
||||
shortName='strategies'
|
||||
currentValue={strategyCount}
|
||||
limit={limit}
|
||||
/>
|
||||
}
|
||||
disabled={limitReached}
|
||||
|
@ -86,7 +86,6 @@ export const setupUiConfigEndpoint = () => {
|
||||
environment: 'enterprise',
|
||||
flags: {
|
||||
newStrategyConfiguration: true,
|
||||
resourceLimits: true,
|
||||
},
|
||||
resourceLimits: {
|
||||
featureEnvironmentStrategies: 2,
|
||||
|
@ -8,12 +8,7 @@ const server = testServerSetup();
|
||||
|
||||
const setupApi = (existingProjectsCount: number) => {
|
||||
testServerRoute(server, '/api/admin/ui-config', {
|
||||
flags: {
|
||||
resourceLimits: true,
|
||||
},
|
||||
resourceLimits: {
|
||||
projects: 1,
|
||||
},
|
||||
resourceLimits: { projects: 1 },
|
||||
versionInfo: {
|
||||
current: { enterprise: 'version' },
|
||||
},
|
||||
|
@ -16,7 +16,6 @@ import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Dialog, styled } from '@mui/material';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import useProjects from 'hooks/api/getters/useProjects/useProjects';
|
||||
import { Limit } from 'component/common/Limit/Limit';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
@ -96,15 +95,12 @@ const configButtonData = {
|
||||
};
|
||||
|
||||
const useProjectLimit = () => {
|
||||
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||
const { projects, loading: loadingProjects } = useProjects();
|
||||
const { uiConfig, loading: loadingConfig } = useUiConfig();
|
||||
const projectsLimit = uiConfig.resourceLimits?.projects;
|
||||
const limitReached =
|
||||
resourceLimitsEnabled && projects.length >= projectsLimit;
|
||||
const limitReached = projects.length >= projectsLimit;
|
||||
|
||||
return {
|
||||
resourceLimitsEnabled,
|
||||
limit: projectsLimit,
|
||||
currentValue: projects.length,
|
||||
limitReached,
|
||||
@ -201,7 +197,6 @@ export const CreateProjectDialog = ({
|
||||
};
|
||||
|
||||
const {
|
||||
resourceLimitsEnabled,
|
||||
limit,
|
||||
currentValue,
|
||||
limitReached,
|
||||
@ -251,15 +246,10 @@ export const CreateProjectDialog = ({
|
||||
creatingProject || limitReached || loadingLimit,
|
||||
}}
|
||||
Limit={
|
||||
<ConditionallyRender
|
||||
condition={resourceLimitsEnabled}
|
||||
show={
|
||||
<Limit
|
||||
name='projects'
|
||||
limit={limit}
|
||||
currentValue={currentValue}
|
||||
/>
|
||||
}
|
||||
<Limit
|
||||
name='projects'
|
||||
limit={limit}
|
||||
currentValue={currentValue}
|
||||
/>
|
||||
}
|
||||
handleSubmit={handleSubmit}
|
||||
|
@ -12,7 +12,6 @@ import {
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Dialog, styled } from '@mui/material';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import useProjects from 'hooks/api/getters/useProjects/useProjects';
|
||||
import { Limit } from 'component/common/Limit/Limit';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
@ -174,8 +173,6 @@ const CreateFeatureDialogContent = ({
|
||||
const { project: projectInfo } = useProjectOverview(project);
|
||||
const { tags: allTags } = useAllTags();
|
||||
|
||||
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||
|
||||
const { globalFlagLimitReached, projectFlagLimitReached, limitMessage } =
|
||||
useFlagLimits({
|
||||
global: {
|
||||
@ -233,15 +230,10 @@ const CreateFeatureDialogContent = ({
|
||||
Icon={<FlagIcon />}
|
||||
validateName={validateToggleName}
|
||||
Limit={
|
||||
<ConditionallyRender
|
||||
condition={resourceLimitsEnabled}
|
||||
show={
|
||||
<Limit
|
||||
name='feature flags'
|
||||
limit={uiConfig.resourceLimits.featureFlags}
|
||||
currentValue={totalFlags ?? 0}
|
||||
/>
|
||||
}
|
||||
<Limit
|
||||
name='feature flags'
|
||||
limit={uiConfig.resourceLimits.featureFlags}
|
||||
currentValue={totalFlags ?? 0}
|
||||
/>
|
||||
}
|
||||
name={name}
|
||||
|
@ -1,5 +1,3 @@
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
|
||||
type FlagLimitsProps = {
|
||||
global: { limit: number; count: number };
|
||||
project: { limit?: number; count: number };
|
||||
@ -30,8 +28,7 @@ export const useFlagLimits = ({ global, project }: FlagLimitsProps) => {
|
||||
};
|
||||
|
||||
const useGlobalFlagLimit = (flagLimit: number, flagCount: number) => {
|
||||
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||
const limitReached = resourceLimitsEnabled && flagCount >= flagLimit;
|
||||
const limitReached = flagCount >= flagLimit;
|
||||
|
||||
return {
|
||||
limitReached,
|
||||
|
@ -8,12 +8,7 @@ const server = testServerSetup();
|
||||
|
||||
const setupApi = () => {
|
||||
testServerRoute(server, '/api/admin/ui-config', {
|
||||
flags: {
|
||||
resourceLimits: true,
|
||||
},
|
||||
resourceLimits: {
|
||||
projects: 1,
|
||||
},
|
||||
resourceLimits: { projects: 1 },
|
||||
versionInfo: {
|
||||
current: { enterprise: 'version' },
|
||||
},
|
||||
|
@ -18,7 +18,6 @@ const setupRoutes = ({
|
||||
testServerRoute(server, '/api/admin/ui-config', {
|
||||
flags: {
|
||||
SE: true,
|
||||
resourceLimits: true,
|
||||
},
|
||||
resourceLimits: {
|
||||
segments: limit,
|
||||
|
@ -20,7 +20,6 @@ import {
|
||||
import { SegmentProjectAlert } from './SegmentProjectAlert';
|
||||
import { sortStrategiesByFeature } from './SegmentDelete/SegmentDeleteUsedSegment/sort-strategies';
|
||||
import type { IFeatureStrategy } from 'interfaces/strategy';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import { useSegments } from 'hooks/api/getters/useSegments/useSegments';
|
||||
import { Limit } from '../common/Limit/Limit';
|
||||
@ -37,15 +36,15 @@ interface ISegmentFormPartOneProps {
|
||||
setCurrentStep: React.Dispatch<React.SetStateAction<SegmentFormStep>>;
|
||||
}
|
||||
|
||||
const StyledForm = styled('div')(({ theme }) => ({
|
||||
const StyledForm = styled('div')({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
}));
|
||||
});
|
||||
|
||||
const StyledContainer = styled('div')(({ theme }) => ({
|
||||
const StyledContainer = styled('div')({
|
||||
maxWidth: '400px',
|
||||
}));
|
||||
});
|
||||
|
||||
const StyledInputDescription = styled('p')(({ theme }) => ({
|
||||
marginBottom: theme.spacing(1),
|
||||
@ -56,11 +55,11 @@ const StyledInput = styled(Input)(({ theme }) => ({
|
||||
marginBottom: theme.spacing(2),
|
||||
}));
|
||||
|
||||
const StyledButtonContainer = styled('div')(({ theme }) => ({
|
||||
const StyledButtonContainer = styled('div')({
|
||||
marginTop: 'auto',
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
}));
|
||||
});
|
||||
|
||||
const StyledCancelButton = styled(Button)(({ theme }) => ({
|
||||
marginLeft: theme.spacing(3),
|
||||
@ -79,16 +78,13 @@ const useSegmentLimit = () => {
|
||||
const { uiConfig, loading: loadingConfig } = useUiConfig();
|
||||
const segmentsLimit = uiConfig.resourceLimits.segments;
|
||||
const segmentsCount = segments?.length || 0;
|
||||
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||
const limitReached =
|
||||
resourceLimitsEnabled && segmentsCount >= segmentsLimit;
|
||||
const limitReached = segmentsCount >= segmentsLimit;
|
||||
|
||||
return {
|
||||
limit: segmentsLimit,
|
||||
limitReached,
|
||||
currentCount: segmentsCount,
|
||||
loading: loadingSegments || loadingConfig,
|
||||
resourceLimitsEnabled,
|
||||
};
|
||||
};
|
||||
|
||||
@ -111,7 +107,6 @@ export const SegmentFormStepOne: React.FC<ISegmentFormPartOneProps> = ({
|
||||
limit,
|
||||
currentCount,
|
||||
loading: loadingSegmentLimit,
|
||||
resourceLimitsEnabled,
|
||||
} = useSegmentLimit();
|
||||
|
||||
const {
|
||||
@ -204,15 +199,10 @@ export const SegmentFormStepOne: React.FC<ISegmentFormPartOneProps> = ({
|
||||
</StyledContainer>
|
||||
|
||||
<LimitContainer>
|
||||
<ConditionallyRender
|
||||
condition={resourceLimitsEnabled}
|
||||
show={
|
||||
<Limit
|
||||
name='segments'
|
||||
limit={limit}
|
||||
currentValue={currentCount}
|
||||
/>
|
||||
}
|
||||
<Limit
|
||||
name='segments'
|
||||
limit={limit}
|
||||
currentValue={currentCount}
|
||||
/>
|
||||
</LimitContainer>
|
||||
|
||||
|
@ -88,7 +88,6 @@ export type UiFlags = {
|
||||
enableLegacyVariants?: boolean;
|
||||
navigationSidebar?: boolean;
|
||||
flagCreator?: boolean;
|
||||
resourceLimits?: boolean;
|
||||
newEventSearch?: boolean;
|
||||
archiveProjects?: boolean;
|
||||
projectListImprovements?: boolean;
|
||||
|
@ -142,7 +142,6 @@ exports[`should create default config 1`] = `
|
||||
"projectOverviewRefactorFeedback": false,
|
||||
"queryMissingTokens": false,
|
||||
"removeUnsafeInlineStyleSrc": false,
|
||||
"resourceLimits": false,
|
||||
"responseTimeMetricsFix": false,
|
||||
"responseTimeWithAppNameKillSwitch": false,
|
||||
"showInactiveUsers": false,
|
||||
|
@ -378,8 +378,6 @@ class FeatureToggleService {
|
||||
environment: string;
|
||||
featureName: string;
|
||||
}) {
|
||||
if (!this.flagResolver.isEnabled('resourceLimits')) return;
|
||||
|
||||
const limit = this.resourceLimits.featureEnvironmentStrategies;
|
||||
const existingCount = (
|
||||
await this.featureStrategiesStore.getStrategiesForFeatureEnv(
|
||||
@ -400,8 +398,6 @@ class FeatureToggleService {
|
||||
updated: IConstraint[];
|
||||
existing: IConstraint[];
|
||||
}) {
|
||||
if (!this.flagResolver.isEnabled('resourceLimits')) return;
|
||||
|
||||
const {
|
||||
constraints: constraintsLimit,
|
||||
constraintValues: constraintValuesLimit,
|
||||
@ -1223,15 +1219,13 @@ class FeatureToggleService {
|
||||
}
|
||||
|
||||
private async validateFeatureFlagLimit() {
|
||||
if (this.flagResolver.isEnabled('resourceLimits')) {
|
||||
const currentFlagCount = await this.featureToggleStore.count();
|
||||
const limit = this.resourceLimits.featureFlags;
|
||||
if (currentFlagCount >= limit) {
|
||||
throwExceedsLimitError(this.eventBus, {
|
||||
resource: 'feature flag',
|
||||
limit,
|
||||
});
|
||||
}
|
||||
const currentFlagCount = await this.featureToggleStore.count();
|
||||
const limit = this.resourceLimits.featureFlags;
|
||||
if (currentFlagCount >= limit) {
|
||||
throwExceedsLimitError(this.eventBus, {
|
||||
resource: 'feature flag',
|
||||
limit,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,9 +14,7 @@ test('Should not allow to exceed project limit on create', async () => {
|
||||
const projectService = createFakeProjectService({
|
||||
...createTestConfig(),
|
||||
flagResolver: alwaysOnFlagResolver,
|
||||
resourceLimits: {
|
||||
projects: LIMIT,
|
||||
},
|
||||
resourceLimits: { projects: LIMIT },
|
||||
eventBus: {
|
||||
emit: () => {},
|
||||
},
|
||||
@ -37,9 +35,7 @@ test('Should not allow to exceed project limit on revive', async () => {
|
||||
const projectService = createFakeProjectService({
|
||||
...createTestConfig(),
|
||||
flagResolver: alwaysOnFlagResolver,
|
||||
resourceLimits: {
|
||||
projects: LIMIT,
|
||||
},
|
||||
resourceLimits: { projects: LIMIT },
|
||||
eventBus: {
|
||||
emit: () => {},
|
||||
},
|
||||
|
@ -325,8 +325,6 @@ export default class ProjectService {
|
||||
}
|
||||
|
||||
async validateProjectLimit() {
|
||||
if (!this.flagResolver.isEnabled('resourceLimits')) return;
|
||||
|
||||
const limit = Math.max(this.resourceLimits.projects, 1);
|
||||
const projectCount = await this.projectStore.count();
|
||||
|
||||
|
@ -13,9 +13,7 @@ test('Should not allow to exceed segment limit', async () => {
|
||||
const segmentService = createFakeSegmentService({
|
||||
getLogger,
|
||||
flagResolver: alwaysOnFlagResolver,
|
||||
resourceLimits: {
|
||||
segments: LIMIT,
|
||||
},
|
||||
resourceLimits: { segments: LIMIT },
|
||||
eventBus: {
|
||||
emit: () => {},
|
||||
},
|
||||
|
@ -129,8 +129,6 @@ export class SegmentService implements ISegmentService {
|
||||
}
|
||||
|
||||
async validateSegmentLimit() {
|
||||
if (!this.flagResolver.isEnabled('resourceLimits')) return;
|
||||
|
||||
const limit = this.resourceLimits.segments;
|
||||
|
||||
const segmentCount = await this.segmentStore.count();
|
||||
|
@ -7,9 +7,7 @@ import { createFakeApiTokenService } from '../features/api-tokens/createApiToken
|
||||
const createServiceWithLimit = (limit: number) => {
|
||||
const config: IUnleashConfig = createTestConfig({
|
||||
experimental: {
|
||||
flags: {
|
||||
resourceLimits: true,
|
||||
},
|
||||
flags: {},
|
||||
},
|
||||
});
|
||||
config.resourceLimits.apiTokens = limit;
|
||||
|
@ -308,15 +308,13 @@ export class ApiTokenService {
|
||||
}
|
||||
|
||||
private async validateApiTokenLimit() {
|
||||
if (this.flagResolver.isEnabled('resourceLimits')) {
|
||||
const currentTokenCount = await this.store.count();
|
||||
const limit = this.resourceLimits.apiTokens;
|
||||
if (currentTokenCount >= limit) {
|
||||
throwExceedsLimitError(this.eventBus, {
|
||||
resource: 'api token',
|
||||
limit,
|
||||
});
|
||||
}
|
||||
const currentTokenCount = await this.store.count();
|
||||
const limit = this.resourceLimits.apiTokens;
|
||||
if (currentTokenCount >= limit) {
|
||||
throwExceedsLimitError(this.eventBus, {
|
||||
resource: 'api token',
|
||||
limit,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,6 @@ export type IFlagKey =
|
||||
| 'enableLegacyVariants'
|
||||
| 'navigationSidebar'
|
||||
| 'anonymizeProjectOwners'
|
||||
| 'resourceLimits'
|
||||
| 'extendedMetrics'
|
||||
| 'removeUnsafeInlineStyleSrc'
|
||||
| 'originMiddleware'
|
||||
@ -278,10 +277,6 @@ const flags: IFlags = {
|
||||
process.env.UNLEASH_EXPERIMENTAL_ANONYMIZE_PROJECT_OWNERS,
|
||||
false,
|
||||
),
|
||||
resourceLimits: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_RESOURCE_LIMITS,
|
||||
false,
|
||||
),
|
||||
extendedMetrics: parseEnvVarBoolean(
|
||||
process.env.UNLEASH_EXPERIMENTAL_EXTENDED_METRICS,
|
||||
false,
|
||||
|
@ -50,7 +50,6 @@ process.nextTick(async () => {
|
||||
projectOverviewRefactorFeedback: true,
|
||||
manyStrategiesPagination: true,
|
||||
enableLegacyVariants: false,
|
||||
resourceLimits: true,
|
||||
extendedMetrics: true,
|
||||
originMiddleware: true,
|
||||
newEventSearch: true,
|
||||
|
Loading…
Reference in New Issue
Block a user