mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-26 01:17:00 +02:00
feat: create and edit environment required approvals (#9621)
This commit is contained in:
parent
07a4106f48
commit
1bd328f4e1
@ -27,6 +27,8 @@ const CreateEnvironment = () => {
|
||||
setName,
|
||||
type,
|
||||
setType,
|
||||
requiredApprovals,
|
||||
setRequiredApprovals,
|
||||
getEnvPayload,
|
||||
validateEnvironmentName,
|
||||
clearErrors,
|
||||
@ -91,6 +93,8 @@ const CreateEnvironment = () => {
|
||||
type={type}
|
||||
setName={setName}
|
||||
setType={setType}
|
||||
requiredApprovals={requiredApprovals}
|
||||
setRequiredApprovals={setRequiredApprovals}
|
||||
mode='Create'
|
||||
clearErrors={clearErrors}
|
||||
Limit={
|
||||
|
@ -12,6 +12,7 @@ import useEnvironmentForm from '../hooks/useEnvironmentForm';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||
import { GO_BACK } from 'constants/navigate';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
|
||||
const EditEnvironment = () => {
|
||||
const { uiConfig } = useUiConfig();
|
||||
@ -21,14 +22,30 @@ const EditEnvironment = () => {
|
||||
const { updateEnvironment } = useEnvironmentApi();
|
||||
|
||||
const navigate = useNavigate();
|
||||
const { name, type, setName, setType, errors, clearErrors } =
|
||||
useEnvironmentForm(environment.name, environment.type);
|
||||
const {
|
||||
name,
|
||||
type,
|
||||
setName,
|
||||
setType,
|
||||
requiredApprovals,
|
||||
setRequiredApprovals,
|
||||
errors,
|
||||
clearErrors,
|
||||
} = useEnvironmentForm(
|
||||
environment.name,
|
||||
environment.type,
|
||||
environment.requiredApprovals,
|
||||
);
|
||||
const { refetch } = usePermissions();
|
||||
const globalChangeRequestConfigEnabled = useUiFlag(
|
||||
'globalChangeRequestConfig',
|
||||
);
|
||||
|
||||
const editPayload = () => {
|
||||
return {
|
||||
type,
|
||||
sortOrder: environment.sortOrder,
|
||||
...(globalChangeRequestConfigEnabled ? { requiredApprovals } : {}),
|
||||
};
|
||||
};
|
||||
|
||||
@ -84,6 +101,8 @@ const EditEnvironment = () => {
|
||||
type={type}
|
||||
setName={setName}
|
||||
setType={setType}
|
||||
requiredApprovals={requiredApprovals}
|
||||
setRequiredApprovals={setRequiredApprovals}
|
||||
mode='Edit'
|
||||
errors={errors}
|
||||
clearErrors={clearErrors}
|
||||
|
@ -0,0 +1,97 @@
|
||||
import {
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
styled,
|
||||
} from '@mui/material';
|
||||
import KeyboardArrowDownOutlined from '@mui/icons-material/KeyboardArrowDownOutlined';
|
||||
import GeneralSelect from '../../common/GeneralSelect/GeneralSelect';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
|
||||
interface IEnvironmentChangeRequestProps {
|
||||
onChange: (approvals: number | null) => void;
|
||||
value: number | null;
|
||||
}
|
||||
|
||||
const StyledRadioGroup = styled(RadioGroup)({
|
||||
flexDirection: 'row',
|
||||
});
|
||||
|
||||
const StyledRadioButtonGroup = styled('div')({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
});
|
||||
|
||||
const StyledRequiredApprovals = styled('p')(({ theme }) => ({
|
||||
marginTop: theme.spacing(1),
|
||||
marginBottom: theme.spacing(0.5),
|
||||
}));
|
||||
|
||||
const useApprovalOptions = () => {
|
||||
const theme = useTheme();
|
||||
const approvalOptions = Array.from(Array(10).keys())
|
||||
.map((key) => String(key + 1))
|
||||
.map((key) => {
|
||||
const labelText = key === '1' ? 'approval' : 'approvals';
|
||||
return {
|
||||
key,
|
||||
label: `${key} ${labelText}`,
|
||||
sx: { fontSize: theme.fontSizes.smallBody },
|
||||
};
|
||||
});
|
||||
return approvalOptions;
|
||||
};
|
||||
|
||||
export const ChangeRequestSelector = ({
|
||||
onChange,
|
||||
value,
|
||||
}: IEnvironmentChangeRequestProps) => {
|
||||
const approvalOptions = useApprovalOptions();
|
||||
|
||||
return (
|
||||
<FormControl component='fieldset'>
|
||||
<StyledRadioGroup
|
||||
data-loading
|
||||
value={value ? 'yes' : 'no'}
|
||||
onChange={(event) => {
|
||||
if (event.target.value === 'yes') {
|
||||
onChange(1);
|
||||
} else {
|
||||
onChange(null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<StyledRadioButtonGroup>
|
||||
<FormControlLabel
|
||||
value='no'
|
||||
label='No'
|
||||
control={<Radio />}
|
||||
/>
|
||||
<FormControlLabel
|
||||
value='yes'
|
||||
label='Yes'
|
||||
control={<Radio />}
|
||||
/>
|
||||
</StyledRadioButtonGroup>
|
||||
</StyledRadioGroup>
|
||||
{value ? (
|
||||
<>
|
||||
<StyledRequiredApprovals>
|
||||
Required approvals
|
||||
</StyledRequiredApprovals>
|
||||
<GeneralSelect
|
||||
label='Set required approvals for the current environment'
|
||||
visuallyHideLabel
|
||||
sx={{ width: '160px' }}
|
||||
options={approvalOptions}
|
||||
value={value ? String(value) : undefined}
|
||||
onChange={(approvals) => onChange(Number(approvals))}
|
||||
IconComponent={KeyboardArrowDownOutlined}
|
||||
fullWidth
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
</FormControl>
|
||||
);
|
||||
};
|
@ -1,14 +1,19 @@
|
||||
import { Box, Button, styled } from '@mui/material';
|
||||
import type React from 'react';
|
||||
import Input from 'component/common/Input/Input';
|
||||
import EnvironmentTypeSelector from './EnvironmentTypeSelector/EnvironmentTypeSelector';
|
||||
import { EnvironmentTypeSelector } from './EnvironmentTypeSelector';
|
||||
import { ChangeRequestSelector } from './ChangeRequestSelector';
|
||||
import { trim } from 'component/common/util';
|
||||
import { useUiFlag } from '../../../hooks/useUiFlag';
|
||||
|
||||
interface IEnvironmentForm {
|
||||
name: string;
|
||||
type: string;
|
||||
requiredApprovals: number | null;
|
||||
setName: React.Dispatch<React.SetStateAction<string>>;
|
||||
setType: React.Dispatch<React.SetStateAction<string>>;
|
||||
setRequiredApprovals: React.Dispatch<React.SetStateAction<number | null>>;
|
||||
|
||||
validateEnvironmentName?: (e: any) => void;
|
||||
handleSubmit: (e: any) => void;
|
||||
handleCancel: () => void;
|
||||
@ -67,14 +72,19 @@ const EnvironmentForm: React.FC<IEnvironmentForm> = ({
|
||||
handleCancel,
|
||||
name,
|
||||
type,
|
||||
requiredApprovals,
|
||||
setName,
|
||||
setType,
|
||||
setRequiredApprovals,
|
||||
validateEnvironmentName,
|
||||
errors,
|
||||
mode,
|
||||
clearErrors,
|
||||
Limit,
|
||||
}) => {
|
||||
const globalChangeRequestConfigEnabled = useUiFlag(
|
||||
'globalChangeRequestConfig',
|
||||
);
|
||||
return (
|
||||
<StyledForm onSubmit={handleSubmit}>
|
||||
<StyledFormHeader>Environment information</StyledFormHeader>
|
||||
@ -102,6 +112,19 @@ const EnvironmentForm: React.FC<IEnvironmentForm> = ({
|
||||
onChange={(e) => setType(e.currentTarget.value)}
|
||||
value={type}
|
||||
/>
|
||||
|
||||
{globalChangeRequestConfigEnabled ? (
|
||||
<>
|
||||
<StyledInputDescription sx={{ mt: 2 }}>
|
||||
Would you like to pre-define change requests for
|
||||
this environment?
|
||||
</StyledInputDescription>
|
||||
<ChangeRequestSelector
|
||||
onChange={setRequiredApprovals}
|
||||
value={requiredApprovals}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
</StyledContainer>
|
||||
|
||||
<LimitContainer>{Limit}</LimitContainer>
|
||||
|
@ -21,7 +21,7 @@ const StyledRadioButtonGroup = styled('div')({
|
||||
flexDirection: 'column',
|
||||
});
|
||||
|
||||
const EnvironmentTypeSelector = ({
|
||||
export const EnvironmentTypeSelector = ({
|
||||
onChange,
|
||||
value,
|
||||
}: IEnvironmentTypeSelectorProps) => {
|
||||
@ -56,5 +56,3 @@ const EnvironmentTypeSelector = ({
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
export default EnvironmentTypeSelector;
|
@ -21,7 +21,7 @@ import type {
|
||||
} from 'interfaces/environments';
|
||||
import useEnvironmentApi from 'hooks/api/actions/useEnvironmentApi/useEnvironmentApi';
|
||||
import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
|
||||
import EnvironmentTypeSelector from 'component/environments/EnvironmentForm/EnvironmentTypeSelector/EnvironmentTypeSelector';
|
||||
import { EnvironmentTypeSelector } from 'component/environments/EnvironmentForm/EnvironmentTypeSelector';
|
||||
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
|
||||
import { EnvironmentProjectSelect } from './EnvironmentProjectSelect/EnvironmentProjectSelect';
|
||||
import { SelectProjectInput } from 'component/admin/apiToken/ApiTokenForm/ProjectSelector/SelectProjectInput/SelectProjectInput';
|
||||
|
@ -2,9 +2,16 @@ import { useEffect, useState } from 'react';
|
||||
import useEnvironmentApi from 'hooks/api/actions/useEnvironmentApi/useEnvironmentApi';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
|
||||
const useEnvironmentForm = (initialName = '', initialType = 'development') => {
|
||||
const useEnvironmentForm = (
|
||||
initialName = '',
|
||||
initialType = 'development',
|
||||
initialRequiredApprovals: number | null = null,
|
||||
) => {
|
||||
const [name, setName] = useState(initialName);
|
||||
const [type, setType] = useState(initialType);
|
||||
const [requiredApprovals, setRequiredApprovals] = useState(
|
||||
initialRequiredApprovals,
|
||||
);
|
||||
const [errors, setErrors] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
@ -15,12 +22,17 @@ const useEnvironmentForm = (initialName = '', initialType = 'development') => {
|
||||
setType(initialType);
|
||||
}, [initialType]);
|
||||
|
||||
useEffect(() => {
|
||||
setRequiredApprovals(initialRequiredApprovals);
|
||||
}, [initialRequiredApprovals]);
|
||||
|
||||
const { validateEnvName } = useEnvironmentApi();
|
||||
|
||||
const getEnvPayload = () => {
|
||||
return {
|
||||
name,
|
||||
type,
|
||||
...(requiredApprovals ? { requiredApprovals } : {}),
|
||||
};
|
||||
};
|
||||
|
||||
@ -51,6 +63,8 @@ const useEnvironmentForm = (initialName = '', initialType = 'development') => {
|
||||
setName,
|
||||
type,
|
||||
setType,
|
||||
requiredApprovals,
|
||||
setRequiredApprovals,
|
||||
getEnvPayload,
|
||||
validateEnvironmentName,
|
||||
clearErrors,
|
||||
|
@ -12,6 +12,7 @@ export interface IEnvironment {
|
||||
apiTokenCount?: number;
|
||||
enabledToggleCount?: number;
|
||||
lastSeenAt: string;
|
||||
requiredApprovals?: number | null;
|
||||
}
|
||||
|
||||
export interface IProjectEnvironment extends IEnvironment {
|
||||
|
@ -92,6 +92,7 @@ export type UiFlags = {
|
||||
edgeObservability?: boolean;
|
||||
adminNavUI?: boolean;
|
||||
tagTypeColor?: boolean;
|
||||
globalChangeRequestConfig?: boolean;
|
||||
};
|
||||
|
||||
export interface IVersionInfo {
|
||||
|
@ -21,7 +21,7 @@ interface IEnvironmentsTable {
|
||||
sort_order: number;
|
||||
enabled: boolean;
|
||||
protected: boolean;
|
||||
required_approvals?: number;
|
||||
required_approvals?: number | null;
|
||||
}
|
||||
|
||||
interface IEnvironmentsWithCountsTable extends IEnvironmentsTable {
|
||||
|
@ -198,7 +198,7 @@ export interface IEnvironment {
|
||||
projectCount?: number;
|
||||
apiTokenCount?: number;
|
||||
enabledToggleCount?: number;
|
||||
requiredApprovals?: number;
|
||||
requiredApprovals?: number | null;
|
||||
}
|
||||
|
||||
export interface IProjectEnvironment extends IEnvironment {
|
||||
@ -216,7 +216,7 @@ export interface IEnvironmentCreate {
|
||||
type: string;
|
||||
sortOrder?: number;
|
||||
enabled?: boolean;
|
||||
requiredApprovals?: number;
|
||||
requiredApprovals?: number | null;
|
||||
}
|
||||
|
||||
export interface IEnvironmentClone {
|
||||
|
Loading…
Reference in New Issue
Block a user