diff --git a/packages/admin/package-lock.json b/packages/admin/package-lock.json index 09d3ca7ed..12a5075bb 100644 --- a/packages/admin/package-lock.json +++ b/packages/admin/package-lock.json @@ -20614,9 +20614,9 @@ } }, "typescript": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", - "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "dev": true }, "typescript-memoize": { diff --git a/packages/admin/package.json b/packages/admin/package.json index c741d8caf..0ad882b8f 100644 --- a/packages/admin/package.json +++ b/packages/admin/package.json @@ -31,7 +31,7 @@ "ember-cli-babel": "^7.19.0", "ember-cli-htmlbars": "^5.1.2", "ember-cli-mirage": "~1.1.6", - "ember-cli-typescript": "^4.0.0", + "ember-cli-typescript": "^4.1.0", "navi-core": "0.2.0" }, "devDependencies": { @@ -76,7 +76,7 @@ "loader.js": "^4.7.0", "npm-run-all": "^4.1.5", "qunit-dom": "^1.2.0", - "typescript": "^3.9.5" + "typescript": "^4.1.5" }, "engines": { "node": "10.* || >= 12" diff --git a/packages/core/package-lock.json b/packages/core/package-lock.json index 896e7af57..8d0ee8c8a 100644 --- a/packages/core/package-lock.json +++ b/packages/core/package-lock.json @@ -12453,13 +12453,15 @@ } }, "ember-concurrency": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-1.3.0.tgz", - "integrity": "sha512-DwGlfWFpYyAkTwsedlEtK4t1DznJSculAW6Vq5S1C0shVPc5b6tTpHB2FFYisannSYkm+wpm1f1Pd40qiNPtOQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-2.0.3.tgz", + "integrity": "sha512-+fOOFt32odnunDL3Du0LqMgnRzDDNKnzo1ry9ppICpvLXekJzYFwU1RniVivfJ+9nbpHMJZQUlZJAm1ZAnTExw==", "requires": { - "ember-cli-babel": "^7.7.3", + "@glimmer/tracking": "^1.0.2", + "ember-cli-babel": "^7.22.1", + "ember-cli-htmlbars": "^5.6.3", "ember-compatibility-helpers": "^1.2.0", - "ember-maybe-import-regenerator": "^0.1.6" + "ember-destroyable-polyfill": "^2.0.2" } }, "ember-concurrency-decorators": { @@ -12661,6 +12663,102 @@ } } }, + "ember-concurrency-ts": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ember-concurrency-ts/-/ember-concurrency-ts-0.2.2.tgz", + "integrity": "sha512-03/NEhXczd93tpg0ycusj3bgXZS15wymU0K8eMvWftyzWS4B+UE03RzimOFrtOxJmE2mNj64hLJUZR9P8LelFw==", + "requires": { + "ember-cli-babel": "^7.19.0", + "ember-cli-htmlbars": "^4.3.1" + }, + "dependencies": { + "broccoli-output-wrapper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/broccoli-output-wrapper/-/broccoli-output-wrapper-2.0.0.tgz", + "integrity": "sha512-V/ozejo+snzNf75i/a6iTmp71k+rlvqjE3+jYfimuMwR1tjNNRdtfno+NGNQB2An9bIAeqZnKhMDurAznHAdtA==", + "requires": { + "heimdalljs-logger": "^0.1.10" + } + }, + "broccoli-plugin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-3.1.0.tgz", + "integrity": "sha512-7w7FP8WJYjLvb0eaw27LO678TGGaom++49O1VYIuzjhXjK5kn2+AMlDm7CaUFw4F7CLGoVQeZ84d8gICMJa4lA==", + "requires": { + "broccoli-node-api": "^1.6.0", + "broccoli-output-wrapper": "^2.0.0", + "fs-merger": "^3.0.1", + "promise-map-series": "^0.2.1", + "quick-temp": "^0.1.3", + "rimraf": "^2.3.4", + "symlink-or-copy": "^1.1.8" + } + }, + "ember-cli-htmlbars": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-4.5.0.tgz", + "integrity": "sha512-bYJpK1pqFu9AadDAGTw05g2LMNzY8xTCIqQm7dMJmKEoUpLRFbPf4SfHXrktzDh7Q5iggl6Skzf1M0bPlIxARw==", + "requires": { + "@ember/edition-utils": "^1.2.0", + "babel-plugin-htmlbars-inline-precompile": "^3.2.0", + "broccoli-debug": "^0.6.5", + "broccoli-persistent-filter": "^2.3.1", + "broccoli-plugin": "^3.1.0", + "common-tags": "^1.8.0", + "ember-cli-babel-plugin-helpers": "^1.1.0", + "fs-tree-diff": "^2.0.1", + "hash-for-dep": "^1.5.1", + "heimdalljs-logger": "^0.1.10", + "json-stable-stringify": "^1.0.1", + "semver": "^6.3.0", + "strip-bom": "^4.0.0", + "walk-sync": "^2.0.2" + } + }, + "fs-tree-diff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-2.0.1.tgz", + "integrity": "sha512-x+CfAZ/lJHQqwlD64pYM5QxWjzWhSjroaVsr8PW831zOApL55qPibed0c+xebaLWVr2BnHFoHdrwOv8pzt8R5A==", + "requires": { + "@types/symlink-or-copy": "^1.2.0", + "heimdalljs-logger": "^0.1.7", + "object-assign": "^4.1.0", + "path-posix": "^1.0.0", + "symlink-or-copy": "^1.1.8" + } + }, + "matcher-collection": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-2.0.1.tgz", + "integrity": "sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ==", + "requires": { + "@types/minimatch": "^3.0.3", + "minimatch": "^3.0.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" + }, + "walk-sync": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-2.2.0.tgz", + "integrity": "sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==", + "requires": { + "@types/minimatch": "^3.0.3", + "ensure-posix-path": "^1.1.0", + "matcher-collection": "^2.0.0", + "minimatch": "^3.0.4" + } + } + } + }, "ember-copy": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ember-copy/-/ember-copy-2.0.1.tgz", @@ -12867,9 +12965,9 @@ } }, "ember-destroyable-polyfill": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/ember-destroyable-polyfill/-/ember-destroyable-polyfill-2.0.3.tgz", - "integrity": "sha512-TovtNqCumzyAiW0/OisSkkVK93xnVF4NRU6+FN0ubpfwEOpRrmM2RqDwXI6YAChCgSHON1cz0DfQStpA1Gjuuw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ember-destroyable-polyfill/-/ember-destroyable-polyfill-2.0.2.tgz", + "integrity": "sha512-9t+ya+9c+FkNM5IAyJIv6ETG8jfZQaUnFCO5SeLlV0wkSw7TOexyb61jh5GVee0KmknfRhrRGGAyT4Y0TwkZ+w==", "requires": { "ember-cli-babel": "^7.22.1", "ember-cli-version-checker": "^5.1.1", @@ -14232,6 +14330,7 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/ember-maybe-import-regenerator/-/ember-maybe-import-regenerator-0.1.6.tgz", "integrity": "sha1-NdQYKK+m1qWbwNo85H80xXPXdso=", + "dev": true, "requires": { "broccoli-funnel": "^1.0.1", "broccoli-merge-trees": "^1.0.0", @@ -14243,6 +14342,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz", "integrity": "sha512-hlSTWGS1t6/xq5YCed7YALg7tKZL3rkl7UwEZ/eCIkn8JxmM6fU6Qs/1hwtjQqfuYxlffuUcgYEm0f5xP4YKaA==", + "dev": true, "requires": { "ensure-posix-path": "^1.0.1" } @@ -14251,6 +14351,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0.tgz", "integrity": "sha512-Wpmw4TbhR3Eq2t3W51eBAQSdKlr+uAyF0GI4GtPfMCD12Y4cIdpKC9l0RjNTH/P9isFypSqqewMPm7//fnZlNA==", + "dev": true, "requires": { "semver": "^5.3.0" } @@ -14259,6 +14360,7 @@ "version": "2.13.4", "resolved": "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.13.4.tgz", "integrity": "sha512-uxQPkEQAzCYdwhZk16O9m1R4xtCRNy4oEUTBrccOPfzlIahRZJic/JeP/ZEL0BC6Mfq6r55eOg6gMF/zdFoCvA==", + "dev": true, "requires": { "ember-rfc176-data": "^0.3.13" } @@ -14267,6 +14369,7 @@ "version": "6.5.1", "resolved": "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.1.tgz", "integrity": "sha512-w6GcnkxvHcNCte5FcLGEG1hUdQvlfvSN/6PtGWU/otg69Ugk8rUk51h41R0Ugoc+TNxyeFG1opRt2RlA87XzNw==", + "dev": true, "requires": { "babel-core": "^6.26.0", "broccoli-funnel": "^2.0.1", @@ -14284,6 +14387,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-2.0.2.tgz", "integrity": "sha512-/vDTqtv7ipjEZQOVqO4vGDVAOZyuYzQ/EgGoyewfOgh1M7IQAToBKZI0oAQPgMBeFPPlIbfMuAngk+ohPBuaHQ==", + "dev": true, "requires": { "array-equal": "^1.0.0", "blank-object": "^1.0.1", @@ -14304,6 +14408,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-2.0.1.tgz", "integrity": "sha512-WjaexJ+I8BxP5V5RNn6um/qDRSmKoiBC/QkRi79FT9ClHfldxRyCDs9mcV7mmoaPlsshmmPaUz5jdtcKA6DClQ==", + "dev": true, "requires": { "broccoli-plugin": "^1.3.0", "merge-trees": "^1.0.1" @@ -14315,6 +14420,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz", "integrity": "sha1-zdw6/F/xaFqAI0iP/3TOb7WlEpY=", + "dev": true, "requires": { "array-equal": "^1.0.0", "blank-object": "^1.0.1", @@ -14336,6 +14442,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz", "integrity": "sha1-oAFRm7UGfwZYnZGvopQkRaLQ/bU=", + "dev": true, "requires": { "broccoli-plugin": "^1.3.0", "can-symlink": "^1.0.0", @@ -14351,6 +14458,7 @@ "version": "1.4.6", "resolved": "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.6.tgz", "integrity": "sha512-0RejLwoC95kv4kta8KAa+FmECJCK78Qgm8SRDEK7YyU0N9Cx6KpY3UCDy9WELl3mCXLN8TokNxc7/hp3lL4lfw==", + "dev": true, "requires": { "async-disk-cache": "^1.2.1", "async-promise-queue": "^1.0.3", @@ -14370,19 +14478,22 @@ "rsvp": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", - "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==" + "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", + "dev": true } } }, "broccoli-source": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/broccoli-source/-/broccoli-source-1.1.0.tgz", - "integrity": "sha1-VPDoLItz9GWAy7xPV48LMvyo+Ak=" + "integrity": "sha1-VPDoLItz9GWAy7xPV48LMvyo+Ak=", + "dev": true }, "ember-cli-babel": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.18.0.tgz", "integrity": "sha512-7ceC8joNYxY2wES16iIBlbPSxwKDBhYwC8drU3ZEvuPDMwVv1KzxCNu1fvxyFEBWhwaRNTUxSCsEVoTd9nosGA==", + "dev": true, "requires": { "amd-name-resolver": "1.2.0", "babel-plugin-debug-macros": "^0.2.0-beta.6", @@ -14403,6 +14514,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-2.0.2.tgz", "integrity": "sha512-/vDTqtv7ipjEZQOVqO4vGDVAOZyuYzQ/EgGoyewfOgh1M7IQAToBKZI0oAQPgMBeFPPlIbfMuAngk+ohPBuaHQ==", + "dev": true, "requires": { "array-equal": "^1.0.0", "blank-object": "^1.0.1", @@ -14425,6 +14537,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-2.2.0.tgz", "integrity": "sha512-G+KtYIVlSOWGcNaTFHk76xR4GdzDLzAS4uxZUKdASuFX0KJE43C6DaqL+y3VTpUFLI2FIkAS6HZ4I1YBi+S3hg==", + "dev": true, "requires": { "resolve": "^1.3.3", "semver": "^5.3.0" @@ -14434,6 +14547,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-trees/-/merge-trees-1.0.1.tgz", "integrity": "sha1-zL5nRWl4f53vF/1G5lJfVwC70j4=", + "dev": true, "requires": { "can-symlink": "^1.0.0", "fs-tree-diff": "^0.5.4", @@ -14446,17 +14560,20 @@ "regenerator-runtime": { "version": "0.9.6", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz", - "integrity": "sha1-0z65XQ0gAaS+OWWXB8UbDLcc4Ck=" + "integrity": "sha1-0z65XQ0gAaS+OWWXB8UbDLcc4Ck=", + "dev": true }, "rsvp": { "version": "4.8.5", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==" + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true }, "workerpool": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-2.3.3.tgz", "integrity": "sha512-L1ovlYHp6UObYqElXXpbd214GgbEKDED0d3sj7pRdFXjNkb2+un/AUcCkceHizO0IVI6SOGGncrcjozruCkRgA==", + "dev": true, "requires": { "object-assign": "4.1.1" } @@ -17756,7 +17873,8 @@ "exists-sync": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.4.tgz", - "integrity": "sha1-l0TCxCjMA7AQYNtFTUsS8O88iHk=" + "integrity": "sha1-l0TCxCjMA7AQYNtFTUsS8O88iHk=", + "dev": true }, "exit": { "version": "0.1.2", @@ -25281,9 +25399,9 @@ } }, "typescript": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", - "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "dev": true }, "typescript-memoize": { diff --git a/packages/core/package.json b/packages/core/package.json index 5c483a769..6e3f74830 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -28,10 +28,11 @@ "ember-cli-htmlbars": "^5.1.2", "ember-cli-moment-shim": "^3.8.0", "ember-cli-string-helpers": "^5.0.0", - "ember-cli-typescript": "^4.0.0", + "ember-cli-typescript": "^4.1.0", "ember-collection": "1.0.0-alpha.9", "ember-composable-helpers": "^4.1.1", - "ember-concurrency": "^1.3.0", + "ember-concurrency": "2.0.3", + "ember-concurrency-ts": "0.2.2", "ember-copy": "^2.0.1", "ember-cp-validations": "^4.0.0-beta.10", "ember-data-model-fragments": "^5.0.0-beta.1", @@ -105,7 +106,7 @@ "npm-run-all": "^4.1.5", "qunit-dom": "^1.0.0", "sass": "^1.30.0", - "typescript": "^3.9.5" + "typescript": "^4.1.5" }, "keywords": [ "ember-addon" diff --git a/packages/dashboards/addon/services/dashboard-data.js b/packages/dashboards/addon/services/dashboard-data.js index 1072a9ed3..9f9221155 100644 --- a/packages/dashboards/addon/services/dashboard-data.js +++ b/packages/dashboards/addon/services/dashboard-data.js @@ -100,7 +100,7 @@ export default class DashboardDataService extends Service { * @param {String} uuid - v1 UUID * @yields {TaskInstance} */ - @task(function* (dashboardId, widget, decorators, options, uuid) { + @task *_fetchRequestsForWidget(dashboardId, widget, decorators, options, uuid) { const { dashboard, requests, id: widgetId } = widget; const fetchTasks = []; @@ -121,8 +121,7 @@ export default class DashboardDataService extends Service { }); return yield fetchTasks.length ? all(fetchTasks) : []; - }) - _fetchRequestsForWidget; + } /** * @property {Task} _fetchRequest @@ -132,7 +131,8 @@ export default class DashboardDataService extends Service { * @param {Array} filterErrors - invalid Filter error objects * @yields {TaskInstance} */ - @(task(function* (requestFragment, decorators, options, filterErrors) { + @task({ enqueue: true, maxConcurrency: FETCH_MAX_CONCURRENCY }) + *_fetchRequest(requestFragment, decorators, options, filterErrors) { const request = this._decorate(decorators, requestFragment.serialize()); return yield this._fetch(request, options, filterErrors).then((result) => { const serverErrors = getWithDefault(result, 'response.meta.errors', []); @@ -142,10 +142,7 @@ export default class DashboardDataService extends Service { response: { meta: { errors: [...serverErrors, ...filterErrors] } }, }); }); - }) - .enqueue() - .maxConcurrency(FETCH_MAX_CONCURRENCY)) - _fetchRequest; + } /** * @method _fetch @@ -155,7 +152,7 @@ export default class DashboardDataService extends Service { * @returns {Promise} response from request */ _fetch(request, options) { - return this.naviFacts.fetch(request, options); + return this.naviFacts.fetch.perform(request, options); } /** diff --git a/packages/dashboards/package-lock.json b/packages/dashboards/package-lock.json index 45587759b..0b1fbb4ae 100644 --- a/packages/dashboards/package-lock.json +++ b/packages/dashboards/package-lock.json @@ -11789,13 +11789,15 @@ } }, "ember-concurrency": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-1.3.0.tgz", - "integrity": "sha512-DwGlfWFpYyAkTwsedlEtK4t1DznJSculAW6Vq5S1C0shVPc5b6tTpHB2FFYisannSYkm+wpm1f1Pd40qiNPtOQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-2.0.3.tgz", + "integrity": "sha512-+fOOFt32odnunDL3Du0LqMgnRzDDNKnzo1ry9ppICpvLXekJzYFwU1RniVivfJ+9nbpHMJZQUlZJAm1ZAnTExw==", "requires": { - "ember-cli-babel": "^7.7.3", + "@glimmer/tracking": "^1.0.2", + "ember-cli-babel": "^7.22.1", + "ember-cli-htmlbars": "^5.6.3", "ember-compatibility-helpers": "^1.2.0", - "ember-maybe-import-regenerator": "^0.1.6" + "ember-destroyable-polyfill": "^2.0.2" } }, "ember-concurrency-decorators": { @@ -11997,6 +11999,102 @@ } } }, + "ember-concurrency-ts": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ember-concurrency-ts/-/ember-concurrency-ts-0.2.2.tgz", + "integrity": "sha512-03/NEhXczd93tpg0ycusj3bgXZS15wymU0K8eMvWftyzWS4B+UE03RzimOFrtOxJmE2mNj64hLJUZR9P8LelFw==", + "requires": { + "ember-cli-babel": "^7.19.0", + "ember-cli-htmlbars": "^4.3.1" + }, + "dependencies": { + "broccoli-output-wrapper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/broccoli-output-wrapper/-/broccoli-output-wrapper-2.0.0.tgz", + "integrity": "sha512-V/ozejo+snzNf75i/a6iTmp71k+rlvqjE3+jYfimuMwR1tjNNRdtfno+NGNQB2An9bIAeqZnKhMDurAznHAdtA==", + "requires": { + "heimdalljs-logger": "^0.1.10" + } + }, + "broccoli-plugin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-3.1.0.tgz", + "integrity": "sha512-7w7FP8WJYjLvb0eaw27LO678TGGaom++49O1VYIuzjhXjK5kn2+AMlDm7CaUFw4F7CLGoVQeZ84d8gICMJa4lA==", + "requires": { + "broccoli-node-api": "^1.6.0", + "broccoli-output-wrapper": "^2.0.0", + "fs-merger": "^3.0.1", + "promise-map-series": "^0.2.1", + "quick-temp": "^0.1.3", + "rimraf": "^2.3.4", + "symlink-or-copy": "^1.1.8" + } + }, + "ember-cli-htmlbars": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-4.5.0.tgz", + "integrity": "sha512-bYJpK1pqFu9AadDAGTw05g2LMNzY8xTCIqQm7dMJmKEoUpLRFbPf4SfHXrktzDh7Q5iggl6Skzf1M0bPlIxARw==", + "requires": { + "@ember/edition-utils": "^1.2.0", + "babel-plugin-htmlbars-inline-precompile": "^3.2.0", + "broccoli-debug": "^0.6.5", + "broccoli-persistent-filter": "^2.3.1", + "broccoli-plugin": "^3.1.0", + "common-tags": "^1.8.0", + "ember-cli-babel-plugin-helpers": "^1.1.0", + "fs-tree-diff": "^2.0.1", + "hash-for-dep": "^1.5.1", + "heimdalljs-logger": "^0.1.10", + "json-stable-stringify": "^1.0.1", + "semver": "^6.3.0", + "strip-bom": "^4.0.0", + "walk-sync": "^2.0.2" + } + }, + "fs-tree-diff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-2.0.1.tgz", + "integrity": "sha512-x+CfAZ/lJHQqwlD64pYM5QxWjzWhSjroaVsr8PW831zOApL55qPibed0c+xebaLWVr2BnHFoHdrwOv8pzt8R5A==", + "requires": { + "@types/symlink-or-copy": "^1.2.0", + "heimdalljs-logger": "^0.1.7", + "object-assign": "^4.1.0", + "path-posix": "^1.0.0", + "symlink-or-copy": "^1.1.8" + } + }, + "matcher-collection": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-2.0.1.tgz", + "integrity": "sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ==", + "requires": { + "@types/minimatch": "^3.0.3", + "minimatch": "^3.0.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" + }, + "walk-sync": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-2.2.0.tgz", + "integrity": "sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==", + "requires": { + "@types/minimatch": "^3.0.3", + "ensure-posix-path": "^1.1.0", + "matcher-collection": "^2.0.0", + "minimatch": "^3.0.4" + } + } + } + }, "ember-copy": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ember-copy/-/ember-copy-2.0.1.tgz", @@ -13591,6 +13689,7 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/ember-maybe-import-regenerator/-/ember-maybe-import-regenerator-0.1.6.tgz", "integrity": "sha1-NdQYKK+m1qWbwNo85H80xXPXdso=", + "dev": true, "requires": { "broccoli-funnel": "^1.0.1", "broccoli-merge-trees": "^1.0.0", @@ -13602,6 +13701,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz", "integrity": "sha512-hlSTWGS1t6/xq5YCed7YALg7tKZL3rkl7UwEZ/eCIkn8JxmM6fU6Qs/1hwtjQqfuYxlffuUcgYEm0f5xP4YKaA==", + "dev": true, "requires": { "ensure-posix-path": "^1.0.1" } @@ -13610,6 +13710,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0.tgz", "integrity": "sha512-Wpmw4TbhR3Eq2t3W51eBAQSdKlr+uAyF0GI4GtPfMCD12Y4cIdpKC9l0RjNTH/P9isFypSqqewMPm7//fnZlNA==", + "dev": true, "requires": { "semver": "^5.3.0" } @@ -13618,6 +13719,7 @@ "version": "2.13.4", "resolved": "https://registry.npmjs.org/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.13.4.tgz", "integrity": "sha512-uxQPkEQAzCYdwhZk16O9m1R4xtCRNy4oEUTBrccOPfzlIahRZJic/JeP/ZEL0BC6Mfq6r55eOg6gMF/zdFoCvA==", + "dev": true, "requires": { "ember-rfc176-data": "^0.3.13" } @@ -13626,6 +13728,7 @@ "version": "6.5.1", "resolved": "https://registry.npmjs.org/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.1.tgz", "integrity": "sha512-w6GcnkxvHcNCte5FcLGEG1hUdQvlfvSN/6PtGWU/otg69Ugk8rUk51h41R0Ugoc+TNxyeFG1opRt2RlA87XzNw==", + "dev": true, "requires": { "babel-core": "^6.26.0", "broccoli-funnel": "^2.0.1", @@ -13643,6 +13746,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-2.0.2.tgz", "integrity": "sha512-/vDTqtv7ipjEZQOVqO4vGDVAOZyuYzQ/EgGoyewfOgh1M7IQAToBKZI0oAQPgMBeFPPlIbfMuAngk+ohPBuaHQ==", + "dev": true, "requires": { "array-equal": "^1.0.0", "blank-object": "^1.0.1", @@ -13663,6 +13767,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-2.0.1.tgz", "integrity": "sha512-WjaexJ+I8BxP5V5RNn6um/qDRSmKoiBC/QkRi79FT9ClHfldxRyCDs9mcV7mmoaPlsshmmPaUz5jdtcKA6DClQ==", + "dev": true, "requires": { "broccoli-plugin": "^1.3.0", "merge-trees": "^1.0.1" @@ -13674,6 +13779,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz", "integrity": "sha1-zdw6/F/xaFqAI0iP/3TOb7WlEpY=", + "dev": true, "requires": { "array-equal": "^1.0.0", "blank-object": "^1.0.1", @@ -13695,6 +13801,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz", "integrity": "sha1-oAFRm7UGfwZYnZGvopQkRaLQ/bU=", + "dev": true, "requires": { "broccoli-plugin": "^1.3.0", "can-symlink": "^1.0.0", @@ -13710,6 +13817,7 @@ "version": "1.4.6", "resolved": "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.6.tgz", "integrity": "sha512-0RejLwoC95kv4kta8KAa+FmECJCK78Qgm8SRDEK7YyU0N9Cx6KpY3UCDy9WELl3mCXLN8TokNxc7/hp3lL4lfw==", + "dev": true, "requires": { "async-disk-cache": "^1.2.1", "async-promise-queue": "^1.0.3", @@ -13729,19 +13837,22 @@ "rsvp": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", - "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==" + "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", + "dev": true } } }, "broccoli-source": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/broccoli-source/-/broccoli-source-1.1.0.tgz", - "integrity": "sha1-VPDoLItz9GWAy7xPV48LMvyo+Ak=" + "integrity": "sha1-VPDoLItz9GWAy7xPV48LMvyo+Ak=", + "dev": true }, "ember-cli-babel": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.18.0.tgz", "integrity": "sha512-7ceC8joNYxY2wES16iIBlbPSxwKDBhYwC8drU3ZEvuPDMwVv1KzxCNu1fvxyFEBWhwaRNTUxSCsEVoTd9nosGA==", + "dev": true, "requires": { "amd-name-resolver": "1.2.0", "babel-plugin-debug-macros": "^0.2.0-beta.6", @@ -13762,6 +13873,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/broccoli-funnel/-/broccoli-funnel-2.0.2.tgz", "integrity": "sha512-/vDTqtv7ipjEZQOVqO4vGDVAOZyuYzQ/EgGoyewfOgh1M7IQAToBKZI0oAQPgMBeFPPlIbfMuAngk+ohPBuaHQ==", + "dev": true, "requires": { "array-equal": "^1.0.0", "blank-object": "^1.0.1", @@ -13784,6 +13896,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-2.2.0.tgz", "integrity": "sha512-G+KtYIVlSOWGcNaTFHk76xR4GdzDLzAS4uxZUKdASuFX0KJE43C6DaqL+y3VTpUFLI2FIkAS6HZ4I1YBi+S3hg==", + "dev": true, "requires": { "resolve": "^1.3.3", "semver": "^5.3.0" @@ -13793,6 +13906,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-trees/-/merge-trees-1.0.1.tgz", "integrity": "sha1-zL5nRWl4f53vF/1G5lJfVwC70j4=", + "dev": true, "requires": { "can-symlink": "^1.0.0", "fs-tree-diff": "^0.5.4", @@ -13805,17 +13919,20 @@ "regenerator-runtime": { "version": "0.9.6", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz", - "integrity": "sha1-0z65XQ0gAaS+OWWXB8UbDLcc4Ck=" + "integrity": "sha1-0z65XQ0gAaS+OWWXB8UbDLcc4Ck=", + "dev": true }, "rsvp": { "version": "4.8.5", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==" + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true }, "workerpool": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-2.3.3.tgz", "integrity": "sha512-L1ovlYHp6UObYqElXXpbd214GgbEKDED0d3sj7pRdFXjNkb2+un/AUcCkceHizO0IVI6SOGGncrcjozruCkRgA==", + "dev": true, "requires": { "object-assign": "4.1.1" } @@ -18297,7 +18414,8 @@ "exists-sync": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/exists-sync/-/exists-sync-0.0.4.tgz", - "integrity": "sha1-l0TCxCjMA7AQYNtFTUsS8O88iHk=" + "integrity": "sha1-l0TCxCjMA7AQYNtFTUsS8O88iHk=", + "dev": true }, "exit": { "version": "0.1.2", @@ -25600,9 +25718,9 @@ } }, "typescript": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", - "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "dev": true }, "typescript-memoize": { diff --git a/packages/dashboards/package.json b/packages/dashboards/package.json index 094908e32..3592784cb 100644 --- a/packages/dashboards/package.json +++ b/packages/dashboards/package.json @@ -34,10 +34,11 @@ "ember-cli-babel": "^7.17.2", "ember-cli-htmlbars": "^5.1.2", "ember-cli-moment-shim": "^3.8.0", - "ember-cli-typescript": "^4.0.0", + "ember-cli-typescript": "^4.1.0", "ember-collection": "1.0.0-alpha.9", "ember-composable-helpers": "^4.1.1", - "ember-concurrency": "1.3.0", + "ember-concurrency": "2.0.3", + "ember-concurrency-ts": "0.2.2", "ember-cp-validations": "^4.0.0-beta.10", "ember-data-model-fragments": "^5.0.0-beta.1", "ember-get-config": "0.2.4", @@ -116,7 +117,7 @@ "npm-run-all": "^4.1.5", "qunit-dom": "^1.0.0", "sass": "^1.30.0", - "typescript": "^3.9.5" + "typescript": "^4.1.5" }, "engines": { "node": "10.* || >= 12" diff --git a/packages/dashboards/tests/unit/services/dashboard-data-test.js b/packages/dashboards/tests/unit/services/dashboard-data-test.js index 7b578edcf..d1a0179bd 100644 --- a/packages/dashboards/tests/unit/services/dashboard-data-test.js +++ b/packages/dashboards/tests/unit/services/dashboard-data-test.js @@ -110,7 +110,11 @@ module('Unit | Service | dashboard data', function (hooks) { data = service.fetchDataForWidgets(1, widgets, layout); - assert.equal(service._fetchRequestsForWidget.concurrency, 2, 'fetch task concurrency is correctly set by config'); + assert.equal( + service._fetchRequest.scheduler.schedulerPolicy.maxConcurrency, + 2, + 'fetch task concurrency is correctly set by config' + ); assert.deepEqual(Object.keys(data), ['1', '2', '3'], 'data is keyed by widget id'); assert.ok(get(data, '1.isRunning'), 'data returns a task instance per widget'); diff --git a/packages/data/addon/adapters/dimensions/bard.ts b/packages/data/addon/adapters/dimensions/bard.ts index dda233b08..82682ae93 100644 --- a/packages/data/addon/adapters/dimensions/bard.ts +++ b/packages/data/addon/adapters/dimensions/bard.ts @@ -1,20 +1,24 @@ /** - * Copyright 2020, Yahoo Holdings Inc. + * Copyright 2021, Yahoo Holdings Inc. * Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms. * * Description: The adapter for the Bard dimension model. */ - -import { inject as service } from '@ember/service'; import EmberObject from '@ember/object'; +import { inject as service } from '@ember/service'; import { configHost } from '../../utils/adapter'; import { serializeFilters } from '../facts/bard'; -import { Filter } from '../facts/interface'; -import NaviMetadataService from 'navi-data/services/navi-metadata'; -import NaviDimensionAdapter, { DimensionFilter } from './interface'; -import { ServiceOptions } from 'navi-data/services/navi-dimension'; -import DimensionMetadataModel, { DimensionColumn } from 'navi-data/models/metadata/dimension'; import { getDefaultDataSourceName } from 'navi-data/utils/adapter'; +import { task } from 'ember-concurrency'; +import { taskFor } from 'ember-concurrency-ts'; +import type { TaskGenerator } from 'ember-concurrency'; +import type { Filter } from '../facts/interface'; +import type NaviMetadataService from 'navi-data/services/navi-metadata'; +import type NaviDimensionAdapter from './interface'; +import type { DimensionFilter } from './interface'; +import type { ServiceOptions } from 'navi-data/services/navi-dimension'; +import type DimensionMetadataModel from 'navi-data/models/metadata/dimension'; +import type { DimensionColumn } from 'navi-data/models/metadata/dimension'; const SUPPORTED_FILTER_OPERATORS = ['in', 'notin', 'startswith', 'contains']; @@ -32,6 +36,7 @@ type LegacyAdapterOptions = { export type FiliDimensionResponse = { rows: Record[]; + meta?: Record; }; export const DefaultField = 'id'; @@ -117,32 +122,40 @@ export default class BardDimensionAdapter extends EmberObject implements NaviDim }); } - all(dimension: DimensionColumn, options: ServiceOptions = {}): Promise { - return this.find(dimension, [], options); + @task *all(dimension: DimensionColumn, options: ServiceOptions = {}): TaskGenerator { + return yield taskFor(this.find).perform(dimension, [], options); } - findById(dimensionName: string, value: string, options: LegacyAdapterOptions) { + @task *findById( + dimensionName: string, + value: string, + options: LegacyAdapterOptions + ): TaskGenerator { const columnMetadata = this.naviMetadata.getById( 'dimension', dimensionName, options.dataSourceName || getDefaultDataSourceName() ) as DimensionMetadataModel; - return this.find({ columnMetadata }, [{ operator: 'in', values: [value] }], options); + return yield taskFor(this.find).perform({ columnMetadata }, [{ operator: 'in', values: [value] }], options); } - find( + @task *find( dimension: DimensionColumn, predicate: DimensionFilter[] = [], options: ServiceOptions = {} - ): Promise { + ): TaskGenerator { const url = this._buildUrl(dimension, undefined); const data = predicate ? this._buildFilterQuery(dimension, predicate) : {}; - return this._find(url, data, options); + return yield this._find(url, data, options); } - search(dimension: DimensionColumn, query: string, options: ServiceOptions = {}): Promise { + @task *search( + dimension: DimensionColumn, + query: string, + options: ServiceOptions = {} + ): TaskGenerator { const url = this._buildUrl(dimension, 'search'); const data: Record = query ? { query } : {}; - return this._find(url, data, options); + return yield this._find(url, data, options); } } diff --git a/packages/data/addon/adapters/dimensions/elide.ts b/packages/data/addon/adapters/dimensions/elide.ts index f6e15475b..bbf18e71b 100644 --- a/packages/data/addon/adapters/dimensions/elide.ts +++ b/packages/data/addon/adapters/dimensions/elide.ts @@ -7,7 +7,11 @@ import EmberObject from '@ember/object'; import { getOwner } from '@ember/application'; import { assert } from '@ember/debug'; -import { AsyncQueryResponse, FilterOperator, QueryStatus, RequestV2 } from '../facts/interface'; +import { QueryStatus } from '../facts/interface'; +import { task } from 'ember-concurrency'; +import { taskFor } from 'ember-concurrency-ts'; +import type { TaskGenerator } from 'ember-concurrency'; +import type { AsyncQueryResponse, FilterOperator, RequestV2 } from '../facts/interface'; import type NaviDimensionAdapter from './interface'; import type { DimensionFilter } from './interface'; import type { ServiceOptions } from 'navi-data/services/navi-dimension'; @@ -30,12 +34,15 @@ export default class ElideDimensionAdapter extends EmberObject implements NaviDi */ private factAdapter: ElideFactsAdapter = getOwner(this).lookup('adapter:facts/elide'); - private formatEnumResponse(dimension: DimensionColumn, values: (string | number)[]): AsyncQueryResponse { + @task private *formatEnumResponse( + dimension: DimensionColumn, + values: (string | number)[] + ): TaskGenerator { const { tableId } = dimension.columnMetadata; const nodes = values.map((value) => `{"node":{"col0":"${value}"}}`); const responseBody = `{"data":{"${tableId}":{"edges":[${nodes.join(',')}]}}}`; - return { + return yield { asyncQuery: { edges: [ { @@ -56,27 +63,27 @@ export default class ElideDimensionAdapter extends EmberObject implements NaviDi }; } - all(dimension: DimensionColumn, options: ServiceOptions = {}): Promise { - return this.find(dimension, [], options); + @task *all(dimension: DimensionColumn, options: ServiceOptions = {}): TaskGenerator { + return yield taskFor(this.find).perform(dimension, [], options); } - async find( + @task *find( dimension: DimensionColumn, predicate: DimensionFilter[] = [], options: ServiceOptions = {} - ): Promise { + ): TaskGenerator { const columnMetadata = dimension.columnMetadata as ElideDimensionMetadataModel; return columnMetadata.hasEnumValues - ? this.findEnum(dimension, predicate, options) - : this.findRequest(dimension, predicate, options); + ? yield taskFor(this.findEnum).perform(dimension, predicate, options) + : yield taskFor(this.findRequest).perform(dimension, predicate, options); } - private findEnum( + @task private *findEnum( dimension: DimensionColumn, predicate: DimensionFilter[], _options: ServiceOptions - ): AsyncQueryResponse { + ): TaskGenerator { const columnMetadata = dimension.columnMetadata as ElideDimensionMetadataModel; const { values } = columnMetadata; @@ -87,14 +94,14 @@ export default class ElideDimensionAdapter extends EmberObject implements NaviDi return filterFn(values, filterValues); }, values); - return this.formatEnumResponse(dimension, filteredValues); + return yield taskFor(this.formatEnumResponse).perform(dimension, filteredValues); } - private findRequest( + @task private *findRequest( dimension: DimensionColumn, predicate: DimensionFilter[] = [], options: ServiceOptions = {} - ): Promise { + ): TaskGenerator { const { columnMetadata, parameters = {} } = dimension; const lookupMetadata = (columnMetadata as ElideDimensionMetadataModel).lookupColumn; const { id, source, tableId } = lookupMetadata; @@ -116,10 +123,14 @@ export default class ElideDimensionAdapter extends EmberObject implements NaviDi requestVersion: '2.0', }; - return this.factAdapter.fetchDataForRequest(request, options); + return yield taskFor(this.factAdapter.fetchDataForRequest).perform(request, options); } - async search(dimension: DimensionColumn, query: string, options: ServiceOptions = {}): Promise { + @task *search( + dimension: DimensionColumn, + query: string, + options: ServiceOptions = {} + ): TaskGenerator { const columnMetadata = dimension.columnMetadata as ElideDimensionMetadataModel; let predicate: DimensionFilter[]; @@ -145,7 +156,7 @@ export default class ElideDimensionAdapter extends EmberObject implements NaviDi } return columnMetadata.hasEnumValues - ? this.findEnum(dimension, predicate, options) - : this.findRequest(dimension, predicate, options); + ? yield taskFor(this.findEnum).perform(dimension, predicate, options) + : yield taskFor(this.findRequest).perform(dimension, predicate, options); } } diff --git a/packages/data/addon/adapters/dimensions/interface.ts b/packages/data/addon/adapters/dimensions/interface.ts index c399ba98e..1b764a9c6 100644 --- a/packages/data/addon/adapters/dimensions/interface.ts +++ b/packages/data/addon/adapters/dimensions/interface.ts @@ -1,11 +1,12 @@ /** - * Copyright 2020, Yahoo Holdings Inc. + * Copyright 2021, Yahoo Holdings Inc. * Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms. */ -import { FilterOperator } from '../facts/interface'; import EmberObject from '@ember/object'; -import { ServiceOptions } from 'navi-data/services/navi-dimension'; -import { DimensionColumn } from 'navi-data/models/metadata/dimension'; +import type { FilterOperator } from '../facts/interface'; +import type { ServiceOptions } from 'navi-data/services/navi-dimension'; +import type { TaskGenerator } from 'ember-concurrency'; +import type { DimensionColumn } from 'navi-data/models/metadata/dimension'; export type DimensionFilter = { operator: FilterOperator; @@ -18,7 +19,7 @@ export default interface NaviDimensionAdapter extends EmberObject { * @param dimension - requested dimension * @param options - adapter options */ - all(dimension: DimensionColumn, options?: ServiceOptions): Promise; + all(dimension: DimensionColumn, options?: ServiceOptions): TaskGenerator; /** * Get dimension value for a filter predicate @@ -26,7 +27,7 @@ export default interface NaviDimensionAdapter extends EmberObject { * @param predicate - filter criteria * @param options - adapter options */ - find(dimension: DimensionColumn, predicate: DimensionFilter[], options?: ServiceOptions): Promise; + find(dimension: DimensionColumn, predicate: DimensionFilter[], options?: ServiceOptions): TaskGenerator; /** * Get dimension values for a search string @@ -34,5 +35,5 @@ export default interface NaviDimensionAdapter extends EmberObject { * @param query - query string * @param options - adapter options */ - search(dimension: DimensionColumn, query: string, options?: ServiceOptions): Promise; + search(dimension: DimensionColumn, query: string, options?: ServiceOptions): TaskGenerator; } diff --git a/packages/data/addon/adapters/facts/bard.ts b/packages/data/addon/adapters/facts/bard.ts index e967fb002..a0a1f2cfa 100644 --- a/packages/data/addon/adapters/facts/bard.ts +++ b/packages/data/addon/adapters/facts/bard.ts @@ -22,12 +22,14 @@ import NaviFactAdapter, { FactAdapterError, } from './interface'; import { omit } from 'lodash-es'; -import NaviMetadataService from 'navi-data/services/navi-metadata'; -import BardTableMetadataModel from 'navi-data/models/metadata/bard/table'; -import { GrainWithAll } from 'navi-data/serializers/metadata/bard'; import { getPeriodForGrain, Grain } from 'navi-data/utils/date'; import moment from 'moment'; import config from 'ember-get-config'; +import { task } from 'ember-concurrency'; +import type NaviMetadataService from 'navi-data/services/navi-metadata'; +import type BardTableMetadataModel from 'navi-data/models/metadata/bard/table'; +import type { GrainWithAll } from 'navi-data/serializers/metadata/bard'; +import type { TaskGenerator } from 'ember-concurrency'; export type Query = RequestOptions & Dict; @@ -332,8 +334,8 @@ export default class BardFactsAdapter extends EmberObject implements NaviFactAda /** * Returns URL String for a request */ - async urlForDownloadQuery(request: RequestV2, options?: RequestOptions): Promise { - return this.urlForFindQuery(request, options); + @task *urlForDownloadQuery(request: RequestV2, options?: RequestOptions): TaskGenerator { + return yield this.urlForFindQuery(request, options); } /** * @property requestDecorator @@ -350,7 +352,7 @@ export default class BardFactsAdapter extends EmberObject implements NaviFactAda /** * Uses the url generated using the adapter to make an ajax request */ - fetchDataForRequest(request: RequestV2, options?: RequestOptions): Promise { + @task *fetchDataForRequest(request: RequestV2, options?: RequestOptions): TaskGenerator { assert('Fact request for fili adapter must be version 2', (request.requestVersion || '').startsWith('2.')); // Decorate and translate the request @@ -376,7 +378,8 @@ export default class BardFactsAdapter extends EmberObject implements NaviFactAda customHeaders = options.customHeaders; } - return this.ajax.request(url, { + // TODO: Drop bard request on cancel https://github.com/yavin-dev/framework/issues/1340 + return yield this.ajax.request(url, { xhrFields: { withCredentials: true, }, diff --git a/packages/data/addon/adapters/facts/elide.ts b/packages/data/addon/adapters/facts/elide.ts index 190bb4342..0128bf1e5 100644 --- a/packages/data/addon/adapters/facts/elide.ts +++ b/packages/data/addon/adapters/facts/elide.ts @@ -4,35 +4,39 @@ */ import EmberObject from '@ember/object'; import { queryManager } from 'ember-apollo-client'; -import NaviFactAdapter, { +import NaviFactAdapter, { QueryStatus, FactAdapterError } from './interface'; +import { assert } from '@ember/debug'; +import { inject as service } from '@ember/service'; +import Interval from '../../utils/classes/interval'; +import { getDefaultDataSource } from '../../utils/adapter'; +import GQLQueries from 'navi-data/gql/fact-queries'; +import { task, timeout } from 'ember-concurrency'; +import { taskFor } from 'ember-concurrency-ts'; +import { v1 } from 'ember-uuid'; +import moment from 'moment'; +import { canonicalizeMetric } from 'navi-data/utils/metric'; +import { omitBy } from 'lodash-es'; +import type { RequestV1, RequestOptions, AsyncQueryResponse, Parameters, - QueryStatus, RequestV2, FilterOperator, Filter, - FactAdapterError, Column, Sort, } from './interface'; -import { assert } from '@ember/debug'; -import { inject as service } from '@ember/service'; -import Interval from '../../utils/classes/interval'; -import { getDefaultDataSource } from '../../utils/adapter'; -import { DocumentNode } from 'graphql'; -import GQLQueries from 'navi-data/gql/fact-queries'; -import { task, timeout } from 'ember-concurrency'; -import { v1 } from 'ember-uuid'; -import moment, { Moment } from 'moment'; -import { Grain } from 'navi-data/utils/date'; -import { canonicalizeMetric } from 'navi-data/utils/metric'; -import NaviMetadataService from 'navi-data/services/navi-metadata'; -import { omitBy } from 'lodash-es'; +import type { DocumentNode } from 'graphql'; +import type { Moment } from 'moment'; +import type { Grain } from 'navi-data/utils/date'; +import type NaviMetadataService from 'navi-data/services/navi-metadata'; +import type { TaskGenerator } from 'ember-concurrency'; const escape = (value: string) => value.replace(/'/g, "\\\\'"); +const DEFAULT_ASYNC_AFTER_SECONDS = 2; + /** * Formats elide request field as `col(param1:"val1", param2:"val2")` */ @@ -226,11 +230,12 @@ export default class ElideFactsAdapter extends EmberObject implements NaviFactAd createAsyncQuery(request: RequestV2, options: RequestOptions = {}): Promise { const mutation: DocumentNode = GQLQueries['asyncFactsMutation']; const query = this.dataQueryFromRequest(request); + const asyncAfterSeconds = DEFAULT_ASYNC_AFTER_SECONDS; const id: string = options.requestId || v1(); const dataSourceName = request.dataSource || options.dataSourceName; // TODO: Add other options based on RequestOptions - const queryOptions = { mutation, variables: { id, query }, context: { dataSourceName } }; + const queryOptions = { mutation, variables: { id, query, asyncAfterSeconds }, context: { dataSourceName } }; return this.apollo.mutate(queryOptions); } @@ -266,40 +271,49 @@ export default class ElideFactsAdapter extends EmberObject implements NaviFactAd * @param _request * @param _options */ - async urlForDownloadQuery(_request: RequestV1, _options: RequestOptions): Promise { - return 'TODO'; + @task *urlForDownloadQuery(_request: RequestV1, _options: RequestOptions): TaskGenerator { + return yield 'TODO'; } /** * @param request * @param options */ - @task(function* (this: ElideFactsAdapter, request: RequestV2, options: RequestOptions) { + @task *fetchDataForRequestTask( + this: ElideFactsAdapter, + request: RequestV2, + options: RequestOptions + ): TaskGenerator { let asyncQueryPayload = yield this.createAsyncQuery(request, options); const asyncQuery = asyncQueryPayload?.asyncQuery.edges[0]?.node; - const { id } = asyncQuery; + let id = asyncQuery.id; let status: QueryStatus = asyncQuery.status; - while (status === QueryStatus.QUEUED || status === QueryStatus.PROCESSING) { - yield timeout(this._pollingInterval); - asyncQueryPayload = yield this.fetchAsyncQuery(id, request.dataSource); - status = asyncQueryPayload?.asyncQuery.edges[0]?.node.status; + try { + while (status === QueryStatus.QUEUED || status === QueryStatus.PROCESSING) { + yield timeout(this._pollingInterval); + asyncQueryPayload = yield this.fetchAsyncQuery(id, request.dataSource); + status = asyncQueryPayload?.asyncQuery.edges[0]?.node.status; + } + return asyncQueryPayload; + } finally { + if (status === QueryStatus.QUEUED || status === QueryStatus.PROCESSING) { + yield this.cancelAsyncQuery(id, request.dataSource); + } } - return asyncQueryPayload; - }) - fetchDataForRequestTask!: TODO; + } /** * @param this * @param request * @param options */ - async fetchDataForRequest( + @task *fetchDataForRequest( this: ElideFactsAdapter, request: RequestV2, options: RequestOptions = {} - ): Promise { - const payload = await this.fetchDataForRequestTask.perform(request, options); - const responseStr = payload?.asyncQuery.edges[0].node.result?.responseBody; + ): TaskGenerator { + const payload: AsyncQueryResponse = yield taskFor(this.fetchDataForRequestTask).perform(request, options); + const responseStr = payload?.asyncQuery.edges[0].node.result?.responseBody || '{}'; const responseBody = JSON.parse(responseStr); if (responseBody.errors) { throw payload; diff --git a/packages/data/addon/adapters/facts/interface.ts b/packages/data/addon/adapters/facts/interface.ts index 58ceb6785..befef9a7e 100644 --- a/packages/data/addon/adapters/facts/interface.ts +++ b/packages/data/addon/adapters/facts/interface.ts @@ -1,10 +1,10 @@ /** - * Copyright 2020, Yahoo Holdings Inc. + * Copyright 2021, Yahoo Holdings Inc. * Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms. */ - import NaviFactsModel from 'navi-data/models/navi-facts'; -import { ColumnType } from 'navi-data/models/metadata/column'; +import type { TaskGenerator } from 'ember-concurrency'; +import type { ColumnType } from 'navi-data/models/metadata/column'; export type RequestV1 = TODO; @@ -128,7 +128,7 @@ export interface AsyncQueryResult { } export default interface NaviFactAdapter { - fetchDataForRequest(request: RequestV1 | RequestV2, options: RequestOptions): Promise; + fetchDataForRequest(request: RequestV1 | RequestV2, options: RequestOptions): TaskGenerator; urlForFindQuery(request: RequestV1 | RequestV2, options: RequestOptions): string; - urlForDownloadQuery(request: RequestV1 | RequestV2, options: RequestOptions): Promise; + urlForDownloadQuery(request: RequestV1 | RequestV2, options: RequestOptions): TaskGenerator; } diff --git a/packages/data/addon/gql/mutations/async-facts-cancel.ts b/packages/data/addon/gql/mutations/async-facts-cancel.ts index ca905f41c..8d3fabc90 100644 --- a/packages/data/addon/gql/mutations/async-facts-cancel.ts +++ b/packages/data/addon/gql/mutations/async-facts-cancel.ts @@ -1,19 +1,21 @@ /** - * Copyright 2020, Yahoo Holdings Inc. + * Copyright 2021, Yahoo Holdings Inc. * Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms. */ import gql from 'graphql-tag'; -export const asyncFactsCancelMutationStr = `mutation($id: String) { - asyncQuery(op: UPDATE, ids: [$id], data: { status: CANCELLED }) { - edges { - node { - id - status +export const asyncFactsCancelMutationStr = ` + mutation($id: ID) { + asyncQuery(op: UPDATE, data: { id: $id, status: CANCELLED }) { + edges { + node { + id + status + } } } } -}`; +`; const mutation = gql` ${asyncFactsCancelMutationStr} diff --git a/packages/data/addon/gql/mutations/async-facts.ts b/packages/data/addon/gql/mutations/async-facts.ts index d125839e2..f75d5eab7 100644 --- a/packages/data/addon/gql/mutations/async-facts.ts +++ b/packages/data/addon/gql/mutations/async-facts.ts @@ -1,12 +1,12 @@ /** - * Copyright 2020, Yahoo Holdings Inc. + * Copyright 2021, Yahoo Holdings Inc. * Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms. */ import gql from 'graphql-tag'; export const asyncFactsMutationStr = ` - mutation($id: ID, $query: String) { - asyncQuery(op: UPSERT, data: { id: $id, query: $query, queryType: GRAPHQL_V1_0, status: QUEUED }) { + mutation($id: ID, $query: String, $asyncAfterSeconds: Int) { + asyncQuery(op: UPSERT, data: { id: $id, query: $query, queryType: GRAPHQL_V1_0, status: QUEUED, asyncAfterSeconds: $asyncAfterSeconds }) { edges { node { id diff --git a/packages/data/addon/models/navi-facts.ts b/packages/data/addon/models/navi-facts.ts index 4ebf508a5..735871b13 100644 --- a/packages/data/addon/models/navi-facts.ts +++ b/packages/data/addon/models/navi-facts.ts @@ -9,6 +9,7 @@ import EmberObject from '@ember/object'; import type NaviFactsService from 'navi-data/services/navi-facts'; import type { RequestV2 } from 'navi-data/adapters/facts/interface'; import type NaviFactResponse from './navi-fact-response'; +import { taskFor } from 'ember-concurrency-ts'; export default class NaviFacts extends EmberObject { /** @@ -29,14 +30,14 @@ export default class NaviFacts extends EmberObject { /** * @returns Promise with the response model object for next page or null when trying to go past last page */ - next(): Promise | null { - return this._factService.fetchNext(this.response, this.request); + next(): Promise { + return taskFor(this._factService.fetchNext).perform(this.response, this.request); } /** * @returns Promise with the response model object for previous page or null when trying to access pages less than the first page */ - previous(): Promise | null { - return this._factService.fetchPrevious(this.response, this.request); + previous(): Promise { + return taskFor(this._factService.fetchNext).perform(this.response, this.request); } } diff --git a/packages/data/addon/services/bard-dimensions.ts b/packages/data/addon/services/bard-dimensions.ts index 11866fd73..3311ca02f 100644 --- a/packages/data/addon/services/bard-dimensions.ts +++ b/packages/data/addon/services/bard-dimensions.ts @@ -1,5 +1,5 @@ /** - * Copyright 2020, Yahoo Holdings Inc. + * Copyright 2021, Yahoo Holdings Inc. * Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms. * * Description: Bard dimensions service that fetches dimension values @@ -21,6 +21,7 @@ import BardDimensionAdapter from 'navi-data/adapters/dimensions/bard'; import { FiliDimensionResponse } from 'navi-data/adapters/dimensions/bard'; import DimensionMetadataModel from 'navi-data/models/metadata/dimension'; import { FilterOperator } from 'navi-data/adapters/facts/interface'; +import { taskFor } from 'ember-concurrency-ts'; const SEARCH_OPERATOR_PRIORITY = ['contains', 'in']; @@ -109,18 +110,20 @@ export default class BardDimensionService extends Service { dimension, options.dataSourceName || getDefaultDataSourceName() ) as DimensionMetadataModel; - return bardAdapter.all({ columnMetadata }, options).then((recordsFromBard: TODO) => { - const serialized = recordsFromBard?.rows; - const dimensions = kegAdapter.pushMany(dimension, serialized, options); - - // Fili provides pagination metadata only when data is partially fetched - const isPartiallyLoaded = recordsFromBard.meta?.pagination; - if (!isPartiallyLoaded) { - this._setLoadedStatus(dimension); - } - - return this._createBardDimensionsArray(recordsFromBard, dimensions, dimension); - }); + return taskFor(bardAdapter.all) + .perform({ columnMetadata }, options) + .then((recordsFromBard: FiliDimensionResponse) => { + const serialized = recordsFromBard?.rows; + const dimensions = kegAdapter.pushMany(dimension, serialized, options); + + // Fili provides pagination metadata only when data is partially fetched + const isPartiallyLoaded = recordsFromBard.meta?.pagination; + if (!isPartiallyLoaded) { + this._setLoadedStatus(dimension); + } + + return this._createBardDimensionsArray(recordsFromBard, dimensions, dimension); + }); } /** @@ -170,11 +173,13 @@ export default class BardDimensionService extends Service { dimension, options.dataSourceName || getDefaultDataSourceName() ) as DimensionMetadataModel; - return bardAdapter.find({ columnMetadata }, andQueries, options).then((recordsFromBard: TODO) => { - const serialized = recordsFromBard?.rows; - const dimensions = kegAdapter.pushMany(dimension, serialized, options); - return this._createBardDimensionsArray(recordsFromBard, dimensions, dimension); - }); + return taskFor(bardAdapter.find) + .perform({ columnMetadata }, andQueries, options) + .then((recordsFromBard: TODO) => { + const serialized = recordsFromBard?.rows; + const dimensions = kegAdapter.pushMany(dimension, serialized, options); + return this._createBardDimensionsArray(recordsFromBard, dimensions, dimension); + }); } /** @@ -203,10 +208,12 @@ export default class BardDimensionService extends Service { if (!isEmpty(recordFromKeg)) { return recordFromKeg; } else { - return bardAdapter.findById(dimension, value, options).then((recordsFromBard: TODO) => { - const serialized = recordsFromBard?.rows; - return kegAdapter.pushMany(dimension, serialized, options).firstObject; - }); + return taskFor(bardAdapter.findById) + .perform(dimension, value, options) + .then((recordsFromBard: TODO) => { + const serialized = recordsFromBard?.rows; + return kegAdapter.pushMany(dimension, serialized, options).firstObject; + }); } }); } @@ -283,7 +290,7 @@ export default class BardDimensionService extends Service { dimension, options.dataSourceName || getDefaultDataSourceName() ) as DimensionMetadataModel; - return bardAdapter.find({ columnMetadata, parameters: { field } }, andFilters, options); + return taskFor(bardAdapter.find).perform({ columnMetadata, parameters: { field } }, andFilters, options); } /** @@ -301,7 +308,7 @@ export default class BardDimensionService extends Service { dimension, options.dataSourceName || getDefaultDataSourceName() ) as DimensionMetadataModel; - return this._bardAdapter.search({ columnMetadata }, query, options); + return taskFor(this._bardAdapter.search).perform({ columnMetadata }, query, options); } /** diff --git a/packages/data/addon/services/navi-dimension.ts b/packages/data/addon/services/navi-dimension.ts index da55c4e18..d7daea638 100644 --- a/packages/data/addon/services/navi-dimension.ts +++ b/packages/data/addon/services/navi-dimension.ts @@ -1,14 +1,18 @@ /** - * Copyright 2020, Yahoo Holdings Inc. + * Copyright 2021, Yahoo Holdings Inc. * Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms. */ import Service from '@ember/service'; -import NaviDimensionSerializer from 'navi-data/serializers/dimensions/interface'; -import NaviDimensionAdapter, { DimensionFilter } from 'navi-data/adapters/dimensions/interface'; +import { task } from 'ember-concurrency'; import { getOwner } from '@ember/application'; import { getDataSource } from 'navi-data/utils/adapter'; -import NaviDimensionModel from 'navi-data/models/navi-dimension'; -import { DimensionColumn } from 'navi-data/models/metadata/dimension'; +import { taskFor } from 'ember-concurrency-ts'; +import type { TaskGenerator } from 'ember-concurrency'; +import type NaviDimensionSerializer from 'navi-data/serializers/dimensions/interface'; +import type NaviDimensionAdapter from 'navi-data/adapters/dimensions/interface'; +import type { DimensionFilter } from 'navi-data/adapters/dimensions/interface'; +import type NaviDimensionModel from 'navi-data/models/navi-dimension'; +import type { DimensionColumn } from 'navi-data/models/metadata/dimension'; export type ServiceOptions = { timeout?: number; @@ -39,9 +43,10 @@ export default class NaviDimensionService extends Service { * @param dimension - requested dimension * @param options - method options */ - async all(dimension: DimensionColumn, options?: ServiceOptions): Promise { + @task *all(dimension: DimensionColumn, options?: ServiceOptions): TaskGenerator { const { type: dataSourceType } = getDataSource(dimension.columnMetadata.source); - const payload = await this.adapterFor(dataSourceType).all(dimension, options); + const adapter = this.adapterFor(dataSourceType); + const payload: unknown = yield taskFor(adapter.all).perform(dimension, options); return this.serializerFor(dataSourceType).normalize(dimension, payload); } @@ -51,13 +56,14 @@ export default class NaviDimensionService extends Service { * @param predicate - filter criteria * @param options - method options */ - async find( + @task *find( dimension: DimensionColumn, predicate: DimensionFilter[], options?: ServiceOptions - ): Promise { + ): TaskGenerator { const { type: dataSourceType } = getDataSource(dimension.columnMetadata.source); - const payload = await this.adapterFor(dataSourceType).find(dimension, predicate, options); + const adapter = this.adapterFor(dataSourceType); + const payload: unknown = yield taskFor(adapter.find).perform(dimension, predicate, options); return this.serializerFor(dataSourceType).normalize(dimension, payload); } @@ -67,9 +73,14 @@ export default class NaviDimensionService extends Service { * @param query - query string * @param options - method options */ - async search(dimension: DimensionColumn, query: string, options?: ServiceOptions): Promise { + @task *search( + dimension: DimensionColumn, + query: string, + options?: ServiceOptions + ): TaskGenerator { const { type: dataSourceType } = getDataSource(dimension.columnMetadata.source); - const payload = await this.adapterFor(dataSourceType).search(dimension, query, options); + const adapter = this.adapterFor(dataSourceType); + const payload: unknown = yield taskFor(adapter.search).perform(dimension, query, options); return this.serializerFor(dataSourceType).normalize(dimension, payload); } } diff --git a/packages/data/addon/services/navi-facts.ts b/packages/data/addon/services/navi-facts.ts index c251ad132..a57ac36c2 100644 --- a/packages/data/addon/services/navi-facts.ts +++ b/packages/data/addon/services/navi-facts.ts @@ -1,35 +1,35 @@ /** - * Copyright 2020, Yahoo Holdings Inc. + * Copyright 2021, Yahoo Holdings Inc. * Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms. * - * Description: Bard facts service that executes and delivers the results + * Description: Navi facts service that executes and delivers the results */ - import Service from '@ember/service'; import { getOwner } from '@ember/application'; +import { getDataSource, getDefaultDataSource } from 'navi-data/utils/adapter'; import NaviFactsModel from 'navi-data/models/navi-facts'; //@ts-ignore import RequestBuilder from 'navi-data/builder/request'; -import NaviFactAdapter, { RequestOptions, RequestV2 } from 'navi-data/adapters/facts/interface'; -import NaviFactSerializer, { ResponseV1 } from 'navi-data/serializers/facts/interface'; -import { getDataSource, getDefaultDataSource } from 'navi-data/utils/adapter'; +import { task } from 'ember-concurrency'; +import { taskFor } from 'ember-concurrency-ts'; +import type { TaskGenerator } from 'ember-concurrency'; +import type NaviFactAdapter from 'navi-data/adapters/facts/interface'; +import type { RequestOptions, RequestV2 } from 'navi-data/adapters/facts/interface'; +import type NaviFactSerializer from 'navi-data/serializers/facts/interface'; +import type { ResponseV1 } from 'navi-data/serializers/facts/interface'; export default class NaviFactsService extends Service { /** - * @method _adapterFor - * - * @param {String} type - * @returns {Adapter} adapter instance for type + * @param type + * @returns adapter instance for type */ _adapterFor(type = 'bard'): NaviFactAdapter { return getOwner(this).lookup(`adapter:facts/${type}`) as NaviFactAdapter; } /** - * @method _serializerFor - * - * @param {String} type - * @returns {Serializer} serializer instance for type + * @param type + * @returns serializer instance for type */ _serializerFor(type = 'bard'): NaviFactSerializer { return getOwner(this).lookup(`serializer:facts/${type}`) as NaviFactSerializer; @@ -38,9 +38,8 @@ export default class NaviFactsService extends Service { /** * Creates a new request builder instance * - * @method request - * @param {Object} baseRequest - existing request to start from - * @returns {Object} request builder interface + * @param baseRequest - existing request to start from + * @returns request builder interface */ request(baseRequest: RequestV2) { // TODO: Fix here @@ -48,10 +47,10 @@ export default class NaviFactsService extends Service { } /** - * @method getURL - Uses the adapter to get the bard query url for the request - * @param {Object} request - request object - * @param {Object} [options] - options object - * @returns {String} - url for the request + * Uses the adapter to get the bard query url for the request + * @param request - request object + * @param options - options object + * @returns url for the request */ getURL(request: RequestV2, options: RequestOptions = {}) { const { type: dataSourceType } = getDataSource(request.dataSource); @@ -66,34 +65,31 @@ export default class NaviFactsService extends Service { } /** - * @method getURL - Uses the adapter to get the download query url for the request - * @param {Object} request - request object - * @param {Object} [options] - options object - * @returns {String} - url for the request + * Uses the adapter to get the download query url for the request + * @param request - request object + * @param options - options object + * @returns - url for the request */ - getDownloadURL(request: RequestV2, options: RequestOptions) { + @task *getDownloadURL(request: RequestV2, options: RequestOptions): TaskGenerator { const { type: dataSourceType } = getDataSource(request.dataSource); const adapter = this._adapterFor(dataSourceType); - return adapter.urlForDownloadQuery(request, options); + return yield taskFor(adapter.urlForDownloadQuery).perform(request, options); } /** - * @method fetch - Returns the bard response model for the request - * @param {Object} request - request object - * @param {Object} [options] - options object - * @param {Number} [options.timeout] - milliseconds to wait before timing out - * @param {String} [options.clientId] - clientId value to be passed as a request header - * @param {Object} [options.customHeaders] - hash of header names and values - * @returns {Promise} - Promise with the bard response model object + * Returns the response model for the request + * @param request - request object + * @param options - options object + * @returns - Promise with the bard response model object */ - async fetch(request: RequestV2, options: RequestOptions = {}): Promise { + @task *fetch(request: RequestV2, options: RequestOptions = {}): TaskGenerator { const dataSourceName = options?.dataSourceName; const type = dataSourceName ? getDataSource(dataSourceName).type : getDefaultDataSource().type; const adapter = this._adapterFor(type); const serializer = this._serializerFor(type); try { - const payload = await adapter.fetchDataForRequest(request, options); + const payload: unknown = yield taskFor(adapter.fetchDataForRequest).perform(request, options); const response = serializer.normalize(payload, request); return NaviFactsModel.create({ request, response, _factService: this }); } catch (e) { @@ -103,18 +99,17 @@ export default class NaviFactsService extends Service { } /** - * @method fetchNext - * @param {Object} response - * @param {Object} request - * @return {Promise|null} returns the promise with the next set of results or null + * @param response + * @param request + * @return returns the promise with the next set of results or null */ - fetchNext(response: ResponseV1, request: RequestV2): Promise | null { + @task *fetchNext(response: ResponseV1, request: RequestV2): TaskGenerator { if (response.meta.pagination) { const { perPage, numberOfResults, currentPage } = response.meta.pagination; const totalPages = numberOfResults / perPage; if (currentPage < totalPages) { - return this.fetch(request, { + return yield taskFor(this.fetch).perform(request, { page: currentPage + 1, perPage: perPage, }); @@ -124,16 +119,15 @@ export default class NaviFactsService extends Service { } /** - * @method fetchPrevious - * @param {Object} response - * @param {Object} request - * @return {Promise|null} returns the promise with the previous set of results or null + * @param response + * @param request + * @return returns the promise with the previous set of results or null */ - fetchPrevious(response: ResponseV1, request: RequestV2): Promise | null { + @task *fetchPrevious(response: ResponseV1, request: RequestV2): TaskGenerator { if (response.meta.pagination) { const { rowsPerPage, currentPage } = response.meta.pagination; if (currentPage > 1) { - return this.fetch(request, { + return yield taskFor(this.fetch).perform(request, { page: currentPage - 1, perPage: rowsPerPage, }); diff --git a/packages/data/package-lock.json b/packages/data/package-lock.json index 559bf27f7..35b338937 100644 --- a/packages/data/package-lock.json +++ b/packages/data/package-lock.json @@ -1764,6 +1764,24 @@ "simple-html-tokenizer": "^0.5.8" } }, + "@glimmer/tracking": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@glimmer/tracking/-/tracking-1.0.4.tgz", + "integrity": "sha512-F+oT8I55ba2puSGIzInmVrv/8QA2PcK1VD+GWgFMhF6WC97D+uZX7BFg+a3s/2N4FVBq5KHE+QxZzgazM151Yw==", + "dev": true, + "requires": { + "@glimmer/env": "^0.1.7", + "@glimmer/validator": "^0.44.0" + }, + "dependencies": { + "@glimmer/validator": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/@glimmer/validator/-/validator-0.44.0.tgz", + "integrity": "sha512-i01plR0EgFVz69GDrEuFgq1NheIjZcyTy3c7q+w7d096ddPVeVcRzU3LKaqCfovvLJ+6lJx40j45ecycASUUyw==", + "dev": true + } + } + }, "@glimmer/util": { "version": "0.42.2", "resolved": "https://registry.npmjs.org/@glimmer/util/-/util-0.42.2.tgz", @@ -10604,14 +10622,143 @@ } }, "ember-concurrency": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-1.3.0.tgz", - "integrity": "sha512-DwGlfWFpYyAkTwsedlEtK4t1DznJSculAW6Vq5S1C0shVPc5b6tTpHB2FFYisannSYkm+wpm1f1Pd40qiNPtOQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-2.0.3.tgz", + "integrity": "sha512-+fOOFt32odnunDL3Du0LqMgnRzDDNKnzo1ry9ppICpvLXekJzYFwU1RniVivfJ+9nbpHMJZQUlZJAm1ZAnTExw==", "dev": true, "requires": { - "ember-cli-babel": "^7.7.3", + "@glimmer/tracking": "^1.0.2", + "ember-cli-babel": "^7.22.1", + "ember-cli-htmlbars": "^5.6.3", "ember-compatibility-helpers": "^1.2.0", - "ember-maybe-import-regenerator": "^0.1.6" + "ember-destroyable-polyfill": "^2.0.2" + } + }, + "ember-concurrency-ts": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ember-concurrency-ts/-/ember-concurrency-ts-0.2.2.tgz", + "integrity": "sha512-03/NEhXczd93tpg0ycusj3bgXZS15wymU0K8eMvWftyzWS4B+UE03RzimOFrtOxJmE2mNj64hLJUZR9P8LelFw==", + "dev": true, + "requires": { + "ember-cli-babel": "^7.19.0", + "ember-cli-htmlbars": "^4.3.1" + }, + "dependencies": { + "babel-plugin-htmlbars-inline-precompile": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-3.2.0.tgz", + "integrity": "sha512-IUeZmgs9tMUGXYu1vfke5I18yYJFldFGdNFQOWslXTnDWXzpwPih7QFduUqvT+awDpDuNtXpdt5JAf43Q1Hhzg==", + "dev": true + }, + "broccoli-output-wrapper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/broccoli-output-wrapper/-/broccoli-output-wrapper-2.0.0.tgz", + "integrity": "sha512-V/ozejo+snzNf75i/a6iTmp71k+rlvqjE3+jYfimuMwR1tjNNRdtfno+NGNQB2An9bIAeqZnKhMDurAznHAdtA==", + "dev": true, + "requires": { + "heimdalljs-logger": "^0.1.10" + } + }, + "broccoli-plugin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-3.1.0.tgz", + "integrity": "sha512-7w7FP8WJYjLvb0eaw27LO678TGGaom++49O1VYIuzjhXjK5kn2+AMlDm7CaUFw4F7CLGoVQeZ84d8gICMJa4lA==", + "dev": true, + "requires": { + "broccoli-node-api": "^1.6.0", + "broccoli-output-wrapper": "^2.0.0", + "fs-merger": "^3.0.1", + "promise-map-series": "^0.2.1", + "quick-temp": "^0.1.3", + "rimraf": "^2.3.4", + "symlink-or-copy": "^1.1.8" + } + }, + "ember-cli-htmlbars": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-4.5.0.tgz", + "integrity": "sha512-bYJpK1pqFu9AadDAGTw05g2LMNzY8xTCIqQm7dMJmKEoUpLRFbPf4SfHXrktzDh7Q5iggl6Skzf1M0bPlIxARw==", + "dev": true, + "requires": { + "@ember/edition-utils": "^1.2.0", + "babel-plugin-htmlbars-inline-precompile": "^3.2.0", + "broccoli-debug": "^0.6.5", + "broccoli-persistent-filter": "^2.3.1", + "broccoli-plugin": "^3.1.0", + "common-tags": "^1.8.0", + "ember-cli-babel-plugin-helpers": "^1.1.0", + "fs-tree-diff": "^2.0.1", + "hash-for-dep": "^1.5.1", + "heimdalljs-logger": "^0.1.10", + "json-stable-stringify": "^1.0.1", + "semver": "^6.3.0", + "strip-bom": "^4.0.0", + "walk-sync": "^2.0.2" + } + }, + "promise-map-series": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.3.tgz", + "integrity": "sha1-wtN3r8kyU/a9A9u3d1XriKsgqEc=", + "dev": true, + "requires": { + "rsvp": "^3.0.14" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + } + } + }, + "ember-destroyable-polyfill": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ember-destroyable-polyfill/-/ember-destroyable-polyfill-2.0.3.tgz", + "integrity": "sha512-TovtNqCumzyAiW0/OisSkkVK93xnVF4NRU6+FN0ubpfwEOpRrmM2RqDwXI6YAChCgSHON1cz0DfQStpA1Gjuuw==", + "dev": true, + "requires": { + "ember-cli-babel": "^7.22.1", + "ember-cli-version-checker": "^5.1.1", + "ember-compatibility-helpers": "^1.2.1" + }, + "dependencies": { + "ember-cli-version-checker": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-5.1.2.tgz", + "integrity": "sha512-rk7GY+FmLn/2e22HsZs0Ycrz8HQ1W3Fv+2TFOuEFW9optnDXDgkntPBIl6gact/LHsfBM5RKbM3dHsIIeLgl0Q==", + "dev": true, + "requires": { + "resolve-package-path": "^3.1.0", + "semver": "^7.3.4", + "silent-error": "^1.1.1" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, "ember-disable-prototype-extensions": { diff --git a/packages/data/package.json b/packages/data/package.json index c6e813f37..7de818804 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -74,7 +74,8 @@ "ember-cli-sri": "^2.1.1", "ember-cli-typescript-blueprints": "^3.0.0", "ember-cli-uglify": "^3.0.0", - "ember-concurrency": "^1.3.0", + "ember-concurrency": "2.0.3", + "ember-concurrency-ts": "0.2.2", "ember-disable-prototype-extensions": "^1.1.3", "ember-export-application-global": "^2.0.1", "ember-fetch": "^8.0.2", diff --git a/packages/data/tests/unit/adapters/dimensions/bard-test.ts b/packages/data/tests/unit/adapters/dimensions/bard-test.ts index b2358302b..688d91b9b 100644 --- a/packages/data/tests/unit/adapters/dimensions/bard-test.ts +++ b/packages/data/tests/unit/adapters/dimensions/bard-test.ts @@ -1,13 +1,15 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; import config from 'ember-get-config'; -import { TestContext as Context } from 'ember-test-helpers'; -import BardDimensionAdapter from 'navi-data/adapters/dimensions/bard'; -import NaviMetadataService from 'navi-data/services/navi-metadata'; -import DimensionMetadataModel from 'navi-data/models/metadata/dimension'; +import { Response } from 'miragejs'; //@ts-ignore import { setupMirage } from 'ember-cli-mirage/test-support'; -import { Server, Response } from 'miragejs'; +import type { TestContext as Context } from 'ember-test-helpers'; +import type BardDimensionAdapter from 'navi-data/adapters/dimensions/bard'; +import type NaviMetadataService from 'navi-data/services/navi-metadata'; +import type DimensionMetadataModel from 'navi-data/models/metadata/dimension'; +import type { Server } from 'miragejs'; +import { taskFor } from 'ember-concurrency-ts'; interface TestContext extends Context { metadataService: NaviMetadataService; @@ -126,7 +128,7 @@ module('Unit | Adapter | Dimensions | Bard', function (hooks) { parameters: { field: 'id' }, }; - const result = await this.adapter.all(containerColumn); + const result = await taskFor(this.adapter.all).perform(containerColumn); assert.deepEqual( result, { @@ -146,7 +148,7 @@ module('Unit | Adapter | Dimensions | Bard', function (hooks) { columnMetadata: this.naviMetadata.getById('dimension', 'container', 'bardTwo') as DimensionMetadataModel, parameters: { field: 'id' }, }; - const result = await this.adapter.find(containerColumn, [{ operator: 'in', values: ['1'] }]); + const result = await taskFor(this.adapter.find).perform(containerColumn, [{ operator: 'in', values: ['1'] }]); assert.deepEqual( result, { @@ -162,7 +164,7 @@ module('Unit | Adapter | Dimensions | Bard', function (hooks) { parameters: { field: 'id' }, }; - const result = await this.adapter.search(containerColumn, 'ag'); + const result = await taskFor(this.adapter.search).perform(containerColumn, 'ag'); assert.deepEqual( result, { @@ -176,7 +178,7 @@ module('Unit | Adapter | Dimensions | Bard', function (hooks) { }); test('findById', async function (this: TestContext, assert) { - const result = await this.adapter.findById('container', '1', { dataSourceName: 'bardTwo' }); + const result = await taskFor(this.adapter.findById).perform('container', '1', { dataSourceName: 'bardTwo' }); assert.deepEqual( result, { @@ -201,7 +203,7 @@ module('Unit | Adapter | Dimensions | Bard', function (hooks) { }); // Sending request for default clientId - await this.adapter.find(ageColumn, [{ operator: 'in', values: ['1'] }]); + await taskFor(this.adapter.find).perform(ageColumn, [{ operator: 'in', values: ['1'] }]); // Setting up assert for provided clientId this.server.get(`${HOST}/v1/dimensions/age/values/`, (_schema, request) => { @@ -210,6 +212,6 @@ module('Unit | Adapter | Dimensions | Bard', function (hooks) { }); // Sending request for provided clientId - await this.adapter.find(ageColumn, [{ operator: 'in', values: ['1'] }], { clientId: 'test id' }); + await taskFor(this.adapter.find).perform(ageColumn, [{ operator: 'in', values: ['1'] }], { clientId: 'test id' }); }); }); diff --git a/packages/data/tests/unit/adapters/dimensions/elide-test.ts b/packages/data/tests/unit/adapters/dimensions/elide-test.ts index 2b3db3b9b..be8e29930 100644 --- a/packages/data/tests/unit/adapters/dimensions/elide-test.ts +++ b/packages/data/tests/unit/adapters/dimensions/elide-test.ts @@ -11,6 +11,8 @@ import ElideTwoScenario from 'navi-data/mirage/scenarios/elide-two'; import { setupMirage } from 'ember-cli-mirage/test-support'; import { Server } from 'miragejs'; import { ResponseEdge } from 'navi-data/serializers/dimensions/elide'; +import { task, TaskGenerator } from 'ember-concurrency'; +import { taskFor } from 'ember-concurrency-ts'; interface TestContext extends Context { metadataService: NaviMetadataService; @@ -23,9 +25,9 @@ function assertRequest(context: TestContext, callback: (request: RequestV2, opti }; const originalFactAdapter = context.owner.factoryFor('adapter:facts/elide').class; class TestAdapter extends originalFactAdapter { - fetchDataForRequest(request: RequestV2, options?: RequestOptions) { + @task *fetchDataForRequest(request: RequestV2, options?: RequestOptions): TaskGenerator { callback(request, options); - return Promise.resolve(fakeResponse); + return yield Promise.resolve(fakeResponse); } } context.owner.unregister('adapter:facts/elide'); @@ -100,7 +102,11 @@ module('Unit | Adapter | Dimensions | Elide', function (hooks) { }); const adapter: ElideDimensionAdapter = this.owner.lookup('adapter:dimensions/elide'); - await adapter.find(TestDimensionColumn, [{ operator: 'in', values: ['v1', 'v2'] }], expectedOptions); + await taskFor(adapter.find).perform( + TestDimensionColumn, + [{ operator: 'in', values: ['v1', 'v2'] }], + expectedOptions + ); }); test('find - enum', async function (this: TestContext, assert) { @@ -120,7 +126,9 @@ module('Unit | Adapter | Dimensions | Elide', function (hooks) { const adapter: ElideDimensionAdapter = this.owner.lookup('adapter:dimensions/elide'); - const emptyInResponse = await adapter.find(TestDimensionColumn, [{ operator: 'in', values: ['v1', 'v2'] }]); + const emptyInResponse = await taskFor(adapter.find).perform(TestDimensionColumn, [ + { operator: 'in', values: ['v1', 'v2'] }, + ]); assert.deepEqual( extractDimValues(TestDimensionColumn, emptyInResponse), [], @@ -128,7 +136,7 @@ module('Unit | Adapter | Dimensions | Elide', function (hooks) { ); const inValues = ['Practical Frozen Fish (enum)', 'Practical Concrete Chair (enum)']; - const inResponse = await adapter.find(TestDimensionColumn, [{ operator: 'in', values: inValues }]); + const inResponse = await taskFor(adapter.find).perform(TestDimensionColumn, [{ operator: 'in', values: inValues }]); assert.deepEqual( extractDimValues(TestDimensionColumn, inResponse), inValues, @@ -136,14 +144,14 @@ module('Unit | Adapter | Dimensions | Elide', function (hooks) { ); const eqValues = ['Practical Frozen Fish (enum)']; - const eqResponse = await adapter.find(TestDimensionColumn, [{ operator: 'eq', values: eqValues }]); + const eqResponse = await taskFor(adapter.find).perform(TestDimensionColumn, [{ operator: 'eq', values: eqValues }]); assert.deepEqual( extractDimValues(TestDimensionColumn, eqResponse), eqValues, '`find` with `eq` operator returns filtered enum value for dimensions that provide them' ); - const filtersResponse = await adapter.find(TestDimensionColumn, [ + const filtersResponse = await taskFor(adapter.find).perform(TestDimensionColumn, [ { operator: 'in', values: inValues }, { operator: 'eq', values: eqValues }, ]); @@ -154,15 +162,15 @@ module('Unit | Adapter | Dimensions | Elide', function (hooks) { '`find` supports multiple predicates when filtering enum values' ); - try { - await adapter.find(TestDimensionColumn, [{ operator: 'gt', values: eqValues }]); - } catch (e) { - assert.equal( - e.message, - 'Assertion Failed: Dimension enum filter operator is not supported: gt', - '`find` throws an error for when requesting unsupported enum filter operators' - ); - } + await taskFor(adapter.find) + .perform(TestDimensionColumn, [{ operator: 'gt', values: eqValues }]) + .catch((e) => { + assert.equal( + e.message, + 'Assertion Failed: Dimension enum filter operator is not supported: gt', + '`find` throws an error for when requesting unsupported enum filter operators' + ); + }); }); test('find - tableSource', async function (this: TestContext, assert) { @@ -198,7 +206,7 @@ module('Unit | Adapter | Dimensions | Elide', function (hooks) { }); const adapter: ElideDimensionAdapter = this.owner.lookup('adapter:dimensions/elide'); - await adapter.find(TestDimensionColumn, [{ operator: 'in', values: ['v1', 'v2'] }]); + await taskFor(adapter.find).perform(TestDimensionColumn, [{ operator: 'in', values: ['v1', 'v2'] }]); }); test('all', async function (this: TestContext, assert) { @@ -237,7 +245,7 @@ module('Unit | Adapter | Dimensions | Elide', function (hooks) { }); const adapter: ElideDimensionAdapter = this.owner.lookup('adapter:dimensions/elide'); - await adapter.all(TestDimensionColumn, expectedOptions); + await taskFor(adapter.all).perform(TestDimensionColumn, expectedOptions); }); test('all - enum', async function (this: TestContext, assert) { @@ -256,7 +264,7 @@ module('Unit | Adapter | Dimensions | Elide', function (hooks) { }); const adapter: ElideDimensionAdapter = this.owner.lookup('adapter:dimensions/elide'); - const response = await adapter.all(TestDimensionColumn); + const response = await taskFor(adapter.all).perform(TestDimensionColumn); assert.deepEqual( extractDimValues(TestDimensionColumn, response), [ @@ -318,7 +326,7 @@ module('Unit | Adapter | Dimensions | Elide', function (hooks) { }); const adapter: ElideDimensionAdapter = this.owner.lookup('adapter:dimensions/elide'); - await adapter.search(TestDimensionColumn, query, expectedOptions); + await taskFor(adapter.search).perform(TestDimensionColumn, query, expectedOptions); }); test('search - enum', async function (this: TestContext, assert) { @@ -338,7 +346,7 @@ module('Unit | Adapter | Dimensions | Elide', function (hooks) { const adapter: ElideDimensionAdapter = this.owner.lookup('adapter:dimensions/elide'); const query = 'ACT'; - const response = await adapter.search(TestDimensionColumn, query); + const response = await taskFor(adapter.search).perform(TestDimensionColumn, query); assert.deepEqual( extractDimValues(TestDimensionColumn, response), ['Practical Frozen Fish (enum)', 'Practical Concrete Chair (enum)'], diff --git a/packages/data/tests/unit/adapters/facts/bard-test.ts b/packages/data/tests/unit/adapters/facts/bard-test.ts index 5b742aaa3..0afa1f1e9 100644 --- a/packages/data/tests/unit/adapters/facts/bard-test.ts +++ b/packages/data/tests/unit/adapters/facts/bard-test.ts @@ -2,10 +2,11 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; import Pretender, { Server as PretenderServer, ResponseData } from 'pretender'; import config from 'ember-get-config'; -import { Filter, RequestV2 } from 'navi-data/adapters/facts/interface'; -import BardFactsAdapter from 'navi-data/adapters/facts/bard'; -import { TestContext } from 'ember-test-helpers'; -import MetadataModelRegistry from 'navi-data/models/metadata/registry'; +import { taskFor } from 'ember-concurrency-ts'; +import type { Filter, RequestV2 } from 'navi-data/adapters/facts/interface'; +import type BardFactsAdapter from 'navi-data/adapters/facts/bard'; +import type { TestContext } from 'ember-test-helpers'; +import type MetadataModelRegistry from 'navi-data/models/metadata/registry'; const HOST = config.navi.dataSources[0].uri; const HOST2 = config.navi.dataSources[1].uri; @@ -1050,13 +1051,13 @@ module('Unit | Adapter | facts/bard', function (hooks) { test('urlForDownloadQuery', async function (assert) { assert.expect(6); assert.equal( - decodeURIComponent(await Adapter.urlForDownloadQuery(TestRequest)), + decodeURIComponent(await taskFor(Adapter.urlForDownloadQuery).perform(TestRequest)), `${HOST}/v1/data/table1/grain1/d1;show=id/d2;show=desc/?dateTime=2015-01-03/2015-01-04T00:00:00.000&metrics=m1,m2,r(p=123)&filters=d3|id-in["v1","v2"],d4|id-in["v3","v4"],d5|id-notin[""]&having=m1-gt[0]&format=json`, 'urlForDownloadQuery correctly built the URL for the provided request' ); assert.equal( - decodeURIComponent(await Adapter.urlForDownloadQuery(TestRequest, { format: 'csv' })), + decodeURIComponent(await taskFor(Adapter.urlForDownloadQuery).perform(TestRequest, { format: 'csv' })), `${HOST}/v1/data/table1/grain1/d1;show=id/d2;show=desc/?dateTime=2015-01-03/2015-01-04T00:00:00.000&metrics=m1,m2,r(p=123)&filters=d3|id-in["v1","v2"],d4|id-in["v3","v4"],d5|id-notin[""]&having=m1-gt[0]&format=csv`, 'urlForDownloadQuery correctly built the URL for the provided request with the format option' ); @@ -1074,7 +1075,7 @@ module('Unit | Adapter | facts/bard', function (hooks) { ], }; assert.equal( - decodeURIComponent(await Adapter.urlForDownloadQuery(onlyDateFilter)), + decodeURIComponent(await taskFor(Adapter.urlForDownloadQuery).perform(onlyDateFilter)), `${HOST}/v1/data/table1/grain1/d1;show=id/d2;show=desc/?dateTime=2015-01-03/2015-01-04T00:00:00.000&metrics=m1,m2,r(p=123)&format=json`, 'urlForDownloadQuery correctly built the URL for a request with only date filter' ); @@ -1096,19 +1097,21 @@ module('Unit | Adapter | facts/bard', function (hooks) { ], }; assert.equal( - decodeURIComponent(await Adapter.urlForDownloadQuery(requestWithSort)), + decodeURIComponent(await taskFor(Adapter.urlForDownloadQuery).perform(requestWithSort)), `${HOST}/v1/data/table1/grain1/d1;show=id/d2;show=desc/?dateTime=2015-01-03/2015-01-04T00:00:00.000&metrics=m1,m2,r(p=123)&sort=m1|desc,m2|desc&format=json`, 'urlForDownloadQuery correctly built the URL for a request with sort' ); assert.equal( - decodeURIComponent(await Adapter.urlForDownloadQuery(TestRequest, { cache: false })), + decodeURIComponent(await taskFor(Adapter.urlForDownloadQuery).perform(TestRequest, { cache: false })), `${HOST}/v1/data/table1/grain1/d1;show=id/d2;show=desc/?dateTime=2015-01-03/2015-01-04T00:00:00.000&metrics=m1,m2,r(p=123)&filters=d3|id-in["v1","v2"],d4|id-in["v3","v4"],d5|id-notin[""]&having=m1-gt[0]&format=json&_cache=false`, 'urlForDownloadQuery correctly built the URL for the provided request with the cache option' ); assert.equal( - decodeURIComponent(await Adapter.urlForDownloadQuery(TestRequest, { dataSourceName: 'bardTwo' })), + decodeURIComponent( + await taskFor(Adapter.urlForDownloadQuery).perform(TestRequest, { dataSourceName: 'bardTwo' }) + ), `${HOST2}/v1/data/table1/grain1/d1;show=id/d2;show=desc/?dateTime=2015-01-03/2015-01-04T00:00:00.000&metrics=m1,m2,r(p=123)&filters=d3|id-in["v1","v2"],d4|id-in["v3","v4"],d5|id-notin[""]&having=m1-gt[0]&format=json`, 'urlForDownloadQuery renders alternative host name if option is given' ); @@ -1117,14 +1120,16 @@ module('Unit | Adapter | facts/bard', function (hooks) { test('fetchDataForRequest', function (assert) { assert.expect(1); - return Adapter.fetchDataForRequest(TestRequest).then(function (result) { - return assert.deepEqual(result, Response, 'Ajax GET returns the response object for TEST Request'); - }); + return taskFor(Adapter.fetchDataForRequest) + .perform(TestRequest) + .then(function (result) { + return assert.deepEqual(result, Response, 'Ajax GET returns the response object for TEST Request'); + }); }); test('fetchDataForRequest with pagination options', async function (assert) { assert.expect(1); - const result = await Adapter.fetchDataForRequest(TestRequest, { + const result = await taskFor(Adapter.fetchDataForRequest).perform(TestRequest, { page: 1, perPage: 100, }); @@ -1156,14 +1161,14 @@ module('Unit | Adapter | facts/bard', function (hooks) { }); // Sending request for default clientId - await Adapter.fetchDataForRequest(TestRequest); + await taskFor(Adapter.fetchDataForRequest).perform(TestRequest); // Setting up assert for provided clientId Server.get(`${HOST}/v1/data/table1/grain1/d1;show=id/d2;show=desc/`, (request1) => { assert.equal(request1.requestHeaders.clientid, 'test id', 'Client id is set to value given in options'); return MockBardResponse; }); - await Adapter.fetchDataForRequest(TestRequest, { + await taskFor(Adapter.fetchDataForRequest).perform(TestRequest, { clientId: 'test id', }); }); @@ -1179,7 +1184,7 @@ module('Unit | Adapter | facts/bard', function (hooks) { return MockBardResponse; }); - await Adapter.fetchDataForRequest(TestRequest, { + await taskFor(Adapter.fetchDataForRequest).perform(TestRequest, { customHeaders: { foo: 'bar', baz: 'qux', @@ -1196,6 +1201,6 @@ module('Unit | Adapter | facts/bard', function (hooks) { return MockBardResponse; }); - await Adapter.fetchDataForRequest(TestRequest, { dataSourceName: 'bardTwo' }); + await taskFor(Adapter.fetchDataForRequest).perform(TestRequest, { dataSourceName: 'bardTwo' }); }); }); diff --git a/packages/data/tests/unit/adapters/facts/elide-test.ts b/packages/data/tests/unit/adapters/facts/elide-test.ts index 34dc31ace..c9836027b 100644 --- a/packages/data/tests/unit/adapters/facts/elide-test.ts +++ b/packages/data/tests/unit/adapters/facts/elide-test.ts @@ -3,12 +3,13 @@ import { setupTest } from 'ember-qunit'; import { asyncFactsMutationStr } from 'navi-data/gql/mutations/async-facts'; import { asyncFactsCancelMutationStr } from 'navi-data/gql/mutations/async-facts-cancel'; import { asyncFactsQueryStr } from 'navi-data/gql/queries/async-facts'; -import { Filter, RequestV2 } from 'navi-data/adapters/facts/interface'; import Pretender from 'pretender'; import config from 'ember-get-config'; import moment from 'moment'; import ElideFactsAdapter, { getElideField } from 'navi-data/adapters/facts/elide'; -import MetadataModelRegistry from 'navi-data/models/metadata/registry'; +import type { Filter, RequestV2 } from 'navi-data/adapters/facts/interface'; +import type MetadataModelRegistry from 'navi-data/models/metadata/registry'; +import { taskFor } from 'ember-concurrency-ts'; const HOST = config.navi.dataSources[2].uri; const uuidRegex = /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/; @@ -290,8 +291,8 @@ module('Unit | Adapter | facts/elide', function (hooks) { assert.deepEqual( Object.keys(requestObj.variables), - ['id', 'query'], - 'createAsyncQuery sends id and query request variables' + ['id', 'query', 'asyncAfterSeconds'], + 'createAsyncQuery sends id, query, and asyncAfterSeconds request variables' ); assert.ok(uuidRegex.exec(requestObj.variables.id), 'A uuid is generated for the request id'); @@ -523,7 +524,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { return [200, { 'Content-Type': 'application/json' }, JSON.stringify({ data: response })]; }); - const result = await adapter.fetchDataForRequest(TestRequest); + const result = await taskFor(adapter.fetchDataForRequest).perform(TestRequest); assert.deepEqual(result, response, 'fetchDataForRequest returns the correct response payload'); }); @@ -535,7 +536,7 @@ module('Unit | Adapter | facts/elide', function (hooks) { Server.post(HOST, () => [400, { 'Content-Type': 'application/json' }, JSON.stringify({ errors })]); try { - await adapter.fetchDataForRequest(TestRequest); + await taskFor(adapter.fetchDataForRequest).perform(TestRequest); } catch ({ errors }) { const responseText = await errors[0].statusText; assert.deepEqual(responseText, errors[0].messages, 'fetchDataForRequest an array of response objects on error'); diff --git a/packages/data/tests/unit/models/bard-dimension-array.js b/packages/data/tests/unit/models/bard-dimension-array.js index b94bf77e8..f276a4320 100644 --- a/packages/data/tests/unit/models/bard-dimension-array.js +++ b/packages/data/tests/unit/models/bard-dimension-array.js @@ -54,7 +54,7 @@ module('Unit | Model | Bard Dimension Array', function (hooks) { assert.equal(Response.dimension, 'd1', '`dimension` property was properly hydrated'); }); - test('pagination methods', function (assert) { + test('pagination methods', async function (assert) { assert.expect(6); assert.deepEqual( @@ -71,7 +71,7 @@ module('Unit | Model | Bard Dimension Array', function (hooks) { Payload.meta.pagination.currentPage = 4; - assert.deepEqual(Response.next(), null, 'Next method returns null when total pages is exceeded'); + assert.deepEqual(await Response.next(), null, 'Next method returns null when total pages is exceeded'); Payload.meta.pagination.currentPage = 2; @@ -89,7 +89,7 @@ module('Unit | Model | Bard Dimension Array', function (hooks) { Payload.response.meta.pagination.currentPage = 1; - assert.deepEqual(Response.previous(), null, 'Previous method returns null trying previous from first page'); + assert.deepEqual(await Response.previous(), null, 'Previous method returns null trying previous from first page'); delete Payload.response.meta.pagination; @@ -99,6 +99,10 @@ module('Unit | Model | Bard Dimension Array', function (hooks) { 'Previous method returns null when there is no pagination options' ); - assert.deepEqual(BardDimensionArray.next(), null, 'Next method returns null when there is no pagination options'); + assert.deepEqual( + await BardDimensionArray.next(), + null, + 'Next method returns null when there is no pagination options' + ); }); }); diff --git a/packages/data/tests/unit/services/navi-dimension-test.ts b/packages/data/tests/unit/services/navi-dimension-test.ts index 95b84c5dc..ade474743 100644 --- a/packages/data/tests/unit/services/navi-dimension-test.ts +++ b/packages/data/tests/unit/services/navi-dimension-test.ts @@ -10,6 +10,7 @@ import DimensionMetadataModel from 'navi-data/models/metadata/dimension'; import { setupMirage } from 'ember-cli-mirage/test-support'; import GraphQLScenario from 'navi-data/mirage/scenarios/elide-one'; import { Server } from 'miragejs'; +import { taskFor } from 'ember-concurrency-ts'; interface TestContext extends Context { metadataService: NaviMetadataService; @@ -39,7 +40,7 @@ module('Unit | Service | navi-dimension', function (hooks) { 'Awesome Concrete Table', 'Handcrafted Concrete Mouse', ].map((dimVal) => NaviDimensionModel.create({ value: dimVal, dimensionColumn: { columnMetadata } })); - const all = await service.all({ columnMetadata }); + const all = await taskFor(service.all).perform({ columnMetadata }); assert.deepEqual(all, expectedDimensionModels, '`all` gets all the unfiltered values for a dimension'); }); @@ -58,7 +59,7 @@ module('Unit | Service | navi-dimension', function (hooks) { 'Tasty Fresh Towels (enum)', 'Intelligent Steel Pizza (enum)', ].map((dimVal) => NaviDimensionModel.create({ value: dimVal, dimensionColumn: { columnMetadata } })); - const all = await service.all({ columnMetadata }); + const all = await taskFor(service.all).perform({ columnMetadata }); assert.deepEqual( all, @@ -79,7 +80,7 @@ module('Unit | Service | navi-dimension', function (hooks) { const expectedDimensionModels = findValues.map((dimVal) => NaviDimensionModel.create({ value: dimVal, dimensionColumn: { columnMetadata } }) ); - const find = await service.find({ columnMetadata }, filters); + const find = await taskFor(service.find).perform({ columnMetadata }, filters); assert.deepEqual( find, expectedDimensionModels, @@ -96,7 +97,7 @@ module('Unit | Service | navi-dimension', function (hooks) { 'table0.dimension0', 'elideOne' ) as DimensionMetadataModel; - const search = await service.search({ columnMetadata }, 'plastic'); + const search = await taskFor(service.search).perform({ columnMetadata }, 'plastic'); const expectedDimensionModels = ['Licensed Plastic Pants', 'Awesome Plastic Fish'].map((dimVal) => NaviDimensionModel.create({ value: dimVal, dimensionColumn: { columnMetadata } }) ); @@ -106,7 +107,7 @@ module('Unit | Service | navi-dimension', function (hooks) { '`search` gets all the values for a dimension that contain the query case insensitively' ); - const noResultSearch = await service.search({ columnMetadata }, 'fuggedaboutit'); + const noResultSearch = await taskFor(service.search).perform({ columnMetadata }, 'fuggedaboutit'); assert.deepEqual(noResultSearch, [], 'Empty array is returned when no values are found'); }); }); diff --git a/packages/data/tests/unit/services/navi-facts-elide-test.ts b/packages/data/tests/unit/services/navi-facts-elide-test.ts index 0ee7eb08e..a6fcca863 100644 --- a/packages/data/tests/unit/services/navi-facts-elide-test.ts +++ b/packages/data/tests/unit/services/navi-facts-elide-test.ts @@ -10,6 +10,7 @@ import NaviFactsService from 'navi-data/services/navi-facts'; import { Filter, RequestV2 } from 'navi-data/adapters/facts/interface'; import NaviFactResponse from 'navi-data/models/navi-fact-response'; import NaviMetadataService from 'navi-data/services/navi-metadata'; +import { taskFor } from 'ember-concurrency-ts'; interface TestContext extends Context { service: NaviFactsService; @@ -95,7 +96,7 @@ module('Unit | Service | Navi Facts - Elide', function (hooks) { }); test('fetch', async function (this: TestContext, assert) { - const model = await this.service.fetch(TestRequest, { dataSourceName: TestRequest.dataSource }); + const model = await taskFor(this.service.fetch).perform(TestRequest, { dataSourceName: TestRequest.dataSource }); const { rows, meta } = model.response as NaviFactResponse; assert.deepEqual( { rows, meta }, @@ -244,7 +245,7 @@ module('Unit | Service | Navi Facts - Elide', function (hooks) { }); test('fetch - only metrics', async function (this: TestContext, assert) { - const model = await this.service.fetch( + const model = await taskFor(this.service.fetch).perform( { table: 'table1', columns: [ @@ -300,7 +301,7 @@ module('Unit | Service | Navi Facts - Elide', function (hooks) { }, ]; - const model = await this.service.fetch( + const model = await taskFor(this.service.fetch).perform( { table: 'table1', columns: [ @@ -327,7 +328,7 @@ module('Unit | Service | Navi Facts - Elide', function (hooks) { ); const noTimeDimResponse = ( - await this.service.fetch( + await taskFor(this.service.fetch).perform( { table: 'table1', columns: [{ field: 'table1.metric1', parameters: {}, type: 'metric' }], @@ -355,7 +356,7 @@ module('Unit | Service | Navi Facts - Elide', function (hooks) { }); test('fetch - incomplete date filters', async function (this: TestContext, assert) { - const model = await this.service.fetch( + const model = await taskFor(this.service.fetch).perform( { table: 'table1', columns: [ @@ -393,7 +394,7 @@ module('Unit | Service | Navi Facts - Elide', function (hooks) { ); const noStartDateResponse = ( - await this.service.fetch( + await taskFor(this.service.fetch).perform( { table: 'table1', columns: [ @@ -434,7 +435,7 @@ module('Unit | Service | Navi Facts - Elide', function (hooks) { const DAY_FORMAT = 'YYYY-MM-DD'; const dateToCurrentResponse = ( - await this.service.fetch( + await taskFor(this.service.fetch).perform( { table: 'table1', columns: [{ field: 'table1.eventTimeDay', parameters: {}, type: 'timeDimension' }], @@ -480,7 +481,7 @@ module('Unit | Service | Navi Facts - Elide', function (hooks) { }); test('fetch - sorts', async function (this: TestContext, assert) { - const model = await this.service.fetch( + const model = await taskFor(this.service.fetch).perform( { table: 'table1', columns: [ @@ -535,7 +536,7 @@ module('Unit | Service | Navi Facts - Elide', function (hooks) { ); const multiSortResponse = ( - await this.service.fetch( + await taskFor(this.service.fetch).perform( { table: 'table1', columns: [ @@ -632,7 +633,7 @@ module('Unit | Service | Navi Facts - Elide', function (hooks) { test('fetch - limit', async function (this: TestContext, assert) { const limit = ( - await this.service.fetch( + await taskFor(this.service.fetch).perform( { table: 'table1', columns: [ @@ -690,7 +691,7 @@ module('Unit | Service | Navi Facts - Elide', function (hooks) { ); const limitless = ( - await this.service.fetch( + await taskFor(this.service.fetch).perform( { table: 'table1', columns: [ @@ -776,8 +777,8 @@ module('Unit | Service | Navi Facts - Elide', function (hooks) { assert.expect(2); // Return an error - await this.service - .fetch( + await taskFor(this.service.fetch) + .perform( { table: 'badTable', columns: [{ field: 'badTable.badMetric', parameters: {}, type: 'metric' }], diff --git a/packages/data/tests/unit/services/navi-facts-test.ts b/packages/data/tests/unit/services/navi-facts-test.ts index 0e151845c..a708c29aa 100644 --- a/packages/data/tests/unit/services/navi-facts-test.ts +++ b/packages/data/tests/unit/services/navi-facts-test.ts @@ -2,14 +2,16 @@ import { module, test, skip } from 'qunit'; import { setupTest } from 'ember-qunit'; import Pretender, { Server as PretenderServer } from 'pretender'; import config from 'ember-get-config'; -import { RequestV2 } from 'navi-data/adapters/facts/interface'; +import { RequestOptions, RequestV2 } from 'navi-data/adapters/facts/interface'; import NaviFactsService from 'navi-data/services/navi-facts'; import { TestContext } from 'ember-test-helpers'; import { ResponseV1 } from 'navi-data/serializers/facts/interface'; import NaviFactResponse from 'navi-data/models/navi-fact-response'; import NaviAdapterError from 'navi-data/errors/navi-adapter-error'; +import { task, TaskGenerator } from 'ember-concurrency'; +import { taskFor } from 'ember-concurrency-ts'; -let Service: NaviFactsService, Server: PretenderServer; +let Server: PretenderServer; const TestRequest: RequestV2 = { table: 'table1', @@ -75,12 +77,22 @@ const Response: ResponseV1 = { const HOST = config.navi.dataSources[0].uri; +function assertRequest(context: TestContext, callback: (request: RequestV2, options?: RequestOptions) => void) { + const originalNaviFacts = context.owner.factoryFor('service:navi-facts').class; + class TestService extends originalNaviFacts { + @task *fetch(request: RequestV2, options?: RequestOptions): TaskGenerator { + callback(request, options); + return yield {}; + } + } + context.owner.unregister('service:navi-facts'); + context.owner.register('service:navi-facts', TestService); +} + module('Unit | Service | Navi Facts', function (hooks) { setupTest(hooks); hooks.beforeEach(function (this: TestContext) { - Service = this.owner.lookup('service:navi-facts'); - //setup Pretender Server = new Pretender(function () { this.get(`${HOST}/v1/data/table1/grain1/d1;show=id/d2;show=id/`, function (request) { @@ -111,12 +123,14 @@ module('Unit | Service | Navi Facts', function (hooks) { }); test('Service Exists', function (assert) { - assert.ok(!!Service, 'Service exists'); + const service: NaviFactsService = this.owner.lookup('service:navi-facts'); + assert.ok(!!service, 'Service exists'); }); test('getURL', function (assert) { + const service: NaviFactsService = this.owner.lookup('service:navi-facts'); assert.deepEqual( - Service.getURL(TestRequest), + service.getURL(TestRequest), `${HOST}/v1/data/table1/grain1/d1;show=id/d2;show=id/?` + 'dateTime=2015-01-03%2F2015-01-04T00%3A00%3A00.000&metrics=m1%2Cm2&' + 'filters=d3%7Cid-in%5B%22v1%22%2C%22v2%22%5D%2Cd4%7Cid-in%5B%22v3%22%2C%22v4%22%5D&having=m1-gt%5B0%5D&' + @@ -125,7 +139,7 @@ module('Unit | Service | Navi Facts', function (hooks) { ); assert.deepEqual( - Service.getURL(TestRequest, { format: 'jsonApi' }), + service.getURL(TestRequest, { format: 'jsonApi' }), `${HOST}/v1/data/table1/grain1/d1;show=id/d2;show=id/?` + 'dateTime=2015-01-03%2F2015-01-04T00%3A00%3A00.000&metrics=m1%2Cm2&' + 'filters=d3%7Cid-in%5B%22v1%22%2C%22v2%22%5D%2Cd4%7Cid-in%5B%22v3%22%2C%22v4%22%5D&having=m1-gt%5B0%5D&' + @@ -135,7 +149,8 @@ module('Unit | Service | Navi Facts', function (hooks) { }); test('fetch', async function (assert) { - const model = await Service.fetch(TestRequest); + const service: NaviFactsService = this.owner.lookup('service:navi-facts'); + const model = await taskFor(service.fetch).perform(TestRequest); const { rows, meta } = model.response as NaviFactResponse; assert.deepEqual( { rows, meta }, @@ -160,13 +175,14 @@ module('Unit | Service | Navi Facts', function (hooks) { assert.deepEqual( model._factService, - Service, + service, 'Fetch returns a navi response model object with the service instance' ); }); test('fetch with pagination', async function (assert) { - const model = await Service.fetch(TestRequest, { page: 2, perPage: 10 }); + const service: NaviFactsService = this.owner.lookup('service:navi-facts'); + const model = await taskFor(service.fetch).perform(TestRequest, { page: 2, perPage: 10 }); const { rows, meta } = model.response as NaviFactResponse; assert.deepEqual( { rows, meta }, @@ -186,6 +202,7 @@ module('Unit | Service | Navi Facts', function (hooks) { test('fetch and catch error', async function (assert) { assert.expect(6); + const service: NaviFactsService = this.owner.lookup('service:navi-facts'); // Return an error object Server.get(`${HOST}/v1/data/table1/grain1/d1;show=id/d2;show=id/`, () => { return [ @@ -197,33 +214,39 @@ module('Unit | Service | Navi Facts', function (hooks) { ]; }); - await Service.fetch(TestRequest).catch((response: NaviAdapterError) => { - assert.ok(true, 'A request error falls into the promise catch block'); - assert.equal( - response.details[0], - 'Result set too large. Try reducing interval or dimensions.', - 'error is passed to catch block' - ); - }); + await taskFor(service.fetch) + .perform(TestRequest) + .catch((response: NaviAdapterError) => { + assert.ok(true, 'A request error falls into the promise catch block'); + assert.equal( + response.details[0], + 'Result set too large. Try reducing interval or dimensions.', + 'error is passed to catch block' + ); + }); // Return an error string Server.get(`${HOST}/v1/data/table1/grain1/d1;show=id/d2;show=id/`, () => { return [500, { 'Content-Type': 'text/plain' }, 'Server Error']; }); - await Service.fetch(TestRequest).catch((response: NaviAdapterError) => { - assert.ok(true, 'A request error falls into the promise catch block'); - assert.equal(response.details[0], 'Server Error', 'String error extracted'); - }); + await taskFor(service.fetch) + .perform(TestRequest) + .catch((response: NaviAdapterError) => { + assert.ok(true, 'A request error falls into the promise catch block'); + assert.equal(response.details[0], 'Server Error', 'String error extracted'); + }); - await Service.fetch({ ...TestRequest, filters: [] }).catch((response: NaviAdapterError) => { - assert.ok(true, 'A request error falls into the promise catch block'); - assert.equal( - response.details[0], - `Exactly one 'table1.dateTime' filter is required, you have 0`, - 'Adapter error is shown' - ); - }); + await taskFor(service.fetch) + .perform({ ...TestRequest, filters: [] }) + .catch((response: NaviAdapterError) => { + assert.ok(true, 'A request error falls into the promise catch block'); + assert.equal( + response.details[0], + `Exactly one 'table1.dateTime' filter is required, you have 0`, + 'Adapter error is shown' + ); + }); }); skip('request builder', function (/*assert*/) { @@ -262,14 +285,13 @@ module('Unit | Service | Navi Facts', function (hooks) { */ }); - test('fetchNext', function (assert) { + test('fetchNext', async function (assert) { assert.expect(2); - const originalFetch = Service.fetch; - //@ts-expect-error - Service.fetch = (request, options) => { - assert.equal(options?.page, 3, 'FetchNext calls fetch with updated options'); - }; + assertRequest(this, (_request, options) => { + assert.equal(options?.page, 3, 'fetchNext calls fetch with updated options'); + }); + const service: NaviFactsService = this.owner.lookup('service:navi-facts'); const response: ResponseV1 = { rows: [], @@ -284,23 +306,24 @@ module('Unit | Service | Navi Facts', function (hooks) { }; const request = {} as RequestV2; - Service.fetchNext(response, request); + await taskFor(service.fetchNext).perform(response, request); //@ts-expect-error response.meta.pagination.currentPage = 3; - assert.equal(Service.fetchNext(response, request), null, 'fetchNext returns null when the last page is reached'); - - Service.fetch = originalFetch; + assert.equal( + await taskFor(service.fetchNext).perform(response, request), + null, + 'fetchNext returns null when the last page is reached' + ); }); - test('fetchPrevious', function (assert) { + test('fetchPrevious', async function (assert) { assert.expect(2); - const originalFetch = Service.fetch; - //@ts-expect-error - Service.fetch = (_request, options) => { - assert.equal(options?.page, 1, 'FetchPrevious calls fetch with updated options'); - }; + assertRequest(this, (_request, options) => { + assert.equal(options?.page, 1, 'fetchPrevious calls fetch with updated options'); + }); + const service: NaviFactsService = this.owner.lookup('service:navi-facts'); const response: ResponseV1 = { rows: [], @@ -315,16 +338,14 @@ module('Unit | Service | Navi Facts', function (hooks) { }; const request = {} as RequestV2; - Service.fetchPrevious(response, request); + await taskFor(service.fetchPrevious).perform(response, request); //@ts-expect-error response.meta.pagination.currentPage = 1; assert.equal( - Service.fetchPrevious(response, request), + await taskFor(service.fetchPrevious).perform(response, request), null, 'fetchPrevious returns null when the first page is reached' ); - - Service.fetch = originalFetch; }); }); diff --git a/packages/directory/package-lock.json b/packages/directory/package-lock.json index 8aeca7d5f..49e9fe37b 100644 --- a/packages/directory/package-lock.json +++ b/packages/directory/package-lock.json @@ -11924,14 +11924,16 @@ } }, "ember-concurrency": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-1.3.0.tgz", - "integrity": "sha512-DwGlfWFpYyAkTwsedlEtK4t1DznJSculAW6Vq5S1C0shVPc5b6tTpHB2FFYisannSYkm+wpm1f1Pd40qiNPtOQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-2.0.3.tgz", + "integrity": "sha512-+fOOFt32odnunDL3Du0LqMgnRzDDNKnzo1ry9ppICpvLXekJzYFwU1RniVivfJ+9nbpHMJZQUlZJAm1ZAnTExw==", "dev": true, "requires": { - "ember-cli-babel": "^7.7.3", + "@glimmer/tracking": "^1.0.2", + "ember-cli-babel": "^7.22.1", + "ember-cli-htmlbars": "^5.6.3", "ember-compatibility-helpers": "^1.2.0", - "ember-maybe-import-regenerator": "^0.1.6" + "ember-destroyable-polyfill": "^2.0.2" } }, "ember-concurrency-decorators": { @@ -12116,6 +12118,111 @@ } } }, + "ember-concurrency-ts": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ember-concurrency-ts/-/ember-concurrency-ts-0.2.2.tgz", + "integrity": "sha512-03/NEhXczd93tpg0ycusj3bgXZS15wymU0K8eMvWftyzWS4B+UE03RzimOFrtOxJmE2mNj64hLJUZR9P8LelFw==", + "dev": true, + "requires": { + "ember-cli-babel": "^7.19.0", + "ember-cli-htmlbars": "^4.3.1" + }, + "dependencies": { + "broccoli-output-wrapper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/broccoli-output-wrapper/-/broccoli-output-wrapper-2.0.0.tgz", + "integrity": "sha512-V/ozejo+snzNf75i/a6iTmp71k+rlvqjE3+jYfimuMwR1tjNNRdtfno+NGNQB2An9bIAeqZnKhMDurAznHAdtA==", + "dev": true, + "requires": { + "heimdalljs-logger": "^0.1.10" + } + }, + "broccoli-plugin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-3.1.0.tgz", + "integrity": "sha512-7w7FP8WJYjLvb0eaw27LO678TGGaom++49O1VYIuzjhXjK5kn2+AMlDm7CaUFw4F7CLGoVQeZ84d8gICMJa4lA==", + "dev": true, + "requires": { + "broccoli-node-api": "^1.6.0", + "broccoli-output-wrapper": "^2.0.0", + "fs-merger": "^3.0.1", + "promise-map-series": "^0.2.1", + "quick-temp": "^0.1.3", + "rimraf": "^2.3.4", + "symlink-or-copy": "^1.1.8" + } + }, + "ember-cli-htmlbars": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-4.5.0.tgz", + "integrity": "sha512-bYJpK1pqFu9AadDAGTw05g2LMNzY8xTCIqQm7dMJmKEoUpLRFbPf4SfHXrktzDh7Q5iggl6Skzf1M0bPlIxARw==", + "dev": true, + "requires": { + "@ember/edition-utils": "^1.2.0", + "babel-plugin-htmlbars-inline-precompile": "^3.2.0", + "broccoli-debug": "^0.6.5", + "broccoli-persistent-filter": "^2.3.1", + "broccoli-plugin": "^3.1.0", + "common-tags": "^1.8.0", + "ember-cli-babel-plugin-helpers": "^1.1.0", + "fs-tree-diff": "^2.0.1", + "hash-for-dep": "^1.5.1", + "heimdalljs-logger": "^0.1.10", + "json-stable-stringify": "^1.0.1", + "semver": "^6.3.0", + "strip-bom": "^4.0.0", + "walk-sync": "^2.0.2" + } + }, + "fs-tree-diff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-2.0.1.tgz", + "integrity": "sha512-x+CfAZ/lJHQqwlD64pYM5QxWjzWhSjroaVsr8PW831zOApL55qPibed0c+xebaLWVr2BnHFoHdrwOv8pzt8R5A==", + "dev": true, + "requires": { + "@types/symlink-or-copy": "^1.2.0", + "heimdalljs-logger": "^0.1.7", + "object-assign": "^4.1.0", + "path-posix": "^1.0.0", + "symlink-or-copy": "^1.1.8" + } + }, + "matcher-collection": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-2.0.1.tgz", + "integrity": "sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ==", + "dev": true, + "requires": { + "@types/minimatch": "^3.0.3", + "minimatch": "^3.0.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "walk-sync": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-2.2.0.tgz", + "integrity": "sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==", + "dev": true, + "requires": { + "@types/minimatch": "^3.0.3", + "ensure-posix-path": "^1.1.0", + "matcher-collection": "^2.0.0", + "minimatch": "^3.0.4" + } + } + } + }, "ember-copy": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ember-copy/-/ember-copy-2.0.1.tgz", @@ -12318,9 +12425,9 @@ } }, "ember-destroyable-polyfill": { - "version": "2.0.3", + "version": "2.0.2", "resolved": "https://registry.npmjs.org/ember-destroyable-polyfill/-/ember-destroyable-polyfill-2.0.3.tgz", - "integrity": "sha512-TovtNqCumzyAiW0/OisSkkVK93xnVF4NRU6+FN0ubpfwEOpRrmM2RqDwXI6YAChCgSHON1cz0DfQStpA1Gjuuw==", + "integrity": "sha512-9t+ya+9c+FkNM5IAyJIv6ETG8jfZQaUnFCO5SeLlV0wkSw7TOexyb61jh5GVee0KmknfRhrRGGAyT4Y0TwkZ+w==", "requires": { "ember-cli-babel": "^7.22.1", "ember-cli-version-checker": "^5.1.1", @@ -25747,9 +25854,9 @@ } }, "typescript": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", - "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "dev": true }, "typescript-memoize": { diff --git a/packages/directory/package.json b/packages/directory/package.json index 2d8820238..f878c3905 100644 --- a/packages/directory/package.json +++ b/packages/directory/package.json @@ -34,7 +34,7 @@ "ember-cli-babel": "^7.17.2", "ember-cli-htmlbars": "^5.1.2", "ember-cli-moment-shim": "^3.8.0", - "ember-cli-typescript": "^4.0.0", + "ember-cli-typescript": "^4.1.0", "ember-data-model-fragments": "^5.0.0-beta.1", "ember-get-config": "0.2.4", "ember-light-table": "^3.0.0-beta.0", @@ -78,7 +78,8 @@ "ember-collection": "1.0.0-alpha.9", "ember-compatibility-helpers": "^1.2.0", "ember-composable-helpers": "^4.1.1", - "ember-concurrency": "1.3.0", + "ember-concurrency": "2.0.3", + "ember-concurrency-ts": "0.2.2", "ember-cp-validations": "^4.0.0-beta.10", "ember-data": "~3.24.0", "ember-disable-prototype-extensions": "^1.1.3", @@ -109,7 +110,7 @@ "npm-run-all": "^4.1.5", "qunit-dom": "^1.0.0", "sass": "^1.30.0", - "typescript": "^3.9.5" + "typescript": "^4.1.5" }, "engines": { "node": "10.* || >= 12" diff --git a/packages/reports/addon/components/filter-values/dimension-select.hbs b/packages/reports/addon/components/filter-values/dimension-select.hbs index 6ac9cd9be..48f955144 100644 --- a/packages/reports/addon/components/filter-values/dimension-select.hbs +++ b/packages/reports/addon/components/filter-values/dimension-select.hbs @@ -11,7 +11,8 @@
; + @computed('args.filter.{columnMetadata,parameters}') get dimensionColumn(): DimensionColumn { const { filter } = this.args; @@ -51,17 +56,13 @@ export default class DimensionSelectComponent extends Component { const searchTerm = term.trim(); this.searchTerm = searchTerm; - - if (searchTerm) { - yield timeout(SEARCH_DEBOUNCE_TIME); - return this.naviDimension.search(this.dimensionColumn, searchTerm); + if (!searchTerm) { + return undefined; } - return undefined; - }).restartable()) - searchDimensionValues!: typeof task; + if (this.dimensionValues === undefined) { + yield timeout(SEARCH_DEBOUNCE_MS); + return yield taskFor(this.naviDimension.search).perform(this.dimensionColumn, searchTerm); + } else { + yield timeout(SEARCH_DEBOUNCE_OFFLINE_MS); + const rawValues: NaviDimensionModel[] = yield this.dimensionValues; + return rawValues.filter((v) => v.displayValue.toLowerCase().includes(searchTerm.toLowerCase())); + } + } } diff --git a/packages/reports/addon/components/power-select-collection-options.ts b/packages/reports/addon/components/power-select-collection-options.ts index 099e459e1..1f18b5768 100644 --- a/packages/reports/addon/components/power-select-collection-options.ts +++ b/packages/reports/addon/components/power-select-collection-options.ts @@ -62,9 +62,15 @@ export default class PowerSelectCollectionOptions extends Options { /** * @property {Array} indexedOptions - array of options that retain original order */ - @computed('args.options') + @computed('args.{options,select.loading}') get indexedOptions(): IndexedOptions[] { - const { options } = this.args; + const { + options, + select: { loading }, + } = this.args; + if (loading) { + return []; + } return options.map((option: {}, idx: number) => ({ option, idx })); } diff --git a/packages/reports/addon/routes/reports/report/view.ts b/packages/reports/addon/routes/reports/report/view.ts index fa640ebfb..38496618d 100644 --- a/packages/reports/addon/routes/reports/report/view.ts +++ b/packages/reports/addon/routes/reports/report/view.ts @@ -8,6 +8,7 @@ import { inject as service } from '@ember/service'; import { merge } from 'lodash-es'; import { isForbiddenError } from 'ember-ajax/errors'; import { reject } from 'rsvp'; +import { taskFor } from 'ember-concurrency-ts'; import type NaviFactsService from 'navi-data/services/navi-facts'; import type NaviVisualizationsService from 'navi-reports/services/navi-visualizations'; import type { ModelFrom, Transition } from 'navi-core/utils/type-utils'; @@ -60,8 +61,8 @@ export default class ReportsReportViewRoute extends Route { }); // Wrap the response in a promise object so we can manually handle loading spinners - return this.facts - .fetch(serializedRequest, requestOptions) + return taskFor(this.facts.fetch) + .perform(serializedRequest, requestOptions) .then((response) => { this._setValidVisualizationType(request, report); this._setValidVisualizationConfig(request, report, response.response); diff --git a/packages/reports/package-lock.json b/packages/reports/package-lock.json index b5578350f..a0a740aad 100644 --- a/packages/reports/package-lock.json +++ b/packages/reports/package-lock.json @@ -12710,13 +12710,15 @@ } }, "ember-concurrency": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-1.3.0.tgz", - "integrity": "sha512-DwGlfWFpYyAkTwsedlEtK4t1DznJSculAW6Vq5S1C0shVPc5b6tTpHB2FFYisannSYkm+wpm1f1Pd40qiNPtOQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-2.0.3.tgz", + "integrity": "sha512-+fOOFt32odnunDL3Du0LqMgnRzDDNKnzo1ry9ppICpvLXekJzYFwU1RniVivfJ+9nbpHMJZQUlZJAm1ZAnTExw==", "requires": { - "ember-cli-babel": "^7.7.3", + "@glimmer/tracking": "^1.0.2", + "ember-cli-babel": "^7.22.1", + "ember-cli-htmlbars": "^5.6.3", "ember-compatibility-helpers": "^1.2.0", - "ember-maybe-import-regenerator": "^0.1.6" + "ember-destroyable-polyfill": "^2.0.2" } }, "ember-concurrency-decorators": { @@ -12918,6 +12920,102 @@ } } }, + "ember-concurrency-ts": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ember-concurrency-ts/-/ember-concurrency-ts-0.2.2.tgz", + "integrity": "sha512-03/NEhXczd93tpg0ycusj3bgXZS15wymU0K8eMvWftyzWS4B+UE03RzimOFrtOxJmE2mNj64hLJUZR9P8LelFw==", + "requires": { + "ember-cli-babel": "^7.19.0", + "ember-cli-htmlbars": "^4.3.1" + }, + "dependencies": { + "broccoli-output-wrapper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/broccoli-output-wrapper/-/broccoli-output-wrapper-2.0.0.tgz", + "integrity": "sha512-V/ozejo+snzNf75i/a6iTmp71k+rlvqjE3+jYfimuMwR1tjNNRdtfno+NGNQB2An9bIAeqZnKhMDurAznHAdtA==", + "requires": { + "heimdalljs-logger": "^0.1.10" + } + }, + "broccoli-plugin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-3.1.0.tgz", + "integrity": "sha512-7w7FP8WJYjLvb0eaw27LO678TGGaom++49O1VYIuzjhXjK5kn2+AMlDm7CaUFw4F7CLGoVQeZ84d8gICMJa4lA==", + "requires": { + "broccoli-node-api": "^1.6.0", + "broccoli-output-wrapper": "^2.0.0", + "fs-merger": "^3.0.1", + "promise-map-series": "^0.2.1", + "quick-temp": "^0.1.3", + "rimraf": "^2.3.4", + "symlink-or-copy": "^1.1.8" + } + }, + "ember-cli-htmlbars": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-4.5.0.tgz", + "integrity": "sha512-bYJpK1pqFu9AadDAGTw05g2LMNzY8xTCIqQm7dMJmKEoUpLRFbPf4SfHXrktzDh7Q5iggl6Skzf1M0bPlIxARw==", + "requires": { + "@ember/edition-utils": "^1.2.0", + "babel-plugin-htmlbars-inline-precompile": "^3.2.0", + "broccoli-debug": "^0.6.5", + "broccoli-persistent-filter": "^2.3.1", + "broccoli-plugin": "^3.1.0", + "common-tags": "^1.8.0", + "ember-cli-babel-plugin-helpers": "^1.1.0", + "fs-tree-diff": "^2.0.1", + "hash-for-dep": "^1.5.1", + "heimdalljs-logger": "^0.1.10", + "json-stable-stringify": "^1.0.1", + "semver": "^6.3.0", + "strip-bom": "^4.0.0", + "walk-sync": "^2.0.2" + } + }, + "fs-tree-diff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-2.0.1.tgz", + "integrity": "sha512-x+CfAZ/lJHQqwlD64pYM5QxWjzWhSjroaVsr8PW831zOApL55qPibed0c+xebaLWVr2BnHFoHdrwOv8pzt8R5A==", + "requires": { + "@types/symlink-or-copy": "^1.2.0", + "heimdalljs-logger": "^0.1.7", + "object-assign": "^4.1.0", + "path-posix": "^1.0.0", + "symlink-or-copy": "^1.1.8" + } + }, + "matcher-collection": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-2.0.1.tgz", + "integrity": "sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ==", + "requires": { + "@types/minimatch": "^3.0.3", + "minimatch": "^3.0.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" + }, + "walk-sync": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-2.2.0.tgz", + "integrity": "sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==", + "requires": { + "@types/minimatch": "^3.0.3", + "ensure-posix-path": "^1.1.0", + "matcher-collection": "^2.0.0", + "minimatch": "^3.0.4" + } + } + } + }, "ember-copy": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ember-copy/-/ember-copy-2.0.1.tgz", @@ -13135,10 +13233,9 @@ } }, "ember-destroyable-polyfill": { - "version": "2.0.3", + "version": "2.0.2", "resolved": "https://registry.npmjs.org/ember-destroyable-polyfill/-/ember-destroyable-polyfill-2.0.3.tgz", - "integrity": "sha512-TovtNqCumzyAiW0/OisSkkVK93xnVF4NRU6+FN0ubpfwEOpRrmM2RqDwXI6YAChCgSHON1cz0DfQStpA1Gjuuw==", - "dev": true, + "integrity": "sha512-9t+ya+9c+FkNM5IAyJIv6ETG8jfZQaUnFCO5SeLlV0wkSw7TOexyb61jh5GVee0KmknfRhrRGGAyT4Y0TwkZ+w==", "requires": { "ember-cli-babel": "^7.22.1", "ember-cli-version-checker": "^5.1.1", @@ -13149,7 +13246,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/ember-cli-version-checker/-/ember-cli-version-checker-5.1.2.tgz", "integrity": "sha512-rk7GY+FmLn/2e22HsZs0Ycrz8HQ1W3Fv+2TFOuEFW9optnDXDgkntPBIl6gact/LHsfBM5RKbM3dHsIIeLgl0Q==", - "dev": true, "requires": { "resolve-package-path": "^3.1.0", "semver": "^7.3.4", @@ -13160,7 +13256,6 @@ "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, "requires": { "lru-cache": "^6.0.0" } diff --git a/packages/reports/package.json b/packages/reports/package.json index 78a1a3602..f65df63e1 100644 --- a/packages/reports/package.json +++ b/packages/reports/package.json @@ -43,10 +43,11 @@ "ember-cli-moment-shim": "^3.8.0", "ember-cli-node-assets": "0.2.2", "ember-cli-shims": "^1.2.0", - "ember-cli-typescript": "^4.0.0", + "ember-cli-typescript": "^4.1.0", "ember-collection": "1.0.0-alpha.9", "ember-composable-helpers": "^4.1.1", - "ember-concurrency": "^1.3.0", + "ember-concurrency": "2.0.3", + "ember-concurrency-ts": "0.2.2", "ember-cp-validations": "^4.0.0-beta.10", "ember-data-model-fragments": "^5.0.0-beta.1", "ember-decorators": "^6.1.1", @@ -128,7 +129,7 @@ "npm-run-all": "^4.1.5", "qunit-dom": "^1.2.0", "sass": "^1.30.0", - "typescript": "^4.0.2" + "typescript": "^4.1.5" }, "engines": { "node": "10.* || >= 12" diff --git a/packages/reports/tests/integration/components/filter-values/dimension-select-test.ts b/packages/reports/tests/integration/components/filter-values/dimension-select-test.ts index 4503f2bd5..4ac1e2cf1 100644 --- a/packages/reports/tests/integration/components/filter-values/dimension-select-test.ts +++ b/packages/reports/tests/integration/components/filter-values/dimension-select-test.ts @@ -12,6 +12,7 @@ import config from 'ember-get-config'; import $ from 'jquery'; import Service from '@ember/service'; import NaviDimensionModel from 'navi-data/models/navi-dimension'; +import { task, TaskGenerator } from 'ember-concurrency'; import type { TestContext as Context } from 'ember-test-helpers'; import type FilterFragment from 'navi-core/models/bard-request-v2/fragments/filter'; import type FragmentFactory from 'navi-core/services/fragment-factory'; @@ -211,23 +212,18 @@ module('Integration | Component | filter values/dimension select', function (hoo ); }); - test('sort is applied numerically or lexicographically', async function (this: TestContext, assert) { - assert.expect(2); + test('sort is applied numerically', async function (this: TestContext, assert) { + assert.expect(1); this.filter = this.fragmentFactory.createFilter('dimension', 'bardOne', 'age', { field: 'id' }, 'in', []); - let LastValue: string | undefined = undefined; - this.owner.register( - 'service:navi-dimension', - class extends Service { - all(dimensionColumn: DimensionColumn) { - const values = ['1', '3', '2', '11', '111']; - if (LastValue) { - values.push(LastValue); - } - return values.map((value) => NaviDimensionModel.create({ value, dimensionColumn })); - } + class MockDimensions extends Service { + @task *all(dimensionColumn: DimensionColumn): TaskGenerator { + const values = ['1', '3', '2', '11', '111']; + return yield values.map((value) => NaviDimensionModel.create({ value, dimensionColumn })); } - ); + } + + this.owner.register('service:navi-dimension', MockDimensions); await render(TEMPLATE); // Open value selector @@ -235,16 +231,30 @@ module('Integration | Component | filter values/dimension select', function (hoo assert.deepEqual( findAll('.ember-power-select-option').map((el) => el.textContent?.trim()), ['1', '2', '3', '11', '111'], - 'Sort is applied as number for string number dimensions' + 'Sort is applied numerically for string number dimensions' ); + }); + + test('sort is applied lexicographically', async function (this: TestContext, assert) { + assert.expect(1); + this.filter = this.fragmentFactory.createFilter('dimension', 'bardOne', 'age', { field: 'id' }, 'in', []); - LastValue = 'stringvalue'; - await clickTrigger(); // close - await clickTrigger(); // open again + class MockDimensions extends Service { + @task *all(dimensionColumn: DimensionColumn): TaskGenerator { + const values = ['1', '3', '2', '11', '111', 'stringvalue']; + return yield values.map((value) => NaviDimensionModel.create({ value, dimensionColumn })); + } + } + + this.owner.register('service:navi-dimension', MockDimensions); + await render(TEMPLATE); + + // Open value selector + await clickTrigger(); assert.deepEqual( findAll('.ember-power-select-option').map((el) => el.textContent?.trim()), - ['1', '11', '111', '2', '3', LastValue], - 'Sort is applied as number for string number dimensions' + ['1', '11', '111', '2', '3', 'stringvalue'], + 'Sort is applied lexicographically if not all string values are numbers' ); }); @@ -252,15 +262,14 @@ module('Integration | Component | filter values/dimension select', function (hoo assert.expect(1); this.filter = this.fragmentFactory.createFilter('dimension', 'bardOne', 'property', { field: 'id' }, 'in', []); - this.owner.register( - 'service:navi-dimension', - class extends Service { - search(dimensionColumn: DimensionColumn) { - const values = ['1', '3', '2', '11', '111']; - return values.map((value) => NaviDimensionModel.create({ value: `Property ${value}`, dimensionColumn })); - } + class MockDimensions extends Service { + @task *search(dimensionColumn: DimensionColumn): TaskGenerator { + const values = ['1', '3', '2', '11', '111']; + return yield values.map((value) => NaviDimensionModel.create({ value: `Property ${value}`, dimensionColumn })); } - ); + } + + this.owner.register('service:navi-dimension', MockDimensions); await render(TEMPLATE); await clickTrigger(); // open diff --git a/packages/reports/tests/unit/routes/reports/report/view-test.js b/packages/reports/tests/unit/routes/reports/report/view-test.js index 12da99746..d300dbc53 100644 --- a/packages/reports/tests/unit/routes/reports/report/view-test.js +++ b/packages/reports/tests/unit/routes/reports/report/view-test.js @@ -3,6 +3,7 @@ import { run } from '@ember/runloop'; import { resolve } from 'rsvp'; import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; +import { task } from 'ember-concurrency'; module('Unit | Route | reports/report/view', function (hooks) { setupTest(hooks); @@ -36,29 +37,32 @@ module('Unit | Route | reports/report/view', function (hooks) { }, }; - let route = this.owner.factoryFor('route:reports/report/view').create({ - modelFor: () => reportModel, - facts: { - fetch(request, options) { - assert.deepEqual(request, serializedRequest, "Report's serialized request is given to fact service"); - - assert.deepEqual( - options, - { - page: 1, - perPage: 10000, - clientId: 'customReports', - customHeaders: { - uiView: 'report.spv.1', - }, - dataSourceName: undefined, + class MockFacts extends EmberObject { + @task *fetch(request, options) { + assert.deepEqual(request, serializedRequest, "Report's serialized request is given to fact service"); + + assert.deepEqual( + options, + { + page: 1, + perPage: 10000, + clientId: 'customReports', + customHeaders: { + uiView: 'report.spv.1', }, - 'Options from route are passed to fact service' - ); + dataSourceName: undefined, + }, + 'Options from route are passed to fact service' + ); - return resolve({ request: serializedRequest, response: factServiceResponse }); - }, - }, + return yield resolve({ request: serializedRequest, response: factServiceResponse }); + } + } + + const facts = MockFacts.create(); + let route = this.owner.factoryFor('route:reports/report/view').create({ + modelFor: () => reportModel, + facts, }); let model = await route.model(); diff --git a/packages/search/addon/components/navi-search-bar.js b/packages/search/addon/components/navi-search-bar.js index 4d5fdc88c..77ae1177b 100644 --- a/packages/search/addon/components/navi-search-bar.js +++ b/packages/search/addon/components/navi-search-bar.js @@ -68,9 +68,9 @@ export default class NaviSearchBarComponent extends Component { * @param {String} query * @returns {Array} results */ - @(task(function* (query) { + @task({ restartable: true }) + *launchQuery(query) { yield timeout(DEBOUNCE_MS); return this.searchProviderService.search(query); - }).restartable()) - launchQuery; + } } diff --git a/packages/search/addon/services/navi-base-search-provider.ts b/packages/search/addon/services/navi-base-search-provider.ts index be7760dbe..5953c2800 100644 --- a/packages/search/addon/services/navi-base-search-provider.ts +++ b/packages/search/addon/services/navi-base-search-provider.ts @@ -1,5 +1,5 @@ /** - * Copyright 2020, Yahoo Holdings Inc. + * Copyright 2021, Yahoo Holdings Inc. * Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms. * * Base search provider service. @@ -7,11 +7,12 @@ import Service from '@ember/service'; import { assert } from '@ember/debug'; +import type { TaskGenerator } from 'ember-concurrency'; export default class NaviBaseSearchProviderService extends Service { - resultThreshold: number = 10; + resultThreshold = 10; - search(): TODO { + search(_query: string): TaskGenerator { assert('Search method must be called from a subclass'); } } diff --git a/packages/search/addon/services/navi-search/navi-asset-search-provider.js b/packages/search/addon/services/navi-search/navi-asset-search-provider.js index 2eade27a5..d9e96fa08 100644 --- a/packages/search/addon/services/navi-search/navi-asset-search-provider.js +++ b/packages/search/addon/services/navi-search/navi-asset-search-provider.js @@ -1,10 +1,9 @@ /** - * Copyright 2020, Yahoo Holdings Inc. + * Copyright 2021, Yahoo Holdings Inc. * Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms. * * This service is used to search for reports and dashboards stored in the persistence layer. */ - import { inject as service } from '@ember/service'; import NaviBaseSearchProviderService from '../navi-base-search-provider'; import { task } from 'ember-concurrency'; @@ -76,7 +75,8 @@ export default class NaviAssetSearchProviderService extends NaviBaseSearchProvid * @yields {Promise} promise with search query results * @returns {Object} Object containing component, title, and data to be displayed */ - @(task(function* (query) { + @task({ restartable: true }) + *search(query) { const types = ['report', 'dashboard']; const promises = []; @@ -98,6 +98,5 @@ export default class NaviAssetSearchProviderService extends NaviBaseSearchProvid getPartialMatchWeight(resultB.title.toLowerCase(), query.toLowerCase()) ), }; - }).restartable()) - search; + } } diff --git a/packages/search/addon/services/navi-search/navi-definition-search-provider.ts b/packages/search/addon/services/navi-search/navi-definition-search-provider.ts index e84121e17..5b40f3ffb 100644 --- a/packages/search/addon/services/navi-search/navi-definition-search-provider.ts +++ b/packages/search/addon/services/navi-search/navi-definition-search-provider.ts @@ -1,17 +1,17 @@ /** - * Copyright 2020, Yahoo Holdings Inc. + * Copyright 2021, Yahoo Holdings Inc. * Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms. * * This service is used to search for definitions stored in the metadata. */ - -import { inject as service } from '@ember/service'; import NaviBaseSearchProviderService from '../navi-base-search-provider'; -//@ts-ignore +import { inject as service } from '@ember/service'; import { task } from 'ember-concurrency'; //@ts-ignore import { searchRecordsByFields } from 'navi-core/utils/search'; -import NaviMetadataService, { MetadataModelTypes } from 'navi-data/services/navi-metadata'; +import type { TaskGenerator } from 'ember-concurrency'; +import type NaviMetadataService from 'navi-data/services/navi-metadata'; +import type { MetadataModelTypes } from 'navi-data/services/navi-metadata'; export default class NaviDefinitionSearchProviderService extends NaviBaseSearchProviderService { @service @@ -28,8 +28,8 @@ export default class NaviDefinitionSearchProviderService extends NaviBaseSearchP * @param {String} query * @returns {Object} Object containing, component, title and data */ - // eslint-disable-next-line require-yield - @(task(function* (this: NaviDefinitionSearchProviderService, query: TODO) { + @task({ restartable: true }) + *search(query: string): TaskGenerator { const types: MetadataModelTypes[] = ['table', 'dimension', 'metric', 'timeDimension']; const kegData: TODO = []; let data = []; @@ -39,11 +39,10 @@ export default class NaviDefinitionSearchProviderService extends NaviBaseSearchP data = searchRecordsByFields(kegData, query, ['id', 'name', 'description']); } - return { + return yield { component: this.displayComponentName, title: 'Definition', data: data.slice(0, this.resultThreshold), }; - }).restartable()) - search: TODO; + } } diff --git a/packages/search/package-lock.json b/packages/search/package-lock.json index 0777f0a04..7cdc0127c 100644 --- a/packages/search/package-lock.json +++ b/packages/search/package-lock.json @@ -10829,14 +10829,16 @@ } }, "ember-concurrency": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-1.3.0.tgz", - "integrity": "sha512-DwGlfWFpYyAkTwsedlEtK4t1DznJSculAW6Vq5S1C0shVPc5b6tTpHB2FFYisannSYkm+wpm1f1Pd40qiNPtOQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ember-concurrency/-/ember-concurrency-2.0.3.tgz", + "integrity": "sha512-+fOOFt32odnunDL3Du0LqMgnRzDDNKnzo1ry9ppICpvLXekJzYFwU1RniVivfJ+9nbpHMJZQUlZJAm1ZAnTExw==", "dev": true, "requires": { - "ember-cli-babel": "^7.7.3", + "@glimmer/tracking": "^1.0.2", + "ember-cli-babel": "^7.22.1", + "ember-cli-htmlbars": "^5.6.3", "ember-compatibility-helpers": "^1.2.0", - "ember-maybe-import-regenerator": "^0.1.6" + "ember-destroyable-polyfill": "^2.0.2" } }, "ember-concurrency-decorators": { @@ -11038,6 +11040,111 @@ } } }, + "ember-concurrency-ts": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ember-concurrency-ts/-/ember-concurrency-ts-0.2.2.tgz", + "integrity": "sha512-03/NEhXczd93tpg0ycusj3bgXZS15wymU0K8eMvWftyzWS4B+UE03RzimOFrtOxJmE2mNj64hLJUZR9P8LelFw==", + "dev": true, + "requires": { + "ember-cli-babel": "^7.19.0", + "ember-cli-htmlbars": "^4.3.1" + }, + "dependencies": { + "broccoli-output-wrapper": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/broccoli-output-wrapper/-/broccoli-output-wrapper-2.0.0.tgz", + "integrity": "sha512-V/ozejo+snzNf75i/a6iTmp71k+rlvqjE3+jYfimuMwR1tjNNRdtfno+NGNQB2An9bIAeqZnKhMDurAznHAdtA==", + "dev": true, + "requires": { + "heimdalljs-logger": "^0.1.10" + } + }, + "broccoli-plugin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-3.1.0.tgz", + "integrity": "sha512-7w7FP8WJYjLvb0eaw27LO678TGGaom++49O1VYIuzjhXjK5kn2+AMlDm7CaUFw4F7CLGoVQeZ84d8gICMJa4lA==", + "dev": true, + "requires": { + "broccoli-node-api": "^1.6.0", + "broccoli-output-wrapper": "^2.0.0", + "fs-merger": "^3.0.1", + "promise-map-series": "^0.2.1", + "quick-temp": "^0.1.3", + "rimraf": "^2.3.4", + "symlink-or-copy": "^1.1.8" + } + }, + "ember-cli-htmlbars": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-4.5.0.tgz", + "integrity": "sha512-bYJpK1pqFu9AadDAGTw05g2LMNzY8xTCIqQm7dMJmKEoUpLRFbPf4SfHXrktzDh7Q5iggl6Skzf1M0bPlIxARw==", + "dev": true, + "requires": { + "@ember/edition-utils": "^1.2.0", + "babel-plugin-htmlbars-inline-precompile": "^3.2.0", + "broccoli-debug": "^0.6.5", + "broccoli-persistent-filter": "^2.3.1", + "broccoli-plugin": "^3.1.0", + "common-tags": "^1.8.0", + "ember-cli-babel-plugin-helpers": "^1.1.0", + "fs-tree-diff": "^2.0.1", + "hash-for-dep": "^1.5.1", + "heimdalljs-logger": "^0.1.10", + "json-stable-stringify": "^1.0.1", + "semver": "^6.3.0", + "strip-bom": "^4.0.0", + "walk-sync": "^2.0.2" + } + }, + "fs-tree-diff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-2.0.1.tgz", + "integrity": "sha512-x+CfAZ/lJHQqwlD64pYM5QxWjzWhSjroaVsr8PW831zOApL55qPibed0c+xebaLWVr2BnHFoHdrwOv8pzt8R5A==", + "dev": true, + "requires": { + "@types/symlink-or-copy": "^1.2.0", + "heimdalljs-logger": "^0.1.7", + "object-assign": "^4.1.0", + "path-posix": "^1.0.0", + "symlink-or-copy": "^1.1.8" + } + }, + "matcher-collection": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-2.0.1.tgz", + "integrity": "sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ==", + "dev": true, + "requires": { + "@types/minimatch": "^3.0.3", + "minimatch": "^3.0.2" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "walk-sync": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-2.2.0.tgz", + "integrity": "sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==", + "dev": true, + "requires": { + "@types/minimatch": "^3.0.3", + "ensure-posix-path": "^1.1.0", + "matcher-collection": "^2.0.0", + "minimatch": "^3.0.4" + } + } + } + }, "ember-data": { "version": "3.24.1", "resolved": "https://registry.npmjs.org/ember-data/-/ember-data-3.24.1.tgz", @@ -21365,9 +21472,9 @@ } }, "typescript": { - "version": "3.9.9", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz", - "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", + "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "dev": true }, "typescript-memoize": { diff --git a/packages/search/package.json b/packages/search/package.json index 02c1ae596..a9fbcbd89 100644 --- a/packages/search/package.json +++ b/packages/search/package.json @@ -31,7 +31,7 @@ "ember-cli-babel": "^7.17.2", "ember-cli-htmlbars": "^5.1.2", "ember-cli-mirage": "~1.1.6", - "ember-cli-typescript": "^4.0.0", + "ember-cli-typescript": "^4.1.0", "ember-data": "~3.24.0", "navi-core": "0.2.0", "navi-dashboards": "0.2.0", @@ -62,7 +62,8 @@ "ember-cli-typescript-blueprints": "^3.0.0", "ember-cli-uglify": "^3.0.0", "ember-composable-helpers": "^4.1.1", - "ember-concurrency": "^1.3.0", + "ember-concurrency": "2.0.3", + "ember-concurrency-ts": "0.2.2", "ember-disable-prototype-extensions": "^1.1.3", "ember-export-application-global": "^2.0.1", "ember-font-awesome": "^3.1.1", @@ -89,7 +90,7 @@ "npm-run-all": "^4.1.5", "qunit-dom": "^1.0.0", "sass": "^1.30.0", - "typescript": "^3.9.5" + "typescript": "^4.1.5" }, "engines": { "node": "8.* || >= 10.*" diff --git a/packages/search/tests/dummy/app/services/navi-search/navi-sample-search-provider.js b/packages/search/tests/dummy/app/services/navi-search/navi-sample-search-provider.js index 20aff9b98..319b44f94 100644 --- a/packages/search/tests/dummy/app/services/navi-search/navi-sample-search-provider.js +++ b/packages/search/tests/dummy/app/services/navi-search/navi-sample-search-provider.js @@ -1,11 +1,10 @@ /** - * Copyright 2020, Yahoo Holdings Inc. + * Copyright 2021, Yahoo Holdings Inc. * Licensed under the terms of the MIT license. See accompanying LICENSE.md file for terms. * * This is a sample search provider. */ - -import NaviBaseSearchProviderService from '../navi-base-search-provider'; +import NaviBaseSearchProviderService from 'navi-search/services/navi-base-search-provider'; import { task } from 'ember-concurrency'; import Response from 'ember-cli-mirage/response'; @@ -15,7 +14,8 @@ export default class NaviSampleSearchProviderService extends NaviBaseSearchProvi * @param {String} query * @returns {Object} Object containing results and dislay component */ - @(task(function* (query) { + @task({ restartable: true }) + *search(query) { let data = yield new Promise(function (resolve, reject) { let payload = []; if (query.toLowerCase().includes('sample')) { @@ -30,6 +30,5 @@ export default class NaviSampleSearchProviderService extends NaviBaseSearchProvi title: 'Sample', data, }; - }).restartable()) - search; + } } diff --git a/packages/search/tests/unit/services/navi-search-provider-test.js b/packages/search/tests/unit/services/navi-search-provider-test.js index ca0906688..450cb6c00 100644 --- a/packages/search/tests/unit/services/navi-search-provider-test.js +++ b/packages/search/tests/unit/services/navi-search-provider-test.js @@ -17,9 +17,9 @@ module('Unit | Service | navi-search-provider', function (hooks) { mockAuthor = store.createRecord('user', { id: 'ciela' }); this.owner.register( 'service:user', - Service.extend({ - getUser: () => mockAuthor, - }) + class extends Service { + getUser = () => mockAuthor; + } ); }); @@ -45,7 +45,7 @@ module('Unit | Service | navi-search-provider', function (hooks) { let results = service.search('sample'); assert.deepEqual( - results.map((result) => result.context.constructor.name), + results.map((result) => result.task.context.constructor.name), ['NaviAssetSearchProviderService', 'NaviDefinitionSearchProviderService', 'NaviSampleSearchProviderService'], 'Search returns a task instance of every available search provider' );