ui: set namespace when looking for and displaying children jobs (#11110)
This commit is contained in:
parent
f09d5ebcd6
commit
eb0ed980a5
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:bug
|
||||||
|
ui: Fixed an issue that prevented periodic and dispatch jobs in a non-default namespace to be properly rendered
|
||||||
|
```
|
|
@ -9,6 +9,7 @@ import classic from 'ember-classic-decorator';
|
||||||
@classic
|
@classic
|
||||||
@classNames('boxed-section')
|
@classNames('boxed-section')
|
||||||
export default class Children extends Component.extend(Sortable) {
|
export default class Children extends Component.extend(Sortable) {
|
||||||
|
@service system;
|
||||||
@service userSettings;
|
@service userSettings;
|
||||||
|
|
||||||
job = null;
|
job = null;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Route from '@ember/routing/route';
|
import Route from '@ember/routing/route';
|
||||||
import { collect } from '@ember/object/computed';
|
import { collect } from '@ember/object/computed';
|
||||||
import { watchRecord, watchRelationship, watchAll } from 'nomad-ui/utils/properties/watch';
|
import { watchRecord, watchRelationship, watchQuery } from 'nomad-ui/utils/properties/watch';
|
||||||
import WithWatchers from 'nomad-ui/mixins/with-watchers';
|
import WithWatchers from 'nomad-ui/mixins/with-watchers';
|
||||||
|
|
||||||
export default class IndexRoute extends Route.extend(WithWatchers) {
|
export default class IndexRoute extends Route.extend(WithWatchers) {
|
||||||
|
@ -15,7 +15,9 @@ export default class IndexRoute extends Route.extend(WithWatchers) {
|
||||||
evaluations: this.watchEvaluations.perform(model),
|
evaluations: this.watchEvaluations.perform(model),
|
||||||
latestDeployment:
|
latestDeployment:
|
||||||
model.get('supportsDeployments') && this.watchLatestDeployment.perform(model),
|
model.get('supportsDeployments') && this.watchLatestDeployment.perform(model),
|
||||||
list: model.get('hasChildren') && this.watchAll.perform(),
|
list:
|
||||||
|
model.get('hasChildren') &&
|
||||||
|
this.watchAllJobs.perform({ namespace: model.namespace.get('name') }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +34,7 @@ export default class IndexRoute extends Route.extend(WithWatchers) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@watchRecord('job') watch;
|
@watchRecord('job') watch;
|
||||||
@watchAll('job') watchAll;
|
@watchQuery('job') watchAllJobs;
|
||||||
@watchRecord('job-summary') watchSummary;
|
@watchRecord('job-summary') watchSummary;
|
||||||
@watchRelationship('allocations') watchAllocations;
|
@watchRelationship('allocations') watchAllocations;
|
||||||
@watchRelationship('evaluations') watchEvaluations;
|
@watchRelationship('evaluations') watchEvaluations;
|
||||||
|
@ -40,7 +42,7 @@ export default class IndexRoute extends Route.extend(WithWatchers) {
|
||||||
|
|
||||||
@collect(
|
@collect(
|
||||||
'watch',
|
'watch',
|
||||||
'watchAll',
|
'watchAllJobs',
|
||||||
'watchSummary',
|
'watchSummary',
|
||||||
'watchAllocations',
|
'watchAllocations',
|
||||||
'watchEvaluations',
|
'watchEvaluations',
|
||||||
|
|
|
@ -31,9 +31,12 @@
|
||||||
@sortProperty={{this.sortProperty}}
|
@sortProperty={{this.sortProperty}}
|
||||||
@sortDescending={{this.sortDescending}}
|
@sortDescending={{this.sortDescending}}
|
||||||
@class="with-foot" as |t|>
|
@class="with-foot" as |t|>
|
||||||
<t.head>
|
<t.head data-test-jobs-header>
|
||||||
<t.sort-by @prop="name">Name</t.sort-by>
|
<t.sort-by @prop="name">Name</t.sort-by>
|
||||||
<t.sort-by @prop="submitTime">Submitted At</t.sort-by>
|
{{#if this.system.shouldShowNamespaces}}
|
||||||
|
<t.sort-by @prop="namespace.name" data-test-jobs-namespace-header>Namespace</t.sort-by>
|
||||||
|
{{/if}}
|
||||||
|
<t.sort-by @prop="submitTime" data-test-jobs-submit-time-header>Submitted At</t.sort-by>
|
||||||
<t.sort-by @prop="status">Status</t.sort-by>
|
<t.sort-by @prop="status">Status</t.sort-by>
|
||||||
<t.sort-by @prop="type">Type</t.sort-by>
|
<t.sort-by @prop="type">Type</t.sort-by>
|
||||||
<t.sort-by @prop="priority">Priority</t.sort-by>
|
<t.sort-by @prop="priority">Priority</t.sort-by>
|
||||||
|
|
|
@ -25,6 +25,7 @@ moduleForJob(
|
||||||
.sortBy('submitTime')
|
.sortBy('submitTime')
|
||||||
.reverse()[0];
|
.reverse()[0];
|
||||||
|
|
||||||
|
assert.ok(JobDetail.jobsHeader.hasSubmitTime);
|
||||||
assert.equal(
|
assert.equal(
|
||||||
JobDetail.jobs[0].submitTime,
|
JobDetail.jobs[0].submitTime,
|
||||||
moment(mostRecentLaunch.submitTime / 1000000).format('MMM DD HH:mm:ss ZZ')
|
moment(mostRecentLaunch.submitTime / 1000000).format('MMM DD HH:mm:ss ZZ')
|
||||||
|
@ -33,6 +34,25 @@ moduleForJob(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
moduleForJob(
|
||||||
|
'Acceptance | job detail (periodic in namespace)',
|
||||||
|
'children',
|
||||||
|
() => {
|
||||||
|
const namespace = server.create('namespace', { id: 'test' });
|
||||||
|
const parent = server.create('job', 'periodic', {
|
||||||
|
shallow: true,
|
||||||
|
namespaceId: namespace.name,
|
||||||
|
});
|
||||||
|
return parent;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'display namespace in children table': async function(job, assert) {
|
||||||
|
assert.ok(JobDetail.jobsHeader.hasNamespace);
|
||||||
|
assert.equal(JobDetail.jobs[0].namespace, job.namespace);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
moduleForJob(
|
moduleForJob(
|
||||||
'Acceptance | job detail (parameterized)',
|
'Acceptance | job detail (parameterized)',
|
||||||
'children',
|
'children',
|
||||||
|
@ -44,6 +64,7 @@ moduleForJob(
|
||||||
.sortBy('submitTime')
|
.sortBy('submitTime')
|
||||||
.reverse()[0];
|
.reverse()[0];
|
||||||
|
|
||||||
|
assert.ok(JobDetail.jobsHeader.hasSubmitTime);
|
||||||
assert.equal(
|
assert.equal(
|
||||||
JobDetail.jobs[0].submitTime,
|
JobDetail.jobs[0].submitTime,
|
||||||
moment(mostRecentLaunch.submitTime / 1000000).format('MMM DD HH:mm:ss ZZ')
|
moment(mostRecentLaunch.submitTime / 1000000).format('MMM DD HH:mm:ss ZZ')
|
||||||
|
@ -52,6 +73,25 @@ moduleForJob(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
moduleForJob(
|
||||||
|
'Acceptance | job detail (parameterized in namespace)',
|
||||||
|
'children',
|
||||||
|
() => {
|
||||||
|
const namespace = server.create('namespace', { id: 'test' });
|
||||||
|
const parent = server.create('job', 'parameterized', {
|
||||||
|
shallow: true,
|
||||||
|
namespaceId: namespace.name,
|
||||||
|
});
|
||||||
|
return parent;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'display namespace in children table': async function(job, assert) {
|
||||||
|
assert.ok(JobDetail.jobsHeader.hasNamespace);
|
||||||
|
assert.equal(JobDetail.jobs[0].namespace, job.namespace);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
moduleForJob('Acceptance | job detail (periodic child)', 'allocations', () => {
|
moduleForJob('Acceptance | job detail (periodic child)', 'allocations', () => {
|
||||||
const parent = server.create('job', 'periodic', { childrenCount: 1, shallow: true });
|
const parent = server.create('job', 'periodic', { childrenCount: 1, shallow: true });
|
||||||
return server.db.jobs.where({ parentId: parent.id })[0];
|
return server.db.jobs.where({ parentId: parent.id })[0];
|
||||||
|
|
|
@ -22,32 +22,51 @@ export default function moduleForJob(title, context, jobFactory, additionalTests
|
||||||
hooks.beforeEach(async function() {
|
hooks.beforeEach(async function() {
|
||||||
server.create('node');
|
server.create('node');
|
||||||
job = jobFactory();
|
job = jobFactory();
|
||||||
await JobDetail.visit({ id: job.id });
|
if (!job.namespace || job.namespace === 'default') {
|
||||||
|
await JobDetail.visit({ id: job.id });
|
||||||
|
} else {
|
||||||
|
await JobDetail.visit({ id: job.id, namespace: job.namespace });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('visiting /jobs/:job_id', async function(assert) {
|
test('visiting /jobs/:job_id', async function(assert) {
|
||||||
assert.equal(currentURL(), `/jobs/${encodeURIComponent(job.id)}`);
|
assert.equal(
|
||||||
|
currentURL(),
|
||||||
|
urlWithNamespace(`/jobs/${encodeURIComponent(job.id)}`, job.namespace)
|
||||||
|
);
|
||||||
assert.equal(document.title, `Job ${job.name} - Nomad`);
|
assert.equal(document.title, `Job ${job.name} - Nomad`);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('the subnav links to overview', async function(assert) {
|
test('the subnav links to overview', async function(assert) {
|
||||||
await JobDetail.tabFor('overview').visit();
|
await JobDetail.tabFor('overview').visit();
|
||||||
assert.equal(currentURL(), `/jobs/${encodeURIComponent(job.id)}`);
|
assert.equal(
|
||||||
|
currentURL(),
|
||||||
|
urlWithNamespace(`/jobs/${encodeURIComponent(job.id)}`, job.namespace)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('the subnav links to definition', async function(assert) {
|
test('the subnav links to definition', async function(assert) {
|
||||||
await JobDetail.tabFor('definition').visit();
|
await JobDetail.tabFor('definition').visit();
|
||||||
assert.equal(currentURL(), `/jobs/${encodeURIComponent(job.id)}/definition`);
|
assert.equal(
|
||||||
|
currentURL(),
|
||||||
|
urlWithNamespace(`/jobs/${encodeURIComponent(job.id)}/definition`, job.namespace)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('the subnav links to versions', async function(assert) {
|
test('the subnav links to versions', async function(assert) {
|
||||||
await JobDetail.tabFor('versions').visit();
|
await JobDetail.tabFor('versions').visit();
|
||||||
assert.equal(currentURL(), `/jobs/${encodeURIComponent(job.id)}/versions`);
|
assert.equal(
|
||||||
|
currentURL(),
|
||||||
|
urlWithNamespace(`/jobs/${encodeURIComponent(job.id)}/versions`, job.namespace)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('the subnav links to evaluations', async function(assert) {
|
test('the subnav links to evaluations', async function(assert) {
|
||||||
await JobDetail.tabFor('evaluations').visit();
|
await JobDetail.tabFor('evaluations').visit();
|
||||||
assert.equal(currentURL(), `/jobs/${encodeURIComponent(job.id)}/evaluations`);
|
assert.equal(
|
||||||
|
currentURL(),
|
||||||
|
urlWithNamespace(`/jobs/${encodeURIComponent(job.id)}/evaluations`, job.namespace)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('the title buttons are dependent on job status', async function(assert) {
|
test('the title buttons are dependent on job status', async function(assert) {
|
||||||
|
@ -99,3 +118,11 @@ export default function moduleForJob(title, context, jobFactory, additionalTests
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function urlWithNamespace(url, namespace) {
|
||||||
|
if (!namespace || namespace === 'default') {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${url}?namespace=${namespace}`;
|
||||||
|
}
|
||||||
|
|
|
@ -64,9 +64,16 @@ export default create({
|
||||||
|
|
||||||
viewAllAllocations: text('[data-test-view-all-allocations]'),
|
viewAllAllocations: text('[data-test-view-all-allocations]'),
|
||||||
|
|
||||||
|
jobsHeader: {
|
||||||
|
scope: '[data-test-jobs-header]',
|
||||||
|
hasSubmitTime: isPresent('[data-test-jobs-submit-time-header]'),
|
||||||
|
hasNamespace: isPresent('[data-test-jobs-namespace-header]'),
|
||||||
|
},
|
||||||
|
|
||||||
jobs: collection('[data-test-job-row]', {
|
jobs: collection('[data-test-job-row]', {
|
||||||
id: attribute('data-test-job-row'),
|
id: attribute('data-test-job-row'),
|
||||||
name: text('[data-test-job-name]'),
|
name: text('[data-test-job-name]'),
|
||||||
|
namespace: text('[data-test-job-namespace]'),
|
||||||
link: attribute('href', '[data-test-job-name] a'),
|
link: attribute('href', '[data-test-job-name] a'),
|
||||||
submitTime: text('[data-test-job-submit-time]'),
|
submitTime: text('[data-test-job-submit-time]'),
|
||||||
status: text('[data-test-job-status]'),
|
status: text('[data-test-job-status]'),
|
||||||
|
|
Loading…
Reference in New Issue