/* * Copyright (c) 2012-2015 Kaarle Ritvanen * See LICENSE file for license details */ angular.module( "aconf", ["ngRoute", "ui.bootstrap", "ui.sortable"] ).config(function($routeProvider) { $routeProvider.when("/login", { templateUrl: "login.html", controller: "aconfLoginCtrl" }).otherwise({templateUrl: "view.html", controller: "aconfObjCtrl"}); }).value("aconfErrorFormat", function(resp) { if (_.isString(resp)) return resp; if (_.isString(resp.data)) return resp.data; if (resp.status == 422) return _.values(resp.data).join("\n"); return JSON.stringify(resp); }).factory("aconfExclusive", function($modal, $q, $rootScope) { var blocked = false; $rootScope.$on("$locationChangeStart", function(event) { if (blocked) event.preventDefault(); }); function unblock() { blocked = false; } function res(task) { return $q(function(resolve, reject) { blocked = true; $modal.open({ backdrop: "static", templateUrl: "wait.html", controller: function($modalInstance) { $modalInstance.rendered.then(function() { task().then( $modalInstance.close, $modalInstance.dismiss ); }); $modalInstance.result.then(resolve, reject); $modalInstance.result.then(unblock, unblock); } }); }); } Object.defineProperty(res, "isRunning", {get: function() { return blocked; }}); return res; }).controller( "aconfCtrl", function( $location, $route, $scope, aconfErrorFormat, aconfExclusive, aconfTxn ) { $scope.loggedIn = function(token, saveRequired) { $scope.txnMgr = aconfTxn(token, saveRequired); $location.path("/config"); }; $scope.validationReady = function(txnValid) { if (txnValid != true) { $scope.txnStatus = "invalid"; $scope.status = aconfErrorFormat( txnValid || "Some values need checking" ); } else if ($scope.txnMgr.isPristine()) { $scope.txnStatus = null; $scope.status = ""; } else { $scope.txnStatus = "changed"; $scope.status = "There are changes to be committed"; } }; function clearState() { $scope.txnStatus = null; $scope.status = ""; $route.reload(); } $scope.commit = function() { aconfExclusive(function() { return $scope.txnMgr.commit(); }).then(clearState, function(resp) { $scope.validationReady( "Commit failed: " + aconfErrorFormat(resp) ); }); }; $scope.revert = function() { $scope.txnMgr.abort(); clearState(); }; $scope.logout = function() { $scope.txnMgr.logout().then(function() { $location.path("/login"); }); }; } ).controller("aconfLoginCtrl", function($http, $scope) { $scope.login = function() { $http({ url: "/login", method: "POST", data: {username: $scope.username, password: $scope.password} }).success(function(data, status, headers) { $scope.loggedIn( headers("X-AConf-Auth-Token"), headers("X-AConf-Save-Required") == "1" ); }).error(function() { $scope.failed = true; $scope.password = ""; }); } $("#username").focus(); }).controller( "aconfObjCtrl", function($location, $q, $scope, aconfPath, aconfType) { $scope.txnMgr.start().then(function() { function menuItems(path, current, data) { if (data.meta.type != "model") return; var items = []; var extraFields = false; var extraStatus = null; function makeItem(path, label, active, klass) { var item = {path: path, label: label}; if (active) item.class = "active"; else if (klass) item.class = klass; return item; } _.each(data.meta.fields, function(field) { if (!field.visible) return; var status = data.status(field.name); if (!aconfType.isTreeNode(field)) { extraFields = true; if (!extraStatus || status == "invalid") extraStatus = status; } else { var p = data.get(field.name); if (p) items.push( makeItem( p, field["ui-name"], aconfPath.isSubordinate(current, p), status ) ); field.visible = false; } }); if (!items.length) return; if (extraFields) items.unshift(makeItem( path, "General", current == path, extraStatus )); else if (current == path) { current = items[0].path; items[0].class = "active"; } return {items: items, current: current}; }; var path = $location.path().substring(7) || "/"; $scope.txnMgr.query("/").then(function(data) { var modules = menuItems("/", path, data); $scope.modules = modules.items; if (path == "/") path = modules.current; function renderObject(path, data) { (data ? $q.when(data) : $scope.txnMgr.query(path)) .then(function(data) { $scope.data = data; }, function() { var comps = aconfPath.split(path); comps.pop(); comps.unshift("/config"); $location.path(aconfPath.join.apply(undefined, comps)); }); } var comps = aconfPath.split(path); function renderTabs(p) { p = aconfPath.join(p, comps.shift()); $scope.txnMgr.query(p).then(function(data) { var menu = menuItems(p, path, data); if (menu) { $scope.tabs = menu.items; renderObject( menu.current, p == menu.current ? data : null ); } else if (comps.length) renderTabs(p); else renderObject(p, data); }); } renderTabs("/"); }); }); } ).directive("aconfMenu", function() { return { restrict: "A", scope: {aconfMenu: "="}, templateUrl: "directive/menu.html" }; }).directive("aconfLayout", function() { return { restrict: "E", scope: {node: "=", onValidate: "&"}, template: '', controller: function($scope) { function validationReady(txnValid) { $scope.onValidate({txnValid: txnValid}); }; this.query = function(path) { return $scope.node.txnMgr.query(path); }; this.updateRequest = function(task) { task.then(validationReady, validationReady); }; this.validationReady = validationReady; } }; }).run(function($location) { $location.path("/login"); });