From 6bccb3b42fd0bb5b65e2aada510ab92507d716b5 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Mon, 9 Nov 2020 17:42:27 -0500 Subject: [PATCH] feat: Show scopes in header in desktop --- ui/desktop/app/router.js | 4 +- ui/desktop/app/routes/index.js | 12 +++ ui/desktop/app/routes/scopes/scope.js | 79 +++++++++++++++++++ ui/desktop/app/services/scope.js | 17 ++++ ui/desktop/app/templates/application.hbs | 4 + ui/desktop/app/templates/index.hbs | 1 + ui/desktop/app/templates/scopes.hbs | 5 +- ui/desktop/app/templates/scopes/index.hbs | 26 ++++++ ui/desktop/app/templates/scopes/scope.hbs | 1 + .../templates/scopes/scope/-header-nav.hbs | 16 ++++ .../app/templates/scopes/scope/index.hbs | 1 + ui/desktop/config/environment.js | 4 +- ui/desktop/package.json | 3 +- ui/desktop/public/app-icons/global.svg | 3 + ui/desktop/public/app-icons/org.svg | 3 + ui/desktop/tests/unit/routes/index-test.js | 11 +++ .../tests/unit/routes/scopes/scope-test.js | 11 +++ ui/desktop/tests/unit/services/scope-test.js | 12 +++ ui/desktop/translations/en-us.yaml | 2 + ui/desktop/vendor/.gitkeep | 0 yarn.lock | 36 +++++---- 21 files changed, 229 insertions(+), 22 deletions(-) create mode 100644 ui/desktop/app/routes/index.js create mode 100644 ui/desktop/app/routes/scopes/scope.js create mode 100644 ui/desktop/app/services/scope.js create mode 100644 ui/desktop/app/templates/index.hbs create mode 100644 ui/desktop/app/templates/scopes/index.hbs create mode 100644 ui/desktop/app/templates/scopes/scope.hbs create mode 100644 ui/desktop/app/templates/scopes/scope/-header-nav.hbs create mode 100644 ui/desktop/app/templates/scopes/scope/index.hbs create mode 100644 ui/desktop/public/app-icons/global.svg create mode 100644 ui/desktop/public/app-icons/org.svg create mode 100644 ui/desktop/tests/unit/routes/index-test.js create mode 100644 ui/desktop/tests/unit/routes/scopes/scope-test.js create mode 100644 ui/desktop/tests/unit/services/scope-test.js create mode 100644 ui/desktop/translations/en-us.yaml delete mode 100644 ui/desktop/vendor/.gitkeep diff --git a/ui/desktop/app/router.js b/ui/desktop/app/router.js index 32dc22624..335c69db4 100644 --- a/ui/desktop/app/router.js +++ b/ui/desktop/app/router.js @@ -7,5 +7,7 @@ export default class Router extends EmberRouter { } Router.map(function () { - this.route('scopes'); + this.route('scopes', function() { + this.route('scope', { path: ':scope_id' }, function() {}); + }); }); diff --git a/ui/desktop/app/routes/index.js b/ui/desktop/app/routes/index.js new file mode 100644 index 000000000..c8728d037 --- /dev/null +++ b/ui/desktop/app/routes/index.js @@ -0,0 +1,12 @@ +import Route from '@ember/routing/route'; + +export default class IndexRoute extends Route { + // =methods + + /** + * Redirects to scopes route for further processing. + */ + redirect() { + this.transitionTo('scopes'); + } +} diff --git a/ui/desktop/app/routes/scopes/scope.js b/ui/desktop/app/routes/scopes/scope.js new file mode 100644 index 000000000..53ab105d3 --- /dev/null +++ b/ui/desktop/app/routes/scopes/scope.js @@ -0,0 +1,79 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; +import { A } from '@ember/array'; + +export default class ScopesScopeRoute extends Route { + // =services + + @service scope; + + // =methods + + /** + * Attempt to load the specified scope from the API. This is allowed + * to fail, since in some cases the user may not have permission to read a + * scope directly, but may have permission to read resources under it. + * If the scope fails to load, we still proceed using a temporary scope object + * consisting of only the specified ID. + * @param {object} params + * @param {string} params.scope_id + * @return {Promise{ScopeModel}} + */ + model({ scope_id: id }) { + // Since only global and org scopes are authenticatable, we can infer type + // from ID because global has a fixed ID. + const type = id === 'global' ? 'global' : 'org'; + return this.store.findRecord('scope', id).catch(() => { + console.error('caught error'); + const maybeExistingScope = this.store.peekRecord('scope', id); + + const scopeOptions = { id, type }; + return ( + maybeExistingScope || this.store.createRecord('scope', scopeOptions) + ); + }); + } + + + /** + * Load all scopes within the current scope context. Always attempt to load + * org scopes. Only attempt to load project scopes if the current scope is + * a project. These are used for scope navigation. + */ + async afterModel(model) { + // Load all orgs + let orgs; + orgs = await this.store.query('scope', { scope_id: 'global' }) + .catch(() => A([])); + // Then pull out the "selected" scopes, if relevant + let selectedOrg; + if (model.isGlobal || model.isOrg) selectedOrg = model; + // Update the scope service with the current scope(s); + this.scope.org = selectedOrg; + this.scopes = { orgs, selectedOrg }; + } + + /** + * Adds the scopes hash to the controller context (see `afterModel`). + * @param {Controller} controller + */ + setupController(controller) { + super.setupController(...arguments); + const scopes = this.scopes; + controller.setProperties({ scopes }); + } + + /** + * Renders the scope-specific sidebar template. + * @override + * @param {object} controller + * @param {object} model + */ + renderTemplate() { + super.renderTemplate(...arguments); + this.render('scopes/scope/-header-nav', { + into: 'application', + outlet: 'header-nav', + }); + } +} diff --git a/ui/desktop/app/services/scope.js b/ui/desktop/app/services/scope.js new file mode 100644 index 000000000..37037eb23 --- /dev/null +++ b/ui/desktop/app/services/scope.js @@ -0,0 +1,17 @@ +import Service from '@ember/service'; +import { tracked } from '@glimmer/tracking'; + +/** + * This simple non-functional service is used to retain references to + * the currently active scope or scopes. + */ +export default class ScopeService extends Service { + + // =attributes + + /** + * @type {ScopeModel} + */ + @tracked org; + +} diff --git a/ui/desktop/app/templates/application.hbs b/ui/desktop/app/templates/application.hbs index 23f96480a..bab0cd57b 100644 --- a/ui/desktop/app/templates/application.hbs +++ b/ui/desktop/app/templates/application.hbs @@ -5,6 +5,10 @@ + + + {{outlet "header-nav"}} + diff --git a/ui/desktop/app/templates/index.hbs b/ui/desktop/app/templates/index.hbs new file mode 100644 index 000000000..e2147cab0 --- /dev/null +++ b/ui/desktop/app/templates/index.hbs @@ -0,0 +1 @@ +{{outlet}} \ No newline at end of file diff --git a/ui/desktop/app/templates/scopes.hbs b/ui/desktop/app/templates/scopes.hbs index 257dd84b7..c24cd6895 100644 --- a/ui/desktop/app/templates/scopes.hbs +++ b/ui/desktop/app/templates/scopes.hbs @@ -1,4 +1 @@ -I'm in scopes -{{@model}} - -{{outlet}} \ No newline at end of file +{{outlet}} diff --git a/ui/desktop/app/templates/scopes/index.hbs b/ui/desktop/app/templates/scopes/index.hbs new file mode 100644 index 000000000..cde799ad1 --- /dev/null +++ b/ui/desktop/app/templates/scopes/index.hbs @@ -0,0 +1,26 @@ +{{outlet}} + + + + + Scope + + + + {{#each @model as |scope|}} + + + + {{scope.name}} + + + + {{scope.id}} + + + {{/each}} + + diff --git a/ui/desktop/app/templates/scopes/scope.hbs b/ui/desktop/app/templates/scopes/scope.hbs new file mode 100644 index 000000000..c24cd6895 --- /dev/null +++ b/ui/desktop/app/templates/scopes/scope.hbs @@ -0,0 +1 @@ +{{outlet}} diff --git a/ui/desktop/app/templates/scopes/scope/-header-nav.hbs b/ui/desktop/app/templates/scopes/scope/-header-nav.hbs new file mode 100644 index 000000000..4a383eb6d --- /dev/null +++ b/ui/desktop/app/templates/scopes/scope/-header-nav.hbs @@ -0,0 +1,16 @@ + + {{!-- {{#if this.session.data.authenticated.isGlobal}} --}} + + {{t "titles.global"}} + + + {{!-- {{/if}} --}} + {{#each this.scopes.orgs as |scope|}} + + {{scope.displayName}} + + {{/each}} + diff --git a/ui/desktop/app/templates/scopes/scope/index.hbs b/ui/desktop/app/templates/scopes/scope/index.hbs new file mode 100644 index 000000000..c24cd6895 --- /dev/null +++ b/ui/desktop/app/templates/scopes/scope/index.hbs @@ -0,0 +1 @@ +{{outlet}} diff --git a/ui/desktop/config/environment.js b/ui/desktop/config/environment.js index 2de008f1c..dbd5328b7 100644 --- a/ui/desktop/config/environment.js +++ b/ui/desktop/config/environment.js @@ -7,8 +7,8 @@ module.exports = function (environment) { let ENV = { modulePrefix: 'desktop', environment, - rootURL: process.env.EMBER_CLI_ELECTRON ? '' : process.env.EMBER_CLI_ELECTRON ? '' : '/', - locationType: process.env.EMBER_CLI_ELECTRON ? 'hash' : process.env.EMBER_CLI_ELECTRON ? 'hash' : 'auto', + rootURL: process.env.EMBER_CLI_ELECTRON ? '' : process.env.EMBER_CLI_ELECTRON ? '' : process.env.EMBER_CLI_ELECTRON ? '' : '/', + locationType: process.env.EMBER_CLI_ELECTRON ? 'hash' : process.env.EMBER_CLI_ELECTRON ? 'hash' : process.env.EMBER_CLI_ELECTRON ? 'hash' : 'auto', EmberENV: { FEATURES: { // Here you can enable experimental features on an ember canary build diff --git a/ui/desktop/package.json b/ui/desktop/package.json index fe4414ee7..ee6ec558d 100644 --- a/ui/desktop/package.json +++ b/ui/desktop/package.json @@ -53,7 +53,7 @@ "ember-cli-template-lint": "^2.0.2", "ember-cli-uglify": "^3.0.0", "ember-data": "~3.20.0", - "ember-data-model-fragments": "^4.0.0", + "ember-data-model-fragments": "5.0.0-beta.0", "ember-electron": "https://github.com/adopted-ember-addons/ember-electron#v3.0.0-beta.4", "ember-exam": "^6.0.1", "ember-export-application-global": "^2.0.1", @@ -62,6 +62,7 @@ "ember-intl": "^5.5.0", "ember-load-initializers": "^2.1.1", "ember-maybe-import-regenerator": "^0.1.6", + "ember-modifier": "^2.1.1", "ember-page-title": "^6.0.3", "ember-qunit": "^4.6.0", "ember-resolver": "^8.0.0", diff --git a/ui/desktop/public/app-icons/global.svg b/ui/desktop/public/app-icons/global.svg new file mode 100644 index 000000000..0e5b84d47 --- /dev/null +++ b/ui/desktop/public/app-icons/global.svg @@ -0,0 +1,3 @@ + + + diff --git a/ui/desktop/public/app-icons/org.svg b/ui/desktop/public/app-icons/org.svg new file mode 100644 index 000000000..238cc8435 --- /dev/null +++ b/ui/desktop/public/app-icons/org.svg @@ -0,0 +1,3 @@ + + + diff --git a/ui/desktop/tests/unit/routes/index-test.js b/ui/desktop/tests/unit/routes/index-test.js new file mode 100644 index 000000000..eaaac17bc --- /dev/null +++ b/ui/desktop/tests/unit/routes/index-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | index', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:index'); + assert.ok(route); + }); +}); diff --git a/ui/desktop/tests/unit/routes/scopes/scope-test.js b/ui/desktop/tests/unit/routes/scopes/scope-test.js new file mode 100644 index 000000000..62c97d9f0 --- /dev/null +++ b/ui/desktop/tests/unit/routes/scopes/scope-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | scopes/scope', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:scopes/scope'); + assert.ok(route); + }); +}); diff --git a/ui/desktop/tests/unit/services/scope-test.js b/ui/desktop/tests/unit/services/scope-test.js new file mode 100644 index 000000000..95493c0b4 --- /dev/null +++ b/ui/desktop/tests/unit/services/scope-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Service | scope', function(hooks) { + setupTest(hooks); + + // TODO: Replace this with your real tests. + test('it exists', function(assert) { + let service = this.owner.lookup('service:scope'); + assert.ok(service); + }); +}); diff --git a/ui/desktop/translations/en-us.yaml b/ui/desktop/translations/en-us.yaml new file mode 100644 index 000000000..960b00647 --- /dev/null +++ b/ui/desktop/translations/en-us.yaml @@ -0,0 +1,2 @@ +titles: + global: Global diff --git a/ui/desktop/vendor/.gitkeep b/ui/desktop/vendor/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/yarn.lock b/yarn.lock index 1d5213a95..d410d9114 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8229,7 +8229,7 @@ ember-cli-babel@7.21.0: rimraf "^3.0.1" semver "^5.5.0" -ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.11.0, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.3.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.2: +ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.11.0, ember-cli-babel@^6.12.0, ember-cli-babel@^6.16.0, ember-cli-babel@^6.3.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1, ember-cli-babel@^6.8.2, ember-cli-babel@^6.9.2: version "6.18.0" resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.18.0.tgz#3f6435fd275172edeff2b634ee7b29ce74318957" integrity sha512-7ceC8joNYxY2wES16iIBlbPSxwKDBhYwC8drU3ZEvuPDMwVv1KzxCNu1fvxyFEBWhwaRNTUxSCsEVoTd9nosGA== @@ -8775,19 +8775,6 @@ ember-data-model-fragments@5.0.0-beta.0: git-repo-info "^2.0.0" npm-git-info "^1.0.3" -ember-data-model-fragments@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/ember-data-model-fragments/-/ember-data-model-fragments-4.0.0.tgz#8570d8b6bef12e8a3518279af01478ef8818a44f" - integrity sha512-DcRRQAWrrfRQBW8+v6takQdS2hNJ9rKWU/uHjnPY6+Vg/y6TxyPU8mo0PF2z0DYAeXwoIQ05iYTJT0sqFPEo+w== - dependencies: - broccoli-file-creator "^2.1.1" - broccoli-merge-trees "^3.0.0" - calculate-cache-key-for-tree "^1.1.0" - ember-cli-babel "^6.8.0" - ember-copy "1.0.0" - git-repo-info "^2.0.0" - npm-git-info "^1.0.3" - ember-data@^3.16.0: version "3.22.1" resolved "https://registry.yarnpkg.com/ember-data/-/ember-data-3.22.1.tgz#5b075fc8a2c3f18dac2305037d34b88666631b1a" @@ -8837,6 +8824,15 @@ ember-decorators-polyfill@^1.1.5: ember-cli-version-checker "^3.1.3" ember-compatibility-helpers "^1.2.0" +ember-destroyable-polyfill@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ember-destroyable-polyfill/-/ember-destroyable-polyfill-2.0.2.tgz#2cc7532bd3c00e351b4da9b7fc683f4daff79671" + integrity sha512-9t+ya+9c+FkNM5IAyJIv6ETG8jfZQaUnFCO5SeLlV0wkSw7TOexyb61jh5GVee0KmknfRhrRGGAyT4Y0TwkZ+w== + dependencies: + ember-cli-babel "^7.22.1" + ember-cli-version-checker "^5.1.1" + ember-compatibility-helpers "^1.2.1" + ember-disable-prototype-extensions@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" @@ -9054,6 +9050,18 @@ ember-modifier@^1.0.3: ember-compatibility-helpers "^1.2.1" ember-modifier-manager-polyfill "^1.2.0" +ember-modifier@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ember-modifier/-/ember-modifier-2.1.1.tgz#aa3a12e2d6cf1622f774f3f1eab4880982a43fa9" + integrity sha512-g9mcpFWgw5lgNU40YNf0USNWqoGTJ+EqjDQKjm7556gaRNDeGnLylFKqx9O3opwLHEt6ZODnRDy9U0S5YEMREg== + dependencies: + ember-cli-babel "^7.22.1" + ember-cli-normalize-entity-name "^1.0.0" + ember-cli-string-utils "^1.1.0" + ember-cli-typescript "^3.1.3" + ember-destroyable-polyfill "^2.0.2" + ember-modifier-manager-polyfill "^1.2.0" + ember-notify@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/ember-notify/-/ember-notify-6.0.0.tgz#f92978e3452934f7c9b70d76ad2ec62bf072495a"