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:
parent
f49cc8cd33
commit
43878230b7
@ -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 don’t 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 don’t 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 don’t 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 don’t 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>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user