From 5c89e3418b01ed43bf66dfe918ea68e9c8b6e958 Mon Sep 17 00:00:00 2001 From: Geordan Neukum Date: Sun, 24 Jul 2022 16:22:38 -0400 Subject: [PATCH 1/3] search-input: update to glimmer Let's update the SearchInput component to extend glimmer/component instead of ember/component. Glimmer components offer a bunch of various advantages over classic components and are the direction that ember is heading in general. While we're here, let's also re-enable the eslint rules for which the SearchInput component had the only violations. --- .eslintrc.js | 2 - app/components/search-input.hbs | 33 ++++++++++ app/components/search-input.js | 78 ++++++++++------------- app/templates/components/search-input.hbs | 14 ---- 4 files changed, 67 insertions(+), 60 deletions(-) create mode 100644 app/components/search-input.hbs delete mode 100644 app/templates/components/search-input.hbs diff --git a/.eslintrc.js b/.eslintrc.js index bab1be22..2271a0e6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -23,12 +23,10 @@ module.exports = { 'no-console': 'off', 'ember/no-new-mixins': 'off', 'ember/no-mixins': 'off', - 'ember/native-classes': 'off', 'ember/require-tagless-components': 'off', 'ember/no-test-this-render': 'off', 'ember/no-classic-classes': 'off', 'ember/no-get': 'off', - 'ember/no-actions-hash': 'off', 'ember/no-classic-components': 'off', 'ember/no-private-routing-service': 'off', }, diff --git a/app/components/search-input.hbs b/app/components/search-input.hbs new file mode 100644 index 00000000..bace7a02 --- /dev/null +++ b/app/components/search-input.hbs @@ -0,0 +1,33 @@ +
+ + {{! Search results dropdown }} + + + +
\ No newline at end of file diff --git a/app/components/search-input.js b/app/components/search-input.js index c95126b3..66430811 100644 --- a/app/components/search-input.js +++ b/app/components/search-input.js @@ -1,75 +1,65 @@ -import { A } from '@ember/array'; import { inject as service } from '@ember/service'; -import Component from '@ember/component'; -import { get, set, computed } from '@ember/object'; -import { isPresent, isEmpty } from '@ember/utils'; +import Component from '@glimmer/component'; +import { get } from '@ember/object'; +import { isPresent } from '@ember/utils'; import { task, timeout } from 'ember-concurrency'; +import { action } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; const SEARCH_DEBOUNCE_PERIOD = 300; const SEARCH_CLOSE_PERIOD = 200; -export default Component.extend({ - query: '', +export default class SearchInput extends Component { + @tracked query = ''; + @tracked _focused = false; - classNames: ['search-input'], - searchService: service('search'), + @service('search') searchService; - _results: A(), - _focused: false, - _resultTetherConstraints: null, + _resultTetherConstraints = null; + + constructor() { + super(...arguments); - init() { this._resultTetherConstraints = [ { to: 'window', pin: ['left', 'right'], }, ]; - this._super(...arguments); - }, - - noResults: computed( - 'query', - 'searchService.{results.[],search.isRunning}', - function () { - if (get(this, 'searchService.search.isRunning')) { - return false; - } - return ( - isPresent(this.query) && isEmpty(get(this, 'searchService.results')) - ); - } - ), + } + + get queryIsPresent() { + return isPresent(this.query); + } - search: task(function* (query) { + @task({ restartable: true }) *search(query) { yield timeout(SEARCH_DEBOUNCE_PERIOD); - set(this, 'query', query); + this.query = query; // Hide and don't run query if there's no search query if (!query) { - return set(this, '_focused', false); + this._focused = false; + return; } // ensure search results are visible if the menu was previously closed above - set(this, '_focused', true); + this._focused = true; yield get(this, 'searchService.search').perform(query); - }).restartable(), + } - closeMenu: task(function* () { + @task *closeMenu() { yield timeout(SEARCH_CLOSE_PERIOD); - set(this, '_focused', false); - }), + this._focused = false; + } - actions: { - onfocus() { - set(this, '_focused', true); - }, + @action onfocus() { + this._focused = true; + } - onblur() { - this.closeMenu.perform(); - }, - }, -}); + @action onblur() { + this.closeMenu.perform(); + } +} diff --git a/app/templates/components/search-input.hbs b/app/templates/components/search-input.hbs deleted file mode 100644 index e4a4da29..00000000 --- a/app/templates/components/search-input.hbs +++ /dev/null @@ -1,14 +0,0 @@ - -{{!-- Search results dropdown --}} - - - From f9f1e37a8e1728cb87a62ce77d8eb6495845082f Mon Sep 17 00:00:00 2001 From: Geordan Neukum Date: Sun, 24 Jul 2022 16:54:10 -0400 Subject: [PATCH 2/3] tests: search-input: use `render` helper Ember's this.render method and @ember/test-helpers's render method are equivalent, but using @ember/test-helpers' render method is the recommended approach. As such, let's go ahead and switch this over. While we're here, let's re-enable this eslint rule as we no longer have any violations. --- .eslintrc.js | 1 - tests/integration/components/search-input-test.js | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 2271a0e6..a34c6390 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -24,7 +24,6 @@ module.exports = { 'ember/no-new-mixins': 'off', 'ember/no-mixins': 'off', 'ember/require-tagless-components': 'off', - 'ember/no-test-this-render': 'off', 'ember/no-classic-classes': 'off', 'ember/no-get': 'off', 'ember/no-classic-components': 'off', diff --git a/tests/integration/components/search-input-test.js b/tests/integration/components/search-input-test.js index ed257760..0a818bb6 100644 --- a/tests/integration/components/search-input-test.js +++ b/tests/integration/components/search-input-test.js @@ -1,6 +1,6 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; -import { fillIn, waitFor } from '@ember/test-helpers'; +import { fillIn, render, waitFor } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import { set } from '@ember/object'; @@ -155,7 +155,7 @@ module('Integration | Component | search input', function (hooks) { ]; }); - await this.render(hbs`{{search-input}}`); + await render(hbs`{{search-input}}`); await fillIn('#search-input', 'model'); @@ -171,7 +171,7 @@ module('Integration | Component | search input', function (hooks) { return []; }); - await this.render(hbs`{{search-input}}`); + await render(hbs`{{search-input}}`); await fillIn('#search-input', 'model'); From 291668ed97e4cc091c49d808f50de85b61a4a755 Mon Sep 17 00:00:00 2001 From: Geordan Neukum Date: Sun, 24 Jul 2022 16:59:33 -0400 Subject: [PATCH 3/3] tests: search-input: prefer angle bracket syntax Let's prefer angle bracket syntax to curly syntax when invoking the SearchInput component in our integration tests. --- tests/integration/components/search-input-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/components/search-input-test.js b/tests/integration/components/search-input-test.js index 0a818bb6..1a012fb5 100644 --- a/tests/integration/components/search-input-test.js +++ b/tests/integration/components/search-input-test.js @@ -155,7 +155,7 @@ module('Integration | Component | search input', function (hooks) { ]; }); - await render(hbs`{{search-input}}`); + await render(hbs``); await fillIn('#search-input', 'model'); @@ -171,7 +171,7 @@ module('Integration | Component | search input', function (hooks) { return []; }); - await render(hbs`{{search-input}}`); + await render(hbs``); await fillIn('#search-input', 'model');