From dc3c0b134ac097aa8c5b8ddf7c472f5e59967863 Mon Sep 17 00:00:00 2001 From: Jai Bhagat Date: Sat, 20 Nov 2021 10:04:15 -0500 Subject: [PATCH 01/11] feat: add status filter to allocations --- ui/app/controllers/jobs/job/allocations.js | 45 +++++++-- ui/app/templates/jobs/job/allocations.hbs | 102 ++++++++++++++++----- 2 files changed, 116 insertions(+), 31 deletions(-) diff --git a/ui/app/controllers/jobs/job/allocations.js b/ui/app/controllers/jobs/job/allocations.js index a01c19951..a8fc3dad6 100644 --- a/ui/app/controllers/jobs/job/allocations.js +++ b/ui/app/controllers/jobs/job/allocations.js @@ -4,14 +4,15 @@ import { action, computed } from '@ember/object'; import Sortable from 'nomad-ui/mixins/sortable'; import Searchable from 'nomad-ui/mixins/searchable'; import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting'; +import { serialize, deserializedQueryParam as selection } from 'nomad-ui/utils/qp-serialize'; import classic from 'ember-classic-decorator'; @classic export default class AllocationsController extends Controller.extend( - Sortable, - Searchable, - WithNamespaceResetting - ) { + Sortable, + Searchable, + WithNamespaceResetting +) { queryParams = [ { currentPage: 'page', @@ -25,8 +26,12 @@ export default class AllocationsController extends Controller.extend( { sortDescending: 'desc', }, + { + qpStatus: 'status', + }, ]; + qpStatus = ''; currentPage = 1; pageSize = 25; @@ -40,11 +45,24 @@ export default class AllocationsController extends Controller.extend( return ['shortId', 'name', 'taskGroupName']; } - @computed('model.allocations.[]') + @computed('model.allocations.[]', 'selectionStatus') get allocations() { - return this.get('model.allocations') || []; + const allocations = this.get('model.allocations') || []; + const { selectionStatus } = this; + + if (!allocations.length) return allocations; + + return allocations.filter(alloc => { + if (selectionStatus.length && !selectionStatus.includes(alloc.status)) { + return false; + } + + return true; + }); } + @selection('qpStatus') selectionStatus; + @alias('allocations') listToSort; @alias('listSorted') listToSearch; @alias('listSearched') sortedAllocations; @@ -53,4 +71,19 @@ export default class AllocationsController extends Controller.extend( gotoAllocation(allocation) { this.transitionToRoute('allocations.allocation', allocation); } + + get optionsAllocationStatus() { + return [ + { key: 'queued', label: 'Queued' }, + { key: 'starting', label: 'Starting' }, + { key: 'running', label: 'Running' }, + { key: 'complete', label: 'Complete' }, + { key: 'failed', label: 'Failed' }, + { key: 'lost', label: 'Lost' }, + ]; + } + + setFacetQueryParam(queryParam, selection) { + this.set(queryParam, serialize(selection)); + } } diff --git a/ui/app/templates/jobs/job/allocations.hbs b/ui/app/templates/jobs/job/allocations.hbs index e14452e48..7d62da118 100644 --- a/ui/app/templates/jobs/job/allocations.hbs +++ b/ui/app/templates/jobs/job/allocations.hbs @@ -1,14 +1,26 @@ {{page-title "Job " this.job.name " allocations"}}
- {{#if this.allocations.length}} -
-
+ {{#if this.model.allocations.length}} +
+
+ @placeholder="Search allocations..." + /> +
+
+
+ +
{{#if this.sortedAllocations}} @@ -16,40 +28,69 @@ @source={{this.sortedAllocations}} @size={{this.pageSize}} @page={{this.currentPage}} - @class="allocations" as |p|> + @class="allocations" as |p| + > + @class="with-foot" as |t| + > - ID - Task Group - Created - Modified - Status - Version - Client - Volume - CPU - Memory + + ID + + + Task Group + + + Created + + + Modified + + + Status + + + Version + + + Client + + + Volume + + + CPU + + + Memory + + @onClick={{action "gotoAllocation" row.model}} + />
@@ -57,17 +98,28 @@ {{else}}
-

No Matches

-

No allocations match the term {{this.searchTerm}}

+

+ No Matches +

+

+ No allocations match the term + + {{this.searchTerm}} + +

{{/if}} {{else}}
-

No Allocations

-

No allocations have been placed.

+

+ No Allocations +

+

+ No allocations have been placed. +

{{/if}} -
+ \ No newline at end of file From 14206f4c4f1f2db2278fcdb56be2e5c4070d5b25 Mon Sep 17 00:00:00 2001 From: Jai Bhagat Date: Sat, 20 Nov 2021 10:21:28 -0500 Subject: [PATCH 02/11] feat: add client status filter --- ui/app/controllers/jobs/job/allocations.js | 28 ++++++++++++++++++++-- ui/app/templates/jobs/job/allocations.hbs | 7 ++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/ui/app/controllers/jobs/job/allocations.js b/ui/app/controllers/jobs/job/allocations.js index a8fc3dad6..8aa14e1e7 100644 --- a/ui/app/controllers/jobs/job/allocations.js +++ b/ui/app/controllers/jobs/job/allocations.js @@ -1,6 +1,9 @@ +/* eslint-disable ember/no-incorrect-calls-with-inline-anonymous-functions */ import { alias } from '@ember/object/computed'; import Controller from '@ember/controller'; import { action, computed } from '@ember/object'; +import { scheduleOnce } from '@ember/runloop'; +import intersection from 'lodash.intersection'; import Sortable from 'nomad-ui/mixins/sortable'; import Searchable from 'nomad-ui/mixins/searchable'; import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting'; @@ -29,9 +32,13 @@ export default class AllocationsController extends Controller.extend( { qpStatus: 'status', }, + { + qpClient: 'client', + }, ]; qpStatus = ''; + qpClient = ''; currentPage = 1; pageSize = 25; @@ -45,10 +52,10 @@ export default class AllocationsController extends Controller.extend( return ['shortId', 'name', 'taskGroupName']; } - @computed('model.allocations.[]', 'selectionStatus') + @computed('model.allocations.[]', 'selectionStatus', 'selectionClient') get allocations() { const allocations = this.get('model.allocations') || []; - const { selectionStatus } = this; + const { selectionStatus, selectionClient } = this; if (!allocations.length) return allocations; @@ -56,12 +63,16 @@ export default class AllocationsController extends Controller.extend( if (selectionStatus.length && !selectionStatus.includes(alloc.status)) { return false; } + if (selectionClient.length && !selectionClient.includes(alloc.get('node.shortId'))) { + return false; + } return true; }); } @selection('qpStatus') selectionStatus; + @selection('qpClient') selectionClient; @alias('allocations') listToSort; @alias('listSorted') listToSearch; @@ -83,6 +94,19 @@ export default class AllocationsController extends Controller.extend( ]; } + @computed('model.allocations.[]', 'selectionClient') + get optionsClients() { + const clients = Array.from(new Set(this.model.allocations.mapBy('node.shortId'))).compact(); + + // Update query param when the list of clients changes. + scheduleOnce('actions', () => { + // eslint-disable-next-line ember/no-side-effects + this.set('qpClient', serialize(intersection(clients, this.selectionClient))); + }); + + return clients.sort().map(dc => ({ key: dc, label: dc })); + } + setFacetQueryParam(queryParam, selection) { this.set(queryParam, serialize(selection)); } diff --git a/ui/app/templates/jobs/job/allocations.hbs b/ui/app/templates/jobs/job/allocations.hbs index 7d62da118..320575a51 100644 --- a/ui/app/templates/jobs/job/allocations.hbs +++ b/ui/app/templates/jobs/job/allocations.hbs @@ -20,6 +20,13 @@ @selection={{this.selectionStatus}} @onSelect={{action this.setFacetQueryParam "qpStatus"}} /> + From c351e68bed679f3ca205b642ccc694fff8962c3c Mon Sep 17 00:00:00 2001 From: Jai Bhagat Date: Sat, 20 Nov 2021 10:30:48 -0500 Subject: [PATCH 03/11] feat: add taskgroup filter to alloc --- ui/app/controllers/jobs/job/allocations.js | 25 ++++++++++++++++++++-- ui/app/templates/jobs/job/allocations.hbs | 7 ++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/ui/app/controllers/jobs/job/allocations.js b/ui/app/controllers/jobs/job/allocations.js index 8aa14e1e7..15ba86319 100644 --- a/ui/app/controllers/jobs/job/allocations.js +++ b/ui/app/controllers/jobs/job/allocations.js @@ -35,10 +35,14 @@ export default class AllocationsController extends Controller.extend( { qpClient: 'client', }, + { + qpTaskGroup: 'taskGroup', + }, ]; qpStatus = ''; qpClient = ''; + qpTaskGroup = ''; currentPage = 1; pageSize = 25; @@ -52,10 +56,10 @@ export default class AllocationsController extends Controller.extend( return ['shortId', 'name', 'taskGroupName']; } - @computed('model.allocations.[]', 'selectionStatus', 'selectionClient') + @computed('model.allocations.[]', 'selectionStatus', 'selectionClient', 'selectionTaskGroup') get allocations() { const allocations = this.get('model.allocations') || []; - const { selectionStatus, selectionClient } = this; + const { selectionStatus, selectionClient, selectionTaskGroup } = this; if (!allocations.length) return allocations; @@ -66,6 +70,9 @@ export default class AllocationsController extends Controller.extend( if (selectionClient.length && !selectionClient.includes(alloc.get('node.shortId'))) { return false; } + if (selectionTaskGroup.length && !selectionTaskGroup.includes(alloc.taskGroupName)) { + return false; + } return true; }); @@ -73,6 +80,7 @@ export default class AllocationsController extends Controller.extend( @selection('qpStatus') selectionStatus; @selection('qpClient') selectionClient; + @selection('qpTaskGroup') selectionTaskGroup; @alias('allocations') listToSort; @alias('listSorted') listToSearch; @@ -107,6 +115,19 @@ export default class AllocationsController extends Controller.extend( return clients.sort().map(dc => ({ key: dc, label: dc })); } + @computed('model.allocations.[]', 'selectionTaskGroup') + get optionsTaskGroups() { + const taskGroups = Array.from(new Set(this.model.allocations.mapBy('taskGroupName'))).compact(); + + // Update query param when the list of clients changes. + scheduleOnce('actions', () => { + // eslint-disable-next-line ember/no-side-effects + this.set('qpTaskGroup', serialize(intersection(taskGroups, this.selectionTaskGroup))); + }); + + return taskGroups.sort().map(dc => ({ key: dc, label: dc })); + } + setFacetQueryParam(queryParam, selection) { this.set(queryParam, serialize(selection)); } diff --git a/ui/app/templates/jobs/job/allocations.hbs b/ui/app/templates/jobs/job/allocations.hbs index 320575a51..2e164ad89 100644 --- a/ui/app/templates/jobs/job/allocations.hbs +++ b/ui/app/templates/jobs/job/allocations.hbs @@ -27,6 +27,13 @@ @selection={{this.selectionClient}} @onSelect={{action this.setFacetQueryParam "qpClient"}} /> + From c3f14395f8b6a8c0530d58b542e7d1ddac111b8e Mon Sep 17 00:00:00 2001 From: Jai Bhagat Date: Sat, 20 Nov 2021 10:49:31 -0500 Subject: [PATCH 04/11] disable eslint for indentation --- ui/app/controllers/jobs/job/allocations.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/app/controllers/jobs/job/allocations.js b/ui/app/controllers/jobs/job/allocations.js index 15ba86319..d8e63f201 100644 --- a/ui/app/controllers/jobs/job/allocations.js +++ b/ui/app/controllers/jobs/job/allocations.js @@ -12,6 +12,7 @@ import classic from 'ember-classic-decorator'; @classic export default class AllocationsController extends Controller.extend( + /*eslint-disable indent */ Sortable, Searchable, WithNamespaceResetting From d1ff1cb82f34c0da647acd5c38c5b173fd856a6a Mon Sep 17 00:00:00 2001 From: Jai Bhagat Date: Tue, 23 Nov 2021 17:57:35 -0500 Subject: [PATCH 05/11] fix: filter callbacks use different param --- ui/app/controllers/jobs/job/allocations.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/app/controllers/jobs/job/allocations.js b/ui/app/controllers/jobs/job/allocations.js index d8e63f201..930bb85cc 100644 --- a/ui/app/controllers/jobs/job/allocations.js +++ b/ui/app/controllers/jobs/job/allocations.js @@ -65,7 +65,7 @@ export default class AllocationsController extends Controller.extend( if (!allocations.length) return allocations; return allocations.filter(alloc => { - if (selectionStatus.length && !selectionStatus.includes(alloc.status)) { + if (selectionStatus.length && !selectionStatus.includes(alloc.clientStatus)) { return false; } if (selectionClient.length && !selectionClient.includes(alloc.get('node.shortId'))) { @@ -113,7 +113,7 @@ export default class AllocationsController extends Controller.extend( this.set('qpClient', serialize(intersection(clients, this.selectionClient))); }); - return clients.sort().map(dc => ({ key: dc, label: dc })); + return clients.sort().map(c => ({ key: c, label: c })); } @computed('model.allocations.[]', 'selectionTaskGroup') @@ -126,7 +126,7 @@ export default class AllocationsController extends Controller.extend( this.set('qpTaskGroup', serialize(intersection(taskGroups, this.selectionTaskGroup))); }); - return taskGroups.sort().map(dc => ({ key: dc, label: dc })); + return taskGroups.sort().map(tg => ({ key: tg, label: tg })); } setFacetQueryParam(queryParam, selection) { From b394859aedb2868511298d81e5da101ceb46ad0b Mon Sep 17 00:00:00 2001 From: Jai Bhagat Date: Tue, 23 Nov 2021 18:24:01 -0500 Subject: [PATCH 06/11] fix: add job version filter --- ui/app/controllers/jobs/job/allocations.js | 32 ++++++++++++++++++++-- ui/app/templates/jobs/job/allocations.hbs | 7 +++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/ui/app/controllers/jobs/job/allocations.js b/ui/app/controllers/jobs/job/allocations.js index 930bb85cc..7c5c28937 100644 --- a/ui/app/controllers/jobs/job/allocations.js +++ b/ui/app/controllers/jobs/job/allocations.js @@ -39,11 +39,15 @@ export default class AllocationsController extends Controller.extend( { qpTaskGroup: 'taskGroup', }, + { + qpJobVersion: 'jobVersion', + }, ]; qpStatus = ''; qpClient = ''; qpTaskGroup = ''; + qpJobVersion = ''; currentPage = 1; pageSize = 25; @@ -57,10 +61,16 @@ export default class AllocationsController extends Controller.extend( return ['shortId', 'name', 'taskGroupName']; } - @computed('model.allocations.[]', 'selectionStatus', 'selectionClient', 'selectionTaskGroup') + @computed( + 'model.allocations.[]', + 'selectionStatus', + 'selectionClient', + 'selectionTaskGroup', + 'selectionJobVersion' + ) get allocations() { const allocations = this.get('model.allocations') || []; - const { selectionStatus, selectionClient, selectionTaskGroup } = this; + const { selectionStatus, selectionClient, selectionTaskGroup, selectionJobVersion } = this; if (!allocations.length) return allocations; @@ -74,7 +84,9 @@ export default class AllocationsController extends Controller.extend( if (selectionTaskGroup.length && !selectionTaskGroup.includes(alloc.taskGroupName)) { return false; } - + if (selectionJobVersion.length && !selectionJobVersion.includes(alloc.jobVersion)) { + return false; + } return true; }); } @@ -82,6 +94,7 @@ export default class AllocationsController extends Controller.extend( @selection('qpStatus') selectionStatus; @selection('qpClient') selectionClient; @selection('qpTaskGroup') selectionTaskGroup; + @selection('qpJobVersion') selectionJobVersion; @alias('allocations') listToSort; @alias('listSorted') listToSearch; @@ -129,6 +142,19 @@ export default class AllocationsController extends Controller.extend( return taskGroups.sort().map(tg => ({ key: tg, label: tg })); } + @computed('model.allocations.[]', 'selectionJobVersion') + get optionsJobVersions() { + const jobVersions = Array.from(new Set(this.model.allocations.mapBy('jobVersion'))).compact(); + + // Update query param when the list of clients changes. + scheduleOnce('actions', () => { + // eslint-disable-next-line ember/no-side-effects + this.set('qpJobVersion', serialize(intersection(jobVersions, this.selectionJobVersion))); + }); + + return jobVersions.sort().map(jv => ({ key: jv, label: jv })); + } + setFacetQueryParam(queryParam, selection) { this.set(queryParam, serialize(selection)); } diff --git a/ui/app/templates/jobs/job/allocations.hbs b/ui/app/templates/jobs/job/allocations.hbs index 2e164ad89..bcb76b60f 100644 --- a/ui/app/templates/jobs/job/allocations.hbs +++ b/ui/app/templates/jobs/job/allocations.hbs @@ -34,6 +34,13 @@ @selection={{this.selectionTaskGroup}} @onSelect={{action this.setFacetQueryParam "qpTaskGroup"}} /> + From febcd5eafd69f36d57e9d582c95772057fd8d820 Mon Sep 17 00:00:00 2001 From: Jai Bhagat Date: Tue, 23 Nov 2021 18:28:33 -0500 Subject: [PATCH 07/11] chore: changelog entry --- .changelog/11544.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/11544.txt diff --git a/.changelog/11544.txt b/.changelog/11544.txt new file mode 100644 index 000000000..6c48985cc --- /dev/null +++ b/.changelog/11544.txt @@ -0,0 +1,3 @@ +```release-note:feature +ui: feat: add filters to allocations table in jobs/job/allocation view +``` From a8854bc3a827cee0522755c3f64a441c35527f8e Mon Sep 17 00:00:00 2001 From: Jai <41024828+ChaiWithJai@users.noreply.github.com> Date: Fri, 17 Dec 2021 09:36:42 -0500 Subject: [PATCH 08/11] fix: remove eslint disable indent --- ui/app/controllers/jobs/job/allocations.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/app/controllers/jobs/job/allocations.js b/ui/app/controllers/jobs/job/allocations.js index 7c5c28937..2b1861ea8 100644 --- a/ui/app/controllers/jobs/job/allocations.js +++ b/ui/app/controllers/jobs/job/allocations.js @@ -12,7 +12,6 @@ import classic from 'ember-classic-decorator'; @classic export default class AllocationsController extends Controller.extend( - /*eslint-disable indent */ Sortable, Searchable, WithNamespaceResetting From 3f363938b7fe2184fb9bd6376edbf92547c3b43e Mon Sep 17 00:00:00 2001 From: Luiz Aoqui Date: Fri, 17 Dec 2021 18:57:54 -0500 Subject: [PATCH 09/11] changelog: fix entry for #11544 --- .changelog/11544.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/11544.txt b/.changelog/11544.txt index 6c48985cc..3daa7ccd7 100644 --- a/.changelog/11544.txt +++ b/.changelog/11544.txt @@ -1,3 +1,3 @@ ```release-note:feature -ui: feat: add filters to allocations table in jobs/job/allocation view +ui: Add filters to allocations table in jobs/job/allocation view ``` From f8709ff55a9414faf780cb24381293b82b36a5ee Mon Sep 17 00:00:00 2001 From: Luiz Aoqui Date: Fri, 17 Dec 2021 19:47:25 -0500 Subject: [PATCH 10/11] ui: fix file formating --- ui/app/templates/jobs/job/allocations.hbs | 83 ++++++----------------- 1 file changed, 21 insertions(+), 62 deletions(-) diff --git a/ui/app/templates/jobs/job/allocations.hbs b/ui/app/templates/jobs/job/allocations.hbs index bcb76b60f..22f3aaac8 100644 --- a/ui/app/templates/jobs/job/allocations.hbs +++ b/ui/app/templates/jobs/job/allocations.hbs @@ -8,8 +8,7 @@ data-test-allocations-search @searchTerm={{mut this.searchTerm}} @onChange={{action this.resetPagination}} - @placeholder="Search allocations..." - /> + @placeholder="Search allocations..." />
@@ -49,69 +48,40 @@ @source={{this.sortedAllocations}} @size={{this.pageSize}} @page={{this.currentPage}} - @class="allocations" as |p| - > + @class="allocations" as |p|> + @class="with-foot" as |t|> - - ID - - - Task Group - - - Created - - - Modified - - - Status - - - Version - - - Client - - - Volume - - - CPU - - - Memory - + ID + Task Group + Created + Modified + Status + Version + Client + Volume + CPU + Memory + @onClick={{action "gotoAllocation" row.model}} />
@@ -119,27 +89,16 @@ {{else}}
-

- No Matches -

-

- No allocations match the term - - {{this.searchTerm}} - -

+

No Matches

+

No allocations match the term {{this.searchTerm}}

{{/if}} {{else}}
-

- No Allocations -

-

- No allocations have been placed. -

+

No Allocations

+

No allocations have been placed.

{{/if}} From ad80c84affcb943829ee5e96c20a3189331ebe1d Mon Sep 17 00:00:00 2001 From: Luiz Aoqui Date: Fri, 17 Dec 2021 19:49:05 -0500 Subject: [PATCH 11/11] ui: fix job allocation filter by status, remove version filter, and add tests --- ui/app/controllers/jobs/job/allocations.js | 60 +++----- ui/app/templates/jobs/job/allocations.hbs | 11 +- ui/tests/acceptance/job-allocations-test.js | 147 ++++++++++++++++++++ ui/tests/pages/jobs/job/allocations.js | 7 + 4 files changed, 173 insertions(+), 52 deletions(-) diff --git a/ui/app/controllers/jobs/job/allocations.js b/ui/app/controllers/jobs/job/allocations.js index 2b1861ea8..d6ec836c4 100644 --- a/ui/app/controllers/jobs/job/allocations.js +++ b/ui/app/controllers/jobs/job/allocations.js @@ -12,10 +12,10 @@ import classic from 'ember-classic-decorator'; @classic export default class AllocationsController extends Controller.extend( - Sortable, - Searchable, - WithNamespaceResetting -) { + Sortable, + Searchable, + WithNamespaceResetting + ) { queryParams = [ { currentPage: 'page', @@ -38,15 +38,11 @@ export default class AllocationsController extends Controller.extend( { qpTaskGroup: 'taskGroup', }, - { - qpJobVersion: 'jobVersion', - }, ]; qpStatus = ''; qpClient = ''; qpTaskGroup = ''; - qpJobVersion = ''; currentPage = 1; pageSize = 25; @@ -60,20 +56,16 @@ export default class AllocationsController extends Controller.extend( return ['shortId', 'name', 'taskGroupName']; } - @computed( - 'model.allocations.[]', - 'selectionStatus', - 'selectionClient', - 'selectionTaskGroup', - 'selectionJobVersion' - ) + @computed('model.allocations.[]') get allocations() { - const allocations = this.get('model.allocations') || []; - const { selectionStatus, selectionClient, selectionTaskGroup, selectionJobVersion } = this; + return this.get('model.allocations') || []; + } - if (!allocations.length) return allocations; + @computed('allocations.[]', 'selectionStatus', 'selectionClient', 'selectionTaskGroup') + get filteredAllocations() { + const { selectionStatus, selectionClient, selectionTaskGroup } = this; - return allocations.filter(alloc => { + return this.allocations.filter(alloc => { if (selectionStatus.length && !selectionStatus.includes(alloc.clientStatus)) { return false; } @@ -83,21 +75,17 @@ export default class AllocationsController extends Controller.extend( if (selectionTaskGroup.length && !selectionTaskGroup.includes(alloc.taskGroupName)) { return false; } - if (selectionJobVersion.length && !selectionJobVersion.includes(alloc.jobVersion)) { - return false; - } return true; }); } + @alias('filteredAllocations') listToSort; + @alias('listSorted') listToSearch; + @alias('listSearched') sortedAllocations; + @selection('qpStatus') selectionStatus; @selection('qpClient') selectionClient; @selection('qpTaskGroup') selectionTaskGroup; - @selection('qpJobVersion') selectionJobVersion; - - @alias('allocations') listToSort; - @alias('listSorted') listToSearch; - @alias('listSearched') sortedAllocations; @action gotoAllocation(allocation) { @@ -106,8 +94,7 @@ export default class AllocationsController extends Controller.extend( get optionsAllocationStatus() { return [ - { key: 'queued', label: 'Queued' }, - { key: 'starting', label: 'Starting' }, + { key: 'pending', label: 'Pending' }, { key: 'running', label: 'Running' }, { key: 'complete', label: 'Complete' }, { key: 'failed', label: 'Failed' }, @@ -132,7 +119,7 @@ export default class AllocationsController extends Controller.extend( get optionsTaskGroups() { const taskGroups = Array.from(new Set(this.model.allocations.mapBy('taskGroupName'))).compact(); - // Update query param when the list of clients changes. + // Update query param when the list of task groups changes. scheduleOnce('actions', () => { // eslint-disable-next-line ember/no-side-effects this.set('qpTaskGroup', serialize(intersection(taskGroups, this.selectionTaskGroup))); @@ -141,19 +128,6 @@ export default class AllocationsController extends Controller.extend( return taskGroups.sort().map(tg => ({ key: tg, label: tg })); } - @computed('model.allocations.[]', 'selectionJobVersion') - get optionsJobVersions() { - const jobVersions = Array.from(new Set(this.model.allocations.mapBy('jobVersion'))).compact(); - - // Update query param when the list of clients changes. - scheduleOnce('actions', () => { - // eslint-disable-next-line ember/no-side-effects - this.set('qpJobVersion', serialize(intersection(jobVersions, this.selectionJobVersion))); - }); - - return jobVersions.sort().map(jv => ({ key: jv, label: jv })); - } - setFacetQueryParam(queryParam, selection) { this.set(queryParam, serialize(selection)); } diff --git a/ui/app/templates/jobs/job/allocations.hbs b/ui/app/templates/jobs/job/allocations.hbs index 22f3aaac8..2dff6a224 100644 --- a/ui/app/templates/jobs/job/allocations.hbs +++ b/ui/app/templates/jobs/job/allocations.hbs @@ -1,7 +1,7 @@ {{page-title "Job " this.job.name " allocations"}}
- {{#if this.model.allocations.length}} + {{#if this.allocations.length}}
-
diff --git a/ui/tests/acceptance/job-allocations-test.js b/ui/tests/acceptance/job-allocations-test.js index 7c86653c3..73fcc7207 100644 --- a/ui/tests/acceptance/job-allocations-test.js +++ b/ui/tests/acceptance/job-allocations-test.js @@ -124,4 +124,151 @@ module('Acceptance | job allocations', function(hooks) { assert.ok(Allocations.error.isPresent, 'Error message is shown'); assert.equal(Allocations.error.title, 'Not Found', 'Error message is for 404'); }); + + testFacet('Status', { + facet: Allocations.facets.status, + paramName: 'status', + expectedOptions: ['Pending', 'Running', 'Complete', 'Failed', 'Lost'], + async beforeEach() { + ['pending', 'running', 'complete', 'failed', 'lost'].forEach(s => { + server.createList('allocation', 5, { clientStatus: s }); + }); + await Allocations.visit({ id: job.id }); + }, + filter: (alloc, selection) => alloc.jobId == job.id && selection.includes(alloc.clientStatus), + }); + + testFacet('Client', { + facet: Allocations.facets.client, + paramName: 'client', + expectedOptions(allocs) { + return Array.from( + new Set( + allocs + .filter(alloc => alloc.jobId == job.id) + .mapBy('nodeId') + .map(id => id.split('-')[0]) + ) + ).sort(); + }, + async beforeEach() { + server.createList('node', 5); + server.createList('allocation', 20); + + await Allocations.visit({ id: job.id }); + }, + filter: (alloc, selection) => + alloc.jobId == job.id && selection.includes(alloc.nodeId.split('-')[0]), + }); + + testFacet('Task Group', { + facet: Allocations.facets.taskGroup, + paramName: 'taskGroup', + expectedOptions(allocs) { + return Array.from( + new Set(allocs.filter(alloc => alloc.jobId == job.id).mapBy('taskGroup')) + ).sort(); + }, + async beforeEach() { + job = server.create('job', { + type: 'service', + status: 'running', + groupsCount: 5, + }); + + await Allocations.visit({ id: job.id }); + }, + filter: (alloc, selection) => alloc.jobId == job.id && selection.includes(alloc.taskGroup), + }); }); + +function testFacet(label, { facet, paramName, beforeEach, filter, expectedOptions }) { + test(`facet ${label} | the ${label} facet has the correct options`, async function(assert) { + await beforeEach(); + await facet.toggle(); + + let expectation; + if (typeof expectedOptions === 'function') { + expectation = expectedOptions(server.db.allocations); + } else { + expectation = expectedOptions; + } + + assert.deepEqual( + facet.options.map(option => option.label.trim()), + expectation, + 'Options for facet are as expected' + ); + }); + + test(`facet ${label} | the ${label} facet filters the allocations list by ${label}`, async function(assert) { + let option; + + await beforeEach(); + + await facet.toggle(); + option = facet.options.objectAt(0); + await option.toggle(); + + const selection = [option.key]; + const expectedAllocs = server.db.allocations + .filter(alloc => filter(alloc, selection)) + .sortBy('modifyIndex') + .reverse(); + + Allocations.allocations.forEach((alloc, index) => { + assert.equal( + alloc.id, + expectedAllocs[index].id, + `Allocation at ${index} is ${expectedAllocs[index].id}` + ); + }); + }); + + test(`facet ${label} | selecting multiple options in the ${label} facet results in a broader search`, async function(assert) { + const selection = []; + + await beforeEach(); + await facet.toggle(); + + const option1 = facet.options.objectAt(0); + const option2 = facet.options.objectAt(1); + await option1.toggle(); + selection.push(option1.key); + await option2.toggle(); + selection.push(option2.key); + + const expectedAllocs = server.db.allocations + .filter(alloc => filter(alloc, selection)) + .sortBy('modifyIndex') + .reverse(); + + Allocations.allocations.forEach((alloc, index) => { + assert.equal( + alloc.id, + expectedAllocs[index].id, + `Allocation at ${index} is ${expectedAllocs[index].id}` + ); + }); + }); + + test(`facet ${label} | selecting options in the ${label} facet updates the ${paramName} query param`, async function(assert) { + const selection = []; + + await beforeEach(); + await facet.toggle(); + + const option1 = facet.options.objectAt(0); + const option2 = facet.options.objectAt(1); + await option1.toggle(); + selection.push(option1.key); + await option2.toggle(); + selection.push(option2.key); + + assert.equal( + currentURL(), + `/jobs/${job.id}/allocations?${paramName}=${encodeURIComponent(JSON.stringify(selection))}`, + 'URL has the correct query param key and value' + ); + }); +} diff --git a/ui/tests/pages/jobs/job/allocations.js b/ui/tests/pages/jobs/job/allocations.js index adb48aa70..8b15cb932 100644 --- a/ui/tests/pages/jobs/job/allocations.js +++ b/ui/tests/pages/jobs/job/allocations.js @@ -11,6 +11,7 @@ import { import allocations from 'nomad-ui/tests/pages/components/allocations'; import error from 'nomad-ui/tests/pages/components/error'; +import { multiFacet } from 'nomad-ui/tests/pages/components/facet'; export default create({ visit: visitable('/jobs/:id/allocations'), @@ -22,6 +23,12 @@ export default create({ ...allocations(), + facets: { + status: multiFacet('[data-test-allocation-status-facet]'), + client: multiFacet('[data-test-allocation-client-facet]'), + taskGroup: multiFacet('[data-test-allocation-task-group-facet]'), + }, + isEmpty: isPresent('[data-test-empty-allocations-list]'), emptyState: { headline: text('[data-test-empty-allocations-list-headline]'),