Browse Source

Page: Compare 2 commits

Unknwon 10 years ago
parent
commit
b2632dec09

+ 1 - 0
README.md

@@ -32,6 +32,7 @@ The goal of this project is to make the easiest, fastest and most painless way t
 - Activity timeline
 - SSH/HTTP(S) protocol support
 - SMTP/LDAP/reverse proxy authentication support
+- Reverse proxy suburl support
 - Register/delete/rename account
 - Create/manage/delete organization with team management
 - Create/migrate/mirror/delete/watch/rename/transfer public/private repository

+ 1 - 0
README_ZH.md

@@ -23,6 +23,7 @@ Gogs 的目标是打造一个最简单、最快速和最轻松的方式搭建自
 - 活动时间线
 - 支持 SSH/HTTP(S) 协议
 - 支持 SMTP/LDAP/反向代理 用户认证
+- 支持反向代理子路径
 - 注册/删除/重命名 用户
 - 创建/管理/删除 组织以及团队管理功能
 - 创建/迁移/镜像/删除/关注/重命名/转移 公开/私有 仓库

+ 1 - 0
cmd/dump.go

@@ -60,6 +60,7 @@ func runDump(ctx *cli.Context) {
 	z.AddFile("gogs-db.sql", path.Join(workDir, "gogs-db.sql"))
 	z.AddFile("custom/conf/app.ini", path.Join(workDir, "custom/conf/app.ini"))
 	z.AddDir("log", path.Join(workDir, "log"))
+	// FIXME: SSH key file.
 	if err = z.Close(); err != nil {
 		os.Remove(fileName)
 		log.Fatalf("Fail to save %s: %v", fileName, err)

+ 10 - 0
conf/locale/locale_en-US.ini

@@ -337,6 +337,15 @@ settings.slack_token = Token
 settings.slack_domain = Domain
 settings.slack_channel = Channel
 
+diff.browse_source = Browse Source
+diff.parent = parent
+diff.commit = commit
+diff.data_not_available = Diff Data Not Available.
+diff.show_diff_stats = Show Diff Stats
+diff.stats_desc = <strong> %d changed files</strong> with <strong>%d additions</strong> and <strong>%d deletions</strong>
+diff.bin = BIN
+diff.view_file = View File
+
 [org]
 org_name_holder = Organization Name
 org_name_helper = Great organization names are short and memorable.
@@ -609,6 +618,7 @@ commit_repo = pushed to <a href="%s/%s/src/%s">%s</a> at <a href="%s/%s">%s</a>
 create_issue = opened issue <a href="%s/%s/issues/%s">%s#%s</a>
 comment_issue = commented on issue <a href="%s/%s/issues/%s">%s#%s</a>
 transfer_repo = transfered repository <code>%s</code> to <a href="/%s%s">%s</a>
+compare_2_commits = View comparison for these 2 commits
 
 [tool]
 ago = ago

+ 10 - 0
conf/locale/locale_zh-CN.ini

@@ -337,6 +337,15 @@ settings.slack_token = 令牌
 settings.slack_domain = 域名
 settings.slack_channel = 频道
 
+diff.browse_source = 浏览代码
+diff.parent = 父节点
+diff.commit = 当前提交
+diff.data_not_available = 暂无可用数据
+diff.show_diff_stats = 显示文件统计
+diff.stats_desc = 共有 <strong> %d 个文件被更改</strong>,包括 <strong>%d 次插入</strong> 和 <strong>%d 次删除</strong>
+diff.bin = 二进制
+diff.view_file = 查看文件
+
 [org]
 org_name_holder = 组织名称
 org_name_helper = 伟大的组织都有一个简短而寓意深刻的名字。
@@ -609,6 +618,7 @@ commit_repo = 推送了 <a href="%s/%s/src/%s">%s</a> 分支的代码到 <a href
 create_issue = 创建了工单 <a href="%s/%s/issues/%s">%s#%s</a>
 comment_issue = 评论了工单 <a href="%s/%s/issues/%s">%s#%s</a>
 transfer_repo = 将仓库 <code>%s</code> 转移至 <a href="/%s%s">%s</a>
+compare_2_commits = 查看 2 次提交的内容对比
 
 [tool]
 ago = 之前

+ 8 - 10
models/action.go

@@ -181,13 +181,19 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
 		commit = &base.PushCommits{}
 	}
 
-	refName := git.RefEndName(refFullName)
+	repoLink := fmt.Sprintf("%s%s/%s", setting.AppUrl, repoUserName, repoName)
+	// if not the first commit, set the compareUrl
+	if !strings.HasPrefix(oldCommitId, "0000000") {
+		commit.CompareUrl = fmt.Sprintf("%s/compare/%s...%s", repoLink, oldCommitId, newCommitId)
+	}
 
 	bs, err := json.Marshal(commit)
 	if err != nil {
 		return errors.New("action.CommitRepoAction(json): " + err.Error())
 	}
 
+	refName := git.RefEndName(refFullName)
+
 	// Change repository bare status and update last updated time.
 	repo, err := GetRepositoryByName(repoUserId, repoName)
 	if err != nil {
@@ -211,7 +217,6 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
 		return errors.New("action.CommitRepoAction(NotifyWatchers): " + err.Error())
 
 	}
-	//qlog.Info("action.CommitRepoAction(end): %d/%s", repoUserId, repoName)
 
 	// New push event hook.
 	if err := repo.GetOwner(); err != nil {
@@ -237,13 +242,6 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
 		return nil
 	}
 
-	repoLink := fmt.Sprintf("%s%s/%s", setting.AppUrl, repoUserName, repoName)
-	compareUrl := ""
-	// if not the first commit, set the compareUrl
-	if !strings.HasPrefix(oldCommitId, "0000000") {
-		compareUrl = fmt.Sprintf("%s/compare/%s...%s", repoLink, oldCommitId, newCommitId)
-	}
-
 	pusher_email, pusher_name := "", ""
 	pusher, err := GetUserByName(userName)
 	if err == nil {
@@ -293,7 +291,7 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
 		},
 		Before:     oldCommitId,
 		After:      newCommitId,
-		CompareUrl: compareUrl,
+		CompareUrl: commit.CompareUrl,
 	}
 
 	for _, w := range ws {

+ 4 - 5
models/update.go

@@ -106,7 +106,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 
 		if err = CommitRepoAction(userId, ru.Id, userName, actEmail,
 			repos.Id, repoUserName, repoName, refName, commit, oldCommitId, newCommitId); err != nil {
-			log.GitLogger.Fatal(4, "runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
+			log.GitLogger.Fatal(4, "CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
 		}
 		return err
 	}
@@ -116,8 +116,8 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 		return fmt.Errorf("runUpdate GetCommit of newCommitId: %v", err)
 	}
 
+	// Push new branch.
 	var l *list.List
-	// if a new branch
 	if isNew {
 		l, err = newCommit.CommitsBefore()
 		if err != nil {
@@ -134,7 +134,7 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 		return fmt.Errorf("runUpdate.Commit repoId: %v", err)
 	}
 
-	// if commits push
+	// Push commits.
 	commits := make([]*base.PushCommit, 0)
 	var actEmail string
 	for e := l.Front(); e != nil; e = e.Next() {
@@ -153,9 +153,8 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName
 		}
 	}
 
-	//commits = append(commits, []string{lastCommit.Id().String(), lastCommit.Message()})
 	if err = CommitRepoAction(userId, ru.Id, userName, actEmail,
-		repos.Id, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits}, oldCommitId, newCommitId); err != nil {
+		repos.Id, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits, ""}, oldCommitId, newCommitId); err != nil {
 		return fmt.Errorf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err)
 	}
 	return nil

