mirror of
https://github.com/Unleash/unleash.git
synced 2025-04-24 01:18:01 +02:00
feat: enable project creation through new form (#6961)
This PR allows very simple project creation. You can add a name and description. The ID is generated for you at the moment (we'll fix this later). Nothing else works, but the project is created successfully.
This commit is contained in:
parent
7754ac69df
commit
cdbe26330e
@ -103,7 +103,30 @@ const CreateProject = () => {
|
|||||||
documentationLinkLabel='Projects documentation'
|
documentationLinkLabel='Projects documentation'
|
||||||
formatApiCode={formatApiCode}
|
formatApiCode={formatApiCode}
|
||||||
>
|
>
|
||||||
<NewProjectForm />
|
<NewProjectForm
|
||||||
|
errors={errors}
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
projectId={projectId}
|
||||||
|
setProjectId={setProjectId}
|
||||||
|
projectName={projectName}
|
||||||
|
projectStickiness={projectStickiness}
|
||||||
|
projectMode={projectMode}
|
||||||
|
setProjectMode={setProjectMode}
|
||||||
|
setProjectStickiness={setProjectStickiness}
|
||||||
|
setProjectName={setProjectName}
|
||||||
|
projectDesc={projectDesc}
|
||||||
|
setProjectDesc={setProjectDesc}
|
||||||
|
mode='Create'
|
||||||
|
clearErrors={clearErrors}
|
||||||
|
validateProjectId={validateProjectId}
|
||||||
|
>
|
||||||
|
<StyledButton onClick={handleCancel}>Cancel</StyledButton>
|
||||||
|
<CreateButton
|
||||||
|
name='project'
|
||||||
|
permission={CREATE_PROJECT}
|
||||||
|
data-testid={CREATE_PROJECT_BTN}
|
||||||
|
/>
|
||||||
|
</NewProjectForm>
|
||||||
</FormTemplate>
|
</FormTemplate>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,7 @@
|
|||||||
import {
|
import { Button, Typography, styled } from '@mui/material';
|
||||||
Button,
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
MenuItem,
|
import Input from 'component/common/Input/Input';
|
||||||
Select,
|
import type { ProjectMode } from '../hooks/useProjectEnterpriseSettingsForm';
|
||||||
TextField,
|
|
||||||
Typography,
|
|
||||||
styled,
|
|
||||||
} from '@mui/material';
|
|
||||||
import { GO_BACK } from 'constants/navigate';
|
|
||||||
import { CreateButton } from 'component/common/CreateButton/CreateButton';
|
|
||||||
import { CREATE_PROJECT } from 'component/providers/AccessProvider/permissions';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
|
|
||||||
const StyledForm = styled('form')(({ theme }) => ({
|
const StyledForm = styled('form')(({ theme }) => ({
|
||||||
background: theme.palette.background.default,
|
background: theme.palette.background.default,
|
||||||
@ -26,8 +18,8 @@ const StyledFormSection = styled('div')(({ theme }) => ({
|
|||||||
const TopGrid = styled(StyledFormSection)(({ theme }) => ({
|
const TopGrid = styled(StyledFormSection)(({ theme }) => ({
|
||||||
display: 'grid',
|
display: 'grid',
|
||||||
gridTemplateAreas:
|
gridTemplateAreas:
|
||||||
'"icon header template" "icon project-name project-name" "icon description description"',
|
'"icon header" "icon project-name" "icon project-description"',
|
||||||
gridTemplateColumns: 'minmax(auto, 50px) 1fr auto',
|
gridTemplateColumns: 'minmax(auto, 50px) 1fr',
|
||||||
gap: theme.spacing(2),
|
gap: theme.spacing(2),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -42,23 +34,24 @@ const StyledHeader = styled(Typography)(({ theme }) => ({
|
|||||||
gridArea: 'header',
|
gridArea: 'header',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledTemplateSelector = styled(Select)(({ theme }) => ({
|
const ProjectNameContainer = styled('div')(({ theme }) => ({
|
||||||
gridArea: 'template',
|
gridArea: 'project-name',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledInput = styled(TextField)(({ theme }) => ({
|
const ProjectDescriptionContainer = styled('div')(({ theme }) => ({
|
||||||
|
gridArea: 'project-description',
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledInput = styled(Input)(({ theme }) => ({
|
||||||
width: '100%',
|
width: '100%',
|
||||||
margin: 0,
|
|
||||||
fieldset: { border: 'none' },
|
fieldset: { border: 'none' },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledProjectName = styled(StyledInput)(({ theme }) => ({
|
const StyledProjectName = styled(StyledInput)(({ theme }) => ({
|
||||||
gridArea: 'project-name',
|
|
||||||
'*': { fontSize: theme.typography.h1.fontSize },
|
'*': { fontSize: theme.typography.h1.fontSize },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledProjectDescription = styled(StyledInput)(({ theme }) => ({
|
const StyledProjectDescription = styled(StyledInput)(({ theme }) => ({
|
||||||
gridArea: 'description',
|
|
||||||
'*': { fontSize: theme.typography.h2.fontSize },
|
'*': { fontSize: theme.typography.h2.fontSize },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -73,33 +66,97 @@ const FormActions = styled(StyledFormSection)(({ theme }) => ({
|
|||||||
justifyContent: 'flex-end',
|
justifyContent: 'flex-end',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const CREATE_PROJECT_BTN = 'CREATE_PROJECT_BTN';
|
type FormProps = {
|
||||||
|
projectId: string;
|
||||||
|
projectName: string;
|
||||||
|
projectDesc: string;
|
||||||
|
projectStickiness?: string;
|
||||||
|
featureLimit?: string;
|
||||||
|
featureCount?: number;
|
||||||
|
projectMode?: string;
|
||||||
|
setProjectStickiness?: React.Dispatch<React.SetStateAction<string>>;
|
||||||
|
setProjectId: React.Dispatch<React.SetStateAction<string>>;
|
||||||
|
setProjectName: React.Dispatch<React.SetStateAction<string>>;
|
||||||
|
setProjectDesc: React.Dispatch<React.SetStateAction<string>>;
|
||||||
|
setFeatureLimit?: React.Dispatch<React.SetStateAction<string>>;
|
||||||
|
setProjectMode?: React.Dispatch<React.SetStateAction<ProjectMode>>;
|
||||||
|
handleSubmit: (e: any) => void;
|
||||||
|
errors: { [key: string]: string };
|
||||||
|
mode: 'Create' | 'Edit';
|
||||||
|
clearErrors: () => void;
|
||||||
|
validateProjectId: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
export const NewProjectForm = () => {
|
const PROJECT_NAME_INPUT = 'PROJECT_NAME_INPUT';
|
||||||
const navigate = useNavigate();
|
const PROJECT_DESCRIPTION_INPUT = 'PROJECT_DESCRIPTION_INPUT';
|
||||||
|
|
||||||
const handleCancel = () => {
|
export const NewProjectForm: React.FC<FormProps> = ({
|
||||||
navigate(GO_BACK);
|
children,
|
||||||
|
handleSubmit,
|
||||||
|
projectName,
|
||||||
|
projectDesc,
|
||||||
|
projectStickiness,
|
||||||
|
featureLimit,
|
||||||
|
featureCount,
|
||||||
|
projectMode,
|
||||||
|
setProjectMode,
|
||||||
|
setProjectId,
|
||||||
|
setProjectName,
|
||||||
|
setProjectDesc,
|
||||||
|
setProjectStickiness,
|
||||||
|
setFeatureLimit,
|
||||||
|
errors,
|
||||||
|
mode,
|
||||||
|
clearErrors,
|
||||||
|
}) => {
|
||||||
|
const handleProjectNameUpdate = (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement>,
|
||||||
|
) => {
|
||||||
|
const input = e.target.value;
|
||||||
|
setProjectName(input);
|
||||||
|
|
||||||
|
// todo: handle this in a real manner. This is a hack for now.
|
||||||
|
const maybeProjectId = input
|
||||||
|
? `${encodeURIComponent(input.trim())}-${uuidv4().slice(-12)}`
|
||||||
|
: '';
|
||||||
|
setProjectId(maybeProjectId);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledForm>
|
<StyledForm
|
||||||
|
onSubmit={(submitEvent) => {
|
||||||
|
handleSubmit(submitEvent);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<TopGrid>
|
<TopGrid>
|
||||||
<StyledIcon>icon</StyledIcon>
|
<StyledIcon>icon</StyledIcon>
|
||||||
<StyledHeader variant='h2'>New project</StyledHeader>
|
<StyledHeader variant='h2'>New project</StyledHeader>
|
||||||
<StyledTemplateSelector
|
<ProjectNameContainer>
|
||||||
id='template-selector'
|
<StyledProjectName
|
||||||
value={'none'}
|
label='Project name'
|
||||||
label='Project creation template'
|
required
|
||||||
name='Project creation template'
|
value={projectName}
|
||||||
>
|
onChange={handleProjectNameUpdate}
|
||||||
<MenuItem value={'none'}>No template</MenuItem>
|
error={Boolean(errors.name)}
|
||||||
</StyledTemplateSelector>
|
errorText={errors.name}
|
||||||
<StyledProjectName label='Project name' required />
|
onFocus={() => {
|
||||||
|
delete errors.name;
|
||||||
|
}}
|
||||||
|
data-testid={PROJECT_NAME_INPUT}
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
</ProjectNameContainer>
|
||||||
|
<ProjectDescriptionContainer>
|
||||||
<StyledProjectDescription
|
<StyledProjectDescription
|
||||||
|
className='description'
|
||||||
label='Description (optional)'
|
label='Description (optional)'
|
||||||
multiline
|
multiline
|
||||||
|
maxRows={20}
|
||||||
|
value={projectDesc}
|
||||||
|
onChange={(e) => setProjectDesc(e.target.value)}
|
||||||
|
data-testid={PROJECT_DESCRIPTION_INPUT}
|
||||||
/>
|
/>
|
||||||
|
</ProjectDescriptionContainer>
|
||||||
</TopGrid>
|
</TopGrid>
|
||||||
<OptionButtons>
|
<OptionButtons>
|
||||||
<Button variant='outlined'>4 selected</Button>
|
<Button variant='outlined'>4 selected</Button>
|
||||||
@ -107,15 +164,7 @@ export const NewProjectForm = () => {
|
|||||||
<Button variant='outlined'>Open</Button>
|
<Button variant='outlined'>Open</Button>
|
||||||
<Button variant='outlined'>1 environment configured</Button>
|
<Button variant='outlined'>1 environment configured</Button>
|
||||||
</OptionButtons>
|
</OptionButtons>
|
||||||
<FormActions>
|
<FormActions>{children}</FormActions>
|
||||||
<Button onClick={handleCancel}>Cancel</Button>
|
|
||||||
|
|
||||||
<CreateButton
|
|
||||||
name='project'
|
|
||||||
permission={CREATE_PROJECT}
|
|
||||||
data-testid={CREATE_PROJECT_BTN}
|
|
||||||
/>
|
|
||||||
</FormActions>
|
|
||||||
</StyledForm>
|
</StyledForm>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user