updates for i18n of UI

This commit is contained in:
kunw 2016-05-13 18:48:06 +08:00
parent 2f59120e48
commit 1c9e1e9eca
38 changed files with 915 additions and 168 deletions

View File

@ -1,6 +1,7 @@
.up-section .up-table-pane {
overflow-y: scroll;
height: 180px;
margin-top: -10px;
}
.up-section .dl-horizontal dt{

View File

@ -17,7 +17,6 @@ body {
margin: 20px 0 20px 0;
background-color: #FFFFFF;
height: 257px;
overflow: auto;
}
.up-section h4 label {
@ -25,10 +24,12 @@ body {
}
.thumbnail {
margin-top: 10px;
display: inline-block;
border: none;
padding: 2px;
box-shadow: none;
width: 30%;
}
.down-section {
@ -61,7 +62,7 @@ body {
.page-header {
padding-bottom: 10px;
margin: 0 10px 10px 10px;
margin: 10px;
border-bottom: none;
}
@ -70,7 +71,7 @@ body {
}
.step-content {
width: 210px;
text-align: center;
}
.display-inline-block {

View File

@ -1,5 +1,5 @@
.main-title {
margin-top: 50px;
margin-top: 20px;
margin-left: 180px;
}

View File

@ -7,7 +7,7 @@
<input type="text" class="form-control search-icon" placeholder="" ng-model="vm.filterInput" size="30">
</div>
</div>
<h5 class="page-header">My Projects: <span class="badge">//vm.resultCount//</span></h5>
<h5 class="page-header">//vm.projectType | tr//: <span class="badge">//vm.resultCount//</span></h5>
<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)">

View File

@ -32,6 +32,7 @@
$scope.$watch('vm.publicity', function(current, origin) {
vm.isPublic = current ? 1 : 0;
vm.projectType = (vm.isPublic == 1) ? 'public_projects' : 'my_projects';
vm.retrieve();
});

View File

@ -3,24 +3,24 @@
<div class="col-xs-10 col-md-10">
<form class="form">
<div class="form-group">
<label for="">Operation:</label>
<label for="">// 'operation' | tr //:</label>
</div>
<div class="form-group">
<input type="checkbox" ng-model="vm.opAll" ng-checked="vm.opCreate && vm.opPull && vm.opPush && vm.opDelete && vm.opOthers" ng-click="vm.checkOperation({checked: 'all'})">&nbsp;All&nbsp;&nbsp;
<input type="checkbox" ng-model="vm.opAll" ng-checked="vm.opCreate && vm.opPull && vm.opPush && vm.opDelete && vm.opOthers" ng-click="vm.checkOperation({checked: 'all'})">&nbsp;// 'all' | tr //&nbsp;&nbsp;
<input type="checkbox" ng-checked="vm.opCreate" ng-model="vm.opCreate" ng-click="vm.checkOperation({checked: 'create'})">&nbsp;Create&nbsp;&nbsp;
<input type="checkbox" ng-checked="vm.opPull" ng-model="vm.opPull" ng-click="vm.checkOperation({checked: 'pull'})">&nbsp;Pull&nbsp;&nbsp;
<input type="checkbox" ng-checked="vm.opPush" ng-model="vm.opPush" ng-click="vm.checkOperation({checked: 'push'})">&nbsp;Push&nbsp;&nbsp;
<input type="checkbox" ng-checked="vm.opDelete" ng-model="vm.opDelete" ng-click="vm.checkOperation({checked: 'delete'})">&nbsp;Delete&nbsp;&nbsp;
<input type="checkbox" ng-checked="vm.opOthers" ng-model="vm.opOthers" ng-click="vm.checkOperation({checked: 'others'})">&nbsp;Others&nbsp;&nbsp;
<input type="checkbox" ng-checked="vm.opOthers" ng-model="vm.opOthers" ng-click="vm.checkOperation({checked: 'others'})">&nbsp;// 'others' | tr //&nbsp;&nbsp;
<input type="text" ng-model="vm.others" size="10">
</div>
<div class="form-group">
<label for="">Duration:</label>
<label for="">// 'duration' | tr //:</label>
</div>
<div class="form-group inline-block col-md-5">
<span class="datetime-picker-title">From:</span>
<span class="datetime-picker-title">// 'from' | tr //:</span>
<!--date-picker picked-date="vm.fromDate"></date-picker-->
<div class="input-group datetimepicker">
<input id="fromDatePicker" class="form-control" type="text" readonly="readonly" ng-model="vm.fromDate" ng-change="vm.pickUp({key:'fromDate', value: vm.fromDate})">
@ -31,7 +31,7 @@
</div>
<div class="form-group inline-block col-md-5">
<span class="datetime-picker-title">To:</span>
<span class="datetime-picker-title">// 'to' | tr //:</span>
<div class="input-group datetimepicker">
<input id="toDatePicker" class="form-control" type="text" readonly="readonly" ng-model="vm.toDate" ng-change="vm.pickUp({key:'toDate', value: vm.toDate})">
<span class="input-group-addon">
@ -45,7 +45,7 @@
<div class="col-xs-2 col-md-2">
<form>
<div class="form-group" style="margin-top: 40%;">
<button type="button" class="btn btn-primary" ng-click="vm.search({op: vm.op})">Search</button>
<button type="button" class="btn btn-primary" ng-click="vm.search({op: vm.op})">// 'search' | tr //</button>
</div>
</form>
</div>

View File

@ -7,7 +7,7 @@
<button class="btn btn-primary" type="button" ng-click="vm.search({op: vm.op, username: vm.username})"><span class="glyphicon glyphicon-search"></span></button>
</span>
<span class="input-group-btn">
<button class="btn btn-link" type="button" ng-click="vm.showAdvancedSearch()">Advanced Search</button>
<button class="btn btn-link" type="button" ng-click="vm.showAdvancedSearch()">// 'advanced_search' | tr //</button>
</span>
</div>
</div>
@ -16,7 +16,7 @@
<div class="sub-pane">
<table class="table table-pane">
<thead>
<th>Username</th><th>Repository Name</th><th>Operation</th><th>Timestamp</th>
<th>// 'username' | tr //</th><th>// 'repository_name' | tr //</th><th>// 'operation' | tr //</th><th>// 'timestamp' | tr //</th>
</thead>
<tbody>
<tr ng-repeat="log in vm.logs">

View File

@ -1,10 +1,10 @@
<div ng-if="!vm.isLoggedIn" class="dropdown">
<a id="dLabel" role="button" data-toggle="dropdown" class="btn btn-link" data-target="#" href="">
<span class="glyphicon glyphicon-user"></span> Language
<span class="glyphicon glyphicon-globe"></span> //vm.languageName//
</a>
<ul class="dropdown-menu multi-level" role="menu" aria-labelledby="dropdownMenu">
<li><a href="#">English</a></li>
<li><a href="#">中文</a></li>
<li><a href="javascript:void(0);" ng-click="vm.setLanguage('en-US')">English</a></li>
<li><a href="javascript:void(0);" ng-click="vm.setLanguage('zh-CN')">中文</a></li>
</ul>
</div>
@ -13,15 +13,15 @@
<span class="glyphicon glyphicon-user"></span> //vm.username//
</a>
<ul class="dropdown-menu multi-level" role="menu" aria-labelledby="dropdownMenu">
<li><a href="/ng/account_setting"><span class="glyphicon glyphicon-pencil"></span> Account Setting</a></li>
<li><a href="/ng/account_setting"><span class="glyphicon glyphicon-pencil"></span> // 'account_setting' | tr //</a></li>
<li class="dropdown-submenu">
<a tabindex="-1" href="#"><span class="glyphicon glyphicon-globe"></span> Languages</a>
<a tabindex="-1" href="#"><span class="glyphicon glyphicon-globe"></span> //vm.languageName//</a>
<ul class="dropdown-menu">
<li><a href="#">English</a></li>
<li><a href="#">中文</a></li>
<li><a href="javascript:void(0);" ng-click="vm.setLanguage('en-US')">English</a></li>
<li><a href="javascript:void(0);" ng-click="vm.setLanguage('zh-CN')">中文</a></li>
</ul>
</li>
<li class="divider"></li>
<li><a href="javascript:void(0)" ng-click="vm.logOut()"><span class="glyphicon glyphicon-log-out"></span> Log Out</a></li>
<li><a href="javascript:void(0)" ng-click="vm.logOut()"><span class="glyphicon glyphicon-log-out"></span> // 'log_out' | tr //</a></li>
</ul>
</div>

View File

@ -6,11 +6,22 @@
.module('harbor.optional.menu')
.directive('optionalMenu', optionalMenu);
OptionalMenuController.$inject = ['$scope', '$window', 'LogOutService'];
OptionalMenuController.$inject = ['$scope', '$window', 'I18nService', 'LogOutService'];
function OptionalMenuController($scope, $window, LogOutService) {
function OptionalMenuController($scope, $window, I18nService, LogOutService) {
var vm = this;
vm.currentLanguage = I18nService().getCurrentLanguage();
vm.setLanguage = setLanguage;
vm.languageName = I18nService().getLanguageName(vm.currentLanguage);
console.log('current language:' + I18nService().getCurrentLanguage());
vm.logOut = logOut;
function setLanguage(name) {
I18nService().setCurrentLanguage(name);
$window.location.reload();
}
function logOut() {
LogOutService()
.success(logOutSuccess)

View File

@ -7,15 +7,15 @@
<button class="btn btn-primary" type="button" ng-click="vm.search({projectId: vm.projectId, username: vm.username})"><span class="glyphicon glyphicon-search"></span></button>
</span>
</div>
<button ng-if="!vm.isOpen" class="btn btn-success" type="button" ng-click="vm.addProjectMember()"><span class="glyphicon glyphicon-plus"></span>Add Member</button>
<button ng-if="vm.isOpen" class="btn btn-default" disabled="disabled" type="button"><span class="glyphicon glyphicon-plus"></span>Add Member</button>
<button ng-if="!vm.isOpen" class="btn btn-success" type="button" ng-click="vm.addProjectMember()"><span class="glyphicon glyphicon-plus"></span>// 'add_member' | tr //</button>
<button ng-if="vm.isOpen" class="btn btn-default" disabled="disabled" type="button"><span class="glyphicon glyphicon-plus"></span>// 'add_member' | tr //</button>
</div>
<div class="pane">
<add-project-member ng-show="vm.isOpen" is-open="vm.isOpen" project-id="//vm.projectId//" reload='vm.search({projectId: vm.projectId, username: vm.username})'></add-project-member>
<div class="sub-pane">
<table class="table table-pane" >
<thead>
<th width="30%">Username</th><th width="40%">Role</th><th width="30%">Operation</th>
<th width="30%">// 'username' | tr //</th><th width="40%">// 'role' | tr //</th><th width="30%">// 'operation' | tr //</th>
</thead>
<tbody>
<tr ng-repeat="pr in vm.projectMembers" edit-project-member username="pr.username" project-id="vm.projectId" user-id="pr.UserId" current-user-id="vm.currentUser.UserId" role-name="pr.Rolename" reload='vm.search({projectId: vm.projectId, username: vm.username})'></tr>

View File

@ -3,18 +3,18 @@
<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">
<input type="text" class="form-control" placeholder="// 'project_name' | tr //" ng-model="vm.projectName">
</div>
<div class="form-group">
<input type="checkbox" ng-model="vm.isPublic">&nbsp;Public Project
<input type="checkbox" ng-model="vm.isPublic">&nbsp;// 'public_projects' | tr //
</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>
<button type="button" class="btn btn-default" ng-click="vm.cancel()">// 'cancel' | tr //</button>
<button type="button" class="btn btn-primary" ng-click="vm.addProject()">// 'save' | tr //</button>
</div>
</form>
</div>

View File

@ -1,4 +1,2 @@
<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>
<button ng-if="vm.isPublic" ng-disabled="!vm.owned" class="btn btn-success" ng-click="vm.toggle()">// 'button_on' | tr //</button>
<button ng-if="!vm.isPublic" ng-disabled="!vm.owned" class="btn btn-danger" ng-click="vm.toggle()">// 'button_off' | tr //</button>

View File

@ -17,20 +17,7 @@
}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) {
@ -45,7 +32,6 @@
}
function editProjectSuccess(data, status) {
setBtnClass();
console.log('edit project successfully:' + status);
}

View File

@ -1,7 +1,7 @@
<div class="down-table-pane">
<table class="table">
<thead>
<th>Project/Repository Name</th><th>Creation Time</th><th>Author</th>
<th>// 'project_repo_name' | tr //</th><th>// 'creation_time' | tr //</th><th>// 'author' | tr //</th>
</thead>
<tbody>
<tr ng-repeat="s in vm.searchResult">

View File

@ -12,15 +12,15 @@
<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>
<button class="btn btn-default" ng-click="vm.doSignIn()">// 'sign_in' | tr //</button>
<button class="btn btn-success" ng-click="vm.doSignUp()">// 'sign_up' | tr //</button>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-1 col-sm-10">
<div class="pull-right">
<a href="javascript:void(0)" ng-click="vm.doForgotPassword()">Forgot Password</a>
<a href="javascript:void(0)" ng-click="vm.doForgotPassword()">// 'forgot_password' | tr //</a>
</div>
</div>
</div>

View File

@ -1,2 +1,2 @@
<button ng-show="vm.isAdmin" class="btn btn-success" ng-click="vm.toggle()">On</button>
<button ng-show="!vm.isAdmin" class="btn btn-danger" ng-click="vm.toggle()">Off</button>
<button ng-show="vm.isAdmin" class="btn btn-success" ng-click="vm.toggle()">// 'button_on' | tr //</button>
<button ng-show="!vm.isAdmin" class="btn btn-danger" ng-click="vm.toggle()">// 'button_off' | tr //</button>

View File

@ -9,7 +9,8 @@
.config(function($httpProvider) {
$httpProvider.defaults.headers.common = {'Accept': 'application/json, text/javascript, */*; q=0.01'};
})
.filter('dateL', localizeDate);
.filter('dateL', localizeDate)
.filter('tr', tr);
function localizeDate() {
return filter;
@ -17,6 +18,19 @@
function filter(input, pattern) {
return moment(new Date(input || '')).format(pattern);
}
}
tr.$inject = ['I18nService'];
function tr(I18nService) {
return tr;
function tr(label) {
var currentLanguage = I18nService().getCurrentLanguage();
if(label && label.length > 0){
return I18nService().getValue(label, currentLanguage);
}
return '';
}
}
})();

View File

@ -4,6 +4,7 @@
.module('harbor.app', [
'ngRoute',
'ngMessages',
'ngCookies',
'harbor.session',
'harbor.layout.header',
'harbor.layout.navigation',
@ -20,6 +21,7 @@
'harbor.layout.system.management',
'harbor.layout.log',
'harbor.layout.admin.option',
'harbor.services.i18n',
'harbor.services.project',
'harbor.services.user',
'harbor.services.repository',

View File

@ -6,9 +6,9 @@
.module('harbor.layout.forgot.password')
.controller('ForgotPasswordController', ForgotPasswordController);
ForgotPasswordController.$inject = ['SendMailService'];
ForgotPasswordController.$inject = ['SendMailService', '$window'];
function ForgotPasswordController(SendMailService) {
function ForgotPasswordController(SendMailService, $window) {
var vm = this;
vm.hasError = false;
vm.errorMessage = '';
@ -24,6 +24,7 @@
function sendMailSuccess(data, status) {
console.log('Successful send mail:' + data);
$window.location.href = '/ng';
}
function sendMailFailed(data) {

View File

@ -1,5 +1,5 @@
<ul class="switch-pane-tabs" role="tablist">
<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>
<li><a tag="repositories" href="#/repositories?project_id=//vm.projectId//">// 'repositories' | tr //</a><span class="gutter">|</span></li>
<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>

View File

@ -52,7 +52,7 @@
visited = ctrl.url.substring(1, ctrl.url.indexOf('?') - 1);
}
element.find('a[tag^="' + visited + '"]').addClass('active');
element.find('a[tag*="' + visited + '"]').addClass('active');
element.on('click', click);
function click(event) {

View File

@ -1,4 +1,5 @@
<ul class="nav-custom">
<li><a tag="dashboard" href="/ng/dashboard">Dashboard</a></li>
<li><a tag="project" href="/ng/project">Project</a></li>
<li><a tag="dashboard" href="/ng/dashboard">// 'dashboard' | tr //</a></li>
<li><a tag="project" href="/ng/project">// 'projects' | tr //</a></li>
<li><a ng-show="vm.isAdmin" tag="admin_option" href="/ng/admin_option#/all_user">// 'admin_options' | tr //</a></li>
</ul>

View File

@ -6,11 +6,18 @@
.module('harbor.layout.navigation')
.directive('navigationHeader', navigationHeader);
NavigationHeaderController.$inject = ['$window'];
NavigationHeaderController.$inject = ['$window', '$scope'];
function NavigationHeaderController($window) {
function NavigationHeaderController($window, $scope) {
var vm = this;
vm.url = $window.location.pathname;
vm.url = $window.location.pathname;
vm.isAdmin = false;
$scope.$on('currentUser', function(e, val) {
if(val.HasAdminRole === 1) {
vm.isAdmin = true;
}
$scope.$apply();
});
}
function navigationHeader() {
@ -26,23 +33,17 @@
return directive;
function link(scope, element, attrs, ctrl) {
function link(scope, element, attrs, ctrl) {
element.find('a').removeClass('active');
var visited = ctrl.url;
if (visited != "/") {
element.find('a[href="' + visited + '"]').addClass('active');
}
if (visited != "/ng") {
element.find('a[href*="' + visited + '"]').addClass('active');
}
element.on('click', click);
function click(event) {
element.find('a').removeClass('active');
$(event.target).not('span').addClass('active');
}
}
}
}

View File

@ -6,7 +6,7 @@
.module('harbor.layout.reset.password')
.controller('ResetPasswordController', ResetPasswordController);
ResetPasswordController.$inject = ['$location', 'ResetPasswordService'];
ResetPasswordController.$inject = ['$location', 'ResetPasswordService', '$window'];
function getParameterByName(name, url) {
name = name.replace(/[\[\]]/g, "\\$&");
@ -17,7 +17,7 @@
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
function ResetPasswordController($location, ResetPasswordService) {
function ResetPasswordController($location, ResetPasswordService, $window) {
var vm = this;
vm.resetUuid = getParameterByName('reset_uuid', $location.absUrl());
vm.resetPassword = resetPassword;
@ -31,6 +31,7 @@
function resetPasswordSuccess(data, status) {
console.log('Successful reset password:' + data);
$window.location.href = '/ng';
}
function resetPasswordFailed(data) {

View File

@ -10,7 +10,7 @@
<div style="height: 500px; overflow-y: auto;">
<table class="table">
<thead>
<th>Username</th><th>Role</th><th>Email</th><th>Registration Time</th><th>Operation</th>
<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">

View File

@ -0,0 +1,358 @@
var global_messages = {
'sign_in': {
'en-US': 'Sign In',
'zh-CN': '登录'
},
'sign_up': {
'en-US': 'Sign Up',
'zh-CN': '注册'
},
'forgot_password': {
'en-US': 'Forgot Password',
'zh-CN': '忘记密码'
},
'login_now': {
'en-US': 'Login Now',
'zh-CN': '立刻登录'
},
'its_easy_to_get_started': {
'en-US': 'It\'s easy to get started ...',
'zh-CN': '这很容易上手...'
},
'anybody_can_read_public_projects': {
'en-US': 'Anybody can read public projects',
'zh-CN': '任何人都可以访问公开的项目'
},
'create_projects_and_connect_repositories': {
'en-US': 'Create projects and connect repositories',
'zh-CN': '创建项目并关联镜像仓库'
},
'user_management_and_role_assignment': {
'en-US': 'User management and role assignment',
'zh-CN': '用户管理和角色分派'
},
'why_use_harbor': {
'en-US': 'Why use Harbor?',
'zh-CN': '为什么要使用Harbor'
},
'index_desc': {
'en-US': 'Project Harbor is to build an enterprise-class, reliable registry server. Enterprises can set up a private registry server in their own environment to improve productivity as well as security. Project Harbor can be used in both development and production environment.',
'zh-CN': 'Harbor是可靠的企业级Registry服务器。企业用户可使用Harbor搭建私有容器Registry服务提高生产效率和安全度既可应用于生产环境也可以在开发环境中使用。'
},
'index_desc_1': {
'en-US': 'Security: Keep their intellectual properties within their organizations.',
'zh-CN': '安全: 确保知识产权在自己组织内部的管控之下。'
},
'index_desc_2': {
'en-US': 'Efficiency: A private registry server is set up within the organization\'s network and can reduce significantly the internet traffic to the public service. ',
'zh-CN': '效率: 搭建组织内部的私有容器Registry服务可显著降低访问公共Registry服务的网络需求。'
},
'index_desc_3': {
'en-US': 'Access Control: RBAC (Role Based Access Control) is provided. User management can be integrated with existing enterprise identity services like AD/LDAP. ',
'zh-CN': '访问控制: 提供基于角色的访问控制,可集成企业目前拥有的用户管理系统(如:AD/LDAP。 '
},
'index_desc_4': {
'en-US': 'Audit: All access to the registry are logged and can be used for audit purpose.',
'zh-CN': '审计: 所有访问Registry服务的操作均被记录便于日后审计。'
},
'index_desc_5': {
'en-US': 'GUI: User friendly single-pane-of-glass management console.',
'zh-CN': '管理界面: 具有友好易用图形管理界面。'
},
'learn_more': {
'en-US': 'Learn more...',
'zh-CN': '更多...'
},
'repositories': {
'en-US': 'Repositories',
'zh-CN': '镜像仓库'
},
'project_repo_name': {
'en-US': 'Project/Repository Name',
'zh-CN': '项目/镜像仓库名称'
},
'creation_time': {
'en-US': 'Creation Time',
'zh-CN': '创建时间'
},
'author': {
'en-US': 'Author',
'zh-CN': '作者'
},
'username': {
'en-US': 'Username',
'zh-CN': '用户名'
},
'username_is_required' : {
'en-US': 'Username is required.',
'zh-CN': '用户名为必填项。'
},
'username_has_been_taken' : {
'en-US': 'Username has been taken.',
'zh-CN': '用户名已被占用。'
},
'username_is_too_long' : {
'en-US': 'Username is too long. (maximum 20 characters)',
'zh-CN': '用户名长度超出限制。最长为20个字符'
},
'username_contains_illegal_chars': {
'en-US': 'Username contains illegal character(s).',
'zh-CN': '用户名包含不合法的字符。'
},
'email': {
'en-US': 'Email',
'zh-CN': '邮箱'
},
'email_desc': {
'en-US': 'The Email address will be used for resetting password.',
'zh-CN': '此邮箱将用于重置密码。'
},
'email_is_required' : {
'en-US': 'Email is required.',
'zh-CN': '邮箱为必填项。'
},
'email_has_been_taken' : {
'en-US': 'Email has been taken.',
'zh-CN': '邮箱已被占用。'
},
'email_content_illegal' : {
'en-US': 'Email format is illegal.',
'zh-CN': '邮箱格式不合法。'
},
'email_does_not_exist' : {
'en-US': 'Email does not exist.',
'zh-CN': '邮箱不存在。'
},
'full_name': {
'en-US': 'Full Name',
'zh-CN': '全名'
},
'full_name_desc': {
'en-US': 'First name & Last name',
'zh-CN': '请输入全名。'
},
'full_name_is_required' : {
'en-US': 'Full name is required.',
'zh-CN': '全名为必填项。'
},
'full_name_is_too_long' : {
'en-US': 'Full name is too long. (maximum 20 characters)',
'zh-CN': '全名长度超出限制。最长为20个字符'
},
'full_name_contains_illegal_chars' : {
'en-US': 'Full name contains illegal character(s).',
'zh-CN': '全名包含不合法的字符。'
},
'password': {
'en-US': 'Password',
'zh-CN': '密码'
},
'password_desc': {
'en-US': 'At least 7 characters with 1 lowercase letter, 1 capital letter and 1 numeric character.',
'zh-CN': '至少输入 7个字符且包含 1个小写字母 1个大写字母和 1个数字。'
},
'password_is_required' : {
'en-US': 'Password is required.',
'zh-CN': '密码为必填项。'
},
'password_is_invalid' : {
'en-US': 'Password is invalid. At least 7 characters with 1 lowercase letter, 1 capital letter and 1 numeric character.',
'zh-CN': '密码无效。至少输入 7个字符且包含 1个小写字母1个大写字母和 1个数字。'
},
'confirm_password': {
'en-US': 'Confirm Password',
'zh-CN': '确认密码'
},
'password_does_not_match' : {
'en-US': 'Passwords do not match.',
'zh-CN': '两次密码输入不一致。'
},
'comments': {
'en-US': 'Comments',
'zh-CN': '备注'
},
'comment_is_too_long' : {
'en-US': 'Comment is too long. (maximum 20 characters)',
'zh-CN': '备注长度超出限制。最长为20个字符'
},
'forgot_password_description': {
'en-US': 'Please input the Email used when you signed up, a reset password Email will be sent to you.',
'zh-CN': '重置邮件将发送到此邮箱。'
},
'emaTimestampil_does_not_exist': {
'en-US': 'Email does not exist',
'zh-CN': '邮箱不存在。'
},
'reset_password': {
'en-US': 'Reset Password',
'zh-CN': '重置密码'
},
'summary': {
'en-US': 'Summary',
'zh-CN': '摘要'
},
'projects': {
'en-US': 'Projects',
'zh-CN': '项目'
},
'public_projects': {
'en-US': 'Public Projects',
'zh-CN': '公开项目'
},
'total_projects': {
'en-US': 'Total Projects',
'zh-CN': '全部项目'
},
'public_repositories': {
'en-US': 'Public Repositories',
'zh-CN': '公开镜像仓库'
},
'total_repositories': {
'en-US': 'Total Repositories',
'zh-CN': '全部镜像仓库'
},
'top_10_repositories': {
'en-US': 'Top 10 Repositories',
'zh-CN': 'Top 10 镜像仓库'
},
'repository_name': {
'en-US': 'Repository Name',
'zh-CN': '镜像仓库名'
},
'size': {
'en-US': 'Size',
'zh-CN': '规格'
},
'creator': {
'en-US': 'Creator',
'zh-CN': '创建者'
},
'logs': {
'en-US': 'Logs',
'zh-CN': '日志'
},
'task_name': {
'en-US': 'Task Name',
'zh-CN': '任务名称'
},
'details': {
'en-US': 'Details',
'zh-CN': '详细信息'
},
'user': {
'en-US': 'User',
'zh-CN': '用户'
},
'users': {
'en-US': 'Users',
'zh-CN': '用户'
},
'my_projects': {
'en-US': 'My Projects',
'zh-CN': '我的项目'
},
'public_projects': {
'en-US': 'Public Projects',
'zh-CN': '公开项目'
},
'project_name': {
'en-US': 'Project Name',
'zh-CN': '项目名称'
},
'role': {
'en-US': 'Role',
'zh-CN': '角色'
},
'publicity': {
'en-US': 'Publicity',
'zh-CN': '公开'
},
'button_on': {
'en-US': 'On',
'zh-CN': '打开'
},
'button_off': {
'en-US': 'Off',
'zh-CN': '关闭'
},
'new_project': {
'en-US': 'New Project',
'zh-CN': '新增项目'
},
'save': {
'en-US': 'Save',
'zh-CN': '保存'
},
'cancel': {
'en-US': 'Cancel',
'zh-CN': '取消'
},
'items': {
'en-US': 'items',
'zh-CN': '条记录'
},
'add_member': {
'en-US': 'Add Member',
'zh-CN': '新增成员'
},
'operation': {
'en-US': 'Operation',
'zh-CN': '操作'
},
'advanced_search': {
'en-US': 'Advanced Search',
'zh-CN': '高级搜索'
},
'all': {
'en-US': 'All',
'zh-CN': '全部'
},
'others': {
'en-US': 'Others',
'zh-CN': '其他'
},
'search': {
'en-US': 'Search',
'zh-CN': '搜索'
},
'duration': {
'en-US': 'Duration',
'zh-CN': '持续时间'
},
'from': {
'en-US': 'From',
'zh-CN': '起始'
},
'to': {
'en-US': 'To',
'zh-CN': '结束'
},
'timestamp': {
'en-US': 'Timestamp',
'zh-CN': '时间戳'
},
'dashboard': {
'en-US': 'Dashboard',
'zh-CN': '消息中心'
},
'admin_options': {
'en-US': 'Admin Options',
'zh-CN': '管理员选项'
},
'account_setting': {
'en-US': 'Account Setting',
'zh-CN': '个人设置'
},
'log_out': {
'en-US': 'Log Out',
'zh-CN': '注销'
},
'registration_time': {
'en-US': 'Registration Time',
'zh-CN': '注册时间'
},
'system_management': {
'en-US': 'System Management',
'zh-CN': '系统管理'
}
};

View File

@ -0,0 +1,40 @@
(function() {
'use strict';
angular
.module('harbor.services.i18n')
.factory('I18nService', I18nService);
I18nService.$inject = ['$cookies'];
function I18nService($cookies) {
var languages = $.extend(true, {}, global_messages);
var defaultLanguage = navigator.language || 'en-US';
var languageNames = {
'en-US': 'English',
'zh-CN': '中文'
};
return tr;
function tr() {
return {
'setCurrentLanguage': function(language) {
if(!language){
language = defaultLanguage;
}
$cookies.put('language', language);
},
'getCurrentLanguage': function() {
return $cookies.get('language') || defaultLanguage;
},
'getLanguageName': function(crrentLanguage) {
return languageNames[crrentLanguage];
},
'getValue': function(key, currentLanguage) {
return languages[key][currentLanguage];
}
}
}
}
})();

View File

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

View File

@ -0,0 +1,322 @@
/**
* @license AngularJS v1.5.3
* (c) 2010-2016 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular, undefined) {'use strict';
/**
* @ngdoc module
* @name ngCookies
* @description
*
* # ngCookies
*
* The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies.
*
*
* <div doc-module-components="ngCookies"></div>
*
* See {@link ngCookies.$cookies `$cookies`} for usage.
*/
angular.module('ngCookies', ['ng']).
/**
* @ngdoc provider
* @name $cookiesProvider
* @description
* Use `$cookiesProvider` to change the default behavior of the {@link ngCookies.$cookies $cookies} service.
* */
provider('$cookies', [function $CookiesProvider() {
/**
* @ngdoc property
* @name $cookiesProvider#defaults
* @description
*
* Object containing default options to pass when setting cookies.
*
* The object may have following properties:
*
* - **path** - `{string}` - The cookie will be available only for this path and its
* sub-paths. By default, this is the URL that appears in your `<base>` tag.
* - **domain** - `{string}` - The cookie will be available only for this domain and
* its sub-domains. For security reasons the user agent will not accept the cookie
* if the current domain is not a sub-domain of this domain or equal to it.
* - **expires** - `{string|Date}` - String of the form "Wdy, DD Mon YYYY HH:MM:SS GMT"
* or a Date object indicating the exact date/time this cookie will expire.
* - **secure** - `{boolean}` - If `true`, then the cookie will only be available through a
* secured connection.
*
* Note: By default, the address that appears in your `<base>` tag will be used as the path.
* This is important so that cookies will be visible for all routes when html5mode is enabled.
*
**/
var defaults = this.defaults = {};
function calcOptions(options) {
return options ? angular.extend({}, defaults, options) : defaults;
}
/**
* @ngdoc service
* @name $cookies
*
* @description
* Provides read/write access to browser's cookies.
*
* <div class="alert alert-info">
* Up until Angular 1.3, `$cookies` exposed properties that represented the
* current browser cookie values. In version 1.4, this behavior has changed, and
* `$cookies` now provides a standard api of getters, setters etc.
* </div>
*
* Requires the {@link ngCookies `ngCookies`} module to be installed.
*
* @example
*
* ```js
* angular.module('cookiesExample', ['ngCookies'])
* .controller('ExampleController', ['$cookies', function($cookies) {
* // Retrieving a cookie
* var favoriteCookie = $cookies.get('myFavorite');
* // Setting a cookie
* $cookies.put('myFavorite', 'oatmeal');
* }]);
* ```
*/
this.$get = ['$$cookieReader', '$$cookieWriter', function($$cookieReader, $$cookieWriter) {
return {
/**
* @ngdoc method
* @name $cookies#get
*
* @description
* Returns the value of given cookie key
*
* @param {string} key Id to use for lookup.
* @returns {string} Raw cookie value.
*/
get: function(key) {
return $$cookieReader()[key];
},
/**
* @ngdoc method
* @name $cookies#getObject
*
* @description
* Returns the deserialized value of given cookie key
*
* @param {string} key Id to use for lookup.
* @returns {Object} Deserialized cookie value.
*/
getObject: function(key) {
var value = this.get(key);
return value ? angular.fromJson(value) : value;
},
/**
* @ngdoc method
* @name $cookies#getAll
*
* @description
* Returns a key value object with all the cookies
*
* @returns {Object} All cookies
*/
getAll: function() {
return $$cookieReader();
},
/**
* @ngdoc method
* @name $cookies#put
*
* @description
* Sets a value for given cookie key
*
* @param {string} key Id for the `value`.
* @param {string} value Raw value to be stored.
* @param {Object=} options Options object.
* See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults}
*/
put: function(key, value, options) {
$$cookieWriter(key, value, calcOptions(options));
},
/**
* @ngdoc method
* @name $cookies#putObject
*
* @description
* Serializes and sets a value for given cookie key
*
* @param {string} key Id for the `value`.
* @param {Object} value Value to be stored.
* @param {Object=} options Options object.
* See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults}
*/
putObject: function(key, value, options) {
this.put(key, angular.toJson(value), options);
},
/**
* @ngdoc method
* @name $cookies#remove
*
* @description
* Remove given cookie
*
* @param {string} key Id of the key-value pair to delete.
* @param {Object=} options Options object.
* See {@link ngCookies.$cookiesProvider#defaults $cookiesProvider.defaults}
*/
remove: function(key, options) {
$$cookieWriter(key, undefined, calcOptions(options));
}
};
}];
}]);
angular.module('ngCookies').
/**
* @ngdoc service
* @name $cookieStore
* @deprecated
* @requires $cookies
*
* @description
* Provides a key-value (string-object) storage, that is backed by session cookies.
* Objects put or retrieved from this storage are automatically serialized or
* deserialized by angular's toJson/fromJson.
*
* Requires the {@link ngCookies `ngCookies`} module to be installed.
*
* <div class="alert alert-danger">
* **Note:** The $cookieStore service is **deprecated**.
* Please use the {@link ngCookies.$cookies `$cookies`} service instead.
* </div>
*
* @example
*
* ```js
* angular.module('cookieStoreExample', ['ngCookies'])
* .controller('ExampleController', ['$cookieStore', function($cookieStore) {
* // Put cookie
* $cookieStore.put('myFavorite','oatmeal');
* // Get cookie
* var favoriteCookie = $cookieStore.get('myFavorite');
* // Removing a cookie
* $cookieStore.remove('myFavorite');
* }]);
* ```
*/
factory('$cookieStore', ['$cookies', function($cookies) {
return {
/**
* @ngdoc method
* @name $cookieStore#get
*
* @description
* Returns the value of given cookie key
*
* @param {string} key Id to use for lookup.
* @returns {Object} Deserialized cookie value, undefined if the cookie does not exist.
*/
get: function(key) {
return $cookies.getObject(key);
},
/**
* @ngdoc method
* @name $cookieStore#put
*
* @description
* Sets a value for given cookie key
*
* @param {string} key Id for the `value`.
* @param {Object} value Value to be stored.
*/
put: function(key, value) {
$cookies.putObject(key, value);
},
/**
* @ngdoc method
* @name $cookieStore#remove
*
* @description
* Remove given cookie
*
* @param {string} key Id of the key-value pair to delete.
*/
remove: function(key) {
$cookies.remove(key);
}
};
}]);
/**
* @name $$cookieWriter
* @requires $document
*
* @description
* This is a private service for writing cookies
*
* @param {string} name Cookie name
* @param {string=} value Cookie value (if undefined, cookie will be deleted)
* @param {Object=} options Object with options that need to be stored for the cookie.
*/
function $$CookieWriter($document, $log, $browser) {
var cookiePath = $browser.baseHref();
var rawDocument = $document[0];
function buildCookieString(name, value, options) {
var path, expires;
options = options || {};
expires = options.expires;
path = angular.isDefined(options.path) ? options.path : cookiePath;
if (angular.isUndefined(value)) {
expires = 'Thu, 01 Jan 1970 00:00:00 GMT';
value = '';
}
if (angular.isString(expires)) {
expires = new Date(expires);
}
var str = encodeURIComponent(name) + '=' + encodeURIComponent(value);
str += path ? ';path=' + path : '';
str += options.domain ? ';domain=' + options.domain : '';
str += expires ? ';expires=' + expires.toUTCString() : '';
str += options.secure ? ';secure' : '';
// per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
// - 300 cookies
// - 20 cookies per unique domain
// - 4096 bytes per cookie
var cookieLength = str.length + 1;
if (cookieLength > 4096) {
$log.warn("Cookie '" + name +
"' possibly not set or overflowed because it was too large (" +
cookieLength + " > 4096 bytes)!");
}
return str;
}
return function(name, value, options) {
rawDocument.cookie = buildCookieString(name, value, options);
};
}
$$CookieWriter.$inject = ['$document', '$log', '$browser'];
angular.module('ngCookies').provider('$$cookieWriter', function $$CookieWriterProvider() {
this.$get = $$CookieWriter;
});
})(window, window.angular);

View File

@ -4,11 +4,11 @@
<div class="col-xs-12 col-md-12 extend-height">
<div class="section">
<h4 class="page-header">
<span ng-show="!vm.toggle">Users</span>
<a ng-show="vm.toggle" href="#/all_user" ng-click="vm.toggleAdminOption()">Users</a>
<span ng-show="!vm.toggle">// 'users' | tr //</span>
<a ng-show="vm.toggle" href="#/all_user" ng-click="vm.toggleAdminOption()">// 'users' | tr //</a>
<span class="gutter">|</span>
<span ng-show="vm.toggle">System Management</span>
<a ng-show="!vm.toggle" href="#/system_management" class="title-color" ng-click="vm.toggleAdminOption()">System Management</a>
<span ng-show="vm.toggle">// 'system_management' | tr //</span>
<a ng-show="!vm.toggle" href="#/system_management" class="title-color" ng-click="vm.toggleAdminOption()">// 'system_management' | tr //</a>
</h4>
<div class="project-pane">
<ng-view></ng-view>

View File

@ -4,25 +4,25 @@
<div class="col-xs-4 col-md-4">
<div class="row">
<div class="up-section">
<h4 class="page-header title-color underlined">Summary</h4>
<h4 class="page-header title-color underlined">// 'summary' | tr //</h4>
<dl class="page-content dl-horizontal">
<dt>Projects:</dt><dd>//vm.statProjects['projects']//</dd>
<dt>Public Projects:</dt><dd>//vm.statProjects['public_projects']//</dd>
<dt>Total Projects:</dt><dd>//vm.statProjects['total_projects']//</dd>
<dt>Repositories:</dt><dd>//vm.statProjects['repositories']//</dd>
<dt>Public Repositories:</dt><dd>//vm.statProjects['public_repositories']//</dd>
<dt>Total Repositories:</dt><dd>//vm.statProjects['total_repositories']//</dd>
<dt>// 'projects' | tr //:</dt><dd>//vm.statProjects['projects']//</dd>
<dt>// 'public_projects' | tr //:</dt><dd>//vm.statProjects['public_projects']//</dd>
<dt>// 'total_projects' | tr //:</dt><dd>//vm.statProjects['total_projects']//</dd>
<dt>// 'repositories' | tr //:</dt><dd>//vm.statProjects['repositories']//</dd>
<dt>// 'public_repositories' | tr //:</dt><dd>//vm.statProjects['public_repositories']//</dd>
<dt>// 'total_repositories' | tr //:</dt><dd>//vm.statProjects['total_repositories']//</dd>
</dl>
</div>
</div>
</div>
<div class="col-xs-8 col-md-8">
<div class="up-section">
<h4 class="page-header title-color underlined">Top 10 Repositories</h4>
<h4 class="page-header title-color underlined">// 'top_10_repositories' | tr //</h4>
<div class="col-xs-4 col-md-12 up-table-pane">
<table class="table">
<thead>
<th>Repository Name</th><th>Size</th><th>Creator</th>
<th>// 'repository_name' | tr //</th><th>// 'size' | tr //</th><th>// 'creator' | tr //</th>
</thead>
<tbody>
<tr ng-repeat="t in vm.top10Repositories">
@ -39,11 +39,11 @@
<div class="row row-custom">
<div class="col-xs-12 col-md-12">
<div class="down-section single">
<h4 class="page-header title-color underlined">Logs</h4>
<h4 class="page-header title-color underlined">// 'logs' | tr //</h4>
<div style="padding: 15px;">
<table class="table">
<thead>
<th>Task Name</th><th>Details</th><th>User</th><th>Time</th>
<th>// 'task_name' | tr //</th><th>// 'details' | tr //</th><th>// 'user' | tr //</th><th>// 'creation_time' | tr //</th>
</thead>
<tbody>
<tr ng-repeat="t in vm.integratedLogs">
@ -51,6 +51,7 @@
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>

View File

@ -2,15 +2,15 @@
<div class="container container-custom">
<div class="row extend-height">
<div class="section">
<h1 class="col-md-12 col-md-offset-2 main-title title-color">Forgot Password</h1>
<h1 class="col-md-12 col-md-offset-2 main-title title-color">// 'forgot_password' | tr //</h1>
<div class="row">
<div class="col-md-12 col-md-offset-2 main-content">
<form name="form" class="form-horizontal" ng-submit="form.$valid && vm.sendMail(user)" >
<div class="form-group">
<label for="email" class="col-sm-3 control-label">Email:</label>
<label for="email" class="col-sm-3 control-label">// 'email' | tr //:</label>
<div class="col-sm-7">
<input type="email" class="form-control" id="email" ng-model="user.email" ng-model-options="{ updateOn: 'blur' }" name="uEmail" required >
<p class="help-block small-size-fonts">Please input the Email used when you signed up, a reset password Email will be sent to you.</p>
<p class="help-block small-size-fonts">// 'forgot_password_description' | tr //</p>
</div>
<div class="col-sm-2">
<span class="asterisk">*</span>
@ -18,15 +18,15 @@
</div>
<div class="error-message">
<div ng-messages="form.uEmail.$error">
<span ng-message="required">Email is required.</span>
<span ng-message="required">// 'email_is_required' | tr //</span>
</div>
<div ng-show="vm.hasError">
<span>//vm.errorMessage//</span>
<span>// vm.errorMessage | tr //</span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-8 col-md-10">
<input type="submit" class="btn btn-success" value="Send">
<input type="submit" class="btn btn-success" ng-disabled="form.$invalid" value="Send">
</div>
</div>
</form>

View File

@ -5,7 +5,7 @@
<div class="row">
<div class="up-section">
<div class="col-sm-offset-1 col-sm-10">
<span class="glyphicon glyphicon-user"></span>&nbsp;&nbsp;<h4 class="title-color display-inline-block">Login now</h4>
<span class="glyphicon glyphicon-user"></span>&nbsp;&nbsp;<h4 class="title-color display-inline-block">// 'login_now' | tr //</h4>
</div>
<sign-in></sign-in>
</div>
@ -13,23 +13,23 @@
</div>
<div class="col-md-8">
<div class="up-section">
<h4 class="page-header">It's easy to get started ...</h4>
<h4 class="page-header display-inline-block">// 'its_easy_to_get_started' | tr //</h4>
<div class="page-content">
<div style="margin-left: auto; margin-right: auto; width: 100%;">
<div class="thumbnail display-inline-block">
<img src="static/ng/resources/img/Step1.png" alt="Step 1">
<h5 class="step-content">Anybody can read public projects</h5>
<h5 class="step-content">// 'anybody_can_read_public_projects' | tr //</h5>
</div>
<div class="thumbnail display-inline-block">
<img src="static/ng/resources/img/Step2.png" alt="Step 2">
<h5 class="step-content">Create projects and connect repositories</h5>
<h5 class="step-content">// 'create_projects_and_connect_repositories' | tr //</h5>
</div>
<div class="thumbnail display-inline-block">
<img src="static/ng/resources/img/Step3.png" alt="Step 3">
<h5 class="step-content">User management and role assignment.</h5>
<h5 class="step-content">// 'user_management_and_role_assignment' | tr //</h5>
</div>
</div>
</div>
@ -42,31 +42,26 @@
<div class="col-md-4">
<div class="row">
<div class="down-section">
<h4 class="page-header underlined">Why use Harbor?</h4>
<p class="page-content text-justify">
Project Harbor is to build an enterprise-class,
reliable registry server. Enterprises can set
up a private registry server in their own environment
to improve productivity as well as security.
Project Harbor can be used in both development
and production environment.
<h4 class="page-header underlined">// 'why_use_harbor' | tr //</h4>
<p class="page-content text-justify" style="margin-bottom: 20px;">
// 'index_desc' | tr //
</p>
<ul>
<li class="long-line">▪︎ Security: Keep their intellectual properties within their organizations.</li>
<li class="long-line">▪︎ Efficiency: A private registry server is set up within the organization's network and can reduce significantly the internet traffic to the public service.</li>
<li class="long-line">▪︎ Access Control: RBAC (Role Based Access Control) is provided. User management can be integrated with existing enterprise identity services like AD/LDAP.</li>
<li class="long-line">▪︎ Audit: All access to the registry are logged and can be used for audit purpose.</li>
<li class="long-line">▪︎ GUI: User friendly single-pane-of-glass management console.</li>
<li class="long-line">▪︎ // 'index_desc_1' | tr //</li>
<li class="long-line">▪︎ // 'index_desc_2' | tr //</li>
<li class="long-line">▪︎ // 'index_desc_3' | tr //</li>
<li class="long-line">▪︎ // 'index_desc_4' | tr //</li>
<li class="long-line">▪︎ // 'index_desc_5' | tr //</li>
</ul>
<div class="page-content pull-right">
<a href="#"><span class="glyphicon glyphicon-triangle-right"></span> Learn more...</a>
<a href="#"><span class="glyphicon glyphicon-triangle-right"></span> // 'learn_more' | tr //</a>
</div>
</div>
</div>
</div>
<div class="col-md-8">
<div class="down-section">
<h4 class="page-header title-color underlined">Repositories</h4>
<h4 class="page-header title-color underlined">// 'repositories' | tr //</h4>
<search filter-by="repository"></search>
</div>
</div>

View File

@ -4,11 +4,11 @@
<div class="col-xs-12 col-md-12 extend-height">
<div class="section">
<h4 class="page-header">
<span ng-show="!vm.publicity">My Projects</span>
<a ng-show="vm.publicity" href="#" ng-click="vm.togglePublicity({publicity: 0})">My Projects</a>
<span ng-show="!vm.publicity">// 'my_projects' | tr //</span>
<a ng-show="vm.publicity" href="#" ng-click="vm.togglePublicity({publicity: 0})">// 'my_projects' | tr //</a>
<span class="gutter">|</span>
<span ng-show="vm.publicity">Public Projects</span>
<a ng-show="!vm.publicity" href="#" class="title-color" ng-click="vm.togglePublicity({publicity: 1})">Public Projects</a></h4>
<span ng-show="vm.publicity">// 'public_projects' | tr //</span>
<a ng-show="!vm.publicity" href="#" class="title-color" ng-click="vm.togglePublicity({publicity: 1})">// 'public_projects' | tr //</a></h4>
<div class="search-pane">
<div class="form-inline">
<div class="input-group">
@ -17,8 +17,8 @@
<button class="btn btn-primary" type="button" ng-click="vm.searchProject()"><span class="glyphicon glyphicon-search"></span></button>
</span>
</div>
<button ng-if="vm.isOpen" class="btn btn-default" disabled="disabled" type="button"><span class="glyphicon glyphicon-plus"></span>New Project</button>
<button ng-if="!vm.isOpen" class="btn btn-success" type="button" ng-show="vm.showAddButton()" ng-click="vm.showAddProject()"><span class="glyphicon glyphicon-plus"></span>New Project</button>
<button ng-if="vm.isOpen" class="btn btn-default" disabled="disabled" type="button"><span class="glyphicon glyphicon-plus"></span> // 'new_project' | tr //</button>
<button ng-if="!vm.isOpen" class="btn btn-success" type="button" ng-show="vm.showAddButton()" ng-click="vm.showAddProject()"><span class="glyphicon glyphicon-plus"></span> // 'new_project' | tr //</button>
</div>
</div>
<div class="pane project-pane">
@ -26,7 +26,7 @@
<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>
<th>// 'project_name' | tr //</th><th>// 'repositories' | tr //</th><th>// 'role' | tr //</th><th>// 'creation_time' | tr //</th><th>// 'publicity' | tr //</th>
</thead>
<tbody>
<tr ng-repeat="p in vm.projects">
@ -39,7 +39,7 @@
</tbody>
</table>
</div>
<div class="col-xs-4 col-md-12 well well-sm well-custom"><div class="col-md-offset-10">//vm.projects ? vm.projects.length : 0// items</div></div>
<div class="col-xs-4 col-md-12 well well-sm well-custom"><div class="col-md-offset-10">//vm.projects ? vm.projects.length : 0// // 'items' | tr //</div></div>
</div>
</div>
</div>

View File

@ -4,11 +4,11 @@
<div class="col-xs-12 col-md-12 extend-height">
<div class="section">
<h4 class="page-header">
<span ng-show="!vm.publicity">My Projects</span>
<a ng-show="vm.publicity" href="#/repositories?project_id=//vm.selectedProject.ProjectId//" class="title-color" ng-click="vm.togglePublicity({publicity: false})">My Projects</a>
<span ng-show="!vm.publicity">// 'my_projects' | tr //</span>
<a ng-show="vm.publicity" href="#/repositories?project_id=//vm.selectedProject.ProjectId//" class="title-color" ng-click="vm.togglePublicity({publicity: false})">// 'my_projects' | tr //</a>
<span class="gutter">|</span>
<span ng-show="vm.publicity">Public Projects</span>
<a ng-show="!vm.publicity" href="#/repositories?project_id=//vm.selectedProject.ProjectId//" class="title-color" ng-click="vm.togglePublicity({publicity: true})">Public Projects</a></h4>
<span ng-show="vm.publicity">// 'public_projects' | tr //</span>
<a ng-show="!vm.publicity" href="#/repositories?project_id=//vm.selectedProject.ProjectId//" class="title-color" ng-click="vm.togglePublicity({publicity: true})">// 'public_projects' | tr //</a></h4>
<div class="switch-pane">
<switch-pane-projects is-open="vm.open" selected-project="vm.selectedProject"></switch-pane-projects>
<span>

View File

@ -2,22 +2,22 @@
<div class="container container-custom">
<div class="row extend-height">
<div class="section">
<h1 class="col-md-12 col-md-offset-2 main-title title-color">Reset Password</h1>
<h1 class="col-md-12 col-md-offset-2 main-title title-color">// 'reset_password' | tr //</h1>
<div class="row">
<div class="col-md-12 col-md-offset-2 main-content">
<form name="form" class="form-horizontal css-form" ng-submit="form.$valid && vm.resetPassword(user)" novalidate>
<div class="form-group">
<label for="password" class="col-sm-3 control-label">Password:</label>
<label for="password" class="col-sm-3 control-label">// 'password' | tr //:</label>
<div class="col-sm-7">
<input type="password" class="form-control" id="password" ng-model="user.password" ng-model-options="{ updateOn: 'blur' }" name="uPassword" required password>
<p class="help-block small-size-fonts">At least 7 characters with 1 lowercase letter, 1 capital letter and 1 numeric character.</p>
<p class="help-block small-size-fonts">// 'password_desc' | tr //</p>
</div>
<div class="col-sm-2">
<span class="asterisk">*</span>
</div>
</div>
<div class="form-group">
<label for="confirmPassword" class="col-sm-3 control-label">Confirm Password:</label>
<label for="confirmPassword" class="col-sm-3 control-label">// 'confirm_password' | tr //:</label>
<div class="col-sm-7">
<input type="password" class="form-control" id="confirmPassword" ng-model="user.confirmPassword" ng-model-options="{ updateOn: 'blur' }" name="uConfirmPassword" compare-to="user.password">
</div>
@ -33,11 +33,11 @@
</div>
<div class="error-message">
<div ng-messages="form.$dirty && form.uPassword.$error">
<span ng-message="required">New password is required.</span>
<span ng-message="password">New password is invalid.</span>
<span ng-message="required">// 'password_is_required' | tr //</span>
<span ng-message="password">// 'password_is_invalid' | tr //</span>
</div>
<div class="error-message" ng-messages="form.$dirty && form.uConfirmPassword.$error">
<span ng-message="compareTo">Confirm password mismatch.</span>
<span ng-message="compareTo">// 'password_does_not_match' | tr //</span>
</div>
</div>
</form>

View File

@ -35,6 +35,7 @@
<script src="/static/ng/vendors/angularjs/angular.js"></script>
<script src="/static/ng/vendors/angularjs/angular-route.js"></script>
<script src="/static/ng/vendors/angularjs/angular-messages.js"></script>
<script src="/static/ng/vendors/angularjs/angular-cookies.js"></script>
<script src="/static/ng/resources/js/harbor.module.js"></script>
<script src="/static/ng/resources/js/harbor.config.js"></script>
@ -92,6 +93,10 @@
<script src="/static/ng/resources/js/layout/admin-option/admin-option.controller.js"></script>
<script src="/static/ng/resources/js/layout/admin-option/admin-option.config.js"></script>
<script src="/static/ng/resources/js/services/i18n/services.i18n.module.js"></script>
<script src="/static/ng/resources/js/services/i18n/locale_messages.js"></script>
<script src="/static/ng/resources/js/services/i18n/services.i18n.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>

View File

@ -2,19 +2,19 @@
<div class="container container-custom">
<div class="row extend-height">
<div class="section">
<h1 class="col-md-12 col-md-offset-2 main-title title-color">Sign Up</h1>
<h1 class="col-md-12 col-md-offset-2 main-title title-color">// 'sign_up' | tr //</h1>
<div class="row">
<div class="col-md-12 col-md-offset-2 main-content">
<form name="form" class="form-horizontal" ng-submit="form.$valid && vm.signUp(user)" >
<div class="form-group">
<label for="username" class="col-sm-3 control-label">Username:</label>
<label for="username" class="col-sm-3 control-label">// 'username' | tr //:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="username" ng-model="user.username" ng-model-options="{ updateOn: 'blur' }" name="uUsername" required maxlength="20" invalid-chars user-exists data-target="username">
<div ng-messages="form.uUsername.$error">
<span ng-message="required">Username is required.</span>
<span ng-message="maxlength">Username maximum length is 20.</span>
<span ng-message="invalidChars">Username contains invalid characters.</span>
<span ng-message="userExists">Username already exists.</span>
<span ng-message="required">// 'username_is_required' | tr //</span>
<span ng-message="maxlength">// 'username_is_too_long' | tr //</span>
<span ng-message="invalidChars">// 'username_contains_illegal_chars' | tr //</span>
<span ng-message="userExists">// 'username_has_been_taken' | tr //</span>
</div>
</div>
<div class="col-sm-2">
@ -22,55 +22,55 @@
</div>
</div>
<div class="form-group">
<label for="email" class="col-sm-3 control-label">Email:</label>
<label for="email" class="col-sm-3 control-label">// 'email' | tr //:</label>
<div class="col-sm-7">
<input type="email" class="form-control" id="email" ng-model="user.email" ng-model-options="{ updateOn: 'blur' }" name="uEmail" required user-exists data-target="email" >
<div ng-messages="form.uEmail.$error">
<span ng-message="required">Email is required.</span>
<span ng-message="email">Email address is illegal.</span>
<span ng-message="userExists">Email address already exists.</span>
<span ng-message="required">// 'email_is_required' | tr //</span>
<span ng-message="email">// 'email_content_illegal' | tr //</span>
<span ng-message="userExists">// 'email_has_been_taken' | tr //</span>
</div>
<p class="help-block small-size-fonts">The Email address will be used for resetting password.</p>
<p class="help-block small-size-fonts">// 'email_desc' | tr //</p>
</div>
<div class="col-sm-2">
<span class="asterisk">*</span>
</div>
</div>
<div class="form-group">
<label for="fullName" class="col-sm-3 control-label">Full Name:</label>
<label for="fullName" class="col-sm-3 control-label">// 'full_name' | tr //:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="fullName" ng-model="user.fullName" ng-model-options="{ updateOn: 'blur' }" name="uFullName" required maxlength="20" invalid-chars>
<div ng-messages="form.uFullName.$error">
<span ng-message="required">Full name is required.</span>
<span ng-message="invalidChars">Full name contains invalid characters.</span>
<span ng-message="maxlength">Full name maximum length is 20.</span>
<span ng-message="required">// 'full_name_is_required' | tr //</span>
<span ng-message="invalidChars">// 'full_name_contains_illegal_chars' | tr //</span>
<span ng-message="maxlength">// 'full_name_is_too_long' | tr //</span>
</div>
<p class="help-block small-size-fonts">First name & Last name.</p>
<p class="help-block small-size-fonts">// 'full_name_desc' | tr //</p>
</div>
<div class="col-sm-2">
<span class="asterisk">*</span>
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-3 control-label">Password:</label>
<label for="password" class="col-sm-3 control-label">// 'password' | tr //:</label>
<div class="col-sm-7">
<input type="password" class="form-control" id="password" ng-model="user.password" ng-model-options="{ updateOn: 'blur' }" name="uPassword" required password>
<div ng-messages="form.uPassword.$error">
<span ng-message="required">Password is required.</span>
<span ng-message="password">Password is not valid.</span>
<span ng-message="required">// 'password_is_required' | tr //</span>
<span ng-message="password">// 'password_is_invalid' | tr //</span>
</div>
<p class="help-block small-size-fonts">At least 7 characters with 1 lowercase letter, 1 capital letter and 1 numeric character.</p>
<p class="help-block small-size-fonts">// 'password_desc' | tr //</p>
</div>
<div class="col-sm-2">
<span class="asterisk">*</span>
</div>
</div>
<div class="form-group">
<label for="confirmPassword" class="col-sm-3 control-label">Confirm Password:</label>
<label for="confirmPassword" class="col-sm-3 control-label">// 'confirm_password' | tr //:</label>
<div class="col-sm-7">
<input type="password" class="form-control" id="confirmPassword" ng-model="user.confirmPassword" ng-model-options="{ updateOn: 'blur' }" name="uConfirmPassword" compare-to="user.password">
<div ng-messages="form.uConfirmPassword.$error">
<span ng-message="compareTo">Confirm password mismatch.</span>
<span ng-message="compareTo">// 'password_does_not_match' | tr //</span>
</div>
</div>
<div class="col-sm-2">
@ -78,17 +78,17 @@
</div>
</div>
<div class="form-group">
<label for="comments" class="col-sm-3 control-label">Comments:</label>
<label for="comments" class="col-sm-3 control-label">// 'comments' | tr //:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="comments" ng-model="user.comment" name="uComments" ng-model-options="{ updateOn: 'blur' }" maxlength="20">
<div ng-messages="form.uComments.$error">
<span ng-show="maxlength">Comments maximum length is 20.</span>
<span ng-show="maxlength">// 'comment_is_too_long' | tr //</span>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-8 col-md-10">
<input type="submit" class="btn btn-success" value="Sign Up">
<input type="submit" class="btn btn-success" ng-disabled="form.$invalid" value="Sign Up">
</div>
</div>
</form>