+ 3 - 63
modules/base/template.go

@@ -5,7 +5,6 @@
 package base
 
 import (
-	"bytes"
 	"container/list"
 	"encoding/json"
 	"errors"
@@ -107,7 +106,6 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
 		return a + b
 	},
 	"ActionIcon": ActionIcon,
-	"ActionDesc": ActionDesc,
 	"DateFormat": DateFormat,
 	"List":       List,
 	"Mail2Domain": func(mail string) string {
@@ -162,19 +160,6 @@ func ActionIcon(opType int) string {
 	}
 }
 
-// FIXME: Legacy
-const (
-	TPL_CREATE_REPO    = `<a href="%s/user/%s">%s</a> created repository <a href="%s">%s</a>`
-	TPL_COMMIT_REPO    = `<a href="%s/user/%s">%s</a> pushed to <a href="%s/src/%s">%s</a> at <a href="%s">%s</a>%s`
-	TPL_COMMIT_REPO_LI = `<div><img src="%s?s=16" alt="user-avatar"/> <a href="%s/commit/%s" rel="nofollow">%s</a> %s</div>`
-	TPL_CREATE_ISSUE   = `<a href="%s/user/%s">%s</a> opened issue <a href="%s/issues/%s">%s#%s</a>
-<div><img src="%s?s=16" alt="user-avatar"/> %s</div>`
-	TPL_TRANSFER_REPO = `<a href="%s/user/%s">%s</a> transfered repository <code>%s</code> to <a href="%s">%s</a>`
-	TPL_PUSH_TAG      = `<a href="%s/user/%s">%s</a> pushed tag <a href="%s/src/%s" rel="nofollow">%s</a> at <a href="%s">%s</a>`
-	TPL_COMMENT_ISSUE = `<a href="%s/user/%s">%s</a> commented on issue <a href="%s/issues/%s">%s#%s</a>
-<div><img src="%s?s=16" alt="user-avatar"/> %s</div>`
-)
-
 type PushCommit struct {
 	Sha1        string
 	Message     string
@@ -183,8 +168,9 @@ type PushCommit struct {
 }
 
 type PushCommits struct {
-	Len     int
-	Commits []*PushCommit
+	Len        int
+	Commits    []*PushCommit
+	CompareUrl string
 }
 
 func ActionContent2Commits(act Actioner) *PushCommits {
@@ -195,52 +181,6 @@ func ActionContent2Commits(act Actioner) *PushCommits {
 	return push
 }
 
-// FIXME: Legacy
-// ActionDesc accepts int that represents action operation type
-// and returns the description.
-func ActionDesc(act Actioner) string {
-	actUserName := act.GetActUserName()
-	email := act.GetActEmail()
-	repoUserName := act.GetRepoUserName()
-	repoName := act.GetRepoName()
-	repoLink := repoUserName + "/" + repoName
-	branch := act.GetBranch()
-	content := act.GetContent()
-	switch act.GetOpType() {
-	case 1: // Create repository.
-		return fmt.Sprintf(TPL_CREATE_REPO, setting.AppSubUrl, actUserName, actUserName, repoLink, repoName)
-	case 5: // Commit repository.
-		var push *PushCommits
-		if err := json.Unmarshal([]byte(content), &push); err != nil {
-			return err.Error()
-		}
-		buf := bytes.NewBuffer([]byte("\n"))
-		for _, commit := range push.Commits {
-			buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, AvatarLink(commit.AuthorEmail), repoLink, commit.Sha1, commit.Sha1[:7], commit.Message) + "\n")
-		}
-		if push.Len > 3 {
-			buf.WriteString(fmt.Sprintf(`<div><a href="{{AppRootSubUrl}}/%s/%s/commits/%s" rel="nofollow">%d other commits >></a></div>`, actUserName, repoName, branch, push.Len))
-		}
-		return fmt.Sprintf(TPL_COMMIT_REPO, setting.AppSubUrl, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink,
-			buf.String())
-	case 6: // Create issue.
-		infos := strings.SplitN(content, "|", 2)
-		return fmt.Sprintf(TPL_CREATE_ISSUE, setting.AppSubUrl, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0],
-			AvatarLink(email), infos[1])
-	case 8: // Transfer repository.
-		newRepoLink := content + "/" + repoName
-		return fmt.Sprintf(TPL_TRANSFER_REPO, setting.AppSubUrl, actUserName, actUserName, repoLink, newRepoLink, newRepoLink)
-	case 9: // Push tag.
-		return fmt.Sprintf(TPL_PUSH_TAG, setting.AppSubUrl, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink)
-	case 10: // Comment issue.
-		infos := strings.SplitN(content, "|", 2)
-		return fmt.Sprintf(TPL_COMMENT_ISSUE, setting.AppSubUrl, actUserName, actUserName, repoLink, infos[0], repoLink, infos[0],
-			AvatarLink(email), infos[1])
-	default:
-		return "invalid type"
-	}
-}
-
 func DiffTypeToStr(diffType int) string {
 	diffTypes := map[int]string{
 		1: "add", 2: "modify", 3: "del",

+ 104 - 0
public/ng/css/gogs.css

@@ -271,6 +271,10 @@ img.avatar-100 {
 .pagination li {
   display: inline;
 }
+.list-unstyled {
+  padding-left: 0;
+  list-style: none;
+}
 .markdown {
   background-color: white;
   font-size: 16px;
@@ -1487,6 +1491,106 @@ The register and sign-in page style
   font-family: Consolas, Menlo, Monaco, "Lucida Console", monospace;
   font-size: 14px;
 }
+.diff-head-box {
+  margin-top: 10px;
+}
+.diff-head-box .panel-body {
+  padding: 10px 15px 5px 10px;
+}
+.diff-head-box .author img {
+  margin-top: -7px;
+}
+.diff-detail-box {
+  margin: 15px 0;
+  line-height: 30px;
+}
+.diff-detail-box ol {
+  clear: both;
+  padding-left: 0;
+  margin-bottom: 28px;
+}
+.diff-detail-box ol li {
+  list-style: none;
+  padding-bottom: 4px;
+  margin-bottom: 4px;
+  border-bottom: 1px dashed #DDD;
+  padding-left: 6px;
+}
+.diff-detail-box span.status {
+  display: inline-block;
+  width: 12px;
+  height: 12px;
+  margin-right: 8px;
+  vertical-align: middle;
+}
+.diff-detail-box span.status.modify {
+  background-color: #f0db88;
+}
+.diff-detail-box span.status.add {
+  background-color: #b4e2b4;
+}
+.diff-detail-box span.status.del {
+  background-color: #e9aeae;
+}
+.diff-detail-box span.status.rename {
+  background-color: #dad8ff;
+}
+.diff-box .count {
+  margin-right: 12px;
+}
+.diff-box .count .bar {
+  background-color: #e75316;
+  height: 12px;
+  width: 40px;
+  display: inline-block;
+  margin: 2px 4px 0 4px;
+  vertical-align: text-top;
+}
+.diff-box .count .bar .add {
+  background-color: #77c64a;
+  height: 12px;
+}
+.diff-box .file {
+  color: #888;
+}
+.diff-box .panel-header {
+  font-size: 14px;
+}
+.diff-file-box .code-diff tbody tr:hover td,
+.diff-file-box .code-diff tbody tr:hover pre {
+  background-color: #FFF8D2 !important;
+  border-color: #F0DB88 !important;
+}
+.diff-file-box .file-body.file-code .lines-num-old {
+  border-right: 1px solid #DDD;
+}
+.file-content .file-body.file-code .lines-num {
+  text-align: right;
+  color: #999;
+  background: #fafafa;
+  width: 1%;
+}
+.diff-file-box .code-diff tbody tr.tag-code td,
+.diff-file-box .code-diff tbody tr.tag-code pre {
+  background-color: #E0E0E0 !important;
+  border-color: #ADADAD !important;
+}
+.diff-file-box .code-diff tbody tr.del-code td,
+.diff-file-box .code-diff tbody tr.del-code pre {
+  background-color: #ffe2dd !important;
+  border-color: #e9aeae !important;
+}
+.diff-file-box .code-diff tbody tr.add-code td,
+.diff-file-box .code-diff tbody tr.add-code pre {
+  background-color: #d1ffd6 !important;
+  border-color: #b4e2b4 !important;
+}
+.compare-head-box {
+  margin-top: 10px;
+}
+.compare-head-box .compare {
+  padding: 0 15px 15px 15px;
+}
 #admin-wrapper,
 #setting-wrapper {
   padding-bottom: 100px;

+ 8 - 0
public/ng/css/ui.css

@@ -713,6 +713,14 @@ ul.menu-radius > li:last-child > a {
   border-bottom-left-radius: .3em;
   border-bottom-right-radius: .3em;
 }
+.panel.panel-info {
+  border-color: #85c5e5;
+}
+.panel.panel-info > .panel-header {
+  color: #31708f;
+  background-color: #d9edf7;
+  border-color: #85c5e5;
+}
 .panel.panel-warning {
   border-color: #F0C36D;
 }

+ 38 - 0
public/ng/js/gogs.js

@@ -299,6 +299,9 @@ function initCore() {
         e.preventDefault();
         $.magnificPopup.close();
     });
+
+    // Collapse.
+    $('.collapse').hide();
 }
 
 function initUserSetting() {
@@ -698,6 +701,37 @@ function initProfile() {
     });
 }
 
