updates for replication and destination UI.

This commit is contained in:
kunw 2016-06-07 16:49:38 +08:00
parent bd0ef1eb3d
commit ea43ff7c28
34 changed files with 1230 additions and 0 deletions

View File

@ -0,0 +1,34 @@
package ng
import (
"net/http"
"github.com/vmware/harbor/dao"
"github.com/vmware/harbor/models"
"github.com/vmware/harbor/utils/log"
)
type NavigationDetailController struct {
BaseController
}
func (ndc *NavigationDetailController) Get() {
sessionUserID := ndc.GetSession("userId")
var isAdmin int
if sessionUserID != nil {
userID := sessionUserID.(int)
u, err := dao.GetUser(models.User{UserID: userID})
if err != nil {
log.Errorf("Error occurred in GetUser, error: %v", err)
ndc.CustomAbort(http.StatusInternalServerError, "Internal error.")
}
if u == nil {
log.Warningf("User was deleted already, user id: %d, canceling request.", userID)
ndc.CustomAbort(http.StatusUnauthorized, "")
}
isAdmin = u.HasAdminRole
}
ndc.Data["IsAdmin"] = isAdmin
ndc.TplName = "ng/navigation-detail.htm"
ndc.Render()
}

View File

@ -0,0 +1,17 @@
.switch-pane-admin-options {
display: inline;
width: 345px;
float: right;
list-style-type: none;
}
.switch-pane-admin-options a, .switch-pane-admin-options span {
display: inline-block;
text-decoration: none;
float: left;
}
.switch-pane-admin-options li .active {
border-bottom: 2px solid rgb(0, 84, 190);
font-weight: bold;
}

View File

@ -0,0 +1,3 @@
.create-destination {
height: 235px;
}

View File

@ -0,0 +1,67 @@
.create-policy {
height: 535px;
overflow-y: auto;
}
.form-group-custom {
margin-top: 10px;
}
.h4-custom {
margin-top: 20px;
}
.h4-custom-down {
display: inline-block;
margin-top: 20px;
}
.hr-line {
margin-top: 0;
margin-bottom: 10px;
}
.form-control-custom {
width: 100% !important;
}
.pane-split {
overflow-x: hidden;
overflow-y: auto;
width: 100%;
}
#upon-pane {
margin-top: 10px;
height: 270px;
min-height: 100px;
max-height: 270px;
}
#upon-pane table>tbody>tr {
cursor: all-scroll;
}
#down-pane {
height: 80px;
min-height: 80px;
}
.sub-pane-split {
margin: 15px;
height: auto;
min-height: 50px;
width: 100%;
}
.well-split {
margin-bottom: 0;
}
.split-handle {
margin-left: auto;
margin-right: auto;
width: 1em;
height: 1em;
cursor: ns-resize;
color: #C0C0C0;
}

View File

