Simon Hunt
Committed by Gerrit Code Review

GUI Topo -- Cleaned up NodeBadge, now that we have a clearer idea of what we want to model.

Change-Id: I754a94cbd1fbe2a2c8affccaca88c48c3fa33b92
......@@ -23,18 +23,15 @@ public final class NodeBadge {
private static final String EMPTY = "";
/** Designates the type of badge. */
public enum Type {
/** Designates the badge status. */
public enum Status {
INFO("i"),
WARN("w"),
ERROR("e"),
CHECK_MARK("/"),
X_MARK("X"),
NUMBER("n");
ERROR("e");
private String code;
Type(String code) {
Status(String code) {
this.code = code;
}
......@@ -43,33 +40,60 @@ public final class NodeBadge {
return "{" + code + "}";
}
/** Returns the type's code in string form. */
/** Returns the status code in string form. */
public String code() {
return code;
}
}
private final Type type;
private final Status status;
private final boolean isGlyph;
private final String text;
private final String message;
// only instantiated through static methods.
private NodeBadge(Type type, String message) {
this.type = type;
private NodeBadge(Status status, boolean isGlyph, String text, String message) {
this.status = status == null ? Status.INFO : status;
this.isGlyph = isGlyph;
this.text = text;
this.message = message;
}
@Override
public String toString() {
return "{Badge " + type + " \"" + message + "\"}";
return "{Badge " + status +
" (" + text + ")" +
(isGlyph ? "*G " : " ") +
"\"" + message + "\"}";
}
/**
* Returns the badge type.
* Returns the badge status.
*
* @return badge type
* @return badge status
*/
public Type type() {
return type;
public Status status() {
return status;
}
/**
* Returns true if the text for this badge designates a glyph ID.
*
* @return true if badge uses glyph
*/
public boolean isGlyph() {
return isGlyph;
}
/**
* Returns the text for the badge.
* Note that if {@link #isGlyph} is true, the text is a glyph ID, otherwise
* the text is displayed verbatim in the badge.
*
* @return text for badge
*/
public String text() {
return text;
}
/**
......@@ -86,64 +110,111 @@ public final class NodeBadge {
}
/**
* Returns an informational badge, with associated message.
* Returns an arbitrary text badge, with default status.
*
* @param message the message
* @return INFO type node badge
* @param txt the text
* @return node badge to display text
*/
public static NodeBadge info(String message) {
return new NodeBadge(Type.INFO, nonNull(message));
public static NodeBadge text(String txt) {
// TODO: consider length constraint on txt (3 chars?)
return new NodeBadge(Status.INFO, false, nonNull(txt), null);
}
/**
* Returns a warning badge, with associated message.
* Returns a glyph badge, with default status.
*
* @param message the message
* @return WARN type node badge
* @param gid the glyph ID
* @return node badge to display glyph
*/
public static NodeBadge warn(String message) {
return new NodeBadge(Type.WARN, nonNull(message));
public static NodeBadge glyph(String gid) {
return new NodeBadge(Status.INFO, true, nonNull(gid), null);
}
/**
* Returns an error badge, with associated message.
* Returns a numeric badge, with default status.
*
* @param message the message
* @return ERROR type node badge
* @param n the number
* @return node badge to display a number
*/
public static NodeBadge error(String message) {
return new NodeBadge(Type.ERROR, nonNull(message));
public static NodeBadge number(int n) {
// TODO: consider constraints, e.g. 1 <= n <= 999
return new NodeBadge(Status.INFO, false, Integer.toString(n), null);
}
/**
* Returns a check-mark badge, with associated message.
* Returns an arbitrary text badge, with the given status.
*
* @param message the message
* @return CHECK_MARK type node badge
* @param s the status
* @param txt the text
* @return node badge to display text
*/
public static NodeBadge checkMark(String message) {
return new NodeBadge(Type.CHECK_MARK, nonNull(message));
public static NodeBadge text(Status s, String txt) {
// TODO: consider length constraint on txt (3 chars?)
return new NodeBadge(s, false, nonNull(txt), null);
}
/**
* Returns an X-mark badge, with associated message.
* Returns a glyph badge, with the given status.
*
* @param message the message
* @return X_MARK type node badge
* @param s the status
* @param gid the glyph ID
* @return node badge to display glyph
*/
public static NodeBadge xMark(String message) {
return new NodeBadge(Type.X_MARK, nonNull(message));
public static NodeBadge glyph(Status s, String gid) {
return new NodeBadge(s, true, nonNull(gid), null);
}
/**
* Returns a numeric badge.
* Returns a numeric badge, with the given status and optional message.
*
* @param s the status
* @param n the number
* @return NUMBER type node badge
* @return node badge to display a number
*/
public static NodeBadge number(int n) {
// TODO: consider constraints, e.g. 1 <= n <= 99
return new NodeBadge(Type.NUMBER, Integer.toString(n));
public static NodeBadge number(Status s, int n) {
// TODO: consider constraints, e.g. 1 <= n <= 999
return new NodeBadge(s, false, Integer.toString(n), null);
}
/**
* Returns an arbitrary text badge, with the given status and optional
* message.
*
* @param s the status
* @param txt the text
* @param msg the optional message
* @return node badge to display text
*/
public static NodeBadge text(Status s, String txt, String msg) {
// TODO: consider length constraint on txt (3 chars?)
return new NodeBadge(s, false, nonNull(txt), msg);
}
/**
* Returns a glyph badge, with the given status and optional message.
*
* @param s the status
* @param gid the glyph ID
* @param msg the optional message
* @return node badge to display glyph
*/
public static NodeBadge glyph(Status s, String gid, String msg) {
return new NodeBadge(s, true, nonNull(gid), msg);
}
/**
* Returns a numeric badge, with the given status and optional message.
*
* @param s the status
* @param n the number
* @param msg the optional message
* @return node badge to display a number
*/
public static NodeBadge number(Status s, int n, String msg) {
// TODO: consider constraints, e.g. 1 <= n <= 999
return new NodeBadge(s, false, Integer.toString(n), msg);
}
}
......
......@@ -38,6 +38,9 @@ public final class TopoJson {
static final String LABEL = "label";
static final String CSS = "css";
static final String BADGE = "badge";
static final String STATUS = "status";
static final String TXT = "txt";
static final String GID = "gid";
static final String MSG = "msg";
static final String TITLE = "title";
......@@ -99,6 +102,16 @@ public final class TopoJson {
return payload;
}
private static ObjectNode json(NodeBadge b) {
ObjectNode n = objectNode()
.put(STATUS, b.status().code())
.put(b.isGlyph() ? GID : TXT, b.text());
if (b.message() != null) {
n.put(MSG, b.message());
}
return n;
}
private static ObjectNode json(DeviceHighlight dh) {
ObjectNode n = objectNode()
.put(ID, dh.elementId());
......@@ -107,10 +120,7 @@ public final class TopoJson {
}
NodeBadge badge = dh.badge();
if (badge != null) {
ObjectNode b = objectNode()
.put(TYPE, badge.type().code())
.put(MSG, badge.message());
n.set(BADGE, b);
n.set(BADGE, json(badge));
}
return n;
}
......
......@@ -17,6 +17,7 @@
package org.onosproject.ui.topo;
import org.junit.Test;
import org.onosproject.ui.topo.NodeBadge.Status;
import static org.junit.Assert.assertEquals;
......@@ -25,92 +26,87 @@ import static org.junit.Assert.assertEquals;
*/
public class NodeBadgeTest {
private static final String SOME_MSG = "a msg";
private static final String WR_T = "wrong type";
private static final String MSG = "a msg";
private static final String TXT = "text";
private static final String GID = "glyph-id";
private static final int NUM = 42;
private static final String NUM_STR = Integer.toString(NUM);
private static final String WR_S = "wrong status";
private static final String WR_B = "wrong boolean";
private static final String WR_T = "wrong text";
private static final String WR_M = "wrong message";
private static final String WR_SF = "wrong string format";
private NodeBadge badge;
private String expStr(String t) {
return "{Badge {" + t + "} \"" + SOME_MSG + "\"}";
private void checkFields(NodeBadge b, Status s, boolean g,
String txt, String msg) {
assertEquals(WR_S, s, b.status());
assertEquals(WR_B, g, b.isGlyph());
assertEquals(WR_T, txt, b.text());
assertEquals(WR_M, msg, b.message());
}
private String expNumStr(String n) {
return "{Badge {n} \"" + n + "\"}";
@Test
public void badgeTypes() {
assertEquals(WR_SF, "i", Status.INFO.code());
assertEquals(WR_SF, "w", Status.WARN.code());
assertEquals(WR_SF, "e", Status.ERROR.code());
assertEquals("unexpected size", 3, Status.values().length);
}
@Test
public void info() {
badge = NodeBadge.info(SOME_MSG);
assertEquals(WR_T, NodeBadge.Type.INFO, badge.type());
assertEquals(WR_M, SOME_MSG, badge.message());
assertEquals(WR_SF, expStr("i"), badge.toString());
public void textOnly() {
badge = NodeBadge.text(TXT);
checkFields(badge, Status.INFO, false, TXT, null);
}
@Test
public void warn() {
badge = NodeBadge.warn(SOME_MSG);
assertEquals(WR_T, NodeBadge.Type.WARN, badge.type());
assertEquals(WR_M, SOME_MSG, badge.message());
assertEquals(WR_SF, expStr("w"), badge.toString());
public void glyphOnly() {
badge = NodeBadge.glyph(GID);
checkFields(badge, Status.INFO, true, GID, null);
}
@Test
public void error() {
badge = NodeBadge.error(SOME_MSG);
assertEquals(WR_T, NodeBadge.Type.ERROR, badge.type());
assertEquals(WR_M, SOME_MSG, badge.message());
assertEquals(WR_SF, expStr("e"), badge.toString());
public void numberOnly() {
badge = NodeBadge.number(NUM);
checkFields(badge, Status.INFO, false, NUM_STR, null);
}
@Test
public void checkMark() {
badge = NodeBadge.checkMark(SOME_MSG);
assertEquals(WR_T, NodeBadge.Type.CHECK_MARK, badge.type());
assertEquals(WR_M, SOME_MSG, badge.message());
assertEquals(WR_SF, expStr("/"), badge.toString());
public void textInfo() {
badge = NodeBadge.text(Status.INFO, TXT);
checkFields(badge, Status.INFO, false, TXT, null);
}
@Test
public void xMark() {
badge = NodeBadge.xMark(SOME_MSG);
assertEquals(WR_T, NodeBadge.Type.X_MARK, badge.type());
assertEquals(WR_M, SOME_MSG, badge.message());
assertEquals(WR_SF, expStr("X"), badge.toString());
public void glyphWarn() {
badge = NodeBadge.glyph(Status.WARN, GID);
checkFields(badge, Status.WARN, true, GID, null);
}
@Test
public void number0() {
badge = NodeBadge.number(0);
assertEquals(WR_T, NodeBadge.Type.NUMBER, badge.type());
assertEquals(WR_M, "0", badge.message());
assertEquals(WR_SF, expNumStr("0"), badge.toString());
public void numberError() {
badge = NodeBadge.number(Status.ERROR, NUM);
checkFields(badge, Status.ERROR, false, NUM_STR, null);
}
@Test
public void number5() {
badge = NodeBadge.number(5);
assertEquals(WR_T, NodeBadge.Type.NUMBER, badge.type());
assertEquals(WR_M, "5", badge.message());
assertEquals(WR_SF, expNumStr("5"), badge.toString());
public void textInfoMsg() {
badge = NodeBadge.text(Status.INFO, TXT, MSG);
checkFields(badge, Status.INFO, false, TXT, MSG);
}
@Test
public void number99() {
badge = NodeBadge.number(99);
assertEquals(WR_T, NodeBadge.Type.NUMBER, badge.type());
assertEquals(WR_M, "99", badge.message());
assertEquals(WR_SF, expNumStr("99"), badge.toString());
public void glyphWarnMsg() {
badge = NodeBadge.glyph(Status.WARN, GID, MSG);
checkFields(badge, Status.WARN, true, GID, MSG);
}
@Test
public void badgeTypes() {
assertEquals(WR_SF, "i", NodeBadge.Type.INFO.code());
assertEquals(WR_SF, "w", NodeBadge.Type.WARN.code());
assertEquals(WR_SF, "e", NodeBadge.Type.ERROR.code());
assertEquals(WR_SF, "/", NodeBadge.Type.CHECK_MARK.code());
assertEquals(WR_SF, "X", NodeBadge.Type.X_MARK.code());
assertEquals(WR_SF, "n", NodeBadge.Type.NUMBER.code());
public void numberErrorMsg() {
badge = NodeBadge.number(Status.ERROR, NUM, MSG);
checkFields(badge, Status.ERROR, false, NUM_STR, MSG);
}
}
......
......@@ -21,9 +21,11 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.Test;
import org.onosproject.ui.JsonUtils;
import org.onosproject.ui.topo.Highlights.Amount;
import org.onosproject.ui.topo.NodeBadge.Status;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
/**
* Unit tests for {@link TopoJson}.
......@@ -32,7 +34,8 @@ public class TopoJsonTest {
private static final String DEV1 = "device-1";
private static final String DEV2 = "device-2";
private static final String BADGE_MSG = "Hello there";
private static final String SOME_MSG = "Hello there";
private static final String GID = "glyph-ID";
private ObjectNode payload;
......@@ -78,15 +81,15 @@ public class TopoJsonTest {
public void badgedDevice() {
Highlights h = new Highlights();
DeviceHighlight dh = new DeviceHighlight(DEV1);
dh.setBadge(NodeBadge.info(BADGE_MSG));
dh.setBadge(NodeBadge.number(7));
h.add(dh);
dh = new DeviceHighlight(DEV2);
dh.setBadge(NodeBadge.number(7));
dh.setBadge(NodeBadge.glyph(Status.WARN, GID, SOME_MSG));
h.add(dh);
payload = TopoJson.json(h);
System.out.println(payload);
// System.out.println(payload);
// dig into the payload, and verify the badges are set on the devices
ArrayNode a = (ArrayNode) payload.get(TopoJson.DEVICES);
......@@ -96,15 +99,19 @@ public class TopoJsonTest {
ObjectNode b = (ObjectNode) d.get(TopoJson.BADGE);
assertNotNull("missing badge", b);
assertEquals("wrong type code", "i", b.get(TopoJson.TYPE).asText());
assertEquals("wrong message", BADGE_MSG, b.get(TopoJson.MSG).asText());
assertEquals("wrong status code", "i", b.get(TopoJson.STATUS).asText());
assertEquals("wrong text", "7", b.get(TopoJson.TXT).asText());
assertNull("glyph?", b.get(TopoJson.GID));
assertNull("msg?", b.get(TopoJson.MSG));
d = (ObjectNode) a.get(1);
assertEquals("wrong device id", DEV2, d.get(TopoJson.ID).asText());
b = (ObjectNode) d.get(TopoJson.BADGE);
assertNotNull("missing badge", b);
assertEquals("wrong type code", "n", b.get(TopoJson.TYPE).asText());
assertEquals("wrong message", "7", b.get(TopoJson.MSG).asText());
assertEquals("wrong status code", "w", b.get(TopoJson.STATUS).asText());
assertNull("text?", b.get(TopoJson.TXT));
assertEquals("wrong text", GID, b.get(TopoJson.GID).asText());
assertEquals("wrong message", SOME_MSG, b.get(TopoJson.MSG).asText());
}
}
......
......@@ -218,6 +218,24 @@
.attr('transform', sus.translate(dx, dy));
}
function updateDeviceBadge(d) {
// TODO: Fix this WIP
var node = d.el,
bsel;
if (d.badge) {
bsel = node.append('g')
.classed('badge', true)
.attr('transform', sus.translate(-14, -14));
bsel.append('circle')
.attr('r', 14);
bsel.append('text')
.attr('transform', sus.translate(-5, 3))
.text('42');
}
}
function updateHostLabel(d) {
var label = trimLabel(hostLabel(d));
d.el.select('text').text(label);
......@@ -241,6 +259,7 @@
var node = d.el;
node.classed('online', d.online);
updateDeviceLabel(d);
updateDeviceBadge(d);
api.posNode(d, true);
}
......
......@@ -860,6 +860,16 @@
});
}
function clearNodeDeco() {
node.selectAll('g.badge').remove();
}
function removeNodeBadges() {
network.nodes.forEach(function (d) {
d.badge = null;
});
}
function updateLinkLabelModel() {
// create the backing data for showing labels..
var data = [];
......@@ -923,6 +933,8 @@
function mkOverlayApi() {
return {
clearNodeDeco: clearNodeDeco,
removeNodeBadges: removeNodeBadges,
clearLinkTrafficStyle: clearLinkTrafficStyle,
removeLinkLabels: removeLinkLabels,
findLinkById: tms.findLinkById,
......
......@@ -294,7 +294,8 @@
unsupLink( key, [less] )
*/
// TODO: clear node highlighting
api.clearNodeDeco();
api.removeNodeBadges();
api.clearLinkTrafficStyle();
api.removeLinkLabels();
......@@ -319,8 +320,11 @@
});
data.devices.forEach(function (device) {
var ddata = api.findNodeById(device.id);
var ddata = api.findNodeById(device.id),
badgeData = device.badge || null;
if (ddata && !ddata.el.empty()) {
ddata.badge = badgeData;
if (!device.subdue) {
api.unsupNode(ddata.id, less);
}
......
{
"event": "showHighlights",
"payload": {
"devices": [],
"devices": [
{
"id": "of:0000000000000001",
"badge": {
"status": "e",
"gid": "xMark",
"msg": "x marks the spot"
}
},
{
"id": "of:0000000000000002",
"badge": {
"status": "w",
"txt": "7"
}
}
],
"hosts": [],
"links": [
{
......