YARN-7620. Allow node partition filters on Queues page of new YARN UI. Contributed by Vasudevan Skm.

This commit is contained in:
Sunil G 2017-12-19 20:27:25 +05:30
parent e040c97b77
commit fe5b057c81
14 changed files with 481 additions and 186 deletions

View File

@ -16,7 +16,27 @@
* limitations under the License.
*/
import Ember from 'ember';
import Ember from "ember";
export default Ember.Component.extend({
export default Ember.Component.extend(Ember.TargetActionSupport,{
actions: {
filterQueuesByPartition(filter) {
this.set("filteredPartition", filter);
this.sendAction("setFilter", filter);
}
},
didInsertElement: function() {
$(".js-filter-queue-by-labels").select2({
width: "350px",
multiple: false
});
$(".js-filter-queue-by-labels").on("select2:select", e => {
this.triggerAction({
action: "filterQueuesByPartition",
target: this,
actionContext: e.params.data.text
});
});
}
});

View File

@ -16,19 +16,20 @@
* limitations under the License.
*/
import Ember from 'ember';
import Ember from "ember";
import {PARTITION_LABEL} from '../constants';
const INBETWEEN_HEIGHT = 130;
export default Ember.Component.extend({
// Map: <queue-name, queue>
map : undefined,
map: undefined,
// Normalized data for d3
treeData: undefined,
// folded queues, folded[<queue-name>] == true means <queue-name> is folded
foldedQueues: { },
foldedQueues: {},
// maxDepth
maxDepth: 0,
@ -42,17 +43,23 @@ export default Ember.Component.extend({
used: undefined,
max: undefined,
didUpdateAttrs: function({ oldAttrs, newAttrs }) {
if (oldAttrs.filteredPartition.value !== newAttrs.filteredPartition.value) {
this.reDraw();
}
},
// Init data
initData: function() {
this.map = { };
this.treeData = { };
this.map = {};
this.treeData = {};
this.maxDepth = 0;
this.numOfLeafQueue = 0;
this.get("model")
.forEach(function(o) {
this.get("model").forEach(
function(o) {
this.map[o.id] = o;
}.bind(this));
}.bind(this)
);
// var selected = this.get("selected");
this.used = this.get("used");
@ -81,9 +88,9 @@ export default Ember.Component.extend({
// Init queues
initQueue: function(queueName, depth, node) {
if ((!queueName) || (!this.map[queueName])) {
if (!queueName || !this.map[queueName]) {
// Queue is not existed
return;
return false;
}
if (depth > this.maxDepth) {
this.maxDepth = this.maxDepth + 1;
@ -91,6 +98,13 @@ export default Ember.Component.extend({
var queue = this.map[queueName];
if (
this.filteredPartition &&
!queue.get("partitions").contains(this.filteredPartition)
) {
return false;
}
var names = this.getChildrenNamesArray(queue);
node.name = queueName;
@ -100,14 +114,21 @@ export default Ember.Component.extend({
if (names.length > 0) {
node.children = [];
names.forEach(function(name) {
names.forEach(
function(name) {
var childQueueData = {};
node.children.push(childQueueData);
this.initQueue(name, depth + 1, childQueueData);
}.bind(this));
const status = this.initQueue(name, depth + 1, childQueueData);
if (!status) {
node.children.pop();
}
}.bind(this)
);
} else {
this.numOfLeafQueue = this.numOfLeafQueue + 1;
}
return true;
},
update: function(source, root, tree, diagonal) {
@ -119,141 +140,183 @@ export default Ember.Component.extend({
var links = tree.links(nodes);
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 200; });
nodes.forEach(function(d) {
d.y = d.depth * 200;
});
// Update the nodes…
var node = this.mainSvg.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++i); });
var node = this.mainSvg.selectAll("g.node").data(nodes, function(d) {
return d.id || (d.id = ++i);
});
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
var nodeEnter = node
.enter()
.append("g")
.attr("class", "node")
.attr("transform", function() { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", function(d){
.attr("transform", function() {
return `translate(${source.y0 + 50}, ${source.x0})`;
})
.on(
"click",
function(d) {
if (d.queueData.get("name") !== this.get("selected")) {
document.location.href = "#/yarn-queues/" + d.queueData.get("name") + "!";
document.location.href =
"#/yarn-queues/" + d.queueData.get("name") + "!";
}
Ember.run.later(this, function () {
Ember.run.later(
this,
function() {
var treeWidth = this.maxDepth * 200;
var treeHeight = this.numOfLeafQueue * INBETWEEN_HEIGHT;
var tree = d3.layout.tree().size([treeHeight, treeWidth]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
this.update(this.treeData, this.treeData, tree, diagonal);
}, 100);
}.bind(this))
.on("dblclick", function (d) {
document.location.href = "#/yarn-queue/" + d.queueData.get("name") + "/apps";
var diagonal = d3.svg.diagonal().projection(function(d) {
return [d.y + 50, d.x];
});
nodeEnter.append("circle")
this.update(this.treeData, this.treeData, tree, diagonal);
},
100
);
}.bind(this)
)
.on("dblclick", function(d) {
document.location.href =
"#/yarn-queue/" + d.queueData.get("name") + "/apps";
});
nodeEnter
.append("circle")
.attr("r", 1e-6)
.style("fill", function(d) {
var maxCap = d.queueData.get(this.max);
maxCap = maxCap === undefined ? 100 : maxCap;
var usedCap = d.queueData.get(this.used) / maxCap * 100.0;
if (usedCap <= 60.0) {
return "mediumaquamarine";
} else if (usedCap <= 100.0) {
return "coral";
.style(
"fill",
function(d) {
const usedCapacity = getUsedCapacity(d.queueData.get("partitionMap"), this.filteredPartition);
if (usedCapacity <= 60.0) {
return "#60cea5";
} else if (usedCapacity <= 100.0) {
return "#ffbc0b";
} else {
return "salmon";
return "#ef6162";
}
}.bind(this));
}.bind(this)
);
// append percentage
nodeEnter.append("text")
.attr("x", function() { return 0; })
nodeEnter
.append("text")
.attr("x", function() {
return 0;
})
.attr("dy", ".35em")
.attr("fill", "white")
.attr("text-anchor", function() { return "middle"; })
.text(function(d) {
var maxCap = d.queueData.get(this.max);
maxCap = maxCap === undefined ? 100 : maxCap;
var usedCap = d.queueData.get(this.used) / maxCap * 100.0;
if (usedCap >= 100.0) {
return usedCap.toFixed(0) + "%";
.attr("text-anchor", function() {
return "middle";
})
.text(
function(d) {
const usedCapacity = getUsedCapacity(d.queueData.get("partitionMap"), this.filteredPartition);
if (usedCapacity >= 100.0) {
return usedCapacity.toFixed(0) + "%";
} else {
return usedCap.toFixed(1) + "%";
return usedCapacity.toFixed(1) + "%";
}
}.bind(this))
}.bind(this)
)
.style("fill-opacity", 1e-6);
// append queue name
nodeEnter.append("text")
nodeEnter
.append("text")
.attr("x", "0px")
.attr("dy", "45px")
.attr("text-anchor", "middle")
.text(function(d) { return d.name; })
.text(function(d) {
return d.name;
})
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
var nodeUpdate = node
.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
.attr("transform", function(d) {
return `translate(${d.y + 50}, ${d.x})`;
});
nodeUpdate.select("circle")
nodeUpdate
.select("circle")
.attr("r", 30)
.attr("href",
function(d) {
.attr("href", function(d) {
return "#/yarn-queues/" + d.queueData.get("name");
})
.style("stroke-width", function(d) {
.style(
"stroke-width",
function(d) {
if (d.queueData.get("name") === this.get("selected")) {
return 7;
} else {
return 2;
}
}.bind(this))
.style("stroke", function(d) {
}.bind(this)
)
.style(
"stroke",
function(d) {
if (d.queueData.get("name") === this.get("selected")) {
return "gray";
} else {
return "gray";
}
}.bind(this));
}.bind(this)
);
nodeUpdate.selectAll("text")
.style("fill-opacity", 1);
nodeUpdate.selectAll("text").style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
var nodeExit = node
.exit()
.transition()
.duration(duration)
.attr("transform", function() { return "translate(" + source.y + "," + source.x + ")"; })
.attr("transform", function() {
return `translate(${source.y}, ${source.x})`;
})
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("circle").attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
nodeExit.select("text").style("fill-opacity", 1e-6);
// Update the links…
var link = this.mainSvg.selectAll("path.link")
.data(links, function(d) { return d.target.id; });
var link = this.mainSvg.selectAll("path.link").data(links, function(d) {
return d.target.id;
});
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
link
.enter()
.insert("path", "g")
.attr("class", "link")
.attr("d", function() {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
var o = { x: source.x0, y: source.y0 + 50 };
return diagonal({ source: o, target: o });
});
// Transition links to their new position.
link.transition()
link
.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
link
.exit()
.transition()
.duration(duration)
.attr("d", function() {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
var o = { x: source.x, y: source.y };
return diagonal({ source: o, target: o });
})
.remove();
@ -267,27 +330,32 @@ export default Ember.Component.extend({
reDraw: function() {
this.initData();
var margin = {top: 20, right: 120, bottom: 20, left: 120};
var margin = { top: 20, right: 120, bottom: 20, left: 120 };
var treeWidth = this.maxDepth * 200;
var treeHeight = this.numOfLeafQueue * INBETWEEN_HEIGHT;
var width = treeWidth + margin.left + margin.right;
var height = treeHeight + margin.top + margin.bottom;
if (this.mainSvg) {
this.mainSvg.remove();
}
this.mainSvg = d3.select("#" + this.get("parentId")).append("svg")
this.mainSvg.selectAll("*").remove();
} else {
this.mainSvg = d3
.select("#" + this.get("parentId"))
.append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "tree-selector")
.attr("class", "tree-selector");
}
this.mainSvg
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var tree = d3.layout.tree().size([treeHeight, treeWidth]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
var diagonal = d3.svg.diagonal().projection(function(d) {
return [d.y + 50, d.x];
});
var root = this.treeData;
root.x0 = height / 2;
@ -302,3 +370,8 @@ export default Ember.Component.extend({
this.reDraw();
}
});
const getUsedCapacity = (partitionMap, filter=PARTITION_LABEL) => {
return partitionMap[filter].absoluteUsedCapacity;
};

View File

@ -0,0 +1,48 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Ember from "ember";
import { PARTITION_LABEL } from "../constants";
export default Ember.Component.extend({
didUpdateAttrs: function({ oldAttrs, newAttrs }) {
this._super(...arguments);
this.set("data", this.initData());
},
init() {
this._super(...arguments);
this.set("data", this.initData());
},
initData() {
const queue = this.get("queue");
const partitionMap = this.get("partitionMap");
const filteredParition = this.get("filteredPartition") || PARTITION_LABEL;
const userLimit = queue.get("userLimit");
const userLimitFactor = queue.get("userLimitFactor");
const isLeafQueue = queue.get("isLeafQueue");
return {
...partitionMap[filteredParition],
userLimit,
userLimitFactor,
isLeafQueue
};
}
});

View File

@ -35,3 +35,5 @@ export const Entities = {
Resource: 'resource',
Unit: 'unit'
}
export const PARTITION_LABEL = 'Default partition';

View File

@ -17,19 +17,39 @@
*/
import Ember from 'ember';
import {PARTITION_LABEL} from '../constants';
export default Ember.Controller.extend({
needReload: true,
selectedQueue: undefined,
showLoading: true,
filteredPartition: PARTITION_LABEL,
breadcrumbs: [{
breadcrumbs: [
{
text: "Home",
routeName: 'application'
}, {
routeName: "application"
},
{
text: "Queues",
routeName: 'yarn-queues',
model: 'root'
}]
routeName: "yarn-queues",
model: "root"
}
],
actions: {
setFilter(partition) {
this.set("filteredPartition", partition);
const model = this.get('model');
const {selectedQueue} = model;
// If the selected queue does not have the filtered partition
// reset it to root
if (!selectedQueue.get('partitions').contains(partition)) {
const root = model.queues.get('firstObject');
document.location.href = "#/yarn-queues/" + root.get("id") + "!";
this.set("model.selectedQueue", root);
this.set("model.selected", root.get('id'));
}
}
}
});

View File

@ -20,24 +20,26 @@ import DS from 'ember-data';
import Converter from 'yarn-ui/utils/converter';
export default DS.Model.extend({
name: DS.attr('string'),
children: DS.attr('array'),
parent: DS.attr('string'),
capacity: DS.attr('number'),
maxCapacity: DS.attr('number'),
usedCapacity: DS.attr('number'),
absCapacity: DS.attr('number'),
absMaxCapacity: DS.attr('number'),
absUsedCapacity: DS.attr('number'),
state: DS.attr('string'),
userLimit: DS.attr('number'),
userLimitFactor: DS.attr('number'),
preemptionDisabled: DS.attr('number'),
numPendingApplications: DS.attr('number'),
numActiveApplications: DS.attr('number'),
users: DS.hasMany('YarnUser'),
type: DS.attr('string'),
resources: DS.attr('object'),
name: DS.attr("string"),
children: DS.attr("array"),
parent: DS.attr("string"),
capacity: DS.attr("number"),
partitions: DS.attr("array"),
partitionMap: DS.attr("object"),
maxCapacity: DS.attr("number"),
usedCapacity: DS.attr("number"),
absCapacity: DS.attr("number"),
absMaxCapacity: DS.attr("number"),
absUsedCapacity: DS.attr("number"),
state: DS.attr("string"),
userLimit: DS.attr("number"),
userLimitFactor: DS.attr("number"),
preemptionDisabled: DS.attr("number"),
numPendingApplications: DS.attr("number"),
numActiveApplications: DS.attr("number"),
users: DS.hasMany("YarnUser"),
type: DS.attr("string"),
resources: DS.attr("object"),
isLeafQueue: function() {
var len = this.get("children.length");
@ -53,21 +55,29 @@ export default DS.Model.extend({
{
label: "Absolute Used",
style: "primary",
value: this.get("name") === "root" ? floatToFixed(this.get("usedCapacity")) : floatToFixed(this.get("absUsedCapacity"))
value:
this.get("name") === "root"
? floatToFixed(this.get("usedCapacity"))
: floatToFixed(this.get("absUsedCapacity"))
},
{
label: "Absolute Capacity",
style: "primary",
value: this.get("name") === "root" ? 100 : floatToFixed(this.get("absCapacity"))
value:
this.get("name") === "root"
? 100
: floatToFixed(this.get("absCapacity"))
},
{
label: "Absolute Max Capacity",
style: "secondary",
value: this.get("name") === "root" ? 100 : floatToFixed(this.get("absMaxCapacity"))
value:
this.get("name") === "root"
? 100
: floatToFixed(this.get("absMaxCapacity"))
}
];
}.property("absCapacity", "usedCapacity", "absMaxCapacity"),
userUsagesDonutChartData: function() {
var data = [];
if (this.get("users")) {
@ -97,5 +107,5 @@ export default DS.Model.extend({
value: this.get("numActiveApplications") || 0
}
];
}.property("numPendingApplications", "numActiveApplications"),
}.property("numPendingApplications", "numActiveApplications")
});

View File

@ -17,6 +17,7 @@
*/
import DS from 'ember-data';
import {PARTITION_LABEL} from '../../constants';
export default DS.JSONAPISerializer.extend({
@ -73,6 +74,11 @@ export default DS.JSONAPISerializer.extend({
numPendingApplications: payload.numPendingApplications,
numActiveApplications: payload.numActiveApplications,
resources: payload.resources,
partitions: payload.capacities.queueCapacitiesByPartition.map(cap => cap.partitionName || PARTITION_LABEL),
partitionMap: payload.capacities.queueCapacitiesByPartition.reduce((init, cap) => {
init[cap.partitionName || PARTITION_LABEL] = cap;
return init;
}, {}),
type: "capacity",
},
// Relationships

View File

@ -3,6 +3,7 @@
@import 'yarn-app.scss';
@import './compose-box.scss';
@import 'em-table.scss';
@import './yarn-queues.scss';
/**
* Licensed to the Apache Software Foundation (ASF) under one

View File

@ -0,0 +1,29 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.filter-partitions {
padding: 15px;
margin-left: auto;
label {
font-weight: 500;
}
.filter-queue-by-labels {
display: inline-block;
max-width: 350px;
}
}

View File

@ -21,9 +21,25 @@
<div class="col-md-12 container-fluid">
<div class="panel panel-default" id="tree-selector-container">
<div class="panel-heading">
Scheduler: {{model.firstObject.type}}
{{#if filteredPartition}}
{{model.firstObject.type}} scheduler - Showing queues from partition {{lower filteredPartition}}
{{else}}
{{model.firstObject.type}} scheduler - Showing queues from all partitions
{{/if}}
</div>
{{tree-selector model=model parentId="tree-selector-container" selected=selected used=used max=max}}
{{#if (eq model.firstObject.type "capacity")}}
<div class="flex">
<div class="filter-partitions flex-right">
<label><i class="glyphicon glyphicon-filter"/> Partitions: </label>
<select onchange={{action "filterQueuesByPartition" value="target.value"}} class="form-control js-filter-queue-by-labels">
{{#each model.firstObject.partitions as |part|}}
<option value={{part}}>{{part}}</option>
{{/each}}
</select>
</div>
</div>
{{/if}}
{{tree-selector model=model parentId="tree-selector-container" selected=selected used=used max=max filteredPartition=filteredPartition}}
</div>
</div>
</div>

View File

@ -0,0 +1,54 @@
{{!
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
}}
<div class="top-1">
<span class="yarn-label primary">
<span class="label-key">absolute used</span>
<span class="label-value">{{data.absoluteUsedCapacity}}%</span>
</span>
<span class="yarn-label primary">
<span class="label-key">absolute capacity</span>
<span class="label-value">{{data.absoluteCapacity}}%</span>
</span>
<span class="yarn-label secondary">
<span class="label-key">absolute max capacity</span>
<span class="label-value">{{data.absoluteMaxCapacity}}%</span>
</span>
</div>
<div class="top-1">
<span class="yarn-label secondary">
<span class="label-key">configured capacity</span>
<span class="label-value">{{data.capacity}}%</span>
</span>
<span class="yarn-label secondary">
<span class="label-key">configured max capacity</span>
<span class="label-value">{{data.maxCapacity}}%</span>
</span>
</div>
{{#if data.isLeafQueue}}
<div class="top-1">
<span class="yarn-label secondary">
<span class="label-key">user limit</span>
<span class="label-value">{{data.userLimit}}%</span>
</span>
<span class="yarn-label secondary">
<span class="label-key">user limit factor</span>
<span class="label-value">{{data.userLimitFactor}}</span>
</span>
</div>
{{/if}}

View File

@ -17,7 +17,7 @@
}}
{{queue-navigator model=model.queues selected=model.selected
used="usedCapacity" max="absMaxCapacity"}}
used="usedCapacity" max="absMaxCapacity" setFilter=(action setFilter)}}
<div class="yarn-compose-box yarn-queues-container">
<div>
@ -31,36 +31,8 @@
{{em-table-simple-status-cell content=model.selectedQueue.state}}
</div>
{{/if}}
<div class="top-1">
{{#each model.selectedQueue.capacitiesBarChartData as |item|}}
<span class="yarn-label {{item.style}}">
<span class="label-key"> {{lower item.label}}</span>
<span class="label-value">{{item.value}}%</span>
</span>
{{/each}}
</div>
<div class="top-1">
<span class="yarn-label secondary">
<span class="label-key">configured capacity</span>
<span class="label-value">{{model.selectedQueue.capacity}}%</span>
</span>
<span class="yarn-label secondary">
<span class="label-key">configured max capacity</span>
<span class="label-value">{{model.selectedQueue.maxCapacity}}%</span>
</span>
</div>
{{#if model.selectedQueue.isLeafQueue}}
<div class="top-1">
<span class="yarn-label secondary">
<span class="label-key">user limit</span>
<span class="label-value">{{model.selectedQueue.userLimit}}%</span>
</span>
<span class="yarn-label secondary">
<span class="label-key">user limit factor</span>
<span class="label-value">{{model.selectedQueue.userLimitFactor}}</span>
</span>
</div>
{{/if}}
{{yarn-queue-partition-capacity-labels partitionMap=model.selectedQueue.partitionMap queue=model.selectedQueue filteredPartition=filteredPartition}}
</div>
<h5> Running Apps </h5>

View File

@ -18,9 +18,10 @@
<div class="queue-page-breadcrumb">
{{breadcrumb-bar breadcrumbs=breadcrumbs}}
</div>
<div class="container-fluid">
{{#if (eq model.queues.firstObject.type "capacity")}}
{{yarn-queue.capacity-queue model=model}}
{{yarn-queue.capacity-queue model=model setFilter=(action "setFilter") filteredPartition=filteredPartition}}
{{else if (eq model.queues.firstObject.type "fair")}}
{{yarn-queue.fair-queue model=model}}
{{else}}

View File

@ -0,0 +1,43 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
moduleForComponent('yarn-queue-partition-capacity-labels', 'Integration | Component | yarn queue partition capacity labels', {
integration: true
});
test('it renders', function(assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.on('myAction', function(val) { ... });" + EOL + EOL +
this.render(hbs`{{yarn-queue-partition-capacity-labels}}`);
assert.equal(this.$().text().trim(), '');
// Template block usage:" + EOL +
this.render(hbs`
{{#yarn-queue-partition-capacity-labels}}
template block text
{{/yarn-queue-partition-capacity-labels}}
`);
assert.equal(this.$().text().trim(), 'template block text');
});