mirror of
https://github.com/goharbor/harbor.git
synced 2024-09-30 06:18:02 +02:00
merge with upstream
This commit is contained in:
commit
626aec5c79
37
controllers/ng/signin.go
Normal file
37
controllers/ng/signin.go
Normal file
@ -0,0 +1,37 @@
|
||||
package ng
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/harbor/dao"
|
||||
"github.com/vmware/harbor/models"
|
||||
"github.com/vmware/harbor/utils/log"
|
||||
)
|
||||
|
||||
type SignInController struct {
|
||||
BaseController
|
||||
}
|
||||
|
||||
func (sic *SignInController) Get() {
|
||||
sessionUserID := sic.GetSession("userId")
|
||||
var hasLoggedIn bool
|
||||
var username string
|
||||
if sessionUserID != nil {
|
||||
hasLoggedIn = true
|
||||
userID := sessionUserID.(int)
|
||||
u, err := dao.GetUser(models.User{UserID: userID})
|
||||
if err != nil {
|
||||
log.Errorf("Error occurred in GetUser, error: %v", err)
|
||||
sic.CustomAbort(http.StatusInternalServerError, "Internal error.")
|
||||
}
|
||||
if u == nil {
|
||||
log.Warningf("User was deleted already, user id: %d, canceling request.", userID)
|
||||
sic.CustomAbort(http.StatusUnauthorized, "")
|
||||
}
|
||||
username = u.Username
|
||||
}
|
||||
sic.Data["Username"] = username
|
||||
sic.Data["HasLoggedIn"] = hasLoggedIn
|
||||
sic.TplName = "ng/sign-in.htm"
|
||||
sic.Render()
|
||||
}
|
@ -20,13 +20,11 @@ import (
|
||||
|
||||
"github.com/vmware/harbor/models"
|
||||
"github.com/vmware/harbor/utils/log"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
// AddAccessLog persists the access logs
|
||||
func AddAccessLog(accessLog models.AccessLog) error {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
p, err := o.Raw(`insert into access_log
|
||||
(user_id, project_id, repo_name, repo_tag, guid, operation, op_time)
|
||||
values (?, ?, ?, ?, ?, ?, now())`).Prepare()
|
||||
@ -43,7 +41,7 @@ func AddAccessLog(accessLog models.AccessLog) error {
|
||||
//GetAccessLogs gets access logs according to different conditions
|
||||
func GetAccessLogs(accessLog models.AccessLog) ([]models.AccessLog, error) {
|
||||
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
sql := `select a.log_id, u.username, a.repo_name, a.repo_tag, a.operation, a.op_time
|
||||
from access_log a left join user u on a.user_id = u.user_id
|
||||
where a.project_id = ? `
|
||||
@ -106,7 +104,7 @@ func GetAccessLogs(accessLog models.AccessLog) ([]models.AccessLog, error) {
|
||||
|
||||
// AccessLog ...
|
||||
func AccessLog(username, projectName, repoName, repoTag, action string) error {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
sql := "insert into access_log (user_id, project_id, repo_name, repo_tag, operation, op_time) " +
|
||||
"select (select user_id as user_id from user where username=?), " +
|
||||
"(select project_id as project_id from project where name=?), ?, ?, ?, now() "
|
||||
|
12
dao/base.go
12
dao/base.go
@ -22,6 +22,7 @@ import (
|
||||
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
@ -97,3 +98,14 @@ func InitDB() {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
var globalOrm orm.Ormer
|
||||
var once sync.Once
|
||||
|
||||
// GetOrmer :set ormer singleton
|
||||
func GetOrmer() orm.Ormer {
|
||||
once.Do(func() {
|
||||
globalOrm = orm.NewOrm()
|
||||
})
|
||||
return globalOrm
|
||||
}
|
||||
|
@ -715,3 +715,10 @@ func TestDeleteUser(t *testing.T) {
|
||||
t.Errorf("user is not nil after deletion, user: %+v", user)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrmer(t *testing.T) {
|
||||
o := GetOrmer()
|
||||
if o == nil {
|
||||
t.Errorf("Error get ormer.")
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/vmware/harbor/utils/log"
|
||||
)
|
||||
|
||||
@ -38,7 +37,7 @@ func AddProject(project models.Project) (int64, error) {
|
||||
return 0, errors.New("project name contains illegal characters")
|
||||
}
|
||||
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
p, err := o.Raw("insert into project (owner_id, name, creation_time, update_time, deleted, public) values (?, ?, ?, ?, ?, ?)").Prepare()
|
||||
if err != nil {
|
||||
@ -81,7 +80,7 @@ func IsProjectPublic(projectName string) bool {
|
||||
|
||||
//ProjectExists returns whether the project exists according to its name of ID.
|
||||
func ProjectExists(nameOrID interface{}) (bool, error) {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
type dummy struct{}
|
||||
sql := `select project_id from project where deleted = 0 and `
|
||||
switch nameOrID.(type) {
|
||||
@ -104,7 +103,7 @@ func ProjectExists(nameOrID interface{}) (bool, error) {
|
||||
|
||||
// GetProjectByID ...
|
||||
func GetProjectByID(id int64) (*models.Project, error) {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
sql := `select p.project_id, p.name, u.username as owner_name, p.owner_id, p.creation_time, p.update_time, p.public
|
||||
from project p left join user u on p.owner_id = u.user_id where p.deleted = 0 and p.project_id = ?`
|
||||
@ -127,7 +126,7 @@ func GetProjectByID(id int64) (*models.Project, error) {
|
||||
|
||||
// GetProjectByName ...
|
||||
func GetProjectByName(name string) (*models.Project, error) {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
var p []models.Project
|
||||
n, err := o.Raw(`select * from project where name = ? and deleted = 0`, name).QueryRows(&p)
|
||||
if err != nil {
|
||||
@ -143,7 +142,7 @@ func GetProjectByName(name string) (*models.Project, error) {
|
||||
|
||||
// GetPermission gets roles that the user has according to the project.
|
||||
func GetPermission(username, projectName string) (string, error) {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
sql := `select r.role_code from role as r
|
||||
inner join project_member as pm on r.role_id = pm.role
|
||||
@ -166,7 +165,7 @@ func GetPermission(username, projectName string) (string, error) {
|
||||
|
||||
// ToggleProjectPublicity toggles the publicity of the project.
|
||||
func ToggleProjectPublicity(projectID int64, publicity int) error {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
sql := "update project set public = ? where project_id = ?"
|
||||
_, err := o.Raw(sql, publicity, projectID).Exec()
|
||||
return err
|
||||
@ -177,7 +176,7 @@ func ToggleProjectPublicity(projectID int64, publicity int) error {
|
||||
// 1. the project is not deleted
|
||||
// 2. the prject is public or the user is a member of the project
|
||||
func SearchProjects(userID int) ([]models.Project, error) {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
sql := `select distinct p.project_id, p.name, p.public
|
||||
from project p
|
||||
left join project_member pm on p.project_id = pm.project_id
|
||||
@ -194,7 +193,7 @@ func SearchProjects(userID int) ([]models.Project, error) {
|
||||
|
||||
// GetUserRelevantProjects returns the projects of the user which are not deleted and name like projectName
|
||||
func GetUserRelevantProjects(userID int, projectName string) ([]models.Project, error) {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
sql := `select distinct
|
||||
p.project_id, p.owner_id, p.name,p.creation_time, p.update_time, p.public, pm.role role
|
||||
from project p
|
||||
@ -235,7 +234,7 @@ func GetAllProjects(projectName string) ([]models.Project, error) {
|
||||
}
|
||||
|
||||
func getProjects(public int, projectName string) ([]models.Project, error) {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
sql := `select project_id, owner_id, creation_time, update_time, name, public
|
||||
from project
|
||||
where deleted = 0`
|
||||
|
@ -16,13 +16,12 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/vmware/harbor/models"
|
||||
)
|
||||
|
||||
// AddProjectMember inserts a record to table project_member
|
||||
func AddProjectMember(projectID int64, userID int, role int) error {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
sql := "insert into project_member (project_id, user_id , role) values (?, ?, ?)"
|
||||
|
||||
@ -33,7 +32,7 @@ func AddProjectMember(projectID int64, userID int, role int) error {
|
||||
|
||||
// UpdateProjectMember updates the record in table project_member
|
||||
func UpdateProjectMember(projectID int64, userID int, role int) error {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
sql := "update project_member set role = ? where project_id = ? and user_id = ?"
|
||||
|
||||
@ -44,7 +43,7 @@ func UpdateProjectMember(projectID int64, userID int, role int) error {
|
||||
|
||||
// DeleteProjectMember delete the record from table project_member
|
||||
func DeleteProjectMember(projectID int64, userID int) error {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
sql := "delete from project_member where project_id = ? and user_id = ?"
|
||||
|
||||
@ -57,7 +56,7 @@ func DeleteProjectMember(projectID int64, userID int) error {
|
||||
|
||||
// GetUserByProject gets all members of the project.
|
||||
func GetUserByProject(projectID int64, queryUser models.User) ([]models.User, error) {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
u := []models.User{}
|
||||
sql := `select u.user_id, u.username, r.name rolename, r.role_id
|
||||
from user u
|
||||
|
@ -22,8 +22,6 @@ import (
|
||||
|
||||
"github.com/vmware/harbor/models"
|
||||
"github.com/vmware/harbor/utils"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
// Register is used for user to register, the password is encrypted before the record is inserted into database.
|
||||
@ -34,7 +32,7 @@ func Register(user models.User) (int64, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
p, err := o.Raw("insert into user (username, password, realname, email, comment, salt, sysadmin_flag, creation_time, update_time) values (?, ?, ?, ?, ?, ?, ?, ?, ?)").Prepare()
|
||||
if err != nil {
|
||||
@ -108,7 +106,7 @@ func UserExists(user models.User, target string) (bool, error) {
|
||||
return false, errors.New("User name and email are blank.")
|
||||
}
|
||||
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
sql := `select user_id from user where 1=1 `
|
||||
queryParam := make([]interface{}, 1)
|
||||
|
@ -18,14 +18,13 @@ package dao
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/vmware/harbor/models"
|
||||
)
|
||||
|
||||
// GetUserProjectRoles returns roles that the user has according to the project.
|
||||
func GetUserProjectRoles(userID int, projectID int64) ([]models.Role, error) {
|
||||
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
sql := `select *
|
||||
from role
|
||||
@ -76,7 +75,7 @@ func IsAdminRole(userIDOrUsername interface{}) (bool, error) {
|
||||
|
||||
// GetRoleByID ...
|
||||
func GetRoleByID(id int) (*models.Role, error) {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
sql := `select *
|
||||
from role
|
||||
|
19
dao/user.go
19
dao/user.go
@ -22,14 +22,13 @@ import (
|
||||
"github.com/vmware/harbor/models"
|
||||
"github.com/vmware/harbor/utils"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/vmware/harbor/utils/log"
|
||||
)
|
||||
|
||||
// GetUser ...
|
||||
func GetUser(query models.User) (*models.User, error) {
|
||||
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
sql := `select user_id, username, email, realname, comment, reset_uuid, salt,
|
||||
sysadmin_flag, creation_time, update_time
|
||||
@ -66,7 +65,7 @@ func GetUser(query models.User) (*models.User, error) {
|
||||
|
||||
// LoginByDb is used for user to login with database auth mode.
|
||||
func LoginByDb(auth models.AuthModel) (*models.User, error) {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
var users []models.User
|
||||
n, err := o.Raw(`select * from user where (username = ? or email = ?) and deleted = 0`,
|
||||
@ -91,7 +90,7 @@ func LoginByDb(auth models.AuthModel) (*models.User, error) {
|
||||
|
||||
// ListUsers lists all users according to different conditions.
|
||||
func ListUsers(query models.User) ([]models.User, error) {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
u := []models.User{}
|
||||
sql := `select user_id, username, email, realname, comment, reset_uuid, salt,
|
||||
sysadmin_flag, creation_time, update_time
|
||||
@ -111,7 +110,7 @@ func ListUsers(query models.User) ([]models.User, error) {
|
||||
|
||||
// ToggleUserAdminRole gives a user admin role.
|
||||
func ToggleUserAdminRole(u models.User) error {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
sql := `update user set sysadmin_flag =not sysadmin_flag where user_id = ?`
|
||||
|
||||
@ -133,7 +132,7 @@ func ChangeUserPassword(u models.User, oldPassword ...string) (err error) {
|
||||
return errors.New("Wrong numbers of params.")
|
||||
}
|
||||
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
|
||||
var r sql.Result
|
||||
if len(oldPassword) == 0 {
|
||||
@ -159,7 +158,7 @@ func ChangeUserPassword(u models.User, oldPassword ...string) (err error) {
|
||||
|
||||
// ResetUserPassword ...
|
||||
func ResetUserPassword(u models.User) error {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
r, err := o.Raw(`update user set password=?, reset_uuid=? where reset_uuid=?`, utils.Encrypt(u.Password, u.Salt), "", u.ResetUUID).Exec()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -176,7 +175,7 @@ func ResetUserPassword(u models.User) error {
|
||||
|
||||
// UpdateUserResetUUID ...
|
||||
func UpdateUserResetUUID(u models.User) error {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
_, err := o.Raw(`update user set reset_uuid=? where email=?`, u.ResetUUID, u.Email).Exec()
|
||||
return err
|
||||
}
|
||||
@ -207,7 +206,7 @@ func CheckUserPassword(query models.User) (*models.User, error) {
|
||||
queryParam = append(queryParam, currentUser.Username)
|
||||
queryParam = append(queryParam, utils.Encrypt(query.Password, currentUser.Salt))
|
||||
}
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
var user []models.User
|
||||
|
||||
n, err := o.Raw(sql, queryParam).QueryRows(&user)
|
||||
@ -226,7 +225,7 @@ func CheckUserPassword(query models.User) (*models.User, error) {
|
||||
|
||||
// DeleteUser ...
|
||||
func DeleteUser(userID int) error {
|
||||
o := orm.NewOrm()
|
||||
o := GetOrmer()
|
||||
_, err := o.Raw(`update user set deleted = 1 where user_id = ?`, userID).Exec()
|
||||
return err
|
||||
}
|
||||
|
@ -6,6 +6,29 @@ body {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.has-logged-in {
|
||||
position: relative;
|
||||
top: 50px;
|
||||
}
|
||||
|
||||
.has-logged-in h4 {
|
||||
float: left;
|
||||
width: 100%;
|
||||
line-height: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.has-logged-in .last-logged-in-time {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.has-logged-in .control-button {
|
||||
height: 2em;
|
||||
width: 100%;
|
||||
padding-right: 10%;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.container-fluid-custom {
|
||||
background-color: #EFEFEF;
|
||||
max-height: 100%;
|
||||
|
@ -56,4 +56,9 @@
|
||||
.well-custom {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.empty-hint {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
@ -108,4 +108,23 @@
|
||||
|
||||
.popover{
|
||||
max-width: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
.popover-header {
|
||||
padding:8px 14px;
|
||||
background-color:#f7f7f7;
|
||||
border-bottom:1px solid #ebebeb;
|
||||
-webkit-border-radius:5px 5px 0 0;
|
||||
-moz-border-radius:5px 5px 0 0;
|
||||
border-radius:5px 5px 0 0;
|
||||
}
|
||||
|
||||
.popover-title {
|
||||
height: 2.5em;
|
||||
padding: 8px 14px;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
border-radius: 5px 5px 0 0;
|
||||
}
|
||||
|
@ -58,7 +58,7 @@
|
||||
|
||||
if($routeParams.project_id){
|
||||
angular.forEach(vm.projects, function(value, index) {
|
||||
if(value['ProjectId'] === $routeParams.project_id) {
|
||||
if(value['ProjectId'] === Number($routeParams.project_id)) {
|
||||
vm.selectedProject = value;
|
||||
}
|
||||
});
|
||||
@ -123,8 +123,15 @@
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
$(document).on('click', clickHandler);
|
||||
|
||||
|
||||
function clickHandler(e) {
|
||||
$('[data-toggle="popover"]').each(function () {
|
||||
//the 'is' for buttons that trigger popups
|
||||
//the 'has' for icons within a button that triggers a popup
|
||||
if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
|
||||
$(this).parent().popover('hide');
|
||||
}
|
||||
});
|
||||
var targetId = $(e.target).attr('id');
|
||||
if(targetId === 'switchPane' ||
|
||||
targetId === 'retrievePane' ||
|
||||
|
@ -31,9 +31,6 @@
|
||||
AddProjectMemberService(vm.projectId, vm.optRole, pm.username)
|
||||
.success(addProjectMemberComplete)
|
||||
.error(addProjectMemberFailed);
|
||||
vm.username = '';
|
||||
vm.optRole = 1;
|
||||
vm.reload();
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,6 +45,7 @@
|
||||
|
||||
function addProjectMemberComplete(data, status, header) {
|
||||
console.log('addProjectMemberComplete: status:' + status + ', data:' + data);
|
||||
vm.reload();
|
||||
}
|
||||
|
||||
function addProjectMemberFailed(data, status, headers) {
|
||||
|
@ -28,7 +28,6 @@
|
||||
|
||||
function updateProjectMember(e) {
|
||||
if(vm.editMode) {
|
||||
vm.editMode = false;
|
||||
console.log('update project member, roleId:' + e.roleId);
|
||||
EditProjectMemberService(e.projectId, e.userId, e.roleId)
|
||||
.success(editProjectMemberComplete)
|
||||
@ -42,12 +41,13 @@
|
||||
DeleteProjectMemberService(e.projectId, e.userId)
|
||||
.success(editProjectMemberComplete)
|
||||
.error(editProjectMemberFailed);
|
||||
vm.reload();
|
||||
}
|
||||
|
||||
function editProjectMemberComplete(data, status, headers) {
|
||||
console.log('edit project member complete: ' + status);
|
||||
vm.lastRoleName = vm.roleName;
|
||||
vm.editMode = false;
|
||||
vm.reload();
|
||||
}
|
||||
|
||||
function editProjectMemberFailed(e) {
|
||||
@ -56,7 +56,6 @@
|
||||
|
||||
function cancelUpdate() {
|
||||
vm.editMode = false;
|
||||
console.log('lastRoleName:' + vm.lastRoleName);
|
||||
vm.roleName = vm.lastRoleName;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
vm.currentRole = getRole({'key': 'roleName', 'value': current});
|
||||
}
|
||||
});
|
||||
|
||||
vm.selectRole = selectRole;
|
||||
|
||||
function selectRole(role) {
|
||||
|
@ -8,7 +8,10 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
|
||||
<div ng-if="vm.repositories.length === 0" class="empty-hint">
|
||||
<h3 style="margin-top: 200px;" class="text-muted">// 'no_repositories' | tr //</h3>
|
||||
</div>
|
||||
<div ng-if="vm.repositories.length > 0" class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
|
||||
<modal-dialog action="vm.deleteImage()" content-type="text/html" title="//vm.modalTitle//" message="//vm.modalMessage//"></modal-dialog>
|
||||
<div class="panel panel-default" ng-repeat="repo in vm.repositories">
|
||||
<div class="panel-heading" role="tab" id="heading//$index + 1//">
|
||||
|
@ -25,9 +25,14 @@
|
||||
vm.retrieve = retrieve;
|
||||
vm.projectId = $routeParams.project_id;
|
||||
vm.tagCount = {};
|
||||
|
||||
vm.retrieve();
|
||||
|
||||
$scope.$watch('vm.repositories', function(current) {
|
||||
if(current) {
|
||||
vm.repositories = current || [];
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on('repoName', function(e, val) {
|
||||
vm.repoName = val;
|
||||
});
|
||||
@ -58,7 +63,7 @@
|
||||
}
|
||||
|
||||
function getRepositoryComplete(data, status) {
|
||||
vm.repositories = data;
|
||||
vm.repositories = data || [];
|
||||
}
|
||||
|
||||
function getRepositoryFailed(response) {
|
||||
|
@ -10,7 +10,7 @@
|
||||
<tbody>
|
||||
<tr ng-repeat="tag in vm.tags">
|
||||
<td>//tag//</td>
|
||||
<td style="text-align: center;"><popup-details repo-name="//vm.repoName//" tag="//tag//"></popup-details></td>
|
||||
<td style="text-align: center;"><popup-details repo-name="//vm.repoName//" tag="//tag//" index="//$index//"></popup-details></td>
|
||||
<td>
|
||||
<pull-command repo-name="//vm.repoName//" tag="//tag//"></pull-command>
|
||||
</td>
|
||||
|
@ -61,11 +61,18 @@
|
||||
'repoName': '='
|
||||
},
|
||||
'replace': true,
|
||||
'link': link,
|
||||
'controller': ListTagController,
|
||||
'controllerAs': 'vm',
|
||||
'bindToController': true
|
||||
};
|
||||
return directive;
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
})();
|
@ -1,4 +1,4 @@
|
||||
<a href="javascript:void(0);">
|
||||
<span tabindex="0" class="glyphicon glyphicon-info-sign" role="button" data-trigger="focus" data-toggle="popover" data-placement="right">
|
||||
<a href="javascript:void(0)" >
|
||||
<span class="glyphicon glyphicon-info-sign" role="button" data-trigger="click" data-toggle="popover" data-placement="right">
|
||||
</span>
|
||||
</a>
|
||||
</a>
|
||||
|
@ -10,8 +10,9 @@
|
||||
|
||||
function PopupDetailsController(ListManifestService, $filter, dateLFilter) {
|
||||
var vm = this;
|
||||
|
||||
|
||||
vm.retrieve = retrieve;
|
||||
|
||||
function retrieve() {
|
||||
ListManifestService(vm.repoName, vm.tag)
|
||||
.success(getManifestSuccess)
|
||||
@ -35,8 +36,10 @@
|
||||
'templateUrl': '/static/ng/resources/js/components/repository/popup-details.directive.html',
|
||||
'scope': {
|
||||
'repoName': '@',
|
||||
'tag': '@'
|
||||
'tag': '@',
|
||||
'index': '@'
|
||||
},
|
||||
'replace': true,
|
||||
'link': link,
|
||||
'controller': PopupDetailsController,
|
||||
'controllerAs': 'vm',
|
||||
@ -46,21 +49,35 @@
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
ctrl.retrieve();
|
||||
scope.$watch('vm.manifest', function(current, origin) {
|
||||
scope.$watch('vm.manifest', function(current) {
|
||||
if(current) {
|
||||
element.find('span').popover({
|
||||
'content': generateContent,
|
||||
'html': true
|
||||
});
|
||||
|
||||
element
|
||||
.popover({
|
||||
'template': '<div class="popover" role="tooltip"><div class="arrow"></div><div class="popover-title"></div><div class="popover-content"></div></div>',
|
||||
'title': '<div class="pull-right clearfix"><a href="javascript:void(0);"><span class="glyphicon glyphicon-remove-circle"></span></a></div>',
|
||||
'content': generateContent,
|
||||
'html': true
|
||||
})
|
||||
.on('shown.bs.popover', function(e){
|
||||
var self = jQuery(this);
|
||||
$('[type="text"]:input', self.parent())
|
||||
.select()
|
||||
.end()
|
||||
.on('click', function() {
|
||||
$(this).select();
|
||||
});
|
||||
self.parent().find('.glyphicon.glyphicon-remove-circle').on('click', function() {
|
||||
element.trigger('click');
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function generateContent() {
|
||||
var content =
|
||||
'<form class="form-horizontal">' +
|
||||
var content = '<form class="form-horizontal">' +
|
||||
'<div class="form-group">' +
|
||||
'<label class="col-sm-3 control-label">Id</label>' +
|
||||
'<div class="col-sm-9"><p class="form-control-static long-line">' + ctrl.manifest['Id'] + '</p></div></div>' +
|
||||
'<div class="col-sm-9"><p class="form-control-static long-line"><input type="text" id="txtImageId" value="' + ctrl.manifest['Id'] + '" readonly size="40"></p></div></div>' +
|
||||
'<div class="form-group"><label class="col-sm-3 control-label">Parent</label>' +
|
||||
'<div class="col-sm-9"><p class="form-control-static long-line">' + ctrl.manifest['Parent'] + '</p></div></div>' +
|
||||
'<div class="form-group"><label class="col-sm-3 control-label">Created</label>' +
|
||||
|
@ -1,9 +1,9 @@
|
||||
<form class="form-inline">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="//vm.repoName//-//vm.tag//" value="docker pull //vm.harborRegUrl////vm.repoName//://vm.tag//" readonly="readonly" size="60">
|
||||
<input type="text" class="form-control" value="docker pull //vm.harborRegUrl////vm.repoName//://vm.tag//" readonly="readonly" size="60">
|
||||
<div class="input-group-addon">
|
||||
<a href="javascript:void(0);" data-clipboard-target="//vm.repoName//-//vm.tag//"><span class="glyphicon glyphicon-duplicate" data-toggle="tooltip" data-placement="right" title="Copied!"></span></a>
|
||||
<a href="javascript:void(0);"><span class="glyphicon glyphicon-duplicate"></span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -29,26 +29,10 @@
|
||||
|
||||
ctrl.harborRegUrl = $('#HarborRegUrl').val() + '/';
|
||||
|
||||
ZeroClipboard.config( { swfPath: "/static/ng/vendors/zc/v2.2.0/ZeroClipboard.swf" } );
|
||||
var clip = new ZeroClipboard(element.find('a'));
|
||||
element.find('span').tooltip({'trigger': 'click'});
|
||||
|
||||
clip.on("ready", function() {
|
||||
console.log("Flash movie loaded and ready.");
|
||||
this.on("aftercopy", function(event) {
|
||||
console.log("Copied text to clipboard: " + event.data["text/plain"]);
|
||||
element.find('span').tooltip('show');
|
||||
setTimeout(function(){
|
||||
element.find('span').tooltip('hide');
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
|
||||
clip.on("error", function(event) {
|
||||
console.log('error[name="' + event.name + '"]: ' + event.message);
|
||||
ZeroClipboard.destroy();
|
||||
element.find('span').tooltip('destroy');
|
||||
});
|
||||
element.find('a').on('click', clickHandler);
|
||||
function clickHandler(e) {
|
||||
element.find('input[type="text"]').select();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,8 @@
|
||||
.module('harbor.sign.in')
|
||||
.directive('signIn', signIn);
|
||||
|
||||
SignInController.$inject = ['SignInService', '$window', '$scope'];
|
||||
function SignInController(SignInService, $window, $scope) {
|
||||
SignInController.$inject = ['SignInService', 'LogOutService', 'currentUser', 'I18nService', '$window', '$scope'];
|
||||
function SignInController(SignInService, LogOutService, currentUser, I18nService, $window, $scope) {
|
||||
var vm = this;
|
||||
|
||||
vm.hasError = false;
|
||||
@ -18,6 +18,9 @@
|
||||
vm.doSignUp = doSignUp;
|
||||
vm.doForgotPassword = doForgotPassword;
|
||||
|
||||
vm.doContinue = doContinue;
|
||||
vm.doLogOut = doLogOut;
|
||||
|
||||
function reset() {
|
||||
vm.hasError = false;
|
||||
vm.errorMessage = '';
|
||||
@ -32,7 +35,7 @@
|
||||
}
|
||||
|
||||
function signedInSuccess(data, status) {
|
||||
$window.location.href = "/ng/project";
|
||||
$window.location.href = "/ng/dashboard";
|
||||
}
|
||||
|
||||
function signedInFailed(data, status) {
|
||||
@ -50,12 +53,32 @@
|
||||
function doForgotPassword() {
|
||||
$window.location.href = '/ng/forgot_password';
|
||||
}
|
||||
|
||||
function doContinue() {
|
||||
$window.location.href = '/ng/dashboard';
|
||||
}
|
||||
|
||||
function doLogOut() {
|
||||
LogOutService()
|
||||
.success(logOutSuccess)
|
||||
.error(logOutFailed);
|
||||
}
|
||||
|
||||
function logOutSuccess(data, status) {
|
||||
currentUser.unset();
|
||||
I18nService().unset();
|
||||
$window.location.href= '/ng';
|
||||
}
|
||||
|
||||
function logOutFailed(data, status) {
|
||||
console.log('Failed to log out:' + data);
|
||||
}
|
||||
}
|
||||
|
||||
function signIn() {
|
||||
var directive = {
|
||||
'restrict': 'E',
|
||||
'templateUrl': '/static/ng/resources/js/components/sign-in/sign-in.directive.html',
|
||||
'templateUrl': '/ng/sign_in',
|
||||
'scope': true,
|
||||
'controller': SignInController,
|
||||
'controllerAs': 'vm',
|
||||
|
@ -38,22 +38,23 @@
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
var visited = ctrl.url.substring(1);
|
||||
|
||||
var visited = ctrl.url.substring(1);
|
||||
if(visited.indexOf('?') >= 0) {
|
||||
visited = ctrl.url.substring(1, ctrl.url.indexOf('?') - 1);
|
||||
visited = ctrl.url.substring(1, ctrl.url.indexOf('?'));
|
||||
}
|
||||
|
||||
scope.$watch('vm.selectedProject', function(current) {
|
||||
if(current) {
|
||||
element.find('a').removeClass('active');
|
||||
element.find('a:first').addClass('active');
|
||||
if(visited) {
|
||||
element.find('a[tag="' + visited + '"]').addClass('active');
|
||||
}else{
|
||||
element.find('a:first').addClass('active');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
element.find('a[tag*="' + visited + '"]').addClass('active');
|
||||
element.find('a').on('click', click);
|
||||
|
||||
element.find('a').on('click', click);
|
||||
|
||||
function click(event) {
|
||||
element.find('a').removeClass('active');
|
||||
$(event.target).addClass('active');
|
||||
|
@ -27,11 +27,7 @@
|
||||
vm.searchProject = searchProject;
|
||||
vm.showAddButton = showAddButton;
|
||||
vm.togglePublicity = togglePublicity;
|
||||
|
||||
$timeout(function() {
|
||||
vm.user = currentUser.get();
|
||||
});
|
||||
|
||||
vm.user = currentUser.get();
|
||||
vm.retrieve();
|
||||
|
||||
function retrieve() {
|
||||
@ -45,7 +41,9 @@
|
||||
data.forEach(function(data){
|
||||
data.role = vm.MAP[data.role_id];
|
||||
});
|
||||
vm.projects = data;
|
||||
|
||||
vm.projects = data || [];
|
||||
|
||||
}
|
||||
|
||||
function listProjectFailed(e) {
|
||||
|
@ -117,5 +117,10 @@ var locale_messages = {
|
||||
'alert_delete_tag_title': 'Delete tag - $0',
|
||||
'alert_delete_tag': 'Delete this "$0" tag now?',
|
||||
'close': 'Close',
|
||||
'ok': 'OK'
|
||||
'ok': 'OK',
|
||||
'welcome': 'Welcome ',
|
||||
'to_harbor': ' to Harbor!',
|
||||
'continue' : 'Continue',
|
||||
'no_projects_add_new_project': 'No projects, add new project now.',
|
||||
'no_repositories': 'No repositories found, please use "docker push" to upload images.'
|
||||
};
|
@ -115,5 +115,10 @@ var locale_messages = {
|
||||
'alert_delete_tag_title': '删除镜像标签 - $0',
|
||||
'alert_delete_tag': '删除镜像标签 "$0" ?',
|
||||
'close': '关闭',
|
||||
'ok': '确认'
|
||||
'ok': '确认',
|
||||
'welcome': '欢迎 ',
|
||||
'to_harbor': ' 使用Harbor!',
|
||||
'continue' : '继续',
|
||||
'no_projects_add_new_project': '当前没有项目,请新增项目。',
|
||||
'no_repositories': '未发现镜像,请用"docker push"命令上传镜像。'
|
||||
};
|
2610
static/ng/vendors/zc/v2.2.0/ZeroClipboard.js
vendored
2610
static/ng/vendors/zc/v2.2.0/ZeroClipboard.js
vendored
File diff suppressed because it is too large
Load Diff
BIN
static/ng/vendors/zc/v2.2.0/ZeroClipboard.swf
vendored
BIN
static/ng/vendors/zc/v2.2.0/ZeroClipboard.swf
vendored
Binary file not shown.
@ -25,4 +25,5 @@ func initNgRouters() {
|
||||
|
||||
beego.Router("/ng/optional_menu", &ng.OptionalMenuController{})
|
||||
beego.Router("/ng/navigation_header", &ng.NavigationHeaderController{})
|
||||
beego.Router("/ng/sign_in", &ng.SignInController{})
|
||||
}
|
||||
|
@ -17,15 +17,15 @@
|
||||
<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">
|
||||
<img src="/static/ng/resources/img/Step1.png" alt="Step 1">
|
||||
<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">
|
||||
<img src="/static/ng/resources/img/Step2.png" alt="Step 2">
|
||||
<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">
|
||||
<img src="/static/ng/resources/img/Step3.png" alt="Step 3">
|
||||
<h5 class="step-content">// 'user_management_and_role_assignment' | tr //</h5>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -30,13 +30,16 @@
|
||||
<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">
|
||||
<tr>
|
||||
<td colspan="5" height="320px" class="empty-hint" ng-if="vm.projects.length === 0"><h3 class="text-muted">// 'no_projects_add_new_project' | tr //</h3></td>
|
||||
</tr>
|
||||
<tr ng-if="vm.projects.length > 0" ng-repeat="p in vm.projects">
|
||||
<td><a href="/ng/repository#/repositories?project_id=//p.ProjectId//&is_public=//p.Public//">//p.Name//</a></td>
|
||||
<td>//p.count//</td>
|
||||
<td>//p.role//</td>
|
||||
<td>//p.CreationTime | dateL : 'YYYY-MM-DD HH:mm:ss'//</td>
|
||||
<td><publicity-button is-public="p.Public" owned="p.OwnerId == vm.user.UserId" project-id="p.ProjectId"></publicity-button></td>
|
||||
</tr>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="#"><img class="img-responsive" src="/static/ng/resources/img/Harbor_Logo_rec.png" alt="Harbor's Logo"/></a>
|
||||
<a class="navbar-brand" href="/ng"><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">
|
||||
|
@ -10,7 +10,6 @@
|
||||
<link rel="stylesheet" href="/static/ng/vendors/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css" />
|
||||
<script src="/static/ng/vendors/spinner/spinner.min.js"></script>
|
||||
|
||||
<script src="/static/ng/vendors/zc/v2.2.0/ZeroClipboard.js"></script>
|
||||
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<!--link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous"-->
|
||||
|
@ -1,3 +1,11 @@
|
||||
{{ if eq .HasLoggedIn true }}
|
||||
<div class="has-logged-in">
|
||||
<h4>// 'welcome' | tr // <strong>{{ .Username }}</strong> // 'to_harbor' | tr //</h4>
|
||||
<!--p class="text-muted last-logged-in-time">Last login time: //vm.lastLoggedInTime//</p-->
|
||||
<p class="control-button"><input type="button" class="btn btn-default pull-right" value="// 'continue' | tr //" ng-click="vm.doContinue()"></p>
|
||||
<p class="control-button"><input type="button" class="btn btn-link pull-right" value="// 'log_out' | tr //" ng-click="vm.doLogOut()"></p>
|
||||
</div>
|
||||
{{ else }}
|
||||
<form name="form" class="form-horizontal css-form" ng-submit="form.$valid" novalidate>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-10">
|
||||
@ -35,4 +43,5 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</form>
|
||||
{{ end }}
|
Loading…
Reference in New Issue
Block a user