Skip to content

Commit

Permalink
Merge pull request #3974 from hashicorp/f-ui-allocations-use-job-brea…
Browse files Browse the repository at this point in the history
…dcrumbs

UI: Allocation and task breadcrumbs extend job breadcrumbs
  • Loading branch information
DingoEatingFuzz committed Mar 14, 2018
2 parents 4252ffe + 7ac2b8e commit b3a0554
Show file tree
Hide file tree
Showing 18 changed files with 200 additions and 53 deletions.
9 changes: 8 additions & 1 deletion ui/app/components/job-page/abstract.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { inject as service } from '@ember/service';
import { qpBuilder } from 'nomad-ui/utils/classes/query-params';

export default Component.extend({
system: service(),
Expand All @@ -22,7 +23,13 @@ export default Component.extend({
{ label: 'Jobs', args: ['jobs'] },
{
label: job.get('name'),
args: ['jobs.job', job],
args: [
'jobs.job',
job,
qpBuilder({
jobNamespace: job.get('namespace.name') || 'default',
}),
],
},
];
}),
Expand Down
35 changes: 34 additions & 1 deletion ui/app/controllers/allocations/allocation.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import { qpBuilder } from 'nomad-ui/utils/classes/query-params';

export default Controller.extend({});
export default Controller.extend({
breadcrumbs: computed('model.job', function() {
return [
{ label: 'Jobs', args: ['jobs'] },
{
label: this.get('model.job.name'),
args: [
'jobs.job',
this.get('model.job'),
qpBuilder({
jobNamespace: this.get('model.namespace.name') || 'default',
}),
],
},
{
label: this.get('model.taskGroupName'),
args: [
'jobs.job.task-group',
this.get('model.job'),
this.get('model.taskGroupName'),
qpBuilder({
jobNamespace: this.get('model.namespace.name') || 'default',
}),
],
},
{
label: this.get('model.shortId'),
args: ['allocations.allocation', this.get('model')],
},
];
}),
});
6 changes: 5 additions & 1 deletion ui/app/controllers/allocations/allocation/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { alias } from '@ember/object/computed';
import Controller from '@ember/controller';
import Controller, { inject as controller } from '@ember/controller';
import Sortable from 'nomad-ui/mixins/sortable';

export default Controller.extend(Sortable, {
allocationController: controller('allocations.allocation'),

queryParams: {
sortProperty: 'sort',
sortDescending: 'desc',
Expand All @@ -11,6 +13,8 @@ export default Controller.extend(Sortable, {
sortProperty: 'name',
sortDescending: false,

breadcrumbs: alias('allocationController.breadcrumbs'),

listToSort: alias('model.states'),
sortedStates: alias('listSorted'),
});
15 changes: 15 additions & 0 deletions ui/app/controllers/allocations/allocation/task.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Controller, { inject as controller } from '@ember/controller';
import { computed } from '@ember/object';

export default Controller.extend({
allocationController: controller('allocations.allocation'),

breadcrumbs: computed('allocationController.breadcrumbs.[]', 'model.name', function() {
return this.get('allocationController.breadcrumbs').concat([
{
label: this.get('model.name'),
args: ['allocations.allocation.task', this.get('model.allocation'), this.get('model')],
},
]);
}),
});
8 changes: 6 additions & 2 deletions ui/app/controllers/allocations/allocation/task/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { alias } from '@ember/object/computed';
import Controller from '@ember/controller';
import Controller, { inject as controller } from '@ember/controller';
import { computed } from '@ember/object';
import { alias } from '@ember/object/computed';

export default Controller.extend({
taskController: controller('allocations.allocation.task'),

breadcrumbs: alias('taskController.breadcrumbs'),

network: alias('model.resources.networks.firstObject'),
ports: computed('network.reservedPorts.[]', 'network.dynamicPorts.[]', function() {
return (this.get('network.reservedPorts') || [])
Expand Down
7 changes: 7 additions & 0 deletions ui/app/controllers/allocations/allocation/task/logs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Controller, { inject as controller } from '@ember/controller';
import { alias } from '@ember/object/computed';

export default Controller.extend({
taskController: controller('allocations.allocation.task'),
breadcrumbs: alias('taskController.breadcrumbs'),
});
9 changes: 8 additions & 1 deletion ui/app/controllers/jobs/job.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import { qpBuilder } from 'nomad-ui/utils/classes/query-params';

export default Controller.extend({
breadcrumbs: computed('model.{name,id}', function() {
return [
{ label: 'Jobs', args: ['jobs'] },
{
label: this.get('model.name'),
args: ['jobs.job', this.get('model')],
args: [
'jobs.job',
this.get('model'),
qpBuilder({
jobNamespace: this.get('model.namespace.name') || 'default',
}),
],
},
];
}),
Expand Down
10 changes: 9 additions & 1 deletion ui/app/controllers/jobs/job/task-group.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { 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 { qpBuilder } from 'nomad-ui/utils/classes/query-params';

export default Controller.extend(Sortable, Searchable, WithNamespaceResetting, {
jobController: controller('jobs.job'),
Expand Down Expand Up @@ -33,7 +34,14 @@ export default Controller.extend(Sortable, Searchable, WithNamespaceResetting, {

breadcrumbs: computed('jobController.breadcrumbs.[]', 'model.{name}', function() {
return this.get('jobController.breadcrumbs').concat([
{ label: this.get('model.name'), args: ['jobs.job.task-group', this.get('model.name')] },
{
label: this.get('model.name'),
args: [
'jobs.job.task-group',
this.get('model.name'),
qpBuilder({ jobNamespace: this.get('model.job.namespace.name') || 'default' }),
],
},
]);
}),

Expand Down
11 changes: 9 additions & 2 deletions ui/app/routes/allocations/allocation.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import Route from '@ember/routing/route';
import WithModelErrorHandling from 'nomad-ui/mixins/with-model-error-handling';
import { collect } from '@ember/object/computed';
import { watchRecord } from 'nomad-ui/utils/properties/watch';
import WithWatchers from 'nomad-ui/mixins/with-watchers';
import notifyError from 'nomad-ui/utils/notify-error';

export default Route.extend(WithModelErrorHandling, WithWatchers, {
export default Route.extend(WithWatchers, {
startWatchers(controller, model) {
controller.set('watcher', this.get('watch').perform(model));
},

model() {
// Preload the job for the allocation since it's required for the breadcrumb trail
return this._super(...arguments)
.then(allocation => allocation.get('job').then(() => allocation))
.catch(notifyError(this));
},

watch: watchRecord('allocation'),

watchers: collect('watch'),
Expand Down
13 changes: 9 additions & 4 deletions ui/app/templates/allocations/allocation/index.hbs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
{{#global-header class="page-header"}}
<li><a href="#">Allocations</a></li>
<li class="is-active">
{{#link-to "allocations.allocation" model}}{{model.shortId}}{{/link-to}}
</li>
{{#each breadcrumbs as |breadcrumb index|}}
<li class="{{if (eq (inc index) breadcrumbs.length) "is-active"}}">
{{#link-to
data-test-breadcrumb=breadcrumb.label
params=breadcrumb.args}}
{{breadcrumb.label}}
{{/link-to}}
</li>
{{/each}}
{{/global-header}}
{{#gutter-menu class="page-body"}}
<section class="section">
Expand Down
20 changes: 9 additions & 11 deletions ui/app/templates/allocations/allocation/task/index.hbs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
{{#global-header class="page-header"}}
<li><a href="#" data-test-breadcrumb="allocations">Allocations</a></li>
<li>
{{#link-to "allocations.allocation" model.allocation data-test-breadcrumb="allocation"}}
{{model.allocation.shortId}}
{{/link-to}}
</li>
<li class="is-active">
{{#link-to "allocations.allocation.task" model.allocation model data-test-breadcrumb="task"}}
{{model.name}}
{{/link-to}}
</li>
{{#each breadcrumbs as |breadcrumb index|}}
<li class="{{if (eq (inc index) breadcrumbs.length) "is-active"}}">
{{#link-to
data-test-breadcrumb=breadcrumb.label
params=breadcrumb.args}}
{{breadcrumb.label}}
{{/link-to}}
</li>
{{/each}}
{{/global-header}}
{{#gutter-menu class="page-body"}}
{{partial "allocations/allocation/task/subnav"}}
Expand Down
20 changes: 9 additions & 11 deletions ui/app/templates/allocations/allocation/task/logs.hbs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
{{#global-header class="page-header"}}
<li><a href="#">Allocations</a></li>
<li>
{{#link-to "allocations.allocation" model.allocation}}
{{model.allocation.shortId}}
{{/link-to}}
</li>
<li class="is-active">
{{#link-to "allocations.allocation.task" model.allocation model}}
{{model.name}}
{{/link-to}}
</li>
{{#each breadcrumbs as |breadcrumb index|}}
<li class="{{if (eq (inc index) breadcrumbs.length) "is-active"}}">
{{#link-to
data-test-breadcrumb=breadcrumb.label
params=breadcrumb.args}}
{{breadcrumb.label}}
{{/link-to}}
</li>
{{/each}}
{{/global-header}}
{{#gutter-menu class="page-body"}}
{{partial "allocations/allocation/task/subnav"}}
Expand Down
5 changes: 1 addition & 4 deletions ui/app/templates/jobs/job/task-group.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
<li class="{{if (eq (inc index) breadcrumbs.length) "is-active"}}">
{{#link-to
data-test-breadcrumb=breadcrumb.label
params=(append
breadcrumb.args
(query-params jobNamespace=(or model.namespace.id "default"))
)}}
params=breadcrumb.args}}
{{breadcrumb.label}}
{{/link-to}}
</li>
Expand Down
12 changes: 12 additions & 0 deletions ui/app/utils/classes/query-params.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copied from source since it isn't exposed to import
// https://github.com/emberjs/ember.js/blob/v2.18.2/packages/ember-routing/lib/system/query_params.js
import EmberObject from '@ember/object';

const QueryParams = EmberObject.extend({
isQueryParams: true,
values: null,
});

export const qpBuilder = values => QueryParams.create({ values });

export default QueryParams;
1 change: 1 addition & 0 deletions ui/mirage/factories/evaluation.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,6 @@ function assignJob(evaluation, server) {
const job = evaluation.jobId ? server.db.jobs.find(evaluation.jobId) : pickOne(server.db.jobs);
evaluation.update({
jobId: job.id,
job_id: job.id,
});
}
1 change: 1 addition & 0 deletions ui/mirage/factories/job.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export default Factory.extend({
groupNames: groups.mapBy('name'),
job,
job_id: job.id,
JobID: job.id,
namespace: job.namespace,
});

Expand Down
2 changes: 2 additions & 0 deletions ui/mirage/serializers/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ export default RestSerializer.extend({
}
},

keyForCollection: keyCase,
keyForAttribute: keyCase,
keyForRelationship: keyCase,
keyForRelationshipIds: keyCase,
keyForEmbeddedRelationship: keyCase,
});
69 changes: 55 additions & 14 deletions ui/tests/acceptance/task-detail-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,75 @@ test('/allocation/:id/:task_name should name the task and list high-level task i
);
});

test('breadcrumbs includes allocations and link to the allocation detail page', function(assert) {
test('breadcrumbs match jobs / job / task group / allocation / task', function(assert) {
const { jobId, taskGroup } = allocation;
const job = server.db.jobs.find(jobId);

const shortId = allocation.id.split('-')[0];

assert.equal(
find('[data-test-breadcrumb="Jobs"]').textContent.trim(),
'Jobs',
'Jobs is the first breadcrumb'
);
assert.equal(
find('[data-test-breadcrumb="allocations"]').textContent.trim(),
'Allocations',
'Allocations is the first breadcrumb'
find(`[data-test-breadcrumb="${job.name}"]`).textContent.trim(),
job.name,
'Job is the second breadcrumb'
);
assert.equal(
find('[data-test-breadcrumb="allocations"]').getAttribute('href'),
'#',
"Allocations breadcrumb doesn't link anywhere"
find(`[data-test-breadcrumb="${taskGroup}`).textContent.trim(),
taskGroup,
'Task Group is the third breadcrumb'
);
assert.equal(
find('[data-test-breadcrumb="allocation"]').textContent.trim(),
allocation.id.split('-')[0],
'Allocation short id is the second breadcrumb'
find(`[data-test-breadcrumb="${shortId}"]`).textContent.trim(),
shortId,
'Allocation short id is the fourth breadcrumb'
);
assert.equal(
find('[data-test-breadcrumb="task"]').textContent.trim(),
find(`[data-test-breadcrumb="${task.name}"]`).textContent.trim(),
task.name,
'Task name is the third breadcrumb'
'Task name is the fifth breadcrumb'
);

click('[data-test-breadcrumb="allocation"]');
click('[data-test-breadcrumb="Jobs"]');
andThen(() => {
assert.equal(currentURL(), '/jobs', 'Jobs breadcrumb links correctly');
});
andThen(() => {
visit(`/allocations/${allocation.id}/${task.name}`);
});
andThen(() => {
click(`[data-test-breadcrumb="${job.name}"]`);
});
andThen(() => {
assert.equal(currentURL(), `/jobs/${job.id}`, 'Job breadcrumb links correctly');
});
andThen(() => {
visit(`/allocations/${allocation.id}/${task.name}`);
});
andThen(() => {
click(`[data-test-breadcrumb="${taskGroup}"]`);
});
andThen(() => {
assert.equal(
currentURL(),
`/jobs/${job.id}/${taskGroup}`,
'Task Group breadcrumb links correctly'
);
});
andThen(() => {
visit(`/allocations/${allocation.id}/${task.name}`);
});
andThen(() => {
click(`[data-test-breadcrumb="${shortId}"]`);
});
andThen(() => {
assert.equal(
currentURL(),
`/allocations/${allocation.id}`,
'Second breadcrumb links back to the allocation detail'
'Allocations breadcrumb links correctly'
);
});
});
Expand Down

0 comments on commit b3a0554

Please sign in to comment.