1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-10-27 11:02:16 +01:00

feat: allow adding project to segment (#3290)

https://linear.app/unleash/issue/2-741/add-project-dropdown-into-creation-of-segments

Allows users to bind a segment to a project when creating or editing a
segment.

<img width="1051" alt="image"
src="https://user-images.githubusercontent.com/14320932/224103846-1fe1f849-496c-4a77-9831-53bcb36f822e.png">
This commit is contained in:
Nuno Góis 2023-03-10 08:16:54 +00:00 committed by GitHub
parent 9b563f60e6
commit ff7185fe5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 66 additions and 2 deletions

View File

@ -30,6 +30,8 @@ export const CreateSegment = () => {
setName, setName,
description, description,
setDescription, setDescription,
project,
setProject,
constraints, constraints,
setConstraints, setConstraints,
getSegmentPayload, getSegmentPayload,
@ -91,6 +93,8 @@ export const CreateSegment = () => {
setName={setName} setName={setName}
description={description} description={description}
setDescription={setDescription} setDescription={setDescription}
project={project}
setProject={setProject}
constraints={constraints} constraints={constraints}
setConstraints={setConstraints} setConstraints={setConstraints}
errors={errors} errors={errors}

View File

@ -33,6 +33,8 @@ export const EditSegment = () => {
setName, setName,
description, description,
setDescription, setDescription,
project,
setProject,
constraints, constraints,
setConstraints, setConstraints,
getSegmentPayload, getSegmentPayload,
@ -41,6 +43,7 @@ export const EditSegment = () => {
} = useSegmentForm( } = useSegmentForm(
segment?.name, segment?.name,
segment?.description, segment?.description,
segment?.project,
segment?.constraints segment?.constraints
); );
@ -94,6 +97,8 @@ export const EditSegment = () => {
setName={setName} setName={setName}
description={description} description={description}
setDescription={setDescription} setDescription={setDescription}
project={project}
setProject={setProject}
constraints={constraints} constraints={constraints}
setConstraints={setConstraints} setConstraints={setConstraints}
errors={errors} errors={errors}

View File

@ -12,9 +12,11 @@ export type SegmentFormMode = 'create' | 'edit';
interface ISegmentProps { interface ISegmentProps {
name: string; name: string;
description: string; description: string;
project: string | null;
constraints: IConstraint[]; constraints: IConstraint[];
setName: React.Dispatch<React.SetStateAction<string>>; setName: React.Dispatch<React.SetStateAction<string>>;
setDescription: React.Dispatch<React.SetStateAction<string>>; setDescription: React.Dispatch<React.SetStateAction<string>>;
setProject: React.Dispatch<React.SetStateAction<string | null>>;
setConstraints: React.Dispatch<React.SetStateAction<IConstraint[]>>; setConstraints: React.Dispatch<React.SetStateAction<IConstraint[]>>;
handleSubmit: (e: any) => void; handleSubmit: (e: any) => void;
errors: { [key: string]: string }; errors: { [key: string]: string };
@ -32,9 +34,11 @@ export const SegmentForm: React.FC<ISegmentProps> = ({
children, children,
name, name,
description, description,
project,
constraints, constraints,
setName, setName,
setDescription, setDescription,
setProject,
setConstraints, setConstraints,
handleSubmit, handleSubmit,
errors, errors,
@ -54,8 +58,10 @@ export const SegmentForm: React.FC<ISegmentProps> = ({
<SegmentFormStepOne <SegmentFormStepOne
name={name} name={name}
description={description} description={description}
project={project}
setName={setName} setName={setName}
setDescription={setDescription} setDescription={setDescription}
setProject={setProject}
errors={errors} errors={errors}
clearErrors={clearErrors} clearErrors={clearErrors}
setCurrentStep={setCurrentStep} setCurrentStep={setCurrentStep}

View File

@ -1,6 +1,6 @@
import { Button, styled } from '@mui/material'; import { Autocomplete, Button, styled, TextField } from '@mui/material';
import Input from 'component/common/Input/Input'; import Input from 'component/common/Input/Input';
import React from 'react'; import React, { useEffect } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { SegmentFormStep } from './SegmentForm'; import { SegmentFormStep } from './SegmentForm';
import { import {
@ -8,12 +8,17 @@ import {
SEGMENT_DESC_ID, SEGMENT_DESC_ID,
SEGMENT_NEXT_BTN_ID, SEGMENT_NEXT_BTN_ID,
} from 'utils/testIds'; } from 'utils/testIds';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import useProjects from 'hooks/api/getters/useProjects/useProjects';
interface ISegmentFormPartOneProps { interface ISegmentFormPartOneProps {
name: string; name: string;
description: string; description: string;
project: string | null;
setName: React.Dispatch<React.SetStateAction<string>>; setName: React.Dispatch<React.SetStateAction<string>>;
setDescription: React.Dispatch<React.SetStateAction<string>>; setDescription: React.Dispatch<React.SetStateAction<string>>;
setProject: React.Dispatch<React.SetStateAction<string | null>>;
errors: { [key: string]: string }; errors: { [key: string]: string };
clearErrors: () => void; clearErrors: () => void;
setCurrentStep: React.Dispatch<React.SetStateAction<SegmentFormStep>>; setCurrentStep: React.Dispatch<React.SetStateAction<SegmentFormStep>>;
@ -52,13 +57,25 @@ export const SegmentFormStepOne: React.FC<ISegmentFormPartOneProps> = ({
children, children,
name, name,
description, description,
project,
setName, setName,
setDescription, setDescription,
setProject,
errors, errors,
clearErrors, clearErrors,
setCurrentStep, setCurrentStep,
}) => { }) => {
const { uiConfig } = useUiConfig();
const navigate = useNavigate(); const navigate = useNavigate();
const { projects } = useProjects();
const [selectedProject, setSelectedProject] = React.useState(
projects.find(({ id }) => id === project) ?? null
);
useEffect(() => {
setSelectedProject(projects.find(({ id }) => id === project) ?? null);
}, [project, projects]);
return ( return (
<StyledForm> <StyledForm>
@ -87,6 +104,28 @@ export const SegmentFormStepOne: React.FC<ISegmentFormPartOneProps> = ({
errorText={errors.description} errorText={errors.description}
data-testid={SEGMENT_DESC_ID} data-testid={SEGMENT_DESC_ID}
/> />
<ConditionallyRender
condition={Boolean(uiConfig.flags.projectScopedSegments)}
show={
<>
<StyledInputDescription>
Is this segment tied to a specific project?
</StyledInputDescription>
<Autocomplete
size="small"
value={selectedProject}
onChange={(_, newValue) => {
setProject(newValue?.id ?? null);
}}
options={projects}
getOptionLabel={option => option.name}
renderInput={params => (
<TextField {...params} label="Project" />
)}
/>
</>
}
/>
</StyledContainer> </StyledContainer>
<StyledButtonContainer> <StyledButtonContainer>
<Button <Button

View File

@ -5,10 +5,12 @@ import { useSegmentValidation } from 'hooks/api/getters/useSegmentValidation/use
export const useSegmentForm = ( export const useSegmentForm = (
initialName = '', initialName = '',
initialDescription = '', initialDescription = '',
initialProject: string | null = null,
initialConstraints: IConstraint[] = [] initialConstraints: IConstraint[] = []
) => { ) => {
const [name, setName] = useState(initialName); const [name, setName] = useState(initialName);
const [description, setDescription] = useState(initialDescription); const [description, setDescription] = useState(initialDescription);
const [project, setProject] = useState<string | null>(initialProject);
const [constraints, setConstraints] = const [constraints, setConstraints] =
useState<IConstraint[]>(initialConstraints); useState<IConstraint[]>(initialConstraints);
const [errors, setErrors] = useState({}); const [errors, setErrors] = useState({});
@ -22,6 +24,10 @@ export const useSegmentForm = (
setDescription(initialDescription); setDescription(initialDescription);
}, [initialDescription]); }, [initialDescription]);
useEffect(() => {
setProject(initialProject);
}, [initialProject]);
useEffect(() => { useEffect(() => {
setConstraints(initialConstraints); setConstraints(initialConstraints);
// eslint-disable-next-line // eslint-disable-next-line
@ -38,6 +44,7 @@ export const useSegmentForm = (
return { return {
name, name,
description, description,
project,
constraints, constraints,
}; };
}; };
@ -51,6 +58,8 @@ export const useSegmentForm = (
setName, setName,
description, description,
setDescription, setDescription,
project,
setProject,
constraints, constraints,
setConstraints, setConstraints,
getSegmentPayload, getSegmentPayload,

View File

@ -4,6 +4,7 @@ export interface ISegment {
id: number; id: number;
name: string; name: string;
description: string; description: string;
project: string | null;
createdAt: string; createdAt: string;
createdBy: string; createdBy: string;
constraints: IConstraint[]; constraints: IConstraint[];