mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +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:
		
							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