mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: Limit environments component (#7548)
This commit is contained in:
		
							parent
							
								
									c802442846
								
							
						
					
					
						commit
						963d051632
					
				@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					import { screen } from '@testing-library/react';
 | 
				
			||||||
 | 
					import { render } from 'utils/testRenderer';
 | 
				
			||||||
 | 
					import { testServerRoute, testServerSetup } from '../../../utils/testServer';
 | 
				
			||||||
 | 
					import CreateEnvironment from './CreateEnvironment';
 | 
				
			||||||
 | 
					import { ADMIN } from '../../providers/AccessProvider/permissions';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const server = testServerSetup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const setupApi = ({
 | 
				
			||||||
 | 
					    resourceLimits,
 | 
				
			||||||
 | 
					    limit,
 | 
				
			||||||
 | 
					    environments,
 | 
				
			||||||
 | 
					}: { resourceLimits: boolean; limit: number; environments: number }) => {
 | 
				
			||||||
 | 
					    testServerRoute(server, '/api/admin/ui-config', {
 | 
				
			||||||
 | 
					        flags: {
 | 
				
			||||||
 | 
					            resourceLimits,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        resourceLimits: {
 | 
				
			||||||
 | 
					            environments: limit,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    testServerRoute(server, '/api/admin/environments', {
 | 
				
			||||||
 | 
					        environments: [...Array(environments).keys()].map((i) => ({
 | 
				
			||||||
 | 
					            name: `environment${i}`,
 | 
				
			||||||
 | 
					        })),
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('show limit reached info', async () => {
 | 
				
			||||||
 | 
					    setupApi({ environments: 1, limit: 1, resourceLimits: true });
 | 
				
			||||||
 | 
					    render(<CreateEnvironment />, { permissions: [{ permission: ADMIN }] });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await screen.findByText('You have reached the limit for environments');
 | 
				
			||||||
 | 
					    const createButton = await screen.findByText('Create environment', {
 | 
				
			||||||
 | 
					        selector: 'button',
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    expect(createButton).toBeDisabled();
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test('show approaching limit info', async () => {
 | 
				
			||||||
 | 
					    setupApi({ environments: 9, limit: 10, resourceLimits: true });
 | 
				
			||||||
 | 
					    render(<CreateEnvironment />, { permissions: [{ permission: ADMIN }] });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await screen.findByText('You are nearing the limit for environments');
 | 
				
			||||||
 | 
					    const createButton = await screen.findByText('Create environment', {
 | 
				
			||||||
 | 
					        selector: 'button',
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    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');
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@ -16,10 +16,13 @@ import { ADMIN } from 'component/providers/AccessProvider/permissions';
 | 
				
			|||||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
 | 
					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 { 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();
 | 
				
			||||||
@ -71,7 +74,7 @@ const CreateEnvironment = () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <ConditionallyRender
 | 
					        <ConditionallyRender
 | 
				
			||||||
            condition={canCreateMoreEnvs}
 | 
					            condition={resourceLimitsEnabled || canCreateMoreEnvs}
 | 
				
			||||||
            show={
 | 
					            show={
 | 
				
			||||||
                <FormTemplate
 | 
					                <FormTemplate
 | 
				
			||||||
                    loading={loading}
 | 
					                    loading={loading}
 | 
				
			||||||
@ -101,8 +104,24 @@ const CreateEnvironment = () => {
 | 
				
			|||||||
                        setType={setType}
 | 
					                        setType={setType}
 | 
				
			||||||
                        mode='Create'
 | 
					                        mode='Create'
 | 
				
			||||||
                        clearErrors={clearErrors}
 | 
					                        clearErrors={clearErrors}
 | 
				
			||||||
 | 
					                        Limit={
 | 
				
			||||||
 | 
					                            <ConditionallyRender
 | 
				
			||||||
 | 
					                                condition={resourceLimitsEnabled}
 | 
				
			||||||
 | 
					                                show={
 | 
				
			||||||
 | 
					                                    <Limit
 | 
				
			||||||
 | 
					                                        name='environments'
 | 
				
			||||||
 | 
					                                        limit={environmentLimit}
 | 
				
			||||||
 | 
					                                        currentValue={environments.length}
 | 
				
			||||||
 | 
					                                    />
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                        <CreateButton name='environment' permission={ADMIN} />
 | 
					                        <CreateButton
 | 
				
			||||||
 | 
					                            name='environment'
 | 
				
			||||||
 | 
					                            permission={ADMIN}
 | 
				
			||||||
 | 
					                            disabled={!canCreateMoreEnvs}
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
                    </EnvironmentForm>
 | 
					                    </EnvironmentForm>
 | 
				
			||||||
                </FormTemplate>
 | 
					                </FormTemplate>
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import { Button, styled } from '@mui/material';
 | 
					import { Box, Button, styled } from '@mui/material';
 | 
				
			||||||
import type React from 'react';
 | 
					import type React from 'react';
 | 
				
			||||||
import Input from 'component/common/Input/Input';
 | 
					import Input from 'component/common/Input/Input';
 | 
				
			||||||
import EnvironmentTypeSelector from './EnvironmentTypeSelector/EnvironmentTypeSelector';
 | 
					import EnvironmentTypeSelector from './EnvironmentTypeSelector/EnvironmentTypeSelector';
 | 
				
			||||||
@ -16,6 +16,7 @@ interface IEnvironmentForm {
 | 
				
			|||||||
    mode: 'Create' | 'Edit';
 | 
					    mode: 'Create' | 'Edit';
 | 
				
			||||||
    clearErrors: () => void;
 | 
					    clearErrors: () => void;
 | 
				
			||||||
    children?: React.ReactNode;
 | 
					    children?: React.ReactNode;
 | 
				
			||||||
 | 
					    Limit?: React.ReactNode;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const StyledForm = styled('form')({
 | 
					const StyledForm = styled('form')({
 | 
				
			||||||
@ -52,6 +53,14 @@ const StyledCancelButton = styled(Button)(({ theme }) => ({
 | 
				
			|||||||
    marginLeft: theme.spacing(3),
 | 
					    marginLeft: theme.spacing(3),
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const LimitContainer = styled(Box)(({ theme }) => ({
 | 
				
			||||||
 | 
					    flex: 1,
 | 
				
			||||||
 | 
					    display: 'flex',
 | 
				
			||||||
 | 
					    alignItems: 'flex-end',
 | 
				
			||||||
 | 
					    marginTop: theme.spacing(3),
 | 
				
			||||||
 | 
					    marginBottom: theme.spacing(3),
 | 
				
			||||||
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const EnvironmentForm: React.FC<IEnvironmentForm> = ({
 | 
					const EnvironmentForm: React.FC<IEnvironmentForm> = ({
 | 
				
			||||||
    children,
 | 
					    children,
 | 
				
			||||||
    handleSubmit,
 | 
					    handleSubmit,
 | 
				
			||||||
@ -64,6 +73,7 @@ const EnvironmentForm: React.FC<IEnvironmentForm> = ({
 | 
				
			|||||||
    errors,
 | 
					    errors,
 | 
				
			||||||
    mode,
 | 
					    mode,
 | 
				
			||||||
    clearErrors,
 | 
					    clearErrors,
 | 
				
			||||||
 | 
					    Limit,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <StyledForm onSubmit={handleSubmit}>
 | 
					        <StyledForm onSubmit={handleSubmit}>
 | 
				
			||||||
@ -93,6 +103,9 @@ const EnvironmentForm: React.FC<IEnvironmentForm> = ({
 | 
				
			|||||||
                    value={type}
 | 
					                    value={type}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
            </StyledContainer>
 | 
					            </StyledContainer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LimitContainer>{Limit}</LimitContainer>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <StyledButtonContainer>
 | 
					            <StyledButtonContainer>
 | 
				
			||||||
                {children}
 | 
					                {children}
 | 
				
			||||||
                <StyledCancelButton onClick={handleCancel}>
 | 
					                <StyledCancelButton onClick={handleCancel}>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,11 +3,7 @@ import { render } from 'utils/testRenderer';
 | 
				
			|||||||
import FeatureOverviewEnvironment from './FeatureOverviewEnvironment';
 | 
					import FeatureOverviewEnvironment from './FeatureOverviewEnvironment';
 | 
				
			||||||
import { Route, Routes } from 'react-router-dom';
 | 
					import { Route, Routes } from 'react-router-dom';
 | 
				
			||||||
import { CREATE_FEATURE_STRATEGY } from 'component/providers/AccessProvider/permissions';
 | 
					import { CREATE_FEATURE_STRATEGY } from 'component/providers/AccessProvider/permissions';
 | 
				
			||||||
import type { IFeatureStrategy } from 'interfaces/strategy';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const strategy = {
 | 
					 | 
				
			||||||
    name: 'default',
 | 
					 | 
				
			||||||
} as IFeatureStrategy;
 | 
					 | 
				
			||||||
const environmentWithoutStrategies = {
 | 
					const environmentWithoutStrategies = {
 | 
				
			||||||
    name: 'production',
 | 
					    name: 'production',
 | 
				
			||||||
    enabled: true,
 | 
					    enabled: true,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user