Skip to content

Commit

Permalink
feat(data-table): include acl columns for userlist (#349)
Browse files Browse the repository at this point in the history
* feat(data-table): include acl columns for userlist

Co-authored-by: Christian Zosel <[email protected]>
  • Loading branch information
derrabauke and czosel committed Dec 21, 2021
1 parent 73a7fd5 commit 4af09c0
Show file tree
Hide file tree
Showing 10 changed files with 289 additions and 165 deletions.
45 changes: 28 additions & 17 deletions addon/components/data-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion addon/components/data-table/head.hbs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<thead>
<tr>
{{yield (hash sorthead=(component "data-table/head/sortable-th" update=@update sortedBy=@sortedBy))}}
{{yield (component "data-table/head/column" update=@update sortedBy=@sortedBy)}}
</tr>
</thead>
19 changes: 19 additions & 0 deletions addon/components/data-table/head/column.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<th>
{{#if @sort}}
<span
data-test-sortable-th={{@sort}}
class="sortable-th"
role="button"
{{on "click" (fn @update @sort)}}
>
{{yield}}
{{#if (eq @sortedBy @sort)}}
<UkIcon @icon="chevron-down"/>
{{else if (eq @sortedBy (concat "-" @sort))}}
<UkIcon @icon="chevron-up"/>
{{/if}}
</span>
{{else}}
{{yield}}
{{/if}}
</th>
15 changes: 0 additions & 15 deletions addon/components/data-table/head/sortable-th.hbs

This file was deleted.

8 changes: 8 additions & 0 deletions addon/controllers/users/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}
61 changes: 51 additions & 10 deletions addon/templates/users/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -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|
>
<table.head as |head|>
<table.head as |Column|>
{{#unless this.emailAsUsername}}
<head.sorthead @sort="username">
<Column @sort="username">
{{t "emeis.users.headings.username"}}
</head.sorthead>
</Column>
{{/unless}}
<head.sorthead @sort="last_name">
<Column @sort="last_name">
{{t "emeis.users.headings.lastName"}}
</head.sorthead>
<head.sorthead @sort="first_name">
</Column>
<Column @sort="first_name">
{{t "emeis.users.headings.firstName"}}
</head.sorthead>
<head.sorthead @sort="email">
</Column>
<Column @sort="email">
{{t "emeis.users.headings.email"}}
</head.sorthead>
</Column>
<Column>
{{t "emeis.roles.title"}}
</Column>
<Column>
{{t "emeis.scopes.title"}}
</Column>
</table.head>
<table.body as |body|>
<body.row>
Expand All @@ -48,6 +54,41 @@
<td data-test-user-email={{user.id}}>
{{user.email}}
</td>
<td>
<ul class="uk-list uk-list-divider">
{{#each user.acls as |acl|}}
<li>
{{#if this.linkToRole}}
<LinkTo @route="roles.edit" @model={{acl.role}} class="uk-link-text">
{{acl.role.name}}
</LinkTo>
{{else}}
{{acl.role.name}}
{{/if}}
</li>
{{else}}
-
{{/each}}
</ul>
</td>
{{!-- SCOPES --}}
<td>
<ul class="uk-list uk-list-divider">
{{#each user.acls as |acl|}}
<li>
{{#if this.linkToScope}}
<LinkTo @route="scopes.edit" @model={{acl.scope}} class="uk-link-text">
{{acl.scope.name}}
</LinkTo>
{{else}}
{{acl.scope.name}}
{{/if}}
</li>
{{else}}
-
{{/each}}
</ul>
</td>
{{/let}}
</body.row>
</table.body>
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { default } from "ember-emeis/components/data-table/head/sortable-th";
export { default } from "ember-emeis/components/data-table/head/column";
131 changes: 97 additions & 34 deletions tests/integration/components/data-table-test.js
Original file line number Diff line number Diff line change
@@ -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`
<DataTable @modelName={{this.modelName}} as |table|>
<table.head as |role|>
<td>Heading 1</td>
<td>Heading 2</td>
<table.head as |Column|>
<Column>Heading 1</Column>
<Column>Heading 2</Column>
</table.head>
<table.body as |body|>
<body.row>
{{log body.model.name}}
{{#let body.model as |role|}}
<td>{{role.name}}</td>
<td data-test-role-slug="{{role.slug}}">{{role.name}}</td>
<td>{{role.slug}}</td>
{{/let}}
</body.row>
Expand All @@ -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) {
Expand All @@ -78,13 +65,13 @@ module("Integration | Component | data-table", function (hooks) {
@modelName={{this.modelName}}
@page={{this.page}}
as |table|>
<table.head as |role|>
<role.sorthead @sort="one">
<table.head as |Column|>
<Column @sort="one">
Heading One
</role.sorthead>
<role.sorthead @sort="two">
</Column>
<Column>
Heading One
</role.sorthead>
</Column>
</table.head>
<table.body as |body|>
<body.row>
Expand Down Expand Up @@ -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`
<DataTable
@modelName={{this.modelName}}
@include={{array "acls.role" "acls.scope"}}
as |table|>
<table.head as |Column|>
<Column @sort="one">
Heading One
</Column>
<Column>
Roles
</Column>
<Column>
Scopes
</Column>
</table.head>
<table.body as |body|>
<body.row>
{{#let body.model as |user|}}
<td>{{user.name}}</td>
<td>{{user.acls.role.name}}</td>
<td>{{user.acls.scope.name}}</td>
{{/let}}
</body.row>
</table.body>
</DataTable>
`);

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";
Expand Down
Loading

0 comments on commit 4af09c0

Please sign in to comment.