Skip to content

Commit

Permalink
Persist the state of the reporting table so that viewers can return t…
Browse files Browse the repository at this point in the history
…o their previous view easily (#4853)
  • Loading branch information
gilluminate authored May 2, 2024
1 parent d1f6a0a commit 8751e3e
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 31 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The types of changes are:
- Added access and erasure support for Marigold Engage by Sailthru integration [#4826](https://github.com/ethyca/fides/pull/4826)
- Added multiple language translations support for privacy center consent page [#4785](https://github.com/ethyca/fides/pull/4785)
- Added ability to export the contents of datamap report [#1545](https://ethyca.atlassian.net/browse/PROD-1545)
- Added state persistence across sessions to the datamap report table [#4853](https://github.com/ethyca/fides/pull/4853)

### Fixed
- Remove the extra 'white-space: normal' CSS for FidesJS HTML descriptions [#4850](https://github.com/ethyca/fides/pull/4850)
Expand Down
33 changes: 33 additions & 0 deletions clients/admin-ui/cypress/e2e/datamap-report.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,19 @@ describe("Minimal datamap report table", () => {
cy.getByTestId("datamap-report-heading").should("be.visible");
});

it("can group by data use", () => {
cy.getByTestId("group-by-menu").should("contain.text", "Group by system");
cy.getByTestId("group-by-menu").click();
cy.getByTestId("group-by-menu-list").within(() => {
cy.getByTestId("group-by-data-use-system").click();
});
cy.getByTestId("group-by-menu").should("contain.text", "Group by data use");

// should persist the grouping when navigating away
cy.reload();
cy.getByTestId("group-by-menu").should("contain.text", "Group by data use");
});

describe("Undeclared data category columns", () => {
it("should have the undeclared data columns disabled by default", () => {
cy.getByTestId("row-0-col-system_undeclared_data_categories").should(
Expand All @@ -105,6 +118,15 @@ describe("Minimal datamap report table", () => {
"2 data use undeclared data categories"
);

// should persist the columns when navigating away
cy.reload();
cy.getByTestId("row-0-col-system_undeclared_data_categories").contains(
"2 system undeclared data categories"
);
cy.getByTestId("row-0-col-data_use_undeclared_data_categories").contains(
"2 data use undeclared data categories"
);

// should be able to expand columns
cy.getByTestId("system_undeclared_data_categories-header-menu").click();
cy.getByTestId(
Expand All @@ -129,6 +151,17 @@ describe("Minimal datamap report table", () => {
"row-0-col-data_use_undeclared_data_categories"
).contains(pokemon);
});

// should persist the expanded columns when navigating away
cy.reload();
["User Contact Email", "Cookie ID"].forEach((pokemon) => {
cy.getByTestId("row-0-col-system_undeclared_data_categories").contains(
pokemon
);
cy.getByTestId(
"row-0-col-data_use_undeclared_data_categories"
).contains(pokemon);
});
});
});

Expand Down
50 changes: 50 additions & 0 deletions clients/admin-ui/src/features/common/hooks/useLocalStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Dispatch, SetStateAction, useState } from "react";

/*
Design taken from: https://usehooks.com/useLocalStorage/
*/

// eslint-disable-next-line import/prefer-default-export
export function useLocalStorage<T = string>(
key: string,
initialValue: T
): [T, Dispatch<SetStateAction<T>>] {
// State to store our value
// Pass initial state function to useState so logic is only executed once
const [storedValue, setStoredValue] = useState<T>(() => {
if (typeof window === "undefined") {
return initialValue;
}
try {
// Get from local storage by key
const item = window.localStorage.getItem(key);
// Parse stored json or if none return initialValue
return item ? JSON.parse(item) : initialValue;
} catch (error) {
// If error also return initialValue
// eslint-disable-next-line no-console
console.error(error);
return initialValue;
}
});
// Return a wrapped version of useState's setter function that ...
// ... persists the new value to localStorage.
const setValue = (value: T | ((x: T) => T)) => {
try {
// Allow value to be a function so we have same API as useState
const valueToStore =
value instanceof Function ? value(storedValue) : value;
// Save state
setStoredValue(valueToStore);
// Save to local storage
if (typeof window !== "undefined") {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
}
} catch (error) {
// A more advanced implementation would handle the error case
// eslint-disable-next-line no-console
console.error(error);
}
};
return [storedValue, setValue];
}
9 changes: 7 additions & 2 deletions clients/admin-ui/src/features/common/table/v2/FidesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ import {
RowData,
Table as TableInstance,
} from "@tanstack/react-table";
import React, { ReactNode, useMemo, useState } from "react";
import React, { ReactNode, useMemo } from "react";

import { useLocalStorage } from "~/features/common/hooks/useLocalStorage";
import { DisplayAllIcon, GroupedIcon } from "~/features/common/Icon";
import { FidesRow } from "~/features/common/table/v2/FidesRow";
import { getTableTHandTDStyles } from "~/features/common/table/v2/util";
import { DATAMAP_LOCAL_STORAGE_KEYS } from "~/features/datamap/constants";

/*
This was throwing a false positive for unused parameters.
Expand Down Expand Up @@ -176,7 +178,10 @@ export const FidesTableV2 = <T,>({
renderRowTooltipLabel,
emptyTableNotice,
}: Props<T>) => {
const [displayAllColumns, setDisplayAllColumns] = useState<string[]>([]);
const [displayAllColumns, setDisplayAllColumns] = useLocalStorage<string[]>(
DATAMAP_LOCAL_STORAGE_KEYS.DISPLAY_ALL_COLUMNS,
[]
);

const handleAddDisplayColumn = (id: string) => {
setDisplayAllColumns([...displayAllColumns, id]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type ColumnSettingsModalProps<T> = {
headerText: string;
prefixColumns: string[];
tableInstance: TableInstance<T>;
onColumnOrderChange: (columns: string[]) => void;
};

export const ColumnSettingsModal = <T,>({
Expand All @@ -38,6 +39,7 @@ export const ColumnSettingsModal = <T,>({
headerText,
tableInstance,
prefixColumns,
onColumnOrderChange,
}: ColumnSettingsModalProps<T>) => {
const initialColumns = useMemo(
() =>
Expand All @@ -49,7 +51,23 @@ export const ColumnSettingsModal = <T,>({
displayText: c.columnDef?.meta?.displayText || c.id,
isVisible:
tableInstance.getState().columnVisibility[c.id] ?? c.getIsVisible(),
})),
}))
.sort((a, b) => {
// columnOrder is not always a complete list. Sorts by columnOrder but leaves the rest alone
const { columnOrder } = tableInstance.getState();
const aIndex = columnOrder.indexOf(a.id);
const bIndex = columnOrder.indexOf(b.id);
if (aIndex === -1 && bIndex === -1) {
return 0;
}
if (aIndex === -1) {
return 1;
}
if (bIndex === -1) {
return -1;
}
return aIndex - bIndex;
}),
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);
Expand All @@ -58,10 +76,11 @@ export const ColumnSettingsModal = <T,>({
});

const handleSave = useCallback(() => {
tableInstance.setColumnOrder([
const newColumnOrder: string[] = [
...prefixColumns,
...columnEditor.columns.map((c) => c.id),
]);
];
onColumnOrderChange(newColumnOrder);
tableInstance.setColumnVisibility(
columnEditor.columns.reduce(
(acc: Record<string, boolean>, current: DraggableColumn) => {
Expand All @@ -73,7 +92,13 @@ export const ColumnSettingsModal = <T,>({
)
);
onClose();
}, [onClose, prefixColumns, tableInstance, columnEditor.columns]);
}, [
onClose,
prefixColumns,
tableInstance,
columnEditor.columns,
onColumnOrderChange,
]);

return (
<Modal isOpen={isOpen} onClose={onClose} isCentered size="2xl">
Expand Down
9 changes: 9 additions & 0 deletions clients/admin-ui/src/features/datamap/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,12 @@ COLUMN_NAME_MAP[SYSTEM_EGRESS] = "Destination Systems";
// COLUMN_NAME_MAP[] = 'Legal Name & Address'; #new;
// COLUMN_NAME_MAP[] = 'Privacy Policy'; #new;
// COLUMN_NAME_MAP[] = 'Data Protection Officer (DPO)'; #new;

// eslint-disable-next-line @typescript-eslint/naming-convention
export enum DATAMAP_LOCAL_STORAGE_KEYS {
GROUP_BY = "datamap-group-by",
COLUMN_ORDER = "datamap-column-order",
TABLE_GROUPING = "datamap-table-grouping",
TABLE_STATE = "datamap-report-table-state",
DISPLAY_ALL_COLUMNS = "datamap-display-all-columns",
}
Loading

0 comments on commit 8751e3e

Please sign in to comment.