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
Showing
5 changed files
with
270 additions
and
15 deletions
... | @@ -36,14 +36,17 @@ public class SettingsViewMessageHandler extends UiMessageHandler { | ... | @@ -36,14 +36,17 @@ public class SettingsViewMessageHandler extends UiMessageHandler { |
36 | private static final String SETTINGS = "settings"; | 36 | private static final String SETTINGS = "settings"; |
37 | 37 | ||
38 | private static final String COMPONENT = "component"; | 38 | private static final String COMPONENT = "component"; |
39 | + private static final String FQ_COMPONENT = "fqComponent"; | ||
39 | private static final String ID = "id"; | 40 | private static final String ID = "id"; |
40 | private static final String TYPE = "type"; | 41 | private static final String TYPE = "type"; |
41 | private static final String VALUE = "value"; | 42 | private static final String VALUE = "value"; |
42 | private static final String DEFAULT = "defValue"; | 43 | private static final String DEFAULT = "defValue"; |
43 | private static final String DESC = "desc"; | 44 | private static final String DESC = "desc"; |
44 | 45 | ||
46 | + private static final char DOT = '.'; | ||
47 | + | ||
45 | private static final String[] COL_IDS = { | 48 | private static final String[] COL_IDS = { |
46 | - COMPONENT, ID, TYPE, VALUE, DEFAULT, DESC | 49 | + COMPONENT, FQ_COMPONENT, ID, TYPE, VALUE, DEFAULT, DESC |
47 | }; | 50 | }; |
48 | 51 | ||
49 | @Override | 52 | @Override |
... | @@ -90,13 +93,25 @@ public class SettingsViewMessageHandler extends UiMessageHandler { | ... | @@ -90,13 +93,25 @@ public class SettingsViewMessageHandler extends UiMessageHandler { |
90 | } | 93 | } |
91 | } | 94 | } |
92 | 95 | ||
93 | - private void populateRow(TableModel.Row row, String component, ConfigProperty prop) { | 96 | + private void populateRow(TableModel.Row row, String fqComp, |
94 | - row.cell(COMPONENT, component) | 97 | + ConfigProperty prop) { |
98 | + row.cell(COMPONENT, simpleName(fqComp)) | ||
99 | + .cell(FQ_COMPONENT, fqComp) | ||
95 | .cell(ID, prop.name()) | 100 | .cell(ID, prop.name()) |
96 | - .cell(TYPE, prop.type().toString().toLowerCase()) | 101 | + .cell(TYPE, typeName(prop)) |
97 | .cell(VALUE, prop.value()) | 102 | .cell(VALUE, prop.value()) |
98 | .cell(DEFAULT, prop.defaultValue()) | 103 | .cell(DEFAULT, prop.defaultValue()) |
99 | .cell(DESC, prop.description()); | 104 | .cell(DESC, prop.description()); |
100 | } | 105 | } |
106 | + | ||
107 | + // return just simple class name: "a.b.c.MyClass" -> "MyClass" | ||
108 | + private String simpleName(String component) { | ||
109 | + int lastDot = component.lastIndexOf(DOT); | ||
110 | + return lastDot < 0 ? component : component.substring(lastDot + 1); | ||
111 | + } | ||
112 | + | ||
113 | + private String typeName(ConfigProperty prop) { | ||
114 | + return prop.type().toString().toLowerCase(); | ||
115 | + } | ||
101 | } | 116 | } |
102 | } | 117 | } | ... | ... |
... | @@ -470,7 +470,7 @@ | ... | @@ -470,7 +470,7 @@ |
470 | }); | 470 | }); |
471 | ks.gestureNotes([ | 471 | ks.gestureNotes([ |
472 | ['click', 'Select a row to show application details'], | 472 | ['click', 'Select a row to show application details'], |
473 | - ['scroll down', 'See more application'] | 473 | + ['scroll down', 'See more applications'] |
474 | ]); | 474 | ]); |
475 | 475 | ||
476 | // if the panelData changes | 476 | // if the panelData changes | ... | ... |
... | @@ -25,3 +25,41 @@ | ... | @@ -25,3 +25,41 @@ |
25 | #ov-settings div.ctrl-btns { | 25 | #ov-settings div.ctrl-btns { |
26 | width: 45px; | 26 | width: 45px; |
27 | } | 27 | } |
28 | + | ||
29 | +#ov-settings div.summary-list td.notdef { | ||
30 | + color: #0071bd; | ||
31 | + font-weight: bold; | ||
32 | +} | ||
33 | + | ||
34 | +#settings-details-panel .container { | ||
35 | + padding: 0 30px; | ||
36 | + overflow-y: scroll; | ||
37 | +} | ||
38 | + | ||
39 | +#settings-details-panel .close-btn { | ||
40 | + position: absolute; | ||
41 | + right: 26px; | ||
42 | + top: 26px; | ||
43 | + cursor: pointer; | ||
44 | +} | ||
45 | + | ||
46 | +#settings-details-panel .top .settings-title { | ||
47 | + width: 90%; | ||
48 | + height: 62px; | ||
49 | + font-size: 20pt; | ||
50 | + font-weight: lighter; | ||
51 | + overflow: hidden; | ||
52 | + white-space: nowrap; | ||
53 | + padding: 0 12px 0 2px; | ||
54 | + margin-top: 19px; | ||
55 | + margin-bottom: 5px; | ||
56 | +} | ||
57 | + | ||
58 | +#settings-details-panel td.label { | ||
59 | + font-weight: bold; | ||
60 | + text-align: right; | ||
61 | + font-size: 12pt; | ||
62 | + padding-right: 6px; | ||
63 | + vertical-align: top; | ||
64 | + width: 120px; | ||
65 | +} | ... | ... |
... | @@ -14,11 +14,10 @@ | ... | @@ -14,11 +14,10 @@ |
14 | <div class="table-header" onos-sortable-header> | 14 | <div class="table-header" onos-sortable-header> |
15 | <table> | 15 | <table> |
16 | <tr> | 16 | <tr> |
17 | - <td colId="component" sortable col-width="300px">Component </td> | 17 | + <td colId="component" sortable col-width="260px">Component </td> |
18 | - <td colId="id" sortable col-width="240px">Property </td> | 18 | + <td colId="id" sortable col-width="260px">Property </td> |
19 | <td colId="type" sortable col-width="100px">Type </td> | 19 | <td colId="type" sortable col-width="100px">Type </td> |
20 | <td colId="value" sortable col-width="100px">Value </td> | 20 | <td colId="value" sortable col-width="100px">Value </td> |
21 | - <td colId="defValue" sortable col-width="100px">Default </td> | ||
22 | <td colId="desc">Description </td> | 21 | <td colId="desc">Description </td> |
23 | </tr> | 22 | </tr> |
24 | </table> | 23 | </table> |
... | @@ -33,17 +32,21 @@ | ... | @@ -33,17 +32,21 @@ |
33 | </tr> | 32 | </tr> |
34 | 33 | ||
35 | <tr ng-repeat="prop in tableData track by $index" | 34 | <tr ng-repeat="prop in tableData track by $index" |
35 | + ng-click="selectCallback($event, prop)" | ||
36 | + ng-class="{selected: prop.id === selId}" | ||
36 | ng-repeat-complete row-id="{{prop.id}}"> | 37 | ng-repeat-complete row-id="{{prop.id}}"> |
37 | <td>{{prop.component}}</td> | 38 | <td>{{prop.component}}</td> |
38 | <td>{{prop.id}}</td> | 39 | <td>{{prop.id}}</td> |
39 | <td>{{prop.type}}</td> | 40 | <td>{{prop.type}}</td> |
40 | - <td>{{prop.value}}</td> | 41 | + <td ng-class="{notdef: prop.value !== prop.defValue}"> |
41 | - <td>{{prop.defValue}}</td> | 42 | + {{prop.value}} |
43 | + </td> | ||
42 | <td>{{prop.desc}}</td> | 44 | <td>{{prop.desc}}</td> |
43 | </tr> | 45 | </tr> |
44 | </table> | 46 | </table> |
45 | </div> | 47 | </div> |
46 | 48 | ||
47 | </div> | 49 | </div> |
50 | + <settings-details-panel></settings-details-panel> | ||
48 | 51 | ||
49 | </div> | 52 | </div> | ... | ... |
... | @@ -21,16 +21,215 @@ | ... | @@ -21,16 +21,215 @@ |
21 | (function () { | 21 | (function () { |
22 | 'use strict'; | 22 | 'use strict'; |
23 | 23 | ||
24 | + // injected refs | ||
25 | + var $log, $scope, wss, fs, ks, ps, is; | ||
26 | + | ||
27 | + // internal state | ||
28 | + var detailsPanel, | ||
29 | + panelData, | ||
30 | + top, | ||
31 | + pStartY, | ||
32 | + pHeight, | ||
33 | + wSize = false; | ||
34 | + | ||
35 | + // constants | ||
36 | + var pName = 'settings-details-panel', | ||
37 | + panelWidth = 540, | ||
38 | + topPdg = 60, | ||
39 | + propOrder = ['fqComponent', 'id', 'type', 'value', 'defValue', 'desc'], | ||
40 | + friendlyProps = [ | ||
41 | + 'Component', 'Property', 'Type', 'Value', 'Default Value', | ||
42 | + 'Description' | ||
43 | + ]; | ||
44 | + | ||
45 | + function createDetailsPanel() { | ||
46 | + detailsPanel = ps.createPanel(pName, { | ||
47 | + width: wSize.width, | ||
48 | + margin: 0, | ||
49 | + hideMargin: 0 | ||
50 | + }); | ||
51 | + | ||
52 | + detailsPanel.el().style({ | ||
53 | + position: 'absolute', | ||
54 | + top: pStartY + 'px' | ||
55 | + }); | ||
56 | + | ||
57 | + detailsPanel.hide(); | ||
58 | + } | ||
59 | + | ||
60 | + function closePanel() { | ||
61 | + if (detailsPanel.isVisible()) { | ||
62 | + $scope.selId = null; | ||
63 | + panelData = null; | ||
64 | + detailsPanel.hide(); | ||
65 | + return true; | ||
66 | + } | ||
67 | + return false; | ||
68 | + } | ||
69 | + | ||
70 | + function addCloseBtn(div) { | ||
71 | + is.loadEmbeddedIcon(div, 'close', 26); | ||
72 | + div.on('click', closePanel); | ||
73 | + } | ||
74 | + | ||
75 | + function setUpPanel() { | ||
76 | + var container, closeBtn, div; | ||
77 | + | ||
78 | + detailsPanel.empty(); | ||
79 | + detailsPanel.width(panelWidth); | ||
80 | + | ||
81 | + container = detailsPanel.append('div').classed('container', true); | ||
82 | + | ||
83 | + top = container.append('div').classed('top', true); | ||
84 | + closeBtn = top.append('div').classed('close-btn', true); | ||
85 | + addCloseBtn(closeBtn); | ||
86 | + | ||
87 | + div = top.append('div').classed('top-content', true); | ||
88 | + | ||
89 | + function ndiv(cls, addTable) { | ||
90 | + var d = div.append('div').classed(cls, true); | ||
91 | + if (addTable) { | ||
92 | + d.append('table'); | ||
93 | + } | ||
94 | + } | ||
95 | + | ||
96 | + ndiv('settings-title'); | ||
97 | + ndiv('settings-props', true); | ||
98 | + } | ||
99 | + | ||
100 | + function addProp(tbody, index, value) { | ||
101 | + var tr = tbody.append('tr'); | ||
102 | + | ||
103 | + function addCell(cls, txt) { | ||
104 | + tr.append('td').attr('class', cls).html(txt); | ||
105 | + } | ||
106 | + | ||
107 | + addCell('label', friendlyProps[index] + ':'); | ||
108 | + addCell('value', value); | ||
109 | + } | ||
110 | + | ||
111 | + function populateTop(details) { | ||
112 | + var propsBody = top.select('.settings-props').append('tbody'); | ||
113 | + | ||
114 | + top.select('.settings-title').text(details.id); | ||
115 | + | ||
116 | + propOrder.forEach(function (prop, i) { | ||
117 | + addProp(propsBody, i, details[prop]); | ||
118 | + }); | ||
119 | + } | ||
120 | + | ||
121 | + function populateDetails() { | ||
122 | + setUpPanel(); | ||
123 | + populateTop(panelData); | ||
124 | + detailsPanel.height(pHeight); | ||
125 | + } | ||
126 | + | ||
24 | angular.module('ovSettings', []) | 127 | angular.module('ovSettings', []) |
25 | - .controller('OvSettingsCtrl', | 128 | + .controller('OvSettingsCtrl', |
26 | - ['$log', '$scope', 'TableBuilderService', | 129 | + ['$log', '$scope', |
130 | + 'WebSocketService', 'FnService', 'KeyService', 'PanelService', | ||
131 | + 'IconService', 'TableBuilderService', | ||
132 | + | ||
133 | + function (_$log_, _$scope_, _wss_, _fs_, _ks_, _ps_, _is_, tbs) { | ||
134 | + $log = _$log_; | ||
135 | + $scope = _$scope_; | ||
136 | + wss = _wss_; | ||
137 | + fs = _fs_; | ||
138 | + ks = _ks_; | ||
139 | + ps = _ps_; | ||
140 | + is = _is_; | ||
141 | + $scope.panelData = {}; | ||
142 | + | ||
143 | + function selCb($event, row) { | ||
144 | + if ($scope.selId) { | ||
145 | + panelData = row; | ||
146 | + populateDetails(); | ||
147 | + detailsPanel.show(); | ||
148 | + } else { | ||
149 | + panelData = null; | ||
150 | + detailsPanel.hide(); | ||
151 | + } | ||
152 | + } | ||
27 | 153 | ||
28 | - function ($log, $scope, tbs) { | ||
29 | tbs.buildTable({ | 154 | tbs.buildTable({ |
30 | scope: $scope, | 155 | scope: $scope, |
31 | - tag: 'setting' | 156 | + tag: 'setting', |
157 | + selCb: selCb | ||
158 | + }); | ||
159 | + | ||
160 | + ks.keyBindings({ | ||
161 | + esc: [$scope.selectCallback, 'Deselect property'], | ||
162 | + _helpFormat: ['esc'] | ||
163 | + }); | ||
164 | + ks.gestureNotes([ | ||
165 | + ['click row', 'Select / deselect settings property'], | ||
166 | + ['scroll down', 'See more settings'] | ||
167 | + ]); | ||
168 | + | ||
169 | + $scope.$on('$destroy', function () { | ||
170 | + ks.unbindKeys(); | ||
32 | }); | 171 | }); |
33 | 172 | ||
34 | $log.log('OvSettingsCtrl has been created'); | 173 | $log.log('OvSettingsCtrl has been created'); |
35 | - }]); | 174 | + }]) |
175 | + | ||
176 | + .directive('settingsDetailsPanel', | ||
177 | + ['$rootScope', '$window', '$timeout', 'KeyService', | ||
178 | + function ($rootScope, $window, $timeout, ks) { | ||
179 | + return function (scope) { | ||
180 | + var unbindWatch; | ||
181 | + | ||
182 | + function heightCalc() { | ||
183 | + pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height') | ||
184 | + + topPdg; | ||
185 | + wSize = fs.windowSize(pStartY); | ||
186 | + pHeight = wSize.height; | ||
187 | + } | ||
188 | + | ||
189 | + function initPanel() { | ||
190 | + heightCalc(); | ||
191 | + createDetailsPanel(); | ||
192 | + $log.debug('start to initialize panel!'); | ||
193 | + } | ||
194 | + | ||
195 | + // Safari has a bug where it renders the fixed-layout table wrong | ||
196 | + // if you ask for the window's size too early | ||
197 | + if (scope.onos.browser === 'safari') { | ||
198 | + $timeout(initPanel); | ||
199 | + } else { | ||
200 | + initPanel(); | ||
201 | + } | ||
202 | + // create key bindings to handle panel | ||
203 | + ks.keyBindings({ | ||
204 | + esc: [closePanel, 'Close the details panel'], | ||
205 | + _helpFormat: ['esc'] | ||
206 | + }); | ||
207 | + ks.gestureNotes([ | ||
208 | + ['click', 'Select a row to show property details'], | ||
209 | + ['scroll down', 'See more properties'] | ||
210 | + ]); | ||
211 | + | ||
212 | + // if the window size changes | ||
213 | + unbindWatch = $rootScope.$watchCollection( | ||
214 | + function () { | ||
215 | + return { | ||
216 | + h: $window.innerHeight, | ||
217 | + w: $window.innerWidth | ||
218 | + }; | ||
219 | + }, function () { | ||
220 | + if (panelData) { | ||
221 | + heightCalc(); | ||
222 | + populateDetails(); | ||
223 | + } | ||
224 | + } | ||
225 | + ); | ||
226 | + | ||
227 | + scope.$on('$destroy', function () { | ||
228 | + panelData = null; | ||
229 | + unbindWatch(); | ||
230 | + ks.unbindKeys(); | ||
231 | + ps.destroyPanel(pName); | ||
232 | + }); | ||
233 | + }; | ||
234 | + }]); | ||
36 | }()); | 235 | }()); | ... | ... |
-
Please register or login to post a comment