diff --git a/CHANGELOG.md b/CHANGELOG.md index 1945ae355dc..5db2a2dbdfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ The types of changes are: ### Added - Added Gzip Middleware for responses [#5225](https://github.com/ethyca/fides/pull/5225) - Adding source and submitted_by fields to privacy requests (Fidesplus) [#5206](https://github.com/ethyca/fides/pull/5206) +- Added Action Required / Monitored / Unmonitored tabs to Data Detection & Discovery page [#5236](https://github.com/ethyca/fides/pull/5236) + ### Changed - Removed unused `username` parameter from the Delighted integration configuration [#5220](https://github.com/ethyca/fides/pull/5220) diff --git a/clients/admin-ui/cypress/e2e/discovery-detection.cy.ts b/clients/admin-ui/cypress/e2e/discovery-detection.cy.ts index a155d21344a..1125ada1363 100644 --- a/clients/admin-ui/cypress/e2e/discovery-detection.cy.ts +++ b/clients/admin-ui/cypress/e2e/discovery-detection.cy.ts @@ -165,12 +165,20 @@ describe("discovery and detection", () => { }).as("getFilteredDetectionTables"); cy.intercept( "GET", - "/api/v1/plus/discovery-monitor/results?*diff_status=monitored&diff_status=muted*", + "/api/v1/plus/discovery-monitor/results?diff_status=monitored*", { fixture: - "detection-discovery/results/detection/table-list-full-schema.json", + "detection-discovery/results/detection/table-list-monitored-tab-filter.json", }, - ).as("getAllDetectionTables"); + ).as("getAllMonitoredTables"); + cy.intercept( + "GET", + "/api/v1/plus/discovery-monitor/results?diff_status=muted*", + { + fixture: + "detection-discovery/results/detection/table-list-unmonitored-tab-filter.json", + }, + ).as("getAllMutedTables"); cy.visit( `${DATA_DETECTION_ROUTE}/my_bigquery_monitor.prj-bigquery-418515.test_dataset_1`, ); @@ -181,12 +189,12 @@ describe("discovery and detection", () => { cy.getByTestId("row-my_bigquery_monitor-consent-reports-20").should( "exist", ); + cy.getByTestId("row-my_bigquery_monitor-consent-reports-19").should( + "exist", + ); cy.getByTestId("row-my_bigquery_monitor-consent-reports-21").should( "not.exist", ); - cy.getByTestId("full-schema-toggle").within(() => { - cy.get("span").should("not.have.attr", "data-checked"); - }); }); it("should navigate to field view on row click", () => { @@ -198,35 +206,42 @@ describe("discovery and detection", () => { ); }); - describe("full schema view", () => { - it("should be able to toggle showing full schema", () => { - cy.getByTestId("full-schema-toggle").click(); - cy.wait("@getAllDetectionTables"); - cy.getByTestId( - "row-my_bigquery_monitor-consent-reports-21-col-status", - ).should("contain", "Unmonitored"); + describe("Tab filter views", () => { + it("should be able to switch to monitored tab", () => { + cy.getByTestId("tab-Monitored").click(); + cy.wait("@getAllMonitoredTables"); + cy.getByTestId( "row-my_bigquery_monitor-consent-reports-22-col-status", ).should("contain", "Monitoring"); }); - it("should allow muted tables to be unmuted", () => { - cy.getByTestId("full-schema-toggle").click(); + it("should allow monitored tables to be muted", () => { + cy.getByTestId("tab-Monitored").click(); cy.getByTestId( - "row-my_bigquery_monitor-consent-reports-21-col-actions", + "row-my_bigquery_monitor-consent-reports-22-col-actions", ).within(() => { - cy.getByTestId("action-Monitor").click(); - cy.wait("@unmuteResource"); + cy.getByTestId("action-Ignore").click(); + cy.wait("@ignoreResource"); }); }); - it("should allow monitored tables to be muted", () => { - cy.getByTestId("full-schema-toggle").click(); + it("should be able to switch to unmonitored tab", () => { + cy.getByTestId("tab-Unmonitored").click(); + cy.wait("@getAllMutedTables"); + cy.getByTestId( - "row-my_bigquery_monitor-consent-reports-22-col-actions", + "row-my_bigquery_monitor-consent-reports-21-col-status", + ).should("contain", "Unmonitored"); + }); + + it("should allow muted tables to be unmuted", () => { + cy.getByTestId("tab-Unmonitored").click(); + cy.getByTestId( + "row-my_bigquery_monitor-consent-reports-21-col-actions", ).within(() => { - cy.getByTestId("action-Ignore").click(); - cy.wait("@ignoreResource"); + cy.getByTestId("action-Monitor").click(); + cy.wait("@unmuteResource"); }); }); }); diff --git a/clients/admin-ui/cypress/fixtures/detection-discovery/results/detection/table-list-full-schema.json b/clients/admin-ui/cypress/fixtures/detection-discovery/results/detection/table-list-full-schema.json deleted file mode 100644 index d8bd5ada4b6..00000000000 --- a/clients/admin-ui/cypress/fixtures/detection-discovery/results/detection/table-list-full-schema.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "items": [ - { - "urn": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20", - "user_assigned_data_categories": [], - "name": "consent-reports-20", - "description": null, - "monitor_config_id": "my_bigquery_monitor", - "updated_at": null, - "source_modified": "2024-03-27T21:47:09.915000+00:00", - "classifications": [], - "diff_status": "addition", - "child_diff_statuses": { - "addition": 9 - }, - "parent_schema": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1", - "schema_name": "test_dataset_1", - "num_rows": 19, - "fields": [ - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Created", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Fides_user_device", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.User_geography", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Preference", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Notice_title", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Phone_number", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Request_origin", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Method", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Email" - ], - "database_name": "prj-bigquery-418515" - }, - { - "urn": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20", - "user_assigned_data_categories": [], - "name": "consent-reports-21", - "description": null, - "monitor_config_id": "my_bigquery_monitor", - "updated_at": null, - "source_modified": "2024-03-27T21:47:09.915000+00:00", - "classifications": [], - "diff_status": "muted", - "child_diff_statuses": {}, - "parent_schema": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1", - "schema_name": "test_dataset_1", - "num_rows": 19, - "fields": [ - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Created", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Fides_user_device", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.User_geography", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Preference", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Notice_title", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Phone_number", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Request_origin", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Method", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Email" - ], - "database_name": "prj-bigquery-418515" - }, - { - "urn": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20", - "user_assigned_data_categories": [], - "name": "consent-reports-22", - "description": null, - "monitor_config_id": "my_bigquery_monitor", - "updated_at": null, - "source_modified": "2024-03-27T21:47:09.915000+00:00", - "classifications": [], - "diff_status": "monitored", - "child_diff_statuses": {}, - "parent_schema": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1", - "schema_name": "test_dataset_1", - "num_rows": 19, - "fields": [ - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Created", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Fides_user_device", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.User_geography", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Preference", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Notice_title", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Phone_number", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Request_origin", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Method", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Email" - ], - "database_name": "prj-bigquery-418515" - }, - { - "urn": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-19", - "user_assigned_data_categories": [], - "name": "consent-reports-19", - "description": null, - "monitor_config_id": "my_bigquery_monitor", - "updated_at": null, - "source_modified": "2024-04-24T19:12:22.287000+00:00", - "classifications": [], - "diff_status": "addition", - "child_diff_statuses": { - "addition": 9 - }, - "parent_schema": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1", - "schema_name": "test_dataset_1", - "num_rows": 13, - "fields": [ - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-19.User_geography", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-19.Phone_number", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-19.Request_origin", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-19.Notice_title", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-19.Preference", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-19.Method", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-19.Email", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-19.Created", - "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-19.Fides_user_device" - ], - "database_name": "prj-bigquery-418515" - } - ], - "total": 2, - "page": 1, - "size": 25, - "pages": 1 -} diff --git a/clients/admin-ui/cypress/fixtures/detection-discovery/results/detection/table-list-monitored-tab-filter.json b/clients/admin-ui/cypress/fixtures/detection-discovery/results/detection/table-list-monitored-tab-filter.json new file mode 100644 index 00000000000..2dbfdd0ee8d --- /dev/null +++ b/clients/admin-ui/cypress/fixtures/detection-discovery/results/detection/table-list-monitored-tab-filter.json @@ -0,0 +1,35 @@ +{ + "items": [ + { + "urn": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20", + "user_assigned_data_categories": [], + "name": "consent-reports-22", + "description": null, + "monitor_config_id": "my_bigquery_monitor", + "updated_at": null, + "source_modified": "2024-03-27T21:47:09.915000+00:00", + "classifications": [], + "diff_status": "monitored", + "child_diff_statuses": {}, + "parent_schema": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1", + "schema_name": "test_dataset_1", + "num_rows": 19, + "fields": [ + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Created", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Fides_user_device", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.User_geography", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Preference", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Notice_title", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Phone_number", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Request_origin", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Method", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Email" + ], + "database_name": "prj-bigquery-418515" + } + ], + "total": 2, + "page": 1, + "size": 25, + "pages": 1 +} diff --git a/clients/admin-ui/cypress/fixtures/detection-discovery/results/detection/table-list-unmonitored-tab-filter.json b/clients/admin-ui/cypress/fixtures/detection-discovery/results/detection/table-list-unmonitored-tab-filter.json new file mode 100644 index 00000000000..33d071646de --- /dev/null +++ b/clients/admin-ui/cypress/fixtures/detection-discovery/results/detection/table-list-unmonitored-tab-filter.json @@ -0,0 +1,35 @@ +{ + "items": [ + { + "urn": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20", + "user_assigned_data_categories": [], + "name": "consent-reports-21", + "description": null, + "monitor_config_id": "my_bigquery_monitor", + "updated_at": null, + "source_modified": "2024-03-27T21:47:09.915000+00:00", + "classifications": [], + "diff_status": "muted", + "child_diff_statuses": {}, + "parent_schema": "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1", + "schema_name": "test_dataset_1", + "num_rows": 19, + "fields": [ + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Created", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Fides_user_device", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.User_geography", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Preference", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Notice_title", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Phone_number", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Request_origin", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Method", + "my_bigquery_monitor.prj-bigquery-418515.test_dataset_1.consent-reports-20.Email" + ], + "database_name": "prj-bigquery-418515" + } + ], + "total": 1, + "page": 1, + "size": 25, + "pages": 1 +} diff --git a/clients/admin-ui/src/features/common/DataTabsHeader.tsx b/clients/admin-ui/src/features/common/DataTabsHeader.tsx index 7cbdb96150f..cebea4a7fbb 100644 --- a/clients/admin-ui/src/features/common/DataTabsHeader.tsx +++ b/clients/admin-ui/src/features/common/DataTabsHeader.tsx @@ -5,15 +5,20 @@ import { FidesTab, TabData, TabListBorder } from "~/features/common/DataTabs"; interface DataTabsHeaderProps { data: Pick[]; border?: TabListBorder; + borderWidth?: TabsProps["borderWidth"]; } const DataTabsHeader = ({ data, border = "partial", + borderWidth = 2, ...other }: DataTabsHeaderProps & Omit) => ( - + {data.map((tab) => ( void; + filterTabs: { label: string }[]; +} + +const DetectionResultFilterTabs = ({ + filterTabs, + onChange, + filterTabIndex, +}: DetectionResultFilterTabsProps) => { + return ( + + ); +}; +export default DetectionResultFilterTabs; diff --git a/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDetectionResultColumns.tsx b/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDetectionResultColumns.tsx index fda31fd7c11..0205071f0b7 100644 --- a/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDetectionResultColumns.tsx +++ b/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDetectionResultColumns.tsx @@ -7,14 +7,17 @@ import FieldDataTypeCell from "~/features/data-discovery-and-detection/tables/ce import ResultStatusBadgeCell from "~/features/data-discovery-and-detection/tables/cells/ResultStatusBadgeCell"; import ResultStatusCell from "~/features/data-discovery-and-detection/tables/cells/ResultStatusCell"; import { DiscoveryMonitorItem } from "~/features/data-discovery-and-detection/types/DiscoveryMonitorItem"; +import { ResourceChangeType } from "~/features/data-discovery-and-detection/types/ResourceChangeType"; import { StagedResourceType } from "~/features/data-discovery-and-detection/types/StagedResourceType"; import findProjectFromUrn from "../utils/findProjectFromUrn"; const useDetectionResultColumns = ({ resourceType, + changeTypeOverride, }: { resourceType?: StagedResourceType; + changeTypeOverride?: ResourceChangeType; }) => { const columnHelper = createColumnHelper(); @@ -28,7 +31,12 @@ const useDetectionResultColumns = ({ const columns = [ columnHelper.accessor((row) => row.name, { id: "name", - cell: (props) => , + cell: (props) => ( + + ), header: (props) => , }), columnHelper.accessor((row) => row.urn, { @@ -40,7 +48,12 @@ const useDetectionResultColumns = ({ }), columnHelper.display({ id: "status", - cell: (props) => , + cell: (props) => ( + + ), header: (props) => , }), columnHelper.accessor((row) => row.system, { @@ -61,9 +74,18 @@ const useDetectionResultColumns = ({ columnHelper.display({ id: "actions", cell: (props) => ( - + ), header: "Actions", + size: 180, }), ]; return { columns }; @@ -73,7 +95,12 @@ const useDetectionResultColumns = ({ const columns = [ columnHelper.accessor((row) => row.name, { id: "name", - cell: (props) => , + cell: (props) => ( + + ), header: (props) => , }), columnHelper.accessor((row) => row.description, { @@ -83,7 +110,12 @@ const useDetectionResultColumns = ({ }), columnHelper.display({ id: "status", - cell: (props) => , + cell: (props) => ( + + ), header: (props) => , }), columnHelper.accessor((row) => row.monitor_config_id, { @@ -111,7 +143,12 @@ const useDetectionResultColumns = ({ const columns = [ columnHelper.accessor((row) => row.name, { id: "name", - cell: (props) => , + cell: (props) => ( + + ), header: (props) => , }), columnHelper.accessor((row) => row.source_data_type, { @@ -126,7 +163,12 @@ const useDetectionResultColumns = ({ }), columnHelper.display({ id: "status", - cell: (props) => , + cell: (props) => ( + + ), header: (props) => , }), columnHelper.accessor((row) => row.monitor_config_id, { diff --git a/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDetectionResultsFilterTabs.tsx b/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDetectionResultsFilterTabs.tsx new file mode 100644 index 00000000000..5dd7f69ba49 --- /dev/null +++ b/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDetectionResultsFilterTabs.tsx @@ -0,0 +1,44 @@ +import { useState } from "react"; + +import { ResourceChangeType } from "~/features/data-discovery-and-detection/types/ResourceChangeType"; +import { DiffStatus } from "~/types/api"; + +interface DetectionResultFiltersTabsProps { + initialFilterTabIndex?: number; +} + +const useDetectionResultsFilterTabs = ({ + initialFilterTabIndex = 0, +}: DetectionResultFiltersTabsProps) => { + const [filterTabIndex, setFilterTabIndex] = useState(initialFilterTabIndex); + + const filterTabs = [ + { + label: "Action Required", + filters: [DiffStatus.ADDITION, DiffStatus.REMOVAL], + childFilters: [DiffStatus.ADDITION, DiffStatus.REMOVAL], + }, + { + label: "Monitored", + filters: [DiffStatus.MONITORED], + childFilters: [], + changeTypeOverride: ResourceChangeType.MONITORED, + }, + { + label: "Unmonitored", + filters: [DiffStatus.MUTED], + childFilters: [], + changeTypeOverride: ResourceChangeType.MUTED, + }, + ]; + + return { + filterTabs, + filterTabIndex, + setFilterTabIndex, + activeDiffFilters: filterTabs[filterTabIndex].filters, + activeChildDiffFilters: filterTabs[filterTabIndex].childFilters, + activeChangeTypeOverride: filterTabs[filterTabIndex].changeTypeOverride, + }; +}; +export default useDetectionResultsFilterTabs; diff --git a/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDiscoveryResultColumns.tsx b/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDiscoveryResultColumns.tsx index 7be2426bf3a..15b6debd4d5 100644 --- a/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDiscoveryResultColumns.tsx +++ b/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDiscoveryResultColumns.tsx @@ -74,6 +74,7 @@ const useDiscoveryResultColumns = ({ ), header: "Actions", + size: 180, }), ]; return { columns }; diff --git a/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDiscoveryResultsFilterTabs.tsx b/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDiscoveryResultsFilterTabs.tsx new file mode 100644 index 00000000000..8959419891c --- /dev/null +++ b/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDiscoveryResultsFilterTabs.tsx @@ -0,0 +1,46 @@ +import { useState } from "react"; + +import { DiffStatus } from "~/types/api"; + +interface DiscoveryResultsFilterTabsProps { + initialFilterTabIndex?: number; +} + +export enum DiscoveryResultsFilterTabsIndexEnum { + ACTION_REQUIRED = 0, + UNMONITORED = 1, +} + +const useDiscoveryResultsFilterTabs = ({ + initialFilterTabIndex = 0, +}: DiscoveryResultsFilterTabsProps) => { + const [filterTabIndex, setFilterTabIndex] = useState(initialFilterTabIndex); + + const filterTabs = [ + { + label: "Action Required", + filters: [ + DiffStatus.CLASSIFICATION_ADDITION, + DiffStatus.CLASSIFICATION_UPDATE, + ], + childFilters: [ + DiffStatus.CLASSIFICATION_ADDITION, + DiffStatus.CLASSIFICATION_UPDATE, + ], + }, + { + label: "Unmonitored", + filters: [DiffStatus.MUTED], + childFilters: [], + }, + ]; + + return { + filterTabs, + filterTabIndex, + setFilterTabIndex, + activeDiffFilters: filterTabs[filterTabIndex].filters, + activeChildDiffFilters: filterTabs[filterTabIndex].childFilters, + }; +}; +export default useDiscoveryResultsFilterTabs; diff --git a/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDiscoveryRoutes.tsx b/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDiscoveryRoutes.tsx index f29452d15ea..5c02b89828f 100644 --- a/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDiscoveryRoutes.tsx +++ b/clients/admin-ui/src/features/data-discovery-and-detection/hooks/useDiscoveryRoutes.tsx @@ -12,16 +12,16 @@ const useDiscoveryRoutes = () => { const navigateToDetectionResults = ({ resourceUrn, - showFullSchema = false, + filterTabIndex, }: { resourceUrn: string; - showFullSchema?: boolean; + filterTabIndex?: number; }) => { router.push({ pathname: DATA_DETECTION_ROUTE_DETAIL, query: { resourceUrn, - showFullSchema, + filterTabIndex, }, }); }; diff --git a/clients/admin-ui/src/features/data-discovery-and-detection/tables/DetectionResultTable.tsx b/clients/admin-ui/src/features/data-discovery-and-detection/tables/DetectionResultTable.tsx index 43e144b138c..5f3f5591bc2 100644 --- a/clients/admin-ui/src/features/data-discovery-and-detection/tables/DetectionResultTable.tsx +++ b/clients/admin-ui/src/features/data-discovery-and-detection/tables/DetectionResultTable.tsx @@ -7,7 +7,7 @@ import { getGroupedRowModel, useReactTable, } from "@tanstack/react-table"; -import { Box, Flex, Switch, Text, VStack } from "fidesui"; +import { Box, Flex, Text, VStack } from "fidesui"; import { useRouter } from "next/router"; import { useEffect, useMemo, useState } from "react"; @@ -18,15 +18,17 @@ import { TableSkeletonLoader, useServerSidePagination, } from "~/features/common/table/v2"; +import DetectionResultFilterTabs from "~/features/data-discovery-and-detection/DetectionResultFilterTabs"; import { useGetMonitorResultsQuery } from "~/features/data-discovery-and-detection/discovery-detection.slice"; import useDetectionResultColumns from "~/features/data-discovery-and-detection/hooks/useDetectionResultColumns"; +import useDetectionResultFilterTabs from "~/features/data-discovery-and-detection/hooks/useDetectionResultsFilterTabs"; import useDiscoveryRoutes from "~/features/data-discovery-and-detection/hooks/useDiscoveryRoutes"; import IconLegendTooltip from "~/features/data-discovery-and-detection/IndicatorLegend"; import { StagedResourceType } from "~/features/data-discovery-and-detection/types/StagedResourceType"; import { findResourceType } from "~/features/data-discovery-and-detection/utils/findResourceType"; import getResourceRowName from "~/features/data-discovery-and-detection/utils/getResourceRowName"; import isNestedField from "~/features/data-discovery-and-detection/utils/isNestedField"; -import { DiffStatus, StagedResource } from "~/types/api"; +import { StagedResource } from "~/types/api"; import { SearchInput } from "../SearchInput"; @@ -66,27 +68,18 @@ const DetectionResultTable = ({ resourceUrn }: MonitorResultTableProps) => { const router = useRouter(); const [searchQuery, setSearchQuery] = useState(""); - const [isShowingFullSchema, setIsShowingFullSchema] = useState( - router.query?.showFullSchema === "true" || false, - ); - - const diffStatusFilter: DiffStatus[] = [ - DiffStatus.ADDITION, - DiffStatus.REMOVAL, - ]; - if (isShowingFullSchema) { - diffStatusFilter.push(DiffStatus.MONITORED); - diffStatusFilter.push(DiffStatus.MUTED); - } - - const childDiffStatusFilter: DiffStatus[] = [ - DiffStatus.ADDITION, - DiffStatus.REMOVAL, - ]; - if (isShowingFullSchema) { - childDiffStatusFilter.push(DiffStatus.MONITORED); - childDiffStatusFilter.push(DiffStatus.MUTED); - } + const { + filterTabs, + setFilterTabIndex, + filterTabIndex, + activeDiffFilters, + activeChildDiffFilters, + activeChangeTypeOverride, + } = useDetectionResultFilterTabs({ + initialFilterTabIndex: router.query?.filterTabIndex + ? Number(router.query?.filterTabIndex) + : undefined, + }); const { PAGE_SIZES, @@ -105,7 +98,13 @@ const DetectionResultTable = ({ resourceUrn }: MonitorResultTableProps) => { useEffect(() => { resetPageIndexToDefault(); - }, [resourceUrn, searchQuery, resetPageIndexToDefault]); + }, [ + resourceUrn, + searchQuery, + resetPageIndexToDefault, + activeDiffFilters, + activeChildDiffFilters, + ]); const { isFetching, @@ -115,14 +114,17 @@ const DetectionResultTable = ({ resourceUrn }: MonitorResultTableProps) => { staged_resource_urn: resourceUrn, page: pageIndex, size: pageSize, - child_diff_status: childDiffStatusFilter, - diff_status: diffStatusFilter, + child_diff_status: activeChildDiffFilters, + diff_status: activeDiffFilters, search: searchQuery, }); const resourceType = findResourceType(resources?.items[0]); - const { columns } = useDetectionResultColumns({ resourceType }); + const { columns } = useDetectionResultColumns({ + resourceType, + changeTypeOverride: activeChangeTypeOverride, + }); const { items: data, @@ -144,7 +146,7 @@ const DetectionResultTable = ({ resourceUrn }: MonitorResultTableProps) => { const handleRowClicked = (row: StagedResource) => navigateToDetectionResults({ resourceUrn: row.urn, - showFullSchema: isShowingFullSchema, + filterTabIndex, }); const getRowIsClickable = (row: StagedResource) => @@ -166,6 +168,11 @@ const DetectionResultTable = ({ resourceUrn }: MonitorResultTableProps) => { return ( <> + { - - setIsShowingFullSchema(!isShowingFullSchema)} - colorScheme="purple" - data-testid="full-schema-toggle" - /> - - Show full schema - - { - const diffStatusFilter: DiffStatus[] = [ - DiffStatus.CLASSIFICATION_ADDITION, - DiffStatus.CLASSIFICATION_UPDATE, - ]; + const router = useRouter(); + const [searchQuery, setSearchQuery] = useState(""); - const childDiffStatusFilter: DiffStatus[] = [ - DiffStatus.CLASSIFICATION_ADDITION, - DiffStatus.CLASSIFICATION_UPDATE, - ]; + const { + filterTabs, + setFilterTabIndex, + filterTabIndex, + activeDiffFilters, + activeChildDiffFilters, + } = useDiscoveryResultsFilterTabs({ + initialFilterTabIndex: router.query?.filterTabIndex + ? Number(router.query?.filterTabIndex) + : undefined, + }); - const [searchQuery, setSearchQuery] = useState(""); const [rowSelection, setRowSelection] = useState({}); const { @@ -99,7 +104,13 @@ const DiscoveryResultTable = ({ resourceUrn }: MonitorResultTableProps) => { useEffect(() => { resetPageIndexToDefault(); - }, [resourceUrn, searchQuery, resetPageIndexToDefault]); + }, [ + resourceUrn, + searchQuery, + resetPageIndexToDefault, + activeDiffFilters, + activeChildDiffFilters, + ]); const { isFetching, @@ -109,8 +120,8 @@ const DiscoveryResultTable = ({ resourceUrn }: MonitorResultTableProps) => { staged_resource_urn: resourceUrn, page: pageIndex, size: pageSize, - child_diff_status: childDiffStatusFilter, - diff_status: diffStatusFilter, + child_diff_status: activeChildDiffFilters, + diff_status: activeDiffFilters, search: searchQuery, }); @@ -163,6 +174,11 @@ const DiscoveryResultTable = ({ resourceUrn }: MonitorResultTableProps) => { return ( <> + @@ -173,9 +189,11 @@ const DiscoveryResultTable = ({ resourceUrn }: MonitorResultTableProps) => { {resourceType === StagedResourceType.TABLE && !!selectedUrns.length && ( )} - {resourceType === StagedResourceType.FIELD && ( - - )} + {resourceType === StagedResourceType.FIELD && + filterTabIndex !== + DiscoveryResultsFilterTabsIndexEnum.UNMONITORED && ( + + )} { +const DetectionItemActionsCell = ({ + resource, + ignoreChildActions = false, +}: DetectionItemActionProps) => { const resourceType = findResourceType(resource); const [confirmResourceMutation, { isLoading: confirmIsLoading }] = useConfirmResourceMutation(); @@ -44,11 +48,15 @@ const DetectionItemActionsCell = ({ resource }: DetectionItemActionProps) => { (!isFieldType && diffStatus === DiffStatus.ADDITION); const showMuteAction = diffStatus !== DiffStatus.MUTED; const showUnmuteAction = diffStatus === DiffStatus.MUTED; - const showConfirmAction = - diffStatus === DiffStatus.MONITORED && + + const childDiffHasChanges = childDiffStatus && (childDiffStatus[DiffStatus.ADDITION] || childDiffStatus[DiffStatus.REMOVAL]); + const showConfirmAction = + diffStatus === DiffStatus.MONITORED && + !ignoreChildActions && + childDiffHasChanges; return ( e.stopPropagation()}> @@ -73,7 +81,7 @@ const DetectionItemActionsCell = ({ resource }: DetectionItemActionProps) => { {showUnmuteAction && ( : } + icon={} onClick={async () => { await unmuteResourceMutation({ staged_resource_urn: resource.urn, @@ -109,7 +117,7 @@ const DetectionItemActionsCell = ({ resource }: DetectionItemActionProps) => { {showMuteAction && ( : } + icon={} onClick={async () => { await muteResourceMutation({ staged_resource_urn: resource.urn,