1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-10-13 11:17:26 +02:00
unleash.unleash/frontend/src/component/project/Project/hooks/useProjectForm.ts
Thomas Heartman c8fa7e477a
chore: allow CR selection when no envs are enabled (#7183)
This PR allows you to configure change requests for all environments
when no environments are enabled explicitly. This is the default state
of the form and makes it so that you can configure CRs even if you want
all envs enabled.

Additionally, it preserves the case where you configure CRs for an
environment and then disable all envs.

This is logic only. It's not available in the UI yet.
2024-05-28 11:35:06 +02:00

209 lines
6.3 KiB
TypeScript

import { useEffect, useState } from 'react';
import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi';
import { formatUnknownError } from 'utils/formatUnknownError';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import type { ProjectMode } from './useProjectEnterpriseSettingsForm';
export const DEFAULT_PROJECT_STICKINESS = 'default';
const useProjectForm = (
initialProjectId = '',
initialProjectName = '',
initialProjectDesc = '',
initialProjectStickiness = DEFAULT_PROJECT_STICKINESS,
initialFeatureLimit = '',
initialProjectMode: ProjectMode = 'open',
initialProjectEnvironments: Set<string> = new Set(),
initialProjectChangeRequestConfiguration: Record<
string,
{ requiredApprovals: number }
> = {},
) => {
const { isEnterprise } = useUiConfig();
const [projectId, setProjectId] = useState(initialProjectId);
const [projectMode, setProjectMode] =
useState<ProjectMode>(initialProjectMode);
const [projectName, setProjectName] = useState(initialProjectName);
const [projectDesc, setProjectDesc] = useState(initialProjectDesc);
const [projectStickiness, setProjectStickiness] = useState<string>(
initialProjectStickiness,
);
const [featureLimit, setFeatureLimit] =
useState<string>(initialFeatureLimit);
const [projectEnvironments, setProjectEnvironments] = useState<Set<string>>(
initialProjectEnvironments,
);
const [
projectChangeRequestConfiguration,
setProjectChangeRequestConfiguration,
] = useState(initialProjectChangeRequestConfiguration);
const updateProjectEnvironments = (newState: Set<string>) => {
if (newState.size !== 0) {
const filteredChangeRequestEnvs = Object.fromEntries(
Object.entries(projectChangeRequestConfiguration).filter(
([env]) => newState.has(env),
),
);
setProjectChangeRequestConfiguration(filteredChangeRequestEnvs);
}
setProjectEnvironments(newState);
};
const crConfig = {
disableChangeRequests: (env: string) => {
setProjectChangeRequestConfiguration((previousState) => {
const { [env]: _, ...rest } = previousState;
return rest;
});
},
enableChangeRequests: (env: string, approvals: number) => {
if (
projectEnvironments.has(env) ||
projectEnvironments.size === 0
) {
setProjectChangeRequestConfiguration((previousState) => ({
...previousState,
[env]: { requiredApprovals: approvals },
}));
}
},
};
const [errors, setErrors] = useState({});
const { validateId } = useProjectApi();
useEffect(() => {
setProjectId(initialProjectId);
}, [initialProjectId]);
useEffect(() => {
setProjectName(initialProjectName);
}, [initialProjectName]);
useEffect(() => {
setProjectDesc(initialProjectDesc);
}, [initialProjectDesc]);
useEffect(() => {
setFeatureLimit(initialFeatureLimit);
}, [initialFeatureLimit]);
useEffect(() => {
setProjectStickiness(initialProjectStickiness);
}, [initialProjectStickiness]);
useEffect(() => {
setProjectMode(initialProjectMode);
}, [initialProjectMode]);
const getCreateProjectPayload = (options?: {
omitId?: boolean;
includeChangeRequestConfig?: boolean;
}) => {
const environmentsPayload =
projectEnvironments.size > 0
? { environments: [...projectEnvironments] }
: {};
const changeRequestEnvironments = Object.entries(
projectChangeRequestConfiguration,
).map(([env, { requiredApprovals }]) => ({
name: env,
requiredApprovals,
}));
const ossPayload = {
...(options?.omitId ? {} : { id: projectId }),
name: projectName,
description: projectDesc,
defaultStickiness: projectStickiness,
...environmentsPayload,
};
return isEnterprise()
? {
...ossPayload,
mode: projectMode,
...(options?.includeChangeRequestConfig
? { changeRequestEnvironments }
: {}),
}
: ossPayload;
};
const getEditProjectPayload = () => {
return {
id: projectId,
name: projectName,
description: projectDesc,
defaultStickiness: projectStickiness,
featureLimit: getFeatureLimitAsNumber(),
};
};
const getFeatureLimitAsNumber = () => {
if (featureLimit === '') {
return null;
}
return Number(featureLimit);
};
const validateProjectId = async () => {
if (projectId.length === 0) {
setErrors((prev) => ({ ...prev, id: 'Id can not be empty.' }));
return false;
}
try {
await validateId(getCreateProjectPayload().id);
return true;
} catch (error: unknown) {
setErrors((prev) => ({ ...prev, id: formatUnknownError(error) }));
return false;
}
};
const validateName = () => {
if (projectName.trim().length === 0) {
setErrors((prev) => ({ ...prev, name: 'Name can not be empty.' }));
return false;
}
return true;
};
const clearErrors = () => {
setErrors({});
};
return {
projectId,
projectName,
projectDesc,
projectMode,
projectStickiness,
featureLimit,
projectEnvironments,
projectChangeRequestConfiguration,
setProjectId,
setProjectName,
setProjectDesc,
setProjectStickiness,
setFeatureLimit,
setProjectMode,
setProjectEnvironments: updateProjectEnvironments,
updateProjectChangeRequestConfig: crConfig,
getCreateProjectPayload,
getEditProjectPayload,
validateName,
validateProjectId,
clearErrors,
errors,
};
};
export default useProjectForm;