Skip to content

Commit

Permalink
Classifier category badge updates (#5212)
Browse files Browse the repository at this point in the history
  • Loading branch information
jpople authored Aug 20, 2024
1 parent 3ad4808 commit 60d005e
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 51 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ The types of changes are:
- Ignore `404` errors on Oracle Responsys deletions [#5203](https://github.com/ethyca/fides/pull/5203)
- Fix white screen issue when privacy request has null value for daysLeft [#5213](https://github.com/ethyca/fides/pull/5213)

### Changed
- Visual updates to badges in D&D result tables [#5212](https://github.com/ethyca/fides/pull/5212)

## [2.43.0](https://github.com/ethyca/fides/compare/2.42.1...2.43.0)

Expand Down
24 changes: 21 additions & 3 deletions clients/admin-ui/cypress/e2e/discovery-detection.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,13 +367,31 @@ describe("discovery and detection", () => {
cy.getByTestId(
"row-my_bigquery_monitor-Test-col-classifications",
).within(() => {
cy.getByTestId("classification-user.contact.phone_number").should(
"exist",
);
cy.getByTestId(
"user-classification-user.contact.phone_number",
).should("exist");
cy.getByTestId("add-category-btn").click();
cy.get(".select-wrapper").should("exist");
});
});

it("shows 'None' when no categories are assigned", () => {
cy.getByTestId(
"row-my_bigquery_monitor-No_categories-col-classifications",
).within(() => {
cy.getByTestId("no-classifications").should("exist");
cy.getByTestId("add-category-btn").should("exist");
});
});

it("doesn't allow adding categories on fields with subfields", () => {
cy.getByTestId(
"row-my_bigquery_monitor-address-col-classifications",
).within(() => {
cy.getByTestId("no-classifications").should("exist");
cy.getByTestId("add-category-btn").should("not.exist");
});
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -290,14 +290,7 @@
"monitor_config_id": "my_bigquery_monitor",
"updated_at": null,
"source_modified": null,
"classifications": [
{
"label": "system",
"score": 1.0,
"aggregated_score": 0.55,
"classification_paradigm": "context"
}
],
"classifications": [],
"diff_status": "addition",
"child_diff_statuses": {},
"table_name": "consent-reports-20",
Expand All @@ -310,6 +303,23 @@
"my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.address.postal_code",
"my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.address.state"
]
},
{
"urn": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.No_categories",
"user_assigned_data_categories": [],
"name": "No_categories",
"description": null,
"monitor_config_id": "my_bigquery_monitor",
"updated_at": null,
"source_modified": null,
"classifications": [],
"diff_status": "addition",
"child_diff_statuses": {},
"table_name": "consent-reports-20",
"parent_table_urn": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20",
"schema_name": "test_dataset_1",
"database_name": "prj-bigquery-418515",
"sub_field_urns": []
}
],
"total": 9,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Flex, FlexProps } from "fidesui";

interface ClassificationCategoryBadgeProps extends FlexProps {
classification?: string | JSX.Element;
children: React.ReactNode;
}

const ClassificationCategoryBadge = ({
children,
onClick,
...props
}: ClassificationCategoryBadgeProps) => {
return (
<Flex
fontSize="xs"
alignItems="center"
gap={1.5}
px={1.5}
h="20px"
borderWidth="1px"
borderColor="gray.200"
borderRadius="sm"
cursor={onClick ? "pointer" : "default"}
_hover={onClick ? { bg: "gray.100" } : undefined}
onClick={onClick}
{...props}
>
{children}
</Flex>
);
};

export default ClassificationCategoryBadge;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
Badge,
Box,
ButtonProps,
CloseIcon,
EditIcon,
IconButton,
Expand All @@ -10,16 +10,32 @@ import {
import { useCallback, useState } from "react";

import useTaxonomies from "~/features/common/hooks/useTaxonomies";
import { StagedResource } from "~/types/api";
import { SparkleIcon } from "~/features/common/Icon/SparkleIcon";
import ClassificationCategoryBadge from "~/features/data-discovery-and-detection/ClassificationCategoryBadge";
import { DiscoveryMonitorItem } from "~/features/data-discovery-and-detection/types/DiscoveryMonitorItem";

import TaxonomySelectDropdown, {
TaxonomySelectOption,
} from "../common/dropdown/TaxonomySelectDropdown";
import { useOutsideClick } from "../common/hooks";
import { useUpdateResourceCategoryMutation } from "./discovery-detection.slice";

const AddCategoryButton = (props: ButtonProps) => (
<IconButton
variant="outline"
w="20px"
h="20px"
minW="20px"
borderRadius="sm"
icon={<SmallAddIcon />}
data-testid="add-category-btn"
aria-label="Add category"
{...props}
/>
);

interface TaxonomyDisplayAndEditProps {
resource: StagedResource;
resource: DiscoveryMonitorItem;
}

const TaxonomyDisplayAndEdit = ({ resource }: TaxonomyDisplayAndEditProps) => {
Expand All @@ -38,9 +54,9 @@ const TaxonomyDisplayAndEdit = ({ resource }: TaxonomyDisplayAndEditProps) => {

const userCategories = resource.user_assigned_data_categories ?? [];

if (!bestClassifiedCategory && !userCategories?.length) {
return <Badge textTransform="none">None</Badge>;
}
const noCategories = !bestClassifiedCategory && !userCategories?.length;

const hasSubfields = resource.sub_field_urns?.length;

const handleAddCategory = (option: TaxonomySelectOption) => {
updateResourceCategoryMutation({
Expand Down Expand Up @@ -74,52 +90,51 @@ const TaxonomyDisplayAndEdit = ({ resource }: TaxonomyDisplayAndEditProps) => {
overflowX="auto"
ref={ref}
>
{noCategories && (
<>
<ClassificationCategoryBadge data-testid="no-classifications">
None
</ClassificationCategoryBadge>
{/* resources with child fields can't have data categories */}
{!hasSubfields && (
<AddCategoryButton onClick={() => setIsAdding(true)} />
)}
</>
)}

{showUserCategories && (
<>
{userCategories.map((category) => (
<Badge
fontWeight="normal"
textTransform="none"
data-testid={`classification-${category}`}
px={1.5}
<ClassificationCategoryBadge
classification={getDataCategoryDisplayName(category)}
key={category}
data-testid={`user-classification-${category}`}
>
{getDataCategoryDisplayName(category)}
<IconButton
variant="ghost"
onClick={() => handleRemoveCategory(category)}
icon={<CloseIcon boxSize={2} />}
size="2xs"
mt={-0.5}
ml={2}
ml={1}
aria-label="Remove category"
/>
</Badge>
</ClassificationCategoryBadge>
))}
<IconButton
w="20px"
h="20px"
minW="20px"
borderRadius="sm"
icon={<SmallAddIcon />}
onClick={() => setIsAdding(true)}
data-testid="add-category-btn"
aria-label="Add category"
/>
<AddCategoryButton onClick={() => setIsAdding(true)} />
</>
)}

{showClassificationResult && (
<Badge
fontWeight="normal"
textTransform="none"
px={1.5}
<ClassificationCategoryBadge
onClick={() => setIsAdding(true)}
cursor="pointer"
data-testid={`classification-${bestClassifiedCategory}`}
>
{getDataCategoryDisplayName(bestClassifiedCategory)}{" "}
<EditIcon ml={0.5} mt={-0.5} />
</Badge>
<SparkleIcon mt={0.5} />
{getDataCategoryDisplayName(bestClassifiedCategory)}
<EditIcon />
</ClassificationCategoryBadge>
)}

{isAdding && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,46 @@
import { Badge } from "fidesui";
import { Badge, BadgeProps } from "fidesui";

import { ResourceChangeType } from "~/features/data-discovery-and-detection/types/ResourceChangeType";
import findResourceChangeType from "~/features/data-discovery-and-detection/utils/findResourceChangeType";
import { StagedResource } from "~/types/api";

interface ResultStatusBadgeProps extends BadgeProps {
colorScheme: string;
}

const ResultStatusBadge = ({ children, ...props }: ResultStatusBadgeProps) => {
return (
<Badge fontSize="xs" fontWeight="normal" textTransform="none" {...props}>
{children}
</Badge>
);
};

const ResultStatusBadgeCell = ({
result,
changeTypeOverride,
}: {
result: StagedResource;
changeTypeOverride?: ResourceChangeType;
}) => {
if (result.user_assigned_data_categories?.length) {
return <ResultStatusBadge colorScheme="green">Reviewed</ResultStatusBadge>;
}
const changeType = changeTypeOverride ?? findResourceChangeType(result);
switch (changeType) {
case ResourceChangeType.MUTED:
return (
<Badge fontSize="xs" colorScheme="gray">
Unmonitored
</Badge>
<ResultStatusBadge colorScheme="gray">Unmonitored</ResultStatusBadge>
);
case ResourceChangeType.MONITORED:
return (
<Badge fontSize="xs" colorScheme="green">
Monitoring
</Badge>
<ResultStatusBadge colorScheme="green">Monitoring</ResultStatusBadge>
);
default:
return (
<Badge fontSize="xs" colorScheme="orange">
<ResultStatusBadge colorScheme="orange">
Pending review
</Badge>
</ResultStatusBadge>
);
}
};
Expand Down

0 comments on commit 60d005e

Please sign in to comment.