diff --git a/ui/app/components/placement-failure.js b/ui/app/components/placement-failure.js
new file mode 100644
index 000000000..00d6fa37e
--- /dev/null
+++ b/ui/app/components/placement-failure.js
@@ -0,0 +1,5 @@
+import Ember from 'ember';
+
+const { Component } = Ember;
+
+export default Component.extend({});
diff --git a/ui/app/templates/components/placement-failure.hbs b/ui/app/templates/components/placement-failure.hbs
new file mode 100644
index 000000000..5066f2d32
--- /dev/null
+++ b/ui/app/templates/components/placement-failure.hbs
@@ -0,0 +1,40 @@
+{{#if taskGroup.placementFailures}}
+ {{#with taskGroup.placementFailures as |failures|}}
+
{{#each model.taskGroups as |taskGroup|}}
- {{#if taskGroup.placementFailures}}
- {{#with taskGroup.placementFailures as |failures|}}
-
- {{taskGroup.name}}
- {{inc failures.coalescedFailures}} unplaced
-
-
- {{#if (eq failures.nodesEvaluated 0)}}
- - No nodes were eligible for evaluation
- {{/if}}
- {{#each-in failures.nodesAvailable as |datacenter available|}}
- {{#if (eq available 0)}}
- - No nodes are available in datacenter {{datacenter}}
- {{/if}}
- {{/each-in}}
- {{#each-in failures.classFiltered as |class count|}}
- - Class {{class}} filtered {{count}} {{pluralize "node" count}}
- {{/each-in}}
- {{#each-in failures.constraintFiltered as |constraint count|}}
- - Constraint
{{constraint}} filtered {{count}} {{pluralize "node" count}}
- {{/each-in}}
- {{#if failures.nodesExhausted}}
- - Resources exhausted on {{failures.nodesExhausted}} {{pluralize "node" failures.nodesExhausted}}
- {{/if}}
- {{#each-in failures.classExhausted as |class count|}}
- - Class {{class}} exhausted on {{count}} {{pluralize "node" count}}
- {{/each-in}}
- {{#each-in failures.dimensionExhausted as |dimension count|}}
- - Dimension {{dimension}} exhausted on {{count}} {{pluralize "node" count}}
- {{/each-in}}
- {{#each-in failures.quotaExhausted as |quota dimension|}}
- - Quota limit hit {{dimension}}
- {{/each-in}}
- {{#each-in failures.scores as |name score|}}
- - Score {{name}} = {{score}}
- {{/each-in}}
-
- {{/with}}
- {{/if}}
+ {{#placement-failure taskGroup=taskGroup}}{{/placement-failure}}
{{/each}}
diff --git a/ui/tests/integration/cleanWhitespace.js b/ui/tests/integration/cleanWhitespace.js
new file mode 100644
index 000000000..c589984b6
--- /dev/null
+++ b/ui/tests/integration/cleanWhitespace.js
@@ -0,0 +1,6 @@
+export default function cleanWhitespace(string) {
+ return string
+ .replace(/\n/g, '')
+ .replace(/ +/g, ' ')
+ .trim();
+}
diff --git a/ui/tests/integration/job-diff-test.js b/ui/tests/integration/job-diff-test.js
index d1821e452..f9fac114c 100644
--- a/ui/tests/integration/job-diff-test.js
+++ b/ui/tests/integration/job-diff-test.js
@@ -1,6 +1,7 @@
import { findAll, find } from 'ember-native-dom-helpers';
import { test, moduleForComponent } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
+import cleanWhitespace from './cleanWhitespace';
moduleForComponent('job-diff', 'Integration | Component | job diff', {
integration: true,
@@ -192,10 +193,3 @@ function field(name, type, newVal, oldVal) {
Name: name,
};
}
-
-function cleanWhitespace(string) {
- return string
- .replace(/\n/g, '')
- .replace(/ +/g, ' ')
- .trim();
-}
diff --git a/ui/tests/integration/placement-failure-test.js b/ui/tests/integration/placement-failure-test.js
new file mode 100644
index 000000000..712c60696
--- /dev/null
+++ b/ui/tests/integration/placement-failure-test.js
@@ -0,0 +1,75 @@
+import { find } from 'ember-native-dom-helpers';
+import { test, moduleForComponent } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+import cleanWhitespace from './cleanWhitespace';
+
+moduleForComponent('placement-failure', 'Integration | Component | placement failure', {
+ integration: true,
+});
+
+const commonTemplate = hbs`
+