mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +01:00
ui: update design for feature naming pattern info (#4656)
This PR updates the design for the feature naming pattern info. In doing so, I've extracted the information into a single component. It also, on @nicolaesocaciu's behest, makes the new toggle form inputs wider when they have room to grow. Light mode: ![image](https://github.com/Unleash/unleash/assets/17786332/0923cf95-18e3-4524-8402-7f42a0ac94ec) Dark mode: ![image](https://github.com/Unleash/unleash/assets/17786332/c2a07f73-8973-42d0-b94a-d7dc4ec38a25) For copying features it looks like this: ![image](https://github.com/Unleash/unleash/assets/17786332/2a39f17b-4d86-408c-8f3b-5f2b24e82c81)
This commit is contained in:
parent
c39d815516
commit
03d6ed0c32
@ -20,6 +20,7 @@ import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
|||||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||||
import { useChangeRequestsEnabled } from '../../../hooks/useChangeRequestsEnabled';
|
import { useChangeRequestsEnabled } from '../../../hooks/useChangeRequestsEnabled';
|
||||||
import useProject from 'hooks/api/getters/useProject/useProject';
|
import useProject from 'hooks/api/getters/useProject/useProject';
|
||||||
|
import { FeatureNamingPatternInfo } from '../FeatureNamingPatternInfo/FeatureNamingPatternInfo';
|
||||||
|
|
||||||
const StyledPage = styled(Paper)(({ theme }) => ({
|
const StyledPage = styled(Paper)(({ theme }) => ({
|
||||||
overflow: 'visible',
|
overflow: 'visible',
|
||||||
@ -141,41 +142,9 @@ export const CopyFeatureToggle = () => {
|
|||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={displayFeatureNamingInfo}
|
condition={displayFeatureNamingInfo}
|
||||||
show={
|
show={
|
||||||
<>
|
<FeatureNamingPatternInfo
|
||||||
<p>
|
featureNaming={featureNaming!}
|
||||||
This project has feature flag naming patterns
|
/>
|
||||||
enabled, so the name must also match the
|
|
||||||
configured pattern.
|
|
||||||
</p>
|
|
||||||
<dl id="feature-naming-pattern-info">
|
|
||||||
<dt>Pattern</dt>
|
|
||||||
<dd>
|
|
||||||
<code>{featureNaming?.pattern}</code>
|
|
||||||
</dd>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(featureNaming?.example)}
|
|
||||||
show={
|
|
||||||
<>
|
|
||||||
<dt>Example</dt>
|
|
||||||
<dd>{featureNaming?.example}</dd>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={Boolean(
|
|
||||||
featureNaming?.description
|
|
||||||
)}
|
|
||||||
show={
|
|
||||||
<>
|
|
||||||
<dt>Description</dt>
|
|
||||||
<dd>
|
|
||||||
{featureNaming?.description}
|
|
||||||
</dd>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</dl>
|
|
||||||
</>
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<StyledForm onSubmit={onSubmit}>
|
<StyledForm onSubmit={onSubmit}>
|
||||||
|
@ -22,6 +22,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useAuthPermissions } from 'hooks/api/getters/useAuth/useAuthPermissions';
|
import { useAuthPermissions } from 'hooks/api/getters/useAuth/useAuthPermissions';
|
||||||
import { FeatureNamingType } from 'interfaces/project';
|
import { FeatureNamingType } from 'interfaces/project';
|
||||||
|
import { FeatureNamingPatternInfo } from '../FeatureNamingPatternInfo/FeatureNamingPatternInfo';
|
||||||
|
|
||||||
interface IFeatureToggleForm {
|
interface IFeatureToggleForm {
|
||||||
type: string;
|
type: string;
|
||||||
@ -44,15 +45,9 @@ interface IFeatureToggleForm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const StyledForm = styled('form')({
|
const StyledForm = styled('form')({
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
height: '100%',
|
height: '100%',
|
||||||
});
|
});
|
||||||
|
|
||||||
const StyledContainer = styled('div')({
|
|
||||||
maxWidth: '400px',
|
|
||||||
});
|
|
||||||
|
|
||||||
const StyledInputDescription = styled('p')(({ theme }) => ({
|
const StyledInputDescription = styled('p')(({ theme }) => ({
|
||||||
marginBottom: theme.spacing(1),
|
marginBottom: theme.spacing(1),
|
||||||
}));
|
}));
|
||||||
@ -82,11 +77,6 @@ const StyledTypeDescription = styled('p')(({ theme }) => ({
|
|||||||
position: 'relative',
|
position: 'relative',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledFlagNamingInfo = styled('div')(({ theme }) => ({
|
|
||||||
fontSize: theme.fontSizes.smallBody,
|
|
||||||
color: theme.palette.text.secondary,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledButtonContainer = styled('div')({
|
const StyledButtonContainer = styled('div')({
|
||||||
marginTop: 'auto',
|
marginTop: 'auto',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -147,156 +137,121 @@ const FeatureForm: React.FC<IFeatureToggleForm> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledForm onSubmit={handleSubmit}>
|
<StyledForm onSubmit={handleSubmit}>
|
||||||
<StyledContainer>
|
<StyledInputDescription>
|
||||||
<StyledInputDescription>
|
What would you like to call your toggle?
|
||||||
What would you like to call your toggle?
|
</StyledInputDescription>
|
||||||
</StyledInputDescription>
|
<ConditionallyRender
|
||||||
<ConditionallyRender
|
condition={displayFeatureNamingInfo}
|
||||||
condition={displayFeatureNamingInfo}
|
show={
|
||||||
show={
|
<FeatureNamingPatternInfo featureNaming={featureNaming!} />
|
||||||
<StyledFlagNamingInfo>
|
}
|
||||||
<p>
|
/>
|
||||||
This project has feature flag naming patterns
|
<StyledInput
|
||||||
enabled.
|
autoFocus
|
||||||
</p>
|
disabled={mode === 'Edit'}
|
||||||
<dl id="feature-naming-pattern-info">
|
label="Name"
|
||||||
<dt>Pattern</dt>
|
aria-details={
|
||||||
<dd>
|
displayFeatureNamingInfo
|
||||||
<code>{featureNaming?.pattern}</code>
|
? 'feature-naming-pattern-info'
|
||||||
</dd>
|
: undefined
|
||||||
<ConditionallyRender
|
}
|
||||||
condition={Boolean(featureNaming?.example)}
|
id="feature-toggle-name"
|
||||||
show={
|
error={Boolean(errors.name)}
|
||||||
<>
|
errorText={errors.name}
|
||||||
<dt>Example</dt>
|
onFocus={() => clearErrors()}
|
||||||
<dd>{featureNaming?.example}</dd>
|
value={name}
|
||||||
</>
|
onChange={e => setName(trim(e.target.value))}
|
||||||
}
|
data-testid={CF_NAME_ID}
|
||||||
/>
|
onBlur={validateToggleName}
|
||||||
<ConditionallyRender
|
/>
|
||||||
condition={Boolean(
|
<StyledInputDescription>
|
||||||
featureNaming?.description
|
What kind of feature toggle do you want?
|
||||||
)}
|
</StyledInputDescription>
|
||||||
show={
|
<FeatureTypeSelect
|
||||||
<>
|
sx={styledSelectInput}
|
||||||
<dt>Description</dt>
|
value={type}
|
||||||
<dd>
|
onChange={setType}
|
||||||
{featureNaming?.description}
|
label={'Toggle type'}
|
||||||
</dd>
|
id="feature-type-select"
|
||||||
</>
|
editable
|
||||||
}
|
data-testid={CF_TYPE_ID}
|
||||||
/>
|
IconComponent={KeyboardArrowDownOutlined}
|
||||||
</dl>
|
/>
|
||||||
</StyledFlagNamingInfo>
|
<StyledTypeDescription>
|
||||||
}
|
{renderToggleDescription()}
|
||||||
/>
|
</StyledTypeDescription>
|
||||||
<StyledInput
|
<ConditionallyRender
|
||||||
autoFocus
|
condition={editable}
|
||||||
disabled={mode === 'Edit'}
|
show={
|
||||||
label="Name"
|
<StyledInputDescription>
|
||||||
aria-details={
|
In which project do you want to save the toggle?
|
||||||
displayFeatureNamingInfo
|
</StyledInputDescription>
|
||||||
? 'feature-naming-pattern-info'
|
}
|
||||||
: undefined
|
/>
|
||||||
}
|
<FeatureProjectSelect
|
||||||
id="feature-toggle-name"
|
value={project}
|
||||||
error={Boolean(errors.name)}
|
onChange={projectId => {
|
||||||
errorText={errors.name}
|
setProject(projectId);
|
||||||
onFocus={() => clearErrors()}
|
navigate(`/projects/${projectId}/create-toggle`, {
|
||||||
value={name}
|
replace: true,
|
||||||
onChange={e => setName(trim(e.target.value))}
|
});
|
||||||
data-testid={CF_NAME_ID}
|
}}
|
||||||
onBlur={validateToggleName}
|
enabled={editable}
|
||||||
/>
|
filter={projectFilterGenerator(permissions, CREATE_FEATURE)}
|
||||||
<StyledInputDescription>
|
IconComponent={KeyboardArrowDownOutlined}
|
||||||
What kind of feature toggle do you want?
|
sx={styledSelectInput}
|
||||||
</StyledInputDescription>
|
/>
|
||||||
<FeatureTypeSelect
|
|
||||||
sx={styledSelectInput}
|
|
||||||
value={type}
|
|
||||||
onChange={setType}
|
|
||||||
label={'Toggle type'}
|
|
||||||
id="feature-type-select"
|
|
||||||
editable
|
|
||||||
data-testid={CF_TYPE_ID}
|
|
||||||
IconComponent={KeyboardArrowDownOutlined}
|
|
||||||
/>
|
|
||||||
<StyledTypeDescription>
|
|
||||||
{renderToggleDescription()}
|
|
||||||
</StyledTypeDescription>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={editable}
|
|
||||||
show={
|
|
||||||
<StyledInputDescription>
|
|
||||||
In which project do you want to save the toggle?
|
|
||||||
</StyledInputDescription>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<FeatureProjectSelect
|
|
||||||
value={project}
|
|
||||||
onChange={projectId => {
|
|
||||||
setProject(projectId);
|
|
||||||
navigate(`/projects/${projectId}/create-toggle`, {
|
|
||||||
replace: true,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
enabled={editable}
|
|
||||||
filter={projectFilterGenerator(permissions, CREATE_FEATURE)}
|
|
||||||
IconComponent={KeyboardArrowDownOutlined}
|
|
||||||
sx={styledSelectInput}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<StyledInputDescription>
|
<StyledInputDescription>
|
||||||
How would you describe your feature toggle?
|
How would you describe your feature toggle?
|
||||||
</StyledInputDescription>
|
</StyledInputDescription>
|
||||||
<StyledInput
|
<StyledInput
|
||||||
multiline
|
multiline
|
||||||
rows={4}
|
rows={4}
|
||||||
label="Description"
|
label="Description"
|
||||||
placeholder="A short description of the feature toggle"
|
placeholder="A short description of the feature toggle"
|
||||||
value={description}
|
value={description}
|
||||||
data-testid={CF_DESC_ID}
|
data-testid={CF_DESC_ID}
|
||||||
onChange={e => setDescription(e.target.value)}
|
onChange={e => setDescription(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<StyledFormControl>
|
<StyledFormControl>
|
||||||
<Typography
|
<Typography
|
||||||
variant="subtitle1"
|
variant="subtitle1"
|
||||||
sx={styledTypography}
|
sx={styledTypography}
|
||||||
data-loading
|
data-loading
|
||||||
component="h2"
|
component="h2"
|
||||||
|
>
|
||||||
|
Impression Data
|
||||||
|
</Typography>
|
||||||
|
<p>
|
||||||
|
When you enable impression data for a feature toggle, your
|
||||||
|
client SDKs will emit events you can listen for every time
|
||||||
|
this toggle gets triggered. Learn more in{' '}
|
||||||
|
<Link
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
href="https://docs.getunleash.io/advanced/impression_data"
|
||||||
>
|
>
|
||||||
Impression Data
|
the impression data documentation
|
||||||
</Typography>
|
</Link>
|
||||||
<p>
|
</p>
|
||||||
When you enable impression data for a feature toggle,
|
<StyledRow>
|
||||||
your client SDKs will emit events you can listen for
|
<FormControlLabel
|
||||||
every time this toggle gets triggered. Learn more in{' '}
|
labelPlacement="start"
|
||||||
<Link
|
style={{ marginLeft: 0 }}
|
||||||
target="_blank"
|
control={
|
||||||
rel="noopener noreferrer"
|
<Switch
|
||||||
href="https://docs.getunleash.io/advanced/impression_data"
|
name="impressionData"
|
||||||
>
|
onChange={() =>
|
||||||
the impression data documentation
|
setImpressionData(!impressionData)
|
||||||
</Link>
|
}
|
||||||
</p>
|
checked={impressionData}
|
||||||
<StyledRow>
|
/>
|
||||||
<FormControlLabel
|
}
|
||||||
labelPlacement="start"
|
label="Enable impression data"
|
||||||
style={{ marginLeft: 0 }}
|
/>
|
||||||
control={
|
</StyledRow>
|
||||||
<Switch
|
</StyledFormControl>
|
||||||
name="impressionData"
|
|
||||||
onChange={() =>
|
|
||||||
setImpressionData(!impressionData)
|
|
||||||
}
|
|
||||||
checked={impressionData}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Enable impression data"
|
|
||||||
/>
|
|
||||||
</StyledRow>
|
|
||||||
</StyledFormControl>
|
|
||||||
</StyledContainer>
|
|
||||||
<StyledButtonContainer>
|
<StyledButtonContainer>
|
||||||
{children}
|
{children}
|
||||||
<StyledCancelButton onClick={handleCancel}>
|
<StyledCancelButton onClick={handleCancel}>
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
import { styled } from '@mui/material';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import { FeatureNamingType } from 'interfaces/project';
|
||||||
|
|
||||||
|
const StyledFlagNamingInfo = styled('article')(({ theme }) => ({
|
||||||
|
fontSize: theme.fontSizes.smallBody,
|
||||||
|
padding: theme.spacing(2),
|
||||||
|
borderRadius: theme.shape.borderRadius,
|
||||||
|
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),
|
||||||
|
},
|
||||||
|
|
||||||
|
marginBlockEnd: theme.spacing(2),
|
||||||
|
}));
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
featureNaming: FeatureNamingType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FeatureNamingPatternInfo: React.FC<Props> = ({
|
||||||
|
featureNaming,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<StyledFlagNamingInfo>
|
||||||
|
<p>This project has feature flag naming patterns enabled.</p>
|
||||||
|
<dl id="feature-naming-pattern-info">
|
||||||
|
<dt>Pattern</dt>
|
||||||
|
<dd>
|
||||||
|
<code>{featureNaming.pattern}</code>
|
||||||
|
</dd>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={Boolean(featureNaming?.example)}
|
||||||
|
show={
|
||||||
|
<>
|
||||||
|
<dt>Example</dt>
|
||||||
|
<dd>{featureNaming?.example}</dd>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={Boolean(featureNaming?.description)}
|
||||||
|
show={
|
||||||
|
<>
|
||||||
|
<dt>Description</dt>
|
||||||
|
<dd>{featureNaming?.description}</dd>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</dl>
|
||||||
|
</StyledFlagNamingInfo>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user