1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

UI: make project settings / creation form full-width (#4675)

This PR makes the project settings / creation forms grow to take up the
full available width, so that it is in line with the new designs.
This commit is contained in:
Thomas Heartman 2023-09-13 08:38:18 +02:00 committed by GitHub
parent f49cc8cd33
commit 43878230b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -44,16 +44,10 @@ const PROJECT_NAME_INPUT = 'PROJECT_NAME_INPUT';
const PROJECT_DESCRIPTION_INPUT = 'PROJECT_DESCRIPTION_INPUT';
const StyledForm = styled('form')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
height: '100%',
paddingBottom: theme.spacing(4),
}));
const StyledContainer = styled('div')(() => ({
maxWidth: '400px',
}));
const StyledDescription = styled('p')(({ theme }) => ({
marginBottom: theme.spacing(1),
marginRight: theme.spacing(1),
@ -215,243 +209,234 @@ const ProjectForm: React.FC<IProjectForm> = ({
return (
<StyledForm onSubmit={handleSubmit}>
<StyledContainer>
<StyledDescription>What is your project Id?</StyledDescription>
<StyledInput
label="Project Id"
value={projectId}
onChange={e => setProjectId(trim(e.target.value))}
error={Boolean(errors.id)}
errorText={errors.id}
onFocus={() => clearErrors()}
onBlur={validateProjectId}
disabled={mode === 'Edit'}
data-testid={PROJECT_ID_INPUT}
autoFocus
required
/>
<StyledDescription>What is your project Id?</StyledDescription>
<StyledInput
label="Project Id"
value={projectId}
onChange={e => setProjectId(trim(e.target.value))}
error={Boolean(errors.id)}
errorText={errors.id}
onFocus={() => clearErrors()}
onBlur={validateProjectId}
disabled={mode === 'Edit'}
data-testid={PROJECT_ID_INPUT}
autoFocus
required
/>
<StyledDescription>
What is your project name?
</StyledDescription>
<StyledInput
label="Project name"
value={projectName}
onChange={e => setProjectName(e.target.value)}
error={Boolean(errors.name)}
errorText={errors.name}
onFocus={() => {
delete errors.name;
<StyledDescription>What is your project name?</StyledDescription>
<StyledInput
label="Project name"
value={projectName}
onChange={e => setProjectName(e.target.value)}
error={Boolean(errors.name)}
errorText={errors.name}
onFocus={() => {
delete errors.name;
}}
data-testid={PROJECT_NAME_INPUT}
required
/>
<StyledDescription>
What is your project description?
</StyledDescription>
<StyledTextField
label="Project description"
variant="outlined"
multiline
maxRows={4}
value={projectDesc}
onChange={e => setProjectDesc(e.target.value)}
data-testid={PROJECT_DESCRIPTION_INPUT}
/>
<ConditionallyRender
condition={setProjectStickiness != null}
show={
<>
<StyledDescription>
What is the default stickiness for the project?
</StyledDescription>
<StickinessSelect
label="Stickiness"
value={projectStickiness}
data-testid={PROJECT_STICKINESS_SELECT}
onChange={e =>
setProjectStickiness &&
setProjectStickiness(e.target.value)
}
editable
/>
</>
}
/>
<>
<Box
sx={{
display: 'flex',
alignItems: 'center',
marginBottom: 1,
gap: 1,
}}
data-testid={PROJECT_NAME_INPUT}
required
/>
<StyledDescription>
What is your project description?
</StyledDescription>
<StyledTextField
label="Project description"
variant="outlined"
multiline
maxRows={4}
value={projectDesc}
onChange={e => setProjectDesc(e.target.value)}
data-testid={PROJECT_DESCRIPTION_INPUT}
/>
<ConditionallyRender
condition={setProjectStickiness != null}
show={
<>
<StyledDescription>
What is the default stickiness for the project?
</StyledDescription>
<StickinessSelect
label="Stickiness"
value={projectStickiness}
data-testid={PROJECT_STICKINESS_SELECT}
onChange={e =>
setProjectStickiness &&
setProjectStickiness(e.target.value)
}
editable
/>
</>
}
/>
<>
<Box
sx={{
display: 'flex',
alignItems: 'center',
marginBottom: 1,
gap: 1,
}}
>
<p>What is your project collaboration mode?</p>
<CollaborationModeTooltip />
</Box>
<StyledSelect
id="project-mode"
value={projectMode}
label="Project collaboration mode"
name="Project collaboration mode"
onChange={e => {
setProjectMode?.(e.target.value as ProjectMode);
}}
options={[
{ key: 'open', label: 'open' },
{ key: 'protected', label: 'protected' },
]}
></StyledSelect>
</>
<>
<Box
sx={{
display: 'flex',
alignItems: 'center',
marginBottom: 1,
gap: 1,
}}
>
<p>Feature flag limit?</p>
<FeatureTogglesLimitTooltip />
</Box>
<StyledSubtitle>
Leave it empty if you dont want to add a limit
</StyledSubtitle>
<StyledInputContainer>
<StyledInput
label={'Limit'}
name="value"
type={'number'}
value={featureLimit}
onChange={e => setFeatureLimit(e.target.value)}
/>
<ConditionallyRender
condition={
featureCount !== undefined &&
Boolean(featureLimit)
}
show={
<Box>
({featureCount} of {featureLimit} used)
</Box>
}
/>
</StyledInputContainer>
</>
<ConditionallyRender
condition={Boolean(shouldShowFlagNaming)}
show={
<StyledFieldset>
<Box
sx={{
display: 'flex',
alignItems: 'center',
marginBottom: 1,
gap: 1,
}}
>
<legend>Feature flag naming pattern?</legend>
<FeatureFlagNamingTooltip />
>
<p>What is your project collaboration mode?</p>
<CollaborationModeTooltip />
</Box>
<StyledSelect
id="project-mode"
value={projectMode}
label="Project collaboration mode"
name="Project collaboration mode"
onChange={e => {
setProjectMode?.(e.target.value as ProjectMode);
}}
options={[
{ key: 'open', label: 'open' },
{ key: 'protected', label: 'protected' },
]}
></StyledSelect>
</>
<>
<Box
sx={{
display: 'flex',
alignItems: 'center',
marginBottom: 1,
gap: 1,
}}
>
<p>Feature flag limit?</p>
<FeatureTogglesLimitTooltip />
</Box>
<StyledSubtitle>
Leave it empty if you dont want to add a limit
</StyledSubtitle>
<StyledInputContainer>
<StyledInput
label={'Limit'}
name="value"
type={'number'}
value={featureLimit}
onChange={e => setFeatureLimit(e.target.value)}
/>
<ConditionallyRender
condition={
featureCount !== undefined && Boolean(featureLimit)
}
show={
<Box>
({featureCount} of {featureLimit} used)
</Box>
}
/>
</StyledInputContainer>
</>
<ConditionallyRender
condition={Boolean(shouldShowFlagNaming)}
show={
<StyledFieldset>
<Box
sx={{
display: 'flex',
alignItems: 'center',
marginBottom: 1,
gap: 1,
}}
>
<legend>Feature flag naming pattern?</legend>
<FeatureFlagNamingTooltip />
</Box>
<StyledSubtitle>
<StyledPatternNamingExplanation id="pattern-naming-description">
<p>
Define a{' '}
<a
href={`https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions`}
target="_blank"
rel="noreferrer"
>
JavaScript RegEx
</a>{' '}
used to enforce feature flag names within
this project. The regex will be surrounded
by a leading <code>^</code> and a trailing{' '}
<code>$</code>.
</p>
<p>
Leave it empty if you dont want to add a
naming pattern.
</p>
</StyledPatternNamingExplanation>
</StyledSubtitle>
<StyledFlagNamingContainer>
<StyledInput
label={'Naming Pattern'}
name="feature flag naming pattern"
aria-describedby="pattern-naming-description"
placeholder="[A-Za-z]+\.[A-Za-z]+\.[A-Za-z0-9-]+"
InputProps={{
startAdornment: (
<InputAdornment position="start">
^
</InputAdornment>
),
endAdornment: (
<InputAdornment position="end">
$
</InputAdornment>
),
}}
type={'text'}
value={featureNamingPattern || ''}
error={Boolean(errors.featureNamingPattern)}
errorText={errors.featureNamingPattern}
onChange={e =>
onSetFeatureNamingPattern(e.target.value)
}
/>
<StyledSubtitle>
<StyledPatternNamingExplanation id="pattern-naming-description">
<p>
Define a{' '}
<a
href={`https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions`}
target="_blank"
rel="noreferrer"
>
JavaScript RegEx
</a>{' '}
used to enforce feature flag names
within this project. The regex will be
surrounded by a leading <code>^</code>{' '}
and a trailing <code>$</code>.
</p>
<p>
Leave it empty if you dont want to add
a naming pattern.
</p>
</StyledPatternNamingExplanation>
<p id="pattern-additional-description">
The example and description will be shown to
users when they create a new feature flag in
this project.
</p>
</StyledSubtitle>
<StyledFlagNamingContainer>
<StyledInput
label={'Naming Pattern'}
name="feature flag naming pattern"
aria-describedby="pattern-naming-description"
placeholder="[A-Za-z]+\.[A-Za-z]+\.[A-Za-z0-9-]+"
InputProps={{
startAdornment: (
<InputAdornment position="start">
^
</InputAdornment>
),
endAdornment: (
<InputAdornment position="end">
$
</InputAdornment>
),
}}
type={'text'}
value={featureNamingPattern || ''}
error={Boolean(errors.featureNamingPattern)}
errorText={errors.featureNamingPattern}
onChange={e =>
onSetFeatureNamingPattern(
e.target.value
)
}
/>
<StyledSubtitle>
<p id="pattern-additional-description">
The example and description will be
shown to users when they create a new
feature flag in this project.
</p>
</StyledSubtitle>
<StyledInput
label={'Naming Example'}
name="feature flag naming example"
type={'text'}
aria-describedby="pattern-additional-description"
value={featureNamingExample || ''}
placeholder="dx.feature1.1-135"
error={Boolean(errors.namingExample)}
errorText={errors.namingExample}
onChange={e =>
onSetFeatureNamingExample(
e.target.value
)
}
/>
<StyledTextField
label={'Naming pattern description'}
name="feature flag naming description"
type={'text'}
aria-describedby="pattern-additional-description"
placeholder={`<project>.<featureName>.<ticket>
<StyledInput
label={'Naming Example'}
name="feature flag naming example"
type={'text'}
aria-describedby="pattern-additional-description"
value={featureNamingExample || ''}
placeholder="dx.feature1.1-135"
error={Boolean(errors.namingExample)}
errorText={errors.namingExample}
onChange={e =>
onSetFeatureNamingExample(e.target.value)
}
/>
<StyledTextField
label={'Naming pattern description'}
name="feature flag naming description"
type={'text'}
aria-describedby="pattern-additional-description"
placeholder={`<project>.<featureName>.<ticket>
The flag name should contain the project name, the feature name, and the ticket number, each separated by a dot.`}
multiline
minRows={5}
value={featureNamingDescription || ''}
onChange={e =>
onSetFeatureNamingDescription(
e.target.value
)
}
/>
</StyledFlagNamingContainer>
</StyledFieldset>
}
/>
</StyledContainer>
multiline
minRows={5}
value={featureNamingDescription || ''}
onChange={e =>
onSetFeatureNamingDescription(
e.target.value
)
}
/>
</StyledFlagNamingContainer>
</StyledFieldset>
}
/>
<StyledButtonContainer>{children}</StyledButtonContainer>
</StyledForm>
);