Simon Hunt

ONOS-4733: Simplified Settings Table view (removed redundant data)

 - Now shows just simple class name for component
 - Removed default value column
 - Values that are *not* the same as the default are highlighted (emboldened)
 - Table rows now selectable and show details panel
     - panel shows component fully qualified class name
     - panel currently read-only
     - in future, user will be able to change the property value from here

Change-Id: I01a2af727dcfad82c6b7d2378701a5cb3e24e43a
......@@ -36,14 +36,17 @@ public class SettingsViewMessageHandler extends UiMessageHandler {
private static final String SETTINGS = "settings";
private static final String COMPONENT = "component";
private static final String FQ_COMPONENT = "fqComponent";
private static final String ID = "id";
private static final String TYPE = "type";
private static final String VALUE = "value";
private static final String DEFAULT = "defValue";
private static final String DESC = "desc";
private static final char DOT = '.';
private static final String[] COL_IDS = {
COMPONENT, ID, TYPE, VALUE, DEFAULT, DESC
COMPONENT, FQ_COMPONENT, ID, TYPE, VALUE, DEFAULT, DESC
};
@Override
......@@ -90,13 +93,25 @@ public class SettingsViewMessageHandler extends UiMessageHandler {
}
}
private void populateRow(TableModel.Row row, String component, ConfigProperty prop) {
row.cell(COMPONENT, component)
private void populateRow(TableModel.Row row, String fqComp,
ConfigProperty prop) {
row.cell(COMPONENT, simpleName(fqComp))
.cell(FQ_COMPONENT, fqComp)
.cell(ID, prop.name())
.cell(TYPE, prop.type().toString().toLowerCase())
.cell(TYPE, typeName(prop))
.cell(VALUE, prop.value())
.cell(DEFAULT, prop.defaultValue())
.cell(DESC, prop.description());
}
// return just simple class name: "a.b.c.MyClass" -> "MyClass"
private String simpleName(String component) {
int lastDot = component.lastIndexOf(DOT);
return lastDot < 0 ? component : component.substring(lastDot + 1);
}
private String typeName(ConfigProperty prop) {
return prop.type().toString().toLowerCase();
}
}
}
......
......@@ -470,7 +470,7 @@
});
ks.gestureNotes([
['click', 'Select a row to show application details'],
['scroll down', 'See more application']
['scroll down', 'See more applications']
]);
// if the panelData changes
......
......@@ -25,3 +25,41 @@
#ov-settings div.ctrl-btns {
width: 45px;
}
#ov-settings div.summary-list td.notdef {
color: #0071bd;
font-weight: bold;
}
#settings-details-panel .container {
padding: 0 30px;
overflow-y: scroll;
}
#settings-details-panel .close-btn {
position: absolute;
right: 26px;
top: 26px;
cursor: pointer;
}
#settings-details-panel .top .settings-title {
width: 90%;
height: 62px;
font-size: 20pt;
font-weight: lighter;
overflow: hidden;
white-space: nowrap;
padding: 0 12px 0 2px;
margin-top: 19px;
margin-bottom: 5px;
}
#settings-details-panel td.label {
font-weight: bold;
text-align: right;
font-size: 12pt;
padding-right: 6px;
vertical-align: top;
width: 120px;
}
......
......@@ -14,11 +14,10 @@
<div class="table-header" onos-sortable-header>
<table>
<tr>
<td colId="component" sortable col-width="300px">Component </td>
<td colId="id" sortable col-width="240px">Property </td>
<td colId="component" sortable col-width="260px">Component </td>
<td colId="id" sortable col-width="260px">Property </td>
<td colId="type" sortable col-width="100px">Type </td>
<td colId="value" sortable col-width="100px">Value </td>
<td colId="defValue" sortable col-width="100px">Default </td>
<td colId="desc">Description </td>
</tr>
</table>
......@@ -33,17 +32,21 @@
</tr>
<tr ng-repeat="prop in tableData track by $index"
ng-click="selectCallback($event, prop)"
ng-class="{selected: prop.id === selId}"
ng-repeat-complete row-id="{{prop.id}}">
<td>{{prop.component}}</td>
<td>{{prop.id}}</td>
<td>{{prop.type}}</td>
<td>{{prop.value}}</td>
<td>{{prop.defValue}}</td>
<td ng-class="{notdef: prop.value !== prop.defValue}">
{{prop.value}}
</td>
<td>{{prop.desc}}</td>
</tr>
</table>
</div>
</div>
<settings-details-panel></settings-details-panel>
</div>
......
......@@ -21,16 +21,215 @@
(function () {
'use strict';
// injected refs
var $log, $scope, wss, fs, ks, ps, is;
// internal state
var detailsPanel,
panelData,
top,
pStartY,
pHeight,
wSize = false;
// constants
var pName = 'settings-details-panel',
panelWidth = 540,
topPdg = 60,
propOrder = ['fqComponent', 'id', 'type', 'value', 'defValue', 'desc'],
friendlyProps = [
'Component', 'Property', 'Type', 'Value', 'Default Value',
'Description'
];
function createDetailsPanel() {
detailsPanel = ps.createPanel(pName, {
width: wSize.width,
margin: 0,
hideMargin: 0
});
detailsPanel.el().style({
position: 'absolute',
top: pStartY + 'px'
});
detailsPanel.hide();
}
function closePanel() {
if (detailsPanel.isVisible()) {
$scope.selId = null;
panelData = null;
detailsPanel.hide();
return true;
}
return false;
}
function addCloseBtn(div) {
is.loadEmbeddedIcon(div, 'close', 26);
div.on('click', closePanel);
}
function setUpPanel() {
var container, closeBtn, div;
detailsPanel.empty();
detailsPanel.width(panelWidth);
container = detailsPanel.append('div').classed('container', true);
top = container.append('div').classed('top', true);
closeBtn = top.append('div').classed('close-btn', true);
addCloseBtn(closeBtn);
div = top.append('div').classed('top-content', true);
function ndiv(cls, addTable) {
var d = div.append('div').classed(cls, true);
if (addTable) {
d.append('table');
}
}
ndiv('settings-title');
ndiv('settings-props', true);
}
function addProp(tbody, index, value) {
var tr = tbody.append('tr');
function addCell(cls, txt) {
tr.append('td').attr('class', cls).html(txt);
}
addCell('label', friendlyProps[index] + ':');
addCell('value', value);
}
function populateTop(details) {
var propsBody = top.select('.settings-props').append('tbody');
top.select('.settings-title').text(details.id);
propOrder.forEach(function (prop, i) {
addProp(propsBody, i, details[prop]);
});
}
function populateDetails() {
setUpPanel();
populateTop(panelData);
detailsPanel.height(pHeight);
}
angular.module('ovSettings', [])
.controller('OvSettingsCtrl',
['$log', '$scope', 'TableBuilderService',
['$log', '$scope',
'WebSocketService', 'FnService', 'KeyService', 'PanelService',
'IconService', 'TableBuilderService',
function (_$log_, _$scope_, _wss_, _fs_, _ks_, _ps_, _is_, tbs) {
$log = _$log_;
$scope = _$scope_;
wss = _wss_;
fs = _fs_;
ks = _ks_;
ps = _ps_;
is = _is_;
$scope.panelData = {};
function selCb($event, row) {
if ($scope.selId) {
panelData = row;
populateDetails();
detailsPanel.show();
} else {
panelData = null;
detailsPanel.hide();
}
}
function ($log, $scope, tbs) {
tbs.buildTable({
scope: $scope,
tag: 'setting'
tag: 'setting',
selCb: selCb
});
ks.keyBindings({
esc: [$scope.selectCallback, 'Deselect property'],
_helpFormat: ['esc']
});
ks.gestureNotes([
['click row', 'Select / deselect settings property'],
['scroll down', 'See more settings']
]);
$scope.$on('$destroy', function () {
ks.unbindKeys();
});
$log.log('OvSettingsCtrl has been created');
}])
.directive('settingsDetailsPanel',
['$rootScope', '$window', '$timeout', 'KeyService',
function ($rootScope, $window, $timeout, ks) {
return function (scope) {
var unbindWatch;
function heightCalc() {
pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
+ topPdg;
wSize = fs.windowSize(pStartY);
pHeight = wSize.height;
}
function initPanel() {
heightCalc();
createDetailsPanel();
$log.debug('start to initialize panel!');
}
// Safari has a bug where it renders the fixed-layout table wrong
// if you ask for the window's size too early
if (scope.onos.browser === 'safari') {
$timeout(initPanel);
} else {
initPanel();
}
// create key bindings to handle panel
ks.keyBindings({
esc: [closePanel, 'Close the details panel'],
_helpFormat: ['esc']
});
ks.gestureNotes([
['click', 'Select a row to show property details'],
['scroll down', 'See more properties']
]);
// if the window size changes
unbindWatch = $rootScope.$watchCollection(
function () {
return {
h: $window.innerHeight,
w: $window.innerWidth
};
}, function () {
if (panelData) {
heightCalc();
populateDetails();
}
}
);
scope.$on('$destroy', function () {
panelData = null;
unbindWatch();
ks.unbindKeys();
ps.destroyPanel(pName);
});
};
}]);
}());
......