GUI -- Application View Details Panel -
- simplified DOM structure
- refactored code to reduce boilerplate
- cleaned up CSS
Change-Id: Iff443d7f038f1f770e7b3e9ed383c65b96ba6886
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/ApplicationViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/ApplicationViewMessageHandler.java
index 5edca13..dca882e 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/ApplicationViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/ApplicationViewMessageHandler.java
@@ -58,7 +58,7 @@
private static final String URL = "url";
private static final String README = "readme";
private static final String ROLE = "role";
- private static final String REQUIRED_APPS = "_required_apps";
+ private static final String REQUIRED_APPS = "required_apps";
private static final String FEATURES = "features";
private static final String PERMISSIONS = "permissions";
@@ -175,13 +175,13 @@
// process required applications
ArrayNode requiredApps = arrayNode();
- app.requiredApps().forEach(s -> requiredApps.add(s));
+ app.requiredApps().forEach(requiredApps::add);
data.set(REQUIRED_APPS, requiredApps);
// process features
ArrayNode features = arrayNode();
- app.features().forEach(f -> features.add(f));
+ app.features().forEach(features::add);
data.set(FEATURES, features);
diff --git a/web/gui/src/main/webapp/app/view/app/app.css b/web/gui/src/main/webapp/app/view/app/app.css
index 4912809..eab45ef 100644
--- a/web/gui/src/main/webapp/app/view/app/app.css
+++ b/web/gui/src/main/webapp/app/view/app/app.css
@@ -15,7 +15,7 @@
*/
/*
- ONOS GUI -- Host View -- CSS file
+ ONOS GUI -- Applications View -- CSS file
*/
#ov-app h2 {
@@ -75,7 +75,7 @@
}
#application-details-panel .container {
- padding: 0 12px;
+ padding: 0 10px;
}
#application-details-panel .close-btn {
@@ -91,60 +91,48 @@
fill: #ccc;
}
-#application-details-panel .dev-icon {
+#application-details-panel .app-icon {
display: inline-block;
padding: 0 6px 0 0;
vertical-align: middle;
}
-.light .dev-icon svg.embeddedIcon .glyph {
- fill: rgb(0, 172, 229);
-}
-.dark .dev-icon svg.embeddedIcon .glyph {
- fill: #486D91;
-}
#application-details-panel h2 {
display: inline-block;
margin: 8px 0;
+ font-size: 12pt;
}
#application-details-panel .top div.left {
float: left;
- padding: 0 18px 0 0;
+ padding: 0 12px 0 0;
}
#application-details-panel .top div.right {
display: inline-block;
+ overflow: hidden;
+ width: 320px;
}
-#application-details-panel td.label {
+#application-details-panel td.label,
+#application-details-panel .app-url i {
font-style: italic;
padding-right: 12px;
/* works for both light and dark themes ... */
color: #777;
}
-#application-details-panel .actionBtns div {
- padding: 12px 6px;
+#application-details-panel td.value-bold {
+ font-weight: bold;
}
-#application-details-panel .top hr {
+#application-details-panel .app-url {
+ padding: 10px 6px 6px;
+}
+
+#application-details-panel hr {
width: 95%;
- margin: 0 auto;
+ margin: 10px auto;
}
-
-.light #application-details-panel hr {
- opacity: .5;
- border-color: #FFF;
-}
-.dark #application-details-panel hr {
- border-color: #666;
-}
-
-#application-details-panel .middle hr {
- width: 95%;
- margin: 0 auto;
-}
-
.light #application-details-panel hr {
opacity: .5;
border-color: #FFF;
@@ -155,25 +143,12 @@
#application-details-panel .bottom table {
border-spacing: 0;
+ width: 100%;
}
-#application-details-panel .bottom th {
- letter-spacing: 0.02em;
-}
-
-.light #application-details-panel .bottom th {
- background-color: #CCC;
- /* default text color */
-}
-.dark #application-details-panel .bottom th {
- background-color: #131313;
- color: #ccc;
-}
-
-#application-details-panel .bottom th,
#application-details-panel .bottom td {
padding: 6px 12px;
- text-align: center;
+ text-align: left;
}
.light #application-details-panel .bottom tr:nth-child(odd) {
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 16c1e72..7f620ae 100644
--- a/web/gui/src/main/webapp/app/view/app/app.js
+++ b/web/gui/src/main/webapp/app/view/app/app.js
@@ -22,7 +22,7 @@
'use strict';
// injected refs
- var $log, $scope, $loc, fs, ps, wss, is, ns, ks, is;
+ var $log, $scope, wss, fs, ks, ps, is;
// internal state
var detailsPanel,
@@ -31,7 +31,6 @@
top,
middle,
bottom,
- iconDiv,
wSize = false;
// constants
@@ -39,9 +38,7 @@
ACTIVE = 'ACTIVE',
appMgmtReq = 'appManagementRequest',
topPdg = 50,
- ctnrPdg = 24,
- tbWidth = 470,
- scrollSize = 17,
+ panelWidth = 500,
pName = 'application-details-panel',
detailsReq = 'appDetailsRequest',
detailsResp = 'appDetailsResponse',
@@ -57,8 +54,9 @@
},
discouragement = 'Deactivating or uninstalling this component can' +
' have serious negative consequences! Do so at your own risk!!',
- propOrder = ['id', 'state', 'category', 'version', 'origin', 'role', 'url'],
- friendlyProps = ['App ID', 'State', 'Category', 'Version', 'Origin', 'Role', 'URL'];
+ propOrder = ['id', 'state', 'category', 'version', 'origin', 'role'],
+ friendlyProps = ['App ID', 'State', 'Category', 'Version', 'Origin', 'Role'];
+ // note: url is handled separately
function createDetailsPane() {
detailsPanel = ps.createPanel(pName, {
@@ -90,158 +88,113 @@
}
function setUpPanel() {
- var container, closeBtn, tblDiv;
+ 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);
- iconDiv = top.append('div').classed('dev-icon', true);
- tblDiv = top.append('div').classed('top-tables', true);
- tblDiv.append('div').classed('left', true).append('table');
- tblDiv.append('div').classed('right', true).append('table');
- tblDiv.append('div').classed('description', true).append('table');
+ div = top.append('div').classed('top-content', true);
- top.append('hr');
+ function ndiv(cls, tcls) {
+ var d = div.append('div').classed(cls, true);
+ if (tcls) {
+ d.append('table').classed(tcls, true);
+ }
+ }
+
+ ndiv('left app-icon');
+ ndiv('right', 'app-props');
+ ndiv('app-url');
+
+ container.append('hr');
middle = container.append('div').classed('middle', true);
- tblDiv = middle.append('div').classed('middle-tables', true);
- tblDiv.append('div').classed('readme', true).append('table');
+ middle.append('div').classed('app-readme', true);
- middle.append('hr');
+ container.append('hr');
+ // TODO: make bottom container scrollable
bottom = container.append('div').classed('bottom', true);
- tblDiv = bottom.append('div').classed('bottom-tables', true).append('table');
- tblDiv.append('h2').html('Features');
- tblDiv.append('div').classed('features', true).append('table');
- tblDiv.append('h2').html('Required Apps');
- tblDiv.append('div').classed('required-apps', true).append('table');
- tblDiv.append('h2').html('Permissions');
- tblDiv.append('div').classed('permissions', true).append('table');
+
+ function nTable(hdr, cls) {
+ bottom.append('h2').html(hdr);
+ bottom.append('div').classed(cls, true).append('table');
+ }
+
+ nTable('Features', 'features');
+ nTable('Required Apps', 'required-apps');
+ nTable('Permissions', 'permissions');
}
function addProp(tbody, index, value) {
- var tr = tbody.append('tr');
+ var tr = tbody.append('tr'),
+ vcls = index ? 'value' : 'value-bold';
function addCell(cls, txt) {
tr.append('td').attr('class', cls).html(txt);
}
- addCell('label', friendlyProps[index] + ' :');
- addCell('value', value);
+
+ addCell('label', friendlyProps[index] + ':');
+ addCell(vcls, value);
}
- function addUrl(tbody, index, value) {
- var href = '<a href="' + value + '" target="_blank">' + value + '</a>';
- addProp(tbody, index, href);
+ function urlize(u) {
+ return '<i>URL:</i> <a href="' + u + '" target="_blank">' + u + '</a>';
}
- function addIcon(tbody, value) {
- var tr = tbody.append('tr');
- var td = tr.append('td');
- td.append('img').attr('src', iconUrlPrefix + value + iconUrlSuffix);
+ function addIcon(elem, value) {
+ elem.append('img').attr('src', iconUrlPrefix + value + iconUrlSuffix);
}
- function addContent(tbody, value) {
- var tr = tbody.append('tr');
- tr.append('td').html(value);
- }
+ function populateTop(details) {
+ var propsBody = top.select('.app-props').append('tbody'),
+ url = details.url;
- function populateTop(tblDiv, details) {
- var leftTbl = tblDiv.select('.left')
- .select('table')
- .append('tbody'),
- rightTbl = tblDiv.select('.right')
- .select('table')
- .append('tbody'),
- descriptionTbl = tblDiv.select('.description')
- .select('table')
- .append('tbody');
+ addIcon(top.select('.app-icon'), details.id);
- top.select('h2').html(details.name);
-
- // place application icon to the left table
- addIcon(leftTbl, details.id);
-
- // place rest of the fields to the right table
propOrder.forEach(function (prop, i) {
- var fn = prop === 'url' ? addUrl : addProp;
- fn(rightTbl, i, details[prop]);
+ addProp(propsBody, i, details[prop]);
});
- // place description field to the description table
- addContent(descriptionTbl, details.desc);
+ if (url) {
+ top.select('.app-url').html(urlize(url));
+ }
}
- function populateMiddle(tblDiv, details) {
- var readmeTbl = tblDiv.select('.readme')
- .select('table')
- .append('tbody');
-
- // place readme field to the readme table
- addContent(readmeTbl, details.readme);
+ function populateMiddle(details) {
+ middle.select('.app-readme').text(details.readme);
}
- function populateName(div, name) {
- var lab = div.select('.label'),
- val = div.select('.value');
- lab.html('Friendly Name:');
- val.html(name);
+ function populateBottom(details) {
+
+ function addItems(cls, items) {
+ var table = bottom.select('.' + cls).select('table'),
+ tbody = table.append('tbody');
+
+ items.forEach(function (item) {
+ tbody.append('tr').append('td').html(item);
+ });
+ }
+
+ addItems('features', details.features);
+ addItems('required-apps', details.required_apps);
+ addItems('permissions', details.permissions);
}
function populateDetails(details) {
- var nameDiv, topTbs, middleTbs, bottomTbs;
setUpPanel();
-
- nameDiv = top.select('.name-div');
- topTbs = top.select('.top-tables');
- middleTbs = middle.select('.middle-tables');
- bottomTbs = bottom.select('.bottom-tables');
-
- populateName(nameDiv, details.name);
- populateTop(topTbs, details);
- populateMiddle(middleTbs, details);
- populateBottom(bottomTbs, details);
-
+ populateTop(details);
+ populateMiddle(details);
+ populateBottom(details);
detailsPanel.height(pHeight);
}
- function addItem(tbody, item) {
- var tr = tbody.append('tr').attr('width', tbWidth + 'px');
- tr.append('td').attr('width', tbWidth + 'px')
- .attr('style', 'text-align:left').html(item);
- }
-
- function addItems(table, items) {
- var tbody = table.append('tbody');
- items.forEach(function (item) {
- addItem(tbody, item);
- });
- }
-
- function populateBottom(tblDiv, details) {
- var featuresTbl = tblDiv.select('.features')
- .select('table'),
- permissionsTbl = tblDiv.select('.permissions')
- .select('table'),
- requiredAppsTbl = tblDiv.select('.required-apps')
- .select('table');
-
- addItems(featuresTbl, details.features);
- addItems(requiredAppsTbl, details._required_apps);
- addItems(permissionsTbl, details.permissions);
-
- featuresTbl.style({
- width: tbWidth + 'px',
- overflow: 'auto',
- display: 'block'
- });
-
- detailsPanel.width(tbWidth + ctnrPdg);
- }
-
function respDetailsCb(data) {
$scope.panelData = data.details;
$scope.$apply();
@@ -250,15 +203,15 @@
angular.module('ovApp', [])
.controller('OvAppCtrl',
['$log', '$scope', '$http',
- 'FnService', 'TableBuilderService', 'PanelService', 'WebSocketService',
- 'IconService', 'UrlFnService', 'KeyService', 'DialogService',
+ 'WebSocketService', 'FnService', 'KeyService', 'PanelService',
+ 'IconService', 'UrlFnService', 'DialogService', 'TableBuilderService',
- function (_$log_, _$scope_, $http, _fs_, tbs, _ps_, _wss_, _is_, ufs, _ks_, ds) {
+ function (_$log_, _$scope_, $http, _wss_, _fs_, _ks_, _ps_, _is_, ufs, ds, tbs) {
$log = _$log_;
$scope = _$scope_;
wss = _wss_;
- ks = _ks_;
fs = _fs_;
+ ks = _ks_;
ps = _ps_;
is = _is_;
$scope.panelData = {};
@@ -285,7 +238,6 @@
} else {
$scope.hidePanel();
}
- $log.debug('Got a click on:', row);
}
function refreshCtrls() {
@@ -318,12 +270,12 @@
// TODO: reexamine where keybindings should be - directive or controller?
ks.keyBindings({
- esc: [$scope.selectCallback, 'Deselect app'],
+ esc: [$scope.selectCallback, 'Deselect application'],
_helpFormat: ['esc']
});
ks.gestureNotes([
- ['click row', 'Select / deselect app'],
- ['scroll down', 'See more apps']
+ ['click row', 'Select / deselect application'],
+ ['scroll down', 'See more applications']
]);
function createConfirmationText(action, itemId) {