Skip to content

Commit

Permalink
Add check for is_default before rendering delete button (#1023)
Browse files Browse the repository at this point in the history
* Add check for is_default before rendering delete button

* Update changelog

* Update test data to include is_default

* Add cypress tests
  • Loading branch information
allisonking authored Aug 30, 2022
1 parent ba09cec commit 362fac9
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 54 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ The types of changes are:
* New column `is_default` added to DataCategory, DataUse, DataSubject, and DataQualifier tables [#976](https://github.com/ethyca/fides/pull/976)
* Added the ability to add taxonomy fields via the UI [#1019](https://github.com/ethyca/fides/pull/1019)
* Added the ability to delete taxonomy fields via the UI [#1006](https://github.com/ethyca/fides/pull/1006)
* Prevent modifying taxonomy `is_default` fields and from adding `is_default=True` fields via the API [#990](https://github.com/ethyca/fides/pull/990).
* Only non-default taxonomy entities can be deleted [#1023](https://github.com/ethyca/fides/pull/1023)
* Prevent deleting taxonomy `is_default` fields and from adding `is_default=True` fields via the API [#990](https://github.com/ethyca/fides/pull/990).
### Changed

* Upgraded base Docker version to Python 3.9 and updated all other references from 3.8 -> 3.9 [#974](https://github.com/ethyca/fides/pull/974)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,19 @@ describe("data category transform", () => {
description: "Account's city level address data.",
label: "Account City",
value: "account.contact.city",
is_default: true,
},
],
description: "Contact data related to a system account.",
label: "Account Contact Data",
value: "account.contact",
is_default: true,
},
],
description: "Data related to a system account.",
label: "Account Data",
value: "account",
is_default: true,
},
{
children: [
Expand All @@ -32,11 +35,13 @@ describe("data category transform", () => {
description: "Data used to manage access to the system.",
label: "Authentication Data",
value: "system.authentication",
is_default: true,
},
],
description: "Data unique to, and under control of the system.",
label: "System Data",
value: "system",
is_default: true,
},
{
children: [
Expand All @@ -46,6 +51,7 @@ describe("data category transform", () => {
"Data derived from user provided data or as a result of user actions in the system.",
label: "Derived Data",
value: "user.derived",
is_default: true,
},
{
children: [
Expand All @@ -55,6 +61,7 @@ describe("data category transform", () => {
"Data provided or created directly by a user that is not identifiable.",
label: "User Provided Non-Identifiable Data",
value: "user.provided.nonidentifiable",
is_default: true,
},
{
children: [
Expand All @@ -63,31 +70,36 @@ describe("data category transform", () => {
description: "Age range data.",
label: "User Provided Non-Specific Age",
value: "user.provided.identifiable.non_specific_age",
is_default: true,
},
{
children: [],
description:
"Data related to the individual's political opinions.",
label: "Political Opinion",
value: "user.provided.identifiable.political_opinion",
is_default: true,
},
],
description:
"Data provided or created directly by a user that is linked to or identifies a user.",
label: "User Provided Identifiable Data",
value: "user.provided.identifiable",
is_default: true,
},
],
description:
"Data provided or created directly by a user of the system.",
label: "User Provided Data",
value: "user.provided",
is_default: true,
},
],
description:
"Data related to the user of the system, either provided directly or derived based on their usage.",
label: "User Data",
value: "user",
is_default: true,
},
]);
});
Expand All @@ -100,20 +112,23 @@ describe("data category transform", () => {
value: "anonymous_user",
description:
"An individual that is unidentifiable to the systems. Note - This should only be applied to truly anonymous users where there is no risk of re-identification",
is_default: true,
children: [],
},
{
label: "Citizen Voter",
value: "citizen_voter",
description:
"An individual registered to voter with a state or authority.",
is_default: true,
children: [],
},
{
label: "Commuter",
value: "commuter",
description:
"An individual that is traveling or transiting in the context of location tracking.",
is_default: true,
children: [],
},
]);
Expand Down
79 changes: 33 additions & 46 deletions clients/ctl/admin-ui/cypress/e2e/taxonomy.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,66 +466,53 @@ describe("Taxonomy management page", () => {
);
});

it("Only renders delete button on nodes without children", () => {
it("Only renders delete button on custom fields without children", () => {
cy.getByTestId(`tab-Data Categories`).click();
// try default fields first
cy.getByTestId("accordion-item-User Data").trigger("mouseover");
cy.getByTestId("delete-btn").should("not.exist");
cy.getByTestId("accordion-item-User Data").click();
cy.getByTestId("item-Biometric Data").trigger("mouseover");
cy.getByTestId("delete-btn");
});
cy.getByTestId("delete-btn").should("not.exist");

it("Can delete a data category", () => {
cy.getByTestId(`tab-Data Categories`).click();
cy.getByTestId("accordion-item-User Data").click();
cy.getByTestId("item-Biometric Data").trigger("mouseover");
cy.getByTestId("delete-btn").click();
cy.getByTestId("continue-btn").click();
cy.wait("@deleteDataCategory").then((interception) => {
const { url } = interception.request;
expect(url).to.contain("user.biometric");
});
cy.getByTestId("toast-success-msg");
// now try custom fields
cy.getByTestId("accordion-item-Custom field").trigger("mouseover");
cy.getByTestId("delete-btn").should("not.exist");
cy.getByTestId("accordion-item-Custom field").click();
cy.getByTestId("item-Custom foo").trigger("mouseover");
cy.getByTestId("delete-btn");
});

it("Can delete a data use", () => {
cy.getByTestId(`tab-Data Uses`).click();
cy.getByTestId("item-Collect").trigger("mouseover");
cy.getByTestId("delete-btn").click();
cy.getByTestId("continue-btn").click();
cy.wait("@deleteDataUse").then((interception) => {
const { url } = interception.request;
expect(url).to.contain("collect");
it("Can delete from each taxonomy type (except Data Subject)", () => {
// Data Subject is slightly different than the others since it doesn't have
// a parent field, so easiest to split it out into its own test
const tabValues = [
{ tab: "Data Categories", request: "@deleteDataCategory" },
{ tab: "Data Uses", request: "@deleteDataUse" },
{ tab: "Identifiability", request: "@deleteDataQualifier" },
];
tabValues.forEach((tabValue) => {
cy.getByTestId(`tab-${tabValue.tab}`).click();
cy.getByTestId("accordion-item-Custom field").click();
cy.getByTestId("item-Custom foo").trigger("mouseover");
cy.getByTestId("delete-btn").click();
cy.getByTestId("continue-btn").click();
cy.wait(tabValue.request).then((interception) => {
const { url } = interception.request;
expect(url).to.contain("custom.foo");
});
cy.getByTestId("toast-success-msg");
});
cy.getByTestId("toast-success-msg");
});

it("Can delete a data subject", () => {
it("Can delete taxonomy field from Data Subject", () => {
cy.getByTestId(`tab-Data Subjects`).click();
cy.getByTestId("item-Commuter").trigger("mouseover");
cy.getByTestId("item-Custom field").trigger("mouseover");
cy.getByTestId("delete-btn").click();
cy.getByTestId("continue-btn").click();
cy.wait("@deleteDataSubject").then((interception) => {
const { url } = interception.request;
expect(url).to.contain("commuter");
});
cy.getByTestId("toast-success-msg");
});

it("Can delete a data qualifier", () => {
cy.getByTestId(`tab-Identifiability`).click();
cy.getByTestId("accordion-item-Aggregated Data").click();
cy.getByTestId("accordion-item-Anonymized Data").click();
cy.getByTestId("accordion-item-Unlinked Pseudonymized Data").click();
cy.getByTestId("accordion-item-Pseudonymized Data").click();
cy.getByTestId("item-Identified Data").trigger("mouseover");
cy.getByTestId("delete-btn").click();
cy.getByTestId("continue-btn").click();
cy.wait("@deleteDataQualifier").then((interception) => {
const { url } = interception.request;
expect(url).to.contain(
"aggregated.anonymized.unlinked_pseudonymized.pseudonymized.identified"
);
expect(url).to.contain("custom");
});
cy.getByTestId("toast-success-msg");
});
Expand All @@ -536,8 +523,8 @@ describe("Taxonomy management page", () => {
body: "Internal Server Error",
}).as("deleteDataCategoryError");
cy.getByTestId(`tab-Data Categories`).click();
cy.getByTestId("accordion-item-User Data").click();
cy.getByTestId("item-Biometric Data").trigger("mouseover");
cy.getByTestId("accordion-item-Custom field").click();
cy.getByTestId("item-Custom foo").trigger("mouseover");
cy.getByTestId("delete-btn").click();
cy.getByTestId("continue-btn").click();
cy.wait("@deleteDataCategoryError");
Expand Down
18 changes: 18 additions & 0 deletions clients/ctl/admin-ui/cypress/fixtures/data_categories.json
Original file line number Diff line number Diff line change
Expand Up @@ -502,5 +502,23 @@
"description": "Data related to the individual's political opinions.",
"parent_key": "user",
"is_default": true
},
{
"fides_key": "custom",
"organization_fides_key": "default_organization",
"tags": null,
"name": "Custom field",
"description": "Custom field for tests",
"parent_key": null,
"is_default": false
},
{
"fides_key": "custom.foo",
"organization_fides_key": "default_organization",
"tags": null,
"name": "Custom foo",
"description": "Custom foo for tests",
"parent_key": "custom",
"is_default": false
}
]
18 changes: 18 additions & 0 deletions clients/ctl/admin-ui/cypress/fixtures/data_qualifiers.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,23 @@
"description": "Data that directly identifies an individual.",
"parent_key": "aggregated.anonymized.unlinked_pseudonymized.pseudonymized",
"is_default": true
},
{
"fides_key": "custom",
"organization_fides_key": "default_organization",
"tags": null,
"name": "Custom field",
"description": "Custom field for tests",
"parent_key": null,
"is_default": false
},
{
"fides_key": "custom.foo",
"organization_fides_key": "default_organization",
"tags": null,
"name": "Custom foo",
"description": "Custom foo for tests",
"parent_key": "custom",
"is_default": false
}
]
10 changes: 10 additions & 0 deletions clients/ctl/admin-ui/cypress/fixtures/data_subjects.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,15 @@
"rights": null,
"automated_decisions_or_profiling": null,
"is_default": true
},
{
"fides_key": "custom",
"organization_fides_key": "default_organization",
"tags": null,
"name": "Custom field",
"description": "Custom field for tests",
"rights": null,
"automated_decisions_or_profiling": null,
"is_default": false
}
]
28 changes: 28 additions & 0 deletions clients/ctl/admin-ui/cypress/fixtures/data_uses.json
Original file line number Diff line number Diff line change
Expand Up @@ -320,5 +320,33 @@
"legitimate_interest": false,
"legitimate_interest_impact_assessment": null,
"is_default": true
},
{
"fides_key": "custom",
"organization_fides_key": "default_organization",
"tags": null,
"name": "Custom field",
"description": "Custom field for tests",
"parent_key": null,
"legal_basis": null,
"special_category": null,
"recipients": null,
"legitimate_interest": false,
"legitimate_interest_impact_assessment": null,
"is_default": false
},
{
"fides_key": "custom.foo",
"organization_fides_key": "default_organization",
"tags": null,
"name": "Custom foo",
"description": "Custom foo for tests",
"parent_key": "custom",
"legal_basis": null,
"special_category": null,
"recipients": null,
"legitimate_interest": false,
"legitimate_interest_impact_assessment": null,
"is_default": false
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface ActionButtonProps {
onDelete: (node: TaxonomyEntityNode) => void;
}
const ActionButtons = ({ node, onEdit, onDelete }: ActionButtonProps) => {
const showDelete = node.children.length === 0;
const showDelete = node.children.length === 0 && !node.is_default;
return (
<ButtonGroup
size="xs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import AccordionTree from "~/features/common/AccordionTree";
import ConfirmationModal from "~/features/common/ConfirmationModal";
import { getErrorMessage } from "~/features/common/helpers";
import { errorToastParams, successToastParams } from "~/features/common/toast";
import { TreeNode } from "~/features/common/types";
import { isErrorResult } from "~/types/errors";

import ActionButtons from "./ActionButtons";
Expand Down Expand Up @@ -89,15 +90,15 @@ const TaxonomyTabContent = ({ useTaxonomy }: Props) => {

const taxonomyType = labels.fides_key.toLocaleLowerCase();

const handleSetEditEntity = (node: TaxonomyEntityNode) => {
const handleSetEditEntity = (node: TreeNode) => {
if (isAdding) {
closeAddForm();
}
const entity = data?.find((d) => d.fides_key === node.value) ?? null;
setEditEntity(entity);
};

const handleSetDeleteKey = (node: TaxonomyEntityNode) => {
const handleSetDeleteKey = (node: TreeNode) => {
setDeleteKey(node.value);
onDeleteOpen();
};
Expand Down Expand Up @@ -125,7 +126,7 @@ const TaxonomyTabContent = ({ useTaxonomy }: Props) => {
<ActionButtons
onDelete={handleSetDeleteKey}
onEdit={handleSetEditEntity}
node={node}
node={node as TaxonomyEntityNode}
/>
)}
/>
Expand Down
1 change: 1 addition & 0 deletions clients/ctl/admin-ui/src/features/taxonomy/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const transformTaxonomyEntityToNodes = (
: thisLevelEntity.name,
description: thisLevelEntity.description,
children: transformTaxonomyEntityToNodes(entities, thisLevelKey),
is_default: thisLevelEntity.is_default ?? false,
};
});
return nodes;
Expand Down
7 changes: 4 additions & 3 deletions clients/ctl/admin-ui/src/features/taxonomy/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { RTKErrorResult } from "~/types/errors";

export interface TaxonomyEntityNode {
value: string;
label: string;
import { TreeNode } from "../common/types";

export interface TaxonomyEntityNode extends TreeNode {
description?: string;
children: TaxonomyEntityNode[];
is_default: boolean;
}

export interface TaxonomyEntity {
Expand Down
Loading

0 comments on commit 362fac9

Please sign in to comment.