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

Custom fields in data use declaration form #3197

Merged
merged 13 commits into from
May 2, 2023
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ The types of changes are:
- Access and erasure support for Unbounce [#2697](https://github.com/ethyca/fides/pull/2697)
- Support pseudonymous consent requests with `fides_user_device_id` [#3158](https://github.com/ethyca/fides/pull/3158)
- Update `fides_consent` cookie format [#3158](https://github.com/ethyca/fides/pull/3158)
- Add custom fields to the data use declaration form [#3197](https://github.com/ethyca/fides/pull/3197)


### Changed

Expand Down
25 changes: 15 additions & 10 deletions clients/admin-ui/cypress/e2e/systems.cy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { stubSystemCrud, stubTaxonomyEntities } from "cypress/support/stubs";
import {
stubPlus,
stubSystemCrud,
stubTaxonomyEntities,
} from "cypress/support/stubs";

import {
ADD_SYSTEMS_MANUAL_ROUTE,
Expand All @@ -12,6 +16,7 @@ describe("System management page", () => {
cy.intercept("GET", "/api/v1/system", {
fixture: "systems/systems.json",
}).as("getSystems");
stubPlus(false);
});

it("Can navigate to the system management page", () => {
Expand Down Expand Up @@ -171,9 +176,6 @@ describe("System management page", () => {
dataset_references: ["demo_users_dataset_2"],
});
});
cy.getByTestId("new-declaration-form").within(() => {
cy.getByTestId("header").contains("System");
});
});
});

Expand Down Expand Up @@ -332,16 +334,18 @@ describe("System management page", () => {
});

// edit the existing declaration
const newDataUse = "collect";
cy.getByTestId("accordion-header-improve.system").click();
cy.getByTestId("improve.system-form").within(() => {
cy.getByTestId("input-data_use").type(`${newDataUse}{enter}`);
cy.getByTestId("input-data_subjects").type(`anonymous{enter}`);
cy.getByTestId("save-btn").click();
});
cy.wait("@putSystem").then((interception) => {
const { body } = interception.request;
expect(body.privacy_declarations.length).to.eql(1);
expect(body.privacy_declarations[0].data_use).to.eql(newDataUse);
expect(body.privacy_declarations[0].data_subjects).to.eql([
"customer",
"anonymous_user",
]);
});
cy.getByTestId("saved-indicator");
});
Expand Down Expand Up @@ -470,7 +474,8 @@ describe("System management page", () => {
cy.getByTestId("toast-success-msg");
});

