1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-01 00:08:27 +01:00

fix: display feature naming patterns in dialog (#7837)

Updates the dialog form template to include a `namingPattern` prop that
can be used to display the naming pattern of whatever the form is used
for.

Also updates the create feature dialog to display the naming pattern in
the current project.

The naming pattern component re-uses the pattern that we have in place
for feature naming patterns, but puts it in an expandable dialog
instead.

Screenies:

Naming pattern closed:

![image](https://github.com/user-attachments/assets/145e4268-1aa0-4c1b-8f08-97857447e2f5)


![image](https://github.com/user-attachments/assets/1613c846-e7d4-41c8-a1c8-a66ab87b6e5f)



Naming pattern open:

![image](https://github.com/user-attachments/assets/1aa37162-500b-4b83-926f-07aa777e8017)
This commit is contained in:
Thomas Heartman 2024-08-12 13:56:07 +02:00
parent 6f9492ef12
commit bc1f261cf2
No known key found for this signature in database
GPG Key ID: BD1F880DAED1EE78
4 changed files with 115 additions and 9 deletions

View File

@ -33,11 +33,14 @@ export const StyledHeader = styled(Typography)({
fontWeight: 'lighter', fontWeight: 'lighter',
}); });
export const ProjectNameContainer = styled('div')({ export const NameContainer = styled('div')(({ theme }) => ({
gridArea: 'project-name', gridArea: 'project-name',
}); display: 'flex',
flexFlow: 'column nowrap',
gap: theme.spacing(2),
}));
export const ProjectDescriptionContainer = styled('div')({ export const DescriptionContainer = styled('div')({
gridArea: 'project-description', gridArea: 'project-description',
}); });

View File

@ -2,8 +2,8 @@ import type { FormEventHandler } from 'react';
import theme from 'themes/theme'; import theme from 'themes/theme';
import { import {
ConfigButtons, ConfigButtons,
ProjectDescriptionContainer, DescriptionContainer,
ProjectNameContainer, NameContainer,
StyledForm, StyledForm,
StyledHeader, StyledHeader,
StyledInput, StyledInput,
@ -15,6 +15,11 @@ import {
import { Button } from '@mui/material'; import { Button } from '@mui/material';
import { CreateButton } from 'component/common/CreateButton/CreateButton'; import { CreateButton } from 'component/common/CreateButton/CreateButton';
import type { IPermissionButtonProps } from 'component/common/PermissionButton/PermissionButton'; import type { IPermissionButtonProps } from 'component/common/PermissionButton/PermissionButton';
import type { FeatureNamingType } from 'interfaces/project';
import { ConditionallyRender } from '../ConditionallyRender/ConditionallyRender';
import { NamingPatternInfo } from './NamingPatternInfo';
type NamingPattern = FeatureNamingType;
type FormProps = { type FormProps = {
createButtonProps: IPermissionButtonProps; createButtonProps: IPermissionButtonProps;
@ -30,12 +35,14 @@ type FormProps = {
setDescription: (newDescription: string) => void; setDescription: (newDescription: string) => void;
setName: (newName: string) => void; setName: (newName: string) => void;
validateName?: () => void; validateName?: () => void;
namingPattern?: NamingPattern;
}; };
export const DialogFormTemplate: React.FC<FormProps> = ({ export const DialogFormTemplate: React.FC<FormProps> = ({
Limit, Limit,
handleSubmit, handleSubmit,
name, name,
namingPattern,
setName, setName,
description, description,
setDescription, setDescription,
@ -47,15 +54,22 @@ export const DialogFormTemplate: React.FC<FormProps> = ({
createButtonProps, createButtonProps,
validateName = () => {}, validateName = () => {},
}) => { }) => {
const displayNamingPattern = Boolean(namingPattern?.pattern);
return ( return (
<StyledForm onSubmit={handleSubmit}> <StyledForm onSubmit={handleSubmit}>
<TopGrid> <TopGrid>
<IconWrapper>{Icon}</IconWrapper> <IconWrapper>{Icon}</IconWrapper>
<StyledHeader variant='h2'>Create {resource}</StyledHeader> <StyledHeader variant='h2'>Create {resource}</StyledHeader>
<ProjectNameContainer> <NameContainer>
<StyledInput <StyledInput
label={`${resource} name`} label={`${resource} name`}
aria-required aria-required
aria-details={
displayNamingPattern
? 'naming-pattern-info'
: undefined
}
value={name} value={name}
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}
error={Boolean(errors.name)} error={Boolean(errors.name)}
@ -74,8 +88,13 @@ export const DialogFormTemplate: React.FC<FormProps> = ({
data-testid='FORM_NAME_INPUT' data-testid='FORM_NAME_INPUT'
size='medium' size='medium'
/> />
</ProjectNameContainer>
<ProjectDescriptionContainer> <ConditionallyRender
condition={displayNamingPattern}
show={<NamingPatternInfo naming={namingPattern!} />}
/>
</NameContainer>
<DescriptionContainer>
<StyledInput <StyledInput
size='medium' size='medium'
className='description' className='description'
@ -92,7 +111,7 @@ export const DialogFormTemplate: React.FC<FormProps> = ({
}} }}
data-testid='FORM_DESCRIPTION_INPUT' data-testid='FORM_DESCRIPTION_INPUT'
/> />
</ProjectDescriptionContainer> </DescriptionContainer>
</TopGrid> </TopGrid>
<ConfigButtons>{configButtons}</ConfigButtons> <ConfigButtons>{configButtons}</ConfigButtons>

View File

@ -0,0 +1,83 @@
import {
Accordion,
AccordionDetails,
AccordionSummary,
styled,
} from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import type { FeatureNamingType } from 'interfaces/project';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
const StyledFlagNamingInfo = styled('article')(({ theme }) => ({
fontSize: theme.typography.body2.fontSize,
borderRadius: theme.shape.borderRadius,
marginInlineStart: theme.spacing(1.5),
backgroundColor: `${theme.palette.background.elevation2}`,
dl: {
display: 'grid',
gridTemplateColumns: 'max-content auto',
rowGap: theme.spacing(1),
columnGap: 0,
},
dt: {
color: theme.palette.text.secondary,
'&::after': { content: '":"' },
},
dd: {
marginInlineStart: theme.spacing(2),
},
}));
const StyledAccordion = styled(Accordion)(({ theme }) => ({
backgroundColor: 'inherit',
boxShadow: 'none',
margin: 0,
}));
type Props = {
naming: FeatureNamingType;
};
export const NamingPatternInfo: React.FC<Props> = ({ naming }) => {
const controlId = 'naming-pattern-info-summary';
return (
<StyledFlagNamingInfo>
<StyledAccordion>
<AccordionSummary
id={controlId}
aria-controls={controlId}
expandIcon={<ExpandMoreIcon />}
>
Name must match:&nbsp;<code>^{naming.pattern}$</code>
</AccordionSummary>
<AccordionDetails>
<p>The name must match this pattern:</p>
<dl id='naming-pattern-info'>
<dt>Pattern</dt>
<dd>
<code>^{naming.pattern}$</code>
</dd>
<ConditionallyRender
condition={Boolean(naming?.example)}
show={
<>
<dt>Example</dt>
<dd>{naming?.example}</dd>
</>
}
/>
<ConditionallyRender
condition={Boolean(naming?.description)}
show={
<>
<dt>Description</dt>
<dd>{naming?.description}</dd>
</>
}
/>
</dl>
</AccordionDetails>
</StyledAccordion>
</StyledFlagNamingInfo>
);
};

View File

@ -227,6 +227,7 @@ const CreateFeatureDialogContent = ({
tooltipProps: { title: limitMessage, arrow: true }, tooltipProps: { title: limitMessage, arrow: true },
}} }}
description={description} description={description}
namingPattern={projectInfo.featureNaming}
errors={errors} errors={errors}
handleSubmit={handleSubmit} handleSubmit={handleSubmit}
Icon={<FlagIcon />} Icon={<FlagIcon />}