@ -0,0 +1,92 @@
<div class="modal fade" id="createPolicyModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<form name="form" class="form-horizontal css-form" novalidate>
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><span class="glyphicon glyphicon-plus"></span>&nbsp;&nbsp;Create New Policy</h4>
</div>
<div class="modal-body">
<div class="create-policy">
<div class="col-md-12">
<h4>General</h4>
<hr class="hr-line"/>
</div>
<div class="form-group col-md-12 form-group-custom">
<label for="name" class="col-md-3 control-label">Name:</label>
<div class="col-md-9">
<input type="text" class="form-control form-control-custom" id="name" ng-model="replication.policy.name" ng-model-options="{ debounce: 500 }" name="uName" required>
<div ng-messages="form.$submitted && form.uName.$error">
<span ng-message="required">Name is required.</span>
</div>
</div>
</div>
<div class="form-group col-md-12 form-group-custom">
<label for="description" class="col-md-3 control-label">Description:</label>
<div class="col-md-9">
<textarea class="form-control form-control-custom" id="description" ng-model="replication.policy.description" ng-model-options="{ updateOn: 'blur' }" ng-value="description" name="uDescription" required ></textarea>
<div ng-messages="form.$submitted && form.uDescription.$error">
<span ng-message="required">Description is required.</span>
</div>
</div>
</div>
<div class="form-group col-md-12 form-group-custom">
<label for="enable" class="col-md-3 control-label">Enable:</label>
<div class="col-md-9">
<input type="checkbox" class="form-control" style="margin-top: 10px; height: auto;" ng-model="replication.policy.enabled" ng-model-options="{ updateOn: 'blur' }" ng-checked="enabled">
</div>
</div>
<div class="col-md-12">
<h4 class="h4-custom">Destination Setting</h4>
<hr class="hr-line"/>
</div>
<div class="form-group col-md-12 form-group-custom">
<label for="destinationName" class="col-md-3 control-label">Name:</label>
<div class="col-md-7">
<select class="form-control form-control-custom" id="destinationName" ng-model="replication.destinations" ng-options="d as d.name for d in vm.destinations track by d.id" ng-click="vm.selectDestination()"></select>
</div>
</div>
<div class="form-group col-md-12 form-group-custom">
<label for="endpoint" class="col-md-3 control-label">Endpoint:</label>
<div class="col-md-9">
<input type="text" class="form-control form-control-custom" id="endpoint" ng-model="replication.destination.endpoint" ng-model-options="{ updateOn: 'blur' }" ng-value="endpoint" name="uEndpoint" required>
<div ng-messages="form.$submitted && form.uEndpoint.$error">
<span ng-message="required">Endpoint is required.</span>
</div>
</div>
</div>
<div class="form-group col-md-12 form-group-custom">
<label for="username" class="col-md-3 control-label">Username:</label>
<div class="col-md-9">
<input type="text" class="form-control" id="username" ng-model="replication.destination.username" ng-model-options="{ updateOn: 'blur' }" ng-value="username" name="uUsername" required>
<div ng-messages="form.$submitted && form.uUsername.$error">
<span ng-message="required">Username is required.</span>
</div>
</div>
</div>
<div class="form-group col-md-12 form-group-custom">
<label for="password" class="col-md-3 control-label">Password:</label>
<div class="col-md-9">
<input type="password" class="form-control" id="password" ng-model="replication.destination.password" ng-model-options="{ updateOn: 'blur' }" ng-value="password" name="uPassword" required>
<div ng-messages="form.$submitted && form.uPassword.$error">
<span ng-message="required">Password is required.</span>
</div>
</div>
</div>
<div class="form-group col-md-12 form-group-custom">
<div class="col-md-3"></div>
<div class="col-md-9">
<button class="btn btn-default" ng-click="vm.testConnection()">Test Connection</button>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" id="btnOk">// 'ok' | tr //</button>
<button type="button" class="btn btn-default" data-dismiss="modal">// 'close' | tr //</button>
</div>
</form>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->

View File

@ -0,0 +1,32 @@
(function() {
'use strict';
angular
.module('harbor.replication')
.directive('createPolicy', createPolicy);
function CreatePolicyController() {
var vm = this;
vm.enabled = true;
vm.save = save;
function save(policy) {
console.log(angular.toJson(policy));
}
}
function createPolicy() {
var directive = {
'restrict': 'E',
'templateUrl': '/static/ng/resources/js/components/replication/create-policy.directive.html',
'scope': true,
'replace': true,
'controller': CreatePolicyController,
'controllerAs': 'vm',
'bindToController': true
};
return directive;
}
})();

View File

