Browse Source

Merge remote-tracking branch 'origin/V20211115' into liuzx_trainjob

tags/v1.21.11.2^2
liuzx 4 years ago
parent
commit
2a2bde71eb
32 changed files with 875 additions and 142 deletions
  1. +1
    -1
      README.md
  2. +9
    -0
      models/issue.go
  3. +89
    -5
      models/repo_activity_custom.go
  4. +11
    -0
      models/repo_collaboration.go
  5. +110
    -52
      models/repo_statistic.go
  6. +2
    -0
      modules/setting/setting.go
  7. +17
    -2
      modules/storage/obs.go
  8. +7
    -1
      options/locale/locale_en-US.ini
  9. +7
    -0
      options/locale/locale_zh-CN.ini
  10. +41
    -0
      public/img/git-logo.svg
  11. +15
    -0
      routers/api/v1/api.go
  12. +384
    -0
      routers/api/v1/repo/repo_dashbord.go
  13. +1
    -1
      routers/home.go
  14. +0
    -0
      routers/org/members.go
  15. +2
    -1
      routers/repo/repo_statistic.go
  16. +5
    -0
      routers/repo/view.go
  17. +7
    -2
      routers/routes/routes.go
  18. +4
    -4
      routers/user/auth.go
  19. +2
    -2
      templates/base/head.tmpl
  20. +2
    -2
      templates/base/head_home.tmpl
  21. +8
    -0
      templates/base/head_navbar.tmpl
  22. +6
    -5
      templates/org/home.tmpl
  23. +6
    -6
      templates/org/navber.tmpl
  24. +13
    -3
      templates/repo/activity.tmpl
  25. +31
    -28
      templates/repo/header.tmpl
  26. +5
    -1
      templates/repo/release/list.tmpl
  27. +15
    -0
      templates/repo/view_file.tmpl
  28. +7
    -0
      templates/repo/wiki/start.tmpl
  29. +9
    -1
      templates/repo/wiki/view.tmpl
  30. +13
    -15
      web_src/js/components/EditAboutInfo.vue
  31. +15
    -10
      web_src/js/components/basic/editDialog.vue
  32. +31
    -0
      web_src/less/openi.less

+ 1
- 1
README.md View File

@@ -2,7 +2,7 @@

<h1><img src="public/img/favicon.png" alt="logo" width="30" height="30">AiForge - 启智AI开发协作平台</h1>

