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 @@ ...@@ -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);
......