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

integrate change request settings be (#2403)

<!-- Thanks for creating a PR! To make it easier for reviewers and
everyone else to understand what your changes relate to, please add some
relevant content to the headings below. Feel free to ignore or delete
sections that you don't think are relevant. Thank you! ❤️ -->
Integrates frontend with the change request settings backedn
## About the changes
<!-- Describe the changes introduced. What are they and why are they
being introduced? Feel free to also add screenshots or steps to view the
changes if they're visual. -->

<!-- Does it close an issue? Multiple? -->
Closes #

<!-- (For internal contributors): Does it relate to an issue on public
roadmap? -->
<!--
Relates to [roadmap](https://github.com/orgs/Unleash/projects/10) item:
#
-->

### Important files
<!-- PRs can contain a lot of changes, but not all changes are equally
important. Where should a reviewer start looking to get an overview of
the changes? Are any files particularly important? -->


## Discussion points
<!-- Anything about the PR you'd like to discuss before it gets merged?
Got any questions or doubts? -->
This commit is contained in:
andreas-unleash 2022-11-11 14:03:30 +02:00 committed by GitHub
parent 70e020ffeb
commit c57baeb35e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 127 additions and 46 deletions

View File

@ -12,6 +12,12 @@ export interface IChangeRequest {
approvals: IChangeRequestApproval[];
}
export interface IChangeRequestEnvironmentConfig {
environment: string;
type: string;
changeRequestEnabled: boolean;
}
export interface IChangeRequestFeature {
name: string;
conflict?: string;

View File

@ -1,43 +1,71 @@
import { useMemo, useState, VFC } from 'react';
import { HeaderGroup, Row } from 'react-table';
import { HeaderGroup, useGlobalFilter, useTable } from 'react-table';
import { Alert, Box, Typography } from '@mui/material';
import {
SortableTableHeader,
Table,
TableCell,
TableBody,
TableCell,
TableRow,
} from 'component/common/Table';
import { useGlobalFilter, useTable } from 'react-table';
import { sortTypes } from 'utils/sortTypes';
import { PageContent } from 'component/common/PageContent/PageContent';
import { PageHeader } from 'component/common/PageHeader/PageHeader';
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch';
import { UPDATE_FEATURE_ENVIRONMENT } from 'component/providers/AccessProvider/permissions';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { Dialogue } from 'component/common/Dialogue/Dialogue';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useChangeRequestConfig } from '../../../../../hooks/api/getters/useChangeRequestConfig/useChangeRequestConfig';
import { useChangeRequestApi } from '../../../../../hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
import { UPDATE_PROJECT } from '@server/types/permissions';
import useToast from '../../../../../hooks/useToast';
import { formatUnknownError } from '../../../../../utils/formatUnknownError';
export const ChangeRequestConfiguration: VFC = () => {
const [dialogState, setDialogState] = useState<{
isOpen: boolean;
enableEnvironment?: string;
isEnabled: boolean;
}>({
isOpen: false,
enableEnvironment: '',
isEnabled: false,
});
const projectId = useRequiredPathParam('projectId');
const data = [
{
environment: 'dev',
type: 'test',
isEnabled: false,
},
] as any[]; // FIXME: type
const { data, loading, refetchChangeRequestConfig } =
useChangeRequestConfig(projectId);
const { updateChangeRequestEnvironmentConfig } = useChangeRequestApi();
const { setToastData, setToastApiError } = useToast();
const onClick = (enableEnvironment: string) => () => {
setDialogState({ isOpen: true, enableEnvironment });
const onClick = (enableEnvironment: string, isEnabled: boolean) => () => {
setDialogState({ isOpen: true, enableEnvironment, isEnabled });
};
const onConfirm = async () => {
if (dialogState.enableEnvironment) {
try {
await updateChangeRequestEnvironmentConfig(
projectId,
dialogState.enableEnvironment,
!dialogState.isEnabled
);
setToastData({
type: 'success',
title: 'Updated change request status',
text: 'Successfully updated change request status.',
});
refetchChangeRequestConfig();
} catch (error) {
const message = formatUnknownError(error);
setToastApiError(message);
}
}
setDialogState({
isOpen: false,
enableEnvironment: '',
isEnabled: false,
});
};
const columns = useMemo(
@ -55,7 +83,8 @@ export const ChangeRequestConfiguration: VFC = () => {
},
{
Header: 'Status',
accessor: 'isEnabled',
accessor: 'changeRequestEnabled',
id: 'changeRequestEnabled',
align: 'center',
Cell: ({ value, row: { original } }: any) => (
@ -67,9 +96,12 @@ export const ChangeRequestConfiguration: VFC = () => {
checked={value}
environmentId={original.environment}
projectId={projectId}
permission={UPDATE_FEATURE_ENVIRONMENT} // FIXME: permission - enable change request
permission={UPDATE_PROJECT}
inputProps={{ 'aria-label': original.environment }}
onClick={onClick(original.environment)}
onClick={onClick(
original.environment,
original.changeRequestEnabled
)}
/>
</Box>
),
@ -84,6 +116,7 @@ export const ChangeRequestConfiguration: VFC = () => {
const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } =
useTable(
{
// @ts-ignore
columns,
data,
sortTypes,
@ -95,11 +128,10 @@ export const ChangeRequestConfiguration: VFC = () => {
},
useGlobalFilter
);
return (
<PageContent
header={<PageHeader titleElement="Change request configuration" />}
// isLoading={loading}
isLoading={loading}
>
<Alert severity="info" sx={{ mb: 3 }}>
If change request is enabled for an environment, then any change
@ -128,20 +160,21 @@ export const ChangeRequestConfiguration: VFC = () => {
</Table>
<Dialogue
onClick={() => {
alert('clicked');
/* FIXME: API action */
}}
onClick={() => onConfirm()}
open={dialogState.isOpen}
onClose={() =>
setDialogState(state => ({ ...state, isOpen: false }))
}
primaryButtonText="Enable"
primaryButtonText={dialogState.isEnabled ? 'Disable' : 'Enable'}
secondaryButtonText="Cancel"
title="Enable change request"
title={`${
dialogState.isEnabled ? 'Disable' : 'Enable'
} change requests`}
>
<Typography sx={{ mb: 1 }}>
You are about to enable Change request
You are about to{' '}
{dialogState.isEnabled ? 'disable' : 'enable'} Change
request
<ConditionallyRender
condition={Boolean(dialogState.enableEnvironment)}
show={
@ -154,12 +187,18 @@ export const ChangeRequestConfiguration: VFC = () => {
/>
.
</Typography>
<Typography variant="body2" color="text.secondary">
When enabling change request for an environment, you need to
be sure that your Unleash Admin already have created the
custom project roles in your Unleash instance so you can
assign your project members from the project access page.
</Typography>
<ConditionallyRender
condition={!dialogState.isEnabled}
show={
<Typography variant="body2" color="text.secondary">
When enabling change request for an environment, you
need to be sure that your Unleash Admin already have
created the custom project roles in your Unleash
instance so you can assign your project members from
the project access page.
</Typography>
}
/>
</Dialogue>
</PageContent>
);

View File

@ -67,10 +67,28 @@ export const useChangeRequestApi = () => {
}
};
const updateChangeRequestEnvironmentConfig = async (
project: string,
environment: string,
enabled: boolean
) => {
const path = `api/admin/projects/${project}/environments/${environment}/change-requests/config`;
const req = createRequest(path, {
method: 'PUT',
body: JSON.stringify({ changeRequestsEnabled: enabled }),
});
try {
return await makeRequest(req.caller, req.id);
} catch (e) {
throw e;
}
};
return {
addChangeRequest,
changeState,
discardChangeRequestEvent,
updateChangeRequestEnvironmentConfig,
errors,
loading,
};

View File

@ -0,0 +1,24 @@
import useSWR from 'swr';
import { formatApiPath } from 'utils/formatPath';
import handleErrorResponses from '../httpErrorResponseHandler';
import { IChangeRequestEnvironmentConfig } from 'component/changeRequest/changeRequest.types';
export const useChangeRequestConfig = (projectId: string) => {
const { data, error, mutate } = useSWR<IChangeRequestEnvironmentConfig[]>(
formatApiPath(`api/admin/projects/${projectId}/change-requests/config`),
fetcher
);
return {
data: data || [],
loading: !error && !data,
refetchChangeRequestConfig: () => mutate(),
error,
};
};
const fetcher = (path: string) => {
return fetch(path)
.then(handleErrorResponses('Request changes'))
.then(res => res.json());
};

View File

@ -2126,13 +2126,12 @@ body-parser@1.19.0:
raw-body "2.4.0"
type-is "~1.6.17"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
brace-expansion@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
braces@^3.0.1, braces@^3.0.2:
version "3.0.2"
@ -2505,11 +2504,6 @@ compression@^1.7.4:
safe-buffer "5.1.2"
vary "~1.1.2"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
concat-stream@^1.5.2:
version "1.6.2"
resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz"
@ -5396,12 +5390,12 @@ min-indent@^1.0.1:
resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz"
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.2, minimatch@^5.0.1:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.1.2, minimatch@^5.0.0, minimatch@^5.0.1:
version "5.1.0"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7"
integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==
dependencies:
brace-expansion "^1.1.7"
brace-expansion "^2.0.1"
minimist-options@4.1.0:
version "4.1.0"