Skip to content

Commit

Permalink
Merge pull request #257 from danielo515/fix/handle-form-cancel
Browse files Browse the repository at this point in the history
fix(formEngine): gracefully handle the close of the form
  • Loading branch information
danielo515 authored May 13, 2024
2 parents 0900c01 + ea350bf commit b5ea042
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 94 deletions.
30 changes: 25 additions & 5 deletions src/FormModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,17 @@ export class FormModal extends Modal {
modalDefinition.fields,
options?.values ?? {},
);
this.formEngine = makeFormEngine((result) => {
this.onSubmit(FormResult.make(result, "ok"));
this.close();
}, this.initialFormValues);
this.formEngine = makeFormEngine({
onSubmit: (result) => {
this.onSubmit(FormResult.make(result, "ok"));
this.close();
},
onCancel: () => {
this.onSubmit(FormResult.make({}, "cancelled"));
this.close();
},
defaultValues: this.initialFormValues,
});
// this.formEngine.subscribe(console.log);
}

Expand Down Expand Up @@ -285,7 +292,11 @@ export class FormModal extends Modal {
}
});

new Setting(contentEl).addButton((btn) =>
const buttons = new Setting(contentEl).addButton((btn) =>
btn.setButtonText("Cancel").onClick(this.formEngine.triggerCancel),
);

buttons.addButton((btn) =>
btn.setButtonText("Submit").setCta().onClick(this.formEngine.triggerSubmit),
);

Expand All @@ -296,7 +307,16 @@ export class FormModal extends Modal {
}
};

const cancelEscapeCallback = (evt: KeyboardEvent) => {
// We don't want to hande it if any modfier is pressed
if (!(evt.ctrlKey || evt.metaKey) && evt.key === "Escape") {
evt.preventDefault();
this.formEngine.triggerCancel();
}
};

contentEl.addEventListener("keydown", submitEnterCallback);
contentEl.addEventListener("keydown", cancelEscapeCallback);
}

onClose() {
Expand Down
57 changes: 24 additions & 33 deletions src/core/FormResult.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ isEmployed:: true`;
it("should return the data formatted as a string matching the provided template", () => {
const result = FormResult.make(formData, "ok");
const template = "My name is {{name}}, and I am {{age}} years old.";
const expectedOutput =
"My name is John Doe, and I am 30 years old.";
const expectedOutput = "My name is John Doe, and I am 30 years old.";
expect(result.asString(template)).toEqual(expectedOutput);
});
});
Expand All @@ -66,9 +65,7 @@ isEmployed:: true`;
const result = FormResult.make(formData, "ok");
const expectedOutput = `name:: John Doe
age:: 30`;
expect(
result.asDataviewProperties({ pick: ["name", "age"] }),
).toEqual(expectedOutput);
expect(result.asDataviewProperties({ pick: ["name", "age"] })).toEqual(expectedOutput);
});