@ -0,0 +1,79 @@
<div class="tab-pane">
<div class="col-xs-12 col-md-12 each-tab-pane">
<div class="form-inline">
<div class="input-group">
<input type="text" class="form-control" placeholder="" ng-model="vm.replicationName" size="30">
<span class="input-group-btn">
<button class="btn btn-primary" type="button" ng-click="vm.search()"><span class="glyphicon glyphicon-search"></span></button>
</span>
</div>
<button ng-if="!vm.isOpen" class="btn btn-success" type="button" ng-click="vm.addReplication()" data-toggle="modal" data-target="#createPolicyModal"><span class="glyphicon glyphicon-plus"></span>New Replication</button>
<create-policy></create-policy>
</div>
<div class="pane-split" id="upon-pane">
<div class="sub-pane-split">
<table class="table table-pane">
<thead>
<th width="10%">Name</th>
<th width="18%">Description</th>
<th width="14%">Destination</th>
<th width="18%">Start Time</th>
<th width="14%">Status</th>
<th width="14%">Activation</th>
<th width="12%">Actions</th>
</thead>
<tbody>
<tr ng-if="vm.replicationPolicies.length == 0">
<td colspan="7" height="100%" class="empty-hint" ><h3 class="text-muted">No replication policies, add new replication policy.</h3></td>
</tr>
<tr policy_id="//r.policy_id//" ng-if="vm.replicationPolicies.length > 0" ng-repeat="r in vm.replicationPolicies" value="//vm.last = $last//">
<td>//r.name//</td>
<td>//r.description//</td>
<td>//r.destination//</td>
<td>//r.start_time//</td>
<td>//r.status//</td>
<td>//r.activation//</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-xs-4 col-md-12 well well-sm well-custom well-split"><div class="col-md-offset-10">//vm.projects ? vm.projects.length : 0// // 'items' | tr //</div></div>
<p class="split-handle"><span class="glyphicon glyphicon-align-justify"></span></p>
<h4 class="h4-custom-down">Replication Jobs</h4>
<hr class="hr-line"/>
<div class="form-inline">
<div class="input-group">
<input type="text" class="form-control" placeholder="" ng-model="vm.replicationJobnName" size="30">
<span class="input-group-btn">
<button class="btn btn-primary" type="button" ng-click="vm.search()"><span class="glyphicon glyphicon-search"></span></button>
</span>
</div>
</div>
<div class="pane-split" id="down-pane">
<div class="sub-pane-split">
<table class="table table-pane" width="98%">
<thead>
<th width="20%">Name</th>
<th width="25%">Operation</th>
<th width="40%">Start Time</th>
<th width="15%">Status</th>
</thead>
<tbody>
<tr ng-if="vm.replicationJobs.length == 0">
<td colspan="4" height="100%" class="empty-hint" ><h3 class="text-muted">No replication jobs.</h3></td>
</tr>
<tr ng-if="vm.replicationJobs.length > 0" ng-repeat="r in vm.replicationJobs">
<td>//r.name//</td>
<td>//r.operation//</td>
<td>//r.start_time//</td>
<td>//r.status//</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,119 @@
(function() {
'use strict';
angular
.module('harbor.replication')
.directive('listReplication', listReplication);
ListReplicationController.$inject = ['getParameterByName', '$location', 'ListReplicationPolicyService', 'ListReplicationJobService'];
function ListReplicationController(getParameterByName, $location, ListReplicationPolicyService, ListReplicationJobService) {
var vm = this;
vm.projectId = getParameterByName('project_id', $location.absUrl());
vm.addReplication = addReplication;
vm.retrievePolicy = retrievePolicy;
vm.retrieveJob = retrieveJob;
vm.last = false;
vm.retrievePolicy();
function retrievePolicy() {
ListReplicationPolicyService(vm.projectId, vm.replicationName)
.success(listReplicationPolicySuccess)
.error(listReplicationPolicyFailed);
}
function retrieveJob(policyId) {
ListReplicationJobService(policyId, vm.replicationJobName)
.success(listReplicationJobSuccess)
.error(listReplicationJobFailed);
}
function listReplicationPolicySuccess(data, status) {
vm.replicationPolicies = data || [];
}
function listReplicationPolicyFailed(data, status) {
console.log('Failed list replication policy:' + data);
}
function listReplicationJobSuccess(data, status) {
vm.replicationJobs = data || [];
}
function listReplicationJobFailed(data, status) {
console.log('Failed list replication job:' + data);
}
function addReplication() {
vm.modalTitle = 'Create New Policy';
}
}
function listReplication($timeout) {
var directive = {
'restrict': 'E',
'templateUrl': '/static/ng/resources/js/components/replication/list-replication.directive.html',
'scope': true,
'link': link,
'controller': ListReplicationController,
'controllerAs': 'vm',
'bindToController': true
};
return directive;
function link(scope, element, attrs, ctrl) {
var uponPaneHeight = element.find('#upon-pane').height();
var handleHeight = element.find('.split-handle').height() + element.find('.split-handle').offset().top + element.find('.well').height() - 24;
var maxDownPaneHeight = 245;
element.find('.split-handle').on('mousedown', mousedownHandler);
function mousedownHandler(e) {
e.preventDefault();
$(document).on('mousemove', mousemoveHandler);
$(document).on('mouseup', mouseupHandler);
}
function mousemoveHandler(e) {
if(element.find('#down-pane').height() <= maxDownPaneHeight) {
element.find('#upon-pane').css({'height' : (uponPaneHeight - (handleHeight - e.pageY)) + 'px'});
element.find('#down-pane').css({'height' : (uponPaneHeight + (handleHeight - e.pageY - 196)) + 'px'});
}else{
element.find('#down-pane').css({'height' : (maxDownPaneHeight) + 'px'});
$(document).off('mousemove');
}
}
function mouseupHandler(e) {
$(document).off('mousedown');
$(document).off('mousemove');
}
scope.$watch('vm.last', function(current) {
$timeout(function(){
if(current) {
element.find('#upon-pane table>tbody>tr').on('click', trClickHandler);
element.find('#upon-pane table>tbody>tr:eq(0)').trigger('click');
}
});
});
function trClickHandler(e) {
element
.find('#upon-pane table>tbody>tr')
.css({'background-color': '#FFFFFF'})
.css({'color': '#000'});
$(this)
.css({'background-color': '#057ac9'})
.css({'color': '#fff'});
ctrl.retrieveJob($(this).attr('policy_id'));
}
}
}
})();

