diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 67d4d35a87..db43657283 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -240,87 +240,98 @@ var tower = angular.module('Tower', [ }); $stateProvider. - state('dashboard', { - url: '/home', - templateUrl: urlPrefix + 'partials/home.html', - controller: Home, - params: { licenseMissing: null }, - data: { - activityStream: true, - refreshButton: true - }, - ncyBreadcrumb: { - label: "DASHBOARD" - }, - resolve: { - graphData: ['$q', 'jobStatusGraphData', '$rootScope', - function($q, jobStatusGraphData, $rootScope) { - return $rootScope.featuresConfigured.promise.then(function() { - return $q.all({ - jobStatus: jobStatusGraphData.get("month", "all"), - }); - }); - } - ] - } - }). - - state('jobs', { - url: '/jobs', - templateUrl: urlPrefix + 'partials/jobs.html', - controller: JobsListController, - ncyBreadcrumb: { - label: "JOBS" - } - }). - - state('projects', { - url: '/projects?{status}', - templateUrl: urlPrefix + 'partials/projects.html', - controller: ProjectsList, - data: { - activityStream: true, - activityStreamTarget: 'project' - }, - ncyBreadcrumb: { - label: "PROJECTS" - } - }). - - state('projects.add', { - url: '/add', - templateUrl: urlPrefix + 'partials/projects.html', - controller: ProjectsAdd, - ncyBreadcrumb: { - parent: "projects", - label: "CREATE PROJECT" - } - }). - - state('projects.edit', { - url: '/:id', - templateUrl: urlPrefix + 'partials/projects.html', - controller: ProjectsEdit, - data: { - activityStreamId: 'id' - }, - ncyBreadcrumb: { - parent: 'projects', - label: '{{name}}' - } - }). - - state('projectOrganizations', { - url: '/projects/:project_id/organizations', - templateUrl: urlPrefix + 'partials/projects.html', - controller: OrganizationsList - }). - - state('projectOrganizationAdd', { - url: '/projects/:project_id/organizations/add', - templateUrl: urlPrefix + 'partials/projects.html', - controller: OrganizationsAdd - }). + // state('dashboard', { + // url: '/home', + // templateUrl: urlPrefix + 'partials/home.html', + // controller: Home, + // params: { licenseMissing: null }, + // data: { + // activityStream: true, + // refreshButton: true + // }, + // ncyBreadcrumb: { + // label: "DASHBOARD" + // }, + // resolve: { + // graphData: ['$q', 'jobStatusGraphData', '$rootScope', + // function($q, jobStatusGraphData, $rootScope) { + // return $rootScope.featuresConfigured.promise.then(function() { + // return $q.all({ + // jobStatus: jobStatusGraphData.get("month", "all"), + // }); + // }); + // } + // ] + // } + // }). + // + // state('jobs', { + // url: '/jobs', + // templateUrl: urlPrefix + 'partials/jobs.html', + // controller: JobsListController, + // ncyBreadcrumb: { + // label: "JOBS" + // } + // }). + // + // state('projects', { + // url: '/projects?{status}', + // templateUrl: urlPrefix + 'partials/projects.html', + // controller: ProjectsList, + // data: { + // activityStream: true, + // activityStreamTarget: 'project' + // }, + // ncyBreadcrumb: { + // label: "PROJECTS" + // }, + // // socket: '{"groups":{"jobs": ["status_changed"]}}' + // // resolve: { + // // socket: ['SocketService', '$rootScope', + // // function(SocketService, $rootScope) { + // // var self = this; + // // $rootScope.socketPromise.promise.then(function(){ + // // SocketService.subscribe(self); + // // return true; + // // }); + // // }] + // // }, + // }). + // + // state('projects.add', { + // url: '/add', + // templateUrl: urlPrefix + 'partials/projects.html', + // controller: ProjectsAdd, + // ncyBreadcrumb: { + // parent: "projects", + // label: "CREATE PROJECT" + // } + // }). + // + // state('projects.edit', { + // url: '/:id', + // templateUrl: urlPrefix + 'partials/projects.html', + // controller: ProjectsEdit, + // data: { + // activityStreamId: 'id' + // }, + // ncyBreadcrumb: { + // parent: 'projects', + // label: '{{name}}' + // } + // }). + // + // state('projectOrganizations', { + // url: '/projects/:project_id/organizations', + // templateUrl: urlPrefix + 'partials/projects.html', + // controller: OrganizationsList + // }). + // + // state('projectOrganizationAdd', { + // url: '/projects/:project_id/organizations/add', + // templateUrl: urlPrefix + 'partials/projects.html', + // controller: OrganizationsAdd + // }). state('teams', { url: '/teams', @@ -523,18 +534,126 @@ var tower = angular.module('Tower', [ }]); }]) -.run(['$q', '$compile', '$cookieStore', '$rootScope', '$log', +.run(['$stateExtender', '$q', '$compile', '$cookieStore', '$rootScope', '$log', 'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer', - 'ClearScope', 'LoadConfig', 'Store', - 'pendoService', 'Prompt', 'Rest', 'Wait', - 'ProcessErrors', '$state', 'GetBasePath', 'ConfigService', + 'ClearScope', 'LoadConfig', 'Store', 'pendoService', 'Prompt', 'Rest', + 'Wait', 'ProcessErrors', '$state', 'GetBasePath', 'ConfigService', 'FeaturesService', '$filter', 'SocketService', - function($q, $compile, $cookieStore, $rootScope, $log, CheckLicense, - $location, Authorization, LoadBasePaths, Timer, ClearScope, - LoadConfig, Store, pendoService, Prompt, Rest, Wait, + function($stateExtender, $q, $compile, $cookieStore, $rootScope, $log, + CheckLicense, $location, Authorization, LoadBasePaths, Timer, + ClearScope, LoadConfig, Store, pendoService, Prompt, Rest, Wait, ProcessErrors, $state, GetBasePath, ConfigService, FeaturesService, $filter, SocketService) { - var sock; + + $stateExtender.addState({ + name: 'dashboard', + url: '/home', + templateUrl: urlPrefix + 'partials/home.html', + controller: Home, + params: { licenseMissing: null }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, + data: { + activityStream: true, + refreshButton: true + }, + ncyBreadcrumb: { + label: "DASHBOARD" + }, + resolve: { + graphData: ['$q', 'jobStatusGraphData', '$rootScope', + function($q, jobStatusGraphData, $rootScope) { + return $rootScope.featuresConfigured.promise.then(function() { + return $q.all({ + jobStatus: jobStatusGraphData.get("month", "all"), + }); + }); + } + ] + } + }); + + $stateExtender.addState({ + name: 'jobs', + url: '/jobs', + templateUrl: urlPrefix + 'partials/jobs.html', + controller: JobsListController, + ncyBreadcrumb: { + label: "JOBS" + }, + params: { + search: { + value: {order_by:'-finished'} + } + }, + socket: { + "groups":{ + "jobs": ["status_changed"], + "schedules": ["changed"] + } + } + }); + + $stateExtender.addState({ + name: 'projects', + url: '/projects?{status}', + templateUrl: urlPrefix + 'partials/projects.html', + controller: ProjectsList, + data: { + activityStream: true, + activityStreamTarget: 'project' + }, + ncyBreadcrumb: { + label: "PROJECTS" + }, + socket: { + "groups":{ + "jobs": ["status_changed"] + } + } + }); + + $stateExtender.addState({ + name: 'projects.add', + url: '/add', + templateUrl: urlPrefix + 'partials/projects.html', + controller: ProjectsAdd, + ncyBreadcrumb: { + parent: "projects", + label: "CREATE PROJECT" + } + }); + + $stateExtender.addState({ + name: 'projects.edit', + url: '/:id', + templateUrl: urlPrefix + 'partials/projects.html', + controller: ProjectsEdit, + data: { + activityStreamId: 'id' + }, + ncyBreadcrumb: { + parent: 'projects', + label: '{{name}}' + } + }); + + $stateExtender.addState({ + name: 'projectOrganizations', + url: '/projects/:project_id/organizations', + templateUrl: urlPrefix + 'partials/projects.html', + controller: OrganizationsList + }); + + $stateExtender.addState({ + name: 'projectOrganizationAdd', + url: '/projects/:project_id/organizations/add', + templateUrl: urlPrefix + 'partials/projects.html', + controller: OrganizationsAdd + }); $rootScope.addPermission = function(scope) { $compile("")(scope); }; @@ -706,121 +825,9 @@ var tower = angular.module('Tower', [ $rootScope.crumbCache = []; - if ($rootScope.removeOpenSocket) { - $rootScope.removeOpenSocket(); - } - $rootScope.removeOpenSocket = $rootScope.$on('OpenSocket', function() { - function openSocket() { - // $rootScope.socket = Socket({ scope: $rootScope}); - $rootScope.socket.init(); - // $rootScope.socket.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); - // } - // }); - // $rootScope.socket.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(); - // $rootScope.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(); - // $rootScope.socket.on("limit_reached", function(data) { - // $log.debug(data.reason); - // $rootScope.sessionTimer.expireSession('session_limit'); - // $state.go('signOut'); - // }); - } - openSocket(); - - setTimeout(function() { - $rootScope.$apply(function() { - $rootScope.socket.checkStatus(); - $log.debug('socket status: ' + $rootScope.socketStatus); - }); - }, 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'){ - SocketService.emit('{"groups":{"jobs": ["status_changed"]}}'); - console.log(toState.name); - } - else if(toState.name === 'jobDetail'){ - SocketService.emit(`{"groups":{"jobs": ["status_changed", "summary"] , "job_events":[${toParams.id}]}}`); - console.log(toState.name); - } - else if(toState.name === 'jobStdout'){ - SocketService.emit('{"groups":{"jobs": ["status_changed"]}}'); - console.log(toState.name); - } - else if(toState.name === 'jobs'){ - SocketService.emit('{"groups":{"jobs": ["status_changed"] , "schedules": ["changed"]}}'); - console.log(toState.name); - } - else if(toState.name === 'portalMode'){ - SocketService.emit('{"groups":{"jobs": ["status_changed"]}}'); - console.log(toState.name); - } - else if(toState.name === 'projects'){ - SocketService.emit('{"groups":{"jobs": ["status_changed"]}}'); - console.log(toState.name); - } - else if(toState.name === 'inventory'){ - SocketService.emit('{"groups":{"jobs": ["status_changed"]}}'); - console.log(toState.name); - } - else if(toState.name === 'adHocJobStdout'){ - SocketService.emit(`{"groups":{"jobs": ["status_changed"] , "ad_hoc_command_events": [${toParams.id}]}}`); - console.log(toState.name); - } - }); + // $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState) { + // SocketService.subscribe(toState, toParams); + // }); $rootScope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState) { diff --git a/awx/ui/client/src/inventories/manage/inventory-manage.route.js b/awx/ui/client/src/inventories/manage/inventory-manage.route.js index 719ce3bf15..65d86d6569 100644 --- a/awx/ui/client/src/inventories/manage/inventory-manage.route.js +++ b/awx/ui/client/src/inventories/manage/inventory-manage.route.js @@ -13,6 +13,11 @@ import GroupsListController from './groups/groups-list.controller'; export default { name: 'inventoryManage', url: '/inventories/:inventory_id/manage?{group:int}{failed}', + socket: { + "groups":{ + "jobs": ["status_changed"] + } + }, params:{ group:{ array: true diff --git a/awx/ui/client/src/job-detail/job-detail.route.js b/awx/ui/client/src/job-detail/job-detail.route.js index d08bcfecf8..274f8f46a4 100644 --- a/awx/ui/client/src/job-detail/job-detail.route.js +++ b/awx/ui/client/src/job-detail/job-detail.route.js @@ -13,22 +13,12 @@ export default { parent: 'jobs', label: "{{ job.id }} - {{ job.name }}" }, - // resolve: { - // jobEventsSocket: ['Socket', '$rootScope', function(Socket, $rootScope) { - // if (!$rootScope.event_socket) { - // $rootScope.event_socket = Socket({ - // scope: $rootScope, - // endpoint: "job_events" - // }); - // $rootScope.event_socket.init(); - // // returns should really be providing $rootScope.event_socket - // // otherwise, we have to inject the entire $rootScope into the controller - // return true; - // } else { - // return true; - // } - // }] - // }, + socket: { + "groups":{ + "jobs": ["status_changed", "summary"] + // "job_events": `[${stateParams.id}]` + } + }, templateUrl: templateUrl('job-detail/job-detail'), controller: 'JobDetailController' }; diff --git a/awx/ui/client/src/shared/Socket.js b/awx/ui/client/src/shared/Socket.js deleted file mode 100644 index ddc0d74fdc..0000000000 --- a/awx/ui/client/src/shared/Socket.js +++ /dev/null @@ -1,207 +0,0 @@ -/************************************************* - * Copyright (c) 2015 Ansible, Inc. - * - * All Rights Reserved - *************************************************/ - - /** - * @ngdoc function - * @name shared.function:Socket - * @description - * Socket.js - * - * Wrapper for lib/socket.io-client/dist/socket.io.js. - */ - -/* global io */ - - -/** - * @ngdoc method - * @name shared.function:Socket#SocketIO - * @methodOf shared.function:Socket - * @description - */ -import ReconnectingWebSocket from 'reconnectingwebsocket' -export default -angular.module('SocketIO', ['Utilities']) - - .factory('Socket', ['$rootScope', '$location', '$log', 'Authorization', - '$state', - function ($rootScope, $location, $log, Authorization, $state) { - return function(params) { - var scope = params.scope, - host = window.location.host, - url; - - url = "ws://" + host + "/websocket/"; - $log.debug('opening socket connection to: ' + url); - - function getSocketTip(status) { - var result = ''; - switch(status) { - case 'error': - result = "Live events: error connecting to the Tower server."; - break; - case 'connecting': - result = "Live events: attempting to connect to the Tower server."; - break; - case "ok": - result = "Live events: connected. Pages containing job status information will automatically update in real-time."; - } - return result; - } - - return { - scope: scope, - url: url, - socket: null, - - init: function() { - var self = this, - token = Authorization.getToken(); - if (!$rootScope.sessionTimer || ($rootScope.sessionTimer && !$rootScope.sessionTimer.isExpired())) { - // We have a valid session token, so attempt socket connection - $log.debug('Socket connecting to: ' + url); - self.scope.socket_url = url; - self.socket = new ReconnectingWebSocket(url, null, { - debug: true, - timeoutInterval: 3000, - maxReconnectAttempts: 10 - }); - self.socket.onopen = function () { - console.log('websocket connected'); //log errors - }; - - self.socket.onerror = function (error) { - console.log('Error Logged: ' + error); //log errors - }; - self.socket.onmessage = function (e) { - console.log('Received From Server: ' + e.data); - var data = JSON.parse(e.data); - // {'groups': - // {'jobs': ['status_changed', 'summary'], - // 'schedules': ['changed'], - // 'ad_hoc_command_events': [ids,], - // 'job_events': [ids,], - // 'control': ['limit_reached'], - // } - // } - if(data.group_name==="jobs"){ - - if (!('status' in data)){ - // we know that this must have been a - // summary complete message - $log.debug('Job summary_complete ' + data.unified_job_id); - $rootScope.$emit('JobSummaryComplete', data); - } - 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); - } - } - if(data.group_name==="job_events"){ - $rootScope.$emit('job_events-'+data.job, data); - } - if(data.group_name==="schedules"){ - $log.debug('Schedule ' + data.unified_job_id + ' status changed to ' + data.status); - $rootScope.$emit('ScheduleStatusChange', data); - } - if(data.group_name==="ad_hoc_command_events"){ - - } - if(data.group_name==="control"){ - $log.debug(data.reason); - $rootScope.sessionTimer.expireSession('session_limit'); - $state.go('signOut'); - } - - - - }; - - } - else { - // encountered expired token, redirect to login page - $rootScope.sessionTimer.expireSession('idle'); - $location.url('/login'); - } - }, - checkStatus: function() { - // Check connection status - var self = this; - if(self){ - if(self.socket){ - if (self.socket.readyState === 0 ) { - self.scope.socketStatus = 'connecting'; - } - else if (self.socket.readyState === 1){ - self.scope.socketStatus = 'ok'; - } - else if (self.socket.readyState === 2 || self.socket.readyState === 3 ){ - self.scope.socketStatus = 'error'; - } - self.scope.socketTip = getSocketTip(self.scope.socketStatus); - return self.scope.socketStatus; - } - } - - }, - on: function (eventName, callback) { - var self = this; - if(self){ - if(self.socket){ - // self.socket.onmessage(function (e) { - // var args = arguments; - // self.scope.$apply(function () { - // callback.apply(self.socket, args); - // }); - // }); - } - } - - }, - emit: function (eventName, data, callback) { - var self = this; - // console.log(eventName) - self.socket.send(eventName, data, function () { - var args = arguments; - self.scope.$apply(function () { - if (callback) { - callback.apply(self.socket, args); - } - }); - }); - }, - getUrl: function() { - return url; - }, - removeAllListeners: function (eventName) { - var self = this; - if(self){ - if(self.socket){ - self.socket.removeEventListener(eventName); - } - } - }, - }; - }; - }]); diff --git a/awx/ui/client/src/shared/socket/socket.service.js b/awx/ui/client/src/shared/socket/socket.service.js index 54aa4662ff..7f26060f72 100644 --- a/awx/ui/client/src/shared/socket/socket.service.js +++ b/awx/ui/client/src/shared/socket/socket.service.js @@ -5,12 +5,12 @@ *************************************************/ import ReconnectingWebSocket from 'reconnectingwebsocket'; export default -['$rootScope', '$location', '$log', 'Authorization','$state', '$q', - function ($rootScope, $location, $log, Authorization, $state, $q) { +['$rootScope', '$location', '$log', 'Authorization','$state', + function ($rootScope, $location, $log, Authorization, $state) { return { init: function() { var self = this, - token = Authorization.getToken(), + // token = Authorization.getToken(), host = window.location.host, url = "ws://" + host + "/websocket/"; if (!$rootScope.sessionTimer || ($rootScope.sessionTimer && !$rootScope.sessionTimer.isExpired())) { @@ -103,6 +103,44 @@ export default $log.debug('socket status: ' + $rootScope.socketStatus); }, 2000); }, + subscribe2: function(state){ + console.log(state.name); + this.emit(JSON.stringify(state.socket)); + }, + // subscribe: function(toState, toParams){ + // if(toState.name === 'dashboard'){ + // this.emit('{"groups":{"jobs": ["status_changed"]}}'); + // console.log(toState.name); + // } + // if(toState.name === 'jobDetail'){ + // this.emit(`{"groups":{"jobs": ["status_changed", "summary"] , "job_events":[${toParams.id}]}}`); + // console.log(toState.name); + // } + // if(toState.name === 'jobStdout'){ + // this.emit('{"groups":{"jobs": ["status_changed"]}}'); + // console.log(toState.name); + // } + // if(toState.name === 'jobs'){ + // this.emit('{"groups":{"jobs": ["status_changed"] , "schedules": ["changed"]}}'); + // console.log(toState.name); + // } + // if(toState.name === 'portalMode'){ + // this.emit('{"groups":{"jobs": ["status_changed"]}}'); + // console.log(toState.name); + // } + // if(toState.name === 'projects'){ + // this.emit('{"groups":{"jobs": ["status_changed"]}}'); + // console.log(toState.name); + // } + // if(toState.name === 'inventoryManage'){ + // this.emit('{"groups":{"jobs": ["status_changed"]}}'); + // console.log(toState.name); + // } + // if(toState.name === 'adHocJobStdout'){ + // this.emit(`{"groups":{"jobs": ["status_changed"] , "ad_hoc_command_events": [${toParams.id}]}}`); + // console.log(toState.name); + // } + // }, checkStatus: function() { function getSocketTip(status) { @@ -138,23 +176,22 @@ export default } }, - on: function (eventName, callback) { - var self = this; - if(self){ - if(self.socket){ - // self.socket.onmessage(function (e) { - // var args = arguments; - // self.scope.$apply(function () { - // callback.apply(self.socket, args); - // }); - // }); - } - } - - }, + // on: function (eventName, callback) { + // var self = this; + // if(self){ + // if(self.socket){ + // // self.socket.onmessage(function (e) { + // // var args = arguments; + // // self.scope.$apply(function () { + // // callback.apply(self.socket, args); + // // }); + // // }); + // } + // } + // + // }, emit: function (eventName, data, callback) { var self = this; - // console.log(eventName) $rootScope.socketPromise.promise.then(function(){ self.socket.send(eventName, data, function () { var args = arguments; @@ -166,9 +203,6 @@ export default }); }); }, - getUrl: function() { - return url; - }, removeAllListeners: function (eventName) { var self = this; if(self){ diff --git a/awx/ui/client/src/shared/stateExtender.provider.js b/awx/ui/client/src/shared/stateExtender.provider.js index 89f6ff97ba..e38a8f7d3f 100644 --- a/awx/ui/client/src/shared/stateExtender.provider.js +++ b/awx/ui/client/src/shared/stateExtender.provider.js @@ -1,10 +1,28 @@ export default function($stateProvider) { this.$get = function() { return { + addSocket: function(state){ + // var resolve = state.resolve || {}; + if(!state.resolve){ + state.resolve = {}; + } + state.resolve.socket = ['SocketService', '$rootScope', + function(SocketService, $rootScope) { + // var self = this; + $rootScope.socketPromise.promise.then(function(){ + SocketService.subscribe2(state); + return true; + }); + }] + }, addState: function(state) { var route = state.route || state.url; + if(state.socket){ + this.addSocket(state); + } + $stateProvider.state(state.name, { url: route, controller: state.controller,