mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-19 00:15:43 +01:00
Show usage in change requests if that'd cause you to not be able to move the segment into a project. - [x] ~Relies on changes from #5407 (and #5405, #5406) to go through first.~ 
191 lines
6.7 KiB
TypeScript
191 lines
6.7 KiB
TypeScript
import { Autocomplete, 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 { 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 {
|
|
ChangeRequestNewStrategy,
|
|
ChangeRequestUpdatedStrategy,
|
|
useStrategiesBySegment,
|
|
} from 'hooks/api/getters/useStrategiesBySegment/useStrategiesBySegment';
|
|
import { SegmentProjectAlert } from './SegmentProjectAlert';
|
|
import { sortStrategiesByFeature } from './SegmentDelete/SegmentDeleteUsedSegment/sort-strategies';
|
|
import { IFeatureStrategy } from 'interfaces/strategy';
|
|
|
|
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')(({ theme }) => ({
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
height: '100%',
|
|
}));
|
|
|
|
const StyledContainer = styled('div')(({ theme }) => ({
|
|
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')(({ theme }) => ({
|
|
marginTop: 'auto',
|
|
display: 'flex',
|
|
justifyContent: 'flex-end',
|
|
}));
|
|
|
|
const StyledCancelButton = styled(Button)(({ theme }) => ({
|
|
marginLeft: theme.spacing(3),
|
|
}));
|
|
|
|
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 {
|
|
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;
|
|
|
|
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>
|
|
<StyledButtonContainer>
|
|
<Button
|
|
type='button'
|
|
variant='contained'
|
|
color='primary'
|
|
onClick={() => setCurrentStep(2)}
|
|
disabled={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>
|
|
);
|
|
};
|