View File

@ -0,0 +1,11 @@
(function() {
'use strict';
angular
.module('harbor.replication', [
'harbor.services.replication.policy',
'harbor.services.replication.job'
]);
})();

View File

@ -0,0 +1,62 @@
<form name="form" class="form-horizontal" ng-submit="form.$valid && vm.changeSettings(system)" >
<div class="col-md-12">
<h5>System Settings</h5>
<hr/>
</div>
<div class="col-md-12 col-md-off-set-1 main-content">
<div class="form-group">
<label for="hostName" class="col-sm-3 control-label">Host Name:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="hostName" ng-model="system.hostName" ng-model-options="{ updateOn: 'blur' }" ng-value="vm.system.hostName" name="uHostName" required>
<div ng-messages="form.$dirty && form.uHostName.$error">
<span ng-message="required">Host name is required.</span>
</div>
</div>
</div>
<div class="form-group">
<label for="urlProtocol" class="col-sm-3 control-label">URL Protocol:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="urlProtocol" ng-model="system.urlProtocol" ng-model-options="{ updateOn: 'blur' }" ng-value="vm.system.urlProtocol" name="uUrlProtocol" required>
<div ng-messages="form.$dirty && form.uUrlProtocol.$error">
<span ng-message="required">Url protocol is required.</span>
</div>
</div>
</div>
<div class="form-group">
<label for="emailServer" class="col-sm-3 control-label">Email server:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="emailServer" ng-model="system.emailServer" ng-model-options="{ updateOn: 'blur' }" ng-value="vm.system.emailServer" name="uEmailServer" required>
<div ng-messages="form.$dirty && form.uEmailServer.$error">
<span ng-message="required">Email server is required.</span>
</div>
</div>
</div>
<div class="form-group">
<label for="ldapUrl" class="col-sm-3 control-label">LDAP URL:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="ldapUrl" ng-model="system.ldapUrl" ng-model-options="{ updateOn: 'blur' }" ng-value="vm.system.ldapUrl" name="uLdapUrl" required>
<div ng-messages="form.$dirty && form.uLdapUrl.$error">
<span ng-message="required">LDAP URL is required.</span>
</div>
</div>
</div>
</div>
<div class="col-md-12">
<h5>Registration</h5>
<hr/>
</div>
<div class="col-md-12 col-md-off-set-1 main-content">
<div class="form-group">
<label for="registration" class="col-sm-3 control-label">Registration:</label>
<div class="col-sm-7">
<select class="form-control" ng-model="vm.currentRegistration" ng-options="r as r.name for r in vm.registrationOptions track by r.value" ng-click="vm.selectRegistration()"></select>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-7 col-md-10">
<input type="submit" class="btn btn-primary" ng-disabled="form.$invalid" value="Save">
<input type="submit" class="btn btn-default" ng-click="vm.cancel()" value="Cancel">
</div>
</div>
</div>
</form>

View File

@ -0,0 +1,54 @@
(function() {
'use strict';
angular
.module('harbor.system.management')
.directive('configuration', configuration);
ConfigurationController.$inject = [];
function ConfigurationController() {
var vm = this;
vm.registrationOptions = [
{
'name': 'on',
'value': true
},
{
'name': 'off',
'value': false
}
];
vm.currentRegistration = {
'name': 'on',
'value': true
};
vm.changeSettings = changeSettings;
vm.selectRegistration = selectRegistration;
function selectRegistration() {
}
function changeSettings(system) {
console.log(system);
}
}
function configuration() {
var directive = {
'restrict': 'E',
'templateUrl': '/static/ng/resources/js/components/system-management/configuration.directive.html',
'scope': true,
'controller': ConfigurationController,
'controllerAs': 'vm',
'bindToController': true
};
return directive;
}
})();

View File

