diff options
Diffstat (limited to 'client')
42 files changed, 385 insertions, 52 deletions
diff --git a/client/images/spin/128x128/Preloader_1.gif b/client/images/spin/128x128/Preloader_1.gif Binary files differnew file mode 100644 index 0000000..dafe17e --- /dev/null +++ b/client/images/spin/128x128/Preloader_1.gif diff --git a/client/images/spin/128x128/Preloader_10.gif b/client/images/spin/128x128/Preloader_10.gif Binary files differnew file mode 100644 index 0000000..cdfa680 --- /dev/null +++ b/client/images/spin/128x128/Preloader_10.gif diff --git a/client/images/spin/128x128/Preloader_2.gif b/client/images/spin/128x128/Preloader_2.gif Binary files differnew file mode 100644 index 0000000..3cb9003 --- /dev/null +++ b/client/images/spin/128x128/Preloader_2.gif diff --git a/client/images/spin/128x128/Preloader_3.gif b/client/images/spin/128x128/Preloader_3.gif Binary files differnew file mode 100644 index 0000000..7f7d415 --- /dev/null +++ b/client/images/spin/128x128/Preloader_3.gif diff --git a/client/images/spin/128x128/Preloader_4.gif b/client/images/spin/128x128/Preloader_4.gif Binary files differnew file mode 100644 index 0000000..78baff6 --- /dev/null +++ b/client/images/spin/128x128/Preloader_4.gif diff --git a/client/images/spin/128x128/Preloader_5.gif b/client/images/spin/128x128/Preloader_5.gif Binary files differnew file mode 100644 index 0000000..c9c1530 --- /dev/null +++ b/client/images/spin/128x128/Preloader_5.gif diff --git a/client/images/spin/128x128/Preloader_6.gif b/client/images/spin/128x128/Preloader_6.gif Binary files differnew file mode 100644 index 0000000..3203d7f --- /dev/null +++ b/client/images/spin/128x128/Preloader_6.gif diff --git a/client/images/spin/128x128/Preloader_7.gif b/client/images/spin/128x128/Preloader_7.gif Binary files differnew file mode 100644 index 0000000..2eb19be --- /dev/null +++ b/client/images/spin/128x128/Preloader_7.gif diff --git a/client/images/spin/128x128/Preloader_8.gif b/client/images/spin/128x128/Preloader_8.gif Binary files differnew file mode 100644 index 0000000..3ba8217 --- /dev/null +++ b/client/images/spin/128x128/Preloader_8.gif diff --git a/client/images/spin/128x128/Preloader_9.gif b/client/images/spin/128x128/Preloader_9.gif Binary files differnew file mode 100644 index 0000000..7018192 --- /dev/null +++ b/client/images/spin/128x128/Preloader_9.gif diff --git a/client/images/spin/32x32/Preloader_1.gif b/client/images/spin/32x32/Preloader_1.gif Binary files differnew file mode 100644 index 0000000..b810330 --- /dev/null +++ b/client/images/spin/32x32/Preloader_1.gif diff --git a/client/images/spin/32x32/Preloader_10.gif b/client/images/spin/32x32/Preloader_10.gif Binary files differnew file mode 100644 index 0000000..f9c462f --- /dev/null +++ b/client/images/spin/32x32/Preloader_10.gif diff --git a/client/images/spin/32x32/Preloader_2.gif b/client/images/spin/32x32/Preloader_2.gif Binary files differnew file mode 100644 index 0000000..f23998f --- /dev/null +++ b/client/images/spin/32x32/Preloader_2.gif diff --git a/client/images/spin/32x32/Preloader_3.gif b/client/images/spin/32x32/Preloader_3.gif Binary files differnew file mode 100644 index 0000000..bb7c60d --- /dev/null +++ b/client/images/spin/32x32/Preloader_3.gif diff --git a/client/images/spin/32x32/Preloader_4.gif b/client/images/spin/32x32/Preloader_4.gif Binary files differnew file mode 100644 index 0000000..117c756 --- /dev/null +++ b/client/images/spin/32x32/Preloader_4.gif diff --git a/client/images/spin/32x32/Preloader_5.gif b/client/images/spin/32x32/Preloader_5.gif Binary files differnew file mode 100644 index 0000000..7169708 --- /dev/null +++ b/client/images/spin/32x32/Preloader_5.gif diff --git a/client/images/spin/32x32/Preloader_6.gif b/client/images/spin/32x32/Preloader_6.gif Binary files differnew file mode 100644 index 0000000..9087ded --- /dev/null +++ b/client/images/spin/32x32/Preloader_6.gif diff --git a/client/images/spin/32x32/Preloader_7.gif b/client/images/spin/32x32/Preloader_7.gif Binary files differnew file mode 100644 index 0000000..0b1e633 --- /dev/null +++ b/client/images/spin/32x32/Preloader_7.gif diff --git a/client/images/spin/32x32/Preloader_8.gif b/client/images/spin/32x32/Preloader_8.gif Binary files differnew file mode 100644 index 0000000..6816be3 --- /dev/null +++ b/client/images/spin/32x32/Preloader_8.gif diff --git a/client/images/spin/32x32/Preloader_9.gif b/client/images/spin/32x32/Preloader_9.gif Binary files differnew file mode 100644 index 0000000..e38dd5a --- /dev/null +++ b/client/images/spin/32x32/Preloader_9.gif diff --git a/client/images/spin/64x64/Preloader_1.gif b/client/images/spin/64x64/Preloader_1.gif Binary files differnew file mode 100644 index 0000000..2004c5f --- /dev/null +++ b/client/images/spin/64x64/Preloader_1.gif diff --git a/client/images/spin/64x64/Preloader_10.gif b/client/images/spin/64x64/Preloader_10.gif Binary files differnew file mode 100644 index 0000000..944ec82 --- /dev/null +++ b/client/images/spin/64x64/Preloader_10.gif diff --git a/client/images/spin/64x64/Preloader_2.gif b/client/images/spin/64x64/Preloader_2.gif Binary files differnew file mode 100644 index 0000000..9821827 --- /dev/null +++ b/client/images/spin/64x64/Preloader_2.gif diff --git a/client/images/spin/64x64/Preloader_3.gif b/client/images/spin/64x64/Preloader_3.gif Binary files differnew file mode 100644 index 0000000..52b81ba --- /dev/null +++ b/client/images/spin/64x64/Preloader_3.gif diff --git a/client/images/spin/64x64/Preloader_4.gif b/client/images/spin/64x64/Preloader_4.gif Binary files differnew file mode 100644 index 0000000..3408b5d --- /dev/null +++ b/client/images/spin/64x64/Preloader_4.gif diff --git a/client/images/spin/64x64/Preloader_5.gif b/client/images/spin/64x64/Preloader_5.gif Binary files differnew file mode 100644 index 0000000..6f0585d --- /dev/null +++ b/client/images/spin/64x64/Preloader_5.gif diff --git a/client/images/spin/64x64/Preloader_6.gif b/client/images/spin/64x64/Preloader_6.gif Binary files differnew file mode 100644 index 0000000..c577f24 --- /dev/null +++ b/client/images/spin/64x64/Preloader_6.gif diff --git a/client/images/spin/64x64/Preloader_7.gif b/client/images/spin/64x64/Preloader_7.gif Binary files differnew file mode 100644 index 0000000..5f6dd5e --- /dev/null +++ b/client/images/spin/64x64/Preloader_7.gif diff --git a/client/images/spin/64x64/Preloader_8.gif b/client/images/spin/64x64/Preloader_8.gif Binary files differnew file mode 100644 index 0000000..b57e4d8 --- /dev/null +++ b/client/images/spin/64x64/Preloader_8.gif diff --git a/client/images/spin/64x64/Preloader_9.gif b/client/images/spin/64x64/Preloader_9.gif Binary files differnew file mode 100644 index 0000000..fc3ddb7 --- /dev/null +++ b/client/images/spin/64x64/Preloader_9.gif diff --git a/client/index.html b/client/index.html index ba183df..8ca2b9f 100644 --- a/client/index.html +++ b/client/index.html @@ -26,7 +26,11 @@ <div class="col-lg-12"> <!-- Login Overlay --> <div ng-include="'./partials/login.html'"></div> - <!-- Nav --> + <!-- Machine Details Overlay --> + <div ng-include="'./partials/home/machineDetails.html'"></div> + <div ng-include="'./partials/loading.html'"></div> + + <!-- Nav --> <div ng-include="'./partials/nav.html'"></div> </div> </div> @@ -76,12 +80,15 @@ <script src="./js/services/Identity.js"></script> <script src="./js/services/Image.js"></script> <script src="./js/services/Compute.js"></script> + <script src="./js/services/Loading.js"></script> <!-- Include controller --> <script src="./js/controllers/login.js"></script> <script src="./js/controllers/status.js"></script> <script src="./js/controllers/home/main.js"></script> + <script src="./js/controllers/home/machineDetails.js"></script> <script src="./js/controllers/network/main.js"></script> + diff --git a/client/js/controllers/home/machineDetails.js b/client/js/controllers/home/machineDetails.js new file mode 100644 index 0000000..24fac42 --- /dev/null +++ b/client/js/controllers/home/machineDetails.js @@ -0,0 +1,41 @@ +/** + * The home controller + * + * @param {$scope} $scope The $scope service from angular + */ +mainApp.controller('machineDetailsCtrl', [ '$scope', 'Compute', '$rootScope', '$timeout', function ($scope, Compute, $rootScope, $timeout) +{ + + $scope.machine={}; + $("#waitingForToggleMachine").hide(); + + $scope.$on('showMachineDetailsEvent', function(eventName ,machine, axioms){ + $scope.machine=machine; + $scope.axioms=axioms; + console.log(machine); + $('#machineDetailsModal').modal({backdrop: false, keyboard: true}); + }); + + + $scope.toggleMachineState=function(){ + $("#waitingForToggleMachine").show(); + + // Fake timeout + $timeout(function(){ + $("#waitingForToggleMachine").hide(); + }, 3000); + $timeout(function(){ + $scope.machine.online=!$scope.machine.online; + + }, 3000); + + + }; + + $scope.applyModifications=function(){ + //Todo + } + + + +}]); diff --git a/client/js/controllers/home/main.js b/client/js/controllers/home/main.js index d25bfad..f84f625 100644 --- a/client/js/controllers/home/main.js +++ b/client/js/controllers/home/main.js @@ -3,15 +3,34 @@ * * @param {$scope} $scope The $scope service from angular */ -mainApp.controller('homeCtrl', [ '$scope', 'Compute', function ($scope, Compute) +mainApp.controller('homeCtrl', [ '$scope', 'Compute', '$rootScope', 'Loading','Identity', function ($scope, Compute, $rootScope, Loading, Identity) { + var callMeAfterPullData=function(data){ + $scope.machines=Compute.getData().machines; + Loading.stop(); + } - var updatePage=function(){ - // TODO Update graph etc... + ; + if(Compute.getData().machines == null && Identity.isAlreadyLogin()){ + Loading.start(); + Compute.pullData(callMeAfterPullData); } - // Retrieve all Data - Compute.pullData(updatePage); - + + + + $scope.raiseShowMachineDetailsEvent=function(id){ + + var callback=function(){ + Loading.stop(); + var data=Compute.getData(); + $rootScope.$broadcast("showMachineDetailsEvent", data.machines[id], data.axioms); + + } + Loading.start(); + Compute.pullMachines(callback); + } + + }]); diff --git a/client/js/controllers/login.js b/client/js/controllers/login.js index 829fc1d..1a89563 100644 --- a/client/js/controllers/login.js +++ b/client/js/controllers/login.js @@ -13,14 +13,19 @@ mainApp.controller('loginCtrl', ['$scope','$sce','Identity', function ($scope,$s if(!Identity.isAlreadyLogin()){ $('#loginModal').modal({backdrop: 'static', keyboard: false}); } + + // Manager logout event $scope.$on('logoutEvent', function(){ + Identity.logout(); $('#loginModal').modal({backdrop: 'static', keyboard: false}); }); - + + // Hide loading button and message alert $('#loadingLoginButton').hide(); $('#failedToLoginAlert').hide(); - + + // Defined function for login $scope.loginAction=function(){ // Begin login state for template diff --git a/client/js/controllers/status.js b/client/js/controllers/status.js index e01df34..940d794 100644 --- a/client/js/controllers/status.js +++ b/client/js/controllers/status.js @@ -10,13 +10,11 @@ mainApp.controller('statusCtrl', ['$scope','Identity', '$rootScope', function ($ { // Give profile to model - $scope.profile=Identity.profile; + $scope.profile=Identity.getProfile(); // Function to logout - $scope.logout=function(){ - Identity.logout(); + $scope.raiseLogoutEvent=function(){ $rootScope.$broadcast('logoutEvent'); - }; }]); diff --git a/client/js/services/Compute.js b/client/js/services/Compute.js index c5c8da9..36ddc16 100644 --- a/client/js/services/Compute.js +++ b/client/js/services/Compute.js @@ -2,38 +2,139 @@ mainApp.factory('Compute',[ '$http', 'Identity', function($http, Identity){ - + // Init data var data={}; - data.machines={}; + data.machines=null; + data.axioms={} // Contain static data + data.axioms.ram=[128,512,1024,2048,4096]; + data.axioms.disk=[1,2,5,10,25,50,100,150,200] + data.axioms.images={}; // Retrieve after - // Parser - var parseGetMachinesAnswer=function(response, failedToSendRequest){ + /** + * Parse pullMachines answer + * @param {response} the server response + * @param {boolean} false if the request as been send true else + * @return {requestParserResult} the result of parsing + */ + var parsePullMachinesAnswer=function(response, failedToSendRequest){ + + // Defined return object + var requestParserResult={}; + requestParserResult.status=1; + requestParserResult.failReason=null; + - }; + if (typeof response.data.Servers !== 'undefined') { + // Set status code + requestParserResult.status=0; + data.machines=response.data.Servers; + } + else if(failedToSendRequest){ + requestParserResult.failReason="Failed to send request"; + } + else{ + requestParserResult.failReason="Error"; + } + return requestParserResult; + }; - // Get Machine - var getMachines=function(callback){ + /** + * Retrieve machine list + * @param {callback} function to call after request complete + */ + var pullMachines=function(callback){ + // Send listServers request var result=$http.post('../server/index.php', - $.param({"token" : Identity.profile.token, "task" : "Compute"})); + $.param({"token" : Identity.getToken(), "task" : "compute", "action":"listServers"})); + + // Wait and handle the response + result.then(function (response){ + callback(parsePullMachinesAnswer(response, false)); + },function(response){ + callback(parsePullMachinesAnswer(response, true)); + }); + }; + + + /** + * Parse pullImages answer + * @param {response} the server response + * @param {boolean} false if the request as been send true else + * @return {requestParserResult} the result of parsing + */ + var parsePullImagesAnswer=function(response, failedToSendRequest){ + + // Defined return object + var requestParserResult={}; + requestParserResult.status=1; + requestParserResult.failReason=null; + if (typeof response.data.Images !== 'undefined') { + // Set status code + requestParserResult.status=0; + data.axioms.images=response.data.Images; + } + else if(failedToSendRequest){ + requestParserResult.failReason="Failed to send request"; + } + else{ + requestParserResult.failReason="Error"; + } + return requestParserResult; }; + + + + /** + * Retrieve machine list + * @param {callback} function to call after request complete + */ + var pullImages=function(callback){ + // Send listServers request + var result=$http.post('../server/index.php', + $.param({"token" : Identity.getToken(), "task" : "compute", "action":"listImages"})); + + // Wait and handle the response + result.then(function (response){ + callback(parsePullImagesAnswer(response, false)); + },function(response){ + callback(parsePullImagesAnswer(response, true)); + }); + }; + /** + * Retrieve all data + * @param {callback} function to call after request complete + */ var pullData=function(callback){ - // TODO call getMachines etc... + var nextFunction=function(response){ + if(response.status==0){ + pullMachines(callback); + } + } + pullImages(nextFunction); } - + + /** + * Get Data + * @return {data} return the data object + */ + var getData=function(){ + return data; + } + // Return services objects return { - getMachines: getMachines - pullData: pullData - data:data + pullMachines: pullMachines, + pullData: pullData, + getData: getData }; diff --git a/client/js/services/Identity.js b/client/js/services/Identity.js index 8ee664c..da85ecd 100644 --- a/client/js/services/Identity.js +++ b/client/js/services/Identity.js @@ -7,37 +7,50 @@ mainApp.factory('Identity',[ '$http', '$cookies', function($http, $cookies){ var profile={}; profile.username=null; profile.projectname=null; - profile.token=null; - - - /** - * Save profile in cookies - */ - var saveCookieForSession=function(){ - $cookies.putObject('profile', 5); - }; - + var token=null; + /* * @returns {boolean} Return true if a cookie is found (and load it in profile) false else */ var isAlreadyLogin=function(){ + + // Load cookies var profileInCookie=$cookies.getObject('profile'); - console.log(profileInCookie); + var tokenPart_0InCookie=$cookies.getObject('token.part_0'); + var tokenPart_1InCookie=$cookies.getObject('token.part_1'); + - if(typeof profileInCookie !== 'undefined'){ + // Check if cookie is defined + if(typeof profileInCookie !== 'undefined' + && typeof tokenPart_0InCookie !== 'undefined' + && typeof tokenPart_1InCookie !== 'undefined' + ){ + + // If yes, put it into variables angular.extend(profile, profileInCookie); + token=tokenPart_0InCookie+tokenPart_1InCookie; + + // Return I'm Login return true; } + // Return I'm not Login return false; } + + /* * Destroy profile cookies */ var logout=function(){ $cookies.remove('profile'); + $cookies.remove('token.part_0'); + $cookies.remove('token.part_1'); + token=null; + profile.username=null; + profile.projectname=null; } @@ -49,15 +62,32 @@ mainApp.factory('Identity',[ '$http', '$cookies', function($http, $cookies){ */ var parseLoginAnswer=function(response, failedToSendRequest){ - + // Defined return object var requestParserResult={}; requestParserResult.status=1; requestParserResult.failReason=null; if (typeof response.data.token !== 'undefined') { + // Set status code requestParserResult.status=0; - profile.token=response.data.token; - saveCookieForSession(); + + // Find the middle of the token to split it + var middle=parseInt(response.data.token.length/2); + + // Create expire date (cookie expire in 55 mins) + var expireDate=new Date(); + expireDate.setMinutes(expireDate.getMinutes()+55); + + // Save profile + $cookies.putObject('profile', profile, {'expires': expireDate}); + // Save first part of token + $cookies.putObject('token.part_0', response.data.token.substring(0, middle), {'expires': expireDate}); + // Save second part of token + $cookies.putObject('token.part_1', response.data.token.substring(middle, response.data.token.length), {'expires': expireDate}); + + // Put token in var + token=response.data.token; + } else if(failedToSendRequest){ requestParserResult.failReason="Failed to send request"; @@ -69,7 +99,6 @@ mainApp.factory('Identity',[ '$http', '$cookies', function($http, $cookies){ return requestParserResult; }; - /** * Function to connect to OpenStack @@ -80,31 +109,50 @@ mainApp.factory('Identity',[ '$http', '$cookies', function($http, $cookies){ * @param {string} projectname The user project name * @param {function} function to call when data is avalaible */ - var login=function(username, password,projectname, callback){ + var login=function(username, password,projectname,callback){ // Set profile information (early) profile.username=username; profile.projectname=projectname; var result=$http.post('../server/index.php', - $.param({"task" : "Authenticate", "user" : username, "password" : password, "project" : projectname})); + $.param({"task" : "Authenticate", "user" : username, "password" : password, "project" : projectname})); // Wait and handle the response result.then(function (response){ - callback(parseLoginAnswer(response), false); + callback(parseLoginAnswer(response, false)); },function(response){ - callback(parseLoginAnswer(response), true) + callback(parseLoginAnswer(response, true)); }); }; + + + /* + * Get the profile + */ + var getProfile=function(){ + return profile; + } + + /* + * Get the token + */ + var getToken=function(){ + return token; + } + + + // Return services objects return { login: login, - profile: profile, + getProfile: getProfile, isAlreadyLogin: isAlreadyLogin, - logout:logout + logout:logout, + getToken:getToken }; diff --git a/client/js/services/Loading.js b/client/js/services/Loading.js new file mode 100644 index 0000000..b12aaa0 --- /dev/null +++ b/client/js/services/Loading.js @@ -0,0 +1,22 @@ + +mainApp.factory('Loading',[ '$http', 'Identity', function($http, Identity){ + + + + + var start=function(){ + $('#loadingModal').modal({backdrop: 'static', keyboard: false}); + }; + + var stop=function(){ + $('#loadingModal').modal('hide'); + } + + + return { + start:start, + stop:stop + }; + + +}]); diff --git a/client/partials/home/machineDetails.html b/client/partials/home/machineDetails.html new file mode 100644 index 0000000..47a65fb --- /dev/null +++ b/client/partials/home/machineDetails.html @@ -0,0 +1,70 @@ +<div class="modal" id="machineDetailsModal" ng-controller="machineDetailsCtrl" > + <div class="modal-dialog"> + <div class="modal-content"></div> + </div> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <!--<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>--> + <h4 class="modal-title">Machine</h4> + + </div> + <div class="modal-body"> + + <form class="form-horizontal" role="form"> + <div class="form-group"> + <label class="control-label col-sm-2" for="email">Name</label> + <div class="col-sm-10"> + <p class="form-control-static">{{ machine.name }}</p> + </div> + </div> + <div class="form-group"> + <label class="control-label col-sm-2" for="pwd">State</label> + <div class="col-sm-10"> + <span ng-if="machine.status=='ACTIVE'">Online</span> + <span ng-if="machine.status!=='ACTIVE'">Offline</span> + + <button class="btn btn-danger" ng-if="machine.status=='ACTIVE'" ng-click="toggleMachineState()">Turn Off</button> + <button class="btn btn-success" ng-if="machine.status!=='ACTIVE'" ng-click="toggleMachineState()">Turn On</button> + <img src="images/spin/32x32/Preloader_1.gif" id="waitingForToggleMachine"></span> + + + </div> + </div> + <fieldset class="form-group"> + <label class="control-label col-sm-2">RAM</label> + <select class="col-sm-20" id="ramSelected"> + <option ng-repeat="ram in axioms.ram" ng-selected="machine.ram == ram">{{ ram }}</option> + </select> + <span>MB</span> + </fieldset> + + <fieldset class="form-group"> + <label class="control-label col-sm-2">Disk</label> + <select class="col-sm-20" id="ramSelected"> + <option ng-repeat="disk in axioms.disk" ng-selected="machine.disk == disk">{{ disk }}</option> + </select> + </fieldset> + + <fieldset class="form-group"> + <label class="control-label col-sm-2">Image</label> + <select class="col-sm-20" id="ramSelected"> + <option ng-repeat="image in axioms.images" ng-selected="machine.imageId == Object.keys(image)">{{ image.name }}</option> + </select> + </fieldset> + + + + + + </form> + + + </div> + <div class="modal-footer"> + <a href="#" data-dismiss="modal" class="btn btn-primary">Apply</a> + <a href="#" data-dismiss="modal" class="btn btn-default">Cancel</a> + </div> + </div> + </div> +</div> diff --git a/client/partials/home/main.html b/client/partials/home/main.html index 7a5045a..f9f8878 100644 --- a/client/partials/home/main.html +++ b/client/partials/home/main.html @@ -1,8 +1,12 @@ - <div class="panel panel-default"> + <div class="panel panel-default" ng-controller="homeCtrl"> <div class="panel-heading"> Home </div> <div class="panel-body"> - Main Content + + Pour charger les machines, recharger la page (temporaire)<br /> + Selectionner une machine: + <div ng-repeat="machine in machines"> <a ng-click="raiseShowMachineDetailsEvent(machine.id)"> {{ machine.name }}</a></div> + </div> -</div>
\ No newline at end of file +</div> diff --git a/client/partials/loading.html b/client/partials/loading.html new file mode 100644 index 0000000..c978190 --- /dev/null +++ b/client/partials/loading.html @@ -0,0 +1,18 @@ +<div class="modal fade" id="loadingModal" ng-controller="loginCtrl"> + <div class="modal-dialog"> + <div class="modal-content"></div> + </div> + <div class="modal-dialog" style="width:200px;"> + <div class="modal-content"> + + <div class="modal-body" > + <div align="center"> + <img src="images/spin/128x128/Preloader_8.gif" /> + </div> + + + </div> + + </div> + </div> +</div> diff --git a/client/partials/nav.html b/client/partials/nav.html index 3c72844..b3ef76a 100644 --- a/client/partials/nav.html +++ b/client/partials/nav.html @@ -32,7 +32,7 @@ <li><a href="#">Informations</a></li> <li><a href="#">Settings</a></li> <li role="separator" class="divider"></li> - <li><a href="#" ng-click="logout()">Logout</a></li> + <li><a href="#" ng-click="raiseLogoutEvent()">Logout</a></li> </ul> </li> </ul> |
