mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-24 07:41:40 +01:00
updates on UI for other pages.
This commit is contained in:
parent
8d07275040
commit
eb26c59738
@ -11,7 +11,7 @@
|
||||
<div class="project-list pane-container">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item" ng-repeat="item in vm.projects | name: vm.filterInput: 'Name'" ng-click="vm.selectItem(item)">
|
||||
<span ng-show="item.ProjectId == vm.selectedId" class="glyphicon glyphicon-ok project-selected"></span> <a href="/ng/repository#/repositories">//item.Name//</a>
|
||||
<span ng-show="item.ProjectId == vm.selectedId" class="glyphicon glyphicon-ok project-selected"></span> <a href="#/repositories?project_id=//item.ProjectId//">//item.Name//</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -13,10 +13,10 @@
|
||||
|
||||
$scope.$watch('vm.selectedProject', function(current, origin) {
|
||||
if(current) {
|
||||
vm.selectedId = current.ProjectId;
|
||||
vm.selectedId = current.ProjectId;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
vm.filterInput = "";
|
||||
vm.selectItem = selectItem;
|
||||
|
||||
|
@ -15,11 +15,12 @@
|
||||
vm.isOpen = val;
|
||||
});
|
||||
|
||||
// $scope.$watch('vm.selectedProject', function(current, origin) {
|
||||
// if(current){
|
||||
// vm.projectName = current.Name;
|
||||
// }
|
||||
// });
|
||||
$scope.$watch('vm.selectedProject', function(current, origin) {
|
||||
if(current){
|
||||
vm.projectName = current.Name;
|
||||
vm.selectedProject = current;
|
||||
}
|
||||
});
|
||||
|
||||
vm.switchPane = switchPane;
|
||||
|
||||
@ -51,12 +52,7 @@
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
scope.$watch('vm.selectedProject', function(current, origin) {
|
||||
if(current){
|
||||
scope.$emit('selectedProjectId', current.ProjectId);
|
||||
ctrl.projectName = current.Name;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,9 +6,9 @@
|
||||
.module('harbor.log')
|
||||
.directive('listLog', listLog);
|
||||
|
||||
ListLogController.$inject = ['$scope','ListLogService'];
|
||||
ListLogController.$inject = ['$scope','ListLogService', '$routeParams'];
|
||||
|
||||
function ListLogController($scope, ListLogService) {
|
||||
function ListLogController($scope, ListLogService, $routeParams) {
|
||||
var vm = this;
|
||||
vm.isOpen = false;
|
||||
|
||||
@ -22,18 +22,16 @@
|
||||
vm.search = search;
|
||||
vm.showAdvancedSearch = showAdvancedSearch;
|
||||
|
||||
$scope.$watch('vm.projectId', function(current, origin) {
|
||||
if(current) {
|
||||
vm.queryParams = {
|
||||
'beginTimestamp' : vm.beginTimestamp,
|
||||
'endTimestamp' : vm.endTimestamp,
|
||||
'keywords' : vm.keywords,
|
||||
'projectId': current,
|
||||
'username' : vm.username
|
||||
};
|
||||
retrieve(vm.queryParams);
|
||||
}
|
||||
});
|
||||
vm.projectId = $routeParams.project_id;
|
||||
vm.queryParams = {
|
||||
'beginTimestamp' : vm.beginTimestamp,
|
||||
'endTimestamp' : vm.endTimestamp,
|
||||
'keywords' : vm.keywords,
|
||||
'projectId': vm.projectId,
|
||||
'username' : vm.username
|
||||
};
|
||||
retrieve(vm.queryParams);
|
||||
|
||||
function search(e) {
|
||||
if(e.op[0] == 'all') {
|
||||
vm.queryParams.keywords = '';
|
||||
@ -94,9 +92,6 @@
|
||||
restrict: 'E',
|
||||
templateUrl: '/static/ng/resources/js/components/log/list-log.directive.html',
|
||||
replace: true,
|
||||
scope: {
|
||||
'projectId': '='
|
||||
},
|
||||
controller: ListLogController,
|
||||
controllerAs: 'vm',
|
||||
bindToController: true
|
||||
|
@ -6,11 +6,11 @@
|
||||
.module('harbor.project.member')
|
||||
.directive('listProjectMember', listProjectMember);
|
||||
|
||||
ListProjectMemberController.$inject = ['$scope', '$q', 'ListProjectMemberService'];
|
||||
ListProjectMemberController.$inject = ['$scope', '$q', 'ListProjectMemberService', '$routeParams'];
|
||||
|
||||
function ListProjectMemberController($scope, $q, ListProjectMemberService) {
|
||||
function ListProjectMemberController($scope, $q, ListProjectMemberService, $routeParams) {
|
||||
var vm = this;
|
||||
|
||||
|
||||
vm.isOpen = false;
|
||||
vm.username = "";
|
||||
|
||||
@ -18,11 +18,8 @@
|
||||
vm.addProjectMember = addProjectMember;
|
||||
vm.retrieve = retrieve;
|
||||
|
||||
$scope.$watch('vm.projectId', function(current, origin) {
|
||||
if(current) {
|
||||
vm.retrieve(current , vm.username);
|
||||
}
|
||||
});
|
||||
vm.projectId = $routeParams.project_id;
|
||||
vm.retrieve(vm.projectId, vm.username);
|
||||
|
||||
function search(e) {
|
||||
console.log('project_id:' + e.projectId);
|
||||
@ -58,9 +55,6 @@
|
||||
restrict: 'E',
|
||||
templateUrl: '/static/ng/resources/js/components/project-member/list-project-member.directive.html',
|
||||
replace: true,
|
||||
scope: {
|
||||
'projectId': '='
|
||||
},
|
||||
link: link,
|
||||
controller: ListProjectMemberController,
|
||||
controllerAs: 'vm',
|
||||
|
@ -1,15 +0,0 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project')
|
||||
.controller('AddProjectController', AddProjectController);
|
||||
|
||||
AddProjectController.$inject = ['AddProjectService'];
|
||||
|
||||
function AddProjectController(AddProjectService) {
|
||||
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,22 @@
|
||||
<div class="well panel-group">
|
||||
<div class="row">
|
||||
<div class="col-xs-10 col-md-10">
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" placeholder="Project Name" ng-model="vm.projectName">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="checkbox" ng-model="vm.isPublic"> Public Project
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-xs-2 col-md-2">
|
||||
<form>
|
||||
<div class="form-group" style="margin-top: 20%;">
|
||||
<button type="button" class="btn btn-default" ng-click="vm.cancel()">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" ng-click="vm.addProject()">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,60 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project')
|
||||
.directive('addProject', addProject);
|
||||
|
||||
AddProjectController.$inject = ['AddProjectService', '$scope'];
|
||||
|
||||
function AddProjectController(AddProjectService, $scope) {
|
||||
var vm = this;
|
||||
vm.projectName = "";
|
||||
vm.isPublic = false;
|
||||
|
||||
vm.addProject = addProject;
|
||||
vm.cancel = cancel;
|
||||
|
||||
function addProject() {
|
||||
|
||||
if(vm.projectName == "") {
|
||||
alert("Please input the project name.");
|
||||
return;
|
||||
}
|
||||
|
||||
AddProjectService(vm.projectName, vm.isPublic)
|
||||
.success(addProjectSuccess)
|
||||
.error(addProjectFailed);
|
||||
|
||||
}
|
||||
|
||||
function addProjectSuccess(data, status) {
|
||||
vm.isOpen = false;
|
||||
$scope.$emit('addedSuccess', true);
|
||||
}
|
||||
|
||||
function addProjectFailed(data, status) {
|
||||
console.log('Failed to add project:' + status);
|
||||
}
|
||||
|
||||
function cancel(){
|
||||
vm.isOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
function addProject() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/ng/resources/js/components/project/add-project.directive.html',
|
||||
'controller': AddProjectController,
|
||||
'scope' : {
|
||||
'isOpen': '='
|
||||
},
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
}
|
||||
|
||||
})();
|
@ -1,15 +0,0 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project')
|
||||
.controller('ListProjectController', ListProjectController);
|
||||
|
||||
ListProjectController.$inject = ['ListProjectService'];
|
||||
|
||||
function ListProjectService(ListProjectService) {
|
||||
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,14 @@
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th>Project Name</th><th>Repositories</th><th>Role</th><th>Creation Time</th><th>Publicity</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="p in vm.projects">
|
||||
<td><a href="/ng/repository?project_id=//p.ProjectId//">//p.Name//</a></td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
<td>//p.CreationTime | dateL : 'YYYY-MM-DD HH:mm:ss'//</td>
|
||||
<td><publicity-button is-public="p.Public" owned="p.OwnerId == vm.currentUser.UserId" project-id="p.ProjectId"></publicity-button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
@ -0,0 +1,77 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project')
|
||||
.directive('listProject', listProject);
|
||||
|
||||
ListProjectController.$inject = ['ListProjectService', 'CurrentUserService', '$scope'];
|
||||
|
||||
function ListProjectController(ListProjectService, CurrentUserService, $scope) {
|
||||
var vm = this;
|
||||
|
||||
vm.retrieve = retrieve;
|
||||
vm.reload = reload;
|
||||
|
||||
vm.getCurrentUser = getCurrentUser;
|
||||
|
||||
function reload() {
|
||||
$.when(vm.getCurrentUser())
|
||||
.done(function(e) {
|
||||
vm.retrieve(vm.projectName);
|
||||
});
|
||||
}
|
||||
|
||||
vm.reload();
|
||||
|
||||
$scope.$on('needToReload', function(e, val) {
|
||||
if(val) {
|
||||
vm.reload(vm.projectName);
|
||||
}
|
||||
});
|
||||
|
||||
function retrieve(projectName) {
|
||||
ListProjectService({'is_public': 0, 'project_name': projectName})
|
||||
.success(listProjectSuccess)
|
||||
.error(listProjectFailed);
|
||||
}
|
||||
|
||||
function listProjectSuccess(data, status) {
|
||||
vm.projects = data;
|
||||
}
|
||||
function listProjectFailed(e) {
|
||||
console.log('Failed in listProject:' + e);
|
||||
}
|
||||
|
||||
function getCurrentUser() {
|
||||
CurrentUserService()
|
||||
.success(getCurrentUserSuccess)
|
||||
.error(getCurrentUserFailed);
|
||||
}
|
||||
|
||||
function getCurrentUserSuccess(data, status) {
|
||||
vm.currentUser = data;
|
||||
}
|
||||
|
||||
function getCurrentUserFailed(e) {
|
||||
console.log('Failed in getCurrentUser:' + e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function listProject() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/ng/resources/js/components/project/list-project.directive.html',
|
||||
'scope': {
|
||||
'projectName': '='
|
||||
},
|
||||
'controller': ListProjectController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
}
|
||||
|
||||
})();
|
@ -3,6 +3,7 @@
|
||||
|
||||
angular
|
||||
.module('harbor.project', [
|
||||
'harbor.services.project'
|
||||
'harbor.services.project',
|
||||
'harbor.services.user'
|
||||
]);
|
||||
})();
|
@ -0,0 +1,4 @@
|
||||
<button ng-if="vm.isPublic && vm.owned" class="//vm.btnClass//" ng-click="vm.toggle()">On</button>
|
||||
<button ng-if="vm.isPublic && !vm.owned" class="btn btn-success" disabled="disabled">On</button>
|
||||
<button ng-if="!vm.isPublic && vm.owned" class="//vm.btnClass//" ng-click="vm.toggle()">Off</button>
|
||||
<button ng-if="!vm.isPublic && !vm.owned" class="btn btn-danger" disabled="disabled">Off</button>
|
@ -0,0 +1,78 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.project')
|
||||
.directive('publicityButton', publicityButton);
|
||||
|
||||
PublicityButtonController.$inject = ['EditProjectService'];
|
||||
|
||||
function PublicityButtonController(EditProjectService) {
|
||||
var vm = this;
|
||||
vm.toggle = toggle;
|
||||
|
||||
if(vm.isPublic == 1) {
|
||||
vm.isPublic = true;
|
||||
}else{
|
||||
vm.isPublic = false;
|
||||
}
|
||||
|
||||
var publicClass = 'btn btn-success';
|
||||
var privateClass = 'btn btn-danger';
|
||||
|
||||
function setBtnClass() {
|
||||
if(vm.isPublic) {
|
||||
vm.btnClass = publicClass;
|
||||
}else{
|
||||
vm.btnClass = privateClass;
|
||||
}
|
||||
}
|
||||
vm.setBtnClass = setBtnClass;
|
||||
vm.setBtnClass();
|
||||
|
||||
function toggle() {
|
||||
|
||||
if(vm.isPublic) {
|
||||
vm.isPublic = false;
|
||||
}else{
|
||||
vm.isPublic = true;
|
||||
}
|
||||
|
||||
EditProjectService(vm.projectId, vm.isPublic)
|
||||
.success(editProjectSuccess)
|
||||
.error(editProjectFailed);
|
||||
}
|
||||
|
||||
function editProjectSuccess(data, status) {
|
||||
setBtnClass();
|
||||
console.log('edit project successfully:' + status);
|
||||
}
|
||||
|
||||
function editProjectFailed(e) {
|
||||
console.log('edit project failed:' + e);
|
||||
}
|
||||
}
|
||||
|
||||
function publicityButton() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/ng/resources/js/components/project/publicity-button.directive.html',
|
||||
'scope': {
|
||||
'isPublic': '=',
|
||||
'owned': '=',
|
||||
'projectId': '='
|
||||
},
|
||||
'link': link,
|
||||
'controller': PublicityButtonController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attr, ctrl) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -5,22 +5,20 @@
|
||||
.module('harbor.repository')
|
||||
.directive('listRepository', listRepository);
|
||||
|
||||
ListRepositoryController.$inject = ['$scope', '$q', 'ListRepositoryService', 'ListTagService', 'nameFilter'];
|
||||
ListRepositoryController.$inject = ['$scope', '$q', 'ListRepositoryService', 'ListTagService', 'nameFilter', '$routeParams'];
|
||||
|
||||
function ListRepositoryController($scope, $q, ListRepositoryService, ListTagService, nameFilter) {
|
||||
function ListRepositoryController($scope, $q, ListRepositoryService, ListTagService, nameFilter, $routeParams) {
|
||||
var vm = this;
|
||||
|
||||
|
||||
vm.filterInput = "";
|
||||
vm.expand = expand;
|
||||
|
||||
vm.retrieve = retrieve;
|
||||
|
||||
$scope.$watch('vm.projectId', function(current, origin) {
|
||||
if(current) {
|
||||
vm.retrieve(current, vm.filterInput);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
vm.projectId = $routeParams.project_id;
|
||||
|
||||
vm.retrieve(vm.projectId, vm.filterInput);
|
||||
|
||||
function retrieve(projectId, filterInput) {
|
||||
ListRepositoryService({'projectId': projectId, 'q': filterInput})
|
||||
.success(getRepositoryComplete)
|
||||
@ -57,9 +55,6 @@
|
||||
restrict: 'E',
|
||||
templateUrl: '/static/ng/resources/js/components/repository/list-repository.directive.html',
|
||||
replace: true,
|
||||
scope: {
|
||||
'projectId': '='
|
||||
},
|
||||
link: 'link',
|
||||
controller: ListRepositoryController,
|
||||
controllerAs: 'vm',
|
||||
@ -69,7 +64,7 @@
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
ListTagController.$inject = ['ListTagService'];
|
||||
|
||||
function ListTagController(ListTagService) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
function listTag() {
|
||||
|
@ -1,15 +0,0 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.search')
|
||||
.controller('SearchController', SearchController);
|
||||
|
||||
SearchController.$inject = ['SearchService'];
|
||||
|
||||
function SearchController(SearchService) {
|
||||
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,12 @@
|
||||
<div class="down-table-pane">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th>Project/Repository Name</th><th>Creation Time</th><th>Author</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="s in vm.searchResult">
|
||||
<td>//s.repository_name//</td><td>N/A</td><td>N/A</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
53
static/ng/resources/js/components/search/search.directive.js
Normal file
53
static/ng/resources/js/components/search/search.directive.js
Normal file
@ -0,0 +1,53 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.search')
|
||||
.directive('search', search);
|
||||
|
||||
SearchController.$inject = ['SearchService', '$scope'];
|
||||
|
||||
function SearchController(SearchService, $scope) {
|
||||
var vm = this;
|
||||
vm.keywords = "";
|
||||
vm.search = searchByFilter;
|
||||
vm.filterBy = 'repository';
|
||||
|
||||
searchByFilter();
|
||||
|
||||
|
||||
function searchByFilter() {
|
||||
SearchService(vm.keywords)
|
||||
.success(searchSuccess)
|
||||
.error(searchFailed);
|
||||
}
|
||||
|
||||
function searchSuccess(data, status) {
|
||||
console.log('filterBy:' + vm.filterBy + ", data:" + data);
|
||||
vm.searchResult = data[vm.filterBy];
|
||||
|
||||
}
|
||||
|
||||
function searchFailed(data, status) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function search() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/ng/resources/js/components/search/search.directive.html',
|
||||
'scope': {
|
||||
'filterBy': '='
|
||||
},
|
||||
'controller': SearchController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
|
||||
return directive;
|
||||
}
|
||||
|
||||
})();
|
@ -0,0 +1,27 @@
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<input type="text" class="form-control" placeholder="Username/Email" ng-model="vm.principal">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<input type="password" class="form-control" placeholder="Password" ng-model="vm.password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<div class="pull-right">
|
||||
<button class="btn btn-default" ng-click="vm.doSignIn()">Sign In</button>
|
||||
<button class="btn btn-success" ng-click="vm.doSignUp()">Sign Up</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<div class="pull-right">
|
||||
<a href="#">Forgot Password</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -0,0 +1,48 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.sign.in')
|
||||
.directive('signIn', signIn);
|
||||
|
||||
SignInController.$inject = ['SignInService', '$window'];
|
||||
function SignInController(SignInService, $window) {
|
||||
var vm = this;
|
||||
vm.principal = "";
|
||||
vm.password = "";
|
||||
vm.doSignIn = doSignIn;
|
||||
|
||||
function doSignIn() {
|
||||
if(vm.principal != "" && vm.password != "") {
|
||||
SignInService(vm.principal, vm.password)
|
||||
.success(signedInSuccess)
|
||||
.error(signedInFailed);
|
||||
}else{
|
||||
$window.alert('Please input your username or password!');
|
||||
}
|
||||
}
|
||||
|
||||
function signedInSuccess(data, status) {
|
||||
console.log(status);
|
||||
$window.location.href = "/ng/project";
|
||||
}
|
||||
|
||||
function signedInFailed(data, status) {
|
||||
console.log(status);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function signIn() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/ng/resources/js/components/sign-in/sign-in.directive.html',
|
||||
'controller': SignInController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
}
|
||||
return directive;
|
||||
}
|
||||
|
||||
})();
|
10
static/ng/resources/js/components/sign-in/sign-in.module.js
Normal file
10
static/ng/resources/js/components/sign-in/sign-in.module.js
Normal file
@ -0,0 +1,10 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.sign.in', [
|
||||
'harbor.services.user'
|
||||
]);
|
||||
|
||||
})();
|
@ -4,15 +4,21 @@
|
||||
.module('harbor.app', [
|
||||
'ngRoute',
|
||||
'harbor.layout.navigation',
|
||||
'harbor.layout.index',
|
||||
'harbor.layout.project',
|
||||
'harbor.layout.repository',
|
||||
'harbor.layout.project.member',
|
||||
'harbor.layout.user',
|
||||
'harbor.layout.log',
|
||||
'harbor.services.project',
|
||||
'harbor.services.user',
|
||||
'harbor.services.repository',
|
||||
'harbor.services.project.member',
|
||||
'harbor.session',
|
||||
'harbor.header',
|
||||
'harbor.sign.in',
|
||||
'harbor.search',
|
||||
'harbor.project',
|
||||
'harbor.details',
|
||||
'harbor.repository',
|
||||
'harbor.project.member',
|
||||
|
@ -24,9 +24,6 @@
|
||||
templateUrl: '/static/ng/resources/js/layout/log/log.controller.html',
|
||||
controller: 'LogController',
|
||||
controllerAs: 'vm'
|
||||
})
|
||||
.otherwise({
|
||||
redirectTo: '/'
|
||||
});
|
||||
}
|
||||
|
@ -6,16 +6,12 @@
|
||||
.module('harbor.details')
|
||||
.controller('DetailsController', DetailsController);
|
||||
|
||||
DetailsController.$inject = ['ListProjectService', '$scope'];
|
||||
DetailsController.$inject = ['ListProjectService', '$scope', '$location'];
|
||||
|
||||
function DetailsController(ListProjectService, $scope) {
|
||||
function DetailsController(ListProjectService, $scope, $location) {
|
||||
var vm = this;
|
||||
vm.isOpen = false;
|
||||
vm.closeRetrievePane = closeRetrievePane;
|
||||
|
||||
$scope.$on('selectedProjectId', function(e, val) {
|
||||
$scope.$broadcast('currentProjectId', val);
|
||||
});
|
||||
vm.closeRetrievePane = closeRetrievePane;
|
||||
|
||||
ListProjectService({'isPublic' : 0, 'projectName' : ''})
|
||||
.then(getProjectComplete)
|
||||
@ -24,6 +20,7 @@
|
||||
function getProjectComplete(response) {
|
||||
vm.projects = response.data;
|
||||
vm.selectedProject = vm.projects[0];
|
||||
$location.url('repositories').search('project_id', vm.selectedProject.ProjectId);
|
||||
}
|
||||
|
||||
function getProjectFailed(response) {
|
13
static/ng/resources/js/layout/index/index.controller.js
Normal file
13
static/ng/resources/js/layout/index/index.controller.js
Normal file
@ -0,0 +1,13 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.layout.index')
|
||||
.controller('IndexController', IndexController);
|
||||
|
||||
function IndexController() {
|
||||
|
||||
}
|
||||
|
||||
})();
|
8
static/ng/resources/js/layout/index/index.module.js
Normal file
8
static/ng/resources/js/layout/index/index.module.js
Normal file
@ -0,0 +1,8 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.layout.index', []);
|
||||
|
||||
})();
|
@ -9,11 +9,7 @@
|
||||
LogController.$inject = ['$scope'];
|
||||
|
||||
function LogController($scope) {
|
||||
var vm = this;
|
||||
$scope.$on('currentProjectId', function(e, val) {
|
||||
console.log('received currentProjecjtId: ' + val + ' in LogController');
|
||||
vm.projectId = val;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
})();
|
@ -1,5 +1,5 @@
|
||||
<ul class="switch-pane-tabs" role="tablist">
|
||||
<li><a tag="repositories" ng-click="vm.clickTab()" href="/ng/repository#/repositories">Repositories</a><span class="gutter">|</span></li>
|
||||
<li><a tag="users" ng-click="vm.clickTab()" href="/ng/repository#/users">Users</a><span class="gutter">|</span></li>
|
||||
<li><a tag="logs" ng-click="vm.clickTab()" href="/ng/repository#/logs">Logs</a></li>
|
||||
<li><a tag="repositories" href="#/repositories?project_id=//vm.projectId//">Repositories</a><span class="gutter">|</span></li>
|
||||
<li><a tag="users" href="#/users?project_id=//vm.projectId//">Users</a><span class="gutter">|</span></li>
|
||||
<li><a tag="logs" href="#/logs?project_id=//vm.projectId//">Logs</a></li>
|
||||
</ul>
|
@ -6,21 +6,24 @@
|
||||
.module('harbor.layout.navigation')
|
||||
.directive('navigationDetails', navigationDetails);
|
||||
|
||||
NavigationDetailsController.$inject = ['$location', '$scope'];
|
||||
NavigationDetailsController.$inject = ['$window', '$location', '$scope'];
|
||||
|
||||
function NavigationDetailsController($location, $scope) {
|
||||
function NavigationDetailsController($window, $location, $scope) {
|
||||
var vm = this;
|
||||
vm.clickTab = clickTab;
|
||||
vm.url = $location.url();
|
||||
|
||||
if(vm.url == "/") {
|
||||
$location.url('/repositories');
|
||||
}
|
||||
$scope.$watch('vm.selectedProject', function(current, origin) {
|
||||
if(current) {
|
||||
vm.projectId = current.ProjectId;
|
||||
}
|
||||
});
|
||||
|
||||
vm.url = $location.url();
|
||||
vm.clickTab = clickTab;
|
||||
|
||||
function clickTab() {
|
||||
function clickTab() {
|
||||
console.log("triggered clickTab of Controller.");
|
||||
vm.isOpen = false;
|
||||
vm.url = $location.url();
|
||||
$scope.$emit('selectedProjectId', vm.selectedProject.ProjectId);
|
||||
$scope.$apply();
|
||||
}
|
||||
|
||||
}
|
||||
@ -32,7 +35,7 @@
|
||||
link: link,
|
||||
scope: {
|
||||
'isOpen': '=',
|
||||
'selectedProject': "="
|
||||
'selectedProject': '='
|
||||
},
|
||||
replace: true,
|
||||
controller: NavigationDetailsController,
|
||||
@ -45,7 +48,7 @@
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
var visited = ctrl.url;
|
||||
|
||||
|
||||
if(visited == "/") {
|
||||
element.find('a:first').addClass('active');
|
||||
}else{
|
||||
@ -54,13 +57,9 @@
|
||||
|
||||
element.on('click', click);
|
||||
|
||||
|
||||
|
||||
|
||||
function click(event) {
|
||||
element.find('a').removeClass('active');
|
||||
$(event.target).not('span').addClass('active');
|
||||
|
||||
ctrl.clickTab();
|
||||
}
|
||||
|
||||
|
@ -9,11 +9,7 @@
|
||||
ProjectMemberController.$inject = ['$scope'];
|
||||
|
||||
function ProjectMemberController($scope) {
|
||||
var vm = this;
|
||||
$scope.$on('currentProjectId', function(e, val) {
|
||||
console.log('received currentProjectId: ' + val + ' in ProjectMemberController');
|
||||
vm.projectId = val;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
})();
|
36
static/ng/resources/js/layout/project/project.controller.js
Normal file
36
static/ng/resources/js/layout/project/project.controller.js
Normal file
@ -0,0 +1,36 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.layout.project')
|
||||
.controller('ProjectController', ProjectController);
|
||||
|
||||
ProjectController.$inject = ['$scope'];
|
||||
|
||||
function ProjectController($scope) {
|
||||
var vm = $scope;
|
||||
vm.showAddProject = showAddProject;
|
||||
vm.isOpen = false;
|
||||
vm.searchProject = searchProject;
|
||||
|
||||
$scope.$on('addedSuccess', function(e, val) {
|
||||
$scope.$broadcast('needToReload', true);
|
||||
});
|
||||
|
||||
function showAddProject() {
|
||||
if(vm.isOpen){
|
||||
vm.isOpen = false;
|
||||
}else{
|
||||
vm.isOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
function searchProject() {
|
||||
|
||||
$scope.$broadcast('needToReload', true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
8
static/ng/resources/js/layout/project/project.module.js
Normal file
8
static/ng/resources/js/layout/project/project.module.js
Normal file
@ -0,0 +1,8 @@
|
||||
(function() {
|
||||
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.layout.project', []);
|
||||
|
||||
})();
|
@ -1 +1 @@
|
||||
<list-repository project-id="vm.projectId"></list-repository>
|
||||
<list-repository></list-repository>
|
@ -9,12 +9,6 @@
|
||||
RepositoryController.$inject = ['$scope'];
|
||||
|
||||
function RepositoryController($scope) {
|
||||
var vm = this;
|
||||
|
||||
$scope.$on('currentProjectId', function(e, val){
|
||||
console.log('received currentProjecjtId: ' + val + ' in RepositoryController');
|
||||
vm.projectId = val;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,12 @@
|
||||
|
||||
return AddProject;
|
||||
|
||||
function AddProject(project) {
|
||||
|
||||
function AddProject(projectName, isPublic) {
|
||||
return $http
|
||||
.post('/api/projects', {
|
||||
'project_name': projectName,
|
||||
'public': isPublic
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('harbor.services.project')
|
||||
.factory('EditProjectService', EditProjectService);
|
||||
|
||||
EditProjectService.$inject = ['$http', '$log'];
|
||||
|
||||
function EditProjectService($http, $log) {
|
||||
|
||||
return EditProject;
|
||||
|
||||
function EditProject(projectId, isPublic) {
|
||||
return $http
|
||||
.put('/api/projects/' + projectId, {
|
||||
'public': isPublic
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
@ -17,15 +17,18 @@
|
||||
|
||||
var isPublic = queryParams.isPublic;
|
||||
var projectName = queryParams.projectName;
|
||||
|
||||
return $http
|
||||
.get('/api/projects',{
|
||||
params: {
|
||||
'is_public': isPublic,
|
||||
'project_name': projectName
|
||||
}
|
||||
});
|
||||
|
||||
return $http({
|
||||
method: 'GET',
|
||||
url: '/api/projects',
|
||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
transformRequest: function(obj) {
|
||||
var str = [];
|
||||
for(var p in obj)
|
||||
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
|
||||
return str.join("&");
|
||||
},
|
||||
data: {'is_public': isPublic, 'project_name': projectName}
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
@ -12,8 +12,19 @@
|
||||
|
||||
return Search;
|
||||
|
||||
function Search(queryParams) {
|
||||
|
||||
function Search(keywords) {
|
||||
return $http({
|
||||
method: 'GET',
|
||||
url: '/api/search',
|
||||
|
||||
transformRequest: function(obj) {
|
||||
var str = [];
|
||||
for(var p in obj)
|
||||
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
|
||||
return str.join("&");
|
||||
},
|
||||
data: {'q': keywords}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,8 +12,19 @@
|
||||
|
||||
return SignIn;
|
||||
|
||||
function SignIn(user) {
|
||||
$log.info(user);
|
||||
function SignIn(principal, password) {
|
||||
return $http({
|
||||
method: 'POST',
|
||||
url: '/login',
|
||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
transformRequest: function(obj) {
|
||||
var str = [];
|
||||
for(var p in obj)
|
||||
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
|
||||
return str.join("&");
|
||||
},
|
||||
data: {'principal': principal, 'password': password}
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
@ -1,4 +1,4 @@
|
||||
<div class="container-fluid container-fluid-custom">
|
||||
<div class="container-fluid container-fluid-custom" ng-controller="IndexController as vm">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
@ -7,33 +7,7 @@
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<span class="glyphicon glyphicon-user"></span> <h4 class="title-color display-inline-block">Login now</h4>
|
||||
</div>
|
||||
<form class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<input type="email" class="form-control" id="inputEmail3" placeholder="Email">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<input type="password" class="form-control" id="inputPassword3" placeholder="Password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<div class="pull-right">
|
||||
<button class="btn btn-default">Sign In</button>
|
||||
<button class="btn btn-success">Sign Up</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
<div class="pull-right">
|
||||
<a href="#">Forgot Password</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<sign-in></sign-in>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -93,33 +67,7 @@
|
||||
<div class="col-md-8">
|
||||
<div class="down-section">
|
||||
<h4 class="page-header title-color underlined">Repositories</h4>
|
||||
<div class="down-table-pane">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th>Project/Repository Name</th><th>Creation Time</th><th>Author</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>myrepo/Ubuntu</td><td>2016-03-22 12:35:00</td><td>Haox</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>myrepo/MySQL</td><td>2016-03-22 12:35:00</td><td>Haox</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>harbor/Nginx</td><td>2016-03-21 11:25:30</td><td>Wenkai Yin</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>harbor/Registry</td><td>2016-03-21 11:25:30</td><td>Wenkai Yin</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>myproject/Alpine</td><td>2016-03-23 09:40:20</td><td>Daniel</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>myproject/Golang</td><td>2016-03-23 09:40:20</td><td>Daniel</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<search filter-by="repository"></search>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
{{.HeaderInclude}}
|
||||
|
||||
<title>{{.Title}}</title>
|
||||
</head>
|
||||
<body ng-app="harbor.app">
|
||||
@ -9,5 +9,6 @@
|
||||
{{.LayoutContent}}
|
||||
{{.FooterContent}}
|
||||
{{.FooterInclude}}
|
||||
{{.HeaderInclude}}
|
||||
</body>
|
||||
</html>
|
@ -1,4 +1,4 @@
|
||||
<div class="container-fluid container-fluid-custom">
|
||||
<div class="container-fluid container-fluid-custom" ng-controller="ProjectController">
|
||||
<div class="container container-custom">
|
||||
<div class="row extend-height">
|
||||
<div class="col-xs-12 col-md-12 extend-height">
|
||||
@ -7,72 +7,23 @@
|
||||
<div class="search-pane">
|
||||
<div class="form-inline">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" placeholder="" size="30">
|
||||
<input type="text" class="form-control" placeholder="" ng-model="inputProjectName" size="30">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-primary" type="button"><span class="glyphicon glyphicon-search"></span></button>
|
||||
<button class="btn btn-primary" type="button" ng-click="searchProject()"><span class="glyphicon glyphicon-search"></span></button>
|
||||
</span>
|
||||
</div>
|
||||
<button class="btn btn-success" type="button"><span class="glyphicon glyphicon-plus"></span>New Project</button>
|
||||
<button class="btn btn-success" type="button" ng-click="showAddProject()"><span class="glyphicon glyphicon-plus"></span>New Project</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pane project-pane">
|
||||
<div class="well panel-group">
|
||||
<div class="row">
|
||||
<div class="col-xs-10 col-md-10">
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" id="addUsername" placeholder="Project Name">
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-inline">
|
||||
<div class="form-group">
|
||||
<input type="checkbox" name="roleId" value="1"> Public Project
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-xs-2 col-md-2">
|
||||
<form>
|
||||
<div class="form-group" style="margin-top: 20%;">
|
||||
<button type="button" class="btn btn-default" id="btnCancel">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="btnSave">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<add-project ng-show="isOpen" is-open="isOpen"></add-project>
|
||||
<div class="sub-pane">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th>Project Name</th><th>Repositories</th><th>Role</th><th>Creation Time</th><th>Publicity</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="#">myrepo</a></td><td>3</td><td>Project Admin</td><td>2016-03-22 12:35:00</td><td><button class="btn btn-success" type="button">On</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#">target1</a></td><td>5</td><td>Guest</td><td>2016-03-22 12:35:00</td><td><button class="btn btn-success" type="button" disabled="disabled">On</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#">myproject</a></td><td>1</td><td>Project Admin</td><td>2016-03-22 12:35:00</td><td><button class="btn btn-danger" type="button">Off</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#">test</a></td><td>3</td><td>Developer</td><td>2016-03-22 12:35:00</td><td><button class="btn btn-danger" type="button">Off</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#">demo</a></td><td>3</td><td>Guest</td><td>2016-03-22 12:35:00</td><td><button class="btn btn-danger" type="button">Off</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#">distribution</a></td><td>3</td><td>Project Admin</td><td>2016-03-22 12:35:00</td><td><button class="btn btn-success" type="button">On</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#">undefined</a></td><td>3</td><td>Project Admin</td><td>2016-03-22 12:35:00</td><td><button class="btn btn-success" type="button">On</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<list-project project-name="inputProjectName"></list-project>
|
||||
</div>
|
||||
<div class="col-xs-4 col-md-12 well well-sm well-custom"><div class="col-md-offset-10">7 items</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -41,6 +41,16 @@
|
||||
<script src="/static/ng/resources/js/layout/navigation/navigation-header.directive.js"></script>
|
||||
<script src="/static/ng/resources/js/layout/navigation/navigation-details.directive.js"></script>
|
||||
|
||||
<script src="/static/ng/resources/js/layout/index/index.module.js"></script>
|
||||
<script src="/static/ng/resources/js/layout/index/index.controller.js"></script>
|
||||
|
||||
<script src="/static/ng/resources/js/layout/project/project.module.js"></script>
|
||||
<script src="/static/ng/resources/js/layout/project/project.controller.js"></script>
|
||||
|
||||
<script src="/static/ng/resources/js/layout/details/details.module.js"></script>
|
||||
<script src="/static/ng/resources/js/layout/details/details.config.js"></script>
|
||||
<script src="/static/ng/resources/js/layout/details/details.controller.js"></script>
|
||||
|
||||
<script src="/static/ng/resources/js/layout/repository/repository.module.js"></script>
|
||||
<script src="/static/ng/resources/js/layout/repository/repository.controller.js"></script>
|
||||
|
||||
@ -53,11 +63,17 @@
|
||||
<script src="/static/ng/resources/js/layout/log/log.module.js"></script>
|
||||
<script src="/static/ng/resources/js/layout/log/log.controller.js"></script>
|
||||
|
||||
<script src="/static/ng/resources/js/services/search/services.search.module.js"></script>
|
||||
<script src="/static/ng/resources/js/services/search/services.search.js"></script>
|
||||
|
||||
<script src="/static/ng/resources/js/services/project/services.project.module.js"></script>
|
||||
<script src="/static/ng/resources/js/services/project/services.list-project.js"></script>
|
||||
<script src="/static/ng/resources/js/services/project/services.add-project.js"></script>
|
||||
<script src="/static/ng/resources/js/services/project/services.edit-project.js"></script>
|
||||
|
||||
<script src="/static/ng/resources/js/services/user/services.user.module.js"></script>
|
||||
<script src="/static/ng/resources/js/services/user/services.current-user.js"></script>
|
||||
<script src="/static/ng/resources/js/services/user/services.sign-in.js"></script>
|
||||
|
||||
<script src="/static/ng/resources/js/services/repository/services.repository.module.js"></script>
|
||||
<script src="/static/ng/resources/js/services/repository/services.list-repository.js"></script>
|
||||
@ -77,9 +93,16 @@
|
||||
|
||||
<script src="/static/ng/resources/js/components/header/header.module.js"></script>
|
||||
|
||||
<script src="/static/ng/resources/js/components/details/details.module.js"></script>
|
||||
<script src="/static/ng/resources/js/components/details/details.config.js"></script>
|
||||
<script src="/static/ng/resources/js/components/details/details.controller.js"></script>
|
||||
<script src="/static/ng/resources/js/components/search/search.module.js"></script>
|
||||
<script src="/static/ng/resources/js/components/search/search.directive.js"></script>
|
||||
|
||||
<script src="/static/ng/resources/js/components/sign-in/sign-in.module.js"></script>
|
||||
<script src="/static/ng/resources/js/components/sign-in/sign-in.directive.js"></script>
|
||||
|
||||
<script src="/static/ng/resources/js/components/project/project.module.js"></script>
|
||||
<script src="/static/ng/resources/js/components/project/add-project.directive.js"></script>
|
||||
<script src="/static/ng/resources/js/components/project/list-project.directive.js"></script>
|
||||
<script src="/static/ng/resources/js/components/project/publicity-button.directive.js"></script>
|
||||
|
||||
<script src="/static/ng/resources/js/components/details/switch-pane-projects.directive.js"></script>
|
||||
<script src="/static/ng/resources/js/components/details/retrieve-projects.directive.js"></script>
|
||||
|
Loading…
Reference in New Issue
Block a user