Simon Hunt

ONOS-1479 - GUI Topology Overlay Work - (WIP)

- Augmented PropertyPanel class for more manipulation, and added unit tests.
- Added TopoConstants.
- Fixed bug in topoPanel.js that was not using the typeID from the event data.

Change-Id: I7ad759217f2d32642a09be2a9199cf1fcb45ac6e
......@@ -17,8 +17,11 @@
package org.onosproject.ui.topo;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Models a panel displayed on the Topology View.
......@@ -29,59 +32,176 @@ public class PropertyPanel {
private String typeId;
private List<Prop> properties = new ArrayList<>();
/**
* Constructs a property panel model with the given title and
* type identifier (icon to display).
*
* @param title title text
* @param typeId type (icon) ID
*/
public PropertyPanel(String title, String typeId) {
this.title = title;
this.typeId = typeId;
}
/**
* Adds a property to the panel.
*
* @param p the property
* @return self, for chaining
*/
public PropertyPanel add(Prop p) {
properties.add(p);
return this;
}
/**
* Returns the title text.
*
* @return title text
*/
public String title() {
return title;
}
/**
* Returns the type identifier.
*
* @return type identifier
*/
public String typeId() {
return typeId;
}
/**
* Returns the list of properties to be displayed.
*
* @return the property list
*/
// TODO: consider protecting this?
public List<Prop> properties() {
return properties;
}
// == MUTATORS
/**
* Sets the title text.
*
* @param title title text
* @return self, for chaining
*/
public PropertyPanel title(String title) {
this.title = title;
return this;
}
// TODO: add other builder-like setters here
/**
* Sets the type identifier (icon ID).
*
* @param typeId type identifier
* @return self, for chaining
*/
public PropertyPanel typeId(String typeId) {
this.typeId = typeId;
return this;
}
/**
* Removes properties with the given keys from the list.
*
* @param keys keys of properties to remove
* @return self, for chaining
*/
public PropertyPanel removeProps(String... keys) {
Set<String> keysForRemoval = Sets.newHashSet(keys);
List<Prop> propsToKeep = new ArrayList<>();
for (Prop p: properties) {
if (!keysForRemoval.contains(p.key())) {
propsToKeep.add(p);
}
}
properties = propsToKeep;
return this;
}
/**
* Removes all currently defined properties.
*
* @return self, for chaining
*/
public PropertyPanel removeAllProps() {
properties.clear();
return this;
}
// ====================
/**
* Simple data carrier for a property, composed of a key/value pair.
*/
public static class Prop {
public final String key;
public final String value;
private final String key;
private final String value;
/**
* Constructs a property data value.
*
* @param key property key
* @param value property value
*/
public Prop(String key, String value) {
this.key = key;
this.value = value;
}
/**
* Returns the property's key.
*
* @return the key
*/
public String key() {
return key;
}
/**
* Returns the property's value.
*
* @return the value
*/
public String value() {
return value;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Prop prop = (Prop) o;
return key.equals(prop.key) && value.equals(prop.value);
}
@Override
public int hashCode() {
int result = key.hashCode();
result = 31 * result + value.hashCode();
return result;
}
@Override
public String toString() {
return "{" + key + " -> " + value + "}";
}
}
// Auxiliary properties separator
/**
* Auxiliary class representing a separator property.
*/
public static class Separator extends Prop {
public Separator() {
super("-", "");
......
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed 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.
*
*/
package org.onosproject.ui.topo;
/**
* Defines string constants used in the Topology View of the ONOS GUI.
* <p>
* See also:
* <ul>
* <li> https://wiki.onosproject.org/display/ONOS/UI+Service+-+GlyphService </li>
* </ul>
*/
public final class TopoConstants {
/**
* Defines constants for standard glyph identifiers.
*/
public static final class Glyphs {
public static final String UNKNOWN = "unknown";
public static final String BIRD = "bird";
public static final String NODE = "node";
public static final String SWITCH = "switch";
public static final String ROADM = "roadm";
public static final String ENDSTATION = "endstation";
public static final String ROUTER = "router";
public static final String BGP_SPEAKER = "bgpSpeaker";
public static final String CHAIN = "chain";
public static final String CROWN = "crown";
public static final String TOPO = "topo";
public static final String REFRESH = "refresh";
public static final String GARBAGE = "garbage";
public static final String FLOW_TABLE = "flowTable";
public static final String PORT_TABLE = "portTable";
public static final String GROUP_TABLE = "groupTable";
public static final String SUMMARY = "summary";
public static final String DETAILS = "details";
public static final String PORTS = "ports";
public static final String MAP = "map";
public static final String CYCLE_LABELS = "cycleLabels";
public static final String OBLIQUE = "oblique";
public static final String FILTERS = "filters";
public static final String RESET_ZOOM = "resetZoom";
public static final String RELATED_INTENTS = "relatedIntents";
public static final String NEXT_INTENT = "nextIntent";
public static final String PREV_INTENT = "prevIntent";
public static final String INTENT_TRAFFIC = "intentTraffic";
public static final String ALL_TRAFFIC = "allTraffic";
public static final String FLOWS = "flows";
public static final String EQ_MASTER = "eqMaster";
public static final String UI_ATTACHED = "uiAttached";
public static final String CHECK_MARK = "checkMark";
public static final String X_MARK = "xMark";
public static final String TRIANGLE_UP = "triangleUp";
public static final String TRIANGLE_DOWN = "triangleDown";
public static final String PLUS = "plus";
public static final String MINUS = "minus";
public static final String PLAY = "play";
public static final String STOP = "stop";
public static final String CLOUD = "cloud";
}
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed 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.
*
*/
package org.onosproject.ui.topo;
import org.junit.Test;
import org.onosproject.ui.topo.PropertyPanel.Prop;
import java.util.Iterator;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for {@link PropertyPanel}.
*/
public class PropertyPanelTest {
private static final String TITLE_ORIG = "Original Title";
private static final String TYPE_ORIG = "Original type ID";
private static final String TITLE_NEW = "New Title";
private static final String TYPE_NEW = "New type";
private static final Prop PROP_A = new Prop("A", "Hay");
private static final Prop PROP_B = new Prop("B", "Bee");
private static final Prop PROP_C = new Prop("C", "Sea");
private static final Prop PROP_Z = new Prop("Z", "Zed");
private PropertyPanel pp;
@Test
public void basic() {
pp = new PropertyPanel(TITLE_ORIG, TYPE_ORIG);
assertEquals("wrong title", TITLE_ORIG, pp.title());
assertEquals("wrong type", TYPE_ORIG, pp.typeId());
assertEquals("unexpected props", 0, pp.properties().size());
}
@Test
public void changeTitle() {
basic();
pp.title(TITLE_NEW);
assertEquals("wrong title", TITLE_NEW, pp.title());
}
@Test
public void changeType() {
basic();
pp.typeId(TYPE_NEW);
assertEquals("wrong type", TYPE_NEW, pp.typeId());
}
private void validateProps(Prop... props) {
Iterator<Prop> iter = pp.properties().iterator();
for (Prop p: props) {
Prop ppProp = iter.next();
assertEquals("Bad prop sequence", p, ppProp);
}
}
@Test
public void props() {
basic();
pp.add(PROP_A).add(PROP_B).add(PROP_C);
assertEquals("bad props", 3, pp.properties().size());
validateProps(PROP_A, PROP_B, PROP_C);
}
@Test
public void removeAllProps() {
props();
assertEquals("wrong props", 3, pp.properties().size());
pp.removeAllProps();
assertEquals("unexpected props", 0, pp.properties().size());
}
@Test
public void adjustProps() {
props();
pp.removeProps("B", "A");
pp.add(PROP_Z);
validateProps(PROP_C, PROP_Z);
}
}
......@@ -28,6 +28,7 @@ import org.onosproject.ui.UiExtensionService;
import org.onosproject.ui.UiMessageHandlerFactory;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.UiTopoOverlayFactory;
import org.onosproject.ui.topo.TopoConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -225,7 +226,8 @@ public class UiWebSocket
ObjectNode instance = mapper.createObjectNode()
.put("id", node.id().toString())
.put("ip", node.ip().toString())
.put("uiAttached", node.equals(service.getLocalNode()));
.put(TopoConstants.Glyphs.UI_ATTACHED,
node.equals(service.getLocalNode()));
instances.add(instance);
}
......
......@@ -203,10 +203,14 @@
.append('svg'),
title = summary.appendHeader('h2'),
table = summary.appendBody('table'),
tbody = table.append('tbody');
tbody = table.append('tbody'),
glyphId = data.type || 'node';
gs.addGlyph(svg, 'node', 40);
gs.addGlyph(svg, 'bird', 24, true, [8,12]);
gs.addGlyph(svg, glyphId, 40);
if (glyphId === 'node') {
gs.addGlyph(svg, 'bird', 24, true, [8,12]);
}
title.text(data.title);
listProps(tbody, data);
......