mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 18:35:44 +03:00
[ui, deployments] Add status panel to child jobs (#17217)
* Treated same-route as sub-route and didnt cancel watchers * Adds panel to child jobs and sub-sorts * removed the safety check in module-for-job tests * [ui] Adds status panel to Sysbatch jobs (#17243) * In working out periodic/param child jobs, realized the intersection with sysbatch is high enough that it ought to be worked on now * Further removal of jobclientstatussummary * Explicitly making mocked jobs in no-deployment mode * remove last remnants of job-client-status-summary component * Screwed up my sorting order a few commits ago; this corrects it * noActiveDeployment gonna be the death of me
This commit is contained in:
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import Component from '@ember/component';
|
||||
import { action, computed } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { camelize } from '@ember/string';
|
||||
import { classNames } from '@ember-decorators/component';
|
||||
import classic from 'ember-classic-decorator';
|
||||
import jobClientStatus from 'nomad-ui/utils/properties/job-client-status';
|
||||
|
||||
@classic
|
||||
@classNames('boxed-section')
|
||||
export default class JobClientStatusSummary extends Component {
|
||||
@service router;
|
||||
@service store;
|
||||
|
||||
@jobClientStatus('nodes', 'job') jobClientStatus;
|
||||
|
||||
get nodes() {
|
||||
return this.store.peekAll('node');
|
||||
}
|
||||
|
||||
job = null;
|
||||
|
||||
@action
|
||||
gotoClients(statusFilter) {
|
||||
this.router.transitionTo('jobs.job.clients', this.job, {
|
||||
queryParams: {
|
||||
status: JSON.stringify(statusFilter),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@computed
|
||||
get isExpanded() {
|
||||
const storageValue = window.localStorage.nomadExpandJobClientStatusSummary;
|
||||
return storageValue != null ? JSON.parse(storageValue) : true;
|
||||
}
|
||||
|
||||
@action
|
||||
onSliceClick(ev, slice) {
|
||||
this.gotoClients([camelize(slice.className)]);
|
||||
}
|
||||
|
||||
persist(item, isOpen) {
|
||||
window.localStorage.nomadExpandJobClientStatusSummary = isOpen;
|
||||
this.notifyPropertyChange('isExpanded');
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,21 @@ export default class JobStatusPanelSteadyComponent extends Component {
|
||||
.filter(
|
||||
(a) => a.clientStatus !== 'running' && a.clientStatus !== 'pending'
|
||||
)
|
||||
.sortBy('jobVersion')
|
||||
.sort((a, b) => {
|
||||
// First sort by jobVersion
|
||||
if (a.jobVersion > b.jobVersion) return 1;
|
||||
if (a.jobVersion < b.jobVersion) return -1;
|
||||
|
||||
// If jobVersion is the same, sort by status order
|
||||
if (a.jobVersion === b.jobVersion) {
|
||||
return (
|
||||
jobAllocStatuses[this.args.job.type].indexOf(b.clientStatus) -
|
||||
jobAllocStatuses[this.args.job.type].indexOf(a.clientStatus)
|
||||
);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
})
|
||||
.reverse();
|
||||
|
||||
// Iterate over the sorted allocs
|
||||
@@ -137,7 +151,7 @@ export default class JobStatusPanelSteadyComponent extends Component {
|
||||
}
|
||||
|
||||
get atMostOneAllocPerNode() {
|
||||
return this.args.job.type === 'system';
|
||||
return this.args.job.type === 'system' || this.args.job.type === 'sysbatch';
|
||||
}
|
||||
|
||||
get versions() {
|
||||
|
||||
@@ -26,9 +26,6 @@
|
||||
DasRecommendations=(component
|
||||
"job-page/parts/das-recommendations" job=@job
|
||||
)
|
||||
JobClientStatusSummary=(component
|
||||
"job-page/parts/job-client-status-summary" job=@job
|
||||
)
|
||||
Children=(component "job-page/parts/children" job=@job)
|
||||
|
||||
StatusPanel=(component
|
||||
|
||||
@@ -22,8 +22,7 @@
|
||||
</span>
|
||||
</:before-namespace>
|
||||
</jobPage.ui.StatsBox>
|
||||
<jobPage.ui.JobClientStatusSummary />
|
||||
<jobPage.ui.Summary @forceCollapsed={{@job.hasClientStatus}} />
|
||||
<jobPage.ui.StatusPanel @statusMode={{@statusMode}} @setStatusMode={{@setStatusMode}} />
|
||||
<jobPage.ui.PlacementFailures />
|
||||
<jobPage.ui.TaskGroups @sortProperty={{@sortProperty}} @sortDescending={{@sortDescending}} />
|
||||
<jobPage.ui.RecentAllocations @activeTask={{@activeTask}} @setActiveTaskQueryParam={{@setActiveTaskQueryParam}} />
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
~}}
|
||||
|
||||
{{#if this.job.hasClientStatus}}
|
||||
<ListAccordion
|
||||
data-test-job-client-summary
|
||||
@source={{array this.job}}
|
||||
@key="id"
|
||||
@startExpanded={{this.isExpanded}}
|
||||
@onToggle={{action this.persist}} as |a|
|
||||
>
|
||||
{{#if (can "read client")}}
|
||||
<a.head @buttonLabel={{if a.isOpen "collapse" "expand"}}>
|
||||
<div class="columns">
|
||||
<div class="column is-minimum nowrap">
|
||||
Job Status in Client
|
||||
<span class="badge {{if a.isOpen "is-white" "is-light"}}">
|
||||
{{this.jobClientStatus.totalNodes}}
|
||||
</span>
|
||||
<span
|
||||
class="tooltip multiline"
|
||||
aria-label="Aggreate status of job's allocations in each client."
|
||||
>
|
||||
{{x-icon "info-circle-outline" class="is-faded"}}
|
||||
</span>
|
||||
</div>
|
||||
{{#unless a.isOpen}}
|
||||
<div class="column">
|
||||
<div class="inline-chart bumper-left">
|
||||
<JobClientStatusBar
|
||||
@onSliceClick={{action this.onSliceClick}}
|
||||
@job={{this.job}}
|
||||
@jobClientStatus={{this.jobClientStatus}}
|
||||
@isNarrow={{true}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</a.head>
|
||||
<a.body>
|
||||
<JobClientStatusBar
|
||||
@onSliceClick={{action this.onSliceClick}}
|
||||
@job={{this.job}}
|
||||
@jobClientStatus={{this.jobClientStatus}}
|
||||
class="split-view" as |chart|
|
||||
>
|
||||
<ol data-test-legend class="legend">
|
||||
{{#each chart.data as |datum index|}}
|
||||
<li
|
||||
data-test-legent-label="{{datum.className}}"
|
||||
class="{{datum.className}}
|
||||
|
||||
{{if (eq datum.label chart.activeDatum.label) "is-active"}}
|
||||
|
||||
{{if (eq datum.value 0) "is-empty" "is-clickable"}}"
|
||||
>
|
||||
{{#if (gt datum.value 0)}}
|
||||
<LinkTo
|
||||
@route="jobs.job.clients"
|
||||
@model={{this.job}}
|
||||
@query={{datum.legendLink.queryParams}}
|
||||
>
|
||||
<JobPage::Parts::SummaryLegendItem
|
||||
@datum={{datum}}
|
||||
@index={{index}}
|
||||
/>
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
<JobPage::Parts::SummaryLegendItem
|
||||
@datum={{datum}}
|
||||
@index={{index}}
|
||||
/>
|
||||
{{/if}}
|
||||
</li>
|
||||
{{/each}}
|
||||
</ol>
|
||||
</JobClientStatusBar>
|
||||
</a.body>
|
||||
{{else}}
|
||||
<a.head @buttonLabel={{if a.isOpen "collapse" "expand"}}>
|
||||
<div class="columns">
|
||||
<div class="column is-minimum nowrap">
|
||||
Job Status in Client
|
||||
<span
|
||||
class="tooltip multiline"
|
||||
aria-label="Aggreate status of job's allocations in each client."
|
||||
>
|
||||
{{x-icon "info-circle-outline" class="is-faded"}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</a.head>
|
||||
<a.body>
|
||||
<div class="empty-message">
|
||||
<h3 data-test-nodes-not-authorized class="empty-message-headline">
|
||||
Not Authorized
|
||||
</h3>
|
||||
<p class="empty-message-body">
|
||||
Your
|
||||
<LinkTo @route="settings.tokens">
|
||||
ACL token
|
||||
</LinkTo>
|
||||
does not provide
|
||||
<code>
|
||||
node:read
|
||||
</code>
|
||||
permission.
|
||||
</p>
|
||||
</div>
|
||||
</a.body>
|
||||
{{/if}}
|
||||
</ListAccordion>
|
||||
{{/if}}
|
||||
@@ -22,8 +22,7 @@
|
||||
</span>
|
||||
</:before-namespace>
|
||||
</jobPage.ui.StatsBox>
|
||||
<jobPage.ui.JobClientStatusSummary />
|
||||
<jobPage.ui.Summary @forceCollapsed={{@job.hasClientStatus}} />
|
||||
<jobPage.ui.StatusPanel @statusMode={{@statusMode}} @setStatusMode={{@setStatusMode}} />
|
||||
<jobPage.ui.PlacementFailures />
|
||||
<jobPage.ui.TaskGroups @sortProperty={{@sortProperty}} @sortDescending={{@sortDescending}} />
|
||||
<jobPage.ui.RecentAllocations @activeTask={{@activeTask}} @setActiveTaskQueryParam={{@setActiveTaskQueryParam}} />
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
<jobPage.ui.Error />
|
||||
<jobPage.ui.Title />
|
||||
<jobPage.ui.StatsBox />
|
||||
<jobPage.ui.JobClientStatusSummary />
|
||||
<jobPage.ui.Summary @forceCollapsed="true" />
|
||||
<jobPage.ui.StatusPanel @statusMode={{@statusMode}} @setStatusMode={{@setStatusMode}} />
|
||||
<jobPage.ui.PlacementFailures />
|
||||
<jobPage.ui.TaskGroups @sortProperty={{@sortProperty}} @sortDescending={{@sortDescending}} />
|
||||
<jobPage.ui.RecentAllocations @activeTask={{@activeTask}} @setActiveTaskQueryParam={{@setActiveTaskQueryParam}} />
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
export const jobAllocStatuses = {
|
||||
service: ['running', 'pending', 'failed', 'lost', 'unplaced'],
|
||||
system: ['running', 'pending', 'failed', 'lost', 'unplaced'],
|
||||
batch: ['running', 'pending', 'failed', 'lost', 'complete', 'unplaced'],
|
||||
batch: ['running', 'pending', 'complete', 'failed', 'lost', 'unplaced'],
|
||||
sysbatch: ['running', 'pending', 'complete', 'failed', 'lost', 'unplaced'],
|
||||
};
|
||||
|
||||
export const jobTypes = ['service', 'system', 'batch'];
|
||||
export const jobTypes = ['service', 'system', 'batch', 'sysbatch'];
|
||||
|
||||
@@ -345,6 +345,7 @@ export default Factory.extend({
|
||||
datacenters: job.datacenters,
|
||||
createAllocations: job.createAllocations,
|
||||
shallow: job.shallow,
|
||||
noActiveDeployment: job.noActiveDeployment,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,11 @@ moduleForJob('Acceptance | job detail (system)', 'allocations', () =>
|
||||
);
|
||||
|
||||
moduleForJob('Acceptance | job detail (sysbatch)', 'allocations', () =>
|
||||
server.create('job', { type: 'sysbatch', shallow: true })
|
||||
server.create('job', {
|
||||
type: 'sysbatch',
|
||||
shallow: true,
|
||||
noActiveDeployment: true,
|
||||
})
|
||||
);
|
||||
|
||||
moduleForJobWithClientStatus(
|
||||
@@ -44,6 +48,7 @@ moduleForJobWithClientStatus(
|
||||
datacenters: ['dc1'],
|
||||
type: 'sysbatch',
|
||||
createAllocations: false,
|
||||
noActiveDeployment: true,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -57,6 +62,7 @@ moduleForJobWithClientStatus(
|
||||
type: 'sysbatch',
|
||||
namespaceId: namespace.name,
|
||||
createAllocations: false,
|
||||
noActiveDeployment: true,
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -71,6 +77,7 @@ moduleForJobWithClientStatus(
|
||||
type: 'sysbatch',
|
||||
namespaceId: namespace.name,
|
||||
createAllocations: false,
|
||||
noActiveDeployment: true,
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -80,6 +87,7 @@ moduleForJob('Acceptance | job detail (sysbatch child)', 'allocations', () => {
|
||||
childrenCount: 1,
|
||||
shallow: true,
|
||||
datacenters: ['dc1'],
|
||||
noActiveDeployment: true,
|
||||
});
|
||||
return server.db.jobs.where({ parentId: parent.id })[0];
|
||||
});
|
||||
@@ -91,6 +99,7 @@ moduleForJobWithClientStatus(
|
||||
childrenCount: 1,
|
||||
shallow: true,
|
||||
datacenters: ['dc1'],
|
||||
noActiveDeployment: true,
|
||||
});
|
||||
return server.db.jobs.where({ parentId: parent.id })[0];
|
||||
}
|
||||
@@ -105,6 +114,7 @@ moduleForJobWithClientStatus(
|
||||
shallow: true,
|
||||
namespaceId: namespace.name,
|
||||
datacenters: ['dc1'],
|
||||
noActiveDeployment: true,
|
||||
});
|
||||
return server.db.jobs.where({ parentId: parent.id })[0];
|
||||
}
|
||||
@@ -119,6 +129,7 @@ moduleForJobWithClientStatus(
|
||||
shallow: true,
|
||||
namespaceId: namespace.name,
|
||||
datacenters: ['*'],
|
||||
noActiveDeployment: true,
|
||||
});
|
||||
return server.db.jobs.where({ parentId: parent.id })[0];
|
||||
}
|
||||
@@ -168,7 +179,11 @@ moduleForJob(
|
||||
moduleForJob(
|
||||
'Acceptance | job detail (parameterized)',
|
||||
'children',
|
||||
() => server.create('job', 'parameterized', { shallow: true }),
|
||||
() =>
|
||||
server.create('job', 'parameterized', {
|
||||
shallow: true,
|
||||
noActiveDeployment: true,
|
||||
}),
|
||||
{
|
||||
'the default sort is submitTime descending': async (job, assert) => {
|
||||
const mostRecentLaunch = server.db.jobs
|
||||
@@ -221,6 +236,7 @@ moduleForJob(
|
||||
const parent = server.create('job', 'parameterized', {
|
||||
childrenCount: 1,
|
||||
shallow: true,
|
||||
noActiveDeployment: true,
|
||||
});
|
||||
return server.db.jobs.where({ parentId: parent.id })[0];
|
||||
}
|
||||
|
||||
@@ -254,6 +254,93 @@ module('Acceptance | job status panel', function (hooks) {
|
||||
});
|
||||
});
|
||||
|
||||
test('After running/pending allocations are covered, fill in allocs by jobVersion, descending (batch)', async function (assert) {
|
||||
assert.expect(7);
|
||||
let job = server.create('job', {
|
||||
status: 'running',
|
||||
datacenters: ['*'],
|
||||
type: 'batch',
|
||||
resourceSpec: ['M: 256, C: 500'], // a single group
|
||||
createAllocations: false,
|
||||
allocStatusDistribution: {
|
||||
running: 0.5,
|
||||
failed: 0.3,
|
||||
unknown: 0,
|
||||
lost: 0,
|
||||
complete: 0.2,
|
||||
},
|
||||
groupTaskCount: 5,
|
||||
shallow: true,
|
||||
version: 5,
|
||||
noActiveDeployment: true,
|
||||
});
|
||||
|
||||
server.create('allocation', {
|
||||
jobId: job.id,
|
||||
clientStatus: 'running',
|
||||
jobVersion: 5,
|
||||
});
|
||||
server.create('allocation', {
|
||||
jobId: job.id,
|
||||
clientStatus: 'pending',
|
||||
jobVersion: 5,
|
||||
});
|
||||
server.create('allocation', {
|
||||
jobId: job.id,
|
||||
clientStatus: 'running',
|
||||
jobVersion: 3,
|
||||
});
|
||||
server.create('allocation', {
|
||||
jobId: job.id,
|
||||
clientStatus: 'failed',
|
||||
jobVersion: 4,
|
||||
});
|
||||
server.create('allocation', {
|
||||
jobId: job.id,
|
||||
clientStatus: 'complete',
|
||||
jobVersion: 4,
|
||||
});
|
||||
server.create('allocation', {
|
||||
jobId: job.id,
|
||||
clientStatus: 'lost',
|
||||
jobVersion: 5,
|
||||
});
|
||||
|
||||
await visit(`/jobs/${job.id}`);
|
||||
assert.dom('.job-status-panel').exists();
|
||||
// We expect to see 5 represented-allocations, since that's the number in our groupTaskCount
|
||||
assert
|
||||
.dom('.ungrouped-allocs .represented-allocation')
|
||||
.exists({ count: 5 });
|
||||
|
||||
// We expect 2 of them to be running, and one to be pending, since running/pending allocations superecede other clientStatuses
|
||||
assert
|
||||
.dom('.ungrouped-allocs .represented-allocation.running')
|
||||
.exists({ count: 2 });
|
||||
assert
|
||||
.dom('.ungrouped-allocs .represented-allocation.pending')
|
||||
.exists({ count: 1 });
|
||||
|
||||
// We expect 1 to be lost, since it has the highest jobVersion
|
||||
assert
|
||||
.dom('.ungrouped-allocs .represented-allocation.lost')
|
||||
.exists({ count: 1 });
|
||||
|
||||
// We expect the remaining one to be complete, rather than failed, since it comes earlier in the jobAllocStatuses.batch constant
|
||||
assert
|
||||
.dom('.ungrouped-allocs .represented-allocation.complete')
|
||||
.exists({ count: 1 });
|
||||
assert
|
||||
.dom('.ungrouped-allocs .represented-allocation.failed')
|
||||
.doesNotExist();
|
||||
|
||||
await percySnapshot(assert, {
|
||||
percyCSS: `
|
||||
.allocation-row td { display: none; }
|
||||
`,
|
||||
});
|
||||
});
|
||||
|
||||
test('Status Panel groups allocations when they get past a threshold', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
|
||||
@@ -5,21 +5,14 @@
|
||||
|
||||
/* eslint-disable qunit/require-expect */
|
||||
/* eslint-disable qunit/no-conditional-assertions */
|
||||
import {
|
||||
click,
|
||||
currentRouteName,
|
||||
currentURL,
|
||||
visit,
|
||||
find,
|
||||
} from '@ember/test-helpers';
|
||||
import { currentRouteName, currentURL, visit, find } from '@ember/test-helpers';
|
||||
import { module, test } from 'qunit';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import JobDetail from 'nomad-ui/tests/pages/jobs/detail';
|
||||
import setPolicy from 'nomad-ui/tests/utils/set-policy';
|
||||
|
||||
const jobTypesWithStatusPanel = ['service', 'system', 'batch'];
|
||||
|
||||
const jobTypesWithStatusPanel = ['service', 'system', 'batch', 'sysbatch'];
|
||||
async function switchToHistorical() {
|
||||
await JobDetail.statusModes.historical.click();
|
||||
}
|
||||
@@ -55,11 +48,6 @@ export default function moduleForJob(
|
||||
} else {
|
||||
await JobDetail.visit({ id: `${job.id}@${job.namespace}` });
|
||||
}
|
||||
|
||||
const hasClientStatus = ['sysbatch'].includes(job.type);
|
||||
if (context === 'allocations' && hasClientStatus) {
|
||||
await click("[data-test-accordion-summary-chart='allocation-status']");
|
||||
}
|
||||
});
|
||||
|
||||
test('visiting /jobs/:job_id', async function (assert) {
|
||||
@@ -117,7 +105,7 @@ export default function moduleForJob(
|
||||
|
||||
if (context === 'allocations') {
|
||||
test('allocations for the job are shown in the overview', async function (assert) {
|
||||
if (!job.parentId && jobTypesWithStatusPanel.includes(job.type)) {
|
||||
if (jobTypesWithStatusPanel.includes(job.type)) {
|
||||
await switchToHistorical(job);
|
||||
}
|
||||
assert.ok(
|
||||
@@ -157,7 +145,7 @@ export default function moduleForJob(
|
||||
});
|
||||
|
||||
test('clicking legend item navigates to a pre-filtered allocations table', async function (assert) {
|
||||
if (!job.parentId && jobTypesWithStatusPanel.includes(job.type)) {
|
||||
if (jobTypesWithStatusPanel.includes(job.type)) {
|
||||
await switchToHistorical(job);
|
||||
}
|
||||
const legendItem = find('.legend li.is-clickable');
|
||||
@@ -178,7 +166,7 @@ export default function moduleForJob(
|
||||
});
|
||||
|
||||
test('clicking in a slice takes you to a pre-filtered allocations table', async function (assert) {
|
||||
if (!job.parentId && jobTypesWithStatusPanel.includes(job.type)) {
|
||||
if (jobTypesWithStatusPanel.includes(job.type)) {
|
||||
await switchToHistorical(job);
|
||||
}
|
||||
const slice = JobDetail.allocationsSummary.slices[0];
|
||||
@@ -301,46 +289,6 @@ export function moduleForJobWithClientStatus(
|
||||
assert.equal(currentURL(), expectedURL);
|
||||
});
|
||||
|
||||
test('job status summary is shown in the overview', async function (assert) {
|
||||
assert.ok(
|
||||
JobDetail.jobClientStatusSummary.statusBar.isPresent,
|
||||
'Summary bar is displayed in the Job Status in Client summary section'
|
||||
);
|
||||
});
|
||||
|
||||
test('clicking legend item navigates to a pre-filtered clients table', async function (assert) {
|
||||
const legendItem =
|
||||
JobDetail.jobClientStatusSummary.statusBar.legend.clickableItems[0];
|
||||
const status = legendItem.label;
|
||||
await legendItem.click();
|
||||
|
||||
const encodedStatus = encodeURIComponent(JSON.stringify([status]));
|
||||
const expectedURL = new URL(
|
||||
urlWithNamespace(
|
||||
`/jobs/${job.name}/clients?status=${encodedStatus}`,
|
||||
job.namespace
|
||||
),
|
||||
window.location
|
||||
);
|
||||
const gotURL = new URL(currentURL(), window.location);
|
||||
assert.deepEqual(gotURL.path, expectedURL.path);
|
||||
assert.deepEqual(gotURL.searchParams, expectedURL.searchParams);
|
||||
});
|
||||
|
||||
test('clicking in a slice takes you to a pre-filtered clients table', async function (assert) {
|
||||
const slice = JobDetail.jobClientStatusSummary.statusBar.slices[0];
|
||||
const status = slice.label;
|
||||
await slice.click();
|
||||
|
||||
const encodedStatus = encodeURIComponent(JSON.stringify([status]));
|
||||
|
||||
const expectedURL = job.namespace
|
||||
? `/jobs/${job.name}@${job.namespace}/clients?status=${encodedStatus}`
|
||||
: `/jobs/${job.name}/clients?status=${encodedStatus}`;
|
||||
|
||||
assert.deepEqual(currentURL(), expectedURL, 'url is correct');
|
||||
});
|
||||
|
||||
for (var testName in additionalTests) {
|
||||
test(testName, async function (assert) {
|
||||
await additionalTests[testName].call(this, job, assert);
|
||||
@@ -366,10 +314,6 @@ export function moduleForJobWithClientStatus(
|
||||
.doesNotExist(
|
||||
'Job Detail Sub Navigation should not render Clients tab'
|
||||
);
|
||||
|
||||
assert
|
||||
.dom('[data-test-nodes-not-authorized]')
|
||||
.exists('Renders Not Authorized message');
|
||||
});
|
||||
|
||||
test('/jobs/job/clients route is protected with authorization logic', async function (assert) {
|
||||
|
||||
@@ -93,16 +93,6 @@ export default create({
|
||||
},
|
||||
},
|
||||
|
||||
jobClientStatusSummary: {
|
||||
scope: '[data-test-job-client-summary]',
|
||||
statusBar: jobClientStatusBar('[data-test-job-client-status-bar]'),
|
||||
toggle: {
|
||||
scope: '[data-test-accordion-head] [data-test-accordion-toggle]',
|
||||
click: clickable(),
|
||||
isDisabled: attribute('disabled'),
|
||||
tooltip: attribute('aria-label'),
|
||||
},
|
||||
},
|
||||
childrenSummary: jobClientStatusBar(
|
||||
'[data-test-children-status-bar]:not(.is-narrow)'
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user