ONOS-3780: Table model now handles two column sorts.
Change-Id: I8899d56fdca2084e4a7ca0392c21d14f1bc6ea62
diff --git a/core/api/src/main/java/org/onosproject/ui/table/TableModel.java b/core/api/src/main/java/org/onosproject/ui/table/TableModel.java
index bf5d95d..2b57b9e 100644
--- a/core/api/src/main/java/org/onosproject/ui/table/TableModel.java
+++ b/core/api/src/main/java/org/onosproject/ui/table/TableModel.java
@@ -52,6 +52,7 @@
private static final CellComparator DEF_CMP = DefaultCellComparator.INSTANCE;
private static final CellFormatter DEF_FMT = DefaultCellFormatter.INSTANCE;
+ private static final String EMPTY = "";
private final String[] columnIds;
private final Set<String> idSet;
@@ -206,14 +207,17 @@
}
/**
- * Sorts the table rows based on the specified column, in the
- * specified direction.
+ * Sorts the table rows based on the specified columns, in the
+ * specified directions. The second column is optional, and can be
+ * disregarded by passing null into id2 and dir2.
*
- * @param columnId column identifier
- * @param dir sort direction
+ * @param id1 first column identifier
+ * @param dir1 first column sort direction
+ * @param id2 second column identifier (may be null)
+ * @param dir2 second column sort direction (may be null)
*/
- public void sort(String columnId, SortDir dir) {
- Collections.sort(rows, new RowComparator(columnId, dir));
+ public void sort(String id1, SortDir dir1, String id2, SortDir dir2) {
+ Collections.sort(rows, new RowComparator(id1, dir1, id2, dir2));
}
@@ -225,33 +229,54 @@
DESC
}
+ private boolean nullOrEmpty(String s) {
+ return s == null || EMPTY.equals(s.trim());
+ }
+
/**
* Row comparator.
*/
private class RowComparator implements Comparator<Row> {
- private final String columnId;
- private final SortDir dir;
- private final CellComparator cellComparator;
+ private final String id1;
+ private final SortDir dir1;
+ private final String id2;
+ private final SortDir dir2;
+ private final CellComparator cc1;
+ private final CellComparator cc2;
/**
* Constructs a row comparator based on the specified
- * column identifier and sort direction.
+ * column identifiers and sort directions. Note that id2 and dir2 may
+ * be null.
*
- * @param columnId column identifier
- * @param dir sort direction
+ * @param id1 first column identifier
+ * @param dir1 first column sort direction
+ * @param id2 second column identifier
+ * @param dir2 second column sort direction
*/
- public RowComparator(String columnId, SortDir dir) {
- this.columnId = columnId;
- this.dir = dir;
- cellComparator = getComparator(columnId);
+ public RowComparator(String id1, SortDir dir1, String id2, SortDir dir2) {
+ this.id1 = id1;
+ this.dir1 = dir1;
+ this.id2 = id2;
+ this.dir2 = dir2;
+ cc1 = getComparator(id1);
+ cc2 = nullOrEmpty(id2) ? null : getComparator(id2);
}
@Override
public int compare(Row a, Row b) {
- Object cellA = a.get(columnId);
- Object cellB = b.get(columnId);
- int result = cellComparator.compare(cellA, cellB);
- return dir == SortDir.ASC ? result : -result;
+ Object cellA = a.get(id1);
+ Object cellB = b.get(id1);
+ int result = cc1.compare(cellA, cellB);
+ result = dir1 == SortDir.ASC ? result : -result;
+
+ if (result == 0 && cc2 != null) {
+ cellA = a.get(id2);
+ cellB = b.get(id2);
+ result = cc2.compare(cellA, cellB);
+ result = dir2 == SortDir.ASC ? result : -result;
+ }
+ return result;
}
}
diff --git a/core/api/src/main/java/org/onosproject/ui/table/TableRequestHandler.java b/core/api/src/main/java/org/onosproject/ui/table/TableRequestHandler.java
index 5cbf01f..f47366c 100644
--- a/core/api/src/main/java/org/onosproject/ui/table/TableRequestHandler.java
+++ b/core/api/src/main/java/org/onosproject/ui/table/TableRequestHandler.java
@@ -20,13 +20,23 @@
import org.onosproject.ui.JsonUtils;
import org.onosproject.ui.RequestHandler;
+import static org.onosproject.ui.table.TableModel.sortDir;
+
/**
* Message handler specifically for table views.
*/
public abstract class TableRequestHandler extends RequestHandler {
+ private static final String FIRST_COL = "firstCol";
+ private static final String FIRST_DIR = "firstDir";
+ private static final String SECOND_COL = "secondCol";
+ private static final String SECOND_DIR = "secondDir";
+
+ private static final String ASC = "asc";
+
private static final String ANNOTS = "annots";
private static final String NO_ROWS_MSG_KEY = "no_rows_msg";
+
private final String respType;
private final String nodeName;
@@ -51,9 +61,11 @@
TableModel tm = createTableModel();
populateTable(tm, payload);
- String sortCol = JsonUtils.string(payload, "sortCol", defaultColumnId());
- String sortDir = JsonUtils.string(payload, "sortDir", "asc");
- tm.sort(sortCol, TableModel.sortDir(sortDir));
+ String firstCol = JsonUtils.string(payload, FIRST_COL, defaultColumnId());
+ String firstDir = JsonUtils.string(payload, FIRST_DIR, ASC);
+ String secondCol = JsonUtils.string(payload, SECOND_COL, null);
+ String secondDir = JsonUtils.string(payload, SECOND_DIR, null);
+ tm.sort(firstCol, sortDir(firstDir), secondCol, sortDir(secondDir));
addTableConfigAnnotations(tm, payload);
diff --git a/core/api/src/test/java/org/onosproject/ui/table/TableModelTest.java b/core/api/src/test/java/org/onosproject/ui/table/TableModelTest.java
index 8c79a05..907ceff 100644
--- a/core/api/src/test/java/org/onosproject/ui/table/TableModelTest.java
+++ b/core/api/src/test/java/org/onosproject/ui/table/TableModelTest.java
@@ -35,6 +35,9 @@
private static final String FOO = "foo";
private static final String BAR = "bar";
private static final String ZOO = "zoo";
+ private static final String ID = "id";
+ private static final String ALPHA = "alpha";
+ private static final String NUMBER = "number";
private enum StarWars {
LUKE_SKYWALKER, LEIA_ORGANA, HAN_SOLO, C3PO, R2D2, JABBA_THE_HUTT
@@ -191,7 +194,7 @@
initUnsortedTable();
// sort by name
- tm.sort(FOO, SortDir.ASC);
+ tm.sort(FOO, SortDir.ASC, null, null);
// verify results
rows = tm.getRows();
@@ -202,7 +205,7 @@
}
// now the other way
- tm.sort(FOO, SortDir.DESC);
+ tm.sort(FOO, SortDir.DESC, null, null);
// verify results
rows = tm.getRows();
@@ -219,7 +222,7 @@
initUnsortedTable();
// sort by number
- tm.sort(BAR, SortDir.ASC);
+ tm.sort(BAR, SortDir.ASC, null, null);
// verify results
rows = tm.getRows();
@@ -230,7 +233,7 @@
}
// now the other way
- tm.sort(BAR, SortDir.DESC);
+ tm.sort(BAR, SortDir.DESC, null, null);
// verify results
rows = tm.getRows();
@@ -250,7 +253,7 @@
tm.setFormatter(BAR, HexFormatter.INSTANCE);
// sort by number
- tm.sort(BAR, SortDir.ASC);
+ tm.sort(BAR, SortDir.ASC, null, null);
// verify results
rows = tm.getRows();
@@ -276,7 +279,7 @@
public void sortAndFormatTwo() {
initUnsortedTable();
tm.setFormatter(BAR, HexFormatter.INSTANCE);
- tm.sort(FOO, SortDir.ASC);
+ tm.sort(FOO, SortDir.ASC, null, null);
rows = tm.getRows();
int nr = rows.length;
for (int i = 0; i < nr; i++) {
@@ -324,7 +327,7 @@
tm.addRow().cell(FOO, StarWars.R2D2);
tm.addRow().cell(FOO, StarWars.LUKE_SKYWALKER);
- tm.sort(FOO, SortDir.ASC);
+ tm.sort(FOO, SortDir.ASC, null, null);
// verify expected results
StarWars[] ordered = StarWars.values();
@@ -336,6 +339,102 @@
}
}
+
+ // ------------------------
+ // Second sort column tests
+
+ private static final String A1 = "a1";
+ private static final String A2 = "a2";
+ private static final String A3 = "a3";
+ private static final String B1 = "b1";
+ private static final String B2 = "b2";
+ private static final String B3 = "b3";
+ private static final String C1 = "c1";
+ private static final String C2 = "c2";
+ private static final String C3 = "c3";
+ private static final String A = "A";
+ private static final String B = "B";
+ private static final String C = "C";
+
+ private static final String[] UNSORTED_IDS = {
+ A3, B2, A1, C2, A2, C3, B1, C1, B3
+ };
+ private static final String[] UNSORTED_ALPHAS = {
+ A, B, A, C, A, C, B, C, B
+ };
+ private static final int[] UNSORTED_NUMBERS = {
+ 3, 2, 1, 2, 2, 3, 1, 1, 3
+ };
+
+ private static final String[] ROW_ORDER_AA_NA = {
+ A1, A2, A3, B1, B2, B3, C1, C2, C3
+ };
+ private static final String[] ROW_ORDER_AD_NA = {
+ C1, C2, C3, B1, B2, B3, A1, A2, A3
+ };
+ private static final String[] ROW_ORDER_AA_ND = {
+ A3, A2, A1, B3, B2, B1, C3, C2, C1
+ };
+ private static final String[] ROW_ORDER_AD_ND = {
+ C3, C2, C1, B3, B2, B1, A3, A2, A1
+ };
+
+ private void testAddRow(TableModel tm, int index) {
+ tm.addRow().cell(ID, UNSORTED_IDS[index])
+ .cell(ALPHA, UNSORTED_ALPHAS[index])
+ .cell(NUMBER, UNSORTED_NUMBERS[index]);
+ }
+
+ private TableModel unsortedDoubleTableModel() {
+ tm = new TableModel(ID, ALPHA, NUMBER);
+ for (int i = 0; i < 9; i++) {
+ testAddRow(tm, i);
+ }
+ return tm;
+ }
+
+ private void verifyRowOrder(String tag, TableModel tm, String[] rowOrder) {
+ int i = 0;
+ for (TableModel.Row row : tm.getRows()) {
+ assertEquals(tag + ": unexpected row id", rowOrder[i++], row.get(ID));
+ }
+ }
+
+ @Test
+ public void sortAlphaAscNumberAsc() {
+ tm = unsortedDoubleTableModel();
+ verifyRowOrder("unsorted", tm, UNSORTED_IDS);
+ tm.sort(ALPHA, SortDir.ASC, NUMBER, SortDir.ASC);
+ verifyRowOrder("aana", tm, ROW_ORDER_AA_NA);
+ }
+
+ @Test
+ public void sortAlphaDescNumberAsc() {
+ tm = unsortedDoubleTableModel();
+ verifyRowOrder("unsorted", tm, UNSORTED_IDS);
+ tm.sort(ALPHA, SortDir.DESC, NUMBER, SortDir.ASC);
+ verifyRowOrder("adna", tm, ROW_ORDER_AD_NA);
+ }
+
+ @Test
+ public void sortAlphaAscNumberDesc() {
+ tm = unsortedDoubleTableModel();
+ verifyRowOrder("unsorted", tm, UNSORTED_IDS);
+ tm.sort(ALPHA, SortDir.ASC, NUMBER, SortDir.DESC);
+ verifyRowOrder("aand", tm, ROW_ORDER_AA_ND);
+ }
+
+ @Test
+ public void sortAlphaDescNumberDesc() {
+ tm = unsortedDoubleTableModel();
+ verifyRowOrder("unsorted", tm, UNSORTED_IDS);
+ tm.sort(ALPHA, SortDir.DESC, NUMBER, SortDir.DESC);
+ verifyRowOrder("adnd", tm, ROW_ORDER_AD_ND);
+ }
+
+ // ----------------
+ // Annotation tests
+
@Test
public void stringAnnotation() {
tm = new TableModel(FOO);
diff --git a/web/gui/src/main/webapp/app/fw/svg/icon.js b/web/gui/src/main/webapp/app/fw/svg/icon.js
index e797f8a..4bc1ffa 100644
--- a/web/gui/src/main/webapp/app/fw/svg/icon.js
+++ b/web/gui/src/main/webapp/app/fw/svg/icon.js
@@ -209,26 +209,16 @@
}
function sortIcons() {
- function sortAsc(div) {
+ function _s(div, gid) {
div.style('display', 'inline-block');
- loadEmbeddedIcon(div, 'upArrow', 10);
+ loadEmbeddedIcon(div, gid, 10);
div.classed('tableColSort', true);
}
- function sortDesc(div) {
- div.style('display', 'inline-block');
- loadEmbeddedIcon(div, 'downArrow', 10);
- div.classed('tableColSort', true);
- }
-
- function sortNone(div) {
- div.remove();
- }
-
return {
- sortAsc: sortAsc,
- sortDesc: sortDesc,
- sortNone: sortNone
+ asc: function (div) { _s(div, 'upArrow'); },
+ desc: function (div) { _s(div, 'downArrow'); },
+ none: function (div) { div.remove(); }
};
}
diff --git a/web/gui/src/main/webapp/app/fw/widget/table.js b/web/gui/src/main/webapp/app/fw/widget/table.js
index 327aedb..29098c4 100644
--- a/web/gui/src/main/webapp/app/fw/widget/table.js
+++ b/web/gui/src/main/webapp/app/fw/widget/table.js
@@ -28,16 +28,11 @@
pdg = 22,
flashTime = 1500,
colWidth = 'col-width',
- tableIcon = 'table-icon',
- asc = 'asc',
- desc = 'desc',
- none = 'none';
+ tableIcon = 'table-icon';
// internal state
- var currCol = {},
- prevCol = {},
- cstmWidths = {},
- sortIconAPI;
+ var cstmWidths = {},
+ api;
// Functions for resizing a tabular view to the window
@@ -94,179 +89,208 @@
}
}
+ // sort columns state model and functions
+ var sortState = {
+ s: {
+ first: null,
+ second: null,
+ touched: null
+ },
+
+ reset: function () {
+ var s = sortState.s;
+ s.first && api.none(s.first.adiv);
+ s.second && api.none(s.second.adiv);
+ sortState.s = { first: null, second: null, touched: null };
+ },
+
+ touch: function (id, adiv) {
+ var s = sortState.s,
+ s1 = s.first,
+ d;
+
+ if (!s.touched) {
+ s.first = { id: id, dir: 'asc', adiv: adiv };
+ s.touched = id;
+ } else {
+ if (id === s.touched) {
+ d = s1.dir === 'asc' ? 'desc' : 'asc';
+ s1.dir = d;
+ s1.adiv = adiv;
+
+ } else {
+ s.second = s.first;
+ s.first = { id: id, dir: 'asc', adiv: adiv };
+ s.touched = id;
+ }
+ }
+ },
+
+ update: function () {
+ var s = sortState.s,
+ s1 = s.first,
+ s2 = s.second;
+ api[s1.dir](s1.adiv);
+ s2 && api.none(s2.adiv);
+ }
+ };
+
// Functions for sorting table rows by header
function updateSortDirection(thElem) {
- sortIconAPI.sortNone(thElem.select('div'));
- currCol.div = thElem.append('div');
- currCol.colId = thElem.attr('colId');
+ var adiv = thElem.select('div'),
+ id = thElem.attr('colId');
- if (currCol.colId === prevCol.colId) {
- (currCol.dir === desc) ? currCol.dir = asc : currCol.dir = desc;
- prevCol.dir = currCol.dir;
- } else {
- currCol.dir = asc;
- prevCol.dir = none;
- }
- (currCol.dir === asc) ?
- sortIconAPI.sortAsc(currCol.div) : sortIconAPI.sortDesc(currCol.div);
-
- if (prevCol.colId && prevCol.dir === none) {
- sortIconAPI.sortNone(prevCol.div);
- }
-
- prevCol.colId = currCol.colId;
- prevCol.div = currCol.div;
+ api.none(adiv);
+ adiv = thElem.append('div');
+ sortState.touch(id, adiv);
+ sortState.update();
}
function sortRequestParams() {
+ var s = sortState.s,
+ s1 = s.first,
+ s2 = s.second,
+ id2 = s2 && s2.id,
+ dir2 = s2 && s2.dir;
return {
- sortCol: currCol.colId,
- sortDir: currCol.dir
+ firstCol: s1.id,
+ firstDir: s1.dir,
+ secondCol: id2,
+ secondDir: dir2
};
}
- function resetSort() {
- if (currCol.div) {
- sortIconAPI.sortNone(currCol.div);
- }
- if (prevCol.div) {
- sortIconAPI.sortNone(prevCol.div);
- }
- currCol = {};
- prevCol = {};
- }
-
angular.module('onosWidget')
- .directive('onosTableResize', ['$log','$window',
- 'FnService', 'MastService',
+ .directive('onosTableResize', ['$log','$window', 'FnService', 'MastService',
- function (_$log_, _$window_, _fs_, _mast_) {
- return function (scope, element) {
- $log = _$log_;
- $window = _$window_;
- fs = _fs_;
- mast = _mast_;
+ function (_$log_, _$window_, _fs_, _mast_) {
+ return function (scope, element) {
+ $log = _$log_;
+ $window = _$window_;
+ fs = _fs_;
+ mast = _mast_;
- var table = d3.select(element[0]),
- tableElems = {
- table: table,
- thead: table.select('.table-header').select('table'),
- tbody: table.select('.table-body').select('table')
- },
- wsz;
+ var table = d3.select(element[0]),
+ tableElems = {
+ table: table,
+ thead: table.select('.table-header').select('table'),
+ tbody: table.select('.table-body').select('table')
+ },
+ wsz;
- findCstmWidths(table);
+ findCstmWidths(table);
- // adjust table on window resize
- scope.$watchCollection(function () {
- return {
- h: $window.innerHeight,
- w: $window.innerWidth
- };
- }, function () {
- wsz = fs.windowSize(0, 30);
- adjustTable(
- scope.tableData.length,
- tableElems,
- wsz.width, wsz.height
- );
- });
+ // adjust table on window resize
+ scope.$watchCollection(function () {
+ return {
+ h: $window.innerHeight,
+ w: $window.innerWidth
+ };
+ }, function () {
+ wsz = fs.windowSize(0, 30);
+ adjustTable(
+ scope.tableData.length,
+ tableElems,
+ wsz.width, wsz.height
+ );
+ });
- // adjust table when data changes
- scope.$watchCollection('tableData', function () {
- adjustTable(
- scope.tableData.length,
- tableElems,
- wsz.width, wsz.height
- );
- });
+ // adjust table when data changes
+ scope.$watchCollection('tableData', function () {
+ adjustTable(
+ scope.tableData.length,
+ tableElems,
+ wsz.width, wsz.height
+ );
+ });
- scope.$on('$destroy', function () {
- cstmWidths = {};
- });
- };
- }])
+ scope.$on('$destroy', function () {
+ cstmWidths = {};
+ });
+ };
+ }])
- .directive('onosSortableHeader', ['$log', 'IconService',
- function (_$log_, _is_) {
- return function (scope, element) {
- $log = _$log_;
- is = _is_;
- var header = d3.select(element[0]);
- sortIconAPI = is.sortIcons();
+ .directive('onosSortableHeader', ['$log', 'IconService',
+ function (_$log_, _is_) {
+ return function (scope, element) {
+ $log = _$log_;
+ is = _is_;
+ var header = d3.select(element[0]);
- header.selectAll('td').on('click', function () {
- var col = d3.select(this);
+ api = is.sortIcons();
- if (col.attr('sortable') === '') {
- updateSortDirection(col);
- scope.sortParams = sortRequestParams();
- scope.sortCallback(scope.sortParams);
- }
- });
+ header.selectAll('td').on('click', function () {
+ var col = d3.select(this);
- scope.$on('$destroy', function () {
- resetSort();
- });
- };
- }])
-
- .directive('onosFlashChanges',
- ['$log', '$parse', '$timeout', 'FnService',
- function ($log, $parse, $timeout, fs) {
-
- return function (scope, element, attrs) {
- var idProp = attrs.idProp,
- table = d3.select(element[0]),
- trs, promise;
-
- function highlightRows() {
- var changedRows = [];
- function classRows(b) {
- if (changedRows.length) {
- angular.forEach(changedRows, function (tr) {
- tr.classed('data-change', b);
- });
- }
- }
- // timeout because 'row-id' was the un-interpolated value
- // "{{link.one}}" for example, instead of link.one evaluated
- // timeout executes on the next digest -- after evaluation
- $timeout(function () {
- if (scope.tableData.length) {
- trs = table.selectAll('tr');
- }
-
- if (trs && !trs.empty()) {
- trs.each(function () {
- var tr = d3.select(this);
- if (fs.find(tr.attr('row-id'),
- scope.changedData,
- idProp) > -1) {
- changedRows.push(tr);
- }
- });
- classRows(true);
- promise = $timeout(function () {
- classRows(false);
- }, flashTime);
- trs = undefined;
- }
- });
+ if (col.attr('sortable') === '') {
+ updateSortDirection(col);
+ scope.sortParams = sortRequestParams();
+ scope.sortCallback(scope.sortParams);
}
+ });
- // new items added:
- scope.$on('ngRepeatComplete', highlightRows);
- // items changed in existing set:
- scope.$watchCollection('changedData', highlightRows);
+ scope.$on('$destroy', function () {
+ sortState.reset();
+ });
+ };
+ }])
- scope.$on('$destroy', function () {
- if (promise) {
- $timeout.cancel(promise);
+ .directive('onosFlashChanges',
+ ['$log', '$parse', '$timeout', 'FnService',
+ function ($log, $parse, $timeout, fs) {
+
+ return function (scope, element, attrs) {
+ var idProp = attrs.idProp,
+ table = d3.select(element[0]),
+ trs, promise;
+
+ function highlightRows() {
+ var changedRows = [];
+ function classRows(b) {
+ if (changedRows.length) {
+ angular.forEach(changedRows, function (tr) {
+ tr.classed('data-change', b);
+ });
+ }
+ }
+ // timeout because 'row-id' was the un-interpolated value
+ // "{{link.one}}" for example, instead of link.one evaluated
+ // timeout executes on the next digest -- after evaluation
+ $timeout(function () {
+ if (scope.tableData.length) {
+ trs = table.selectAll('tr');
+ }
+
+ if (trs && !trs.empty()) {
+ trs.each(function () {
+ var tr = d3.select(this);
+ if (fs.find(tr.attr('row-id'),
+ scope.changedData,
+ idProp) > -1) {
+ changedRows.push(tr);
+ }
+ });
+ classRows(true);
+ promise = $timeout(function () {
+ classRows(false);
+ }, flashTime);
+ trs = undefined;
}
});
- };
- }]);
+ }
+
+ // new items added:
+ scope.$on('ngRepeatComplete', highlightRows);
+ // items changed in existing set:
+ scope.$watchCollection('changedData', highlightRows);
+
+ scope.$on('$destroy', function () {
+ if (promise) {
+ $timeout.cancel(promise);
+ }
+ });
+ };
+ }]);
}());
diff --git a/web/gui/src/main/webapp/app/view/app/app.js b/web/gui/src/main/webapp/app/view/app/app.js
index 11473b6..c4166d1 100644
--- a/web/gui/src/main/webapp/app/view/app/app.js
+++ b/web/gui/src/main/webapp/app/view/app/app.js
@@ -77,8 +77,10 @@
respCb: refreshCtrls,
// pre-populate sort so active apps are at the top of the list
sortParams: {
- sortCol: 'state',
- sortDir: 'desc'
+ firstCol: 'state',
+ firstDir: 'desc',
+ secondCol: 'id',
+ secondDir: 'asc'
}
});
diff --git a/web/gui/src/main/webapp/app/view/device/device.html b/web/gui/src/main/webapp/app/view/device/device.html
index 9f9e37d..022984b 100644
--- a/web/gui/src/main/webapp/app/view/device/device.html
+++ b/web/gui/src/main/webapp/app/view/device/device.html
@@ -39,7 +39,7 @@
<table>
<tr>
<td colId="available" class="table-icon" sortable></td>
- <td colId="type" class="table-icon" sortable></td>
+ <td colId="type" class="table-icon"></td>
<td colId="name" sortable>Friendly Name </td>
<td colId="id" sortable>Device ID </td>
<td colId="masterid" sortable>Master Instance </td>
diff --git a/web/gui/src/main/webapp/app/view/host/host.html b/web/gui/src/main/webapp/app/view/host/host.html
index a103dac..6de96d5 100644
--- a/web/gui/src/main/webapp/app/view/host/host.html
+++ b/web/gui/src/main/webapp/app/view/host/host.html
@@ -14,7 +14,7 @@
<div class="table-header" onos-sortable-header>
<table>
<tr>
- <td colId="type" class="table-icon" sortable></td>
+ <td colId="type" class="table-icon"></td>
<td colId="id" sortable>Host ID </td>
<td colId="mac" sortable>MAC Address </td>
<td colId="vlan" sortable>VLAN ID </td>