mirror of
https://github.com/Unleash/unleash.git
synced 2025-11-10 01:19:53 +01:00
feat: warning when empty segment (#10868)
This commit is contained in:
parent
07758a4267
commit
8db708369d
@ -0,0 +1,70 @@
|
|||||||
|
import { screen } from '@testing-library/react';
|
||||||
|
import { render } from 'utils/testRenderer';
|
||||||
|
import { FeatureStrategySegmentList } from './FeatureStrategySegmentList.tsx';
|
||||||
|
import type { ISegment } from 'interfaces/segment';
|
||||||
|
|
||||||
|
const createMockSegment = (
|
||||||
|
id: number,
|
||||||
|
name: string,
|
||||||
|
constraints: ISegment['constraints'] = [],
|
||||||
|
): ISegment => ({
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
description: `Description for ${name}`,
|
||||||
|
createdAt: '2023-01-01T00:00:00Z',
|
||||||
|
createdBy: 'test-user',
|
||||||
|
constraints,
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('FeatureStrategySegmentList', () => {
|
||||||
|
test('should not show warning when segment has constraints', () => {
|
||||||
|
const segments: ISegment[] = [
|
||||||
|
createMockSegment(1, 'Segment with constraints', [
|
||||||
|
{
|
||||||
|
contextName: 'userId',
|
||||||
|
operator: 'IN',
|
||||||
|
values: ['user1', 'user2'],
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
|
||||||
|
render(
|
||||||
|
<FeatureStrategySegmentList
|
||||||
|
segments={segments}
|
||||||
|
setSegments={() => {}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('Selected Segments')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByText('Segment with constraints'),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.queryByText(/You are adding an empty segment/i),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show warning when segment has no constraints', () => {
|
||||||
|
const segments: ISegment[] = [
|
||||||
|
createMockSegment(1, 'pre-access-demo-accounts', []),
|
||||||
|
];
|
||||||
|
|
||||||
|
render(
|
||||||
|
<FeatureStrategySegmentList
|
||||||
|
segments={segments}
|
||||||
|
setSegments={() => {}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('Selected Segments')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByText('pre-access-demo-accounts'),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByText(/You are adding an empty segment/i),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByText(/This will activate this feature for ALL USERS/i),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -3,7 +3,7 @@ import { Fragment, useId, useState } from 'react';
|
|||||||
import type { ISegment } from 'interfaces/segment';
|
import type { ISegment } from 'interfaces/segment';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { FeatureStrategySegmentChip } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentChip';
|
import { FeatureStrategySegmentChip } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentChip';
|
||||||
import { styled } from '@mui/material';
|
import { Alert, styled } from '@mui/material';
|
||||||
import { SegmentItem } from 'component/common/SegmentItem/SegmentItem';
|
import { SegmentItem } from 'component/common/SegmentItem/SegmentItem';
|
||||||
|
|
||||||
interface IFeatureStrategySegmentListProps {
|
interface IFeatureStrategySegmentListProps {
|
||||||
@ -38,6 +38,11 @@ const StyledPreviewContainer = styled('div')({
|
|||||||
display: 'contents',
|
display: 'contents',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const StyledWarningAlert = styled(Alert)(({ theme }) => ({
|
||||||
|
marginTop: theme.spacing(1.5),
|
||||||
|
marginBottom: theme.spacing(0.5),
|
||||||
|
}));
|
||||||
|
|
||||||
export const FeatureStrategySegmentList = ({
|
export const FeatureStrategySegmentList = ({
|
||||||
segments,
|
segments,
|
||||||
setSegments,
|
setSegments,
|
||||||
@ -50,6 +55,11 @@ export const FeatureStrategySegmentList = ({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const emptySegments = segments.filter(
|
||||||
|
(segment) => !segment.constraints || segment.constraints.length === 0,
|
||||||
|
);
|
||||||
|
const hasEmptySegments = emptySegments.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
@ -60,6 +70,17 @@ export const FeatureStrategySegmentList = ({
|
|||||||
</StyledSelectedSegmentsLabel>
|
</StyledSelectedSegmentsLabel>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={hasEmptySegments}
|
||||||
|
show={
|
||||||
|
<StyledWarningAlert severity='warning'>
|
||||||
|
<strong>Warning!</strong> You are adding an empty
|
||||||
|
segment{emptySegments.length > 1 ? 's' : ''} (
|
||||||
|
{emptySegments.map((s) => s.name).join(', ')}). This
|
||||||
|
will activate this feature for ALL USERS.
|
||||||
|
</StyledWarningAlert>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<StyledList>
|
<StyledList>
|
||||||
{segments.map((segment, i) => (
|
{segments.map((segment, i) => (
|
||||||
<Fragment key={segment.id}>
|
<Fragment key={segment.id}>
|
||||||
|
|||||||
@ -0,0 +1,70 @@
|
|||||||
|
import { screen } from '@testing-library/react';
|
||||||
|
import { render } from 'utils/testRenderer';
|
||||||
|
import { MilestoneStrategySegmentList } from './MilestoneStrategySegmentList.tsx';
|
||||||
|
import type { ISegment } from 'interfaces/segment';
|
||||||
|
|
||||||
|
const createMockSegment = (
|
||||||
|
id: number,
|
||||||
|
name: string,
|
||||||
|
constraints: ISegment['constraints'] = [],
|
||||||
|
): ISegment => ({
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
description: `Description for ${name}`,
|
||||||
|
createdAt: '2023-01-01T00:00:00Z',
|
||||||
|
createdBy: 'test-user',
|
||||||
|
constraints,
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('MilestoneStrategySegmentList', () => {
|
||||||
|
test('should not show warning when segment has constraints', () => {
|
||||||
|
const segments: ISegment[] = [
|
||||||
|
createMockSegment(1, 'Segment with constraints', [
|
||||||
|
{
|
||||||
|
contextName: 'userId',
|
||||||
|
operator: 'IN',
|
||||||
|
values: ['user1', 'user2'],
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
|
||||||
|
render(
|
||||||
|
<MilestoneStrategySegmentList
|
||||||
|
segments={segments}
|
||||||
|
setSegments={() => {}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('Selected Segments')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByText('Segment with constraints'),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.queryByText(/You are adding an empty segment/i),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should show warning when segment has no constraints', () => {
|
||||||
|
const segments: ISegment[] = [
|
||||||
|
createMockSegment(1, 'pre-access-demo-accounts', []),
|
||||||
|
];
|
||||||
|
|
||||||
|
render(
|
||||||
|
<MilestoneStrategySegmentList
|
||||||
|
segments={segments}
|
||||||
|
setSegments={() => {}}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('Selected Segments')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByText('pre-access-demo-accounts'),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByText(/You are adding an empty segment/i),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.getByText(/This will activate this feature for ALL USERS/i),
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,8 +1,9 @@
|
|||||||
|
import type React from 'react';
|
||||||
import { Fragment, useState } from 'react';
|
import { Fragment, useState } from 'react';
|
||||||
import type { ISegment } from 'interfaces/segment';
|
import type { ISegment } from 'interfaces/segment';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { FeatureStrategySegmentChip } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentChip';
|
import { FeatureStrategySegmentChip } from 'component/feature/FeatureStrategy/FeatureStrategySegment/FeatureStrategySegmentChip';
|
||||||
import { styled } from '@mui/material';
|
import { Alert, styled } from '@mui/material';
|
||||||
import { SegmentItem } from 'component/common/SegmentItem/SegmentItem';
|
import { SegmentItem } from 'component/common/SegmentItem/SegmentItem';
|
||||||
|
|
||||||
const StyledList = styled('div')(({ theme }) => ({
|
const StyledList = styled('div')(({ theme }) => ({
|
||||||
@ -28,6 +29,11 @@ const StyledAnd = styled('p')(({ theme }) => ({
|
|||||||
backgroundColor: theme.palette.background.elevation2,
|
backgroundColor: theme.palette.background.elevation2,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const StyledWarningAlert = styled(Alert)(({ theme }) => ({
|
||||||
|
marginTop: theme.spacing(1.5),
|
||||||
|
marginBottom: theme.spacing(1.5),
|
||||||
|
}));
|
||||||
|
|
||||||
type IMilestoneStrategySegmentListProps = {
|
type IMilestoneStrategySegmentListProps = {
|
||||||
segments: ISegment[];
|
segments: ISegment[];
|
||||||
setSegments: React.Dispatch<React.SetStateAction<ISegment[]>>;
|
setSegments: React.Dispatch<React.SetStateAction<ISegment[]>>;
|
||||||
@ -44,6 +50,11 @@ export const MilestoneStrategySegmentList = ({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const emptySegments = segments.filter(
|
||||||
|
(segment) => !segment.constraints || segment.constraints.length === 0,
|
||||||
|
);
|
||||||
|
const hasEmptySegments = emptySegments.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
@ -54,6 +65,17 @@ export const MilestoneStrategySegmentList = ({
|
|||||||
</StyledSelectedSegmentsLabel>
|
</StyledSelectedSegmentsLabel>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={hasEmptySegments}
|
||||||
|
show={
|
||||||
|
<StyledWarningAlert severity='warning'>
|
||||||
|
<strong>Warning!</strong> You are adding an empty
|
||||||
|
segment{emptySegments.length > 1 ? 's' : ''} (
|
||||||
|
{emptySegments.map((s) => s.name).join(', ')}). This
|
||||||
|
will activate this feature for ALL USERS.
|
||||||
|
</StyledWarningAlert>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<StyledList>
|
<StyledList>
|
||||||
{segments.map((segment, i) => (
|
{segments.map((segment, i) => (
|
||||||
<Fragment key={segment.id}>
|
<Fragment key={segment.id}>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user