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

feat: project feature limit UI (#4220)

This commit is contained in:
Jaanus Sellin 2023-07-11 14:55:43 +03:00 committed by GitHub
parent 81c005013e
commit 469727bb19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 112 additions and 6 deletions

View File

@ -32,6 +32,7 @@ const CreateProject = () => {
projectName,
projectMode,
projectDesc,
featureLimit,
setProjectId,
setProjectName,
setProjectDesc,
@ -40,6 +41,7 @@ const CreateProject = () => {
validateProjectId,
validateName,
setProjectStickiness,
setFeatureLimit,
setProjectMode,
projectStickiness,
errors,
@ -105,7 +107,9 @@ const CreateProject = () => {
projectName={projectName}
projectMode={projectMode}
projectStickiness={projectStickiness}
featureLimit={featureLimit}
setProjectStickiness={setProjectStickiness}
setFeatureLimit={setFeatureLimit}
setProjectMode={setProjectMode}
setProjectName={setProjectName}
projectDesc={projectDesc}

View File

@ -126,6 +126,8 @@ const EditProject = () => {
projectStickiness={projectStickiness}
setProjectStickiness={setProjectStickiness}
setProjectMode={setProjectMode}
setFeatureLimit={() => {}}
featureLimit={''}
projectDesc={projectDesc}
setProjectDesc={setProjectDesc}
mode="Edit"

View File

@ -0,0 +1,16 @@
import { Box } from '@mui/material';
import { FC } from 'react';
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
export const FeatureTogglesLimitTooltip: FC = () => (
<HelpIcon
htmlTooltip
tooltip={
<Box>
Enforce an upper limit of the number of feature toggles that may
be created for this project. You can create unlimited feature
toggle if there is no limit set.
</Box>
}
/>
);

View File

@ -7,6 +7,8 @@ import { ProjectMode } from '../hooks/useProjectForm';
import { Box, styled, TextField } from '@mui/material';
import { CollaborationModeTooltip } from './CollaborationModeTooltip';
import Input from 'component/common/Input/Input';
import { FeatureTogglesLimitTooltip } from './FeatureTogglesLimitTooltip';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
interface IProjectForm {
projectId: string;
@ -14,11 +16,14 @@ interface IProjectForm {
projectDesc: string;
projectStickiness?: string;
projectMode?: string;
featureLimit: string;
featureCount?: number;
setProjectStickiness?: React.Dispatch<React.SetStateAction<string>>;
setProjectMode?: React.Dispatch<React.SetStateAction<ProjectMode>>;
setProjectId: React.Dispatch<React.SetStateAction<string>>;
setProjectName: React.Dispatch<React.SetStateAction<string>>;
setProjectDesc: React.Dispatch<React.SetStateAction<string>>;
setFeatureLimit: React.Dispatch<React.SetStateAction<string>>;
handleSubmit: (e: any) => void;
errors: { [key: string]: string };
mode: 'Create' | 'Edit';
@ -47,9 +52,17 @@ const StyledDescription = styled('p')(({ theme }) => ({
marginRight: theme.spacing(1),
}));
const StyledSubtitle = styled('div')(({ theme }) => ({
color: theme.palette.text.secondary,
fontSize: theme.fontSizes.smallerBody,
lineHeight: 1.25,
paddingBottom: theme.spacing(1),
}));
const StyledInput = styled(Input)(({ theme }) => ({
width: '100%',
marginBottom: theme.spacing(2),
paddingRight: theme.spacing(1),
}));
const StyledTextField = styled(TextField)(({ theme }) => ({
@ -57,12 +70,22 @@ const StyledTextField = styled(TextField)(({ theme }) => ({
marginBottom: theme.spacing(2),
}));
const StyledSelect = styled(Select)(({ theme }) => ({
marginBottom: theme.spacing(2),
minWidth: '200px',
}));
const StyledButtonContainer = styled('div')(() => ({
marginTop: 'auto',
display: 'flex',
justifyContent: 'flex-end',
}));
const StyledInputContainer = styled('div')(() => ({
display: 'flex',
alignItems: 'center',
}));
const ProjectForm: React.FC<IProjectForm> = ({
children,
handleSubmit,
@ -71,16 +94,20 @@ const ProjectForm: React.FC<IProjectForm> = ({
projectDesc,
projectStickiness,
projectMode,
featureLimit,
featureCount,
setProjectId,
setProjectName,
setProjectDesc,
setProjectStickiness,
setProjectMode,
setFeatureLimit,
errors,
mode,
validateProjectId,
clearErrors,
}) => {
const { uiConfig } = useUiConfig();
return (
<StyledForm onSubmit={handleSubmit}>
<StyledContainer>
@ -158,7 +185,7 @@ const ProjectForm: React.FC<IProjectForm> = ({
<p>What is your project collaboration mode?</p>
<CollaborationModeTooltip />
</Box>
<Select
<StyledSelect
id="project-mode"
value={projectMode}
label="Project collaboration mode"
@ -170,11 +197,54 @@ const ProjectForm: React.FC<IProjectForm> = ({
{ key: 'open', label: 'open' },
{ key: 'protected', label: 'protected' },
]}
style={{ minWidth: '200px' }}
></Select>
></StyledSelect>
</>
<ConditionallyRender
condition={Boolean(uiConfig.flags.newProjectLayout)}
show={
<>
<Box
sx={{
display: 'flex',
alignItems: 'center',
marginBottom: 1,
gap: 1,
}}
>
<p>Feature toggles 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 &&
featureLimit !== undefined &&
featureLimit.length > 0
}
show={
<Box>
({featureCount} of {featureLimit}{' '}
used)
</Box>
}
/>
</StyledInputContainer>
</>
}
/>
</StyledContainer>
<StyledButtonContainer>{children}</StyledButtonContainer>
</StyledForm>
);

View File

@ -29,7 +29,6 @@ const EditProject = () => {
const id = useRequiredPathParam('projectId');
const { project } = useProject(id);
const { defaultStickiness } = useDefaultProjectSettings(id);
const navigate = useNavigate();
const { trackEvent } = usePlausibleTracker();
const {
@ -38,11 +37,13 @@ const EditProject = () => {
projectDesc,
projectStickiness,
projectMode,
featureLimit,
setProjectId,
setProjectName,
setProjectDesc,
setProjectStickiness,
setProjectMode,
setFeatureLimit,
getProjectPayload,
clearErrors,
validateProjectId,
@ -113,6 +114,8 @@ const EditProject = () => {
setProjectId={setProjectId}
projectName={projectName}
projectMode={projectMode}
featureLimit={featureLimit}
featureCount={project.features.length}
setProjectName={setProjectName}
projectStickiness={projectStickiness}
setProjectStickiness={setProjectStickiness}
@ -120,6 +123,7 @@ const EditProject = () => {
projectDesc={projectDesc}
mode="Edit"
setProjectDesc={setProjectDesc}
setFeatureLimit={setFeatureLimit}
clearErrors={clearErrors}
validateProjectId={validateProjectId}
>

View File

@ -9,7 +9,8 @@ const useProjectForm = (
initialProjectName = '',
initialProjectDesc = '',
initialProjectStickiness = DEFAULT_PROJECT_STICKINESS,
initialProjectMode: ProjectMode = 'open'
initialProjectMode: ProjectMode = 'open',
initialFeatureLimit = ''
) => {
const [projectId, setProjectId] = useState(initialProjectId);
@ -20,6 +21,8 @@ const useProjectForm = (
);
const [projectMode, setProjectMode] =
useState<ProjectMode>(initialProjectMode);
const [featureLimit, setFeatureLimit] =
useState<string>(initialFeatureLimit);
const [errors, setErrors] = useState({});
const { validateId } = useProjectApi();
@ -40,6 +43,10 @@ const useProjectForm = (
setProjectMode(initialProjectMode);
}, [initialProjectMode]);
useEffect(() => {
setFeatureLimit(initialFeatureLimit);
}, [initialFeatureLimit]);
useEffect(() => {
setProjectStickiness(initialProjectStickiness);
}, [initialProjectStickiness]);
@ -50,6 +57,7 @@ const useProjectForm = (
name: projectName,
description: projectDesc,
defaultStickiness: projectStickiness,
featureLimit: featureLimit,
mode: projectMode,
};
};
@ -87,11 +95,13 @@ const useProjectForm = (
projectDesc,
projectStickiness,
projectMode,
featureLimit,
setProjectId,
setProjectName,
setProjectDesc,
setProjectStickiness,
setProjectMode,
setFeatureLimit,
getProjectPayload,
validateName,
validateProjectId,