Skip to content

Commit

Permalink
New fields on system forms (#1082)
Browse files Browse the repository at this point in the history
* Extend DescribeSystemsForm

* Extend PrivacyDeclarationForm

* Add joint controller and data protection impact assessment

* Move system dependency field to abridged form

* Prepare data protection impact assessment for payload

* Add cypress tests

* Extend ReviewSystemForm

* Add tests for extended review form

* Fix adding another declaration when name field is blank

* Rename SuccessPage --> SystemRegisterSuccess

* Pass system object through props

* Update tests

* Update changelog

* Refactor ReviewSystemForm

* Move config wizard system forms to system directory (#1097)

* Move system forms to system directory

* Refactor form layout components into its own file

* Rename files from form --> step

* Update changelog
  • Loading branch information
allisonking authored Sep 20, 2022
1 parent 1d3bffc commit 3f17946
Show file tree
Hide file tree
Showing 16 changed files with 512 additions and 120 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ The types of changes are:
* New page to add a system via yaml [#1062](https://github.com/ethyca/fides/pull/1062)
* Skeleton of page to add a system manually [#1068](https://github.com/ethyca/fides/pull/1068)
* Refactor config wizard system forms to be reused for system management [#1072](https://github.com/ethyca/fides/pull/1072)
* Add additional optional fields to system management forms [#1082](https://github.com/ethyca/fides/pull/1082)
* Delete a system through the UI [#1085](https://github.com/ethyca/fides/pull/1085)

### Changed

* Changed behavior of `load_default_taxonomy` to append instead of upsert [#1040](https://github.com/ethyca/fides/pull/1040)
* Changed behavior of adding privacy declarations to decouple the actions of the "add" and "next" buttons [#1086](https://github.com/ethyca/fides/pull/1086)
* Moved system related UI components from the `config-wizard` directory to the `system` directory [#1097](https://github.com/ethyca/fides/pull/1097)

### Fixed

Expand Down
162 changes: 159 additions & 3 deletions clients/ctl/admin-ui/cypress/e2e/systems.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ describe("System management page", () => {
cy.intercept("GET", "/api/v1/data_use", {
fixture: "data_uses.json",
}).as("getDataUse");
cy.intercept("GET", "/api/v1/system", {
fixture: "systems.json",
}).as("getSystems");
cy.intercept("GET", "/api/v1/dataset", { fixture: "datasets.json" }).as(
"getDatasets"
);
});

it("Can step through the flow", () => {
Expand All @@ -135,13 +141,19 @@ describe("System management page", () => {
cy.visit("/system/new");
cy.getByTestId("manually-generate-btn").click();
cy.url().should("contain", "/system/new/configure");
cy.wait("@getSystems");
cy.getByTestId("input-name").type(system.name);
cy.getByTestId("input-fides_key").type(system.fides_key);
cy.getByTestId("input-description").type(system.description);
cy.getByTestId("input-system_type").type(system.system_type);
system.tags.forEach((tag) => {
cy.getByTestId("input-tags").type(`${tag}{enter}`);
});
cy.getByTestId("input-system_dependencies").click();
cy.getByTestId("input-system_dependencies").within(() => {
cy.contains("Demo Analytics System").click();
});

cy.getByTestId("confirm-btn").click();
cy.wait("@postSystem").then((interception) => {
const { body } = interception.request;
Expand All @@ -153,6 +165,8 @@ describe("System management page", () => {
system_type: system.system_type,
tags: system.tags,
privacy_declarations: [],
third_country_transfers: [],
system_dependencies: ["demo_analytics_system"],
});
});

Expand Down Expand Up @@ -183,9 +197,10 @@ describe("System management page", () => {
cy.getByTestId("next-btn").click();
cy.wait("@putSystem").then((interception) => {
const { body } = interception.request;
// eslint-disable-next-line @typescript-eslint/naming-convention
const { dataset_references, ...expected } = declaration;
expect(body.privacy_declarations[0]).to.eql(expected);
expect(body.privacy_declarations[0]).to.eql({
...declaration,
dataset_references: [],
});
});

// Now at the Review stage
Expand All @@ -199,6 +214,9 @@ describe("System management page", () => {
system.tags.forEach((tag) => {
cy.getByTestId("review-System tags").contains(tag);
});
system.system_dependencies.forEach((dep) => {
cy.getByTestId("review-System dependencies").contains(dep);
});
// Open up the privacy declaration
cy.getByTestId(
"declaration-Analyze customer behaviour for improvements."
Expand All @@ -216,6 +234,9 @@ describe("System management page", () => {
cy.getByTestId("declaration-Data qualifier").contains(
reviewDeclaration.data_qualifier
);
reviewDeclaration.dataset_references.forEach((dr) => {
cy.getByTestId("declaration-Dataset references").contains(dr);
});

cy.getByTestId("confirm-btn").click();

Expand All @@ -228,6 +249,141 @@ describe("System management page", () => {
cy.url().should("match", /system$/);
});
});

it("Can render and post extended form fields", () => {
const system = {
fides_key: "foo",
system_type: "cool system",
data_responsibility_title: "Sub-Processor",
organization_fides_key: "default_organization",
administrating_department: "department",
third_country_transfers: ["USA"],
joint_controller: {
name: "bob",
email: "[email protected]",
},
data_protection_impact_assessment: {
is_required: true,
progress: "in progress",
link: "http://www.ethyca.com",
},
};
cy.visit("/system/new");
cy.getByTestId("manually-generate-btn").click();
// input required fields
cy.getByTestId("input-fides_key").type(system.fides_key);
cy.getByTestId("input-system_type").type(system.system_type);

// now input extra fields
cy.getByTestId("input-data_responsibility_title").click();
cy.getByTestId("input-data_responsibility_title").within(() => {
cy.contains(system.data_responsibility_title).click();
});
cy.getByTestId("input-administrating_department").type(
system.administrating_department
);
cy.getByTestId("input-third_country_transfers").type(
"United States of America{enter}"
);
cy.getByTestId("input-joint_controller.name").type(
system.joint_controller.name
);
cy.getByTestId("input-joint_controller.email").type(
system.joint_controller.email
);
cy.getByTestId(
"input-data_protection_impact_assessment.is_required"
).within(() => {
cy.getByTestId("option-true").click();
});
cy.getByTestId("input-data_protection_impact_assessment.progress").type(
system.data_protection_impact_assessment.progress
);
cy.getByTestId("input-data_protection_impact_assessment.link").type(
system.data_protection_impact_assessment.link
);

cy.getByTestId("confirm-btn").click();
cy.wait("@postSystem").then((interception) => {
const { body } = interception.request;
expect(body).to.eql({
name: "",
organization_fides_key: system.organization_fides_key,
fides_key: system.fides_key,
description: "",
system_type: system.system_type,
tags: [],
privacy_declarations: [],
third_country_transfers: ["USA"],
system_dependencies: [],
administrating_department: system.administrating_department,
data_responsibility_title: system.data_responsibility_title,
joint_controller: {
...system.joint_controller,
address: "",
phone: "",
},
data_protection_impact_assessment:
system.data_protection_impact_assessment,
});
});

// Fill in the privacy declaration form
cy.wait("@getDataCategory");
cy.wait("@getDataQualifier");
cy.wait("@getDataSubject");
cy.wait("@getDataUse");
cy.wait("@getDatasets");
cy.getByTestId("privacy-declaration-form");
const declaration = {
name: "my declaration",
data_categories: ["user.biometric", "user.contact"],
data_use: "advertising",
data_subjects: ["citizen_voter", "consultant"],
dataset_references: ["demo_users_dataset_2"],
};
cy.getByTestId("input-name").type(declaration.name);
declaration.data_categories.forEach((dc) => {
cy.getByTestId("input-data_categories").type(`${dc}{enter}`);
});
cy.getByTestId("input-data_use").type(`${declaration.data_use}{enter}`);
declaration.data_subjects.forEach((ds) => {
cy.getByTestId("input-data_subjects").type(`${ds}{enter}`);
});
cy.getByTestId("input-dataset_references").click();
cy.getByTestId("input-dataset_references").within(() => {
cy.contains("Demo Users Dataset 2").click();
});
cy.getByTestId("add-btn").click();
cy.getByTestId("next-btn").click();
cy.wait("@putSystem").then((interception) => {
const { body } = interception.request;
expect(body.privacy_declarations[0]).to.eql(declaration);
});

// Now at the Review stage
cy.getByTestId("review-heading");
cy.getByTestId("review-Data responsibility title").contains(
"Controller"
);
cy.getByTestId("review-Administrating department").contains(
"Engineering"
);
cy.getByTestId("review-Geographic location").contains("USA");
cy.getByTestId("review-Geographic location").contains("CAN");
cy.getByTestId("review-Joint controller").within(() => {
cy.getByTestId("review-Name").contains("Sally Controller");
});
cy.getByTestId("review-Data protection impact assessment").within(
() => {
cy.getByTestId("review-Is required").contains("Yes");
cy.getByTestId("review-Progress").contains("Complete");
cy.getByTestId("review-Link").contains(
"https://example.org/analytics_system_data_protection_impact_assessment"
);
}
);
});
});
});

Expand Down
4 changes: 2 additions & 2 deletions clients/ctl/admin-ui/cypress/fixtures/system.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"dataset_references": ["demo_users_dataset"]
}
],
"system_dependencies": null,
"joint_controller": null,
"system_dependencies": ["demo_marketing_system"],
"joint_controller": { "name": "Sally Controller" },
"third_country_transfers": ["USA", "CAN"],
"administrating_department": "Engineering",
"data_protection_impact_assessment": {
Expand Down
9 changes: 9 additions & 0 deletions clients/ctl/admin-ui/src/features/common/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,12 @@ export const parseError = (

return defaultError;
};

/**
* Given an enumeration, create options out of its key and values
*/
export const enumToOptions = (e: { [s: number]: string }) =>
Object.entries(e).map((entry) => ({
value: entry[1],
label: entry[1],
}));
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import React from "react";

import { useAppDispatch, useAppSelector } from "~/app/hooks";
import { CloseSolidIcon } from "~/features/common/Icon";
import DescribeSystemStep from "~/features/system/DescribeSystemStep";
import PrivacyDeclarationStep from "~/features/system/PrivacyDeclarationStep";
import ReviewSystemStep from "~/features/system/ReviewSystemStep";
import SystemRegisterSuccess from "~/features/system/SystemRegisterSuccess";
import { System } from "~/types/api";

import HorizontalStepper from "../common/HorizontalStepper";
Expand All @@ -19,12 +23,8 @@ import {
setSystemToCreate,
} from "./config-wizard.slice";
import { HORIZONTAL_STEPS, STEPS } from "./constants";
import DescribeSystemsForm from "./DescribeSystemsForm";
import OrganizationInfoForm from "./OrganizationInfoForm";
import PrivacyDeclarationForm from "./PrivacyDeclarationForm";
import ReviewSystemForm from "./ReviewSystemForm";
import ScanResultsForm from "./ScanResultsForm";
import SystemRegisterSuccess from "./SystemRegisterSuccess";
import ViewYourDataMapPage from "./ViewYourDataMapPage";

const ConfigWizardWalkthrough = () => {
Expand Down Expand Up @@ -81,23 +81,26 @@ const ConfigWizardWalkthrough = () => {
/>
) : null}
{reviewStep === 1 && (
<DescribeSystemsForm
<DescribeSystemStep
onCancel={handleCancelSetup}
onSuccess={handleSuccess}
abridged
/>
)}
{reviewStep === 2 && system && (
<PrivacyDeclarationForm
<PrivacyDeclarationStep
system={system}
onCancel={handleCancelSetup}
onSuccess={handleSuccess}
abridged
/>
)}
{reviewStep === 3 && system && (
<ReviewSystemForm
<ReviewSystemStep
system={system}
onCancel={handleCancelSetup}
onSuccess={() => dispatch(changeReviewStep())}
abridged
/>
)}
{reviewStep === 4 && system && (
Expand Down
Loading

0 comments on commit 3f17946

Please sign in to comment.