Initial commit
This commit is contained in:
commit
880e39de2e
511 files changed
+38363
No files matched your search
@@ -0,0 +1,22 @@
|
||||
angular.module('portal.common.directives.compareTo', ['ui.router'])
|
||||
.directive('compareTo', function(){
|
||||
return {
|
||||
require: 'ngModel',
|
||||
scope: {
|
||||
otherModelValue: '=compareTo'
|
||||
},
|
||||
link: function(scope, element, attributes, ngModel) {
|
||||
|
||||
ngModel.$validators.compareTo = function(modelValue) {
|
||||
if ((modelValue === null || modelValue === undefined) && scope.otherModelValue === null) {
|
||||
return true;
|
||||
}
|
||||
return modelValue === scope.otherModelValue;
|
||||
};
|
||||
|
||||
scope.$watch('otherModelValue', function() {
|
||||
ngModel.$validate();
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular.module('portal.common.directives.permissions', ['ui.router'])
|
||||
.directive('hasPermission', function(permissions){
|
||||
return {
|
||||
link: function(scope, element, attrs) {
|
||||
if (!_.isString(attrs.hasPermission)){
|
||||
throw 'hasPermission value must be a string';
|
||||
}
|
||||
var value = attrs.hasPermission.trim();
|
||||
var notPermissionFlag = value[0] === '!';
|
||||
if (notPermissionFlag) {
|
||||
value = value.slice(1).trim();
|
||||
}
|
||||
|
||||
function toggleVisibility() {
|
||||
permissions.canView({permission: value}).then(function(allowed){
|
||||
if ((allowed && !notPermissionFlag) || (!allowed && notPermissionFlag)) {
|
||||
element.css('display', 'block');
|
||||
} else {
|
||||
element.css('display', 'none');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
toggleVisibility();
|
||||
scope.$on('permissionsChanged', toggleVisibility);
|
||||
}
|
||||
};
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,14 @@
|
||||
<md-tabs md-selected="tabIndex" layout="column" layout-fill class="stretch-height">
|
||||
<md-tab ng-repeat="tab in visibleTabs" md-on-select="processTabClick($event, tab, $index);" active="tab.active"layout="column" layout-fill>
|
||||
<md-tab-label>
|
||||
<div layout="row">
|
||||
<div ng-bind-html="tab.leftItem"></div>
|
||||
<span id="{{tab.title.toLowerCase()}}-tab">{{tab.title}}</span>
|
||||
<div ng-bind-html="tab.rightItem"></div>
|
||||
</div>
|
||||
</md-tab-label>
|
||||
<md-tab-body>
|
||||
<div ng-include src="tab.source" style="height:100%"></div>
|
||||
</md-tab-body>
|
||||
</md-tab>
|
||||
</md-tabs>
|
||||
@@ -0,0 +1,129 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var _$state;
|
||||
|
||||
/**
|
||||
* Creates a tabset with a scrollable tab bar
|
||||
* Based on the incredible example at http://www.bootply.com/l2ChB4vYmC
|
||||
*/
|
||||
angular.module('portal.common.directives.portalTabset', ['ui.router'])
|
||||
.directive('portalTabSet', function ($state) {
|
||||
_$state = $state;
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: false, //Nothing shows up if you use replace: true
|
||||
transclude: true,
|
||||
scope: {
|
||||
tabs: '=',
|
||||
tabIndex: '=?',
|
||||
},
|
||||
templateUrl: 'common/directives/portal-tab-set/portal-tab-set.html',
|
||||
link: repoTabsetLink
|
||||
};
|
||||
});
|
||||
|
||||
function repoTabsetLink(scope, element, attrs, fn) {
|
||||
|
||||
//The default starting position of the tab group.
|
||||
var DEFAULT_TAB_POSITION = 0;
|
||||
|
||||
scope.tabIndex = scope.tabIndex === null || scope.tabIndex === undefined ? 0 : scope.tabIndex;
|
||||
scope.visibleTabs = [];
|
||||
|
||||
scope.$watch('tabIndex', function(value) {
|
||||
if (scope.tabIndex === null || scope.tabIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
scope.tabIndex = value;
|
||||
});
|
||||
|
||||
scope.tabsetSelectChange = function(index) {
|
||||
scope.tabIndex = index;
|
||||
scope.$emit('tabsetSelectChange', index);
|
||||
};
|
||||
|
||||
scope.$on('changeTabSelection', function(value) {
|
||||
scope.tabIndex = value;
|
||||
});
|
||||
|
||||
/**
|
||||
* Determines if the state object for a tab is active.
|
||||
*
|
||||
* @param {type} state A tab's state
|
||||
* @returns {boolean} True if the state is active, false otherwise.
|
||||
*/
|
||||
function isActive(state) {
|
||||
var isState = _$state.is(state);
|
||||
return isState || (_$state.current.name.indexOf(state) >= 0); // allow for sub tabs.
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the tabs after the state succesfully changes.
|
||||
*
|
||||
* @param {type} tabs An array of tabs. See action-pane.js for example
|
||||
* @returns {undefined}
|
||||
*/
|
||||
function updateTabStates(tabs) {
|
||||
//Update the active tag for each tab to reflect state change
|
||||
var activeTab = false;
|
||||
if (angular.isArray(tabs)) {
|
||||
tabs.forEach(function (tab) {
|
||||
tab.active = isActive(tab.state);
|
||||
activeTab = activeTab || tab.active;
|
||||
});
|
||||
//If no tab has been specified, activate the first tab.
|
||||
if (!activeTab && angular.isDefined(tabs[0])) {
|
||||
tabs[0].default = true;
|
||||
tabs[0].active = true;
|
||||
}
|
||||
|
||||
//Now notify tabs to respect tab activation
|
||||
scope.$broadcast('tabActivated');
|
||||
}
|
||||
}
|
||||
|
||||
scope.$on('tabsetDidChange', function (evt, tabs) {
|
||||
scope.tabs = tabs;
|
||||
update();
|
||||
});
|
||||
|
||||
function update() {
|
||||
updateVisisbleTabls();
|
||||
updateTabStates(scope.tabs);
|
||||
}
|
||||
|
||||
function updateVisisbleTabls() {
|
||||
for (var i = 0; i < scope.tabs.length; i++) {
|
||||
var tab = scope.tabs[i];
|
||||
if (tab.visible === undefined || tab.visible) {
|
||||
scope.visibleTabs[i] = tab;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scope.$on('$stateChangeSuccess', function () {
|
||||
updateTabStates(scope.tabs);
|
||||
});
|
||||
|
||||
/**
|
||||
* Changes the state to the specified tab state. If the control key was
|
||||
* held when the tab was click on, opens the tab's "big" state (fullscreen) in
|
||||
* a new tab.
|
||||
*
|
||||
* @param {$event} evt The click event. Used to determine if ctrl/cmd was held
|
||||
* during the click.
|
||||
* @param {type} tab The tab to activate. A tab object from $scope.tabs.
|
||||
*
|
||||
* @returns {undefined}
|
||||
*/
|
||||
scope.processTabClick = function (evt, tab, index) {
|
||||
_$state.go(tab.state);
|
||||
update();
|
||||
scope.tabsetSelectChange(index);
|
||||
};
|
||||
|
||||
updateVisisbleTabls();
|
||||
update();
|
||||
} //end dcdTabsetLink function
|
||||
})();
|
||||
@@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<i id="icon" class="material-icons" title="{{stats}}">{{iconImage}}</i>
|
||||
</div>
|
||||
@@ -0,0 +1,357 @@
|
||||
angular.module('portal.common.directives.portalWebsocket', ['ui.router'])
|
||||
.directive('portalWebsocket', PortalWebsocket);
|
||||
|
||||
function PortalWebsocket(Request, $timeout, portalUtils, PortalPubSub) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'common/directives/portal-websocket/portal-websocket.html',
|
||||
link: function (scope) {
|
||||
|
||||
scope.iconImage = 'import_export';
|
||||
scope.stats = 'not started';
|
||||
|
||||
var PingPong = function (msg) {
|
||||
this.date = msg.date;
|
||||
this.pull = msg.pull;
|
||||
this.data = msg.data;
|
||||
};
|
||||
|
||||
var Pinger = function () {
|
||||
this.progress = 0;
|
||||
this.count = 0;
|
||||
this.iterations = null;
|
||||
this.ping = null;
|
||||
this.pong = null;
|
||||
|
||||
this.bwConvert = function (bytes, msec) {
|
||||
var res = bytes / msec * 1000 * 8; // bits/second;
|
||||
var units;
|
||||
if (res > 1000000) {
|
||||
res /= 1024000; // Mbits/sec
|
||||
units = 'Mbps';
|
||||
} else if (res > 1024) {
|
||||
res /= 1000; // Kbits/sec
|
||||
units = 'Kbps';
|
||||
} else {
|
||||
units = 'bps';
|
||||
}
|
||||
return this.round(res, 1) + units;
|
||||
};
|
||||
|
||||
this.round = function (value, decimals) {
|
||||
return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
|
||||
};
|
||||
|
||||
this.isDone = function () {
|
||||
if (this.count >= this.iterations) {
|
||||
this.progress = 100;
|
||||
return true;
|
||||
} else {
|
||||
this.progress = this.round(this.count / this.iterations * 100, 0);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
var LatencyTask = portalUtils.inherit(function () {
|
||||
Pinger.call(this);
|
||||
this.iterations = 100;
|
||||
this.latencySum = 0;
|
||||
this.latencyMin = 0;
|
||||
this.latencyAve = 0;
|
||||
this.latencyMax = 0;
|
||||
this.pps = 'n/a';
|
||||
|
||||
this.getPing = function () {
|
||||
this.ping = new PingPong({'date': new Date().getTime(), 'pull': 0, 'data': []});
|
||||
return this.ping;
|
||||
};
|
||||
|
||||
this.onPong = function (pong) {
|
||||
this.pong = pong;
|
||||
this.count++;
|
||||
var now = new Date().getTime();
|
||||
var msec = now - this.pong.date;
|
||||
this.latencySum += msec;
|
||||
this.latencyAve = this.round(this.latencySum / this.count, 0);
|
||||
if (this.latencyMin === 0 || msec < this.latencyMin) {
|
||||
this.latencyMin = msec;
|
||||
}
|
||||
if (this.latencyMax === 0 || msec > this.latencyMax) {
|
||||
this.latencyMax = msec;
|
||||
}
|
||||
// calc aggregate ppps
|
||||
this.pps = this.count / this.latencySum * 1000;
|
||||
this.pps = this.round(this.pps, 1);
|
||||
return this.isDone();
|
||||
};
|
||||
|
||||
|
||||
return this;
|
||||
}, Pinger);
|
||||
|
||||
var DownloadTask = portalUtils.inherit(function (latencyTask) {
|
||||
Pinger.call(this);
|
||||
this.iterations = 20;
|
||||
this.downloadBytes = 0;
|
||||
this.downloadTime = 0;
|
||||
this.download = 0;
|
||||
this.pull = 10000;
|
||||
|
||||
this.getPing = function () {
|
||||
this.ping = new PingPong({'date': new Date().getTime(), 'pull': this.pull, 'data': []});
|
||||
return this.ping;
|
||||
};
|
||||
|
||||
this.onPong = function (pong) {
|
||||
this.pong = pong;
|
||||
this.count++;
|
||||
var now = new Date().getTime();
|
||||
var msec = now - this.pong.date - latencyTask.latencyAve / 2;
|
||||
var bytes = this.pong.data.length;
|
||||
this.downloadBytes += bytes;
|
||||
this.downloadTime += msec;
|
||||
// calc aggregate download bandwidth
|
||||
this.download = this.bwConvert(this.downloadBytes, this.downloadTime);
|
||||
return this.isDone();
|
||||
};
|
||||
|
||||
return this;
|
||||
}, Pinger);
|
||||
|
||||
var UploadTask = portalUtils.inherit(function (latencyTask, downloadTask) {
|
||||
Pinger.call(this);
|
||||
this.iterations = 20;
|
||||
this.uploadBytes = 0;
|
||||
this.uploadTime = 0;
|
||||
this.upload = 0;
|
||||
|
||||
this.getPing = function () {
|
||||
this.ping = new PingPong({'date': new Date().getTime(), 'pull': 0, 'data': downloadTask.pong.data});
|
||||
return this.ping;
|
||||
};
|
||||
|
||||
this.onPong = function (pong) {
|
||||
this.pong = pong;
|
||||
this.count++;
|
||||
var now = new Date().getTime();
|
||||
var msec = now - this.pong.date - latencyTask.latencyAve / 2;
|
||||
var bytes = this.ping.data.length;
|
||||
this.uploadBytes += bytes;
|
||||
this.uploadTime += msec;
|
||||
this.upload = this.bwConvert(this.uploadBytes, this.uploadTime);
|
||||
return this.isDone();
|
||||
};
|
||||
|
||||
return this;
|
||||
}, Pinger);
|
||||
|
||||
var icon = document.getElementById('icon');
|
||||
|
||||
var latencyTask = new LatencyTask();
|
||||
var downloadTask = new DownloadTask(latencyTask);
|
||||
var uploadTask = new UploadTask(latencyTask, downloadTask);
|
||||
var task = latencyTask;
|
||||
var transport = null;
|
||||
var stompClient = null;
|
||||
var subscription = null;
|
||||
|
||||
function onConnectionSuccess(frame) {
|
||||
|
||||
transport = stompClient.ws.transport;
|
||||
|
||||
// subscribe to the /info/pong queue for this user, requires controller annotations:
|
||||
// @SubscribeMapping('/info/ping')
|
||||
// @SendToUser('/queue/info/pong')
|
||||
var headers = {/*ack: 'client'*/};
|
||||
subscription = stompClient.subscribe('/user/queue/pong', onPong, headers);
|
||||
|
||||
// if not websocket scale down the number of iterations
|
||||
if (transport !== 'websocket') {
|
||||
var div = 5;
|
||||
latencyTask.iterations /= div;
|
||||
downloadTask.iterations /= div;
|
||||
uploadTask.iterations /= div;
|
||||
}
|
||||
|
||||
// kick it off
|
||||
task = latencyTask;
|
||||
sendPing();
|
||||
}
|
||||
|
||||
function onPong(frame) {
|
||||
|
||||
// frame.ack();
|
||||
scope.$apply(function () {
|
||||
var done = task.onPong(new PingPong(JSON.parse(frame.body)));
|
||||
|
||||
// switch tasks when finished
|
||||
if (done && task === latencyTask) {
|
||||
task = downloadTask;
|
||||
} else if (done && task === downloadTask) {
|
||||
task = uploadTask;
|
||||
} else if (done && task === uploadTask) {
|
||||
task = null;
|
||||
}
|
||||
|
||||
if (task !== null) {
|
||||
|
||||
sendPing();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
scope.busy = function () {
|
||||
return task !== null;
|
||||
};
|
||||
|
||||
function connect(transports) {
|
||||
|
||||
|
||||
// create stomp client
|
||||
var options = {transports: transports};
|
||||
var socket = new SockJS(Request.baseURI + '/ws/stomp', null, options);
|
||||
stompClient = Stomp.over(socket);
|
||||
stompClient.debug = null;
|
||||
|
||||
// connect to server
|
||||
scope.stats = 'connecting';
|
||||
var headers = {};
|
||||
stompClient.connect(headers, onConnectionSuccess, onConnectionFailure);
|
||||
}
|
||||
|
||||
function sendPing() {
|
||||
setActiveStatus();
|
||||
stompClient.send('/start/ping', {}, JSON.stringify(task.getPing()));
|
||||
}
|
||||
|
||||
var timer = null;
|
||||
|
||||
function flash() {
|
||||
icon.style.color = (icon.style.color === 'green') ? 'goldenrod' : 'green';
|
||||
if (getProgress() < 100) {
|
||||
timer = $timeout(flash, 250);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getProgress() {
|
||||
return Math.round((latencyTask.progress + uploadTask.progress + downloadTask.progress) / 3);
|
||||
}
|
||||
|
||||
function finish() {
|
||||
$timeout.cancel(timer);
|
||||
|
||||
// shutdown the websocket connection
|
||||
subscription.unsubscribe();
|
||||
stompClient.disconnect();
|
||||
stompClient = null;
|
||||
|
||||
if (transport === 'websocket') {
|
||||
setSuccessfulStatus();
|
||||
} else {
|
||||
setDegradedStatus();
|
||||
}
|
||||
}
|
||||
|
||||
function onConnectionFailure(error) {
|
||||
$timeout.cancel(timer);
|
||||
stompClient = null; // Stomp connections are closed on failure
|
||||
setFailureStatus(error.toString());
|
||||
}
|
||||
|
||||
|
||||
function createStats() {
|
||||
var min = latencyTask.latencyMin;
|
||||
var ave = latencyTask.latencyAve;
|
||||
var max = latencyTask.latencyMax;
|
||||
var pps = latencyTask.pps;
|
||||
var upload = uploadTask.upload;
|
||||
var download = downloadTask.download;
|
||||
var latency = min + '/' + ave + '/' + max;
|
||||
|
||||
// always start with the transport
|
||||
var stats = transport;
|
||||
if (latencyTask.progress > 0) {
|
||||
stats += ', ' + latency + 'ms, ' + pps + 'pps';
|
||||
}
|
||||
if (downloadTask.progress > 0) {
|
||||
stats += ', ' + download;
|
||||
}
|
||||
if (uploadTask.progress > 0) {
|
||||
stats += '/' + upload;
|
||||
}
|
||||
if (getProgress() < 100) {
|
||||
stats += ', ' + getProgress() + '%';
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
|
||||
function setActiveStatus() {
|
||||
|
||||
// make available to html
|
||||
scope.stats = createStats();
|
||||
|
||||
// icon stays flashing
|
||||
|
||||
// notify login dialog that we are not finished
|
||||
PortalPubSub.publish('StompTestStatus', {status: 'active', stats: scope.stats});
|
||||
}
|
||||
|
||||
|
||||
// green
|
||||
function setSuccessfulStatus() {
|
||||
|
||||
// make available to html
|
||||
scope.stats = createStats();
|
||||
|
||||
// flashing has stopped, set green check
|
||||
scope.iconImage = 'check';
|
||||
icon.style.color = 'green';
|
||||
|
||||
// publish status (to login dialog)
|
||||
PortalPubSub.publish('StompTestStatus', {status: 'successful', stats: scope.stats});
|
||||
}
|
||||
|
||||
// yellow
|
||||
function setDegradedStatus() {
|
||||
|
||||
// make available to html
|
||||
scope.stats = createStats();
|
||||
|
||||
// flashing has stopped, set yellow info flag
|
||||
scope.iconImage = 'info';
|
||||
icon.style.color = 'goldenrod';
|
||||
|
||||
// publish status (to login dialog)
|
||||
PortalPubSub.publish('StompTestStatus', {status: 'degraded', stats: scope.stats});
|
||||
}
|
||||
|
||||
//red
|
||||
function setFailureStatus(msg) {
|
||||
|
||||
// set hover over
|
||||
scope.stats = 'failed: ' + msg;
|
||||
|
||||
// flashing has stopped, set red error flag
|
||||
scope.iconImage = 'error';
|
||||
icon.style.color = 'red';
|
||||
|
||||
// publish status (to login dialog)
|
||||
PortalPubSub.publish('StompTestStatus', {status: 'failure', stats: scope.stats});
|
||||
|
||||
}
|
||||
|
||||
// start the test
|
||||
flash();
|
||||
var transports = [/*'websocket', 'xhr-streaming', 'eventsource', 'xhr-polling', 'jsonp-polling'*/];
|
||||
connect(transports);
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user