+function initTimeSwitch() {
+    // Time switch.
+    $(".time-since[title]").on("click", function () {
+        var $this = $(this);
+
+        var title = $this.attr("title");
+        var text = $this.text();
+
+        $this.text(title);
+        $this.attr("title", text);
+    });
+}
+
+function initDiff() {
+    $('.diff-detail-box>a').click(function () {
+        $($(this).data('target')).slideToggle(100);
+    })
+    
+    var $counter = $('.diff-counter');
+    if ($counter.length < 1) {
+        return;
+    }
+    $counter.each(function (i, item) {
+        var $item = $(item);
+        var addLine = $item.find('span[data-line].add').data("line");
+        var delLine = $item.find('span[data-line].del').data("line");
+        var addPercent = parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine)) * 100;
+        $item.find(".bar .add").css("width", addPercent + "%");
+    });
+}
+
 $(document).ready(function () {
     Gogs.AppSubUrl = $('head').data('suburl') || '';
     initCore();
@@ -737,6 +771,10 @@ $(document).ready(function () {
     if ($('#user-profile-page').length) {
         initProfile();
     }
+    if ($('#diff-page').length) {
+        initTimeSwitch();
+        initDiff();
+    }
 
     $('#dashboard-sidebar-menu').tabs();
     $('#pull-issue-preview').markdown_preview(".issue-add-comment");

File diff suppressed because it is too large
+ 0 - 0
public/ng/js/min/gogs-min.js


+ 4 - 0
public/ng/less/gogs/base.less

@@ -291,4 +291,8 @@ clear: both;
     li {
         display: inline;
     }
+}
+.list-unstyled {
+    padding-left: 0;
+    list-style: none;
 }

+ 127 - 26
public/ng/less/gogs/repository.less

@@ -494,37 +494,138 @@
   }
 }
 .repo-user-list-block {
-  position: relative;
-  top: 5px;
+    position: relative;
+    top: 5px;
 }
 .setting-list {
-  width: 100%;
-  list-style: none;
+    width: 100%;
+    list-style: none;
 }
 #commits-list {
-  padding-top: 20px;
-  h4{
-    line-height: 30px;
-    margin-bottom: 0;
-  }
+    padding-top: 20px;
+    h4{
+        line-height: 30px;
+        margin-bottom: 0;
+    }
 }
 .commit-list {
-  th {
-    background-color: #FFF;
-    line-height: 28px !important;
-  }
-  .date {
-    width: 120px;
-  }
-  .author {
-    padding-left: 20px;
-    min-width: 180px;
-    img {
-      margin-top: -4px;
+    th {
+        background-color: #FFF;
+        line-height: 28px !important;
+    }
+    .date {
+        width: 120px;
+    }
+    .author {
+        padding-left: 20px;
+        min-width: 180px;
+        img {
+            margin-top: -4px;
+        }
+    }
+    .sha a {
+        font-family: Consolas, Menlo, Monaco, "Lucida Console", monospace;
+        font-size: 14px;
+    }
+}
+.diff-head-box {
+    margin-top: 10px;
+    .panel-body {
+        padding: 10px 15px 5px 10px;
+    }
+    .author {
+        img {
+            margin-top: -7px;
+        }
+    }
+}
+.diff-detail-box {
+    margin: 15px 0;
+    line-height: 30px;
+    ol {
+        clear: both;
+        padding-left: 0;
+        margin-bottom: 28px;
+        li {
+            list-style: none;
+            padding-bottom: 4px;
+            margin-bottom: 4px;
+            border-bottom: 1px dashed #DDD;
+            padding-left: 6px;
+        }
+    }
+    span.status{
+        display: inline-block;
+        width: 12px;
+        height: 12px;
+        margin-right: 8px;
+        vertical-align: middle;
+        &.modify {
+            background-color: #f0db88;
+        }
+        &.add {
+            background-color: #b4e2b4;
+        }
+        &.del {
+            background-color: #e9aeae;
+        }
+        &.rename {
+            background-color: #dad8ff;
+        }
+    }
+}
+.diff-box {
+    .count {
+        margin-right: 12px;
+        .bar {
+            background-color: #e75316;
+            height: 12px;
+            width: 40px;
+            display: inline-block;
+            margin: 2px 4px 0 4px;
+            vertical-align: text-top;
+            .add {
+                background-color: #77c64a;
+                height: 12px;
+            }
+        }
+    }
+    .file {
+        color: #888;
+    }
+    .panel-header {
+        font-size: 14px;
+    }
+}
+.diff-file-box .code-diff tbody tr:hover td, .diff-file-box .code-diff tbody tr:hover pre {
+    background-color: #FFF8D2 !important;
+    border-color: #F0DB88 !important;
+}
+.diff-file-box .file-body.file-code .lines-num-old {
+border-right: 1px solid #DDD;
+}
+.file-content .file-body.file-code .lines-num {
+text-align: right;
+color: #999;
+background: #fafafa;
+width: 1%;
+}
+.diff-file-box .code-diff tbody tr.tag-code td, .diff-file-box .code-diff tbody tr.tag-code pre {
+background-color: #E0E0E0 !important;
+border-color: #ADADAD !important;
+}
+.diff-file-box .code-diff tbody tr.del-code td, .diff-file-box .code-diff tbody tr.del-code pre {
+background-color: #ffe2dd !important;
+border-color: #e9aeae !important;
+}
+.diff-file-box .code-diff tbody tr.add-code td, .diff-file-box .code-diff tbody tr.add-code pre {
+background-color: #d1ffd6 !important;
+border-color: #b4e2b4 !important;
+}
+
+.compare-head-box {
+    margin-top: 10px;
+    .compare {
+        padding: 0 15px 15px 15px;
     }
-  }
-  .sha a {
-    font-family: Consolas, Menlo, Monaco, "Lucida Console", monospace;
-    font-size: 14px;
-  }
 }

+ 8 - 0
public/ng/less/ui/panel.less

@@ -36,6 +36,14 @@
           border-bottom-right-radius: .3em;
         }
     }
