mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-11-02 01:01:03 +01:00
ONOS-5579 Refactoring Details Panel
Added an Editable Textfield Component Refactored Device View Refactored Host View Change-Id: I7ca423f6c198f8e09b20ed4e57e352de04b797e9
This commit is contained in:
parent
a441074299
commit
f50a1775a7
16
web/gui/src/main/webapp/app/fw/layer/details-panel.css
Normal file
16
web/gui/src/main/webapp/app/fw/layer/details-panel.css
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2017-present Open Networking Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
178
web/gui/src/main/webapp/app/fw/layer/details-panel.js
Normal file
178
web/gui/src/main/webapp/app/fw/layer/details-panel.js
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 2017-present Open Networking Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
|
||||
var ps, fs, mast, wss, is, EditableTextComponent;
|
||||
|
||||
var panel,
|
||||
pStartY,
|
||||
wSize,
|
||||
wssHandlers = {},
|
||||
options;
|
||||
|
||||
// Constants
|
||||
var topPdg = 28,
|
||||
defaultLabelWidth = 110,
|
||||
defaultValueWidth = 80;
|
||||
|
||||
// Elements
|
||||
var container,
|
||||
top,
|
||||
bottom;
|
||||
|
||||
function createDetailsPanel(name, _options) {
|
||||
options = _options;
|
||||
scope = options.scope;
|
||||
|
||||
panel = ps.createPanel(name, options);
|
||||
|
||||
calculatePositions();
|
||||
|
||||
panel.el().style({
|
||||
position: 'absolute',
|
||||
top: pStartY + 'px',
|
||||
});
|
||||
|
||||
hide();
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
function calculatePositions() {
|
||||
pStartY = fs.noPxStyle(d3.select('.tabular-header'), 'height')
|
||||
+ mast.mastHeight() + topPdg;
|
||||
wSize = fs.windowSize(pStartY);
|
||||
pHeight = wSize.height;
|
||||
}
|
||||
|
||||
function hide() {
|
||||
panel.hide();
|
||||
}
|
||||
|
||||
function setResponse(name, callback) {
|
||||
var additionalHandler = {};
|
||||
additionalHandler[name] = callback;
|
||||
|
||||
wss.bindHandlers(additionalHandler);
|
||||
wssHandlers = _.extend({}, wssHandlers, additionalHandler);
|
||||
}
|
||||
|
||||
function addContainers() {
|
||||
container = panel.append('div').classed('container', true);
|
||||
top = container.append('div').classed('top', true);
|
||||
bottom = container.append('div').classed('bottom', true);
|
||||
}
|
||||
|
||||
function addCloseButton(onClose) {
|
||||
var closeBtn = top.append('div').classed('close-btn', true);
|
||||
|
||||
is.loadEmbeddedIcon(closeBtn, 'close', 20);
|
||||
closeBtn.on('click', onClose || function () {});
|
||||
}
|
||||
|
||||
function addHeading(icon) {
|
||||
top.append('div').classed('iconDiv ' + icon, true);
|
||||
new EditableTextComponent(top.append('h2'), {
|
||||
scope: options.scope,
|
||||
nameChangeRequest: options.nameChangeRequest,
|
||||
keyBindings: options.keyBindings,
|
||||
});
|
||||
}
|
||||
|
||||
function addTable(parent, className) {
|
||||
return parent.append('div').classed(className, true).append('table');
|
||||
}
|
||||
|
||||
function addProp(tbody, key, value) {
|
||||
console.log(tbody);
|
||||
var tr = tbody.append('tr');
|
||||
|
||||
function addCell(cls, txt, width) {
|
||||
tr.append('td').attr('class', cls).attr('width', width).text(txt);
|
||||
}
|
||||
|
||||
addCell('label', key + ' :', defaultLabelWidth);
|
||||
addCell('value', value, defaultValueWidth);
|
||||
}
|
||||
|
||||
function addPropsList(el, props) {
|
||||
var tblDiv = el.append('div').classed('top-tables', true);
|
||||
var left = addTable(tblDiv, 'left').append('tbody');
|
||||
var right = addTable(tblDiv, 'right').append('tbody');
|
||||
|
||||
var keys = _.keys(props);
|
||||
|
||||
_.each(props, function (value, key) {
|
||||
var index = keys.indexOf(key);
|
||||
|
||||
if (index < keys.length / 2) {
|
||||
addProp(left, key, value);
|
||||
} else {
|
||||
addProp(right, key, value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function empty() {
|
||||
panel.empty();
|
||||
}
|
||||
|
||||
function select(id) {
|
||||
return panel.el().select(id);
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
wss.unbindHandlers(wssHandlers);
|
||||
}
|
||||
|
||||
angular.module('onosLayer')
|
||||
.factory('DetailsPanelService', [
|
||||
|
||||
'PanelService', 'FnService', 'MastService', 'WebSocketService',
|
||||
'IconService', 'EditableTextComponent',
|
||||
|
||||
function (_ps_, _fs_, _mast_, _wss_, _is_, _etc_) {
|
||||
|
||||
ps = _ps_;
|
||||
fs = _fs_;
|
||||
mast = _mast_;
|
||||
wss = _wss_;
|
||||
is = _is_;
|
||||
EditableTextComponent = _etc_;
|
||||
|
||||
return {
|
||||
create: createDetailsPanel,
|
||||
setResponse: setResponse,
|
||||
|
||||
addContainers: addContainers,
|
||||
addCloseButton: addCloseButton,
|
||||
addHeading: addHeading,
|
||||
addPropsList: addPropsList,
|
||||
|
||||
// Elements
|
||||
container: function () { return container; },
|
||||
top: function () { return top; },
|
||||
bottom: function () { return bottom; },
|
||||
select: select,
|
||||
|
||||
empty: empty,
|
||||
hide: hide,
|
||||
destroy: destroy,
|
||||
};
|
||||
},
|
||||
]);
|
||||
})();
|
||||
119
web/gui/src/main/webapp/app/fw/layer/editable-text.js
Normal file
119
web/gui/src/main/webapp/app/fw/layer/editable-text.js
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2017-present Open Networking Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
|
||||
var ks, wss;
|
||||
|
||||
var EditableText = function (el, options) {
|
||||
// constructor
|
||||
this.el = el;
|
||||
this.scope = options.scope;
|
||||
this.options = options;
|
||||
|
||||
this.el.classed('editable clickable', true).on('click', this.onEdit.bind(this));
|
||||
this.editingName = false;
|
||||
};
|
||||
|
||||
EditableText.prototype = {
|
||||
|
||||
bindHandlers: function () {
|
||||
ks.keyBindings({
|
||||
'enter': this.save.bind(this),
|
||||
'esc': [this.cancel.bind(this), 'Close the details panel']
|
||||
});
|
||||
},
|
||||
|
||||
unbindHandlers: function () {
|
||||
ks.unbindKeys();
|
||||
|
||||
if (this.options.keyBindings) {
|
||||
// Reset to original bindings before editable text
|
||||
ks.keyBindings(this.options.keyBindings);
|
||||
}
|
||||
},
|
||||
|
||||
addTextField: function () {
|
||||
return this.el.append('input').classed('name-input', true)
|
||||
.attr('type', 'text')
|
||||
.attr('value', this.scope.panelData.name)[0][0];
|
||||
},
|
||||
|
||||
onEdit: function () {
|
||||
if (!this.editingName) {
|
||||
this.el.classed('editable clickable', false);
|
||||
this.el.text('');
|
||||
|
||||
var el = this.addTextField();
|
||||
el.focus();
|
||||
el.select();
|
||||
this.editingName = true;
|
||||
|
||||
this.bindHandlers();
|
||||
|
||||
ks.enableGlobalKeys(false);
|
||||
}
|
||||
},
|
||||
|
||||
exit: function (name) {
|
||||
this.el.text(name);
|
||||
this.el.classed('editable clickable', true);
|
||||
this.editingName = false;
|
||||
ks.enableGlobalKeys(true);
|
||||
this.unbindHandlers();
|
||||
},
|
||||
|
||||
cancel: function (a, b, ev) {
|
||||
|
||||
if (this.editingName) {
|
||||
this.exit(this.scope.panelData.name);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
save: function () {
|
||||
var id = this.scope.panelData.id,
|
||||
val,
|
||||
newVal;
|
||||
|
||||
if (this.editingName) {
|
||||
val = this.el.select('input').property('value').trim();
|
||||
newVal = val || id;
|
||||
|
||||
this.exit(newVal);
|
||||
this.scope.panelData.name = newVal;
|
||||
wss.sendEvent(this.options.nameChangeRequest, { id: id, name: val });
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
angular.module('onosLayer')
|
||||
.factory('EditableTextComponent', [
|
||||
|
||||
'KeyService', 'WebSocketService',
|
||||
|
||||
function (_ks_, _wss_) {
|
||||
ks = _ks_;
|
||||
wss = _wss_;
|
||||
|
||||
return EditableText;
|
||||
},
|
||||
]);
|
||||
|
||||
})();
|
||||
@ -22,17 +22,14 @@
|
||||
'use strict';
|
||||
|
||||
// injected refs
|
||||
var $log, $scope, $loc, fs, mast, ps, wss, is, ns, ks;
|
||||
var $log, $scope, $loc, fs, mast, ps, wss, is, ns, ks, dps;
|
||||
|
||||
// internal state
|
||||
var detailsPanel,
|
||||
pStartY,
|
||||
pHeight,
|
||||
top,
|
||||
bottom,
|
||||
iconDiv,
|
||||
wSize,
|
||||
editingName = false,
|
||||
device;
|
||||
|
||||
// constants
|
||||
@ -40,19 +37,12 @@
|
||||
ctnrPdg = 24,
|
||||
scrollSize = 17,
|
||||
portsTblPdg = 50,
|
||||
defaultLabelWidth = 110,
|
||||
defaultValueWidth = 80,
|
||||
|
||||
pName = 'device-details-panel',
|
||||
detailsReq = 'deviceDetailsRequest',
|
||||
detailsResp = 'deviceDetailsResponse',
|
||||
nameChangeReq = 'deviceNameChangeRequest',
|
||||
nameChangeResp = 'deviceNameChangeResponse',
|
||||
friendlyProps = [
|
||||
'URI', 'Type', 'Master ID', 'Chassis ID',
|
||||
'Vendor', 'H/W Version', 'S/W Version', 'Protocol', 'Serial #',
|
||||
'Pipeconf',
|
||||
],
|
||||
portCols = [
|
||||
'enabled', 'id', 'speed', 'type', 'elinks_dest', 'name',
|
||||
],
|
||||
@ -60,6 +50,11 @@
|
||||
'Enabled', 'ID', 'Speed', 'Type', 'Egress Links', 'Name',
|
||||
];
|
||||
|
||||
var keyBindings = {
|
||||
esc: [closePanel, 'Close the details panel'],
|
||||
_helpFormat: ['esc'],
|
||||
};
|
||||
|
||||
function closePanel() {
|
||||
if (detailsPanel.isVisible()) {
|
||||
$scope.selId = null;
|
||||
@ -69,119 +64,44 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
function addCloseBtn(div) {
|
||||
is.loadEmbeddedIcon(div, 'close', 20);
|
||||
div.on('click', closePanel);
|
||||
}
|
||||
|
||||
function exitEditMode(nameH2, name) {
|
||||
nameH2.text(name);
|
||||
nameH2.classed('editable clickable', true);
|
||||
editingName = false;
|
||||
ks.enableGlobalKeys(true);
|
||||
}
|
||||
|
||||
function editNameSave() {
|
||||
var nameH2 = top.select('h2'),
|
||||
id = $scope.panelData.id,
|
||||
val,
|
||||
newVal;
|
||||
|
||||
if (editingName) {
|
||||
val = nameH2.select('input').property('value').trim();
|
||||
newVal = val || id;
|
||||
|
||||
exitEditMode(nameH2, newVal);
|
||||
$scope.panelData.name = newVal;
|
||||
wss.sendEvent(nameChangeReq, { id: id, name: val });
|
||||
}
|
||||
}
|
||||
|
||||
function editNameCancel() {
|
||||
if (editingName) {
|
||||
exitEditMode(top.select('h2'), $scope.panelData.name);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function editName() {
|
||||
var nameH2 = top.select('h2'),
|
||||
tf, el;
|
||||
|
||||
if (!editingName) {
|
||||
nameH2.classed('editable clickable', false);
|
||||
nameH2.text('');
|
||||
tf = nameH2.append('input').classed('name-input', true)
|
||||
.attr('type', 'text')
|
||||
.attr('value', $scope.panelData.name);
|
||||
el = tf[0][0];
|
||||
el.focus();
|
||||
el.select();
|
||||
editingName = true;
|
||||
ks.enableGlobalKeys(false);
|
||||
}
|
||||
}
|
||||
|
||||
function handleEscape() {
|
||||
return editNameCancel() || closePanel();
|
||||
}
|
||||
|
||||
function setUpPanel() {
|
||||
var container, closeBtn, tblDiv;
|
||||
detailsPanel.empty();
|
||||
// var container, closeBtn, tblDiv;
|
||||
|
||||
container = detailsPanel.append('div').classed('container', true);
|
||||
dps.empty();
|
||||
dps.addContainers();
|
||||
dps.addCloseButton(closePanel);
|
||||
|
||||
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);
|
||||
top.append('h2').classed('editable clickable', true).on('click', editName);
|
||||
var top = dps.top();
|
||||
var bottom = dps.bottom();
|
||||
|
||||
tblDiv = top.append('div').classed('top-tables', true);
|
||||
tblDiv.append('div').classed('left', true).append('table');
|
||||
tblDiv.append('div').classed('right', true).append('table');
|
||||
dps.addHeading('dev-icon');
|
||||
top.append('div').classed('top-content', true);
|
||||
|
||||
top.append('hr');
|
||||
|
||||
bottom = container.append('div').classed('bottom', true);
|
||||
bottom.append('h2').classed('ports-title', true).text('Ports');
|
||||
bottom.append('table');
|
||||
}
|
||||
|
||||
function addProp(tbody, index, value) {
|
||||
var tr = tbody.append('tr');
|
||||
|
||||
function addCell(cls, txt, width) {
|
||||
tr.append('td').attr('class', cls).attr('width', width).text(txt);
|
||||
}
|
||||
addCell('label', friendlyProps[index] + ' :', defaultLabelWidth);
|
||||
addCell('value', value, defaultValueWidth);
|
||||
function friendlyPropsList(details) {
|
||||
return {
|
||||
'URI': device.id,
|
||||
'Type': device.type,
|
||||
'Master ID': details['masterid'],
|
||||
'Chassis ID': details['chassid'],
|
||||
'Vendor': device.mfr,
|
||||
'H/W Version': device.hw,
|
||||
'S/W Version': device.sw,
|
||||
'Protocol': details['protocol'],
|
||||
'Serial #': device.serial,
|
||||
'Pipeconf': details['pipeconf'],
|
||||
};
|
||||
}
|
||||
|
||||
function populateTop(tblDiv, details) {
|
||||
var leftTbl = tblDiv.select('.left')
|
||||
.select('table')
|
||||
.append('tbody'),
|
||||
rightTbl = tblDiv.select('.right')
|
||||
.select('table')
|
||||
.append('tbody');
|
||||
|
||||
is.loadEmbeddedIcon(iconDiv, details._iconid_type, 40);
|
||||
top.select('h2').text(details.name);
|
||||
|
||||
// === demonstrate use of JsonCodec object see ONOS-5976
|
||||
addProp(leftTbl, 0, device.id);
|
||||
addProp(leftTbl, 1, device.type);
|
||||
addProp(leftTbl, 2, details['masterid']);
|
||||
addProp(leftTbl, 3, details['chassid']);
|
||||
addProp(leftTbl, 4, device.mfr);
|
||||
addProp(rightTbl, 5, device.hw);
|
||||
addProp(rightTbl, 6, device.sw);
|
||||
addProp(rightTbl, 7, details['protocol']);
|
||||
addProp(rightTbl, 8, device.serial);
|
||||
addProp(rightTbl, 9, details['pipeconf']);
|
||||
is.loadEmbeddedIcon(dps.select('.iconDiv'), details._iconid_type, 40);
|
||||
dps.top().select('h2').text(details.name);
|
||||
dps.addPropsList(tblDiv, friendlyPropsList(details));
|
||||
}
|
||||
|
||||
function addPortRow(tbody, port) {
|
||||
@ -193,6 +113,7 @@
|
||||
}
|
||||
|
||||
function populateBottom(table, ports) {
|
||||
|
||||
var theader = table.append('thead').append('tr'),
|
||||
tbody = table.append('tbody'),
|
||||
tbWidth, tbHeight;
|
||||
@ -200,16 +121,15 @@
|
||||
friendlyPortCols.forEach(function (col) {
|
||||
theader.append('th').text(col);
|
||||
});
|
||||
|
||||
ports.forEach(function (port) {
|
||||
addPortRow(tbody, port);
|
||||
});
|
||||
|
||||
tbWidth = fs.noPxStyle(tbody, 'width') + scrollSize;
|
||||
tbHeight = pHeight
|
||||
- (fs.noPxStyle(detailsPanel.el()
|
||||
.select('.top'), 'height')
|
||||
+ fs.noPxStyle(detailsPanel.el()
|
||||
.select('.ports-title'), 'height')
|
||||
- (fs.noPxStyle(detailsPanel.el().select('.top'), 'height')
|
||||
+ fs.noPxStyle(detailsPanel.el().select('.ports-title'), 'height')
|
||||
+ portsTblPdg);
|
||||
|
||||
table.style({
|
||||
@ -223,15 +143,14 @@
|
||||
}
|
||||
|
||||
function populateDetails(details) {
|
||||
var topTbs, btmTbl, ports;
|
||||
var btmTbl, ports;
|
||||
|
||||
setUpPanel();
|
||||
|
||||
topTbs = top.select('.top-tables');
|
||||
btmTbl = bottom.select('table');
|
||||
btmTbl = dps.bottom().select('table');
|
||||
ports = details.ports;
|
||||
|
||||
populateTop(topTbs, details);
|
||||
populateTop(dps.select('.top-content'), details);
|
||||
populateBottom(btmTbl, ports);
|
||||
|
||||
detailsPanel.height(pHeight);
|
||||
@ -250,18 +169,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
function createDetailsPane() {
|
||||
detailsPanel = ps.createPanel(pName, {
|
||||
function createDetailsPanel() {
|
||||
detailsPanel = dps.create(pName, {
|
||||
width: wSize.width,
|
||||
margin: 0,
|
||||
hideMargin: 0,
|
||||
scope: $scope,
|
||||
keyBindings: keyBindings,
|
||||
nameChangeRequest: nameChangeReq,
|
||||
});
|
||||
detailsPanel.el().style({
|
||||
position: 'absolute',
|
||||
top: pStartY + 'px',
|
||||
});
|
||||
|
||||
dps.setResponse(detailsResp, respDetailsCb);
|
||||
|
||||
$scope.hidePanel = function () { detailsPanel.hide(); };
|
||||
detailsPanel.hide();
|
||||
}
|
||||
|
||||
// Sample functions for detail panel creation
|
||||
@ -283,10 +203,10 @@
|
||||
['$log', '$scope', '$location', 'TableBuilderService',
|
||||
'TableDetailService', 'FnService',
|
||||
'MastService', 'PanelService', 'WebSocketService', 'IconService',
|
||||
'NavService', 'KeyService',
|
||||
'NavService', 'KeyService', 'DetailsPanelService',
|
||||
|
||||
function (_$log_, _$scope_, _$location_,
|
||||
tbs, tds, _fs_, _mast_, _ps_, _wss_, _is_, _ns_, _ks_) {
|
||||
tbs, tds, _fs_, _mast_, _ps_, _wss_, _is_, _ns_, _ks_, _dps_) {
|
||||
var params,
|
||||
handlers = {};
|
||||
|
||||
@ -300,6 +220,7 @@
|
||||
is = _is_;
|
||||
ns = _ns_;
|
||||
ks = _ks_;
|
||||
dps = _dps_;
|
||||
|
||||
params = $loc.search();
|
||||
|
||||
@ -310,7 +231,7 @@
|
||||
$scope.meterTip = 'Show meter view for selected device';
|
||||
|
||||
// details panel handlers
|
||||
handlers[detailsResp] = respDetailsCb;
|
||||
// handlers[detailsResp] = respDetailsCb;
|
||||
handlers[nameChangeResp] = respNameCb;
|
||||
wss.bindHandlers(handlers);
|
||||
|
||||
@ -352,6 +273,7 @@
|
||||
};
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
dps.destroy();
|
||||
wss.unbindHandlers(handlers);
|
||||
});
|
||||
|
||||
@ -373,7 +295,7 @@
|
||||
|
||||
function initPanel() {
|
||||
heightCalc();
|
||||
createDetailsPane();
|
||||
createDetailsPanel();
|
||||
}
|
||||
|
||||
// Safari has a bug where it renders the fixed-layout table wrong
|
||||
@ -384,11 +306,8 @@
|
||||
initPanel();
|
||||
}
|
||||
// create key bindings to handle panel
|
||||
ks.keyBindings({
|
||||
enter: editNameSave,
|
||||
esc: [handleEscape, 'Close the details panel'],
|
||||
_helpFormat: ['esc'],
|
||||
});
|
||||
ks.keyBindings(keyBindings);
|
||||
|
||||
ks.gestureNotes([
|
||||
['click', 'Select a row to show device details'],
|
||||
['scroll down', 'See more devices'],
|
||||
|
||||
@ -22,16 +22,14 @@
|
||||
'use strict';
|
||||
|
||||
// injected refs
|
||||
var $log, $scope, $loc, fs, mast, ps, wss, is, ns, ks;
|
||||
var $log, $scope, $loc, fs, mast, ps, wss, is, ns, ks, dps;
|
||||
|
||||
// internal state
|
||||
var detailsPanel,
|
||||
pStartY,
|
||||
pHeight,
|
||||
top,
|
||||
iconDiv,
|
||||
wSize,
|
||||
editingName = false;
|
||||
wSize;
|
||||
|
||||
// constants
|
||||
var topPdg = 28,
|
||||
@ -41,13 +39,10 @@
|
||||
nameChangeReq = 'hostNameChangeRequest',
|
||||
nameChangeResp = 'hostNameChangeResponse';
|
||||
|
||||
var propOrder = [
|
||||
'id', 'ip', 'mac', 'vlan', 'configured', 'location',
|
||||
],
|
||||
friendlyProps = [
|
||||
'Host ID', 'IP Address', 'MAC Address', 'VLAN',
|
||||
'Configured', 'Location',
|
||||
];
|
||||
var keyBindings = {
|
||||
esc: [closePanel, 'Close the details panel'],
|
||||
_helpFormat: ['esc'],
|
||||
};
|
||||
|
||||
function closePanel() {
|
||||
if (detailsPanel.isVisible()) {
|
||||
@ -58,105 +53,41 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
function addCloseBtn(div) {
|
||||
is.loadEmbeddedIcon(div, 'close', 20);
|
||||
div.on('click', closePanel);
|
||||
}
|
||||
|
||||
function exitEditMode(nameH2, name) {
|
||||
nameH2.text(name);
|
||||
nameH2.classed('editable clickable', true);
|
||||
editingName = false;
|
||||
ks.enableGlobalKeys(true);
|
||||
}
|
||||
|
||||
function editNameSave() {
|
||||
var nameH2 = top.select('h2'),
|
||||
id = $scope.panelData.id,
|
||||
ip = $scope.panelData.ip,
|
||||
val,
|
||||
newVal;
|
||||
|
||||
if (editingName) {
|
||||
val = nameH2.select('input').property('value').trim();
|
||||
newVal = val || ip;
|
||||
|
||||
exitEditMode(nameH2, newVal);
|
||||
$scope.panelData.name = newVal;
|
||||
wss.sendEvent(nameChangeReq, { id: id, name: val });
|
||||
}
|
||||
}
|
||||
|
||||
function editNameCancel() {
|
||||
if (editingName) {
|
||||
exitEditMode(top.select('h2'), $scope.panelData.name);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function editName() {
|
||||
var nameH2 = top.select('h2'),
|
||||
tf, el;
|
||||
|
||||
if (!editingName) {
|
||||
nameH2.classed('editable clickable', false);
|
||||
nameH2.text('');
|
||||
tf = nameH2.append('input').classed('name-input', true)
|
||||
.attr('type', 'text')
|
||||
.attr('value', $scope.panelData.name);
|
||||
el = tf[0][0];
|
||||
el.focus();
|
||||
el.select();
|
||||
editingName = true;
|
||||
ks.enableGlobalKeys(false);
|
||||
}
|
||||
}
|
||||
|
||||
function handleEscape() {
|
||||
return editNameCancel() || closePanel();
|
||||
}
|
||||
|
||||
function setUpPanel() {
|
||||
var container, closeBtn;
|
||||
detailsPanel.empty();
|
||||
|
||||
container = detailsPanel.append('div').classed('container', true);
|
||||
dps.empty();
|
||||
dps.addContainers();
|
||||
dps.addCloseButton(closePanel);
|
||||
|
||||
top = container.append('div').classed('top', true);
|
||||
closeBtn = top.append('div').classed('close-btn', true);
|
||||
addCloseBtn(closeBtn);
|
||||
iconDiv = top.append('div').classed('host-icon', true);
|
||||
top.append('h2').classed('editable clickable', true).on('click', editName);
|
||||
var top = dps.top();
|
||||
|
||||
dps.addHeading('host-icon');
|
||||
top.append('div').classed('top-content', true);
|
||||
|
||||
top.append('div').classed('top-tables', true);
|
||||
top.append('hr');
|
||||
}
|
||||
|
||||
function addProp(tbody, index, value) {
|
||||
var tr = tbody.append('tr');
|
||||
|
||||
function addCell(cls, txt) {
|
||||
tr.append('td').attr('class', cls).text(txt);
|
||||
}
|
||||
addCell('label', friendlyProps[index] + ' :');
|
||||
addCell('value', value);
|
||||
function friendlyPropsList(details) {
|
||||
return {
|
||||
'Host ID': details.id,
|
||||
'IP Address': details.ip[0],
|
||||
'MAC Address': details.mac,
|
||||
'VLAN': details.vlan,
|
||||
'Configured': details.configured,
|
||||
'Location': details.location,
|
||||
};
|
||||
}
|
||||
|
||||
function populateTop(details) {
|
||||
var tab = top.select('.top-tables').append('table').append('tbody');
|
||||
|
||||
is.loadEmbeddedIcon(iconDiv, details._iconid_type, 40);
|
||||
top.select('h2').text(details.name);
|
||||
|
||||
propOrder.forEach(function (prop, i) {
|
||||
addProp(tab, i, details[prop]);
|
||||
});
|
||||
function populateTop(tblDiv, details) {
|
||||
is.loadEmbeddedIcon(dps.select('.iconDiv'), details._iconid_type, 40);
|
||||
dps.top().select('h2').text(details.name);
|
||||
dps.addPropsList(tblDiv, friendlyPropsList(details));
|
||||
}
|
||||
|
||||
function populateDetails(details) {
|
||||
setUpPanel();
|
||||
populateTop(details);
|
||||
populateTop(dps.select('.top-content'), details);
|
||||
detailsPanel.height(pHeight);
|
||||
// configure width based on content.. for now hardcoded
|
||||
detailsPanel.width(400);
|
||||
@ -174,18 +105,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
function createDetailsPane() {
|
||||
detailsPanel = ps.createPanel(pName, {
|
||||
function createDetailsPanel() {
|
||||
detailsPanel = dps.create(pName, {
|
||||
width: wSize.width,
|
||||
margin: 0,
|
||||
hideMargin: 0,
|
||||
scope: $scope,
|
||||
keyBindings: keyBindings,
|
||||
nameChangeRequest: nameChangeReq,
|
||||
});
|
||||
detailsPanel.el().style({
|
||||
position: 'absolute',
|
||||
top: pStartY + 'px',
|
||||
});
|
||||
|
||||
dps.setResponse(detailsResp, respDetailsCb);
|
||||
|
||||
$scope.hidePanel = function () { detailsPanel.hide(); };
|
||||
detailsPanel.hide();
|
||||
}
|
||||
|
||||
|
||||
@ -196,12 +128,12 @@
|
||||
'$location',
|
||||
'TableBuilderService',
|
||||
'FnService', 'MastService', 'PanelService', 'WebSocketService',
|
||||
'IconService', 'NavService', 'KeyService',
|
||||
'IconService', 'NavService', 'KeyService', 'DetailsPanelService',
|
||||
|
||||
function (_$log_, _$scope_, _$location_,
|
||||
tbs,
|
||||
_fs_, _mast_, _ps_, _wss_,
|
||||
_is_, _ns_, _ks_) {
|
||||
_is_, _ns_, _ks_, _dps_) {
|
||||
|
||||
var params,
|
||||
handlers = {};
|
||||
@ -216,13 +148,13 @@
|
||||
is = _is_;
|
||||
ns = _ns_;
|
||||
ks = _ks_;
|
||||
dps = _dps_;
|
||||
|
||||
params = $loc.search();
|
||||
|
||||
$scope.panelData = {};
|
||||
|
||||
// details panel handlers
|
||||
handlers[detailsResp] = respDetailsCb;
|
||||
handlers[nameChangeResp] = respNameCb;
|
||||
wss.bindHandlers(handlers);
|
||||
|
||||
@ -254,6 +186,7 @@
|
||||
};
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
dps.destroy();
|
||||
wss.unbindHandlers(handlers);
|
||||
});
|
||||
|
||||
@ -261,7 +194,7 @@
|
||||
}])
|
||||
|
||||
.directive('hostDetailsPanel',
|
||||
['$rootScope', '$window', '$timeout', 'KeyService',
|
||||
['$rootScope', '$window', '$timeout', 'KeyService', 'DetailsPanelService',
|
||||
function ($rootScope, $window, $timeout, ks) {
|
||||
return function (scope) {
|
||||
var unbindWatch;
|
||||
@ -275,7 +208,7 @@
|
||||
|
||||
function initPanel() {
|
||||
heightCalc();
|
||||
createDetailsPane();
|
||||
createDetailsPanel();
|
||||
}
|
||||
|
||||
// Safari has a bug where it renders the fixed-layout table wrong
|
||||
@ -286,11 +219,7 @@
|
||||
initPanel();
|
||||
}
|
||||
// create key bindings to handle panel
|
||||
ks.keyBindings({
|
||||
enter: editNameSave,
|
||||
esc: [handleEscape, 'Close the details panel'],
|
||||
_helpFormat: ['esc'],
|
||||
});
|
||||
ks.keyBindings(keyBindings);
|
||||
ks.gestureNotes([
|
||||
['click', 'Select a row to show device details'],
|
||||
['scroll down', 'See more devices'],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user