[ui] Adds meta k/v tables to Task Group and Task pages (#24594)

* Experimenting with a generic meta job-part component

* Taskstate.task gets me every time

* continue-on-error false test

* continue-on-error back in, but explicit success check after exam

* Testfixes for new meta structure on tasks and groups

* Clean up test and dev code
This commit is contained in:
Phil Renaud
2024-12-17 10:46:03 -05:00
committed by GitHub
parent abeae5c47b
commit 932c3ebfb0
15 changed files with 88 additions and 28 deletions

3
.changelog/24594.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:improvement
ui: Adds metadata tables to Task Group and Task pages
```

View File

@@ -62,13 +62,13 @@ export default class TaskGroup extends Fragment {
@fragment('group-scaling') scaling;
@attr() meta;
@fragment('structured-attributes') meta;
@computed('job.meta.raw', 'meta')
@computed('job.meta.raw', 'meta.raw')
get mergedMeta() {
return {
...this.job.get('meta.raw'),
...this.meta,
...this.get('meta.raw'),
};
}

View File

@@ -21,15 +21,15 @@ export default class Task extends Fragment {
@fragmentArray('action', { defaultValue: () => [] })
actions;
@attr() meta;
@fragment('structured-attributes') meta;
@fragment('task-schedule') schedule;
@computed('taskGroup.mergedMeta', 'meta')
@computed('meta.raw', 'taskGroup.mergedMeta')
get mergedMeta() {
return {
...this.taskGroup.mergedMeta,
...this.meta,
...this.meta?.raw,
};
}

View File

@@ -287,4 +287,9 @@
</ListTable>
</div>
</div>
{{#if this.model.task.meta}}
<JobPage::Parts::Meta
@meta={{this.model.task.meta}}
/>
{{/if}}
</section>

View File

@@ -22,7 +22,7 @@
PlacementFailures=(component "job-page/parts/placement-failures" job=@job)
TaskGroups=(component "job-page/parts/task-groups" job=@job)
RecentAllocations=(component "job-page/parts/recent-allocations" job=@job activeTask=@activeTask setActiveTaskQueryParam=@setActiveTaskQueryParam)
Meta=(component "job-page/parts/meta" job=@job)
Meta=(component "job-page/parts/meta" meta=@job.meta)
DasRecommendations=(component
"job-page/parts/das-recommendations" job=@job
)
@@ -35,4 +35,4 @@
)
)
}}
}}

View File

@@ -3,7 +3,7 @@
SPDX-License-Identifier: BUSL-1.1
~}}
{{#if @job.meta.structured}}
{{#if @meta.structured}}
<div class="boxed-section">
<div class="boxed-section-head">
Meta
@@ -11,7 +11,7 @@
<div class="boxed-section-body is-full-bleed">
<AttributesTable
data-test-meta
@attributePairs={{@job.meta.structured.root}}
@attributePairs={{@meta.structured.root}}
@class="attributes-table" />
</div>
</div>

View File

@@ -220,7 +220,7 @@
</t.head>
<t.body @key="model.id" as |row|>
<AllocationRow
{{keyboard-shortcut
{{keyboard-shortcut
enumerated=true
action=(action "gotoAllocation" row.model)
}}
@@ -360,4 +360,10 @@
</div>
</div>
{{/if}}
{{#if this.model.meta}}
<JobPage::Parts::Meta
@meta={{this.model.meta}}
/>
{{/if}}
</section>

View File

@@ -57,6 +57,9 @@ export default Factory.extend({
// When true, the group will simulate a "scheduled" block's paused state
withPausedTasks: false,
// When true, the tasks will have metadata
withTaskMeta: false,
afterCreate(group, server) {
let taskIds = [];
let volumes = Object.keys(group.volumes);
@@ -114,6 +117,7 @@ export default Factory.extend({
})),
createRecommendations: group.createRecommendations,
withSchedule: group.withPausedTasks,
withMeta: group.withTaskMeta,
});
});
taskIds = tasks.mapBy('id');

View File

@@ -26,6 +26,8 @@ export default Factory.extend({
// Set in the TaskGroup factory
volumeMounts: [],
meta: null,
JobID: '',
name: (id) => `task-${dasherize(faker.hacker.noun())}-${id}`,
@@ -128,5 +130,9 @@ export default Factory.extend({
});
task.update({ schedule: schedule });
}
if (task.withMeta) {
task.update({ meta: { raw: { foo: 'bar' } } });
}
},
});

View File

@@ -12,7 +12,6 @@ import a11yAudit from 'nomad-ui/tests/helpers/a11y-audit';
import Task from 'nomad-ui/tests/pages/allocations/task/detail';
import Layout from 'nomad-ui/tests/pages/layout';
import moment from 'moment';
let allocation;
let task;
@@ -213,6 +212,28 @@ module('Acceptance | task detail', function (hooks) {
});
});
test('when a task group has metadata, the metadata table is shown', async function (assert) {
const job = server.create('job', {
createAllocations: false,
});
const taskGroup = server.create('task-group', {
job,
name: 'scaling',
count: 1,
withTaskMeta: true,
});
job.update({ taskGroupIds: [taskGroup.id] });
allocation = server.db.allocations[1];
server.db.taskStates.update(
{ allocationId: allocation.id },
{ state: 'running' }
);
const jobTask = taskGroup.tasks.models[0];
task = jobTask;
await Task.visit({ id: allocation.id, name: task.name });
assert.ok(Task.hasMeta);
});
test('each recent event should list the time, type, and description of the event', async function (assert) {
const event = server.db.taskEvents.where({ taskStateId: task.id })[0];
const recentEvent = Task.events.objectAt(Task.events.length - 1);

View File

@@ -453,6 +453,19 @@ module('Acceptance | task group detail', function (hooks) {
assert.notOk(TaskGroup.hasVolumes);
});
test('when the task group has metadata, the metadata table is shown', async function (assert) {
job = server.create('job', {
meta: { raw: { a: 'b' } },
});
taskGroup = server.create('task-group', {
job,
meta: { raw: { foo: 'bar' } },
});
await TaskGroup.visit({ id: job.id, name: taskGroup.name });
assert.ok(TaskGroup.hasMeta);
});
test('each row in the volumes table lists information about the volume', async function (assert) {
await TaskGroup.visit({ id: job.id, name: taskGroup.name });

View File

@@ -60,6 +60,8 @@ export default create({
clientSource: text('[data-test-volume-client-source]'),
}),
hasMeta: isPresent('[data-test-meta]'),
events: collection('[data-test-task-event]', {
time: text('[data-test-task-event-time]'),
type: text('[data-test-task-event-type]'),

View File

@@ -54,6 +54,8 @@ export default create({
permissions: text('[data-test-volume-permissions]'),
}),
hasMeta: isPresent('[data-test-meta]'),
hasScaleEvents: isPresent('[data-test-scale-events]'),
scaleEvents: collection(
'[data-test-scale-events] [data-test-accordion-head]',

View File

@@ -76,24 +76,22 @@ module('Unit | Model | task-group', function (hooks) {
const jobWithMeta = run(() =>
store.createRecord('job', {
name: 'example-with-meta',
meta: store.createFragment('structured-attributes', {
raw: { a: 'b' },
}),
meta: { raw: { a: 'b' } },
taskGroups: [
{
name: 'one',
meta: { c: 'd' },
meta: { raw: { c: 'd' } },
},
{
name: 'two',
},
{
name: 'three',
meta: null,
meta: { raw: null },
},
{
name: 'four',
meta: {},
meta: { raw: {} },
},
],
})
@@ -114,18 +112,18 @@ module('Unit | Model | task-group', function (hooks) {
taskGroups: [
{
name: 'one',
meta: { c: 'd' },
meta: { raw: { c: 'd' } },
},
{
name: 'two',
},
{
name: 'three',
meta: null,
meta: { raw: null },
},
{
name: 'four',
meta: {},
meta: { raw: {} },
},
],
})

View File

@@ -20,22 +20,22 @@ module('Unit | Model | task', function (hooks) {
taskGroups: [
{
name: 'one',
meta: { a: 'b' },
meta: { raw: { a: 'b' } },
tasks: [
{
name: 'task-one',
meta: { c: 'd' },
meta: { raw: { c: 'd' } },
},
{
name: 'task-two',
},
{
name: 'task-three',
meta: null,
meta: { raw: null },
},
{
name: 'task-four',
meta: {},
meta: { raw: {} },
},
],
},
@@ -44,18 +44,18 @@ module('Unit | Model | task', function (hooks) {
tasks: [
{
name: 'task-one',
meta: { c: 'd' },
meta: { raw: { c: 'd' } },
},
{
name: 'task-two',
},
{
name: 'task-three',
meta: null,
meta: { raw: null },
},
{
name: 'task-four',
meta: {},
meta: { raw: {} },
},
],
},