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
Showing
5 changed files
with
310 additions
and
10 deletions
| ... | @@ -17,8 +17,11 @@ | ... | @@ -17,8 +17,11 @@ |
| 17 | 17 | ||
| 18 | package org.onosproject.ui.topo; | 18 | package org.onosproject.ui.topo; |
| 19 | 19 | ||
| 20 | +import com.google.common.collect.Sets; | ||
| 21 | + | ||
| 20 | import java.util.ArrayList; | 22 | import java.util.ArrayList; |
| 21 | import java.util.List; | 23 | import java.util.List; |
| 24 | +import java.util.Set; | ||
| 22 | 25 | ||
| 23 | /** | 26 | /** |
| 24 | * Models a panel displayed on the Topology View. | 27 | * Models a panel displayed on the Topology View. |
| ... | @@ -29,59 +32,176 @@ public class PropertyPanel { | ... | @@ -29,59 +32,176 @@ public class PropertyPanel { |
| 29 | private String typeId; | 32 | private String typeId; |
| 30 | private List<Prop> properties = new ArrayList<>(); | 33 | private List<Prop> properties = new ArrayList<>(); |
| 31 | 34 | ||
| 32 | - | 35 | + /** |
| 36 | + * Constructs a property panel model with the given title and | ||
| 37 | + * type identifier (icon to display). | ||
| 38 | + * | ||
| 39 | + * @param title title text | ||
| 40 | + * @param typeId type (icon) ID | ||
| 41 | + */ | ||
| 33 | public PropertyPanel(String title, String typeId) { | 42 | public PropertyPanel(String title, String typeId) { |
| 34 | this.title = title; | 43 | this.title = title; |
| 35 | this.typeId = typeId; | 44 | this.typeId = typeId; |
| 36 | } | 45 | } |
| 37 | 46 | ||
| 47 | + /** | ||
| 48 | + * Adds a property to the panel. | ||
| 49 | + * | ||
| 50 | + * @param p the property | ||
| 51 | + * @return self, for chaining | ||
| 52 | + */ | ||
| 38 | public PropertyPanel add(Prop p) { | 53 | public PropertyPanel add(Prop p) { |
| 39 | properties.add(p); | 54 | properties.add(p); |
| 40 | return this; | 55 | return this; |
| 41 | } | 56 | } |
| 42 | 57 | ||
| 58 | + /** | ||
| 59 | + * Returns the title text. | ||
| 60 | + * | ||
| 61 | + * @return title text | ||
| 62 | + */ | ||
| 43 | public String title() { | 63 | public String title() { |
| 44 | return title; | 64 | return title; |
| 45 | } | 65 | } |
| 46 | 66 | ||
| 67 | + /** | ||
| 68 | + * Returns the type identifier. | ||
| 69 | + * | ||
| 70 | + * @return type identifier | ||
| 71 | + */ | ||
| 47 | public String typeId() { | 72 | public String typeId() { |
| 48 | return typeId; | 73 | return typeId; |
| 49 | } | 74 | } |
| 50 | 75 | ||
| 76 | + /** | ||
| 77 | + * Returns the list of properties to be displayed. | ||
| 78 | + * | ||
| 79 | + * @return the property list | ||
| 80 | + */ | ||
| 51 | // TODO: consider protecting this? | 81 | // TODO: consider protecting this? |
| 52 | public List<Prop> properties() { | 82 | public List<Prop> properties() { |
| 53 | return properties; | 83 | return properties; |
| 54 | } | 84 | } |
| 55 | 85 | ||
| 86 | + // == MUTATORS | ||
| 87 | + | ||
| 88 | + /** | ||
| 89 | + * Sets the title text. | ||
| 90 | + * | ||
| 91 | + * @param title title text | ||
| 92 | + * @return self, for chaining | ||
| 93 | + */ | ||
| 56 | public PropertyPanel title(String title) { | 94 | public PropertyPanel title(String title) { |
| 57 | this.title = title; | 95 | this.title = title; |
| 58 | return this; | 96 | return this; |
| 59 | } | 97 | } |
| 60 | 98 | ||
| 61 | - // TODO: add other builder-like setters here | 99 | + /** |
| 100 | + * Sets the type identifier (icon ID). | ||
| 101 | + * | ||
| 102 | + * @param typeId type identifier | ||
| 103 | + * @return self, for chaining | ||
| 104 | + */ | ||
| 105 | + public PropertyPanel typeId(String typeId) { | ||
| 106 | + this.typeId = typeId; | ||
| 107 | + return this; | ||
| 108 | + } | ||
| 62 | 109 | ||
| 110 | + /** | ||
| 111 | + * Removes properties with the given keys from the list. | ||
| 112 | + * | ||
| 113 | + * @param keys keys of properties to remove | ||
| 114 | + * @return self, for chaining | ||
| 115 | + */ | ||
| 116 | + public PropertyPanel removeProps(String... keys) { | ||
| 117 | + Set<String> keysForRemoval = Sets.newHashSet(keys); | ||
| 118 | + List<Prop> propsToKeep = new ArrayList<>(); | ||
| 119 | + for (Prop p: properties) { | ||
| 120 | + if (!keysForRemoval.contains(p.key())) { | ||
| 121 | + propsToKeep.add(p); | ||
| 122 | + } | ||
| 123 | + } | ||
| 124 | + properties = propsToKeep; | ||
| 125 | + return this; | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + /** | ||
| 129 | + * Removes all currently defined properties. | ||
| 130 | + * | ||
| 131 | + * @return self, for chaining | ||
| 132 | + */ | ||
| 133 | + public PropertyPanel removeAllProps() { | ||
| 134 | + properties.clear(); | ||
| 135 | + return this; | ||
| 136 | + } | ||
| 63 | 137 | ||
| 64 | // ==================== | 138 | // ==================== |
| 65 | 139 | ||
| 140 | + /** | ||
| 141 | + * Simple data carrier for a property, composed of a key/value pair. | ||
| 142 | + */ | ||
| 66 | public static class Prop { | 143 | public static class Prop { |
| 67 | - public final String key; | 144 | + private final String key; |
| 68 | - public final String value; | 145 | + private final String value; |
| 69 | - | 146 | + |
| 147 | + /** | ||
| 148 | + * Constructs a property data value. | ||
| 149 | + * | ||
| 150 | + * @param key property key | ||
| 151 | + * @param value property value | ||
| 152 | + */ | ||
| 70 | public Prop(String key, String value) { | 153 | public Prop(String key, String value) { |
| 71 | this.key = key; | 154 | this.key = key; |
| 72 | this.value = value; | 155 | this.value = value; |
| 73 | } | 156 | } |
| 74 | 157 | ||
| 158 | + /** | ||
| 159 | + * Returns the property's key. | ||
| 160 | + * | ||
| 161 | + * @return the key | ||
| 162 | + */ | ||
| 75 | public String key() { | 163 | public String key() { |
| 76 | return key; | 164 | return key; |
| 77 | } | 165 | } |
| 78 | 166 | ||
| 167 | + /** | ||
| 168 | + * Returns the property's value. | ||
| 169 | + * | ||
| 170 | + * @return the value | ||
| 171 | + */ | ||
| 79 | public String value() { | 172 | public String value() { |
| 80 | return value; | 173 | return value; |
| 81 | } | 174 | } |
| 175 | + | ||
| 176 | + @Override | ||
| 177 | + public boolean equals(Object o) { | ||
| 178 | + if (this == o) { | ||
| 179 | + return true; | ||
| 180 | + } | ||
| 181 | + if (o == null || getClass() != o.getClass()) { | ||
| 182 | + return false; | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + Prop prop = (Prop) o; | ||
| 186 | + return key.equals(prop.key) && value.equals(prop.value); | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + @Override | ||
| 190 | + public int hashCode() { | ||
| 191 | + int result = key.hashCode(); | ||
| 192 | + result = 31 * result + value.hashCode(); | ||
| 193 | + return result; | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + @Override | ||
| 197 | + public String toString() { | ||
| 198 | + return "{" + key + " -> " + value + "}"; | ||
| 199 | + } | ||
| 82 | } | 200 | } |
| 83 | 201 | ||
| 84 | - // Auxiliary properties separator | 202 | + /** |
| 203 | + * Auxiliary class representing a separator property. | ||
| 204 | + */ | ||
| 85 | public static class Separator extends Prop { | 205 | public static class Separator extends Prop { |
| 86 | public Separator() { | 206 | public Separator() { |
| 87 | super("-", ""); | 207 | super("-", ""); | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + * | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | +package org.onosproject.ui.topo; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * Defines string constants used in the Topology View of the ONOS GUI. | ||
| 22 | + * <p> | ||
| 23 | + * See also: | ||
| 24 | + * <ul> | ||
| 25 | + * <li> https://wiki.onosproject.org/display/ONOS/UI+Service+-+GlyphService </li> | ||
| 26 | + * </ul> | ||
| 27 | + */ | ||
| 28 | +public final class TopoConstants { | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * Defines constants for standard glyph identifiers. | ||
| 32 | + */ | ||
| 33 | + public static final class Glyphs { | ||
| 34 | + public static final String UNKNOWN = "unknown"; | ||
| 35 | + public static final String BIRD = "bird"; | ||
| 36 | + public static final String NODE = "node"; | ||
| 37 | + public static final String SWITCH = "switch"; | ||
| 38 | + public static final String ROADM = "roadm"; | ||
| 39 | + public static final String ENDSTATION = "endstation"; | ||
| 40 | + public static final String ROUTER = "router"; | ||
| 41 | + public static final String BGP_SPEAKER = "bgpSpeaker"; | ||
| 42 | + public static final String CHAIN = "chain"; | ||
| 43 | + public static final String CROWN = "crown"; | ||
| 44 | + public static final String TOPO = "topo"; | ||
| 45 | + public static final String REFRESH = "refresh"; | ||
| 46 | + public static final String GARBAGE = "garbage"; | ||
| 47 | + public static final String FLOW_TABLE = "flowTable"; | ||
| 48 | + public static final String PORT_TABLE = "portTable"; | ||
| 49 | + public static final String GROUP_TABLE = "groupTable"; | ||
| 50 | + public static final String SUMMARY = "summary"; | ||
| 51 | + public static final String DETAILS = "details"; | ||
| 52 | + public static final String PORTS = "ports"; | ||
| 53 | + public static final String MAP = "map"; | ||
| 54 | + public static final String CYCLE_LABELS = "cycleLabels"; | ||
| 55 | + public static final String OBLIQUE = "oblique"; | ||
| 56 | + public static final String FILTERS = "filters"; | ||
| 57 | + public static final String RESET_ZOOM = "resetZoom"; | ||
| 58 | + public static final String RELATED_INTENTS = "relatedIntents"; | ||
| 59 | + public static final String NEXT_INTENT = "nextIntent"; | ||
| 60 | + public static final String PREV_INTENT = "prevIntent"; | ||
| 61 | + public static final String INTENT_TRAFFIC = "intentTraffic"; | ||
| 62 | + public static final String ALL_TRAFFIC = "allTraffic"; | ||
| 63 | + public static final String FLOWS = "flows"; | ||
| 64 | + public static final String EQ_MASTER = "eqMaster"; | ||
| 65 | + public static final String UI_ATTACHED = "uiAttached"; | ||
| 66 | + public static final String CHECK_MARK = "checkMark"; | ||
| 67 | + public static final String X_MARK = "xMark"; | ||
| 68 | + public static final String TRIANGLE_UP = "triangleUp"; | ||
| 69 | + public static final String TRIANGLE_DOWN = "triangleDown"; | ||
| 70 | + public static final String PLUS = "plus"; | ||
| 71 | + public static final String MINUS = "minus"; | ||
| 72 | + public static final String PLAY = "play"; | ||
| 73 | + public static final String STOP = "stop"; | ||
| 74 | + public static final String CLOUD = "cloud"; | ||
| 75 | + } | ||
| 76 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + * | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | +package org.onosproject.ui.topo; | ||
| 19 | + | ||
| 20 | +import org.junit.Test; | ||
| 21 | +import org.onosproject.ui.topo.PropertyPanel.Prop; | ||
| 22 | + | ||
| 23 | +import java.util.Iterator; | ||
| 24 | + | ||
| 25 | +import static org.junit.Assert.assertEquals; | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | + * Unit tests for {@link PropertyPanel}. | ||
| 29 | + */ | ||
| 30 | +public class PropertyPanelTest { | ||
| 31 | + | ||
| 32 | + private static final String TITLE_ORIG = "Original Title"; | ||
| 33 | + private static final String TYPE_ORIG = "Original type ID"; | ||
| 34 | + private static final String TITLE_NEW = "New Title"; | ||
| 35 | + private static final String TYPE_NEW = "New type"; | ||
| 36 | + | ||
| 37 | + private static final Prop PROP_A = new Prop("A", "Hay"); | ||
| 38 | + private static final Prop PROP_B = new Prop("B", "Bee"); | ||
| 39 | + private static final Prop PROP_C = new Prop("C", "Sea"); | ||
| 40 | + private static final Prop PROP_Z = new Prop("Z", "Zed"); | ||
| 41 | + | ||
| 42 | + private PropertyPanel pp; | ||
| 43 | + | ||
| 44 | + | ||
| 45 | + @Test | ||
| 46 | + public void basic() { | ||
| 47 | + pp = new PropertyPanel(TITLE_ORIG, TYPE_ORIG); | ||
| 48 | + assertEquals("wrong title", TITLE_ORIG, pp.title()); | ||
| 49 | + assertEquals("wrong type", TYPE_ORIG, pp.typeId()); | ||
| 50 | + assertEquals("unexpected props", 0, pp.properties().size()); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + @Test | ||
| 54 | + public void changeTitle() { | ||
| 55 | + basic(); | ||
| 56 | + pp.title(TITLE_NEW); | ||
| 57 | + assertEquals("wrong title", TITLE_NEW, pp.title()); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + @Test | ||
| 61 | + public void changeType() { | ||
| 62 | + basic(); | ||
| 63 | + pp.typeId(TYPE_NEW); | ||
| 64 | + assertEquals("wrong type", TYPE_NEW, pp.typeId()); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + private void validateProps(Prop... props) { | ||
| 68 | + Iterator<Prop> iter = pp.properties().iterator(); | ||
| 69 | + for (Prop p: props) { | ||
| 70 | + Prop ppProp = iter.next(); | ||
| 71 | + assertEquals("Bad prop sequence", p, ppProp); | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + @Test | ||
| 76 | + public void props() { | ||
| 77 | + basic(); | ||
| 78 | + pp.add(PROP_A).add(PROP_B).add(PROP_C); | ||
| 79 | + assertEquals("bad props", 3, pp.properties().size()); | ||
| 80 | + validateProps(PROP_A, PROP_B, PROP_C); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + @Test | ||
| 84 | + public void removeAllProps() { | ||
| 85 | + props(); | ||
| 86 | + assertEquals("wrong props", 3, pp.properties().size()); | ||
| 87 | + pp.removeAllProps(); | ||
| 88 | + assertEquals("unexpected props", 0, pp.properties().size()); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + @Test | ||
| 92 | + public void adjustProps() { | ||
| 93 | + props(); | ||
| 94 | + pp.removeProps("B", "A"); | ||
| 95 | + pp.add(PROP_Z); | ||
| 96 | + validateProps(PROP_C, PROP_Z); | ||
| 97 | + } | ||
| 98 | +} |
| ... | @@ -28,6 +28,7 @@ import org.onosproject.ui.UiExtensionService; | ... | @@ -28,6 +28,7 @@ import org.onosproject.ui.UiExtensionService; |
| 28 | import org.onosproject.ui.UiMessageHandlerFactory; | 28 | import org.onosproject.ui.UiMessageHandlerFactory; |
| 29 | import org.onosproject.ui.UiMessageHandler; | 29 | import org.onosproject.ui.UiMessageHandler; |
| 30 | import org.onosproject.ui.UiTopoOverlayFactory; | 30 | import org.onosproject.ui.UiTopoOverlayFactory; |
| 31 | +import org.onosproject.ui.topo.TopoConstants; | ||
| 31 | import org.slf4j.Logger; | 32 | import org.slf4j.Logger; |
| 32 | import org.slf4j.LoggerFactory; | 33 | import org.slf4j.LoggerFactory; |
| 33 | 34 | ||
| ... | @@ -225,7 +226,8 @@ public class UiWebSocket | ... | @@ -225,7 +226,8 @@ public class UiWebSocket |
| 225 | ObjectNode instance = mapper.createObjectNode() | 226 | ObjectNode instance = mapper.createObjectNode() |
| 226 | .put("id", node.id().toString()) | 227 | .put("id", node.id().toString()) |
| 227 | .put("ip", node.ip().toString()) | 228 | .put("ip", node.ip().toString()) |
| 228 | - .put("uiAttached", node.equals(service.getLocalNode())); | 229 | + .put(TopoConstants.Glyphs.UI_ATTACHED, |
| 230 | + node.equals(service.getLocalNode())); | ||
| 229 | instances.add(instance); | 231 | instances.add(instance); |
| 230 | } | 232 | } |
| 231 | 233 | ... | ... |
| ... | @@ -203,10 +203,14 @@ | ... | @@ -203,10 +203,14 @@ |
| 203 | .append('svg'), | 203 | .append('svg'), |
| 204 | title = summary.appendHeader('h2'), | 204 | title = summary.appendHeader('h2'), |
| 205 | table = summary.appendBody('table'), | 205 | table = summary.appendBody('table'), |
| 206 | - tbody = table.append('tbody'); | 206 | + tbody = table.append('tbody'), |
| 207 | + glyphId = data.type || 'node'; | ||
| 207 | 208 | ||
| 208 | - gs.addGlyph(svg, 'node', 40); | 209 | + gs.addGlyph(svg, glyphId, 40); |
| 209 | - gs.addGlyph(svg, 'bird', 24, true, [8,12]); | 210 | + |
| 211 | + if (glyphId === 'node') { | ||
| 212 | + gs.addGlyph(svg, 'bird', 24, true, [8,12]); | ||
| 213 | + } | ||
| 210 | 214 | ||
| 211 | title.text(data.title); | 215 | title.text(data.title); |
| 212 | listProps(tbody, data); | 216 | listProps(tbody, data); | ... | ... |
-
Please register or login to post a comment