From e7d07486a1cead3390a20db2b86385602a6f96c8 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Mon, 8 Jul 2024 09:03:08 +0200 Subject: [PATCH] feat: limit segments component (#7553) --- .../CreateSegmentButton.tsx | 9 +-- .../src/component/segments/SegmentDocs.tsx | 3 +- .../segments/SegmentFormStepOne.test.tsx | 75 +++++++++++++++++++ .../component/segments/SegmentFormStepOne.tsx | 62 ++++++++++++++- .../SegmentTable/SegmentTable.test.tsx | 48 ------------ .../segments/SegmentTable/SegmentTable.tsx | 37 +-------- 6 files changed, 141 insertions(+), 93 deletions(-) create mode 100644 frontend/src/component/segments/SegmentFormStepOne.test.tsx delete mode 100644 frontend/src/component/segments/SegmentTable/SegmentTable.test.tsx diff --git a/frontend/src/component/segments/CreateSegmentButton/CreateSegmentButton.tsx b/frontend/src/component/segments/CreateSegmentButton/CreateSegmentButton.tsx index 74711b6a78..4ececc5016 100644 --- a/frontend/src/component/segments/CreateSegmentButton/CreateSegmentButton.tsx +++ b/frontend/src/component/segments/CreateSegmentButton/CreateSegmentButton.tsx @@ -8,10 +8,7 @@ import { useNavigate } from 'react-router-dom'; import { useOptionalPathParam } from 'hooks/useOptionalPathParam'; import type { FC } from 'react'; -export const CreateSegmentButton: FC<{ - disabled: boolean; - tooltip?: string; -}> = ({ disabled, tooltip }) => { +export const CreateSegmentButton: FC = () => { const projectId = useOptionalPathParam('projectId'); const navigate = useNavigate(); @@ -26,10 +23,6 @@ export const CreateSegmentButton: FC<{ }} permission={[CREATE_SEGMENT, UPDATE_PROJECT_SEGMENT]} projectId={projectId} - disabled={disabled} - tooltipProps={{ - title: tooltip, - }} data-testid={NAVIGATE_TO_CREATE_SEGMENT} > New segment diff --git a/frontend/src/component/segments/SegmentDocs.tsx b/frontend/src/component/segments/SegmentDocs.tsx index 17b0aac148..03a241c8eb 100644 --- a/frontend/src/component/segments/SegmentDocs.tsx +++ b/frontend/src/component/segments/SegmentDocs.tsx @@ -16,7 +16,8 @@ export const SegmentDocsValuesInfo = () => { target='_blank' rel='noreferrer' > - at most {segmentValuesLimit} across all of its contraints + at most {segmentValuesLimit} values across all of its + constraints . diff --git a/frontend/src/component/segments/SegmentFormStepOne.test.tsx b/frontend/src/component/segments/SegmentFormStepOne.test.tsx new file mode 100644 index 0000000000..a455bef761 --- /dev/null +++ b/frontend/src/component/segments/SegmentFormStepOne.test.tsx @@ -0,0 +1,75 @@ +import { render } from 'utils/testRenderer'; +import { screen, waitFor } from '@testing-library/react'; +import { testServerRoute, testServerSetup } from 'utils/testServer'; +import { SegmentFormStepOne } from './SegmentFormStepOne'; + +const server = testServerSetup(); + +const setupRoutes = ({ + limit, + segments, +}: { limit: number; segments: number }) => { + testServerRoute(server, 'api/admin/segments', { + segments: [...Array(segments).keys()].map((i) => ({ + name: `segment${i}`, + })), + }); + + testServerRoute(server, '/api/admin/ui-config', { + flags: { + SE: true, + resourceLimits: true, + }, + resourceLimits: { + segments: limit, + }, + }); +}; + +const irrelevant = () => {}; + +test('Do not allow next step when limit reached', async () => { + setupRoutes({ limit: 1, segments: 1 }); + + render( + , + ); + + await screen.findByText('You have reached the limit for segments'); + const nextStep = await screen.findByText('Next'); + expect(nextStep).toBeDisabled(); +}); + +test('Allows next step when approaching limit', async () => { + setupRoutes({ limit: 10, segments: 9 }); + + render( + , + ); + + await screen.findByText('You are nearing the limit for segments'); + await waitFor(async () => { + const nextStep = await screen.findByText('Next'); + expect(nextStep).toBeEnabled(); + }); +}); diff --git a/frontend/src/component/segments/SegmentFormStepOne.tsx b/frontend/src/component/segments/SegmentFormStepOne.tsx index 46097e0fcd..cb5a8b87ef 100644 --- a/frontend/src/component/segments/SegmentFormStepOne.tsx +++ b/frontend/src/component/segments/SegmentFormStepOne.tsx @@ -1,4 +1,4 @@ -import { Autocomplete, Button, styled, TextField } from '@mui/material'; +import { Autocomplete, Box, Button, styled, TextField } from '@mui/material'; import Input from 'component/common/Input/Input'; import React, { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; @@ -20,6 +20,10 @@ 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'; interface ISegmentFormPartOneProps { name: string; @@ -62,6 +66,32 @@ const StyledCancelButton = styled(Button)(({ theme }) => ({ 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 useSegmentLimit = () => { + const { segments, loading: loadingSegments } = useSegments(); + const { uiConfig, loading: loadingConfig } = useUiConfig(); + const segmentsLimit = uiConfig.resourceLimits.segments; + const segmentsCount = segments?.length || 0; + const resourceLimitsEnabled = useUiFlag('resourceLimits'); + const limitReached = + resourceLimitsEnabled && segmentsCount >= segmentsLimit; + + return { + limit: segmentsLimit, + limitReached, + currentCount: segmentsCount, + loading: loadingSegments || loadingConfig, + resourceLimitsEnabled, + }; +}; + export const SegmentFormStepOne: React.FC = ({ name, description, @@ -76,6 +106,13 @@ export const SegmentFormStepOne: React.FC = ({ const projectId = useOptionalPathParam('projectId'); const navigate = useNavigate(); const { projects, loading: loadingProjects } = useProjects(); + const { + limitReached, + limit, + currentCount, + loading: loadingSegmentLimit, + resourceLimitsEnabled, + } = useSegmentLimit(); const { strategies, @@ -106,7 +143,7 @@ export const SegmentFormStepOne: React.FC = ({ setSelectedProject(projects.find(({ id }) => id === project) ?? null); }, [project, projects]); - const loading = loadingProjects && loadingStrategies; + const loading = loadingProjects || loadingStrategies || loadingSegmentLimit; return ( @@ -165,13 +202,32 @@ export const SegmentFormStepOne: React.FC = ({ } /> + + + + } + /> + +