From fdfabf9e327da3db8c957f551d72c5670a2524cc Mon Sep 17 00:00:00 2001 From: RachelElysia <71795832+RachelElysia@users.noreply.github.com> Date: Mon, 25 Oct 2021 09:43:52 -0400 Subject: [PATCH] Packs UI: Create pack navigates to pack's edit page (#2581) --- changes/issue-2569-fix-create-pack-page-bug | 1 + .../forms/packs/EditPackForm/EditPackForm.tsx | 11 +- .../forms/packs/PackForm/PackForm.jsx | 84 ------------ .../forms/packs/PackForm/PackForm.tests.jsx | 59 --------- .../forms/packs/PackForm/PackForm.tsx | 123 ++++++++++++++++++ .../packs/PackForm/{index.js => index.ts} | 0 .../forms/packs/PackForm/validate.js | 15 --- .../pages/packs/EditPackPage/EditPackPage.tsx | 20 ++- .../PackComposerPage/PackComposerPage.jsx | 19 ++- .../PackComposerPage.tests.jsx | 8 -- 10 files changed, 163 insertions(+), 177 deletions(-) create mode 100644 changes/issue-2569-fix-create-pack-page-bug delete mode 100644 frontend/components/forms/packs/PackForm/PackForm.jsx delete mode 100644 frontend/components/forms/packs/PackForm/PackForm.tests.jsx create mode 100644 frontend/components/forms/packs/PackForm/PackForm.tsx rename frontend/components/forms/packs/PackForm/{index.js => index.ts} (100%) delete mode 100644 frontend/components/forms/packs/PackForm/validate.js diff --git a/changes/issue-2569-fix-create-pack-page-bug b/changes/issue-2569-fix-create-pack-page-bug new file mode 100644 index 0000000000..579fdee943 --- /dev/null +++ b/changes/issue-2569-fix-create-pack-page-bug @@ -0,0 +1 @@ +* Redirected to edit pack page after creating a pack \ No newline at end of file diff --git a/frontend/components/forms/packs/EditPackForm/EditPackForm.tsx b/frontend/components/forms/packs/EditPackForm/EditPackForm.tsx index 8d86469c5d..1789c65f7e 100644 --- a/frontend/components/forms/packs/EditPackForm/EditPackForm.tsx +++ b/frontend/components/forms/packs/EditPackForm/EditPackForm.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { useDeepEffect } from "utilities/hooks"; // @ts-ignore +import { useDeepEffect } from "utilities/hooks"; import Button from "components/buttons/Button"; @@ -74,6 +74,7 @@ const EditPackForm = ({ isPremiumTier, formData, }: IEditPackForm): JSX.Element => { + const [errors, setErrors] = useState<{ [key: string]: any }>({}); const [packName, setPackName] = useState(formData.name); const [packDescription, setPackDescription] = useState( formData.description @@ -101,6 +102,13 @@ const EditPackForm = ({ }; const onFormSubmit = () => { + if (packName === "") { + return setErrors({ + ...errors, + name: "Pack name must be present", + }); + } + handleSubmit({ name: packName, description: packDescription, @@ -117,6 +125,7 @@ const EditPackForm = ({ placeholder="Name" label="Name" name="name" + error={errors.name} inputWrapperClass={`${baseClass}__pack-title`} /> -

New pack

