Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Systems frontend scaffolding #696

Merged
merged 39 commits into from
Jun 1, 2022
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
1541652
Add import sorting, same as fidesops#9de2136
allisonking May 19, 2022
51acf14
Run import sorting
allisonking May 19, 2022
d70341d
Update changelog
allisonking May 19, 2022
8fdfd64
Use baseurl for easier imports
allisonking May 19, 2022
85b3256
Add prettier
allisonking May 19, 2022
657a1ff
Simplify components via a Layout component
allisonking May 19, 2022
189052d
Add testing to the NavBar
allisonking May 19, 2022
c6d43ed
Fix pluralization in routes
allisonking May 19, 2022
b0a46a4
Remove unused import
allisonking May 19, 2022
c552049
Update changelog
allisonking May 20, 2022
b646afd
Run prettier
allisonking May 20, 2022
2140645
Update changelog
allisonking May 20, 2022
37d44c6
Add redux for datasets
allisonking May 20, 2022
daf3e06
Rename folder to match pluralization
allisonking May 20, 2022
e3f0655
Add dataset table
allisonking May 20, 2022
caccb58
Revert "Update changelog"
allisonking May 20, 2022
4c7dee5
Fix path to page
allisonking May 20, 2022
fcff5fe
Add .prettierignore to leave the changelog alone
allisonking May 20, 2022
8b0d36f
Update changelog
allisonking May 20, 2022
109d8af
merge main
allisonking May 20, 2022
70bcc26
Configure redux store
allisonking May 20, 2022
8ccc97d
Configure proxy to backend
allisonking May 20, 2022
daf4859
Populate the dataset table
allisonking May 20, 2022
a8cb6ba
Add a note about the rewrite
allisonking May 20, 2022
b9c6e03
Merge branch 'aking-676-dataset-api-frontend' into aking-run-prettier
allisonking May 20, 2022
cc78291
Merge branch 'aking-run-prettier' into aking-676-dataset-api-frontend-b
allisonking May 20, 2022
dfc51c6
Add API path to production .env file
allisonking May 23, 2022
06946a3
Refactor types
allisonking May 23, 2022
3343b50
Add systems page
allisonking May 23, 2022
a8a1beb
Update changelog
allisonking May 23, 2022
0530412
Add space between props and component
allisonking May 24, 2022
2bce84d
Remove any type
allisonking May 24, 2022
d19170f
Change import path shortcut from @ to ~
allisonking May 25, 2022
39c4711
Merge aking-676-dataset-api-frontend
allisonking May 25, 2022
bea7eb9
Merge aking-676-dataset-api-frontend-b
allisonking May 25, 2022
9a966ef
Add unit tests for systems
allisonking May 25, 2022
3ac3f3d
merge main
allisonking May 25, 2022
d3ed0d2
merge main
allisonking May 31, 2022
21d8d95
Update changelog
allisonking Jun 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ The types of changes are:
* UI static assets are now built with the docker container [#663](https://github.com/ethyca/fides/issues/663)
* Host static files via fidesapi [#621](https://github.com/ethyca/fides/pull/621)
* Navigation bar for management UI
* Dataset backend integration for management UI
* Integration for management UI
* Datasets
* Systems
* Okta, aws and database credentials can now come from `fidesctl.toml` config [#694](https://github.com/ethyca/fides/pull/694)

### Changed
Expand Down
19 changes: 19 additions & 0 deletions clients/admin-ui/__tests__/features/system.slice.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { AnyAction } from "@reduxjs/toolkit";

import { reducer, setSystems } from "~/features/system";
import { mockSystems } from "~/mocks/data";

const initialState = {
systems: [],
};

describe("System slice", () => {
it("should return the initial state", () => {
expect(reducer(undefined, {} as AnyAction)).toEqual(initialState);
});

it("should handle a dataset being added", () => {
const systems = mockSystems(1);
expect(reducer(initialState, setSystems(systems))).toEqual({ systems });
});
});
23 changes: 23 additions & 0 deletions clients/admin-ui/__tests__/features/system.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { render } from "@testing-library/react";

import SystemTable from "~/features/system/SystemTable";
import { mockSystems } from "~/mocks/data";

describe("SystemTable", () => {
it("renders an empty state", () => {
const { getByTestId, queryByTestId } = render(<SystemTable systems={[]} />);
expect(getByTestId("empty-state")).toBeInTheDocument();
expect(queryByTestId("systems-table")).toBeNull();
});

it("renders a table", () => {
const numSystems = 10;
const systems = mockSystems(numSystems);
const { getByTestId, queryByTestId, getAllByTestId } = render(
<SystemTable systems={systems} />
);
expect(queryByTestId("empty-state")).toBeNull();
expect(getByTestId("systems-table")).toBeInTheDocument();
expect(getAllByTestId("systems-row")).toHaveLength(numSystems);
});
});
7 changes: 6 additions & 1 deletion clients/admin-ui/src/app/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@ import { setupListeners } from "@reduxjs/toolkit/query/react";
import { createWrapper } from "next-redux-wrapper";

import { datasetApi } from "~/features/dataset";
import { systemApi } from "~/features/system";
import { reducer as userReducer } from "~/features/user";

const makeStore = () => {
const store = configureStore({
reducer: {
user: userReducer,
[datasetApi.reducerPath]: datasetApi.reducer,
[systemApi.reducerPath]: systemApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(datasetApi.middleware),
getDefaultMiddleware().concat(
datasetApi.middleware,
systemApi.middleware
),
});
setupListeners(store.dispatch);
return store;
Expand Down
2 changes: 1 addition & 1 deletion clients/admin-ui/src/features/common/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const NavBar = () => {
borderColor="gray.100"
>
<nav>
<NavLink title="Systems" href="/system" disabled />
<NavLink title="Systems" href="/system" />
<NavLink title="Datasets" href="/dataset" />
<NavLink title="Policies" href="/policy" disabled />
<NavLink title="Taxonomy" href="/taxonomy" disabled />
Expand Down
32 changes: 32 additions & 0 deletions clients/admin-ui/src/features/system/SystemTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Table, Tbody, Td, Th, Thead, Tr } from "@fidesui/react";

import { System } from "./types";

interface Props {
systems: System[] | undefined;
}
const SystemsTable = ({ systems }: Props) => {
if (!systems || !systems.length) {
return <div data-testid="empty-state">Empty state</div>;
}
return (
<Table size="sm" data-testid="systems-table">
<Thead>
<Tr>
<Th>Name</Th>
<Th>Description</Th>
</Tr>
</Thead>
<Tbody>
{systems.map((system) => (
<Tr key={system.fides_key} data-testid="systems-row">
<Td>{system.name}</Td>
<Td>{system.description}</Td>
</Tr>
))}
</Tbody>
</Table>
);
};

export default SystemsTable;
1 change: 1 addition & 0 deletions clients/admin-ui/src/features/system/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./system.slice";
49 changes: 49 additions & 0 deletions clients/admin-ui/src/features/system/system.slice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { HYDRATE } from "next-redux-wrapper";

import { System } from "./types";

export interface State {
systems: System[];
}

const initialState: State = {
systems: [],
};

export const systemApi = createApi({
reducerPath: "systemApi",
baseQuery: fetchBaseQuery({
baseUrl: process.env.NEXT_PUBLIC_FIDESCTL_API,
}),
tagTypes: ["System"],
endpoints: (build) => ({
getAllSystems: build.query<System[], void>({
query: () => ({ url: `system/` }),
providesTags: () => ["System"],
}),
}),
});

export const { useGetAllSystemsQuery } = systemApi;

export const systemSlice = createSlice({
name: "system",
initialState,
reducers: {
setSystems: (state, action: PayloadAction<System[]>) => ({
systems: action.payload,
}),
},
extraReducers: {
[HYDRATE]: (state, action) => ({
...state,
...action.payload.datasets,
}),
},
});

export const { setSystems } = systemSlice.actions;

export const { reducer } = systemSlice;
42 changes: 42 additions & 0 deletions clients/admin-ui/src/features/system/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {
ContactDetails,
FidesBase,
FidesKey,
} from "~/features/common/fides-types";

export interface System extends FidesBase {
registry_id?: number;
meta?: Record<string, string>;
fidesctl_meta?: SystemMetadata;
system_type: string;
data_responsibility_title: DataResponsibilityTitle;
privacy_declarations: PrivacyDeclaration[];
system_dependencies?: FidesKey[];
joint_controller?: ContactDetails[];
third_country_transfers?: string[];
administrating_department?: string;
data_protection_impact_assessment: DataProtectionImpactAssessment;
}

type DataResponsibilityTitle = "Controller" | "Processor" | "Sub-Processor";

interface SystemMetadata {
resource_id?: string;
endpoint_address?: string;
endpoint_port?: string;
}

interface PrivacyDeclaration {
name: string;
data_categories: FidesKey[];
data_use: FidesKey;
data_qualifier: FidesKey;
data_subjects: FidesKey[];
dataset_references?: FidesKey[];
}

interface DataProtectionImpactAssessment {
is_required: boolean;
progress?: string;
link?: string;
}
28 changes: 28 additions & 0 deletions clients/admin-ui/src/mocks/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { System } from "~/features/system/types";

/**
* Returns a mock system object. Can override default values by
* passing in a Partial<System>
*/
export const mockSystem = (partialSystem?: Partial<System>): System => {
const system: System = {
system_type: "Service",
data_responsibility_title: "Controller",
privacy_declarations: [],
data_protection_impact_assessment: { is_required: true },
fides_key: "analytics_system",
organization_fides_key: "sample_organization",
};
return Object.assign(system, partialSystem);
};

/**
* Returns a list of mock systems of length `number`
*/
export const mockSystems = (number: number) =>
Array.from({ length: number }, (_, i) =>
mockSystem({
system_type: `Service ${i}`,
fides_key: `analytics_system_${i}`,
})
);
31 changes: 31 additions & 0 deletions clients/admin-ui/src/pages/system/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Heading, Spinner } from "@fidesui/react";
import type { NextPage } from "next";
import React from "react";

import Layout from "~/features/common/Layout";
import { useGetAllSystemsQuery } from "~/features/system";
import SystemsTable from "~/features/system/SystemTable";

const useSystemsTable = () => {
const { data, isLoading } = useGetAllSystemsQuery();

return {
isLoading,
systems: data,
};
};

const Systems: NextPage = () => {
const { isLoading, systems } = useSystemsTable();

return (
<Layout title="Systems">
<Heading mb={8} fontSize="2xl" fontWeight="semibold">
Systems
</Heading>
{isLoading ? <Spinner /> : <SystemsTable systems={systems} />}
</Layout>
);
};

export default Systems;