mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-24 17:51:14 +02:00
feat: segments limit ui (#7528)
This commit is contained in:
parent
6d913809ca
commit
d924519abb
@ -6,8 +6,12 @@ import PermissionButton from 'component/common/PermissionButton/PermissionButton
|
|||||||
import { NAVIGATE_TO_CREATE_SEGMENT } from 'utils/testIds';
|
import { NAVIGATE_TO_CREATE_SEGMENT } from 'utils/testIds';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { useOptionalPathParam } from 'hooks/useOptionalPathParam';
|
import { useOptionalPathParam } from 'hooks/useOptionalPathParam';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
|
||||||
export const CreateSegmentButton = () => {
|
export const CreateSegmentButton: FC<{
|
||||||
|
disabled: boolean;
|
||||||
|
tooltip?: string;
|
||||||
|
}> = ({ disabled, tooltip }) => {
|
||||||
const projectId = useOptionalPathParam('projectId');
|
const projectId = useOptionalPathParam('projectId');
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
@ -22,6 +26,10 @@ export const CreateSegmentButton = () => {
|
|||||||
}}
|
}}
|
||||||
permission={[CREATE_SEGMENT, UPDATE_PROJECT_SEGMENT]}
|
permission={[CREATE_SEGMENT, UPDATE_PROJECT_SEGMENT]}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
|
disabled={disabled}
|
||||||
|
tooltipProps={{
|
||||||
|
title: tooltip,
|
||||||
|
}}
|
||||||
data-testid={NAVIGATE_TO_CREATE_SEGMENT}
|
data-testid={NAVIGATE_TO_CREATE_SEGMENT}
|
||||||
>
|
>
|
||||||
New segment
|
New segment
|
||||||
|
@ -2,6 +2,7 @@ import { render } from 'utils/testRenderer';
|
|||||||
import { screen } from '@testing-library/react';
|
import { screen } from '@testing-library/react';
|
||||||
import { SegmentTable } from './SegmentTable';
|
import { SegmentTable } from './SegmentTable';
|
||||||
import { testServerRoute, testServerSetup } from 'utils/testServer';
|
import { testServerRoute, testServerSetup } from 'utils/testServer';
|
||||||
|
import { CREATE_SEGMENT } from '../../providers/AccessProvider/permissions';
|
||||||
|
|
||||||
const server = testServerSetup();
|
const server = testServerSetup();
|
||||||
|
|
||||||
@ -23,6 +24,10 @@ const setupRoutes = () => {
|
|||||||
testServerRoute(server, '/api/admin/ui-config', {
|
testServerRoute(server, '/api/admin/ui-config', {
|
||||||
flags: {
|
flags: {
|
||||||
SE: true,
|
SE: true,
|
||||||
|
resourceLimits: true,
|
||||||
|
},
|
||||||
|
resourceLimits: {
|
||||||
|
segments: 2,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -30,8 +35,14 @@ const setupRoutes = () => {
|
|||||||
test('should show the count of projects and features used in', async () => {
|
test('should show the count of projects and features used in', async () => {
|
||||||
setupRoutes();
|
setupRoutes();
|
||||||
|
|
||||||
render(<SegmentTable />);
|
render(<SegmentTable />, { permissions: [{ permission: CREATE_SEGMENT }] });
|
||||||
|
|
||||||
|
const loadingSegment = await screen.findByText('New segment');
|
||||||
|
expect(loadingSegment).toBeDisabled();
|
||||||
|
|
||||||
await screen.findByText('2 feature flags');
|
await screen.findByText('2 feature flags');
|
||||||
await screen.findByText('3 projects');
|
await screen.findByText('3 projects');
|
||||||
|
|
||||||
|
const segment = await screen.findByText('New segment');
|
||||||
|
expect(segment).not.toBeDisabled();
|
||||||
});
|
});
|
||||||
|
@ -29,15 +29,41 @@ import { useConditionallyHiddenColumns } from 'hooks/useConditionallyHiddenColum
|
|||||||
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
||||||
import { useOptionalPathParam } from 'hooks/useOptionalPathParam';
|
import { useOptionalPathParam } from 'hooks/useOptionalPathParam';
|
||||||
import { UsedInCell } from 'component/context/ContextList/UsedInCell';
|
import { UsedInCell } from 'component/context/ContextList/UsedInCell';
|
||||||
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
|
import { useUiFlag } from 'hooks/useUiFlag';
|
||||||
|
|
||||||
|
const useSegmentLimit = (segmentsLimit: number, segmentsCount: number) => {
|
||||||
|
const resourceLimitsEnabled = useUiFlag('resourceLimits');
|
||||||
|
const limitReached =
|
||||||
|
resourceLimitsEnabled && segmentsCount >= segmentsLimit;
|
||||||
|
|
||||||
|
return {
|
||||||
|
limitReached,
|
||||||
|
limitMessage: limitReached
|
||||||
|
? `Limit of ${segmentsCount} segments reached`
|
||||||
|
: undefined,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const SegmentTable = () => {
|
export const SegmentTable = () => {
|
||||||
const projectId = useOptionalPathParam('projectId');
|
const projectId = useOptionalPathParam('projectId');
|
||||||
const { segments, loading } = useSegments();
|
const { segments, loading: loadingSegments } = useSegments();
|
||||||
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
||||||
const [initialState] = useState({
|
const [initialState] = useState({
|
||||||
sortBy: [{ id: 'createdAt' }],
|
sortBy: [{ id: 'createdAt' }],
|
||||||
hiddenColumns: ['description'],
|
hiddenColumns: ['description'],
|
||||||
});
|
});
|
||||||
|
const { uiConfig, loading: loadingConfig } = useUiConfig();
|
||||||
|
const segmentLimit = uiConfig.resourceLimits.segments;
|
||||||
|
const segmentCount = segments?.length || 0;
|
||||||
|
|
||||||
|
const { limitReached, limitMessage } = useSegmentLimit(
|
||||||
|
segmentLimit,
|
||||||
|
segmentCount,
|
||||||
|
);
|
||||||
|
|
||||||
|
const createSegmentDisabled =
|
||||||
|
loadingSegments || loadingConfig || limitReached;
|
||||||
|
|
||||||
const data = useMemo(() => {
|
const data = useMemo(() => {
|
||||||
if (!segments) {
|
if (!segments) {
|
||||||
@ -112,15 +138,18 @@ export const SegmentTable = () => {
|
|||||||
onChange={setGlobalFilter}
|
onChange={setGlobalFilter}
|
||||||
/>
|
/>
|
||||||
<PageHeader.Divider />
|
<PageHeader.Divider />
|
||||||
<CreateSegmentButton />
|
<CreateSegmentButton
|
||||||
|
disabled={createSegmentDisabled}
|
||||||
|
tooltip={limitMessage}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
isLoading={loading}
|
isLoading={loadingSegments}
|
||||||
>
|
>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={!loading && data.length === 0}
|
condition={!loadingSegments && data.length === 0}
|
||||||
show={
|
show={
|
||||||
<TablePlaceholder>
|
<TablePlaceholder>
|
||||||
<SegmentEmpty />
|
<SegmentEmpty />
|
||||||
|
@ -41,5 +41,6 @@ export const defaultValue: IUiConfig = {
|
|||||||
environments: 50,
|
environments: 50,
|
||||||
constraintValues: 250,
|
constraintValues: 250,
|
||||||
projects: 500,
|
projects: 500,
|
||||||
|
segments: 300,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -32,4 +32,6 @@ export interface ResourceLimitsSchema {
|
|||||||
constraintValues: number;
|
constraintValues: number;
|
||||||
/** The maximum number of projects allowed. */
|
/** The maximum number of projects allowed. */
|
||||||
projects: number;
|
projects: number;
|
||||||
|
/** The maximum number of segment allowed. */
|
||||||
|
segments: number;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user