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