Merge pull request #4458 from hashicorp/f-ui-refactor-breadcrumbs
UI: Refactor breadcrumbs
This commit is contained in:
commit
38b4d30272
|
@ -0,0 +1,11 @@
|
|||
import Component from '@ember/component';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { reads } from '@ember/object/computed';
|
||||
|
||||
export default Component.extend({
|
||||
breadcrumbsService: service('breadcrumbs'),
|
||||
|
||||
tagName: '',
|
||||
|
||||
breadcrumbs: reads('breadcrumbsService.breadcrumbs'),
|
||||
});
|
|
@ -1,7 +1,5 @@
|
|||
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(),
|
||||
|
@ -20,23 +18,6 @@ export default Component.extend({
|
|||
// Set to a { title, description } to surface an error
|
||||
errorMessage: null,
|
||||
|
||||
breadcrumbs: computed('job.{name,id}', function() {
|
||||
const job = this.get('job');
|
||||
return [
|
||||
{ label: 'Jobs', args: ['jobs'] },
|
||||
{
|
||||
label: job.get('name'),
|
||||
args: [
|
||||
'jobs.job',
|
||||
job,
|
||||
qpBuilder({
|
||||
jobNamespace: job.get('namespace.name') || 'default',
|
||||
}),
|
||||
],
|
||||
},
|
||||
];
|
||||
}),
|
||||
|
||||
actions: {
|
||||
clearErrorMessage() {
|
||||
this.set('errorMessage', null);
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
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.job', function() {
|
||||
return [
|
||||
{ label: 'Jobs', args: ['jobs'] },
|
||||
{
|
||||
label: this.get('model.job.name'),
|
||||
args: [
|
||||
'jobs.job',
|
||||
this.get('model.job.plainId'),
|
||||
qpBuilder({
|
||||
jobNamespace: this.get('model.job.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')],
|
||||
},
|
||||
];
|
||||
}),
|
||||
});
|
|
@ -1,11 +1,9 @@
|
|||
import { alias } from '@ember/object/computed';
|
||||
import Controller, { inject as controller } from '@ember/controller';
|
||||
import Controller from '@ember/controller';
|
||||
import Sortable from 'nomad-ui/mixins/sortable';
|
||||
import { lazyClick } from 'nomad-ui/helpers/lazy-click';
|
||||
|
||||
export default Controller.extend(Sortable, {
|
||||
allocationController: controller('allocations.allocation'),
|
||||
|
||||
queryParams: {
|
||||
sortProperty: 'sort',
|
||||
sortDescending: 'desc',
|
||||
|
@ -14,8 +12,6 @@ export default Controller.extend(Sortable, {
|
|||
sortProperty: 'name',
|
||||
sortDescending: false,
|
||||
|
||||
breadcrumbs: alias('allocationController.breadcrumbs'),
|
||||
|
||||
listToSort: alias('model.states'),
|
||||
sortedStates: alias('listSorted'),
|
||||
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
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')],
|
||||
},
|
||||
]);
|
||||
}),
|
||||
});
|
|
@ -1,12 +1,8 @@
|
|||
import Controller, { inject as controller } from '@ember/controller';
|
||||
import 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') || [])
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
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'),
|
||||
});
|
|
@ -1,21 +0,0 @@
|
|||
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.plainId'),
|
||||
qpBuilder({
|
||||
jobNamespace: this.get('model.namespace.name') || 'default',
|
||||
}),
|
||||
],
|
||||
},
|
||||
];
|
||||
}),
|
||||
});
|
|
@ -1,11 +1,4 @@
|
|||
import { alias } from '@ember/object/computed';
|
||||
import Controller, { inject as controller } from '@ember/controller';
|
||||
import Controller from '@ember/controller';
|
||||
import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting';
|
||||
|
||||
export default Controller.extend(WithNamespaceResetting, {
|
||||
jobController: controller('jobs.job'),
|
||||
|
||||
job: alias('model.job'),
|
||||
|
||||
breadcrumbs: alias('jobController.breadcrumbs'),
|
||||
});
|
||||
export default Controller.extend(WithNamespaceResetting);
|
||||
|
|
|
@ -1,12 +1,4 @@
|
|||
import { alias } from '@ember/object/computed';
|
||||
import Controller, { inject as controller } from '@ember/controller';
|
||||
import Controller from '@ember/controller';
|
||||
import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting';
|
||||
|
||||
export default Controller.extend(WithNamespaceResetting, {
|
||||
jobController: controller('jobs.job'),
|
||||
|
||||
job: alias('model'),
|
||||
deployments: alias('model.deployments'),
|
||||
|
||||
breadcrumbs: alias('jobController.breadcrumbs'),
|
||||
});
|
||||
export default Controller.extend(WithNamespaceResetting);
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
import { inject as service } from '@ember/service';
|
||||
import { alias } from '@ember/object/computed';
|
||||
import Controller, { inject as controller } from '@ember/controller';
|
||||
import Controller from '@ember/controller';
|
||||
import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting';
|
||||
|
||||
export default Controller.extend(WithNamespaceResetting, {
|
||||
system: service(),
|
||||
|
||||
jobController: controller('jobs.job'),
|
||||
|
||||
queryParams: {
|
||||
currentPage: 'page',
|
||||
sortProperty: 'sort',
|
||||
|
@ -19,9 +16,6 @@ export default Controller.extend(WithNamespaceResetting, {
|
|||
sortProperty: 'name',
|
||||
sortDescending: false,
|
||||
|
||||
breadcrumbs: alias('jobController.breadcrumbs'),
|
||||
job: alias('model'),
|
||||
|
||||
actions: {
|
||||
gotoTaskGroup(taskGroup) {
|
||||
this.transitionToRoute('jobs.job.task-group', taskGroup.get('job'), taskGroup);
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
import { alias } from '@ember/object/computed';
|
||||
import Controller, { inject as controller } from '@ember/controller';
|
||||
|
||||
export default Controller.extend({
|
||||
jobController: controller('jobs.job'),
|
||||
breadcrumbs: alias('jobController.breadcrumbs'),
|
||||
});
|
|
@ -1,14 +1,11 @@
|
|||
import { alias } from '@ember/object/computed';
|
||||
import Controller, { inject as controller } from '@ember/controller';
|
||||
import Controller from '@ember/controller';
|
||||
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'),
|
||||
|
||||
queryParams: {
|
||||
currentPage: 'page',
|
||||
searchTerm: 'search',
|
||||
|
@ -32,19 +29,6 @@ export default Controller.extend(Sortable, Searchable, WithNamespaceResetting, {
|
|||
listToSearch: alias('listSorted'),
|
||||
sortedAllocations: alias('listSearched'),
|
||||
|
||||
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'),
|
||||
qpBuilder({ jobNamespace: this.get('model.job.namespace.name') || 'default' }),
|
||||
],
|
||||
},
|
||||
]);
|
||||
}),
|
||||
|
||||
actions: {
|
||||
gotoAllocation(allocation) {
|
||||
this.transitionToRoute('allocations.allocation', allocation);
|
||||
|
|
|
@ -1,12 +1,4 @@
|
|||
import { alias } from '@ember/object/computed';
|
||||
import Controller, { inject as controller } from '@ember/controller';
|
||||
import Controller from '@ember/controller';
|
||||
import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting';
|
||||
|
||||
export default Controller.extend(WithNamespaceResetting, {
|
||||
jobController: controller('jobs.job'),
|
||||
|
||||
job: alias('model'),
|
||||
versions: alias('model.versions'),
|
||||
|
||||
breadcrumbs: alias('jobController.breadcrumbs'),
|
||||
});
|
||||
export default Controller.extend(WithNamespaceResetting);
|
||||
|
|
|
@ -3,12 +3,38 @@ 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';
|
||||
import { qpBuilder } from 'nomad-ui/utils/classes/query-params';
|
||||
import { jobCrumbs } from 'nomad-ui/utils/breadcrumb-utils';
|
||||
|
||||
export default Route.extend(WithWatchers, {
|
||||
startWatchers(controller, model) {
|
||||
controller.set('watcher', this.get('watch').perform(model));
|
||||
},
|
||||
|
||||
// Allocation breadcrumbs extend from job / task group breadcrumbs
|
||||
// even though the route structure does not.
|
||||
breadcrumbs(model) {
|
||||
return [
|
||||
{ label: 'Jobs', args: ['jobs.index'] },
|
||||
...jobCrumbs(model.get('job')),
|
||||
{
|
||||
label: model.get('taskGroupName'),
|
||||
args: [
|
||||
'jobs.job.task-group',
|
||||
model.get('job'),
|
||||
model.get('taskGroupName'),
|
||||
qpBuilder({
|
||||
jobNamespace: model.get('namespace.name') || 'default',
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
label: model.get('shortId'),
|
||||
args: ['allocations.allocation', model],
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
model() {
|
||||
// Preload the job for the allocation since it's required for the breadcrumb trail
|
||||
return this._super(...arguments)
|
||||
|
|
|
@ -5,6 +5,16 @@ import EmberError from '@ember/error';
|
|||
export default Route.extend({
|
||||
store: service(),
|
||||
|
||||
breadcrumbs(model) {
|
||||
if (!model) return [];
|
||||
return [
|
||||
{
|
||||
label: model.get('name'),
|
||||
args: ['allocations.allocation.task', model.get('allocation'), model],
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
model({ name }) {
|
||||
const allocation = this.modelFor('allocations.allocation');
|
||||
if (allocation) {
|
||||
|
|
|
@ -8,6 +8,13 @@ export default Route.extend(WithForbiddenState, {
|
|||
store: service(),
|
||||
system: service(),
|
||||
|
||||
breadcrumbs: [
|
||||
{
|
||||
label: 'Clients',
|
||||
args: ['clients.index'],
|
||||
},
|
||||
],
|
||||
|
||||
beforeModel() {
|
||||
return this.get('system.leader');
|
||||
},
|
||||
|
|
|
@ -12,6 +12,16 @@ export default Route.extend(WithWatchers, {
|
|||
return this._super(...arguments).catch(notifyError(this));
|
||||
},
|
||||
|
||||
breadcrumbs(model) {
|
||||
if (!model) return [];
|
||||
return [
|
||||
{
|
||||
label: model.get('shortId'),
|
||||
args: ['clients.client', model.get('id')],
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
afterModel(model) {
|
||||
if (model && model.get('isPartial')) {
|
||||
return model.reload().then(node => node.get('allocations'));
|
||||
|
|
|
@ -8,6 +8,13 @@ export default Route.extend(WithForbiddenState, {
|
|||
system: service(),
|
||||
store: service(),
|
||||
|
||||
breadcrumbs: [
|
||||
{
|
||||
label: 'Jobs',
|
||||
args: ['jobs.index'],
|
||||
},
|
||||
],
|
||||
|
||||
beforeModel() {
|
||||
return this.get('system.namespaces');
|
||||
},
|
||||
|
|
|
@ -2,11 +2,14 @@ import { inject as service } from '@ember/service';
|
|||
import Route from '@ember/routing/route';
|
||||
import RSVP from 'rsvp';
|
||||
import notifyError from 'nomad-ui/utils/notify-error';
|
||||
import { jobCrumbs } from 'nomad-ui/utils/breadcrumb-utils';
|
||||
|
||||
export default Route.extend({
|
||||
store: service(),
|
||||
token: service(),
|
||||
|
||||
breadcrumbs: jobCrumbs,
|
||||
|
||||
serialize(model) {
|
||||
return { job_name: model.get('plainId') };
|
||||
},
|
||||
|
|
|
@ -2,8 +2,23 @@ import Route from '@ember/routing/route';
|
|||
import { collect } from '@ember/object/computed';
|
||||
import { watchRecord, watchRelationship } from 'nomad-ui/utils/properties/watch';
|
||||
import WithWatchers from 'nomad-ui/mixins/with-watchers';
|
||||
import { qpBuilder } from 'nomad-ui/utils/classes/query-params';
|
||||
|
||||
export default Route.extend(WithWatchers, {
|
||||
breadcrumbs(model) {
|
||||
if (!model) return [];
|
||||
return [
|
||||
{
|
||||
label: model.get('name'),
|
||||
args: [
|
||||
'jobs.job.task-group',
|
||||
model.get('name'),
|
||||
qpBuilder({ jobNamespace: model.get('job.namespace.name') || 'default' }),
|
||||
],
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
model({ name }) {
|
||||
// If the job is a partial (from the list request) it won't have task
|
||||
// groups. Reload the job to ensure task groups are present.
|
||||
|
|
|
@ -8,6 +8,13 @@ export default Route.extend(WithForbiddenState, {
|
|||
store: service(),
|
||||
system: service(),
|
||||
|
||||
breadcrumbs: [
|
||||
{
|
||||
label: 'Servers',
|
||||
args: ['servers.index'],
|
||||
},
|
||||
],
|
||||
|
||||
beforeModel() {
|
||||
return this.get('system.leader');
|
||||
},
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import { getOwner } from '@ember/application';
|
||||
import Service, { inject as service } from '@ember/service';
|
||||
import { computed } from '@ember/object';
|
||||
|
||||
export default Service.extend({
|
||||
router: service(),
|
||||
|
||||
// currentURL is only used to listen to all transitions.
|
||||
// currentRouteName has all information necessary to compute breadcrumbs,
|
||||
// but it doesn't change when a transition to the same route with a different
|
||||
// model occurs.
|
||||
breadcrumbs: computed('router.currentURL', 'router.currentRouteName', function() {
|
||||
const owner = getOwner(this);
|
||||
const allRoutes = (this.get('router.currentRouteName') || '')
|
||||
.split('.')
|
||||
.without('')
|
||||
.map((segment, index, allSegments) => allSegments.slice(0, index + 1).join('.'));
|
||||
|
||||
let crumbs = [];
|
||||
allRoutes.forEach(routeName => {
|
||||
const route = owner.lookup(`route:${routeName}`);
|
||||
|
||||
// Routes can reset the breadcrumb trail to start anew even
|
||||
// if the route is deeply nested.
|
||||
if (route.get('resetBreadcrumbs')) {
|
||||
crumbs = [];
|
||||
}
|
||||
|
||||
// Breadcrumbs are either an array of static crumbs
|
||||
// or a function that returns breadcrumbs given the current
|
||||
// model for the route's controller.
|
||||
let breadcrumbs = route.get('breadcrumbs') || [];
|
||||
if (typeof breadcrumbs === 'function') {
|
||||
breadcrumbs = breadcrumbs(route.get('controller.model')) || [];
|
||||
}
|
||||
|
||||
crumbs.push(...breadcrumbs);
|
||||
});
|
||||
|
||||
return crumbs;
|
||||
}),
|
||||
});
|
|
@ -1,3 +1,6 @@
|
|||
<div class="page-layout">
|
||||
{{#global-header class="page-header"}}
|
||||
{{app-breadcrumbs}}
|
||||
{{/global-header}}
|
||||
{{outlet}}
|
||||
</div>
|
||||
|
|
|
@ -1,14 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#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">
|
||||
<h1 data-test-title class="title">
|
||||
|
|
|
@ -1,14 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#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"}}
|
||||
<section class="section">
|
||||
|
|
|
@ -1,14 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#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"}}
|
||||
<section class="section">
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
<div class="page-layout">
|
||||
{{#global-header class="page-header"}}
|
||||
{{app-breadcrumbs}}
|
||||
{{/global-header}}
|
||||
{{outlet}}
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
<li>
|
||||
{{#link-to "clients.index" data-test-breadcrumb="clients"}}Clients{{/link-to}}
|
||||
</li>
|
||||
<li class="is-active">
|
||||
{{#link-to "clients.client" model.id data-test-breadcrumb="client"}}{{model.shortId}}{{/link-to}}
|
||||
</li>
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body"}}
|
||||
<section class="section">
|
||||
<h1 data-test-title class="title">
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
<li class="is-active">
|
||||
{{#link-to "clients.index"}}Clients{{/link-to}}
|
||||
</li>
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body"}}
|
||||
<section class="section">
|
||||
{{#if isForbidden}}
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
<li class="is-active">
|
||||
{{#link-to "clients.index"}}Clients{{/link-to}}
|
||||
</li>
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body"}}
|
||||
<section class="section has-text-centered">{{partial "partials/loading-spinner"}}</section>
|
||||
{{/gutter-menu}}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{{#each breadcrumbs as |breadcrumb index|}}
|
||||
<li class="{{if (eq (inc index) breadcrumbs.length) "is-active"}}">
|
||||
{{#if breadcrumb.isPending}}
|
||||
<a href="#" aria-label="loading" data-test-breadcrumb="loading">…</a>
|
||||
{{else}}
|
||||
{{#link-to
|
||||
params=breadcrumb.args
|
||||
data-test-breadcrumb=breadcrumb.args.firstObject}}
|
||||
{{breadcrumb.label}}
|
||||
{{/link-to}}
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each}}
|
|
@ -1,10 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#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}}
|
||||
{{#job-page/parts/body job=job onNamespaceChange=onNamespaceChange}}
|
||||
{{job-page/parts/error errorMessage=errorMessage onDismiss=(action "clearErrorMessage")}}
|
||||
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#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}}
|
||||
{{#job-page/parts/body job=job onNamespaceChange=onNamespaceChange}}
|
||||
{{job-page/parts/error errorMessage=errorMessage onDismiss=(action "clearErrorMessage")}}
|
||||
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#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}}
|
||||
{{#job-page/parts/body job=job onNamespaceChange=onNamespaceChange}}
|
||||
{{job-page/parts/error errorMessage=errorMessage onDismiss=(action "clearErrorMessage")}}
|
||||
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#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}}
|
||||
{{#job-page/parts/body job=job onNamespaceChange=onNamespaceChange}}
|
||||
{{job-page/parts/error errorMessage=errorMessage onDismiss=(action "clearErrorMessage")}}
|
||||
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#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}}
|
||||
{{#job-page/parts/body job=job onNamespaceChange=onNamespaceChange}}
|
||||
{{job-page/parts/error errorMessage=errorMessage onDismiss=(action "clearErrorMessage")}}
|
||||
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#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}}
|
||||
{{#job-page/parts/body job=job onNamespaceChange=onNamespaceChange}}
|
||||
{{job-page/parts/error errorMessage=errorMessage onDismiss=(action "clearErrorMessage")}}
|
||||
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#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}}
|
||||
{{#job-page/parts/body job=job onNamespaceChange=onNamespaceChange}}
|
||||
{{job-page/parts/error errorMessage=errorMessage onDismiss=(action "clearErrorMessage")}}
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
<div class="page-layout">
|
||||
{{#global-header class="page-header"}}
|
||||
{{app-breadcrumbs}}
|
||||
{{/global-header}}
|
||||
{{outlet}}
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
<li class="is-active">
|
||||
{{#link-to "jobs.index"}}Jobs{{/link-to}}
|
||||
</li>
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body" onNamespaceChange=(action "refresh")}}
|
||||
<section class="section">
|
||||
{{#if isForbidden}}
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#each breadcrumbs as |breadcrumb index|}}
|
||||
<li class="{{if (eq (inc index) breadcrumbs.length) "is-active"}}">
|
||||
{{#link-to params=breadcrumb.args}}{{breadcrumb.label}}{{/link-to}}
|
||||
</li>
|
||||
{{/each}}
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body" onNamespaceChange=(action "gotoJobs")}}
|
||||
{{partial "jobs/job/subnav"}}
|
||||
<section class="section">
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#each breadcrumbs as |breadcrumb index|}}
|
||||
<li class="{{if (eq (inc index) breadcrumbs.length) "is-active"}}">
|
||||
{{#link-to params=breadcrumb.args}}{{breadcrumb.label}}{{/link-to}}
|
||||
</li>
|
||||
{{/each}}
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body" onNamespaceChange=(action "gotoJobs")}}
|
||||
{{partial "jobs/job/subnav"}}
|
||||
<section class="section">
|
||||
{{job-deployments-stream deployments=deployments}}
|
||||
{{job-deployments-stream deployments=model.deployments}}
|
||||
</section>
|
||||
{{/gutter-menu}}
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#each breadcrumbs as |breadcrumb index|}}
|
||||
<li class="{{if (eq (inc index) breadcrumbs.length) "is-active"}}">
|
||||
{{#link-to params=breadcrumb.args}}{{breadcrumb.label}}{{/link-to}}
|
||||
</li>
|
||||
{{/each}}
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body"}}
|
||||
{{partial "jobs/job/subnav"}}
|
||||
<section class="section has-text-centered">{{partial "partials/loading-spinner"}}</section>
|
||||
|
|
|
@ -1,14 +1,3 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#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" onNamespaceChange=(action "gotoJobs")}}
|
||||
<div class="tabs is-subnav">
|
||||
<ul>
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
{{#global-header class="page-header"}}
|
||||
{{#each breadcrumbs as |breadcrumb index|}}
|
||||
<li class="{{if (eq (inc index) breadcrumbs.length) "is-active"}}">
|
||||
{{#link-to params=breadcrumb.args}}{{breadcrumb.label}}{{/link-to}}
|
||||
</li>
|
||||
{{/each}}
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body" onNamespaceChange=(action "gotoJobs")}}
|
||||
{{partial "jobs/job/subnav"}}
|
||||
<section class="section">
|
||||
{{job-versions-stream versions=versions verbose=true}}
|
||||
{{job-versions-stream versions=model.versions verbose=true}}
|
||||
</section>
|
||||
{{/gutter-menu}}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
{{#global-header class="page-header"}}
|
||||
<li class="is-active">
|
||||
{{#link-to "jobs.index"}}Jobs{{/link-to}}
|
||||
</li>
|
||||
{{app-breadcrumbs}}
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body"}}
|
||||
<section class="section has-text-centered">{{partial "partials/loading-spinner"}}</section>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<div class="page-layout">
|
||||
{{#global-header class="page-header"}}
|
||||
{{app-breadcrumbs}}
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body"}}
|
||||
<section class="section has-text-centered">{{partial "partials/loading-spinner"}}</section>
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<div class="page-layout">
|
||||
{{#global-header class="page-header"}}
|
||||
<li class="is-active">
|
||||
{{#link-to "servers.index"}}Servers{{/link-to}}
|
||||
</li>
|
||||
{{app-breadcrumbs}}
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body"}}
|
||||
<section class="section">
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<div class="page-layout">
|
||||
{{#global-header class="page-header"}}
|
||||
{{app-breadcrumbs}}
|
||||
{{/global-header}}
|
||||
{{#gutter-menu class="page-body"}}
|
||||
{{outlet}}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import PromiseObject from 'nomad-ui/utils/classes/promise-object';
|
||||
import { qpBuilder } from 'nomad-ui/utils/classes/query-params';
|
||||
|
||||
export const jobCrumb = job => ({
|
||||
label: job.get('trimmedName'),
|
||||
args: [
|
||||
'jobs.job.index',
|
||||
job.get('plainId'),
|
||||
qpBuilder({
|
||||
jobNamespace: job.get('namespace.name') || 'default',
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
export const jobCrumbs = job => {
|
||||
if (!job) return [];
|
||||
|
||||
if (job.get('parent.content')) {
|
||||
return [
|
||||
PromiseObject.create({
|
||||
promise: job.get('parent').then(parent => jobCrumb(parent)),
|
||||
}),
|
||||
jobCrumb(job),
|
||||
];
|
||||
} else {
|
||||
return [jobCrumb(job)];
|
||||
}
|
||||
};
|
|
@ -26,19 +26,19 @@ test('/clients/:id should have a breadcrumb trail linking back to clients', func
|
|||
|
||||
andThen(() => {
|
||||
assert.equal(
|
||||
find('[data-test-breadcrumb="clients"]').textContent.trim(),
|
||||
find('[data-test-breadcrumb="clients.index"]').textContent.trim(),
|
||||
'Clients',
|
||||
'First breadcrumb says clients'
|
||||
);
|
||||
assert.equal(
|
||||
find('[data-test-breadcrumb="client"]').textContent.trim(),
|
||||
find('[data-test-breadcrumb="clients.client"]').textContent.trim(),
|
||||
node.id.split('-')[0],
|
||||
'Second breadcrumb says the node short id'
|
||||
);
|
||||
});
|
||||
|
||||
andThen(() => {
|
||||
click(find('[data-test-breadcrumb="clients"]'));
|
||||
click(find('[data-test-breadcrumb="clients.index"]'));
|
||||
});
|
||||
|
||||
andThen(() => {
|
||||
|
|
|
@ -37,32 +37,32 @@ test('breadcrumbs match jobs / job / task group / allocation / task', function(a
|
|||
const shortId = allocation.id.split('-')[0];
|
||||
|
||||
assert.equal(
|
||||
find('[data-test-breadcrumb="Jobs"]').textContent.trim(),
|
||||
find('[data-test-breadcrumb="jobs.index"]').textContent.trim(),
|
||||
'Jobs',
|
||||
'Jobs is the first breadcrumb'
|
||||
);
|
||||
assert.equal(
|
||||
find(`[data-test-breadcrumb="${job.name}"]`).textContent.trim(),
|
||||
find('[data-test-breadcrumb="jobs.job.index"]').textContent.trim(),
|
||||
job.name,
|
||||
'Job is the second breadcrumb'
|
||||
);
|
||||
assert.equal(
|
||||
find(`[data-test-breadcrumb="${taskGroup}`).textContent.trim(),
|
||||
find('[data-test-breadcrumb="jobs.job.task-group"]').textContent.trim(),
|
||||
taskGroup,
|
||||
'Task Group is the third breadcrumb'
|
||||
);
|
||||
assert.equal(
|
||||
find(`[data-test-breadcrumb="${shortId}"]`).textContent.trim(),
|
||||
find('[data-test-breadcrumb="allocations.allocation"]').textContent.trim(),
|
||||
shortId,
|
||||
'Allocation short id is the fourth breadcrumb'
|
||||
);
|
||||
assert.equal(
|
||||
find(`[data-test-breadcrumb="${task.name}"]`).textContent.trim(),
|
||||
find('[data-test-breadcrumb="allocations.allocation.task"]').textContent.trim(),
|
||||
task.name,
|
||||
'Task name is the fifth breadcrumb'
|
||||
);
|
||||
|
||||
click('[data-test-breadcrumb="Jobs"]');
|
||||
click('[data-test-breadcrumb="jobs.index"]');
|
||||
andThen(() => {
|
||||
assert.equal(currentURL(), '/jobs', 'Jobs breadcrumb links correctly');
|
||||
});
|
||||
|
@ -70,7 +70,7 @@ test('breadcrumbs match jobs / job / task group / allocation / task', function(a
|
|||
visit(`/allocations/${allocation.id}/${task.name}`);
|
||||
});
|
||||
andThen(() => {
|
||||
click(`[data-test-breadcrumb="${job.name}"]`);
|
||||
click('[data-test-breadcrumb="jobs.job.index"]');
|
||||
});
|
||||
andThen(() => {
|
||||
assert.equal(currentURL(), `/jobs/${job.id}`, 'Job breadcrumb links correctly');
|
||||
|
@ -79,7 +79,7 @@ test('breadcrumbs match jobs / job / task group / allocation / task', function(a
|
|||
visit(`/allocations/${allocation.id}/${task.name}`);
|
||||
});
|
||||
andThen(() => {
|
||||
click(`[data-test-breadcrumb="${taskGroup}"]`);
|
||||
click('[data-test-breadcrumb="jobs.job.task-group"]');
|
||||
});
|
||||
andThen(() => {
|
||||
assert.equal(
|
||||
|
@ -92,7 +92,7 @@ test('breadcrumbs match jobs / job / task group / allocation / task', function(a
|
|||
visit(`/allocations/${allocation.id}/${task.name}`);
|
||||
});
|
||||
andThen(() => {
|
||||
click(`[data-test-breadcrumb="${shortId}"]`);
|
||||
click('[data-test-breadcrumb="allocations.allocation"]');
|
||||
});
|
||||
andThen(() => {
|
||||
assert.equal(
|
||||
|
|
|
@ -86,31 +86,31 @@ test('/jobs/:id/:task-group should list high-level metrics for the allocation',
|
|||
|
||||
test('/jobs/:id/:task-group should have breadcrumbs for job and jobs', function(assert) {
|
||||
assert.equal(
|
||||
find('[data-test-breadcrumb="Jobs"]').textContent.trim(),
|
||||
find('[data-test-breadcrumb="jobs.index"]').textContent.trim(),
|
||||
'Jobs',
|
||||
'First breadcrumb says jobs'
|
||||
);
|
||||
assert.equal(
|
||||
find(`[data-test-breadcrumb="${job.name}"]`).textContent.trim(),
|
||||
find('[data-test-breadcrumb="jobs.job.index"]').textContent.trim(),
|
||||
job.name,
|
||||
'Second breadcrumb says the job name'
|
||||
);
|
||||
assert.equal(
|
||||
find(`[data-test-breadcrumb="${taskGroup.name}"]`).textContent.trim(),
|
||||
find('[data-test-breadcrumb="jobs.job.task-group"]').textContent.trim(),
|
||||
taskGroup.name,
|
||||
'Third breadcrumb says the job name'
|
||||
);
|
||||
});
|
||||
|
||||
test('/jobs/:id/:task-group first breadcrumb should link to jobs', function(assert) {
|
||||
click('[data-test-breadcrumb="Jobs"]');
|
||||
click('[data-test-breadcrumb="jobs.index"]');
|
||||
andThen(() => {
|
||||
assert.equal(currentURL(), '/jobs', 'First breadcrumb links back to jobs');
|
||||
});
|
||||
});
|
||||
|
||||
test('/jobs/:id/:task-group second breadcrumb should link to the job for the task group', function(assert) {
|
||||
click(`[data-test-breadcrumb="${job.name}"]`);
|
||||
click('[data-test-breadcrumb="jobs.job.index"]');
|
||||
andThen(() => {
|
||||
assert.equal(
|
||||
currentURL(),
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
import Service from '@ember/service';
|
||||
import { getOwner } from '@ember/application';
|
||||
import RSVP from 'rsvp';
|
||||
import { test, moduleForComponent } from 'ember-qunit';
|
||||
import { findAll } from 'ember-native-dom-helpers';
|
||||
import wait from 'ember-test-helpers/wait';
|
||||
import hbs from 'htmlbars-inline-precompile';
|
||||
import PromiseObject from 'nomad-ui/utils/classes/promise-object';
|
||||
|
||||
moduleForComponent('app-breadcrumbs', 'Integration | Component | app breadcrumbs', {
|
||||
integration: true,
|
||||
beforeEach() {
|
||||
const mockBreadcrumbs = Service.extend({
|
||||
breadcrumbs: [],
|
||||
});
|
||||
|
||||
this.register('service:breadcrumbs', mockBreadcrumbs);
|
||||
this.breadcrumbs = getOwner(this).lookup('service:breadcrumbs');
|
||||
},
|
||||
});
|
||||
|
||||
const commonCrumbs = [{ label: 'One', args: ['one'] }, { label: 'Two', args: ['two'] }];
|
||||
|
||||
const template = hbs`
|
||||
{{app-breadcrumbs}}
|
||||
`;
|
||||
|
||||
test('breadcrumbs comes from the breadcrumbs service', function(assert) {
|
||||
this.breadcrumbs.set('breadcrumbs', commonCrumbs);
|
||||
|
||||
this.render(template);
|
||||
|
||||
assert.equal(
|
||||
findAll('[data-test-breadcrumb]').length,
|
||||
commonCrumbs.length,
|
||||
'The number of crumbs matches the crumbs from the service'
|
||||
);
|
||||
});
|
||||
|
||||
test('every breadcrumb is rendered correctly', function(assert) {
|
||||
this.breadcrumbs.set('breadcrumbs', commonCrumbs);
|
||||
|
||||
this.render(template);
|
||||
|
||||
const renderedCrumbs = findAll('[data-test-breadcrumb]');
|
||||
|
||||
renderedCrumbs.forEach((crumb, index) => {
|
||||
assert.equal(
|
||||
crumb.textContent.trim(),
|
||||
commonCrumbs[index].label,
|
||||
`Crumb ${index} is ${commonCrumbs[index].label}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('when breadcrumbs are pending promises, an ellipsis is rendered', function(assert) {
|
||||
let resolvePromise;
|
||||
const promise = new RSVP.Promise(resolve => {
|
||||
resolvePromise = resolve;
|
||||
});
|
||||
|
||||
this.breadcrumbs.set('breadcrumbs', [
|
||||
{ label: 'One', args: ['one'] },
|
||||
PromiseObject.create({ promise }),
|
||||
{ label: 'Three', args: ['three'] },
|
||||
]);
|
||||
|
||||
this.render(template);
|
||||
|
||||
assert.equal(
|
||||
findAll('[data-test-breadcrumb]')[1].textContent.trim(),
|
||||
'…',
|
||||
'Promise breadcrumb is in a loading state'
|
||||
);
|
||||
|
||||
resolvePromise({ label: 'Two', args: ['two'] });
|
||||
|
||||
return wait().then(() => {
|
||||
assert.equal(
|
||||
findAll('[data-test-breadcrumb]')[1].textContent.trim(),
|
||||
'Two',
|
||||
'Promise breadcrumb has resolved and now renders Two'
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,149 @@
|
|||
import Service from '@ember/service';
|
||||
import Route from '@ember/routing/route';
|
||||
import Controller from '@ember/controller';
|
||||
import { get } from '@ember/object';
|
||||
import { alias } from '@ember/object/computed';
|
||||
import { getOwner } from '@ember/application';
|
||||
import RSVP from 'rsvp';
|
||||
import { moduleFor, test } from 'ember-qunit';
|
||||
import PromiseObject from 'nomad-ui/utils/classes/promise-object';
|
||||
|
||||
const makeRoute = (crumbs, controller = {}) =>
|
||||
Route.extend({
|
||||
breadcrumbs: crumbs,
|
||||
controller: Controller.extend(controller).create(),
|
||||
});
|
||||
|
||||
moduleFor('service:breadcrumbs', 'Unit | Service | Breadcrumbs', {
|
||||
beforeEach() {
|
||||
const mockRouter = Service.extend({
|
||||
currentRouteName: 'application',
|
||||
currentURL: '/',
|
||||
});
|
||||
|
||||
this.register('service:router', mockRouter);
|
||||
this.router = getOwner(this).lookup('service:router');
|
||||
|
||||
const none = makeRoute();
|
||||
const fixed = makeRoute([{ label: 'Static', args: ['static.index'] }]);
|
||||
const manyFixed = makeRoute([
|
||||
{ label: 'Static 1', args: ['static.index', 1] },
|
||||
{ label: 'Static 2', args: ['static.index', 2] },
|
||||
]);
|
||||
const dynamic = makeRoute(model => [{ label: model, args: ['dynamic.index', model] }], {
|
||||
model: 'Label of the Crumb',
|
||||
});
|
||||
const manyDynamic = makeRoute(
|
||||
model => [
|
||||
{ label: get(model, 'fishOne'), args: ['dynamic.index', get(model, 'fishOne')] },
|
||||
{ label: get(model, 'fishTwo'), args: ['dynamic.index', get(model, 'fishTwo')] },
|
||||
],
|
||||
{
|
||||
model: {
|
||||
fishOne: 'red',
|
||||
fishTwo: 'blue',
|
||||
},
|
||||
}
|
||||
);
|
||||
const promise = makeRoute([
|
||||
PromiseObject.create({
|
||||
promise: RSVP.Promise.resolve({
|
||||
label: 'delayed',
|
||||
args: ['wait.for.it'],
|
||||
}),
|
||||
}),
|
||||
]);
|
||||
const fromURL = makeRoute(model => [{ label: model, args: ['url'] }], {
|
||||
router: getOwner(this).lookup('service:router'),
|
||||
model: alias('router.currentURL'),
|
||||
});
|
||||
|
||||
this.register('route:none', none);
|
||||
this.register('route:none.more-none', none);
|
||||
this.register('route:static', fixed);
|
||||
this.register('route:static.many', manyFixed);
|
||||
this.register('route:dynamic', dynamic);
|
||||
this.register('route:dynamic.many', manyDynamic);
|
||||
this.register('route:promise', promise);
|
||||
this.register('route:url', fromURL);
|
||||
},
|
||||
|
||||
subject() {
|
||||
return getOwner(this)
|
||||
.factoryFor('service:breadcrumbs')
|
||||
.create();
|
||||
},
|
||||
});
|
||||
|
||||
test('when the route hierarchy has no breadcrumbs', function(assert) {
|
||||
this.router.set('currentRouteName', 'none');
|
||||
|
||||
const service = this.subject();
|
||||
assert.deepEqual(service.get('breadcrumbs'), []);
|
||||
});
|
||||
|
||||
test('when the route hierarchy has one segment with static crumbs', function(assert) {
|
||||
this.router.set('currentRouteName', 'static');
|
||||
|
||||
const service = this.subject();
|
||||
assert.deepEqual(service.get('breadcrumbs'), [{ label: 'Static', args: ['static.index'] }]);
|
||||
});
|
||||
|
||||
test('when the route hierarchy has multiple segments with static crumbs', function(assert) {
|
||||
this.router.set('currentRouteName', 'static.many');
|
||||
|
||||
const service = this.subject();
|
||||
assert.deepEqual(service.get('breadcrumbs'), [
|
||||
{ label: 'Static', args: ['static.index'] },
|
||||
{ label: 'Static 1', args: ['static.index', 1] },
|
||||
{ label: 'Static 2', args: ['static.index', 2] },
|
||||
]);
|
||||
});
|
||||
|
||||
test('when the route hierarchy has a function as its breadcrumbs property', function(assert) {
|
||||
this.router.set('currentRouteName', 'dynamic');
|
||||
|
||||
const service = this.subject();
|
||||
assert.deepEqual(service.get('breadcrumbs'), [
|
||||
{ label: 'Label of the Crumb', args: ['dynamic.index', 'Label of the Crumb'] },
|
||||
]);
|
||||
});
|
||||
|
||||
test('when the route hierarchy has multiple segments with dynamic crumbs', function(assert) {
|
||||
this.router.set('currentRouteName', 'dynamic.many');
|
||||
|
||||
const service = this.subject();
|
||||
assert.deepEqual(service.get('breadcrumbs'), [
|
||||
{ label: 'Label of the Crumb', args: ['dynamic.index', 'Label of the Crumb'] },
|
||||
{ label: 'red', args: ['dynamic.index', 'red'] },
|
||||
{ label: 'blue', args: ['dynamic.index', 'blue'] },
|
||||
]);
|
||||
});
|
||||
|
||||
test('when a route provides a breadcrumb that is a promise, it gets passed through to the template', function(assert) {
|
||||
this.router.set('currentRouteName', 'promise');
|
||||
|
||||
const service = this.subject();
|
||||
assert.ok(service.get('breadcrumbs.firstObject') instanceof PromiseObject);
|
||||
});
|
||||
|
||||
// This happens when transitioning to the current route but with a different model
|
||||
// jobs.job.index --> jobs.job.index
|
||||
// /jobs/one --> /jobs/two
|
||||
test('when the route stays the same but the url changes, breadcrumbs get recomputed', function(assert) {
|
||||
this.router.set('currentRouteName', 'url');
|
||||
|
||||
const service = this.subject();
|
||||
assert.deepEqual(
|
||||
service.get('breadcrumbs'),
|
||||
[{ label: '/', args: ['url'] }],
|
||||
'The label is initially / as is the router currentURL'
|
||||
);
|
||||
|
||||
this.router.set('currentURL', '/somewhere/else');
|
||||
assert.deepEqual(
|
||||
service.get('breadcrumbs'),
|
||||
[{ label: '/somewhere/else', args: ['url'] }],
|
||||
'The label changes with currentURL since it is an alias and a change to currentURL recomputes breadcrumbs'
|
||||
);
|
||||
});
|
Loading…
Reference in New Issue