Simon Hunt

ONOS-3755: use thousand separator for packet and byte counts, etc. Fix alignment…

… (numbers right justified).

Change-Id: Idb407fb16a82d5e3fb6fd10a6599b263a777deb2
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
16 16
17 package org.onosproject.ui.table.cell; 17 package org.onosproject.ui.table.cell;
18 18
19 +import org.onosproject.ui.table.CellFormatter;
20 +
19 import java.text.DecimalFormat; 21 import java.text.DecimalFormat;
20 import java.text.NumberFormat; 22 import java.text.NumberFormat;
21 23
...@@ -24,17 +26,35 @@ import java.text.NumberFormat; ...@@ -24,17 +26,35 @@ import java.text.NumberFormat;
24 */ 26 */
25 public final class NumberFormatter extends AbstractCellFormatter { 27 public final class NumberFormatter extends AbstractCellFormatter {
26 28
29 + private static final String FMT_INTEGER = "#,##0";
30 + private static final String FMT_5DP = "#,##0.00000";
31 +
32 +
27 private final NumberFormat format; 33 private final NumberFormat format;
28 34
29 /** 35 /**
30 - * Creates a formatter using a default decimal format. 36 + * Creates a formatter using the default format (no decimal places).
37 + * For example
38 + * <pre>
39 + * 12345 formatted as "12,345"
40 + * </pre>
31 */ 41 */
32 public NumberFormatter() { 42 public NumberFormatter() {
33 - this(new DecimalFormat("#,##0.00000")); 43 + this(FMT_INTEGER);
44 + }
45 +
46 + /**
47 + * Creates a formatter using a {@link DecimalFormat} configured with the
48 + * given format string.
49 + *
50 + * @param decimalFormat the format string
51 + */
52 + public NumberFormatter(String decimalFormat) {
53 + this(new DecimalFormat(decimalFormat));
34 } 54 }
35 55
36 /** 56 /**
37 - * Creates a formatter using the specified format. 57 + * Creates a formatter using the specified {@link NumberFormat}.
38 * 58 *
39 * @param format number format 59 * @param format number format
40 */ 60 */
...@@ -47,4 +67,23 @@ public final class NumberFormatter extends AbstractCellFormatter { ...@@ -47,4 +67,23 @@ public final class NumberFormatter extends AbstractCellFormatter {
47 return format.format(value); 67 return format.format(value);
48 } 68 }
49 69
70 + /**
71 + * An instance of this class that formats as integers (no decimal places).
72 + * For example
73 + * <pre>
74 + * 12345 formatted as "12,345"
75 + * </pre>
76 + */
77 + public static final CellFormatter INTEGER = new NumberFormatter();
78 +
79 + /**
80 + * An instance of this class that formats to 5 decimal places.
81 + * For example
82 + * <pre>
83 + * 12.3 formatted as "12.30000"
84 + * 1234 formatted as "1,234.00000"
85 + * </pre>
86 + */
87 + public static final CellFormatter TO_5DP = new NumberFormatter(FMT_5DP);
88 +
50 } 89 }
......
1 +/*
2 + * Copyright 2016 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 +package org.onosproject.ui.table.cell;
18 +
19 +import org.junit.Test;
20 +import org.onosproject.ui.table.CellFormatter;
21 +
22 +import static org.junit.Assert.assertEquals;
23 +
24 +/**
25 + * Unit tests for {@link NumberFormatter}.
26 + */
27 +public class NumberFormatterTest {
28 +
29 +
30 + private CellFormatter f5dp = NumberFormatter.TO_5DP;
31 + private CellFormatter fInt = NumberFormatter.INTEGER;
32 +
33 + @Test
34 + public void defaultNullValue() {
35 + assertEquals("default null value", "", f5dp.format(null));
36 + }
37 +
38 + @Test
39 + public void defaultZero() {
40 + assertEquals("default zero", "0.00000", f5dp.format(0));
41 + }
42 +
43 + @Test
44 + public void defaultFifty() {
45 + assertEquals("default fifty", "50.00000", f5dp.format(50));
46 + }
47 +
48 + @Test
49 + public void default2G() {
50 + assertEquals("default 2G", "2,000.00000", f5dp.format(2000));
51 + }
52 +
53 + @Test
54 + public void integerNullValue() {
55 + assertEquals("integer null value", "", fInt.format(null));
56 + }
57 +
58 + @Test
59 + public void integerZero() {
60 + assertEquals("integer zero", "0", fInt.format(0));
61 + }
62 +
63 + @Test
64 + public void integerFifty() {
65 + assertEquals("integer fifty", "50", fInt.format(50));
66 + }
67 +
68 + @Test
69 + public void integer2G() {
70 + assertEquals("integer 2G", "2,000", fInt.format(2000));
71 + }
72 +
73 + @Test
74 + public void integer5M() {
75 + assertEquals("integer 5M", "5,000,042", fInt.format(5000042));
76 + }
77 +
78 +}
...@@ -32,6 +32,7 @@ import org.onosproject.ui.table.TableRequestHandler; ...@@ -32,6 +32,7 @@ import org.onosproject.ui.table.TableRequestHandler;
32 import org.onosproject.ui.table.cell.EnumFormatter; 32 import org.onosproject.ui.table.cell.EnumFormatter;
33 import org.onosproject.ui.table.cell.HexFormatter; 33 import org.onosproject.ui.table.cell.HexFormatter;
34 import org.onosproject.ui.table.cell.HexLongFormatter; 34 import org.onosproject.ui.table.cell.HexLongFormatter;
35 +import org.onosproject.ui.table.cell.NumberFormatter;
35 36
36 import java.util.Collection; 37 import java.util.Collection;
37 import java.util.List; 38 import java.util.List;
...@@ -88,9 +89,11 @@ public class FlowViewMessageHandler extends UiMessageHandler { ...@@ -88,9 +89,11 @@ public class FlowViewMessageHandler extends UiMessageHandler {
88 TableModel tm = super.createTableModel(); 89 TableModel tm = super.createTableModel();
89 tm.setFormatter(ID, HexLongFormatter.INSTANCE); 90 tm.setFormatter(ID, HexLongFormatter.INSTANCE);
90 tm.setFormatter(GROUP_ID, HexFormatter.INSTANCE); 91 tm.setFormatter(GROUP_ID, HexFormatter.INSTANCE);
92 + tm.setFormatter(STATE, EnumFormatter.INSTANCE);
93 + tm.setFormatter(PACKETS, NumberFormatter.INTEGER);
94 + tm.setFormatter(BYTES, NumberFormatter.INTEGER);
91 tm.setFormatter(SELECTOR, new SelectorFormatter()); 95 tm.setFormatter(SELECTOR, new SelectorFormatter());
92 tm.setFormatter(TREATMENT, new TreatmentFormatter()); 96 tm.setFormatter(TREATMENT, new TreatmentFormatter());
93 - tm.setFormatter(STATE, EnumFormatter.INSTANCE);
94 return tm; 97 return tm;
95 } 98 }
96 99
...@@ -112,13 +115,13 @@ public class FlowViewMessageHandler extends UiMessageHandler { ...@@ -112,13 +115,13 @@ public class FlowViewMessageHandler extends UiMessageHandler {
112 .cell(GROUP_ID, flow.groupId().id()) 115 .cell(GROUP_ID, flow.groupId().id())
113 .cell(TABLE_ID, flow.tableId()) 116 .cell(TABLE_ID, flow.tableId())
114 .cell(PRIORITY, flow.priority()) 117 .cell(PRIORITY, flow.priority())
115 - .cell(SELECTOR, flow)
116 - .cell(TREATMENT, flow)
117 .cell(TIMEOUT, flow.timeout()) 118 .cell(TIMEOUT, flow.timeout())
118 .cell(PERMANENT, flow.isPermanent()) 119 .cell(PERMANENT, flow.isPermanent())
119 .cell(STATE, flow.state()) 120 .cell(STATE, flow.state())
120 .cell(PACKETS, flow.packets()) 121 .cell(PACKETS, flow.packets())
121 - .cell(BYTES, flow.bytes()); 122 + .cell(BYTES, flow.bytes())
123 + .cell(SELECTOR, flow)
124 + .cell(TREATMENT, flow);
122 } 125 }
123 126
124 private final class SelectorFormatter implements CellFormatter { 127 private final class SelectorFormatter implements CellFormatter {
......
...@@ -30,6 +30,7 @@ import org.onosproject.ui.table.TableModel; ...@@ -30,6 +30,7 @@ import org.onosproject.ui.table.TableModel;
30 import org.onosproject.ui.table.TableRequestHandler; 30 import org.onosproject.ui.table.TableRequestHandler;
31 import org.onosproject.ui.table.cell.EnumFormatter; 31 import org.onosproject.ui.table.cell.EnumFormatter;
32 import org.onosproject.ui.table.cell.HexFormatter; 32 import org.onosproject.ui.table.cell.HexFormatter;
33 +import org.onosproject.ui.table.cell.NumberFormatter;
33 34
34 import java.util.Collection; 35 import java.util.Collection;
35 import java.util.List; 36 import java.util.List;
...@@ -78,6 +79,8 @@ public class GroupViewMessageHandler extends UiMessageHandler { ...@@ -78,6 +79,8 @@ public class GroupViewMessageHandler extends UiMessageHandler {
78 TableModel tm = super.createTableModel(); 79 TableModel tm = super.createTableModel();
79 tm.setFormatter(ID, HexFormatter.INSTANCE); 80 tm.setFormatter(ID, HexFormatter.INSTANCE);
80 tm.setFormatter(TYPE, EnumFormatter.INSTANCE); 81 tm.setFormatter(TYPE, EnumFormatter.INSTANCE);
82 + tm.setFormatter(PACKETS, NumberFormatter.INTEGER);
83 + tm.setFormatter(BYTES, NumberFormatter.INTEGER);
81 tm.setFormatter(BUCKETS, new BucketFormatter()); 84 tm.setFormatter(BUCKETS, new BucketFormatter());
82 return tm; 85 return tm;
83 } 86 }
......
...@@ -28,6 +28,8 @@ import org.onosproject.ui.UiMessageHandler; ...@@ -28,6 +28,8 @@ import org.onosproject.ui.UiMessageHandler;
28 import org.onosproject.ui.table.CellFormatter; 28 import org.onosproject.ui.table.CellFormatter;
29 import org.onosproject.ui.table.TableModel; 29 import org.onosproject.ui.table.TableModel;
30 import org.onosproject.ui.table.TableRequestHandler; 30 import org.onosproject.ui.table.TableRequestHandler;
31 +import org.onosproject.ui.table.cell.HexLongFormatter;
32 +import org.onosproject.ui.table.cell.NumberFormatter;
31 33
32 import java.util.Collection; 34 import java.util.Collection;
33 35
...@@ -71,6 +73,9 @@ public class MeterViewMessageHandler extends UiMessageHandler { ...@@ -71,6 +73,9 @@ public class MeterViewMessageHandler extends UiMessageHandler {
71 @Override 73 @Override
72 protected TableModel createTableModel() { 74 protected TableModel createTableModel() {
73 TableModel tm = super.createTableModel(); 75 TableModel tm = super.createTableModel();
76 + tm.setFormatter(ID, HexLongFormatter.INSTANCE);
77 + tm.setFormatter(PACKETS, NumberFormatter.INTEGER);
78 + tm.setFormatter(BYTES, NumberFormatter.INTEGER);
74 tm.setFormatter(BANDS, new BandFormatter()); 79 tm.setFormatter(BANDS, new BandFormatter());
75 return tm; 80 return tm;
76 } 81 }
......
...@@ -26,6 +26,7 @@ import org.onosproject.ui.RequestHandler; ...@@ -26,6 +26,7 @@ import org.onosproject.ui.RequestHandler;
26 import org.onosproject.ui.UiMessageHandler; 26 import org.onosproject.ui.UiMessageHandler;
27 import org.onosproject.ui.table.TableModel; 27 import org.onosproject.ui.table.TableModel;
28 import org.onosproject.ui.table.TableRequestHandler; 28 import org.onosproject.ui.table.TableRequestHandler;
29 +import org.onosproject.ui.table.cell.NumberFormatter;
29 30
30 import java.util.Collection; 31 import java.util.Collection;
31 32
...@@ -71,6 +72,18 @@ public class PortViewMessageHandler extends UiMessageHandler { ...@@ -71,6 +72,18 @@ public class PortViewMessageHandler extends UiMessageHandler {
71 } 72 }
72 73
73 @Override 74 @Override
75 + protected TableModel createTableModel() {
76 + TableModel tm = super.createTableModel();
77 + tm.setFormatter(PKT_RX, NumberFormatter.INTEGER);
78 + tm.setFormatter(PKT_TX, NumberFormatter.INTEGER);
79 + tm.setFormatter(BYTES_RX, NumberFormatter.INTEGER);
80 + tm.setFormatter(BYTES_TX, NumberFormatter.INTEGER);
81 + tm.setFormatter(PKT_RX_DRP, NumberFormatter.INTEGER);
82 + tm.setFormatter(PKT_TX_DRP, NumberFormatter.INTEGER);
83 + return tm;
84 + }
85 +
86 + @Override
74 protected void populateTable(TableModel tm, ObjectNode payload) { 87 protected void populateTable(TableModel tm, ObjectNode payload) {
75 String uri = string(payload, "devId"); 88 String uri = string(payload, "devId");
76 if (!Strings.isNullOrEmpty(uri)) { 89 if (!Strings.isNullOrEmpty(uri)) {
......
...@@ -76,7 +76,7 @@ public class ProcessorViewMessageHandler extends UiMessageHandler { ...@@ -76,7 +76,7 @@ public class ProcessorViewMessageHandler extends UiMessageHandler {
76 @Override 76 @Override
77 protected TableModel createTableModel() { 77 protected TableModel createTableModel() {
78 TableModel tm = super.createTableModel(); 78 TableModel tm = super.createTableModel();
79 - tm.setFormatter(AVG_MS, new NumberFormatter()); 79 + tm.setFormatter(AVG_MS, NumberFormatter.TO_5DP);
80 return tm; 80 return tm;
81 } 81 }
82 82
......
...@@ -78,8 +78,15 @@ ...@@ -78,8 +78,15 @@
78 background-color: #5A5600; 78 background-color: #5A5600;
79 } 79 }
80 80
81 +#ov-flow td {
82 + text-align: center;
83 +}
84 +#ov-flow td.right {
85 + text-align: right;
86 +}
81 #ov-flow td.selector, 87 #ov-flow td.selector,
82 #ov-flow td.treatment { 88 #ov-flow td.treatment {
89 + text-align: left;
83 padding-left: 36px; 90 padding-left: 36px;
84 opacity: 0.65; 91 opacity: 0.65;
85 } 92 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -50,8 +50,8 @@ ...@@ -50,8 +50,8 @@
50 <td colId="timeout" sortable>Timeout </td> 50 <td colId="timeout" sortable>Timeout </td>
51 <td colId="permanent" sortable>Permanent </td> 51 <td colId="permanent" sortable>Permanent </td>
52 <td colId="state" sortable>State </td> 52 <td colId="state" sortable>State </td>
53 - <td colId="packets" sortable>Packets </td> 53 + <td class="right" colId="packets" sortable>Packets </td>
54 - <td colId="bytes" sortable>Bytes </td> 54 + <td class="right" colId="bytes" sortable>Bytes </td>
55 </tr> 55 </tr>
56 </table> 56 </table>
57 </div> 57 </div>
...@@ -74,8 +74,8 @@ ...@@ -74,8 +74,8 @@
74 <td>{{flow.timeout}}</td> 74 <td>{{flow.timeout}}</td>
75 <td>{{flow.permanent}}</td> 75 <td>{{flow.permanent}}</td>
76 <td>{{flow.state}}</td> 76 <td>{{flow.state}}</td>
77 - <td>{{flow.packets}}</td> 77 + <td class="right">{{flow.packets}}</td>
78 - <td>{{flow.bytes}}</td> 78 + <td class="right">{{flow.bytes}}</td>
79 </tr> 79 </tr>
80 <tr row-id="{{flow.id}}"> 80 <tr row-id="{{flow.id}}">
81 <td class="selector" colspan="10">{{flow.selector}}</td> 81 <td class="selector" colspan="10">{{flow.selector}}</td>
......
...@@ -70,7 +70,14 @@ ...@@ -70,7 +70,14 @@
70 background-color: #5A5600; 70 background-color: #5A5600;
71 } 71 }
72 72
73 +#ov-group td {
74 + text-align: center;
75 +}
76 +#ov-group td.right {
77 + text-align: right;
78 +}
73 #ov-group td.buckets { 79 #ov-group td.buckets {
80 + text-align: left;
74 padding-left: 36px; 81 padding-left: 36px;
75 opacity: 0.65; 82 opacity: 0.65;
76 } 83 }
......
...@@ -46,8 +46,8 @@ ...@@ -46,8 +46,8 @@
46 <td colId="app_id" sortable>App ID </td> 46 <td colId="app_id" sortable>App ID </td>
47 <td colId="state" sortable>State </td> 47 <td colId="state" sortable>State </td>
48 <td colId="type" sortable>Type </td> 48 <td colId="type" sortable>Type </td>
49 - <td colId="packets" sortable>Packets </td> 49 + <td class="right" colId="packets" sortable>Packets </td>
50 - <td colId="bytes" sortable>Bytes </td> 50 + <td class="right" colId="bytes" sortable>Bytes </td>
51 </tr> 51 </tr>
52 </table> 52 </table>
53 </div> 53 </div>
...@@ -66,8 +66,8 @@ ...@@ -66,8 +66,8 @@
66 <td>{{group.app_id}}</td> 66 <td>{{group.app_id}}</td>
67 <td>{{group.state}}</td> 67 <td>{{group.state}}</td>
68 <td>{{group.type}}</td> 68 <td>{{group.type}}</td>
69 - <td>{{group.packets}}</td> 69 + <td class="right">{{group.packets}}</td>
70 - <td>{{group.bytes}}</td> 70 + <td class="right">{{group.bytes}}</td>
71 </tr> 71 </tr>
72 <tr row-id="{{group.id}}" ng-repeat-end> 72 <tr row-id="{{group.id}}" ng-repeat-end>
73 <td class="buckets" colspan="6" 73 <td class="buckets" colspan="6"
......
...@@ -70,7 +70,14 @@ ...@@ -70,7 +70,14 @@
70 background-color: #5A5600; 70 background-color: #5A5600;
71 } 71 }
72 72
73 +#ov-meter td {
74 + text-align: center;
75 +}
76 +#ov-meter td.right {
77 + text-align: right;
78 +}
73 #ov-meter td.bands { 79 #ov-meter td.bands {
80 + text-align: left;
74 padding-left: 36px; 81 padding-left: 36px;
75 opacity: 0.65; 82 opacity: 0.65;
76 } 83 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -45,8 +45,8 @@ ...@@ -45,8 +45,8 @@
45 <td colId="id" sortable>Meter ID </td> 45 <td colId="id" sortable>Meter ID </td>
46 <td colId="app_id" sortable>App ID </td> 46 <td colId="app_id" sortable>App ID </td>
47 <td colId="state" sortable>State </td> 47 <td colId="state" sortable>State </td>
48 - <td colId="packets" sortable>Packets </td> 48 + <td class="right" colId="packets" sortable>Packets </td>
49 - <td colId="bytes" sortable>Bytes </td> 49 + <td class="right" colId="bytes" sortable>Bytes </td>
50 </tr> 50 </tr>
51 </table> 51 </table>
52 </div> 52 </div>
...@@ -64,8 +64,8 @@ ...@@ -64,8 +64,8 @@
64 <td>{{meter.id}}</td> 64 <td>{{meter.id}}</td>
65 <td>{{meter.app_id}}</td> 65 <td>{{meter.app_id}}</td>
66 <td>{{meter.state}}</td> 66 <td>{{meter.state}}</td>
67 - <td>{{meter.packets}}</td> 67 + <td class="right">{{meter.packets}}</td>
68 - <td>{{meter.bytes}}</td> 68 + <td class="right">{{meter.bytes}}</td>
69 </tr> 69 </tr>
70 <tr row-id="{{meter.id}}" ng-repeat-end> 70 <tr row-id="{{meter.id}}" ng-repeat-end>
71 <td class="bands" colspan="5" 71 <td class="bands" colspan="5"
......
...@@ -40,6 +40,9 @@ ...@@ -40,6 +40,9 @@
40 } 40 }
41 41
42 #ov-port td { 42 #ov-port td {
43 + text-align: center;
44 +}
45 +#ov-port td.right {
43 text-align: right; 46 text-align: right;
44 } 47 }
45 48
......
...@@ -43,13 +43,13 @@ ...@@ -43,13 +43,13 @@
43 <table> 43 <table>
44 <tr> 44 <tr>
45 <td colId="id" col-width="60px" sortable>Port ID </td> 45 <td colId="id" col-width="60px" sortable>Port ID </td>
46 - <td colId="pkt_rx" sortable>Pkts Received </td> 46 + <td class="right" colId="pkt_rx" sortable>Pkts Received </td>
47 - <td colId="pkt_tx" sortable>Pkts Sent </td> 47 + <td class="right" colId="pkt_tx" sortable>Pkts Sent </td>
48 - <td colId="bytes_rx" sortable>Bytes Received </td> 48 + <td class="right" colId="bytes_rx" sortable>Bytes Received </td>
49 - <td colId="bytes_tx" sortable>Bytes Sent </td> 49 + <td class="right" colId="bytes_tx" sortable>Bytes Sent </td>
50 - <td colId="pkt_rx_drp" sortable>Pkts Received Dropped </td> 50 + <td class="right" colId="pkt_rx_drp" sortable>Pkts Received Dropped </td>
51 - <td colId="pkt_tx_drp" sortable>Pkts Sent Dropped </td> 51 + <td class="right" colId="pkt_tx_drp" sortable>Pkts Sent Dropped </td>
52 - <td colId="duration" sortable>Duration (sec) </td> 52 + <td class="right" colId="duration" sortable>Duration (sec) </td>
53 </tr> 53 </tr>
54 </table> 54 </table>
55 </div> 55 </div>
...@@ -65,13 +65,13 @@ ...@@ -65,13 +65,13 @@
65 <tr ng-repeat="port in tableData track by $index" 65 <tr ng-repeat="port in tableData track by $index"
66 ng-repeat-complete row-id="{{port.id}}"> 66 ng-repeat-complete row-id="{{port.id}}">
67 <td>{{port.id}}</td> 67 <td>{{port.id}}</td>
68 - <td>{{port.pkt_rx}}</td> 68 + <td class="right">{{port.pkt_rx}}</td>
69 - <td>{{port.pkt_tx}}</td> 69 + <td class="right">{{port.pkt_tx}}</td>
70 - <td>{{port.bytes_rx}}</td> 70 + <td class="right">{{port.bytes_rx}}</td>
71 - <td>{{port.bytes_tx}}</td> 71 + <td class="right">{{port.bytes_tx}}</td>
72 - <td>{{port.pkt_rx_drp}}</td> 72 + <td class="right">{{port.pkt_rx_drp}}</td>
73 - <td>{{port.pkt_tx_drp}}</td> 73 + <td class="right">{{port.pkt_tx_drp}}</td>
74 - <td>{{port.duration}}</td> 74 + <td class="right">{{port.duration}}</td>
75 </tr> 75 </tr>
76 </table> 76 </table>
77 </div> 77 </div>
......