From 87d8a2a50bbd8c44460101a965d2e6d8ee9a9fb9 Mon Sep 17 00:00:00 2001 From: Michael Lange Date: Wed, 11 Oct 2017 13:44:27 -0700 Subject: [PATCH] Sync the active namespace as a query param on the jobs list page --- ui/app/components/allocation-row.js | 15 ++++++++----- ui/app/controllers/jobs/index.js | 32 +++++++++++++++++++++++++-- ui/app/routes/jobs/index.js | 18 +++++++++++++++ ui/app/templates/jobs/index.hbs | 4 ++-- ui/mirage/factories/job.js | 7 +++++- ui/tests/acceptance/jobs-list-test.js | 23 +++++++++++++++++++ 6 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 ui/app/routes/jobs/index.js diff --git a/ui/app/components/allocation-row.js b/ui/app/components/allocation-row.js index b210d5b01..129f096eb 100644 --- a/ui/app/components/allocation-row.js +++ b/ui/app/components/allocation-row.js @@ -47,10 +47,15 @@ export default Component.extend({ // and manually re-link the two records here. const allocation = this.get('allocation'); - this.get('store') - .findRecord('job', allocation.get('originalJobId')) - .then(job => { - allocation.set('job', job); - }); + const job = this.get('store').peekRecord('job', allocation.get('originalJobId')); + if (job) { + allocation.set('job', job); + } else { + this.get('store') + .findRecord('job', allocation.get('originalJobId')) + .then(job => { + allocation.set('job', job); + }); + } }, }); diff --git a/ui/app/controllers/jobs/index.js b/ui/app/controllers/jobs/index.js index 3dcdd053e..5e1c585fe 100644 --- a/ui/app/controllers/jobs/index.js +++ b/ui/app/controllers/jobs/index.js @@ -2,9 +2,11 @@ import Ember from 'ember'; import Sortable from 'nomad-ui/mixins/sortable'; import Searchable from 'nomad-ui/mixins/searchable'; -const { Controller, computed } = Ember; +const { Controller, computed, observer, inject } = Ember; export default Controller.extend(Sortable, Searchable, { + system: inject.service(), + pendingJobs: computed.filterBy('model', 'status', 'pending'), runningJobs: computed.filterBy('model', 'status', 'running'), deadJobs: computed.filterBy('model', 'status', 'dead'), @@ -14,22 +16,48 @@ export default Controller.extend(Sortable, Searchable, { searchTerm: 'search', sortProperty: 'sort', sortDescending: 'desc', + jobNamespace: 'namespace', }, currentPage: 1, pageSize: 10, + jobNamespace: 'default', sortProperty: 'modifyIndex', sortDescending: true, searchProps: computed(() => ['id', 'name']), - listToSort: computed.alias('model'), + filteredJobs: computed('model.[]', 'jobNamespace', function() { + if (this.get('system.namespaces.length')) { + return this.get('model').filterBy('namespace.name', this.get('jobNamespace')); + } else { + return this.get('model'); + } + }), + + listToSort: computed.alias('filteredJobs'), listToSearch: computed.alias('listSorted'), sortedJobs: computed.alias('listSearched'), isShowingDeploymentDetails: false, + // The namespace query param should act as an alias to the system active namespace. + // But query param defaults can't be CPs: https://github.com/emberjs/ember.js/issues/9819 + syncNamespaceService: observer('jobNamespace', function() { + const newNamespace = this.get('jobNamespace'); + const currentNamespace = this.get('system.activeNamespace.id'); + const bothAreDefault = + currentNamespace == undefined || + (currentNamespace === 'default' && newNamespace == undefined) || + newNamespace === 'default'; + + if (currentNamespace !== newNamespace && !bothAreDefault) { + this.set('system.activeNamespace', newNamespace); + this.send('refreshRoute'); + } + }), + actions: { gotoJob(job) { this.transitionToRoute('jobs.job', job); diff --git a/ui/app/routes/jobs/index.js b/ui/app/routes/jobs/index.js new file mode 100644 index 000000000..2893e7e9a --- /dev/null +++ b/ui/app/routes/jobs/index.js @@ -0,0 +1,18 @@ +import Ember from 'ember'; + +const { Route, inject } = Ember; + +export default Route.extend({ + system: inject.service(), + + setupController(controller) { + this._super(...arguments); + + const namespace = this.get('system.activeNamespace.id'); + if (namespace && namespace !== 'default') { + controller.set('jobNamespace', namespace); + } else { + controller.set('jobNamespace', 'default'); + } + }, +}); diff --git a/ui/app/templates/jobs/index.hbs b/ui/app/templates/jobs/index.hbs index bea0dd239..a49c338cb 100644 --- a/ui/app/templates/jobs/index.hbs +++ b/ui/app/templates/jobs/index.hbs @@ -3,7 +3,7 @@ {{/global-header}} {{#gutter-menu class="page-body" onNamespaceChange=(action "refresh")}}
- {{#if model.length}} + {{#if filteredJobs.length}}
{{search-box searchTerm=(mut searchTerm) placeholder="Search jobs..."}}
@@ -41,7 +41,7 @@ {{else}}
- {{#if (eq model.length 0)}} + {{#if (eq filteredJobs.length 0)}}

No Jobs

There are currently no visible jobs in the cluster. It could be that the cluster is empty. It could also mean {{#link-to "settings.tokens"}}you don't have access to see any jobs{{/link-to}}. diff --git a/ui/mirage/factories/job.js b/ui/mirage/factories/job.js index 18cf21da3..7cc5372f5 100644 --- a/ui/mirage/factories/job.js +++ b/ui/mirage/factories/job.js @@ -50,9 +50,14 @@ export default Factory.extend({ job.update({ taskGroupIds: groups.mapBy('id'), task_group_ids: groups.mapBy('id'), - namespaceId: server.db.namespaces.length ? pickOne(server.db.namespaces).id : null, }); + if (!job.namespaceId) { + job.update({ + namespaceId: server.db.namespaces.length ? pickOne(server.db.namespaces).id : null, + }); + } + const jobSummary = server.create('job-summary', { groupNames: groups.mapBy('name'), job, diff --git a/ui/tests/acceptance/jobs-list-test.js b/ui/tests/acceptance/jobs-list-test.js index 36f0fb576..b0ffac36a 100644 --- a/ui/tests/acceptance/jobs-list-test.js +++ b/ui/tests/acceptance/jobs-list-test.js @@ -107,3 +107,26 @@ test('when there are jobs, but no matches for a search result, there is an empty assert.equal(find('.empty-message-headline').textContent, 'No Matches'); }); }); + +test('when the namespace query param is set, only matching jobs are shown and the namespace value is forwarded to app state', function( + assert +) { + server.createList('namespace', 2); + const job1 = server.create('job', { namespaceId: server.db.namespaces[0].id }); + const job2 = server.create('job', { namespaceId: server.db.namespaces[1].id }); + + visit('/jobs'); + + andThen(() => { + assert.equal(findAll('.job-row').length, 1, 'One job in the default namespace'); + assert.equal(find('.job-row td').textContent, job1.name, 'The correct job is shown'); + }); + + const secondNamespace = server.db.namespaces[1]; + visit(`/jobs?namespace=${secondNamespace.id}`); + + andThen(() => { + assert.equal(findAll('.job-row').length, 1, `One job in the ${secondNamespace.name} namespace`); + assert.equal(find('.job-row td').textContent, job2.name, 'The correct job is shown'); + }); +});