diff --git a/Deploy/templates/jobservice/env b/Deploy/templates/jobservice/env
index 9422721..5359e85 100644
--- a/Deploy/templates/jobservice/env
+++ b/Deploy/templates/jobservice/env
@@ -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
diff --git a/dao/dao_test.go b/dao/dao_test.go
index 5a17986..6992247 100644
--- a/dao/dao_test.go
+++ b/dao/dao_test.go
@@ -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)
}
}
diff --git a/dao/replication_job.go b/dao/replication_job.go
index f0d4782..adc4739 100644
--- a/dao/replication_job.go
+++ b/dao/replication_job.go
@@ -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 {
diff --git a/job/replication/error.go b/job/replication/error.go
index 197dabb..19eedd1 100644
--- a/job/replication/error.go
+++ b/job/replication/error.go
@@ -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
+}
diff --git a/models/replication_job.go b/models/replication_job.go
index 59c2ad3..8d847f9 100644
--- a/models/replication_job.go
+++ b/models/replication_job.go
@@ -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 ...
diff --git a/static/resources/css/repository.css b/static/resources/css/repository.css
index 6c927ec..29fe870 100644
--- a/static/resources/css/repository.css
+++ b/static/resources/css/repository.css
@@ -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;
+}
\ No newline at end of file
diff --git a/static/resources/js/components/details/retrieve-projects.directive.js b/static/resources/js/components/details/retrieve-projects.directive.js
index 8ed1d9a..9d8e873 100644
--- a/static/resources/js/components/details/retrieve-projects.directive.js
+++ b/static/resources/js/components/details/retrieve-projects.directive.js
@@ -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());
}
diff --git a/static/resources/js/components/dismissable-alerts/dismissable-alerts.directive.html b/static/resources/js/components/dismissable-alerts/dismissable-alerts.directive.html
new file mode 100644
index 0000000..fb0bd2a
--- /dev/null
+++ b/static/resources/js/components/dismissable-alerts/dismissable-alerts.directive.html
@@ -0,0 +1,4 @@
+
+ ×
+ // 'caution' | tr // //message//
+
\ No newline at end of file
diff --git a/static/resources/js/components/dismissable-alerts/dismissable-alerts.directive.js b/static/resources/js/components/dismissable-alerts/dismissable-alerts.directive.js
new file mode 100644
index 0000000..09bfa05
--- /dev/null
+++ b/static/resources/js/components/dismissable-alerts/dismissable-alerts.directive.js
@@ -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;
+ }
+ });
+ }
+ }
+
+})();
\ No newline at end of file
diff --git a/static/resources/js/components/dismissable-alerts/dismissable-alerts.module.js b/static/resources/js/components/dismissable-alerts/dismissable-alerts.module.js
new file mode 100644
index 0000000..d6a7e61
--- /dev/null
+++ b/static/resources/js/components/dismissable-alerts/dismissable-alerts.module.js
@@ -0,0 +1,7 @@
+(function() {
+
+ 'use strict';
+
+ angular.module('harbor.dismissable.alerts', []);
+
+})();
\ No newline at end of file
diff --git a/static/resources/js/components/inline-help/inline-help.directive.html b/static/resources/js/components/inline-help/inline-help.directive.html
index 3855f53..4d32d29 100644
--- a/static/resources/js/components/inline-help/inline-help.directive.html
+++ b/static/resources/js/components/inline-help/inline-help.directive.html
@@ -1,5 +1,3 @@
-
+
\ No newline at end of file
diff --git a/static/resources/js/components/log/list-log.directive.js b/static/resources/js/components/log/list-log.directive.js
index 567f035..ece3190 100644
--- a/static/resources/js/components/log/list-log.directive.js
+++ b/static/resources/js/components/log/list-log.directive.js
@@ -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',
diff --git a/static/resources/js/components/project-member/edit-project-member.directive.html b/static/resources/js/components/project-member/edit-project-member.directive.html
index 7dff549..09627f5 100644
--- a/static/resources/js/components/project-member/edit-project-member.directive.html
+++ b/static/resources/js/components/project-member/edit-project-member.directive.html
@@ -2,7 +2,7 @@
-
+
diff --git a/static/resources/js/components/project-member/list-project-member.directive.js b/static/resources/js/components/project-member/list-project-member.directive.js
index 77415f6..7c537ca 100644
--- a/static/resources/js/components/project-member/list-project-member.directive.js
+++ b/static/resources/js/components/project-member/list-project-member.directive.js
@@ -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',
diff --git a/static/resources/js/components/project/add-project.directive.html b/static/resources/js/components/project/add-project.directive.html
index 16fa3c9..52c0d50 100644
--- a/static/resources/js/components/project/add-project.directive.html
+++ b/static/resources/js/components/project/add-project.directive.html
@@ -14,7 +14,7 @@
// 'public' | tr //
-
+
diff --git a/static/resources/js/components/project/publicity-button.directive.js b/static/resources/js/components/project/publicity-button.directive.js
index 5d86eb0..84c1f43 100644
--- a/static/resources/js/components/project/publicity-button.directive.js
+++ b/static/resources/js/components/project/publicity-button.directive.js
@@ -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;
+ }
+ });
}
}
diff --git a/static/resources/js/components/replication/create-policy.directive.js b/static/resources/js/components/replication/create-policy.directive.js
index 100273c..b1bc16a 100644
--- a/static/resources/js/components/replication/create-policy.directive.js
+++ b/static/resources/js/components/replication/create-policy.directive.js
@@ -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 = [];
diff --git a/static/resources/js/components/replication/list-replication.directive.html b/static/resources/js/components/replication/list-replication.directive.html
index f748c88..bc5a845 100644
--- a/static/resources/js/components/replication/list-replication.directive.html
+++ b/static/resources/js/components/replication/list-replication.directive.html
@@ -41,8 +41,8 @@
diff --git a/static/resources/js/components/replication/list-replication.directive.js b/static/resources/js/components/replication/list-replication.directive.js
index 0b38dfe..e8dbd8c 100644
--- a/static/resources/js/components/replication/list-replication.directive.js
+++ b/static/resources/js/components/replication/list-replication.directive.js
@@ -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;
}
diff --git a/static/resources/js/components/repository/list-repository.directive.js b/static/resources/js/components/repository/list-repository.directive.js
index 2bd1aca..2abd5dc 100644
--- a/static/resources/js/components/repository/list-repository.directive.js
+++ b/static/resources/js/components/repository/list-repository.directive.js
@@ -17,7 +17,7 @@
vm.filterInput = '';
vm.toggleInProgress = [];
-
+
var hashValue = $location.hash();
if(hashValue) {
var slashIndex = hashValue.indexOf('/');
diff --git a/static/resources/js/components/repository/list-tag.directive.js b/static/resources/js/components/repository/list-tag.directive.js
index 38b3abb..c797bd5 100644
--- a/static/resources/js/components/repository/list-tag.directive.js
+++ b/static/resources/js/components/repository/list-tag.directive.js
@@ -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) {
diff --git a/static/resources/js/components/system-management/create-destination.directive.html b/static/resources/js/components/system-management/create-destination.directive.html
index a5f1f50..04f0765 100644
--- a/static/resources/js/components/system-management/create-destination.directive.html
+++ b/static/resources/js/components/system-management/create-destination.directive.html
@@ -49,7 +49,7 @@
-
+
diff --git a/static/resources/js/components/user/toggle-admin.directive.js b/static/resources/js/components/user/toggle-admin.directive.js
index 999e796..d0eac16 100644
--- a/static/resources/js/components/user/toggle-admin.directive.js
+++ b/static/resources/js/components/user/toggle-admin.directive.js
@@ -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);
}
}
diff --git a/static/resources/js/harbor.config.js b/static/resources/js/harbor.config.js
index 2196a1f..8e8c392 100644
--- a/static/resources/js/harbor.config.js
+++ b/static/resources/js/harbor.config.js
@@ -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);
}
diff --git a/static/resources/js/harbor.module.js b/static/resources/js/harbor.module.js
index 3b7e85a..d92272c 100644
--- a/static/resources/js/harbor.module.js
+++ b/static/resources/js/harbor.module.js
@@ -45,6 +45,7 @@
'harbor.replication',
'harbor.system.management',
'harbor.loading.progress',
- 'harbor.inline.help'
+ 'harbor.inline.help',
+ 'harbor.dismissable.alerts'
]);
})();
\ No newline at end of file
diff --git a/static/resources/js/layout/details/details.controller.js b/static/resources/js/layout/details/details.controller.js
index 974ae16..c2d6c03 100644
--- a/static/resources/js/layout/details/details.controller.js
+++ b/static/resources/js/layout/details/details.controller.js
@@ -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;
}
}
diff --git a/static/resources/js/services/i18n/locale_messages_en-US.js b/static/resources/js/services/i18n/locale_messages_en-US.js
index b14060f..f72d492 100644
--- a/static/resources/js/services/i18n/locale_messages_en-US.js
+++ b/static/resources/js/services/i18n/locale_messages_en-US.js
@@ -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 = {
'Developer : Developer has read and write privileges for a project. ' +
'Guest : Guest has read-only privilege for a specified project.',
'inline_help_publicity_title': 'Publicity of Project ',
- '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'
};
\ No newline at end of file
diff --git a/static/resources/js/services/i18n/locale_messages_zh-CN.js b/static/resources/js/services/i18n/locale_messages_zh-CN.js
index 3d34db4..895d959 100644
--- a/static/resources/js/services/i18n/locale_messages_zh-CN.js
+++ b/static/resources/js/services/i18n/locale_messages_zh-CN.js
@@ -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 = {
'开发人员 : “开发人员” 拥有一个项目的读/写权限。 ' +
'来宾用户 : “来宾用户”拥有特定项目的只读权限。',
'inline_help_publicity_title': '公开项目 ',
- 'inline_help_publicity': '设置该项目为公开。'
+ 'inline_help_publicity': '设置该项目为公开。',
+ 'alert_job_contains_error': '当前复制任务中包含错误,请检查。',
+ 'caution': '注意'
};
\ No newline at end of file
diff --git a/views/repository.htm b/views/repository.htm
index 7e5f45f..7aaa029 100644
--- a/views/repository.htm
+++ b/views/repository.htm
@@ -2,7 +2,7 @@
diff --git a/views/sections/header-include.htm b/views/sections/header-include.htm
index 5f83064..a78d61c 100644
--- a/views/sections/header-include.htm
+++ b/views/sections/header-include.htm
@@ -240,4 +240,7 @@
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file