You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by mr...@apache.org on 2017/11/27 23:29:35 UTC
[23/30] ambari git commit: Merge trunk with feature branch and fix
some UT compilation issues (mradhakrishnan)
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
index 85d659d..da1ab3f 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
@@ -119,14 +119,14 @@
</div>
<div id="upload-definition-file-panel" ng-if="createController">
- <div class="col-sm-12 big-radio clearfix hide-soft" ng-class="{'disabled' : networkLost || useRedhatSatellite,'visible':stackRepoUpdateLinkExists}">
- <input type="radio" ng-model="selectedOption.index" value="1" ng-change="togglePublicLocalOptionSelect()" ng-disabled="networkLost || useRedhatSatellite">
- <span>{{'versions.usePublic' | translate}}</span>
+ <div class="checkbox col-sm-12 big-radio clearfix hide-soft" ng-class="{'disabled' : networkLost || useRedhatSatellite,'visible':stackRepoUpdateLinkExists}">
+ <input id="use-public" type="radio" ng-model="selectedOption.index" value="1" ng-change="togglePublicLocalOptionSelect()" ng-disabled="networkLost || useRedhatSatellite">
+ <label for="use-public">{{'versions.usePublic' | translate}}</label>
<a id="public-disabled-link" href="javascript:void(0);" ng-if="networkLost" ng-click="showPublicRepoDisabledDialog()">{{'versions.networkIssues.networkLost'| translate}}</a>
</div>
- <div class="col-sm-12 big-radio clearfix">
- <input type="radio" ng-model="selectedOption.index" value="2" ng-change="togglePublicLocalOptionSelect()">
- {{'versions.useLocal' | translate}}
+ <div class="checkbox col-sm-12 big-radio clearfix">
+ <input id="use-local" type="radio" ng-model="selectedOption.index" value="2" ng-change="togglePublicLocalOptionSelect()">
+ <label for="use-local">{{'versions.useLocal' | translate}}</label>
</div>
</div>
@@ -181,20 +181,22 @@
<div class="col-sm-9">
<div class="form-group repo-name-url {{repository.Repositories.repo_name}}"
ng-class="{'has-error': repository.hasError }" ng-repeat="repository in os.repositories">
- <span class="repo-name-label control-label col-sm-3">{{repository.Repositories.repo_id}}</span>
- <div class="col-sm-7 repo-url">
- <input type="text" class="form-control"
- placeholder="{{(repository.Repositories.repo_name.indexOf('UTILS') < 0 )?('versions.repository.placeholder' | translate) : ''}}"
- ng-model="repository.Repositories.base_url"
- ng-change="onRepoUrlChange(repository)" ng-disabled="useRedhatSatellite">
+ <div ng-if="showRepo(repository)">
+ <span class="repo-name-label control-label col-sm-3">{{repository.Repositories.repo_id}}</span>
+ <div class="col-sm-7 repo-url">
+ <input type="text" class="form-control"
+ placeholder="{{(repository.Repositories.repo_name.indexOf('UTILS') < 0 )?('versions.repository.placeholder' | translate) : ''}}"
+ ng-model="repository.Repositories.base_url"
+ ng-change="onRepoUrlChange(repository)" ng-disabled="useRedhatSatellite">
+ </div>
+ <i class="fa fa-undo orange-icon cursor-pointer"
+ ng-if="selectedOption.index == 1 && repository.Repositories.base_url != repository.Repositories.initial_base_url
+ || selectedOption.index == 2 && repository.Repositories.base_url != ''
+ || editController && repository.Repositories.base_url != repository.Repositories.initial_base_url"
+ ng-click="undoChange(repository)"
+ tooltip-html-unsafe="{{'common.undo' | translate}}"
+ aria-hidden="true"></i>
</div>
- <i class="fa fa-undo orange-icon cursor-pointer"
- ng-if="selectedOption.index == 1 && repository.Repositories.base_url != repository.Repositories.initial_base_url
- || selectedOption.index == 2 && repository.Repositories.base_url != ''
- || editController && repository.Repositories.base_url != repository.Repositories.initial_base_url"
- ng-click="undoChange(repository)"
- tooltip-html-unsafe="{{'common.undo' | translate}}"
- aria-hidden="true"></i>
</div>
</div>
<div class="col-sm-1 remove-icon" ng-click="removeOS()" ng-class="{'disabled' : useRedhatSatellite}"><i
@@ -204,22 +206,21 @@
</div>
</div>
<div class="clearfix advanced-radio-buttons">
- <div class="col-sm-9" id="skip-validation">
+ <div class="col-sm-9">
<div class="checkbox">
- <label>
- <input type="checkbox" ng-model="skipValidation" ng-change="clearErrors()"
- ng-disabled="useRedhatSatellite">
+ <input type="checkbox" id="skip-validation" ng-model="skipValidation" ng-change="clearErrors()" ng-disabled="useRedhatSatellite">
+ <label for="skip-validation">
<span ng-class="{'disabled' : useRedhatSatellite}">{{'versions.skipValidation' | translate}}</span>
<i class="fa fa-question-circle"
tooltip-html-unsafe="{{'versions.alerts.skipValidationWarning' | translate}}" aria-hidden="true"></i>
</label>
</div>
</div>
- <div class="col-sm-9" id="use-redhat">
+ <div class="col-sm-9">
<div class="checkbox">
- <label>
- <input type="checkbox" ng-model="useRedhatSatellite" ng-change="clearErrors()"
- ng-disabled="isPublicRepoSelected()">
+ <input type="checkbox" id="use-redhat" ng-model="useRedhatSatellite" ng-change="clearErrors()"
+ ng-disabled="isPublicRepoSelected()">
+ <label for="use-redhat">
<span ng-class="{'disabled' : isPublicRepoSelected()}"
tooltip="{{(isPublicRepoSelected())? ('versions.useRedhatSatellite.disabledMsg' | translate) : ''}}">{{'versions.useRedhatSatellite.title' | translate}}</span>
<i class="fa fa-question-circle"
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html
index 0c9e1b9..dbd1021 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/create.html
@@ -16,7 +16,6 @@
* limitations under the License.
-->
<ol class="breadcrumb">
- <li> <link-to route="views.listViewUrls">{{'urls.viewUrls' | translate}}</link-to></li>
<li class="active">{{'urls.createNewUrl' | translate}}</li>
</ol>
<hr>
@@ -25,9 +24,9 @@
<form class="form-horizontal create-user-form" role="form" novalidate name="formHolder.form" autocomplete="off">
<div class="form-group" ng-class="{'has-error' : formHolder.form.url_name.$error.required && formHolder.form.submitted}">
- <label for="urlname" class="col-sm-2 control-label">{{'urls.name' | translate}}</label>
+ <label for="urlname" class="col-sm-2 control-label">{{'common.name' | translate}}</label>
<div class="col-sm-10">
- <input ng-minlength="2" ng-maxlength="25" type="text" id="urlname" class="form-control urlname-input" name="url_name" placeholder="{{'urls.name' | translate}}" ng-model="url.urlName" required autocomplete="off">
+ <input ng-minlength="2" ng-maxlength="25" type="text" id="urlname" class="form-control urlname-input" name="url_name" placeholder="{{'common.name' | translate}}" ng-model="url.urlName" required autocomplete="off">
<div class="alert alert-danger top-margin" ng-show="formHolder.form.url_name.$error.required && formHolder.form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
<div class="alert alert-danger top-margin" ng-show="formHolder.form.url_name.$error.minlength && formHolder.form.submitted">{{'common.alerts.minimumTwoChars' | translate}}</div>
<div class="alert alert-danger top-margin" ng-show="formHolder.form.url_name.$error.maxlength && formHolder.form.submitted">{{'common.alerts.maxTwentyFiveChars' | translate}}</div>
@@ -68,7 +67,6 @@
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button ng-disabled="stepTwoNotCompleted" class="btn btn-primary pull-right left-margin saveuser" ng-click="saveUrl()">{{'common.controls.save' | translate}}</button>
- <link-to route="views.listViewUrls" class="btn btn-default pull-right cancel">{{'common.controls.cancel' | translate}}</link-to>
</div>
</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html
index 9198818..61366db 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/urls/edit.html
@@ -16,7 +16,6 @@
* limitations under the License.
-->
<ol class="breadcrumb">
- <li> <link-to route="views.listViewUrls">{{'urls.viewUrls' | translate}}</link-to></li>
<li class="active">{{'urls.edit' | translate}} {{url.url_name}}</li>
<div class="pull-right top-margin-4">
<button class="btn deleteuser-btn btn-danger" ng-click="deleteUrl()">{{'views.urlDelete' | translate}}</button>
@@ -27,9 +26,9 @@
<form class="form-horizontal create-user-form" role="form" novalidate name="url_form" autocomplete="off">
<div class="form-group" ng-class="{'has-error' : url_form.url_name.$error.required && url_form.submitted}">
- <label for="urlname" class="col-sm-2 control-label">{{'urls.name' | translate}}</label>
+ <label for="urlname" class="col-sm-2 control-label">{{'common.name' | translate}}</label>
<div class="col-sm-10">
- <input disabled type="text" id="urlname" class="form-control urlname-input" name="url_name" placeholder="{{'urls.name' | translate}}" ng-model="url.url_name" required autocomplete="off">
+ <input disabled type="text" id="urlname" class="form-control urlname-input" name="url_name" placeholder="{{'common.name' | translate}}" ng-model="url.url_name" required autocomplete="off">
<div class="alert alert-danger top-margin" ng-show="url_form.url_name.$error.required && url_form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
</div>
</div>
@@ -70,7 +69,6 @@
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button ng-disabled="stepTwoNotCompleted" class="btn btn-primary pull-right left-margin saveuser" ng-click="updateUrl()">{{'common.controls.save' | translate}}</button>
- <link-to route="views.listViewUrls" class="btn btn-default pull-right cancel">{{'common.controls.cancel' | translate}}</link-to>
</div>
</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
new file mode 100644
index 0000000..5656417
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
@@ -0,0 +1,122 @@
+<!--
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+-->
+
+<div id="group-edit">
+ <div class="clearfix">
+ <ol class="breadcrumb pull-left">
+ <li><a href="#/userManagement?tab=groups">{{'common.groups' | translate}}</a></li>
+ <li class="active">{{group.group_name}}</li>
+ </ol>
+ <div class="pull-right">
+ <div ng-switch="group.group_type != 'LOCAL'">
+ <button
+ ng-switch-when="true"
+ class="btn disabled deletegroup-btn"
+ tooltip="{{'common.cannotDelete' | translate: '{term: constants.group}'}}">
+ {{'common.delete' | translate: '{term: constants.group}'}}
+ </button>
+ <button ng-switch-when="false" class="btn btn-danger deletegroup-btn" ng-click="deleteGroup(group)">
+ {{'common.delete' | translate: '{term: constants.group}'}}
+ </button>
+ </div>
+ </div>
+ </div>
+
+ <form class="form-horizontal" role="form" novalidate name="form" >
+ <div class="form-group">
+ <label class="col-sm-2 control-label">{{'common.type' | translate}}</label>
+ <div class="col-sm-10">
+ <label class="control-label">{{group.groupTypeName | translate}}</label>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label">{{group.groupTypeName | translate}} {{'groups.members' | translate}}</label>
+ <div class="col-sm-10">
+ <editable-list items-source="group.editingUsers" resource-type="User" editable="group.group_type == 'LOCAL'"></editable-list>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="role" class="col-sm-2 roles-label">
+ {{'groups.role' | translate}}
+ <i class="fa fa-question-circle" aria-hidden="true" ng-click="showHelpPage()"></i>
+ </label>
+ <div class="col-sm-3">
+ <select class="form-control"
+ id="role"
+ name="role"
+ ng-change="updateRole()"
+ ng-options="item as item.permission_label for item in roleOptions track by item.permission_name"
+ ng-model="currentRole">
+ </select>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label">{{'common.privileges' | translate}}</label>
+ <div class="col-sm-10">
+ <table class="table" ng-hide="hidePrivileges">
+ <thead>
+ <tr>
+ <th>{{'common.cluster' | translate}}</th>
+ <th>{{'common.clusterRole' | translate}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr ng-repeat="(name, privilege) in privileges.clusters">
+ <td>
+ <span class="glyphicon glyphicon-cloud"></span>
+ <a href="#/clusters/{{name}}/manageAccess">{{name}}</a>
+ </td>
+ <td>
+ <span tooltip="{{item}}" ng-repeat="item in privilege">{{item | translate}}{{$last ? '' : ', '}}</span>
+ </td>
+ </tr>
+ <tr>
+ <td ng-show="noClusterPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.cluster}'}}</td>
+ </tr>
+ </tbody>
+ <thead class="view-permission-header">
+ <tr>
+ <th>{{'common.view' | translate}}</th>
+ <th>{{'common.viewPermissions' | translate}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr ng-repeat="(name, privilege) in privileges.views">
+ <td>
+ <span class="glyphicon glyphicon-th"></span>
+ <a href="#/views/{{privilege.view_name}}/versions/{{privilege.version}}/instances/{{name}}/edit">{{name}}</a>
+ </td>
+ <td>
+ <span tooltip="{{item}}" ng-repeat="item in privilege.privileges">{{item | translate}}{{$last ? '' : ', '}}</span>
+ </td>
+ <td>
+ <i class="fa fa-trash-o" aria-hidden="true" ng-click="removeViewPrivilege(name, privilege);"></i>
+ </td>
+ </tr>
+ <tr>
+ <td ng-show="noViewPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.view}'}}</td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="alert alert-info" ng-show="hidePrivileges">
+ {{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.group.toLowerCase()}'}}
+ </div>
+ </div>
+ </div>
+ </form>
+</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupsList.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupsList.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupsList.html
new file mode 100644
index 0000000..d79d14e
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupsList.html
@@ -0,0 +1,94 @@
+<!--
+* 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="groups-pane">
+ <div class="clearfix panel">
+ <button class="btn btn-default creategroup-btn pull-right" ng-click="createGroup()">
+ {{'groups.createLocal' | translate}}
+ </button>
+ </div>
+ <table class="table table-striped table-hover col-sm-12">
+ <thead>
+ <tr>
+ <th class="col-sm-6">
+ <span>{{'groups.name' | translate}}</span>
+ </th>
+ <th class="col-sm-2">
+ <span>{{'common.type' | translate}}</span>
+ </th>
+ <th class="col-sm-2">
+ <span>{{'groups.members' | translate}}</span>
+ </th>
+ <th class="col-sm-2">
+ <span>{{'common.actions' | translate}}</span>
+ </th>
+ </tr>
+ <tr>
+ <th class="col-sm-6">
+ <div class="search-container">
+ <input type="text" class="form-control namefilter" placeholder="{{'common.any' | translate}}" ng-model="filter.name" ng-change="resetPagination()">
+ <button type="button" class="close" ng-show="filter.name" ng-click="filter.name=''; resetPagination()"><span aria-hidden="true">×</span><span class="sr-only">{{'common.controls.close' | translate}}</span></button>
+ </div>
+ </th>
+ <th class="col-sm-2">
+ <select class="form-control typefilter"
+ ng-model="filter.type"
+ ng-options="item.label for item in typeFilterOptions"
+ ng-change="resetPagination();">
+ </select>
+ </th>
+ <th class="col-sm-2"></th>
+ <th class="col-sm-2"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr ng-repeat="group in groups">
+ <td class="col-sm-8">
+ <span>{{group.group_name}}</span>
+ </td>
+ <td class="col-sm-2">{{group.groupTypeName | translate}}</td>
+ <td class="col-sm-2">{{'groups.membersPlural' | translate: '{n: group.members && group.members.length || 0}'}}</td>
+ <td class="entity-actions">
+ <link-to route="userManagement.editGroup" class="link-to-group" id="{{group.group_name}}">
+ <i class="fa fa-pencil"></i>
+ </link-to>
+ <a href ng-click="deleteGroup(group)">
+ <i class="fa fa-trash-o"></i>
+ </a>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <div ng-if="isLoading" class="spinner-container">
+ <i class="fa fa-2x fa-spinner fa-spin" aria-hidden="true"></i>
+ </div>
+ <div class="alert empty-table-alert col-sm-12" ng-show="!groups.length && !isLoading">
+ {{'common.alerts.nothingToDisplay' | translate: '{term: constants.groups}'}}
+ </div>
+ <div class="col-sm-12 table-bar" ng-show="totalGroups > minRowsToShowPagination">
+ <div class="pull-left filtered-info">
+ <span>{{'common.filterInfo' | translate: '{showed: tableInfo.showed, total: tableInfo.total, term: constants.groups}'}}</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="totalGroups" max-size="maxVisiblePages" items-per-page="groupsPerPage" ng-model="currentPage" ng-change="pageChanged()"></pagination>
+ </div>
+ <div class="pull-right">
+ <select class="form-control" ng-model="groupsPerPage" ng-change="groupsPerPageChanges()" ng-options="currOption for currOption in [10, 25, 50, 100]"></select>
+ </div>
+ </div>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
new file mode 100644
index 0000000..8520fc2
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
@@ -0,0 +1,36 @@
+<!--
+* 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 id="user-management">
+ <ul class="nav nav-tabs">
+ <li ng-class="{active: activeTab === 'USERS'}">
+ <a href="#/userManagement?tab=users" >{{'common.users' | translate}}</a>
+ </li>
+ <li ng-class="{active: activeTab === 'GROUPS'}">
+ <a href="#/userManagement?tab=groups" >{{'common.groups' | translate}}</a>
+ </li>
+ </ul>
+ <div>
+ <div class="users" ng-if="activeTab === 'USERS'">
+ <div ng-include="'views/userManagement/usersList.html'" ng-controller="UsersListCtrl"></div>
+ </div>
+ <div class="groups" ng-if="activeTab === 'GROUPS'">
+ <div ng-include="'views/userManagement/groupsList.html'" ng-controller="GroupsListCtrl"></div>
+ </div>
+ </div>
+</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/changePassword.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/changePassword.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/changePassword.html
new file mode 100644
index 0000000..f29d315
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/changePassword.html
@@ -0,0 +1,46 @@
+<!--
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+-->
+<div class="modal-header">
+ <h3 class="modal-title">{{'users.changePasswordFor' | translate: '{userName: userName}'}}</h3>
+</div>
+<div class="modal-body">
+ <form class="form-horizontal" novalidate name="form.passwordChangeForm" role="form" >
+ <div class="form-group" ng-class="{'has-error' : (form.passwordChangeForm.currentPassword.$error.required && form.passwordChangeForm.submitted)}">
+ <label for="" class="col-sm-4 control-label" >{{'users.yourPassword' | translate}}</label>
+ <div class="col-sm-8">
+ <input type="password" name="currentPassword" class="form-control bottom-margin" placeholder="{{'users.yourPassword' | translate}}" required ng-model="passwordData.currentUserPassword" autocomplete="off">
+ <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted'>{{'users.alerts.passwordRequired' | translate}}</div>
+ </div>
+ </div>
+ <div class="form-group no-margin-bottom" ng-class="{'has-error' : (form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted) || form.passwordChangeForm.confirmPassword.$error.passwordVerify}">
+ <label for="" class="col-sm-4 control-label">{{'users.newPassword' | translate}}:</label>
+ <div class="col-sm-8">
+ <input type="password" class="form-control bottom-margin" name="password" placeholder="{{'users.newPassword' | translate}}" required ng-model="passwordData.password" autocomplete="off">
+ <input type="password" class="form-control bottom-margin" name="confirmPassword" placeholder="{{'users.newPasswordConfirmation' | translate}}" required ng-model="passwordData.passwordConfirmation"
+ password-verify="passwordData.password" autocomplete="off">
+ <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.confirmPassword.$error.passwordVerify'>{{'users.alerts.wrongPassword' | translate}}</div>
+ <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted'>{{'users.alerts.passwordRequired' | translate}}</div>
+ </div>
+
+ </div>
+ </form>
+</div>
+<div class="modal-footer">
+ <button class="btn btn-default" ng-click="cancel()">{{'common.controls.cancel' | translate}}</button>
+ <button class="btn btn-primary" ng-click="ok()">{{'common.controls.ok' | translate}}</button>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
new file mode 100644
index 0000000..e11b478
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
@@ -0,0 +1,86 @@
+<!--
+* 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.
+-->
+
+<form id="create-group-form" role="form" novalidate name="form.groupCreateForm">
+ <div class="modal-header">
+ <h1 class="modal-title">
+ {{'groups.createLocal' | translate}}
+ </h1>
+ </div>
+ <div class="modal-body">
+ <div class="form-group"
+ ng-class="{ 'has-error': (form.groupCreateForm.groupName.$error.required || form.groupCreateForm.groupName.$error.pattern) && form.groupCreateForm.submitted }">
+ <label for="groupName">
+ {{'groups.name' | translate}}<span> *</span>
+ </label>
+ <input type="text"
+ placeholder="{{'groups.name' | translate}}"
+ ng-pattern="/^([a-zA-Z0-9._\s]+)$/"
+ autofocus
+ ng-maxlength="80"
+ autocomplete="off"
+ class="form-control"
+ ng-model="formData.groupName"
+ name="groupName"
+ id="groupName"
+ ng-change="checkIfInstanceExist()"
+ required>
+ <span class="help-block validation-block"
+ ng-show='form.groupCreateForm.groupName.$error.required && form.groupCreateForm.submitted'>
+ {{'common.alerts.fieldRequired' | translate}}
+ </span>
+ <span class="help-block validation-block"
+ ng-show='form.groupCreateForm.groupName.$error.pattern && form.groupCreateForm.submitted'>
+ {{'common.alerts.noSpecialChars' | translate}}
+ </span>
+ </div>
+
+ <div class="form-group">
+ <label>{{'groups.addUsers' | translate}}</label>
+ <div>
+ <editable-list items-source="formData.members" resource-type="User" editable="true"></editable-list>
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="form-group col-sm-6"
+ ng-class="{ 'has-error': form.groupCreateForm.role.$error.required && form.groupCreateForm.submitted }">
+ <label for="role" class="nowrap roles-label">
+ {{'groups.role' | translate}}
+ <i class="fa fa-question-circle" aria-hidden="true" ng-click="showHelpPage()"></i>
+ </label>
+ <select
+ class="form-control"
+ id="role"
+ name="role"
+ ng-model="formData.role">
+ <option value="" class="hide">{{'common.select' | translate}}</option>
+ <option ng-repeat="role in roleOptions" value="{{role.permission_name}}">{{role.permission_label}}</option>
+ </select>
+ <span class="help-block validation-block" ng-show='form.groupCreateForm.role.$error.required && form.groupCreateForm.submitted'>
+ {{'common.alerts.fieldRequired' | translate}}
+ </span>
+ </div>
+ </div>
+
+ </div>
+ <div class="modal-footer">
+ <button class="btn btn-default" ng-click="cancel()">{{'common.controls.cancel' | translate}}</button>
+ <button class="btn btn-primary" ng-click="save()" type="submit">{{'common.controls.save' | translate}}</button>
+ </div>
+</form>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
new file mode 100644
index 0000000..2a71102
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
@@ -0,0 +1,147 @@
+<!--
+* 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.
+-->
+
+<form id="create-user-form" role="form" novalidate name="form.userCreateForm">
+ <div class="modal-header">
+ <h1 class="modal-title">
+ {{'users.create' | translate}}
+ </h1>
+ </div>
+ <div class="modal-body">
+ <div class="form-group"
+ ng-class="{ 'has-error': (form.userCreateForm.userName.$error.required || form.userCreateForm.userName.$error.pattern) && form.userCreateForm.submitted }">
+ <label for="userName">
+ {{'users.username' | translate}}<span> *</span>
+ <i class="fa fa-question-circle" aria-hidden="true"></i>
+ </label>
+ <input type="text"
+ autofocus
+ placeholder="{{'users.user.name' | translate}}"
+ ng-pattern="/^[^<>&`|\\]+$/"
+ ng-maxlength="80"
+ tooltip="{{'users.userNameTip' | translate}}"
+ autocomplete="off"
+ tooltip-trigger="focus"
+ class="form-control"
+ ng-model="formData.userName"
+ name="userName"
+ id="userName"
+ ng-change="checkIfInstanceExist()"
+ required>
+ <span class="help-block validation-block"
+ ng-show='form.userCreateForm.userName.$error.required && form.userCreateForm.submitted'>
+ {{'common.alerts.fieldRequired' | translate}}
+ </span>
+ <span class="help-block validation-block"
+ ng-show='form.userCreateForm.userName.$error.pattern && form.userCreateForm.submitted'>
+ {{'common.alerts.noSpecialChars' | translate}}
+ </span>
+ </div>
+
+ <div class="row">
+ <div class="form-group col-sm-6"
+ ng-class="{ 'has-error': form.userCreateForm.password.$error.required && form.userCreateForm.submitted }">
+ <label for="password">
+ {{'users.password' | translate}}<span> *</span>
+ </label>
+ <input type="password"
+ id="password"
+ class="form-control"
+ name="password"
+ placeholder="{{'users.password' | translate}}"
+ required
+ ng-model="formData.password"
+ autocomplete="off">
+ <span class="help-block validation-block"
+ ng-show='form.userCreateForm.password.$error.required && form.userCreateForm.submitted'>
+ {{'common.alerts.fieldRequired' | translate}}
+ </span>
+ </div>
+ <div class="form-group col-sm-6"
+ ng-class="{ 'has-error': form.userCreateForm.confirmPassword.$error.passwordVerify || (form.userCreateForm.confirmPassword.$error.required && form.userCreateForm.submitted) }">
+ <label for="confirmPassword">
+ {{'users.confirmPassword' | translate}}<span> *</span>
+ </label>
+ <input type="password"
+ id="confirmPassword"
+ class="form-control"
+ name="confirmPassword"
+ placeholder="{{'users.confirmPassword' | translate}}"
+ required
+ password-verify="formData.password"
+ ng-model="formData.confirmPassword"
+ autocomplete="off">
+ <span class="help-block validation-block"
+ ng-show='form.userCreateForm.confirmPassword.$error.required && form.userCreateForm.submitted'>
+ {{'common.alerts.fieldRequired' | translate}}
+ </span>
+ <span class="help-block validation-block"
+ ng-show='form.userCreateForm.confirmPassword.$error.passwordVerify'>
+ {{'users.alerts.wrongPassword' | translate}}
+ </span>
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="form-group col-sm-6"
+ ng-class="{ 'has-error': form.userCreateForm.role.$error.required && form.userCreateForm.submitted }">
+ <label for="role" class="nowrap roles-label">
+ {{'users.role' | translate}}<span> *</span>
+ <i class="fa fa-question-circle" aria-hidden="true" ng-click="showHelpPage()"></i>
+ </label>
+ <select
+ class="form-control"
+ id="role"
+ name="role"
+ ng-model="formData.role"
+ required>
+ <option value="" class="hide">{{'common.select' | translate}}</option>
+ <option ng-repeat="role in roleOptions" value="{{role.permission_name}}">{{role.permission_label}}</option>
+ </select>
+ <span class="help-block validation-block" ng-show='form.userCreateForm.role.$error.required && form.userCreateForm.submitted'>
+ {{'common.alerts.fieldRequired' | translate}}
+ </span>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label>
+ {{'users.isAmbariAdmin' | translate}}<span> *</span>
+ <i class="fa fa-question-circle" aria-hidden="true"></i>
+ </label>
+ <div>
+ <toggle-switch model="formData.isAdmin" on-label="{{'common.yes' | translate}}" off-label="{{'common.no' | translate}}" class="switch-primary" data-off-color="danger"></toggle-switch>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label>
+ {{'users.isActive' | translate}}<span> *</span>
+ <i class="fa fa-question-circle" aria-hidden="true"></i>
+ </label>
+ <div>
+ <toggle-switch model="formData.isActive" on-label="{{'users.active' | translate}}" off-label="{{'users.inactive' | translate}}" class="switch-primary" data-off-color="danger"></toggle-switch>
+ </div>
+ </div>
+
+ </div>
+ <div class="modal-footer">
+ <button class="btn btn-default" ng-click="cancel()">{{'common.controls.cancel' | translate}}</button>
+ <button class="btn btn-primary" ng-click="save()" type="submit">{{'common.controls.save' | translate}}</button>
+ </div>
+</form>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html
new file mode 100644
index 0000000..cc46173
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/userEdit.html
@@ -0,0 +1,140 @@
+<!--
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+-->
+
+<div ng-show="user" id="user-edit">
+ <div class="clearfix">
+ <ol class="breadcrumb pull-left">
+ <li><a href="#/userManagement?tab=users">{{'common.users' | translate}}</a></li>
+ <li class="active"><span class="glyphicon glyphicon-flash" ng-show="user.admin"></span>{{user.user_name}}</li>
+ </ol>
+ <div class="pull-right">
+ <div ng-switch="isCurrentUser || user.user_type != 'LOCAL'">
+ <button class="btn deleteuser-btn disabled btn-default" ng-switch-when="true" tooltip="{{'common.cannotDelete' | translate: '{term: constants.user}'}}">{{'common.delete' | translate: '{term: constants.user}'}}</button>
+ <button class="btn deleteuser-btn btn-danger" ng-switch-when="false" ng-click="deleteUser()">{{'common.delete' | translate: '{term: constants.user}'}}</button>
+ </div>
+ </div>
+ </div>
+ <hr>
+ <form class="form-horizontal" role="form" >
+ <div class="form-group">
+ <label class="col-sm-2 ">{{'common.type' | translate}}</label>
+ <div class="col-sm-10">
+ <label>{{user.userTypeName}}</label>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 ">{{'users.status' | translate}}</label>
+ <div class="col-sm-10">
+ <toggle-switch on-change="toggleUserActive()" disabled-tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.status}'}}" ng-disabled="isCurrentUser" model="user.active" on-label="{{'users.active' | translate}}" off-label="{{'users.inactive' | translate}}" class="switch-primary userstatus {{user ? '' : 'no-animation'}}" data-off-color="danger"></toggle-switch>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 "><span class="glyphicon glyphicon-flash"></span> {{'users.ambariAdmin' | translate}}</label>
+ <div class="col-sm-10">
+ <toggle-switch on-change="toggleUserAdmin()" disabled-tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.admin}'}}" ng-disabled="isCurrentUser" model="user.admin" on-label="{{'common.yes' | translate}}" off-label="{{'common.no' | translate}}" class="switch-primary userstatus {{user ? '' : 'no-animation'}}" data-off-color="danger"></toggle-switch>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 ">{{'users.password' | translate}}</label>
+ <div class="col-sm-10">
+ <div ng-switch="user.user_type != 'LOCAL'">
+ <button class="btn deleteuser-btn disabled btn-default" ng-switch-when="true" tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.password}'}}">{{'users.changePassword' | translate}}</button>
+ <a href ng-click="openChangePwdDialog()" ng-switch-when="false" class="btn btn-default changepassword">{{'users.changePassword' | translate}}</a>
+ </div>
+
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 ">{{getUserMembership(user.user_type)}}</label>
+ <div class="col-sm-10">
+ <editable-list items-source="editingGroupsList" resource-type="Group" editable="user.user_type == 'LOCAL'"></editable-list>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="role" class="col-sm-2 roles-label">
+ {{'users.role' | translate}}
+ <i class="fa fa-question-circle" aria-hidden="true" ng-click="showHelpPage()"></i>
+ </label>
+ <div class="col-sm-3">
+ <select ng-hide="user.admin"
+ class="form-control"
+ id="role"
+ name="role"
+ ng-options="item as item.permission_label for item in roleOptions track by item.permission_name"
+ ng-change="updateRole()"
+ ng-model="currentRole">
+ </select>
+ <span ng-show="user.admin" class="roles-label">{{user.roles[0].permission_label}}</span>
+ </div>
+ </div>
+
+ <div class="form-group" >
+ <label class="col-sm-2 ">{{'common.privileges' | translate}}</label>
+ <div class="col-sm-10">
+ <table class="table" ng-hide="hidePrivileges || user.admin">
+ <thead>
+ <tr>
+ <th>{{'common.cluster' | translate}}</th>
+ <th>{{'common.clusterRole' | translate}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr ng-repeat="(name, privilege) in privilegesView.clusters">
+ <td>
+ <span class="glyphicon glyphicon-cloud"></span>
+ <a href="#/clusters/{{name}}/manageAccess">{{name}}</a>
+ </td>
+ <td>
+ <span tooltip="{{privilege.permission_label}}">{{privilege.permission_label}}</span>
+ </td>
+ </tr>
+ <tr>
+ <td ng-show="noClusterPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.cluster}'}}</td>
+ </tr>
+ </tbody>
+ <thead class="view-permission-header">
+ <tr>
+ <th>{{'common.view' | translate}}</th>
+ <th>{{'common.viewPermissions' | translate}}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr ng-repeat="(name, privilege) in privilegesView.views">
+ <td>
+ <span class="glyphicon glyphicon-th"></span>
+ <a href="#/views/{{privilege.view_name}}/versions/{{privilege.version}}/instances/{{name}}/edit">{{name}}</a>
+ </td>
+ <td>
+ <span tooltip="{{item}}" ng-repeat="item in privilege.privileges track by $index">{{item | translate}}{{$last ? '' : ', '}}</span>
+ </td>
+ <td>
+ <i class="fa fa-trash-o" aria-hidden="true" ng-click="removeViewPrivilege(name, privilege);"></i>
+ </td>
+ </tr>
+ <tr>
+ <td ng-show="noViewPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.view}'}}</td>
+ </tr>
+ </tbody>
+ </table>
+ <div class="alert alert-info" ng-show="hidePrivileges && !user.admin">{{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.user}'}}</div>
+ <div class="alert alert-info" ng-show="user.admin">{{'users.userIsAdmin' | translate}}</div>
+ </div>
+ </div>
+ </form>
+</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html
new file mode 100644
index 0000000..4a33a31
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/usersList.html
@@ -0,0 +1,119 @@
+<!--
+* 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="users-pane">
+ <div class="clearfix panel">
+ <button class="btn btn-default createuser-btn pull-right" ng-click="createUser();">
+ {{'users.create' | translate}}
+ </button>
+ </div>
+ <table class="table table-striped table-hover">
+ <thead>
+ <tr class="fix-bottom">
+ <th>
+ <span>{{'users.username' | translate}}</span>
+ </th>
+ <th>
+ <span>{{'clusters.role' | translate}}</span>
+ </th>
+ <th>
+ <span>{{'users.status' | translate}}</span>
+ </th>
+ <th>
+ <span>{{'common.type' | translate}}</span>
+ </th>
+ <th>
+ <span>{{'common.group' | translate}}</span>
+ </th>
+ <th class="entity-actions">
+ <span>{{'common.actions' | translate}}</span>
+ </th>
+ </tr>
+ <tr class="fix-top">
+ <th>
+ <div class="search-container">
+ <input type="text" class="form-control namefilter" placeholder="{{'common.any' | translate}}" ng-model="filters.name" ng-change="resetPagination()">
+ <button type="button" class="close clearfilter" ng-show="filters.name" ng-click="filters.name=''; resetPagination()">
+ <span aria-hidden="true">×</span><span class="sr-only">{{'common.controls.close' | translate}}</span>
+ </button>
+ </div>
+ </th>
+ <th></th>
+ <th>
+ <select class="form-control statusfilter"
+ ng-model="filters.status"
+ ng-options="item.label for item in activeFilterOptions"
+ ng-change="resetPagination()">
+ </select>
+ </th>
+ <th>
+ <select class="form-control typefilter"
+ ng-model="filters.type"
+ ng-options="item.label for item in typeFilterOptions"
+ ng-change="resetPagination()">
+ </select>
+ </th>
+ <th></th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr ng-repeat="user in users">
+ <td>
+ <span>{{user.Users.user_name}}</span>
+ </td>
+ <td>
+ <span>{{user.Users.roles[0].permission_label}}</span>
+ </td>
+ <td>
+ <span>
+ {{(user.Users.active ? 'users.active' : 'users.inactive') | translate}}
+ </span>
+ </td>
+ <td><span>{{user.Users.userTypeName}}</span></td>
+ <td><span>{{user.Users.groups.length ? user.Users.groups.join(' ') : '-'}}</span></td>
+ <td class="entity-actions">
+ <a href="#/users/{{user.Users.encodedName}}/edit">
+ <i class="fa fa-pencil"></i>
+ </a>
+ <a href ng-click="deleteUser(user.Users)">
+ <i class="fa fa-trash-o"></i>
+ </a>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <div ng-if="isLoading" class="spinner-container">
+ <i class="fa fa-2x fa-spinner fa-spin" aria-hidden="true"></i>
+ </div>
+ <div class="alert empty-table-alert col-sm-12" ng-show="!users.length && !isLoading">
+ {{'common.alerts.nothingToDisplay' | translate: '{term: constants.users}'}}
+ </div>
+ <div class="col-sm-12 table-bar" ng-show="totalUsers > minRowsToShowPagination">
+ <div class="pull-left filtered-info">
+ <span>{{'common.filterInfo' | translate: '{showed: tableInfo.showed, total: tableInfo.total, term: constants.users}'}}</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="totalUsers" max-size="maxVisiblePages" items-per-page="usersPerPage" ng-model="currentPage" ng-change="pageChanged()"></pagination>
+ </div>
+ <div class="pull-right">
+ <select class="form-control" ng-model="usersPerPage" ng-change="usersPerPageChanges()" ng-options="currOption for currOption in [10, 25, 50, 100]"></select>
+ </div>
+ </div>
+</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/users/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/users/create.html
deleted file mode 100644
index 80a3b04..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/create.html
+++ /dev/null
@@ -1,82 +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.
--->
-<ol class="breadcrumb">
- <li><a href="#/users">{{'common.users' | translate}}</a></li>
- <li class="active">{{'users.create' | translate}}</li>
-</ol>
-<hr>
-<form class="form-horizontal create-user-form" role="form" novalidate name="form" autocomplete="off">
- <div class="form-group" ng-class="{'has-error' : form.user_name.$error.required && form.submitted}">
- <label for="username" class="col-sm-2 control-label">{{'users.username' | translate}}</label>
- <div class="col-sm-10"
- ng-class="{'has-error': form.user_name.$error.pattern}">
- <input
- autofocus
- type="text"
- id="username"
- class="form-control username-input"
- name="user_name"
- placeholder="{{'users.userName' | translate}}"
- ng-model="user.user_name"
- ng-required="true"
- ng-pattern="/^[^<>&`|\\]+$/"
- ng-maxlength="80"
- tooltip="{{'users.userNameTip' | translate}}"
- autocomplete="off"
- tooltip-trigger="focus">
- <div class="alert alert-danger top-margin" ng-show="form.user_name.$error.required && form.submitted">{{'common.alerts.fieldIsRequired' | translate}}</div>
- </div>
- </div>
- <div class="form-group">
- <label for="" class="col-sm-2 control-label">{{'common.type' | translate}}</label>
- <div class="col-sm-10">
- <label for="" class="control-label">{{'common.local' | translate}}</label>
- </div>
- </div>
- <div class="form-group">
- <label for="" class="col-sm-2 control-label">{{'users.status' | translate}}</label>
- <div class="col-sm-10">
- <toggle-switch model="user.active" on-label="{{'users.active' | translate}}" off-label="{{'users.inactive' | translate}}" class="switch-primary userstatus" data-off-color="danger"></toggle-switch>
- </div>
- </div>
- <div class="form-group">
- <label for="" class="col-sm-2 control-label"><span class="glyphicon glyphicon-flash"></span>{{'users.ambariAdmin' | translate}}</label>
- <div class="col-sm-10">
- <toggle-switch ng-disabled="isCurrentUser" model="user.admin" on-label="{{'common.yes' | translate}}" off-label="{{'common.no' | translate}}" class="switch-primary userstatus" data-off-color="danger"></toggle-switch>
- </div>
- </div>
- <div class="form-group" ng-class="{'has-error' : (form.password.$error.required && form.submitted) || form.confirmPassword.$error.passwordVerify}">
- <label for="password" class="col-sm-2 control-label">{{'users.password' | translate}}</label>
- <div class="col-sm-10">
- <input type="password" class="form-control bottom-margin userpassword" name="password" placeholder="{{'users.password' | translate}}" required ng-model="user.password" autocomplete="off">
- <input type="password" class="form-control bottom-margin userpasswordconfirm" name="confirmPassword" placeholder="{{'users.passwordConfirmation' | translate}}" required ng-model="user.passwordConfirmation"
- password-verify="user.password" autocomplete="off">
-
- <div class="alert alert-danger" ng-show='form.confirmPassword.$error.passwordVerify'>{{'users.alerts.wrongPassword' | translate}}</div>
- <div class="alert alert-danger" ng-show='form.password.$error.required && form.submitted'>{{'users.alerts.passwordRequired' | translate}}</div>
-
- </div>
- </div>
- <div class="form-group">
- <div class="col-sm-offset-2 col-sm-10">
- <button class="btn btn-primary pull-right left-margin saveuser" ng-click="createUser()">{{'common.controls.save' | translate}}</button>
- <a class="btn btn-default pull-right cancel" href ng-click="cancel()">{{'common.controls.cancel' | translate}}</a>
- </div>
- </div>
-
-</form>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/users/list.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/list.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/users/list.html
deleted file mode 100644
index 09024a5..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/list.html
+++ /dev/null
@@ -1,96 +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="users-pane">
- <div class="clearfix">
- <ol class="breadcrumb pull-left">
- <li class="active">{{'common.users' | translate}}</li>
- </ol>
- <div class="pull-right top-margin-4">
- <link-to route="users.create" class="btn btn-primary createuser-btn"><span class="glyphicon glyphicon-plus"></span> {{'users.create' | translate}}</link-to>
- </div>
- </div>
- <hr>
- <table class="table table-striped table-hover">
- <thead>
- <tr>
- <th width="30">
- <span class="bottom-margin admin-filter glyphicon glyphicon-flash"
- ng-class="{'no-filter' : !adminFilter}"
- ng-click="toggleAdminFilter()"
- tooltip="{{(adminFilter ? 'users.showAll' : 'users.showAdmin') | translate}}"
- ></span>
- </th>
- <th>
- <div class="search-container">
- <label for="">{{'users.username' | translate}}</label>
- <input type="text" class="form-control namefilter" placeholder="{{'common.any' | translate}}" ng-model="currentNameFilter" ng-change="resetPagination()">
- <button type="button" class="close clearfilter" ng-show="currentNameFilter" ng-click="currentNameFilter=''; resetPagination()"><span aria-hidden="true">×</span><span class="sr-only">{{'common.controls.close' | translate}}</span></button>
- </div>
- </th>
- <th>
- <label for="">{{'common.type' | translate}}</label>
- <select class="form-control typefilter"
- ng-model="currentTypeFilter"
- ng-options="item.label for item in typeFilterOptions"
- ng-change="resetPagination()">
- </select>
-
- </th>
- <th>
- <label for="">{{'users.status' | translate}}</label>
- <select class="form-control statusfilter"
- ng-model="currentActiveFilter"
- ng-options="item.label for item in activeFilterOptions"
- ng-change="resetPagination()">
- </select>
- </th>
- </tr>
- </thead>
- <tbody>
- <tr ng-repeat="user in users">
- <td>
- <span class="glyphicon" tooltip="{{user.Users.admin ? constants.admin : ''}}" ng-class="{'glyphicon-flash' : user.Users.admin}"></span>
- </td>
- <td>
- <a href="#/users/{{user.Users.encoded_name}}">{{user.Users.user_name}}</a>
- </td>
- <td>{{user.Users.userTypeName}}</td>
- <td><span ng-class="user.Users.active ? 'text-success' : 'text-danger'">{{(user.Users.active ? 'users.active' : 'users.inactive') | translate}}</span></td>
- </tr>
- </tbody>
- </table>
- <div ng-if="isLoading" 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="!users.length && !isLoading">
- {{'common.alerts.nothingToDisplay' | translate: '{term: constants.users}'}}
- </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: constants.users}'}}</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="totalUsers" max-size="maxVisiblePages" items-per-page="usersPerPage" ng-model="currentPage" ng-change="pageChanged()"></pagination>
- </div>
- <div class="pull-right">
- <select class="form-control" ng-model="usersPerPage" ng-change="usersPerPageChanges()" ng-options="currOption for currOption in [10, 25, 50, 100]"></select>
- </div>
- </div>
-</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/users/modals/changePassword.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/modals/changePassword.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/users/modals/changePassword.html
deleted file mode 100644
index f29d315..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/modals/changePassword.html
+++ /dev/null
@@ -1,46 +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">{{'users.changePasswordFor' | translate: '{userName: userName}'}}</h3>
-</div>
-<div class="modal-body">
- <form class="form-horizontal" novalidate name="form.passwordChangeForm" role="form" >
- <div class="form-group" ng-class="{'has-error' : (form.passwordChangeForm.currentPassword.$error.required && form.passwordChangeForm.submitted)}">
- <label for="" class="col-sm-4 control-label" >{{'users.yourPassword' | translate}}</label>
- <div class="col-sm-8">
- <input type="password" name="currentPassword" class="form-control bottom-margin" placeholder="{{'users.yourPassword' | translate}}" required ng-model="passwordData.currentUserPassword" autocomplete="off">
- <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted'>{{'users.alerts.passwordRequired' | translate}}</div>
- </div>
- </div>
- <div class="form-group no-margin-bottom" ng-class="{'has-error' : (form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted) || form.passwordChangeForm.confirmPassword.$error.passwordVerify}">
- <label for="" class="col-sm-4 control-label">{{'users.newPassword' | translate}}:</label>
- <div class="col-sm-8">
- <input type="password" class="form-control bottom-margin" name="password" placeholder="{{'users.newPassword' | translate}}" required ng-model="passwordData.password" autocomplete="off">
- <input type="password" class="form-control bottom-margin" name="confirmPassword" placeholder="{{'users.newPasswordConfirmation' | translate}}" required ng-model="passwordData.passwordConfirmation"
- password-verify="passwordData.password" autocomplete="off">
- <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.confirmPassword.$error.passwordVerify'>{{'users.alerts.wrongPassword' | translate}}</div>
- <div class="alert alert-danger no-margin-bottom" ng-show='form.passwordChangeForm.password.$error.required && form.passwordChangeForm.submitted'>{{'users.alerts.passwordRequired' | translate}}</div>
- </div>
-
- </div>
- </form>
-</div>
-<div class="modal-footer">
- <button class="btn btn-default" ng-click="cancel()">{{'common.controls.cancel' | translate}}</button>
- <button class="btn btn-primary" ng-click="ok()">{{'common.controls.ok' | translate}}</button>
-</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/app/views/users/show.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/show.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/users/show.html
deleted file mode 100644
index f965c5d..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/users/show.html
+++ /dev/null
@@ -1,122 +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 ng-show="user" class="user-edit-panel">
- <div class="clearfix">
- <ol class="breadcrumb pull-left">
- <li><a href="#/users">{{'common.users' | translate}}</a></li>
- <li class="active"><span class="glyphicon glyphicon-flash" ng-show="user.admin"></span>{{user.user_name}}</li>
- </ol>
- <div class="pull-right top-margin-4">
- <div ng-switch="isCurrentUser || user.user_type != 'LOCAL'">
- <button class="btn deleteuser-btn disabled btn-default" ng-switch-when="true" tooltip="{{'common.cannotDelete' | translate: '{term: constants.user}'}}">{{'common.delete' | translate: '{term: constants.user}'}}</button>
- <button class="btn deleteuser-btn btn-danger" ng-switch-when="false" ng-click="deleteUser()">{{'common.delete' | translate: '{term: constants.user}'}}</button>
- </div>
- </div>
- </div>
- <hr>
- <form class="form-horizontal" role="form" >
- <div class="form-group">
- <label for="" class="col-sm-2 control-label">{{'common.type' | translate}}</label>
- <div class="col-sm-10">
- <label for="" class="control-label">{{user.userTypeName}}</label>
- </div>
- </div>
- <div class="form-group">
- <label for="" class="col-sm-2 control-label">{{'users.status' | translate}}</label>
- <div class="col-sm-10">
- <toggle-switch on-change="toggleUserActive()" disabled-tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.status}'}}" ng-disabled="isCurrentUser" model="user.active" on-label="{{'users.active' | translate}}" off-label="{{'users.inactive' | translate}}" class="switch-primary userstatus {{user ? '' : 'no-animation'}}" data-off-color="danger"></toggle-switch>
- </div>
- </div>
- <div class="form-group">
- <label for="" class="col-sm-2 control-label"><span class="glyphicon glyphicon-flash"></span> {{'users.ambariAdmin' | translate}}</label>
- <div class="col-sm-10">
- <toggle-switch on-change="toggleUserAdmin()" disabled-tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.admin}'}}" ng-disabled="isCurrentUser" model="user.admin" on-label="{{'common.yes' | translate}}" off-label="{{'common.no' | translate}}" class="switch-primary userstatus {{user ? '' : 'no-animation'}}" data-off-color="danger"></toggle-switch>
- </div>
- </div>
- <div class="form-group">
- <label for="password" class="col-sm-2 control-label">{{'users.password' | translate}}</label>
- <div class="col-sm-10">
- <div ng-switch="user.user_type != 'LOCAL'">
- <button class="btn deleteuser-btn disabled btn-default" ng-switch-when="true" tooltip="{{'users.alerts.cannotChange' | translate: '{term: constants.password}'}}">{{'users.changePassword' | translate}}</button>
- <a href ng-click="openChangePwdDialog()" ng-switch-when="false" class="btn btn-default changepassword">{{'users.changePassword' | translate}}</a>
- </div>
-
- </div>
- </div>
- <div class="form-group">
- <label for="groups" class="col-sm-2 control-label">{{getUserMembership(user.user_type)}}</label>
- <div class="col-sm-10">
- <editable-list items-source="editingGroupsList" resource-type="Group" editable="user.user_type == 'LOCAL'"></editable-list>
- </div>
-
- </div>
- <div class="form-group" >
- <label for="" class="col-sm-2 control-label">{{'common.privileges' | translate}}</label>
- <div class="col-sm-10">
- <table class="table" ng-hide="hidePrivileges || user.admin">
- <thead>
- <tr>
- <th>{{'common.cluster' | translate}}</th>
- <th>{{'common.clusterRole' | translate}}</th>
- </tr>
- </thead>
- <tbody>
- <tr ng-repeat="(name, privilege) in privileges.clusters">
- <td>
- <span class="glyphicon glyphicon-cloud"></span>
- <a href="#/clusters/{{name}}/manageAccess">{{name}}</a>
- </td>
- <td>
- <span tooltip="{{privilege.permission_label}}">{{privilege.permission_label}}</span>
- </td>
- </tr>
- <tr>
- <td ng-show="noClusterPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.cluster}'}}</td>
- </tr>
- </tbody>
- <thead class="view-permission-header">
- <tr>
- <th>{{'common.view' | translate}}</th>
- <th>{{'common.viewPermissions' | translate}}</th>
- </tr>
- </thead>
- <tbody>
- <tr ng-repeat="(name, privilege) in privileges.views">
- <td>
- <span class="glyphicon glyphicon-th"></span>
- <a href="#/views/{{privilege.view_name}}/versions/{{privilege.version}}/instances/{{name}}/edit">{{name}}</a>
- </td>
- <td>
- <span tooltip="{{item}}" ng-repeat="item in privilege.privileges track by $index">{{item | translate}}{{$last ? '' : ', '}}</span>
- </td>
- <td>
- <i class="fa fa-trash-o" aria-hidden="true" ng-click="removePrivilege(name, privilege);"></i>
- </td>
- </tr>
- <tr>
- <td ng-show="noViewPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.view}'}}</td>
- </tr>
- </tbody>
- </table>
- <div class="alert alert-info" ng-show="!privileges && !user.admin">{{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.user}'}}</div>
- <div class="alert alert-info" ng-show="user.admin">{{'users.userIsAdmin' | translate}}</div>
- </div>
- </div>
- </form>
-</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/bower.json
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/bower.json b/ambari-admin/src/main/resources/ui/admin-web/bower.json
index dbdf005..c38f464 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/bower.json
+++ b/ambari-admin/src/main/resources/ui/admin-web/bower.json
@@ -2,7 +2,7 @@
"name": "adminconsole",
"private": true,
"dependencies": {
- "bootstrap": "3.1.1",
+ "bootstrap": "3.3.7",
"angular": "1.2.26",
"angular-route": "1.2.26",
"angular-bootstrap": "0.11.0",
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/gulpfile.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/gulpfile.js b/ambari-admin/src/main/resources/ui/admin-web/gulpfile.js
index 2f47b85..9b377d1 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/gulpfile.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/gulpfile.js
@@ -24,10 +24,10 @@ var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
gulp.task('styles', function () {
- return gulp.src('app/styles/*.css')
+ return gulp.src('app/styles/**/*.css')
.pipe($.order([
- 'app/styles/main.css',
- 'app/styles/custom-admin-ui.css' // This should always be the last stylesheet. So it can be dropped and be effective on build time
+ 'app/styles/theme/bootstrap-ambari.css',
+ 'app/styles/main.css'
], { base: './' }))
.pipe($.concat('main.css'))
.pipe($.autoprefixer('last 1 version'))
@@ -64,8 +64,8 @@ gulp.task('images', function () {
});
gulp.task('fonts', function () {
- return $.bowerFiles()
- .pipe($.filter('**/*.{eot,svg,ttf,woff}'))
+ return gulp.src('app/bower_components/**/fonts/*.{eot,svg,ttf,woff}')
+ .pipe($.addSrc('app/assets/fonts/*'))
.pipe($.flatten())
.pipe(gulp.dest('dist/fonts'))
.pipe($.size());
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/package.json
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/package.json b/ambari-admin/src/main/resources/ui/admin-web/package.json
index efcd9d4..b7c514c 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/package.json
+++ b/ambari-admin/src/main/resources/ui/admin-web/package.json
@@ -5,19 +5,19 @@
"devDependencies": {
"bower": "1.3.8",
"gulp": "^3.8.8",
+ "gulp-add-src": "^0.2.0",
"gulp-autoprefixer": "0.0.7",
- "gulp-bower-files": "0.2.1",
"gulp-cache": "0.1.1",
"gulp-clean": "0.2.4",
+ "gulp-concat": "2.6.0",
"gulp-filter": "0.4.1",
"gulp-flatten": "0.0.2",
"gulp-load-plugins": "0.5.0",
+ "gulp-order": "1.1.1",
"gulp-plumber": "0.6.6",
"gulp-size": "0.3.0",
"gulp-uglify": "0.2.1",
"gulp-useref": "0.4.2",
- "gulp-concat": "2.6.0",
- "gulp-order": "1.1.1",
"http-server": "0.6.1",
"karma": "0.12.16",
"karma-chrome-launcher": "0.1.4",
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/AppCtrl_test.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/AppCtrl_test.js b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/AppCtrl_test.js
new file mode 100644
index 0000000..1bbe47a
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/AppCtrl_test.js
@@ -0,0 +1,211 @@
+/**
+ * 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.
+ */
+
+describe('#AppCtrl', function () {
+
+ var scope, ctrl, $httpBackend, $window, clusterService, deferred;
+
+ beforeEach(function () {
+ module('ambariAdminConsole', function ($provide) {
+ $provide.value('$route', {
+ current: null
+ });
+ $provide.value('$window', {
+ location: {
+ pathname: 'http://c6401.ambari.apache.org:8080/views/ADMIN_VIEW/2.0.0/INSTANCE/#/'
+ },
+ localStorage: {
+ getItem: function () {
+ return null;
+ },
+ setItem: angular.noop
+ }
+ });
+ localStorage.ambari = JSON.stringify({
+ app: {
+ authenticated: true,
+ loginName: 'admin',
+ user: 'user'
+ }
+ });
+ });
+ inject(function (_$httpBackend_, $rootScope, $controller, _$window_, _Cluster_, _$q_) {
+ clusterService = _Cluster_;
+ deferred = _$q_.defer();
+ spyOn(clusterService, 'getStatus').andReturn(deferred.promise);
+ deferred.resolve({
+ Clusters: {
+ provisioning_state: 'INIT'
+ }
+ });
+ $window = _$window_;
+ $httpBackend = _$httpBackend_;
+ $httpBackend.whenGET(/api\/v1\/services\/AMBARI\/components\/AMBARI_SERVER.+/).respond(200, {
+ RootServiceComponents: {
+ component_version: 2.2,
+ properties: {
+ 'user.inactivity.timeout.default': 20
+ }
+ }
+ });
+ $httpBackend.whenGET(/\/api\/v1\/views.+/).respond(200, {
+ "href": "http://c6401.ambari.apache.org:8080/api/v1/views?fields=versions/instances/ViewInstanceInfo&versions/ViewVersionInfo/system=false&versions/instances/ViewInstanceInfo/visible=true",
+ "items": [
+ {
+ "ViewInfo": {
+ "view_name": "SLIDER"
+ },
+ "href": "http://c6401.ambari.apache.org:8080/api/v1/views/SLIDER",
+ "versions": [
+ {
+ "ViewVersionInfo": {
+ "system": false,
+ "version": "1.0.0",
+ "view_name": "SLIDER"
+ },
+ "href": "http://c6401.ambari.apache.org:8080/api/v1/views/SLIDER/versions/1.0.0",
+ "instances": [
+ {
+ "ViewInstanceInfo": {
+ "context_path": "/views/SLIDER/1.0.0/VisibleInstance",
+ "description": "VisibleInstance",
+ "icon64_path": null,
+ "icon_path": null,
+ "instance_data": {},
+ "instance_name": "VisibleInstance",
+ "label": "VisibleInstance",
+ "properties": {
+ "ambari.server.password": "123",
+ "ambari.server.url": "123",
+ "ambari.server.username": "123",
+ "slider.user": null,
+ "view.kerberos.principal": null,
+ "view.kerberos.principal.keytab": null
+ },
+ "static": false,
+ "version": "1.0.0",
+ "view_name": "SLIDER",
+ "visible": true
+ },
+ "href": "http://c6401.ambari.apache.org:8080/api/v1/views/SLIDER/versions/1.0.0/instances/VisibleInstance"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ });
+ $httpBackend.whenGET(/\/persist\/user-pref-.*/).respond(200, {
+ data: {
+ data: {
+ addingNewRepository: true
+ }
+ }
+ });
+ scope = $rootScope.$new();
+ scope.$apply();
+ ctrl = $controller('AppCtrl', {
+ $scope: scope
+ });
+ });
+ });
+
+ afterEach(function() {
+ $httpBackend.verifyNoOutstandingExpectation();
+ $httpBackend.verifyNoOutstandingRequest();
+ });
+
+ describe('signout', function () {
+
+ beforeEach(function () {
+ $httpBackend.whenGET(/\/api\/v1\/logout\?_=\d+/).respond(200,{
+ message: "successfully logged out"
+ });
+ $httpBackend.whenGET(/\/api\/v1\/users\/admin\/authorizations.*/).respond(200, {
+ items: [
+ {
+ AuthorizationInfo: {
+ authorization_id: "AMBARI.RENAME_CLUSTER"
+ }
+ }
+ ]
+ });
+ });
+
+ it('should reset window.location and ambari localstorage', function () {
+ scope.signOut();
+
+ runs(function() {
+ chai.expect($window.location.pathname).to.equal('/');
+ });
+
+ var data = JSON.parse(localStorage.ambari);
+ chai.expect(data.app.authenticated).to.equal(undefined);
+ chai.expect(data.app.loginName).to.equal(undefined);
+ chai.expect(data.app.user).to.equal(undefined);
+ $httpBackend.flush();
+ });
+ });
+
+ describe('roles loading', function () {
+
+ var mock = {
+ callback: angular.noop
+ },
+ cases = [
+ {
+ canPersistData: true,
+ items: [
+ {
+ AuthorizationInfo: {
+ authorization_id: 'CLUSTER.MANAGE_USER_PERSISTED_DATA'
+ }
+ }
+ ],
+ title: 'user can persist data'
+ },
+ {
+ canPersistData: false,
+ items: [],
+ title: 'user can\'t persist data'
+ }
+ ];
+
+ angular.forEach(cases, function (item) {
+
+ describe(item.title, function () {
+
+ beforeEach(function () {
+ $httpBackend.whenGET(/\/api\/v1\/users\/admin\/authorizations.*/).respond(200, {
+ items: item.items
+ });
+ spyOn(mock, 'callback');
+ scope.authDataLoad.promise.then(mock.callback);
+ $httpBackend.flush();
+ });
+
+ it('authDataLoad should be resolved with the correct argument', function () {
+ expect(mock.callback).toHaveBeenCalledWith(item.canPersistData);
+ });
+
+ });
+
+ });
+
+ });
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/e83bf1bd/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/ClusterInformationCtrl_test.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/ClusterInformationCtrl_test.js b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/ClusterInformationCtrl_test.js
new file mode 100644
index 0000000..2972e7f
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/ClusterInformationCtrl_test.js
@@ -0,0 +1,102 @@
+/**
+ * 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.
+ */
+
+describe('ClusterInformationCtrl', function() {
+ beforeEach(module('ambariAdminConsole'));
+
+ var ctrl, $scope, Cluster, deferred, ConfirmationModal;
+
+ beforeEach(inject(function($controller, $rootScope, _Cluster_, _$q_, _ConfirmationModal_){
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ Cluster = _Cluster_;
+ ConfirmationModal = _ConfirmationModal_;
+ deferred = _$q_.defer();
+ $scope = $rootScope.$new();
+ $scope.$apply();
+ ctrl = $controller('ClusterInformationCtrl', {
+ $scope: $scope
+ });
+
+ spyOn(Cluster, 'getBlueprint').andReturn(deferred.promise);
+ spyOn(Cluster, 'editName').andReturn(deferred.promise);
+ spyOn(ConfirmationModal, 'show').andReturn(deferred.promise);
+ }));
+
+ describe('#getBlueprint', function() {
+ it('Cluster.getBlueprint should be called', function() {
+ $scope.cluster = {
+ Clusters: {
+ cluster_name: 'c1'
+ }
+ };
+ $scope.getBlueprint();
+ expect(Cluster.getBlueprint).toHaveBeenCalled();
+ });
+ });
+
+ describe('#toggleSaveButton', function() {
+ beforeEach(function() {
+ $scope.cluster = {
+ Clusters: {
+ cluster_name: 'c1'
+ }
+ };
+ });
+
+ it('isClusterNameEdited should be true', function() {
+ $scope.edit = {
+ clusterName: 'c2'
+ };
+ $scope.toggleSaveButton();
+ expect($scope.isClusterNameEdited).toBeTruthy();
+ });
+
+ it('isClusterNameEdited should be false', function() {
+ $scope.edit = {
+ clusterName: 'c1'
+ };
+ $scope.toggleSaveButton();
+ expect($scope.isClusterNameEdited).toBeFalsy();
+ });
+ });
+
+ describe('#confirmClusterNameChange', function() {
+ it('ConfirmationModal.show should be called', function() {
+ $scope.edit = {
+ clusterName: 'c1'
+ };
+ $scope.confirmClusterNameChange();
+ expect(ConfirmationModal.show).toHaveBeenCalled();
+ });
+ });
+
+ describe('#saveClusterName', function() {
+ it('Cluster.editName should be called', function() {
+ $scope.edit = {
+ clusterName: 'c1'
+ };
+ $scope.cluster = {
+ Clusters: {
+ cluster_name: 'c2'
+ }
+ };
+ $scope.saveClusterName();
+ expect(Cluster.editName).toHaveBeenCalledWith('c2', 'c1');
+ });
+ });
+});