Merge remote-tracking branch 'upstream/new-ui-with-sync-image' into new-ui-with-sync-image

This commit is contained in:
Wenkai Yin
2016-07-06 14:03:27 +08:00
33 changed files with 298 additions and 163 deletions
+1
View File
@@ -8,6 +8,7 @@ REGISTRY_URL=http://registry:5000
VERIFY_REMOTE_CERT=$verify_remote_cert
MAX_JOB_WORKERS=$max_job_workers
LOG_LEVEL=debug
LOG_DIR=/var/log/jobs
GODEBUG=netdns=cgo
EXT_ENDPOINT=$ui_url
TOKEN_URL=http://ui
+22 -22
View File
@@ -1139,24 +1139,40 @@ func TestGetRepPolicyByProject(t *testing.T) {
func TestGetRepJobByPolicy(t *testing.T) {
jobs, err := GetRepJobByPolicy(999)
if err != nil {
log.Errorf("Error occured in GetRepJobByPolicy: %v, policy ID: %d", err, 999)
t.Errorf("Error occured in GetRepJobByPolicy: %v, policy ID: %d", err, 999)
return
}
if len(jobs) > 0 {
log.Errorf("Unexpected length of jobs, expected: 0, in fact: %d", len(jobs))
t.Errorf("Unexpected length of jobs, expected: 0, in fact: %d", len(jobs))
return
}
jobs, err = GetRepJobByPolicy(policyID)
if err != nil {
log.Errorf("Error occured in GetRepJobByPolicy: %v, policy ID: %d", err, policyID)
t.Errorf("Error occured in GetRepJobByPolicy: %v, policy ID: %d", err, policyID)
return
}
if len(jobs) != 1 {
log.Errorf("Unexpected length of jobs, expected: 1, in fact: %d", len(jobs))
t.Errorf("Unexpected length of jobs, expected: 1, in fact: %d", len(jobs))
return
}
if jobs[0].ID != jobID {
log.Errorf("Unexpected job ID in the result, expected: %d, in fact: %d", jobID, jobs[0].ID)
t.Errorf("Unexpected job ID in the result, expected: %d, in fact: %d", jobID, jobs[0].ID)
return
}
}
func TestFilterRepJobs(t *testing.T) {
jobs, err := FilterRepJobs(policyID, "", "", nil, nil, 1000)
if err != nil {
t.Errorf("Error occured in FilterRepJobs: %v, policy ID: %d", err, policyID)
return
}
if len(jobs) != 1 {
t.Errorf("Unexpected length of jobs, expected: 1, in fact: %d", len(jobs))
return
}
if jobs[0].ID != jobID {
t.Errorf("Unexpected job ID in the result, expected: %d, in fact: %d", jobID, jobs[0].ID)
return
}
}
@@ -1179,22 +1195,6 @@ func TestDeleteRepJob(t *testing.T) {
}
}
func TestFilterRepJobs(t *testing.T) {
jobs, err := FilterRepJobs(policyID, "", "", nil, nil, 1000)
if err != nil {
log.Errorf("Error occured in FilterRepJobs: %v, policy ID: %d", err, policyID)
return
}
if len(jobs) != 1 {
log.Errorf("Unexpected length of jobs, expected: 1, in fact: %d", len(jobs))
return
}
if jobs[0].ID != jobID {
log.Errorf("Unexpected job ID in the result, expected: %d, in fact: %d", jobID, jobs[0].ID)
return
}
}
func TestGetRepoJobToStop(t *testing.T) {
jobs := [...]models.RepJob{
models.RepJob{
@@ -1265,7 +1265,7 @@ func TestDeleteRepTarget(t *testing.T) {
func TestFilterRepPolicies(t *testing.T) {
_, err := FilterRepPolicies("name", 0)
if err != nil {
t.Fatalf("failed to filter policy")
t.Fatalf("failed to filter policy: %v", err)
}
}
+7 -4
View File
@@ -150,10 +150,13 @@ func FilterRepPolicies(name string, projectID int64) ([]*models.RepPolicy, error
sql := `select rp.id, rp.project_id, p.name as project_name, rp.target_id,
rt.name as target_name, rp.name, rp.enabled, rp.description,
rp.cron_str, rp.start_time, rp.creation_time, rp.update_time
rp.cron_str, rp.start_time, rp.creation_time, rp.update_time,
count(rj.status) as error_job_count
from replication_policy rp
join project p on rp.project_id=p.project_id
join replication_target rt on rp.target_id=rt.id `
left join project p on rp.project_id=p.project_id
left join replication_target rt on rp.target_id=rt.id
left join replication_job rj on rp.id=rj.policy_id and (rj.status="error"
or rj.status="retrying") `
if len(name) != 0 && projectID != 0 {
sql += `where rp.name like ? and rp.project_id = ? `
@@ -167,7 +170,7 @@ func FilterRepPolicies(name string, projectID int64) ([]*models.RepPolicy, error
args = append(args, projectID)
}
sql += `order by rp.creation_time`
sql += `group by rp.id order by rp.creation_time`
var policies []*models.RepPolicy
if _, err := o.Raw(sql, args).QueryRows(&policies); err != nil {
+6 -1
View File
@@ -23,7 +23,7 @@ func retry(err error) bool {
if err == nil {
return false
}
return isTemporary(err)
return isNetworkErr(err)
}
func isTemporary(err error) bool {
@@ -32,3 +32,8 @@ func isTemporary(err error) bool {
}
return false
}
func isNetworkErr(err error) bool {
_, ok := err.(net.Error)
return ok
}
+7 -6
View File
@@ -56,12 +56,13 @@ type RepPolicy struct {
TargetName string `json:"target_name,omitempty"`
Name string `orm:"column(name)" json:"name"`
// Target RepTarget `orm:"-" json:"target"`
Enabled int `orm:"column(enabled)" json:"enabled"`
Description string `orm:"column(description)" json:"description"`
CronStr string `orm:"column(cron_str)" json:"cron_str"`
StartTime time.Time `orm:"column(start_time)" json:"start_time"`
CreationTime time.Time `orm:"column(creation_time);auto_now_add" json:"creation_time"`
UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"`
Enabled int `orm:"column(enabled)" json:"enabled"`
Description string `orm:"column(description)" json:"description"`
CronStr string `orm:"column(cron_str)" json:"cron_str"`
StartTime time.Time `orm:"column(start_time)" json:"start_time"`
CreationTime time.Time `orm:"column(creation_time);auto_now_add" json:"creation_time"`
UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"`
ErrorJobCount int `json:"error_job_count"`
}
// Valid ...
+27 -13
View File
@@ -110,20 +110,34 @@
}
.popover-header {
padding:8px 14px;
background-color:#f7f7f7;
border-bottom:1px solid #ebebeb;
-webkit-border-radius:5px 5px 0 0;
-moz-border-radius:5px 5px 0 0;
border-radius:5px 5px 0 0;
padding:8px 14px;
background-color:#f7f7f7;
border-bottom:1px solid #ebebeb;
-webkit-border-radius:5px 5px 0 0;
-moz-border-radius:5px 5px 0 0;
border-radius:5px 5px 0 0;
}
.popover-title {
height: 2.5em;
padding: 8px 14px;
margin: 0;
font-size: 14px;
background-color: #f7f7f7;
border-bottom: 1px solid #ebebeb;
border-radius: 5px 5px 0 0;
height: 2.5em;
padding: 8px 14px;
margin: 0;
font-size: 14px;
background-color: #f7f7f7;
border-bottom: 1px solid #ebebeb;
border-radius: 5px 5px 0 0;
}
.alert-custom {
position: fixed;
bottom: 24px;
z-index: 99;
width: 1110px;
padding: 10px;
background-color: #f2dede;
background-image: none;
}
.alert-custom .close {
right: 0;
}
@@ -44,7 +44,7 @@
}
function getProjectSuccess(data, status) {
vm.projects = data;
vm.projects = data || [];
if(!angular.isDefined(vm.projects)) {
vm.isPublic = 1;
@@ -77,11 +77,11 @@
});
}
function getProjectFailed(response) {
$scope.$emit('modalTitle', $filter('tr')('error'));
$scope.$emit('modalMessage', $filter('tr')('failed_to_get_project'));
$scope.$emit('raiseError', true);
console.log('Failed to list projects:' + response);
function getProjectFailed() {
// $scope.$emit('modalTitle', $filter('tr')('error'));
// $scope.$emit('modalMessage', $filter('tr')('failed_to_get_project'));
// $scope.$emit('raiseError', true);
console.log('Failed to list projects.');
}
function selectItem(item) {
@@ -91,7 +91,6 @@
$scope.$on('$locationChangeSuccess', function(e) {
var projectId = getParameterByName('project_id', $location.absUrl());
vm.checkProjectMember(projectId);
vm.isOpen = false;
});
@@ -107,12 +106,7 @@
}
function getCurrentProjectMemberFailed(data, status) {
vm.isProjectMember = false;
// $scope.$emit('modalTitle', $filter('tr')('error'));
// $scope.$emit('modalMessage', $filter('tr')('failed_to_get_project_member'));
// $scope.$emit('raiseError', true);
vm.isProjectMember = false;
console.log('Current user has no member for the project:' + status + ', location.url:' + $location.url());
}
@@ -0,0 +1,4 @@
<div ng-show="toggleAlert" class="alert alert-danger alert-dismissible alert-custom" role="alert">
<button type="button" class="close" ng-click="close()"><span aria-hidden="true">&times;</span></button>
<strong>// 'caution' | tr //</strong>&nbsp;&nbsp;//message//
</div>
@@ -0,0 +1,34 @@
(function() {
'use strict';
angular
.module('harbor.dismissable.alerts')
.directive('dismissableAlerts', dismissableAlerts);
function dismissableAlerts() {
var directive = {
'restrict': 'E',
'templateUrl': '/static/resources/js/components/dismissable-alerts/dismissable-alerts.directive.html',
'link': link
};
return directive;
function link(scope, element, attrs, ctrl) {
scope.close = function() {
scope.toggleAlert = false;
}
scope.$on('raiseAlert', function(e, val) {
console.log('received raiseAlert:' + angular.toJson(val));
if(val.show) {
scope.message = val.message;
scope.toggleAlert = true;
}else{
scope.message = ''
scope.toggleAlert = false;
}
});
}
}
})();
@@ -0,0 +1,7 @@
(function() {
'use strict';
angular.module('harbor.dismissable.alerts', []);
})();
@@ -1,5 +1,3 @@
<a href="javascript:void(0)" role="button" tab-index="0"
data-trigger="focus" data-toggle="popover" data-placement="right"
data-title="//vm.helpTitle//">
<a role="button" tab-index="0" data-trigger="focus" data-toggle="popover" data-placement="right" data-title="//vm.helpTitle//">
<span class="glyphicon glyphicon-info-sign"></span>
</a>
@@ -37,9 +37,15 @@
'projectId': vm.projectId,
'username' : vm.username
};
retrieve(vm.queryParams);
$scope.$on('$locationChangeSuccess', function() {
if(vm.publicity) {
vm.target = 'repositories';
}
vm.projectId = getParameterByName('project_id', $location.absUrl());
vm.queryParams = {
'beginTimestamp' : vm.beginTimestamp,
@@ -128,7 +134,9 @@
restrict: 'E',
templateUrl: '/static/resources/js/components/log/list-log.directive.html',
scope: {
'sectionHeight': '='
'sectionHeight': '=',
'target': '=',
'publicity': '='
},
controller: ListLogController,
controllerAs: 'vm',
@@ -2,7 +2,7 @@
<td width="45%"><switch-role roles="vm.roles" edit-mode="vm.editMode" user-id="vm.userId" role-name="vm.roleName"></switch-role></td>
<td width="25%">
<a ng-show="vm.userId != vm.currentUserId" href="javascript:void(0);" ng-click="vm.updateProjectMember({projectId: vm.projectId, userId: vm.userId, roleId: vm.roleId})">
<span ng-if="!vm.editMode" class="glyphicon glyphicon-pencil" title="// 'edit' | tr //"></span><span ng-if="vm.editMode" class="glyphicon glyphicon-ok" title="Confirm">
<span ng-if="!vm.editMode" class="glyphicon glyphicon-pencil" title="// 'edit' | tr //"></span><span ng-if="vm.editMode" class="glyphicon glyphicon-ok" title="// 'confirm' | tr //">
</a>
<a ng-show="vm.userId != vm.currentUserId" href="javascript:void(0);" ng-click="vm.cancelUpdate()" title="// 'cancel' | tr //">
<span ng-if="vm.editMode" class="glyphicon glyphicon-remove"></span>
@@ -22,7 +22,7 @@
vm.deleteProjectMember = deleteProjectMember;
vm.retrieve = retrieve;
vm.username = '';
vm.projectId = getParameterByName('project_id', $location.absUrl());
vm.retrieve();
@@ -78,11 +78,7 @@
function getProjectMemberFailed(response) {
console.log('Failed to get project members:' + response);
vm.projectMembers = [];
$scope.$emit('modalTitle', $filter('tr')('error'));
$scope.$emit('modalMessage', $filter('tr')('failed_to_get_project_member'));
$scope.$emit('raiseError', true);
vm.target = 'repositories';
$location.url('repositories').search('project_id', vm.projectId);
}
@@ -93,7 +89,8 @@
'restrict': 'E',
'templateUrl': '/static/resources/js/components/project-member/list-project-member.directive.html',
'scope': {
'sectionHeight': '='
'sectionHeight': '=',
'target': '='
},
'controller': ListProjectMemberController,
'controllerAs': 'vm',
@@ -14,7 +14,7 @@
</div>
<div class="form-group" style="margin-top: 5px;">
<input type="checkbox" ng-model="vm.isPublic">&nbsp;// 'public' | tr //
<inline-help help-title="// 'inline_help_publicity_title' | tr //" content="// 'inline_help_publicity' | tr //"></inline-help>
<inline-help help-title="//'inline_help_publicity_title' | tr//" content="//'inline_help_publicity' | tr//"></inline-help>
</div>
</div>
<div class="col-xs-2 col-md-2">
@@ -6,19 +6,38 @@
.module('harbor.project')
.directive('publicityButton', publicityButton);
PublicityButtonController.$inject = ['ToggleProjectPublicityService'];
PublicityButtonController.$inject = ['$scope', 'ToggleProjectPublicityService', '$filter', 'trFilter'];
function PublicityButtonController(ToggleProjectPublicityService) {
function PublicityButtonController($scope, ToggleProjectPublicityService, $filter, trFilter) {
var vm = this;
vm.toggle = toggle;
if(vm.isPublic === 1) {
vm.isPublic = true;
}else{
vm.isPublic = false;
function toggle() {
if(vm.isPublic) {
vm.isPublic = false;
}else{
vm.isPublic = true;
}
ToggleProjectPublicityService(vm.projectId, vm.isPublic)
.success(toggleProjectPublicitySuccess)
.error(toggleProjectPublicityFailed);
}
function toggle() {
function toggleProjectPublicitySuccess(data, status) {
console.log('Successful toggle project publicity.');
}
function toggleProjectPublicityFailed(e, status) {
$scope.$emit('modalTitle', $filter('tr')('error'));
var message;
if(status === 403) {
message = $filter('tr')('failed_to_toggle_publicity_insuffient_permissions');
}else{
message = $filter('tr')('failed_to_toggle_publicity');
}
$scope.$emit('modalMessage', message);
$scope.$emit('raiseError', true);
if(vm.isPublic) {
vm.isPublic = false;
@@ -26,16 +45,6 @@
vm.isPublic = true;
}
ToggleProjectPublicityService(vm.projectId, vm.isPublic)
.success(toggleProjectPublicitySuccess)
.error(toggleProjectPublicityFailed);
}
function toggleProjectPublicitySuccess(data, status) {
console.log('Successful toggle project publicity.');
}
function toggleProjectPublicityFailed(e) {
console.log('Failed to toggle project publicity:' + e);
}
}
@@ -57,7 +66,11 @@
return directive;
function link(scope, element, attr, ctrl) {
scope.$watch('vm.isPublic', function(current, origin) {
if(current) {
ctrl.isPublic = current;
}
});
}
}
@@ -171,6 +171,7 @@
vm.policy = policy;
if(vm.targetEditable) {
vm.policy.targetId = vm1.selection.id;
saveDestination();
saveOrUpdatePolicy();
}
}
@@ -366,6 +367,8 @@
ctrl.pingMessage = '';
ctrl.pingAvailable = true;
ctrl.saveTIP = false;
ctrl.pingTIP = false;
ctrl.toggleErrorMessage = false;
ctrl.errorMessages = [];
@@ -41,8 +41,8 @@
</td>
<td width="15%">
<div class="display-inline-block" ng-switch on="//r.enabled//">
<a href="javascript:void(0);" ng-click="vm.togglePolicy(r.id, 0)" title="// 'disabled' | tr //"><span ng-switch-when="1" class="glyphicon glyphicon-stop color-danger"></span></a>
<a href="javascript:void(0);" ng-click="vm.togglePolicy(r.id, 1)" title="// 'enabled' | tr //"><span ng-switch-when="0" class="glyphicon glyphicon-play color-success"></span></a>
<a href="javascript:void(0);" ng-click="vm.togglePolicy(r.id, 0)" title="// 'disable' | tr //"><span ng-switch-when="1" class="glyphicon glyphicon-stop color-danger"></span></a>
<a href="javascript:void(0);" ng-click="vm.togglePolicy(r.id, 1)" title="// 'enable' | tr //"><span ng-switch-when="0" class="glyphicon glyphicon-play color-success"></span></a>
</div>
&nbsp;
<a href="javascript:void(0);" data-toggle="modal" data-target="#createPolicyModal" ng-click="vm.editReplication(r.id)" title="// 'edit_policy' | tr //"><span class="glyphicon glyphicon-pencil"></span></a>
@@ -15,6 +15,7 @@
{'key': 'pending', 'value': $filter('tr')('pending')},
{'key': 'running', 'value': $filter('tr')('running')},
{'key': 'error' , 'value': $filter('tr')('error')},
{'key': 'retrying', 'value': $filter('tr')('retrying')},
{'key': 'stopped', 'value': $filter('tr')('stopped')},
{'key': 'finished', 'value':$filter('tr')('finished')},
{'key': 'canceled', 'value': $filter('tr')('canceled')}
@@ -28,7 +29,7 @@
var vm = this;
vm.sectionHeight = {'min-height': '1200px'};
$scope.$on('$locationChangeSuccess', function() {
vm.projectId = getParameterByName('project_id', $location.absUrl());
vm.retrievePolicy();
@@ -59,7 +60,7 @@
vm.searchJobTIP = false;
vm.refreshJobTIP = false;
function searchReplicationPolicy() {
vm.retrievePolicy();
}
@@ -102,9 +103,17 @@
function listReplicationJobSuccess(data, status) {
vm.replicationJobs = data || [];
var alertInfo = {
'show': false,
'message': ''
};
angular.forEach(vm.replicationJobs, function(item) {
for(var key in item) {
var value = item[key]
var value = item[key];
if(key === 'status' && (value === 'error' || value === 'retrying')) {
alertInfo.show = true;
alertInfo.message = $filter('tr')('alert_job_contains_error');
}
switch(key) {
case 'operation':
case 'status':
@@ -114,6 +123,8 @@
}
}
});
$scope.$emit('raiseAlert', alertInfo);
vm.searchJobTIP = false;
vm.refreshJobTIP = false;
}
@@ -17,7 +17,7 @@
vm.filterInput = '';
vm.toggleInProgress = [];
var hashValue = $location.hash();
if(hashValue) {
var slashIndex = hashValue.indexOf('/');
@@ -31,13 +31,13 @@
function retrieve() {
ListTagService(vm.repoName)
.then(getTagComplete)
.catch(getTagFailed);
.success(getTagSuccess)
.error(getTagFailed);
}
function getTagComplete(response) {
function getTagSuccess(data) {
vm.tags = response.data;
vm.tags = data || [];
vm.tagCount[vm.repoName] = vm.tags.length;
$scope.$emit('tags', vm.tags);
@@ -48,11 +48,11 @@
});
}
function getTagFailed(response) {
function getTagFailed(data) {
$scope.$emit('modalTitle', $filter('tr')('error'));
$scope.$emit('modalMessage', $filter('tr')('failed_to_get_tag') + response);
$scope.$emit('raiseError', true);
console.log('Failed to get tag:' + response);
console.log('Failed to get tag:' + data);
}
function deleteTag(e) {
@@ -49,7 +49,7 @@
<div class="form-group col-md-12 form-group-custom">
<div class="col-md-3"></div>
<div class="col-md-9">
<button type="submit" class="btn btn-default" ng-disabled="vm.notAvailable || !vm.pingAvailable" ng-click="form.$valid && vm.pingDestination()" loading-progress hide-target="false" toggle-in-progress="vm.pingTIP">// 'test_connection' | tr //</button>
<button type="button" class="btn btn-default" ng-disabled="vm.notAvailable || !vm.pingAvailable" ng-click="vm.pingDestination()" loading-progress hide-target="false" toggle-in-progress="vm.pingTIP">// 'test_connection' | tr //</button>
</div>
</div>
<div class="form-group col-md-12 form-group-custom">
@@ -21,7 +21,7 @@
vm.pingDestination = pingDestination;
vm.editable = true;
vm.notAvailable = true;
vm.notAvailable = false;
vm.pingAvailable = true;
vm.pingMessage = '';
@@ -40,7 +40,6 @@
});
function addNew() {
vm.editable = true;
vm.modalTitle = $filter('tr')('add_new_destination', []);
vm0.name = '';
vm0.endpoint = '';
@@ -153,7 +152,7 @@
function pingDestinationFailed(data, status) {
vm.pingTIP = false;
vm.pingMessage = $filter('tr')('failed_to_ping_target', []) + (data && data.length > 0 ? ':' + data : '.');
vm.pingMessage = $filter('tr')('failed_to_ping_target', []) + (data && data.length > 0 ? ':' + data : '');
}
}
@@ -176,33 +175,34 @@
function link(scope, element, attrs, ctrl) {
element.find('#createDestinationModal').on('show.bs.modal', function() {
scope.form.$setPristine();
scope.form.$setUntouched();
ctrl.notAvailble = true;
ctrl.pingAvailable = true;
ctrl.pingMessage = '';
ctrl.toggleErrorMessage = false;
ctrl.errorMessages = [];
switch(ctrl.action) {
case 'ADD_NEW':
ctrl.addNew();
break;
case 'EDIT':
ctrl.edit(ctrl.targetId);
break;
}
scope.$watch('vm.errorMessages', function(current) {
if(current && current.length > 0) {
ctrl.toggleErrorMessage = true;
scope.$apply(function(){
scope.form.$setPristine();
scope.form.$setUntouched();
ctrl.notAvailble = false;
ctrl.pingAvailable = true;
ctrl.pingMessage = '';
ctrl.pingTIP = false;
ctrl.toggleErrorMessage = false;
ctrl.errorMessages = [];
switch(ctrl.action) {
case 'ADD_NEW':
ctrl.addNew();
break;
case 'EDIT':
ctrl.edit(ctrl.targetId);
break;
}
}, true);
scope.$apply();
scope.$watch('vm.errorMessages', function(current) {
if(current && current.length > 0) {
ctrl.toggleErrorMessage = true;
}
}, true);
});
});
ctrl.save = save;
@@ -33,9 +33,9 @@
<td width="30%">//r.endpoint//</td>
<td width="35%">//r.creation_time | dateL : 'YYYY-MM-DD HH:mm:ss'//</td>
<td width="15%">
<a href="javascript:void(0);" data-toggle="modal" data-target="#createDestinationModal" ng-click="vm.editDestination(r.id)"><span class="glyphicon glyphicon-pencil"></span></a>
<a href="javascript:void(0);" data-toggle="modal" data-target="#createDestinationModal" ng-click="vm.editDestination(r.id)" title="// 'edit' | tr //" ><span class="glyphicon glyphicon-pencil"></span></a>
&nbsp;
<a href="javascript:void(0);" ng-click="vm.confirmToDelete(r.id)"><span class="glyphicon glyphicon-trash"></span></a>
<a href="javascript:void(0);" ng-click="vm.confirmToDelete(r.id)" title="// 'delete' | tr //"><span class="glyphicon glyphicon-trash"></span></a>
</td>
</tr>
</tbody>
@@ -42,11 +42,11 @@
</td>
<td width="12%">
<div class="display-inline-block" ng-switch on="//r.enabled//">
<a href="javascript:void(0);" ng-click="vm.togglePolicy(r.id, 0)"><span ng-switch-when="1" class="glyphicon glyphicon-stop color-danger"></span></a>
<a href="javascript:void(0);" ng-click="vm.togglePolicy(r.id, 1)"><span ng-switch-when="0" class="glyphicon glyphicon-play color-success"></span></a>
<a href="javascript:void(0);" ng-click="vm.togglePolicy(r.id, 0)" title="// 'disable' | tr //"><span ng-switch-when="1" class="glyphicon glyphicon-stop color-danger"></span></a>
<a href="javascript:void(0);" ng-click="vm.togglePolicy(r.id, 1)" title="// 'enable' | tr //"><span ng-switch-when="0" class="glyphicon glyphicon-play color-success"></span></a>
</div>
&nbsp;
<a href="javascript:void(0);" data-toggle="modal" data-target="#createPolicyModal" ng-click="vm.editReplication(r.id)"><span class="glyphicon glyphicon-pencil"></span></a>
<a href="javascript:void(0);" data-toggle="modal" data-target="#createPolicyModal" ng-click="vm.editReplication(r.id)" title="// 'edit_policy' | tr //"><span class="glyphicon glyphicon-pencil"></span></a>
&nbsp;
<!--a href="javascript:void(0);"><span class="glyphicon glyphicon-trash"></span></a-->
</td>
@@ -34,6 +34,11 @@
$scope.$emit('modalTitle', $filter('tr')('error'));
$scope.$emit('modalMessage', $filter('tr')('failed_to_toggle_admin'));
$scope.$emit('raiseError', true);
if(vm.isAdmin) {
vm.isAdmin = false;
}else{
vm.isAdmin = true;
}
console.log('Failed to toggle admin:' + data);
}
}
+25 -6
View File
@@ -20,17 +20,36 @@
function RedirectInterceptorService($q, $window) {
return {
'responseError': function(rejection) {
var pathname = $window.location.pathname;
var exclusion = ['/', '/search', '/reset_password', '/sign_up', '/forgot_password', '/repository'];
var url = rejection.config.url;
console.log('url:' + url);
var exclusion = [
'/',
'/search',
'/reset_password',
'/sign_up',
'/forgot_password',
'/api/targets/ping',
'/api/users/current',
'/api/repositories',
/^\/api\/projects\/[0-9]+\/members\/current$/
];
var isExcluded = false;
for(var i in exclusion) {
if(exclusion[i] === pathname) {
isExcluded = true;
switch(typeof(exclusion[i])) {
case 'string':
isExcluded = (exclusion[i] === url);
break;
case 'object':
isExcluded = exclusion[i].test(url);
break;
}
}
if(rejection.status === 401 && !isExcluded) {
if(isExcluded) {
break;
}
}
if(!isExcluded && rejection.status === 401) {
$window.location.href = '/';
return;
}
return $q.reject(rejection);
}
+2 -1
View File
@@ -45,6 +45,7 @@
'harbor.replication',
'harbor.system.management',
'harbor.loading.progress',
'harbor.inline.help'
'harbor.inline.help',
'harbor.dismissable.alerts'
]);
})();
@@ -15,7 +15,6 @@
vm.isProjectMember = false;
vm.togglePublicity = togglePublicity;
vm.target = 'repositories';
vm.sectionDefaultHeight = {'min-height': '579px'};
@@ -55,7 +54,7 @@
}
});
function togglePublicity(e) {
function togglePublicity(e) {
vm.publicity = e.publicity;
}
}
@@ -79,6 +79,7 @@ var locale_messages = {
'new_project': 'New Project',
'save': 'Save',
'cancel': 'Cancel',
'confirm': 'Confirm',
'items': 'items',
'add_member': 'Add Member',
'operation': 'Operation',
@@ -153,7 +154,9 @@ var locale_messages = {
'status': 'Status',
'logs' : 'Logs',
'enabled': 'Enabled',
'enable': 'Enable',
'disabled': 'Disabled',
'disable': 'Disable',
'no_replication_policies_add_new': 'No replication policies, add new replication policy.',
'no_replication_policies': 'No replication policies.',
'no_replication_jobs': 'No replication jobs.',
@@ -186,9 +189,9 @@ var locale_messages = {
'successful_added': 'Added new user successfully.',
'copyright': 'Copyright',
'all_rights_reserved': 'All Rights Reserved.',
'pinging_target': 'Testing connection, please wait...',
'pinging_target': 'Testing connection, please stand by...',
'successful_ping_target': 'Test connection successfully.',
'failed_to_ping_target': 'Faild to connect target.',
'failed_to_ping_target': 'Cannot connect to the target.',
'policy_already_exists': 'Policy alreay exists.',
'destination_already_exists': 'Destination already exists.',
'refresh': 'Refresh',
@@ -205,6 +208,7 @@ var locale_messages = {
'finished': 'Finished',
'canceled': 'Canceled',
'stopped': 'Stopped',
'retrying': 'Retrying',
'error': 'Error',
'failed_to_get_project_member': 'Failed to get current project member.',
'failed_to_delete_repo': 'Failed to delete repository. ',
@@ -235,6 +239,8 @@ var locale_messages = {
'failed_to_delete_destination': 'Failed to delete destination.',
'failed_to_create_destination': 'Failed to create destination.',
'failed_to_update_destination': 'Failed to update destination.',
'failed_to_toggle_publicity_insuffient_permissions': 'Failed to toggle project publicity, insuffient permissions.',
'failed_to_toggle_publicity': 'Failed to toggle project publicity.',
'project_admin': 'Project Admin',
'developer': 'Developer',
'guest': 'Guest',
@@ -243,6 +249,7 @@ var locale_messages = {
'<strong>Developer</strong>: Developer has read and write privileges for a project.<br/>' +
'<strong>Guest</strong>: Guest has read-only privilege for a specified project.',
'inline_help_publicity_title': '<strong>Publicity of Project</strong>',
'inline_help_publicity': 'Setting the project as public.'
'inline_help_publicity': 'Setting the project as public.',
'alert_job_contains_error': 'Found errors in the current replication jobs, please look into it.',
'caution': 'Caution'
};
@@ -79,6 +79,7 @@ var locale_messages = {
'new_project': '新增项目',
'save': '保存',
'cancel': '取消',
'confirm': '确认',
'items': '条记录',
'add_member': '新增成员',
'operation': '操作',
@@ -150,8 +151,10 @@ var locale_messages = {
'actions': '操作',
'status': '状态',
'logs': '日志',
'enabled': '启用',
'disabled': '用',
'enabled': '启用',
'enable': '用',
'disabled': '已停用',
'disable': '停用',
'no_replication_policies_add_new': '没有复制策略,请新增复制策略。',
'no_replication_policies': '没有复制策略。',
'no_replications': '没有复制策略。',
@@ -160,7 +163,6 @@ var locale_messages = {
'name_is_required': '名称为必填项',
'name_is_too_long': '名称长度超出限制。(最长为20个字符)',
'description_is_too_long': '描述内容长度超出限制。(最长为20个字符)',
'enable': '启用',
'general_setting': '一般设置',
'destination_setting': '目标设置',
'endpoint': '终端URL',
@@ -199,12 +201,13 @@ var locale_messages = {
'edit': '修改',
'delete': '删除',
'all': '全部',
'transfer': '传输',
'pending': '等待',
'transfer': '复制',
'pending': '等待',
'running': '进行中',
'finished': '已完成',
'canceled': '取消',
'stopped': '止',
'canceled': '取消',
'stopped': '已终止',
'retrying': '重试中',
'error': '错误',
'failed_to_get_project_member': '无法获取当前项目成员。',
'failed_to_delete_repo': '无法删除镜像仓库。',
@@ -235,6 +238,8 @@ var locale_messages = {
'failed_to_delete_destination': '删除目标失败。',
'failed_to_create_destination': '创建目标失败。',
'failed_to_update_destination': '修改目标失败。',
'failed_to_toggle_publicity_insuffient_permissions': '切换项目公开失败,权限不足。',
'failed_to_toggle_publicity': '切换项目公开失败。',
'project_admin': '项目管理员',
'developer': '开发人员',
'guest': '来宾用户',
@@ -243,5 +248,7 @@ var locale_messages = {
'<strong>开发人员</strong>: “开发人员” 拥有一个项目的读/写权限。<br/>' +
'<strong>来宾用户</strong>: “来宾用户”拥有特定项目的只读权限。',
'inline_help_publicity_title': '<strong>公开项目</strong>',
'inline_help_publicity': '设置该项目为公开。'
'inline_help_publicity': '设置该项目为公开。',
'alert_job_contains_error': '当前复制任务中包含错误,请检查。',
'caution': '注意'
};
+4 -3
View File
@@ -2,7 +2,7 @@
<modal-dialog action="vm.action()" content-type="//vm.contentType//" modal-title="//vm.modalTitle//" modal-message="//vm.modalMessage//" confirm-only="vm.confirmOnly"></modal-dialog>
<div class="container container-custom">
<div class="row extend-height">
<div class="col-xs-12 col-md-12 extend-height">
<div class="col-xs-12 col-md-12 extend-height">
<div class="section" ng-style="vm.sectionHeight">
<h4 class="page-header">
<span ng-show="!vm.publicity">// 'my_projects' | tr //</span>
@@ -22,10 +22,11 @@
<input type="hidden" id="HarborRegUrl" value="{{.HarborRegUrl}}">
<list-repository ng-if="vm.target === 'repositories'" section-height="vm.sectionHeight"></list-repository>
<list-replication ng-if="vm.target === 'replication'" section-height="vm.sectionHeight"></list-replication>
<list-project-member ng-if="vm.target === 'users'" section-height="vm.sectionHeight"></list-project-member>
<list-log ng-if="vm.target === 'logs'" section-height="vm.sectionHeight"></list-log>
<list-project-member ng-if="vm.target === 'users'" section-height="vm.sectionHeight" target="vm.target"></list-project-member>
<list-log ng-if="vm.target === 'logs'" section-height="vm.sectionHeight" target="vm.target" publicity="vm.publicity"></list-log>
</div>
</div>
<dismissable-alerts></dismissable-alerts>
</div>
</div>
</div>
+4 -1
View File
@@ -240,4 +240,7 @@
<script src="/static/resources/js/components/loading-progress/loading-progress.directive.js"></script>
<script src="/static/resources/js/components/inline-help/inline-help.module.js"></script>
<script src="/static/resources/js/components/inline-help/inline-help.directive.js"></script>
<script src="/static/resources/js/components/inline-help/inline-help.directive.js"></script>
<script src="/static/resources/js/components/dismissable-alerts/dismissable-alerts.module.js"></script>
<script src="/static/resources/js/components/dismissable-alerts/dismissable-alerts.directive.js"></script>