diff --git a/addon/components/data-table.js b/addon/components/data-table.js index 2df6e61e..addbdb4a 100644 --- a/addon/components/data-table.js +++ b/addon/components/data-table.js @@ -85,27 +85,38 @@ export default class DataTableComponent extends Component { typeof this.args.modelName === "string" ); - let options = { - filter: { search: this.search, ...(this.args.filter || {}) }, - sort: this.sort, - include: this.args.include || "", - }; - - if (!this.search) { - options = { - ...options, - page: { - number: this.page, - size: this.emeisOptions.pageSize, - }, + try { + let includes = this.args.include; + if (this.args.include && Array.isArray(this.args.include)) { + includes = this.args.include.join(","); + } + + let options = { + filter: { search: this.search, ...(this.args.filter || {}) }, + sort: this.sort, + include: includes, }; - } - const data = yield this.store.query(this.args.modelName, options); + if (!this.search) { + options = { + ...options, + page: { + number: this.page, + size: this.emeisOptions.pageSize, + }, + }; + } - this.numPages = data.meta.pagination?.pages; + const data = yield this.store.query(this.args.modelName, options); + this.numPages = data.meta.pagination?.pages; - return data; + return data; + } catch (error) { + console.error( + "Non-standard JSON:API response while fetching table data.", + error + ); + } } @action diff --git a/addon/components/data-table/head.hbs b/addon/components/data-table/head.hbs index bbcdbcab..7b8fe0eb 100644 --- a/addon/components/data-table/head.hbs +++ b/addon/components/data-table/head.hbs @@ -1,5 +1,5 @@ - {{yield (hash sorthead=(component "data-table/head/sortable-th" update=@update sortedBy=@sortedBy))}} + {{yield (component "data-table/head/column" update=@update sortedBy=@sortedBy)}} \ No newline at end of file diff --git a/addon/components/data-table/head/column.hbs b/addon/components/data-table/head/column.hbs new file mode 100644 index 00000000..7531ea0b --- /dev/null +++ b/addon/components/data-table/head/column.hbs @@ -0,0 +1,19 @@ + + {{#if @sort}} + + {{yield}} + {{#if (eq @sortedBy @sort)}} + + {{else if (eq @sortedBy (concat "-" @sort))}} + + {{/if}} + + {{else}} + {{yield}} + {{/if}} + \ No newline at end of file diff --git a/addon/components/data-table/head/sortable-th.hbs b/addon/components/data-table/head/sortable-th.hbs deleted file mode 100644 index 5d2bf5a1..00000000 --- a/addon/components/data-table/head/sortable-th.hbs +++ /dev/null @@ -1,15 +0,0 @@ - - - {{yield}} - {{#if (eq @sortedBy @sort)}} - - {{else if (eq @sortedBy (concat "-" @sort))}} - - {{/if}} - - \ No newline at end of file diff --git a/addon/controllers/users/index.js b/addon/controllers/users/index.js index 7225ff98..f3097091 100644 --- a/addon/controllers/users/index.js +++ b/addon/controllers/users/index.js @@ -8,4 +8,12 @@ export default class UsersIndexController extends PaginationController { get emailAsUsername() { return this.emeisOptions.emailAsUsername; } + + get linkToRole() { + return this.emeisOptions.navigationEntries?.includes("roles"); + } + + get linkToScope() { + return this.emeisOptions.navigationEntries?.includes("scopes"); + } } diff --git a/addon/templates/users/index.hbs b/addon/templates/users/index.hbs index 1f10effd..0a86af84 100644 --- a/addon/templates/users/index.hbs +++ b/addon/templates/users/index.hbs @@ -6,24 +6,30 @@ @updatePage={{fn this.updateQueryParam "page"}} @updateSearch={{fn this.updateQueryParam "search"}} @updateSort={{fn this.updateQueryParam "sort"}} - @include={{"acls.role"}} + @include={{array "acls.role" "acls.scope"}} as |table| > - + {{#unless this.emailAsUsername}} - + {{t "emeis.users.headings.username"}} - + {{/unless}} - + {{t "emeis.users.headings.lastName"}} - - + + {{t "emeis.users.headings.firstName"}} - - + + {{t "emeis.users.headings.email"}} - + + + {{t "emeis.roles.title"}} + + + {{t "emeis.scopes.title"}} + @@ -48,6 +54,41 @@ {{user.email}} + +
    + {{#each user.acls as |acl|}} +
  • + {{#if this.linkToRole}} + + {{acl.role.name}} + + {{else}} + {{acl.role.name}} + {{/if}} +
  • + {{else}} + - + {{/each}} +
+ + {{!-- SCOPES --}} + +
    + {{#each user.acls as |acl|}} +
  • + {{#if this.linkToScope}} + + {{acl.scope.name}} + + {{else}} + {{acl.scope.name}} + {{/if}} +
  • + {{else}} + - + {{/each}} +
+ {{/let}}
diff --git a/app/components/data-table/head/sortable-th.js b/app/components/data-table/head/column.js similarity index 82% rename from app/components/data-table/head/sortable-th.js rename to app/components/data-table/head/column.js index 624c6fc4..eac99981 100644 --- a/app/components/data-table/head/sortable-th.js +++ b/app/components/data-table/head/column.js @@ -1 +1 @@ -export { default } from "ember-emeis/components/data-table/head/sortable-th"; +export { default } from "ember-emeis/components/data-table/head/column"; diff --git a/tests/integration/components/data-table-test.js b/tests/integration/components/data-table-test.js index 2f66e1da..a7f339aa 100644 --- a/tests/integration/components/data-table-test.js +++ b/tests/integration/components/data-table-test.js @@ -1,42 +1,32 @@ import { render, click, fillIn } from "@ember/test-helpers"; import { hbs } from "ember-cli-htmlbars"; +import { setupMirage } from "ember-cli-mirage/test-support"; import { setupIntl } from "ember-intl/test-support"; import { setupRenderingTest } from "ember-qunit"; import { module, test } from "qunit"; module("Integration | Component | data-table", function (hooks) { setupRenderingTest(hooks); - setupIntl(hooks); + setupMirage(hooks); + setupIntl(hooks, "en"); test("fetch and display correct data", async function (assert) { - assert.expect(11); + assert.expect(7); this.set("modelName", "role"); - - const store = this.owner.lookup("service:store"); - store.query = (modelName) => { - assert.strictEqual(modelName, this.modelName); - - const data = [ - { name: "Role 1", slug: "role-1" }, - { name: "Role 2", slug: "role-2" }, - ]; - - data.meta = { pagination: { pages: 5 } }; - - return data; - }; + const role = this.server.createList("role", 10)[0]; await render(hbs` - - Heading 1 - Heading 2 + + Heading 1 + Heading 2 + {{log body.model.name}} {{#let body.model as |role|}} - {{role.name}} + {{role.name}} {{role.slug}} {{/let}} @@ -48,16 +38,13 @@ module("Integration | Component | data-table", function (hooks) { assert.dom('form button[type="submit"]').exists(); assert.dom("thead tr").exists({ count: 1 }); - assert.dom("thead tr td:first-child").hasText("Heading 1"); - assert.dom("thead tr td:last-child").hasText("Heading 2"); - - assert.dom("tbody tr").exists({ count: 2 }); + assert.dom("thead tr th:first-child").hasText("Heading 1"); + assert.dom("thead tr th:last-child").hasText("Heading 2"); - assert.dom("tbody tr:first-child td:first-child").hasText("Role 1"); - assert.dom("tbody tr:first-child td:last-child").hasText("role-1"); - - assert.dom("tbody tr:last-child td:first-child").hasText("Role 2"); - assert.dom("tbody tr:last-child td:last-child").hasText("role-2"); + assert.dom("tbody tr").exists({ count: 10 }); + assert + .dom(`tbody tr td[data-test-role-slug=${role.slug}]`) + .hasText(role.name.en); }); test("pagination", async function (assert) { @@ -78,13 +65,13 @@ module("Integration | Component | data-table", function (hooks) { @modelName={{this.modelName}} @page={{this.page}} as |table|> - - + + Heading One - - + + Heading One - + @@ -118,6 +105,82 @@ module("Integration | Component | data-table", function (hooks) { assert.dom("tfoot li:last-child").hasClass("uk-disabled"); }); + test("datatable fetches includes", async function (assert) { + assert.expect(6); + + this.set("modelName", "user"); + + const store = this.owner.lookup("service:store"); + store.query = (_, options) => { + assert.strictEqual(options.include, "acls.role,acls.scope"); + + const data = [ + { + name: "User 1", + acls: { + role: { + id: "role-1", + name: "Role 1", + }, + scope: { + name: "scope1", + }, + }, + }, + { + name: "User 2", + acls: { + role: { + id: "role-2", + name: "Role 2", + }, + scope: { + name: "scope2", + }, + }, + }, + ]; + + data.meta = { pagination: { pages: 1 } }; + return data; + }; + + await render(hbs` + + + + Heading One + + + Roles + + + Scopes + + + + + {{#let body.model as |user|}} + {{user.name}} + {{user.acls.role.name}} + {{user.acls.scope.name}} + {{/let}} + + + + `); + + assert.dom("thead tr th:first-child").hasText("Heading One"); + assert.dom("thead tr th:last-child").hasText("Scopes"); + + assert.dom("tbody tr td:first-child").hasText("User 1"); + assert.dom("tbody tr:last-child td:nth-child(2)").hasText("Role 2"); + assert.dom("tbody tr:last-child td:nth-child(3)").hasText("scope2"); + }); + test("search", async function (assert) { assert.expect(5); const search = "test"; diff --git a/tests/integration/components/data-table/head/column-test.js b/tests/integration/components/data-table/head/column-test.js new file mode 100644 index 00000000..b1b58a96 --- /dev/null +++ b/tests/integration/components/data-table/head/column-test.js @@ -0,0 +1,84 @@ +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 | data-table/head/column", function (hooks) { + setupRenderingTest(hooks); + + hooks.beforeEach(function (assert) { + this.set("sort", "last_name"); + this.set("update", (sort) => { + this.set("sort", sort); + assert.step("update"); + }); + }); + + test("it renders", async function (assert) { + await render(hbs` + + + test + + + `); + + assert.dom(this.element).hasText("test"); + assert.dom("span[icon=chevron-down]").exists(); + }); + + test("it renders as block", async function (assert) { + await render(hbs` + + template block text + + `); + + assert.dom(this.element).hasText("template block text"); + }); + + test("it toggles sort state", async function (assert) { + await render(hbs` + + + one + + + two + + + `); + + assert.dom("[data-test-sortable-th=last_name]").hasText("one"); + assert.dom("[data-test-sortable-th=first_name]").hasText("two"); + assert + .dom("[data-test-sortable-th=last_name] span[icon=chevron-down]") + .exists(); + + this.set("sort", "first_name"); + + assert + .dom("[data-test-sortable-th=last_name] span[icon=chevron-down]") + .doesNotExist(); + assert + .dom("[data-test-sortable-th=first_name] span[icon=chevron-down]") + .exists(); + + await click("[data-test-sortable-th=last_name]"); + + assert.verifySteps(["update"]); + + assert + .dom("[data-test-sortable-th=first_name] span[icon=chevron-down]") + .doesNotExist(); + assert + .dom("[data-test-sortable-th=last_name] span[icon=chevron-down]") + .exists(); + + this.set("sort", "-last_name"); + + assert + .dom("[data-test-sortable-th=last_name] span[icon=chevron-up]") + .exists(); + }); +}); diff --git a/tests/integration/components/data-table/head/sortable-th-test.js b/tests/integration/components/data-table/head/sortable-th-test.js deleted file mode 100644 index d9112ecb..00000000 --- a/tests/integration/components/data-table/head/sortable-th-test.js +++ /dev/null @@ -1,87 +0,0 @@ -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 | data-table/head/sortable-th", - function (hooks) { - setupRenderingTest(hooks); - - hooks.beforeEach(function (assert) { - this.set("sort", "last_name"); - this.set("update", (sort) => { - this.set("sort", sort); - assert.step("update"); - }); - }); - - test("it renders", async function (assert) { - await render(hbs` - - - test - - - `); - - assert.dom(this.element).hasText("test"); - assert.dom("span[icon=chevron-down]").exists(); - }); - - test("it renders as block", async function (assert) { - await render(hbs` - - template block text - - `); - - assert.dom(this.element).hasText("template block text"); - }); - - test("it toggles sort state", async function (assert) { - await render(hbs` - - - one - - - two - - - `); - - assert.dom("[data-test-sortable-th=last_name]").hasText("one"); - assert.dom("[data-test-sortable-th=first_name]").hasText("two"); - assert - .dom("[data-test-sortable-th=last_name] span[icon=chevron-down]") - .exists(); - - this.set("sort", "first_name"); - - assert - .dom("[data-test-sortable-th=last_name] span[icon=chevron-down]") - .doesNotExist(); - assert - .dom("[data-test-sortable-th=first_name] span[icon=chevron-down]") - .exists(); - - await click("[data-test-sortable-th=last_name]"); - - assert.verifySteps(["update"]); - - assert - .dom("[data-test-sortable-th=first_name] span[icon=chevron-down]") - .doesNotExist(); - assert - .dom("[data-test-sortable-th=last_name] span[icon=chevron-down]") - .exists(); - - this.set("sort", "-last_name"); - - assert - .dom("[data-test-sortable-th=last_name] span[icon=chevron-up]") - .exists(); - }); - } -);