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