Skip to content

Commit

Permalink
Action Center results MVP (#5622)
Browse files Browse the repository at this point in the history
  • Loading branch information
gilluminate authored Jan 8, 2025
1 parent 2d9f1ef commit 483d798
Show file tree
Hide file tree
Showing 24 changed files with 601 additions and 26 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ Changes can also be flagged with a GitHub label for tracking purposes. The URL o
## [Unreleased](https://github.com/ethyca/fides/compare/2.52.0...main)

### Added
- Added Action Center MVP behind new feature flag [#5622](https://github.com/ethyca/fides/pull/5622)
- Added cache-clearing methods to the `DBCache` model to allow deleting cache entries [#5629](https://github.com/ethyca/fides/pull/5629)

### Fixed
- Fixed issue where the custom report "reset" button was not working as expected [#5649](https://github.com/ethyca/fides/pull/5649)
- Fixed column ordering issue in the Data Map report [#5649](https://github.com/ethyca/fides/pull/5649)
- Fixed issue where the Data Map report filter dialog was missing an Accordion item label [#5649](https://github.com/ethyca/fides/pull/5649)


## [2.52.0](https://github.com/ethyca/fides/compare/2.51.2...2.52.0)

### Added
Expand Down
119 changes: 119 additions & 0 deletions clients/admin-ui/cypress/e2e/action-center.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { stubActionCenter, stubPlus } from "cypress/support/stubs";

import {
ACTION_CENTER_ROUTE,
INTEGRATION_MANAGEMENT_ROUTE,
} from "~/features/common/nav/v2/routes";

describe("Action center", () => {
beforeEach(() => {
cy.login();
stubPlus(true);
stubActionCenter();
});

describe("disabled web monitor", () => {
beforeEach(() => {
cy.intercept("GET", "/api/v1/config*", {
body: {
detection_discovery: {
website_monitor_enabled: false,
},
},
}).as("getTranslationConfig");
cy.visit(ACTION_CENTER_ROUTE);
});
it("should display a message that the web monitor is disabled", () => {
cy.wait("@getTranslationConfig");
cy.contains("currently disabled").should("exist");
});
});

describe("empty action center", () => {
beforeEach(() => {
cy.intercept("GET", "/api/v1/plus/discovery-monitor/aggregate-results*", {
fixture: "empty-pagination.json",
}).as("getMonitorResults");
cy.visit(ACTION_CENTER_ROUTE);
});
it("should display empty state", () => {
cy.wait("@getMonitorResults");
cy.get("[data-testid='search-bar']").should("exist");
cy.get(`[class*='ant-empty'] [class*='ant-empty-image']`).should("exist");
cy.get(
`[class*='ant-empty'] a[href="${INTEGRATION_MANAGEMENT_ROUTE}"]`,
).should("exist");
});
});

describe("Action center monitor results", () => {
const webMonitorKey = "my_web_monitor_2";
const integrationMonitorKey = "My_New_BQ_Monitor";
beforeEach(() => {
cy.visit(ACTION_CENTER_ROUTE);
});
it("should render the current monitor results", () => {
cy.get("[data-testid='Action center']").should("exist");
cy.wait("@getMonitorResults");
cy.get("[data-testid*='monitor-result-']").should("have.length", 3);
cy.get("[data-testid^='monitor-result-']").each((result) => {
const monitorKey = result
.attr("data-testid")
.replace("monitor-result-", "");
// linked title
cy.wrap(result)
.contains("assets detected")
.should("have.attr", "href", `${ACTION_CENTER_ROUTE}/${monitorKey}`);
// last monitored relative date with real date in tooltip
cy.wrap(result)
.find("[data-testid='monitor-date']")
.contains(" ago")
.realHover();
cy.get(".ant-tooltip-inner").should("contain", "December");
});
// description
cy.getByTestId(`monitor-result-${webMonitorKey}`).should(
"contain",
"92 Browser Requests, 5 Cookies detected.",
);
// monitor name
cy.getByTestId(`monitor-result-${webMonitorKey}`).should(
"contain",
"my web monitor 2",
);
});
it("should have appropriate actions for web monitors", () => {
cy.wait("@getMonitorResults");
// Add button
// TODO: [HJ-337] uncomment when Add button is implemented
// cy.getByTestId(`add-button-${webMonitorKey}`).should("exist");
// Review button
cy.getByTestId(`review-button-${webMonitorKey}`).should(
"have.attr",
"href",
`${ACTION_CENTER_ROUTE}/${webMonitorKey}`,
);
});
it.skip("Should have appropriate actions for Integrations monitors", () => {
cy.wait("@getMonitorResults");
// Classify button
cy.getByTestId(`review-button-${integrationMonitorKey}`).should(
"have.attr",
"href",
`${ACTION_CENTER_ROUTE}/${integrationMonitorKey}`,
);
// Ignore button
cy.getByTestId(`ignore-button-${integrationMonitorKey}`).should("exist");
});
it.skip("Should have appropriate actions for SSO monitors", () => {
cy.wait("@getMonitorResults");
// Add button
cy.getByTestId(`add-button-${webMonitorKey}`).should("exist");
// Ignore button
cy.getByTestId(`ignore-button-${webMonitorKey}`).should("exist");
});
it.skip("Should paginate results", () => {
// TODO: mock pagination and also test skeleton loading state
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"items": [
{
"name": "my web monitor 2",
"key": "my_web_monitor_2",
"last_monitored": "2024-12-17T17:31:20.791014Z",
"updates": {
"Browser Request": 92,
"Cookie": 5
},
"total_updates": 97
},
{
"name": "my web monitor 1",
"key": "my_web_monitor_1",
"last_monitored": "2024-12-17T17:31:02.319068Z",
"updates": {
"Browser Request": 201,
"Cookie": 24
},
"total_updates": 225
},
{
"name": "My New BQ Monitor",
"key": "My_New_BQ_Monitor",
"last_monitored": "2024-12-16T20:04:16.824025Z",
"updates": {
"Database": 2,
"Field": 216,
"Schema": 13,
"Table": 22
},
"total_updates": 253
}
],
"total": 3,
"page": 1,
"size": 25,
"pages": 1
}
13 changes: 13 additions & 0 deletions clients/admin-ui/cypress/support/stubs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,3 +502,16 @@ export const stubFidesCloud = () => {
domain_verification_records: [],
}).as("getFidesCloud");
};

export const stubActionCenter = () => {
cy.intercept("GET", "/api/v1/config*", {
body: {
detection_discovery: {
website_monitor_enabled: true,
},
},
}).as("getTranslationConfig");
cy.intercept("GET", "/api/v1/plus/discovery-monitor/aggregate-results*", {
fixture: "detection-discovery/results/aggregate-results",
}).as("getMonitorResults");
};
5 changes: 3 additions & 2 deletions clients/admin-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
},
"dependencies": {
"@ant-design/cssinjs": "^1.21.0",
"@date-fns/tz": "^1.2.0",
"@fontsource/inter": "^4.5.15",
"@monaco-editor/react": "^4.6.0",
"@reduxjs/toolkit": "^1.9.3",
Expand All @@ -40,8 +41,8 @@
"cytoscape": "^3.30.0",
"cytoscape-klay": "^3.1.4",
"d3-hierarchy": "^3.1.2",
"date-fns": "^2.29.3",
"date-fns-tz": "^2.0.0",
"date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"eslint-plugin-tailwindcss": "^3.17.4",
"fides-js": "^0.0.1",
"fidesui": "*",
Expand Down
2 changes: 1 addition & 1 deletion clients/admin-ui/src/features/common/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const SearchBar = ({
onChange(event.target.value);

return (
<Space.Compact className="w-96">
<Space.Compact className="w-96" data-testid="search-bar">
<Input
autoComplete="off"
value={search}
Expand Down
1 change: 1 addition & 0 deletions clients/admin-ui/src/features/common/api.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export const baseApi = createApi({
"Languages",
"Locations",
"Messaging Templates",
"Monitor Summary",
"Dictionary",
"System Vendors",
"Latest Scan",
Expand Down
7 changes: 7 additions & 0 deletions clients/admin-ui/src/features/common/nav/v2/nav-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ export const NAV_CONFIG: NavConfigGroup[] = [
{
title: "Detection & Discovery",
routes: [
{
title: "Action center",
path: routes.ACTION_CENTER_ROUTE,
scopes: [],
requiresFlag: "webMonitor",
requiresPlus: true,
},
{
title: "Activity",
path: routes.DETECTION_DISCOVERY_ACTIVITY_ROUTE,
Expand Down
1 change: 1 addition & 0 deletions clients/admin-ui/src/features/common/nav/v2/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const DATASET_COLLECTION_SUBFIELD_DETAIL_ROUTE =
"/dataset/[datasetId]/[collectionName]/[...subfieldNames]";

// Detection and discovery
export const ACTION_CENTER_ROUTE = "/data-discovery/action-center";
export const DETECTION_DISCOVERY_ACTIVITY_ROUTE = "/data-discovery/activity";
export const DATA_DETECTION_ROUTE = "/data-discovery/detection";
export const DATA_DETECTION_ROUTE_DETAIL =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const useServerSidePagination = () => {
const defaultPageIndex = 1;
const [pageSize, setPageSize] = useState(PAGE_SIZES[0]);
const [pageIndex, setPageIndex] = useState<number>(defaultPageIndex);
const [totalPages, setTotalPages] = useState<number | null>();
const [totalPages, setTotalPages] = useState<number | null | undefined>(1);
const onPreviousPageClick = useCallback(() => {
setPageIndex((prev) => prev - 1);
}, [setPageIndex]);
Expand All @@ -53,7 +53,7 @@ export const useServerSidePagination = () => {
setPageIndex((prev) => prev + 1);
}, [setPageIndex]);
const isNextPageDisabled = useMemo(
() => pageIndex === totalPages,
() => !!totalPages && (pageIndex === totalPages || totalPages < 2),
[pageIndex, totalPages],
);

Expand Down
6 changes: 5 additions & 1 deletion clients/admin-ui/src/features/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const debounce = (fn: (props?: any) => void, ms = 0) => {
};

export const formatDate = (value: string | number | Date): string =>
format(new Date(value), "MMMM d, Y, KK:mm:ss z");
format(new Date(value), "MMMM d, y, KK:mm:ss z");

export const utf8ToB64 = (str: string): string =>
window.btoa(unescape(encodeURIComponent(str)));
Expand Down Expand Up @@ -116,3 +116,7 @@ export const getOptionsFromMap = <T = string>(
label: value,
value: key,
}));

export const getWebsiteIconUrl = (hostname: string) => {
return `https://icons.duckduckgo.com/ip3/${hostname}.ico`;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { AntAlert as Alert, AntFlex as Flex, Spinner } from "fidesui";

import Layout from "~/features/common/Layout";

interface DisabledMonitorPageProps {
isConfigLoading: boolean;
}

const DISABLED_MONITOR_MESSAGE = "Action center is currently disabled.";

export const DisabledMonitorPage = ({
isConfigLoading,
}: DisabledMonitorPageProps) => (
<Layout title="Action center" mainProps={{ className: "h-full" }}>
<Flex justify="center" align="center" className="h-full">
{isConfigLoading ? (
<Spinner color="minos.500" />
) : (
<Alert
message="Coming soon..."
description={DISABLED_MONITOR_MESSAGE}
type="info"
showIcon
/>
)}
</Flex>
</Layout>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { AntButton as Button, AntEmpty as Empty } from "fidesui";
import NextLink from "next/link";

import { INTEGRATION_MANAGEMENT_ROUTE } from "~/features/common/nav/v2/routes";

export const EmptyMonitorResult = () => (
<Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
description="All caught up! Set up an integration monitor to track your infrastructure in greater detail."
>
<NextLink href={INTEGRATION_MANAGEMENT_ROUTE} passHref legacyBehavior>
<Button type="primary">Visit integrations</Button>
</NextLink>
</Empty>
);
Loading

0 comments on commit 483d798

Please sign in to comment.