From 31e4a992a46ad13d3186bef22c8c33868e6a521f Mon Sep 17 00:00:00 2001 From: Jonas Cosandey Date: Mon, 29 Jun 2020 10:10:52 +0200 Subject: [PATCH] feat(edit-form): add a minimalistic form for editing model fields --- addon/components/edit-form.hbs | 40 +++++++ addon/components/edit-form.js | 51 +++++++++ addon/components/edit-form/element.hbs | 9 ++ app/components/edit-form.js | 1 + app/components/edit-form/element.js | 1 + .../integration/components/edit-form-test.js | 103 ++++++++++++++++++ .../components/edit-form/element-test.js | 21 ++++ 7 files changed, 226 insertions(+) create mode 100644 addon/components/edit-form.hbs create mode 100644 addon/components/edit-form.js create mode 100644 addon/components/edit-form/element.hbs create mode 100644 app/components/edit-form.js create mode 100644 app/components/edit-form/element.js create mode 100644 tests/integration/components/edit-form-test.js create mode 100644 tests/integration/components/edit-form/element-test.js diff --git a/addon/components/edit-form.hbs b/addon/components/edit-form.hbs new file mode 100644 index 00000000..37585193 --- /dev/null +++ b/addon/components/edit-form.hbs @@ -0,0 +1,40 @@ +
+ {{yield}} + +
+ {{! without quotes on the @route the LinkTo component tries to set the property listViewRouteName which has no setter}} + + {{t "emeis.form.back"}} + + + {{#unless @noDelete}} + + {{t "emeis.form.delete"}} + + {{/unless}} + + + {{t "emeis.form.save"}} + +
+
diff --git a/addon/components/edit-form.js b/addon/components/edit-form.js new file mode 100644 index 00000000..fc2740cf --- /dev/null +++ b/addon/components/edit-form.js @@ -0,0 +1,51 @@ +import { inject as service } from "@ember/service"; +import Component from "@glimmer/component"; +import { task } from "ember-concurrency-decorators"; + +import handleModelErrors from "ember-emeis/decorators/handle-model-errors"; + +export default class EditFormComponent extends Component { + @service intl; + @service notification; + @service router; + + get parentRouteName() { + return this.router.currentRoute.parent.name; + } + + get listViewRouteName() { + return ( + this.args.listViewRouteName || + `${this.parentRouteName}.index`.replace("ember-emeis.", "") + ); + } + + @task + *save(event) { + try { + event.preventDefault(); + + const model = this.args.updateModel(this.args.model, this.form.elements); + const isNew = model.isNew; + + yield model.save(); + + this.notification.success(this.intl.t("emeis.form.save-success")); + + if (isNew) { + this.router.replaceWith(`${this.parentRouteName}.edit`, model); + } + } catch (exception) { + this.notification.danger(this.intl.t("emeis.form.save-error")); + } + } + + @task + @handleModelErrors({ errorMessage: "emeis.form.delete-error" }) + *delete() { + yield this.args.model.destroyRecord(); + this.notification.success(this.intl.t("emeis.form.delete-success")); + // I dont really understand why this replaceWith needs the "ember-emeis." prefix and the onw in save does not :/. + this.router.replaceWith(`ember-emeis.${this.listViewRouteName}`); + } +} diff --git a/addon/components/edit-form/element.hbs b/addon/components/edit-form/element.hbs new file mode 100644 index 00000000..86fe76e9 --- /dev/null +++ b/addon/components/edit-form/element.hbs @@ -0,0 +1,9 @@ +
+ +
+ {{yield}} + +
+
diff --git a/app/components/edit-form.js b/app/components/edit-form.js new file mode 100644 index 00000000..a929bf28 --- /dev/null +++ b/app/components/edit-form.js @@ -0,0 +1 @@ +export { default } from "ember-emeis/components/edit-form"; diff --git a/app/components/edit-form/element.js b/app/components/edit-form/element.js new file mode 100644 index 00000000..93d6b92f --- /dev/null +++ b/app/components/edit-form/element.js @@ -0,0 +1 @@ +export { default } from "ember-emeis/components/edit-form/element"; diff --git a/tests/integration/components/edit-form-test.js b/tests/integration/components/edit-form-test.js new file mode 100644 index 00000000..ee102b69 --- /dev/null +++ b/tests/integration/components/edit-form-test.js @@ -0,0 +1,103 @@ +import { render, click } from "@ember/test-helpers"; +import { hbs } from "ember-cli-htmlbars"; +import { setupRenderingTest } from "ember-qunit"; +import { module, test } from "qunit"; + +module("Integration | Component | edit-form", function (hooks) { + setupRenderingTest(hooks); + hooks.beforeEach(function () { + const router = class { + replaceWith() {} + hasRoute() {} + transitionTo() {} + _doTransition() {} + generateURL() {} + currentRoute = { + parent: { + name: "ember-emeis.parent-route", + }, + }; + }; + this.router = new router(); + this.owner.register("service:router", this.router, { instantiate: false }); + this.owner.register("service:-routing", this.router, { + instantiate: false, + }); + this.owner.register("router:main", this.router, { instantiate: false }); + }); + + hooks.afterEach(function () { + delete this.router; + }); + + test("noDelete", async function (assert) { + assert.expect(3); + + await render(hbs``); + + assert.dom("[data-test-back]").exists(); + assert.dom("[data-test-delete]").doesNotExist(); + assert.dom("[data-test-save]").exists(); + }); + + test("back", async function (assert) { + assert.expect(1); + this.router.transitionTo = (route) => { + assert.equal(route, "parent-route.index"); + }; + + await render(hbs``); + + await click("[data-test-back]"); + }); + + test("delete", async function (assert) { + assert.expect(3); + this.router.replaceWith = (route) => { + assert.equal(route, "ember-emeis.parent-route.index"); + }; + + this.set("model", { + destroyRecord() { + assert.step("destroyRecord"); + }, + }); + + await render(hbs``); + + await click("[data-test-delete]"); + assert.verifySteps(["destroyRecord"]); + }); + + test("save", async function (assert) { + assert.expect(7); + this.router.replaceWith = (route) => { + assert.equal(route, "ember-emeis.parent-route.edit"); + assert.step("replaceWith"); + }; + + this.setProperties({ + model: { + save() { + assert.step("save"); + }, + isNew: true, + }, + updateModel(model, elements) { + assert.ok(elements.test, "Test that test input is passed"); + assert.ok(model, "Test if model is truthy"); + assert.step("updateModel"); + return model; + }, + }); + + await render(hbs` + + + + `); + + await click("[data-test-save]"); + assert.verifySteps(["updateModel", "save", "replaceWith"]); + }); +}); diff --git a/tests/integration/components/edit-form/element-test.js b/tests/integration/components/edit-form/element-test.js new file mode 100644 index 00000000..760aa100 --- /dev/null +++ b/tests/integration/components/edit-form/element-test.js @@ -0,0 +1,21 @@ +import { render } from "@ember/test-helpers"; +import { hbs } from "ember-cli-htmlbars"; +import { setupRenderingTest } from "ember-qunit"; +import { module, test } from "qunit"; + +module("Integration | Component | edit-form/element", function (hooks) { + setupRenderingTest(hooks); + + test("it renders", async function (assert) { + this.set("label", "Hey"); + + await render(hbs` + + Text + + `); + + assert.dom("label").hasText(this.label); + assert.dom(".uk-form-controls").hasText("Text"); + }); +});