+    &.panel-info {
+        border-color: #85c5e5;
+        > .panel-header {
+            color: #31708f;
+            background-color: #d9edf7;
+            border-color: #85c5e5;
+        }
+    }
     &.panel-warning {
         border-color: #F0C36D;
         > .panel-header {

+ 2 - 0
routers/repo/commit.go

@@ -159,6 +159,7 @@ func Diff(ctx *middleware.Context) {
 	ctx.Data["IsImageFile"] = isImageFile
 	ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitId)
 	ctx.Data["Commit"] = commit
+	ctx.Data["Author"] = models.ValidateCommitWithEmail(commit)
 	ctx.Data["Diff"] = diff
 	ctx.Data["Parents"] = parents
 	ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
@@ -212,6 +213,7 @@ func CompareDiff(ctx *middleware.Context) {
 		ctx.Handle(500, "CommitsBeforeUntil", err)
 		return
 	}
+	commits = models.ValidateCommitsWithEmails(commits)
 
 	ctx.Data["Commits"] = commits
 	ctx.Data["CommitCount"] = commits.Len()

+ 3 - 1
templates/repo/commits_table.tmpl

@@ -1,10 +1,12 @@
 <div id="commits-list">
     <div class="panel panel-radius">
         <div class="panel-header">
+            {{if not .IsDiffCompare}}
             <form class="search pull-right" action="{{.RepoLink}}/commits/{{.BranchName}}/search" method="get" id="commits-search-form">
                 <input class="ipt ipt-radius" type="search" name="q" placeholder="{{.i18n.Tr "repo.commits.search"}}" value="{{.Keyword}}" />
                 <button class="btn btn-black btn-small btn-radius">{{.i18n.Tr "repo.commits.find"}}</button>
             </form>
+            {{end}}
             <h4>{{.CommitCount}} {{.i18n.Tr "repo.commits.commits"}}</h4>
         </div>
         <table class="panel-body table commit-list table-striped">
@@ -31,7 +33,7 @@
             </tbody>
         </table>
     </div>
-    {{if not .IsSearchPage}}
+    {{if and (not .IsSearchPage) (not .IsDiffCompare)}}
     <ul class="pagination">
         {{if .LastPageNum}}<li><a class="btn btn-medium btn-gray btn-radius" href="{{.RepoLink}}/commits/{{.BranchName}}{{if .FileName}}/{{.FileName}}{{end}}?p={{.LastPageNum}}" rel="nofollow">&laquo; {{.i18n.Tr "repo.commits.newer"}}</a></li>{{end}}
         {{if .NextPageNum}}<li><a class="btn btn-medium btn-gray btn-radius" href="{{.RepoLink}}/commits/{{.BranchName}}{{if .FileName}}/{{.FileName}}{{end}}?p={{.NextPageNum}}" rel="nofollow">&raquo; {{.i18n.Tr "repo.commits.older"}}</a></li>{{end}}

+ 41 - 35
templates/repo/diff.tmpl

@@ -1,49 +1,54 @@
-{{template "base/head" .}}
-{{template "base/navbar" .}}
-{{template "repo/nav" .}}
-<div id="body" class="container" data-page="repo">
-    <div id="source">
-      {{if .IsDiffCompare }}
-        <div class="panel panel-info diff-box diff-head-box">
-            <div class="panel-heading">
-                <a class="pull-right btn btn-primary btn-sm" rel="nofollow" href="{{.SourcePath}}">Browse Source</a>
-                <h4><a href="{{$.RepoLink}}/commit/{{.BeforeCommitId}}" class="label label-success">{{ShortSha .BeforeCommitId}}</a> ... <a href="{{$.RepoLink}}/commit/{{.AfterCommitId}}" class="label label-success">{{ShortSha .AfterCommitId}}</a></h4>
+{{template "ng/base/head" .}}
+{{template "ng/base/header" .}}
+<div id="repo-wrapper">
+    {{template "repo/header" .}}
+    <div class="container clear" id="diff-page">
+        {{if .IsDiffCompare }}
+        <div class="panel panel-info panel-radius compare-head-box">
+            <div class="panel-header">
+                <a class="pull-right btn btn-blue btn-header btn-medium btn-radius" rel="nofollow" href="{{.SourcePath}}">{{.i18n.Tr "repo.diff.browse_source"}}</a>
+                <h4><a href="{{$.RepoLink}}/commit/{{.BeforeCommitId}}" class="label label-green">{{ShortSha .BeforeCommitId}}</a> ... <a href="{{$.RepoLink}}/commit/{{.AfterCommitId}}" class="label label-green">{{ShortSha .AfterCommitId}}</a></h4>
             </div>
             <div class="panel-body compare">
-              {{template "repo/commits_table" .}}
+                {{template "repo/commits_table" .}}
             </div>
         </div>
-      {{else}}
-          <div class="panel panel-info diff-box diff-head-box">
-            <div class="panel-heading">
-                <a class="pull-right btn btn-primary btn-sm" rel="nofollow" href="{{.SourcePath}}">Browse Source</a>
+        {{else}}
+        <div class="panel panel-info panel-radius diff-head-box">
+            <div class="panel-header">
+                <a class="pull-right btn btn-blue btn-header btn-medium btn-radius" rel="nofollow" href="{{.SourcePath}}">{{.i18n.Tr "repo.diff.browse_source"}}</a>
                 <h4>{{.Commit.Message}}</h4>
             </div>
             <div class="panel-body">
                 <span class="pull-right">
-                <ul class="list-unstyled">
-                    {{range .Parents}}
-                    <li>parent <a href="{{$.RepoLink}}/commit/{{.}}"><span class="label label-default sha">{{ShortSha .}}</span></a></li>
-                    {{end}}
-                    <li>commit <span class="label label-default sha">{{ShortSha .CommitId}}</span></li>
-                </ul>
+                    <ul class="list-unstyled">
+                        <li class="inline">{{.i18n.Tr "repo.diff.parent"}}</li>
+                        {{range .Parents}}
+                        <li class="inline"><a href="{{$.RepoLink}}/commit/{{.}}"><span class="label label-blue">{{ShortSha .}}</span></a></li>
+                        {{end}}
+                        <li class="inline">{{.i18n.Tr "repo.diff.commit"}} <span class="label label-blue">{{ShortSha .CommitId}}</span></li>
+                    </ul>
                 </span>
                 <p class="author">
-                    <img class="avatar" src="{{AvatarLink .Commit.Author.Email}}" alt=""/>
-                    <a class="name" href="{{AppSubUrl}}/user/email2user?email={{.Commit.Author.Email}}"><strong>{{.Commit.Author.Name}}</strong></a>
-                    <span class="time">{{TimeSince .Commit.Author.When $.Lang}}</span>
+                    <img class="avatar-30" src="{{AvatarLink .Commit.Author.Email}}" />
+                    {{if .Author}}
+                    <a href="{{AppSubUrl}}/{{.Author}}"><strong>{{.Commit.Author.Name}}</strong></a>
+                    {{else}}
+                    <strong>{{.Commit.Author.Name}}</strong>
+                    {{end}}
+                    <span class="text-grey" id="authored-time">{{TimeSince .Commit.Author.When $.Lang}}</span> 
                 </p>
-          </div>
+            </div>
         </div>
-      {{end}}
+        {{end}}
         {{if .DiffNotAvailable}}
-        <h4>Diff Data Not Available.</h4>
+        <h4>{{.i18n.Tr "repo.diff.data_not_available"}}</h4>
         {{else}}
         <div class="diff-detail-box diff-box">
-            <a class="pull-right btn btn-default" data-toggle="collapse" data-target="#diff-files">Show Diff Stats</a>
+            <a class="pull-right btn btn-gray btn-header btn-radius text-black" data-target="#diff-files">{{.i18n.Tr "repo.diff.show_diff_stats"}}</a>
             <p class="showing">
                 <i class="fa fa-retweet"></i>
-                <strong> {{.Diff.NumFiles}} changed files</strong> with <strong>{{.Diff.TotalAddition}} additions</strong> and <strong>{{.Diff.TotalDeletion}} deletions</strong>.
+                {{.i18n.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}}
             </p>
             <ol class="detail-files collapse" id="diff-files">
                 {{range .Diff.Files}}
@@ -57,7 +62,7 @@
                         </span>
                         <span class="del" data-line="{{.Deletion}}">{{.Deletion}}</span>
                         {{else}}
-                        <span>BIN</span>
+                        <span>{{$.i18n.Tr "repo.diff.bin"}}</span>
                         {{end}}
                     </div>
                     <!-- todo finish all file status, now modify, add, delete and rename -->
@@ -69,8 +74,8 @@
         </div>
 
         {{range .Diff.Files}}
-        <div class="panel panel-default diff-file-box diff-box file-content" id="diff-{{.Index}}">
-            <div class="panel-heading">
+        <div class="panel diff-file-box diff-box file-content" id="diff-{{.Index}}">
+            <div class="panel-header">
                 <div class="diff-counter count pull-left">
                     {{if not .IsBin}}
                     <span class="add" data-line="{{.Addition}}">+ {{.Addition}}</span>
@@ -80,10 +85,10 @@
                     </span>
                     <span class="del" data-line="{{.Deletion}}">- {{.Deletion}}</span>
                     {{else}}
-                    BIN
+                    {{$.i18n.Tr "repo.diff.bin"}}
                     {{end}}
                 </div>
-                <a class="btn btn-default btn-sm pull-right" rel="nofollow" href="{{$.SourcePath}}/{{.Name}}">View File</a>
+                <a class="btn btn-gray btn-header btn-radius text-black pull-right" rel="nofollow" href="{{$.SourcePath}}/{{.Name}}">{{$.i18n.Tr "repo.diff.view_file"}}</a>
                 <span class="file">{{.Name}}</span>
             </div>
             {{$isImage := (call $.IsImageFile .Name)}}
@@ -115,8 +120,9 @@
                 {{end}}
             </div>
         </div>
+        <br> 
         {{end}}
         {{end}}
     </div>
 </div>
-{{template "base/footer" .}}
+{{template "ng/base/footer" .}}

+ 1 - 0
templates/user/dashboard/feeds.tmpl

@@ -28,6 +28,7 @@
                 {{range $push.Commits}}
                 <li><img class="avatar-16" src="{{AvatarLink .AuthorEmail}}?s=16"> <a href="{{AppSubUrl}}/{{$repoLink}}/commit/{{.Sha1}}">{{ShortSha .Sha1}}</a> <span class="text-truncate grid-4-5">{{.Message}}</span></li>
                 {{end}}
+                {{if $push.CompareUrl}}<li><a href="{{$push.CompareUrl}}">{{$.i18n.Tr "action.compare_2_commits"}} »</a></li>{{end}}
             </ul>
         </div>
         {{else if eq .GetOpType 6}}

Some files were not shown because too many files changed in this diff