update for validation on project and member.

This commit is contained in:
kunw 2016-06-25 16:15:50 +08:00
parent 4caf2becb4
commit 2911f09b34
13 changed files with 133 additions and 81 deletions

View File

@ -1,33 +1,29 @@
<div class="well panel-group">
<div class="row">
<div class="col-xs-10 col-md-10">
<form name="form" novalidate ng-submit="form.$valid">
<form name="form" class="css-form" novalidate>
<div class="col-xs-10 col-md-10">
<div class="form-group col-md-6">
<input type="text" class="form-control" id="addUsername" placeholder="// 'username' | tr //" ng-model="pm.username" name="uUsername" ng-model-options="{ debounce: 250 }" ng-change="vm.reset()" required>
<div class="error-message">
<div ng-messages="form.$dirty && form.uUsername.$error">
<div ng-messages="form.$submitted && form.uUsername.$error">
<span ng-message="required">// 'username_is_required' | tr //</span>
</div>
<span ng-show="vm.hasError">// vm.errorMessage | tr //</span>
</div>
</div>
</form>
<form class="form-inline clearfix">
<div class="form-group">
<label for="roleIdList">// 'role' | tr //:</label>&nbsp;&nbsp;
<span ng-repeat="role in vm.roles">
<input type="radio" name="role" ng-model="vm.optRole" value="//role.id//">&nbsp;//role.name//&nbsp;&nbsp;
</span>
</div>
</form>
</div>
<div class="col-xs-2 col-md-2">
<form>
</div>
<div class="col-xs-2 col-md-2">
<div class="form-group">
<button type="button" class="btn btn-primary" id="btnSave" ng-disabled="form.$invalid" ng-click="vm.save(pm)">// 'save' | tr //</button>
<button type="submit" class="btn btn-primary" id="btnSave" ng-click="vm.save(pm)">// 'save' | tr //</button>
<button type="button" class="btn btn-default" id="btnCancel" ng-click="vm.cancel(form)">// 'cancel' | tr //</button>
</div>
</form>
</div>
</div>
</div>
</form>
</div>

View File

@ -10,37 +10,41 @@
function AddProjectMemberController($scope, roles, AddProjectMemberService) {
var vm = this;
vm.username = '';
$scope.pm = {};
var pm = $scope.pm;
vm.roles = roles();
vm.optRole = 1;
vm.reset = reset;
vm.save = save;
vm.cancel = cancel;
vm.reset = reset;
vm.hasError = false;
vm.errorMessage = '';
function reset() {
vm.hasError = false;
vm.errorMessage = '';
}
function save(pm) {
if(pm && angular.isDefined(pm.username)) {
AddProjectMemberService(vm.projectId, vm.optRole, pm.username)
.success(addProjectMemberComplete)
.error(addProjectMemberFailed);
.error(addProjectMemberFailed);
}
}
function cancel(form) {
if(form) {
form.$setPristine();
}
form.$setPristine();
form.$setUntouched();
vm.isOpen = false;
vm.username = '';
pm.username = '';
vm.optRole = 1;
vm.hasError = false;
vm.errorMessage = '';
}
function addProjectMemberComplete(data, status, header) {
@ -49,7 +53,7 @@
}
function addProjectMemberFailed(data, status, headers) {
if(status === 409) {
if(status === 409 && pm.username != '') {
vm.hasError = true;
vm.errorMessage = 'username_already_exist';
}
@ -60,6 +64,11 @@
console.log('addProjectMemberFailed: status:' + status + ', data:' + data);
}
function reset() {
vm.hasError = false;
vm.errorMessage = '';
}
}
function addProjectMember() {
@ -71,12 +80,18 @@
'isOpen': '=',
'reload': '&'
},
'link': link,
'controller': AddProjectMemberController,
'controllerAs': 'vm',
'bindToController': true
};
return directive;
function link(scope, element, attrs, ctrl) {
scope.form.$setPristine();
scope.form.$setUntouched();
}
}
})();

View File

@ -7,5 +7,5 @@
<a ng-show="vm.userId != vm.currentUserId" href="javascript:void(0);" ng-click="vm.cancelUpdate()" title="Cancel">
<span ng-if="vm.editMode" class="glyphicon glyphicon-repeat"></span>
</a>
<a ng-show="vm.userId != vm.currentUserId && !vm.editMode" href="javascript:void(0);" data-toggle="modal" data-target="#myModal" ng-click="vm.deleteProjectMember()" title="Delete"><span class="glyphicon glyphicon-trash"></span></a>
<a ng-show="vm.userId != vm.currentUserId && !vm.editMode" href="javascript:void(0);" ng-click="vm.deleteProjectMember()" title="Delete"><span class="glyphicon glyphicon-trash"></span></a>
</td>

