1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-10 01:16:39 +02:00
unleash.unleash/frontend/src/component/segments/SegmentFormStepOne.tsx
gitar-bot[bot] 4615ff40ce
[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>
2024-08-22 13:20:53 +02:00

237 lines
8.0 KiB
TypeScript

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';
import type { SegmentFormStep } from './SegmentForm';
import {
SEGMENT_NAME_ID,
SEGMENT_DESC_ID,
SEGMENT_NEXT_BTN_ID,
} from 'utils/testIds';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import useProjects from 'hooks/api/getters/useProjects/useProjects';
import { useOptionalPathParam } from 'hooks/useOptionalPathParam';
import { GO_BACK } from 'constants/navigate';
import {
type ChangeRequestNewStrategy,
type ChangeRequestUpdatedStrategy,
useStrategiesBySegment,
} from 'hooks/api/getters/useStrategiesBySegment/useStrategiesBySegment';
import { SegmentProjectAlert } from './SegmentProjectAlert';
import { sortStrategiesByFeature } from './SegmentDelete/SegmentDeleteUsedSegment/sort-strategies';
import type { IFeatureStrategy } from 'interfaces/strategy';
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;
description: string;
project?: string;
setName: React.Dispatch<React.SetStateAction<string>>;
setDescription: React.Dispatch<React.SetStateAction<string>>;
setProject: React.Dispatch<React.SetStateAction<string | undefined>>;
errors: { [key: string]: string };
clearErrors: () => void;
setCurrentStep: React.Dispatch<React.SetStateAction<SegmentFormStep>>;
}
const StyledForm = styled('div')({
display: 'flex',
flexDirection: 'column',
height: '100%',
});
const StyledContainer = styled('div')({
maxWidth: '400px',
});
const StyledInputDescription = styled('p')(({ theme }) => ({
marginBottom: theme.spacing(1),
}));
const StyledInput = styled(Input)(({ theme }) => ({
width: '100%',
marginBottom: theme.spacing(2),
}));
const StyledButtonContainer = styled('div')({
marginTop: 'auto',
display: 'flex',
justifyContent: 'flex-end',
});
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 limitReached = segmentsCount >= segmentsLimit;
return {
limit: segmentsLimit,
limitReached,
currentCount: segmentsCount,
loading: loadingSegments || loadingConfig,
};
};
export const SegmentFormStepOne: React.FC<ISegmentFormPartOneProps> = ({
name,
description,
project,
setName,
setDescription,
setProject,
errors,
setCurrentStep,
}) => {
const segmentId = useOptionalPathParam('segmentId');
const projectId = useOptionalPathParam('projectId');
const navigate = useNavigate();
const { projects, loading: loadingProjects } = useProjects();
const {
limitReached,
limit,
currentCount,
loading: loadingSegmentLimit,
} = useSegmentLimit();
const {
strategies,
changeRequestStrategies,
loading: loadingStrategies,
} = useStrategiesBySegment(segmentId);
const collectedStrategies = sortStrategiesByFeature<
IFeatureStrategy,
ChangeRequestUpdatedStrategy,
ChangeRequestNewStrategy
>(strategies ?? [], changeRequestStrategies ?? []);
const projectsUsed = new Set<string>(
collectedStrategies.map(({ projectId }) => projectId!).filter(Boolean),
);
const availableProjects = projects.filter(
({ id }) =>
!projectsUsed.size ||
(projectsUsed.size === 1 && projectsUsed.has(id)),
);
const [selectedProject, setSelectedProject] = React.useState(
projects.find(({ id }) => id === project) ?? null,
);
useEffect(() => {
setSelectedProject(projects.find(({ id }) => id === project) ?? null);
}, [project, projects]);
const loading = loadingProjects || loadingStrategies || loadingSegmentLimit;
return (
<StyledForm>
<StyledContainer>
<StyledInputDescription>
What is the segment name?
</StyledInputDescription>
<StyledInput
label='Segment name'
value={name}
onChange={(e) => setName(e.target.value)}
error={Boolean(errors.name)}
errorText={errors.name}
autoFocus
required
data-testid={SEGMENT_NAME_ID}
/>
<StyledInputDescription>
What is the segment description?
</StyledInputDescription>
<StyledInput
label='Description (optional)'
value={description}
onChange={(e) => setDescription(e.target.value)}
error={Boolean(errors.description)}
errorText={errors.description}
data-testid={SEGMENT_DESC_ID}
/>
<ConditionallyRender
condition={!projectId && !loading}
show={
<>
<StyledInputDescription>
Is this segment tied to a specific project?
</StyledInputDescription>
<Autocomplete
size='small'
value={selectedProject}
onChange={(_, newValue) => {
setProject(newValue?.id);
}}
options={availableProjects}
getOptionLabel={(option) => option.name}
renderInput={(params) => (
<TextField {...params} label='Project' />
)}
disabled={projectsUsed.size > 1}
/>
<SegmentProjectAlert
projects={projects}
strategies={collectedStrategies}
projectsUsed={Array.from(projectsUsed)}
availableProjects={availableProjects}
/>
</>
}
/>
</StyledContainer>
<LimitContainer>
<Limit
name='segments'
limit={limit}
currentValue={currentCount}
/>
</LimitContainer>
<StyledButtonContainer>
<Button
type='button'
variant='contained'
color='primary'
onClick={() => setCurrentStep(2)}
disabled={
loading ||
limitReached ||
name.length === 0 ||
Boolean(errors.name)
}
data-testid={SEGMENT_NEXT_BTN_ID}
>
Next
</Button>
<StyledCancelButton
type='button'
onClick={() => {
navigate(GO_BACK);
}}
>
Cancel
</StyledCancelButton>
</StyledButtonContainer>
</StyledForm>
);
};