Skip to content

Commit

Permalink
System history UI with diff modal (#4021)
Browse files Browse the repository at this point in the history
  • Loading branch information
galvana authored Sep 11, 2023
1 parent 9258673 commit 4572b0c
Show file tree
Hide file tree
Showing 13 changed files with 1,012 additions and 57 deletions.
7 changes: 7 additions & 0 deletions clients/admin-ui/src/features/common/Icon/NextArrow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createIcon } from "@fidesui/react";

export default createIcon({
displayName: "NextArrow",
viewBox: "0 0 12 12",
d: "M6.58584 5.99999L4.11084 3.52499L4.81784 2.81799L7.99984 5.99999L4.81784 9.18199L4.11084 8.47499L6.58584 5.99999Z",
});
7 changes: 7 additions & 0 deletions clients/admin-ui/src/features/common/Icon/PrevArrow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createIcon } from "@fidesui/react";

export default createIcon({
displayName: "PrevArrow",
viewBox: "0 0 12 12",
d: "M5.414 5.99999L7.889 8.47499L7.182 9.18199L4 5.99999L7.182 2.81799L7.889 3.52499L5.414 5.99999Z",
});
10 changes: 8 additions & 2 deletions clients/admin-ui/src/features/plus/plus.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,15 @@ const plusApi = baseApi.injectEndpoints({
}),
getSystemHistory: build.query<
SystemHistoryResponse,
{ system_key: string }
{ system_key: string; page?: number; size?: number }
>({
query: (params) => ({ url: `plus/system/${params.system_key}/history` }),
query: (params) => ({
url: `plus/system/${params.system_key}/history`,
params: {
page: params.page,
size: params.size,
},
}),
providesTags: () => ["System History"],
}),
}),
Expand Down
3 changes: 2 additions & 1 deletion clients/admin-ui/src/features/system/SystemFormTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,8 @@ const SystemFormTabs = ({
<Box px={6} paddingBottom={6}>
<Text fontSize="sm" lineHeight={5} fontWeight="medium">
All changes to this system are tracked here in this audit table by
date and by user.
date and by user. You can inspect the changes by selecting any of
the events listed.
</Text>
</Box>
<SystemHistoryTable system={activeSystem} />
Expand Down
233 changes: 181 additions & 52 deletions clients/admin-ui/src/features/system/history/SystemHistoryTable.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
import { Table, Tbody, Td, Thead, Tr } from "@fidesui/react";
import {
Button,
Flex,
Table,
Tbody,
Td,
Text,
Thead,
Tr,
} from "@fidesui/react";
import _ from "lodash";
import React from "react";
import React, { useState } from "react";

import NextArrow from "~/features/common/Icon/NextArrow";
import PrevArrow from "~/features/common/Icon/PrevArrow";
import { useGetSystemHistoryQuery } from "~/features/plus/plus.slice";
import { PrivacyDeclaration } from "~/types/api";
import { SystemHistory } from "~/types/api/models/SystemHistory";
import { SystemResponse } from "~/types/api/models/SystemResponse";

import SystemHistoryModal from "./modal/SystemHistoryModal";

interface Props {
system: SystemResponse;
}
Expand Down Expand Up @@ -34,14 +48,81 @@ const formatDateAndTime = (dateString: string) => {
return { formattedTime, formattedDate };
};

function alignArrays(
before: PrivacyDeclaration[],
after: PrivacyDeclaration[]
) {
const allNames = new Set([...before, ...after].map((item) => item.data_use));
const alignedBefore: PrivacyDeclaration[] = [];
const alignedAfter: PrivacyDeclaration[] = [];

allNames.forEach((data_use) => {
const firstItem = before.find((item) => item.data_use === data_use) || {
data_use: "",
data_categories: [],
};
const secondItem = after.find((item) => item.data_use === data_use) || {
data_use: "",
data_categories: [],
};
alignedBefore.push(firstItem);
alignedAfter.push(secondItem);
});

return [alignedBefore, alignedAfter];
}

const itemsPerPage = 10;

const SystemHistoryTable = ({ system }: Props) => {
// Fetch system history data
const [currentPage, setCurrentPage] = useState(1);
const { data } = useGetSystemHistoryQuery({
system_key: system.fides_key,
page: currentPage,
size: itemsPerPage,
});
const [isModalOpen, setModalOpen] = useState(false);
const [selectedHistory, setSelectedHistory] = useState<SystemHistory | null>(
null
);

const systemHistories = data?.items || [];

const openModal = (history: SystemHistory) => {
// Align the privacy_declarations arrays
const beforePrivacyDeclarations =
history?.before?.privacy_declarations || [];
const afterPrivacyDeclarations = history?.after?.privacy_declarations || [];
const [alignedBefore, alignedAfter] = alignArrays(
beforePrivacyDeclarations,
afterPrivacyDeclarations
);

// Create new initialValues objects with the aligned arrays
const alignedBeforeInitialValues = {
...history?.before,
privacy_declarations: alignedBefore,
};
const alignedAfterInitialValues = {
...history?.after,
privacy_declarations: alignedAfter,
};

setSelectedHistory({
before: alignedBeforeInitialValues,
after: alignedAfterInitialValues,
edited_by: history.edited_by,
system_id: history.system_id,
created_at: history.created_at,
});
setModalOpen(true);
};

const closeModal = () => {
setModalOpen(false);
setSelectedHistory(null);
};

const describeSystemChange = (history: SystemHistory) => {
// eslint-disable-next-line @typescript-eslint/naming-convention
const { edited_by, before, after, created_at } = history;
Expand Down Expand Up @@ -146,58 +227,106 @@ const SystemHistoryTable = ({ system }: Props) => {

const { formattedTime, formattedDate } = formatDateAndTime(system.created_at);

const totalPages = data ? Math.ceil(data.total / itemsPerPage) : 0;

const handleNextPage = () => {
if (currentPage < totalPages) {
setCurrentPage(currentPage + 1);
}
};

const handlePrevPage = () => {
if (currentPage > 1) {
setCurrentPage(currentPage - 1);
}
};

return (
<Table style={{ marginLeft: "24px" }}>
<Thead>
<Tr>
<Td
style={{
paddingTop: 16,
paddingBottom: 16,
paddingLeft: 16,
fontSize: 12,
borderTop: "1px solid #E2E8F0",
borderLeft: "1px solid #E2E8F0",
borderRight: "1px solid #E2E8F0",
background: "#F7FAFC",
}}
>
System created
{system.created_by && (
<>
{" "}
by <b>{system.created_by}</b>{" "}
</>
)}{" "}
on {formattedDate} at {formattedTime}
</Td>
</Tr>
</Thead>
<Tbody>
{systemHistories.map((history: SystemHistory, index: number) => {
const description = describeSystemChange(history);
return (
<Tr
// eslint-disable-next-line react/no-array-index-key
key={index}
<>
<Table ml="24px">
<Thead>
<Tr>
<Td
p="16px"
fontSize="12px"
border="1px solid #E2E8F0"
background="#F7FAFC"
>
<Td
style={{
paddingTop: 10,
paddingBottom: 10,
paddingLeft: 16,
fontSize: 12,
borderLeft: "1px solid #E2E8F0",
borderRight: "1px solid #E2E8F0",
}}
System created
{system.created_by && (
<>
{" "}
by <b>{system.created_by}</b>{" "}
</>
)}{" "}
on {formattedDate} at {formattedTime}
</Td>
</Tr>
</Thead>
<Tbody>
{systemHistories.map((history, index) => {
const description = describeSystemChange(history);
return (
<Tr
// eslint-disable-next-line react/no-array-index-key
key={index}
onClick={() => openModal(history)}
style={{ cursor: "pointer" }}
>
{description}
</Td>
</Tr>
);
})}
</Tbody>
</Table>
<Td
pt="10px"
pb="10px"
pl="16px"
fontSize="12px"
border="1px solid #E2E8F0"
>
{description}
</Td>
</Tr>
);
})}
</Tbody>
</Table>
{(data?.total || 0) > 10 && (
<Flex
alignItems="center"
justifyContent="flex-start"
marginTop="12px"
marginLeft="24px"
>
<Text fontSize="xs" lineHeight={4} fontWeight="600" paddingX={2}>
{(currentPage - 1) * itemsPerPage + 1} -{" "}
{Math.min(currentPage * itemsPerPage, data?.total || 0)} of{" "}
{data?.total || 0}
</Text>
<Button
size="xs"
width="24px"
variant="outline"
paddingX={0}
marginRight={2}
onClick={handlePrevPage}
disabled={currentPage === 1}
>
<PrevArrow />
</Button>
<Button
size="xs"
variant="outline"
paddingX={0}
onClick={handleNextPage}
disabled={currentPage === totalPages || totalPages === 0}
>
<NextArrow />
</Button>
</Flex>
)}
<SystemHistoryModal
selectedHistory={selectedHistory!}
isOpen={isModalOpen}
onClose={closeModal}
/>
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { createContext, ReactNode, useContext, useMemo } from "react";

import { SystemHistory } from "~/types/api/models/SystemHistory";

type FormType = "before" | "after";

interface SelectedHistoryContextProps {
selectedHistory: SystemHistory | null;
formType: FormType;
}

const SelectedHistoryContext =
createContext<SelectedHistoryContextProps | null>(null);

export const useSelectedHistory = () => useContext(SelectedHistoryContext)!;

interface SelectedHistoryProviderProps {
children: ReactNode;
selectedHistory: SystemHistory | null;
formType: FormType;
}

const SelectedHistoryProvider: React.FC<SelectedHistoryProviderProps> = ({
children,
selectedHistory,
formType,
}) => {
const value = useMemo(
() => ({ selectedHistory, formType }),
[selectedHistory, formType]
);

return (
<SelectedHistoryContext.Provider value={value}>
{children}
</SelectedHistoryContext.Provider>
);
};

export default SelectedHistoryProvider;
Loading

0 comments on commit 4572b0c

Please sign in to comment.