@ -0,0 +1,62 @@
<div class="modal fade" id="createDestinationModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><span class="glyphicon glyphicon-plus"></span>&nbsp;&nbsp;Create New Destination</h4>
</div>
<div class="modal-body">
<div class="create-destination">
<form name="form" class="form-horizontal" ng-submit="form.$valid" novalidate>
<div class="form-group col-md-12 form-group-custom">
<label for="name" class="col-md-3 control-label">Name:</label>
<div class="col-md-9">
<input type="text" class="form-control form-control-custom" id="name" ng-model="destination.name" ng-model-options="{ updateOn: 'blur' }" ng-value="vm.destination.name" name="uName" required>
<div ng-messages="form.$dirty && form.uName.$error">
<span ng-message="required">Name is required.</span>
</div>
</div>
</div>
<div class="form-group col-md-12 form-group-custom">
<label for="description" class="col-md-3 control-label">Endpoint:</label>
<div class="col-md-9">
<input type="text" class="form-control form-control-custom" id="endpoint" ng-model="destination.endpoint" ng-model-options="{ updateOn: 'blur' }" ng-value="vm.destination.endpoint" name="uEndpoint" required >
<div ng-messages="form.$dirty && form.uEndpoint.$error">
<span ng-message="required">Endpoint is required.</span>
</div>
</div>
</div>
<div class="form-group col-md-12 form-group-custom">
<label for="username" class="col-md-3 control-label">Username:</label>
<div class="col-md-9">
<input type="text" class="form-control" id="username" ng-model="destination.username" ng-model-options="{ updateOn: 'blur' }" ng-value="vm.destination.username" name="uUsername" required>
<div ng-messages="form.$dirty && form.uUsername.$error">
<span ng-message="required">Username is required.</span>
</div>
</div>
</div>
<div class="form-group col-md-12 form-group-custom">
<label for="password" class="col-md-3 control-label">Password:</label>
<div class="col-md-9">
<input type="password" class="form-control" id="password" ng-model="destination.password" ng-model-options="{ updateOn: 'blur' }" ng-value="vm.destination.password" name="uPassword" required>
<div ng-messages="form.$dirty && form.uPassword.$error">
<span ng-message="required">Password is required.</span>
</div>
</div>
</div>
<div class="form-group col-md-12 form-group-custom">
<div class="col-md-3"></div>
<div class="col-md-9">
<button class="btn btn-default" ng-click="vm.testConnection()">Test Connection</button>
</div>
</div>
</form>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" id="btnOk" ng-click="vm.save(destination)">// 'ok' | tr //</button>
<button type="button" class="btn btn-default" data-dismiss="modal">// 'close' | tr //</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->

View File

@ -0,0 +1,47 @@
(function() {
'use strict';
angular
.module('harbor.system.management')
.directive('createDestination', createDestination);
CreateDestinationController.$inject = ['CreateDestinationService'];
function CreateDestinationController(CreateDestinationService) {
var vm = this;
vm.save = save;
function save(destination) {
if(destination) {
console.log('destination:' + angular.toJson(destination));
CreateDestinationService(destination.name, destination.endpoint,
destination.username, destination.password)
.success(createDestinationSuccess)
.error(createDestinationFailed);
}
}
function createDestinationSuccess(data, status) {
alert('Successful created destination.');
}
function createDestinationFailed(data, status) {
console.log('Failed create destination:' + data);
}
}
function createDestination() {
var directive = {
'restrict': 'E',
'templateUrl': '/static/ng/resources/js/components/system-management/create-destination.directive.html',
'scope': true,
'controller': CreateDestinationController,
'controllerAs': 'vm',
'bindToController': true
};
return directive;
}
})();

View File

@ -0,0 +1,38 @@
<div class="tab-pane">
<div class="col-xs-12 col-md-12 each-tab-pane">
<div class="form-inline">
<div class="input-group">
<input type="text" class="form-control" placeholder="" ng-model="vm.destinationName" size="30">
<span class="input-group-btn">
<button class="btn btn-primary" type="button" ng-click="vm.search()"><span class="glyphicon glyphicon-search"></span></button>
</span>
</div>
<button ng-if="!vm.isOpen" class="btn btn-success" type="button" ng-click="vm.addDestination()" data-toggle="modal" data-target="#createDestinationModal"><span class="glyphicon glyphicon-plus"></span>New Destination</button>
<create-destination></create-destination>
</div>
<div class="pane">
<div class="sub-pane">
<table class="table table-pane">
<thead>
<th width="20%">Name</th>
<th width="40%">Endpoint</th>
<th width="20%">Creation Time</th>
<th width="20%">Action</th>
</thead>
<tbody>
<tr ng-if="vm.destinations.length == 0">
<td colspan="7" height="100%" class="empty-hint" ><h3 class="text-muted">No destinations, add new destination.</h3></td>
</tr>
<tr ng-if="vm.destinations.length > 0" ng-repeat="r in vm.destinations">
<td>//r.name//</td>
<td>//r.url//</td>
<td>//r.creation_time//</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-xs-4 col-md-12 well well-sm well-custom well-split"><div class="col-md-offset-10">//vm.destinations ? vm.destinations.length : 0// // 'items' | tr //</div></div>
</div>
</div>

