mirror of
https://github.com/ansible/awx.git
synced 2026-02-19 04:00:06 -03:30
switching socket.io-client for ReconnectingWebSocket library
This commit is contained in:
@@ -713,80 +713,53 @@ var tower = angular.module('Tower', [
|
|||||||
$rootScope.removeOpenSocket();
|
$rootScope.removeOpenSocket();
|
||||||
}
|
}
|
||||||
$rootScope.removeOpenSocket = $rootScope.$on('OpenSocket', function() {
|
$rootScope.removeOpenSocket = $rootScope.$on('OpenSocket', function() {
|
||||||
// Listen for job changes and issue callbacks to initiate
|
|
||||||
// DOM updates
|
|
||||||
function openSocket() {
|
function openSocket() {
|
||||||
var schedule_socket, control_socket;
|
$rootScope.socket = Socket({ scope: $rootScope});
|
||||||
|
$rootScope.socket.init();
|
||||||
sock = Socket({ scope: $rootScope, endpoint: "jobs" });
|
|
||||||
sock.init();
|
|
||||||
sock.on("status_changed", function(data) {
|
|
||||||
$log.debug('Job ' + data.unified_job_id +
|
|
||||||
' status changed to ' + data.status +
|
|
||||||
' send to ' + $location.$$url);
|
|
||||||
|
|
||||||
// this acts as a router...it emits the proper
|
|
||||||
// value based on what URL the user is currently
|
|
||||||
// accessing.
|
|
||||||
if ($state.is('jobs')) {
|
|
||||||
$rootScope.$emit('JobStatusChange-jobs', data);
|
|
||||||
} else if ($state.includes('jobDetail') ||
|
|
||||||
$state.is('adHocJobStdout') ||
|
|
||||||
$state.is('inventorySyncStdout') ||
|
|
||||||
$state.is('managementJobStdout') ||
|
|
||||||
$state.is('scmUpdateStdout')) {
|
|
||||||
|
|
||||||
$log.debug("sending status to standard out");
|
|
||||||
$rootScope.$emit('JobStatusChange-jobStdout', data);
|
|
||||||
}
|
|
||||||
if ($state.includes('jobDetail')) {
|
|
||||||
$rootScope.$emit('JobStatusChange-jobDetails', data);
|
|
||||||
} else if ($state.is('dashboard')) {
|
|
||||||
$rootScope.$emit('JobStatusChange-home', data);
|
|
||||||
} else if ($state.is('portalMode')) {
|
|
||||||
$rootScope.$emit('JobStatusChange-portal', data);
|
|
||||||
} else if ($state.is('projects')) {
|
|
||||||
$rootScope.$emit('JobStatusChange-projects', data);
|
|
||||||
} else if ($state.is('inventoryManage')) {
|
|
||||||
$rootScope.$emit('JobStatusChange-inventory', data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sock.on("summary_complete", function(data) {
|
|
||||||
$log.debug('Job summary_complete ' + data.unified_job_id);
|
|
||||||
$rootScope.$emit('JobSummaryComplete', data);
|
|
||||||
});
|
|
||||||
|
|
||||||
schedule_socket = Socket({
|
|
||||||
scope: $rootScope,
|
|
||||||
endpoint: "schedules"
|
|
||||||
});
|
|
||||||
schedule_socket.init();
|
|
||||||
schedule_socket.on("schedule_changed", function(data) {
|
|
||||||
$log.debug('Schedule ' + data.unified_job_id + ' status changed to ' + data.status);
|
|
||||||
$rootScope.$emit('ScheduleStatusChange', data);
|
|
||||||
});
|
|
||||||
|
|
||||||
control_socket = Socket({
|
|
||||||
scope: $rootScope,
|
|
||||||
endpoint: "control"
|
|
||||||
});
|
|
||||||
control_socket.init();
|
|
||||||
control_socket.on("limit_reached", function(data) {
|
|
||||||
$log.debug(data.reason);
|
|
||||||
$rootScope.sessionTimer.expireSession('session_limit');
|
|
||||||
$state.go('signOut');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
openSocket();
|
openSocket();
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
$rootScope.$apply(function() {
|
$rootScope.$apply(function() {
|
||||||
sock.checkStatus();
|
$rootScope.socket.checkStatus();
|
||||||
$log.debug('socket status: ' + $rootScope.socketStatus);
|
$log.debug('socket status: ' + $rootScope.socketStatus);
|
||||||
});
|
});
|
||||||
}, 2000);
|
}, 2000);
|
||||||
});
|
});
|
||||||
|
// {'groups':
|
||||||
|
// {'jobs': ['status_changed', 'summary'],
|
||||||
|
// 'schedules': ['changed'],
|
||||||
|
// 'ad_hoc_command_events': [ids,],
|
||||||
|
// 'job_events': [ids,],
|
||||||
|
// 'control': ['limit_reached'],
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState) {
|
||||||
|
if(toState.name === 'dashboard'){
|
||||||
|
$rootScope.socket.emit('{"groups":{"jobs": ["status_changed"]}}');
|
||||||
|
}
|
||||||
|
else if(toState.name === 'jobDetail'){
|
||||||
|
$rootScope.socket.emit(`{"groups":{"jobs": ["status_changed", "summary"]},{"job_events":[${toParams.id}]}}`);
|
||||||
|
}
|
||||||
|
else if(toState.name === 'jobStdout'){
|
||||||
|
$rootScope.socket.emit('{"groups":{"jobs": ["status_changed"]}}');
|
||||||
|
}
|
||||||
|
else if(toState.name === 'jobs'){
|
||||||
|
$rootScope.socket.emit('{"groups":{"jobs": ["status_changed"]}, {"schedules": ["changed"]}}');
|
||||||
|
}
|
||||||
|
else if(toState.name === 'portalMode'){
|
||||||
|
$rootScope.socket.emit('{"groups":{"jobs": ["status_changed"]}}');
|
||||||
|
}
|
||||||
|
else if(toState.name === 'projects'){
|
||||||
|
$rootScope.socket.emit('{"groups":{"jobs": ["status_changed"]}}');
|
||||||
|
}
|
||||||
|
else if(toState.name === 'inventory'){
|
||||||
|
$rootScope.socket.emit('{"groups":{"jobs": ["status_changed"]}}');
|
||||||
|
}
|
||||||
|
else if(toState.name === 'adHocJobStdout'){
|
||||||
|
$rootScope.socket.emit(`{"groups":{"ad_hoc_command_events": [${toParams.id}]}}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState) {
|
$rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState) {
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
// custom_login_info: "example notice" // have a notice displayed in the login modal for users. note that, as a security measure, custom html is not supported and will be escaped.
|
// custom_login_info: "example notice" // have a notice displayed in the login modal for users. note that, as a security measure, custom html is not supported and will be escaped.
|
||||||
tooltip_delay: { show: 500, hide: 100 }, // Default number of milliseconds to delay displaying/hiding tooltips
|
tooltip_delay: { show: 500, hide: 100 }, // Default number of milliseconds to delay displaying/hiding tooltips
|
||||||
|
|
||||||
debug_mode: false, // Enable console logging messages
|
debug_mode: true, // Enable console logging messages
|
||||||
|
|
||||||
password_length: 8, // Minimum user password length. Set to 0 to not set a limit
|
password_length: 8, // Minimum user password length. Set to 0 to not set a limit
|
||||||
password_hasLowercase: true, // require a lowercase letter in the password
|
password_hasLowercase: true, // require a lowercase letter in the password
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ export default
|
|||||||
"<p><i class=\"fa fa-circle unreachable-hosts-color\"></i> Unreachable</p>\n" +
|
"<p><i class=\"fa fa-circle unreachable-hosts-color\"></i> Unreachable</p>\n" +
|
||||||
"<p><i class=\"fa fa-circle failed-hosts-color\"></i> Failed</p>\n";
|
"<p><i class=\"fa fa-circle failed-hosts-color\"></i> Failed</p>\n";
|
||||||
function openSocket() {
|
function openSocket() {
|
||||||
$rootScope.event_socket.on("job_events-" + job_id, function(data) {
|
$rootScope.socket.on("job_events-" + job_id, function(data) {
|
||||||
// update elapsed time on each event received
|
// update elapsed time on each event received
|
||||||
scope.job_status.elapsed = GetElapsed({
|
scope.job_status.elapsed = GetElapsed({
|
||||||
start: scope.job.created,
|
start: scope.job.created,
|
||||||
@@ -213,9 +213,9 @@ export default
|
|||||||
});
|
});
|
||||||
// Unbind $rootScope socket event binding(s) so that they don't get triggered
|
// Unbind $rootScope socket event binding(s) so that they don't get triggered
|
||||||
// in another instance of this controller
|
// in another instance of this controller
|
||||||
scope.$on('$destroy', function() {
|
// scope.$on('$destroy', function() {
|
||||||
$rootScope.event_socket.removeAllListeners("job_events-" + job_id);
|
// $rootScope.socket.removeAllListeners("job_events-" + job_id);
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
openSocket();
|
openSocket();
|
||||||
|
|
||||||
|
|||||||
@@ -13,22 +13,22 @@ export default {
|
|||||||
parent: 'jobs',
|
parent: 'jobs',
|
||||||
label: "{{ job.id }} - {{ job.name }}"
|
label: "{{ job.id }} - {{ job.name }}"
|
||||||
},
|
},
|
||||||
resolve: {
|
// resolve: {
|
||||||
jobEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) {
|
// jobEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) {
|
||||||
if (!$rootScope.event_socket) {
|
// if (!$rootScope.event_socket) {
|
||||||
$rootScope.event_socket = Socket({
|
// $rootScope.event_socket = Socket({
|
||||||
scope: $rootScope,
|
// scope: $rootScope,
|
||||||
endpoint: "job_events"
|
// endpoint: "job_events"
|
||||||
});
|
// });
|
||||||
$rootScope.event_socket.init();
|
// $rootScope.event_socket.init();
|
||||||
// returns should really be providing $rootScope.event_socket
|
// // returns should really be providing $rootScope.event_socket
|
||||||
// otherwise, we have to inject the entire $rootScope into the controller
|
// // otherwise, we have to inject the entire $rootScope into the controller
|
||||||
return true;
|
// return true;
|
||||||
} else {
|
// } else {
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
}]
|
// }]
|
||||||
},
|
// },
|
||||||
templateUrl: templateUrl('job-detail/job-detail'),
|
templateUrl: templateUrl('job-detail/job-detail'),
|
||||||
controller: 'JobDetailController'
|
controller: 'JobDetailController'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,16 +22,16 @@
|
|||||||
* @methodOf shared.function:Socket
|
* @methodOf shared.function:Socket
|
||||||
* @description
|
* @description
|
||||||
*/
|
*/
|
||||||
|
import ReconnectingWebSocket from 'reconnectingwebsocket'
|
||||||
export default
|
export default
|
||||||
angular.module('SocketIO', ['Utilities'])
|
angular.module('SocketIO', ['Utilities'])
|
||||||
|
|
||||||
.factory('Socket', ['$rootScope', '$location', '$log', 'Authorization', 'Store', function ($rootScope, $location, $log, Authorization, Store) {
|
.factory('Socket', ['$rootScope', '$location', '$log', 'Authorization', 'Store', function ($rootScope, $location, $log, Authorization, Store) {
|
||||||
return function(params) {
|
return function(params) {
|
||||||
var scope = params.scope,
|
var scope = params.scope,
|
||||||
host = $location.host(),
|
host = window.location.host,
|
||||||
endpoint = params.endpoint,
|
endpoint = params.endpoint,
|
||||||
protocol = $location.protocol(),
|
protocol = $location.protocol(),
|
||||||
io = require('socket.io-client'),
|
|
||||||
config, socketPort,
|
config, socketPort,
|
||||||
url;
|
url;
|
||||||
|
|
||||||
@@ -45,7 +45,9 @@ angular.module('SocketIO', ['Utilities'])
|
|||||||
config = Store('AnsibleConfig');
|
config = Store('AnsibleConfig');
|
||||||
socketPort = config.websocket_port;
|
socketPort = config.websocket_port;
|
||||||
}
|
}
|
||||||
url = protocol + '://' + host + ':' + socketPort + '/socket.io/' + endpoint;
|
|
||||||
|
url = "ws://" + host + "/websocket/";
|
||||||
|
// url = protocol + '://' + host + ':' + socketPort + '/socket.io/' + endpoint;
|
||||||
$log.debug('opening socket connection to: ' + url);
|
$log.debug('opening socket connection to: ' + url);
|
||||||
|
|
||||||
function getSocketTip(status) {
|
function getSocketTip(status) {
|
||||||
@@ -75,86 +77,10 @@ angular.module('SocketIO', ['Utilities'])
|
|||||||
// We have a valid session token, so attempt socket connection
|
// We have a valid session token, so attempt socket connection
|
||||||
$log.debug('Socket connecting to: ' + url);
|
$log.debug('Socket connecting to: ' + url);
|
||||||
self.scope.socket_url = url;
|
self.scope.socket_url = url;
|
||||||
self.socket = io.connect(url, {
|
self.socket = new ReconnectingWebSocket(url, null, {
|
||||||
query: "Token="+token,
|
debug: true,
|
||||||
headers:
|
timeoutInterval: 3000,
|
||||||
{
|
maxReconnectAttempts: 10
|
||||||
'Authorization': 'Token ' + token, // i don't think these are actually inserted into the header--jt
|
|
||||||
'X-Auth-Token': 'Token ' + token
|
|
||||||
},
|
|
||||||
'connect timeout': 3000,
|
|
||||||
'try multiple transports': false,
|
|
||||||
'max reconnection attempts': 10,
|
|
||||||
'reconnection limit': 2000,
|
|
||||||
'force new connection': true
|
|
||||||
});
|
|
||||||
|
|
||||||
self.socket.on('connection', function() {
|
|
||||||
$log.debug('Socket connecting...');
|
|
||||||
self.scope.$apply(function () {
|
|
||||||
self.scope.socketStatus = 'connecting';
|
|
||||||
self.scope.socketTip = getSocketTip(self.scope.socketStatus);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
self.socket.on('connect', function() {
|
|
||||||
$log.debug('Socket connection established');
|
|
||||||
self.scope.$apply(function () {
|
|
||||||
self.scope.socketStatus = 'ok';
|
|
||||||
self.scope.socketTip = getSocketTip(self.scope.socketStatus);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
self.socket.on('connect_failed', function(reason) {
|
|
||||||
var r = reason || 'connection refused by host',
|
|
||||||
token_actual = Authorization.getToken();
|
|
||||||
|
|
||||||
$log.debug('Socket connection failed: ' + r);
|
|
||||||
|
|
||||||
if (token_actual === token) {
|
|
||||||
self.socket.socket.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.scope.$apply(function () {
|
|
||||||
self.scope.socketStatus = 'error';
|
|
||||||
self.scope.socketTip = getSocketTip(self.scope.socketStatus);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
self.socket.on('diconnect', function() {
|
|
||||||
$log.debug('Socket disconnected');
|
|
||||||
self.scope.$apply(function() {
|
|
||||||
self.scope.socketStatus = 'error';
|
|
||||||
self.scope.socketTip = getSocketTip(self.scope.socketStatus);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
self.socket.on('error', function(reason) {
|
|
||||||
var r = reason || 'connection refused by host';
|
|
||||||
$log.debug('Socket error: ' + r);
|
|
||||||
$log.error('Socket error: ' + r);
|
|
||||||
self.scope.$apply(function() {
|
|
||||||
self.scope.socketStatus = 'error';
|
|
||||||
self.scope.socketTip = getSocketTip(self.scope.socketStatus);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
self.socket.on('reconnecting', function() {
|
|
||||||
$log.debug('Socket attempting reconnect...');
|
|
||||||
self.scope.$apply(function() {
|
|
||||||
self.scope.socketStatus = 'connecting';
|
|
||||||
self.scope.socketTip = getSocketTip(self.scope.socketStatus);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
self.socket.on('reconnect', function() {
|
|
||||||
$log.debug('Socket reconnected');
|
|
||||||
self.scope.$apply(function() {
|
|
||||||
self.scope.socketStatus = 'ok';
|
|
||||||
self.scope.socketTip = getSocketTip(self.scope.socketStatus);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
self.socket.on('reconnect_failed', function(reason) {
|
|
||||||
$log.error('Socket reconnect failed: ' + reason);
|
|
||||||
self.scope.$apply(function() {
|
|
||||||
self.scope.socketStatus = 'error';
|
|
||||||
self.scope.socketTip = getSocketTip(self.scope.socketStatus);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -167,21 +93,19 @@ angular.module('SocketIO', ['Utilities'])
|
|||||||
// Check connection status
|
// Check connection status
|
||||||
var self = this;
|
var self = this;
|
||||||
if(self){
|
if(self){
|
||||||
if(self.socket){
|
if(self.socket){
|
||||||
if(self.socket.socket){
|
if (self.socket.readyState === 0 ) {
|
||||||
if (self.socket.socket.connected) {
|
self.scope.socketStatus = 'connecting';
|
||||||
self.scope.socketStatus = 'ok';
|
}
|
||||||
}
|
else if (self.socket.readyState === 1){
|
||||||
else if (self.socket.socket.connecting || self.socket.reconnecting) {
|
self.scope.socketStatus = 'ok';
|
||||||
self.scope.socketStatus = 'connecting';
|
}
|
||||||
}
|
else if (self.socket.readyState === 2 || self.socket.readyState === 3 ){
|
||||||
else {
|
self.scope.socketStatus = 'error';
|
||||||
self.scope.socketStatus = 'error';
|
}
|
||||||
}
|
self.scope.socketTip = getSocketTip(self.scope.socketStatus);
|
||||||
self.scope.socketTip = getSocketTip(self.scope.socketStatus);
|
return self.scope.socketStatus;
|
||||||
return self.scope.socketStatus;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -189,7 +113,8 @@ angular.module('SocketIO', ['Utilities'])
|
|||||||
var self = this;
|
var self = this;
|
||||||
if(self){
|
if(self){
|
||||||
if(self.socket){
|
if(self.socket){
|
||||||
self.socket.on(eventName, function () {
|
self.socket.onmessage(eventName, function (e) {
|
||||||
|
console.log('Received From Server: ' + e.data);
|
||||||
var args = arguments;
|
var args = arguments;
|
||||||
self.scope.$apply(function () {
|
self.scope.$apply(function () {
|
||||||
callback.apply(self.socket, args);
|
callback.apply(self.socket, args);
|
||||||
@@ -201,7 +126,7 @@ angular.module('SocketIO', ['Utilities'])
|
|||||||
},
|
},
|
||||||
emit: function (eventName, data, callback) {
|
emit: function (eventName, data, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.socket.emit(eventName, data, function () {
|
self.socket.send(eventName, data, function () {
|
||||||
var args = arguments;
|
var args = arguments;
|
||||||
self.scope.$apply(function () {
|
self.scope.$apply(function () {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
@@ -217,7 +142,7 @@ angular.module('SocketIO', ['Utilities'])
|
|||||||
var self = this;
|
var self = this;
|
||||||
if(self){
|
if(self){
|
||||||
if(self.socket){
|
if(self.socket){
|
||||||
self.socket.removeAllListeners(eventName);
|
self.socket.removeEventListener(eventName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce
|
|||||||
function openSockets() {
|
function openSockets() {
|
||||||
if ($state.current.name === 'jobDetail') {
|
if ($state.current.name === 'jobDetail') {
|
||||||
$log.debug("socket watching on job_events-" + job_id);
|
$log.debug("socket watching on job_events-" + job_id);
|
||||||
$rootScope.event_socket.on("job_events-" + job_id, function() {
|
$rootScope.socket.on("job_events-" + job_id, function() {
|
||||||
$log.debug("socket fired on job_events-" + job_id);
|
$log.debug("socket fired on job_events-" + job_id);
|
||||||
if (api_complete) {
|
if (api_complete) {
|
||||||
event_queue++;
|
event_queue++;
|
||||||
@@ -30,9 +30,9 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce
|
|||||||
});
|
});
|
||||||
// Unbind $rootScope socket event binding(s) so that they don't get triggered
|
// Unbind $rootScope socket event binding(s) so that they don't get triggered
|
||||||
// in another instance of this controller
|
// in another instance of this controller
|
||||||
$scope.$on('$destroy', function() {
|
// $scope.$on('$destroy', function() {
|
||||||
$rootScope.event_socket.removeAllListeners("job_events-" + job_id);
|
// $rootScope.socket.removeAllListeners("job_events-" + job_id);
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
if ($state.current.name === 'adHocJobStdout') {
|
if ($state.current.name === 'adHocJobStdout') {
|
||||||
$log.debug("socket watching on ad_hoc_command_events-" + job_id);
|
$log.debug("socket watching on ad_hoc_command_events-" + job_id);
|
||||||
@@ -44,9 +44,9 @@ export default ['$log', '$rootScope', '$scope', '$state', '$stateParams', 'Proce
|
|||||||
});
|
});
|
||||||
// Unbind $rootScope socket event binding(s) so that they don't get triggered
|
// Unbind $rootScope socket event binding(s) so that they don't get triggered
|
||||||
// in another instance of this controller
|
// in another instance of this controller
|
||||||
$scope.$on('$destroy', function() {
|
// $scope.$on('$destroy', function() {
|
||||||
$rootScope.adhoc_event_socket.removeAllListeners("ad_hoc_command_events-" + job_id);
|
// $rootScope.adhoc_event_socket.removeAllListeners("ad_hoc_command_events-" + job_id);
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,8 @@
|
|||||||
"moment": "^2.10.2",
|
"moment": "^2.10.2",
|
||||||
"ng-toast": "leigh-johnson/ngToast#2.0.1",
|
"ng-toast": "leigh-johnson/ngToast#2.0.1",
|
||||||
"nvd3": "leigh-johnson/nvd3#1.7.1",
|
"nvd3": "leigh-johnson/nvd3#1.7.1",
|
||||||
"select2": "^4.0.2",
|
"reconnectingwebsocket": "^1.0.0",
|
||||||
"socket.io-client": "^0.9.17"
|
"rrule": "jkbrzt/rrule#4ff63b2f8524fd6d5ba6e80db770953b5cd08a0c",
|
||||||
|
"select2": "^4.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ var vendorPkgs = [
|
|||||||
'ng-toast',
|
'ng-toast',
|
||||||
'nvd3',
|
'nvd3',
|
||||||
'select2',
|
'select2',
|
||||||
'socket.io-client',
|
'reconnectingwebsocket'
|
||||||
];
|
];
|
||||||
|
|
||||||
var dev = {
|
var dev = {
|
||||||
|
|||||||
Reference in New Issue
Block a user