You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by xi...@apache.org on 2014/05/19 20:58:55 UTC
git commit: AMBARI-5715. Usability: Ability to edit local repo urls
in the UI - post install.(xiwang)
Repository: ambari
Updated Branches:
refs/heads/trunk 742f5af65 -> 8b1d76cdf
AMBARI-5715. Usability: Ability to edit local repo urls in the UI - post install.(xiwang)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/8b1d76cd
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/8b1d76cd
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/8b1d76cd
Branch: refs/heads/trunk
Commit: 8b1d76cdf4e0d8e54ba157411d997a4e1e00bc3d
Parents: 742f5af
Author: Xi Wang <xi...@apache.org>
Authored: Fri May 16 11:35:25 2014 -0700
Committer: Xi Wang <xi...@apache.org>
Committed: Mon May 19 11:50:47 2014 -0700
----------------------------------------------------------------------
.../app/controllers/main/admin/cluster.js | 7 +-
ambari-web/app/messages.js | 9 +
ambari-web/app/styles/application.less | 114 ++++++++++
ambari-web/app/templates/common/modal_popup.hbs | 3 +
ambari-web/app/templates/main/admin/cluster.hbs | 80 +++++--
ambari-web/app/views/common/modal_popup.js | 6 +
ambari-web/app/views/main/admin/cluster.js | 218 ++++++++++++++++++-
7 files changed, 411 insertions(+), 26 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b1d76cd/ambari-web/app/controllers/main/admin/cluster.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/cluster.js b/ambari-web/app/controllers/main/admin/cluster.js
index 7a348b1..6e105da 100644
--- a/ambari-web/app/controllers/main/admin/cluster.js
+++ b/ambari-web/app/controllers/main/admin/cluster.js
@@ -22,7 +22,7 @@ var stringUtils = require('utils/string_utils');
App.MainAdminClusterController = Em.Controller.extend({
name:'mainAdminClusterController',
services: [],
- repositories: [],
+ allRepos: [],
upgradeVersion: '',
/**
* get the newest version of HDP from server
@@ -98,6 +98,9 @@ App.MainAdminClusterController = Em.Controller.extend({
baseUrl: repository.Repositories.base_url,
osType: osType,
repoId: repository.Repositories.repo_id,
+ repoName : repository.Repositories.repo_name,
+ stackName : repository.Repositories.stack_name,
+ stackVersion : repository.Repositories.stack_version,
isFirst: false
});
var group = allRepos.findProperty('name', osType);
@@ -113,7 +116,7 @@ App.MainAdminClusterController = Em.Controller.extend({
});
}, this);
allRepos.stackVersion = App.get('currentStackVersionNumber');
- this.set('repositories', allRepos);
+ this.set('allRepos', allRepos);
},
loadRepositoriesErrorCallback: function(request, ajaxOptions, error) {
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b1d76cd/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index ca273c7..7df4930 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -116,6 +116,7 @@ Em.I18n.translations = {
'common.component':'Component',
'common.quickLinks':'Quick Links',
'common.save':'Save',
+ 'common.saveAnyway':'Save Anyway',
'common.servers':'Servers',
'common.clients':'Clients',
'common.user': 'User',
@@ -163,6 +164,7 @@ Em.I18n.translations = {
'common.startTime': 'Start Time',
'common.duration': 'Duration',
'common.reinstall': 'Re-Install',
+ 'common.revert': 'Revert',
'common.errorPopup.header': 'An error has been encountered',
'common.use': 'Use',
'common.stacks': 'Stacks',
@@ -1024,6 +1026,13 @@ Em.I18n.translations = {
'admin.cluster.repositories.repositories':'Repositories',
'admin.cluster.repositories.os':'OS',
'admin.cluster.repositories.baseUrl':'Base URL',
+ 'admin.cluster.repositories.popup.header.success':'Repo Base URLs Saved',
+ 'admin.cluster.repositories.popup.header.fail':'Base URL Validation Failed',
+ 'admin.cluster.repositories.popup.body.success':'The Repo Base URL has been saved successfully.',
+ 'admin.cluster.repositories.popup.body.fail':'The Base URL failed validation and has not been saved.',
+ 'admin.cluster.repositories.invalidURLAttention': '<b>Attention:</b> Please make sure all repository URLs are valid before saving.',
+ 'admin.cluster.repositories.emptyURLattention':'<b>Attention:</b> Repository URLs are REQUIRED before you can save.',
+ 'admin.cluster.repositories.skipValidation.tooltip':'<b>Warning:</b> This is for advanced users only. Use this option if you want to skip validation for Repository Base URLs.',
'admin.misc.header': 'Service Users and Groups',
'admin.misc.nothingToShow': 'No user accounts to display',
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b1d76cd/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index a251225..aac13a4 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -5853,6 +5853,8 @@ i.icon-asterisks {
}
.accordion-body {
.repositories-table {
+ overflow: auto;
+ margin-bottom: 10px;
div {
float: left;
min-height: 1px;
@@ -5954,6 +5956,118 @@ i.icon-asterisks {
}
}
+.admin-cluster {
+ .repositories-table {
+ margin-bottom: 10px;
+ border: 1px solid #dddddd;
+ overflow: auto;
+ div {
+ float: left;
+ min-height: 1px;
+ }
+ .thead {
+ width: 100%;
+ .th {
+ font-weight: bold;
+ padding: 8px;
+ }
+ .os-th {
+ width: 10%;
+ }
+ .name-th {
+ width: 16%;
+ }
+ .url-th {
+ width: 66%;
+ }
+ }
+ .tbody {
+ width: 100%;
+ .trow {
+ width: 100%;
+ border-top: 1px solid #dddddd;
+ padding-top: 8px;
+ .os-td {
+ padding-top: 4px;
+ padding-left: 8px;
+ width: 9%;
+ }
+ .sub-trow {
+ width: 100%;
+ min-height: 39px;
+ .name-td {
+ width: 16%;
+ padding-top: 4px;
+ }
+ .url-td {
+ width: 60%;
+ .ember-text-field {
+ width: 100%;
+ }
+ }
+ .url-text-td {
+ width: 70%;
+ padding-top: 4px;
+ padding-left: 3px;
+ overflow: scroll;
+ }
+ .edit-td {
+ width: 8%;
+ padding-top: 4px;
+ padding-left: 5px;
+ a {
+ cursor: pointer;
+ }
+ }
+ .edit-buttons-td {
+ // save or cancel
+ width: 9%;
+ }
+ .clear-td {
+ width: 3%;
+ padding-top: 5px;
+ padding-left: 12px;
+ a {
+ cursor: pointer;
+ text-decoration: none;
+ }
+ .icon-remove-sign {
+ color: #808080;
+ }
+ }
+ }
+ }
+ }
+ .textfield-error input {
+ border-color: #b94a48;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ }
+ .disabled-textfield input {
+ color: #808080;
+ disabled: disabled;
+ pointer-events: none;
+ cursor: default;
+ background: #E4E4E4;
+ }
+ .disabled-label {
+ color: #808080;
+ }
+ }
+ #skip-validation {
+ margin-top: 10px;
+ .checkbox {
+ margin-left: 3px;
+ margin-right: 8px;
+ margin-top: 0px;
+ }
+ .icon-question-sign {
+ color: @blue;
+ }
+ }
+}
+
#config-group-select-create-dialog {
.select-create-config-group-div {
margin-left: 20px;
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b1d76cd/ambari-web/app/templates/common/modal_popup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/modal_popup.hbs b/ambari-web/app/templates/common/modal_popup.hbs
index 65a95d7..c2326d4 100644
--- a/ambari-web/app/templates/common/modal_popup.hbs
+++ b/ambari-web/app/templates/common/modal_popup.hbs
@@ -51,6 +51,9 @@
<label id="footer-checkbox">{{view Ember.Checkbox classNames="checkbox" checkedBinding="view.isNotShowBgChecked"}}
{{t app.settings.notShowBgOperations}}</label>
{{/if}}
+ {{#if view.third}}
+ <button class="btn" {{bindAttr disabled="view.disableThird"}} {{action onThird target="view"}}>{{view.third}}</button>
+ {{/if}}
{{#if view.secondary}}
<button class="btn" {{bindAttr disabled="view.disableSecondary"}} {{action onSecondary target="view"}}>{{view.secondary}}</button>
{{/if}}
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b1d76cd/ambari-web/app/templates/main/admin/cluster.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/admin/cluster.hbs b/ambari-web/app/templates/main/admin/cluster.hbs
index 771b261..b38b28c 100644
--- a/ambari-web/app/templates/main/admin/cluster.hbs
+++ b/ambari-web/app/templates/main/admin/cluster.hbs
@@ -56,30 +56,66 @@
</div>
<ul class="nav nav-tabs">
<li class="active">
- <a href="javascript:void(null);">{{repositories.stackVersion}}</a>
+ <a href="javascript:void(null);">{{view.allRepositoriesGroups.stackVersion}}</a>
</li>
</ul>
- <table class="table table-bordered">
- <thead>
- <tr>
- <th>{{t admin.cluster.repositories.os}}</th>
- <th>{{t common.name}}</th>
- <th>{{t admin.cluster.repositories.baseUrl}}</th>
- </tr>
- </thead>
- <tbody>
- {{#each repoGroup in repositories}}
- {{#each repo in repoGroup.repositories}}
- <tr>
- {{#if repo.isFirst}}
- <td {{bindAttr rowspan="repoGroup.repositories.length"}}>{{repo.osType}}</td>
- {{/if}}
- <td>{{repo.repoId}}</td>
- <td>{{repo.baseUrl}}</td>
- </tr>
- {{/each}}
+ <div class="repositories-table">
+ <div class="thead">
+ <div class="th os-th">{{t common.os}}</div>
+ <div class="th name-th">{{t common.name}}</div>
+ <div class="th url-th">{{t installer.step1.advancedRepo.localRepo.column.baseUrl}}</div>
+ </div>
+ <div class="tbody">
+ {{#each repoGroup in view.allRepositoriesGroups}}
+ <div class="trow">
+ <div class="os-td">
+ <label>
+ <span class="os">{{repoGroup.name}}</span>
+ </label>
+ </div>
+ <div style="width:89%">
+ {{#each repository in repoGroup.repositories}}
+ <div class="sub-trow">
+ <div class="name-td">{{repository.repoId}}</div>
+ <!--edit mode for current url-->
+ {{#if repository.onEdit}}
+ <div {{bindAttr class=":url-td repository.empty-error:textfield-error repository.invalid-error:textfield-error"}}>
+ {{view Ember.TextField valueBinding="repository.baseUrl"}}
+ </div>
+ <div class="clear-td">
+ {{#if repository.clearAll}}
+ <a {{action "clearGroupLocalRepository" repository target="view" }}>
+ <i class="icon-remove-sign"></i>
+ </a>
+ {{/if}}
+ </div>
+ <div class="edit-buttons-td">
+ <a class="btn" {{action doCancel repository target="view"}}>{{t common.cancel}}</a>
+ </div>
+ <div class="edit-buttons-td">
+ {{#if repository.empty-error}}
+ <a class="btn btn-primary" disabled="disabled">{{t common.save}}</a>
+ {{else}}
+ <a class="btn btn-primary" {{action saveRepoUrls repository target="view"}}>{{t common.save}}</a>
+ {{/if}}
+ </div>
+ <!--non-edit mode for current url-->
+ {{else}}
+ <div class="url-text-td">
+ {{repository.baseUrl}}
+ </div>
+ <div class="edit-td">
+ <a {{action "onEditClick" repository target="view" }}>
+ <i class="icon-edit"></i> {{t common.edit}}
+ </a>
+ </div>
+ {{/if}}
+ </div>
+ {{/each}}
+ </div>
+ </div>
{{/each}}
- </tbody>
- </table>
+ </div>
+ </div>
</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b1d76cd/ambari-web/app/views/common/modal_popup.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/modal_popup.js b/ambari-web/app/views/common/modal_popup.js
index 9be6050..550af3c 100644
--- a/ambari-web/app/views/common/modal_popup.js
+++ b/ambari-web/app/views/common/modal_popup.js
@@ -28,9 +28,11 @@ App.ModalPopup = Ember.View.extend({
// define bodyClass which extends Ember.View to use an arbitrary Handlebars template as the body
primary: Em.I18n.t('ok'),
secondary: Em.I18n.t('common.cancel'),
+ third: null,
autoHeight: true,
disablePrimary: false,
disableSecondary: false,
+ disableThird: false,
primaryClass: 'btn-success',
onPrimary: function () {
this.hide();
@@ -40,6 +42,10 @@ App.ModalPopup = Ember.View.extend({
this.hide();
},
+ onThird: function () {
+ this.hide();
+ },
+
onClose: function () {
this.hide();
},
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b1d76cd/ambari-web/app/views/main/admin/cluster.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/admin/cluster.js b/ambari-web/app/views/main/admin/cluster.js
index 3c26f03..44ae19b 100644
--- a/ambari-web/app/views/main/admin/cluster.js
+++ b/ambari-web/app/views/main/admin/cluster.js
@@ -24,5 +24,219 @@ App.MainAdminClusterView = Em.View.extend({
isUpgradeAvailable: function(){
return stringUtils.compareVersions(this.get('controller.upgradeVersion').replace(/HDP(Local)?-/, ''), App.get('currentStackVersionNumber')) === 1;
- }.property('controller.upgradeVersion', 'App.currentStackVersion')
-});
\ No newline at end of file
+ }.property('controller.upgradeVersion', 'App.currentStackVersion'),
+
+ didInsertElement: function () {
+ this.get('controller').loadRepositories();
+ },
+
+ /**
+ * List of all repo-groups
+ * @type {Object[][]}
+ */
+ allRepositoriesGroups: function () {
+ var repos = this.get('controller.allRepos');
+ var reposGroup = [];
+ var repositories = [];
+ reposGroup.set('stackVersion', App.get('currentStackVersionNumber'));
+ if (repos) {
+ repos.forEach(function (group) {
+ group.repositories.forEach (function(repo) {
+ var cur_repo = Em.Object.create({
+ 'repoId': repo.repoId,
+ 'id': repo.repoId + '-' + repo.osType,
+ 'repoName' : repo.repoName,
+ 'stackName' : repo.stackName,
+ 'stackVersion' : repo.stackVersion,
+ 'baseUrl': repo.baseUrl,
+ 'originalBaseUrl': repo.baseUrl,
+ 'osType': repo.osType,
+ 'onEdit': false,
+ 'empty-error': !repo.baseUrl,
+ 'undo': false,
+ 'clearAll': repo.baseUrl
+ });
+ var cur_group = reposGroup.findProperty('name', group.name);
+ if (!cur_group) {
+ var cur_group = Ember.Object.create({
+ name: group.name,
+ repositories: []
+ });
+ reposGroup.push(cur_group);
+ }
+ cur_group.repositories.push(cur_repo);
+ repositories.push(cur_repo);
+ });
+ });
+ }
+ this.set('allRepos', repositories);
+ return reposGroup;
+ }.property('controller.allRepos'),
+
+ /**
+ * Onclick handler for edit action of each repo, enter edit mode
+ * @param {object} event
+ */
+ onEditClick:function (event) {
+ var targetRepo = this.get('allRepos').findProperty('id', event.context.get('id'));
+ if (targetRepo) {
+ targetRepo.set('onEdit', true);
+ }
+ },
+
+ /**
+ * Onclick handler for undo action of each repo group
+ * @method undoGroupLocalRepository
+ * @param {object} event
+ */
+ undoGroupLocalRepository: function (event) {
+ this.doActionForGroupLocalRepository(event, 'originalBaseUrl');
+ },
+
+ /**
+ * Handler for clear icon click
+ * @method clearGroupLocalRepository
+ * @param {object} event
+ */
+ clearGroupLocalRepository: function (event) {
+ this.doActionForGroupLocalRepository(event, '');
+ },
+
+ /**
+ * Common handler for repo groups actions
+ * @method doActionForGroupLocalRepository
+ * @param {object} event
+ * @param {string} newBaseUrlField
+ */
+ doActionForGroupLocalRepository: function (event, newBaseUrlField) {
+ var targetRepo = this.get('allRepos').findProperty('id', event.context.get('id'));
+ if (targetRepo) {
+ targetRepo.set('baseUrl', Em.isEmpty(newBaseUrlField) ? '' : Em.get(targetRepo, newBaseUrlField));
+ }
+ },
+
+ /**
+ * Handler when editing any repo group BaseUrl
+ * @method editGroupLocalRepository
+ */
+ editGroupLocalRepository: function (event) {
+ var repos = this.get('allRepos');
+ repos.forEach(function (targetRepo) {
+ targetRepo.set('undo', targetRepo.get('baseUrl') != targetRepo.get('originalBaseUrl'));
+ targetRepo.set('clearAll', targetRepo.get('baseUrl'));
+ targetRepo.set('empty-error', !targetRepo.get('baseUrl'));
+
+ });
+ }.observes('allRepos.@each.baseUrl'),
+
+ /**
+ * onSuccess callback for save Repo URL.
+ */
+ doSaveRepoUrlsSuccessCallback: function (response, request, data) {
+ var id = data.repoId + '-' + data.osType;
+ console.log('Success in check Repo URL. data repoId+osType: ' + id);
+ var targetRepo = this.get('allRepos').findProperty('id', id);
+ if (!targetRepo) {
+ return;
+ } else {
+ App.ModalPopup.show({
+ header: Em.I18n.t('admin.cluster.repositories.popup.header.success'),
+ secondary: null,
+ onPrimary: function () {
+ this.hide();
+ targetRepo.set('baseUrl', data.data.Repositories.base_url);
+ targetRepo.set('originalBaseUrl', data.data.Repositories.base_url);
+ targetRepo.set('onEdit', false);
+ },
+ message: Em.I18n.t('admin.cluster.repositories.popup.body.success'),
+ bodyClass: Em.View.extend({
+ template: Em.Handlebars.compile('<div class="alert alert-success">{{{message}}}</div>')
+ })
+ })
+ }
+ },
+
+ /**
+ * onError callback for save Repo URL.
+ */
+ doSaveRepoUrlsErrorCallback: function (request, ajaxOptions, error, data) {
+ console.log('Error in check Repo URL. The baseURL sent is: ' + data.data);
+ var self = this;
+ var id = data.url.split('/')[10] + '-' + data.url.split('/')[8];
+ var targetRepo = this.get('allRepos').findProperty('id', id);
+ if (!targetRepo) {
+ return;
+ } else {
+ App.ModalPopup.show({
+ header: Em.I18n.t('admin.cluster.repositories.popup.header.fail'),
+ primary: Em.I18n.t('common.saveAnyway'),
+ secondary: Em.I18n.t('common.revert'),
+ third: Em.I18n.t('common.cancel'),
+ onPrimary: function () {
+ // save anyway: Go ahead and save with Repo URL validation turned off and close Dialog when done.
+ this.hide();
+ self.doSaveRepoUrls(id, false);
+ },
+ onSecondary: function () {
+ // Revert: Close dialog, revert URL value, go back to non-Edit mode
+ this.hide();
+ targetRepo.set('baseUrl', targetRepo.get('originalBaseUrl'));
+ targetRepo.set('onEdit', false);
+ },
+ onThird: function () {
+ // cancel: Close dialog but stay in Edit mode
+ this.hide();
+ },
+ message: Em.I18n.t('admin.cluster.repositories.popup.body.fail'),
+ bodyClass: Em.View.extend({
+ template: Em.Handlebars.compile('<div class="alert alert-warning">{{{message}}}</div>')
+ })
+ })
+ }
+ },
+
+ /**
+ * Check validation and Save the customized local urls
+ */
+ doSaveRepoUrls: function (id, verifyBaseUrl) {
+ var targetRepo = this.get('allRepos').findProperty('id', id);
+ var verifyBaseUrl = verifyBaseUrl;
+ App.ajax.send({
+ name: 'wizard.advanced_repositories.valid_url',
+ sender: this,
+ data: {
+ stackName: targetRepo.stackName,
+ stackVersion: targetRepo.stackVersion,
+ repoId: targetRepo.repoId,
+ osType: targetRepo.osType,
+ data: {
+ 'Repositories': {
+ 'base_url': targetRepo.baseUrl,
+ "verify_base_url": verifyBaseUrl
+ }
+ }
+ },
+ success: 'doSaveRepoUrlsSuccessCallback',
+ error: 'doSaveRepoUrlsErrorCallback'
+ });
+ },
+ /**
+ * Check validation and Save the customized local urls
+ */
+ saveRepoUrls: function (event) {
+ this.doSaveRepoUrls(event.context.get('id'), true);
+ },
+
+ /**
+ * on click handler 'Cancel' for current repo in edit mode
+ */
+ doCancel: function (event) {
+ var targetRepo = this.get('allRepos').findProperty('id', event.context.get('id'));
+ if (targetRepo) {
+ targetRepo.set('baseUrl', targetRepo.get('originalBaseUrl'));
+ targetRepo.set('onEdit', false);
+ }
+ }
+
+});
+