Skip to content

Commit

Permalink
feat(emeisOptions): make "delete" and "deactivate" buttons visibility…
Browse files Browse the repository at this point in the history
… configurable (#462)

* feat: insert re-/activate button for users and scopes

This replaces the obsolete back-button in the edit form
 of scopes and users with a de-/activate button.
The "isActive" checkbox on the user edit form got deleted as well.

* feat(emeisOptions): config edit form buttons

Make buttons visibility configurable via actions block in the emeisOptions.

* fix: improve edit-form for toggling active state

- handle edge cases for emeisOptions
- fix tests after refactoring
- include back link for roles and permissions view
  • Loading branch information
derrabauke authored Apr 19, 2022
1 parent 9561fe8 commit afc7ca4
Show file tree
Hide file tree
Showing 20 changed files with 129 additions and 50 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,21 @@ export default class EmeisOptionsService extends Service {
customComponents = {
users: DummyButton,
},
/*
Within the actions block you can define functions which evaluate the visibility of the "deactivate" and "delete" buttons in the model edit form. The visibilty must be defined for each model separately.
The model must support the "isActive" property for deactivation capabilities, which are currently only supported by user and scope.
*/
actions = {
user: {
deactivate: (model) => myUser.canChange(model),
delete: (model) => myUser.canDelete(model),
},
scope: {
deactivate: () => false, // statically deactivate the deactivate-button
// leaving out the "delete" key here will always display the delete button
}
}
// define custom fields for a given context (user, scope, role or permission)
metaFields = {
user: [],
Expand Down
21 changes: 12 additions & 9 deletions addon/components/edit-form.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,19 @@
</div>

<div class="uk-flex uk-flex-right uk-margin">
{{! without quotes on the @route the LinkTo component tries to set the property listViewRouteName which has no setter}}
<LinkTo
@route="{{this.relativeListViewRouteName}}"
class="uk-button uk-button-default uk-margin-right"
data-test-back
>
{{t "emeis.form.back"}}
</LinkTo>
{{#if (and this.modelHasActiveState this.canChangeActiveState)}}
<UkButton
@loading={{this.toggleActiveState.isRunning}}
@disabled={{this.toggleActiveState.isRunning}}
class="uk-margin-right uk-button-default"
data-test-toggle-active
@onClick={{perform this.toggleActiveState}}
>
{{t (concat "emeis.form." (if @model.isActive "deactivate" "activate"))}}
</UkButton>
{{/if}}

{{#if (and (not @disableDelete) (not @model.isNew))}}
{{#if (and (not @disableDelete) (not @model.isNew) this.canDeleteModel)}}
<UkButton
@loading={{this.delete.isRunning}}
@disabled={{this.delete.isRunning}}
Expand Down
38 changes: 38 additions & 0 deletions addon/components/edit-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,44 @@ export default class EditFormComponent extends Component {
return this.emeisOptions.customComponents?.[this.modelName];
}

get modelHasActiveState() {
return this.args.model?.isActive !== undefined;
}

get canChangeActiveState() {
return this.emeisOptions.actions?.[this.args.model._internalModel.modelName]
?.deactivate
? this.emeisOptions.actions[
this.args.model._internalModel.modelName
].deactivate(this.args.model)
: true;
}

get canDeleteModel() {
return this.emeisOptions.actions?.[this.args.model._internalModel.modelName]
?.delete
? this.emeisOptions.actions[
this.args.model._internalModel.modelName
].delete(this.args.model)
: true;
}

@task
@handleTaskErrors({ errorMessage: "emeis.form.save-error" })
*toggleActiveState() {
const activeState = this.args.model.isActive;
this.args.model.isActive = !activeState;
yield this.args.model.save();

this.notification.success(
this.intl.t(
activeState
? "emeis.form.deactivate-success"
: "emeis.form.activate-success"
)
);
}

@task
@handleTaskErrors({ errorMessage: "emeis.form.save-error" })
*save(event) {
Expand Down
2 changes: 1 addition & 1 deletion addon/components/tree-node.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
{{/unless}}
</UkButton>
{{/if}}
<LinkTo @route={{@itemRoute}} @model={{@item}} class="uk-link-text" data-test-node-id={{@item.id}}>
<LinkTo @route={{@itemRoute}} @model={{@item}} class="uk-link-text {{unless @item.isActive "text-line-through"}}" data-test-node-id={{@item.id}}>
{{@item.name}}{{#if @item.children}} ({{@item.children.length}}){{/if}}
</LinkTo>
{{#if this.expanded}}
Expand Down
1 change: 0 additions & 1 deletion addon/controllers/users/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ export default class UsersEditController extends PaginationController {
model.firstName = formElements.firstName.value;
model.lastName = formElements.lastName.value;
model.email = formElements.email.value;
model.isActive = formElements.isActive.checked;

// additional fields might not be present
model.phone = formElements.phone?.value;
Expand Down
1 change: 1 addition & 0 deletions addon/models/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default class ScopeModel extends LocalizedModel {
@localizedAttr description;
@attr level;
@attr metainfo;
@attr isActive;

@belongsTo("scope", { inverse: "children", async: false }) parent;
@hasMany("scope", { inverse: "parent", async: false }) children;
Expand Down
4 changes: 4 additions & 0 deletions addon/templates/permissions/edit.hbs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
<LinkTo @route="permissions.index" class="uk-button uk-padding-remove uk-margin-small-bottom" data-test-back>
<UkIcon @icon="arrow-left" @ratio="1.5" />
{{t "emeis.form.back"}}
</LinkTo>
<EditForm @model={{@model}} @updateModel={{this.updateModel}}>
<EditForm::Element @label={{t "emeis.permissions.headings.slug"}}>
<input
Expand Down
4 changes: 4 additions & 0 deletions addon/templates/roles/edit.hbs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
<LinkTo @route="roles.index" class="uk-button uk-padding-remove uk-margin-small-bottom" data-test-back>
<UkIcon @icon="arrow-left" @ratio="1.5" />
{{t "emeis.form.back"}}
</LinkTo>
<EditForm @model={{@model}} @updateModel={{this.updateModel}} class="uk-margin">
<EditForm::Element @label={{t "emeis.roles.headings.slug"}}>
<input
Expand Down
14 changes: 1 addition & 13 deletions addon/templates/users/edit.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<LinkTo @route="users.index" class="uk-button uk-padding-remove uk-margin-small-bottom" data-test-user-back-link>
<LinkTo @route="users.index" class="uk-button uk-padding-remove uk-margin-small-bottom" data-test-back>
<UkIcon @icon="arrow-left" @ratio="1.5" />
{{t "emeis.form.back"}}
</LinkTo>
Expand Down Expand Up @@ -134,17 +134,6 @@
{{#each this.metaFields as |field|}}
<MetaField @field={{field}} @model={{@model}} />
{{/each}}

<EditForm::Element @label={{t "emeis.users.headings.isActive"}}>
<input
class="uk-checkbox"
type="checkbox"
name="isActive"
placeholder="{{t "emeis.users.headings.isActive"}}..."
checked={{@model.isActive}}
/>
</EditForm::Element>

</EditForm>

</div>
Expand Down Expand Up @@ -230,4 +219,3 @@
{{/if}}
</div>
</div>
{{!-- {{outlet}} --}}
4 changes: 2 additions & 2 deletions addon/templates/users/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@
{{#let body.model as |user|}}
{{#if this.emailAsUsername}}
<td>
<LinkTo @route="users.edit" @model={{user}} class="uk-link-text">
<LinkTo @route="users.edit" @model={{user}} class="uk-link-text {{unless user.isActive "text-line-through"}}">
{{user.lastName}}
</LinkTo>
</td>
<td>{{user.firstName}}</td>
{{else}}
<td data-test-user-username={{user.id}}>
<LinkTo @route="users.edit" @model={{user}} class="uk-link-text">
<LinkTo @route="users.edit" @model={{user}} class="uk-link-text {{unless user.isActive "text-line-through"}}">
{{user.username}}
</LinkTo>
</td>
Expand Down
8 changes: 8 additions & 0 deletions app/styles/ember-emeis.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ $ember-power-select-border-color: $global-border;
transition: width 0.3s ease-out;
}

.text-line-through {
text-decoration: line-through;

&:hover {
text-decoration: line-through;
}
}

// fixes the negative margin overlap of uk-grid
.uk-grid-divider-fix {
margin-left: 0;
Expand Down
5 changes: 1 addition & 4 deletions tests/acceptance/scopes-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ module("Acceptance | scopes", function (hooks) {
});

test("detail view /scopes/:id", async function (assert) {
assert.expect(7);
assert.expect(6);

const scope = this.server.create("scope");
const futureParent = this.server.create("scope");
Expand Down Expand Up @@ -82,9 +82,6 @@ module("Acceptance | scopes", function (hooks) {
assert.strictEqual(relationships.parent.data.id, futureParent.id);
});
await click("[data-test-save]");

await click("[data-test-back]");
assert.strictEqual(currentURL(), "/scopes");
});

test("create view /scopes/new", async function (assert) {
Expand Down
13 changes: 3 additions & 10 deletions tests/acceptance/users-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ module("Acceptance | users", function (hooks) {
});

test("detail view /users/:id", async function (assert) {
assert.expect(27);
assert.expect(25);

const user = this.server.create("user", {
isActive: true,
Expand Down Expand Up @@ -96,8 +96,6 @@ module("Acceptance | users", function (hooks) {
assert.dom('[name="city"]').isRequired();
assert.dom('[name="zip"]').isRequired();

assert.dom('[name="isActive"]').isChecked();

const username = "newusername",
firstName = "John",
lastName = "Doe",
Expand All @@ -118,8 +116,6 @@ module("Acceptance | users", function (hooks) {
await fillIn('[name="city"]', city);
await fillIn('[name="zip"]', zip);

await click('[name="isActive"]');

this.assertRequest("PATCH", `/api/v1/users/${user.id}`, (request) => {
const attributes = JSON.parse(request.requestBody).data.attributes;

Expand All @@ -132,7 +128,6 @@ module("Acceptance | users", function (hooks) {
assert.strictEqual(attributes.address, address);
assert.strictEqual(attributes.city.en, city);
assert.strictEqual(attributes.zip, zip);
assert.false(attributes["is-active"]);
});
await click("[data-test-save]");

Expand All @@ -142,7 +137,7 @@ module("Acceptance | users", function (hooks) {
});

test("create view /users/new", async function (assert) {
assert.expect(25);
assert.expect(24);

await visit("/users");
assert.strictEqual(currentURL(), "/users");
Expand Down Expand Up @@ -204,9 +199,7 @@ module("Acceptance | users", function (hooks) {
assert.dom('[name="city"]').hasValue(user.city.en);
assert.dom('[name="zip"]').hasValue(user.zip.toString());

assert.dom('[name="isActive"]').isChecked();

assert.dom("[data-test-user-back-link]").exists();
assert.dom("[data-test-back]").exists();
});

test("list view /users/:id/acl", async function (assert) {
Expand Down
9 changes: 9 additions & 0 deletions tests/dummy/app/services/emeis-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ export default class EmeisOptionsService extends Service {
customComponents = {
users: TestButtonComponent,
};
actions = {
user: {
delete: () => true,
},
scope: {
delete: (model) => model.id !== "special",
deactivate: (model) => model.id !== "special",
},
};
metaFields = {
user: [
{
Expand Down
1 change: 1 addition & 0 deletions tests/dummy/mirage/factories/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export default Factory.extend({
description: () => localize(faker.lorem.paragraph()),
level: () => 0,
metainfo: () => {},
isActive: () => faker.datatype.boolean(),
});
1 change: 1 addition & 0 deletions tests/dummy/mirage/scenarios/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default function (server) {
name: { en: "scope with static ID" },
level: 2,
parent: level1[0],
isActive: true,
});
server.createList("user", 50);
server.createList("permission", 50);
Expand Down
28 changes: 20 additions & 8 deletions tests/integration/components/edit-form-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,32 @@ module("Integration | Component | edit-form", function (hooks) {

await render(hbs`<EditForm @disableDelete="true"/>`);

assert.dom("[data-test-back]").exists();
assert.dom("[data-test-toggle-active]").doesNotExist();
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.strictEqual(route, "parent-route.index");
};
test("toggle active state", async function (assert) {
assert.expect(2);

this.setProperties({
model: {
save() {
assert.step("save");
},
isNew: false,
isActive: true,
},
});

await render(hbs`<EditForm />`);
await render(hbs`
<EditForm @model={{this.model}} @updateModel={{this.updateModel}}>
<input name="test">
</EditForm>
`);

await click("[data-test-back]");
await click("[data-test-toggle-active]");
assert.verifySteps(["save"]);
});

test("delete", async function (assert) {
Expand Down
2 changes: 0 additions & 2 deletions tests/unit/controllers/users/edit-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ module("Unit | Controller | users/edit", function (hooks) {
address: { value: "address" },
city: { value: "city" },
zip: { value: "zip" },
isActive: { checked: true },
});

assert.strictEqual(model.username, "username");
Expand All @@ -38,7 +37,6 @@ module("Unit | Controller | users/edit", function (hooks) {
assert.strictEqual(model.address, "address");
assert.strictEqual(model.city, "city");
assert.strictEqual(model.zip, "zip");
assert.true(model.isActive);
});

test("queryParamsfilter", function (assert) {
Expand Down
4 changes: 4 additions & 0 deletions translations/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,14 @@ emeis:
save: "Speichern"
back: "Zurück"
delete: "Löschen"
activate: "Aktivieren"
deactivate: "Deaktivieren"
ok: "OK"
cancel: "Abbrechen"
confirmText: "Sind Sie sich sicher, dass Sie diese Aktion fortfahren wollen?"
confirmEntryDelete: "Sind Sie sich sicher, dass Sie diesen Eintrag löschen wollen?"
activate-success: "Aktivierung erfolgreich."
deactivate-success: "Deaktivierung erfolgreich."
save-success: "Erfolgreich gespeichert."
delete-success: "Erfolgreich gelöscht."
save-error: "Während dem Speichern ist ein Fehler aufgetretten. Bitte versuchen Sie es erneut."
Expand Down
4 changes: 4 additions & 0 deletions translations/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,14 @@ emeis:
save: "Save"
back: "Back"
delete: "Delete"
activate: "Activate"
deactivate: "Deactivate"
ok: "OK"
cancel: "Cancel"
confirmText: "Are you sure you want to proceed with this action?"
confirmEntryDelete: "Are you sure you want to delete this entry?"
activate-success: "Activation successful."
deactivate-success: "Deactivation successful."
save-success: "Saved successfully"
delete-success: "Deleted successfully"
save-error: "A problem occurred while saving. Please try again."
Expand Down

0 comments on commit afc7ca4

Please sign in to comment.