diff --git a/.changelog/24594.txt b/.changelog/24594.txt
new file mode 100644
index 00000000000..f271b8bab14
--- /dev/null
+++ b/.changelog/24594.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: Adds metadata tables to Task Group and Task pages
+```
diff --git a/ui/app/models/task-group.js b/ui/app/models/task-group.js
index 8db1771f06c..111bf988b9a 100644
--- a/ui/app/models/task-group.js
+++ b/ui/app/models/task-group.js
@@ -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'),
};
}
diff --git a/ui/app/models/task.js b/ui/app/models/task.js
index d5dd382327e..25847565f12 100644
--- a/ui/app/models/task.js
+++ b/ui/app/models/task.js
@@ -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,
};
}
diff --git a/ui/app/templates/allocations/allocation/task/index.hbs b/ui/app/templates/allocations/allocation/task/index.hbs
index 3942021b0a9..578827da545 100644
--- a/ui/app/templates/allocations/allocation/task/index.hbs
+++ b/ui/app/templates/allocations/allocation/task/index.hbs
@@ -287,4 +287,9 @@
+ {{#if this.model.task.meta}}
+
+ {{/if}}
diff --git a/ui/app/templates/components/job-page.hbs b/ui/app/templates/components/job-page.hbs
index 44f62cfbec7..996386b63fb 100644
--- a/ui/app/templates/components/job-page.hbs
+++ b/ui/app/templates/components/job-page.hbs
@@ -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 @@
)
)
-}}
\ No newline at end of file
+}}
diff --git a/ui/app/templates/components/job-page/parts/meta.hbs b/ui/app/templates/components/job-page/parts/meta.hbs
index 27b67ca5850..7539a784cb6 100644
--- a/ui/app/templates/components/job-page/parts/meta.hbs
+++ b/ui/app/templates/components/job-page/parts/meta.hbs
@@ -3,7 +3,7 @@
SPDX-License-Identifier: BUSL-1.1
~}}
-{{#if @job.meta.structured}}
+{{#if @meta.structured}}
diff --git a/ui/app/templates/jobs/job/task-group.hbs b/ui/app/templates/jobs/job/task-group.hbs
index ebd0eb386ac..88fdb6e226c 100644
--- a/ui/app/templates/jobs/job/task-group.hbs
+++ b/ui/app/templates/jobs/job/task-group.hbs
@@ -220,7 +220,7 @@
{{/if}}
+
+ {{#if this.model.meta}}
+
+ {{/if}}
diff --git a/ui/mirage/factories/task-group.js b/ui/mirage/factories/task-group.js
index 41625b249b0..d592dec04d4 100644
--- a/ui/mirage/factories/task-group.js
+++ b/ui/mirage/factories/task-group.js
@@ -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');
diff --git a/ui/mirage/factories/task.js b/ui/mirage/factories/task.js
index 6148a4ffa56..16c6a04f380 100644
--- a/ui/mirage/factories/task.js
+++ b/ui/mirage/factories/task.js
@@ -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' } } });
+ }
},
});
diff --git a/ui/tests/acceptance/task-detail-test.js b/ui/tests/acceptance/task-detail-test.js
index ba6e77b307e..06321965754 100644
--- a/ui/tests/acceptance/task-detail-test.js
+++ b/ui/tests/acceptance/task-detail-test.js
@@ -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);
diff --git a/ui/tests/acceptance/task-group-detail-test.js b/ui/tests/acceptance/task-group-detail-test.js
index 694c286dca5..c53de086b43 100644
--- a/ui/tests/acceptance/task-group-detail-test.js
+++ b/ui/tests/acceptance/task-group-detail-test.js
@@ -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 });
diff --git a/ui/tests/pages/allocations/task/detail.js b/ui/tests/pages/allocations/task/detail.js
index 45d6efa304a..3931e30ec14 100644
--- a/ui/tests/pages/allocations/task/detail.js
+++ b/ui/tests/pages/allocations/task/detail.js
@@ -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]'),
diff --git a/ui/tests/pages/jobs/job/task-group.js b/ui/tests/pages/jobs/job/task-group.js
index 35216e9da5b..0161f1b03e6 100644
--- a/ui/tests/pages/jobs/job/task-group.js
+++ b/ui/tests/pages/jobs/job/task-group.js
@@ -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]',
diff --git a/ui/tests/unit/models/task-group-test.js b/ui/tests/unit/models/task-group-test.js
index 4733060f69a..7913412b9da 100644
--- a/ui/tests/unit/models/task-group-test.js
+++ b/ui/tests/unit/models/task-group-test.js
@@ -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: {} },
},
],
})
diff --git a/ui/tests/unit/models/task-test.js b/ui/tests/unit/models/task-test.js
index 20b432f3fb6..1878bf2c215 100644
--- a/ui/tests/unit/models/task-test.js
+++ b/ui/tests/unit/models/task-test.js
@@ -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: {} },
},
],
},