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
320 additions
and
108 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 () { | ||
| 151 | - btn.cb(data); | ||
| 152 | }; | 150 | }; |
| 153 | 151 | ||
| 154 | - if (btn) { | 152 | + // install core buttons, and include any additional from the current overlay |
| 155 | - addFn({ | 153 | + function installButtons(buttons, addFn, data, devId) { |
| 156 | - id: current.mkId(bid), | 154 | + |
| 157 | - gid: current.mkGid(btn.gid), | 155 | + angular.forEach(buttons, function (btn) { |
| 158 | - cb: funcWrap, | 156 | + var path = coreButtonPath[btn.id], |
| 159 | - tt: btn.tt | 157 | + _id, |
| 160 | - }); | 158 | + _gid, |
| 159 | + _cb, | ||
| 160 | + action; | ||
| 161 | + | ||
| 162 | + if (path) { | ||
| 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 () {}; | ||
| 161 | } | 173 | } |
| 174 | + | ||
| 175 | + _cb = function () { action(data); }; | ||
| 176 | + | ||
| 177 | + addFn({ id: _id, gid: _gid, cb: _cb, tt: btn.tt}); | ||
| 162 | }); | 178 | }); |
| 163 | - } | ||
| 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