Skip to content

Commit

Permalink
feat(relationship-select): add component to select a model for a rela…
Browse files Browse the repository at this point in the history
…tionship via power-select
  • Loading branch information
velrest committed Oct 14, 2020
1 parent 38155db commit 373f213
Show file tree
Hide file tree
Showing 7 changed files with 422 additions and 17 deletions.
25 changes: 25 additions & 0 deletions addon/components/relationship-select.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<input
class="hidden-input"
value={{or (or @selected.id @selected.length) ""}}
...attributes
{{did-insert (perform this.fetchModels)}}
/>
{{#with
(component
(if @multiple "power-select-multiple" "power-select")
) as |RelationPowerSelect|
}}
<RelationPowerSelect
@searchEnabled={{true}}
@search={{perform this.fetchModels}}
@options={{this.models}}
@selected={{@selected}}
@placeholder={{
if this.fetchModels.isRunning (t "emeis.loading") @placeholder
}}
@noMatchesMessage={{t "emeis.empty"}}
@onChange={{@onChange}} as |model|
>
{{yield model}}
</RelationPowerSelect>
{{/with}}
23 changes: 23 additions & 0 deletions addon/components/relationship-select.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { inject as service } from "@ember/service";
import Component from "@glimmer/component";
import { timeout } from "ember-concurrency";
import { restartableTask, lastValue } from "ember-concurrency-decorators";

import handleModelErrors from "ember-emeis/decorators/handle-model-errors";

export default class RelationshipSelectComponent extends Component {
@service notification;
@service intl;
@service store;

@lastValue("fetchModels") models;

@restartableTask
@handleModelErrors
*fetchModels(search) {
yield timeout(200);
return yield typeof search === "string"
? this.store.query(this.args.modelName, { filter: { search } })
: this.store.findAll(this.args.modelName);
}
}
1 change: 1 addition & 0 deletions app/components/relationship-select.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "ember-emeis/components/relationship-select";
12 changes: 12 additions & 0 deletions app/styles/ember-emeis.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,15 @@
cursor: pointer;
outline: inherit;
}

.hidden-input {
height: 0;
width: 100%;
border: none;
display: block;
font-size: 0;
}

$ember-power-select-default-border-radius: 0;
$ember-power-select-border-color: $global-border;
@import "ember-power-select";
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"ember-data": "^3.22.0",
"ember-intl": "^5.5.0",
"ember-modifier": "^2.1.1",
"ember-power-select": "^4.0.2",
"ember-simple-set-helper": "^0.1.2",
"ember-test-selectors": "^5.0.0",
"ember-truth-helpers": "^2.1.0",
Expand Down
91 changes: 91 additions & 0 deletions tests/integration/components/relationship-select-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { render, waitUntil } 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 {
typeInSearch,
clickTrigger,
selectChoose,
} from "ember-power-select/test-support/helpers";
import { setupRenderingTest } from "ember-qunit";
import { module, test } from "qunit";

import setupRequestAssertions from "./../../helpers/assert-request";

module("Integration | Component | relationship-select", function (hooks) {
setupRenderingTest(hooks);
setupMirage(hooks);
setupRequestAssertions(hooks);
setupIntl(hooks, ["en"]);

test("single select", async function (assert) {
this.set("modelName", "role");
const role = this.server.create("role");

await render(hbs`
<RelationshipSelect
@modelName={{this.modelName}}
@onChange={{set this.selected}}
@selected={{this.selected}}
@placeholder="test"
as |model|
>
<span data-test-name>{{model.name}}</span>
</RelationshipSelect>
`);

this.assertRequest("GET", "/api/v1/roles", (request) => {
assert.ok(request);
});
await clickTrigger();

// For some reason the await click is not actually waiting for the fetch task to finish.
// Probably some runloop issue.
await waitUntil(() => this.element.querySelector("[data-test-name]"));
assert.dom("[data-test-name]").hasText(role.name.en);

this.assertRequest("GET", "/api/v1/roles", (request) => {
assert.equal(request.queryParams.search, "test");
});
await typeInSearch("test");

await selectChoose("", role.name.en);
assert.equal(this.selected.name, role.name.en);
});

test("multiple select", async function (assert) {
this.set("modelName", "role");
const role = this.server.create("role");

await render(hbs`
<RelationshipSelect
@modelName={{this.modelName}}
@onChange={{set this.selected}}
@selected={{this.selected}}
@placeholder="test"
@multiple="true"
as |model|
>
<span data-test-name>{{model.name}}</span>
</RelationshipSelect>
`);

this.assertRequest("GET", "/api/v1/roles", (request) => {
assert.ok(request);
});
await clickTrigger();

// For some reason the await click is not actually waiting for the fetch task to finish.
// Probably some runloop issue.
await waitUntil(() => this.element.querySelector("[data-test-name]"));
assert.dom("[data-test-name]").hasText(role.name.en);

this.assertRequest("GET", "/api/v1/roles", (request) => {
assert.equal(request.queryParams.search, "test");
});
await typeInSearch("test");

await selectChoose("", role.name.en);
assert.equal(this.selected[0].name, role.name.en);
});
});
Loading

0 comments on commit 373f213

Please sign in to comment.