Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade Privacy Request table to use FidesTable V2 #4990

Merged
merged 13 commits into from
Jun 17, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ The types of changes are:
### Changed
- Move new data map reporting table out of beta and remove old table from Data Lineage map. [#4963](https://github.com/ethyca/fides/pull/4963)
- Disable the 'connect to a database' button if the `dataDiscoveryAndDetection` feature flag is enabled [#1455](https://github.com/ethyca/fidesplus/pull/1455)
- Upgrade Privacy Request table to use FidesTable V2 [#4990](https://github.com/ethyca/fides/pull/4990)

### Fixed
- Fixed an issue where the GPP signal status was prematurely set to `ready` in some scenarios [#4957](https://github.com/ethyca/fides/pull/4957)
Expand Down
19 changes: 3 additions & 16 deletions clients/admin-ui/cypress/e2e/privacy-requests.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe("Privacy Requests", () => {
cy.visit("/privacy-requests");
cy.wait("@getPrivacyRequests");

cy.getByTestIdPrefix("privacy-request-row").as("rows");
cy.get("[role='row']").as("rows");

// Annoyingly fancy, I know, but this selects the containing rows that have a badge with the
// matching status text -- as opposed to just filtering by status which would yield the badge
Expand All @@ -29,7 +29,7 @@ describe("Privacy Requests", () => {
.get("@rows")
.getByTestId("request-status-badge")
.filter(`:contains('${status}')`)
.closest("[data-testid^='privacy-request-row']");
.closest("[role='row']");

selectByStatus("New").as("rowsNew");
selectByStatus("Completed").as("rowsCompleted");
Expand All @@ -44,26 +44,14 @@ describe("Privacy Requests", () => {
});

it("allows navigation to the details of request", () => {
cy.get("@rowsNew")
.first()
.within(() => {
cy.getByTestId("privacy-request-more-btn").click();
});

cy.getByTestId("privacy-request-more-menu")
.contains("View Details")
.click();

cy.get("@rowsNew").first().click();
cy.location("pathname").should("match", /^\/privacy-requests\/pri.+/);
});

it("allows approving a new request", () => {
cy.get("@rowsNew")
.first()
.within(() => {
// The approve button shows up on hover, but there isn't a good way to simulate that in
// tests. Instead we click on the menu button to make all the controls appear.
cy.getByTestId("privacy-request-more-btn").click();
cy.getByTestId("privacy-request-approve-btn").click();
});

Expand All @@ -78,7 +66,6 @@ describe("Privacy Requests", () => {
cy.get("@rowsNew")
.first()
.within(() => {
cy.getByTestId("privacy-request-more-btn").click();
cy.getByTestId("privacy-request-deny-btn").click();
});

Expand Down
3 changes: 2 additions & 1 deletion clients/admin-ui/src/features/common/RequestStatusBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Badge } from "fidesui";
import { PrivacyRequestStatus } from "privacy-requests/types";
import { ComponentProps } from "react";

import { PrivacyRequestStatus } from "~/types/api";

export const statusPropMap: {
[key in PrivacyRequestStatus]: ComponentProps<typeof Badge>;
} = {
Expand Down
3 changes: 2 additions & 1 deletion clients/admin-ui/src/features/common/RequestType.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Box, Tag } from "fidesui";
import { ActionType, Rule } from "privacy-requests/types";
import { Rule } from "privacy-requests/types";
import React from "react";

import { capitalize } from "~/features/common/utils";
import { ActionType } from "~/types/api";

type RequestTypeProps = {
rules: Rule[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,51 +94,58 @@ const MultiSelectDropdown: React.FC<MultiSelectDropdwonProps> = ({
onOpen={handleOpen}
strategy="fixed"
>
<Tooltip
fontSize=".75rem"
hasArrow
aria-label=""
label={getMenuButtonText()}
lineHeight="1.25rem"
isDisabled={tooltipDisabled || !(selectedList.size > 0)}
placement={tooltipPlacement}
>
<MenuButton
aria-label={getMenuButtonText()}
as={Button}
fontWeight="normal"
rightIcon={<ArrowDownLineIcon />}
size="sm"
variant="outline"
_active={{
bg: "none",
}}
_hover={{
bg: "none",
}}
>
{!tooltipDisabled && (
<Text display="inline-block" isTruncated width={width}>
{getMenuButtonText()}
</Text>
)}
{tooltipDisabled && (
<HStack>
<Text>{getMenuButtonText()}</Text>
{selectedList.size > 0 && (
<Text color="complimentary.500">{selectedList.size}</Text>
{({ onClose }) => (
<>
<Tooltip
fontSize=".75rem"
hasArrow
aria-label=""
label={getMenuButtonText()}
lineHeight="1.25rem"
isDisabled={tooltipDisabled || !(selectedList.size > 0)}
placement={tooltipPlacement}
>
<MenuButton
aria-label={getMenuButtonText()}
as={Button}
fontWeight="normal"
rightIcon={<ArrowDownLineIcon />}
size="sm"
variant="outline"
_active={{
bg: "none",
}}
_hover={{
bg: "none",
}}
>
{!tooltipDisabled && (
<Text display="inline-block" isTruncated width={width}>
{getMenuButtonText()}
</Text>
)}
{tooltipDisabled && (
<HStack>
<Text>{getMenuButtonText()}</Text>
{selectedList.size > 0 && (
<Text color="complimentary.500">{selectedList.size}</Text>
)}
</HStack>
)}
</HStack>
</MenuButton>
</Tooltip>
{isOpen && (
<MultiSelectDropdownList
defaultValues={[...selectedList.keys()]}
items={defaultItems}
onSelection={(items) => {
handleSelection(items);
onClose();
}}
/>
)}
</MenuButton>
</Tooltip>
{isOpen ? (
<MultiSelectDropdownList
defaultValues={[...selectedList.keys()]}
items={defaultItems}
onSelection={handleSelection}
/>
) : null}
</>
)}
</Menu>
</Box>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,25 @@ import {
MenuItem,
MenuList,
Spacer,
Text,
} from "fidesui";
import React, { useState } from "react";

type MultiSelectDropdownListProps = {
/**
* List of default item values
*/
defaultValues?: string[];
/**
* List of key/value pair items
*/
items: Map<string, boolean>;
/**
* Event handler invoked when user item selections are applied
*/
onSelection: (items: Map<string, boolean>) => void;
};

const MultiSelectDropdownList: React.FC<MultiSelectDropdownListProps> = ({
/**
* @param defaultValues - List of default item values
* @param items - List of key/value pair items
* @param onSelection - Event handler invoked when user item selections are applied
*/
const MultiSelectDropdownList = ({
defaultValues,
items,
onSelection,
}) => {
}: MultiSelectDropdownListProps) => {
const [pendingItems, setPendingItems] = useState(items);

// Listeners
Expand Down Expand Up @@ -59,7 +54,7 @@ const MultiSelectDropdownList: React.FC<MultiSelectDropdownListProps> = ({
};

return (
<MenuList lineHeight="1rem" p="0">
<MenuList lineHeight="1rem" pt="0">
<Flex borderBottom="1px" borderColor="gray.200" cursor="auto" p="8px">
<Button onClick={handleClear} size="xs" variant="outline">
Clear
Expand All @@ -86,22 +81,29 @@ const MultiSelectDropdownList: React.FC<MultiSelectDropdownListProps> = ({
{[...items].sort().map(([key]) => (
<MenuItem
key={key}
paddingTop="10px"
paddingRight="8.5px"
paddingBottom="10px"
paddingLeft="8.5px"
_focus={{
bg: "gray.100",
p={0}
onKeyPress={(e) => {
if (e.key === " ") {
e.currentTarget.getElementsByTagName("input")[0].click();
}
if (e.key === "Enter") {
handleDone();
}
}}
>
<Checkbox
aria-label={key}
isChecked={items.get(key)}
spacing=".5rem"
spacing={2}
value={key}
width="100%"
fontSize="0.75rem"
paddingTop="10px"
paddingRight="8.5px"
paddingBottom="10px"
paddingLeft="8.5px"
onClick={(e) => e.stopPropagation()}
>
<Text fontSize="0.75rem">{key}</Text>
{key}
</Checkbox>
</MenuItem>
))}
Expand Down
Loading
Loading