View File

@ -6,9 +6,9 @@
.module('harbor.project.member')
.directive('editProjectMember', editProjectMember);
EditProjectMemberController.$inject = ['$scope', 'roles', 'getRole','EditProjectMemberService'];
EditProjectMemberController.$inject = ['$scope', 'roles', 'getRole','EditProjectMemberService', '$filter', 'trFilter'];
function EditProjectMemberController($scope, roles, getRole, EditProjectMemberService) {
function EditProjectMemberController($scope, roles, getRole, EditProjectMemberService, $filter, trFilter) {
var vm = this;
vm.roles = roles();
@ -49,6 +49,7 @@
}
function editProjectMemberFailed(e) {
alert($filter('tr')('failed_to_change_member'));
console.log('Failed to edit project member:' + e);
}

View File

@ -12,14 +12,14 @@
</div>
<div class="pane">
<add-project-member ng-show="vm.isOpen" is-open="vm.isOpen" project-id="//vm.projectId//" reload='vm.search({projectId: vm.projectId, username: vm.username})'></add-project-member>
<modal-dialog modal-title="// 'confirm_to_delete_member_title' | tr //" modal-message="// 'confirm_to_delete_member' | tr //" action="vm.deleteProjectMember()"></modal-dialog>
<modal-dialog modal-title="// vm.modalTitle //" modal-message="// vm.modalMessage //" confirm-only="true"></modal-dialog>
<div class="sub-pane">
<table class="table table-pane" >
<thead>
<th width="30%">// 'username' | tr //</th><th width="40%">// 'role' | tr //</th><th width="30%">// 'operation' | tr //</th>
</thead>
<tbody>
<tr ng-repeat="pr in vm.projectMembers" edit-project-member username="pr.username" project-id="vm.projectId" user-id="pr.user_id" delete="vm.deleteMember({projectId: vm.projectId, userId: pr.user_id})" current-user-id="vm.user.user_id" role-name="pr.role_name" reload='vm.search({projectId: vm.projectId, username: vm.username})'></tr>
<tr ng-repeat="pr in vm.projectMembers" edit-project-member username="pr.username" project-id="vm.projectId" user-id="pr.user_id" delete="vm.deleteProjectMember({projectId: vm.projectId, userId: pr.user_id})" current-user-id="vm.user.user_id" role-name="pr.role_name" reload='vm.search({projectId: vm.projectId, username: vm.username})'></tr>
</tbody>
</table>
</div>

View File

@ -6,16 +6,15 @@
.module('harbor.project.member')
.directive('listProjectMember', listProjectMember);
ListProjectMemberController.$inject = ['$scope', 'ListProjectMemberService', 'DeleteProjectMemberService', 'getParameterByName', '$location', 'currentUser'];
ListProjectMemberController.$inject = ['$scope', 'ListProjectMemberService', 'DeleteProjectMemberService', 'getParameterByName', '$location', 'currentUser', '$filter', 'trFilter'];
function ListProjectMemberController($scope, ListProjectMemberService, DeleteProjectMemberService, getParameterByName, $location, currentUser) {
function ListProjectMemberController($scope, ListProjectMemberService, DeleteProjectMemberService, getParameterByName, $location, currentUser, $filter, trFilter) {
var vm = this;
vm.isOpen = false;
vm.search = search;
vm.addProjectMember = addProjectMember;
vm.deleteProjectMember = deleteProjectMember;
vm.deleteMember = deleteMember
vm.retrieve = retrieve;
vm.username = '';
@ -41,27 +40,21 @@
}
}
function deleteProjectMember() {
DeleteProjectMemberService(vm.selectedProjectId, vm.selectedUserId)
function deleteProjectMember(e) {
DeleteProjectMemberService(e.projectId, e.userId)
.success(deleteProjectMemberSuccess)
.error(deleteProjectMemberFailed);
}
function deleteMember(e) {
vm.selectedProjectId = e.projectId;
vm.selectedUserId = e.userId;
vm.modalTitle = 'Delete project member';
vm.modalMessage = 'Are you sure to delete the current member?';
}
function deleteProjectMemberSuccess(data, status) {
console.log('Successful delete project member complete.');
vm.retrieve();
}
function deleteProjectMemberFailed(e) {
vm.modalTitle = $filter('tr')('confirm_to_delete_member_title');
vm.modalMessage = $filter('tr')('failed_to_delete_member');
$scope.$broadcast('showDialog', true);
console.log('Failed to edit project member:' + e);
}

View File

@ -1,12 +1,13 @@
<div class="well panel-group">
<div class="row">
<div class="col-xs-10 col-md-10">
<form name="form" ng-submit="form.$valid">
<div class="form-group col-md-6">
<input type="text" class="form-control" placeholder="// 'project_name' | tr //" ng-model="p.projectName" name="uProjectName" ng-model-options="{ debounce: 250 }" ng-change="vm.reset()" required>
<form name="form" class="css-form" novalidate>
<div class="row">
<div class="col-xs-10 col-md-10">
<div class="form-group col-md-7">
<input type="text" class="form-control" placeholder="// 'project_name' | tr //" ng-model="p.projectName" name="uProjectName" ng-change="vm.reset()" ng-model-options="{ debounce: 250 }" project-name required>
<div class="error-message">
<div ng-messages="form.$dirty && form.uProjectName.$error" ng-if="form.uProjectName.$touched">
<div ng-messages="form.$submitted && form.uProjectName.$error">
<span ng-message="required">// 'project_name_is_required' | tr //</span>
<span ng-message="projectName">// 'project_name_is_invalid' | tr //</span>
</div>
<span ng-show="vm.hasError">// vm.errorMessage | tr //</span>
</div>
@ -14,15 +15,13 @@
<div class="form-group">
<input type="checkbox" ng-model="vm.isPublic">&nbsp;// 'public' | tr //
</div>
</form>
</div>
<div class="col-xs-2 col-md-2">
<form>
</div>
<div class="col-xs-2 col-md-2">
<div class="form-group">
<button type="button" class="btn btn-primary" ng-disabled="form.$invalid" ng-click="vm.addProject(p)">// 'save' | tr //</button>
<button type="submit" class="btn btn-primary" ng-click="vm.addProject(p)">// 'save' | tr //</button>
<button type="button" class="btn btn-default" ng-click="vm.cancel(form)">// 'cancel' | tr //</button>
</div>
</form>
</div>
</div>
</div>
</form>
</div>

View File

@ -10,21 +10,20 @@
function AddProjectController(AddProjectService, $scope) {
var vm = this;
vm.projectName = "";
$scope.p = {};
var vm0 = $scope.p;
vm0.projectName = '';
vm.isPublic = false;
vm.reset = reset;
vm.addProject = addProject;
vm.cancel = cancel;
vm.reset = reset;
vm.hasError = false;
vm.errorMessage = '';
function reset() {
vm.hasError = false;
vm.errorMessage = '';
}
function addProject(p) {
if(p && angular.isDefined(p.projectName)) {
AddProjectService(p.projectName, vm.isPublic)
@ -34,17 +33,20 @@
}
function addProjectSuccess(data, status) {
vm.projectName = "";
vm.isPublic = false;
$scope.$emit('addedSuccess', true);
vm.hasError = false;
vm.errorMessage = '';
}
function addProjectFailed(data, status) {
vm.hasError = true;
if(status == 400) {
vm.errorMessage = 'project_name_is_invalid';
if(status === 400 && vm0.projectName!= '' && vm0.projectName.length < 4) {
vm.errorMessage = 'project_name_is_too_short';
}
if(status === 409) {
if(status === 400 && vm0.projectName.length > 30) {
vm.errorMessage = 'project_name_is_too_long';
}
if(status === 409 && vm0.projectName != '') {
vm.errorMessage = 'project_already_exist';
}
console.log('Failed to add project:' + status);
@ -53,10 +55,19 @@
function cancel(form){
if(form) {
form.$setPristine();
form.$setUntouched();
}
vm.isOpen = false;
vm.projectName = '';
vm0.projectName = '';
vm.isPublic = false;
vm.hasError = false;
vm.errorMessage = '';
}
function reset() {
vm.hasError = false;
vm.errorMessage = '';
}
}
@ -75,7 +86,8 @@
return directive;
function link(scope, element, attrs, ctrl) {
scope.form.$setPristine();
scope.form.$setUntouched();
}
}

View File

@ -0,0 +1,27 @@
(function() {
'use strict';
angular
.module('harbor.validator')
.directive('projectName', projectName);
projectName.$inject = ['PROJECT_REGEXP']
function projectName(PROJECT_REGEXP) {
var directive = {
'require': 'ngModel',
'link': link
};
return directive;
function link(scope, element, attrs, ctrl) {
ctrl.$validators.projectName = validator;
function validator(modelValue, viewValue) {
return PROJECT_REGEXP.test(modelValue);
}
}
}
})();

View File

@ -5,6 +5,6 @@
angular
.module('harbor.validator')
.constant('INVALID_CHARS', [",","~","#", "$", "%"])
.constant('PASSWORD_REGEXP', /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{7,20}$/);
.constant('PASSWORD_REGEXP', /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{7,20}$/)
.constant('PROJECT_REGEXP', /^[a-z0-9](?:-*[a-z0-9])*(?:[._][a-z0-9](?:-*[a-z0-9])*)*$/);
})();

View File

@ -108,7 +108,9 @@ var locale_messages = {
'username_email': 'Username/Email',
'project_name_is_required': 'Project name is required',
'project_already_exist': 'Project already exist',
'project_name_is_invalid': 'Project name is invalid',
'project_name_is_invalid': 'Project name is invalid, it should be all lowercase and with no space.',
'project_name_is_too_short': 'Project name is too short, it should be greater than 4 characters.',
'project_name_is_too_long': 'Project name is too long, it should be less than 30 characters.',
'projects_or_repositories': 'Projects or repositories',
'tag': 'Tag',
'image_details': 'Image Details',
@ -130,7 +132,9 @@ var locale_messages = {
'no_projects_add_new_project': 'No projects, add new project now.',
'no_repositories': 'No repositories found, please use "docker push" to upload images.',
'confirm_to_delete_member_title': 'Delete project member',
'confirm_to_delete_member': 'Are you sure to delete the current project member?',
'failed_to_change_member': 'Project member can not be changed, insuffient permissions.',
'failed_to_delete_member': 'Project member can not be deleted, insuffient permissions.',
'confirm_to_change_member_title': 'Change project member',
'confirm_to_delete_user_title': 'Delete user',
'confirm_to_delete_user': 'Are you sure to delete the current user?',
'confirm_to_delete_destination_title': 'Delete destination',
@ -180,7 +184,7 @@ var locale_messages = {
'copyright': 'Copyright',
'all_rights_reserved': 'All Rights Reserved.',
'successful_ping_target': 'Successful Ping target.',
'failed_ping_target': 'Failed Ping target:',
'failed_ping_target': 'Failed to Ping target:',
'policy_already_exists': 'Policy alreay exists.',
'failed_update_policy': 'Failed update policy:',
'destination_already_exists': 'Destination already exists.',

View File

@ -108,7 +108,9 @@ var locale_messages = {
'username_email': '用户名/邮箱',
'project_name_is_required': '项目名称为必填项。',
'project_already_exist': '项目已存在。',
'project_name_is_invalid': '项目名称无效。',
'project_name_is_invalid': '项目名称无效。全部为小写字母,且不能包含空格。',
'project_name_is_too_short': '项目名称长度过短至少多于4个字符。',
'projecT_name_is_too_long': '项目名称长度超出限制最长30个字符。',
'projects_or_repositories': '项目和镜像资源',
'tag': '标签',
'image_details': '镜像明细',
@ -128,7 +130,9 @@ var locale_messages = {
'no_projects_add_new_project': '当前没有项目,请新增项目。',
'no_repositories': '未发现镜像,请用"docker push"命令上传镜像。',
'confirm_to_delete_member_title': '删除项目成员',
'confirm_to_delete_member': '确认删除当前项目成员吗?',
'failed_to_change_member': '无法修改项目成员,权限不足。',
'failed_to_delete_member': '无法删除项目成员,权限不足。',
'confirm_to_change_member_title': '修改项目成员',
'confirm_to_delete_user_title': '删除用户',
'confirm_to_delete_user': '确认删除当前用户吗?',
'confirm_to_delete_destination_title': '删除目标',

View File

@ -175,6 +175,7 @@
<script src="/static/resources/js/components/validator/confirm-password.validator.js"></script>
<script src="/static/resources/js/components/validator/user-exist.validator.js"></script>
<script src="/static/resources/js/components/validator/invalid-chars.validator.js"></script>
<script src="/static/resources/js/components/validator/project-name.validator.js"></script>
<script src="/static/resources/js/components/search/search.module.js"></script>
<script src="/static/resources/js/components/search/search.directive.js"></script>