View File

@ -0,0 +1,51 @@
(function() {
'use strict';
angular
.module('harbor.system.management')
.directive('destination', destination);
DestinationController.$inject = ['ListDestinationService'];
function DestinationController(ListDestinationService) {
var vm = this;
vm.retrieve = retrieve;
vm.search = search;
vm.retrieve();
function retrieve() {
ListDestinationService()
.success(listDestinationSuccess)
.error(listDestinationFailed);
}
function search() {
vm.retrieve();
}
function listDestinationSuccess(data, status) {
vm.destinations = data;
}
function listDestinationFailed(data, status) {
console.log('Failed list destination:' + data);
}
}
function destination() {
var directive = {
'restrict': 'E',
'templateUrl': '/static/ng/resources/js/components/system-management/destination.directive.html',
'scope': true,
'controller': DestinationController,
'controllerAs': 'vm',
'bindToController': true
};
return directive;
}
})();

View File

@ -0,0 +1,44 @@
<div class="tab-pane">
<div class="col-xs-12 col-md-12 each-tab-pane">
<div class="form-inline">
<div class="input-group">
<input type="text" class="form-control" placeholder="" ng-model="vm.replicationName" size="30">
<span class="input-group-btn">
<button class="btn btn-primary" type="button" ng-click="vm.search()"><span class="glyphicon glyphicon-search"></span></button>
</span>
</div>
</div>
<div class="pane">
<div class="sub-pane">
<table class="table table-pane">
<thead>
<th width="12%">Name</th>
<th width="14%">Description</th>
<th width="12%">Project</th>
<th width="14%">Destination</th>
<th width="12%">Start Time</th>
<th width="12%">Status</th>
<th width="12%">Activation</th>
<th width="12%">Actions</th>
</thead>
<tbody>
<tr ng-if="vm.replications.length == 0">
<td colspan="7" height="100%" class="empty-hint" ><h3 class="text-muted">No replications.</h3></td>
</tr>
<tr ng-if="vm.replications.length > 0" ng-repeat="r in vm.replications">
<td>//r.name//</td>
<td>//r.description//</td>
<td>//r.project//</td>
<td>//r.destination//</td>
<td>//r.start_time//</td>
<td>//r.status//</td>
<td>//r.activation//</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-xs-4 col-md-12 well well-sm well-custom well-split"><div class="col-md-offset-10">//vm.replications ? vm.replications.length : 0// // 'items' | tr //</div></div>
</div>
</div>

View File

@ -0,0 +1,33 @@
(function() {
'use strict';
angular
.module('harbor.system.management')
.directive('replication', replication);
ReplicationController.$inject = ['ListReplicationPolicyService'];
function ReplicationController(ListReplicationPolicyService) {
var vm = this;
ListReplicationPolicyService()
.then(function(data) {
vm.replications = data;
}, function(data) {
});
}
function replication() {
var directive = {
'restrict': 'E',
'templateUrl': '/static/ng/resources/js/components/system-management/replication.directive.html',
'scope': true,
'controller': ReplicationController,
'controllerAs': 'vm',
'bindToController': true
};
return directive;
}
})();

View File

@ -0,0 +1,10 @@
<div class="switch-pane">
<span>
<navigation-admin-options target="vm.target"></navigation-admin-options>
</span>
</div>
<div class="pane project-pane">
<destination ng-if="vm.target === 'destinations'"></destination>
<replication ng-if="vm.target === 'replication'"></replication>
<configuration ng-if="vm.target === 'configuration'"></configuration>
</div>

View File

@ -0,0 +1,26 @@
(function() {
'use strict';
angular
.module('harbor.system.management')
.directive('systemManagement', systemManagement);
function SystemManagementController() {
var vm = this;
vm.target = 'destinations';
}
function systemManagement() {
var directive = {
'restrict': 'E',
'templateUrl': '/static/ng/resources/js/components/system-management/system-management.directive.html',
'scope': true,
'controller': SystemManagementController,
'controllerAs': 'vm',
'bindToController': true
};
return directive;
}
})();

