From 8064fd60cbbb24a6a1276cb3e4406875b5c0547d Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Mon, 15 Jul 2024 16:46:51 -0300 Subject: [PATCH 01/24] PROD-1397 Update models --- clients/admin-ui/src/types/api/index.ts | 1 + .../types/api/models/Page_BasicSystemResponse_.ts | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 clients/admin-ui/src/types/api/models/Page_BasicSystemResponse_.ts diff --git a/clients/admin-ui/src/types/api/index.ts b/clients/admin-ui/src/types/api/index.ts index 54ea0a83c5..7d270549a5 100644 --- a/clients/admin-ui/src/types/api/index.ts +++ b/clients/admin-ui/src/types/api/index.ts @@ -247,6 +247,7 @@ export type { NotificationApplicationConfig } from "./models/NotificationApplica export type { OktaConfig } from "./models/OktaConfig"; export type { Organization } from "./models/Organization"; export type { OrganizationMetadata } from "./models/OrganizationMetadata"; +export type { Page_BasicSystemResponse_ } from "./models/Page_BasicSystemResponse_"; export type { Page_ClassifyInstanceResponseValues_ } from "./models/Page_ClassifyInstanceResponseValues_"; export type { Page_ConnectionConfigurationResponse_ } from "./models/Page_ConnectionConfigurationResponse_"; export type { Page_ConnectionSystemTypeMap_ } from "./models/Page_ConnectionSystemTypeMap_"; diff --git a/clients/admin-ui/src/types/api/models/Page_BasicSystemResponse_.ts b/clients/admin-ui/src/types/api/models/Page_BasicSystemResponse_.ts new file mode 100644 index 0000000000..8a8ef4ec75 --- /dev/null +++ b/clients/admin-ui/src/types/api/models/Page_BasicSystemResponse_.ts @@ -0,0 +1,13 @@ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { BasicSystemResponse } from "./BasicSystemResponse"; + +export type Page_BasicSystemResponse_ = { + items: Array; + total: number; + page: number; + size: number; + pages?: number; +}; From d89581ae8fedf80dad88a60bfed815bb46da412f Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Mon, 15 Jul 2024 18:52:16 -0300 Subject: [PATCH 02/24] PROD-1397 Update system page to a table ui and using paginated endpoints --- .../src/features/common/nav/v2/nav-config.ts | 2 +- .../src/features/common/nav/v2/routes.ts | 1 + .../system-data-flow/DataFlowSystemsModal.tsx | 5 +- .../src/features/system/SystemCard.tsx | 120 -------- .../src/features/system/SystemsManagement.tsx | 52 ---- .../src/features/system/system.slice.ts | 15 + clients/admin-ui/src/pages/systems/index.tsx | 283 +++++++++++++++++- 7 files changed, 290 insertions(+), 188 deletions(-) delete mode 100644 clients/admin-ui/src/features/system/SystemCard.tsx delete mode 100644 clients/admin-ui/src/features/system/SystemsManagement.tsx diff --git a/clients/admin-ui/src/features/common/nav/v2/nav-config.ts b/clients/admin-ui/src/features/common/nav/v2/nav-config.ts index 1a08a5b1f7..0d5126d218 100644 --- a/clients/admin-ui/src/features/common/nav/v2/nav-config.ts +++ b/clients/admin-ui/src/features/common/nav/v2/nav-config.ts @@ -71,7 +71,7 @@ export const NAV_CONFIG: NavConfigGroup[] = [ scopes: [ScopeRegistryEnum.DATAMAP_READ], }, { - title: "Systems & vendors", + title: "Systems", path: routes.SYSTEM_ROUTE, scopes: [ScopeRegistryEnum.SYSTEM_READ], }, diff --git a/clients/admin-ui/src/features/common/nav/v2/routes.ts b/clients/admin-ui/src/features/common/nav/v2/routes.ts index cf44fb8cc2..d1f4955a39 100644 --- a/clients/admin-ui/src/features/common/nav/v2/routes.ts +++ b/clients/admin-ui/src/features/common/nav/v2/routes.ts @@ -8,6 +8,7 @@ export const ADD_SYSTEMS_MULTIPLE_ROUTE = "/add-systems/multiple"; export const DATAMAP_ROUTE = "/datamap"; export const REPORTING_DATAMAP_ROUTE = "/reporting/datamap"; export const SYSTEM_ROUTE = "/systems"; +export const EDIT_SYSTEM_ROUTE = "/systems/configure/[id]"; export const CLASSIFY_SYSTEMS_ROUTE = "/classify-systems"; export const DATASET_ROUTE = "/dataset"; diff --git a/clients/admin-ui/src/features/common/system-data-flow/DataFlowSystemsModal.tsx b/clients/admin-ui/src/features/common/system-data-flow/DataFlowSystemsModal.tsx index 2db34544da..8c46395127 100644 --- a/clients/admin-ui/src/features/common/system-data-flow/DataFlowSystemsModal.tsx +++ b/clients/admin-ui/src/features/common/system-data-flow/DataFlowSystemsModal.tsx @@ -21,7 +21,6 @@ import { import { useFormikContext } from "formik"; import { ChangeEvent, useMemo, useState } from "react"; -import { SEARCH_FILTER } from "~/features/system/SystemsManagement"; import { DataFlow, System } from "~/types/api"; import DataFlowSystemsTable from "./DataFlowSystemsTable"; @@ -34,6 +33,10 @@ type Props = { flowType: string; }; +export const SEARCH_FILTER = (system: System, search: string) => + system.name?.toLocaleLowerCase().includes(search.toLocaleLowerCase()) || + system.description?.toLocaleLowerCase().includes(search.toLocaleLowerCase()); + const DataFlowSystemsModal = ({ currentSystem, systems, diff --git a/clients/admin-ui/src/features/system/SystemCard.tsx b/clients/admin-ui/src/features/system/SystemCard.tsx deleted file mode 100644 index 7cd3d576f1..0000000000 --- a/clients/admin-ui/src/features/system/SystemCard.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { - Box, - Heading, - IconButton, - Menu, - MenuButton, - MenuItem, - MenuList, - MoreIcon, - Text, - useDisclosure, - useToast, -} from "fidesui"; -import Link from "next/link"; -import { useRouter } from "next/router"; - -import { useAppDispatch } from "~/app/hooks"; -import ConfirmationModal from "~/features/common/modals/ConfirmationModal"; -import { SYSTEM_ROUTE } from "~/features/common/nav/v2/routes"; -import Restrict from "~/features/common/Restrict"; -import { ScopeRegistryEnum, System } from "~/types/api"; - -import { getErrorMessage, isErrorResult } from "../common/helpers"; -import { errorToastParams, successToastParams } from "../common/toast"; -import { setActiveSystem, useDeleteSystemMutation } from "./system.slice"; - -interface SystemCardProps { - system: System; -} -const SystemCard = ({ system }: SystemCardProps) => { - const { - isOpen: deleteIsOpen, - onOpen: onDeleteOpen, - onClose: onDeleteClose, - } = useDisclosure(); - const toast = useToast(); - const dispatch = useAppDispatch(); - const router = useRouter(); - - const [deleteSystem] = useDeleteSystemMutation(); - - const handleEdit = () => { - dispatch(setActiveSystem(system)); - router.push(`${SYSTEM_ROUTE}/configure/${system.fides_key}`); - }; - - const handleDelete = async () => { - const result = await deleteSystem(system.fides_key); - if (isErrorResult(result)) { - toast(errorToastParams(getErrorMessage(result.error))); - } else { - toast(successToastParams("Successfully deleted system")); - } - onDeleteClose(); - }; - - const systemName = - system.name === "" || system.name == null ? system.fides_key : system.name; - - return ( - - - - - {systemName} - - - {system.description} - - - - - } - aria-label="more actions" - variant="unstyled" - size="sm" - data-testid="more-btn" - m={1} - /> - - - Edit - - - - Delete - - - - - - - You are about to permanently delete the system{" "} - - {systemName} - - . - - Are you sure you would like to continue? - - } - /> - - ); -}; - -export default SystemCard; diff --git a/clients/admin-ui/src/features/system/SystemsManagement.tsx b/clients/admin-ui/src/features/system/SystemsManagement.tsx deleted file mode 100644 index a099bd6257..0000000000 --- a/clients/admin-ui/src/features/system/SystemsManagement.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { Box } from "fidesui"; -import { useMemo, useState } from "react"; - -import BorderGrid from "~/features/common/BorderGrid"; -import SearchBar from "~/features/common/SearchBar"; -import SystemCard from "~/features/system/SystemCard"; -import { System } from "~/types/api"; - -export const SEARCH_FILTER = (system: System, search: string) => - system.name?.toLocaleLowerCase().includes(search.toLocaleLowerCase()) || - system.description?.toLocaleLowerCase().includes(search.toLocaleLowerCase()); - -interface Props { - systems: System[] | undefined; -} -const SystemsManagement = ({ systems }: Props) => { - const [searchFilter, setSearchFilter] = useState(""); - - const filteredSystems = useMemo(() => { - if (!systems) { - return []; - } - - return systems.filter((s) => SEARCH_FILTER(s, searchFilter)); - }, [systems, searchFilter]); - - if (!systems || !systems.length) { - return
No systems registered.
; - } - - return ( - - - - - - columns={3} - items={filteredSystems} - renderItem={(system) => } - /> - - ); -}; - -export default SystemsManagement; diff --git a/clients/admin-ui/src/features/system/system.slice.ts b/clients/admin-ui/src/features/system/system.slice.ts index beca37cd1a..cb198b4397 100644 --- a/clients/admin-ui/src/features/system/system.slice.ts +++ b/clients/admin-ui/src/features/system/system.slice.ts @@ -6,6 +6,7 @@ import { BulkPutConnectionConfiguration, ConnectionConfigurationResponse, CreateConnectionConfigurationWithSecrets, + Page_BasicSystemResponse_, System, SystemResponse, TestStatusMessage, @@ -22,6 +23,11 @@ interface UpsertResponse { updated: number; } +interface PaginationParams { + page: number; + size: number; +} + export type ConnectionConfigSecretsRequest = { systemFidesKey: string; secrets: { @@ -31,6 +37,14 @@ export type ConnectionConfigSecretsRequest = { const systemApi = baseApi.injectEndpoints({ endpoints: (build) => ({ + getSystems: build.query({ + query: (params) => ({ + method: "GET", + url: `system`, + params, + }), + providesTags: () => ["System"], + }), getAllSystems: build.query({ query: () => ({ url: `system` }), providesTags: () => ["System"], @@ -158,6 +172,7 @@ const systemApi = baseApi.injectEndpoints({ }); export const { + useGetSystemsQuery, useGetAllSystemsQuery, useGetSystemByFidesKeyQuery, useCreateSystemMutation, diff --git a/clients/admin-ui/src/pages/systems/index.tsx b/clients/admin-ui/src/pages/systems/index.tsx index 13062c3aa3..10f29a2129 100644 --- a/clients/admin-ui/src/pages/systems/index.tsx +++ b/clients/admin-ui/src/pages/systems/index.tsx @@ -1,30 +1,285 @@ -import { Spinner } from "fidesui"; +/* eslint-disable react/no-unstable-nested-components */ +/* eslint-disable @typescript-eslint/no-use-before-define */ +import { + createColumnHelper, + getCoreRowModel, + getFilteredRowModel, + getSortedRowModel, + useReactTable, +} from "@tanstack/react-table"; +import { + Button, + ConfirmationModal, + HStack, + Text, + useDisclosure, + useToast, + VStack, +} from "fidesui"; import type { NextPage } from "next"; -import React from "react"; +import NextLink from "next/link"; +import { useRouter } from "next/router"; +import React, { useEffect, useMemo } from "react"; +import { useAppDispatch } from "~/app/hooks"; +import { getErrorMessage } from "~/features/common/helpers"; import Layout from "~/features/common/Layout"; +import { + ADD_SYSTEMS_ROUTE, + EDIT_SYSTEM_ROUTE, +} from "~/features/common/nav/v2/routes"; import PageHeader from "~/features/common/PageHeader"; -import { useGetAllSystemsQuery } from "~/features/system"; -import SystemsManagement from "~/features/system/SystemsManagement"; +import Restrict from "~/features/common/Restrict"; +import { + DefaultCell, + DefaultHeaderCell, + FidesTableV2, + PaginationBar, + TableSkeletonLoader, + useServerSidePagination, +} from "~/features/common/table/v2"; +import { errorToastParams, successToastParams } from "~/features/common/toast"; +import { + setActiveSystem, + useDeleteSystemMutation, + useGetSystemsQuery, +} from "~/features/system"; +import { BasicSystemResponse, ScopeRegistryEnum } from "~/types/api"; +import { isErrorResult } from "~/types/errors"; -const useSystemsData = () => { - const { data, isLoading } = useGetAllSystemsQuery(); +const columnHelper = createColumnHelper(); - return { - isLoading, - systems: data, - }; +const EMPTY_RESPONSE = { + items: [], + total: 0, + page: 1, + size: 20, + pages: 1, }; const Systems: NextPage = () => { - const { isLoading, systems } = useSystemsData(); + const router = useRouter(); + const dispatch = useAppDispatch(); + const toast = useToast(); + const { + isOpen: deleteIsOpen, + onOpen: onDeleteOpen, + onClose: onDeleteClose, + } = useDisclosure(); + const [deleteSystem] = useDeleteSystemMutation(); + const [selectedSystemForDelete, setSelectedSystemForDelete] = + React.useState(null); + + const { + PAGE_SIZES, + pageSize, + setPageSize, + onPreviousPageClick, + isPreviousPageDisabled, + onNextPageClick, + isNextPageDisabled, + startRange, + endRange, + pageIndex, + setTotalPages, + } = useServerSidePagination(); + + const { + data: systemsResponse, + isLoading, + isFetching, + } = useGetSystemsQuery({ + page: pageIndex, + size: pageSize, + }); + + const { + items: data, + total: totalRows, + pages: totalPages, + } = useMemo(() => systemsResponse ?? EMPTY_RESPONSE, [systemsResponse]); + + useEffect(() => { + setTotalPages(totalPages); + }, [totalPages, setTotalPages]); + + const getSystemName = (system: BasicSystemResponse) => + system.name && !(system.name === "") ? system.name : system.fides_key; + + const handleEdit = (system: BasicSystemResponse) => { + dispatch(setActiveSystem(system)); + router.push({ + pathname: EDIT_SYSTEM_ROUTE, + query: { + id: system.fides_key, + }, + }); + }; + + const handleDelete = async (system: BasicSystemResponse) => { + const result = await deleteSystem(system.fides_key); + if (isErrorResult(result)) { + toast(errorToastParams(getErrorMessage(result.error))); + } else { + toast(successToastParams("Successfully deleted system")); + } + onDeleteClose(); + }; + + const columns = useMemo( + () => [ + columnHelper.accessor((row) => row.name, { + id: "name", + cell: (props) => ( + + ), + header: (props) => , + size: 200, + }), + columnHelper.accessor((row) => row.description, { + id: "description", + cell: (props) => , + header: (props) => , + size: 200, + }), + columnHelper.accessor((row) => row.administrating_department, { + id: "department", + cell: (props) => , + header: (props) => , + size: 200, + }), + columnHelper.display({ + id: "actions", + header: "Actions", + cell: ({ row }) => { + const system = row.original; + return ( + + + + + + + ); + }, + meta: { + disableRowClick: true, + }, + }), + ], + [] + ); + + const tableInstance = useReactTable({ + getCoreRowModel: getCoreRowModel(), + getFilteredRowModel: getFilteredRowModel(), + getSortedRowModel: getSortedRowModel(), + columns, + data, + }); return ( - - - {isLoading ? : } + + + + View and manage recently detected systems and vendors here. + + + {isLoading ? ( + + ) : ( + } + onRowClick={handleEdit} + /> + )} + + + handleDelete} + title={`Delete ${ + selectedSystemForDelete && getSystemName(selectedSystemForDelete) + }`} + message={ + <> + + You are about to permanently delete the system{" "} + + {selectedSystemForDelete && + getSystemName(selectedSystemForDelete)} + + . + + Are you sure you would like to continue? + + } + /> ); }; +const EmptyTableNotice = () => ( + + + + No systems found. + + + Click "Add a system" to add your first system to Fides. + + + + + + +); + export default Systems; From 23fe1c12b9720446b4fdc8c8447261ee8a0bb8ea Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Mon, 15 Jul 2024 19:06:08 -0300 Subject: [PATCH 03/24] PROD-1397 Add search bar and edit/delete icons --- .../src/features/system/system.slice.ts | 8 ++- clients/admin-ui/src/pages/systems/index.tsx | 62 ++++++++++++++----- 2 files changed, 54 insertions(+), 16 deletions(-) diff --git a/clients/admin-ui/src/features/system/system.slice.ts b/clients/admin-ui/src/features/system/system.slice.ts index cb198b4397..41fc0a864a 100644 --- a/clients/admin-ui/src/features/system/system.slice.ts +++ b/clients/admin-ui/src/features/system/system.slice.ts @@ -27,6 +27,9 @@ interface PaginationParams { page: number; size: number; } +interface SearchParams { + search?: string; +} export type ConnectionConfigSecretsRequest = { systemFidesKey: string; @@ -37,7 +40,10 @@ export type ConnectionConfigSecretsRequest = { const systemApi = baseApi.injectEndpoints({ endpoints: (build) => ({ - getSystems: build.query({ + getSystems: build.query< + Page_BasicSystemResponse_, + PaginationParams & SearchParams + >({ query: (params) => ({ method: "GET", url: `system`, diff --git a/clients/admin-ui/src/pages/systems/index.tsx b/clients/admin-ui/src/pages/systems/index.tsx index 10f29a2129..9d17ddd62d 100644 --- a/clients/admin-ui/src/pages/systems/index.tsx +++ b/clients/admin-ui/src/pages/systems/index.tsx @@ -10,7 +10,9 @@ import { import { Button, ConfirmationModal, + EditIcon, HStack, + IconButton, Text, useDisclosure, useToast, @@ -19,10 +21,11 @@ import { import type { NextPage } from "next"; import NextLink from "next/link"; import { useRouter } from "next/router"; -import React, { useEffect, useMemo } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import { useAppDispatch } from "~/app/hooks"; import { getErrorMessage } from "~/features/common/helpers"; +import { TrashCanOutlineIcon } from "~/features/common/Icon/TrashCanOutlineIcon"; import Layout from "~/features/common/Layout"; import { ADD_SYSTEMS_ROUTE, @@ -34,7 +37,9 @@ import { DefaultCell, DefaultHeaderCell, FidesTableV2, + GlobalFilterV2, PaginationBar, + TableActionBar, TableSkeletonLoader, useServerSidePagination, } from "~/features/common/table/v2"; @@ -82,8 +87,15 @@ const Systems: NextPage = () => { endRange, pageIndex, setTotalPages, + resetPageIndexToDefault, } = useServerSidePagination(); + const [globalFilter, setGlobalFilter] = useState(); + const updateGlobalFilter = (searchTerm: string) => { + resetPageIndexToDefault(); + setGlobalFilter(searchTerm); + }; + const { data: systemsResponse, isLoading, @@ -91,6 +103,7 @@ const Systems: NextPage = () => { } = useGetSystemsQuery({ page: pageIndex, size: pageSize, + search: globalFilter, }); const { @@ -155,23 +168,28 @@ const Systems: NextPage = () => { const system = row.original; return ( - + /> - + /> ); @@ -202,11 +220,25 @@ const Systems: NextPage = () => { {isLoading ? ( ) : ( - } - onRowClick={handleEdit} - /> + <> + + + + { + // here something + } + + + } + onRowClick={handleEdit} + /> + )} Date: Mon, 15 Jul 2024 19:11:33 -0300 Subject: [PATCH 04/24] PROD-1397 Add column table --- clients/admin-ui/src/pages/systems/index.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/clients/admin-ui/src/pages/systems/index.tsx b/clients/admin-ui/src/pages/systems/index.tsx index 9d17ddd62d..f130140970 100644 --- a/clients/admin-ui/src/pages/systems/index.tsx +++ b/clients/admin-ui/src/pages/systems/index.tsx @@ -153,7 +153,7 @@ const Systems: NextPage = () => { id: "description", cell: (props) => , header: (props) => , - size: 200, + size: 300, }), columnHelper.accessor((row) => row.administrating_department, { id: "department", @@ -161,6 +161,16 @@ const Systems: NextPage = () => { header: (props) => , size: 200, }), + columnHelper.accessor((row) => row.processes_personal_data, { + id: "processes_personal_data", + cell: (props) => ( + + ), + header: (props) => ( + + ), + size: 100, + }), columnHelper.display({ id: "actions", header: "Actions", From 55ff6efdf67641d303bf77a6b779a13cf7a4b338 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Mon, 15 Jul 2024 19:23:13 -0300 Subject: [PATCH 05/24] PROD-1397 Fix lint issues --- .../user-management/AssignSystemsModal.tsx | 5 +++- clients/admin-ui/src/pages/systems/index.tsx | 25 +++++++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/clients/admin-ui/src/features/user-management/AssignSystemsModal.tsx b/clients/admin-ui/src/features/user-management/AssignSystemsModal.tsx index 1a3fadde17..be22664b78 100644 --- a/clients/admin-ui/src/features/user-management/AssignSystemsModal.tsx +++ b/clients/admin-ui/src/features/user-management/AssignSystemsModal.tsx @@ -21,11 +21,14 @@ import { ChangeEvent, useMemo, useState } from "react"; import SearchBar from "~/features/common/SearchBar"; import { useGetAllSystemsQuery } from "~/features/system"; -import { SEARCH_FILTER } from "~/features/system/SystemsManagement"; import { System } from "~/types/api"; import AssignSystemsTable from "./AssignSystemsTable"; +export const SEARCH_FILTER = (system: System, search: string) => + system.name?.toLocaleLowerCase().includes(search.toLocaleLowerCase()) || + system.description?.toLocaleLowerCase().includes(search.toLocaleLowerCase()); + const AssignSystemsModal = ({ isOpen, onClose, diff --git a/clients/admin-ui/src/pages/systems/index.tsx b/clients/admin-ui/src/pages/systems/index.tsx index f130140970..86f6d17b43 100644 --- a/clients/admin-ui/src/pages/systems/index.tsx +++ b/clients/admin-ui/src/pages/systems/index.tsx @@ -21,7 +21,7 @@ import { import type { NextPage } from "next"; import NextLink from "next/link"; import { useRouter } from "next/router"; -import React, { useEffect, useMemo, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { useAppDispatch } from "~/app/hooks"; import { getErrorMessage } from "~/features/common/helpers"; @@ -119,15 +119,18 @@ const Systems: NextPage = () => { const getSystemName = (system: BasicSystemResponse) => system.name && !(system.name === "") ? system.name : system.fides_key; - const handleEdit = (system: BasicSystemResponse) => { - dispatch(setActiveSystem(system)); - router.push({ - pathname: EDIT_SYSTEM_ROUTE, - query: { - id: system.fides_key, - }, - }); - }; + const handleEdit = useCallback( + (system: BasicSystemResponse) => { + dispatch(setActiveSystem(system)); + router.push({ + pathname: EDIT_SYSTEM_ROUTE, + query: { + id: system.fides_key, + }, + }); + }, + [dispatch, router] + ); const handleDelete = async (system: BasicSystemResponse) => { const result = await deleteSystem(system.fides_key); @@ -209,7 +212,7 @@ const Systems: NextPage = () => { }, }), ], - [] + [handleEdit, onDeleteOpen] ); const tableInstance = useReactTable({ From e61939b50eb6ffd006f411fff51784bead1d153e Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Mon, 15 Jul 2024 20:40:35 -0300 Subject: [PATCH 06/24] PROD-1397 Update tests --- clients/admin-ui/cypress/e2e/nav-bar.cy.ts | 10 +- .../e2e/system-integrations-plus.cy.ts | 3 - .../cypress/e2e/system-integrations.cy.ts | 3 - clients/admin-ui/cypress/e2e/systems.cy.ts | 33 +++-- .../fixtures/systems/systems_paginated.json | 105 ++++++++++++++ .../systems/systems_paginated_search.json | 41 ++++++ .../features/common/nav/v2/nav-config.test.ts | 8 +- .../table/v2/filters/GlobalFilterV2.tsx | 4 +- .../src/pages/systems/configure/[id].tsx | 2 +- clients/admin-ui/src/pages/systems/index.tsx | 133 +++++++++--------- .../cypress-e2e/cypress/e2e/smoke_test.cy.ts | 4 +- 11 files changed, 243 insertions(+), 103 deletions(-) create mode 100644 clients/admin-ui/cypress/fixtures/systems/systems_paginated.json create mode 100644 clients/admin-ui/cypress/fixtures/systems/systems_paginated_search.json diff --git a/clients/admin-ui/cypress/e2e/nav-bar.cy.ts b/clients/admin-ui/cypress/e2e/nav-bar.cy.ts index 604a61407c..1d06259322 100644 --- a/clients/admin-ui/cypress/e2e/nav-bar.cy.ts +++ b/clients/admin-ui/cypress/e2e/nav-bar.cy.ts @@ -13,7 +13,7 @@ describe("Nav Bar", () => { cy.getByTestId("Home-nav-link"); }); cy.getByTestId("Data inventory-nav-group").within(() => { - cy.getByTestId("Systems & vendors-nav-link"); + cy.getByTestId("Systems-nav-link"); cy.getByTestId("Add systems-nav-link"); cy.getByTestId("Manage datasets-nav-link"); }); @@ -50,18 +50,18 @@ describe("Nav Bar", () => { cy.getByTestId("Home-nav-link") .should("have.css", "background-color") .should("eql", ACTIVE_COLOR); - cy.getByTestId("Systems & vendors-nav-link") + cy.getByTestId("Systems-nav-link") .should("have.css", "background-color") .should("not.eql", ACTIVE_COLOR); // Navigate by clicking a nav link. - cy.getByTestId("Systems & vendors-nav-link").click(); + cy.getByTestId("Systems-nav-link").click(); // The nav should update which page is active. cy.getByTestId("Home-nav-link") .should("have.css", "background-color") .should("not.eql", ACTIVE_COLOR); - cy.getByTestId("Systems & vendors-nav-link") + cy.getByTestId("Systems-nav-link") .should("have.css", "background-color") .should("eql", ACTIVE_COLOR); }); @@ -75,7 +75,7 @@ describe("Nav Bar", () => { cy.getByTestId("Request manager-nav-link").should("not.be.visible"); // Move to another page - cy.getByTestId("Systems & vendors-nav-link").click(); + cy.getByTestId("Systems-nav-link").click(); cy.getByTestId("Request manager-nav-link").should("not.be.visible"); }); }); diff --git a/clients/admin-ui/cypress/e2e/system-integrations-plus.cy.ts b/clients/admin-ui/cypress/e2e/system-integrations-plus.cy.ts index 8ae8f43b94..a938c85aaf 100644 --- a/clients/admin-ui/cypress/e2e/system-integrations-plus.cy.ts +++ b/clients/admin-ui/cypress/e2e/system-integrations-plus.cy.ts @@ -24,7 +24,6 @@ describe("System integrations", () => { it("should render the integration configuration panel when navigating to integrations tab", () => { cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("edit-btn").click(); }); cy.wait("@getDict"); @@ -35,7 +34,6 @@ describe("System integrations", () => { describe("Integration search", () => { beforeEach(() => { cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("edit-btn").click(); }); cy.getByTestId("tab-Integrations").click(); @@ -60,7 +58,6 @@ describe("System integrations", () => { describe("Integration form contents", () => { beforeEach(() => { cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("edit-btn").click(); }); cy.getByTestId("tab-Integrations").click(); diff --git a/clients/admin-ui/cypress/e2e/system-integrations.cy.ts b/clients/admin-ui/cypress/e2e/system-integrations.cy.ts index e4f523a878..6e0e882a33 100644 --- a/clients/admin-ui/cypress/e2e/system-integrations.cy.ts +++ b/clients/admin-ui/cypress/e2e/system-integrations.cy.ts @@ -21,7 +21,6 @@ describe("System integrations", () => { it("should render the integration configuration panel when navigating to integrations tab", () => { cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("edit-btn").click(); }); cy.getByTestId("tab-Integrations").click(); @@ -31,7 +30,6 @@ describe("System integrations", () => { describe("Integration search", () => { beforeEach(() => { cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("edit-btn").click(); }); cy.getByTestId("tab-Integrations").click(); @@ -56,7 +54,6 @@ describe("System integrations", () => { describe("Integration form contents", () => { beforeEach(() => { cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("edit-btn").click(); }); cy.getByTestId("tab-Integrations").click(); diff --git a/clients/admin-ui/cypress/e2e/systems.cy.ts b/clients/admin-ui/cypress/e2e/systems.cy.ts index 29020604ff..7e71643e1d 100644 --- a/clients/admin-ui/cypress/e2e/systems.cy.ts +++ b/clients/admin-ui/cypress/e2e/systems.cy.ts @@ -16,9 +16,14 @@ import { RoleRegistryEnum } from "~/types/api"; describe("System management page", () => { beforeEach(() => { cy.login(); - cy.intercept("GET", "/api/v1/system", { - fixture: "systems/systems.json", + cy.intercept("GET", "/api/v1/system*", { + fixture: "systems/systems_paginated.json", }).as("getSystems"); + + cy.intercept("GET", "/api/v1/system?page=1&size=25&search=demo+m", { + fixture: "systems/systems_paginated_search.json", + }).as("getSystemsWithSearch"); + stubPlus(false); }); @@ -34,7 +39,7 @@ describe("System management page", () => { it("Can navigate to the system management page", () => { cy.visit("/"); - cy.getByTestId("Systems & vendors-nav-link").click(); + cy.getByTestId("Systems-nav-link").click(); cy.wait("@getSystems"); cy.getByTestId("system-management"); }); @@ -44,11 +49,10 @@ describe("System management page", () => { cy.visit(SYSTEM_ROUTE); }); - it("Can render system cards", () => { + it("Can render system rows", () => { cy.getByTestId("system-fidesctl_system"); cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("edit-btn"); cy.getByTestId("delete-btn"); }); @@ -57,7 +61,12 @@ describe("System management page", () => { }); it("Can search and filter cards", () => { - cy.getByTestId("system-search").type("demo m"); + cy.getByTestId("system-search").type("demo m{enter}"); + + cy.wait("@getSystemsWithSearch").then((interception) => { + expect(interception.request.query.search).to.eq("demo m"); + }); + cy.getByTestId("system-fidesctl_system").should("not.exist"); cy.getByTestId("system-demo_analytics_system").should("not.exist"); cy.getByTestId("system-demo_marketing_system"); @@ -224,7 +233,6 @@ describe("System management page", () => { it("Can delete a system from its card", () => { cy.visit(SYSTEM_ROUTE); cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("delete-btn").click(); }); cy.getByTestId("confirmation-modal"); @@ -240,7 +248,6 @@ describe("System management page", () => { cy.assumeRole(RoleRegistryEnum.VIEWER); cy.visit(SYSTEM_ROUTE); cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("delete-btn").should("not.exist"); }); }); @@ -258,7 +265,6 @@ describe("System management page", () => { }).as("deleteSystemError"); cy.visit(SYSTEM_ROUTE); cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("delete-btn").click(); }); cy.getByTestId("confirmation-modal"); @@ -296,9 +302,7 @@ describe("System management page", () => { }); it("Can go to a system's edit page by clicking its card", () => { - cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("system-box").click(); - }); + cy.getByTestId("row-0").click(); cy.url().should("contain", "/systems/configure/fidesctl_system"); }); @@ -328,7 +332,6 @@ describe("System management page", () => { it.skip("Can go through the edit flow", () => { cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("edit-btn").click(); }); cy.url().should("contain", "/systems/configure/fidesctl_system"); @@ -398,7 +401,6 @@ describe("System management page", () => { administrating_department: "department", }; cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("edit-btn").click(); }); @@ -450,7 +452,6 @@ describe("System management page", () => { it.skip("warns when a data use and processing activity is being added that is already used", () => { cy.visit(SYSTEM_ROUTE); cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("edit-btn").click(); }); // "functional.service.improve" and "Store system data." are already being used @@ -507,7 +508,6 @@ describe("System management page", () => { it.skip("can have multiple of the same data use if the names are different", () => { cy.visit(SYSTEM_ROUTE); cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("edit-btn").click(); }); // "functional.service.improve" and "Store system data." are already being used @@ -671,7 +671,6 @@ describe("System management page", () => { cy.visit(SYSTEM_ROUTE); cy.getByTestId("system-fidesctl_system").within(() => { - cy.getByTestId("more-btn").click(); cy.getByTestId("edit-btn").click(); }); cy.getByTestId("tab-Data flow").click(); diff --git a/clients/admin-ui/cypress/fixtures/systems/systems_paginated.json b/clients/admin-ui/cypress/fixtures/systems/systems_paginated.json new file mode 100644 index 0000000000..0e8dd6a694 --- /dev/null +++ b/clients/admin-ui/cypress/fixtures/systems/systems_paginated.json @@ -0,0 +1,105 @@ +{ + "items": [ + { + "fides_key": "fidesctl_system", + "organization_fides_key": "default_organization", + "tags": null, + "name": "Fidesctl System", + "description": "Software that functionally applies Fides.", + "meta": null, + "fidesctl_meta": null, + "system_type": "Service", + "privacy_declarations": [ + { + "name": "Store system data.", + "data_categories": ["system.operations", "user.contact"], + "data_use": "functional.service.improve", + "data_subjects": ["anonymous_user"], + "dataset_references": ["public"], + "cookies": [{ "name": "cookie" }, { "name": "cookie2" }], + "id": "pri_ac9d4dfb-d033-4b06-bc7f-968df8d125ff" + } + ], + "administrating_department": "Not defined", + "ingress": [], + "egress": [], + "cookies": [ + { + "name": "test_cookie", + "path": "/", + "domain": "https://www.example.com" + } + ] + }, + { + "fides_key": "demo_analytics_system", + "organization_fides_key": "default_organization", + "tags": null, + "name": "Demo Analytics System", + "description": "A system used for analyzing customer behaviour.", + "meta": null, + "fidesctl_meta": null, + "system_type": "Service", + "egress": null, + "ingress": [ + { + "fides_key": "demo_marketing_system", + "type": "system", + "data_categories": null + } + ], + "privacy_declarations": [ + { + "name": "Analyze customer behaviour for improvements.", + "data_categories": ["user.contact", "user.device.cookie_id"], + "data_use": "functional.service.improve", + "data_subjects": ["customer"], + "dataset_references": ["demo_users_dataset"], + "egress": null, + "ingress": null, + "cookies": [], + "id": "pri_ac9d4dfb-d033-4b06-bc7f-968df8d125ff" + } + ], + "administrating_department": "Engineering", + "cookies": [] + }, + { + "fides_key": "demo_marketing_system", + "organization_fides_key": "default_organization", + "tags": null, + "name": "Demo Marketing System", + "description": "Collect data about our users for marketing.", + "meta": null, + "fidesctl_meta": null, + "system_type": "Service", + "egress": [ + { + "fides_key": "demo_analytics_system", + "type": "system", + "data_categories": null + } + ], + "ingress": null, + "privacy_declarations": [ + { + "name": "Collect data for marketing", + "data_categories": ["user.device.cookie_id"], + "data_use": "marketing", + "data_subjects": ["customer"], + "dataset_references": null, + "egress": null, + "ingress": null, + "cookies": [{ "name": "_ga" }], + "id": "pri_06430a1c-1365-422e-90a7-d444ddb32181" + } + ], + "administrating_department": "Marketing", + "cookies": [] + } + ], + "total": 3, + "page": 1, + "size": 20, + "pages": 1 +} diff --git a/clients/admin-ui/cypress/fixtures/systems/systems_paginated_search.json b/clients/admin-ui/cypress/fixtures/systems/systems_paginated_search.json new file mode 100644 index 0000000000..0c8306074f --- /dev/null +++ b/clients/admin-ui/cypress/fixtures/systems/systems_paginated_search.json @@ -0,0 +1,41 @@ +{ + "items": [ + { + "fides_key": "demo_marketing_system", + "organization_fides_key": "default_organization", + "tags": null, + "name": "Demo Marketing System", + "description": "Collect data about our users for marketing.", + "meta": null, + "fidesctl_meta": null, + "system_type": "Service", + "egress": [ + { + "fides_key": "demo_analytics_system", + "type": "system", + "data_categories": null + } + ], + "ingress": null, + "privacy_declarations": [ + { + "name": "Collect data for marketing", + "data_categories": ["user.device.cookie_id"], + "data_use": "marketing", + "data_subjects": ["customer"], + "dataset_references": null, + "egress": null, + "ingress": null, + "cookies": [{ "name": "_ga" }], + "id": "pri_06430a1c-1365-422e-90a7-d444ddb32181" + } + ], + "administrating_department": "Marketing", + "cookies": [] + } + ], + "total": 3, + "page": 1, + "size": 20, + "pages": 1 +} diff --git a/clients/admin-ui/src/features/common/nav/v2/nav-config.test.ts b/clients/admin-ui/src/features/common/nav/v2/nav-config.test.ts index cfad515e79..836744ffe1 100644 --- a/clients/admin-ui/src/features/common/nav/v2/nav-config.test.ts +++ b/clients/admin-ui/src/features/common/nav/v2/nav-config.test.ts @@ -44,7 +44,7 @@ describe("configureNavGroups", () => { expect(navGroups[1]).toMatchObject({ title: "Data inventory", children: [ - { title: "Systems & vendors", path: routes.SYSTEM_ROUTE }, + { title: "Systems", path: routes.SYSTEM_ROUTE }, { title: "Add systems", path: routes.ADD_SYSTEMS_ROUTE }, { title: "Manage datasets", path: routes.DATASET_ROUTE }, ], @@ -79,7 +79,7 @@ describe("configureNavGroups", () => { title: "Data inventory", children: [ { title: "Data lineage", path: routes.DATAMAP_ROUTE }, - { title: "Systems & vendors", path: routes.SYSTEM_ROUTE }, + { title: "Systems", path: routes.SYSTEM_ROUTE }, { title: "Add systems", path: routes.ADD_SYSTEMS_ROUTE }, { title: "Manage datasets", path: routes.DATASET_ROUTE }, { title: "Reporting", path: routes.REPORTING_DATAMAP_ROUTE }, @@ -101,7 +101,7 @@ describe("configureNavGroups", () => { expect(navGroups[1]).toMatchObject({ title: "Data inventory", - children: [{ title: "Systems & vendors", path: routes.SYSTEM_ROUTE }], + children: [{ title: "Systems", path: routes.SYSTEM_ROUTE }], }); }); @@ -146,7 +146,7 @@ describe("configureNavGroups", () => { expect(navGroups[1]).toMatchObject({ title: "Data inventory", children: [ - { title: "Systems & vendors", path: routes.SYSTEM_ROUTE }, + { title: "Systems", path: routes.SYSTEM_ROUTE }, { title: "Add systems", path: routes.ADD_SYSTEMS_ROUTE }, { title: "Manage datasets", path: routes.DATASET_ROUTE }, ], diff --git a/clients/admin-ui/src/features/common/table/v2/filters/GlobalFilterV2.tsx b/clients/admin-ui/src/features/common/table/v2/filters/GlobalFilterV2.tsx index 71bf506916..076ff6b86c 100644 --- a/clients/admin-ui/src/features/common/table/v2/filters/GlobalFilterV2.tsx +++ b/clients/admin-ui/src/features/common/table/v2/filters/GlobalFilterV2.tsx @@ -7,12 +7,14 @@ type GlobalFilterProps = { globalFilter: any; setGlobalFilter: (filterValue: any) => void; placeholder?: string; + testid?: string; }; export const GlobalFilterV2 = ({ globalFilter, setGlobalFilter, placeholder, + testid = "global-text-filter", }: GlobalFilterProps) => { const [value, setValue] = useState(globalFilter); @@ -36,7 +38,7 @@ export const GlobalFilterV2 = ({ onClear={onClear} search={value || ""} placeholder={placeholder} - data-testid="global-text-filter" + data-testid={testid} /> ); diff --git a/clients/admin-ui/src/pages/systems/configure/[id].tsx b/clients/admin-ui/src/pages/systems/configure/[id].tsx index 77403e6b42..2c15f2c5ad 100644 --- a/clients/admin-ui/src/pages/systems/configure/[id].tsx +++ b/clients/admin-ui/src/pages/systems/configure/[id].tsx @@ -111,7 +111,7 @@ const ConfigureSystem: NextPage = () => { { cell: ({ row }) => { const system = row.original; return ( - + { { return ( - - - View and manage recently detected systems and vendors here. - - - {isLoading ? ( - - ) : ( - <> - - + + + View and manage recently detected systems and vendors here. + + + {isLoading ? ( + + ) : ( + <> + + + + } + onRowClick={handleEdit} /> - - { - // here something - } - - - } - onRowClick={handleEdit} - /> - - )} - + + )} + - handleDelete} - title={`Delete ${ - selectedSystemForDelete && getSystemName(selectedSystemForDelete) - }`} - message={ - <> - - You are about to permanently delete the system{" "} - - {selectedSystemForDelete && - getSystemName(selectedSystemForDelete)} + handleDelete(selectedSystemForDelete!)} + title={`Delete ${ + selectedSystemForDelete && getSystemName(selectedSystemForDelete) + }`} + message={ + <> + + You are about to permanently delete the system{" "} + + {selectedSystemForDelete && + getSystemName(selectedSystemForDelete)} + + . - . - - Are you sure you would like to continue? - - } - /> + Are you sure you would like to continue? + + } + /> + ); }; diff --git a/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts b/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts index 1d41c27d41..c4e7e858b7 100644 --- a/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts +++ b/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts @@ -94,13 +94,13 @@ describe("Smoke test", () => { cy.login(); // Postgres - cy.getByTestId("Systems & vendors-nav-link").click(); + cy.getByTestId("Systems-nav-link").click(); cy.getByTestId("system-cookie_house_postgresql_database").click(); cy.getByTestId("tab-Integrations").click(); cy.get("button").contains("Test").click(); // Mongo - cy.getByTestId("Systems & vendors-nav-link").click(); + cy.getByTestId("Systems-nav-link").click(); cy.getByTestId("system-cookie_house_customer_database").click(); cy.getByTestId("tab-Integrations").click(); cy.get("button").contains("Test").click(); From 75795f2c4165a6a964930fa6fdd88c2ace728025 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Mon, 15 Jul 2024 21:11:19 -0300 Subject: [PATCH 07/24] PROD-1397 Update smoke test --- clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts b/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts index c4e7e858b7..d5ec7909d0 100644 --- a/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts +++ b/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts @@ -89,19 +89,24 @@ describe("Smoke test", () => { }); }); - it("can access Mongo and Postgres connectors from the Admin UI", () => { + it.only("can access Mongo and Postgres connectors from the Admin UI", () => { cy.visit(ADMIN_UI_URL); cy.login(); // Postgres cy.getByTestId("Systems-nav-link").click(); - cy.getByTestId("system-cookie_house_postgresql_database").click(); + cy.getByTestId("system-cookie_house_postgresql_database").within(() => { + cy.getByTestId("edit-btn").click(); + }); + cy.getByTestId("tab-Integrations").click(); cy.get("button").contains("Test").click(); // Mongo cy.getByTestId("Systems-nav-link").click(); - cy.getByTestId("system-cookie_house_customer_database").click(); + cy.getByTestId("system-cookie_house_customer_database").within(() => { + cy.getByTestId("edit-btn").click(); + }); cy.getByTestId("tab-Integrations").click(); cy.get("button").contains("Test").click(); }); From b73384569c22c52e6d3ba0272d90dab4f555a346 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Mon, 15 Jul 2024 21:19:07 -0300 Subject: [PATCH 08/24] PROD-1397 Update tests --- clients/admin-ui/cypress/e2e/system-integrations-plus.cy.ts | 4 ++-- clients/admin-ui/cypress/e2e/system-integrations.cy.ts | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/clients/admin-ui/cypress/e2e/system-integrations-plus.cy.ts b/clients/admin-ui/cypress/e2e/system-integrations-plus.cy.ts index a938c85aaf..db100ee044 100644 --- a/clients/admin-ui/cypress/e2e/system-integrations-plus.cy.ts +++ b/clients/admin-ui/cypress/e2e/system-integrations-plus.cy.ts @@ -5,8 +5,8 @@ import { SYSTEM_ROUTE } from "~/features/common/nav/v2/routes"; describe("System integrations", () => { beforeEach(() => { cy.login(); - cy.intercept("GET", "/api/v1/system", { - fixture: "systems/systems.json", + cy.intercept("GET", "/api/v1/system*", { + fixture: "systems/systems_paginated.json", }).as("getSystems"); cy.intercept("GET", "/api/v1/connection_type*", { fixture: "connectors/connection_types.json", diff --git a/clients/admin-ui/cypress/e2e/system-integrations.cy.ts b/clients/admin-ui/cypress/e2e/system-integrations.cy.ts index 6e0e882a33..b3a1f3cd71 100644 --- a/clients/admin-ui/cypress/e2e/system-integrations.cy.ts +++ b/clients/admin-ui/cypress/e2e/system-integrations.cy.ts @@ -5,9 +5,10 @@ import { SYSTEM_ROUTE } from "~/features/common/nav/v2/routes"; describe("System integrations", () => { beforeEach(() => { cy.login(); - cy.intercept("GET", "/api/v1/system", { - fixture: "systems/systems.json", + cy.intercept("GET", "/api/v1/system*", { + fixture: "systems/systems_paginated.json", }).as("getSystems"); + cy.intercept("GET", "/api/v1/connection_type*", { fixture: "connectors/connection_types.json", }).as("getConnectionTypes"); From 126dc1860e5d2832e3ea71c45f037042a046c34c Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Mon, 15 Jul 2024 21:36:29 -0300 Subject: [PATCH 09/24] PROD-1397 Fix smoke test --- clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts b/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts index d5ec7909d0..bb620ae717 100644 --- a/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts +++ b/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts @@ -89,7 +89,7 @@ describe("Smoke test", () => { }); }); - it.only("can access Mongo and Postgres connectors from the Admin UI", () => { + it("can access Mongo and Postgres connectors from the Admin UI", () => { cy.visit(ADMIN_UI_URL); cy.login(); From 533ee42e610783888506992c74479e1d32e989a5 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 16 Jul 2024 11:14:45 -0300 Subject: [PATCH 10/24] PROD-1397 Change page title --- clients/admin-ui/src/pages/systems/configure/[id].tsx | 2 +- clients/admin-ui/src/pages/systems/index.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clients/admin-ui/src/pages/systems/configure/[id].tsx b/clients/admin-ui/src/pages/systems/configure/[id].tsx index 2c15f2c5ad..dadf42d5a0 100644 --- a/clients/admin-ui/src/pages/systems/configure/[id].tsx +++ b/clients/admin-ui/src/pages/systems/configure/[id].tsx @@ -111,7 +111,7 @@ const ConfigureSystem: NextPage = () => { { }); return ( - + - + View and manage recently detected systems and vendors here. From cdb4ca9da81c5235f527aa920c553ff74dca54d8 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 16 Jul 2024 11:41:06 -0300 Subject: [PATCH 11/24] PROD-1397 Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7660601c18..4a7f28309a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ The types of changes are: ### Changed - Updated the sample dataset for the Amplitude integration [#5063](https://github.com/ethyca/fides/pull/5063) +- Updated System's page to display a table that uses a paginated endpoint [#5084](https://github.com/ethyca/fides/pull/5084) + ## [2.40.0](https://github.com/ethyca/fides/compare/2.39.2...2.40.0) From a9a6ec094c6cdc1065a353439e00d598a78e214b Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 16 Jul 2024 14:49:27 -0300 Subject: [PATCH 12/24] PROD-1397 Update system nav title --- clients/admin-ui/cypress/e2e/nav-bar.cy.ts | 10 +++++----- clients/admin-ui/cypress/e2e/systems.cy.ts | 2 +- .../admin-ui/src/features/common/nav/v2/nav-config.ts | 2 +- clients/admin-ui/src/pages/systems/configure/[id].tsx | 4 ++-- clients/admin-ui/src/pages/systems/index.tsx | 4 ++-- clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/clients/admin-ui/cypress/e2e/nav-bar.cy.ts b/clients/admin-ui/cypress/e2e/nav-bar.cy.ts index 1d06259322..ded8630046 100644 --- a/clients/admin-ui/cypress/e2e/nav-bar.cy.ts +++ b/clients/admin-ui/cypress/e2e/nav-bar.cy.ts @@ -13,7 +13,7 @@ describe("Nav Bar", () => { cy.getByTestId("Home-nav-link"); }); cy.getByTestId("Data inventory-nav-group").within(() => { - cy.getByTestId("Systems-nav-link"); + cy.getByTestId("System inventory-nav-link"); cy.getByTestId("Add systems-nav-link"); cy.getByTestId("Manage datasets-nav-link"); }); @@ -50,18 +50,18 @@ describe("Nav Bar", () => { cy.getByTestId("Home-nav-link") .should("have.css", "background-color") .should("eql", ACTIVE_COLOR); - cy.getByTestId("Systems-nav-link") + cy.getByTestId("System inventory-nav-link") .should("have.css", "background-color") .should("not.eql", ACTIVE_COLOR); // Navigate by clicking a nav link. - cy.getByTestId("Systems-nav-link").click(); + cy.getByTestId("System inventory-nav-link").click(); // The nav should update which page is active. cy.getByTestId("Home-nav-link") .should("have.css", "background-color") .should("not.eql", ACTIVE_COLOR); - cy.getByTestId("Systems-nav-link") + cy.getByTestId("System inventory-nav-link") .should("have.css", "background-color") .should("eql", ACTIVE_COLOR); }); @@ -75,7 +75,7 @@ describe("Nav Bar", () => { cy.getByTestId("Request manager-nav-link").should("not.be.visible"); // Move to another page - cy.getByTestId("Systems-nav-link").click(); + cy.getByTestId("System inventory-nav-link").click(); cy.getByTestId("Request manager-nav-link").should("not.be.visible"); }); }); diff --git a/clients/admin-ui/cypress/e2e/systems.cy.ts b/clients/admin-ui/cypress/e2e/systems.cy.ts index 7e71643e1d..5ac8ce3ebf 100644 --- a/clients/admin-ui/cypress/e2e/systems.cy.ts +++ b/clients/admin-ui/cypress/e2e/systems.cy.ts @@ -39,7 +39,7 @@ describe("System management page", () => { it("Can navigate to the system management page", () => { cy.visit("/"); - cy.getByTestId("Systems-nav-link").click(); + cy.getByTestId("System inventory-nav-link").click(); cy.wait("@getSystems"); cy.getByTestId("system-management"); }); diff --git a/clients/admin-ui/src/features/common/nav/v2/nav-config.ts b/clients/admin-ui/src/features/common/nav/v2/nav-config.ts index 0d5126d218..7ca8fd1056 100644 --- a/clients/admin-ui/src/features/common/nav/v2/nav-config.ts +++ b/clients/admin-ui/src/features/common/nav/v2/nav-config.ts @@ -71,7 +71,7 @@ export const NAV_CONFIG: NavConfigGroup[] = [ scopes: [ScopeRegistryEnum.DATAMAP_READ], }, { - title: "Systems", + title: "System inventory", path: routes.SYSTEM_ROUTE, scopes: [ScopeRegistryEnum.SYSTEM_READ], }, diff --git a/clients/admin-ui/src/pages/systems/configure/[id].tsx b/clients/admin-ui/src/pages/systems/configure/[id].tsx index dadf42d5a0..21563a4bb4 100644 --- a/clients/admin-ui/src/pages/systems/configure/[id].tsx +++ b/clients/admin-ui/src/pages/systems/configure/[id].tsx @@ -108,10 +108,10 @@ const ConfigureSystem: NextPage = () => { } return ( - + { }); return ( - + - + View and manage recently detected systems and vendors here. diff --git a/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts b/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts index bb620ae717..ec5f0a87ae 100644 --- a/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts +++ b/clients/cypress-e2e/cypress/e2e/smoke_test.cy.ts @@ -94,7 +94,7 @@ describe("Smoke test", () => { cy.login(); // Postgres - cy.getByTestId("Systems-nav-link").click(); + cy.getByTestId("System inventory-nav-link").click(); cy.getByTestId("system-cookie_house_postgresql_database").within(() => { cy.getByTestId("edit-btn").click(); }); @@ -103,7 +103,7 @@ describe("Smoke test", () => { cy.get("button").contains("Test").click(); // Mongo - cy.getByTestId("Systems-nav-link").click(); + cy.getByTestId("System inventory-nav-link").click(); cy.getByTestId("system-cookie_house_customer_database").within(() => { cy.getByTestId("edit-btn").click(); }); From 3dda204437be138ba8c25b17a82ebc1020495690 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 16 Jul 2024 15:58:21 -0300 Subject: [PATCH 13/24] PROD-1397 Update unit tests --- .../src/features/common/nav/v2/nav-config.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clients/admin-ui/src/features/common/nav/v2/nav-config.test.ts b/clients/admin-ui/src/features/common/nav/v2/nav-config.test.ts index 836744ffe1..c58f94252b 100644 --- a/clients/admin-ui/src/features/common/nav/v2/nav-config.test.ts +++ b/clients/admin-ui/src/features/common/nav/v2/nav-config.test.ts @@ -44,7 +44,7 @@ describe("configureNavGroups", () => { expect(navGroups[1]).toMatchObject({ title: "Data inventory", children: [ - { title: "Systems", path: routes.SYSTEM_ROUTE }, + { title: "System inventory", path: routes.SYSTEM_ROUTE }, { title: "Add systems", path: routes.ADD_SYSTEMS_ROUTE }, { title: "Manage datasets", path: routes.DATASET_ROUTE }, ], @@ -79,7 +79,7 @@ describe("configureNavGroups", () => { title: "Data inventory", children: [ { title: "Data lineage", path: routes.DATAMAP_ROUTE }, - { title: "Systems", path: routes.SYSTEM_ROUTE }, + { title: "System inventory", path: routes.SYSTEM_ROUTE }, { title: "Add systems", path: routes.ADD_SYSTEMS_ROUTE }, { title: "Manage datasets", path: routes.DATASET_ROUTE }, { title: "Reporting", path: routes.REPORTING_DATAMAP_ROUTE }, @@ -101,7 +101,7 @@ describe("configureNavGroups", () => { expect(navGroups[1]).toMatchObject({ title: "Data inventory", - children: [{ title: "Systems", path: routes.SYSTEM_ROUTE }], + children: [{ title: "System inventory", path: routes.SYSTEM_ROUTE }], }); }); @@ -146,7 +146,7 @@ describe("configureNavGroups", () => { expect(navGroups[1]).toMatchObject({ title: "Data inventory", children: [ - { title: "Systems", path: routes.SYSTEM_ROUTE }, + { title: "System inventory", path: routes.SYSTEM_ROUTE }, { title: "Add systems", path: routes.ADD_SYSTEMS_ROUTE }, { title: "Manage datasets", path: routes.DATASET_ROUTE }, ], From 977dd8342ae490ed84f723d8db5cc9af7f1881c9 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 16 Jul 2024 23:45:10 -0300 Subject: [PATCH 14/24] PROD-1397 Fix tests --- clients/admin-ui/cypress/e2e/auth.cy.ts | 4 ++-- clients/admin-ui/cypress/e2e/systems.cy.ts | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/clients/admin-ui/cypress/e2e/auth.cy.ts b/clients/admin-ui/cypress/e2e/auth.cy.ts index ea6809eb0e..fc2f90e569 100644 --- a/clients/admin-ui/cypress/e2e/auth.cy.ts +++ b/clients/admin-ui/cypress/e2e/auth.cy.ts @@ -60,12 +60,12 @@ describe("User Authentication", () => { cy.getByTestId("User Management"); cy.visit(SYSTEM_ROUTE); - cy.getByTestId("Systems"); + cy.getByTestId("system-management"); }); it("lets them log out", () => { cy.visit(SYSTEM_ROUTE); - cy.getByTestId("Systems"); + cy.getByTestId("system-management"); cy.intercept("POST", "/api/v1/logout", { statusCode: 204, diff --git a/clients/admin-ui/cypress/e2e/systems.cy.ts b/clients/admin-ui/cypress/e2e/systems.cy.ts index 5ac8ce3ebf..0bd0b1bac4 100644 --- a/clients/admin-ui/cypress/e2e/systems.cy.ts +++ b/clients/admin-ui/cypress/e2e/systems.cy.ts @@ -16,7 +16,11 @@ import { RoleRegistryEnum } from "~/types/api"; describe("System management page", () => { beforeEach(() => { cy.login(); - cy.intercept("GET", "/api/v1/system*", { + cy.intercept("GET", "/api/v1/system", { + fixture: "systems/systems.json", + }).as("getSystems"); + + cy.intercept("GET", "/api/v1/system?*", { fixture: "systems/systems_paginated.json", }).as("getSystems"); From 7a8503b020571cc70ff694ea83ff7cd12423ffc7 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Wed, 17 Jul 2024 10:20:07 -0300 Subject: [PATCH 15/24] PROD-1899 WIP --- .../src/features/common/CommonSubscriptions.tsx | 4 ++-- .../src/features/common/features/features.slice.ts | 6 ++---- .../common/system-data-flow/DataFlowAccordionForm.tsx | 5 +---- .../src/features/configure-consent/AddVendor.tsx | 7 +++++-- .../src/features/system/SystemInformationForm.tsx | 4 ++-- .../src/features/system/SystemRegisterSuccess.tsx | 7 ++++--- .../src/features/system/history/SystemHistoryTable.tsx | 4 ++-- clients/admin-ui/src/features/system/system.slice.ts | 10 ++++++---- 8 files changed, 24 insertions(+), 23 deletions(-) diff --git a/clients/admin-ui/src/features/common/CommonSubscriptions.tsx b/clients/admin-ui/src/features/common/CommonSubscriptions.tsx index 36f09fdb67..443a9d9f83 100644 --- a/clients/admin-ui/src/features/common/CommonSubscriptions.tsx +++ b/clients/admin-ui/src/features/common/CommonSubscriptions.tsx @@ -1,13 +1,13 @@ import { useAppSelector } from "~/app/hooks"; import { useGetHealthQuery } from "~/features/common/health.slice"; import { useGetHealthQuery as useGetPlusHealthQuery } from "~/features/plus/plus.slice"; -import { useGetAllSystemsQuery } from "~/features/system/system.slice"; +import { useGetSystemsQuery } from "~/features/system"; import { selectThisUsersScopes } from "~/features/user-management"; const useCommonSubscriptions = () => { useGetHealthQuery(); useGetPlusHealthQuery(); - useGetAllSystemsQuery(); + useGetSystemsQuery({ page: 1, size: 1 }); // used to preload systems count on selectSystemsCount useAppSelector(selectThisUsersScopes); }; diff --git a/clients/admin-ui/src/features/common/features/features.slice.ts b/clients/admin-ui/src/features/common/features/features.slice.ts index bdecb7326b..86726417f9 100644 --- a/clients/admin-ui/src/features/common/features/features.slice.ts +++ b/clients/admin-ui/src/features/common/features/features.slice.ts @@ -6,7 +6,7 @@ import { type RootState } from "~/app/store"; import { selectHealth } from "~/features/common/health.slice"; import { selectInitialConnections } from "~/features/datastore-connections"; import { selectHealth as selectPlusHealth } from "~/features/plus/plus.slice"; -import { selectAllSystems } from "~/features/system"; +import { selectSystemsCount } from "~/features/system"; import flagDefaults from "~/flags.json"; import { configureFlags, flagsForEnv } from "./config"; @@ -146,7 +146,7 @@ export type Features = { export const useFeatures = (): Features => { const health = useAppSelector(selectHealth); const plusHealth = useAppSelector(selectPlusHealth); - const allSystems = useAppSelector(selectAllSystems); + const systemsCount = useAppSelector(selectSystemsCount); const initialConnections = useAppSelector(selectInitialConnections); const version = health?.version; @@ -163,8 +163,6 @@ export const useFeatures = (): Features => { const tcf = plusHealth ? !!plusHealth.tcf.enabled : false; - const systemsCount = allSystems?.length ?? 0; - const connectionsCount = initialConnections?.total ?? 0; const { flags } = useFlags(); diff --git a/clients/admin-ui/src/features/common/system-data-flow/DataFlowAccordionForm.tsx b/clients/admin-ui/src/features/common/system-data-flow/DataFlowAccordionForm.tsx index e129e2f711..8461e5fd22 100644 --- a/clients/admin-ui/src/features/common/system-data-flow/DataFlowAccordionForm.tsx +++ b/clients/admin-ui/src/features/common/system-data-flow/DataFlowAccordionForm.tsx @@ -22,12 +22,10 @@ import { import { Form, Formik, FormikHelpers } from "formik"; import React, { useEffect, useMemo, useState } from "react"; -import { useAppSelector } from "~/app/hooks"; import { useGetAllSystemsQuery, useUpdateSystemMutation, } from "~/features/system"; -import { selectAllSystems } from "~/features/system/system.slice"; import { DataFlow, System } from "~/types/api"; const defaultInitialValues = { @@ -53,8 +51,7 @@ export const DataFlowAccordionForm = ({ const dataFlowSystemsModal = useDisclosure(); const [updateSystemMutationTrigger] = useUpdateSystemMutation(); - useGetAllSystemsQuery(); - const systems = useAppSelector(selectAllSystems); + const { data: systems = [] } = useGetAllSystemsQuery(); const initialDataFlows = useMemo(() => { let dataFlows = isIngress ? system.ingress : system.egress; diff --git a/clients/admin-ui/src/features/configure-consent/AddVendor.tsx b/clients/admin-ui/src/features/configure-consent/AddVendor.tsx index aa185f9fdf..9b8abac4ec 100644 --- a/clients/admin-ui/src/features/configure-consent/AddVendor.tsx +++ b/clients/admin-ui/src/features/configure-consent/AddVendor.tsx @@ -20,7 +20,10 @@ import { selectDictEntry, useGetAllDictionaryEntriesQuery, } from "~/features/plus/plus.slice"; -import { selectAllSystems, useCreateSystemMutation } from "~/features/system"; +import { + useCreateSystemMutation, + useGetAllSystemsQuery, +} from "~/features/system"; import { selectLockedForGVL, selectSuggestions, @@ -64,7 +67,7 @@ const AddVendor = ({ const dispatch = useAppDispatch(); - const systems = useAppSelector(selectAllSystems); + const { data: systems = [] } = useGetAllSystemsQuery(); const ValidationSchema = useMemo( () => diff --git a/clients/admin-ui/src/features/system/SystemInformationForm.tsx b/clients/admin-ui/src/features/system/SystemInformationForm.tsx index 342069cec5..20f2414c57 100644 --- a/clients/admin-ui/src/features/system/SystemInformationForm.tsx +++ b/clients/admin-ui/src/features/system/SystemInformationForm.tsx @@ -50,8 +50,8 @@ import { transformSystemToFormValues, } from "~/features/system/form"; import { - selectAllSystems, useCreateSystemMutation, + useGetAllSystemsQuery, useUpdateSystemMutation, } from "~/features/system/system.slice"; import SystemFormInputGroup from "~/features/system/SystemFormInputGroup"; @@ -91,7 +91,7 @@ const SystemInformationForm = ({ withHeader, children, }: Props) => { - const systems = useAppSelector(selectAllSystems); + const { data: systems = [] } = useGetAllSystemsQuery(); const dispatch = useAppDispatch(); const customFields = useCustomFields({ diff --git a/clients/admin-ui/src/features/system/SystemRegisterSuccess.tsx b/clients/admin-ui/src/features/system/SystemRegisterSuccess.tsx index c2ddd07327..eb144274dd 100644 --- a/clients/admin-ui/src/features/system/SystemRegisterSuccess.tsx +++ b/clients/admin-ui/src/features/system/SystemRegisterSuccess.tsx @@ -17,11 +17,11 @@ import { } from "fidesui"; import { useRouter } from "next/router"; -import { useAppDispatch, useAppSelector } from "~/app/hooks"; +import { useAppDispatch } from "~/app/hooks"; import { SYSTEM_ROUTE } from "~/features/common/nav/v2/routes"; import { - selectAllSystems, setActiveSystem, + useGetAllSystemsQuery, } from "~/features/system/system.slice"; import { System } from "~/types/api"; @@ -30,7 +30,8 @@ interface Props { onAddNextSystem: () => void; } const SystemRegisterSuccess = ({ system, onAddNextSystem }: Props) => { - const allRegisteredSystems = useAppSelector(selectAllSystems); + const { data: allRegisteredSystems = [] } = useGetAllSystemsQuery(); + const dispatch = useAppDispatch(); const router = useRouter(); const otherSystems = allRegisteredSystems diff --git a/clients/admin-ui/src/features/system/history/SystemHistoryTable.tsx b/clients/admin-ui/src/features/system/history/SystemHistoryTable.tsx index 88c402d535..bde3460e4f 100644 --- a/clients/admin-ui/src/features/system/history/SystemHistoryTable.tsx +++ b/clients/admin-ui/src/features/system/history/SystemHistoryTable.tsx @@ -9,7 +9,7 @@ import { selectAllDictEntries, useGetSystemHistoryQuery, } from "~/features/plus/plus.slice"; -import { selectAllSystems } from "~/features/system/system.slice"; +import { useGetAllSystemsQuery } from "~/features/system/system.slice"; import { SystemHistoryResponse } from "~/types/api"; import { SystemResponse } from "~/types/api/models/SystemResponse"; @@ -41,7 +41,7 @@ const SystemHistoryTable = ({ system }: Props) => { const [selectedHistory, setSelectedHistory] = useState(null); const dictionaryOptions = useAppSelector(selectAllDictEntries); - const systems = useAppSelector(selectAllSystems); + const { data: systems = [] } = useGetAllSystemsQuery(); const systemHistories = data?.items || []; diff --git a/clients/admin-ui/src/features/system/system.slice.ts b/clients/admin-ui/src/features/system/system.slice.ts index 41fc0a864a..8c98db4bf7 100644 --- a/clients/admin-ui/src/features/system/system.slice.ts +++ b/clients/admin-ui/src/features/system/system.slice.ts @@ -244,10 +244,12 @@ export const selectActiveClassifySystemFidesKey = createSelector( (state) => state.activeClassifySystemFidesKey ); -const emptySelectAllSystems: SystemResponse[] = []; -export const selectAllSystems = createSelector( - [(RootState) => RootState, systemApi.endpoints.getAllSystems.select()], - (RootState, { data }) => data || emptySelectAllSystems +export const selectSystemsCount = createSelector( + [ + (RootState) => RootState, + systemApi.endpoints.getSystems.select({ page: 1, size: 1 }), + ], + (RootState, { data }) => data?.total || 0 ); export const selectActiveClassifySystem = createSelector( From e34f044cfe06da2536a4394af7c601c24416184f Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 30 Jul 2024 08:56:19 -0300 Subject: [PATCH 16/24] PROD-1899 Add back selectallsystem selector until selectActiveClassifySystemis removed --- .../src/features/system/ClassifySystemsTable.tsx | 1 + clients/admin-ui/src/features/system/system.slice.ts | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/clients/admin-ui/src/features/system/ClassifySystemsTable.tsx b/clients/admin-ui/src/features/system/ClassifySystemsTable.tsx index ae405f7171..f0f4b519c6 100644 --- a/clients/admin-ui/src/features/system/ClassifySystemsTable.tsx +++ b/clients/admin-ui/src/features/system/ClassifySystemsTable.tsx @@ -22,6 +22,7 @@ const ClassifySystemsTable = ({ systems }: { systems: System[] }) => { const handleClick = (system: System) => { dispatch(setActiveClassifySystemFidesKey(system.fides_key)); }; + const [hideEmpty, setHideEmpty] = useState(false); const filteredSystems = hideEmpty ? systems.filter( diff --git a/clients/admin-ui/src/features/system/system.slice.ts b/clients/admin-ui/src/features/system/system.slice.ts index 8c98db4bf7..d7e78b5bfb 100644 --- a/clients/admin-ui/src/features/system/system.slice.ts +++ b/clients/admin-ui/src/features/system/system.slice.ts @@ -244,6 +244,10 @@ export const selectActiveClassifySystemFidesKey = createSelector( (state) => state.activeClassifySystemFidesKey ); +/** + * Selects the number of systems + * By using the paginated getSystems endpoint, we can get the total number of systems + */ export const selectSystemsCount = createSelector( [ (RootState) => RootState, @@ -252,6 +256,11 @@ export const selectSystemsCount = createSelector( (RootState, { data }) => data?.total || 0 ); +export const selectAllSystems = createSelector( + systemApi.endpoints.getAllSystems.select(), + ({ data }) => data +); + export const selectActiveClassifySystem = createSelector( [selectAllSystems, selectActiveClassifySystemFidesKey], (allSystems, fidesKey) => { From e1c23ad991a353cf388714eff6642877649d9ffd Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 30 Jul 2024 10:10:23 -0300 Subject: [PATCH 17/24] PROD-1899 Remove system classification page, table, test and related redux states (the page was already disabled) --- .../cypress/e2e/systems-classify.cy.ts | 147 ------------------ .../features/config-wizard/ScanResults.tsx | 17 +- .../admin-ui/src/features/plus/plus.slice.ts | 15 -- .../features/system/ClassifySystemsTable.tsx | 84 ---------- .../src/features/system/system.slice.ts | 44 +----- .../src/pages/classify-systems/index.tsx | 119 -------------- 6 files changed, 2 insertions(+), 424 deletions(-) delete mode 100644 clients/admin-ui/cypress/e2e/systems-classify.cy.ts delete mode 100644 clients/admin-ui/src/features/system/ClassifySystemsTable.tsx delete mode 100644 clients/admin-ui/src/pages/classify-systems/index.tsx diff --git a/clients/admin-ui/cypress/e2e/systems-classify.cy.ts b/clients/admin-ui/cypress/e2e/systems-classify.cy.ts deleted file mode 100644 index 6741653fe0..0000000000 --- a/clients/admin-ui/cypress/e2e/systems-classify.cy.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { stubPlus, stubTaxonomyEntities } from "cypress/support/stubs"; - -describe.skip("Classify systems page", () => { - beforeEach(() => { - cy.login(); - cy.intercept("GET", "/api/v1/system", { - fixture: "systems/systems.json", - }).as("getSystems"); - }); - - it("Should reroute if not in plus", () => { - stubPlus(false); - cy.visit("/classify-systems"); - cy.url().should("eql", `${Cypress.config().baseUrl}/`); - }); - - describe("With plus enabled", () => { - beforeEach(() => { - stubPlus(true); - stubTaxonomyEntities(); - cy.intercept("GET", "/api/v1/plus/classify*", { - fixture: "classify/list-systems.json", - }).as("getClassifyList"); - cy.intercept("GET", "/api/v1/system", { - fixture: "systems/systems.json", - }).as("getSystems"); - }); - - it("Should be accessible to plus users", () => { - cy.visit("/classify-systems"); - cy.getByTestId("systems-classify-table"); - }); - - it("Should render an empty state if no classifications are found", () => { - cy.intercept("GET", "/api/v1/plus/classify*", { - body: [], - }).as("getEmptyClassifyList"); - cy.visit("/classify-systems"); - cy.getByTestId("no-classifications"); - }); - - it("Should render a proper description based on the existence of classification and data flows", () => { - cy.intercept("GET", "/api/v1/plus/classify/details/*", { - fixture: "classify/system-details.json", - }); - cy.visit("/classify-systems"); - - // No data flows exist on the system - cy.getByTestId("row-fidesctl_system").click(); - cy.getByTestId("no-data-flows"); - cy.getByTestId("save-btn").should("exist"); - cy.getByTestId("close-drawer-btn").click(); - - // Only ingresses exist - cy.getByTestId("row-demo_analytics_system").click(); - cy.getByTestId("data-flow-with-classification").contains("receives data"); - cy.getByTestId("save-btn").should("exist"); - cy.getByTestId("close-drawer-btn").click(); - - // Only egresses exist - cy.getByTestId("row-demo_marketing_system").click(); - cy.getByTestId("data-flow-with-classification").contains("sends data"); - cy.getByTestId("save-btn").should("exist"); - cy.getByTestId("close-drawer-btn").click(); - - // No classifications determined, though classify did run - cy.visit("/classify-systems"); // visit again to clear the redux cache - cy.fixture("classify/system-details.json").then((details) => { - cy.intercept("GET", "/api/v1/plus/classify/details/*", { - body: { ...details, ingress: [], egress: [] }, - }).as("getClassifyDetailsEmpty"); - }); - cy.getByTestId("row-demo_marketing_system").click(); - cy.wait("@getClassifyDetailsEmpty"); - cy.getByTestId("no-classification"); - cy.getByTestId("save-btn").should("exist"); - cy.getByTestId("close-drawer-btn").click(); - - // Classification is still in progress - cy.visit("/classify-systems"); - cy.fixture("classify/system-details.json").then((details) => { - cy.intercept("GET", "/api/v1/plus/classify/details/*", { - body: { ...details, ingress: [], egress: [], status: "Processing" }, - }).as("getClassifyDetailsProcessing"); - }); - cy.wait("@getSystems"); - cy.getByTestId("row-demo_marketing_system").click(); - cy.wait("@getClassifyDetailsProcessing"); - cy.getByTestId("processing"); - cy.getByTestId("save-btn").should("not.exist"); - cy.getByTestId("close-drawer-btn").click(); - - // No classification ever occurred - cy.visit("/classify-systems"); - cy.intercept("GET", "/api/v1/plus/classify/details/*", { - body: {}, - }).as("getClassifyEmpty"); - cy.getByTestId("row-demo_marketing_system").click(); - cy.wait("@getClassifyEmpty"); - cy.getByTestId("no-classification-instance"); - cy.getByTestId("classification-status-badge").contains("Unknown"); - cy.getByTestId("save-btn").should("exist"); - }); - - it("Can edit a system's data flows", () => { - cy.intercept("GET", "/api/v1/plus/classify/details/*", { - fixture: "classify/system-details.json", - }); - cy.intercept("PUT", "/api/v1/plus/classify/*", { body: undefined }).as( - "putClassifyInstance" - ); - cy.intercept("PUT", "/api/v1/system*", { - fixture: "systems/system.json", - }).as("putSystem"); - cy.visit("/classify-systems"); - - // Open up an ingress - cy.getByTestId("row-demo_analytics_system").click(); - cy.getByTestId("accordion-item-ingress").click(); - cy.getByTestId("accordion-item-demo_marketing_system").click(); - // Should have the classified suggestion - cy.getByTestId("classified-select").contains("system"); - // Select a category from the taxonomy. - cy.getByTestId("data-category-dropdown").click(); - cy.getByTestId("data-category-checkbox-tree") - .contains("User Data") - .click(); - cy.getByTestId("data-category-done-btn").click(); - cy.getByTestId("classified-select").contains("user"); - - // Trigger a save - cy.getByTestId("save-btn").click(); - cy.wait("@putSystem").then((interception) => { - const { body } = interception.request; - expect(body.ingress[0].data_categories).to.eql(["system", "user"]); - }); - cy.wait("@putClassifyInstance").then((interception) => { - const { body } = interception.request; - expect(body).to.eql({ - dataset_fides_key: "demo_analytics_system", - status: "Reviewed", - }); - }); - cy.getByTestId("toast-success-msg"); - }); - }); -}); diff --git a/clients/admin-ui/src/features/config-wizard/ScanResults.tsx b/clients/admin-ui/src/features/config-wizard/ScanResults.tsx index 376970793c..0ea5aa0c8c 100644 --- a/clients/admin-ui/src/features/config-wizard/ScanResults.tsx +++ b/clients/admin-ui/src/features/config-wizard/ScanResults.tsx @@ -20,19 +20,14 @@ import { useAPIHelper } from "~/features/common/hooks"; import { useSystemOrDatamapRoute } from "~/features/common/hooks/useSystemOrDatamapRoute"; import WarningModal from "~/features/common/modals/WarningModal"; import { SystemsCheckboxTable } from "~/features/common/SystemsCheckboxTable"; -import { - setSystemsToClassify, - useUpsertSystemsMutation, -} from "~/features/system"; +import { useUpsertSystemsMutation } from "~/features/system"; import { System } from "~/types/api"; import { changeStep, reset, - selectAddSystemsMethod, selectSystemsForReview, } from "./config-wizard.slice"; -import { SystemMethods } from "./types"; const ALL_COLUMNS: ColumnMetadata[] = [ { name: "Name", attribute: "name" }, @@ -55,7 +50,6 @@ const ScanResults = () => { const [selectedSystems, setSelectedSystems] = useState(systems); const [selectedColumns, setSelectedColumns] = useState(ALL_COLUMNS); - const method = useAppSelector(selectAddSystemsMethod); const { handleError } = useAPIHelper(); /** @@ -77,15 +71,6 @@ const ScanResults = () => { return handleError(response.error); } - /* - * Eventually, all scanners will go through some sort of classify flow. - * But for now, only the data flow scanner does - */ - if (method === SystemMethods.DATA_FLOW) { - dispatch(setSystemsToClassify(selectedSystems)); - return navigateAndReset("/classify-systems"); - } - return navigateAndReset(systemOrDatamapRoute); }; diff --git a/clients/admin-ui/src/features/plus/plus.slice.ts b/clients/admin-ui/src/features/plus/plus.slice.ts index 85251b2672..f81a003adf 100644 --- a/clients/admin-ui/src/features/plus/plus.slice.ts +++ b/clients/admin-ui/src/features/plus/plus.slice.ts @@ -10,7 +10,6 @@ import { } from "~/features/dataset/dataset.slice"; import { CreateSaasConnectionConfig } from "~/features/datastore-connections"; import { CreateSaasConnectionConfigResponse } from "~/features/datastore-connections/types"; -import { selectSystemsToClassify } from "~/features/system"; import { AllowList, AllowListUpdate, @@ -507,15 +506,6 @@ export const selectDatasetClassifyInstances = createSelector( ({ data: instances }) => instances ?? emptyClassifyInstances ); -export const selectSystemClassifyInstances = createSelector( - [(state) => state, selectSystemsToClassify], - (state, systems) => - plusApi.endpoints.getAllClassifyInstances.select({ - resource_type: GenerateTypes.SYSTEMS, - fides_keys: systems?.map((s) => s.fides_key), - })(state)?.data ?? emptyClassifyInstances -); - const emptyClassifyInstanceMap: Map = new Map(); @@ -537,11 +527,6 @@ export const selectDatasetClassifyInstanceMap = createSelector( (instances) => instancesToMap(instances) ); -export const selectSystemClassifyInstanceMap = createSelector( - selectSystemClassifyInstances, - (instances) => instancesToMap(instances) -); - /** * This is the root of ClassifyInstance selectors that parallel the dataset's structure. These used * the cached getClassifyDataset response state, which is a query using the "active" dataset's diff --git a/clients/admin-ui/src/features/system/ClassifySystemsTable.tsx b/clients/admin-ui/src/features/system/ClassifySystemsTable.tsx deleted file mode 100644 index f0f4b519c6..0000000000 --- a/clients/admin-ui/src/features/system/ClassifySystemsTable.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import ClassifyResultsToggle from "common/ClassifyResultsToggle"; -import { Flex, Stack, Table, Tbody, Td, Text, Th, Thead, Tr } from "fidesui"; -import { useState } from "react"; - -import { useAppDispatch, useAppSelector } from "~/app/hooks"; -import { SystemTableCell } from "~/features/common/SystemsCheckboxTable"; -import ClassificationStatusBadge from "~/features/plus/ClassificationStatusBadge"; -import { selectSystemClassifyInstanceMap } from "~/features/plus/plus.slice"; -import { GenerateTypes, System } from "~/types/api"; - -import EditClassifySystemDrawer from "./EditClassifySystemDrawer"; -import { - selectActiveClassifySystem, - setActiveClassifySystemFidesKey, -} from "./system.slice"; - -const ClassifySystemsTable = ({ systems }: { systems: System[] }) => { - const dispatch = useAppDispatch(); - const classifyInstanceMap = useAppSelector(selectSystemClassifyInstanceMap); - const activeSystem = useAppSelector(selectActiveClassifySystem); - - const handleClick = (system: System) => { - dispatch(setActiveClassifySystemFidesKey(system.fides_key)); - }; - - const [hideEmpty, setHideEmpty] = useState(false); - const filteredSystems = hideEmpty - ? systems.filter( - (system) => classifyInstanceMap.get(system.fides_key)?.has_labels - ) - : systems; - - return ( - - - - Only Show Findings - - - - - - - - - - - - {filteredSystems.map((system) => { - const classifyInstance = classifyInstanceMap.get(system.fides_key); - return ( - handleClick(system)} - > - - - - ); - })} - -
System NameClassification Status
- - - -
- {activeSystem ? ( - dispatch(setActiveClassifySystemFidesKey(undefined))} - /> - ) : null} -
- ); -}; - -export default ClassifySystemsTable; diff --git a/clients/admin-ui/src/features/system/system.slice.ts b/clients/admin-ui/src/features/system/system.slice.ts index d7e78b5bfb..578fbf9319 100644 --- a/clients/admin-ui/src/features/system/system.slice.ts +++ b/clients/admin-ui/src/features/system/system.slice.ts @@ -209,26 +209,10 @@ export const systemSlice = createSlice({ ) => { draftState.activeSystem = action.payload; }, - setActiveClassifySystemFidesKey: ( - draftState, - action: PayloadAction - ) => { - draftState.activeClassifySystemFidesKey = action.payload; - }, - setSystemsToClassify: ( - draftState, - action: PayloadAction - ) => { - draftState.systemsToClassify = action.payload; - }, }, }); -export const { - setActiveSystem, - setActiveClassifySystemFidesKey, - setSystemsToClassify, -} = systemSlice.actions; +export const { setActiveSystem } = systemSlice.actions; export const { reducer } = systemSlice; @@ -239,11 +223,6 @@ export const selectActiveSystem = createSelector( (state) => state.activeSystem ); -export const selectActiveClassifySystemFidesKey = createSelector( - selectSystem, - (state) => state.activeClassifySystemFidesKey -); - /** * Selects the number of systems * By using the paginated getSystems endpoint, we can get the total number of systems @@ -255,24 +234,3 @@ export const selectSystemsCount = createSelector( ], (RootState, { data }) => data?.total || 0 ); - -export const selectAllSystems = createSelector( - systemApi.endpoints.getAllSystems.select(), - ({ data }) => data -); - -export const selectActiveClassifySystem = createSelector( - [selectAllSystems, selectActiveClassifySystemFidesKey], - (allSystems, fidesKey) => { - if (fidesKey === undefined) { - return undefined; - } - const system = allSystems?.find((s) => s.fides_key === fidesKey); - return system; - } -); - -export const selectSystemsToClassify = createSelector( - selectSystem, - (state) => state.systemsToClassify -); diff --git a/clients/admin-ui/src/pages/classify-systems/index.tsx b/clients/admin-ui/src/pages/classify-systems/index.tsx deleted file mode 100644 index ece0ac18fa..0000000000 --- a/clients/admin-ui/src/pages/classify-systems/index.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { Button, Heading, HStack, Spinner, Stack, Text } from "fidesui"; -import type { NextPage } from "next"; -import NextLink from "next/link"; -import { useRouter } from "next/router"; -import { ReactNode, useEffect } from "react"; -import { useDispatch } from "react-redux"; - -import { useAppSelector } from "~/app/hooks"; -import { usePollForClassifications } from "~/features/common/classifications"; -import { useSystemOrDatamapRoute } from "~/features/common/hooks/useSystemOrDatamapRoute"; -import Layout from "~/features/common/Layout"; -import { useGetHealthQuery } from "~/features/plus/plus.slice"; -import { - selectSystemsToClassify, - setSystemsToClassify, - useGetAllSystemsQuery, -} from "~/features/system"; -import ClassifySystemsTable from "~/features/system/ClassifySystemsTable"; -import { GenerateTypes } from "~/types/api"; - -const ClassifySystemsLayout = ({ children }: { children: ReactNode }) => ( - - - - Classified systems - - {children} - - -); - -const ClassifySystems: NextPage = () => { - const router = useRouter(); - const dispatch = useDispatch(); - const { systemOrDatamapRoute } = useSystemOrDatamapRoute(); - const { isSuccess: hasPlus, isLoading: isLoadingPlus } = useGetHealthQuery(); - /** - * TODO: fides#1744 - * Because there is currently no way to associate a scan with its classification, - * we attempt to get the classification results for only the systems in review. - * However, because this is its own page that can be navigated to directly, - * we can't necessarily rely on knowing which systems were put into review - * Therefore, as a fallback, query all systems. - */ - const systemsToClassify = useAppSelector(selectSystemsToClassify); - const { isLoading: isLoadingSystems, data: allSystems } = - useGetAllSystemsQuery(undefined, { - skip: !hasPlus || (systemsToClassify && systemsToClassify.length > 0), - }); - const systems = systemsToClassify || allSystems; - useEffect(() => { - if (allSystems && allSystems.length) { - dispatch(setSystemsToClassify(allSystems)); - } - }, [dispatch, allSystems]); - - const { - isLoading: isLoadingClassifications, - data: classifications, - isClassificationFinished, - } = usePollForClassifications({ - resourceType: GenerateTypes.SYSTEMS, - fidesKeys: systems?.map((s) => s.fides_key), - skip: !hasPlus, - }); - - useEffect(() => { - if (!isLoadingPlus && !hasPlus) { - router.push("/"); - } - }, [router, hasPlus, isLoadingPlus]); - - const isLoading = isLoadingSystems || isLoadingClassifications; - - if (isLoading) { - return ( - - - - ); - } - - if (!classifications || classifications.length === 0) { - return ( - - - No classifications found. Have you run a scan? - - - ); - } - - return ( - - - {isClassificationFinished - ? "All systems have been classifed by Fides." - : "Systems are still being classified by Fides."} - - {systems && systems.length ? ( - - ) : ( - "No systems with classifications found" - )} - - - - - ); -}; - -export default ClassifySystems; From b94284fae2afa961c54e7187af51060f05dbee49 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 30 Jul 2024 10:41:25 -0300 Subject: [PATCH 18/24] PROD-1899 Update tests --- clients/admin-ui/cypress/e2e/routes.cy.ts | 3 +-- clients/admin-ui/cypress/e2e/user-management.cy.ts | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/clients/admin-ui/cypress/e2e/routes.cy.ts b/clients/admin-ui/cypress/e2e/routes.cy.ts index f0ff757d14..9c13c04c0a 100644 --- a/clients/admin-ui/cypress/e2e/routes.cy.ts +++ b/clients/admin-ui/cypress/e2e/routes.cy.ts @@ -16,7 +16,7 @@ describe("Routes", () => { describe("permissions", () => { beforeEach(() => { // For these tests, let's say we always have systems and connectors - cy.intercept("GET", "/api/v1/system", { + cy.intercept("GET", "/api/v1/system*", { fixture: "systems/systems.json", }).as("getSystems"); cy.intercept("GET", "/api/v1/connection*", { @@ -29,7 +29,6 @@ describe("Routes", () => { cy.assumeRole(RoleRegistryEnum.OWNER); cy.visit("/"); cy.visit(ADD_SYSTEMS_ROUTE); - cy.wait("@getSystems"); cy.getByTestId("add-systems"); cy.visit("/privacy-requests"); cy.getByTestId("privacy-requests"); diff --git a/clients/admin-ui/cypress/e2e/user-management.cy.ts b/clients/admin-ui/cypress/e2e/user-management.cy.ts index 7b1b002a86..7a94595853 100644 --- a/clients/admin-ui/cypress/e2e/user-management.cy.ts +++ b/clients/admin-ui/cypress/e2e/user-management.cy.ts @@ -371,7 +371,6 @@ describe("User management", () => { beforeEach(() => { cy.visit(`/user-management/profile/${USER_1_ID}`); cy.getByTestId("tab-Permissions").click(); - cy.wait("@getSystems"); cy.wait("@getUserManagedSystems"); }); @@ -391,7 +390,6 @@ describe("User management", () => { beforeEach(() => { cy.visit(`/user-management/profile/${USER_1_ID}`); cy.getByTestId("tab-Permissions").click(); - cy.wait("@getSystems"); cy.wait("@getUserManagedSystems"); cy.getByTestId("assign-systems-delete-table"); }); From b63d28b98a8bcf954d4e778031ac8912653ca536 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 30 Jul 2024 10:55:28 -0300 Subject: [PATCH 19/24] PROD-1899 Removed unused component --- .../features/system/SystemRegisterSuccess.tsx | 122 ------------------ 1 file changed, 122 deletions(-) delete mode 100644 clients/admin-ui/src/features/system/SystemRegisterSuccess.tsx diff --git a/clients/admin-ui/src/features/system/SystemRegisterSuccess.tsx b/clients/admin-ui/src/features/system/SystemRegisterSuccess.tsx deleted file mode 100644 index eb144274dd..0000000000 --- a/clients/admin-ui/src/features/system/SystemRegisterSuccess.tsx +++ /dev/null @@ -1,122 +0,0 @@ -import { - Badge, - Box, - Button, - chakra, - Heading, - Stack, - StepperCircleCheckmarkIcon, - Table, - TableContainer, - Tbody, - Td, - Text, - Th, - Thead, - Tr, -} from "fidesui"; -import { useRouter } from "next/router"; - -import { useAppDispatch } from "~/app/hooks"; -import { SYSTEM_ROUTE } from "~/features/common/nav/v2/routes"; -import { - setActiveSystem, - useGetAllSystemsQuery, -} from "~/features/system/system.slice"; -import { System } from "~/types/api"; - -interface Props { - system: System; - onAddNextSystem: () => void; -} -const SystemRegisterSuccess = ({ system, onAddNextSystem }: Props) => { - const { data: allRegisteredSystems = [] } = useGetAllSystemsQuery(); - - const dispatch = useAppDispatch(); - const router = useRouter(); - const otherSystems = allRegisteredSystems - ? allRegisteredSystems.filter( - (registeredSystem) => registeredSystem.name !== system.name - ) - : []; - - const systemName = system.name ?? system.fides_key; - - const onFinish = () => { - dispatch(setActiveSystem(undefined)); - - router.push(SYSTEM_ROUTE); - }; - - return ( - - - - - Success - - {systemName} successfully registered! - - {systemName} has been successfully added to the registry! - - - - - - - - - - - - - {otherSystems.map((s) => ( - - - - - ))} - -
System Name
{systemName} - -
{s.name} - -
-
- You can continue to add more systems now or finish. - - - - - -
-
- ); -}; -export default SystemRegisterSuccess; From 52c985672b1da148bf7bf3bc53aaceba5e403de5 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 30 Jul 2024 14:48:13 -0300 Subject: [PATCH 20/24] PROD-1899 Add back FE validation for systems with the same name using search param for paginated endpoint --- .../features/configure-consent/AddVendor.tsx | 19 ++++++++++++------- .../features/system/SystemInformationForm.tsx | 18 ++++++++++++------ .../src/features/system/system.slice.ts | 1 + 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/clients/admin-ui/src/features/configure-consent/AddVendor.tsx b/clients/admin-ui/src/features/configure-consent/AddVendor.tsx index 9b8abac4ec..7604dc5837 100644 --- a/clients/admin-ui/src/features/configure-consent/AddVendor.tsx +++ b/clients/admin-ui/src/features/configure-consent/AddVendor.tsx @@ -22,7 +22,7 @@ import { } from "~/features/plus/plus.slice"; import { useCreateSystemMutation, - useGetAllSystemsQuery, + useLazyGetSystemsQuery, } from "~/features/system"; import { selectLockedForGVL, @@ -67,7 +67,7 @@ const AddVendor = ({ const dispatch = useAppDispatch(); - const { data: systems = [] } = useGetAllSystemsQuery(); + const [getSystemQueryTrigger] = useLazyGetSystemsQuery(); const ValidationSchema = useMemo( () => @@ -75,17 +75,22 @@ const AddVendor = ({ name: Yup.string() .required() .label("Vendor name") - .test("is-unique", "", (value, context) => { - const takenSystemNames = systems.map((s) => s.name); - if (takenSystemNames.some((name) => name === value)) { + .test("is-unique", "", async (value, context) => { + const { data } = await getSystemQueryTrigger({ + page: 1, + size: 10, + search: value, + }); + const similarSystemNames = data?.items || []; + if (similarSystemNames.some((s) => s.name === value)) { return context.createError({ - message: `You already have a vendor called "${value}". Please specify a unique name for this vendor.`, + message: `You already have a system called "${value}". Please specify a unique name for this system.`, }); } return true; }), }), - [systems] + [getSystemQueryTrigger] ); // Subscribe and get dictionary values diff --git a/clients/admin-ui/src/features/system/SystemInformationForm.tsx b/clients/admin-ui/src/features/system/SystemInformationForm.tsx index 20f2414c57..e8bd9606de 100644 --- a/clients/admin-ui/src/features/system/SystemInformationForm.tsx +++ b/clients/admin-ui/src/features/system/SystemInformationForm.tsx @@ -52,6 +52,7 @@ import { import { useCreateSystemMutation, useGetAllSystemsQuery, + useLazyGetSystemsQuery, useUpdateSystemMutation, } from "~/features/system/system.slice"; import SystemFormInputGroup from "~/features/system/SystemFormInputGroup"; @@ -115,17 +116,22 @@ const SystemInformationForm = ({ [passedInSystem, customFields.customFieldValues] ); + const [getSystemQueryTrigger] = useLazyGetSystemsQuery(); + const ValidationSchema = useMemo( () => Yup.object().shape({ name: Yup.string() .required() .label("System name") - .test("is-unique", "", (value, context) => { - const takenSystemNames = systems - .map((s) => s.name) - .filter((name) => name !== initialValues.name); - if (takenSystemNames.some((name) => name === value)) { + .test("is-unique", "", async (value, context) => { + const { data } = await getSystemQueryTrigger({ + page: 1, + size: 10, + search: value, + }); + const similarSystemNames = data?.items || []; + if (similarSystemNames.some((s) => s.name === value)) { return context.createError({ message: `You already have a system called "${value}". Please specify a unique name for this system.`, }); @@ -134,7 +140,7 @@ const SystemInformationForm = ({ }), privacy_policy: Yup.string().min(1).url().nullable(), }), - [systems, initialValues.name] + [getSystemQueryTrigger] ); const features = useFeatures(); diff --git a/clients/admin-ui/src/features/system/system.slice.ts b/clients/admin-ui/src/features/system/system.slice.ts index 578fbf9319..c19f8a1928 100644 --- a/clients/admin-ui/src/features/system/system.slice.ts +++ b/clients/admin-ui/src/features/system/system.slice.ts @@ -179,6 +179,7 @@ const systemApi = baseApi.injectEndpoints({ export const { useGetSystemsQuery, + useLazyGetSystemsQuery, useGetAllSystemsQuery, useGetSystemByFidesKeyQuery, useCreateSystemMutation, From 520d3241eaffaa399455f629bb0bc05ae5ec7c3f Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 30 Jul 2024 14:52:05 -0300 Subject: [PATCH 21/24] PROD-1899 Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c45e95d240..2a4d0d77a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ The types of changes are: - Serve GVL languages as they are requested [#5112](https://github.com/ethyca/fides/pull/5112) - Changed text on system integrations tab to direct to new integration management [#5097](https://github.com/ethyca/fides/pull/5097) - Updates to consent experience styling [#5085](https://github.com/ethyca/fides/pull/5085) +- Improve performance by removing the need to load every system into redux store [#5135](https://github.com/ethyca/fides/pull/5135) + ### Developer Experience - Add `.syncignore` to reduce file sync size with new volumes [#5104](https://github.com/ethyca/fides/pull/5104) From f900e8d2d3b2e3871f2228bd12499f0c047127a2 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 30 Jul 2024 14:59:10 -0300 Subject: [PATCH 22/24] PROD-1899 Fix edit system validation --- .../src/features/system/SystemInformationForm.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/clients/admin-ui/src/features/system/SystemInformationForm.tsx b/clients/admin-ui/src/features/system/SystemInformationForm.tsx index e8bd9606de..c2cbf87225 100644 --- a/clients/admin-ui/src/features/system/SystemInformationForm.tsx +++ b/clients/admin-ui/src/features/system/SystemInformationForm.tsx @@ -130,7 +130,11 @@ const SystemInformationForm = ({ size: 10, search: value, }); - const similarSystemNames = data?.items || []; + const systemResults = data?.items || []; + const similarSystemNames = systemResults.filter( + (s) => s.name !== initialValues.name + ); + console.log(similarSystemNames); if (similarSystemNames.some((s) => s.name === value)) { return context.createError({ message: `You already have a system called "${value}". Please specify a unique name for this system.`, @@ -140,7 +144,7 @@ const SystemInformationForm = ({ }), privacy_policy: Yup.string().min(1).url().nullable(), }), - [getSystemQueryTrigger] + [getSystemQueryTrigger, initialValues.name] ); const features = useFeatures(); From ba8bad60162fc0177800c6ff3b30f6a392eb17e5 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Tue, 30 Jul 2024 15:05:28 -0300 Subject: [PATCH 23/24] Remove console log --- clients/admin-ui/src/features/system/SystemInformationForm.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/clients/admin-ui/src/features/system/SystemInformationForm.tsx b/clients/admin-ui/src/features/system/SystemInformationForm.tsx index c2cbf87225..5e5f59801f 100644 --- a/clients/admin-ui/src/features/system/SystemInformationForm.tsx +++ b/clients/admin-ui/src/features/system/SystemInformationForm.tsx @@ -134,7 +134,6 @@ const SystemInformationForm = ({ const similarSystemNames = systemResults.filter( (s) => s.name !== initialValues.name ); - console.log(similarSystemNames); if (similarSystemNames.some((s) => s.name === value)) { return context.createError({ message: `You already have a system called "${value}". Please specify a unique name for this system.`, From 5204adaa0824a9fc1c90742611db46d30e588358 Mon Sep 17 00:00:00 2001 From: Lucano Vera Date: Wed, 31 Jul 2024 13:14:18 -0300 Subject: [PATCH 24/24] Update clients/admin-ui/src/features/configure-consent/AddVendor.tsx Co-authored-by: jpople --- clients/admin-ui/src/features/configure-consent/AddVendor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/admin-ui/src/features/configure-consent/AddVendor.tsx b/clients/admin-ui/src/features/configure-consent/AddVendor.tsx index 7604dc5837..32cb3d86d3 100644 --- a/clients/admin-ui/src/features/configure-consent/AddVendor.tsx +++ b/clients/admin-ui/src/features/configure-consent/AddVendor.tsx @@ -84,7 +84,7 @@ const AddVendor = ({ const similarSystemNames = data?.items || []; if (similarSystemNames.some((s) => s.name === value)) { return context.createError({ - message: `You already have a system called "${value}". Please specify a unique name for this system.`, + message: `You already have a vendor called "${value}". Please specify a unique name for this vendor.`, }); } return true;