- {baseError &&
{baseError}
} - - -
- -
-
- -
- - ); - } -} - -export default Form(PackForm, { - fields: fieldNames, - validate, -}); diff --git a/frontend/components/forms/packs/PackForm/PackForm.tests.jsx b/frontend/components/forms/packs/PackForm/PackForm.tests.jsx deleted file mode 100644 index 3420aef6bb..0000000000 --- a/frontend/components/forms/packs/PackForm/PackForm.tests.jsx +++ /dev/null @@ -1,59 +0,0 @@ -import React from "react"; -import { mount } from "enzyme"; -import { noop } from "lodash"; - -import { fillInFormInput } from "test/helpers"; -import targetMock from "test/target_mock"; -import PackForm from "./index"; - -describe("PackForm - component", () => { - beforeEach(targetMock); - - it("renders the base error", () => { - const baseError = "Pack already exists"; - const formWithError = mount( - - ); - const formWithoutError = mount(); - - expect(formWithError.text()).toContain(baseError); - expect(formWithoutError.text()).not.toContain(baseError); - }); - - it("renders the correct components", () => { - const form = mount(); - - expect(form.find("InputField").length).toEqual(2); - expect(form.find("SelectTargetsDropdown").length).toEqual(1); - expect(form.find("Button").length).toEqual(1); - }); - - it("validates the query pack name field", () => { - const handleSubmitSpy = jest.fn(); - const form = mount(); - - form.find("form").simulate("submit"); - - expect(handleSubmitSpy).not.toHaveBeenCalled(); - - const formFieldProps = form.find("PackForm").prop("fields"); - - expect(formFieldProps.name).toMatchObject({ - error: "Title field must be completed", - }); - }); - - it("calls the handleSubmit prop when a valid form is submitted", () => { - const handleSubmitSpy = jest.fn(); - const form = mount().find( - "form" - ); - const nameField = form.find("InputField").find({ name: "name" }); - - fillInFormInput(nameField, "Mac OS Attacks"); - - form.simulate("submit"); - - expect(handleSubmitSpy).toHaveBeenCalled(); - }); -}); diff --git a/frontend/components/forms/packs/PackForm/PackForm.tsx b/frontend/components/forms/packs/PackForm/PackForm.tsx new file mode 100644 index 0000000000..ff9941b21f --- /dev/null +++ b/frontend/components/forms/packs/PackForm/PackForm.tsx @@ -0,0 +1,123 @@ +import React, { Component, useState } from "react"; +import PropTypes from "prop-types"; +import classnames from "classnames"; + +import Button from "components/buttons/Button"; +import { IQuery } from "interfaces/query"; +import { ITarget, ITargetsAPIResponse } from "interfaces/target"; +// @ts-ignore +import InputField from "components/forms/fields/InputField"; +// @ts-ignore +import SelectTargetsDropdown from "components/forms/fields/SelectTargetsDropdown"; + +const baseClass = "pack-form"; + +interface IPackForm { + className?: string; + handleSubmit: (formData: IEditPackFormData) => void; + onFetchTargets?: ( + query: IQuery, + targetsResponse: ITargetsAPIResponse + ) => boolean; + selectedTargetsCount?: number; + isPremiumTier?: boolean; + formData: IEditPackFormData; + baseError: any; +} + +interface IEditPackFormData { + name: string; + description: string; + targets: ITarget[]; +} + +interface IFormErrors { + name?: string; +} + +const EditPackForm = ({ + className, + handleSubmit, + onFetchTargets, + selectedTargetsCount, + isPremiumTier, + formData, + baseError, +}: IPackForm): JSX.Element => { + const [errors, setErrors] = useState<{ [key: string]: any }>({}); + const [packName, setPackName] = useState(""); + const [packDescription, setPackDescription] = useState(""); + const [packFormTargets, setPackFormTargets] = useState([]); + + const onChangePackName = (value: string) => { + setPackName(value); + }; + + const onChangePackDescription = (value: string) => { + setPackDescription(value); + }; + + const onChangePackTargets = (value: ITarget[]) => { + setPackFormTargets(value); + }; + + const onFormSubmit = () => { + if (packName === "") { + return setErrors({ + ...errors, + name: "Pack name must be present", + }); + } + + handleSubmit({ + name: packName, + description: packDescription, + targets: [...packFormTargets], + }); + }; + + const packFormClass = classnames(baseClass, className); + + return ( +
+

New pack

