From 082682e6d32097b7b24032ff30bdace20ecad51a Mon Sep 17 00:00:00 2001 From: Erik Jan de Wit Date: Tue, 8 Sep 2020 19:16:08 +0200 Subject: [PATCH] initial version of json file upload component (#75) --- jest.config.js | 1 + src/components/alert/Alerts.test.tsx | 9 +- .../json-file-upload/JsonFileUpload.test.tsx | 35 ++ .../json-file-upload/JsonFileUpload.tsx | 118 ++++ .../JsonFileUpload.test.tsx.snap | 504 ++++++++++++++++++ src/forms/client/ImportForm.tsx | 89 +--- src/stories/JsonFileUpload.stories.tsx | 22 + 7 files changed, 690 insertions(+), 88 deletions(-) create mode 100644 src/components/json-file-upload/JsonFileUpload.test.tsx create mode 100644 src/components/json-file-upload/JsonFileUpload.tsx create mode 100644 src/components/json-file-upload/__snapshots__/JsonFileUpload.test.tsx.snap create mode 100644 src/stories/JsonFileUpload.stories.tsx diff --git a/jest.config.js b/jest.config.js index b71d007106..35e8578fbc 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,6 @@ module.exports = { ...require("@snowpack/app-scripts-react/jest.config.js")(), + "snapshotSerializers": ["enzyme-to-json/serializer"], "moduleNameMapper": { "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/src/__mocks__/fileMock.js", "\\.(css|less)$": "/src/__mocks__/styleMock.js" diff --git a/src/components/alert/Alerts.test.tsx b/src/components/alert/Alerts.test.tsx index 25ec565a55..8d33be21c2 100644 --- a/src/components/alert/Alerts.test.tsx +++ b/src/components/alert/Alerts.test.tsx @@ -1,7 +1,6 @@ import React from "react"; import { Button, AlertVariant } from "@patternfly/react-core"; import { mount } from "enzyme"; -import EnzymeToJson from "enzyme-to-json"; import { act } from "react-dom/test-utils"; import { AlertPanel } from "./AlertPanel"; @@ -20,9 +19,7 @@ const WithButton = () => { }; it("renders global alerts", () => { - const empty = EnzymeToJson( - mount( {}} />) - ); + const empty = mount( {}} />); expect(empty).toMatchSnapshot(); const tree = mount(); @@ -32,10 +29,10 @@ it("renders global alerts", () => { act(() => { button!.simulate("click"); }); - expect(EnzymeToJson(tree)).toMatchSnapshot(); + expect(tree).toMatchSnapshot(); act(() => { jest.runAllTimers(); }); - expect(EnzymeToJson(tree)).toMatchSnapshot(); + expect(tree).toMatchSnapshot(); }); diff --git a/src/components/json-file-upload/JsonFileUpload.test.tsx b/src/components/json-file-upload/JsonFileUpload.test.tsx new file mode 100644 index 0000000000..f087ad52d5 --- /dev/null +++ b/src/components/json-file-upload/JsonFileUpload.test.tsx @@ -0,0 +1,35 @@ +import React from "react"; +import { mount } from "enzyme"; + +import { JsonFileUpload } from "./JsonFileUpload"; + +describe("", () => { + it("render", () => { + const comp = mount(); + expect(comp).toMatchSnapshot(); + }); + + it("upload file", async () => { + const onChange = jest.fn((value) => value); + const comp = mount(); + + const fileInput = comp.find('[type="file"]'); + expect(fileInput.length).toBe(1); + + const json = '{"bla": "test"}'; + const file = new File([json], "test.json"); + + const dummyFileReader = { + onload: jest.fn(), + readAsText: () => Promise.resolve(json), + }; + (window as any).FileReader = jest.fn(() => dummyFileReader); + + fileInput.simulate("change", { + target: { + files: [file], + }, + }); + expect(comp).toMatchSnapshot(); + }); +}); diff --git a/src/components/json-file-upload/JsonFileUpload.tsx b/src/components/json-file-upload/JsonFileUpload.tsx new file mode 100644 index 0000000000..dbb9a4faf2 --- /dev/null +++ b/src/components/json-file-upload/JsonFileUpload.tsx @@ -0,0 +1,118 @@ +import React, { useState } from "react"; +import { + FormGroup, + FileUpload, + Modal, + ModalVariant, + Button, +} from "@patternfly/react-core"; +import { useTranslation } from "react-i18next"; + +type FileUpload = { + value: string | File; + filename: string; + isLoading: boolean; + modal: boolean; +}; + +export type JsonFileUploadProps = { + id: string; + onChange: ( + value: string | File, + filename: string, + event: + | React.DragEvent // User dragged/dropped a file + | React.ChangeEvent // User typed in the TextArea + | React.MouseEvent // User clicked Clear button + ) => void; +}; + +export const JsonFileUpload = ({ + id, + onChange, + ...rest +}: JsonFileUploadProps) => { + const { t } = useTranslation(); + const defaultUpload = { + value: "", + filename: "", + isLoading: false, + modal: false, + }; + const [fileUpload, setFileUpload] = useState(defaultUpload); + const removeDialog = () => setFileUpload({ ...fileUpload, modal: false }); + const handleChange = ( + value: string | File, + filename: string, + event: + | React.DragEvent + | React.ChangeEvent + | React.MouseEvent + ): void => { + if (event.nativeEvent instanceof MouseEvent) { + setFileUpload({ ...fileUpload, modal: true }); + } else { + setFileUpload({ + ...fileUpload, + value, + filename, + }); + onChange(value, filename, event); + } + }; + + return ( + <> + {fileUpload.modal && ( + { + setFileUpload(defaultUpload); + onChange("", "", event); + }} + > + {t("Clear")} + , + , + ]} + > + {t("confirmImportClear")} + + )} + + + setFileUpload({ ...fileUpload, isLoading: true }) + } + onReadFinished={() => + setFileUpload({ ...fileUpload, isLoading: false }) + } + isLoading={fileUpload.isLoading} + dropzoneProps={{ + accept: ".json", + }} + /> + + + ); +}; diff --git a/src/components/json-file-upload/__snapshots__/JsonFileUpload.test.tsx.snap b/src/components/json-file-upload/__snapshots__/JsonFileUpload.test.tsx.snap new file mode 100644 index 0000000000..ba35026dd7 --- /dev/null +++ b/src/components/json-file-upload/__snapshots__/JsonFileUpload.test.tsx.snap @@ -0,0 +1,504 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` render 1`] = ` + + +
+
+ + +
+
+ + + +
+
+ +
+ + + + + + + + + +
+
+
+
+ +
+ +
+
+
+
+
+ Upload a JSON file +
+
+
+
+
+`; + +exports[` upload file 1`] = ` + + +
+
+ + +
+
+ + + +
+
+ +
+ + + + + + + + + +
+
+
+
+ +
+ +
+
+
+
+
+ Upload a JSON file +
+
+
+
+
+`; diff --git a/src/forms/client/ImportForm.tsx b/src/forms/client/ImportForm.tsx index 20ea58e832..c312e0a4c5 100644 --- a/src/forms/client/ImportForm.tsx +++ b/src/forms/client/ImportForm.tsx @@ -6,41 +6,25 @@ import { Divider, Form, FormGroup, - FileUpload, TextInput, ActionGroup, Button, AlertVariant, - Modal, - ModalVariant, } from "@patternfly/react-core"; import { useTranslation } from "react-i18next"; import { ClientRepresentation } from "../../model/client-model"; import { ClientDescription } from "./ClientDescription"; import { HttpClientContext } from "../../http-service/HttpClientContext"; +import { JsonFileUpload } from "../../components/json-file-upload/JsonFileUpload"; import { useAlerts } from "../../components/alert/Alerts"; import { AlertPanel } from "../../components/alert/AlertPanel"; -type FileUpload = { - value: string | File; - filename: string; - isLoading: boolean; - modal: boolean; -}; - export const ImportForm = () => { const { t } = useTranslation(); const httpClient = useContext(HttpClientContext)!; const [add, alerts, hide] = useAlerts(); - const defaultUpload = { - value: "", - filename: "", - isLoading: false, - modal: false, - }; - const [fileUpload, setFileUpload] = useState(defaultUpload); const defaultClient = { protocol: "", clientId: "", @@ -49,21 +33,11 @@ export const ImportForm = () => { }; const [client, setClient] = useState(defaultClient); - const handleFileChange = (value: string | File, filename: string) => { - if (value === "" && client.protocol !== "") { - // clear clicked - setFileUpload({ ...fileUpload, modal: true }); - } else { - setFileUpload({ - ...fileUpload, - value, - filename, - }); - setClient({ - ...client, - ...(value ? JSON.parse(value as string) : defaultClient), - }); - } + const handleFileChange = (value: string | File) => { + setClient({ + ...client, + ...(value ? JSON.parse(value as string) : defaultClient), + }); }; const handleDescriptionChange = ( value: string, @@ -72,7 +46,6 @@ export const ImportForm = () => { const name = (event.target as HTMLInputElement).name; setClient({ ...client, [name]: value }); }; - const removeDialog = () => setFileUpload({ ...fileUpload, modal: false }); const save = async () => { try { @@ -95,56 +68,8 @@ export const ImportForm = () => { - {fileUpload.modal && ( - { - setClient(defaultClient); - setFileUpload(defaultUpload); - }} - > - {t("Clear")} - , - , - ]} - > - {t("confirmImportClear")} - - )}
- - - setFileUpload({ ...fileUpload, isLoading: true }) - } - onReadFinished={() => - setFileUpload({ ...fileUpload, isLoading: false }) - } - isLoading={fileUpload.isLoading} - dropzoneProps={{ - accept: ".json", - }} - /> - + = (args) => ( + +); + +export const Dialog = Template.bind({}); +Dialog.args = { + id: "jsonFile", +};