[![release](https://img.shields.io/badge/release-1.21.9.2-blue)](https://git.openi.org.cn/OpenI/aiforge/releases/latest)
[![release](https://img.shields.io/badge/release-1.21.11.1-blue)](https://git.openi.org.cn/OpenI/aiforge/releases/latest)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)




+ 9
- 0
models/issue.go View File

@@ -1356,6 +1356,15 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
return accum, nil
}

func GetPullCountByUserAndRepoId(repoId int64, userId int64) int64 {
issue := new(Issue)
total, err := x.Where("is_pull=true and repo_id=? and poster_id=?", repoId, userId).Count(issue)
if err != nil {
return 0
}
return total
}

func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats, error) {
stats := &IssueStats{}



+ 89
- 5
models/repo_activity_custom.go View File

@@ -2,12 +2,19 @@ package models

import (
"fmt"
"sort"
"strings"
"time"

"code.gitea.io/gitea/modules/git"
)

type ContributorWithUserId struct {
git.Contributor
UserId int64
IsAdmin bool
}

func GetRepoKPIStats(repo *Repository) (*git.RepoKPIStats, error) {
wikiPath := ""
if repo.HasWiki() {
@@ -63,22 +70,39 @@ func getRepoKPIStats(repoPath string, wikiPath string) (*git.RepoKPIStats, error
}

if recentlyContributors != nil {
resentlyContributorDistinctDict := make(map[string]int, 0)
for _, recentlyContributor := range recentlyContributors {

user, err := GetUserByActivateEmail(recentlyContributor.Email)
var ok bool
if err == nil {
_, ok = contributorDistinctDict[user.Email]
value, ok := resentlyContributorDistinctDict[user.Email]
if !ok {
resentlyContributorDistinctDict[user.Email] = recentlyContributor.CommitCnt
} else {
resentlyContributorDistinctDict[user.Email] = value + recentlyContributor.CommitCnt
}

} else {
_, ok = contributorDistinctDict[recentlyContributor.Email]
value, ok := resentlyContributorDistinctDict[recentlyContributor.Email]
if !ok {
resentlyContributorDistinctDict[recentlyContributor.Email] = recentlyContributor.CommitCnt
} else {
resentlyContributorDistinctDict[recentlyContributor.Email] = value + recentlyContributor.CommitCnt
}

}

if !ok {
}

for k, v := range resentlyContributorDistinctDict {
count, ok := contributorDistinctDict[k]
if ok && count == v {
stats.ContributorsAdded++
newContributersDict[recentlyContributor.Email] = struct{}{}
}

}

}

stats.Contributors = int64(len(contributorDistinctDict))
@@ -101,6 +125,66 @@ func getRepoKPIStats(repoPath string, wikiPath string) (*git.RepoKPIStats, error

}

func GetTop10Contributor(repoPath string) ([]ContributorWithUserId, error) {
contributors, err := git.GetContributors(repoPath)
if err != nil {
return make([]ContributorWithUserId, 0), err
}
contributorDistinctDict := make(map[string]ContributorWithUserId, 0)
if contributors != nil {
for _, contributor := range contributors {
if strings.Compare(contributor.Email, "") == 0 {
continue
}

user, err := GetUserByActivateEmail(contributor.Email)
if err == nil {

value, ok := contributorDistinctDict[user.Email]
if !ok {
contributorDistinctDict[user.Email] = ContributorWithUserId{
contributor,
user.ID,
user.IsAdmin,
}
} else {

value.CommitCnt += contributor.CommitCnt
}

} else {
value, ok := contributorDistinctDict[contributor.Email]
if !ok {
contributorDistinctDict[contributor.Email] = ContributorWithUserId{
contributor,
-1,
false,
}
} else {
value.CommitCnt += contributor.CommitCnt
}

}

}
v := make([]ContributorWithUserId, 0, len(contributorDistinctDict))
for _, value := range contributorDistinctDict {
v = append(v, value)
}

sort.Slice(v, func(i, j int) bool {
return v[i].CommitCnt > v[j].CommitCnt
})

if len(v) <= 10 {
return v, nil
} else {
return v[0:10], nil
}
}
return make([]ContributorWithUserId, 0), nil
}

func setKeyContributerDict(contributorDistinctDict map[string]int, email string, keyContributorsDict map[string]struct{}) {
if contributorDistinctDict[email] >= 3 {
_, ok := keyContributorsDict[email]


+ 11
- 0
models/repo_collaboration.go View File

@@ -114,6 +114,17 @@ func (repo *Repository) isCollaborator(e Engine, userID int64) (bool, error) {
return e.Get(&Collaboration{RepoID: repo.ID, UserID: userID})
}

func (repo *Repository) GetCollaboratorMode(userID int64) int {
collaboration := &Collaboration{RepoID: repo.ID, UserID: userID}
has, err := x.Get(&collaboration)
if err != nil || !has {
return -1
} else {
return int(collaboration.Mode)
}

}

// IsCollaborator check if a user is a collaborator of a repository
func (repo *Repository) IsCollaborator(userID int64) (bool, error) {
return repo.isCollaborator(x, userID)


+ 110
- 52
models/repo_statistic.go View File

@@ -9,56 +9,56 @@ import (

// RepoStatistic statistic info of all repository
type RepoStatistic struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"unique(s) NOT NULL"`
Name string `xorm:"INDEX"`
IsPrivate bool
Date string `xorm:"unique(s) NOT NULL"`
NumWatches int64 `xorm:"NOT NULL DEFAULT 0"`
NumWatchesAdded int64 `xorm:"NOT NULL DEFAULT 0"`
NumStars int64 `xorm:"NOT NULL DEFAULT 0"`
NumStarsAdded int64 `xorm:"NOT NULL DEFAULT 0"`
NumForks int64 `xorm:"NOT NULL DEFAULT 0"`
NumForksAdded int64 `xorm:"NOT NULL DEFAULT 0"`
NumDownloads int64 `xorm:"NOT NULL DEFAULT 0"`
NumDownloadsAdded int64 `xorm:"NOT NULL DEFAULT 0"`
NumComments int64 `xorm:"NOT NULL DEFAULT 0"`
NumCommentsAdded int64 `xorm:"NOT NULL DEFAULT 0"`
NumVisits int64 `xorm:"NOT NULL DEFAULT 0"`
NumClosedIssues int64 `xorm:"NOT NULL DEFAULT 0"`
NumClosedIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0"`
NumVersions int64 `xorm:"NOT NULL DEFAULT 0"`
NumDevMonths int64 `xorm:"NOT NULL DEFAULT 0"`
RepoSize int64 `xorm:"NOT NULL DEFAULT 0"`
DatasetSize int64 `xorm:"NOT NULL DEFAULT 0"`
NumModels int64 `xorm:"NOT NULL DEFAULT 0"`
NumWikiViews int64 `xorm:"NOT NULL DEFAULT 0"`
NumCommits int64 `xorm:"NOT NULL DEFAULT 0"`
NumCommitsAdded int64 `xorm:"NOT NULL DEFAULT 0"`
NumIssues int64 `xorm:"NOT NULL DEFAULT 0"`
NumIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0"`
NumPulls int64 `xorm:"NOT NULL DEFAULT 0"`
NumPullsAdded int64 `xorm:"NOT NULL DEFAULT 0"`
IssueFixedRate float32 `xorm:"NOT NULL"`
NumContributor int64 `xorm:"NOT NULL DEFAULT 0"`
NumContributorAdded int64 `xorm:"NOT NULL DEFAULT 0"`
NumKeyContributor int64 `xorm:"NOT NULL DEFAULT 0"`
NumContributorsGrowth int64 `xorm:"NOT NULL DEFAULT 0"`
NumCommitsGrowth int64 `xorm:"NOT NULL DEFAULT 0"`
NumCommitLinesGrowth int64 `xorm:"NOT NULL DEFAULT 0"`
NumIssuesGrowth int64 `xorm:"NOT NULL DEFAULT 0"`
NumCommentsGrowth int64 `xorm:"NOT NULL DEFAULT 0"`
Impact float64 `xorm:"NOT NULL DEFAULT 0"`
Completeness float64 `xorm:"NOT NULL DEFAULT 0"`
Liveness float64 `xorm:"NOT NULL DEFAULT 0"`
ProjectHealth float64 `xorm:"NOT NULL DEFAULT 0"`
TeamHealth float64 `xorm:"NOT NULL DEFAULT 0"`
Growth float64 `xorm:"NOT NULL DEFAULT 0"`
RadarTotal float64 `xorm:"NOT NULL DEFAULT 0"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
ID int64 `xorm:"pk autoincr" json:"-"`
RepoID int64 `xorm:"unique(s) NOT NULL" json:"repo_id"`
Name string `xorm:"INDEX" json:"name"`
IsPrivate bool `json:"isPrivate"`
Date string `xorm:"unique(s) NOT NULL" json:"date"`
NumWatches int64 `xorm:"NOT NULL DEFAULT 0" json:"watch"`
NumWatchesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumStars int64 `xorm:"NOT NULL DEFAULT 0" json:"star"`
NumStarsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumForks int64 `xorm:"NOT NULL DEFAULT 0" json:"fork"`
NumForksAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumDownloads int64 `xorm:"NOT NULL DEFAULT 0" json:"download"`
NumDownloadsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumComments int64 `xorm:"NOT NULL DEFAULT 0" json:"comment"`
NumCommentsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumVisits int64 `xorm:"NOT NULL DEFAULT 0" json:"view"`
NumClosedIssues int64 `xorm:"NOT NULL DEFAULT 0" json:"issueClosed"`
NumClosedIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumVersions int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumDevMonths int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
RepoSize int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
DatasetSize int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumModels int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumWikiViews int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumCommits int64 `xorm:"NOT NULL DEFAULT 0" json:"commit"`
NumCommitsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumIssues int64 `xorm:"NOT NULL DEFAULT 0" json:"issue"`
NumIssuesAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumPulls int64 `xorm:"NOT NULL DEFAULT 0" json:"pr"`
NumPullsAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
IssueFixedRate float32 `xorm:"NOT NULL" json:"issueClosedRatio"`
NumContributor int64 `xorm:"NOT NULL DEFAULT 0" json:"contributor"`
NumContributorAdded int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumKeyContributor int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumContributorsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumCommitsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumCommitLinesGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumIssuesGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
NumCommentsGrowth int64 `xorm:"NOT NULL DEFAULT 0" json:"-"`
Impact float64 `xorm:"NOT NULL DEFAULT 0" json:"impact"`
Completeness float64 `xorm:"NOT NULL DEFAULT 0" json:"completeness"`
Liveness float64 `xorm:"NOT NULL DEFAULT 0" json:"liveness"`
ProjectHealth float64 `xorm:"NOT NULL DEFAULT 0" json:"projectHealth"`
TeamHealth float64 `xorm:"NOT NULL DEFAULT 0" json:"teamHealth"`
Growth float64 `xorm:"NOT NULL DEFAULT 0" json:"growth"`
RadarTotal float64 `xorm:"NOT NULL DEFAULT 0" json:"openi"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created" json:"-"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated" json:"-"`
}

func DeleteRepoStatDaily(date string) error {
@@ -81,9 +81,60 @@ func DeleteRepoStatDaily(date string) error {
return nil
}

func GetRepoStatisticByDate(date string) ([]*RepoStatistic, error) {
func CountRepoStatByRawSql(sql string) (int64, error) {

return xStatistic.SQL(sql).Count()

}

func GetRepoStatisticByRawSql(sql string) []*RepoStatistic {
repoStatistics := make([]*RepoStatistic, 0)
err := xStatistic.Where("date = ?", date).Find(&repoStatistics)
xStatistic.SQL(sql).Find(&repoStatistics)
return repoStatistics
}

func GetRepoStatLastUpdatedTime(repoId ...string) (string, string, error) {

repoStatistic := new(RepoStatistic)
var has bool
var err error
if len(repoId) == 0 {
has, err = xStatistic.Desc("created_unix").Limit(1).Cols("created_unix", "date").Get(repoStatistic)

} else {
has, err = xStatistic.Where("repo_id=?", repoId[0]).Desc("created_unix").Limit(1).Cols("created_unix", "date").Get(repoStatistic)
}

if err != nil {
return "", "", err
} else {
if has {
return repoStatistic.CreatedUnix.Format("2006-01-02 15:04:05"), repoStatistic.Date, nil
} else {
return "", "", fmt.Errorf("Can not get the latest record.")
}
}

}

func GetRepoStatisticByDateAndRepoId(date string, repoId int64) (*RepoStatistic, error) {
repoStatistic := new(RepoStatistic)
has, err := xStatistic.Where("date=? and repo_id=?", date, repoId).Get(repoStatistic)
if err != nil {
return nil, err
} else {
if has {
return repoStatistic, nil
} else {
return nil, fmt.Errorf("The num of return records is 0.")
}
}

}

func GetRepoStatisticByDate(date string, repoId int64) ([]*RepoStatistic, error) {
repoStatistics := make([]*RepoStatistic, 0)
err := xStatistic.Where("date = ? and repo_id=?", date, repoId).Find(&repoStatistics)
return repoStatistics, err

}
@@ -107,6 +158,13 @@ func InsertRepoStat(repoStat *RepoStatistic) (int64, error) {
return xStatistic.Insert(repoStat)
}

func RestoreRepoStatFork(numForks int64, repoId int64) error {
sql := "update repo_statistic set num_forks=? where repo_id=?"

_, err := xStatistic.Exec(sql, numForks, repoId)
return err
}

func UpdateRepoStat(repoStat *RepoStatistic) error {
sql := "update repo_statistic set impact=?,completeness=?,liveness=?,project_health=?,team_health=?,growth=?,radar_total=? where repo_id=? and date=?"



+ 2
- 0
modules/setting/setting.go View File

@@ -544,6 +544,7 @@ var (
GrowthContributors float64
GrowthCommit float64
GrowthComments float64
RecordBeginTime string
}{}
)

@@ -1324,6 +1325,7 @@ func SetRadarMapConfig() {
RadarMap.GrowthContributors = sec.Key("growth_contributors").MustFloat64(0.2)
RadarMap.GrowthCommit = sec.Key("growth_commit").MustFloat64(0.2)
RadarMap.GrowthComments = sec.Key("growth_comments").MustFloat64(0.2)
RadarMap.RecordBeginTime = sec.Key("record_beigin_time").MustString("2021-11-05")

}



+ 17
- 2
modules/storage/obs.go View File

@@ -178,6 +178,7 @@ func GetObsListObject(jobName, parentDir string) ([]FileInfo, error) {
input := &obs.ListObjectsInput{}
input.Bucket = setting.Bucket
input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/")
strPrefix := strings.Split(input.Prefix, "/")
output, err := ObsCli.ListObjects(input)
fileInfos := make([]FileInfo, 0)
if err == nil {
@@ -186,15 +187,29 @@ func GetObsListObject(jobName, parentDir string) ([]FileInfo, error) {
var isDir bool
var fileName,nextParentDir string
if strings.HasSuffix(val.Key, "/") {
//dirs in next level dir
if len(str1) - len(strPrefix) > 2 {
continue
}
fileName = str1[len(str1)-2]
isDir = true
nextParentDir = fileName
if fileName == parentDir || (fileName + "/") == setting.OutPutPath {
if parentDir == "" {
nextParentDir = fileName
} else {
nextParentDir = parentDir + "/" + fileName
}

if fileName == strPrefix[len(strPrefix)-1] || (fileName + "/") == setting.OutPutPath {
continue
}
} else {
//files in next level dir
if len(str1) - len(strPrefix) > 1 {
continue
}
fileName = str1[len(str1)-1]
isDir = false
nextParentDir = parentDir
}

fileInfo := FileInfo{


+ 7
- 1
options/locale/locale_en-US.ini View File

@@ -755,6 +755,7 @@ unit_disabled = The site administrator has disabled this repository section.
language_other = Other
datasets = Datasets
datasets.desc = Enable Dataset
cloudbrain_helper=Use GPU/NPU resources to open notebooks, model training tasks, etc.

debug=Debug
stop=Stop
@@ -785,7 +786,12 @@ cloudbrain_operate = Operate
cloudbrain_status_createtime = Status/Createtime
cloudbrain_status_runtime = Running Time


record_begintime_get_err=Can not get the record begin time.
parameter_is_wrong=The input parameter is wrong.
total_count_get_error=Can not get the total page.
last_update_time_error=Can not get the last updated time.
get_repo_stat_error=Can not get the statistics of the repository.
get_repo_info_error=Can not get the information of the repository.
modelarts.notebook=Debug Task
modelarts.train_job=Train Task
modelarts.train_job.new_debug= New Debug Task


+ 7
- 0
options/locale/locale_zh-CN.ini View File

@@ -757,6 +757,7 @@ unit_disabled=站点管理员已禁用此项目单元。
language_other=其它
datasets=数据集
datasets.desc=数据集功能
cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等

debug=调试
stop=停止
@@ -787,6 +788,12 @@ cloudbrain_status_createtime=状态/创建时间
cloudbrain_status_runtime = 运行时长
cloudbrain_jobname_err=只能以小写字母或数字开头且只包含小写字母、数字、_和-,不能以_结尾,最长36个字符。

record_begintime_get_err=无法获取统计开始时间。
parameter_is_wrong=输入参数错误,请检查输入参数。
total_count_get_error=查询总页数失败。
last_update_time_error=查询最新更新时间失败。
get_repo_stat_error=查询当前仓库的统计信息失败。
get_repo_info_error=查询当前仓库信息失败。
modelarts.notebook=调试任务
modelarts.train_job=训练任务
modelarts.train_job.new_debug=新建调试任务


+ 41
- 0
public/img/git-logo.svg View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.4.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 96 17.3" style="enable-background:new 0 0 96 17.3;" xml:space="preserve">
<style type="text/css">
.st0{fill:#5BB973;}
</style>
<g>
<path class="st0" d="M5.9,12.5l-1,3.8h-3L6.6,1.5H10l4.7,14.8h-3.1l-1-3.8H5.9z M6.5,10.2H10L9.6,8.5C9.4,7.8,9.1,7,8.9,6.1
C8.7,5.3,8.5,4.5,8.3,3.7H8.2C8,4.5,7.8,5.3,7.6,6.2S7.2,7.8,6.9,8.5L6.5,10.2z"/>
<path class="st0" d="M19.5,1.5v14.8h-3V1.5H19.5z"/>
<path class="st0" d="M27.7,6.6v10.6h-2.1V6.6h-1.8v-2h1.8V0.3h2.1v4.3h1.7v2H27.7z M31.6,7.4c-0.2,0.9-0.5,1.8-0.8,2.7
c-0.3,0.9-0.7,1.6-1.1,2.2c-0.1-0.1-0.2-0.2-0.4-0.3s-0.3-0.2-0.4-0.3c-0.2-0.1-0.3-0.2-0.5-0.3c-0.2-0.1-0.3-0.2-0.4-0.2
c0.4-0.5,0.7-1.1,1-1.9s0.5-1.5,0.6-2.3L31.6,7.4z M34.6,5.8c0,0.9-0.1,1.9-0.3,2.9c-0.1,1-0.4,2-0.7,3s-0.8,2-1.4,2.9
c-0.6,0.9-1.4,1.8-2.4,2.6c-0.1-0.1-0.2-0.2-0.3-0.4c-0.1-0.1-0.3-0.3-0.4-0.4c-0.1-0.1-0.3-0.3-0.4-0.4s-0.3-0.2-0.4-0.3
c0.9-0.7,1.6-1.5,2.1-2.3c0.6-0.8,1-1.7,1.3-2.5c0.3-0.9,0.5-1.7,0.7-2.6s0.2-1.7,0.3-2.5h-2.7V3.7h2.7V0.5h2v3.2h3.7
c0,0.1,0,0.3,0,0.4c0,0.1,0,0.2,0,0.3s0,0.2,0,0.3l-0.1,2.7l1.3-0.3c0.1,0.4,0.3,0.9,0.4,1.3c0.1,0.5,0.3,0.9,0.4,1.4
c0.1,0.5,0.2,0.9,0.3,1.3c0.1,0.4,0.2,0.8,0.2,1.1L39,12.8c-0.1-0.5-0.2-1.1-0.3-1.8s-0.3-1.4-0.5-2.1c0,1.2-0.1,2.1-0.1,3
c0,0.8-0.1,1.5-0.2,2.1c-0.1,0.6-0.1,1-0.2,1.4c-0.1,0.3-0.2,0.6-0.3,0.8c-0.2,0.3-0.4,0.5-0.7,0.7c-0.2,0.1-0.5,0.2-0.8,0.3
C35.6,17,35.3,17,34.8,17s-0.9,0-1.3,0c0-0.3-0.1-0.6-0.2-1c-0.1-0.4-0.3-0.7-0.4-1c0.4,0,0.9,0.1,1.2,0.1c0.4,0,0.7,0,0.8,0
c0.2,0,0.3,0,0.4-0.1c0.1,0,0.2-0.1,0.3-0.2c0.1-0.1,0.2-0.4,0.3-0.8c0.1-0.4,0.1-0.9,0.2-1.6s0.1-1.6,0.1-2.7
c0-1.1,0.1-2.4,0.1-3.9H34.6z"/>
<path class="st0" d="M47.8,1.1C47.6,1.7,47.3,2.4,47,3c-0.3,0.6-0.6,1.2-0.9,1.9v12.4h-2.2v-9c-0.2,0.2-0.4,0.5-0.6,0.7
S43,9.3,42.8,9.5c0-0.1-0.1-0.3-0.2-0.5c-0.1-0.2-0.2-0.4-0.3-0.6c-0.1-0.2-0.2-0.4-0.3-0.6s-0.2-0.4-0.3-0.5
c0.4-0.4,0.8-0.9,1.2-1.4c0.4-0.5,0.8-1.1,1.1-1.6c0.4-0.6,0.7-1.2,1-1.8c0.3-0.6,0.6-1.3,0.8-1.9L47.8,1.1z M53.5,13.2v4h-2.2V5.3
h-0.7c-0.4,0.7-0.7,1.3-1.1,1.9s-0.8,1.1-1.2,1.6c-0.1-0.1-0.2-0.2-0.3-0.4c-0.1-0.1-0.3-0.3-0.4-0.4S47.2,7.8,47,7.7
c-0.2-0.1-0.3-0.2-0.4-0.3C47,6.9,47.4,6.5,47.8,6c0.4-0.5,0.7-1.1,1-1.7s0.6-1.2,0.9-1.8c0.3-0.6,0.5-1.3,0.7-1.9l2.1,0.5
c-0.1,0.4-0.3,0.8-0.4,1.1s-0.3,0.7-0.5,1.1h7v2h-5.1v1.9h4.7v1.9h-4.7v2h4.9v2H53.5z"/>
<path class="st0" d="M69.3,11.3v6h-2.2v-6h-7V9.1h7V3.6H61V1.5h14.4v2.1h-6v5.5h7.1v2.2H69.3z M64.1,4.2c0.1,0.3,0.3,0.6,0.4,0.9
s0.3,0.6,0.4,1c0.1,0.3,0.2,0.6,0.4,0.9c0.1,0.3,0.2,0.6,0.2,0.8l-2.1,0.6c0-0.2-0.1-0.5-0.2-0.8s-0.2-0.6-0.3-1
c-0.1-0.3-0.2-0.7-0.4-1c-0.1-0.3-0.3-0.7-0.4-1L64.1,4.2z M74.6,4.7c-0.3,0.7-0.7,1.4-1,2.1c-0.3,0.7-0.7,1.2-1,1.7l-1.9-0.5
c0.1-0.3,0.3-0.6,0.4-0.9s0.3-0.6,0.4-1c0.1-0.3,0.3-0.7,0.4-1c0.1-0.3,0.2-0.6,0.3-0.9L74.6,4.7z"/>
<path class="st0" d="M89.4,2c0.4,0.4,0.9,0.8,1.3,1.3c0.5,0.5,0.9,0.9,1.3,1.4s0.8,0.9,1.2,1.4c0.4,0.5,0.7,0.9,0.9,1.3l-1.8,1.3
c-0.1-0.2-0.3-0.4-0.4-0.6c-0.2-0.2-0.3-0.5-0.5-0.7c-1.6,0.1-3,0.1-4.1,0.2c-1.2,0.1-2.1,0.1-3,0.2c-0.8,0-1.5,0.1-2,0.1
s-1,0.1-1.3,0.1s-0.6,0.1-0.8,0.1c-0.2,0-0.4,0.1-0.5,0.1c0-0.1-0.1-0.2-0.1-0.4c-0.1-0.2-0.1-0.4-0.2-0.6
c-0.1-0.2-0.1-0.4-0.2-0.6C79,6.3,78.9,6.2,78.9,6c0.3-0.1,0.6-0.2,0.9-0.5c0.3-0.3,0.7-0.6,1-1c0.4-0.4,0.7-0.8,1.1-1.2
c0.4-0.4,0.7-0.9,1-1.3c0.3-0.4,0.6-0.8,0.8-1.2c0.2-0.4,0.4-0.6,0.5-0.8L86.4,1c-0.6,0.8-1.2,1.7-1.9,2.4s-1.4,1.5-2,2.2l7.4-0.2
c-0.3-0.4-0.7-0.8-1.1-1.2c-0.4-0.4-0.7-0.7-1-1.1L89.4,2z M82.4,16.3v0.9h-2.2V9.3h12.2v7.9H90v-0.9H82.4z M82.4,14.2H90v-2.9
h-7.6V14.2z"/>
</g>
</svg>

+ 15
- 0
routers/api/v1/api.go View File

@@ -523,6 +523,21 @@ func RegisterRoutes(m *macaron.Macaron) {
Get(notify.GetThread).
Patch(notify.ReadThread)
}, reqToken())
adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true})
//Project board
m.Group("/projectboard", func() {

m.Get("/restoreFork", adminReq, repo.RestoreForkNumber)

m.Group("/project", func() {
m.Get("", adminReq, repo.GetAllProjectsPeriodStatistics)
m.Group("/:id", func() {
m.Get("", adminReq, repo.GetProjectLatestStatistics)
m.Get("/period", adminReq, repo.GetProjectPeriodStatistics)

})
})
})

// Users
m.Group("/users", func() {


+ 384
- 0
routers/api/v1/repo/repo_dashbord.go View File

@@ -0,0 +1,384 @@
package repo

import (
"fmt"
"net/http"
"strconv"
"time"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"

"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
)

const DEFAULT_PAGE_SIZE = 10
const DATE_FORMAT = "2006-01-02"

type ProjectsPeriodData struct {
RecordBeginTime string `json:"recordBeginTime"`
LastUpdatedTime string `json:"lastUpdatedTime"`
PageSize int `json:"pageSize"`
TotalPage int `json:"totalPage"`
PageRecords []*models.RepoStatistic `json:"pageRecords"`
}

type UserInfo struct {
User string `json:"user"`
Mode int `json:"mode"`
PR int64 `json:"pr"`
Commit int `json:"commit"`
}

type ProjectLatestData struct {
RecordBeginTime string `json:"recordBeginTime"`
LastUpdatedTime string `json:"lastUpdatedTime"`
CreatTime string `json:"creatTime"`
OpenI float64 `json:"openi"`
Comment int64 `json:"comment"`
View int64 `json:"view"`
Download int64 `json:"download"`
IssueClosedRatio float32 `json:"issueClosedRatio"`
Impact float64 `json:"impact"`
Completeness float64 `json:"completeness"`
Liveness float64 `json:"liveness"`
ProjectHealth float64 `json:"projectHealth"`
TeamHealth float64 `json:"teamHealth"`
Growth float64 `json:"growth"`
Description string `json:"description"`
Top10 []UserInfo `json:"top10"`
}

func RestoreForkNumber(ctx *context.Context) {
repos, err := models.GetAllRepositories()
if err != nil {
log.Error("GetAllRepositories failed: %v", err.Error())
return
}
for _, repo := range repos {
models.RestoreRepoStatFork(int64(repo.NumForks), repo.ID)
}

ctx.JSON(http.StatusOK, struct{}{})
}

func GetAllProjectsPeriodStatistics(ctx *context.Context) {

recordBeginTime, err := getRecordBeginTime()
if err != nil {
log.Error("Can not get record begin time", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime)
if err != nil {
log.Error("Parameter is wrong", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong"))
return
}
q := ctx.QueryTrim("q")
page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
pageSize := ctx.QueryInt("pagesize")
if pageSize <= 0 {
pageSize = DEFAULT_PAGE_SIZE
}
orderBy := getOrderBy(ctx)

latestUpdatedTime, latestDate, err := models.GetRepoStatLastUpdatedTime()
if err != nil {
log.Error("Can not query the last updated time.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.last_update_time_error"))
return
}

countSql := generateCountSql(beginTime, endTime, latestDate, q)
total, err := models.CountRepoStatByRawSql(countSql)
if err != nil {
log.Error("Can not query total count.", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.total_count_get_error"))
return
}

projectsPeriodData := ProjectsPeriodData{
RecordBeginTime: recordBeginTime.Format(DATE_FORMAT),
PageSize: pageSize,
TotalPage: getTotalPage(total, pageSize),
LastUpdatedTime: latestUpdatedTime,
PageRecords: models.GetRepoStatisticByRawSql(generatePageSql(beginTime, endTime, latestDate, q, orderBy, page, pageSize)),
}

ctx.JSON(http.StatusOK, projectsPeriodData)

}

func GetProjectLatestStatistics(ctx *context.Context) {
repoId := ctx.Params(":id")
recordBeginTime, err := getRecordBeginTime()
if err != nil {
log.Error("Can not get record begin time", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
latestUpdatedTime, latestDate, err := models.GetRepoStatLastUpdatedTime(repoId)
repoIdInt, _ := strconv.ParseInt(repoId, 10, 64)
repoStat, err := models.GetRepoStatisticByDateAndRepoId(latestDate, repoIdInt)
if err != nil {
log.Error("Can not get the repo statistics "+repoId, err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.get_repo_stat_error"))
return
}

repository, err := models.GetRepositoryByID(repoIdInt)
if err != nil {
log.Error("Can not get the repo info "+repoId, err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.get_repo_info_error"))
return
}
projectLatestData := ProjectLatestData{
RecordBeginTime: recordBeginTime.Format(DATE_FORMAT),
CreatTime: time.Unix(int64(repository.CreatedUnix), 0).Format(DATE_FORMAT),
LastUpdatedTime: latestUpdatedTime,
OpenI: repoStat.RadarTotal,
Comment: repoStat.NumComments,
View: repoStat.NumVisits,
Download: repoStat.NumDownloads,
IssueClosedRatio: repoStat.IssueFixedRate,
Impact: repoStat.Impact,
Completeness: repoStat.Completeness,
Liveness: repoStat.Liveness,
ProjectHealth: repoStat.ProjectHealth,
TeamHealth: repoStat.TeamHealth,
Growth: repoStat.Growth,
Description: repository.Description,
}

contributors, err := models.GetTop10Contributor(repository.RepoPath())
if err != nil {
log.Error("can not get contributors", err)
}
users := make([]UserInfo, 0)

for _, contributor := range contributors {
mode := repository.GetCollaboratorMode(contributor.UserId)
if mode == -1 {
if contributor.IsAdmin {
mode = int(models.AccessModeAdmin)
}
if contributor.UserId == repository.OwnerID {
mode = int(models.AccessModeOwner)
}
}

pr := models.GetPullCountByUserAndRepoId(repoIdInt, contributor.UserId)
userInfo := UserInfo{
User: contributor.Committer,
Commit: contributor.CommitCnt,
Mode: mode,
PR: pr,
}
users = append(users, userInfo)

}

projectLatestData.Top10 = users

ctx.JSON(http.StatusOK, projectLatestData)

}

func GetProjectPeriodStatistics(ctx *context.Context) {
repoId := ctx.Params(":id")
recordBeginTime, err := getRecordBeginTime()
if err != nil {
log.Error("Can not get record begin time", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}

repoIdInt, _ := strconv.ParseInt(repoId, 10, 64)

if err != nil {
log.Error("Can not get record begin time", err)
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.record_begintime_get_err"))
return
}
beginTime, endTime, err := getTimePeroid(ctx, recordBeginTime)
isOpenI := ctx.QueryBool("openi")
var repositorys []*models.RepoStatistic
if isOpenI {
repositorys = models.GetRepoStatisticByRawSql(generateRadarSql(beginTime, endTime, repoIdInt))
} else {
repositorys = models.GetRepoStatisticByRawSql(generateTargetSql(beginTime, endTime, repoIdInt))
}
ctx.JSON(http.StatusOK, repositorys)
}

func generateRadarSql(beginTime time.Time, endTime time.Time, repoId int64) string {
sql := "SELECT date, impact, completeness, liveness, project_health, team_health, growth, radar_total FROM repo_statistic" +
" where repo_id=" + strconv.FormatInt(repoId, 10) + " and created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
" and created_unix<" + strconv.FormatInt(endTime.Unix(), 10)

return sql
}

func generateTargetSql(beginTime time.Time, endTime time.Time, repoId int64) string {
sql := "SELECT date, num_visits,num_downloads,num_commits FROM repo_statistic" +
" where repo_id=" + strconv.FormatInt(repoId, 10) + " and created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
" and created_unix<" + strconv.FormatInt(endTime.Unix(), 10)

return sql
}

func generateCountSql(beginTime time.Time, endTime time.Time, yesterday string, q string) string {
countSql := "SELECT count(*) FROM " +
"(SELECT repo_id FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
" and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," +
"(SELECT repo_id,name,is_private,radar_total from public.repo_statistic where date='" + yesterday + "') B" +
" where A.repo_id=B.repo_id"
if q != "" {
countSql = countSql + " and B.name like '%" + q + "%'"
}
return countSql
}

func generatePageSql(beginTime time.Time, endTime time.Time, yesterday string, q string, orderBy string, page int, pageSize int) string {
countSql := "SELECT A.repo_id,name,is_private,radar_total,num_watches,num_visits,num_downloads,num_pulls,num_commits,num_stars,num_forks,num_issues,num_closed_issues,num_contributor FROM " +
"(SELECT repo_id,sum(num_watches_added) as num_watches,sum(num_visits) as num_visits, sum(num_downloads_added) as num_downloads,sum(num_pulls_added) as num_pulls,sum(num_commits_added) as num_commits,sum(num_stars_added) as num_stars,sum(num_forks_added) num_forks,sum(num_issues_added) as num_issues,sum(num_closed_issues_added) as num_closed_issues,sum(num_contributor_added) as num_contributor " +
" FROM repo_statistic where created_unix >=" + strconv.FormatInt(beginTime.Unix(), 10) +
" and created_unix<" + strconv.FormatInt(endTime.Unix(), 10) + " group by repo_id) A," +
"(SELECT repo_id,name,is_private,radar_total from public.repo_statistic where date='" + yesterday + "') B" +
" where A.repo_id=B.repo_id"
if q != "" {
countSql = countSql + " and B.name like '%" + q + "%'"
}
countSql = countSql + " order by " + orderBy + " desc,A.repo_id" + " limit " + strconv.Itoa(pageSize) + " offset " + strconv.Itoa((page-1)*pageSize)
return countSql
}

func getOrderBy(ctx *context.Context) string {
orderBy := ""
switch ctx.Query("sort") {
case "openi":
orderBy = "B.radar_total"
case "view":
orderBy = "A.num_visits"
case "download":
orderBy = "A.num_downloads"
case "pr":
orderBy = "A.num_pulls"
case "commit":
orderBy = "A.num_commits"
case "watch":
orderBy = "A.num_watches"
case "star":
orderBy = "A.num_stars"
case "fork":
orderBy = "A.num_forks"
case "issue":
orderBy = "A.num_issues"
case "issue_closed":
orderBy = "A.num_closed_issues"
case "contributor":
orderBy = "A.num_contributor"
default:
orderBy = "B.radar_total"
}
return orderBy
}

func getTimePeroid(ctx *context.Context, recordBeginTime time.Time) (time.Time, time.Time, error) {
queryType := ctx.QueryTrim("type")
now := time.Now()
recordBeginTimeTemp := recordBeginTime.AddDate(0, 0, 1)

beginTimeStr := ctx.QueryTrim("beginTime")
endTimeStr := ctx.QueryTrim("endTime")
var beginTime time.Time
var endTime time.Time

if queryType != "" {

if queryType == "all" {
beginTime = recordBeginTimeTemp
endTime = now
} else if queryType == "yesterday" {
endTime = now
beginTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location())

} else if queryType == "current_week" {
beginTime = now.AddDate(0, 0, -int(time.Now().Weekday())+1)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())
endTime = now
} else if queryType == "current_month" {
endTime = now
beginTime = time.Date(endTime.Year(), endTime.Month(), 2, 0, 0, 0, 0, now.Location())
} else if queryType == "monthly" {
endTime = now
beginTime = now.AddDate(0, -1, 1)
beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location())

} else if queryType == "current_year" {
endTime = now
beginTime = time.Date(endTime.Year(), 1, 2, 0, 0, 0, 0, now.Location())

} else if queryType == "last_month" {

lastMonthTime := now.AddDate(0, -1, 0)
beginTime = time.Date(lastMonthTime.Year(), lastMonthTime.Month(), 2, 0, 0, 0, 0, now.Location())
endTime = time.Date(now.Year(), now.Month(), 2, 0, 0, 0, 0, now.Location())

} else {
return now, now, fmt.Errorf("The value of type parameter is wrong.")

}

} else {
if beginTimeStr == "" || endTimeStr == "" {
//如果查询类型和开始时间结束时间都未设置,按queryType=all处理
beginTime = recordBeginTimeTemp
endTime = now

} else {

beginTime, err := time.Parse("2006-01-02", beginTimeStr)
if err != nil {
return now, now, err
}

endTime, err := time.Parse("2006-01-02", endTimeStr)
if err != nil {
return now, now, err
}

beginTime = beginTime.AddDate(0, 0, 1)
endTime = endTime.AddDate(0, 0, 1)
}

}

if beginTime.Before(recordBeginTimeTemp) {
beginTime = recordBeginTimeTemp
}

return beginTime, endTime, nil

}

func getRecordBeginTime() (time.Time, error) {

return time.Parse(DATE_FORMAT, setting.RadarMap.RecordBeginTime)
}

func getTotalPage(total int64, pageSize int) int {

another := 0
if int(total)%pageSize != 0 {
another = 1
}
return int(total)/pageSize + another

}

+ 1
- 1
routers/home.go View File

@@ -146,7 +146,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
ctx.Data["SortType"] = "hot"
orderBy = models.SearchOrderByHot
}
orderBy = orderBy + ",id"
//todo:support other topics
keyword := strings.Trim(ctx.Query("q"), " ")
topic := strings.Trim(ctx.Query("topic"), " ")


+ 0
- 0
routers/org/members.go View File


+ 2
- 1
routers/repo/repo_statistic.go View File

@@ -93,6 +93,7 @@ func RepoStatisticDaily(date string) {
IsPrivate: repo.IsPrivate,
NumWatches: int64(repo.NumWatches),
NumStars: int64(repo.NumStars),
NumForks: int64(repo.NumForks),
NumDownloads: repo.CloneCnt,
NumComments: numComments,
NumVisits: int64(numVisits),
@@ -115,7 +116,7 @@ func RepoStatisticDaily(date string) {
}

dayBeforeDate := t.AddDate(0, 0, -1).Format("2006-01-02")
repoStatisticsBefore, err := models.GetRepoStatisticByDate(dayBeforeDate)
repoStatisticsBefore, err := models.GetRepoStatisticByDate(dayBeforeDate, repo.ID)

if err != nil {
log.Error("get data of day before the date failed ", err)


+ 5
- 0
routers/repo/view.go View File

@@ -243,6 +243,11 @@ func renderDirectory(ctx *context.Context, treeLink string) {
ctx.Data["ReadmeInList"] = true
ctx.Data["ReadmeExist"] = true
ctx.Data["FileIsSymlink"] = readmeFile.isSymlink
ctx.Data["ReadmeName"] = readmeFile.name

if ctx.Repo.CanEnableEditor() {
ctx.Data["CanEditFile"] = true
}

dataRc, err := readmeFile.blob.DataAsync()
if err != nil {


+ 7
- 2
routers/routes/routes.go View File

@@ -311,7 +311,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Head("/", func() string {
return ""
})
m.Get("/", routers.Dashboard)
m.Get("/", routers.Home)
m.Get("/dashboard", routers.Dashboard)
m.Group("/explore", func() {
m.Get("", func(ctx *context.Context) {
@@ -615,6 +615,11 @@ func RegisterRoutes(m *macaron.Macaron) {
//reqRepoBlockChainWriter := context.RequireRepoWriter(models.UnitTypeBlockChain)

// ***** START: Organization *****
m.Group("/org", func() {
m.Group("/:org", func() {
m.Get("/members", org.Members)
}, context.OrgAssignment())
})
m.Group("/org", func() {
m.Group("", func() {
m.Get("/create", org.Create)
@@ -625,7 +630,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/dashboard", user.Dashboard)
m.Get("/^:type(issues|pulls)$", user.Issues)
m.Get("/milestones", reqMilestonesDashboardPageEnabled, user.Milestones)
m.Get("/members", org.Members)
//m.Get("/members", org.Members)
m.Post("/members/action/:action", org.MembersAction)

m.Get("/teams", org.Teams)


+ 4
- 4
routers/user/auth.go View File

@@ -544,7 +544,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR

if err := models.UpdateUserCols(u, "language"); err != nil {
log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", u.ID, u.Language))
return setting.AppSubURL + "/"
return setting.AppSubURL + "/dashboard"
}
} else {
// Language setting of the user use the one previously set
@@ -562,7 +562,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
u.SetLastLogin()
if err := models.UpdateUserCols(u, "last_login_unix"); err != nil {
ctx.ServerError("UpdateUserCols", err)
return setting.AppSubURL + "/"
return setting.AppSubURL + "/dashboard"
}

if redirectTo := ctx.GetCookie("redirect_to"); len(redirectTo) > 0 && !util.IsExternalURL(redirectTo) {
@@ -574,9 +574,9 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
}

if obeyRedirect {
ctx.Redirect(setting.AppSubURL + "/")
ctx.Redirect(setting.AppSubURL + "/dashboard")
}
return setting.AppSubURL + "/"
return setting.AppSubURL + "/dashboard"
}

// SignInOAuth handles the OAuth2 login buttons


+ 2
- 2
templates/base/head.tmpl View File

@@ -180,8 +180,8 @@
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?7c4ef0a24be6109ab22e63c832ab21cf";
var s = document.getElementsByTagName("script")[0];
hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>


+ 2
- 2
templates/base/head_home.tmpl View File

@@ -181,8 +181,8 @@
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?7c4ef0a24be6109ab22e63c832ab21cf";
var s = document.getElementsByTagName("script")[0];
hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>


+ 8
- 0
templates/base/head_navbar.tmpl View File

@@ -7,6 +7,14 @@
<i class="sidebar icon"></i>
</div>
</div>
<div style="width:1px;background:#606266;height:80%;margin:auto 0.5rem"></div>
<div class="item brand" style="margin-left: 0.9rem;">
<a href="/">
<img class="ui mini image" style="height: 1.3rem;" src="{{StaticUrlPrefix}}/img/git-logo.svg">
</a>
</div>


{{if .IsSigned}}
<a class="item {{if .PageIsDashboard}}active{{end}}" href="/dashboard">{{.i18n.Tr "index"}}</a>


+ 6
- 5
templates/org/home.tmpl View File

@@ -38,11 +38,12 @@
<div class="ui sixteen wide mobile six wide tablet five wide computer column">
<h4 class="ui top attached header">
<strong>{{.i18n.Tr "org.people"}}</strong>
{{if .IsOrganizationMember}}
<div class="ui right">
<a class="text grey" href="{{.OrgLink}}/members">{{.Org.NumMembers}} {{svg "octicon-chevron-right" 16}}</a>
</div>
{{end}}
<div class="ui right">
<a class="text grey" href="{{.OrgLink}}/members">{{.Org.NumMembers}} {{svg "octicon-chevron-right" 16}}</a>
</div>
<!-- {{if .IsOrganizationMember}} -->
<!-- {{end}} -->
</h4>
<div class="ui attached segment members">
{{$isMember := .IsOrganizationMember}}


+ 6
- 6
templates/org/navber.tmpl View File

@@ -3,10 +3,10 @@
<a class="{{if $.PageIsOrgHome}}active{{end}} item" href="{{.HomeLink}}">
{{svg "octicon-home" 16}}&nbsp;{{$.i18n.Tr "org.home"}}
</a>
<a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members">
{{svg "octicon-organization" 16}}&nbsp;{{$.i18n.Tr "org.people"}}
</a>
{{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}}
<a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members">
{{svg "octicon-organization" 16}}&nbsp;{{$.i18n.Tr "org.people"}}
</a>
<a class="{{if $.PageIsOrgTeams}}active{{end}} item" href="{{$.OrgLink}}/teams">
{{svg "octicon-jersey" 16}}&nbsp;{{$.i18n.Tr "org.teams"}}
</a>
@@ -23,10 +23,10 @@
{{svg "octicon-home" 16}}&nbsp;{{$.i18n.Tr "org.home"}}
</a>
{{end}}
<a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members">
{{svg "octicon-organization" 16}}&nbsp;{{$.i18n.Tr "org.people"}}
</a>
{{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}}
<a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members">
{{svg "octicon-organization" 16}}&nbsp;{{$.i18n.Tr "org.people"}}
</a>
<a class="{{if $.PageIsOrgTeams}}active{{end}} item" href="{{$.OrgLink}}/teams">
{{svg "octicon-jersey" 16}}&nbsp;{{$.i18n.Tr "org.teams"}}
</a>


+ 13
- 3
templates/repo/activity.tmpl View File

@@ -2,8 +2,18 @@
<div class="repository commits">
{{template "repo/header" .}}
<div class="ui container">
<h2 class="ui header">{{.DateFrom}} - {{.DateUntil}}
<div class="ui right">
<div class="ui three column stackable grid" style="align-items: center;">
<div class="column">
<div class="ui breadcrumb">
<a class="section" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}">{{.i18n.Tr "repo.code"}}</a>
<div class="divider"> / </div>
<div class="active section" href="{{.RepoLink}}/activity">{{.i18n.Tr "repo.activity"}}</div>
</div>
</div>
<div class="column center aligned" style="font-weight: 800;">
{{.DateFrom}} - {{.DateUntil}}
</div>
<div class="column right aligned">
<!-- Period -->
<div class="ui floating dropdown jump filter">
<div class="ui basic compact button">
@@ -23,7 +33,7 @@
</div>
</div>
</div>
</h2>
</div>
<div class="ui divider"></div>

{{if (or (.Permission.CanRead $.UnitTypeIssues) (.Permission.CanRead $.UnitTypePullRequests))}}


+ 31
- 28
templates/repo/header.tmpl View File

@@ -92,16 +92,27 @@
{{if not .Repository.IsBeingCreated}}
<div class="ui tabular stackable menu navbar">
{{if .Permission.CanRead $.UnitTypeCode}}
<a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}">
{{svg "octicon-code" 16}} {{.i18n.Tr "repo.code"}}
<div class="dropdown-menu">
<a class="{{if or .PageIsViewCode .PageIsReleaseList .PageIsWiki .PageIsActivity}}active{{end}} item" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}">
<span>{{svg "octicon-code" 16}} {{.i18n.Tr "repo.code"}} <i class="dropdown icon"></i></span>
</a>
{{end}}
<div class="dropdown-content">
<a style="border: none;" class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases">
{{svg "octicon-tag" 16}} {{.i18n.Tr "repo.releases"}} <span class="ui {{if not .NumReleases}}gray{{else}}blue{{end}} small label">{{.NumReleases}}</span>
</a>
<a style="border: none;" class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki" {{if (.Permission.CanRead $.UnitTypeExternalWiki)}} target="_blank" rel="noopener noreferrer" {{end}}>
{{svg "octicon-book" 16}} {{.i18n.Tr "repo.wiki"}}
</a>
<a style="border: none;" class="{{if .PageIsActivity}}active{{end}} item" href="{{.RepoLink}}/activity">
{{svg "octicon-pulse" 16}} {{.i18n.Tr "repo.activity"}}
</a>

{{if .Permission.CanRead $.UnitTypeDatasets}}
<a class="{{if .PageIsDataset}}active{{end}} item" href="{{.RepoLink}}/datasets?type=0">
{{svg "octicon-inbox" 16}} {{.i18n.Tr "datasets"}}
</a>
</div>
</div>
{{end}}


{{if .Permission.CanRead $.UnitTypeIssues}}
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues">
@@ -109,11 +120,11 @@
</a>
{{end}}

{{if .Permission.CanRead $.UnitTypeExternalTracker}}
<!-- {{if .Permission.CanRead $.UnitTypeExternalTracker}}
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoExternalIssuesLink}}" target="_blank" rel="noopener noreferrer">
{{svg "octicon-link-external" 16}} {{.i18n.Tr "repo.issues"}} </span>
</a>
{{end}}
{{end}} -->

{{if and .Repository.CanEnablePulls (.Permission.CanRead $.UnitTypePullRequests)}}
<a class="{{if .PageIsPullList}}active{{end}} item" href="{{.RepoLink}}/pulls">
@@ -121,35 +132,22 @@
</a>
{{end}}

{{if and (.Permission.CanRead $.UnitTypeReleases) (not .IsEmptyRepo) }}
<a class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases">
{{svg "octicon-tag" 16}} {{.i18n.Tr "repo.releases"}} <span class="ui {{if not .NumReleases}}gray{{else}}blue{{end}} small label">{{.NumReleases}}</span>
{{if .Permission.CanRead $.UnitTypeDatasets}}
<a class="{{if .PageIsDataset}}active{{end}} item" href="{{.RepoLink}}/datasets?type=0">
{{svg "octicon-inbox" 16}} {{.i18n.Tr "datasets"}}
</a>
{{end}}

{{if or (.Permission.CanRead $.UnitTypeWiki) (.Permission.CanRead $.UnitTypeExternalWiki)}}
<a class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki" {{if (.Permission.CanRead $.UnitTypeExternalWiki)}} target="_blank" rel="noopener noreferrer" {{end}}>
{{svg "octicon-book" 16}} {{.i18n.Tr "repo.wiki"}}
</a>
{{end}}

{{if and (.Permission.CanReadAny $.UnitTypePullRequests $.UnitTypeIssues $.UnitTypeReleases) (not .IsEmptyRepo)}}
<a class="{{if .PageIsActivity}}active{{end}} item" href="{{.RepoLink}}/activity">
{{svg "octicon-pulse" 16}} {{.i18n.Tr "repo.activity"}}
</a>
{{end}}

{{if .Permission.CanRead $.UnitTypeCloudBrain}}
<a class="{{if .PageIsCloudBrain}}active{{end}} item" href="{{.RepoLink}}/cloudbrain">
{{svg "octicon-server" 16}} {{.i18n.Tr "repo.cloudbrain"}}
<span>{{svg "octicon-server" 16}} {{.i18n.Tr "repo.cloudbrain"}}<i class="question circle icon link cloudbrain-question" data-content={{.i18n.Tr "repo.cloudbrain_helper"}} data-position="top center" data-variation="mini"></i></span>
</a>
{{end}}
{{if .IsSigned}}
<!-- {{if .IsSigned}}
<a class="{{if .PageIsBlockChain}}active{{end}} item " href="{{.RepoLink}}/blockchain">
{{svg "octicon-law" 16}}
{{.i18n.Tr "repo.balance"}}
</a>
{{end}}
{{end}} -->

{{template "custom/extra_tabs" .}}

@@ -243,4 +241,9 @@
window.location.href = repolink + "/datasets?type=" + checked_radio
})
})
$('.question.circle.icon').hover(function(){
$(this).popup('show')
$('.ui.popup.mini.top.center').css({"border-color":'rgba(50, 145, 248, 100)',"color":"rgba(3, 102, 214, 100)","border-radius":"5px"})
});
</script>

+ 5
- 1
templates/repo/release/list.tmpl View File

@@ -4,7 +4,11 @@
<div class="ui container">
{{template "base/alert" .}}
<h2 class="ui header">
{{.i18n.Tr "repo.release.releases"}}
<div class="ui breadcrumb">
<a class="section" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}">{{.i18n.Tr "repo.code"}}</a>
<div class="divider"> / </div>
<div class="active section" href="{{.RepoLink}}/releases">{{.i18n.Tr "repo.releases"}}</div>
</div>
{{if .CanCreateRelease}}
<div class="ui right">
<a class="ui small green button" href="{{$.RepoLink}}/releases/new">


+ 15
- 0
templates/repo/view_file.tmpl View File

@@ -34,6 +34,21 @@
</div>
{{end}}
</div>

{{if .ReadmeInList}}
<div class="file-header-right">
<div class="ui right file-actions">
{{if .Repository.CanEnableEditor}}
{{if .CanEditFile}}
<a href="{{.RepoLink}}/_edit/{{EscapePound .BranchName}}/{{EscapePound .ReadmeName}}"><span class="btn-octicon poping up" data-content="{{.EditFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-pencil" 16}}</span></a>
{{else}}
<span class="btn-octicon poping up disabled" data-content="{{.EditFileTooltip}}" data-position="bottom center" data-variation="tiny inverted">{{svg "octicon-pencil" 16}}</span>
{{end}}
{{end}}
</div>
</div>
{{end}}
{{if not .ReadmeInList}}
<div class="file-header-right">
<div class="ui right file-actions">


+ 7
- 0
templates/repo/wiki/start.tmpl View File

@@ -2,6 +2,13 @@
<div class="repository wiki start">
{{template "repo/header" .}}
<div class="ui container">
<h2 class="ui header">
<div class="ui breadcrumb">
<a class="section" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}">{{.i18n.Tr "repo.code"}}</a>
<div class="divider"> / </div>
<div class="active section" href="{{.RepoLink}}/wiki">{{.i18n.Tr "repo.wiki"}}</div>
</div>
</h2>
<div class="ui center segment">
{{svg "octicon-book" 32}}
<h2>{{.i18n.Tr "repo.wiki.welcome"}}</h2>


+ 9
- 1
templates/repo/wiki/view.tmpl View File

@@ -3,6 +3,14 @@
{{template "repo/header" .}}
{{ $title := .title}}
<div class="ui container">
<h2 class="ui header">
<div class="ui breadcrumb">
<a class="section" href="{{.RepoLink}}{{if (ne .BranchName .Repository.DefaultBranch)}}/src/{{.BranchNameSubURL | EscapePound}}{{end}}">{{.i18n.Tr "repo.code"}}</a>
<div class="divider"> / </div>
<div class="active section" href="{{.RepoLink}}/wiki">{{.i18n.Tr "repo.wiki"}}</div>
</div>
</h2>
<div class="ui divider"></div>
<div class="ui stackable grid">
<div class="ui ten wide column">
<div class="choose page">
@@ -28,7 +36,7 @@
</div>
</div>
</div>
<div class="ui six wide column">
<div class="ui six wide column right aligned">
<div class="ui action small input" id="clone-panel">
{{if not $.DisableHTTP}}
<button class="ui basic clone button" id="repo-clone-https" data-link="{{.WikiCloneLink.HTTPS}}">


+ 13
- 15
web_src/js/components/EditAboutInfo.vue View File

@@ -1,9 +1,9 @@
<template>
<div>
<h4 id="about-desc" class="ui header">简介
<!-- <a class="edit-icon" href="javascript:void(0)" @click="editClick">
<i class="gray edit outline icon"></i>
</a> -->
<h4 id="about-desc" class="ui header desc-home">简介
<a class="edit-icon" href="javascript:void(0)" @click="editClick">
<i class="gray edit outline icon" style="margin-right: 0;"></i>
</a>
</h4>
<edit-dialog-cmpt
:vmContext="vmContext"
@@ -11,8 +11,8 @@
v-model="editDataDialog"
:deleteCallback="editDataFunc"
:deleteLoading ="editDataListLoading"
deleteParam = "ruleForm"
@input="initForm"
deleteParam = "ruleForm"
@input="initForm"
>
<div slot="title">
@@ -20,7 +20,7 @@
<div slot="content">
<el-form label-position="top" :model="info" :rules="rule" ref="ruleForm">
<el-form-item label="简介" prop="desc">
<el-input v-model="info.desc" type="textarea" :autosize="{minRows:2,maxRows:6}"></el-input>
<el-input v-model="info.desc" type="textarea" placeholder="请输入内容" :autosize="{minRows:4,maxRows:6}" maxlength="255" show-word-limit></el-input>
</el-form-item>
<el-form-item label="主页" prop="index_web" >
<el-input v-model="info.index_web" placeholder="主页(eg: https://git.openi.org.cn)"></el-input>
@@ -70,7 +70,7 @@ export default {
this.info.desc = el;
},
getWeb() {
const el = $('a.link').text();
const el = $('a.link.edit-link').text();
this.info.index_web = el;
},
getRepoName() {
@@ -79,7 +79,6 @@ export default {
},
initForm(diaolog) {
if (diaolog === false) {
console.log("--watch----------")
this.getRepoName();
this.getDesc();
this.getWeb();
@@ -133,12 +132,11 @@ export default {

<style scoped>
.edit-icon{
float: right;
font-size: 16px;
display: block;
top: -2px;
color: #8c92a4;
background-color: transparent;
}
}
.desc-home{
display: flex;
justify-content: space-between;
}

</style>

+ 15
- 10
web_src/js/components/basic/editDialog.vue View File

@@ -14,8 +14,8 @@
<slot name="content"></slot>
<div slot="footer" class="dialog-footer">
<el-button @click="deleteDialog = false">{{"取消"}}</el-button>
<el-button type="primary" @click="deleteCallback.call(vmContext,deleteParam)">{{"确定"}}</el-button>
<el-button size="small" @click="deleteDialog = false">{{"取消"}}</el-button>
<el-button size="small" style="background-color: #21ba45;color: #fff;" @click="deleteCallback.call(vmContext,deleteParam)">{{"确定"}}</el-button>
</div>
</el-dialog>
</template>
@@ -80,26 +80,31 @@ export default {
.message-box__content .message-box-title{font-size:16px;padding:2px 0;color:#333;}
.message-box__content .message-box-p{font-size:16px;padding:20px 0;color:#333;}
.message-box__content .message-box-info{color:#999;padding:2px 0;}
.dialog-footer,.el-message-box__btns{text-align:center;}


/deep/ .el-dialog__body{
padding: 1rem;
}
/deep/ .el-dialog__header {
background: #0067b3;
padding: 12px 30px;
line-height: 25px;}
background: #f0f0f0;
padding: 1rem;
}
/deep/ .el-dialog__title {
font-family: PingFangSC-Regular;
font-size: 18px;
color: #fff;
font-size: 1.28571429rem;
color: rgba(0,0,0,.87);
font-weight: 200;
line-height: 25px;
height: 25px;
}
/deep/ .el-dialog__footer {
background: #eff3f9;
padding: 20px 30px;
padding: 1rem;
}
/deep/ .el-dialog{
width: 40%;
width: 30%;
}
/deep/ .el-form-item__label{
padding: 0;
}
</style>

+ 31
- 0
web_src/less/openi.less View File

@@ -244,3 +244,34 @@ footer .column{margin-bottom:0!important; padding-bottom:0!important;}
width: 100%;
}

.dropdown-menu {
position: relative;
display: inline-block;
margin-top: 4px;
}
.dropdown-menu:hover .dropdown-content {
display: block;
}
.dropdown-content{
display: none;
position: absolute;
background-color: #ffffff;
min-width: 180px;
z-index: 999;
border: 1px solid transparent;
border-color: #d4d4d5;
border-top: none;

}
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown-content a:hover {background-color: #f1f1f1}
.cloudbrain-question{
margin-left: 4px !important;
color: #3291F8;
}

Loading…
Cancel
Save