it("warns when a data use is being edited to one that is already used", () => {
// Cannot currently edit the data use or name fields—they have been disabled
it.skip("warns when a data use is being edited to one that is already used", () => {
cy.fixture("systems/systems_with_data_uses.json").then((systems) => {
cy.intercept("GET", "/api/v1/system/*", {
body: systems[0],
Expand Down Expand Up @@ -589,12 +594,12 @@ describe("System management page", () => {
});

it("Can open both accordion items", () => {
cy.getByTestId("data-flow-accordion").within(()=>{
cy.getByTestId("data-flow-accordion").within(() => {
cy.getByTestId("data-flow-button-Source").click();
cy.getByTestId("data-flow-panel-Source").should("exist");
cy.getByTestId("data-flow-button-Destination").click();
cy.getByTestId("data-flow-panel-Destination").should("exist");
})
});
});
});
});
6 changes: 5 additions & 1 deletion clients/admin-ui/src/features/common/custom-fields/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,11 @@ export const useCustomFields = ({

// When creating an resource, the fides key may have initially been blank. But by the time the
// form is submitted it must not be blank (not undefined, not an empty string).
const fidesKey = formValues.fides_key || resourceFidesKey;
const fidesKey =
"fides_key" in formValues && formValues.fides_key !== ""
? formValues.fides_key
: resourceFidesKey;

TheAndrewJackson marked this conversation as resolved.
Show resolved Hide resolved
if (!fidesKey) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Props = FormikProps<FormValues> & {
isLoading: boolean;
onClose: () => void;
handleDropdownChange: (value: FieldTypes) => void;
isEditing: boolean;
};

export const CustomFieldForm = ({
Expand All @@ -38,6 +39,7 @@ export const CustomFieldForm = ({
isLoading,
onClose,
handleDropdownChange,
isEditing,
}: Props) => {
const { validateForm } = useFormikContext<FormValues>();
useEffect(() => {
Expand Down Expand Up @@ -71,6 +73,7 @@ export const CustomFieldForm = ({
name="resource_type"
options={RESOURCE_TYPE_OPTIONS}
labelProps={CustomFieldLabelStyles}
isDisabled={isEditing}
/>
</FormSection>
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export const CustomFieldModal = ({
}

const transformedCustomField = transformCustomField(customField, allowList);
const isEditing = !!transformedCustomField;
const initialValues = transformedCustomField || initialValuesTemplate;

const handleDropdownChange = (value: FieldTypes) => {
Expand Down Expand Up @@ -276,6 +277,7 @@ export const CustomFieldModal = ({
>
{(props) => (
<CustomFieldForm
isEditing={isEditing}
validationSchema={validationSchema}
isLoading={isLoading}
onClose={onClose}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const PrivacyDeclarationAccordionItem = ({
<AccordionPanel backgroundColor="gray.50" pt={0}>
<Stack spacing={4}>
<PrivacyDeclarationFormComponents
isEditing
onDelete={onDelete}
{...dataProps}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,15 @@ export interface DataProps {
allDataCategories: DataCategory[];
allDataUses: DataUse[];
allDataSubjects: DataSubject[];
isEditing?: boolean;
}

export const PrivacyDeclarationFormComponents = ({
allDataUses,
allDataCategories,
allDataSubjects,
onDelete,
isEditing,
}: DataProps & Pick<Props, "onDelete">) => {
const { dirty, isSubmitting, isValid, initialValues } =
useFormikContext<PrivacyDeclarationFormValues>();
Expand All @@ -110,12 +112,14 @@ export const PrivacyDeclarationFormComponents = ({
tooltip="What is the system using the data for. For example, is it for third party advertising or perhaps simply providing system operations."
variant="stacked"
singleValueBlock
isDisabled={isEditing}
/>
<CustomTextInput
id="name"
label="Processing Activity"
name="name"
variant="stacked"
disabled={isEditing}
tooltip="The personal data processing activity or activities associated with this data use."
/>
<CustomSelect
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ interface AccordionProps extends DataProps {
onEdit: (
oldDeclaration: PrivacyDeclarationWithId,
newDeclaration: PrivacyDeclarationWithId
) => Promise<boolean>;
onDelete: (declaration: PrivacyDeclarationWithId) => Promise<boolean>;
) => Promise<PrivacyDeclarationWithId[] | undefined>;
onDelete: (
declaration: PrivacyDeclarationWithId
) => Promise<PrivacyDeclarationWithId[] | undefined>;
}

const PrivacyDeclarationAccordionItem = ({
Expand All @@ -34,13 +36,14 @@ const PrivacyDeclarationAccordionItem = ({
AccordionProps,
"privacyDeclarations"
>) => {
const handleEdit = (newValues: PrivacyDeclarationWithId) =>
onEdit(privacyDeclaration, newValues);
const handleEdit = (values: PrivacyDeclarationWithId) =>
onEdit(privacyDeclaration, values);

const { initialValues, renderHeader, handleSubmit } =
usePrivacyDeclarationForm({
initialValues: privacyDeclaration,
onSubmit: handleEdit,
privacyDeclarationId: privacyDeclaration.id,
...dataProps,
});

Expand Down Expand Up @@ -71,6 +74,7 @@ const PrivacyDeclarationAccordionItem = ({
<AccordionPanel backgroundColor="gray.50" pt={0}>
<Stack spacing={4}>
<PrivacyDeclarationFormComponents
privacyDeclarationId={privacyDeclaration.id}
onDelete={onDelete}
{...dataProps}
/>
Expand Down
Loading