AMBARI-22377 Ambari 3.0: Implement new design for Admin View: Views page. (atkach)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/dd0421a2 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/dd0421a2 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/dd0421a2 Branch: refs/heads/branch-feature-AMBARI-21674 Commit: dd0421a214f2f9b6c2546bad6d2bc5d743094a40 Parents: 654404d Author: Andrii Tkach <[email protected]> Authored: Tue Nov 7 18:17:20 2017 +0200 Committer: Andrii Tkach <[email protected]> Committed: Tue Nov 7 19:52:10 2017 +0200 ---------------------------------------------------------------------- .../main/resources/ui/admin-web/app/index.html | 1 + .../ambariViews/CloneViewInstanceCtrl.js | 274 ++++++++++++++ .../ambariViews/CreateViewInstanceCtrl.js | 353 +++++++----------- .../controllers/ambariViews/ViewsListCtrl.js | 360 +++++++------------ .../ui/admin-web/app/scripts/i18n.config.js | 14 +- .../ui/admin-web/app/scripts/routes.js | 34 +- .../ui/admin-web/app/scripts/services/View.js | 32 +- .../resources/ui/admin-web/app/styles/main.css | 45 ++- .../resources/ui/admin-web/app/styles/views.css | 49 +++ .../app/views/ambariViews/listTable.html | 110 ------ .../app/views/ambariViews/listUrls.html | 117 ------ .../app/views/ambariViews/modals/create.html | 238 +++++++----- .../app/views/ambariViews/modals/edit.html | 138 ------- .../app/views/ambariViews/viewsList.html | 134 +++++++ .../ui/admin-web/app/views/urls/create.html | 4 +- .../ui/admin-web/app/views/urls/edit.html | 4 +- .../unit/controllers/CloneViewInstanceCtrl.js | 135 +++++++ .../unit/controllers/CreateViewInstanceCtrl.js | 135 ------- 18 files changed, 1050 insertions(+), 1127 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/ambari-admin/src/main/resources/ui/admin-web/app/index.html ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/index.html b/ambari-admin/src/main/resources/ui/admin-web/app/index.html index e9983aa..41cc60f 100644 --- a/ambari-admin/src/main/resources/ui/admin-web/app/index.html +++ b/ambari-admin/src/main/resources/ui/admin-web/app/index.html @@ -139,6 +139,7 @@ <script src="scripts/controllers/ambariViews/ViewUrlCtrl.js"></script> <script src="scripts/controllers/ambariViews/ViewUrlEditCtrl.js"></script> <script src="scripts/controllers/ambariViews/CreateViewInstanceCtrl.js"></script> +<script src="scripts/controllers/ambariViews/CloneViewInstanceCtrl.js"></script> <script src="scripts/controllers/clusters/ClustersManageAccessCtrl.js"></script> <script src="scripts/controllers/clusters/UserAccessListCtrl.js"></script> <script src="scripts/controllers/clusters/ExportBlueprintCtrl.js"></script> http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CloneViewInstanceCtrl.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CloneViewInstanceCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CloneViewInstanceCtrl.js new file mode 100644 index 0000000..cb37e63 --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CloneViewInstanceCtrl.js @@ -0,0 +1,274 @@ +/** + * 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') +.controller('CloneViewInstanceCtrl',['$scope', 'View','RemoteCluster' , 'Alert', 'Cluster', '$routeParams', '$location', 'UnsavedDialog', '$translate', function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, UnsavedDialog, $translate) { + var $t = $translate.instant; + $scope.form = {}; + $scope.constants = { + props: $t('views.properties') + }; + $scope.isClone = $routeParams.instanceId ? true : false; + var targetUrl = ''; + + function loadMeta(){ + View.getMeta($routeParams.viewId, $scope.version).then(function(data) { + var viewVersion = data.data, + parameters; + + $scope.view = viewVersion; + parameters = viewVersion.ViewVersionInfo.parameters; + + angular.forEach(parameters, function (item) { + item.value = item['defaultValue']; + item.clusterConfig = !!item.clusterConfig; + item.displayName = item.name.replace(/\./g, '\.\u200B'); + item.clusterConfig ? $scope.numberOfClusterConfigs++ : $scope.numberOfSettingConfigs++; + }); + + $scope.clusterConfigurable = viewVersion.ViewVersionInfo.cluster_configurable; + $scope.clusterConfigurableErrorMsg = $scope.clusterConfigurable ? "" : $t('views.alerts.cannotUseOption'); + + $scope.instance = { + view_name: viewVersion.ViewVersionInfo.view_name, + version: viewVersion.ViewVersionInfo.version, + instance_name: '', + label: '', + visible: true, + icon_path: '', + icon64_path: '', + properties: parameters, + description: '', + clusterType: 'NONE' + }; + + //if cloning view instance, then get the instance data and populate settings and properties + if($scope.isClone) { + View.getInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId) + .then(function(instance) { + $scope.instanceClone = instance; + $scope.instance.version = instance.ViewInstanceInfo.version; + $scope.version = instance.ViewInstanceInfo.version; + $scope.instance.instance_name = instance.ViewInstanceInfo.instance_name + $t('common.copy'); + $scope.instance.label = instance.ViewInstanceInfo.label + $t('common.copy'); + $scope.instance.visible = instance.ViewInstanceInfo.visible; + $scope.instance.description = instance.ViewInstanceInfo.description; + $scope.instance.clusterType=instance.ViewInstanceInfo.cluster_type; + + initConfigurations(parameters); + }) + .catch(function(data) { + Alert.error($t('views.alerts.cannotLoadInstanceInfo'), data.data.message); + }); + } + + loadClusters(); + loadRemoteClusters(); + + }); + } + + function initConfigurations(parameters) { + var configuration = angular.copy($scope.instanceClone.ViewInstanceInfo.properties); + + //iterate through the view parameters and get the values from the instance being cloned + for (var i = 0; i < parameters.length; i++) { + parameters[i].value = configuration[parameters[i].name]; + parameters[i].clusterConfig = !!parameters[i].clusterConfig; + } + } + + $scope.$watch(function(scope) { + return scope.version; + }, function(version) { + if( version ){ + loadMeta(); + } + }); + + $scope.enableLocalCluster = function () { + if($scope.errorKeys.length > 0) { + $scope.errorKeys.forEach( function (key) { + try { + $scope.form.instanceCreateForm[key].validationError = false; + $scope.form.instanceCreateForm[key].validationMessage = ''; + } catch (e) { + console.log($t('views.alerts.unableToResetErrorMessage', {key: key})); + } + }); + $scope.errorKeys = []; + } + }; + + // $scope.view = viewVersion; + $scope.isAdvancedClosed = true; + $scope.instanceExists = false; + $scope.errorKeys = []; + + $scope.clusterConfigurable = false; + $scope.clusterConfigurableErrorMsg = ""; + $scope.clusters = []; + $scope.remoteClusters = []; + $scope.noLocalClusterAvailible = true; + $scope.noRemoteClusterAvailible = true; + $scope.cluster = null; + $scope.data = {}; + $scope.data.remoteCluster = null; + $scope.numberOfClusterConfigs = 0; + $scope.numberOfSettingConfigs = 0; + + function loadClusters() { + Cluster.getAllClusters().then(function (clusters) { + if(clusters.length >0){ + clusters.forEach(function(cluster) { + $scope.clusters.push({ + "name" : cluster.Clusters.cluster_name, + "id" : cluster.Clusters.cluster_id + }) + }); + $scope.noLocalClusterAvailible = false; + //do not set to default Local Cluster configuration when cloning instance + if($scope.clusterConfigurable && !$scope.isClone){ + $scope.instance.clusterType = "LOCAL_AMBARI"; + } + }else{ + $scope.clusters.push($t('common.noClusters')); + } + $scope.cluster = $scope.clusters[0]; + }); + } + + function loadRemoteClusters() { + RemoteCluster.listAll().then(function (clusters) { + if(clusters.length >0){ + clusters.forEach(function(cluster) { + $scope.remoteClusters.push({ + "name" : cluster.ClusterInfo.name, + "id" : cluster.ClusterInfo.cluster_id + }) + }); + $scope.noRemoteClusterAvailible = false; + }else{ + $scope.remoteClusters.push($t('common.noClusters')); + } + $scope.data.remoteCluster = $scope.remoteClusters[0]; + }); + } + + + $scope.versions = []; + $scope.version = null; + + View.getVersions($routeParams.viewId).then(function(versions) { + $scope.versions = versions; + $scope.version = $scope.versions[$scope.versions.length-1]; + }); + + + $scope.nameValidationPattern = /^\s*\w*\s*$/; + + $scope.save = function() { + if (!$scope.form.instanceCreateForm.isSaving) { + $scope.form.instanceCreateForm.submitted = true; + if($scope.form.instanceCreateForm.$valid){ + $scope.form.instanceCreateForm.isSaving = true; + + switch($scope.instance.clusterType) { + case 'LOCAL_AMBARI': + console.log($scope.cluster); + $scope.instance.clusterId = $scope.cluster.id; + break; + case 'REMOTE_AMBARI': + console.log($scope.data.remoteCluster); + $scope.instance.clusterId = $scope.data.remoteCluster.id; + + break; + default: + $scope.instance.clusterId = null; + } + console.log($scope.instance.clusterId); + View.createInstance($scope.instance) + .then(function(data) { + Alert.success($t('views.alerts.instanceCreated', {instanceName: $scope.instance.instance_name})); + $scope.form.instanceCreateForm.$setPristine(); + if( targetUrl ){ + $location.path(targetUrl); + } else { + $location.path('/views/' + $scope.instance.view_name + '/versions/' + $scope.instance.version + '/instances/' + $scope.instance.instance_name + '/edit'); + } + $scope.form.instanceCreateForm.isSaving = false; + $scope.$root.$emit('instancesUpdate'); + }) + .catch(function (data) { + var errorMessage = data.message; + var showGeneralError = true; + + if (data.status >= 400 && $scope.instance.clusterType == 'NONE') { + try { + var errorObject = JSON.parse(errorMessage); + errorMessage = errorObject.detail; + angular.forEach(errorObject.propertyResults, function (item, key) { + $scope.form.instanceCreateForm[key].validationError = !item.valid; + if (!item.valid) { + showGeneralError = false; + $scope.form.instanceCreateForm[key].validationMessage = item.detail; + $scope.errorKeys.push(key); + } + }); + + if (showGeneralError) { + $scope.form.instanceCreateForm.generalValidationError = errorMessage; + } + } catch (e) { + console.error($t('views.alerts.unableToParseError', {message: data.message})); + } + } + Alert.error($t('views.alerts.cannotCreateInstance'), errorMessage); + $scope.form.instanceCreateForm.isSaving = false; + }); + } + } + }; + + $scope.cancel = function() { + $scope.form.instanceCreateForm.$setPristine(); + $location.path('/views'); + }; + + $scope.$on('$locationChangeStart', function(event, __targetUrl) { + if( $scope.form.instanceCreateForm.$dirty ){ + UnsavedDialog().then(function(action) { + targetUrl = __targetUrl.split('#').pop(); + switch(action){ + case 'save': + $scope.save(); + break; + case 'discard': + $scope.form.instanceCreateForm.$setPristine(); + $location.path(targetUrl); + break; + case 'cancel': + targetUrl = ''; + break; + } + }); + event.preventDefault(); + } + }); +}]); http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js index 94b8cc1..d5e3758 100644 --- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js @@ -18,263 +18,170 @@ 'use strict'; angular.module('ambariAdminConsole') -.controller('CreateViewInstanceCtrl',['$scope', 'View','RemoteCluster' , 'Alert', 'Cluster', '$routeParams', '$location', 'UnsavedDialog', '$translate', function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, UnsavedDialog, $translate) { +.controller('CreateViewInstanceCtrl', +['$scope', 'View','RemoteCluster' , 'Alert', 'Cluster', '$routeParams', '$location', 'UnsavedDialog', '$translate', '$modalInstance', 'views', '$q', +function($scope, View, RemoteCluster, Alert, Cluster, $routeParams, $location, UnsavedDialog, $translate, $modalInstance, views, $q) { + var $t = $translate.instant; + var viewToVersionMap = {}; + var instances = {}; $scope.form = {}; - $scope.constants = { - props: $t('views.properties') + $scope.nameValidationPattern = /^\s*\w*\s*$/; + $scope.isLoading = false; + $scope.isLocalTypeChosen = true; + $scope.views = views; + $scope.viewOptions = []; + $scope.versionOptions = []; + $scope.localClusters = []; + $scope.remoteClusters = []; + $scope.clusterOptions = []; + $scope.isInstanceExists = false; + $scope.formData = { + view: null, + version: null, + instanceName: '', + displayName: '', + description: '', + clusterName: null, + visible: true }; - $scope.isClone = $routeParams.instanceId ? true : false; - var targetUrl = ''; - - function loadMeta(){ - View.getMeta($routeParams.viewId, $scope.version).then(function(data) { - var viewVersion = data.data, - parameters; - - $scope.view = viewVersion; - parameters = viewVersion.ViewVersionInfo.parameters; - - angular.forEach(parameters, function (item) { - item.value = item['defaultValue']; - item.clusterConfig = !!item.clusterConfig; - item.displayName = item.name.replace(/\./g, '\.\u200B'); - item.clusterConfig ? $scope.numberOfClusterConfigs++ : $scope.numberOfSettingConfigs++; - }); - - $scope.clusterConfigurable = viewVersion.ViewVersionInfo.cluster_configurable; - $scope.clusterConfigurableErrorMsg = $scope.clusterConfigurable ? "" : $t('views.alerts.cannotUseOption'); - - $scope.instance = { - view_name: viewVersion.ViewVersionInfo.view_name, - version: viewVersion.ViewVersionInfo.version, - instance_name: '', - label: '', - visible: true, - icon_path: '', - icon64_path: '', - properties: parameters, - description: '', - clusterType: 'NONE' - }; - - //if cloning view instance, then get the instance data and populate settings and properties - if($scope.isClone) { - View.getInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId) - .then(function(instance) { - $scope.instanceClone = instance; - $scope.instance.version = instance.ViewInstanceInfo.version; - $scope.version = instance.ViewInstanceInfo.version; - $scope.instance.instance_name = instance.ViewInstanceInfo.instance_name + $t('common.copy'); - $scope.instance.label = instance.ViewInstanceInfo.label + $t('common.copy'); - $scope.instance.visible = instance.ViewInstanceInfo.visible; - $scope.instance.description = instance.ViewInstanceInfo.description; - $scope.instance.clusterType=instance.ViewInstanceInfo.cluster_type; - - initConfigurations(parameters); - }) - .catch(function(data) { - Alert.error($t('views.alerts.cannotLoadInstanceInfo'), data.data.message); - }); - } - - loadClusters(); - loadRemoteClusters(); - - }); - } - function initConfigurations(parameters) { - var configuration = angular.copy($scope.instanceClone.ViewInstanceInfo.properties); - - //iterate through the view parameters and get the values from the instance being cloned - for (var i = 0; i < parameters.length; i++) { - parameters[i].value = configuration[parameters[i].name]; - parameters[i].clusterConfig = !!parameters[i].clusterConfig; - } + $scope.updateVersionOptions = function () { + if (viewToVersionMap[$scope.formData.view.value]) { + $scope.versionOptions = viewToVersionMap[$scope.formData.view.value]; + $scope.formData.version = $scope.versionOptions[0]; } + }; - $scope.$watch(function(scope) { - return scope.version; - }, function(version) { - if( version ){ - loadMeta(); - } - }); - - $scope.enableLocalCluster = function () { - if($scope.errorKeys.length > 0) { - $scope.errorKeys.forEach( function (key) { - try { - $scope.form.instanceCreateForm[key].validationError = false; - $scope.form.instanceCreateForm[key].validationMessage = ''; - } catch (e) { - console.log($t('views.alerts.unableToResetErrorMessage', {key: key})); - } - }); - $scope.errorKeys = []; + $scope.switchClusterType = function(bool) { + $scope.isLocalTypeChosen = bool; + if ($scope.isLocalTypeChosen) { + $scope.clusterOptions = $scope.localClusters; + } else { + $scope.clusterOptions = $scope.remoteClusters; } + $scope.formData.clusterName = $scope.clusterOptions[0]; }; - // $scope.view = viewVersion; - $scope.isAdvancedClosed = true; - $scope.instanceExists = false; - $scope.errorKeys = []; - - $scope.clusterConfigurable = false; - $scope.clusterConfigurableErrorMsg = ""; - $scope.clusters = []; - $scope.remoteClusters = []; - $scope.noLocalClusterAvailible = true; - $scope.noRemoteClusterAvailible = true; - $scope.cluster = null; - $scope.data = {}; - $scope.data.remoteCluster = null; - $scope.numberOfClusterConfigs = 0; - $scope.numberOfSettingConfigs = 0; - - function loadClusters() { - Cluster.getAllClusters().then(function (clusters) { - if(clusters.length >0){ - clusters.forEach(function(cluster) { - $scope.clusters.push({ - "name" : cluster.Clusters.cluster_name, - "id" : cluster.Clusters.cluster_id - }) - }); - $scope.noLocalClusterAvailible = false; - //do not set to default Local Cluster configuration when cloning instance - if($scope.clusterConfigurable && !$scope.isClone){ - $scope.instance.clusterType = "LOCAL_AMBARI"; - } - }else{ - $scope.clusters.push($t('common.noClusters')); - } - $scope.cluster = $scope.clusters[0]; - }); - } - - function loadRemoteClusters() { - RemoteCluster.listAll().then(function (clusters) { - if(clusters.length >0){ - clusters.forEach(function(cluster) { - $scope.remoteClusters.push({ - "name" : cluster.ClusterInfo.name, - "id" : cluster.ClusterInfo.cluster_id - }) - }); - $scope.noRemoteClusterAvailible = false; - }else{ - $scope.remoteClusters.push($t('common.noClusters')); - } - $scope.data.remoteCluster = $scope.remoteClusters[0]; - }); - } - - - $scope.versions = []; - $scope.version = null; - - View.getVersions($routeParams.viewId).then(function(versions) { - $scope.versions = versions; - $scope.version = $scope.versions[$scope.versions.length-1]; - }); - - - $scope.nameValidationPattern = /^\s*\w*\s*$/; - - $scope.save = function() { - if (!$scope.form.instanceCreateForm.isSaving) { + $scope.save = function () { + var instanceName = $scope.form.instanceCreateForm.instanceName.$viewValue; $scope.form.instanceCreateForm.submitted = true; - if($scope.form.instanceCreateForm.$valid){ - $scope.form.instanceCreateForm.isSaving = true; - - switch($scope.instance.clusterType) { - case 'LOCAL_AMBARI': - console.log($scope.cluster); - $scope.instance.clusterId = $scope.cluster.id; - break; - case 'REMOTE_AMBARI': - console.log($scope.data.remoteCluster); - $scope.instance.clusterId = $scope.data.remoteCluster.id; - - break; - default: - $scope.instance.clusterId = null; - } - console.log($scope.instance.clusterId); - View.createInstance($scope.instance) - .then(function(data) { - Alert.success($t('views.alerts.instanceCreated', {instanceName: $scope.instance.instance_name})); - $scope.form.instanceCreateForm.$setPristine(); - if( targetUrl ){ - $location.path(targetUrl); - } else { - $location.path('/views/' + $scope.instance.view_name + '/versions/' + $scope.instance.version + '/instances/' + $scope.instance.instance_name + '/edit'); - } - $scope.form.instanceCreateForm.isSaving = false; - $scope.$root.$emit('instancesUpdate'); + if ($scope.form.instanceCreateForm.$valid) { + View.createInstance({ + instance_name: instanceName, + label: $scope.form.instanceCreateForm.displayName.$viewValue, + visible: $scope.form.instanceCreateForm.visible.$viewValue, + icon_path: '', + icon64_path: '', + description: $scope.form.instanceCreateForm.description.$viewValue, + view_name: $scope.form.instanceCreateForm.view.$viewValue.value, + version: $scope.form.instanceCreateForm.version.$viewValue.value, + properties: [], + clusterId: $scope.form.instanceCreateForm.clusterName.$viewValue.id, + clusterType: $scope.isLocalTypeChosen ? 'LOCAL_AMBARI': 'REMOTE_AMBARI' + }) + .then(function () { + $modalInstance.dismiss('created'); + Alert.success($t('views.alerts.instanceCreated', {instanceName: instanceName})); + $location.path('/views/' + $scope.form.instanceCreateForm.view.$viewValue.value + + '/versions/' + $scope.form.instanceCreateForm.version.$viewValue.value + + '/instances/' + instanceName + '/edit'); }) .catch(function (data) { var errorMessage = data.message; - var showGeneralError = true; - if (data.status >= 400 && $scope.instance.clusterType == 'NONE') { + if (data.status >= 400) { try { - var errorObject = JSON.parse(errorMessage); - errorMessage = errorObject.detail; - angular.forEach(errorObject.propertyResults, function (item, key) { - $scope.form.instanceCreateForm[key].validationError = !item.valid; - if (!item.valid) { - showGeneralError = false; - $scope.form.instanceCreateForm[key].validationMessage = item.detail; - $scope.errorKeys.push(key); - } - }); - - if (showGeneralError) { - $scope.form.instanceCreateForm.generalValidationError = errorMessage; - } + errorMessage = JSON.parse(errorMessage).detail; } catch (e) { - console.error($t('views.alerts.unableToParseError', {message: data.message})); + console.warn(data.message, e); } } Alert.error($t('views.alerts.cannotCreateInstance'), errorMessage); - $scope.form.instanceCreateForm.isSaving = false; }); - } } }; - $scope.cancel = function() { - $scope.form.instanceCreateForm.$setPristine(); - $location.path('/views'); + $scope.cancel = function () { + unsavedChangesCheck(); + }; + + $scope.checkIfInstanceExist = function() { + $scope.isInstanceExists = Boolean(instances[$scope.formData.instanceName]); }; - $scope.$on('$locationChangeStart', function(event, __targetUrl) { - if( $scope.form.instanceCreateForm.$dirty ){ - UnsavedDialog().then(function(action) { - targetUrl = __targetUrl.split('#').pop(); - switch(action){ + function initViewAndVersionSelect () { + $scope.viewOptions = []; + angular.forEach($scope.views, function(view) { + $scope.viewOptions.push({ + label: view.view_name, + value: view.view_name + }); + viewToVersionMap[view.view_name] = view.versionsList.map(function(version) { + angular.forEach(version.instances, function(instance) { + instances[instance.ViewInstanceInfo.instance_name] = true; + }); + return { + label: version.ViewVersionInfo.version, + value: version.ViewVersionInfo.version + } + }); + }); + $scope.formData.view = $scope.viewOptions[0]; + $scope.updateVersionOptions(); + } + + function loadClusters() { + return Cluster.getAllClusters().then(function (clusters) { + clusters.forEach(function (cluster) { + $scope.localClusters.push({ + label: cluster.Clusters.cluster_name, + value: cluster.Clusters.cluster_name, + id: cluster.Clusters.cluster_id + }); + }); + }); + } + + function loadRemoteClusters() { + return RemoteCluster.listAll().then(function (clusters) { + clusters.forEach(function (cluster) { + $scope.remoteClusters.push({ + label: cluster.ClusterInfo.name, + value: cluster.ClusterInfo.name, + id: cluster.ClusterInfo.cluster_id + }); + }); + }); + } + + function loadFormData () { + $scope.isLoading = true; + initViewAndVersionSelect(); + $q.all(loadClusters(), loadRemoteClusters()).then(function() { + $scope.isLoading = false; + $scope.switchClusterType(true); + }); + } + + function unsavedChangesCheck() { + if ($scope.form.instanceCreateForm.$dirty) { + UnsavedDialog().then(function (action) { + switch (action) { case 'save': $scope.save(); break; case 'discard': - $scope.form.instanceCreateForm.$setPristine(); - $location.path(targetUrl); + $modalInstance.close('discard'); break; case 'cancel': - targetUrl = ''; break; } }); - event.preventDefault(); + } else { + $modalInstance.close('discard'); } - }); - - - - - + } + loadFormData(); }]); http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js index 4e7bae3..aba5702 100644 --- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js +++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsListCtrl.js @@ -18,272 +18,186 @@ 'use strict'; angular.module('ambariAdminConsole') -.controller('ViewsListCtrl',['$scope', 'View','$modal', 'Alert', 'ConfirmationModal', '$location', '$translate', function($scope, View, $modal, Alert, ConfirmationModal, $location, $translate) { - var deferredList = [], - $t = $translate.instant; - $scope.isLoadingViews = false; - $scope.isLoadingUrls = false; - $scope.constants = { - unable: $t('views.alerts.unableToCreate'), - views: $t('common.views').toLowerCase() - }; - $scope.$on('$locationChangeStart', function() { - deferredList.forEach(function(def) { - def.reject(); - }) - }); - - $scope.createUrlDisabled = false; +.controller('ViewsListCtrl',['$scope', 'View','$modal', 'Alert', 'ConfirmationModal', '$translate', function($scope, View, $modal, Alert, ConfirmationModal, $translate) { + var $t = $translate.instant; + var VIEWS_VERSION_STATUS_TIMEOUT = 5000; + $scope.isLoading = false; + $scope.minInstanceForPagination = 10; - function checkViewVersionStatus(view, versionObj, versionNumber){ + function checkViewVersionStatus(view, versionObj, versionNumber) { var deferred = View.checkViewVersionStatus(view.view_name, versionNumber); - deferredList.push(deferred); - deferred.promise.then(function(status) { - deferredList.splice(deferredList.indexOf(deferred), 1); - if (status !== 'DEPLOYED' && status !== 'ERROR') { - checkViewVersionStatus(view, versionObj, versionNumber); + deferred.promise.then(function (status) { + if (versionNeedStatusUpdate(status)) { + setTimeout(function() { + checkViewVersionStatus(view, versionObj, versionNumber); + }, VIEWS_VERSION_STATUS_TIMEOUT); } else { - $scope.$evalAsync(function() { - versionObj.status = status; - angular.forEach(view.versions, function(version) { - if(version.status === 'DEPLOYED'){ - view.canCreateInstance = true; - } - }) - }); + versionObj.status = status; + angular.forEach(view.versions, function (version) { + if (version.status === 'DEPLOYED') { + view.canCreateInstance = true; + } + }) } }); } - function loadViews(){ - $scope.isLoadingViews = true; - View.all().then(function(views) { - $scope.isLoadingViews = false; + function versionNeedStatusUpdate(status) { + return status !== 'DEPLOYED' && status !== 'ERROR'; + } + + function loadViews() { + $scope.isLoading = true; + View.all().then(function (views) { + $scope.isLoading = false; $scope.views = views; - $scope.getFilteredViews(); - angular.forEach(views, function(view) { - angular.forEach(view.versions, function(versionObj, versionNumber) { - if (versionObj.status !== 'DEPLOYED' || versionObj.status !== 'ERROR'){ - checkViewVersionStatus(view, versionObj, versionNumber); - } + $scope.instances = []; + angular.forEach(views, function (view) { + // TODO uncomment if view need status update + // angular.forEach(view.versions, function (versionObj, versionNumber) { + // if (versionNeedStatusUpdate(versionObj.status)) { + // checkViewVersionStatus(view, versionObj, versionNumber); + // } + // }); + angular.forEach(view.instances, function (instance) { + instance.ViewInstanceInfo.short_url_name = instance.ViewInstanceInfo.short_url_name || ''; + instance.ViewInstanceInfo.short_url = instance.ViewInstanceInfo.short_url || ''; + $scope.instances.push(instance.ViewInstanceInfo); }); - }) - }).catch(function(data) { + }); + initTypeFilter(); + $scope.filterInstances(); + }).catch(function (data) { Alert.error($t('views.alerts.cannotLoadViews'), data.data.message); }); } - loadViews(); + function initTypeFilter() { + var uniqTypes = $.unique($scope.instances.map(function(instance) { + return instance.view_name; + })); + $scope.typeFilterOptions = [ { label: $t('common.all'), value: '*'} ] + .concat(uniqTypes.map(function(type) { + return { + label: type, + value: type + }; + })); + $scope.instanceTypeFilter = $scope.typeFilterOptions[0]; + } - $scope.createInstance = function(view) { - var modalInstance = $modal.open({ - templateUrl: 'views/ambariViews/modals/create.html', - size: 'lg', - controller: 'CreateViewInstanceCtrl', - resolve: { - viewVersion: function(){ - return view.versionsList[ view.versionsList.length-1]; + function showInstancesOnPage() { + var startIndex = ($scope.currentPage - 1) * $scope.instancesPerPage + 1; + var endIndex = $scope.currentPage * $scope.instancesPerPage; + var showedCount = 0; + var filteredCount = 0; + + angular.forEach($scope.instances, function(instance) { + instance.isShowed = false; + if (instance.isFiltered) { + filteredCount++; + if (filteredCount >= startIndex && filteredCount <= endIndex) { + instance.isShowed = true; + showedCount++; } } }); + $scope.tableInfo.showed = showedCount; + } - modalInstance.result.then(loadViews); - }; - - $scope.viewsFilter = ''; - $scope.filteredViews = []; - $scope.getFilteredViews = function(views) { - var result = []; - var filter = $scope.viewsFilter.toLowerCase(); - if(!filter){ // if no filter return all views - result = $scope.views.map(function(view) { - view.isOpened = false; - return view; - }); - } else { - result = $scope.views.map(function(view) { - view.isOpened = true; - if(view.view_name.toLowerCase().indexOf(filter) >= 0){ - return view; // if filter matched with view name -- return whole view - } else { - var instances = []; - angular.forEach(view.instances, function(instance) { - if(instance.ViewInstanceInfo.label.toLowerCase().indexOf(filter) >= 0){ - instances.push(instance); - } - }); - if( instances.length ){ // If inside view exists instances with matched filter - show only this instances - var v = angular.copy(view); - v.instances = instances; - return v; - } - } - }).filter(function(view) { - return !!view; // Remove 'undefined' - }); - } - $scope.filteredViews = result; - }; - - $scope.gotoCreate = function(viewName, isAllowed) { - if(isAllowed){ - $location.path('/views/'+viewName+'/new'); - } - }; - - $scope.deleteInstance = function(instance) { - ConfirmationModal.show( - $t('common.delete', { - term: $t('views.viewInstance') - }), - $t('common.deleteConfirmation', { - instanceType: $t('views.viewInstance'), - instanceName: instance.ViewInstanceInfo.label - }) - ).then(function() { - View.deleteInstance(instance.ViewInstanceInfo.view_name, instance.ViewInstanceInfo.version, instance.ViewInstanceInfo.instance_name) - .then(function() { - loadViews(); - }) - .catch(function(data) { - Alert.error($t('views.alerts.cannotDeleteInstance'), data.data.message); - }); - }); - }; - - $scope.reloadViews = function () { - loadViews(); - }; - - /** - * Url listing - */ - - $scope.loadedUrls = []; - $scope.urlsPerPage = 10; + $scope.views = []; + $scope.instances = []; + $scope.instancesPerPage = 10; $scope.currentPage = 1; - $scope.totalUrls = 1; - $scope.urlNameFilter = ''; - $scope.urlSuffixfilter = ''; - $scope.maxVisiblePages=20; + $scope.instanceNameFilter = ''; + $scope.instanceUrlFilter = ''; + $scope.maxVisiblePages = 10; + $scope.isNotEmptyFilter = true; + $scope.instanceTypeFilter = ''; $scope.tableInfo = { - total: 0, + filtered: 0, showed: 0 }; - $scope.isNotEmptyFilter = true; - - - $scope.pageChanged = function() { - $scope.listViewUrls(); - }; + loadViews(); - $scope.urlsPerPageChanged = function() { + $scope.filterInstances = function() { + var filteredCount = 0; + angular.forEach($scope.instances, function(instance) { + if ($scope.instanceNameFilter && instance.short_url_name.indexOf($scope.instanceNameFilter) === -1) { + return instance.isFiltered = false; + } + if ($scope.instanceUrlFilter && ('/main/view/'+ instance.view_name + '/' + instance.short_url).indexOf($scope.instanceUrlFilter) === -1) { + return instance.isFiltered = false; + } + if ($scope.instanceTypeFilter.value !== '*' && instance.view_name.indexOf($scope.instanceTypeFilter.value) === -1) { + return instance.isFiltered = false; + } + filteredCount++; + instance.isFiltered = true; + }); + $scope.tableInfo.filtered = filteredCount; $scope.resetPagination(); }; + $scope.pageChanged = function() { + showInstancesOnPage(); + }; $scope.resetPagination = function() { $scope.currentPage = 1; - $scope.listViewUrls(); + showInstancesOnPage(); }; - - $scope.getVersions = function(instances) { - var names = []; - - instances.map(function(view){ - var name = view.view_name; - names.push(name); - }); - - var output = [], - keys = []; - - angular.forEach(names, function(item) { - var key = item; - if(keys.indexOf(key) === -1) { - keys.push(key); - output.push(item); - } - }); - return output; - }; - - - $scope.clearFilters = function () { - $scope.urlNameFilter = ''; - $scope.urlSuffixfilter = ''; + $scope.instanceNameFilter = ''; + $scope.instanceUrlFilter = ''; $scope.instanceTypeFilter = $scope.typeFilterOptions[0]; $scope.resetPagination(); }; - - $scope.$watch( - function (scope) { - return Boolean(scope.urlNameFilter || scope.urlSuffixfilter || (scope.instanceTypeFilter && scope.instanceTypeFilter.value !== '*')); - }, - function (newValue, oldValue, scope) { - scope.isNotEmptyFilter = newValue; - } + function (scope) { + return Boolean(scope.instanceNameFilter || scope.instanceUrlFilter || (scope.instanceTypeFilter && scope.instanceTypeFilter.value !== '*')); + }, + function (newValue, oldValue, scope) { + scope.isNotEmptyFilter = newValue; + } ); - - - - $scope.listViewUrls = function(){ - $scope.isLoadingUrls = true; - View.allUrls({ - currentPage: $scope.currentPage, - urlsPerPage: $scope.urlsPerPage, - searchString: $scope.urlNameFilter, - suffixSearch: $scope.urlSuffixfilter, - instanceType: $scope.instanceTypeFilter?$scope.instanceTypeFilter.value:'*' - }).then(function(urls) { - $scope.isLoadingUrls = false; - $scope.urls = urls; - $scope.ViewNameFilterOptions = urls.items.map(function(url){ - return url.ViewUrlInfo.view_instance_common_name; - }); - - $scope.totalUrls = urls.itemTotal; - $scope.tableInfo.showed = urls.items.length; - $scope.tableInfo.total = urls.itemTotal; - - // get all view instances to enable/disable creation if empty - - }).catch(function(data) { - Alert.error($t('views.alerts.cannotLoadViewUrls'), data.message); + $scope.createInstance = function () { + var modalInstance = $modal.open({ + templateUrl: 'views/ambariViews/modals/create.html', + controller: 'CreateViewInstanceCtrl', + resolve: { + views: function() { + return $scope.views; + } + }, + backdrop: 'static' }); - }; + modalInstance.result.then(loadViews); + }; - $scope.initViewUrls = function(){ - $scope.listViewUrls(); - View.getAllVisibleInstance().then(function(instances){ - // if no instances then disable the create button - if(!instances.length){ - $scope.createUrlDisabled = true; - } else { - $scope.typeFilterOptions = [{ label: $t('common.all'), value: '*'}] - .concat($scope.getVersions(instances).map(function(key) { - return { - label: key, - value: key - }; - })); - - $scope.instanceTypeFilter = $scope.typeFilterOptions[0]; - } - - }).catch(function(data) { - // Make the create button enabled, and swallow the error - $scope.createUrlDisabled = false; + $scope.deleteInstance = function (instance) { + ConfirmationModal.show( + $t('common.delete', { + term: $t('views.viewInstance') + }), + $t('common.deleteConfirmation', { + instanceType: $t('views.viewInstance'), + instanceName: instance.label + }) + ).then(function () { + View.deleteInstance(instance.view_name, instance.version, instance.instance_name) + .then(function () { + loadViews(); + }) + .catch(function (data) { + Alert.error($t('views.alerts.cannotDeleteInstance'), data.data.message); + }); }); - }; - -}]); \ No newline at end of file +}]); http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/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 index cb52df1..73ab064 100644 --- 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 @@ -32,7 +32,6 @@ angular.module('ambariAdminConsole') 'common.register': 'Register', 'common.clusters': 'Clusters', 'common.views': 'Views', - 'common.viewUrls': 'View URLs', 'common.roles': 'Roles', 'common.users': 'Users', 'common.groups': 'Groups', @@ -80,6 +79,7 @@ angular.module('ambariAdminConsole') 'common.remoteClusterDelConfirmation': 'Are you sure you want to delete {{instanceType}} {{instanceName}}? This operation cannot be undone.', 'common.messageInstanceAffected': 'The following View Instances are using this Remote Cluster for configuration, and will need to be reconfigured:', 'common.local': 'Local', + 'common.remote': 'Remote', 'common.pam': 'PAM', 'common.ldap': 'LDAP', 'common.jwt': 'JWT', @@ -100,6 +100,7 @@ angular.module('ambariAdminConsole') 'common.clusterManagement': 'Cluster Management', 'common.userManagement': 'User Management', 'common.admin': 'Admin', + 'common.actions': 'Actions', 'common.clusterNameChangeConfirmation.title': 'Confirm Cluster Name Change', 'common.clusterNameChangeConfirmation.message': 'Are you sure you want to change the cluster name to {{clusterName}}?', @@ -191,7 +192,7 @@ angular.module('ambariAdminConsole') 'views.viewInstance': 'View Instance', 'views.create': 'Create Instance', 'views.clone': 'Clone Instance', - 'views.createViewInstance': 'Create View Instance', + 'views.createViewInstance': 'Create Instance', 'views.edit': 'Edit', 'views.viewName': 'View Name', 'views.instances': 'Instances', @@ -239,7 +240,6 @@ angular.module('ambariAdminConsole') 'views.alerts.cannotEditInstance': 'Cannot Edit Static Instances', 'views.alerts.cannotDeleteStaticInstance': 'Cannot Delete Static Instances', 'views.alerts.deployError': 'Error deploying. Check Ambari Server log.', - 'views.alerts.unableToCreate': 'Unable to create view instances', 'views.alerts.cannotUseOption': 'This view cannot use this option', 'views.alerts.unableToResetErrorMessage': 'Unable to reset error message for prop: {{key}}', 'views.alerts.instanceCreated': 'Created View Instance {{instanceName}}', @@ -256,7 +256,12 @@ angular.module('ambariAdminConsole') 'views.alerts.savedRemoteClusterInformation': 'Remote cluster information is saved.', 'views.alerts.credentialsUpdated': 'Credentials Updated.', - 'urls.name': 'Name', + 'views.table.viewType': 'View Type', + 'views.emptyTable': 'No Views to display', + 'views.createInstance.selectView': 'Select View', + 'views.createInstance.selectVersion': 'Select Version', + 'views.createInstance.clusterType': 'Cluster Type', + 'urls.url': 'URL', 'urls.viewUrls': 'View URLs', 'urls.createNewUrl': 'Create New URL', @@ -267,7 +272,6 @@ angular.module('ambariAdminConsole') 'urls.step1': 'Create URL', 'urls.step2': 'Select instance', 'urls.step3': 'Assign URL', - 'urls.noUrlsToDisplay': 'No URLs to display.', 'urls.noViewInstances': 'No view instances', 'urls.none': 'None', 'urls.change': 'Change', http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/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 index d2d8253..2cb077a 100644 --- 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 @@ -93,14 +93,20 @@ angular.module('ambariAdminConsole') views: { list: { url: '/views', - templateUrl: 'views/ambariViews/listTable.html', + templateUrl: 'views/ambariViews/viewsList.html', controller: 'ViewsListCtrl', label: 'Views' }, - listViewUrls: { - url: '/viewUrls', - templateUrl: 'views/ambariViews/listUrls.html', - controller: 'ViewsListCtrl', + clone: { + url: '/views/:viewId/versions/:version/instances/:instanceId/clone', + templateUrl: 'views/ambariViews/create.html', + controller: 'CloneViewInstanceCtrl', + label: 'Views' + }, + edit: { + url: '/views/:viewId/versions/:version/instances/:instanceId/edit', + templateUrl: 'views/ambariViews/edit.html', + controller: 'ViewsEditCtrl', label: 'Views' }, createViewUrl:{ @@ -120,24 +126,6 @@ angular.module('ambariAdminConsole') templateUrl: 'views/urls/edit.html', controller: 'ViewUrlEditCtrl', label: 'Views' - }, - clone: { - url: '/views/:viewId/versions/:version/instances/:instanceId/clone', - templateUrl: 'views/ambariViews/create.html', - controller: 'CreateViewInstanceCtrl', - label: 'Views' - }, - edit: { - url: '/views/:viewId/versions/:version/instances/:instanceId/edit', - templateUrl: 'views/ambariViews/edit.html', - controller: 'ViewsEditCtrl', - label: 'Views' - }, - create: { - url: '/views/:viewId/new', - templateUrl: 'views/ambariViews/create.html', - controller: 'CreateViewInstanceCtrl', - label: 'Views' } }, stackVersions: { http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/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 index f549b29..b38b0c2 100644 --- 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 @@ -61,32 +61,6 @@ angular.module('ambariAdminConsole') angular.element(this,item); } - ViewUrl.all = function(params) { - var deferred = $q.defer(); - - $http({ - method: 'GET', - dataType: "json", - url: Settings.baseUrl + '/view/urls?' - + 'ViewUrlInfo/url_name.matches(.*'+params.searchString+'.*)' - + '&ViewUrlInfo/url_suffix.matches(.*'+params.suffixSearch+'.*)' - + '&fields=*' - + '&from=' + (params.currentPage-1)*params.urlsPerPage - + '&page_size=' + params.urlsPerPage - + (params.instanceType === '*' ? '' : '&ViewUrlInfo/view_instance_common_name=' + params.instanceType) - - }) - .success(function(data) { - deferred.resolve(new ViewUrl(data)); - }) - .error(function(data) { - deferred.reject(data); - }); - - return deferred.promise; - }; - - ViewUrl.updateShortUrl = function(payload){ var deferred = $q.defer(); @@ -176,7 +150,7 @@ angular.module('ambariAdminConsole') 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 + if (version.ViewVersionInfo.status === 'DEPLOYED'){ // if at least one version is deployed self.canCreateInstance = true; } @@ -203,10 +177,6 @@ angular.module('ambariAdminConsole') return ViewInstance.find(viewName, version, instanceName); }; - View.allUrls = function(req){ - return ViewUrl.all(req) - }; - View.getUrlInfo = function(urlName){ return ViewUrl.urlInfo(urlName); }; http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/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 index 66f23af..bd06bc0 100644 --- 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 @@ -367,10 +367,6 @@ a.gotoinstance{ width: 14px; } -.namefilter { - font-weight: normal; -} - .settings-edit-toggle.disabled, .properties-toggle.disabled{ color: #999; cursor: not-allowed; @@ -480,25 +476,18 @@ a.gotoinstance{ .search-container{ position: relative; } -.search-container .close{ +.search-container .close { position: absolute; right: 10px; - top: 32px; + top: 8px; +} +.search-container input { + font-weight: normal; } .groups-pane .search-container .close{ top: 32px; } -.views-urls-table .search-container .close{ - top: 7px; - right: 10px; - z-index: 10; -} -.views-list-table .search-container .close{ - right: 50px; - top: 7px; - z-index: 10; -} .groups-pane table thead th{ border-top: 0; } @@ -563,9 +552,7 @@ table.no-border tr td{ .no-border{ border: none !important; } -.top-margin-4{ - margin-top: 4px; -} + .table > thead > tr > th.vertical-top{ vertical-align: top; } @@ -647,10 +634,14 @@ button.btn.btn-xs{ border-radius: 3px; } -a.btn-primary { +a.btn-primary, a.btn-primary:focus { color: #fff; } +a.btn-default, a.btn-default:focus { + color: #666; +} + .clusterDisplayName { display:inline-block; width:90%; @@ -686,6 +677,12 @@ a.alert-link, a.alert-link:hover, a.alert-link:visited{ color: #666; } +.empty-table-alert { + background-color: #f0f0f0; + text-align: center; + text-transform: uppercase; +} + .alert-container { position: fixed; top: 50px; @@ -1475,10 +1472,6 @@ legend { text-overflow: ellipsis; } -.pull-right { - float: right; -} - body { height: 100%; background-color: #f0f0f0; @@ -1498,3 +1491,7 @@ body { background-color: #fff; padding: 15px; } + +.navigation-bar-fit-height { + z-index: 1001; +} http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css new file mode 100644 index 0000000..9ab66f5 --- /dev/null +++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/views.css @@ -0,0 +1,49 @@ +/** + * 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. + */ + +.view-instance-actions>a { + color: inherit; + font-size: 16px; + cursor: pointer; + padding: 0 5px; +} + +td.view-instance-actions, +th.view-instance-actions { + width: 10%; +} + +.view-instance-actions>a:hover, +.view-instance-actions>a:visited:hover, +.view-instance-actions>a:focus:hover { + text-decoration: none; +} + +#create-instance-form i { + cursor: pointer; +} + +#create-instance-form button.active { + color: #333; + background-color: #e6e6e6; + border-color: #adadad; +} + +input[type="checkbox"] + label { + line-height: 18px; +} http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listTable.html ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listTable.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listTable.html deleted file mode 100644 index 91b9a93..0000000 --- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listTable.html +++ /dev/null @@ -1,110 +0,0 @@ -<!-- -* 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. ---> - -<div class="views-list-table"> - <div class="clearfix"> - <ol class="breadcrumb pull-left"> - <li class="active">{{'common.views' | translate}}</li> - <button ng-click="reloadViews()" - class="btn btn-xs"> - <i class="glyphicon glyphicon-refresh"></i> - </button> - </ol> - <div class="pull-right col-sm-4"> - <div class="input-group search-container"> - <input type="text" class="form-control search-input" placeholder="{{'common.search' | translate}}" ng-model="viewsFilter" ng-change="getFilteredViews()"> - <button type="button" class="close clear-search" ng-show="viewsFilter" ng-click="viewsFilter=''; getFilteredViews()"><span aria-hidden="true">×</span><span class="sr-only">{{"common.controls.close" | translate}}</span></button> - <span class="input-group-addon"> - <span class="glyphicon glyphicon-search"></span> - </span> - </div> - </div> - </div> - <hr> - <div class="row"> - <div class="col-sm-3 padding-left-30"><h4>{{'views.viewName' | translate}}</h4></div> - <div class="col-sm-3"><h4>{{'views.instances' | translate}}</h4></div> - <div class="col-sm-6"><h4></h4></div> - </div> - <accordion close-others="false"> - <accordion-group ng-repeat="view in filteredViews" is-open="view.isOpened"> - <accordion-heading> - <div class="row"> - <div class="col-sm-4"> - <i class="glyphicon glyphicon-chevron-right" ng-class="{'opened': view.isOpened}"></i> - {{view.view_name}} - </div> - <div class="col-sm-3"> - <span ng-repeat="(version, vData) in view.versions"> - {{version}} - <span ng-switch="vData.status"> - <span ng-switch-when="PENDING" class="viewstatus pending" ng-switch-when="true" tooltip="{{'views.pending' | translate}}"></span> - <div class="viewstatus deploying" ng-switch-when="DEPLOYING" tooltip="{{'views.deploying' | translate}}"> - <div class="rect1"></div> - <div class="rect2"></div> - <div class="rect3"></div> - </div> - <span ng-switch-when="DEPLOYED">({{vData.count}})</span> - <span ng-switch-when="ERROR" tooltip="{{'views.alerts.deployError' | translate}}"><i class="fa fa-exclamation-triangle"></i></span> - </span> - {{$last ? '' : ', '}} - </span> - </div> - <div class="col-sm-6">{{view.description}}</div> - </div> - </accordion-heading> - <table class="table instances-table"> - <tbody> - <tr ng-repeat="instance in view.instances"> - <td class="col-sm-1"></td> - <td class="col-sm-5"> - <a href="#/views/{{view.view_name}}/versions/{{instance.ViewInstanceInfo.version}}/instances/{{instance.ViewInstanceInfo.instance_name}}/edit" class="instance-link">{{instance.label}}</a> - </td> - <td class="col-sm-5">{{instance.ViewInstanceInfo.version}}</td> - <td class="col-sm-5 " ><div class="description-column" tooltip="{{instance.ViewInstanceInfo.description}}">{{instance.ViewInstanceInfo.description || 'No description'}}</div> - </td> - <td class="col-sm-1"> - <a class="instance-link ng-scope ng-binding" href="#/views/{{view.view_name}}/versions/{{instance.ViewInstanceInfo.version}}/instances/{{instance.ViewInstanceInfo.instance_name}}/clone"><i class="fa fa-copy"></i></a> - </td> - <td class="col-sm-1"> - <a class="instance-link ng-scope ng-binding" href ng-click="deleteInstance(instance)"><i class="fa fa-trash-o"></i></a> - </td> - </tr> - </tbody> - <tfoot> - <tr> - <td class="col-sm-4"></td> - <td class="col-sm-3 padding-left-30"> - <a tooltip="{{view.canCreateInstance ? '' : constants.unable}}" class="btn btn-default createisntance-btn {{view.canCreateInstance ? '' : 'disabled'}}" href ng-click="gotoCreate(view.view_name, view.canCreateInstance);"><span class="glyphicon glyphicon-plus"></span> {{'views.create' | translate}}</a> - </td> - <td class="col-sm-3"></td> - <td class="col-sm-3"> - </td> - </tr> - </tfoot> - </table> - </accordion-group> - <div ng-if="isLoadingViews" class="spinner-container"> - <i class="fa fa-2x fa-spinner fa-spin" aria-hidden="true"></i> - </div> - <div class="alert alert-info" ng-show="views && !filteredViews.length && !isLoadingViews"> - {{'common.alerts.nothingToDisplay' | translate: '{term: constants.views}'}} - </div> - - </accordion> -</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listUrls.html ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listUrls.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listUrls.html deleted file mode 100644 index 13ff311..0000000 --- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/listUrls.html +++ /dev/null @@ -1,117 +0,0 @@ -<!-- -* 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. ---> - -<div class="views-urls-table" data-ng-init="initViewUrls()"> - - - <div class="clearfix"> - <ol class="breadcrumb pull-left"> - <li class="active">{{'common.viewUrls' | translate}}</li> - </ol> - <div class="pull-right top-margin-4"> - <div class="tooltip-wrapper" tooltip="{{(createUrlDisabled)? ('urls.noViewInstances' | translate) : ''}}"> - <link-to ng-disabled="createUrlDisabled" route="views.createViewUrl" class="btn btn-primary createuser-btn"><span class="glyphicon glyphicon-plus"></span> {{'urls.createNewUrl' | translate}}</link-to> - </div> - </div> - </div> - <hr> - <table class="table table-striped table-hover"> - <thead> - <tr class="fix-bottom"> - - <th class="fix-bottom col-md-2"> - <span>{{'urls.name' | translate}}</span> - </th> - <th class="fix-bottom col-md-3"> - <span>{{'urls.url' | translate}}</span> - </th> - <th class="fix-bottom col-md-2"> - <span >{{'urls.view' | translate}}</span> - </th> - <th class="fix-bottom col-md-2"> - <span>{{'urls.viewInstance' | translate}}</span> - </th> - </tr> - - <tr> - - <th class="fix-top"> - <div class="search-container"> - <input type="text" class="form-control namefilter" placeholder="{{'common.any' | translate}}" ng-model="urlNameFilter" ng-change="resetPagination()"> - <button type="button" class="close clearfilter" ng-show="urlNameFilter" ng-click="urlNameFilter=''; resetPagination()"><span class="pull-right" aria-hidden="true">×</span><span class="sr-only">{{'common.controls.close' | translate}}</span></button> - </div> - </th> - <th class="fix-top"> - <div class="search-container"> - <input type="text" class="form-control namefilter" placeholder="{{'common.any' | translate}}" ng-model="urlSuffixfilter" ng-change="resetPagination()"> - <button type="button" class="close clearfilter" ng-show="urlSuffixfilter" ng-click="urlSuffixfilter=''; resetPagination()"><span class="pull-right" aria-hidden="true">×</span><span class="sr-only">{{'common.controls.close' | translate}}</span></button> - </div> - </th> - <th class="fix-top"> - <select class="form-control typefilter v-small-input" - ng-model="instanceTypeFilter" - ng-options="item.label for item in typeFilterOptions" - ng-change="resetPagination()"> - </select> - </th> - <th class="fix-top"> - </th> - </tr> - - </thead> - <tbody> - <tr ng-repeat="url in urls.items"> - - <td> - <a href="#/urls/edit/{{url.ViewUrlInfo.url_name}}">{{url.ViewUrlInfo.url_name}}</a> - </td> - <td> - <a target="_blank" href="{{fromSiteRoot('/#/main/view/' + url.ViewUrlInfo.view_instance_common_name + '/' + url.ViewUrlInfo.url_suffix)}}">/main/view/{{url.ViewUrlInfo.view_instance_common_name}}/{{url.ViewUrlInfo.url_suffix}} - <i class="fa fa-external-link" aria-hidden="true"></i></a> - - </td> - <td> - <span>{{url.ViewUrlInfo.view_instance_common_name}} {{"{"+url.ViewUrlInfo.view_instance_version+"}"}} </span> - </td> - <td> - <span>{{url.ViewUrlInfo.view_instance_name}}</span> - </td> - - </tr> - </tbody> - </table> - <div ng-if="isLoadingUrls" class="spinner-container"> - <i class="fa fa-2x fa-spinner fa-spin" aria-hidden="true"></i> - </div> - <div class="alert alert-info col-sm-12" ng-show="!urls.items.length && !isLoadingUrls"> - {{'urls.noUrlsToDisplay'| translate}} - </div> - <div class="col-sm-12 table-bar"> - <div class="pull-left filtered-info"> - <span>{{'common.filterInfo' | translate: '{showed: tableInfo.showed, total: tableInfo.total, term: urs.urls}'}}</span> - <span ng-show="isNotEmptyFilter">- <a href ng-click="clearFilters()">{{'common.controls.clearFilters' | translate}}</a></span> - </div> - <div class="pull-right left-margin"> - <pagination class="paginator" total-items="totalUrls" max-size="maxVisiblePages" items-per-page="urlsPerPage" ng-model="currentPage" ng-change="pageChanged()"></pagination> - </div> - <div class="pull-right"> - <select class="form-control" ng-model="urlsPerPage" ng-change="urlsPerPageChanged()" ng-options="currOption for currOption in [10, 25, 50, 100]"></select> - </div> - </div> - -</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/create.html ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/create.html index c5410c1..48757d4 100644 --- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/create.html +++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/create.html @@ -15,110 +15,160 @@ * See the License for the specific language governing permissions and * limitations under the License. --> -<form class="form-horizontal" role="form" name="form.instanceCreateForm" novalidate> +<form role="form" id="create-instance-form" name="form.instanceCreateForm" novalidate> <div class="modal-header"> <h3 class="modal-title">{{'views.createViewInstance' | translate}}</h3> </div> -<div class="modal-body createViewModal"> - <div class="view-header"> - <img src="http://placehold.it/64x64" alt="" class="icon-big"> - <img src="http://placehold.it/32x32" alt="" class="icon-small"> - <div class="description"> - <h3>{{view.ViewVersionInfo.view_name}}</h3> - <span>{{view.ViewVersionInfo.label}} | Version: {{view.ViewVersionInfo.version}}</span> +<div class="modal-body" ng-hide="isLoading"> + + <div class="row"> + + <div class="form-group col-sm-6" ng-class="{ 'has-error': form.instanceCreateForm.view.$error.required && form.instanceCreateForm.submitted }"> + <label for="view"> + {{'views.createInstance.selectView' | translate}}<span>*</span> + <i class="fa fa-question-circle" aria-hidden="true"></i> + </label> + <select + class="form-control" + id="view" + name="view" + ng-model="formData.view" + ng-change="updateVersionOptions()" + ng-options="item.label for item in viewOptions" + required> + </select> + <span class="help-block validation-block" ng-show='form.instanceCreateForm.view.$error.required && form.instanceCreateForm.submitted'> + {{'common.alerts.fieldRequired' | translate}} + </span> + </div> + + <div class="form-group col-sm-6" ng-class="{ 'has-error': form.instanceCreateForm.version.$error.required && form.instanceCreateForm.submitted }"> + <label for="version"> + {{'views.createInstance.selectVersion' | translate}}<span>*</span> + <i class="fa fa-question-circle" aria-hidden="true"></i> + </label> + <select + class="form-control" + id="version" + name="version" + ng-model="formData.version" + ng-options="item.label for item in versionOptions"> + </select> + <span class="help-block validation-block" ng-show='form.instanceCreateForm.version.$error.required && form.instanceCreateForm.submitted'> + {{'common.alerts.fieldRequired' | translate}} + </span> </div> </div> - - <div class="panel panel-default"> - <div class="panel-heading"> - <h3 class="panel-title">{{'common.details' | translate}}</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-labe col-sm-2">{{'views.instanceName' | translate}}</label> - <div class="col-sm-10"> - <input type="text" class="form-control" name="instanceNameInput" ng-pattern="nameValidationPattern" required ng-model="instance.instance_name"> - <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.instanceNameInput.$error.required && form.instanceCreateForm.submitted'> - {{'common.alerts.fieldRequired' | translate}} - </div> - <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.instanceNameInput.$error.pattern && form.instanceCreateForm.submitted'> - {{'common.alerts.noSpecialChars' | translate}} - </div> - <div class="alert alert-danger no-margin-bottom top-margin" ng-show='instanceExists'> - {{'views.alerts.instanceExists' | translate}} - </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-labe col-sm-2">{{'common.displayLabel' | translate}}</label> - <div class="col-sm-10"> - <input type="text" class="form-control" name="displayLabel" ng-model="instance.label" required ng-pattern="nameValidationPattern"> + <div class="h4">{{'common.details' | translate}}</div> + <div class="form-group" + ng-class="{ 'has-error': (form.instanceCreateForm.instanceName.$error.required || form.instanceCreateForm.instanceName.$error.pattern || isInstanceExists) && form.instanceCreateForm.submitted }"> + <label for="instanceName"> + {{'views.instanceName' | translate}}<span>*</span> + <i class="fa fa-question-circle" aria-hidden="true"></i> + </label> + <input type="text" class="form-control" + ng-model="formData.instanceName" + name="instanceName" + id="instanceName" + ng-change="checkIfInstanceExist()" + ng-pattern="nameValidationPattern" required> + <span class="help-block validation-block" + ng-show='form.instanceCreateForm.instanceName.$error.required && form.instanceCreateForm.submitted'> + {{'common.alerts.fieldRequired' | translate}} + </span> + <span class="help-block validation-block" + ng-show='form.instanceCreateForm.instanceName.$error.pattern && form.instanceCreateForm.submitted'> + {{'common.alerts.noSpecialChars' | translate}} + </span> + <span class="help-block validation-block" + ng-show='isInstanceExists && form.instanceCreateForm.submitted'> + {{'views.alerts.instanceExists' | translate}} + </span> + </div> - <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.displayLabel.$error.required && form.instanceCreateForm.submitted'> - {{'common.alerts.fieldRequired' | translate}} - </div> - <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.displayLabel.$error.pattern && form.instanceCreateForm.submitted'> - {{'common.alerts.noSpecialChars' | translate}} - </div> - </div> - </div> - </div> - <div class="form-group"> - <div class="col-sm-10 col-sm-offset-2"> - <button class="btn btn-default" ng-click="isAdvancedClosed = !isAdvancedClosed">{{'views.advanced' | translate}}</button> - </div> - </div> - <div collapse="isAdvancedClosed"> - <div class="form-group"> - <div class="col-sm-10 col-sm-offset-2"> - <div class="checkbox"> - <label> - <input type="checkbox" ng-model='instance.visible'> {{'views.visible' | translate}} - </label> - </div> - </div> - </div> - <div class="form-group"> - <div class="col-sm-10 col-sm-offset-2"> - <label for="" class="control-label col-sm-2">{{'views.icon' | translate}}</label> - <div class="col-sm-10"> - <input type="text" class="form-control" name="iconUrl" ng-model="instance.icon_path"> - </div> - </div> - </div> - <div class="form-group"> - <div class="col-sm-10 col-sm-offset-2"> - <label for="" class="control-label col-sm-2">{{'views.icon64' | translate}}</label> - <div class="col-sm-10"> - <input type="text" class="form-control" name="icon64Url" ng-model="instance.icon64_path"> - </div> - </div> - </div> - </div> - </div> + <div class="form-group" ng-class="{ 'has-error': form.instanceCreateForm.displayName.$error.required && form.instanceCreateForm.submitted }"> + <label for="displayName"> + {{'views.displayName' | translate}}<span>*</span> + <i class="fa fa-question-circle" aria-hidden="true"></i> + </label> + <input type="text" class="form-control" required + name="displayName" + ng-model="formData.displayName" + id="displayName"> + <span class="help-block validation-block" ng-show='form.instanceCreateForm.displayName.$error.required && form.instanceCreateForm.submitted'> + {{'common.alerts.fieldRequired' | translate}} + </span> + </div> - <div class="panel panel-default"> - <div class="panel-heading"> - <h3 class="panel-title">{{'views.configuration' | translate}}</h3> - </div> - <div class="panel-body"> - <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">{{parameter.description}}</label> - <div class="col-sm-9"> - <input type="text" class="form-control" name="{{parameter.name}}" ng-required="parameter.required" ng-model="parameter.value"> - <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted'> - {{'common.alerts.fieldRequired' | translate}} - </div> - </div> - </div> + <div class="form-group" ng-class="{ 'has-error': form.instanceCreateForm.description.$error.required && form.instanceCreateForm.submitted }"> + <label for="description"> + {{'views.description' | translate}}<span>*</span> + <i class="fa fa-question-circle" aria-hidden="true"></i> + </label> + <input type="text" class="form-control" required + name="description" + ng-model="formData.description" + id="description"> + <span class="help-block validation-block" ng-show='form.instanceCreateForm.description.$error.required && form.instanceCreateForm.submitted'> + {{'common.alerts.fieldRequired' | translate}} + </span> + </div> + + <div class="form-group checkbox"> + <input type="checkbox" class="form-control" + name="visible" + ng-model="formData.visible" + id="visible"> + <label for="visible"> + {{'views.visible' | translate}} + <i class="fa fa-question-circle" aria-hidden="true"></i> + </label> + </div> + + <div class="h4">{{'views.clusterConfiguration' | translate}}</div> + <div class="form-group"> + <label for="clusterType"> + {{'views.createInstance.clusterType' | translate}}? + <i class="fa fa-question-circle" aria-hidden="true"></i> + </label> + <div> + <div class="btn-group" role="group" id="clusterType"> + <button type="button" class="btn btn-default" + ng-class="isLocalTypeChosen && 'active'" + ng-click="switchClusterType(true)"> + {{'common.local' | translate}} + </button> + <button type="button" class="btn btn-default" + ng-class="!isLocalTypeChosen && 'active'" + ng-click="switchClusterType(false)"> + {{'common.remote' | translate}} + </button> </div> </div> - + </div> + <div class="row"> + <div class="form-group col-sm-6" ng-class="{ 'has-error': form.instanceCreateForm.clusterName.$error.required && form.instanceCreateForm.submitted }"> + <label for="clusterName"> + {{'views.clusterName' | translate}}<span>*</span> + <i class="fa fa-question-circle" aria-hidden="true"></i> + </label> + <select + required + name="clusterName" + ng-options="item.label for item in clusterOptions" + class="form-control" + ng-model="formData.clusterName" + id="clusterName"> + </select> + <span class="help-block validation-block" ng-show='form.instanceCreateForm.clusterName.$error.required && form.instanceCreateForm.submitted'> + {{'common.alerts.fieldRequired' | translate}} + </span> + </div> + </div> +</div> +<div ng-if="isLoading" class="spinner-container"> + <i class="fa fa-2x fa-spinner fa-spin" aria-hidden="true"></i> </div> <div class="modal-footer"> <button class="btn btn-default" ng-click="cancel()">{{'common.controls.cancel' | translate}}</button> http://git-wip-us.apache.org/repos/asf/ambari/blob/dd0421a2/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/edit.html ---------------------------------------------------------------------- diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/edit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/edit.html deleted file mode 100644 index aab526e..0000000 --- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/modals/edit.html +++ /dev/null @@ -1,138 +0,0 @@ -<!-- -* 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. ---> - -<div class="modal-header"> - <h3 class="modal-title">{{'views.edit' | translate}} {{instance.ViewInstanceInfo.view_name}}: {{instance.ViewInstanceInfo.label}}</h3> -</div> -<div class="modal-body"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> - <h3 class="panel-title pull-left">{{'views.settings' | translate}}</h3> - <div class="pull-right"> - <a href ng-click="edit.editSettingsDisabled = !edit.editSettingsDisabled" ng-show="edit.editSettingsDisabled"> <span class="glyphicon glyphicon-cog"></span> {{'views.edit' | translate}}</a> - </div> - </div> - <div class="panel-body"> - <form class="form-horizontal"> - <fieldset ng-disabled="edit.editSettingsDisabled"> - <div class="form-group"> - <label for="" class="col-sm-2 control-label">{{'views.instanceId' | translate}}</label> - <label for="" class="col-sm-10 control-label text-left">{{instance.ViewInstanceInfo.instance_name}}</label> - </div> - <div class="form-group"> - <label for="" class="col-sm-2 control-label">{{'views.displayName' | translate}}</label> - <div class="col-sm-10"><input type="text" class="form-control" placeholder="{{'views.displayName' | translate}}" ng-model="settings.label"></div> - </div> - <div class="form-group"> - <div class="col-sm-offset-2 col-sm-10"> - <div class="checkbox"> - <label> - <input type="checkbox" ng-model="settings.visible"> {{'views.visible' | translate}} - </label> - </div> - </div> - </div> - <div class="form-group" ng-hide="edit.editSettingsDisabled"> - <div class="col-sm-offset-2 col-sm-10"> - <button class="btn btn-default pull-right left-margin" ng-click="cancelSettings()">{{'common.controls.cancel' | translate}}</button> - <button class="btn btn-primary pull-right" ng-click="saveSettings()">{{'common.controls.save' | translate}}</button> - </div> - </div> - </fieldset> - </form> - </div> - </div> - - <div class="panel panel-default views-permissions-panel" style=""> - <div class="panel-heading clearfix"> - <h3 class="panel-title pull-left">{{'views.permissions' | translate}}</h3> - <div class="pull-right"> - <a href ng-click="edit.editPermissionDisabled = !edit.editPermissionDisabled" ng-show="edit.editPermissionDisabled"> <span class="glyphicon glyphicon-cog"></span> {{'views.edit' | translate}}</a> - </div> - </div> - <div class="panel-body"> - <form class="form-horizontal"> - <div class="form-group"> - <div class="col-sm-2"></div> - <label class="col-sm-5 control-label text-left">{{'common.users' | translate}}</label> - <label class="col-sm-5 control-label text-left">{{'common.groups' | translate}}</label> - </div> - <div class="form-group" ng-repeat="permission in permissions"> - <label class="col-sm-2 control-label">{{permission.PermissionInfo.permission_name}}</label> - <div class="col-sm-5" ng-switch="edit.editPermissionDisabled"> - <textarea name="" id="" cols="30" rows="4" class="form-control" ng-model="permissionsEdit[permission.PermissionInfo.permission_name].USER" ng-switch-when="false"></textarea> - <div class="well" ng-switch-when="true"> - <span ng-repeat="user in permission.USER"> - <link-to route="users.show" id="{{user}}">{{user}}</link-to> - <button type="button" class="close remove-button" - ng-click="removePermission(permission.name, 'USER', user)"><span aria-hidden="true">×</span><span class="sr-only">{{'common.controls.close' | translate}}</span></button> - {{$last ? '' :', '}} - </span> - </div> - </div> - <div class="col-sm-5" ng-switch="edit.editPermissionDisabled"> - <textarea name="" id="" cols="30" rows="4" class="form-control" ng-model="permissionsEdit[permission.PermissionInfo.permission_name].GROUP" ng-switch-when="false"></textarea> - <div class="well" ng-switch-when="true"> - <span ng-repeat="group in permission.GROUP"> - <link-to route="groups.edit" id="{{group}}" >{{group}}</link-to> - <button type="button" class="close remove-button" - ng-click="removePermission(permission.name, 'GROUP', group)"><span aria-hidden="true">×</span><span class="sr-only">{{'common.controls.close' | translate}}</span></button> - {{$last ? '' :', '}} - </span> - </div> - </div> - </div> - <div class="form-group" ng-hide="edit.editPermissionDisabled"> - <div class="col-sm-offset-2 col-sm-10"> - <button class="btn btn-default pull-right left-margin" ng-click="cancelPermissions()">{{'common.controls.cancel' | translate}}</button> - <button class="btn btn-primary pull-right" ng-click="savePermissions()">{{'common.controls.save' | translate}}</button> - </div> - </div> - </form> - - </div> - </div> - - <div class="panel panel-default"> - <div class="panel-heading clearfix"> - <h3 class="panel-title pull-left">{{'views.configuration' | translate}}</h3> - <div class="pull-right"> - <a href ng-click="edit.editConfigurationDisabled = !edit.editConfigurationDisabled" ng-show="edit.editConfigurationDisabled"> <span class="glyphicon glyphicon-cog"></span> {{'views.edit' | translate}}</a> - </div> - </div> - <div class="panel-body"> - <form action="" class="form-horizontal"> - <fieldset ng-disabled="edit.editConfigurationDisabled"> - <div class="form-group" ng-repeat="(propertyName, propertyValue) in configuration"> - <label for="" class="control-label col-sm-3">{{propertyName}}</label> - <div class="col-sm-9"><input type="text" class="form-control" ng-model="configuration[propertyName]"></div> - </div> - <div class="form-group" ng-hide="edit.editConfigurationDisabled"> - <div class="col-sm-offset-2 col-sm-10"> - <button class="btn btn-default pull-right left-margin" ng-click="cancelConfiguration()">{{'common.controls.cancel' | translate}}</button> - <button class="btn btn-primary pull-right" ng-click="saveConfiguration()">{{'common.controls.save' | translate}}</button> - </div> - </div> - </fieldset> - </form> - </div> - </div> -</div> -<div class="modal-footer"> - <button class="btn btn-default" ng-click="close()">{{'common.controls.save' | translate}}</button> -</div>
