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 @@
package org.onosproject.ui.table.cell;
import org.onosproject.ui.table.CellFormatter;
import java.text.DecimalFormat;
import java.text.NumberFormat;
......@@ -24,17 +26,35 @@ import java.text.NumberFormat;
*/
public final class NumberFormatter extends AbstractCellFormatter {
private static final String FMT_INTEGER = "#,##0";
private static final String FMT_5DP = "#,##0.00000";
private final NumberFormat format;
/**
* Creates a formatter using a default decimal format.
* Creates a formatter using the default format (no decimal places).
* For example
* <pre>
* 12345 formatted as "12,345"
* </pre>
*/
public NumberFormatter() {
this(new DecimalFormat("#,##0.00000"));
this(FMT_INTEGER);
}
/**
* Creates a formatter using a {@link DecimalFormat} configured with the
* given format string.
*
* @param decimalFormat the format string
*/
public NumberFormatter(String decimalFormat) {
this(new DecimalFormat(decimalFormat));
}
/**
* Creates a formatter using the specified format.
* Creates a formatter using the specified {@link NumberFormat}.
*
* @param format number format
*/
......@@ -47,4 +67,23 @@ public final class NumberFormatter extends AbstractCellFormatter {
return format.format(value);
}
/**
* An instance of this class that formats as integers (no decimal places).
* For example
* <pre>
* 12345 formatted as "12,345"
* </pre>
*/
public static final CellFormatter INTEGER = new NumberFormatter();
/**
* An instance of this class that formats to 5 decimal places.
* For example
* <pre>
* 12.3 formatted as "12.30000"
* 1234 formatted as "1,234.00000"
* </pre>
*/
public static final CellFormatter TO_5DP = new NumberFormatter(FMT_5DP);
}
......
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.ui.table.cell;
import org.junit.Test;
import org.onosproject.ui.table.CellFormatter;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for {@link NumberFormatter}.
*/
public class NumberFormatterTest {
private CellFormatter f5dp = NumberFormatter.TO_5DP;
private CellFormatter fInt = NumberFormatter.INTEGER;
@Test
public void defaultNullValue() {
assertEquals("default null value", "", f5dp.format(null));
}
@Test
public void defaultZero() {
assertEquals("default zero", "0.00000", f5dp.format(0));
}
@Test
public void defaultFifty() {
assertEquals("default fifty", "50.00000", f5dp.format(50));
}
@Test
public void default2G() {
assertEquals("default 2G", "2,000.00000", f5dp.format(2000));
}
@Test
public void integerNullValue() {
assertEquals("integer null value", "", fInt.format(null));
}
@Test
public void integerZero() {
assertEquals("integer zero", "0", fInt.format(0));
}
@Test
public void integerFifty() {
assertEquals("integer fifty", "50", fInt.format(50));
}
@Test
public void integer2G() {
assertEquals("integer 2G", "2,000", fInt.format(2000));
}
@Test
public void integer5M() {
assertEquals("integer 5M", "5,000,042", fInt.format(5000042));
}
}
......@@ -32,6 +32,7 @@ import org.onosproject.ui.table.TableRequestHandler;
import org.onosproject.ui.table.cell.EnumFormatter;
import org.onosproject.ui.table.cell.HexFormatter;
import org.onosproject.ui.table.cell.HexLongFormatter;
import org.onosproject.ui.table.cell.NumberFormatter;
import java.util.Collection;
import java.util.List;
......@@ -88,9 +89,11 @@ public class FlowViewMessageHandler extends UiMessageHandler {
TableModel tm = super.createTableModel();
tm.setFormatter(ID, HexLongFormatter.INSTANCE);
tm.setFormatter(GROUP_ID, HexFormatter.INSTANCE);
tm.setFormatter(STATE, EnumFormatter.INSTANCE);
tm.setFormatter(PACKETS, NumberFormatter.INTEGER);
tm.setFormatter(BYTES, NumberFormatter.INTEGER);
tm.setFormatter(SELECTOR, new SelectorFormatter());
tm.setFormatter(TREATMENT, new TreatmentFormatter());
tm.setFormatter(STATE, EnumFormatter.INSTANCE);
return tm;
}
......@@ -112,13 +115,13 @@ public class FlowViewMessageHandler extends UiMessageHandler {
.cell(GROUP_ID, flow.groupId().id())
.cell(TABLE_ID, flow.tableId())
.cell(PRIORITY, flow.priority())
.cell(SELECTOR, flow)
.cell(TREATMENT, flow)
.cell(TIMEOUT, flow.timeout())
.cell(PERMANENT, flow.isPermanent())
.cell(STATE, flow.state())
.cell(PACKETS, flow.packets())
.cell(BYTES, flow.bytes());
.cell(BYTES, flow.bytes())
.cell(SELECTOR, flow)
.cell(TREATMENT, flow);
}
private final class SelectorFormatter implements CellFormatter {
......
......@@ -30,6 +30,7 @@ import org.onosproject.ui.table.TableModel;
import org.onosproject.ui.table.TableRequestHandler;
import org.onosproject.ui.table.cell.EnumFormatter;
import org.onosproject.ui.table.cell.HexFormatter;
import org.onosproject.ui.table.cell.NumberFormatter;
import java.util.Collection;
import java.util.List;
......@@ -78,6 +79,8 @@ public class GroupViewMessageHandler extends UiMessageHandler {
TableModel tm = super.createTableModel();
tm.setFormatter(ID, HexFormatter.INSTANCE);
tm.setFormatter(TYPE, EnumFormatter.INSTANCE);
tm.setFormatter(PACKETS, NumberFormatter.INTEGER);
tm.setFormatter(BYTES, NumberFormatter.INTEGER);
tm.setFormatter(BUCKETS, new BucketFormatter());
return tm;
}
......
......@@ -28,6 +28,8 @@ import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.table.CellFormatter;
import org.onosproject.ui.table.TableModel;
import org.onosproject.ui.table.TableRequestHandler;
import org.onosproject.ui.table.cell.HexLongFormatter;
import org.onosproject.ui.table.cell.NumberFormatter;
import java.util.Collection;
......@@ -71,6 +73,9 @@ public class MeterViewMessageHandler extends UiMessageHandler {
@Override
protected TableModel createTableModel() {
TableModel tm = super.createTableModel();
tm.setFormatter(ID, HexLongFormatter.INSTANCE);
tm.setFormatter(PACKETS, NumberFormatter.INTEGER);
tm.setFormatter(BYTES, NumberFormatter.INTEGER);
tm.setFormatter(BANDS, new BandFormatter());
return tm;
}
......
......@@ -26,6 +26,7 @@ import org.onosproject.ui.RequestHandler;
import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.table.TableModel;
import org.onosproject.ui.table.TableRequestHandler;
import org.onosproject.ui.table.cell.NumberFormatter;
import java.util.Collection;
......@@ -71,6 +72,18 @@ public class PortViewMessageHandler extends UiMessageHandler {
}
@Override
protected TableModel createTableModel() {
TableModel tm = super.createTableModel();
tm.setFormatter(PKT_RX, NumberFormatter.INTEGER);
tm.setFormatter(PKT_TX, NumberFormatter.INTEGER);
tm.setFormatter(BYTES_RX, NumberFormatter.INTEGER);
tm.setFormatter(BYTES_TX, NumberFormatter.INTEGER);
tm.setFormatter(PKT_RX_DRP, NumberFormatter.INTEGER);
tm.setFormatter(PKT_TX_DRP, NumberFormatter.INTEGER);
return tm;
}
@Override
protected void populateTable(TableModel tm, ObjectNode payload) {
String uri = string(payload, "devId");
if (!Strings.isNullOrEmpty(uri)) {
......
......@@ -76,7 +76,7 @@ public class ProcessorViewMessageHandler extends UiMessageHandler {
@Override
protected TableModel createTableModel() {
TableModel tm = super.createTableModel();
tm.setFormatter(AVG_MS, new NumberFormatter());
tm.setFormatter(AVG_MS, NumberFormatter.TO_5DP);
return tm;
}
......
......@@ -78,8 +78,15 @@
background-color: #5A5600;
}
#ov-flow td {
text-align: center;
}
#ov-flow td.right {
text-align: right;
}
#ov-flow td.selector,
#ov-flow td.treatment {
text-align: left;
padding-left: 36px;
opacity: 0.65;
}
\ No newline at end of file
......
......@@ -50,8 +50,8 @@
<td colId="timeout" sortable>Timeout </td>
<td colId="permanent" sortable>Permanent </td>
<td colId="state" sortable>State </td>
<td colId="packets" sortable>Packets </td>
<td colId="bytes" sortable>Bytes </td>
<td class="right" colId="packets" sortable>Packets </td>
<td class="right" colId="bytes" sortable>Bytes </td>
</tr>
</table>
</div>
......@@ -74,8 +74,8 @@
<td>{{flow.timeout}}</td>
<td>{{flow.permanent}}</td>
<td>{{flow.state}}</td>
<td>{{flow.packets}}</td>
<td>{{flow.bytes}}</td>
<td class="right">{{flow.packets}}</td>
<td class="right">{{flow.bytes}}</td>
</tr>
<tr row-id="{{flow.id}}">
<td class="selector" colspan="10">{{flow.selector}}</td>
......
......@@ -70,7 +70,14 @@
background-color: #5A5600;
}
#ov-group td {
text-align: center;
}
#ov-group td.right {
text-align: right;
}
#ov-group td.buckets {
text-align: left;
padding-left: 36px;
opacity: 0.65;
}
......
......@@ -46,8 +46,8 @@
<td colId="app_id" sortable>App ID </td>
<td colId="state" sortable>State </td>
<td colId="type" sortable>Type </td>
<td colId="packets" sortable>Packets </td>
<td colId="bytes" sortable>Bytes </td>
<td class="right" colId="packets" sortable>Packets </td>
<td class="right" colId="bytes" sortable>Bytes </td>
</tr>
</table>
</div>
......@@ -66,8 +66,8 @@
<td>{{group.app_id}}</td>
<td>{{group.state}}</td>
<td>{{group.type}}</td>
<td>{{group.packets}}</td>
<td>{{group.bytes}}</td>
<td class="right">{{group.packets}}</td>
<td class="right">{{group.bytes}}</td>
</tr>
<tr row-id="{{group.id}}" ng-repeat-end>
<td class="buckets" colspan="6"
......
......@@ -70,7 +70,14 @@
background-color: #5A5600;
}
#ov-meter td {
text-align: center;
}
#ov-meter td.right {
text-align: right;
}
#ov-meter td.bands {
text-align: left;
padding-left: 36px;
opacity: 0.65;
}
\ No newline at end of file
......
......@@ -45,8 +45,8 @@
<td colId="id" sortable>Meter ID </td>
<td colId="app_id" sortable>App ID </td>
<td colId="state" sortable>State </td>
<td colId="packets" sortable>Packets </td>
<td colId="bytes" sortable>Bytes </td>
<td class="right" colId="packets" sortable>Packets </td>
<td class="right" colId="bytes" sortable>Bytes </td>
</tr>
</table>
</div>
......@@ -64,8 +64,8 @@
<td>{{meter.id}}</td>
<td>{{meter.app_id}}</td>
<td>{{meter.state}}</td>
<td>{{meter.packets}}</td>
<td>{{meter.bytes}}</td>
<td class="right">{{meter.packets}}</td>
<td class="right">{{meter.bytes}}</td>
</tr>
<tr row-id="{{meter.id}}" ng-repeat-end>
<td class="bands" colspan="5"
......
......@@ -40,6 +40,9 @@
}
#ov-port td {
text-align: center;
}
#ov-port td.right {
text-align: right;
}
......
......@@ -43,13 +43,13 @@
<table>
<tr>
<td colId="id" col-width="60px" sortable>Port ID </td>
<td colId="pkt_rx" sortable>Pkts Received </td>
<td colId="pkt_tx" sortable>Pkts Sent </td>
<td colId="bytes_rx" sortable>Bytes Received </td>
<td colId="bytes_tx" sortable>Bytes Sent </td>
<td colId="pkt_rx_drp" sortable>Pkts Received Dropped </td>
<td colId="pkt_tx_drp" sortable>Pkts Sent Dropped </td>
<td colId="duration" sortable>Duration (sec) </td>
<td class="right" colId="pkt_rx" sortable>Pkts Received </td>
<td class="right" colId="pkt_tx" sortable>Pkts Sent </td>
<td class="right" colId="bytes_rx" sortable>Bytes Received </td>
<td class="right" colId="bytes_tx" sortable>Bytes Sent </td>
<td class="right" colId="pkt_rx_drp" sortable>Pkts Received Dropped </td>
<td class="right" colId="pkt_tx_drp" sortable>Pkts Sent Dropped </td>
<td class="right" colId="duration" sortable>Duration (sec) </td>
</tr>
</table>
</div>
......@@ -65,13 +65,13 @@
<tr ng-repeat="port in tableData track by $index"
ng-repeat-complete row-id="{{port.id}}">
<td>{{port.id}}</td>
<td>{{port.pkt_rx}}</td>
<td>{{port.pkt_tx}}</td>
<td>{{port.bytes_rx}}</td>
<td>{{port.bytes_tx}}</td>
<td>{{port.pkt_rx_drp}}</td>
<td>{{port.pkt_tx_drp}}</td>
<td>{{port.duration}}</td>
<td class="right">{{port.pkt_rx}}</td>
<td class="right">{{port.pkt_tx}}</td>
<td class="right">{{port.bytes_rx}}</td>
<td class="right">{{port.bytes_tx}}</td>
<td class="right">{{port.pkt_rx_drp}}</td>
<td class="right">{{port.pkt_tx_drp}}</td>
<td class="right">{{port.duration}}</td>
</tr>
</table>
</div>
......