Skip to content

Commit

Permalink
TCF purpose summary modal (#4477)
Browse files Browse the repository at this point in the history
Co-authored-by: Adrian Galvan <[email protected]>
  • Loading branch information
TheAndrewJackson and galvana authored Dec 5, 2023
1 parent b9a1087 commit 5dab33f
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 3 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ The types of changes are:
- New purposes endpoint and indices to improve system lookups [#4452](https://github.com/ethyca/fides/pull/4452)
- Cypress tests for fides.js GPP extension [#4476](https://github.com/ethyca/fides/pull/4476)
- Add support for global TCF Purpose Overrides [#4464](https://github.com/ethyca/fides/pull/4464)
- Readonly consent management table and modal [#4456](https://github.com/ethyca/fides/pull/4456), [#4477](https://github.com/ethyca/fides/pull/4477

### Changed
- Increased max number of preferences allowed in privacy preference API calls [#4469](https://github.com/ethyca/fides/pull/4469)
Expand All @@ -42,7 +43,6 @@ The types of changes are:
- Added feature flag for separating system name and Compass vendor selector [#4437](https://github.com/ethyca/fides/pull/4437)
- Fire GPP events per spec [#4433](https://github.com/ethyca/fides/pull/4433)
- New override option `fides_tcf_gdpr_applies` for setting `gdprApplies` on the CMP API [#4453](https://github.com/ethyca/fides/pull/4453)
- Readonly consent management table [#4456](https://github.com/ethyca/fides/pull/4456)

### Changed
- Improved bulk vendor adding table UX [#4425](https://github.com/ethyca/fides/pull/4425)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/* eslint-disable react/no-array-index-key */
import {
Accordion,
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
Box,
Button,
Flex,
Modal,
ModalBody,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Spacer,
Spinner,
useDisclosure,
} from "@fidesui/react";
import { FieldArray, Form, Formik } from "formik";

import {
CustomCreatableSelect,
CustomTextInput,
Label,
} from "~/features/common/form/inputs";
import { useGetSystemPurposeSummaryQuery } from "~/features/plus/plus.slice";
import { SystemPurposeSummary } from "~/types/api";

export const useConsentManagementModal = () => {
const { isOpen, onOpen, onClose } = useDisclosure();

return { isOpen, onOpen, onClose };
};

type Props = {
isOpen: boolean;
onClose: () => void;
fidesKey: string;
};

type FormValues = SystemPurposeSummary;

export const ConsentManagementModal = ({
isOpen,
onClose,
fidesKey,
}: Props) => {
const { data: systemPurposeSummary, isLoading } =
useGetSystemPurposeSummaryQuery(fidesKey);

return (
<Modal
isOpen={isOpen}
onClose={onClose}
size="xxl"
returnFocusOnClose={false}
isCentered
>
<ModalOverlay />
<ModalContent maxWidth="800px">
<ModalHeader>Vendor</ModalHeader>
<ModalBody>
{isLoading ? (
<Flex
width="100%"
height="324px"
alignItems="center"
justifyContent="center"
>
<Spinner />
</Flex>
) : (
<Formik<FormValues>
initialValues={
systemPurposeSummary as unknown as SystemPurposeSummary
}
enableReinitialize
onSubmit={() => {}}
>
{({ values }) => (
<Form>
<Box mb={6}>
<CustomTextInput
label="Vendor Name"
variant="stacked"
name="name"
disabled
/>
</Box>
{Object.entries(values?.purposes || {}).length > 0 ? (
<Label> Purposes </Label>
) : null}
<FieldArray
name="purposes"
render={() => (
<Accordion allowMultiple>
{Object.entries(values.purposes).map(
([purposeName], index: number) => (
<AccordionItem key={index}>
{({ isExpanded }) => (
<>
<AccordionButton
backgroundColor={
isExpanded ? "gray.50" : "unset"
}
>
<Box flex="1" textAlign="left">
{purposeName}
</Box>
<AccordionIcon />
</AccordionButton>
<AccordionPanel backgroundColor="gray.50">
<Box my={4}>
<CustomCreatableSelect
label="Data Uses"
isMulti
disableMenu
isDisabled
options={[]}
variant="stacked"
name={`purposes['${purposeName}'].data_uses`}
/>
</Box>
<CustomCreatableSelect
label="Legal Basis"
isMulti
disableMenu
isDisabled
options={[]}
variant="stacked"
name={`purposes['${purposeName}'].legal_bases`}
/>
</AccordionPanel>
</>
)}
</AccordionItem>
)
)}
</Accordion>
)}
/>
<Box my={4}>
<CustomCreatableSelect
label="Features"
isMulti
options={[]}
disableMenu
isDisabled
variant="stacked"
name="features"
/>
</Box>
<CustomCreatableSelect
label="Data Categories"
isMulti
options={[]}
disableMenu
isDisabled
variant="stacked"
name="data_categories"
/>
</Form>
)}
</Formik>
)}
</ModalBody>

<ModalFooter>
<Button variant="outline" size="sm" onClick={onClose}>
Close{" "}
</Button>
<Spacer />
</ModalFooter>
</ModalContent>
</Modal>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import {
Option,
useConsentManagementFilters,
} from "~/features/configure-consent/ConsentManagementFilterModal";
import {
ConsentManagementModal,
useConsentManagementModal,
} from "~/features/configure-consent/ConsentManagementModal";
import {
useGetHealthQuery,
useGetVendorReportQuery,
Expand All @@ -42,6 +46,12 @@ const emptyVendorReportResponse: Page_SystemSummary_ = {
export const ConsentManagementTable = () => {
const { tcf: isTcfEnabled } = useFeatures();
const { isLoading: isLoadingHealthCheck } = useGetHealthQuery();
const {
isOpen: isRowModalOpen,
onOpen: onRowModalOpen,
onClose: onRowModalClose,
} = useConsentManagementModal();
const [systemFidesKey, setSystemFidesKey] = useState<string>();

const {
isOpen: isFilterOpen,
Expand Down Expand Up @@ -109,8 +119,8 @@ export const ConsentManagementTable = () => {
startRange,
endRange,
pageIndex,
resetPageIndexToDefault,
setTotalPages,
resetPageIndexToDefault,
} = useServerSidePagination();

const [globalFilter, setGlobalFilter] = useState<string>();
Expand Down Expand Up @@ -222,11 +232,23 @@ export const ConsentManagementTable = () => {
getCoreRowModel: getCoreRowModel(),
});

const onRowClick = (system: SystemSummary) => {
setSystemFidesKey(system.fides_key);
onRowModalOpen();
};

if (isReportLoading || isLoadingHealthCheck) {
return <TableSkeletonLoader rowHeight={36} numRows={15} />;
}
return (
<Flex flex={1} direction="column" overflow="auto">
{isRowModalOpen && systemFidesKey ? (
<ConsentManagementModal
isOpen={isRowModalOpen}
fidesKey={systemFidesKey}
onClose={onRowModalClose}
/>
) : null}
<TableActionBar>
<GlobalFilterV2
globalFilter={globalFilter}
Expand Down Expand Up @@ -258,7 +280,7 @@ export const ConsentManagementTable = () => {
</Button>
</Flex>
</TableActionBar>
<FidesTableV2 tableInstance={tableInstance} />
<FidesTableV2 tableInstance={tableInstance} onRowClick={onRowClick} />
<PaginationBar
totalRows={totalRows}
pageSizes={PAGE_SIZES}
Expand Down
9 changes: 9 additions & 0 deletions clients/admin-ui/src/features/plus/plus.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
Page_SystemHistoryResponse_,
Page_SystemSummary_,
ResourceTypes,
SystemPurposeSummary,
SystemScannerStatus,
SystemScanResponse,
SystemsDiff,
Expand Down Expand Up @@ -297,6 +298,13 @@ const plusApi = baseApi.injectEndpoints({
}),
providesTags: ["Fides Cloud Config"],
}),
getSystemPurposeSummary: build.query<SystemPurposeSummary, string>({
query: (fidesKey: string) => ({
url: `plus/system/${fidesKey}/purpose-summary`,
method: "GET",
}),
providesTags: ["System"],
}),
getVendorReport: build.query<
Page_SystemSummary_,
{
Expand Down Expand Up @@ -453,6 +461,7 @@ export const {
useGetAllSystemVendorsQuery,
usePostSystemVendorsMutation,
useGetSystemHistoryQuery,
useGetSystemPurposeSummaryQuery,
useUpdateCustomAssetMutation,
usePatchPlusSystemConnectionConfigsMutation,
useCreatePlusSaasConnectionConfigMutation,
Expand Down
1 change: 1 addition & 0 deletions clients/admin-ui/src/types/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ export type { Strategy } from "./models/Strategy";
export type { System } from "./models/System";
export type { SystemHistoryResponse } from "./models/SystemHistoryResponse";
export type { SystemMetadata } from "./models/SystemMetadata";
export type { SystemPurposeSummary } from "./models/SystemPurposeSummary";
export type { SystemResponse } from "./models/SystemResponse";
export type { SystemScanHistory } from "./models/SystemScanHistory";
export type { SystemScannerStatus } from "./models/SystemScannerStatus";
Expand Down
1 change: 1 addition & 0 deletions clients/admin-ui/src/types/api/models/ScopeRegistryEnum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export enum ScopeRegistryEnum {
DATASET_DELETE = "dataset:delete",
DATASET_READ = "dataset:read",
ENCRYPTION_EXEC = "encryption:exec",
ENDPOINT_CACHE_UPDATE = "endpoint_cache:update",
EVALUATION_CREATE = "evaluation:create",
EVALUATION_DELETE = "evaluation:delete",
EVALUATION_READ = "evaluation:read",
Expand Down
14 changes: 14 additions & 0 deletions clients/admin-ui/src/types/api/models/SystemPurposeSummary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */

/**
* A summary of privacy declaration information for a system aggregated by TCF purpose.
*/
export type SystemPurposeSummary = {
fides_key: string;
name: string;
purposes: Record<string, Record<string, Array<any>>>;
features: Array<string>;
data_categories: Array<string>;
};

0 comments on commit 5dab33f

Please sign in to comment.