diff --git a/changelog/13590.txt b/changelog/13590.txt
new file mode 100644
index 000000000..873160707
--- /dev/null
+++ b/changelog/13590.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+ui: Fixes issue with SearchSelect component not holding focus
+```
\ No newline at end of file
diff --git a/ui/lib/core/addon/components/search-select.js b/ui/lib/core/addon/components/search-select.js
index 303420a44..dd85aa7f5 100644
--- a/ui/lib/core/addon/components/search-select.js
+++ b/ui/lib/core/addon/components/search-select.js
@@ -3,32 +3,34 @@ import { inject as service } from '@ember/service';
import { task } from 'ember-concurrency';
import { computed } from '@ember/object';
import { singularize } from 'ember-inflector';
+import { resolve } from 'rsvp';
+import { filterOptions, defaultMatcher } from 'ember-power-select/utils/group-utils';
import layout from '../templates/components/search-select';
/**
* @module SearchSelect
- * The `SearchSelect` is an implementation of the [ember-power-select-with-create](https://github.com/poteto/ember-cli-flash) used for form elements where options come dynamically from the API.
+ * The `SearchSelect` is an implementation of the [ember-power-select](https://github.com/cibernox/ember-power-select) used for form elements where options come dynamically from the API.
* @example
*
*
- * @param id {String} - The name of the form field
- * @param models {Array} - An array of model types to fetch from the API.
- * @param onChange {Func} - The onchange action for this form field.
- * @param inputValue {String | Array} - A comma-separated string or an array of strings.
- * @param label {String} - Label for this form field
- * @param fallbackComponent {String} - name of component to be rendered if the API call 403s
- * @param [backend] {String} - name of the backend if the query for options needs additional information (eg. secret backend)
- * @param [disallowNewItems=false] {Boolean} - Controls whether or not the user can add a new item if none found
- * @param [helpText] {String} - Text to be displayed in the info tooltip for this form field
- * @param [selectLimit] {Number} - A number that sets the limit to how many select options they can choose
- * @param [subText] {String} - Text to be displayed below the label
- * @param [subLabel] {String} - a smaller label below the main Label
- * @param [wildcardLabel] {String} - when you want the searchSelect component to return a count on the model for options returned when using a wildcard you must provide a label of the count e.g. role. Should be singular.
+ * @param {string} id - The name of the form field
+ * @param {Array} models - An array of model types to fetch from the API.
+ * @param {function} onChange - The onchange action for this form field.
+ * @param {string | Array} inputValue - A comma-separated string or an array of strings.
+ * @param {string} label - Label for this form field
+ * @param {string} fallbackComponent - name of component to be rendered if the API call 403s
+ * @param {string} [backend] - name of the backend if the query for options needs additional information (eg. secret backend)
+ * @param {boolean} [disallowNewItems=false] - Controls whether or not the user can add a new item if none found
+ * @param {string} [helpText] - Text to be displayed in the info tooltip for this form field
+ * @param {number} [selectLimit] - A number that sets the limit to how many select options they can choose
+ * @param {string} [subText] - Text to be displayed below the label
+ * @param {string} [subLabel] - a smaller label below the main Label
+ * @param {string} [wildcardLabel] - when you want the searchSelect component to return a count on the model for options returned when using a wildcard you must provide a label of the count e.g. role. Should be singular.
*
- * @param options {Array} - *Advanced usage* - `options` can be passed directly from the outside to the
+ * @param {Array} options - *Advanced usage* - `options` can be passed directly from the outside to the
* power-select component. If doing this, `models` should not also be passed as that will overwrite the
* passed value.
- * @param search {Func} - *Advanced usage* - Customizes how the power-select component searches for matches -
+ * @param {function} search - *Advanced usage* - Customizes how the power-select component searches for matches -
* see the power-select docs for more information.
*
*/
@@ -48,6 +50,7 @@ export default Component.extend({
shouldUseFallback: false,
shouldRenderName: false,
disallowNewItems: false,
+
init() {
this._super(...arguments);
this.set('selectedOptions', this.inputValue || []);
@@ -130,20 +133,39 @@ export default Component.extend({
this.onChange(this.selectedOptions);
}
},
+ shouldShowCreate(id, options) {
+ if (options && options.length && options.firstObject.groupName) {
+ return !options.some((group) => group.options.findBy('id', id));
+ }
+ let existingOption = this.options && (this.options.findBy('id', id) || this.options.findBy('name', id));
+ if (this.disallowNewItems && !existingOption) {
+ return false;
+ }
+ return !existingOption;
+ },
+ //----- adapted from ember-power-select-with-create
+ addCreateOption(term, results) {
+ if (this.shouldShowCreate(term, results)) {
+ const name = `Add new ${singularize(this.label)}: ${term}`;
+ const suggestion = {
+ __isSuggestion__: true,
+ __value__: term,
+ name,
+ id: name,
+ };
+ results.unshift(suggestion);
+ }
+ },
+ filter(options, searchText) {
+ const matcher = (option, text) => defaultMatcher(option.searchText, text);
+ return filterOptions(options || [], searchText, matcher);
+ },
+ // -----
+
actions: {
onChange(val) {
this.onChange(val);
},
- createOption(optionId) {
- let newOption = { name: optionId, id: optionId, new: true };
- this.selectedOptions.pushObject(newOption);
- this.handleChange();
- },
- selectOption(option) {
- this.selectedOptions.pushObject(option);
- this.options.removeObject(option);
- this.handleChange();
- },
discardSelection(selected) {
this.selectedOptions.removeObject(selected);
// fire off getSelectedValue action higher up in get-credentials-card component
@@ -152,18 +174,34 @@ export default Component.extend({
}
this.handleChange();
},
- constructSuggestion(id) {
- return `Add new ${singularize(this.label)}: ${id}`;
- },
- hideCreateOptionOnSameID(id, options) {
- if (options && options.length && options.firstObject.groupName) {
- return !options.some((group) => group.options.findBy('id', id));
+ // ----- adapted from ember-power-select-with-create
+ searchAndSuggest(term, select) {
+ if (term.length === 0) {
+ return this.options;
}
- let existingOption = this.options && (this.options.findBy('id', id) || this.options.findBy('name', id));
- if (this.disallowNewItems && !existingOption) {
- return false;
+ if (this.search) {
+ return resolve(this.search(term, select)).then((results) => {
+ if (results.toArray) {
+ results = results.toArray();
+ }
+ this.addCreateOption(term, results);
+ return results;
+ });
}
- return !existingOption;
+ const newOptions = this.filter(this.options, term);
+ this.addCreateOption(term, newOptions);
+ return newOptions;
},
+ selectOrCreate(selection) {
+ if (selection && selection.__isSuggestion__) {
+ const name = selection.__value__;
+ this.selectedOptions.pushObject({ name, id: name, new: true });
+ } else {
+ this.selectedOptions.pushObject(selection);
+ this.options.removeObject(selection);
+ }
+ this.handleChange();
+ },
+ // -----
},
});
diff --git a/ui/lib/core/addon/templates/components/search-select.hbs b/ui/lib/core/addon/templates/components/search-select.hbs
index ce87273cd..0e5fe04ad 100644
--- a/ui/lib/core/addon/templates/components/search-select.hbs
+++ b/ui/lib/core/addon/templates/components/search-select.hbs
@@ -22,17 +22,14 @@
{{/if}}
{{! template-lint-configure simple-unless "warn" }}
{{#unless (gte this.selectedOptions.length this.selectLimit)}}
-
{{#if this.shouldRenderName}}
@@ -43,7 +40,7 @@
{{else}}
{{option.id}}
{{/if}}
-
+
{{/unless}}
{{#each this.selectedOptions as |selected|}}
diff --git a/ui/lib/core/package.json b/ui/lib/core/package.json
index b0ddc13f6..c3e272deb 100644
--- a/ui/lib/core/package.json
+++ b/ui/lib/core/package.json
@@ -18,7 +18,7 @@
"ember-composable-helpers": "*",
"ember-concurrency": "*",
"ember-maybe-in-element": "*",
- "ember-power-select-with-create": "*",
+ "ember-power-select": "*",
"ember-radio-button": "*",
"ember-router-helpers": "*",
"ember-svg-jar": "*",
diff --git a/ui/lib/core/stories/search-select.md b/ui/lib/core/stories/search-select.md
index 648add433..2f537b5bd 100644
--- a/ui/lib/core/stories/search-select.md
+++ b/ui/lib/core/stories/search-select.md
@@ -1,26 +1,32 @@
## SearchSelect
-The `SearchSelect` is an implementation of the [ember-power-select-with-create](https://github.com/poteto/ember-cli-flash) used for form elements where options come dynamically from the API.
+The `SearchSelect` is an implementation of the [ember-power-select](https://github.com/cibernox/ember-power-select) used for form elements where options come dynamically from the API.
**Params**
-| Param | Type | Description |
-| --- | --- | --- |
-| id | String
| The name of the form field |
-| models | String
| An array of model types to fetch from the API. |
-| onChange | Func
| The onchange action for this form field. |
-| inputValue | String
\| Array
| A comma-separated string or an array of strings. |
-| [helpText] | String
| Text to be displayed in the info tooltip for this form field |
-| label | String
| Label for this form field |
-| fallbackComponent | String
| name of component to be rendered if the API call 403s |
-| options | Array
| *Advanced usage* - `options` can be passed directly from the outside to the power-select component. If doing this, `models` should not also be passed as that will overwrite the passed value. |
-| search | Func
| *Advanced usage* - Customizes how the power-select component searches for matches - see the power-select docs for more information. |
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| id | string
| | The name of the form field |
+| models | Array
| | An array of model types to fetch from the API. |
+| onChange | function
| | The onchange action for this form field. |
+| inputValue | string
\| Array
| | A comma-separated string or an array of strings. |
+| label | string
| | Label for this form field |
+| fallbackComponent | string
| | name of component to be rendered if the API call 403s |
+| [backend] | string
| | name of the backend if the query for options needs additional information (eg. secret backend) |
+| [disallowNewItems] | boolean
| false
| Controls whether or not the user can add a new item if none found |
+| [helpText] | string
| | Text to be displayed in the info tooltip for this form field |
+| [selectLimit] | number
| | A number that sets the limit to how many select options they can choose |
+| [subText] | string
| | Text to be displayed below the label |
+| [subLabel] | string
| | a smaller label below the main Label |
+| [wildcardLabel] | string
| | when you want the searchSelect component to return a count on the model for options returned when using a wildcard you must provide a label of the count e.g. role. Should be singular. |
+| options | Array
| | *Advanced usage* - `options` can be passed directly from the outside to the power-select component. If doing this, `models` should not also be passed as that will overwrite the passed value. |
+| search | function
| | *Advanced usage* - Customizes how the power-select component searches for matches - see the power-select docs for more information. |
**Example**
```js
-
+
```
**See**
diff --git a/ui/package.json b/ui/package.json
index 8ca347b8b..d867b938a 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -126,7 +126,7 @@
"ember-maybe-in-element": "^2.0.3",
"ember-modal-dialog": "^3.0.3",
"ember-page-title": "^6.0.3",
- "ember-power-select-with-create": "0.9.0",
+ "ember-power-select": "^5.0.3",
"ember-promise-helpers": "^1.0.9",
"ember-qunit": "^5.1.4",
"ember-radio-button": "^2.0.1",
diff --git a/ui/yarn.lock b/ui/yarn.lock
index dc2e803d6..dc022a1ff 100644
--- a/ui/yarn.lock
+++ b/ui/yarn.lock
@@ -2632,6 +2632,19 @@
resolve "^1.8.1"
semver "^7.3.2"
+"@embroider/macros@0.47.2":
+ version "0.47.2"
+ resolved "https://registry.yarnpkg.com/@embroider/macros/-/macros-0.47.2.tgz#23cbe92cac3c24747f054e1eea2a22538bf7ebd0"
+ integrity sha512-ViNWluJCeM5OPlM3rs8kdOz3RV5rpfXX5D2rDnc/q86xRS0xf4NFEjYRV7W6fBcD0b3v5jSHDTwrjq9Kee4rHg==
+ dependencies:
+ "@embroider/shared-internals" "0.47.2"
+ assert-never "^1.2.1"
+ ember-cli-babel "^7.26.6"
+ find-up "^5.0.0"
+ lodash "^4.17.21"
+ resolve "^1.20.0"
+ semver "^7.3.2"
+
"@embroider/macros@^0.43.5":
version "0.43.5"
resolved "https://registry.yarnpkg.com/@embroider/macros/-/macros-0.43.5.tgz#f846bb883482436611a58a3512c687d4f9fddfad"
@@ -2670,6 +2683,19 @@
semver "^7.3.5"
typescript-memoize "^1.0.1"
+"@embroider/shared-internals@0.47.2":
+ version "0.47.2"
+ resolved "https://registry.yarnpkg.com/@embroider/shared-internals/-/shared-internals-0.47.2.tgz#24e9fa0dd9c529d5c996ee1325729ea08d1fa19f"
+ integrity sha512-SxdZYjAE0fiM5zGDz+12euWIsQZ1tsfR1k+NKmiWMyLhA5T3pNgbR2/Djvx/cVIxOtEavGGSllYbzRKBtV4xMg==
+ dependencies:
+ babel-import-util "^0.2.0"
+ ember-rfc176-data "^0.3.17"
+ fs-extra "^9.1.0"
+ lodash "^4.17.21"
+ resolve-package-path "^4.0.1"
+ semver "^7.3.5"
+ typescript-memoize "^1.0.1"
+
"@embroider/util@^0.39.0 || ^0.40.0 || ^0.41.0", "@embroider/util@^0.39.1 || ^0.40.0 || ^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@embroider/util/-/util-0.41.0.tgz#5324cb4742aa4ed8d613c4f88a466f73e4e6acc1"
@@ -2679,6 +2705,15 @@
broccoli-funnel "^3.0.5"
ember-cli-babel "^7.23.1"
+"@embroider/util@^0.47.2":
+ version "0.47.2"
+ resolved "https://registry.yarnpkg.com/@embroider/util/-/util-0.47.2.tgz#d06497b4b84c07ed9c7b628293bb019c533f4556"
+ integrity sha512-g9OqnFJPktGu9NS0Ug3Pxz1JE3jeDceeVE4IrlxDrVmBXMA/GrBvpwjolWgl6jh97cMJyExdz62jIvPHV4256Q==
+ dependencies:
+ "@embroider/macros" "0.47.2"
+ broccoli-funnel "^3.0.5"
+ ember-cli-babel "^7.23.1"
+
"@emotion/cache@^10.0.27", "@emotion/cache@^10.0.9":
version "10.0.29"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"
@@ -9577,13 +9612,13 @@ ember-assign-helper@^0.2.0:
dependencies:
ember-cli-babel "^6.6.0"
-ember-assign-helper@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/ember-assign-helper/-/ember-assign-helper-0.3.0.tgz#7a023dd165ef56b28f77f70fd20e88261380aca7"
- integrity sha512-kDY0IRP6PUSJjghM2gIq24OD7d6XcZ1666zmZrywxEVjCenhaR0Oi/BXUU8JEATrIcXIExMIu34GKrHHlCLw0Q==
+ember-assign-helper@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/ember-assign-helper/-/ember-assign-helper-0.4.0.tgz#f0a313033656c0d2cbbcb29d55b9cd13f04bc7c1"
+ integrity sha512-GKHhT4HD2fhtDnuBk6eCdCA8XGew9hY7TVs8zjrykegiI7weC0CGtpJscmIG3O0gEEb0d07UTkF2pjfNGLx4Nw==
dependencies:
- ember-cli-babel "^7.19.0"
- ember-cli-htmlbars "^4.3.1"
+ ember-cli-babel "^7.26.0"
+ ember-cli-htmlbars "^6.0.0"
ember-auto-import@^1.10.1, ember-auto-import@^1.11.3:
version "1.12.0"
@@ -9665,7 +9700,7 @@ ember-basic-dropdown-hover@0.6.0:
ember-cli-babel "^7.1.2"
ember-cli-htmlbars "^3.0.0"
-ember-basic-dropdown@3.0.19, ember-basic-dropdown@^1.1.2, ember-basic-dropdown@^3.0.21:
+ember-basic-dropdown@3.0.19, ember-basic-dropdown@^1.1.2, "ember-basic-dropdown@^3.1.0 || ^4.0.2":
version "3.0.19"
resolved "https://registry.yarnpkg.com/ember-basic-dropdown/-/ember-basic-dropdown-3.0.19.tgz#e15e71097cbcbc585e85c2c5cf677a6434edb1d5"
integrity sha512-5mZ4hbfGLd+TrFAp0JsfcpIb10zqF60SorKc1Bsm29kJF2wy8p0JUXMb21VVF7+phkrRFYbcXy5enFc8qdm4xw==
@@ -9919,7 +9954,7 @@ ember-cli-htmlbars@^4.3.1:
strip-bom "^4.0.0"
walk-sync "^2.0.2"
-ember-cli-htmlbars@^5.0.0, ember-cli-htmlbars@^5.1.0, ember-cli-htmlbars@^5.2.0, ember-cli-htmlbars@^5.3.2, ember-cli-htmlbars@^5.7.0:
+ember-cli-htmlbars@^5.1.0, ember-cli-htmlbars@^5.2.0, ember-cli-htmlbars@^5.3.2, ember-cli-htmlbars@^5.7.0:
version "5.7.2"
resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-5.7.2.tgz#e0cd2fb3c20d85fe4c3e228e6f0590ee1c645ba8"
integrity sha512-Uj6R+3TtBV5RZoJY14oZn/sNPnc+UgmC8nb5rI4P3fR/gYoyTFIZSXiIM7zl++IpMoIrocxOrgt+mhonKphgGg==
@@ -10619,24 +10654,16 @@ ember-page-title@^6.0.3:
dependencies:
ember-cli-babel "^7.23.1"
-ember-power-select-with-create@0.9.0:
- version "0.9.0"
- resolved "https://registry.yarnpkg.com/ember-power-select-with-create/-/ember-power-select-with-create-0.9.0.tgz#83ed037987dc5824f2bf702d278d055932ec1c87"
- integrity sha512-AQW7N+vZHTojfKSqp/L3HlB81SW3AJtvFJYpdwHqoIcmTsW0BGfXH2z/GVWBUky6fPQLCngKs2Uv5PmpbboVYQ==
- dependencies:
- ember-cli-babel "^7.20.0"
- ember-cli-htmlbars "^5.0.0"
- ember-power-select "^4.0.0"
-
-ember-power-select@^4.0.0:
- version "4.1.7"
- resolved "https://registry.yarnpkg.com/ember-power-select/-/ember-power-select-4.1.7.tgz#eb547dd37448357d8f3fa789db18ddbba43fb8ca"
- integrity sha512-Q4cjUudWb7JA6q7qe0jhcpLsipuFUHMwkYC05HxST5qm3MRMEzs6KfZ3Xd/TcrjBLSoWniw3Q61Quwcb41w5Jw==
+ember-power-select@^5.0.3:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/ember-power-select/-/ember-power-select-5.0.3.tgz#615da0742a222a8c090590dd2cbb2db3a6147ac5"
+ integrity sha512-V72DxohhuPdsF6Rcxu1cVL2faHSk83RdTCkxeDT71NeQQNpHKbslhc0c+MMU52wm0mzch+oWmti/2McpL/vIvQ==
dependencies:
+ "@embroider/util" "^0.47.2"
"@glimmer/component" "^1.0.4"
"@glimmer/tracking" "^1.0.4"
- ember-assign-helper "^0.3.0"
- ember-basic-dropdown "^3.0.21"
+ ember-assign-helper "^0.4.0"
+ ember-basic-dropdown "^3.1.0 || ^4.0.2"
ember-cli-babel "^7.26.0"
ember-cli-htmlbars "^6.0.0"
ember-cli-typescript "^4.2.0"