| @@ -2,7 +2,7 @@ | |||||
| <h1><img src="public/img/favicon.png" alt="logo" width="30" height="30">AiForge - 启智AI开发协作平台</h1> | <h1><img src="public/img/favicon.png" alt="logo" width="30" height="30">AiForge - 启智AI开发协作平台</h1> | ||||
| [](https://git.openi.org.cn/OpenI/aiforge/releases/latest) | |||||
| [](https://git.openi.org.cn/OpenI/aiforge/releases/latest) | |||||
| [](https://opensource.org/licenses/MIT) | [](https://opensource.org/licenses/MIT) | ||||
| @@ -1356,6 +1356,15 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) { | |||||
| return accum, nil | 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) { | func getIssueStatsChunk(opts *IssueStatsOptions, issueIDs []int64) (*IssueStats, error) { | ||||
| stats := &IssueStats{} | stats := &IssueStats{} | ||||
| @@ -2,12 +2,19 @@ package models | |||||
| import ( | import ( | ||||
| "fmt" | "fmt" | ||||
| "sort" | |||||
| "strings" | "strings" | ||||
| "time" | "time" | ||||
| "code.gitea.io/gitea/modules/git" | "code.gitea.io/gitea/modules/git" | ||||
| ) | ) | ||||
| type ContributorWithUserId struct { | |||||
| git.Contributor | |||||
| UserId int64 | |||||
| IsAdmin bool | |||||
| } | |||||
| func GetRepoKPIStats(repo *Repository) (*git.RepoKPIStats, error) { | func GetRepoKPIStats(repo *Repository) (*git.RepoKPIStats, error) { | ||||
| wikiPath := "" | wikiPath := "" | ||||
| if repo.HasWiki() { | if repo.HasWiki() { | ||||
| @@ -63,22 +70,39 @@ func getRepoKPIStats(repoPath string, wikiPath string) (*git.RepoKPIStats, error | |||||
| } | } | ||||
| if recentlyContributors != nil { | if recentlyContributors != nil { | ||||
| resentlyContributorDistinctDict := make(map[string]int, 0) | |||||
| for _, recentlyContributor := range recentlyContributors { | for _, recentlyContributor := range recentlyContributors { | ||||
| user, err := GetUserByActivateEmail(recentlyContributor.Email) | user, err := GetUserByActivateEmail(recentlyContributor.Email) | ||||
| var ok bool | |||||
| if err == nil { | 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 { | } 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++ | stats.ContributorsAdded++ | ||||
| newContributersDict[recentlyContributor.Email] = struct{}{} | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| stats.Contributors = int64(len(contributorDistinctDict)) | 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{}) { | func setKeyContributerDict(contributorDistinctDict map[string]int, email string, keyContributorsDict map[string]struct{}) { | ||||
| if contributorDistinctDict[email] >= 3 { | if contributorDistinctDict[email] >= 3 { | ||||
| _, ok := keyContributorsDict[email] | _, ok := keyContributorsDict[email] | ||||
| @@ -114,6 +114,17 @@ func (repo *Repository) isCollaborator(e Engine, userID int64) (bool, error) { | |||||
| return e.Get(&Collaboration{RepoID: repo.ID, UserID: userID}) | 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 | // IsCollaborator check if a user is a collaborator of a repository | ||||
| func (repo *Repository) IsCollaborator(userID int64) (bool, error) { | func (repo *Repository) IsCollaborator(userID int64) (bool, error) { | ||||
| return repo.isCollaborator(x, userID) | return repo.isCollaborator(x, userID) | ||||
| @@ -9,56 +9,56 @@ import ( | |||||
| // RepoStatistic statistic info of all repository | // RepoStatistic statistic info of all repository | ||||
| type RepoStatistic struct { | 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 { | func DeleteRepoStatDaily(date string) error { | ||||
| @@ -81,9 +81,60 @@ func DeleteRepoStatDaily(date string) error { | |||||
| return nil | 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) | 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 | return repoStatistics, err | ||||
| } | } | ||||
| @@ -107,6 +158,13 @@ func InsertRepoStat(repoStat *RepoStatistic) (int64, error) { | |||||
| return xStatistic.Insert(repoStat) | 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 { | 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=?" | sql := "update repo_statistic set impact=?,completeness=?,liveness=?,project_health=?,team_health=?,growth=?,radar_total=? where repo_id=? and date=?" | ||||
| @@ -544,6 +544,7 @@ var ( | |||||
| GrowthContributors float64 | GrowthContributors float64 | ||||
| GrowthCommit float64 | GrowthCommit float64 | ||||
| GrowthComments float64 | GrowthComments float64 | ||||
| RecordBeginTime string | |||||
| }{} | }{} | ||||
| ) | ) | ||||
| @@ -1324,6 +1325,7 @@ func SetRadarMapConfig() { | |||||
| RadarMap.GrowthContributors = sec.Key("growth_contributors").MustFloat64(0.2) | RadarMap.GrowthContributors = sec.Key("growth_contributors").MustFloat64(0.2) | ||||
| RadarMap.GrowthCommit = sec.Key("growth_commit").MustFloat64(0.2) | RadarMap.GrowthCommit = sec.Key("growth_commit").MustFloat64(0.2) | ||||
| RadarMap.GrowthComments = sec.Key("growth_comments").MustFloat64(0.2) | RadarMap.GrowthComments = sec.Key("growth_comments").MustFloat64(0.2) | ||||
| RadarMap.RecordBeginTime = sec.Key("record_beigin_time").MustString("2021-11-05") | |||||
| } | } | ||||
| @@ -178,6 +178,7 @@ func GetObsListObject(jobName, parentDir string) ([]FileInfo, error) { | |||||
| input := &obs.ListObjectsInput{} | input := &obs.ListObjectsInput{} | ||||
| input.Bucket = setting.Bucket | input.Bucket = setting.Bucket | ||||
| input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/") | input.Prefix = strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/") | ||||
| strPrefix := strings.Split(input.Prefix, "/") | |||||
| output, err := ObsCli.ListObjects(input) | output, err := ObsCli.ListObjects(input) | ||||
| fileInfos := make([]FileInfo, 0) | fileInfos := make([]FileInfo, 0) | ||||
| if err == nil { | if err == nil { | ||||
| @@ -186,15 +187,29 @@ func GetObsListObject(jobName, parentDir string) ([]FileInfo, error) { | |||||
| var isDir bool | var isDir bool | ||||
| var fileName,nextParentDir string | var fileName,nextParentDir string | ||||
| if strings.HasSuffix(val.Key, "/") { | if strings.HasSuffix(val.Key, "/") { | ||||
| //dirs in next level dir | |||||
| if len(str1) - len(strPrefix) > 2 { | |||||
| continue | |||||
| } | |||||
| fileName = str1[len(str1)-2] | fileName = str1[len(str1)-2] | ||||
| isDir = true | 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 | continue | ||||
| } | } | ||||
| } else { | } else { | ||||
| //files in next level dir | |||||
| if len(str1) - len(strPrefix) > 1 { | |||||
| continue | |||||
| } | |||||
| fileName = str1[len(str1)-1] | fileName = str1[len(str1)-1] | ||||
| isDir = false | isDir = false | ||||
| nextParentDir = parentDir | |||||
| } | } | ||||
| fileInfo := FileInfo{ | fileInfo := FileInfo{ | ||||
| @@ -755,6 +755,7 @@ unit_disabled = The site administrator has disabled this repository section. | |||||
| language_other = Other | language_other = Other | ||||
| datasets = Datasets | datasets = Datasets | ||||
| datasets.desc = Enable Dataset | datasets.desc = Enable Dataset | ||||
| cloudbrain_helper=Use GPU/NPU resources to open notebooks, model training tasks, etc. | |||||
| debug=Debug | debug=Debug | ||||
| stop=Stop | stop=Stop | ||||
| @@ -785,7 +786,12 @@ cloudbrain_operate = Operate | |||||
| cloudbrain_status_createtime = Status/Createtime | cloudbrain_status_createtime = Status/Createtime | ||||
| cloudbrain_status_runtime = Running Time | 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.notebook=Debug Task | ||||
| modelarts.train_job=Train Task | modelarts.train_job=Train Task | ||||
| modelarts.train_job.new_debug= New Debug Task | modelarts.train_job.new_debug= New Debug Task | ||||
| @@ -757,6 +757,7 @@ unit_disabled=站点管理员已禁用此项目单元。 | |||||
| language_other=其它 | language_other=其它 | ||||
| datasets=数据集 | datasets=数据集 | ||||
| datasets.desc=数据集功能 | datasets.desc=数据集功能 | ||||
| cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等 | |||||
| debug=调试 | debug=调试 | ||||
| stop=停止 | stop=停止 | ||||
| @@ -787,6 +788,12 @@ cloudbrain_status_createtime=状态/创建时间 | |||||
| cloudbrain_status_runtime = 运行时长 | cloudbrain_status_runtime = 运行时长 | ||||
| cloudbrain_jobname_err=只能以小写字母或数字开头且只包含小写字母、数字、_和-,不能以_结尾,最长36个字符。 | 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.notebook=调试任务 | ||||
| modelarts.train_job=训练任务 | modelarts.train_job=训练任务 | ||||
| modelarts.train_job.new_debug=新建调试任务 | modelarts.train_job.new_debug=新建调试任务 | ||||
| @@ -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> | |||||
| @@ -523,6 +523,21 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| Get(notify.GetThread). | Get(notify.GetThread). | ||||
| Patch(notify.ReadThread) | Patch(notify.ReadThread) | ||||
| }, reqToken()) | }, 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 | // Users | ||||
| m.Group("/users", func() { | m.Group("/users", func() { | ||||
| @@ -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 | |||||
| } | |||||
| @@ -146,7 +146,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { | |||||
| ctx.Data["SortType"] = "hot" | ctx.Data["SortType"] = "hot" | ||||
| orderBy = models.SearchOrderByHot | orderBy = models.SearchOrderByHot | ||||
| } | } | ||||
| orderBy = orderBy + ",id" | |||||
| //todo:support other topics | //todo:support other topics | ||||
| keyword := strings.Trim(ctx.Query("q"), " ") | keyword := strings.Trim(ctx.Query("q"), " ") | ||||
| topic := strings.Trim(ctx.Query("topic"), " ") | topic := strings.Trim(ctx.Query("topic"), " ") | ||||
| @@ -93,6 +93,7 @@ func RepoStatisticDaily(date string) { | |||||
| IsPrivate: repo.IsPrivate, | IsPrivate: repo.IsPrivate, | ||||
| NumWatches: int64(repo.NumWatches), | NumWatches: int64(repo.NumWatches), | ||||
| NumStars: int64(repo.NumStars), | NumStars: int64(repo.NumStars), | ||||
| NumForks: int64(repo.NumForks), | |||||
| NumDownloads: repo.CloneCnt, | NumDownloads: repo.CloneCnt, | ||||
| NumComments: numComments, | NumComments: numComments, | ||||
| NumVisits: int64(numVisits), | NumVisits: int64(numVisits), | ||||
| @@ -115,7 +116,7 @@ func RepoStatisticDaily(date string) { | |||||
| } | } | ||||
| dayBeforeDate := t.AddDate(0, 0, -1).Format("2006-01-02") | 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 { | if err != nil { | ||||
| log.Error("get data of day before the date failed ", err) | log.Error("get data of day before the date failed ", err) | ||||
| @@ -243,6 +243,11 @@ func renderDirectory(ctx *context.Context, treeLink string) { | |||||
| ctx.Data["ReadmeInList"] = true | ctx.Data["ReadmeInList"] = true | ||||
| ctx.Data["ReadmeExist"] = true | ctx.Data["ReadmeExist"] = true | ||||
| ctx.Data["FileIsSymlink"] = readmeFile.isSymlink | ctx.Data["FileIsSymlink"] = readmeFile.isSymlink | ||||
| ctx.Data["ReadmeName"] = readmeFile.name | |||||
| if ctx.Repo.CanEnableEditor() { | |||||
| ctx.Data["CanEditFile"] = true | |||||
| } | |||||
| dataRc, err := readmeFile.blob.DataAsync() | dataRc, err := readmeFile.blob.DataAsync() | ||||
| if err != nil { | if err != nil { | ||||
| @@ -311,7 +311,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Head("/", func() string { | m.Head("/", func() string { | ||||
| return "" | return "" | ||||
| }) | }) | ||||
| m.Get("/", routers.Dashboard) | |||||
| m.Get("/", routers.Home) | |||||
| m.Get("/dashboard", routers.Dashboard) | m.Get("/dashboard", routers.Dashboard) | ||||
| m.Group("/explore", func() { | m.Group("/explore", func() { | ||||
| m.Get("", func(ctx *context.Context) { | m.Get("", func(ctx *context.Context) { | ||||
| @@ -615,6 +615,11 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| //reqRepoBlockChainWriter := context.RequireRepoWriter(models.UnitTypeBlockChain) | //reqRepoBlockChainWriter := context.RequireRepoWriter(models.UnitTypeBlockChain) | ||||
| // ***** START: Organization ***** | // ***** START: Organization ***** | ||||
| m.Group("/org", func() { | |||||
| m.Group("/:org", func() { | |||||
| m.Get("/members", org.Members) | |||||
| }, context.OrgAssignment()) | |||||
| }) | |||||
| m.Group("/org", func() { | m.Group("/org", func() { | ||||
| m.Group("", func() { | m.Group("", func() { | ||||
| m.Get("/create", org.Create) | m.Get("/create", org.Create) | ||||
| @@ -625,7 +630,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Get("/dashboard", user.Dashboard) | m.Get("/dashboard", user.Dashboard) | ||||
| m.Get("/^:type(issues|pulls)$", user.Issues) | m.Get("/^:type(issues|pulls)$", user.Issues) | ||||
| m.Get("/milestones", reqMilestonesDashboardPageEnabled, user.Milestones) | m.Get("/milestones", reqMilestonesDashboardPageEnabled, user.Milestones) | ||||
| m.Get("/members", org.Members) | |||||
| //m.Get("/members", org.Members) | |||||
| m.Post("/members/action/:action", org.MembersAction) | m.Post("/members/action/:action", org.MembersAction) | ||||
| m.Get("/teams", org.Teams) | m.Get("/teams", org.Teams) | ||||
| @@ -544,7 +544,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR | |||||
| if err := models.UpdateUserCols(u, "language"); err != nil { | if err := models.UpdateUserCols(u, "language"); err != nil { | ||||
| log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", u.ID, u.Language)) | log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", u.ID, u.Language)) | ||||
| return setting.AppSubURL + "/" | |||||
| return setting.AppSubURL + "/dashboard" | |||||
| } | } | ||||
| } else { | } else { | ||||
| // Language setting of the user use the one previously set | // 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() | u.SetLastLogin() | ||||
| if err := models.UpdateUserCols(u, "last_login_unix"); err != nil { | if err := models.UpdateUserCols(u, "last_login_unix"); err != nil { | ||||
| ctx.ServerError("UpdateUserCols", err) | ctx.ServerError("UpdateUserCols", err) | ||||
| return setting.AppSubURL + "/" | |||||
| return setting.AppSubURL + "/dashboard" | |||||
| } | } | ||||
| if redirectTo := ctx.GetCookie("redirect_to"); len(redirectTo) > 0 && !util.IsExternalURL(redirectTo) { | 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 { | if obeyRedirect { | ||||
| ctx.Redirect(setting.AppSubURL + "/") | |||||
| ctx.Redirect(setting.AppSubURL + "/dashboard") | |||||
| } | } | ||||
| return setting.AppSubURL + "/" | |||||
| return setting.AppSubURL + "/dashboard" | |||||
| } | } | ||||
| // SignInOAuth handles the OAuth2 login buttons | // SignInOAuth handles the OAuth2 login buttons | ||||
| @@ -180,8 +180,8 @@ | |||||
| var _hmt = _hmt || []; | var _hmt = _hmt || []; | ||||
| (function() { | (function() { | ||||
| var hm = document.createElement("script"); | 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); | s.parentNode.insertBefore(hm, s); | ||||
| })(); | })(); | ||||
| </script> | </script> | ||||
| @@ -181,8 +181,8 @@ | |||||
| var _hmt = _hmt || []; | var _hmt = _hmt || []; | ||||
| (function() { | (function() { | ||||
| var hm = document.createElement("script"); | 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); | s.parentNode.insertBefore(hm, s); | ||||
| })(); | })(); | ||||
| </script> | </script> | ||||
| @@ -7,6 +7,14 @@ | |||||
| <i class="sidebar icon"></i> | <i class="sidebar icon"></i> | ||||
| </div> | </div> | ||||
| </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}} | {{if .IsSigned}} | ||||
| <a class="item {{if .PageIsDashboard}}active{{end}}" href="/dashboard">{{.i18n.Tr "index"}}</a> | <a class="item {{if .PageIsDashboard}}active{{end}}" href="/dashboard">{{.i18n.Tr "index"}}</a> | ||||
| @@ -38,11 +38,12 @@ | |||||
| <div class="ui sixteen wide mobile six wide tablet five wide computer column"> | <div class="ui sixteen wide mobile six wide tablet five wide computer column"> | ||||
| <h4 class="ui top attached header"> | <h4 class="ui top attached header"> | ||||
| <strong>{{.i18n.Tr "org.people"}}</strong> | <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> | </h4> | ||||
| <div class="ui attached segment members"> | <div class="ui attached segment members"> | ||||
| {{$isMember := .IsOrganizationMember}} | {{$isMember := .IsOrganizationMember}} | ||||
| @@ -3,10 +3,10 @@ | |||||
| <a class="{{if $.PageIsOrgHome}}active{{end}} item" href="{{.HomeLink}}"> | <a class="{{if $.PageIsOrgHome}}active{{end}} item" href="{{.HomeLink}}"> | ||||
| {{svg "octicon-home" 16}} {{$.i18n.Tr "org.home"}} | {{svg "octicon-home" 16}} {{$.i18n.Tr "org.home"}} | ||||
| </a> | </a> | ||||
| <a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members"> | |||||
| {{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} | |||||
| </a> | |||||
| {{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}} | {{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}} | ||||
| <a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members"> | |||||
| {{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} | |||||
| </a> | |||||
| <a class="{{if $.PageIsOrgTeams}}active{{end}} item" href="{{$.OrgLink}}/teams"> | <a class="{{if $.PageIsOrgTeams}}active{{end}} item" href="{{$.OrgLink}}/teams"> | ||||
| {{svg "octicon-jersey" 16}} {{$.i18n.Tr "org.teams"}} | {{svg "octicon-jersey" 16}} {{$.i18n.Tr "org.teams"}} | ||||
| </a> | </a> | ||||
| @@ -23,10 +23,10 @@ | |||||
| {{svg "octicon-home" 16}} {{$.i18n.Tr "org.home"}} | {{svg "octicon-home" 16}} {{$.i18n.Tr "org.home"}} | ||||
| </a> | </a> | ||||
| {{end}} | {{end}} | ||||
| <a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members"> | |||||
| {{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} | |||||
| </a> | |||||
| {{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}} | {{if or ($.IsOrganizationMember) ($.IsOrganizationOwner)}} | ||||
| <a class="{{if $.PageIsOrgMembers}}active{{end}} item" href="{{$.OrgLink}}/members"> | |||||
| {{svg "octicon-organization" 16}} {{$.i18n.Tr "org.people"}} | |||||
| </a> | |||||
| <a class="{{if $.PageIsOrgTeams}}active{{end}} item" href="{{$.OrgLink}}/teams"> | <a class="{{if $.PageIsOrgTeams}}active{{end}} item" href="{{$.OrgLink}}/teams"> | ||||
| {{svg "octicon-jersey" 16}} {{$.i18n.Tr "org.teams"}} | {{svg "octicon-jersey" 16}} {{$.i18n.Tr "org.teams"}} | ||||
| </a> | </a> | ||||
| @@ -2,8 +2,18 @@ | |||||
| <div class="repository commits"> | <div class="repository commits"> | ||||
| {{template "repo/header" .}} | {{template "repo/header" .}} | ||||
| <div class="ui container"> | <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 --> | <!-- Period --> | ||||
| <div class="ui floating dropdown jump filter"> | <div class="ui floating dropdown jump filter"> | ||||
| <div class="ui basic compact button"> | <div class="ui basic compact button"> | ||||
| @@ -23,7 +33,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </h2> | |||||
| </div> | |||||
| <div class="ui divider"></div> | <div class="ui divider"></div> | ||||
| {{if (or (.Permission.CanRead $.UnitTypeIssues) (.Permission.CanRead $.UnitTypePullRequests))}} | {{if (or (.Permission.CanRead $.UnitTypeIssues) (.Permission.CanRead $.UnitTypePullRequests))}} | ||||
| @@ -92,16 +92,27 @@ | |||||
| {{if not .Repository.IsBeingCreated}} | {{if not .Repository.IsBeingCreated}} | ||||
| <div class="ui tabular stackable menu navbar"> | <div class="ui tabular stackable menu navbar"> | ||||
| {{if .Permission.CanRead $.UnitTypeCode}} | {{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> | </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}} | {{end}} | ||||
| {{if .Permission.CanRead $.UnitTypeIssues}} | {{if .Permission.CanRead $.UnitTypeIssues}} | ||||
| <a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues"> | <a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues"> | ||||
| @@ -109,11 +120,11 @@ | |||||
| </a> | </a> | ||||
| {{end}} | {{end}} | ||||
| {{if .Permission.CanRead $.UnitTypeExternalTracker}} | |||||
| <!-- {{if .Permission.CanRead $.UnitTypeExternalTracker}} | |||||
| <a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoExternalIssuesLink}}" target="_blank" rel="noopener noreferrer"> | <a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoExternalIssuesLink}}" target="_blank" rel="noopener noreferrer"> | ||||
| {{svg "octicon-link-external" 16}} {{.i18n.Tr "repo.issues"}} </span> | {{svg "octicon-link-external" 16}} {{.i18n.Tr "repo.issues"}} </span> | ||||
| </a> | </a> | ||||
| {{end}} | |||||
| {{end}} --> | |||||
| {{if and .Repository.CanEnablePulls (.Permission.CanRead $.UnitTypePullRequests)}} | {{if and .Repository.CanEnablePulls (.Permission.CanRead $.UnitTypePullRequests)}} | ||||
| <a class="{{if .PageIsPullList}}active{{end}} item" href="{{.RepoLink}}/pulls"> | <a class="{{if .PageIsPullList}}active{{end}} item" href="{{.RepoLink}}/pulls"> | ||||
| @@ -121,35 +132,22 @@ | |||||
| </a> | </a> | ||||
| {{end}} | {{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> | </a> | ||||
| {{end}} | {{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}} | {{if .Permission.CanRead $.UnitTypeCloudBrain}} | ||||
| <a class="{{if .PageIsCloudBrain}}active{{end}} item" href="{{.RepoLink}}/cloudbrain"> | <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> | </a> | ||||
| {{end}} | {{end}} | ||||
| {{if .IsSigned}} | |||||
| <!-- {{if .IsSigned}} | |||||
| <a class="{{if .PageIsBlockChain}}active{{end}} item " href="{{.RepoLink}}/blockchain"> | <a class="{{if .PageIsBlockChain}}active{{end}} item " href="{{.RepoLink}}/blockchain"> | ||||
| {{svg "octicon-law" 16}} | {{svg "octicon-law" 16}} | ||||
| {{.i18n.Tr "repo.balance"}} | {{.i18n.Tr "repo.balance"}} | ||||
| </a> | </a> | ||||
| {{end}} | |||||
| {{end}} --> | |||||
| {{template "custom/extra_tabs" .}} | {{template "custom/extra_tabs" .}} | ||||
| @@ -243,4 +241,9 @@ | |||||
| window.location.href = repolink + "/datasets?type=" + checked_radio | 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> | </script> | ||||
| @@ -4,7 +4,11 @@ | |||||
| <div class="ui container"> | <div class="ui container"> | ||||
| {{template "base/alert" .}} | {{template "base/alert" .}} | ||||
| <h2 class="ui header"> | <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}} | {{if .CanCreateRelease}} | ||||
| <div class="ui right"> | <div class="ui right"> | ||||
| <a class="ui small green button" href="{{$.RepoLink}}/releases/new"> | <a class="ui small green button" href="{{$.RepoLink}}/releases/new"> | ||||
| @@ -34,6 +34,21 @@ | |||||
| </div> | </div> | ||||
| {{end}} | {{end}} | ||||
| </div> | </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}} | {{if not .ReadmeInList}} | ||||
| <div class="file-header-right"> | <div class="file-header-right"> | ||||
| <div class="ui right file-actions"> | <div class="ui right file-actions"> | ||||
| @@ -2,6 +2,13 @@ | |||||
| <div class="repository wiki start"> | <div class="repository wiki start"> | ||||
| {{template "repo/header" .}} | {{template "repo/header" .}} | ||||
| <div class="ui container"> | <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"> | <div class="ui center segment"> | ||||
| {{svg "octicon-book" 32}} | {{svg "octicon-book" 32}} | ||||
| <h2>{{.i18n.Tr "repo.wiki.welcome"}}</h2> | <h2>{{.i18n.Tr "repo.wiki.welcome"}}</h2> | ||||
| @@ -3,6 +3,14 @@ | |||||
| {{template "repo/header" .}} | {{template "repo/header" .}} | ||||
| {{ $title := .title}} | {{ $title := .title}} | ||||
| <div class="ui container"> | <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 stackable grid"> | ||||
| <div class="ui ten wide column"> | <div class="ui ten wide column"> | ||||
| <div class="choose page"> | <div class="choose page"> | ||||
| @@ -28,7 +36,7 @@ | |||||
| </div> | </div> | ||||
| </div> | </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"> | <div class="ui action small input" id="clone-panel"> | ||||
| {{if not $.DisableHTTP}} | {{if not $.DisableHTTP}} | ||||
| <button class="ui basic clone button" id="repo-clone-https" data-link="{{.WikiCloneLink.HTTPS}}"> | <button class="ui basic clone button" id="repo-clone-https" data-link="{{.WikiCloneLink.HTTPS}}"> | ||||
| @@ -1,9 +1,9 @@ | |||||
| <template> | <template> | ||||
| <div> | <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> | </h4> | ||||
| <edit-dialog-cmpt | <edit-dialog-cmpt | ||||
| :vmContext="vmContext" | :vmContext="vmContext" | ||||
| @@ -11,8 +11,8 @@ | |||||
| v-model="editDataDialog" | v-model="editDataDialog" | ||||
| :deleteCallback="editDataFunc" | :deleteCallback="editDataFunc" | ||||
| :deleteLoading ="editDataListLoading" | :deleteLoading ="editDataListLoading" | ||||
| deleteParam = "ruleForm" | |||||
| @input="initForm" | |||||
| deleteParam = "ruleForm" | |||||
| @input="initForm" | |||||
| > | > | ||||
| <div slot="title"> | <div slot="title"> | ||||
| @@ -20,7 +20,7 @@ | |||||
| <div slot="content"> | <div slot="content"> | ||||
| <el-form label-position="top" :model="info" :rules="rule" ref="ruleForm"> | <el-form label-position="top" :model="info" :rules="rule" ref="ruleForm"> | ||||
| <el-form-item label="简介" prop="desc"> | <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> | ||||
| <el-form-item label="主页" prop="index_web" > | <el-form-item label="主页" prop="index_web" > | ||||
| <el-input v-model="info.index_web" placeholder="主页(eg: https://git.openi.org.cn)"></el-input> | <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; | this.info.desc = el; | ||||
| }, | }, | ||||
| getWeb() { | getWeb() { | ||||
| const el = $('a.link').text(); | |||||
| const el = $('a.link.edit-link').text(); | |||||
| this.info.index_web = el; | this.info.index_web = el; | ||||
| }, | }, | ||||
| getRepoName() { | getRepoName() { | ||||
| @@ -79,7 +79,6 @@ export default { | |||||
| }, | }, | ||||
| initForm(diaolog) { | initForm(diaolog) { | ||||
| if (diaolog === false) { | if (diaolog === false) { | ||||
| console.log("--watch----------") | |||||
| this.getRepoName(); | this.getRepoName(); | ||||
| this.getDesc(); | this.getDesc(); | ||||
| this.getWeb(); | this.getWeb(); | ||||
| @@ -133,12 +132,11 @@ export default { | |||||
| <style scoped> | <style scoped> | ||||
| .edit-icon{ | .edit-icon{ | ||||
| float: right; | |||||
| font-size: 16px; | |||||
| display: block; | |||||
| top: -2px; | |||||
| color: #8c92a4; | color: #8c92a4; | ||||
| background-color: transparent; | |||||
| } | |||||
| } | |||||
| .desc-home{ | |||||
| display: flex; | |||||
| justify-content: space-between; | |||||
| } | |||||
| </style> | </style> | ||||
| @@ -14,8 +14,8 @@ | |||||
| <slot name="content"></slot> | <slot name="content"></slot> | ||||
| <div slot="footer" class="dialog-footer"> | <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> | </div> | ||||
| </el-dialog> | </el-dialog> | ||||
| </template> | </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-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-p{font-size:16px;padding:20px 0;color:#333;} | ||||
| .message-box__content .message-box-info{color:#999;padding:2px 0;} | .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 { | /deep/ .el-dialog__header { | ||||
| background: #0067b3; | |||||
| padding: 12px 30px; | |||||
| line-height: 25px;} | |||||
| background: #f0f0f0; | |||||
| padding: 1rem; | |||||
| } | |||||
| /deep/ .el-dialog__title { | /deep/ .el-dialog__title { | ||||
| font-family: PingFangSC-Regular; | font-family: PingFangSC-Regular; | ||||
| font-size: 18px; | |||||
| color: #fff; | |||||
| font-size: 1.28571429rem; | |||||
| color: rgba(0,0,0,.87); | |||||
| font-weight: 200; | font-weight: 200; | ||||
| line-height: 25px; | line-height: 25px; | ||||
| height: 25px; | height: 25px; | ||||
| } | } | ||||
| /deep/ .el-dialog__footer { | /deep/ .el-dialog__footer { | ||||
| background: #eff3f9; | background: #eff3f9; | ||||
| padding: 20px 30px; | |||||
| padding: 1rem; | |||||
| } | } | ||||
| /deep/ .el-dialog{ | /deep/ .el-dialog{ | ||||
| width: 40%; | |||||
| width: 30%; | |||||
| } | |||||
| /deep/ .el-form-item__label{ | |||||
| padding: 0; | |||||
| } | } | ||||
| </style> | </style> | ||||
| @@ -244,3 +244,34 @@ footer .column{margin-bottom:0!important; padding-bottom:0!important;} | |||||
| width: 100%; | 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; | |||||
| } | |||||