ONOS-1479 -- GUI - augmenting topology view for extensibility:
- Implemented server-side topo panel button descriptors, with overlay ability to remove core buttons and add custom buttons. Change-Id: Id9ecc4c5e2d2db942232d2156ecf3bc858c0c61f
Showing
9 changed files
with
324 additions
and
112 deletions
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 | + * Designates a descriptor for a button on the topology view panels. | ||
22 | + */ | ||
23 | +public class ButtonDescriptor { | ||
24 | + | ||
25 | + private final String id; | ||
26 | + private final String glyphId; | ||
27 | + private final String tooltip; | ||
28 | + | ||
29 | + /** | ||
30 | + * Creates a button descriptor with the given identifier, glyph ID, and | ||
31 | + * tooltip text. To reference a custom glyph defined in the overlay itself, | ||
32 | + * prefix its ID with an asterisk, (e.g. {@code "*myGlyph"}). Alternatively, | ||
33 | + * use one of the {@link TopoConstants.Glyphs predefined constant}. | ||
34 | + * | ||
35 | + * @param id identifier for the button | ||
36 | + * @param glyphId identifier for the glyph | ||
37 | + * @param tooltip tooltip text | ||
38 | + */ | ||
39 | + public ButtonDescriptor(String id, String glyphId, String tooltip) { | ||
40 | + this.id = id; | ||
41 | + this.glyphId = glyphId; | ||
42 | + this.tooltip = tooltip; | ||
43 | + } | ||
44 | + | ||
45 | + /** | ||
46 | + * Returns the identifier for this button. | ||
47 | + * | ||
48 | + * @return identifier | ||
49 | + */ | ||
50 | + public String id() { | ||
51 | + return id; | ||
52 | + } | ||
53 | + | ||
54 | + /** | ||
55 | + * Returns the glyph identifier for this button. | ||
56 | + * | ||
57 | + * @return glyph identifier | ||
58 | + */ | ||
59 | + public String glyphId() { | ||
60 | + return glyphId; | ||
61 | + } | ||
62 | + | ||
63 | + /** | ||
64 | + * Returns the tooltip text for this button. | ||
65 | + * | ||
66 | + * @return tooltip text | ||
67 | + */ | ||
68 | + public String tooltip() { | ||
69 | + return tooltip; | ||
70 | + } | ||
71 | + | ||
72 | + @Override | ||
73 | + public boolean equals(Object o) { | ||
74 | + if (this == o) { | ||
75 | + return true; | ||
76 | + } | ||
77 | + if (o == null || getClass() != o.getClass()) { | ||
78 | + return false; | ||
79 | + } | ||
80 | + | ||
81 | + ButtonDescriptor that = (ButtonDescriptor) o; | ||
82 | + return id.equals(that.id); | ||
83 | + | ||
84 | + } | ||
85 | + | ||
86 | + @Override | ||
87 | + public int hashCode() { | ||
88 | + return id.hashCode(); | ||
89 | + } | ||
90 | +} |
... | @@ -35,7 +35,7 @@ public class PropertyPanel { | ... | @@ -35,7 +35,7 @@ public class PropertyPanel { |
35 | private String typeId; | 35 | private String typeId; |
36 | private String id; | 36 | private String id; |
37 | private List<Prop> properties = new ArrayList<>(); | 37 | private List<Prop> properties = new ArrayList<>(); |
38 | - private List<Button> buttons = new ArrayList<>(); | 38 | + private List<ButtonDescriptor> buttons = new ArrayList<>(); |
39 | 39 | ||
40 | /** | 40 | /** |
41 | * Constructs a property panel model with the given title and | 41 | * Constructs a property panel model with the given title and |
... | @@ -181,7 +181,7 @@ public class PropertyPanel { | ... | @@ -181,7 +181,7 @@ public class PropertyPanel { |
181 | * @return the button list | 181 | * @return the button list |
182 | */ | 182 | */ |
183 | // TODO: consider protecting this? | 183 | // TODO: consider protecting this? |
184 | - public List<Button> buttons() { | 184 | + public List<ButtonDescriptor> buttons() { |
185 | return buttons; | 185 | return buttons; |
186 | } | 186 | } |
187 | 187 | ||
... | @@ -216,14 +216,14 @@ public class PropertyPanel { | ... | @@ -216,14 +216,14 @@ public class PropertyPanel { |
216 | * @return self, for chaining | 216 | * @return self, for chaining |
217 | */ | 217 | */ |
218 | public PropertyPanel removeProps(String... keys) { | 218 | public PropertyPanel removeProps(String... keys) { |
219 | - Set<String> keysForRemoval = Sets.newHashSet(keys); | 219 | + Set<String> forRemoval = Sets.newHashSet(keys); |
220 | - List<Prop> propsToKeep = new ArrayList<>(); | 220 | + List<Prop> toKeep = new ArrayList<>(); |
221 | for (Prop p: properties) { | 221 | for (Prop p: properties) { |
222 | - if (!keysForRemoval.contains(p.key())) { | 222 | + if (!forRemoval.contains(p.key())) { |
223 | - propsToKeep.add(p); | 223 | + toKeep.add(p); |
224 | } | 224 | } |
225 | } | 225 | } |
226 | - properties = propsToKeep; | 226 | + properties = toKeep; |
227 | return this; | 227 | return this; |
228 | } | 228 | } |
229 | 229 | ||
... | @@ -238,13 +238,41 @@ public class PropertyPanel { | ... | @@ -238,13 +238,41 @@ public class PropertyPanel { |
238 | } | 238 | } |
239 | 239 | ||
240 | /** | 240 | /** |
241 | - * Adds a button descriptor with the given identifier, to the panel data. | 241 | + * Adds the given button descriptor to the panel data. |
242 | * | 242 | * |
243 | - * @param id button identifier | 243 | + * @param button button descriptor |
244 | * @return self, for chaining | 244 | * @return self, for chaining |
245 | */ | 245 | */ |
246 | - public PropertyPanel addButton(String id) { | 246 | + public PropertyPanel addButton(ButtonDescriptor button) { |
247 | - buttons.add(new Button(id)); | 247 | + buttons.add(button); |
248 | + return this; | ||
249 | + } | ||
250 | + | ||
251 | + /** | ||
252 | + * Removes buttons with the given descriptors from the list. | ||
253 | + * | ||
254 | + * @param descriptors descriptors to remove | ||
255 | + * @return self, for chaining | ||
256 | + */ | ||
257 | + public PropertyPanel removeButtons(ButtonDescriptor... descriptors) { | ||
258 | + Set<ButtonDescriptor> forRemoval = Sets.newHashSet(descriptors); | ||
259 | + List<ButtonDescriptor> toKeep = new ArrayList<>(); | ||
260 | + for (ButtonDescriptor bd: buttons) { | ||
261 | + if (!forRemoval.contains(bd)) { | ||
262 | + toKeep.add(bd); | ||
263 | + } | ||
264 | + } | ||
265 | + buttons = toKeep; | ||
266 | + return this; | ||
267 | + } | ||
268 | + | ||
269 | + /** | ||
270 | + * Removes all currently defined buttons. | ||
271 | + * | ||
272 | + * @return self, for chaining | ||
273 | + */ | ||
274 | + public PropertyPanel removeAllButtons() { | ||
275 | + buttons.clear(); | ||
248 | return this; | 276 | return this; |
249 | } | 277 | } |
250 | 278 | ||
... | @@ -322,29 +350,4 @@ public class PropertyPanel { | ... | @@ -322,29 +350,4 @@ public class PropertyPanel { |
322 | } | 350 | } |
323 | } | 351 | } |
324 | 352 | ||
325 | - /** | ||
326 | - * Button descriptor. Note that these work in conjunction with | ||
327 | - * "buttons" defined in the JavaScript code for the overlay. | ||
328 | - */ | ||
329 | - public static class Button { | ||
330 | - private final String id; | ||
331 | - | ||
332 | - /** | ||
333 | - * Constructs a button descriptor with the given identifier. | ||
334 | - * | ||
335 | - * @param id button identifier | ||
336 | - */ | ||
337 | - public Button(String id) { | ||
338 | - this.id = id; | ||
339 | - } | ||
340 | - | ||
341 | - /** | ||
342 | - * Returns the identifier for this button. | ||
343 | - * | ||
344 | - * @return button identifier | ||
345 | - */ | ||
346 | - public String id() { | ||
347 | - return id; | ||
348 | - } | ||
349 | - } | ||
350 | } | 353 | } | ... | ... |
... | @@ -79,6 +79,8 @@ public final class TopoConstants { | ... | @@ -79,6 +79,8 @@ public final class TopoConstants { |
79 | * details panels. | 79 | * details panels. |
80 | */ | 80 | */ |
81 | public static final class Properties { | 81 | public static final class Properties { |
82 | + public static final String SEPARATOR = "-"; | ||
83 | + | ||
82 | // summary panel | 84 | // summary panel |
83 | public static final String DEVICES = "Devices"; | 85 | public static final String DEVICES = "Devices"; |
84 | public static final String LINKS = "Links"; | 86 | public static final String LINKS = "Links"; |
... | @@ -106,4 +108,30 @@ public final class TopoConstants { | ... | @@ -106,4 +108,30 @@ public final class TopoConstants { |
106 | public static final String VLAN = "VLAN"; | 108 | public static final String VLAN = "VLAN"; |
107 | } | 109 | } |
108 | 110 | ||
111 | + private static final class CoreButton extends ButtonDescriptor { | ||
112 | + private CoreButton(String tag, String glyphId, boolean extra) { | ||
113 | + super("show" + tag + "View", | ||
114 | + glyphId, | ||
115 | + "Show " + tag + " View" + (extra ? " for this Device" : "")); | ||
116 | + } | ||
117 | + } | ||
118 | + | ||
119 | + /** | ||
120 | + * Defines constants for core buttons that appear on the topology | ||
121 | + * details panel. | ||
122 | + */ | ||
123 | + public static final class CoreButtons { | ||
124 | + public static final ButtonDescriptor SHOW_DEVICE_VIEW = | ||
125 | + new CoreButton("Device", Glyphs.SWITCH, false); | ||
126 | + | ||
127 | + public static final ButtonDescriptor SHOW_FLOW_VIEW = | ||
128 | + new CoreButton("Flow", Glyphs.FLOW_TABLE, true); | ||
129 | + | ||
130 | + public static final ButtonDescriptor SHOW_PORT_VIEW = | ||
131 | + new CoreButton("Port", Glyphs.PORT_TABLE, true); | ||
132 | + | ||
133 | + public static final ButtonDescriptor SHOW_GROUP_VIEW = | ||
134 | + new CoreButton("Group", Glyphs.GROUP_TABLE, true); | ||
135 | + } | ||
136 | + | ||
109 | } | 137 | } | ... | ... |
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 | + | ||
22 | +import static org.junit.Assert.assertEquals; | ||
23 | + | ||
24 | +/** | ||
25 | + * Unit tests for {@link ButtonDescriptor}. | ||
26 | + */ | ||
27 | +public class ButtonDescriptorTest { | ||
28 | + | ||
29 | + private static final String ID = "my-id"; | ||
30 | + private static final String GID = "my-glyphId"; | ||
31 | + private static final String TT = "my-tewltyp"; | ||
32 | + | ||
33 | + private ButtonDescriptor bd; | ||
34 | + | ||
35 | + | ||
36 | + @Test | ||
37 | + public void basic() { | ||
38 | + bd = new ButtonDescriptor(ID, GID, TT); | ||
39 | + | ||
40 | + assertEquals("bad id", ID, bd.id()); | ||
41 | + assertEquals("bad gid", GID, bd.glyphId()); | ||
42 | + assertEquals("bad tt", TT, bd.tooltip()); | ||
43 | + } | ||
44 | + | ||
45 | +} |
... | @@ -25,9 +25,7 @@ import java.util.HashMap; | ... | @@ -25,9 +25,7 @@ import java.util.HashMap; |
25 | import java.util.Iterator; | 25 | import java.util.Iterator; |
26 | import java.util.Map; | 26 | import java.util.Map; |
27 | 27 | ||
28 | -import static org.junit.Assert.assertEquals; | 28 | +import static org.junit.Assert.*; |
29 | -import static org.junit.Assert.assertNull; | ||
30 | -import static org.junit.Assert.fail; | ||
31 | 29 | ||
32 | /** | 30 | /** |
33 | * Unit tests for {@link PropertyPanel}. | 31 | * Unit tests for {@link PropertyPanel}. |
... | @@ -43,11 +41,20 @@ public class PropertyPanelTest { | ... | @@ -43,11 +41,20 @@ public class PropertyPanelTest { |
43 | private static final String KEY_A = "A"; | 41 | private static final String KEY_A = "A"; |
44 | private static final String KEY_B = "B"; | 42 | private static final String KEY_B = "B"; |
45 | private static final String KEY_C = "C"; | 43 | private static final String KEY_C = "C"; |
44 | + private static final String SEP = "-"; | ||
46 | private static final String KEY_Z = "Z"; | 45 | private static final String KEY_Z = "Z"; |
47 | private static final String VALUE_A = "Hay"; | 46 | private static final String VALUE_A = "Hay"; |
48 | private static final String VALUE_B = "Bee"; | 47 | private static final String VALUE_B = "Bee"; |
49 | private static final String VALUE_C = "Sea"; | 48 | private static final String VALUE_C = "Sea"; |
50 | private static final String VALUE_Z = "Zed"; | 49 | private static final String VALUE_Z = "Zed"; |
50 | + private static final String GID_A = "gid-A"; | ||
51 | + private static final String GID_B = "gid-B"; | ||
52 | + private static final String GID_C = "gid-C"; | ||
53 | + private static final String GID_Z = "gid-Z"; | ||
54 | + private static final String TT_A = "toolTip-A"; | ||
55 | + private static final String TT_B = "toolTip-B"; | ||
56 | + private static final String TT_C = "toolTip-C"; | ||
57 | + private static final String TT_Z = "toolTip-Z"; | ||
51 | 58 | ||
52 | private static final Map<String, Prop> PROP_MAP = new HashMap<>(); | 59 | private static final Map<String, Prop> PROP_MAP = new HashMap<>(); |
53 | 60 | ||
... | @@ -73,6 +80,7 @@ public class PropertyPanelTest { | ... | @@ -73,6 +80,7 @@ public class PropertyPanelTest { |
73 | PROP_MAP.put(KEY_B, new Prop(KEY_B, VALUE_B)); | 80 | PROP_MAP.put(KEY_B, new Prop(KEY_B, VALUE_B)); |
74 | PROP_MAP.put(KEY_C, new Prop(KEY_C, VALUE_C)); | 81 | PROP_MAP.put(KEY_C, new Prop(KEY_C, VALUE_C)); |
75 | PROP_MAP.put(KEY_Z, new Prop(KEY_Z, VALUE_Z)); | 82 | PROP_MAP.put(KEY_Z, new Prop(KEY_Z, VALUE_Z)); |
83 | + PROP_MAP.put(SEP, new PropertyPanel.Separator()); | ||
76 | } | 84 | } |
77 | 85 | ||
78 | @Test | 86 | @Test |
... | @@ -82,6 +90,7 @@ public class PropertyPanelTest { | ... | @@ -82,6 +90,7 @@ public class PropertyPanelTest { |
82 | assertEquals("wrong type", TYPE_ORIG, pp.typeId()); | 90 | assertEquals("wrong type", TYPE_ORIG, pp.typeId()); |
83 | assertNull("id?", pp.id()); | 91 | assertNull("id?", pp.id()); |
84 | assertEquals("unexpected props", 0, pp.properties().size()); | 92 | assertEquals("unexpected props", 0, pp.properties().size()); |
93 | + assertEquals("unexpected buttons", 0, pp.buttons().size()); | ||
85 | } | 94 | } |
86 | 95 | ||
87 | @Test | 96 | @Test |
... | @@ -141,6 +150,16 @@ public class PropertyPanelTest { | ... | @@ -141,6 +150,16 @@ public class PropertyPanelTest { |
141 | } | 150 | } |
142 | 151 | ||
143 | @Test | 152 | @Test |
153 | + public void separator() { | ||
154 | + props(); | ||
155 | + pp.addSeparator() | ||
156 | + .addProp(KEY_Z, VALUE_Z); | ||
157 | + | ||
158 | + assertEquals("bad props", 5, pp.properties().size()); | ||
159 | + validateProps(KEY_A, KEY_B, KEY_C, SEP, KEY_Z); | ||
160 | + } | ||
161 | + | ||
162 | + @Test | ||
144 | public void removeAllProps() { | 163 | public void removeAllProps() { |
145 | props(); | 164 | props(); |
146 | assertEquals("wrong props", 3, pp.properties().size()); | 165 | assertEquals("wrong props", 3, pp.properties().size()); |
... | @@ -192,4 +211,40 @@ public class PropertyPanelTest { | ... | @@ -192,4 +211,40 @@ public class PropertyPanelTest { |
192 | validateProp(KEY_B, ">byyy<"); | 211 | validateProp(KEY_B, ">byyy<"); |
193 | } | 212 | } |
194 | 213 | ||
214 | + private static final ButtonDescriptor BD_A = | ||
215 | + new ButtonDescriptor(KEY_A, GID_A, TT_A); | ||
216 | + private static final ButtonDescriptor BD_B = | ||
217 | + new ButtonDescriptor(KEY_B, GID_B, TT_B); | ||
218 | + private static final ButtonDescriptor BD_C = | ||
219 | + new ButtonDescriptor(KEY_C, GID_C, TT_C); | ||
220 | + private static final ButtonDescriptor BD_Z = | ||
221 | + new ButtonDescriptor(KEY_Z, GID_Z, TT_Z); | ||
222 | + | ||
223 | + private void verifyButtons(String... keys) { | ||
224 | + Iterator<ButtonDescriptor> iter = pp.buttons().iterator(); | ||
225 | + for (String k: keys) { | ||
226 | + assertEquals("wrong button", k, iter.next().id()); | ||
227 | + } | ||
228 | + assertFalse("too many buttons", iter.hasNext()); | ||
229 | + } | ||
230 | + | ||
231 | + @Test | ||
232 | + public void buttons() { | ||
233 | + basic(); | ||
234 | + pp.addButton(BD_A) | ||
235 | + .addButton(BD_B); | ||
236 | + assertEquals("wrong buttons", 2, pp.buttons().size()); | ||
237 | + verifyButtons(KEY_A, KEY_B); | ||
238 | + | ||
239 | + pp.removeButtons(BD_B) | ||
240 | + .addButton(BD_C) | ||
241 | + .addButton(BD_Z); | ||
242 | + assertEquals("wrong buttons", 3, pp.buttons().size()); | ||
243 | + verifyButtons(KEY_A, KEY_C, KEY_Z); | ||
244 | + | ||
245 | + pp.removeAllButtons() | ||
246 | + .addButton(BD_B); | ||
247 | + assertEquals("wrong buttons", 1, pp.buttons().size()); | ||
248 | + verifyButtons(KEY_B); | ||
249 | + } | ||
195 | } | 250 | } | ... | ... |
... | @@ -72,6 +72,7 @@ import org.onosproject.net.topology.TopologyService; | ... | @@ -72,6 +72,7 @@ import org.onosproject.net.topology.TopologyService; |
72 | import org.onosproject.ui.JsonUtils; | 72 | import org.onosproject.ui.JsonUtils; |
73 | import org.onosproject.ui.UiConnection; | 73 | import org.onosproject.ui.UiConnection; |
74 | import org.onosproject.ui.UiMessageHandler; | 74 | import org.onosproject.ui.UiMessageHandler; |
75 | +import org.onosproject.ui.topo.ButtonDescriptor; | ||
75 | import org.onosproject.ui.topo.PropertyPanel; | 76 | import org.onosproject.ui.topo.PropertyPanel; |
76 | import org.slf4j.Logger; | 77 | import org.slf4j.Logger; |
77 | import org.slf4j.LoggerFactory; | 78 | import org.slf4j.LoggerFactory; |
... | @@ -107,7 +108,8 @@ import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED; | ... | @@ -107,7 +108,8 @@ import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED; |
107 | import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED; | 108 | import static org.onosproject.net.link.LinkEvent.Type.LINK_REMOVED; |
108 | import static org.onosproject.ui.impl.TopologyViewMessageHandlerBase.StatsType.FLOW; | 109 | import static org.onosproject.ui.impl.TopologyViewMessageHandlerBase.StatsType.FLOW; |
109 | import static org.onosproject.ui.impl.TopologyViewMessageHandlerBase.StatsType.PORT; | 110 | import static org.onosproject.ui.impl.TopologyViewMessageHandlerBase.StatsType.PORT; |
110 | -import static org.onosproject.ui.topo.TopoConstants.*; | 111 | +import static org.onosproject.ui.topo.TopoConstants.CoreButtons; |
112 | +import static org.onosproject.ui.topo.TopoConstants.Properties; | ||
111 | 113 | ||
112 | /** | 114 | /** |
113 | * Facility for creating messages bound for the topology viewer. | 115 | * Facility for creating messages bound for the topology viewer. |
... | @@ -474,6 +476,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { | ... | @@ -474,6 +476,7 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { |
474 | 476 | ||
475 | PropertyPanel pp = new PropertyPanel(title, typeId) | 477 | PropertyPanel pp = new PropertyPanel(title, typeId) |
476 | .id(deviceId.toString()) | 478 | .id(deviceId.toString()) |
479 | + | ||
477 | .addProp(Properties.URI, deviceId.toString()) | 480 | .addProp(Properties.URI, deviceId.toString()) |
478 | .addProp(Properties.VENDOR, device.manufacturer()) | 481 | .addProp(Properties.VENDOR, device.manufacturer()) |
479 | .addProp(Properties.HW_VERSION, device.hwVersion()) | 482 | .addProp(Properties.HW_VERSION, device.hwVersion()) |
... | @@ -481,14 +484,19 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { | ... | @@ -481,14 +484,19 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { |
481 | .addProp(Properties.SERIAL_NUMBER, device.serialNumber()) | 484 | .addProp(Properties.SERIAL_NUMBER, device.serialNumber()) |
482 | .addProp(Properties.PROTOCOL, annot.value(AnnotationKeys.PROTOCOL)) | 485 | .addProp(Properties.PROTOCOL, annot.value(AnnotationKeys.PROTOCOL)) |
483 | .addSeparator() | 486 | .addSeparator() |
487 | + | ||
484 | .addProp(Properties.LATITUDE, annot.value(AnnotationKeys.LATITUDE)) | 488 | .addProp(Properties.LATITUDE, annot.value(AnnotationKeys.LATITUDE)) |
485 | .addProp(Properties.LONGITUDE, annot.value(AnnotationKeys.LONGITUDE)) | 489 | .addProp(Properties.LONGITUDE, annot.value(AnnotationKeys.LONGITUDE)) |
486 | .addSeparator() | 490 | .addSeparator() |
491 | + | ||
487 | .addProp(Properties.PORTS, portCount) | 492 | .addProp(Properties.PORTS, portCount) |
488 | .addProp(Properties.FLOWS, flowCount) | 493 | .addProp(Properties.FLOWS, flowCount) |
489 | - .addProp(Properties.TUNNELS, tunnelCount); | 494 | + .addProp(Properties.TUNNELS, tunnelCount) |
490 | 495 | ||
491 | - // TODO: add button descriptors | 496 | + .addButton(CoreButtons.SHOW_DEVICE_VIEW) |
497 | + .addButton(CoreButtons.SHOW_FLOW_VIEW) | ||
498 | + .addButton(CoreButtons.SHOW_PORT_VIEW) | ||
499 | + .addButton(CoreButtons.SHOW_GROUP_VIEW); | ||
492 | 500 | ||
493 | return pp; | 501 | return pp; |
494 | } | 502 | } |
... | @@ -862,13 +870,22 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { | ... | @@ -862,13 +870,22 @@ public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler { |
862 | result.set("props", pnode); | 870 | result.set("props", pnode); |
863 | 871 | ||
864 | ArrayNode buttons = arrayNode(); | 872 | ArrayNode buttons = arrayNode(); |
865 | - for (PropertyPanel.Button b : pp.buttons()) { | 873 | + for (ButtonDescriptor b : pp.buttons()) { |
866 | - buttons.add(b.id()); | 874 | + buttons.add(json(b)); |
867 | } | 875 | } |
868 | result.set("buttons", buttons); | 876 | result.set("buttons", buttons); |
869 | return result; | 877 | return result; |
870 | } | 878 | } |
871 | 879 | ||
880 | + // translates the button descriptor into JSON | ||
881 | + private ObjectNode json(ButtonDescriptor bdesc) { | ||
882 | + return objectNode() | ||
883 | + .put("id", bdesc.id()) | ||
884 | + .put("gid", bdesc.glyphId()) | ||
885 | + .put("tt", bdesc.tooltip()); | ||
886 | + } | ||
887 | + | ||
888 | + | ||
872 | // Produces canonical link key, i.e. one that will match link and its inverse. | 889 | // Produces canonical link key, i.e. one that will match link and its inverse. |
873 | static LinkKey canonicalLinkKey(Link link) { | 890 | static LinkKey canonicalLinkKey(Link link) { |
874 | String sn = link.src().elementId().toString(); | 891 | String sn = link.src().elementId().toString(); | ... | ... |
... | @@ -30,7 +30,7 @@ | ... | @@ -30,7 +30,7 @@ |
30 | var tos = 'TopoOverlayService: '; | 30 | var tos = 'TopoOverlayService: '; |
31 | 31 | ||
32 | // injected refs | 32 | // injected refs |
33 | - var $log, fs, gs, wss; | 33 | + var $log, fs, gs, wss, ns; |
34 | 34 | ||
35 | // internal state | 35 | // internal state |
36 | var overlays = {}, | 36 | var overlays = {}, |
... | @@ -142,37 +142,53 @@ | ... | @@ -142,37 +142,53 @@ |
142 | } | 142 | } |
143 | } | 143 | } |
144 | 144 | ||
145 | - // install buttons from the current overlay | 145 | + var coreButtonPath = { |
146 | - function installButtons(bids, addFn, data) { | 146 | + showDeviceView: 'device', |
147 | - if (current) { | 147 | + showFlowView: 'flow', |
148 | - bids.forEach(function (bid) { | 148 | + showPortView: 'port', |
149 | - var btn = current.buttons[bid], | 149 | + showGroupView: 'group' |
150 | - funcWrap = function () { | 150 | + }; |
151 | - btn.cb(data); | 151 | + |
152 | - }; | 152 | + // install core buttons, and include any additional from the current overlay |
153 | - | 153 | + function installButtons(buttons, addFn, data, devId) { |
154 | - if (btn) { | 154 | + |
155 | - addFn({ | 155 | + angular.forEach(buttons, function (btn) { |
156 | - id: current.mkId(bid), | 156 | + var path = coreButtonPath[btn.id], |
157 | - gid: current.mkGid(btn.gid), | 157 | + _id, |
158 | - cb: funcWrap, | 158 | + _gid, |
159 | - tt: btn.tt | 159 | + _cb, |
160 | - }); | 160 | + action; |
161 | - } | 161 | + |
162 | - }); | 162 | + if (path) { |
163 | - } | 163 | + // core callback function |
164 | + _id = btn.id; | ||
165 | + _gid = btn.gid; | ||
166 | + action = function () { | ||
167 | + ns.navTo(path, { devId: devId }); | ||
168 | + }; | ||
169 | + } else if (current) { | ||
170 | + _id = current.mkId(btn.id); | ||
171 | + _gid = current.mkGid(btn.gid); | ||
172 | + action = current.buttonActions[btn.id] || function () {}; | ||
173 | + } | ||
174 | + | ||
175 | + _cb = function () { action(data); }; | ||
176 | + | ||
177 | + addFn({ id: _id, gid: _gid, cb: _cb, tt: btn.tt}); | ||
178 | + }); | ||
164 | 179 | ||
165 | } | 180 | } |
166 | 181 | ||
167 | angular.module('ovTopo') | 182 | angular.module('ovTopo') |
168 | .factory('TopoOverlayService', | 183 | .factory('TopoOverlayService', |
169 | - ['$log', 'FnService', 'GlyphService', 'WebSocketService', | 184 | + ['$log', 'FnService', 'GlyphService', 'WebSocketService', 'NavService', |
170 | 185 | ||
171 | - function (_$log_, _fs_, _gs_, _wss_) { | 186 | + function (_$log_, _fs_, _gs_, _wss_, _ns_) { |
172 | $log = _$log_; | 187 | $log = _$log_; |
173 | fs = _fs_; | 188 | fs = _fs_; |
174 | gs = _gs_; | 189 | gs = _gs_; |
175 | wss = _wss_; | 190 | wss = _wss_; |
191 | + ns = _ns_; | ||
176 | 192 | ||
177 | return { | 193 | return { |
178 | register: register, | 194 | register: register, | ... | ... |
... | @@ -272,7 +272,7 @@ | ... | @@ -272,7 +272,7 @@ |
272 | .select('.actionBtns') | 272 | .select('.actionBtns') |
273 | .append('div') | 273 | .append('div') |
274 | .classed('actionBtn', true); | 274 | .classed('actionBtn', true); |
275 | - bns.button(btnDiv, idDet + o.id, o.gid, o.cb, o.tt); | 275 | + bns.button(btnDiv, idDet + '-' + o.id, o.gid, o.cb, o.tt); |
276 | } | 276 | } |
277 | 277 | ||
278 | var friendlyIndex = { | 278 | var friendlyIndex = { | ... | ... |
... | @@ -229,13 +229,14 @@ | ... | @@ -229,13 +229,14 @@ |
229 | // Event Handlers | 229 | // Event Handlers |
230 | 230 | ||
231 | function showDetails(data) { | 231 | function showDetails(data) { |
232 | - var buttons = fs.isA(data.buttons); | 232 | + var buttons = fs.isA(data.buttons) || []; |
233 | 233 | ||
234 | // display the data for the single selected node | 234 | // display the data for the single selected node |
235 | tps.displaySingle(data); | 235 | tps.displaySingle(data); |
236 | 236 | ||
237 | - // TODO: use server-side-button-descriptors to add buttons | 237 | + tov.installButtons(buttons, tps.addAction, data, data.props['URI']); |
238 | 238 | ||
239 | + // TODO: MOVE traffic buttons to the traffic overlay | ||
239 | // always add the 'show traffic' action | 240 | // always add the 'show traffic' action |
240 | tps.addAction({ | 241 | tps.addAction({ |
241 | id: '-sin-rel-traf-btn', | 242 | id: '-sin-rel-traf-btn', |
... | @@ -254,49 +255,6 @@ | ... | @@ -254,49 +255,6 @@ |
254 | }); | 255 | }); |
255 | } | 256 | } |
256 | 257 | ||
257 | - // TODO: for now, install overlay buttons here | ||
258 | - if (buttons) { | ||
259 | - tov.installButtons(buttons, tps.addAction, data); | ||
260 | - } | ||
261 | - | ||
262 | - | ||
263 | - // TODO: have the server return explicit class and ID of each node | ||
264 | - // for now, we assume the node is a device if it has a URI | ||
265 | - if ((data.props).hasOwnProperty('URI')) { | ||
266 | - tps.addAction({ | ||
267 | - id: 'device-table-btn', | ||
268 | - gid: data.type, | ||
269 | - cb: function () { | ||
270 | - ns.navTo(devPath, { devId: data.props['URI'] }); | ||
271 | - }, | ||
272 | - tt: 'Show device view' | ||
273 | - }); | ||
274 | - tps.addAction({ | ||
275 | - id: 'flows-table-btn', | ||
276 | - gid: 'flowTable', | ||
277 | - cb: function () { | ||
278 | - ns.navTo(flowPath, { devId: data.props['URI'] }); | ||
279 | - }, | ||
280 | - tt: 'Show flow view for this device' | ||
281 | - }); | ||
282 | - tps.addAction({ | ||
283 | - id: 'ports-table-btn', | ||
284 | - gid: 'portTable', | ||
285 | - cb: function () { | ||
286 | - ns.navTo(portPath, { devId: data.props['URI'] }); | ||
287 | - }, | ||
288 | - tt: 'Show port view for this device' | ||
289 | - }); | ||
290 | - tps.addAction({ | ||
291 | - id: 'groups-table-btn', | ||
292 | - gid: 'groupTable', | ||
293 | - cb: function () { | ||
294 | - ns.navTo(groupPath, { devId: data.props['URI'] }); | ||
295 | - }, | ||
296 | - tt: 'Show group view for this device' | ||
297 | - }); | ||
298 | - } | ||
299 | - | ||
300 | tps.displaySomething(); | 258 | tps.displaySomething(); |
301 | } | 259 | } |
302 | 260 | ... | ... |
-
Please register or login to post a comment