Skip to content

Commit

Permalink
Fixes 616 - Adds file attachment logic to JSONRecordForm and some uni…
Browse files Browse the repository at this point in the history
…t tests.
  • Loading branch information
alexcottner committed Nov 13, 2023
1 parent 39e807d commit 6c145af
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 4 deletions.
66 changes: 62 additions & 4 deletions src/components/record/JSONRecordForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,95 @@ const schema: RJSFSchema = {
default: "{}",
};

const schemaWithUpload: RJSFSchema = {
type: "object",
properties: {
jsonContent: {
type: "string",
title: "JSON record",
default: "{}",
},
__attachment__: {
type: "string",
format: "data-url",
title: "File attachment",
},
},
required: ["jsonContent"],
};

const uiSchemaWithUpload: UiSchema = {
jsonContent: {
"ui:help": "This must be valid JSON.",
},
"ui:order": ["jsonContent", "__attachment__"],
};

const uiSchema: UiSchema = {
data: {
"ui:widget": JSONEditor,
"ui:help": "This must be valid JSON.",
},
"ui:order": [],
};

type Props = {
disabled: boolean;
record: string; // JSON string representation of a record data
attachmentEnabled?: boolean;
attachmentRequired?: boolean;
onSubmit: (data: Object) => void;
children?: React.ReactNode;
};

function splitAttachment(record: string) {
const jsRecord = JSON.parse(record);
const attachment = jsRecord.attachment || {};
if (jsRecord.attachment) {
delete jsRecord.attachment;
}
return {
attachment: attachment,
jsonContent: JSON.stringify(jsRecord),
};
}

export default function JSONRecordForm({
disabled,
record,
onSubmit,
children,
attachmentEnabled,
attachmentRequired,
}: Props) {
const handleOnSubmit = data => {
onSubmit({ ...data, formData: JSON.parse(data.formData) });
const formData = attachmentEnabled
? {
...JSON.parse(data.formData.jsonContent),
__attachment__: data.formData.__attachment__,
}
: JSON.parse(data.formData);
onSubmit({ ...data, formData });
};

const _uiSchema = attachmentEnabled ? uiSchemaWithUpload : uiSchema;
const _record: any | string = attachmentEnabled
? splitAttachment(record)
: record;
const _schema = attachmentEnabled ? schemaWithUpload : schema;
if (attachmentEnabled && attachmentRequired) {
_schema.required.push("__attachment__");
}

return (
<div>
<BaseForm
schema={schema}
formData={record}
uiSchema={disabled ? { ...uiSchema, "ui:readonly": true } : uiSchema}
schema={_schema}
formData={_record}
uiSchema={disabled ? { ..._uiSchema, "ui:readonly": true } : _uiSchema}
onSubmit={handleOnSubmit}
data-testid="JSONRecordForm"
disabled={disabled}
>
{children}
</BaseForm>
Expand Down
3 changes: 3 additions & 0 deletions src/components/record/RecordForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ export default function RecordForm(props: Props) {
disabled={!allowEditing}
record={JSON.stringify(recordData, null, 2)}
onSubmit={handleOnSubmit}
attachmentEnabled={attachment?.enabled}
// require an attachment on initial insert if attachments are required
attachmentRequired={attachment?.required && !record}
>
{buttons}
</JSONRecordForm>
Expand Down
100 changes: 100 additions & 0 deletions test/components/record/JSONRecordForm_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React from "react";
import { render, fireEvent } from "@testing-library/react";
import JSONRecordForm from "../../../src/components/record/JSONRecordForm";

describe("JSONRecordForm", () => {
let lastSubmittedData = null;
const submitMock = data => {
lastSubmittedData = data;
};

it("Renders an empty form for a new record (attachments disabled)", async () => {
const result = render(
<JSONRecordForm disabled={false} record="{}" onSubmit={submitMock} />
);
expect(result.queryByLabelText("JSON record").value).toBe("{}");
fireEvent.click(result.queryByText("Submit"));
expect(lastSubmittedData.formData).toStrictEqual({});
});

it("Renders the expected form for an existing record (attachments disabled)", async () => {
const result = render(
<JSONRecordForm
disabled={false}
record='{ "foo": "bar" }'
onSubmit={submitMock}
/>
);
expect(result.queryByLabelText("JSON record").value).toBe(
'{ "foo": "bar" }'
);
fireEvent.click(result.queryByText("Submit"));
expect(lastSubmittedData.formData).toStrictEqual({ foo: "bar" });
});

it("Renders an empty form for a new record (attachments enabled)", async () => {
const result = render(
<JSONRecordForm
disabled={false}
record="{}"
onSubmit={submitMock}
attachmentEnabled={true}
/>
);
expect(result.queryByLabelText("JSON record*").value).toBe("{}");
expect(result.queryByLabelText("File attachment")).toBeDefined();
fireEvent.click(result.queryByText("Submit"));
expect(lastSubmittedData.formData).toStrictEqual({
__attachment__: undefined,
});
});

it("Renders the expected form for an existing record (attachments enabled)", async () => {
const result = render(
<JSONRecordForm
disabled={false}
record='{ "foo": "bar" }'
onSubmit={submitMock}
attachmentEnabled={true}
/>
);
expect(result.queryByLabelText("JSON record*").value).toBe('{"foo":"bar"}');
expect(result.queryByLabelText("File attachment")).toBeDefined();
fireEvent.click(result.queryByText("Submit"));
expect(lastSubmittedData.formData).toStrictEqual({
foo: "bar",
__attachment__: undefined,
});
});

it("Requires an attachment to submit when told attachmentRequired and attachmentEnabled are true", async () => {
lastSubmittedData = null;
const result = render(
<JSONRecordForm
disabled={false}
record='{ "foo": "bar" }'
onSubmit={submitMock}
attachmentEnabled={true}
attachmentRequired={true}
/>
);
expect(result.queryByLabelText("JSON record*").value).toBe('{"foo":"bar"}');
expect(result.queryByLabelText("File attachment")).toBeDefined();
fireEvent.click(result.queryByText("Submit"));
expect(lastSubmittedData).toBeNull();
});

it("Disables the form when disabled is true", async () => {
const result = render(
<JSONRecordForm
disabled={true}
record='{ "foo": "bar" }'
onSubmit={submitMock}
/>
);
const input = result.queryByLabelText("JSON record");
expect(input.value).toBe('{ "foo": "bar" }');
expect(input.disabled).toBe(true);
expect(result.queryByText("Submit").disabled).toBe(true);
});
});

0 comments on commit 6c145af

Please sign in to comment.