View File

@ -0,0 +1,8 @@
(function() {
'use strict';
angular
.module('harbor.system.management', []);
})();

View File

@ -0,0 +1,35 @@
<div class="search-pane">
<div class="form-inline">
<div class="input-group">
<input type="text" class="form-control" placeholder="" ng-model="vm.username" size="30">
<span class="input-group-btn">
<button class="btn btn-primary" type="button" ng-click="vm.searchUser()"><span class="glyphicon glyphicon-search"></span></button>
</span>
</div>
</div>
</div>
<div class="pane project-pane">
<div class="sub-pane">
<table class="table">
<thead>
<th>// 'username' | tr //</th><th>// 'role' | tr //</th><th>// 'email' | tr //</th><th>// 'registration_time' | tr //</th><th>// 'operation' | tr //</th>
</thead>
<tbody>
<tr ng-repeat="u in vm.users">
<td>//u.username//</td>
<td>N/A</td>
<td>//u.email//</td>
<td>//u.creation_time | dateL : 'YYYY-MM-DD HH:mm:ss'//</td>
<td>
<toggle-admin has-admin-role="u.HasAdminRole == 1" user-id="//u.UserId//"></toggle-admin>&nbsp;&nbsp;
&nbsp;&nbsp;<a href="javascript:void(0)" ng-click="vm.deleteUser(u.UserId)"><span class="glyphicon glyphicon-trash"></span></a>
</td>
</tr>
</tbody>
</table>
</div>
<div class="col-xs-4 col-md-12 well well-sm well-custom">
<div class="col-md-offset-10">//vm.users ? vm.users.length : 0// items</div>
</div>
</div>

View File

@ -0,0 +1,67 @@
(function() {
'use strict';
angular
.module('harbor.user')
.directive('listUser', listUser);
ListUserController.$inject = ['ListUserService', 'DeleteUserService'];
function ListUserController(ListUserService, DeleteUserService) {
var vm = this;
vm.username = '';
vm.searchUser = searchUser;
vm.deleteUser = deleteUser;
vm.retrieve = retrieve;
vm.retrieve();
function searchUser() {
vm.retrieve();
}
function deleteUser(userId) {
DeleteUserService(userId)
.success(deleteUserSuccess)
.error(deleteUserFailed);
}
function retrieve() {
ListUserService(vm.username)
.success(listUserSuccess)
.error(listUserFailed);
}
function deleteUserSuccess(data, status) {
console.log('Successful delete user.');
vm.retrieve();
}
function deleteUserFailed(data, status) {
console.log('Failed delete user.');
}
function listUserSuccess(data, status) {
vm.users = data;
}
function listUserFailed(data, status) {
console.log('Failed list user:' + data);
}
}
function listUser() {
var directive = {
'restrict': 'E',
'templateUrl': '/static/ng/resources/js/components/user/list-user.directive.html',
'scope': true,
'controller': ListUserController,
'controllerAs': 'vm',
'bindToController': true
};
return directive;
}
})();

View File

@ -0,0 +1,5 @@
<ul class="switch-pane-admin-options" role="tablist">
<li><a tag="destinations" href="#/destinations">Destinations</a><span class="gutter">|</span></li>
<li><a tag="replication" href="#/replication">Replication</a><span class="gutter">|</span></li>
<li><a tag="configuration" href="#/configuration">Configuration</a></li>
</ul>

View File

@ -0,0 +1,51 @@
(function() {
'use strict';
angular
.module('harbor.layout.navigation')
.directive('navigationAdminOptions', navigationAdminOptions);
NavigationAdminOptions.$inject = ['$location'];
function NavigationAdminOptions($location) {
var vm = this;
vm.path = $location.path();
}
function navigationAdminOptions() {
var directive = {
'restrict': 'E',
'templateUrl': '/static/ng/resources/js/layout/navigation/navigation-admin-options.directive.html',
'scope': {
'target': '='
},
'link': link,
'controller': NavigationAdminOptions,
'controllerAs': 'vm',
'bindToController': true
};
return directive;
function link(scope, element, attrs, ctrl) {
var visited = ctrl.path.substring(1);
console.log('visited:' + visited);
if(visited) {
element.find('a[tag="' + visited + '"]').addClass('active');
}else{
element.find('a:first').addClass('active');
}
element.find('a').on('click', click);
function click(event) {
element.find('a').removeClass('active');
$(event.target).addClass('active');
ctrl.target = $(this).attr('tag');
scope.$apply();
}
}
}
})();

