http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js new file mode 100644 index 0000000..d9f5eb5 --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.config(['$translateProvider', function($translateProvider) { + $translateProvider.translations('en',{ + 'CLUSTER.OPERATE': 'Operator', + 'CLUSTER.READ': 'Read-Only', + 'VIEW.USE': 'Use' + }); + + $translateProvider.preferredLanguage('en'); +}]); \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js new file mode 100644 index 0000000..e47c97d --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js @@ -0,0 +1,111 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.constant('ROUTES', { + root: { + url: '/', + templateUrl: 'views/main.html', + controller: 'MainCtrl' + }, + users: { + list: { + url: '/users', + templateUrl: 'views/users/list.html', + controller: 'UsersListCtrl' + }, + edit: { + url: '/users/:id/edit', + templateUrl: 'views/users/create.html', + controller: 'UsersCreateCtrl' + }, + create: { + url: '/users/new', + templateUrl: 'views/users/create.html', + controller: 'UsersCreateCtrl' + }, + show: { + url: '/users/:id', + templateUrl: 'views/users/show.html', + controller: 'UsersShowCtrl' + } + }, + groups: { + list: { + url: '/groups', + templateUrl: 'views/groups/list.html', + controller: 'GroupsListCtrl' + }, + edit: { + url: '/groups/:id/edit', + templateUrl: 'views/groups/edit.html', + controller: 'GroupsEditCtrl' + }, + create: { + url: '/groups/new', + templateUrl: 'views/groups/create.html', + controller: 'GroupsCreateCtrl' + } + }, + views: { + list: { + url: '/views', + templateUrl: 'views/ambariViews/listTable.html', + controller: 'ViewsListCtrl', + }, + edit: { + url: '/views/:viewId/versions/:version/instances/:instanceId/edit', + templateUrl: 'views/ambariViews/edit.html', + controller: 'ViewsEditCtrl' + }, + create: { + url: '/views/:viewId/versions/:version/new', + templateUrl: 'views/ambariViews/create.html', + controller: 'CreateViewInstanceCtrl' + } + }, + clusters:{ + manageAccess: { + url: '/clusters/:id/manageAccess', + templateUrl: 'views/clusters/manageAccess.html', + controller: 'ClustersManageAccessCtrl' + } + }, + dashboard:{ + url: '/dashboard', + controller: ['$window', function($window) { + $window.location.href = '/#/main/dashboard'; + }], + template: '' + } +}) +.config(['$routeProvider', '$locationProvider', 'ROUTES', function($routeProvider, $locationProvider, ROUTES) { + var createRoute = function(routeObj) { + if(routeObj.url){ + $routeProvider.when(routeObj.url, routeObj); + } else { + angular.forEach(routeObj, createRoute); + } + }; + angular.forEach(ROUTES, createRoute); +}]) +.run(['$rootScope', 'ROUTES', function($rootScope, ROUTES) { + // Make routes available in every template and controller + $rootScope.ROUTES = ROUTES; +}]); http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Alert.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Alert.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Alert.js new file mode 100644 index 0000000..bd81b9a --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Alert.js @@ -0,0 +1,106 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.factory('Alert', [function() { + + var hideTimeout = null; + var $boxContainer = null; + var removingTimeout = null; + + function createAlertBox(innerHTML, moreInfo, type){ + if (!$boxContainer) { + $boxContainer = angular.element('<div class="alert-container"/>').appendTo('body'); + $boxContainer + .on('mouseenter', function() { + clearTimeout(removingTimeout); + }) + .on('mouseleave', function() { + startRemovingTimeout(); + }); + } + var elem = angular.element('<div><div class="icon-box"></div></div>').addClass('ambariAlert').addClass(type).addClass('invisible'); + + elem.append('<div class="content">' + innerHTML + '</div>'); + if (moreInfo) { + $(' <a href class="more-collapse"> more...</a>').appendTo(elem.find('.content')) + .on('click', function() { + elem.find('.more').show(); + $(this).remove(); + return false; + }); + elem.append('<div class="more">'+moreInfo+'</div>'); + } + + $('<button type="button" class="close"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>') + .appendTo(elem) + .on('click', function() { + var $box = $(this).closest('.ambariAlert'); + $box.remove(); + }); + + var $icon = $('<span class="glyphicon"></span>'); + switch (type){ + case 'error': + $icon.addClass('glyphicon-remove-sign'); + break; + case 'success': + $icon.addClass('glyphicon-ok-sign'); + break; + case 'info': + $icon.addClass('glyphicon-info-sign'); + break; + } + elem.find('.icon-box').append($icon); + + elem.appendTo($boxContainer); + setTimeout(function() { + elem.removeClass('invisible'); + }, 0); + + startRemovingTimeout(); + }; + + function startRemovingTimeout(){ + clearTimeout(removingTimeout); + removingTimeout = setTimeout(removeTopBox, 5000); + } + + function removeTopBox(){ + $boxContainer.children().first().remove(); + if (!$boxContainer.children().length) { + $boxContainer.remove(); + $boxContainer = null; + } else { + startRemovingTimeout(); + } + } + + return { + error: function(innerHTML, moreInfo) { + createAlertBox(innerHTML, moreInfo, 'error'); + }, + success: function(innerHTML, moreInfo) { + createAlertBox(innerHTML, moreInfo, 'success'); + }, + info: function(innerHTML, moreInfo) { + createAlertBox(innerHTML, moreInfo, 'info'); + } + }; +}]); http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Auth.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Auth.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Auth.js new file mode 100644 index 0000000..36b29b1 --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Auth.js @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.factory('Auth',['$http', 'Settings', function($http, Settings) { + var ambari; + var currentUserName; + if (localStorage.ambari) { + ambari = JSON.parse(localStorage.ambari); + if (ambari && ambari.app && ambari.app.loginName) { + currentUserName = ambari.app.loginName; + } + } + return { + signout: function() { + return $http({ + method: 'GET', + url: Settings.baseUrl + '/logout' + }); + }, + getCurrentUser: function() { + return currentUserName; + } + }; +}]); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js new file mode 100644 index 0000000..624e773 --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js @@ -0,0 +1,118 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.factory('Cluster', ['$http', '$q', 'Settings', function($http, $q, Settings) { + return { + getStatus: function() { + var deferred = $q.defer(); + + $http.get(Settings.baseUrl + '/clusters?fields=Clusters/provisioning_state') + .then(function(data, status, headers) { + deferred.resolve(data.data.items[0]); + }) + .catch(function(data) { + deferred.reject(data); + }); + + return deferred.promise; + }, + getPermissions: function() { + var deferred = $q.defer(); + + $http({ + method: 'GET', + url: Settings.baseUrl + '/permissions', + params: { + fields: 'PermissionInfo', + 'PermissionInfo/resource_name': 'CLUSTER' + } + }) + .success(function(data) { + deferred.resolve(data.items); + }) + .catch(function(data) { + deferred.reject(data); }); + + return deferred.promise; + }, + getPrivileges: function(params) { + var deferred = $q.defer(); + + $http({ + method: 'GET', + url: Settings.baseUrl + '/clusters/'+params.clusterId, + params : { + 'fields': 'privileges/PrivilegeInfo' + } + }) + .success(function(data) { + deferred.resolve(data.privileges); + }) + .catch(function(data) { + deferred.reject(data); + }); + + return deferred.promise; + }, + createPrivileges: function(params, data) { + return $http({ + method: 'POST', + url: Settings.baseUrl + '/clusters/'+params.clusterId+'/privileges', + data: data + }); + }, + deletePrivileges: function(params, data) { + return $http({ + method: 'DELETE', + url: Settings.baseUrl + '/clusters/'+params.clusterId+'/privileges', + data: data + }); + }, + updatePrivileges: function(params, privileges) { + return $http({ + method: 'PUT', + url: Settings.baseUrl + '/clusters/' + params.clusterId + '/privileges', + data: privileges + }); + }, + deletePrivilege: function(clusterId, permissionName, principalType, principalName) { + return $http({ + method: 'DELETE', + url: Settings.baseUrl + '/clusters/'+clusterId+'/privileges', + params: { + 'PrivilegeInfo/principal_type': principalType, + 'PrivilegeInfo/principal_name': principalName, + 'PrivilegeInfo/permission_name': permissionName + } + }); + }, + editName: function(oldName, newName) { + return $http({ + method: 'PUT', + url: Settings.baseUrl + '/clusters/' + oldName, + data: { + Clusters: { + "cluster_name": newName + } + } + }); + } + }; +}]); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/ConfirmationModal.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/ConfirmationModal.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/ConfirmationModal.js new file mode 100644 index 0000000..a26f1df --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/ConfirmationModal.js @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.factory('ConfirmationModal', ['$modal', '$q', function($modal, $q) { + + return { + show: function(header, body) { + var deferred = $q.defer(); + + var modalInstance = $modal.open({ + templateUrl: 'views/modals/ConfirmationModal.html', + controller: ['$scope', '$modalInstance', function($scope, $modalInstance) { + $scope.header = header; + $scope.body = body; + + $scope.ok = function() { + $modalInstance.close(); + deferred.resolve(); + }; + $scope.cancel = function() { + $modalInstance.dismiss(); + deferred.reject(); + } + }] + }); + return deferred.promise; + } + }; +}]); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GetDifference.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GetDifference.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GetDifference.js new file mode 100644 index 0000000..b15aa8c --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GetDifference.js @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.factory('getDifference', [function() { + return function(oldArr, newArr) { + var result = { + add: [], + del: [] + }; + angular.forEach(newArr, function(item) { + var itemIndex = oldArr.indexOf(item); + if(itemIndex >= 0){ + oldArr.splice(itemIndex, 1); + } else { + result.add.push(item); + } + }); + + result.del = oldArr; + + return result; + }; +}]); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js new file mode 100644 index 0000000..cf35d4f --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js @@ -0,0 +1,194 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.factory('Group', ['$http', '$q', 'Settings', function($http, $q, Settings) { + function Group(item){ + if(typeof item === 'string'){ + this.group_name = item; + } else if(typeof item === 'object'){ + angular.extend(this, item.Groups); + this.getMembers(); + } + } + + Group.prototype.isLDAP = function() { + var deferred = $q.defer(); + var self = this; + if( typeof this.ldap_group === 'boolean' ){ + deferred.resolve(this.ldap_group) + } else { + $http({ + method: 'GET', + url: Settings.baseUrl + '/groups/'+this.group_name + }). + success(function(data) { + self.ldap_group = data.Groups.ldap_group; + deferred.resolve(self.ldap_group); + }); + } + + return deferred.promise; + } + + Group.prototype.save = function() { + return $http({ + method : 'POST', + url: Settings.baseUrl + '/groups', + data:{ + 'Groups/group_name': this.group_name + } + }); + }; + + Group.prototype.destroy = function() { + var deferred = $q.defer(); + $http.delete(Settings.baseUrl + '/groups/' +this.group_name) + .success(function() { + deferred.resolve(); + }) + .error(function(data) { + deferred.reject(data); + }); + + return deferred.promise; + }; + + Group.prototype.getMembers = function() { + var deferred = $q.defer(); + var self = this; + + $http({ + method: 'GET', + url: Settings.baseUrl + '/groups/' + this.group_name + '/members' + }) + .success(function(data) { + self.members = []; + angular.forEach(data.items, function(member) { + self.members.push(member.MemberInfo.user_name); + }); + deferred.resolve(self.members); + }) + .error(function(data) { + deferred.reject(data); + }); + + return deferred.promise; + }; + + Group.prototype.saveMembers = function() { + var self = this; + var deferred = $q.defer(); + + var members = []; + angular.forEach(this.members, function(member) { + members.push({ + 'MemberInfo/user_name' : member, + 'MemberInfo/group_name' : self.group_name + }); + }); + + $http({ + method: 'PUT', + url: Settings.baseUrl + '/groups/' + this.group_name + '/members', + data: members + }) + .success(function(data) { + deferred.resolve(data); + }) + .error(function(data) { + deferred.reject(data); + }); + return deferred.promise; + } + + Group.prototype.addMember = function(memberName) { + var deferred = $q.defer(); + + $http({ + method: 'POST', + url: Settings.baseUrl + '/groups/' + this.group_name + '/members' + '/'+ member.user_name + }) + .success(function(data) { + deferred.resolve(data) + }) + .error(function(data) { + deferred.reject(data); + }); + + return deferred.promise; + }; + + Group.prototype.removeMember = function(memberId) { + return $http.delete(Settings.baseUrl + '/groups/'+this.group_name+'/members/'+memberId); + }; + + Group.removeMemberFromGroup = function(groupName, memberName) { + return $http.delete(Settings.baseUrl + '/groups/'+groupName + '/members/'+memberName); + }; + + Group.addMemberToGroup = function(groupName, memberName) { + return $http.post(Settings.baseUrl + '/groups/' + groupName + '/members/'+memberName); + }; + + Group.all = function(params) { + var deferred = $q.defer(); + + $http.get(Settings.baseUrl + '/groups?' + + 'Groups/group_name.matches(.*'+params.searchString+'.*)' + + '&fields=*' + + '&from='+ (params.currentPage-1)*params.groupsPerPage + + '&page_size=' + params.groupsPerPage + + (params.ldap_group === '*' ? '' : '&Groups/ldap_group='+params.ldap_group) + ) + .success(function(data) { + var groups = []; + if(Array.isArray(data.items)){ + angular.forEach(data.items, function(item) { + groups.push(new Group(item)); + }); + } + groups.itemTotal = data.itemTotal; + deferred.resolve(groups); + }) + .error(function(data) { + deferred.reject(data); + }); + + return deferred.promise; + }; + + Group.listByName = function(name) { + return $http.get(Settings.baseUrl + '/groups?' + + 'Groups/group_name.matches(.*'+name+'.*)' + ); + }; + + Group.getPrivileges = function(groupId) { + return $http.get(Settings.baseUrl + '/privileges', { + params:{ + 'PrivilegeInfo/principal_type': 'GROUP', + 'PrivilegeInfo/principal_name': groupId, + 'fields': '*' + } + }); + }; + + return Group; +}]); http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js new file mode 100644 index 0000000..2fed344 --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.factory('PermissionLoader', ['Cluster', 'View', '$q', function(Cluster, View, $q) { + + function getPermissionsFor(resource, params){ + var deferred = $q.defer(); + resource.getPermissions(params).then(function(permissions) { + var permissionsInner = {}; // Save object into closure, until it completely fills to prevent blinkong + angular.forEach(permissions, function(permission) { + permission.GROUP = []; + permission.USER = []; + permissionsInner[permission.PermissionInfo.permission_name] = permission; + }); + + // Now we can get privileges + resource.getPrivileges(params).then(function(privileges) { + angular.forEach(privileges, function(privilege) { + permissionsInner[privilege.PrivilegeInfo.permission_name][privilege.PrivilegeInfo.principal_type].push(privilege.PrivilegeInfo.principal_name); + }); + + // After all builded - return object + deferred.resolve(permissionsInner); + }). + catch(function(data) { + deferred.reject(data); + }); + + }) + .catch(function(data) { + deferred.reject(data); + }); + + return deferred.promise; + } + + return { + getClusterPermissions: function(params) { + return getPermissionsFor(Cluster, params); + }, + getViewPermissions: function(params) { + return getPermissionsFor(View, params); + } + }; +}]); http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js new file mode 100644 index 0000000..1c36ceb --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js @@ -0,0 +1,140 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.factory('PermissionSaver', ['Cluster', 'View', '$q', 'getDifference', function(Cluster, View, $q, getDifference) { + + function savePermissionsFor(resource, permissions, params){ + var arr = []; + + angular.forEach(permissions, function(permission) { + // Sanitaize input + var users = permission.USER.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()}); + var groups = permission.GROUP.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()}); + // Build array + arr = arr.concat(users.map(function(user) { + return { + 'PrivilegeInfo':{ + 'permission_name': permission.PermissionInfo.permission_name, + 'principal_name': user, + 'principal_type': 'USER' + } + } + })); + + arr = arr.concat(groups.map(function(group) { + return { + 'PrivilegeInfo':{ + 'permission_name': permission.PermissionInfo.permission_name, + 'principal_name': group, + 'principal_type': 'GROUP' + } + } + })); + }); + + return resource.updatePrivileges(params, arr); + } + + function savePermissionsForOld(resource, oldPermissions, newPermissions, params){ + var deferred = $q.defer(); + + var addArr = []; + var delArr = []; + angular.forEach(newPermissions, function(permission) { + // Sanitize input + var users = permission.USER.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()}); + var groups = permission.GROUP.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()}); + + var userObj = getDifference(angular.copy(oldPermissions[permission.PermissionInfo.permission_name].USER) , users); + var groupObj = getDifference(angular.copy(oldPermissions[permission.PermissionInfo.permission_name].GROUP) , groups); + + // Build Add array + addArr = addArr.concat(userObj.add.map(function(user) { + return { + 'PrivilegeInfo':{ + 'permission_name': permission.PermissionInfo.permission_name, + 'principal_name': user, + 'principal_type': 'USER' + } + } + })); + addArr = addArr.concat(groupObj.add.map(function(group) { + return { + 'PrivilegeInfo':{ + 'permission_name': permission.PermissionInfo.permission_name, + 'principal_name': group, + 'principal_type': 'GROUP' + } + } + })); + + // Build del array + delArr = delArr.concat(userObj.del.map(function(user) { + return { + 'PrivilegeInfo':{ + 'permission_name': permission.PermissionInfo.permission_name, + 'principal_name': user, + 'principal_type': 'USER' + } + } + })); + delArr = delArr.concat(groupObj.del.map(function(group) { + return { + 'PrivilegeInfo':{ + 'permission_name': permission.PermissionInfo.permission_name, + 'principal_name': group, + 'principal_type': 'GROUP' + } + } + })); + }); + + if(addArr.length){ + resource.createPrivileges(params, addArr) + .then(function() { + deferred.resolve(); + }) + .catch(function(data) { + deferred.reject(data); + }); + } + + if(delArr.length){ + resource.deletePrivileges(params, delArr) + .then(function() { + deferred.resolve(); + }) + .catch(function(data) { + deferred.resolve(data); + }); + } + + return deferred.promise; + } + + return { + saveClusterPermissions: function(oldPermissions, newPermissions, params) { + return savePermissionsFor(Cluster, oldPermissions, newPermissions, params); + }, + saveViewPermissions: function(permissions, params) { + return savePermissionsFor(View, permissions, params); + } + }; +}]); http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/UnsavedDialog.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/UnsavedDialog.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/UnsavedDialog.js new file mode 100644 index 0000000..2966a8c --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/UnsavedDialog.js @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.service('UnsavedDialog', ['$modal', function($modal) { + + return function(){ + var modalInstance = $modal.open({ + template: '<div class="modal-header"><h3 class="modal-title">Warning</h3></div><div class="modal-body">You have unsaved changes. Save changes or discard?</div><div class="modal-footer"><div class="btn btn-default" ng-click="cancel()">Cancel</div><div class="btn btn-warning" ng-click="discard()">Discard</div><div class="btn btn-primary" ng-click="save()">Save</div></div>', + controller: ['$scope', '$modalInstance', function($scope, $modalInstance) { + $scope.save = function() { + $modalInstance.close('save'); + }; + $scope.discard = function() { + $modalInstance.close('discard'); + }; + $scope.cancel = function() { + $modalInstance.close('cancel'); + }; + }] + }); + + return modalInstance.result; + }; +}]); http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js new file mode 100644 index 0000000..379b2ca --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js @@ -0,0 +1,91 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.factory('User', ['Restangular', '$http', 'Settings', function(Restangular, $http, Settings) { + Restangular.addResponseInterceptor(function(data, operation, what, url, response, deferred) { + var extractedData; + if(operation === 'getList'){ + extractedData = data.items; + extractedData.itemTotal = data.itemTotal; + } else { + extractedData = data; + } + + return extractedData; + }); + + var Users = Restangular.all('users'); + + return { + list: function(params) { + return $http.get( + Settings.baseUrl + '/users/?' + + 'Users/user_name.matches(.*'+params.searchString+'.*)' + + '&fields=*' + + '&from=' + (params.currentPage-1)*params.usersPerPage + + '&page_size=' + params.usersPerPage + + (params.ldap_user === '*' ? '' : '&Users/ldap_user=' + params.ldap_user) + + (params.active === '*' ? '' : '&Users/active=' + params.active) + + (params.admin ? '&Users/admin=true' : '') + ); + }, + listByName: function(name) { + return $http.get( + Settings.baseUrl + '/users?' + + 'Users/user_name.matches(.*'+name+'.*)' + + '&from=0&page_size=20' + ); + }, + get: function(userId) { + return Restangular.one('users', userId).get(); + }, + create: function(userObj) { + return Restangular.all('users').post(userObj); + }, + setActive: function(userId, isActive) { + return Restangular.one('users', userId).customPUT({'Users/active':isActive}); + }, + setAdmin: function(userId, isAdmin) { + return Restangular.one('users', userId).customPUT({'Users/admin':isAdmin}); + }, + setPassword: function(user, password, currentUserPassword) { + return $http({ + method: 'PUT', + url: Settings.baseUrl + '/users/' + user.user_name, + data: { + 'Users/password': password, + 'Users/old_password': currentUserPassword + } + }); + }, + delete: function(userId) { + return Restangular.one('users', userId).remove(); + }, + getPrivileges : function(userId) { + return $http.get(Settings.baseUrl + '/privileges', { + params:{ + 'PrivilegeInfo/principal_type': 'USER', + 'PrivilegeInfo/principal_name': userId, + 'fields': '*' + } + }); + } + }; +}]); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js new file mode 100644 index 0000000..b945984 --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js @@ -0,0 +1,308 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +angular.module('ambariAdminConsole') +.factory('View', ['$http', '$q', 'Settings', function($http, $q, Settings) { + + function ViewInstance(item){ + angular.extend(this, item); + }; + + ViewInstance.find = function(viewName, version, instanceName) { + var deferred = $q.defer(); + var fields = [ + 'privileges/PrivilegeInfo', + 'ViewInstanceInfo', + 'resources' + ]; + + $http({ + method: 'GET', + url: Settings.baseUrl + '/views/'+viewName+'/versions/'+version+'/instances/'+instanceName, + params:{ + 'fields': fields.join(',') + } + }) + .success(function(data) { + deferred.resolve(new ViewInstance(data)); + }) + .error(function(data) { + deferred.reject(data); + }); + + return deferred.promise; + }; + + + function View(item){ + var self = this; + self.view_name = item.ViewInfo.view_name; + self.versions = ''; + self.instances = []; + self.canCreateInstance = false; + var versions = {}; + angular.forEach(item.versions, function(version) { + versions[version.ViewVersionInfo.version] = {count: version.instances.length, status: version.ViewVersionInfo.status}; + if(version.ViewVersionInfo.status === 'DEPLOYED'){ // if atelast one version is deployed + self.canCreateInstance = true; + } + + angular.forEach(version.instances, function(instance) { + instance.label = instance.ViewInstanceInfo.label || version.ViewVersionInfo.label || instance.ViewInstanceInfo.view_name; + }); + + self.instances = self.instances.concat(version.instances); + }); + self.versions = versions; + + self.versionsList = item.versions; + } + + View.getInstance = function(viewName, version, instanceName) { + return ViewInstance.find(viewName, version, instanceName); + }; + + View.deleteInstance = function(viewName, version, instanceName) { + return $http.delete(Settings.baseUrl +'/views/'+viewName+'/versions/'+version+'/instances/'+instanceName, { + headers: { + 'X-Requested-By': 'ambari' + } + }); + }; + + View.updateInstance = function(viewName, version, instanceName, data) { + return $http({ + method: 'PUT', + url: Settings.baseUrl + '/views/' +viewName + '/versions/'+version+'/instances/' + instanceName, + data: data + }); + }; + + View.getPermissions = function(params) { + var deferred = $q.defer(); + + var fields = [ + 'permissions/PermissionInfo/permission_name' + ]; + $http({ + method: 'GET', + url: Settings.baseUrl + '/views/' + params.viewName + '/versions/'+ params.version, + params: { + 'fields': fields.join(',') + } + }).success(function(data) { + deferred.resolve(data.permissions); + }) + .catch(function(data) { + deferred.reject(data); + }); + + return deferred.promise; + }; + + View.getPrivileges = function(params) { + var deferred = $q.defer(); + + $http({ + method: 'GET', + url: Settings.baseUrl + '/views/' + params.viewName + '/versions/' + params.version + '/instances/' + params.instanceId, + params: { + fields: 'privileges/PrivilegeInfo' + } + }) + .success(function(data) { + deferred.resolve(data.privileges); + }) + .catch(function(data) { + deferred.reject(data); + }); + + return deferred.promise; + }; + + + + View.getVersions = function(viewName) { + var deferred = $q.defer(); + + $http({ + method: 'GET', + url: Settings.baseUrl + '/views/'+viewName + '?versions/ViewVersionInfo/status=DEPLOYED' + }).success(function(data) { + var versions = []; + angular.forEach(data.versions, function(version) { + versions.push(version.ViewVersionInfo.version); + }); + + deferred.resolve(versions); + }).catch(function(data) { + deferred.reject(data); + }); + return deferred.promise; + }; + + View.createInstance = function(instanceInfo) { + var deferred = $q.defer(); + var properties = {}; + + angular.forEach(instanceInfo.properties, function(property) { + properties[property.name] = property.value + }); + + $http({ + method: 'POST', + url: Settings.baseUrl + '/views/' + instanceInfo.view_name +'/versions/'+instanceInfo.version + '/instances/'+instanceInfo.instance_name, + data:{ + 'ViewInstanceInfo' : { + instance_name: instanceInfo.instance_name, + label: instanceInfo.label, + visible: instanceInfo.visible, + icon_path: instanceInfo.icon_path, + icon64_path: instanceInfo.icon64_path, + properties: properties, + description: instanceInfo.description + } + } + }) + .success(function(data) { + deferred.resolve(data); + }) + .error(function(data) { + deferred.reject(data); + }); + + return deferred.promise; + }; + + View.createPrivileges = function(params, data) { + return $http({ + method: 'POST', + url: Settings.baseUrl + '/views/' + params.view_name +'/versions/'+params.version+'/instances/'+params.instance_name+'/privileges', + data: data + }); + }; + + View.deletePrivileges = function(params, data) { + return $http({ + method: 'DELETE', + url: Settings.baseUrl + '/views/' + params.view_name +'/versions/'+params.version+'/instances/'+params.instance_name+'/privileges', + data: data + }); + }; + + View.updatePrivileges = function(params, privileges) { + return $http({ + method: 'PUT', + url: Settings.baseUrl + '/views/' + params.view_name +'/versions/'+params.version+'/instances/'+params.instance_name+'/privileges', + data: privileges + }); + }; + + View.deletePrivilege = function(params) { + return $http({ + method: 'DELETE', + url: Settings.baseUrl + '/views/' + params.view_name +'/versions/'+params.version+'/instances/'+params.instance_name+'/privileges', + params: { + 'PrivilegeInfo/principal_type': params.principalType, + 'PrivilegeInfo/principal_name': params.principalName, + 'PrivilegeInfo/permission_name': params.permissionName + } + }); + }; + + View.getMeta = function(view_name, version) { + return $http({ + method: 'GET', + url: Settings.baseUrl + '/views/'+view_name+'/versions/'+version + }); + }; + + View.checkViewVersionStatus = function(view_name, version) { + var deferred = $q.defer(); + + $http({ + method: 'GET', + url: Settings.baseUrl + '/views/' + view_name + '/versions/' + version, + params:{ + 'fields': 'ViewVersionInfo/status' + } + }).then(function(data) { + deferred.resolve(data.data.ViewVersionInfo.status); + }).catch(function(err) { + deferred.reject(err); + }); + + return deferred; + }; + + View.getAllVisibleInstance = function() { + var deferred = $q.defer(); + $http({ + method: 'GET', + url: Settings.baseUrl + '/views', + params:{ + 'fields': 'versions/instances/ViewInstanceInfo', + 'versions/ViewVersionInfo/system': false, + 'versions/instances/ViewInstanceInfo/visible': true + } + }).then(function(data) { + var instances = []; + data.data.items.forEach(function(view) { + view.versions.forEach(function(version) { + version.instances.forEach(function(instance) { + instances.push(instance.ViewInstanceInfo); + }); + }) + }); + deferred.resolve(instances); + }); + + return deferred.promise; + }; + + View.all = function() { + var deferred = $q.defer(); + var fields = [ + 'versions/ViewVersionInfo/version', + 'versions/instances/ViewInstanceInfo', + 'versions/*' + ]; + + $http({ + method: 'GET', + url: Settings.baseUrl + '/views', + params:{ + 'fields': fields.join(','), + 'versions/ViewVersionInfo/system': false + } + }).success(function(data) { + var views = []; + angular.forEach(data.items, function(item) { + views.push(new View(item)); + }); + deferred.resolve(views); + }) + .error(function(data) { + deferred.reject(data); + }); + + return deferred.promise; + }; + return View; +}]); http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css new file mode 100644 index 0000000..e7e4391 --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css @@ -0,0 +1,1245 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +/* + ------ START editable-list DIRECTIVE SECTION ------ - +*/ +.editable-list-container.well{ + padding: 10px; + position: relative; + margin-bottom: 25px; + cursor: pointer; +} +.editable-list-container.well.edit-mode{ + cursor: default; +} +.editable-list-container.well.disabled{ + background: white; +} + +.editable-list-container .items-box{ + +} +.editable-list-container .items-box ul.items-list{ + list-style-type: none; + margin: 0; + padding: 0; +} + +.editable-list-container .items-box ul.items-list li.item{ + display: inline-block; + padding: 4px 8px; + margin: 0 5px 5px 2px; + background: white; + border: 1px solid #ebebeb; + max-width: 100%; + white-space: nowrap; + position: relative; +} + +.editable-list-container.edit-mode .items-box ul.items-list li.item{ + padding-right: 25px; +} + +.editable-list-container .items-box ul.items-list li.item.ng-leave-active{ + display: none; +} +.editable-list-container .items-box ul.items-list li a{ + text-decoration: none; +} + +.editable-list-container .items-box ul.items-list li.item .close{ + margin: -2px 0 0 5px; + width: 13px; + outline: none; + position: absolute; + display: none; +} +.editable-list-container.edit-mode .items-box ul.items-list li.item .close{ + display: inline-block; +} + +.editable-list-container .actions-panel{ + position: absolute; + right: 5px; + bottom: -30px; + padding: 2px 5px 5px 5px; + background: #f5f5f5; + border: 1px solid #e3e3e3; + border-top: none; + border-radius: 0 0 4px 4px; + + -webkit-transition: all 0.3s; + -o-transition: all 0.3s; + transition: all 0.3s; + + -ms-transform-origin: 0% 0%; /* IE 9 */ + -webkit-transform-origin: 0% 0%; /* Chrome, Safari, Opera */ + transform-origin: 0% 0%; + + -webkit-transform: rotateX(0deg); + -ms-transform: rotateX(0deg); + -o-transform: rotateX(0deg); + transform: rotateX(0deg); +} +.editable-list-container .actions-panel.ng-hide{ + -webkit-transform: rotateX(90deg); + -ms-transform: rotateX(90deg); + -o-transform: rotateX(90deg); + transform: rotateX(90deg); +} + +.editable-list-container.edit-mode .items-box ul.items-list li.item.add-item-input.ng-hidden{ + display: none !important; +} +.editable-list-container.edit-mode .items-box ul.items-list li.item.add-item-input{ + display: inline-block!important; + outline: none; + line-height: 20px; + max-width: 200px; + text-overflow: ellipsis; + white-space: nowrap; + position: relative; + padding-right: 8px; + -webkit-transition: none; + -o-transition: none; + transition: none; +} + +.cluster-installation-progress-label{ + display: block; + color: #888; + text-align: center; + padding: 10px 0px; + cursor: default; +} + +.add-item-input span{ + display: block; + outline: none; + min-width: 30px; + position: relative; + cursor: pointer; +} +.add-item-input span:focus{ + cursor: default; +} +.editable-list-container .items-box ul.items-list li.item.add-item{ + color: #ddd; +} +.add-item-input span:empty:before{ + content: 'New'; + position: absolute; + left: 0; + color: #ddd; +} +.add-item-input span:focus:before{ + display: none; +} +.typeahead-box{ + position: absolute; + left: 0; + margin-top: 5px; + background: white; + border: 1px solid #ebebeb; + z-index: 1000; + min-width: 65px; +} +.typeahead-box ul{ + list-style-type: none; + margin: 0; + padding: 0; +} +.typeahead-box ul li{ + padding: 3px 5px; + display: block; + cursor: pointer; +} + +.typeahead-box ul li.selected, .typeahead-box ul li:hover{ + background: #eee; +} + +.editable-list-container.disabled .pencil-box{ + display: none; +} +.editable-list-container .pencil-box{ + position: absolute; + right: 5px; + top: 5px; + opacity: 0; + -webkit-transition: all 0.3s; + -o-transition: all 0.3s; + transition: all 0.3s; +} +.editable-list-container:hover .pencil-box{ + opacity: 1; +} +.editable-list-container.edit-mode:hover .pencil-box{ + opacity: 0; +} + +/* + ------ END editable-list DIRECTIVE SECTION ------ - +*/ + +.tooltip-inner{ + word-wrap: break-word; + text-align: left; +} + + .instances-table{ + table-layout: fixed; + } + .description-column{ + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + max-width: 100%; + display: inline-block; + } + +.paginator{ + margin: 0; +} +.mainpage .panel-body{ + padding: 20px; + height: 620px; +} +.mainpage h1{ + font-size: 24px; + margin-top: 10px; +} +.mainpage .panel-body #main-operations-boxes { + padding: 10px; +} +.mainpage .panel-body #main-operations-boxes .thumbnail{ + display: block; + height: 230px; + padding: 8px; + background-color: #eeeeee; + margin-bottom: 20px; + margin-left: 20px; + margin-right: 10px; + border: none; + border-radius: 0px; +} +.mainpage .panel-body #main-operations-boxes .thumbnail .title, +.mainpage .panel-body #main-operations-boxes .thumbnail .description, +.mainpage .panel-body #main-operations-boxes .thumbnail .buttons { + text-align: center; + line-height: 1.5; +} +.mainpage .panel-body #main-operations-boxes .thumbnail .buttons .btn{ + width: 200px; + margin: 5px; +} +.mainpage .panel-body #main-operations-boxes .thumbnail .buttons .btn.userslist-button, +.mainpage .panel-body #main-operations-boxes .thumbnail .buttons .btn.groupslist-button { + width: 100px; +} +.mainpage .panel-body #main-operations-boxes .thumbnail .glyphicon { + font-size: 50px; + text-align: center; + display: block; + line-height: 1.5; +} +.mainpage .panel-body #main-operations-boxes .col-sm-5 { + width: 43.5%; +} + +.views-list-table .panel{ + border-radius: 0; + border: none; + margin-top: 0; +} +.views-list-table h4{ + font-size: 14px; +} +.views-list-table .panel-group .panel + .panel{ + margin-top: 0; +} +.views-list-table .panel-group .panel .panel-heading{ + border-radius: 0; + border-top: 1px solid #ddd; +} +.views-list-table .panel-group .panel .panel-heading{ + background: #f9f9f9; +} +.views-list-table .panel-group .panel:nth-child(even) .panel-heading{ + background: none; +} +.views-list-table .panel-group .panel .panel-heading .panel-title{ + font-size: 14px; + font-weight: normal; + cursor: pointer; +} +.views-list-table .panel-group .panel .panel-body{ + padding-top: 0; + padding-bottom: 0; +} +.views-list-table .panel-group .panel .panel-body table tr:first-child td{ + border-top: none; +} +.views-list-table .glyphicon.glyphicon-chevron-right{ + -webkit-transition: all 0.3s; + -o-transition: all 0.3s; + transition: all 0.3s; +} +.views-list-table .glyphicon.glyphicon-chevron-right.opened{ + -webkit-transform: rotateZ(90deg); + -ms-transform: rotateZ(90deg); + -o-transform: rotateZ(90deg); + transform: rotateZ(90deg); +} + +a.gotoinstance{ + font-size: 12px; +} + +.ats-switch{ + border-color: #333; +} +.ats-switch.disabled, .ats-switch.disabled:hover{ + cursor: not-allowed !important; + box-shadow: none!important; + border-color: #ccc!important; +} +.ats-switch.disabled .switch-left, .ats-switch.disabled .switch-right, .ats-switch.disabled .knob{ + cursor: not-allowed!important; +} +.hide-soft{ + display: none; +} +.visible{ + display: block; +} +.not-required{ + font-weight: normal; +} +.panel{ + box-shadow: none; + border-radius: 0; +} + +.views-list-table .panel-group .panel:nth-child(even) .panel-heading{ + background: #f9f9f9; +} + +.users-pane table .glyphicon{ + width: 14px; +} + +.groups-pane table .search-container .namefilter, +.users-pane table .search-container .namefilter { + font-weight: normal; +} + +.settings-edit-toggle.disabled, .properties-toggle.disabled{ + color: #999; + cursor: not-allowed; +} + +.pulldown2{ + -webkit-transform: translateY(2px); + -ms-transform: translateY(2px); + -o-transform: translateY(2px); + transform: translateY(2px); +} +.btn.deleteuser-btn.disabled, .btn.deleteuser-btn[disabled], .btn.btn-delete-instance.disabled, .btn-default.disabled{ + pointer-events: auto; + cursor: not-allowed !important; + background-color: #e6e6e6 !important; +} + +.about .logo{ + float: left; + width: 20%; +} +.about .content{ + float: left; +} +.about .content .project{ + font-weight: bold; + font-size: 2em; +} + +.breadcrumb{ + background: none; + font-size: 24px; + margin: 0; + padding: 0; +} + +.user-edit-panel .ats-switch span.switch-right , .create-user-form .ats-switch span.switch-right{ + background-color: #da4f49; + color: white; +} +/* + Style topnav menu +*/ +.navbar-views-dropdown > a{ + color: #c3c3c3; + font-size: 1.3em; + padding: 10px 25px 18px; + display: block; + box-shadow: none!important; + background: none!important; + text-decoration: none; +} +.navbar-views-dropdown > a:hover{ + color: #fff; +} +.navbar-views-dropdown > a > i{ + display: block; + margin-top: 1px; + margin-bottom: -12px; +} +.navbar-views-dropdown .dropdown-menu{ + margin-top: -2px; +} + +.navbar-views-dropdown .dropdown-menu a:hover{ + background: #666; + color: #fff; +} +.navbar-views-dropdown .dropdown-menu .disabled a:hover{ + background: none; + color: #999; +} +#top-nav .navbar.navbar-static-top{ + min-height: 40px; +} +#top-nav .navbar-inverse{ + background: none; + border: none; +} +#top-nav .navbar.navbar-static-top .navbar-inner { + background-image: -moz-linear-gradient(top, #555555, #333333); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#333333)); + background-image: -webkit-linear-gradient(top, #555555, #333333); + background-image: -o-linear-gradient(top, #555555, #333333); + background-image: linear-gradient(to bottom, #555555, #333333); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#555555, endColorstr=#333333); + -webkit-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); + max-height: 40px; + height: 40px; +} +#top-nav .dropdown-toggle.navbar-btn{ + margin: 4px 0 0 0; +} +#top-nav .navbar.navbar-static-top .logo { + float: left; + padding-top: 2px; +} +#top-nav .navbar.navbar-static-top .logo img { + height: 32px; +} +#top-nav .navbar.navbar-static-top .brand { + color: #ffffff; + font-size: 16px; + font-weight: normal; + line-height: 32px; + margin-left: 0; + padding: 2px 5px 0 10px; + text-shadow: 0 1px 0 #555555; + display: block; + float: left; + text-decoration: none; + +} +#top-nav .navbar.navbar-static-top .brand.cluster-name{ + margin-left: 10px; +} + +.create-view-form{ + padding-bottom: 50px; +} + +.create-view-form .description{ + display: inline-block; + vertical-align: middle; +} +.create-view-form .description h4 span{ + font-weight: normal; + +} +.create-view-form .view-header{ +} + +.left-navbar .panel{ + border-radius: 0; +} +.left-navbar .panel-heading { + padding: 8px 15px; + font-size: 15px; +} +.left-navbar .panel-body { + padding: 5px 15px; + font-size: 14px; +} +.left-navbar .panel-body #cluster-name input{ + font-size: 14px; +} +.left-navbar .panel-body #cluster-name form{ + margin-top: 4px; + margin-bottom: -12px; +} +.left-navbar .panel-body h5 .glyphicon{ + font-size: 13px; + color: #428bca; +} +.left-navbar .panel-body hr{ + margin-top: 5px; + margin-bottom: 5px; +} +.left-navbar .panel-body li{ + margin: 0 -15px; +} +.left-navbar .panel-body li a{ + border-radius: 0; + padding-left: 33px; + padding-top: 8px; + padding-bottom: 8px; +} +.left-navbar .panel-body li .noclusters{ + color: #808080; + padding-left: 33px; + padding-top: 8px; + padding-bottom: 8px; + margin: 0px; +} +.left-navbar .panel-body li.active a{ + background: #666; +} + +.search-container{ + position: relative; +} +.search-container .close{ + position: absolute; + right: 10px; + top: 30px; +} +.groups-pane .search-container .close{ + top: 30px; +} +.views-list-table .search-container .close{ + top: 5px; + right: 50px; + z-index: 10; +} +.views-list-pane .search-container .close{ + right: 50px; + top: 5px; + z-index: 100; +} +.groups-pane table thead th{ + border-top: 0; +} +.groups-pane table thead tr:first-child th{ + border: 0; +} + +.container{ + padding-left: 0; + width: 940px; +} + + +@media (min-width: 1200px) { + .container, .navbar-static-top .container, .navbar-fixed-top .container, .navbar-fixed-bottom .container{ + width: 1130px; + } + .container{ + width: 1170px; + } + .mainpage .panel-body #main-operations-boxes .col-sm-5 { + width: 44%; + } +} + +ul.nav li > a{ + cursor: pointer; +} + +.admin-filter{ + cursor: pointer; +} + +.glyphicon-flash.no-filter{ + color: #999; +} + +.top-buffer{ + padding-top: 20px; +} +.bottom-buffer{ + padding-bottom: 20px; +} +.right-buffer{ + padding-right: 20px; +} +.right-margin{ + margin-right: 20px; +} +.left-margin{ + margin-left: 10px; +} +.bottom-margin{ + margin-bottom: 10px; +} +.top-margin{ + margin-top: 10px; +} +.text-left{ + text-align: left !important; +} +.text-center{ + text-align: center!important; +} +.padding-top-7{ + padding-top: 7px; +} +.padding-left-30{ + padding-left: 30px; +} +.no-margin-bottom{ + margin-bottom: 0!important; +} +table.no-border tr td{ + border: none; +} +.no-border{ + border: none !important; +} +.top-margin-4{ + margin-top: 4px; +} +.table > thead > tr > th.vertical-top{ + vertical-align: top; +} + +.groups-pane table ul{ + list-style-type: none; + margin: 0; + padding: 0; +} +.groups-pane table ul li { + margin: 0; + padding: 0; +} + +.property-form label{ + width: 214px; + word-wrap: break-word; + text-overflow: ellipsis; + overflow: hidden; +} + +.views-list-pane{} +.views-list-pane .panel-body table{ + margin-bottom: 0; +} +.views-list-pane .panel-body table tbody td{ + border-top: none; + vertical-align: middle; +} + +.group-edit .users button.close , .remove-button{ + float: none; + -webkit-transform: translateY(1px); + -ms-transform: translateY(1px); + -o-transform: translateY(1px); + transform: translateY(1px); +} + +.cluster-manage-access-pane .well, .views-permissions-panel .well{ + min-height: 63px; +} + +.views-permissions-panel .panel-body{ + padding-bottom: 0; +} + +.views-permissions-panel .panel-body table{ + margin-bottom: 0; +} + + +.views-list-pane accordion .panel-group .panel-heading{ + cursor: pointer; +} + + + +.btn { + display: inline-block; + *display: inline; + padding: 4px 14px; + margin-bottom: 0; + *margin-left: .3em; + font-size: 14px; + line-height: 20px; + *line-height: 20px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + cursor: pointer; + background-color: #f5f5f5; + *background-color: #e6e6e6; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border: 1px solid #bbbbbb; + *border: 0; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-bottom-color: #a2a2a2; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:hover, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + color: #333333; + background-color: #e6e6e6; + *background-color: #d9d9d9; +} + +.btn:active, +.btn.active { + background-color: #cccccc \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover { + color: #333333; + text-decoration: none; + background-color: #e6e6e6; + *background-color: #d9d9d9; + /* Buttons in IE7 don't get borders, so darken on hover */ + + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn.active, +.btn:active { + background-color: #e6e6e6; + background-color: #d9d9d9 \9; + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled, +.btn[disabled] { + cursor: default; + background-color: #e6e6e6; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + + + +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} + +.btn { + border-color: #c5c5c5; + border-color: rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25); +} + +.btn-primary { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #006dcc; + *background-color: #0044cc; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(to bottom, #0088cc, #0044cc); + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + color: #ffffff; + background-color: #0044cc; + *background-color: #003bb3; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #003399 \9; +} + +.btn-warning { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #faa732; + *background-color: #f89406; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-repeat: repeat-x; + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + color: #ffffff; + background-color: #f89406; + *background-color: #df8505; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} + +.btn-danger { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #da4f49; + *background-color: #bd362f; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(to bottom, #ee5f5b, #bd362f); + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-repeat: repeat-x; + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + color: #ffffff; + background-color: #bd362f; + *background-color: #a9302a; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} + +.btn-success { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #5bb75b; + *background-color: #51a351; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(to bottom, #62c462, #51a351); + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-repeat: repeat-x; + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + color: #ffffff; + background-color: #51a351; + *background-color: #499249; +} + +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} + +.btn-info { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #49afcd; + *background-color: #2f96b4; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-repeat: repeat-x; + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + color: #ffffff; + background-color: #2f96b4; + *background-color: #2a85a0; +} + +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} + +.btn-inverse { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #363636; + *background-color: #222222; + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); + background-image: -webkit-linear-gradient(top, #444444, #222222); + background-image: -o-linear-gradient(top, #444444, #222222); + background-image: linear-gradient(to bottom, #444444, #222222); + background-image: -moz-linear-gradient(top, #444444, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); + filter: progid:dximagetransform.microsoft.gradient(enabled=false); +} + +.btn-inverse:hover, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + color: #ffffff; + background-color: #222222; + *background-color: #151515; +} + +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} + +button.btn, +input[type="submit"].btn { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} + +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} + +button.btn.btn-xs{ + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.alert-info { + background-color: #E6F1F6; + border-color: #D2D9DD; + color: #4E575B; + text-shadow: none; +} +.alert-info .link { + padding: 0 15px; +} +.alert-info .link-left-pad { + padding-left: 15px; +} +.breadcrumb > .active { + color: #666; +} + +.alert-container { + position: fixed; + top: 50px; + z-index: 1000; + width: 300px; + margin-left: -150px; + left: 50%; +} +.ambariAlert { + position: relative; + border: 1px solid #c4c4c4; + border-radius: 4px 0 0 4px; + box-shadow: 0 0px 4px #ebebeb; + width: 300px; + background: white; + margin-bottom: 20px; + z-index: 1000; + padding: 20px 20px 20px 60px; + max-height: 100%; + display: block; + clear: both; + text-align: left; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.ambariAlert .content { + display: inline-block; + padding-right: 10px; +} +.ambariAlert .icon-box { + display: inline-block; + font-size: 30px; + position: absolute; + left: 15px; + top: 10px; +} +.ambariAlert .more { + display: none; + margin-top: 10px; +} +.ambariAlert .more.visible { + display: block; +} +.ambariAlert.invisible { + -webkit-transform: translateX(1000px); + -ms-transform: translateX(1000px); + -o-transform: translateX(1000px); + transform: translateX(1000px); + + padding: 0; + margin: 0; + max-height: 0; +} +.ambariAlert .close { + position: absolute; + right: 10px; + top: 10px; + outline: none; +} +.ambariAlert.error { + border-left: 3px solid #ef2427; +} +.ambariAlert.error .icon-box { + color: #ef2427; +} + +.ambariAlert.success { + border-left: 3px solid #82c534; +} +.ambariAlert.success .icon-box { + color: #82c534; +} + +.ambariAlert.info { + border-left: 3px solid #ffbc5b; +} +.ambariAlert.info .icon-box { + color: #ffbc5b; +} + +.edit-cluster-name { + cursor: pointer; +} + +.edit-cluster-name:hover { + color: #428bca; +} + +.editClusterNameForm button.btn { + padding: 4px 8px; +} + +.editClusterNameForm input { + width: 161px; + float: left; + margin-right: 5px; +} + +.no-animation *{ + -webkit-transition: none!important; + -o-transition: none!important; + transition: none!important; +} + + +.viewstatus{ + display: inline-block; +} +.viewstatus.pending{ + width: 12px; + height: 12px; + border: 2px solid black; + border-radius: 50%; + vertical-align: middle; + position: relative; + border-radius: 50%; +} + +.viewstatus.pending:before, .viewstatus.pending:after{ + content: ''; + position: absolute; + left: 4px; + top: 3px; + width: 5px; + height: 2px; + background: black; +} +.viewstatus.pending:after{ + top: -3px; + left: 3px; + width: 2px; + height: 2px; + border-radius: 100%; +} +.viewstatus.pending:before{ + -webkit-transform-origin: 0% 50%; + -moz-transform-origin: 0% 50%; + -ms-transform-origin: 0% 50%; + -o-transform-origin: 0% 50%; + transform-origin: 0% 50%; + + animation: rotate 2.0s infinite linear; + -webkit-animation: rotate 2.0s infinite linear; +} + +@-webkit-keyframes rotate { 100% { -webkit-transform: rotate(360deg) }} +@keyframes rotate { 100% { transform: rotate(360deg); -webkit-transform: rotate(360deg) }} + + +.viewstatus.deploying{ + width: 17px; + height: 12px; + text-align: center; + vertical-align: middle; +} +.viewstatus.deploying > div{ + background: black; + height: 100%; + width: 3px; + display: inline-block; + -webkit-animation: stretchdelay 1.2s infinite ease-in-out; + animation: stretchdelay 1.2s infinite ease-in-out; +} +.viewstatus.deploying .rect2 { + -webkit-animation-delay: -1.1s; + animation-delay: -1.1s; +} +.viewstatus.deploying .rect3 { + -webkit-animation-delay: -1.0s; + animation-delay: -1.0s; +} + +@-webkit-keyframes stretchdelay { + 0%, 40%, 100% { -webkit-transform: scaleY(0.4) } + 20% { -webkit-transform: scaleY(1.0) } +} + +@keyframes stretchdelay { + 0%, 40%, 100% { + transform: scaleY(0.4); + -webkit-transform: scaleY(0.4); + } 20% { + transform: scaleY(1.0); + -webkit-transform: scaleY(1.0); + } +} + +accordion .panel-group .panel{ + overflow: visible; +} http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html new file mode 100644 index 0000000..1039316 --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html @@ -0,0 +1,122 @@ +<!-- +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +--> +<ol class="breadcrumb"> + <li><a href="#/views">Views</a></li> + <li class="active">Create Instance</li> +</ol> +<hr> +<form class="form-horizontal create-view-form" role="form" name="form.instanceCreateForm" novalidate> + <div class="view-header"> + <div class="form-group"> + <div class="col-sm-2"> + <label for="" class="control-label">View</label> + </div> + <div class="col-sm-10"><label for="" class="control-label">{{view.ViewVersionInfo.view_name}}</label></div> + </div> + <div class="form-group"> + <div class="col-sm-2"><label for="" class="control-label">Version</label></div> + <div class="col-sm-2"> + <select ng-model="version" class="instanceversion-input form-control" ng-change="versionChanged()" ng-options="o as o for o in versions"></select> + </div> + </div> + </div> + + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">Details</h3> + </div> + <div class="panel-body"> + <div class="form-group" + ng-class="{'has-error' : ( (form.instanceCreateForm.instanceNameInput.$error.required || form.instanceCreateForm.instanceNameInput.$error.pattern) && form.instanceCreateForm.submitted) || instanceExists }" + > + <label for="" class="control-label col-sm-2">Instance Name</label> + <div class="col-sm-10"> + <input type="text" class="form-control instancename-input" name="instanceNameInput" ng-pattern="nameValidationPattern" required ng-model="instance.instance_name" autocomplete="off"> + + <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.instanceNameInput.$error.required && form.instanceCreateForm.submitted'> + This field is required. + </div> + <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.instanceNameInput.$error.pattern && form.instanceCreateForm.submitted'> + Must not contain any special characters or spaces. + </div> + <div class="alert alert-danger no-margin-bottom top-margin" ng-show='instanceExists'> + Instance with this name already exists. + </div> + </div> + </div> + <div class="form-group" + ng-class="{'has-error' : ( (form.instanceCreateForm.displayLabel.$error.required || form.instanceCreateForm.displayLabel.$error.pattern) && form.instanceCreateForm.submitted)}"> + <label for="" class="control-label col-sm-2">Display Name</label> + <div class="col-sm-10"> + <input type="text" class="form-control instancelabel-input" name="displayLabel" ng-model="instance.label" required ng-pattern="/^([a-zA-Z0-9._\s]+)$/" autocomplete="off"> + + <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.displayLabel.$error.required && form.instanceCreateForm.submitted'> + This field is required. + </div> + <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.displayLabel.$error.pattern && form.instanceCreateForm.submitted'> + Must not contain any special characters. + </div> + </div> + </div> + <div class="form-group" ng-class="{'has-error' : form.instanceCreateForm.description.$error.required && form.instanceCreateForm.submitted }"> + <label for="" class="control-label col-sm-2">Description</label> + <div class="col-sm-10"> + <input type="text" class="form-control" name="description" ng-model="instance.description" maxlength="140" required> + <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.description.$error.required && form.instanceCreateForm.submitted'> + This field is required. + </div> + </div> + </div> + <div class="form-group"> + <div class="col-sm-10 col-sm-offset-2"> + <div class="checkbox"> + <label> + <input type="checkbox" ng-model='instance.visible' class="visibilityCheckbox"> Visible + </label> + </div> + </div> + </div> + </div> + </div> + <div class="panel panel-default"> + <div class="panel-heading"> + <h3 class="panel-title">Properties</h3> + </div> + <div class="panel-body property-form"> + <div class="form-group" ng-repeat="parameter in instance.properties" + ng-class="{'has-error' : (form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted)}" > + <label for="" class="col-sm-3 control-label" ng-class="{'not-required': !parameter.required}" tooltip="{{parameter.description}}">{{parameter.name}}{{parameter.required ? '*' : ''}}</label> + <div class="col-sm-9"> + <input type="{{parameter.masked ? 'password' : 'text'}}" class="form-control viewproperty-input" name="{{parameter.name}}" ng-required="parameter.required" ng-model="parameter.value" autocomplete="off" tooltip="{{parameter.description}}"> + <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted'> + This field is required. + </div> + </div> + </div> + <div ng-show="!instance.properties.length"> + <div class="alert alert-info">There are no properties defined for this view.</div> + </div> + </div> + </div> + + <div class="col-sm-12 "> + <button class="btn btn-primary pull-right left-margin save-button" ng-click="save()" type="submit">Save</button> + <a href ng-click="cancel()" class="btn btn-default pull-right cancel-button">Cancel</a> + </div> + +</form> \ No newline at end of file