GUI -- Application View Details Panel -
- simplified DOM structure - refactored code to reduce boilerplate - cleaned up CSS Change-Id: Iff443d7f038f1f770e7b3e9ed383c65b96ba6886
Showing
3 changed files
with
95 additions
and
168 deletions
... | @@ -58,7 +58,7 @@ public class ApplicationViewMessageHandler extends UiMessageHandler { | ... | @@ -58,7 +58,7 @@ public class ApplicationViewMessageHandler extends UiMessageHandler { |
58 | private static final String URL = "url"; | 58 | private static final String URL = "url"; |
59 | private static final String README = "readme"; | 59 | private static final String README = "readme"; |
60 | private static final String ROLE = "role"; | 60 | private static final String ROLE = "role"; |
61 | - private static final String REQUIRED_APPS = "_required_apps"; | 61 | + private static final String REQUIRED_APPS = "required_apps"; |
62 | private static final String FEATURES = "features"; | 62 | private static final String FEATURES = "features"; |
63 | private static final String PERMISSIONS = "permissions"; | 63 | private static final String PERMISSIONS = "permissions"; |
64 | 64 | ||
... | @@ -175,13 +175,13 @@ public class ApplicationViewMessageHandler extends UiMessageHandler { | ... | @@ -175,13 +175,13 @@ public class ApplicationViewMessageHandler extends UiMessageHandler { |
175 | 175 | ||
176 | // process required applications | 176 | // process required applications |
177 | ArrayNode requiredApps = arrayNode(); | 177 | ArrayNode requiredApps = arrayNode(); |
178 | - app.requiredApps().forEach(s -> requiredApps.add(s)); | 178 | + app.requiredApps().forEach(requiredApps::add); |
179 | 179 | ||
180 | data.set(REQUIRED_APPS, requiredApps); | 180 | data.set(REQUIRED_APPS, requiredApps); |
181 | 181 | ||
182 | // process features | 182 | // process features |
183 | ArrayNode features = arrayNode(); | 183 | ArrayNode features = arrayNode(); |
184 | - app.features().forEach(f -> features.add(f)); | 184 | + app.features().forEach(features::add); |
185 | 185 | ||
186 | data.set(FEATURES, features); | 186 | data.set(FEATURES, features); |
187 | 187 | ... | ... |
... | @@ -15,7 +15,7 @@ | ... | @@ -15,7 +15,7 @@ |
15 | */ | 15 | */ |
16 | 16 | ||
17 | /* | 17 | /* |
18 | - ONOS GUI -- Host View -- CSS file | 18 | + ONOS GUI -- Applications View -- CSS file |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #ov-app h2 { | 21 | #ov-app h2 { |
... | @@ -75,7 +75,7 @@ | ... | @@ -75,7 +75,7 @@ |
75 | } | 75 | } |
76 | 76 | ||
77 | #application-details-panel .container { | 77 | #application-details-panel .container { |
78 | - padding: 0 12px; | 78 | + padding: 0 10px; |
79 | } | 79 | } |
80 | 80 | ||
81 | #application-details-panel .close-btn { | 81 | #application-details-panel .close-btn { |
... | @@ -91,60 +91,48 @@ | ... | @@ -91,60 +91,48 @@ |
91 | fill: #ccc; | 91 | fill: #ccc; |
92 | } | 92 | } |
93 | 93 | ||
94 | -#application-details-panel .dev-icon { | 94 | +#application-details-panel .app-icon { |
95 | display: inline-block; | 95 | display: inline-block; |
96 | padding: 0 6px 0 0; | 96 | padding: 0 6px 0 0; |
97 | vertical-align: middle; | 97 | vertical-align: middle; |
98 | } | 98 | } |
99 | -.light .dev-icon svg.embeddedIcon .glyph { | ||
100 | - fill: rgb(0, 172, 229); | ||
101 | -} | ||
102 | -.dark .dev-icon svg.embeddedIcon .glyph { | ||
103 | - fill: #486D91; | ||
104 | -} | ||
105 | 99 | ||
106 | #application-details-panel h2 { | 100 | #application-details-panel h2 { |
107 | display: inline-block; | 101 | display: inline-block; |
108 | margin: 8px 0; | 102 | margin: 8px 0; |
103 | + font-size: 12pt; | ||
109 | } | 104 | } |
110 | 105 | ||
111 | #application-details-panel .top div.left { | 106 | #application-details-panel .top div.left { |
112 | float: left; | 107 | float: left; |
113 | - padding: 0 18px 0 0; | 108 | + padding: 0 12px 0 0; |
114 | } | 109 | } |
115 | #application-details-panel .top div.right { | 110 | #application-details-panel .top div.right { |
116 | display: inline-block; | 111 | display: inline-block; |
112 | + overflow: hidden; | ||
113 | + width: 320px; | ||
117 | } | 114 | } |
118 | 115 | ||
119 | -#application-details-panel td.label { | 116 | +#application-details-panel td.label, |
117 | +#application-details-panel .app-url i { | ||
120 | font-style: italic; | 118 | font-style: italic; |
121 | padding-right: 12px; | 119 | padding-right: 12px; |
122 | /* works for both light and dark themes ... */ | 120 | /* works for both light and dark themes ... */ |
123 | color: #777; | 121 | color: #777; |
124 | } | 122 | } |
125 | 123 | ||
126 | -#application-details-panel .actionBtns div { | 124 | +#application-details-panel td.value-bold { |
127 | - padding: 12px 6px; | 125 | + font-weight: bold; |
128 | } | 126 | } |
129 | 127 | ||
130 | -#application-details-panel .top hr { | 128 | +#application-details-panel .app-url { |
131 | - width: 95%; | 129 | + padding: 10px 6px 6px; |
132 | - margin: 0 auto; | ||
133 | } | 130 | } |
134 | 131 | ||
135 | -.light #application-details-panel hr { | 132 | +#application-details-panel hr { |
136 | - opacity: .5; | ||
137 | - border-color: #FFF; | ||
138 | -} | ||
139 | -.dark #application-details-panel hr { | ||
140 | - border-color: #666; | ||
141 | -} | ||
142 | - | ||
143 | -#application-details-panel .middle hr { | ||
144 | width: 95%; | 133 | width: 95%; |
145 | - margin: 0 auto; | 134 | + margin: 10px auto; |
146 | } | 135 | } |
147 | - | ||
148 | .light #application-details-panel hr { | 136 | .light #application-details-panel hr { |
149 | opacity: .5; | 137 | opacity: .5; |
150 | border-color: #FFF; | 138 | border-color: #FFF; |
... | @@ -155,25 +143,12 @@ | ... | @@ -155,25 +143,12 @@ |
155 | 143 | ||
156 | #application-details-panel .bottom table { | 144 | #application-details-panel .bottom table { |
157 | border-spacing: 0; | 145 | border-spacing: 0; |
146 | + width: 100%; | ||
158 | } | 147 | } |
159 | 148 | ||
160 | -#application-details-panel .bottom th { | ||
161 | - letter-spacing: 0.02em; | ||
162 | -} | ||
163 | - | ||
164 | -.light #application-details-panel .bottom th { | ||
165 | - background-color: #CCC; | ||
166 | - /* default text color */ | ||
167 | -} | ||
168 | -.dark #application-details-panel .bottom th { | ||
169 | - background-color: #131313; | ||
170 | - color: #ccc; | ||
171 | -} | ||
172 | - | ||
173 | -#application-details-panel .bottom th, | ||
174 | #application-details-panel .bottom td { | 149 | #application-details-panel .bottom td { |
175 | padding: 6px 12px; | 150 | padding: 6px 12px; |
176 | - text-align: center; | 151 | + text-align: left; |
177 | } | 152 | } |
178 | 153 | ||
179 | .light #application-details-panel .bottom tr:nth-child(odd) { | 154 | .light #application-details-panel .bottom tr:nth-child(odd) { | ... | ... |
... | @@ -22,7 +22,7 @@ | ... | @@ -22,7 +22,7 @@ |
22 | 'use strict'; | 22 | 'use strict'; |
23 | 23 | ||
24 | // injected refs | 24 | // injected refs |
25 | - var $log, $scope, $loc, fs, ps, wss, is, ns, ks, is; | 25 | + var $log, $scope, wss, fs, ks, ps, is; |
26 | 26 | ||
27 | // internal state | 27 | // internal state |
28 | var detailsPanel, | 28 | var detailsPanel, |
... | @@ -31,7 +31,6 @@ | ... | @@ -31,7 +31,6 @@ |
31 | top, | 31 | top, |
32 | middle, | 32 | middle, |
33 | bottom, | 33 | bottom, |
34 | - iconDiv, | ||
35 | wSize = false; | 34 | wSize = false; |
36 | 35 | ||
37 | // constants | 36 | // constants |
... | @@ -39,9 +38,7 @@ | ... | @@ -39,9 +38,7 @@ |
39 | ACTIVE = 'ACTIVE', | 38 | ACTIVE = 'ACTIVE', |
40 | appMgmtReq = 'appManagementRequest', | 39 | appMgmtReq = 'appManagementRequest', |
41 | topPdg = 50, | 40 | topPdg = 50, |
42 | - ctnrPdg = 24, | 41 | + panelWidth = 500, |
43 | - tbWidth = 470, | ||
44 | - scrollSize = 17, | ||
45 | pName = 'application-details-panel', | 42 | pName = 'application-details-panel', |
46 | detailsReq = 'appDetailsRequest', | 43 | detailsReq = 'appDetailsRequest', |
47 | detailsResp = 'appDetailsResponse', | 44 | detailsResp = 'appDetailsResponse', |
... | @@ -57,8 +54,9 @@ | ... | @@ -57,8 +54,9 @@ |
57 | }, | 54 | }, |
58 | discouragement = 'Deactivating or uninstalling this component can' + | 55 | discouragement = 'Deactivating or uninstalling this component can' + |
59 | ' have serious negative consequences! Do so at your own risk!!', | 56 | ' have serious negative consequences! Do so at your own risk!!', |
60 | - propOrder = ['id', 'state', 'category', 'version', 'origin', 'role', 'url'], | 57 | + propOrder = ['id', 'state', 'category', 'version', 'origin', 'role'], |
61 | - friendlyProps = ['App ID', 'State', 'Category', 'Version', 'Origin', 'Role', 'URL']; | 58 | + friendlyProps = ['App ID', 'State', 'Category', 'Version', 'Origin', 'Role']; |
59 | + // note: url is handled separately | ||
62 | 60 | ||
63 | function createDetailsPane() { | 61 | function createDetailsPane() { |
64 | detailsPanel = ps.createPanel(pName, { | 62 | detailsPanel = ps.createPanel(pName, { |
... | @@ -90,156 +88,111 @@ | ... | @@ -90,156 +88,111 @@ |
90 | } | 88 | } |
91 | 89 | ||
92 | function setUpPanel() { | 90 | function setUpPanel() { |
93 | - var container, closeBtn, tblDiv; | 91 | + var container, closeBtn, div; |
92 | + | ||
94 | detailsPanel.empty(); | 93 | detailsPanel.empty(); |
94 | + detailsPanel.width(panelWidth); | ||
95 | 95 | ||
96 | container = detailsPanel.append('div').classed('container', true); | 96 | container = detailsPanel.append('div').classed('container', true); |
97 | 97 | ||
98 | top = container.append('div').classed('top', true); | 98 | top = container.append('div').classed('top', true); |
99 | closeBtn = top.append('div').classed('close-btn', true); | 99 | closeBtn = top.append('div').classed('close-btn', true); |
100 | addCloseBtn(closeBtn); | 100 | addCloseBtn(closeBtn); |
101 | - iconDiv = top.append('div').classed('dev-icon', true); | ||
102 | 101 | ||
103 | - tblDiv = top.append('div').classed('top-tables', true); | 102 | + div = top.append('div').classed('top-content', true); |
104 | - tblDiv.append('div').classed('left', true).append('table'); | 103 | + |
105 | - tblDiv.append('div').classed('right', true).append('table'); | 104 | + function ndiv(cls, tcls) { |
106 | - tblDiv.append('div').classed('description', true).append('table'); | 105 | + var d = div.append('div').classed(cls, true); |
106 | + if (tcls) { | ||
107 | + d.append('table').classed(tcls, true); | ||
108 | + } | ||
109 | + } | ||
110 | + | ||
111 | + ndiv('left app-icon'); | ||
112 | + ndiv('right', 'app-props'); | ||
113 | + ndiv('app-url'); | ||
107 | 114 | ||
108 | - top.append('hr'); | 115 | + container.append('hr'); |
109 | 116 | ||
110 | middle = container.append('div').classed('middle', true); | 117 | middle = container.append('div').classed('middle', true); |
111 | - tblDiv = middle.append('div').classed('middle-tables', true); | 118 | + middle.append('div').classed('app-readme', true); |
112 | - tblDiv.append('div').classed('readme', true).append('table'); | ||
113 | 119 | ||
114 | - middle.append('hr'); | 120 | + container.append('hr'); |
115 | 121 | ||
122 | + // TODO: make bottom container scrollable | ||
116 | bottom = container.append('div').classed('bottom', true); | 123 | bottom = container.append('div').classed('bottom', true); |
117 | - tblDiv = bottom.append('div').classed('bottom-tables', true).append('table'); | 124 | + |
118 | - tblDiv.append('h2').html('Features'); | 125 | + function nTable(hdr, cls) { |
119 | - tblDiv.append('div').classed('features', true).append('table'); | 126 | + bottom.append('h2').html(hdr); |
120 | - tblDiv.append('h2').html('Required Apps'); | 127 | + bottom.append('div').classed(cls, true).append('table'); |
121 | - tblDiv.append('div').classed('required-apps', true).append('table'); | 128 | + } |
122 | - tblDiv.append('h2').html('Permissions'); | 129 | + |
123 | - tblDiv.append('div').classed('permissions', true).append('table'); | 130 | + nTable('Features', 'features'); |
131 | + nTable('Required Apps', 'required-apps'); | ||
132 | + nTable('Permissions', 'permissions'); | ||
124 | } | 133 | } |
125 | 134 | ||
126 | function addProp(tbody, index, value) { | 135 | function addProp(tbody, index, value) { |
127 | - var tr = tbody.append('tr'); | 136 | + var tr = tbody.append('tr'), |
137 | + vcls = index ? 'value' : 'value-bold'; | ||
128 | 138 | ||
129 | function addCell(cls, txt) { | 139 | function addCell(cls, txt) { |
130 | tr.append('td').attr('class', cls).html(txt); | 140 | tr.append('td').attr('class', cls).html(txt); |
131 | } | 141 | } |
132 | - addCell('label', friendlyProps[index] + ' :'); | ||
133 | - addCell('value', value); | ||
134 | - } | ||
135 | 142 | ||
136 | - function addUrl(tbody, index, value) { | 143 | + addCell('label', friendlyProps[index] + ':'); |
137 | - var href = '<a href="' + value + '" target="_blank">' + value + '</a>'; | 144 | + addCell(vcls, value); |
138 | - addProp(tbody, index, href); | ||
139 | } | 145 | } |
140 | 146 | ||
141 | - function addIcon(tbody, value) { | 147 | + function urlize(u) { |
142 | - var tr = tbody.append('tr'); | 148 | + return '<i>URL:</i> <a href="' + u + '" target="_blank">' + u + '</a>'; |
143 | - var td = tr.append('td'); | ||
144 | - td.append('img').attr('src', iconUrlPrefix + value + iconUrlSuffix); | ||
145 | } | 149 | } |
146 | 150 | ||
147 | - function addContent(tbody, value) { | 151 | + function addIcon(elem, value) { |
148 | - var tr = tbody.append('tr'); | 152 | + elem.append('img').attr('src', iconUrlPrefix + value + iconUrlSuffix); |
149 | - tr.append('td').html(value); | ||
150 | } | 153 | } |
151 | 154 | ||
152 | - function populateTop(tblDiv, details) { | 155 | + function populateTop(details) { |
153 | - var leftTbl = tblDiv.select('.left') | 156 | + var propsBody = top.select('.app-props').append('tbody'), |
154 | - .select('table') | 157 | + url = details.url; |
155 | - .append('tbody'), | ||
156 | - rightTbl = tblDiv.select('.right') | ||
157 | - .select('table') | ||
158 | - .append('tbody'), | ||
159 | - descriptionTbl = tblDiv.select('.description') | ||
160 | - .select('table') | ||
161 | - .append('tbody'); | ||
162 | - | ||
163 | - top.select('h2').html(details.name); | ||
164 | 158 | ||
165 | - // place application icon to the left table | 159 | + addIcon(top.select('.app-icon'), details.id); |
166 | - addIcon(leftTbl, details.id); | ||
167 | 160 | ||
168 | - // place rest of the fields to the right table | ||
169 | propOrder.forEach(function (prop, i) { | 161 | propOrder.forEach(function (prop, i) { |
170 | - var fn = prop === 'url' ? addUrl : addProp; | 162 | + addProp(propsBody, i, details[prop]); |
171 | - fn(rightTbl, i, details[prop]); | ||
172 | }); | 163 | }); |
173 | 164 | ||
174 | - // place description field to the description table | 165 | + if (url) { |
175 | - addContent(descriptionTbl, details.desc); | 166 | + top.select('.app-url').html(urlize(url)); |
176 | - } | 167 | + } |
177 | - | ||
178 | - function populateMiddle(tblDiv, details) { | ||
179 | - var readmeTbl = tblDiv.select('.readme') | ||
180 | - .select('table') | ||
181 | - .append('tbody'); | ||
182 | - | ||
183 | - // place readme field to the readme table | ||
184 | - addContent(readmeTbl, details.readme); | ||
185 | } | 168 | } |
186 | 169 | ||
187 | - function populateName(div, name) { | 170 | + function populateMiddle(details) { |
188 | - var lab = div.select('.label'), | 171 | + middle.select('.app-readme').text(details.readme); |
189 | - val = div.select('.value'); | ||
190 | - lab.html('Friendly Name:'); | ||
191 | - val.html(name); | ||
192 | } | 172 | } |
193 | 173 | ||
194 | - function populateDetails(details) { | 174 | + function populateBottom(details) { |
195 | - var nameDiv, topTbs, middleTbs, bottomTbs; | ||
196 | - setUpPanel(); | ||
197 | - | ||
198 | - nameDiv = top.select('.name-div'); | ||
199 | - topTbs = top.select('.top-tables'); | ||
200 | - middleTbs = middle.select('.middle-tables'); | ||
201 | - bottomTbs = bottom.select('.bottom-tables'); | ||
202 | 175 | ||
203 | - populateName(nameDiv, details.name); | 176 | + function addItems(cls, items) { |
204 | - populateTop(topTbs, details); | 177 | + var table = bottom.select('.' + cls).select('table'), |
205 | - populateMiddle(middleTbs, details); | 178 | + tbody = table.append('tbody'); |
206 | - populateBottom(bottomTbs, details); | ||
207 | - | ||
208 | - detailsPanel.height(pHeight); | ||
209 | - } | ||
210 | 179 | ||
211 | - function addItem(tbody, item) { | 180 | + items.forEach(function (item) { |
212 | - var tr = tbody.append('tr').attr('width', tbWidth + 'px'); | 181 | + tbody.append('tr').append('td').html(item); |
213 | - tr.append('td').attr('width', tbWidth + 'px') | 182 | + }); |
214 | - .attr('style', 'text-align:left').html(item); | 183 | + } |
215 | - } | ||
216 | 184 | ||
217 | - function addItems(table, items) { | 185 | + addItems('features', details.features); |
218 | - var tbody = table.append('tbody'); | 186 | + addItems('required-apps', details.required_apps); |
219 | - items.forEach(function (item) { | 187 | + addItems('permissions', details.permissions); |
220 | - addItem(tbody, item); | ||
221 | - }); | ||
222 | } | 188 | } |
223 | 189 | ||
224 | - function populateBottom(tblDiv, details) { | 190 | + function populateDetails(details) { |
225 | - var featuresTbl = tblDiv.select('.features') | 191 | + setUpPanel(); |
226 | - .select('table'), | 192 | + populateTop(details); |
227 | - permissionsTbl = tblDiv.select('.permissions') | 193 | + populateMiddle(details); |
228 | - .select('table'), | 194 | + populateBottom(details); |
229 | - requiredAppsTbl = tblDiv.select('.required-apps') | 195 | + detailsPanel.height(pHeight); |
230 | - .select('table'); | ||
231 | - | ||
232 | - addItems(featuresTbl, details.features); | ||
233 | - addItems(requiredAppsTbl, details._required_apps); | ||
234 | - addItems(permissionsTbl, details.permissions); | ||
235 | - | ||
236 | - featuresTbl.style({ | ||
237 | - width: tbWidth + 'px', | ||
238 | - overflow: 'auto', | ||
239 | - display: 'block' | ||
240 | - }); | ||
241 | - | ||
242 | - detailsPanel.width(tbWidth + ctnrPdg); | ||
243 | } | 196 | } |
244 | 197 | ||
245 | function respDetailsCb(data) { | 198 | function respDetailsCb(data) { |
... | @@ -250,15 +203,15 @@ | ... | @@ -250,15 +203,15 @@ |
250 | angular.module('ovApp', []) | 203 | angular.module('ovApp', []) |
251 | .controller('OvAppCtrl', | 204 | .controller('OvAppCtrl', |
252 | ['$log', '$scope', '$http', | 205 | ['$log', '$scope', '$http', |
253 | - 'FnService', 'TableBuilderService', 'PanelService', 'WebSocketService', | 206 | + 'WebSocketService', 'FnService', 'KeyService', 'PanelService', |
254 | - 'IconService', 'UrlFnService', 'KeyService', 'DialogService', | 207 | + 'IconService', 'UrlFnService', 'DialogService', 'TableBuilderService', |
255 | 208 | ||
256 | - function (_$log_, _$scope_, $http, _fs_, tbs, _ps_, _wss_, _is_, ufs, _ks_, ds) { | 209 | + function (_$log_, _$scope_, $http, _wss_, _fs_, _ks_, _ps_, _is_, ufs, ds, tbs) { |
257 | $log = _$log_; | 210 | $log = _$log_; |
258 | $scope = _$scope_; | 211 | $scope = _$scope_; |
259 | wss = _wss_; | 212 | wss = _wss_; |
260 | - ks = _ks_; | ||
261 | fs = _fs_; | 213 | fs = _fs_; |
214 | + ks = _ks_; | ||
262 | ps = _ps_; | 215 | ps = _ps_; |
263 | is = _is_; | 216 | is = _is_; |
264 | $scope.panelData = {}; | 217 | $scope.panelData = {}; |
... | @@ -285,7 +238,6 @@ | ... | @@ -285,7 +238,6 @@ |
285 | } else { | 238 | } else { |
286 | $scope.hidePanel(); | 239 | $scope.hidePanel(); |
287 | } | 240 | } |
288 | - $log.debug('Got a click on:', row); | ||
289 | } | 241 | } |
290 | 242 | ||
291 | function refreshCtrls() { | 243 | function refreshCtrls() { |
... | @@ -318,12 +270,12 @@ | ... | @@ -318,12 +270,12 @@ |
318 | 270 | ||
319 | // TODO: reexamine where keybindings should be - directive or controller? | 271 | // TODO: reexamine where keybindings should be - directive or controller? |
320 | ks.keyBindings({ | 272 | ks.keyBindings({ |
321 | - esc: [$scope.selectCallback, 'Deselect app'], | 273 | + esc: [$scope.selectCallback, 'Deselect application'], |
322 | _helpFormat: ['esc'] | 274 | _helpFormat: ['esc'] |
323 | }); | 275 | }); |
324 | ks.gestureNotes([ | 276 | ks.gestureNotes([ |
325 | - ['click row', 'Select / deselect app'], | 277 | + ['click row', 'Select / deselect application'], |
326 | - ['scroll down', 'See more apps'] | 278 | + ['scroll down', 'See more applications'] |
327 | ]); | 279 | ]); |
328 | 280 | ||
329 | function createConfirmationText(action, itemId) { | 281 | function createConfirmationText(action, itemId) { | ... | ... |
-
Please register or login to post a comment