it("should return the data as a string of dataview properties with all keys except the specified ones using options.omit", () => {
Expand Down Expand Up @@ -111,20 +108,18 @@ age:: 30`;
const result = FormResult.make(formData, "ok");
const expectedOutput = `name: John Doe
age: 30`;
expect(
result.asFrontmatterString({ pick: ["name", "age"] }).trim(),
).toEqual(expectedOutput);
expect(result.asFrontmatterString({ pick: ["name", "age"] }).trim()).toEqual(
expectedOutput,
);
});

it("should return the data as a YAML frontmatter string with all keys except the specified ones using options.omit", () => {
const result = FormResult.make(formData, "ok");
const expectedOutput = `name: John Doe
age: 30`;
expect(
result
.asFrontmatterString({ omit: ["hobbies", "isEmployed"] })
.trim(),
).toEqual(expectedOutput);
expect(result.asFrontmatterString({ omit: ["hobbies", "isEmployed"] }).trim()).toEqual(
expectedOutput,
);
});

it("should return the data as a YAML frontmatter string with only the specified keys using options.pick and ignoring options.omit", () => {
Expand Down Expand Up @@ -178,30 +173,26 @@ age: 30`;
expect(result.get("foo")).toEqual("");
});
});
describe('Shorthand proxied accessors', () => {
it('Should allow access to a value in the data directly using dot notation',
() => {
const result = FormResult.make(formData, "ok");
// @ts-ignore
expect(result.name.toString()).toEqual("John Doe");
})
it('Should allow access to a value in the data directly and allow to use shorthand methods on the returned value',
() => {
const result = FormResult.make(formData, "ok");
// @ts-ignore
expect(result.name.upper.toString()).toEqual("JOHN DOE");
}
)
it('proxied access to bullet list should return a bullet list', () => {
describe("Shorthand proxied accessors", () => {
it("Should allow access to a value in the data directly using dot notation", () => {
const result = FormResult.make(formData, "ok");
// @ts-ignore
expect(result.name.toString()).toEqual("John Doe");
});
it("Should allow access to a value in the data directly and allow to use shorthand methods on the returned value", () => {
const result = FormResult.make(formData, "ok");
// @ts-ignore
expect(result.name.upper.toString()).toEqual("JOHN DOE");
});
it("proxied access to bullet list should return a bullet list", () => {
const result = FormResult.make(formData, "ok");
// @ts-ignore
expect(result.hobbies.bullets).toEqual("- reading\n- swimming");
})
it('accessing a non existing key should return a safe ResultValue, letting chain without issues', () => {
});
it("accessing a non existing key should return a safe ResultValue, letting chain without issues", () => {
const result = FormResult.make(formData, "ok");
// @ts-ignore
expect(result.foo.upper.lower.toString()).toEqual("");
})
})

});
});
});
34 changes: 28 additions & 6 deletions src/store/formStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { makeFormEngine } from "./formStore";
describe("Form Engine", () => {
it("should update form fields correctly", () => {
const onSubmitMock = jest.fn();
const formEngine = makeFormEngine(onSubmitMock);
const formEngine = makeFormEngine({ onSubmit: onSubmitMock, onCancel: console.log });

// Add fields to the form
const field1 = formEngine.addField({ name: "fieldName1" });
Expand All @@ -24,7 +24,7 @@ describe("Form Engine", () => {

it("should handle field errors correctly", () => {
const onSubmitMock = jest.fn();
const formEngine = makeFormEngine(onSubmitMock);
const formEngine = makeFormEngine({ onSubmit: onSubmitMock, onCancel: console.log });
// Add a field to the form
const field1 = formEngine.addField({
name: "fieldName1",
Expand All @@ -43,7 +43,7 @@ describe("Form Engine", () => {
});
it("field errors should prefer field label over field name", () => {
const onSubmitMock = jest.fn();
const formEngine = makeFormEngine(onSubmitMock);
const formEngine = makeFormEngine({ onSubmit: onSubmitMock, onCancel: console.log });
// Add a field to the form
const field1 = formEngine.addField({
name: "fieldName1",
Expand All @@ -63,7 +63,7 @@ describe("Form Engine", () => {
});
it("Clears the errors when a value is set", () => {
const onSubmitMock = jest.fn();
const formEngine = makeFormEngine(onSubmitMock);
const formEngine = makeFormEngine({ onSubmit: onSubmitMock, onCancel: console.log });
// Add a field to the form
const field1 = formEngine.addField({
name: "fieldName1",
Expand Down Expand Up @@ -92,7 +92,11 @@ describe("Form Engine", () => {
fieldName1: "default1",
fieldName2: "default2",
};
const formEngine = makeFormEngine(onSubmitMock, defaultValues);
const formEngine = makeFormEngine({
onSubmit: onSubmitMock,
defaultValues,
onCancel: console.log,
});

// Add fields to the form
const field1 = formEngine.addField({ name: "fieldName1" });
Expand All @@ -114,7 +118,11 @@ describe("Form Engine", () => {
const defaultValues = {
fieldName1: "default1",
};
const formEngine = makeFormEngine(onSubmitMock, defaultValues);
const formEngine = makeFormEngine({
onSubmit: onSubmitMock,
defaultValues,
onCancel: console.log,
});

// Add fields to the form
const field1 = formEngine.addField({ name: "fieldName1" });
Expand All @@ -128,4 +136,18 @@ describe("Form Engine", () => {
fieldName1: "default1",
});
});
it("should flag the form as cancelled and call the onCancel callback when the cancel button is clicked", () => {
const onCancelMock = jest.fn();
const formEngine = makeFormEngine({ onSubmit: console.log, onCancel: onCancelMock });
// Add a field to the form
const field1 = formEngine.addField({ name: "fieldName1" });
// Update field value with an empty string
field1.value.set("");
// Trigger form submission
formEngine.triggerCancel();
// Assert that the onCancel callback is called
expect(onCancelMock).toHaveBeenCalled();
// Assert that the form is not valid
// expect(get(formEngine.isValid)).toBe(false); // is it worth checking this?
});
});
Loading

0 comments on commit b5ea042

Please sign in to comment.