View File

@ -0,0 +1,24 @@
(function() {
'use strict';
angular
.module('harbor.services.destination')
.factory('CreateDestinationService', CreateDestinationService);
CreateDestinationService.$inject = ['$http'];
function CreateDestinationService($http) {
return createDestination;
function createDestination(name, endpoint, username, password) {
return $http
.post('/api/targets', {
'name': name,
'url': endpoint,
'username': username,
'password': password
});
}
}
})()

View File

@ -0,0 +1,8 @@
(function() {
'use strict';
angular
.module('harbor.services.destination', []);
})();

View File

@ -0,0 +1,23 @@
(function() {
'use strict';
angular
.module('harbor.services.destination')
.factory('ListDestinationService', ListDestinationService);
ListDestinationService.$inject = ['$http'];
function ListDestinationService($http) {
return listDestination;
function listDestination(name) {
return $http
.get('/api/targets', {
'params': {
'name': name
}
});
}
}
})()

View File

@ -0,0 +1,25 @@
(function() {
'use strict';
angular
.module('harbor.services.replication.job')
.factory('ListReplicationJobService', ListReplicationJobService);
ListReplicationJobService.$inject = ['$http'];
function ListReplicationJobService($http) {
return listReplicationJob;
function listReplicationJob(policyId, name) {
return $http
.get('/api/jobs/replication/', {
'params': {
'policy_id': policyId,
'name': name
}
});
}
}
})();

View File

@ -0,0 +1,8 @@
(function() {
'use strict';
angular
.module('harbor.services.replication.job', []);
})();

View File

@ -0,0 +1,28 @@
(function() {
'use strict';
angular
.module('harbor.services.replication.policy')
.factory('CreateReplicationPolicyService', CreateReplicationPolicyService);
CreateReplicationPolicyService.$inject = ['$http'];
function CreateReplicationPolicyService($http) {
return createReplicaitonPolicy;
function createReplicationPolicy(policy) {
return $http
.post('/api/policies/replication', {
'project_id': policy.projectId,
'target_id': policy.targetId,
'name': policy.name,
'enabled': policy.enabled,
'description': policy.description,
'cron_str': policy.cronStr,
'start_time': policy.startTime
})
}
}
})();

View File

@ -0,0 +1,27 @@
(function() {
'use strict';
angular
.module('harbor.services.replication.policy')
.factory('ListReplicationPolicyService', ListReplicationPolicyService);
ListReplicationPolicyService.$inject = ['$http'];
function ListReplicationPolicyService($http) {
return listReplicationPolicy;
function listReplicationPolicy(projectId, name) {
return $http
.get('/api/policies/replication', {
'params': {
'project_id': projectId,
'name': name
}
});
}
}
})();

View File

@ -0,0 +1,8 @@
(function() {
'use strict';
angular
.module('harbor.services.replication.policy', []);
})();

24
views/ng/header.htm Normal file
View File

@ -0,0 +1,24 @@
<nav class="navbar navbar-default navbar-custom" ng-controller="HeaderController as vm">
<div class="container container-custom">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-harbor-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/ng/main"><img class="img-responsive" src="/static/ng/resources/img/Harbor_Logo_rec.png" alt="Harbor's Logo"/></a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-harbor-navbar-collapse-1">
<optional-menu current="vm.current"></optional-menu>
<ul class="nav navbar-nav navbar-right">
<li>
<navigation-header></navigation-header>
</li>
<li>
<search-input search-input='vm.searchInput'></search-input>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>

View File

@ -0,0 +1,8 @@
<ul class="switch-pane-tabs pull-right" {{ if eq .IsAdmin 1 }} style="width: 365px" {{ end }} role="tablist">
<li><a tag="repositories" href="#/repositories?project_id=//vm.projectId//">// 'repositories' | tr //</a><span class="gutter">|</span></li>
{{ if eq .IsAdmin 1 }}
<li><a tag="replication" href="#/replication?project_id=//vm.projectId//">Replication</a><span class="gutter">|</span></li>
{{ end }}
<li><a tag="users" href="#/users?project_id=//vm.projectId//">// 'users' | tr //</a><span class="gutter">|</span></li>
<li><a tag="logs" href="#/logs?project_id=//vm.projectId//">// 'logs' | tr //</a></li>
</ul>