diff --git a/.changelog/14612.txt b/.changelog/14612.txt
new file mode 100644
index 000000000000..282b62c3bfba
--- /dev/null
+++ b/.changelog/14612.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: adds a sidebar to show in-page logs for a given task, accessible via job, client, or task group routes
+```
diff --git a/ui/app/components/allocation-service-sidebar.js b/ui/app/components/allocation-service-sidebar.js
index bab46f0ed645..13ce37e2adbc 100644
--- a/ui/app/components/allocation-service-sidebar.js
+++ b/ui/app/components/allocation-service-sidebar.js
@@ -10,7 +10,7 @@ export default class AllocationServiceSidebarComponent extends Component {
}
keyCommands = [
{
- label: 'Close Evaluations Sidebar',
+ label: 'Close Service Sidebar',
pattern: ['Escape'],
action: () => this.args.fns.closeSidebar(),
},
diff --git a/ui/app/components/streaming-file.js b/ui/app/components/streaming-file.js
index 8239aedf8f5b..73fb390a4dd3 100644
--- a/ui/app/components/streaming-file.js
+++ b/ui/app/components/streaming-file.js
@@ -22,6 +22,7 @@ export default class StreamingFile extends Component.extend(WindowResizable) {
isStreaming = true;
logger = null;
follow = true;
+ shouldFillHeight = true;
// Internal bookkeeping to avoid multiple scroll events on one frame
requestFrame = true;
@@ -89,7 +90,9 @@ export default class StreamingFile extends Component.extend(WindowResizable) {
didInsertElement() {
super.didInsertElement(...arguments);
- this.fillAvailableHeight();
+ if (this.shouldFillHeight) {
+ this.fillAvailableHeight();
+ }
this.set('_scrollHandler', this.scrollHandler.bind(this));
this.element.addEventListener('scroll', this._scrollHandler);
@@ -105,7 +108,9 @@ export default class StreamingFile extends Component.extend(WindowResizable) {
}
windowResizeHandler() {
- once(this, this.fillAvailableHeight);
+ if (this.shouldFillHeight) {
+ once(this, this.fillAvailableHeight);
+ }
}
fillAvailableHeight() {
diff --git a/ui/app/components/task-context-sidebar.hbs b/ui/app/components/task-context-sidebar.hbs
new file mode 100644
index 000000000000..523e3c118c63
--- /dev/null
+++ b/ui/app/components/task-context-sidebar.hbs
@@ -0,0 +1,44 @@
+
+
+
\ No newline at end of file
diff --git a/ui/app/components/task-context-sidebar.js b/ui/app/components/task-context-sidebar.js
new file mode 100644
index 000000000000..31ce73aa3215
--- /dev/null
+++ b/ui/app/components/task-context-sidebar.js
@@ -0,0 +1,16 @@
+// @ts-check
+import Component from '@glimmer/component';
+
+export default class TaskContextSidebarComponent extends Component {
+ get isSideBarOpen() {
+ return !!this.args.task;
+ }
+
+ keyCommands = [
+ {
+ label: 'Close Task Logs Sidebar',
+ pattern: ['Escape'],
+ action: () => this.args.fns.closeSidebar(),
+ },
+ ];
+}
diff --git a/ui/app/components/task-log.js b/ui/app/components/task-log.js
index 2ed7325d0371..cf27d928f59e 100644
--- a/ui/app/components/task-log.js
+++ b/ui/app/components/task-log.js
@@ -35,6 +35,8 @@ export default class TaskLog extends Component {
isStreaming = true;
streamMode = 'streaming';
+ shouldFillHeight = true;
+
@alias('userSettings.logMode') mode;
@computed('allocation.{id,node.httpAddr}', 'useServer')
diff --git a/ui/app/components/task-sub-row.hbs b/ui/app/components/task-sub-row.hbs
index 203fd6555e57..09e65a872438 100644
--- a/ui/app/components/task-sub-row.hbs
+++ b/ui/app/components/task-sub-row.hbs
@@ -1,16 +1,16 @@
-
- /
-
- {{this.task.name}}
-
- {{!-- TODO: in-page logs --}}
- {{!-- --}}
+
+ {{this.task.name}}
+
+
|
{{#if this.task.isRunning}}
@@ -76,4 +76,13 @@
|
-{{yield}}
\ No newline at end of file
+{{yield}}
+
+{{#if this.shouldShowLogs}}
+
+{{/if}}
diff --git a/ui/app/components/task-sub-row.js b/ui/app/components/task-sub-row.js
index 1499c2edf126..5eec51214199 100644
--- a/ui/app/components/task-sub-row.js
+++ b/ui/app/components/task-sub-row.js
@@ -71,4 +71,22 @@ export default class TaskSubRowComponent extends Component {
} while (this.enablePolling);
}).drop())
fetchStats;
+
+ //#region Logs Sidebar
+
+ @alias('args.active') shouldShowLogs;
+
+ @action handleTaskLogsClick(task) {
+ if (this.args.onSetActiveTask) {
+ this.args.onSetActiveTask(task);
+ }
+ }
+
+ @action closeSidebar() {
+ if (this.args.onSetActiveTask) {
+ this.args.onSetActiveTask(null);
+ }
+ }
+
+ //#endregion Logs Sidebar
}
diff --git a/ui/app/controllers/clients/client/index.js b/ui/app/controllers/clients/client/index.js
index 1775a07270db..dc29fc70915b 100644
--- a/ui/app/controllers/clients/client/index.js
+++ b/ui/app/controllers/clients/client/index.js
@@ -47,6 +47,7 @@ export default class ClientController extends Controller.extend(
{
qpStatus: 'status',
},
+ 'activeTask',
];
// Set in the route
@@ -57,6 +58,7 @@ export default class ClientController extends Controller.extend(
qpStatus = '';
currentPage = 1;
pageSize = 8;
+ activeTask = null;
sortProperty = 'modifyIndex';
sortDescending = true;
@@ -266,4 +268,13 @@ export default class ClientController extends Controller.extend(
setFacetQueryParam(queryParam, selection) {
this.set(queryParam, serialize(selection));
}
+
+ @action
+ setActiveTaskQueryParam(task) {
+ if (task) {
+ this.set('activeTask', `${task.allocation.id}-${task.name}`);
+ } else {
+ this.set('activeTask', null);
+ }
+ }
}
diff --git a/ui/app/controllers/jobs/job/allocations.js b/ui/app/controllers/jobs/job/allocations.js
index 33ee81bdb081..68c84487a5c2 100644
--- a/ui/app/controllers/jobs/job/allocations.js
+++ b/ui/app/controllers/jobs/job/allocations.js
@@ -41,6 +41,7 @@ export default class AllocationsController extends Controller.extend(
{
qpTaskGroup: 'taskGroup',
},
+ 'activeTask',
];
qpStatus = '';
@@ -48,6 +49,7 @@ export default class AllocationsController extends Controller.extend(
qpTaskGroup = '';
currentPage = 1;
pageSize = 25;
+ activeTask = null;
sortProperty = 'modifyIndex';
sortDescending = true;
@@ -159,4 +161,13 @@ export default class AllocationsController extends Controller.extend(
setFacetQueryParam(queryParam, selection) {
this.set(queryParam, serialize(selection));
}
+
+ @action
+ setActiveTaskQueryParam(task) {
+ if (task) {
+ this.set('activeTask', `${task.allocation.id}-${task.name}`);
+ } else {
+ this.set('activeTask', null);
+ }
+ }
}
diff --git a/ui/app/controllers/jobs/job/index.js b/ui/app/controllers/jobs/job/index.js
index f066ac554b26..ed5fc0caeb87 100644
--- a/ui/app/controllers/jobs/job/index.js
+++ b/ui/app/controllers/jobs/job/index.js
@@ -3,7 +3,7 @@ import { alias } from '@ember/object/computed';
import { inject as service } from '@ember/service';
import WithNamespaceResetting from 'nomad-ui/mixins/with-namespace-resetting';
import classic from 'ember-classic-decorator';
-
+import { action } from '@ember/object';
@classic
export default class IndexController extends Controller.extend(
WithNamespaceResetting
@@ -20,6 +20,7 @@ export default class IndexController extends Controller.extend(
{
sortDescending: 'desc',
},
+ 'activeTask',
];
currentPage = 1;
@@ -28,4 +29,14 @@ export default class IndexController extends Controller.extend(
sortProperty = 'name';
sortDescending = false;
+ activeTask = null;
+
+ @action
+ setActiveTaskQueryParam(task) {
+ if (task) {
+ this.set('activeTask', `${task.allocation.id}-${task.name}`);
+ } else {
+ this.set('activeTask', null);
+ }
+ }
}
diff --git a/ui/app/controllers/jobs/job/task-group.js b/ui/app/controllers/jobs/job/task-group.js
index 763fa5b3d8d9..004970a1cbb8 100644
--- a/ui/app/controllers/jobs/job/task-group.js
+++ b/ui/app/controllers/jobs/job/task-group.js
@@ -43,6 +43,7 @@ export default class TaskGroupController extends Controller.extend(
{
qpClient: 'client',
},
+ 'activeTask',
];
currentPage = 1;
@@ -52,6 +53,7 @@ export default class TaskGroupController extends Controller.extend(
qpClient = '';
sortProperty = 'modifyIndex';
sortDescending = true;
+ activeTask = null;
@computed
get searchProps() {
@@ -186,4 +188,13 @@ export default class TaskGroupController extends Controller.extend(
args: ['jobs.job.task-group', job, name],
};
}
+
+ @action
+ setActiveTaskQueryParam(task) {
+ if (task) {
+ this.set('activeTask', `${task.allocation.id}-${task.name}`);
+ } else {
+ this.set('activeTask', null);
+ }
+ }
}
diff --git a/ui/app/styles/components/boxed-section.scss b/ui/app/styles/components/boxed-section.scss
index 901dc75036cf..4ac5b726a1f9 100644
--- a/ui/app/styles/components/boxed-section.scss
+++ b/ui/app/styles/components/boxed-section.scss
@@ -26,6 +26,9 @@
.is-padded {
padding: 0em 0em 0em 1em;
}
+ .is-one-line {
+ white-space: nowrap;
+ }
}
.is-fixed-width {
diff --git a/ui/app/styles/components/sidebar.scss b/ui/app/styles/components/sidebar.scss
index 357a42fd21a1..21c08bf1e1ff 100644
--- a/ui/app/styles/components/sidebar.scss
+++ b/ui/app/styles/components/sidebar.scss
@@ -56,3 +56,78 @@ $subNavOffset: 49px;
padding: 10px;
width: 100px;
}
+
+.task-context-sidebar {
+ animation-name: slideFromRight;
+ animation-duration: 150ms;
+ animation-fill-mode: both;
+
+ header {
+ display: grid;
+ justify-content: left;
+ grid-template-columns: 1fr auto auto;
+ gap: 2rem;
+ border-bottom: 1px solid $grey-blue;
+ padding-bottom: 1rem;
+ margin-bottom: 24px;
+ height: 50px;
+
+ .title {
+ margin-bottom: unset;
+ }
+
+ .link {
+ align-self: center;
+ }
+
+ .state {
+ font-size: 1rem;
+ font-weight: normal;
+ margin-left: 1rem;
+ text-transform: capitalize;
+
+ &:before {
+ content: '';
+ display: inline-block;
+ height: 1rem;
+ width: 1rem;
+ margin-right: 5px;
+ border-radius: 4px;
+ position: relative;
+ top: 2px;
+ }
+
+ &.running:before {
+ background-color: $green;
+ }
+ &.dead:before {
+ background-color: $red;
+ }
+ &.pending:before {
+ background-color: $grey-lighter;
+ }
+ }
+ }
+
+ // Instead of trying to calculate on the fly with JS, let's use vh and offset nav and headers above.
+ // We can make this a LOT more streamlined when CSS Container Queries are available.
+ $sidebarTopOffset: 161px;
+ $sidebarInnerPadding: 48px;
+ $sidebarHeaderOffset: 74px;
+ $cliHeaderOffset: 54.5px;
+ .cli-window {
+ height: calc(
+ 100vh - $sidebarTopOffset - $sidebarInnerPadding - $sidebarHeaderOffset -
+ $cliHeaderOffset
+ );
+ }
+}
+
+@keyframes slideFromRight {
+ from {
+ transform: translateX(100%);
+ }
+ to {
+ transform: translateX(0%);
+ }
+}
diff --git a/ui/app/styles/components/task-sub-row.scss b/ui/app/styles/components/task-sub-row.scss
index e8334b03d579..5d7796858b35 100644
--- a/ui/app/styles/components/task-sub-row.scss
+++ b/ui/app/styles/components/task-sub-row.scss
@@ -1,16 +1,39 @@
table tbody .task-sub-row {
td {
border-top: 2px solid white;
- }
- td:nth-child(1) {
- padding-left: 4rem;
- a {
- margin-right: 1rem;
- }
- svg.flight-icon {
- position: relative;
- top: 3px;
+ .name-grid {
+ display: inline-grid;
+ grid-template-columns: auto 1fr;
+ margin-left: 4rem;
+ gap: 1rem;
+
+ .task-name {
+ display: block;
+ width: 150px;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ &:before {
+ color: black;
+ content: '/';
+ display: inline-block;
+ margin-right: 0.5rem;
+ text-decoration: none;
+ }
+ }
+
+ .logs-sidebar-trigger {
+ color: $blue;
+ text-decoration: underline;
+ font-weight: normal;
+ svg {
+ color: black;
+ margin-right: 5px;
+ position: relative;
+ top: 3px;
+ }
+ }
}
}
}
diff --git a/ui/app/styles/components/toggle.scss b/ui/app/styles/components/toggle.scss
index efa07688e150..612041b94019 100644
--- a/ui/app/styles/components/toggle.scss
+++ b/ui/app/styles/components/toggle.scss
@@ -31,7 +31,9 @@ $size: 12px;
.toggler {
display: inline-block;
position: relative;
- vertical-align: middle;
+ vertical-align: baseline;
+ position: relative;
+ top: 1px;
width: $size * 2;
height: $size;
border-radius: $size;
diff --git a/ui/app/templates/application.hbs b/ui/app/templates/application.hbs
index 3492b2a9e8c9..8a16c4f2db97 100644
--- a/ui/app/templates/application.hbs
+++ b/ui/app/templates/application.hbs
@@ -26,6 +26,8 @@
+
+
{{#if this.error}}
diff --git a/ui/app/templates/clients/client/index.hbs b/ui/app/templates/clients/client/index.hbs
index 22056e0b2818..61e277018859 100644
--- a/ui/app/templates/clients/client/index.hbs
+++ b/ui/app/templates/clients/client/index.hbs
@@ -497,9 +497,8 @@
@class="is-padded"
/>
-
+
{{#if this.showSubTasks}}
{{#each row.model.states as |task|}}
-
+
{{/each}}
{{/if}}
diff --git a/ui/app/templates/components/job-page.hbs b/ui/app/templates/components/job-page.hbs
index 564524cd74ca..2b094a903380 100644
--- a/ui/app/templates/components/job-page.hbs
+++ b/ui/app/templates/components/job-page.hbs
@@ -19,7 +19,7 @@
"job-page/parts/latest-deployment" job=@job handleError=this.handleError
)
TaskGroups=(component "job-page/parts/task-groups" job=@job)
- RecentAllocations=(component "job-page/parts/recent-allocations" job=@job)
+ RecentAllocations=(component "job-page/parts/recent-allocations" job=@job activeTask=@activeTask setActiveTaskQueryParam=@setActiveTaskQueryParam)
Meta=(component "job-page/parts/meta" job=@job)
DasRecommendations=(component
"job-page/parts/das-recommendations" job=@job
diff --git a/ui/app/templates/components/job-page/batch.hbs b/ui/app/templates/components/job-page/batch.hbs
index 12712b17bc87..1ed2b2af243d 100644
--- a/ui/app/templates/components/job-page/batch.hbs
+++ b/ui/app/templates/components/job-page/batch.hbs
@@ -6,7 +6,7 @@
-
+
\ No newline at end of file
diff --git a/ui/app/templates/components/job-page/parameterized-child.hbs b/ui/app/templates/components/job-page/parameterized-child.hbs
index 49a65c67e6cd..9c80a7617b1f 100644
--- a/ui/app/templates/components/job-page/parameterized-child.hbs
+++ b/ui/app/templates/components/job-page/parameterized-child.hbs
@@ -21,7 +21,7 @@
-
+
{{#if @job.meta}}
diff --git a/ui/app/templates/components/job-page/parts/recent-allocations.hbs b/ui/app/templates/components/job-page/parts/recent-allocations.hbs
index e91aca79f263..31e91729d924 100644
--- a/ui/app/templates/components/job-page/parts/recent-allocations.hbs
+++ b/ui/app/templates/components/job-page/parts/recent-allocations.hbs
@@ -3,7 +3,6 @@
Recent Allocations
+
{{/each}}
{{/if}}
diff --git a/ui/app/templates/components/job-page/periodic-child.hbs b/ui/app/templates/components/job-page/periodic-child.hbs
index 3164926803dc..69eef3292d7c 100644
--- a/ui/app/templates/components/job-page/periodic-child.hbs
+++ b/ui/app/templates/components/job-page/periodic-child.hbs
@@ -21,7 +21,7 @@
-
+
\ No newline at end of file
diff --git a/ui/app/templates/components/job-page/service.hbs b/ui/app/templates/components/job-page/service.hbs
index 233e85d3f308..2927e64233eb 100644
--- a/ui/app/templates/components/job-page/service.hbs
+++ b/ui/app/templates/components/job-page/service.hbs
@@ -8,7 +8,7 @@
-
+
\ No newline at end of file
diff --git a/ui/app/templates/components/job-page/sysbatch.hbs b/ui/app/templates/components/job-page/sysbatch.hbs
index 2b9c7e0c0f8d..01f63b41ce56 100644
--- a/ui/app/templates/components/job-page/sysbatch.hbs
+++ b/ui/app/templates/components/job-page/sysbatch.hbs
@@ -7,7 +7,7 @@
-
+
\ No newline at end of file
diff --git a/ui/app/templates/components/job-page/system.hbs b/ui/app/templates/components/job-page/system.hbs
index 693e74bccbdc..1728d6eedb39 100644
--- a/ui/app/templates/components/job-page/system.hbs
+++ b/ui/app/templates/components/job-page/system.hbs
@@ -8,7 +8,7 @@
-
+
\ No newline at end of file
diff --git a/ui/app/templates/components/task-log.hbs b/ui/app/templates/components/task-log.hbs
index b1209a021299..7bb124e29fee 100644
--- a/ui/app/templates/components/task-log.hbs
+++ b/ui/app/templates/components/task-log.hbs
@@ -25,5 +25,5 @@
-
+
diff --git a/ui/app/templates/jobs/job/allocations.hbs b/ui/app/templates/jobs/job/allocations.hbs
index d655a9e8f932..a7f520adba7c 100644
--- a/ui/app/templates/jobs/job/allocations.hbs
+++ b/ui/app/templates/jobs/job/allocations.hbs
@@ -71,7 +71,7 @@
@context="job"
@onClick={{action "gotoAllocation" row.model}} />
{{#each row.model.states as |task|}}
-
+
{{/each}}
diff --git a/ui/app/templates/jobs/job/index.hbs b/ui/app/templates/jobs/job/index.hbs
index 0ff6bd3acbb1..a1426d21f4ce 100644
--- a/ui/app/templates/jobs/job/index.hbs
+++ b/ui/app/templates/jobs/job/index.hbs
@@ -5,4 +5,6 @@
sortProperty=this.sortProperty
sortDescending=this.sortDescending
currentPage=this.currentPage
+ activeTask=this.activeTask
+ setActiveTaskQueryParam=this.setActiveTaskQueryParam
}}
\ No newline at end of file
diff --git a/ui/app/templates/jobs/job/task-group.hbs b/ui/app/templates/jobs/job/task-group.hbs
index ef5fedd12d81..57091b930579 100644
--- a/ui/app/templates/jobs/job/task-group.hbs
+++ b/ui/app/templates/jobs/job/task-group.hbs
@@ -149,9 +149,8 @@
@class="is-padded"
@inputClass="is-compact"
/>
-
+
{{#if this.showSubTasks}}
{{#each row.model.states as |task|}}
-
+
{{/each}}
{{/if}}
diff --git a/ui/tests/acceptance/task-logs-test.js b/ui/tests/acceptance/task-logs-test.js
index 90ca1e9b3dc5..54b8a4e381c4 100644
--- a/ui/tests/acceptance/task-logs-test.js
+++ b/ui/tests/acceptance/task-logs-test.js
@@ -1,23 +1,27 @@
/* eslint-disable qunit/require-expect */
-import { currentURL } from '@ember/test-helpers';
+import { click, currentURL } from '@ember/test-helpers';
import { run } from '@ember/runloop';
import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { setupMirage } from 'ember-cli-mirage/test-support';
import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit';
import TaskLogs from 'nomad-ui/tests/pages/allocations/task/logs';
+import percySnapshot from '@percy/ember';
+import faker from 'nomad-ui/mirage/faker';
let allocation;
let task;
+let job;
module('Acceptance | task logs', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
hooks.beforeEach(async function () {
+ faker.seed(1);
server.create('agent');
server.create('node', 'forceIPv4');
- const job = server.create('job', { createAllocations: false });
+ job = server.create('job', { createAllocations: false });
allocation = server.create('allocation', {
jobId: job.id,
@@ -26,14 +30,15 @@ module('Acceptance | task logs', function (hooks) {
task = server.db.taskStates.where({ allocationId: allocation.id })[0];
run.later(run, run.cancelTimers, 1000);
- await TaskLogs.visit({ id: allocation.id, name: task.name });
});
test('it passes an accessibility audit', async function (assert) {
+ await TaskLogs.visit({ id: allocation.id, name: task.name });
await a11yAudit(assert);
});
test('/allocation/:id/:task_name/logs should have a log component', async function (assert) {
+ await TaskLogs.visit({ id: allocation.id, name: task.name });
assert.equal(
currentURL(),
`/allocations/${allocation.id}/${task.name}/logs`,
@@ -44,6 +49,7 @@ module('Acceptance | task logs', function (hooks) {
});
test('the stdout log immediately starts streaming', async function (assert) {
+ await TaskLogs.visit({ id: allocation.id, name: task.name });
const node = server.db.nodes.find(allocation.nodeId);
const logUrlRegex = new RegExp(
`${node.httpAddr}/v1/client/fs/logs/${allocation.id}`
@@ -55,4 +61,31 @@ module('Acceptance | task logs', function (hooks) {
'Log requests were made'
);
});
+
+ test('logs are accessible in a sidebar context', async function (assert) {
+ await TaskLogs.visitParentJob({
+ id: job.id,
+ allocationId: allocation.id,
+ name: task.name,
+ });
+ assert.notOk(TaskLogs.sidebarIsPresent, 'Sidebar is not present');
+
+ run.later(() => {
+ run.cancelTimers();
+ }, 500);
+
+ await click('button.logs-sidebar-trigger');
+
+ assert.ok(TaskLogs.sidebarIsPresent, 'Sidebar is present');
+ assert
+ .dom('.task-context-sidebar h1.title')
+ .includesText(task.name, 'Sidebar title is correct');
+ assert
+ .dom('.task-context-sidebar h1.title')
+ .includesText(task.state, 'Task state is correctly displayed');
+ await percySnapshot(assert);
+
+ await click('.sidebar button.close');
+ assert.notOk(TaskLogs.sidebarIsPresent, 'Sidebar is not present');
+ });
});
diff --git a/ui/tests/integration/components/task-sub-row-test.js b/ui/tests/integration/components/task-sub-row-test.js
index 05b38eec3974..7eb7b2f62e4a 100644
--- a/ui/tests/integration/components/task-sub-row-test.js
+++ b/ui/tests/integration/components/task-sub-row-test.js
@@ -51,10 +51,28 @@ const mockTask = {
module('Integration | Component | task-sub-row', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
- assert.expect(2);
+ assert.expect(6);
this.set('task', mockTask);
await render(hbs``);
- assert.dom(this.element).hasText(`/ ${mockTask.name}`);
+ assert.ok(
+ this.element.textContent.includes(`${mockTask.name}`),
+ 'Task name is rendered'
+ );
+ assert.dom('.task-sub-row').doesNotHaveClass('is-active');
+
+ await render(hbs``);
+ assert.dom('.task-sub-row').hasClass('is-active');
+
+ await render(
+ hbs``
+ );
+ assert.dom('.task-sub-row td:nth-child(1)').hasAttribute('colspan', '5');
+
+ await render(
+ hbs``
+ );
+ assert.dom('.task-sub-row td:nth-child(1)').hasAttribute('colspan', '9');
+
await componentA11yAudit(this.element, assert);
});
});
diff --git a/ui/tests/pages/allocations/task/logs.js b/ui/tests/pages/allocations/task/logs.js
index 12a09145911a..f436aa624517 100644
--- a/ui/tests/pages/allocations/task/logs.js
+++ b/ui/tests/pages/allocations/task/logs.js
@@ -2,6 +2,8 @@ import { create, isPresent, visitable } from 'ember-cli-page-object';
export default create({
visit: visitable('/allocations/:id/:name/logs'),
+ visitParentJob: visitable('/jobs/:id/allocations'),
hasTaskLog: isPresent('[data-test-task-log]'),
+ sidebarIsPresent: isPresent('.sidebar.task-context-sidebar'),
});