From 92a6809b2a18b66640d41d53fd540f96b7bb6aaa Mon Sep 17 00:00:00 2001 From: Michael Lange Date: Wed, 23 Jan 2019 13:56:32 -0800 Subject: [PATCH] Introduce encode/decode for array query params --- ui/app/controllers/jobs/index.js | 72 ++++++++++++++++++++++++++------ ui/app/templates/jobs/index.hbs | 8 ++-- 2 files changed, 64 insertions(+), 16 deletions(-) diff --git a/ui/app/controllers/jobs/index.js b/ui/app/controllers/jobs/index.js index a6dfd31fa..747e4f8c6 100644 --- a/ui/app/controllers/jobs/index.js +++ b/ui/app/controllers/jobs/index.js @@ -2,9 +2,28 @@ import { inject as service } from '@ember/service'; import { alias } from '@ember/object/computed'; import Controller, { inject as controller } from '@ember/controller'; import { 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'; +// An unattractive but robust way to encode query params +const qpSerialize = arr => (arr.length ? JSON.stringify(arr) : ''); +const qpDeserialize = str => { + try { + return JSON.parse(str) + .compact() + .without(''); + } catch (e) { + return []; + } +}; + +const selectionFromQP = qpKey => + computed(qpKey, function() { + return qpDeserialize(this.get(qpKey)); + }); + export default Controller.extend(Sortable, Searchable, { system: service(), jobsController: controller('jobs'), @@ -16,6 +35,10 @@ export default Controller.extend(Sortable, Searchable, { searchTerm: 'search', sortProperty: 'sort', sortDescending: 'desc', + qpType: 'type', + qpStatus: 'status', + qpDatacenter: 'dc', + qpPrefix: 'prefix', }, currentPage: 1, @@ -50,10 +73,16 @@ export default Controller.extend(Sortable, Searchable, { .reduce(flatten, []) ); - return Array.from(allDatacenters) - .compact() - .sort() - .map(dc => ({ key: dc, label: dc })); + // Remove any invalid datacenters from the query param/selection + const availableDatacenters = Array.from(allDatacenters).compact(); + scheduleOnce('actions', () => { + this.set( + 'qpDatacenter', + qpSerialize(intersection(availableDatacenters, this.get('facetSelectionDatacenter'))) + ); + }); + + return availableDatacenters.sort().map(dc => ({ key: dc, label: dc })); }), facetOptionsPrefix: computed('visibleJobs.[]', function() { @@ -77,10 +106,20 @@ export default Controller.extend(Sortable, Searchable, { count: nameHistogram[key], })); - // Only consider prefixes that match more than one name, then convert to an - // options array, including the counts in the label - return nameTable - .filter(name => name.count > 1) + // Only consider prefixes that match more than one name + const prefixes = nameTable.filter(name => name.count > 1); + + // Remove any invalid prefixes from the query param/selection + const availablePrefixes = prefixes.mapBy('prefix'); + scheduleOnce('actions', () => { + this.set( + 'qpPrefix', + qpSerialize(intersection(availablePrefixes, this.get('facetSelectionPrefix'))) + ); + }); + + // Sort, format, and include the count in the label + return prefixes .sortBy('prefix') .reverse() .map(name => ({ @@ -89,10 +128,15 @@ export default Controller.extend(Sortable, Searchable, { })); }), - facetSelectionType: computed(() => []), - facetSelectionStatus: computed(() => []), - facetSelectionDatacenter: computed(() => []), - facetSelectionPrefix: computed(() => []), + qpType: '', + qpStatus: '', + qpDatacenter: '', + qpPrefix: '', + + facetSelectionType: selectionFromQP('qpType'), + facetSelectionStatus: selectionFromQP('qpStatus'), + facetSelectionDatacenter: selectionFromQP('qpDatacenter'), + facetSelectionPrefix: selectionFromQP('qpPrefix'), /** Filtered jobs are those that match the selected namespace and aren't children @@ -150,6 +194,10 @@ export default Controller.extend(Sortable, Searchable, { isShowingDeploymentDetails: false, + setFacetQueryParam(queryParam, selection) { + this.set(queryParam, qpSerialize(selection)); + }, + actions: { gotoJob(job) { this.transitionToRoute('jobs.job', job.get('plainId')); diff --git a/ui/app/templates/jobs/index.hbs b/ui/app/templates/jobs/index.hbs index 2ef98ccf2..c5c27d535 100644 --- a/ui/app/templates/jobs/index.hbs +++ b/ui/app/templates/jobs/index.hbs @@ -18,22 +18,22 @@ label="Type" options=facetOptionsType selection=facetSelectionType - onSelect=(action (mut facetSelectionType))}} + onSelect=(action setFacetQueryParam "qpType")}} {{multi-select-dropdown label="Status" options=facetOptionsStatus selection=facetSelectionStatus - onSelect=(action (mut facetSelectionStatus))}} + onSelect=(action setFacetQueryParam "qpStatus")}} {{multi-select-dropdown label="Datacenter" options=facetOptionsDatacenter selection=facetSelectionDatacenter - onSelect=(action (mut facetSelectionDatacenter))}} + onSelect=(action setFacetQueryParam "qpDatacenter")}} {{multi-select-dropdown label="Prefix" options=facetOptionsPrefix selection=facetSelectionPrefix - onSelect=(action (mut facetSelectionPrefix))}} + onSelect=(action setFacetQueryParam "qpPrefix")}}