+ {baseError &&
{baseError}
} + + +
+ +
+
+ +
+ + ); +}; + +export default EditPackForm; diff --git a/frontend/components/forms/packs/PackForm/index.js b/frontend/components/forms/packs/PackForm/index.ts similarity index 100% rename from frontend/components/forms/packs/PackForm/index.js rename to frontend/components/forms/packs/PackForm/index.ts diff --git a/frontend/components/forms/packs/PackForm/validate.js b/frontend/components/forms/packs/PackForm/validate.js deleted file mode 100644 index c0031f0848..0000000000 --- a/frontend/components/forms/packs/PackForm/validate.js +++ /dev/null @@ -1,15 +0,0 @@ -import { size } from "lodash"; - -const validate = (formData) => { - const errors = {}; - - if (!formData.name) { - errors.name = "Title field must be completed"; - } - - const valid = !size(errors); - - return { valid, errors }; -}; - -export default validate; diff --git a/frontend/pages/packs/EditPackPage/EditPackPage.tsx b/frontend/pages/packs/EditPackPage/EditPackPage.tsx index 78b2518966..c2644199c1 100644 --- a/frontend/pages/packs/EditPackPage/EditPackPage.tsx +++ b/frontend/pages/packs/EditPackPage/EditPackPage.tsx @@ -229,10 +229,22 @@ const EditPacksPage = ({ window.scrollTo(0, 0); dispatch(renderFlash("success", `Successfully updated this pack.`)); }) - .catch(() => { - dispatch( - renderFlash("error", `Could not update pack. Please try again.`) - ); + .catch((response) => { + if ( + response.errors[0].reason.slice(0, 27) === + "Error 1062: Duplicate entry" + ) { + dispatch( + renderFlash( + "error", + "Unable to update pack. Pack names must be unique." + ) + ); + } else { + dispatch( + renderFlash("error", `Could not update pack. Please try again.`) + ); + } }); }; diff --git a/frontend/pages/packs/PackComposerPage/PackComposerPage.jsx b/frontend/pages/packs/PackComposerPage/PackComposerPage.jsx index 58c1cdcb82..e28036a77d 100644 --- a/frontend/pages/packs/PackComposerPage/PackComposerPage.jsx +++ b/frontend/pages/packs/PackComposerPage/PackComposerPage.jsx @@ -44,7 +44,7 @@ export class PackComposerPage extends Component { visitPackPage = (packID) => { const { dispatch } = this.props; - dispatch(push(PATHS.PACK({ id: packID }))); + dispatch(push(PATHS.PACK(packID))); return false; }; @@ -58,13 +58,20 @@ export class PackComposerPage extends Component { .then((pack) => { const { id: packID } = pack; - return visitPackPage(packID); - }) - .then(() => { dispatch(renderFlash("success", `Pack successfully created.`)); + visitPackPage(packID); }) - .catch(() => { - dispatch(renderFlash("error", "Unable to create pack.")); + .catch((response) => { + if (response.base.slice(0, 27) === "Error 1062: Duplicate entry") { + dispatch( + renderFlash( + "error", + "Unable to create pack. Pack names must be unique." + ) + ); + } else { + dispatch(renderFlash("error", "Unable to create pack.")); + } }); }; diff --git a/frontend/pages/packs/PackComposerPage/PackComposerPage.tests.jsx b/frontend/pages/packs/PackComposerPage/PackComposerPage.tests.jsx index e351538859..c7f5643ee1 100644 --- a/frontend/pages/packs/PackComposerPage/PackComposerPage.tests.jsx +++ b/frontend/pages/packs/PackComposerPage/PackComposerPage.tests.jsx @@ -19,14 +19,6 @@ describe("PackComposerPage - component", () => { expect(page.length).toEqual(1); }); - it("renders a PackForm component", () => { - const page = mount( - connectedComponent(ConnectedPacksComposerPage, { mockStore }) - ); - - expect(page.find("PackForm").length).toEqual(1); - }); - it("renders a PackInfoSidePanel component", () => { const page = mount( connectedComponent(ConnectedPacksComposerPage, { mockStore })