diff --git a/ui/app/adapters/evaluation.js b/ui/app/adapters/evaluation.js
index 13f0caabb3db..62f00be8771c 100644
--- a/ui/app/adapters/evaluation.js
+++ b/ui/app/adapters/evaluation.js
@@ -1,3 +1,4 @@
+import { get } from '@ember/object';
import ApplicationAdapter from './application';
export default class EvaluationAdapter extends ApplicationAdapter {
@@ -6,4 +7,9 @@ export default class EvaluationAdapter extends ApplicationAdapter {
result.meta = { nextToken: headers['x-nomad-nexttoken'] };
return result;
}
+
+ urlForFindRecord(id, modelName, snapshot) {
+ let url = super.urlForFindRecord(...arguments);
+ return `${url}?related=true`;
+ }
}
diff --git a/ui/app/controllers/evaluations/evaluation.js b/ui/app/controllers/evaluations/evaluation.js
new file mode 100644
index 000000000000..78969ac5e4cc
--- /dev/null
+++ b/ui/app/controllers/evaluations/evaluation.js
@@ -0,0 +1,15 @@
+import Controller from '@ember/controller';
+
+export default class EvaluationController extends Controller {
+ get eval() {
+ return this.model;
+ }
+
+ get breadcrumb() {
+ return {
+ title: 'Evaluation',
+ label: this.eval.get('shortId'),
+ args: ['evaluations.evaluation', this.eval.get('id')],
+ };
+ }
+}
diff --git a/ui/app/controllers/evaluations/evaluation/index.js b/ui/app/controllers/evaluations/evaluation/index.js
new file mode 100644
index 000000000000..2c04db7561b1
--- /dev/null
+++ b/ui/app/controllers/evaluations/evaluation/index.js
@@ -0,0 +1,23 @@
+/* eslint-disable ember/no-observers */
+/* eslint-disable ember/no-incorrect-calls-with-inline-anonymous-functions */
+import { alias } from '@ember/object/computed';
+import Controller from '@ember/controller';
+import { action, computed } from '@ember/object';
+import { observes } from '@ember-decorators/object';
+import { scheduleOnce } from '@ember/runloop';
+import { task } from 'ember-concurrency';
+import intersection from 'lodash.intersection';
+import Sortable from 'nomad-ui/mixins/sortable';
+import Searchable from 'nomad-ui/mixins/searchable';
+import messageFromAdapterError from 'nomad-ui/utils/message-from-adapter-error';
+import {
+ serialize,
+ deserializedQueryParam as selection,
+} from 'nomad-ui/utils/qp-serialize';
+import classic from 'ember-classic-decorator';
+
+@classic
+export default class EvaluationController extends Controller.extend(
+ Sortable,
+ Searchable
+) {}
diff --git a/ui/app/models/evaluation-stub.js b/ui/app/models/evaluation-stub.js
new file mode 100644
index 000000000000..e8d8cb72a302
--- /dev/null
+++ b/ui/app/models/evaluation-stub.js
@@ -0,0 +1,30 @@
+import { bool, equal } from '@ember/object/computed';
+import Model from '@ember-data/model';
+import { attr, belongsTo, hasMany } from '@ember-data/model';
+import { fragmentArray } from 'ember-data-model-fragments/attributes';
+import shortUUIDProperty from '../utils/properties/short-uuid';
+import Fragment from 'ember-data-model-fragments/fragment';
+
+export default class EvaluationStub extends Fragment {
+ @shortUUIDProperty('evalId') shortId;
+ @attr('string') evalId;
+ @attr('string') type;
+ @attr('string') triggeredBy;
+ @attr('string') status;
+ @attr('string') statusDescription;
+
+ @belongsTo('job') job;
+ @belongsTo('node') node;
+
+ get hasJob() {
+ return !!this.plainJobId;
+ }
+
+ get hasNode() {
+ return !!this.belongsTo('node').id();
+ }
+
+ get nodeId() {
+ return this.belongsTo('node').id();
+ }
+}
diff --git a/ui/app/models/evaluation.js b/ui/app/models/evaluation.js
index 51507708bc39..23aefad10eae 100644
--- a/ui/app/models/evaluation.js
+++ b/ui/app/models/evaluation.js
@@ -1,6 +1,6 @@
import { bool, equal } from '@ember/object/computed';
import Model from '@ember-data/model';
-import { attr, belongsTo } from '@ember-data/model';
+import { attr, belongsTo, hasMany } from '@ember-data/model';
import { fragmentArray } from 'ember-data-model-fragments/attributes';
import shortUUIDProperty from '../utils/properties/short-uuid';
@@ -21,6 +21,8 @@ export default class Evaluation extends Model {
@belongsTo('job') job;
@belongsTo('node') node;
+ @fragmentArray('evaluation-stub') relatedEvals;
+
@attr('number') modifyIndex;
@attr('date') modifyTime;
diff --git a/ui/app/router.js b/ui/app/router.js
index 596fa543a95e..7394830364cb 100644
--- a/ui/app/router.js
+++ b/ui/app/router.js
@@ -75,7 +75,9 @@ Router.map(function () {
});
// if we don't include function() the outlet won't render
- this.route('evaluations', function () {});
+ this.route('evaluations', function () {
+ this.route('evaluation', { path: '/:evaluation_id' });
+ });
this.route('not-found', { path: '/*' });
});
diff --git a/ui/app/routes/evaluations/evaluation.js b/ui/app/routes/evaluations/evaluation.js
new file mode 100644
index 000000000000..b0535222ce7b
--- /dev/null
+++ b/ui/app/routes/evaluations/evaluation.js
@@ -0,0 +1,10 @@
+import { inject as service } from '@ember/service';
+import Route from '@ember/routing/route';
+
+export default class EvaluationRoute extends Route {
+ @service store;
+
+ model(params) {
+ return this.store.findRecord('evaluation', params.evaluation_id);
+ }
+}
diff --git a/ui/app/routes/evaluations/evaluation/index.js b/ui/app/routes/evaluations/evaluation/index.js
new file mode 100644
index 000000000000..3805dfde714c
--- /dev/null
+++ b/ui/app/routes/evaluations/evaluation/index.js
@@ -0,0 +1,4 @@
+import Route from '@ember/routing/route';
+import WithWatchers from 'nomad-ui/mixins/with-watchers';
+
+export default class EvaluationRoute extends Route.extend(WithWatchers) {}
diff --git a/ui/app/serializers/evaluation-stub.js b/ui/app/serializers/evaluation-stub.js
new file mode 100644
index 000000000000..fe72b44ddce0
--- /dev/null
+++ b/ui/app/serializers/evaluation-stub.js
@@ -0,0 +1,23 @@
+import { inject as service } from '@ember/service';
+import { get } from '@ember/object';
+import ApplicationSerializer from './application';
+import classic from 'ember-classic-decorator';
+
+@classic
+export default class EvaluationStub extends ApplicationSerializer {
+ @service system;
+
+ mapToArray = ['FailedTGAllocs'];
+ separateNanos = ['CreateTime', 'ModifyTime'];
+
+ normalize(typeHash, hash) {
+ console.log(hash);
+ console.log(typeHash);
+ hash.EvalId = hash.ID;
+ hash.PlainJobId = hash.JobID;
+ hash.Namespace = hash.Namespace || get(hash, 'Job.Namespace') || 'default';
+ hash.JobID = JSON.stringify([hash.JobID, hash.Namespace]);
+
+ return super.normalize(typeHash, hash);
+ }
+}
diff --git a/ui/app/templates/evaluations/evaluation.hbs b/ui/app/templates/evaluations/evaluation.hbs
new file mode 100644
index 000000000000..818e2aedbc34
--- /dev/null
+++ b/ui/app/templates/evaluations/evaluation.hbs
@@ -0,0 +1,7 @@
+