From 52fbb9788aa80adb56c96389f73c878cc0fe8b42 Mon Sep 17 00:00:00 2001 From: FuXiaoHei Date: Thu, 1 May 2014 17:44:22 +0800 Subject: [PATCH] add collaboration page ui --- public/css/gogs.css | 63 ++++++++++++- public/js/app.js | 44 ++++++++- routers/repo/repo.go | 113 ----------------------- routers/repo/setting.go | 144 ++++++++++++++++++++++++++++++ templates/repo/collaboration.tmpl | 51 +++++++++++ templates/repo/setting.tmpl | 8 +- web.go | 9 +- 7 files changed, 306 insertions(+), 126 deletions(-) create mode 100644 routers/repo/setting.go create mode 100644 templates/repo/collaboration.tmpl diff --git a/public/css/gogs.css b/public/css/gogs.css index 12b6d8b058..ce9f27e410 100755 --- a/public/css/gogs.css +++ b/public/css/gogs.css @@ -387,6 +387,12 @@ html, body { /* gogits user setting */ +#user-setting-nav { + background-color: #FFF; + border: 1px solid #CCC; + padding: 0; +} + #user-setting-nav > h4, #user-setting-container > h4, #user-setting-container > div > h4, #ssh-keys > h4, #user-delete > h4, #repo-setting-container .tab-pane > h4 { padding-bottom: 18px; @@ -396,13 +402,14 @@ html, body { #user-setting-nav .list-group .list-group-item a { margin-left: 0; - padding: .6em; + padding: .6em 1.2em; font-size: 14px; color: #3B73AF; } #user-setting-nav .list-group .list-group-item { background-color: transparent; + margin-bottom: .6em; } #user-setting-nav .list-group .list-group-item-success a { @@ -431,10 +438,60 @@ html, body { border-left: 4px solid #DD4B39; } +#repo-setting-container{ + padding-right: 0; +} + #repo-setting-container .form-horizontal label { line-height: 30px; } +#repo-collab-list li.collab{ + margin-bottom: .6em; +} + +#repo-collab-list .avatar{ + margin-right: 1em; + width: 40px; +} + +#repo-collab-list a.member{ + color: #444; +} + +#repo-collab-list .remove-collab{ + color: #DD4B39; +} + +#repo-collab-form .dropdown-menu{ + margin-left: 15px; + margin-top: 4px; + padding: 0; +} + +#repo-collab-form .dropdown-menu li{ + padding: 0 1em; + line-height: 36px; + cursor: pointer; + font-weight: bold; +} + +#repo-collab-form .dropdown-menu li:hover{ + background-color: #e8f0ff; +} + +#repo-collab-form .dropdown-menu img{ + width: 28px; + height: 28px; + margin-right: 1em; + vertical-align: middle; + margin-top: -3px; +} + +#repo-collab-form .dropdown-menu ul{ + margin-bottom: 0; +} + /* gogits user ssh keys */ #ssh-keys .list-group-item { @@ -649,6 +706,10 @@ html, body { padding: 0; } +#repo-toolbar ul.navbar-right { + margin-right: 0; +} + .activity-list { font-size: 14px; } diff --git a/public/js/app.js b/public/js/app.js index 30e9d5d0bb..7d70b7fece 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -240,7 +240,7 @@ var Gogits = { } }); - $(window).on('hashchange',function (e) { + $(window).on('hashchange', function (e) { var m = window.location.hash.match(/^#(L\d+)\-(L\d+)$/); var $list = $('.code-view ol.linenums > li'); if (m) { @@ -387,7 +387,7 @@ function initRepository() { var $clone = $('.clone-group-btn'); if ($clone.length) { var $url = $('.clone-group-url'); - $clone.find('button[data-link]').on("click",function (e) { + $clone.find('button[data-link]').on("click", function (e) { var $this = $(this); if (!$this.hasClass('btn-primary')) { $clone.find('.input-group-btn .btn-primary').removeClass('btn-primary').addClass("btn-default"); @@ -408,7 +408,7 @@ function initRepository() { var $watch = $('#repo-watching'), watchLink = $watch.data("watch"), unwatchLink = $watch.data("unwatch"); - $watch.on('click', '.to-watch',function () { + $watch.on('click', '.to-watch', function () { if ($watch.hasClass("watching")) { return false; } @@ -468,7 +468,7 @@ function initRepository() { function initInstall() { // database type change (function () { - var mysql_default = '127.0.0.1:3306' + var mysql_default = '127.0.0.1:3306' var postgres_default = '127.0.0.1:5432' $('#install-database').on("change", function () { @@ -585,6 +585,39 @@ function initRelease() { }()); } +function initRepoSetting() { + // repo member add + $('#repo-collaborator').on('keyup', function () { + var $this = $(this); + if (!$this.val()) { + $this.next().toggleHide(); + return; + } + $.ajax({ + url: '/api/v1/users/search?q=' + $this.val(), + dataType: "json", + success: function (json) { + if (json.ok && json.data) { + var html = ''; + $.each(json.data, function (i, item) { + html += '
  • ' + item.username + '
  • '; + }); + $this.next().toggleShow(); + $this.next().find('ul').html(html); + }else{ + $this.next().toggleHide(); + } + } + }); + }).on('focus', function () { + if (!$(this).val()) { + $(this).next().toggleHide(); + } + }).next().on("click",'li',function(){ + $('#repo-collaborator').val($(this).text()); + }); +} + (function ($) { $(function () { initCore(); @@ -607,5 +640,8 @@ function initRelease() { if ($('#release').length) { initRelease(); } + if ($('#repo-setting-container').length) { + initRepoSetting(); + } }); })(jQuery); diff --git a/routers/repo/repo.go b/routers/repo/repo.go index 76964dff13..e82c6ae988 100644 --- a/routers/repo/repo.go +++ b/routers/repo/repo.go @@ -286,119 +286,6 @@ func authRequired(ctx *middleware.Context) { ctx.HTML(401, fmt.Sprintf("status/401")) } -func Setting(ctx *middleware.Context, params martini.Params) { - if !ctx.Repo.IsOwner { - ctx.Handle(404, "repo.Setting", nil) - return - } - - ctx.Data["IsRepoToolbarSetting"] = true - - var title string - if t, ok := ctx.Data["Title"].(string); ok { - title = t - } - - ctx.Data["Title"] = title + " - settings" - ctx.HTML(200, "repo/setting") -} - -func SettingPost(ctx *middleware.Context) { - if !ctx.Repo.IsOwner { - ctx.Error(404) - return - } - - ctx.Data["IsRepoToolbarSetting"] = true - - switch ctx.Query("action") { - case "update": - newRepoName := ctx.Query("name") - // Check if repository name has been changed. - if ctx.Repo.Repository.Name != newRepoName { - isExist, err := models.IsRepositoryExist(ctx.Repo.Owner, newRepoName) - if err != nil { - ctx.Handle(500, "repo.SettingPost(update: check existence)", err) - return - } else if isExist { - ctx.RenderWithErr("Repository name has been taken in your repositories.", "repo/setting", nil) - return - } else if err = models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil { - ctx.Handle(500, "repo.SettingPost(change repository name)", err) - return - } - log.Trace("%s Repository name changed: %s/%s -> %s", ctx.Req.RequestURI, ctx.User.Name, ctx.Repo.Repository.Name, newRepoName) - - ctx.Repo.Repository.Name = newRepoName - } - - br := ctx.Query("branch") - - if git.IsBranchExist(models.RepoPath(ctx.User.Name, ctx.Repo.Repository.Name), br) { - ctx.Repo.Repository.DefaultBranch = br - } - ctx.Repo.Repository.Description = ctx.Query("desc") - ctx.Repo.Repository.Website = ctx.Query("site") - ctx.Repo.Repository.IsPrivate = ctx.Query("private") == "on" - ctx.Repo.Repository.IsGoget = ctx.Query("goget") == "on" - if err := models.UpdateRepository(ctx.Repo.Repository); err != nil { - ctx.Handle(404, "repo.SettingPost(update)", err) - return - } - log.Trace("%s Repository updated: %s/%s", ctx.Req.RequestURI, ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) - - if ctx.Repo.Repository.IsMirror { - if len(ctx.Query("interval")) > 0 { - var err error - ctx.Repo.Mirror.Interval, err = base.StrTo(ctx.Query("interval")).Int() - if err != nil { - log.Error("repo.SettingPost(get mirror interval): %v", err) - } else if err = models.UpdateMirror(ctx.Repo.Mirror); err != nil { - log.Error("repo.SettingPost(UpdateMirror): %v", err) - } - } - } - - ctx.Flash.Success("Repository options has been successfully updated.") - ctx.Redirect(fmt.Sprintf("/%s/%s/settings", ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)) - case "transfer": - if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") { - ctx.RenderWithErr("Please make sure you entered repository name is correct.", "repo/setting", nil) - return - } - - newOwner := ctx.Query("owner") - // Check if new owner exists. - isExist, err := models.IsUserExist(newOwner) - if err != nil { - ctx.Handle(500, "repo.SettingPost(transfer: check existence)", err) - return - } else if !isExist { - ctx.RenderWithErr("Please make sure you entered owner name is correct.", "repo/setting", nil) - return - } else if err = models.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository); err != nil { - ctx.Handle(500, "repo.SettingPost(transfer repository)", err) - return - } - log.Trace("%s Repository transfered: %s/%s -> %s", ctx.Req.RequestURI, ctx.User.Name, ctx.Repo.Repository.Name, newOwner) - - ctx.Redirect("/") - case "delete": - if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") { - ctx.RenderWithErr("Please make sure you entered repository name is correct.", "repo/setting", nil) - return - } - - if err := models.DeleteRepository(ctx.User.Id, ctx.Repo.Repository.Id, ctx.User.LowerName); err != nil { - ctx.Handle(500, "repo.Delete", err) - return - } - log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.LowerName) - - ctx.Redirect("/") - } -} - func Action(ctx *middleware.Context, params martini.Params) { var err error switch params["action"] { diff --git a/routers/repo/setting.go b/routers/repo/setting.go new file mode 100644 index 0000000000..bb36260912 --- /dev/null +++ b/routers/repo/setting.go @@ -0,0 +1,144 @@ +// Copyright 2014 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repo + +import ( + "fmt" + "github.com/gogits/git" + "github.com/gogits/gogs/models" + "github.com/gogits/gogs/modules/base" + "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/middleware" +) + +func Setting(ctx *middleware.Context) { + if !ctx.Repo.IsOwner { + ctx.Handle(404, "repo.Setting", nil) + return + } + + ctx.Data["IsRepoToolbarSetting"] = true + + var title string + if t, ok := ctx.Data["Title"].(string); ok { + title = t + } + + ctx.Data["Title"] = title + " - settings" + ctx.HTML(200, "repo/setting") +} + +func SettingPost(ctx *middleware.Context) { + if !ctx.Repo.IsOwner { + ctx.Error(404) + return + } + + ctx.Data["IsRepoToolbarSetting"] = true + + switch ctx.Query("action") { + case "update": + newRepoName := ctx.Query("name") + // Check if repository name has been changed. + if ctx.Repo.Repository.Name != newRepoName { + isExist, err := models.IsRepositoryExist(ctx.Repo.Owner, newRepoName) + if err != nil { + ctx.Handle(500, "repo.SettingPost(update: check existence)", err) + return + } else if isExist { + ctx.RenderWithErr("Repository name has been taken in your repositories.", "repo/setting", nil) + return + } else if err = models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil { + ctx.Handle(500, "repo.SettingPost(change repository name)", err) + return + } + log.Trace("%s Repository name changed: %s/%s -> %s", ctx.Req.RequestURI, ctx.User.Name, ctx.Repo.Repository.Name, newRepoName) + + ctx.Repo.Repository.Name = newRepoName + } + + br := ctx.Query("branch") + + if git.IsBranchExist(models.RepoPath(ctx.User.Name, ctx.Repo.Repository.Name), br) { + ctx.Repo.Repository.DefaultBranch = br + } + ctx.Repo.Repository.Description = ctx.Query("desc") + ctx.Repo.Repository.Website = ctx.Query("site") + ctx.Repo.Repository.IsPrivate = ctx.Query("private") == "on" + ctx.Repo.Repository.IsGoget = ctx.Query("goget") == "on" + if err := models.UpdateRepository(ctx.Repo.Repository); err != nil { + ctx.Handle(404, "repo.SettingPost(update)", err) + return + } + log.Trace("%s Repository updated: %s/%s", ctx.Req.RequestURI, ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) + + if ctx.Repo.Repository.IsMirror { + if len(ctx.Query("interval")) > 0 { + var err error + ctx.Repo.Mirror.Interval, err = base.StrTo(ctx.Query("interval")).Int() + if err != nil { + log.Error("repo.SettingPost(get mirror interval): %v", err) + } else if err = models.UpdateMirror(ctx.Repo.Mirror); err != nil { + log.Error("repo.SettingPost(UpdateMirror): %v", err) + } + } + } + + ctx.Flash.Success("Repository options has been successfully updated.") + ctx.Redirect(fmt.Sprintf("/%s/%s/settings", ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)) + case "transfer": + if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") { + ctx.RenderWithErr("Please make sure you entered repository name is correct.", "repo/setting", nil) + return + } + + newOwner := ctx.Query("owner") + // Check if new owner exists. + isExist, err := models.IsUserExist(newOwner) + if err != nil { + ctx.Handle(500, "repo.SettingPost(transfer: check existence)", err) + return + } else if !isExist { + ctx.RenderWithErr("Please make sure you entered owner name is correct.", "repo/setting", nil) + return + } else if err = models.TransferOwnership(ctx.User, newOwner, ctx.Repo.Repository); err != nil { + ctx.Handle(500, "repo.SettingPost(transfer repository)", err) + return + } + log.Trace("%s Repository transfered: %s/%s -> %s", ctx.Req.RequestURI, ctx.User.Name, ctx.Repo.Repository.Name, newOwner) + + ctx.Redirect("/") + case "delete": + if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") { + ctx.RenderWithErr("Please make sure you entered repository name is correct.", "repo/setting", nil) + return + } + + if err := models.DeleteRepository(ctx.User.Id, ctx.Repo.Repository.Id, ctx.User.LowerName); err != nil { + ctx.Handle(500, "repo.Delete", err) + return + } + log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.LowerName) + + ctx.Redirect("/") + } +} + +func Collaboration(ctx *middleware.Context) { + if !ctx.Repo.IsOwner { + ctx.Handle(404, "repo.Setting", nil) + return + } + + ctx.Data["IsRepoToolbarSetting"] = true + + var title string + if t, ok := ctx.Data["Title"].(string); ok { + title = t + } + + ctx.Data["Title"] = title + " - collaboration" + ctx.HTML(200, "repo/collaboration") +} diff --git a/templates/repo/collaboration.tmpl b/templates/repo/collaboration.tmpl new file mode 100644 index 0000000000..aea0aa4147 --- /dev/null +++ b/templates/repo/collaboration.tmpl @@ -0,0 +1,51 @@ +{{template "base/head" .}} +{{template "base/navbar" .}} +{{template "repo/nav" .}} +{{template "repo/toolbar" .}} +
    +
    + +
    + +
    + {{template "base/alert" .}} +
    +
    + Collaborators +
    +
    + +
    + +
    + +
    +
    +{{template "base/footer" .}} \ No newline at end of file diff --git a/templates/repo/setting.tmpl b/templates/repo/setting.tmpl index 61621fe0e4..9066b587d8 100644 --- a/templates/repo/setting.tmpl +++ b/templates/repo/setting.tmpl @@ -3,15 +3,15 @@ {{template "repo/nav" .}} {{template "repo/toolbar" .}}
    -
    + -
    +
    {{template "base/alert" .}}
    diff --git a/web.go b/web.go index 962764af5d..49ad004008 100644 --- a/web.go +++ b/web.go @@ -121,10 +121,10 @@ func runWeb(*cli.Context) { m.Get("/user/:username", ignSignIn, user.Profile) m.Group("/repo", func(r martini.Router) { - m.Get("/create", repo.Create) - m.Post("/create", bindIgnErr(auth.CreateRepoForm{}), repo.CreatePost) - m.Get("/migrate", repo.Migrate) - m.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost) + r.Get("/create", repo.Create) + r.Post("/create", bindIgnErr(auth.CreateRepoForm{}), repo.CreatePost) + r.Get("/migrate", repo.Migrate) + r.Post("/migrate", bindIgnErr(auth.MigrateRepoForm{}), repo.MigratePost) }, reqSignIn) adminReq := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true, AdminRequire: true}) @@ -150,6 +150,7 @@ func runWeb(*cli.Context) { m.Group("/:username/:reponame", func(r martini.Router) { r.Get("/settings", repo.Setting) r.Post("/settings", repo.SettingPost) + r.Get("/collaboration", repo.Collaboration) r.Get("/action/:action", repo.Action) r.Get("/issues/new", repo.CreateIssue) r.Post("/issues/new", bindIgnErr(auth.CreateIssueForm{}), repo.CreateIssuePost)