@@ -6,6 +6,7 @@ | |||||
package cmd | package cmd | ||||
import ( | import ( | ||||
"code.gitea.io/gitea/services/repository" | |||||
"encoding/json" | "encoding/json" | ||||
"fmt" | "fmt" | ||||
"net/http" | "net/http" | ||||
@@ -208,6 +209,21 @@ func runServ(c *cli.Context) error { | |||||
os.Setenv(models.ProtectedBranchPRID, fmt.Sprintf("%d", 0)) | os.Setenv(models.ProtectedBranchPRID, fmt.Sprintf("%d", 0)) | ||||
os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey)) | os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey)) | ||||
os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID)) | os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID)) | ||||
//set environment for pre-receive hook script | |||||
if verb == "git-receive-pack" { | |||||
os.Setenv(models.EnvRepoMaxFileSize, fmt.Sprint(setting.Repository.Upload.FileMaxSize)) | |||||
os.Setenv(models.EnvRepoMaxSize, fmt.Sprint(setting.Repository.RepoMaxSize)) | |||||
os.Setenv(models.EnvPushSizeCheckFlag, fmt.Sprint(setting.Repository.Upload.ShellFlag)) | |||||
if setting.Repository.Upload.ShellFlag == repository.SHELL_FLAG_ON { | |||||
env, _ := private.GetHookConfig(username, reponame) | |||||
if env != nil && len(env) > 0 { | |||||
repoSize := env[models.EnvRepoSize] | |||||
if repoSize != "" { | |||||
os.Setenv(models.EnvRepoSize, repoSize) | |||||
} | |||||
} | |||||
} | |||||
} | |||||
//LFS token authentication | //LFS token authentication | ||||
if verb == lfsAuthenticateVerb { | if verb == lfsAuthenticateVerb { | ||||
@@ -523,17 +523,21 @@ DROP TRIGGER IF EXISTS es_udpate_repository_lang on public.language_stat; | |||||
CREATE OR REPLACE FUNCTION public.udpate_repository_lang() RETURNS trigger AS | CREATE OR REPLACE FUNCTION public.udpate_repository_lang() RETURNS trigger AS | ||||
$def$ | $def$ | ||||
DECLARE | |||||
privateValue bigint; | |||||
BEGIN | BEGIN | ||||
if (TG_OP = 'UPDATE') then | if (TG_OP = 'UPDATE') then | ||||
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id; | |||||
select into privateValue updated_unix from public.repository where id=NEW.repo_id; | |||||
update public.repository_es SET updated_unix=privateValue,lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id; | |||||
elsif (TG_OP = 'INSERT') then | elsif (TG_OP = 'INSERT') then | ||||
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id; | |||||
select into privateValue updated_unix from public.repository where id=NEW.repo_id; | |||||
update public.repository_es SET updated_unix=privateValue,lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=NEW.repo_id) where id=NEW.repo_id; | |||||
elsif (TG_OP = 'DELETE') then | elsif (TG_OP = 'DELETE') then | ||||
if exists(select 1 from public.repository where id=OLD.repo_id) then | if exists(select 1 from public.repository where id=OLD.repo_id) then | ||||
update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=OLD.repo_id) where id=OLD.repo_id; | update public.repository_es SET lang=(select array_to_string(array_agg(language order by percentage desc),',') from public.language_stat where repo_id=OLD.repo_id) where id=OLD.repo_id; | ||||
end if; | end if; | ||||
end if; | end if; | ||||
return null; | |||||
return NEW; | |||||
END; | END; | ||||
$def$ | $def$ | ||||
LANGUAGE plpgsql; | LANGUAGE plpgsql; | ||||
@@ -1554,6 +1554,11 @@ func GetAllMirrorRepositoriesCount() (int64, error) { | |||||
return x.Where("is_mirror = ?", true).Count(repo) | return x.Where("is_mirror = ?", true).Count(repo) | ||||
} | } | ||||
func GetAllOrgRepositoriesCount() (int64, error) { | |||||
repo := new(Repository) | |||||
return x.Table("repository").Join("INNER", []string{"\"user\"", "u"}, "repository.owner_id = u.id and u.type=1").Count(repo) | |||||
} | |||||
func GetAllForkRepositoriesCount() (int64, error) { | func GetAllForkRepositoriesCount() (int64, error) { | ||||
repo := new(Repository) | repo := new(Repository) | ||||
return x.Where("is_fork = ?", true).Count(repo) | return x.Where("is_fork = ?", true).Count(repo) | ||||
@@ -2,6 +2,8 @@ package models | |||||
import ( | import ( | ||||
"fmt" | "fmt" | ||||
"strconv" | |||||
"time" | |||||
"code.gitea.io/gitea/modules/timeutil" | "code.gitea.io/gitea/modules/timeutil" | ||||
) | ) | ||||
@@ -45,6 +47,7 @@ type SummaryStatistic struct { | |||||
NumRepoFork int64 `xorm:"NOT NULL DEFAULT 0"` | NumRepoFork int64 `xorm:"NOT NULL DEFAULT 0"` | ||||
NumRepoMirror int64 `xorm:"NOT NULL DEFAULT 0"` | NumRepoMirror int64 `xorm:"NOT NULL DEFAULT 0"` | ||||
NumRepoSelf int64 `xorm:"NOT NULL DEFAULT 0"` | NumRepoSelf int64 `xorm:"NOT NULL DEFAULT 0"` | ||||
NumRepoOrg int64 `xorm:"NOT NULL DEFAULT 0"` | |||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | ||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | ||||
} | } | ||||
@@ -69,6 +72,51 @@ func DeleteSummaryStatisticDaily(date string) error { | |||||
return nil | return nil | ||||
} | } | ||||
func GetLatest2SummaryStatistic() ([]*SummaryStatistic, error) { | |||||
summaryStatistics := make([]*SummaryStatistic, 0) | |||||
err := xStatistic.Desc("created_unix").Limit(2).Find(&summaryStatistics) | |||||
return summaryStatistics, err | |||||
} | |||||
func GetSummaryStatisticByTimeCount(beginTime time.Time, endTime time.Time) (int64, error) { | |||||
summaryStatistics := new(SummaryStatistic) | |||||
total, err := xStatistic.Asc("created_unix").Where("created_unix>=" + strconv.FormatInt(beginTime.Unix(), 10) + " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10)).Count(summaryStatistics) | |||||
return total, err | |||||
} | |||||
func GetSummaryStatisticByDateCount(dates []string) (int64, error) { | |||||
summaryStatistics := new(SummaryStatistic) | |||||
total, err := xStatistic.Asc("created_unix").In("date", dates).Count(summaryStatistics) | |||||
return total, err | |||||
} | |||||
func GetAllSummaryStatisticByTime(beginTime time.Time, endTime time.Time) ([]*SummaryStatistic, error) { | |||||
summaryStatistics := make([]*SummaryStatistic, 0) | |||||
err := xStatistic.Asc("created_unix").Where("created_unix>=" + strconv.FormatInt(beginTime.Unix(), 10) + " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10)).Find(&summaryStatistics) | |||||
return summaryStatistics, err | |||||
} | |||||
func GetSummaryStatisticByTime(beginTime time.Time, endTime time.Time, page int, pageSize int) ([]*SummaryStatistic, error) { | |||||
summaryStatistics := make([]*SummaryStatistic, 0) | |||||
err := xStatistic.Asc("created_unix").Limit(pageSize+1, (page-1)*pageSize).Where("created_unix>=" + strconv.FormatInt(beginTime.Unix(), 10) + " and created_unix<" + strconv.FormatInt(endTime.Unix(), 10)).Find(&summaryStatistics) | |||||
return summaryStatistics, err | |||||
} | |||||
func GetAllSummaryStatisticByDates(dates []string) ([]*SummaryStatistic, error) { | |||||
summaryStatistics := make([]*SummaryStatistic, 0) | |||||
err := xStatistic.Asc("created_unix").In("date", dates).Find(&summaryStatistics) | |||||
return summaryStatistics, err | |||||
} | |||||
func GetSummaryStatisticByDates(dates []string, page int, pageSize int) ([]*SummaryStatistic, error) { | |||||
summaryStatistics := make([]*SummaryStatistic, 0) | |||||
err := xStatistic.Asc("created_unix").In("date", dates).Limit(pageSize+1, (page-1)*pageSize).Find(&summaryStatistics) | |||||
return summaryStatistics, err | |||||
} | |||||
func InsertSummaryStatistic(summaryStatistic *SummaryStatistic) (int64, error) { | func InsertSummaryStatistic(summaryStatistic *SummaryStatistic) (int64, error) { | ||||
return xStatistic.Insert(summaryStatistic) | return xStatistic.Insert(summaryStatistic) | ||||
} | } |
@@ -4,6 +4,7 @@ import ( | |||||
"fmt" | "fmt" | ||||
"sort" | "sort" | ||||
"strconv" | "strconv" | ||||
"strings" | |||||
"time" | "time" | ||||
"code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
@@ -227,7 +228,27 @@ func getLastCountDate() int64 { | |||||
return pageStartTime.Unix() | return pageStartTime.Unix() | ||||
} | } | ||||
func QueryMetrics(start int64, end int64) ([]*UserMetrics, int64) { | |||||
func QueryMetricsPage(start int64, end int64, page int, pageSize int) ([]*UserMetrics, int64) { | |||||
statictisSess := xStatistic.NewSession() | |||||
defer statictisSess.Close() | |||||
cond := "count_date >" + fmt.Sprint(start) + " and count_date<" + fmt.Sprint(end) | |||||
allCount, err := statictisSess.Where(cond).Count(new(UserMetrics)) | |||||
if err != nil { | |||||
log.Info("query error." + err.Error()) | |||||
return nil, 0 | |||||
} | |||||
userMetricsList := make([]*UserMetrics, 0) | |||||
//.Limit(pageSize, page*pageSize) | |||||
if err := statictisSess.Table(new(UserMetrics)).Where(cond).OrderBy("count_date desc"). | |||||
Find(&userMetricsList); err != nil { | |||||
return nil, 0 | |||||
} | |||||
postDeal(userMetricsList) | |||||
return userMetricsList, allCount | |||||
} | |||||
func QueryMetrics(start int64, end int64) ([]*UserMetrics, int) { | |||||
statictisSess := xStatistic.NewSession() | statictisSess := xStatistic.NewSession() | ||||
defer statictisSess.Close() | defer statictisSess.Close() | ||||
userMetricsList := make([]*UserMetrics, 0) | userMetricsList := make([]*UserMetrics, 0) | ||||
@@ -235,7 +256,76 @@ func QueryMetrics(start int64, end int64) ([]*UserMetrics, int64) { | |||||
Find(&userMetricsList); err != nil { | Find(&userMetricsList); err != nil { | ||||
return nil, 0 | return nil, 0 | ||||
} | } | ||||
return userMetricsList, int64(len(userMetricsList)) | |||||
postDeal(userMetricsList) | |||||
return userMetricsList, len(userMetricsList) | |||||
} | |||||
func postDeal(userMetricsList []*UserMetrics) { | |||||
for _, userMetrics := range userMetricsList { | |||||
userMetrics.DisplayDate = userMetrics.DataDate | |||||
userMetrics.TotalRegistUser = userMetrics.ActivateRegistUser + userMetrics.NotActivateRegistUser | |||||
userMetrics.TotalNotActivateRegistUser = userMetrics.TotalUser - userMetrics.TotalActivateRegistUser | |||||
} | |||||
} | |||||
func QueryMetricsForAll() []*UserMetrics { | |||||
statictisSess := xStatistic.NewSession() | |||||
defer statictisSess.Close() | |||||
userMetricsList := make([]*UserMetrics, 0) | |||||
if err := statictisSess.Table(new(UserMetrics)).OrderBy("count_date desc"). | |||||
Find(&userMetricsList); err != nil { | |||||
return nil | |||||
} | |||||
return makeResultForMonth(userMetricsList, len(userMetricsList)) | |||||
} | |||||
func QueryMetricsForYear() []*UserMetrics { | |||||
currentTimeNow := time.Now() | |||||
currentYearEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()) | |||||
currentYearStartTime := time.Date(currentTimeNow.Year(), 1, 1, 0, 0, 0, 0, currentTimeNow.Location()) | |||||
allUserInfo, count := QueryMetrics(currentYearStartTime.Unix(), currentYearEndTime.Unix()) | |||||
return makeResultForMonth(allUserInfo, count) | |||||
} | |||||
func makeResultForMonth(allUserInfo []*UserMetrics, count int) []*UserMetrics { | |||||
monthMap := make(map[string]*UserMetrics) | |||||
if count > 0 { | |||||
for _, userMetrics := range allUserInfo { | |||||
dateTime := time.Unix(userMetrics.CountDate, 0) | |||||
month := fmt.Sprint(dateTime.Year()) + "-" + fmt.Sprint(int(dateTime.Month())) | |||||
if _, ok := monthMap[month]; !ok { | |||||
monthUserMetrics := &UserMetrics{ | |||||
DisplayDate: month, | |||||
ActivateRegistUser: userMetrics.ActivateRegistUser, | |||||
NotActivateRegistUser: userMetrics.NotActivateRegistUser, | |||||
TotalUser: userMetrics.TotalUser, | |||||
TotalNotActivateRegistUser: userMetrics.TotalUser - userMetrics.TotalActivateRegistUser, | |||||
TotalActivateRegistUser: userMetrics.TotalActivateRegistUser, | |||||
TotalHasActivityUser: userMetrics.TotalHasActivityUser, | |||||
HasActivityUser: userMetrics.HasActivityUser, | |||||
DaysForMonth: 1, | |||||
TotalRegistUser: userMetrics.ActivateRegistUser + userMetrics.NotActivateRegistUser, | |||||
} | |||||
monthMap[month] = monthUserMetrics | |||||
} else { | |||||
value := monthMap[month] | |||||
value.ActivateRegistUser += userMetrics.ActivateRegistUser | |||||
value.NotActivateRegistUser += userMetrics.NotActivateRegistUser | |||||
value.HasActivityUser += userMetrics.HasActivityUser | |||||
value.TotalRegistUser += userMetrics.TotalRegistUser | |||||
value.DaysForMonth += 1 | |||||
} | |||||
} | |||||
} | |||||
result := make([]*UserMetrics, 0) | |||||
for _, value := range monthMap { | |||||
result = append(result, value) | |||||
} | |||||
sort.Slice(result, func(i, j int) bool { | |||||
return strings.Compare(result[i].DisplayDate, result[j].DisplayDate) > 0 | |||||
}) | |||||
return result | |||||
} | } | ||||
func QueryRankList(key string, tableName string, limit int) ([]*UserBusinessAnalysisAll, int64) { | func QueryRankList(key string, tableName string, limit int) ([]*UserBusinessAnalysisAll, int64) { | ||||
@@ -540,6 +630,7 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||||
if minUserIndex > dateRecordAll.UserIndexPrimitive { | if minUserIndex > dateRecordAll.UserIndexPrimitive { | ||||
minUserIndex = dateRecordAll.UserIndexPrimitive | minUserIndex = dateRecordAll.UserIndexPrimitive | ||||
} | } | ||||
dateRecordBatch = append(dateRecordBatch, dateRecordAll) | dateRecordBatch = append(dateRecordBatch, dateRecordAll) | ||||
if len(dateRecordBatch) >= BATCH_INSERT_SIZE { | if len(dateRecordBatch) >= BATCH_INSERT_SIZE { | ||||
insertTable(dateRecordBatch, tableName, statictisSess) | insertTable(dateRecordBatch, tableName, statictisSess) | ||||
@@ -695,7 +786,7 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||||
log.Info("query user error. return.") | log.Info("query user error. return.") | ||||
return err | return err | ||||
} | } | ||||
userNewAddActivity := make(map[int64]map[int64]int64) | |||||
ParaWeight := getParaWeight() | ParaWeight := getParaWeight() | ||||
userMetrics := make(map[string]int) | userMetrics := make(map[string]int) | ||||
var indexTotal int64 | var indexTotal int64 | ||||
@@ -767,6 +858,9 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||||
dateRecord.UserIndexPrimitive = getUserIndex(dateRecord, ParaWeight) | dateRecord.UserIndexPrimitive = getUserIndex(dateRecord, ParaWeight) | ||||
setUserMetrics(userMetrics, userRecord, start_unix, end_unix, dateRecord) | setUserMetrics(userMetrics, userRecord, start_unix, end_unix, dateRecord) | ||||
if getUserActivate(dateRecord) > 0 { | |||||
addUserToMap(userNewAddActivity, userRecord.CreatedUnix, dateRecord.ID) | |||||
} | |||||
_, err = statictisSess.Insert(&dateRecord) | _, err = statictisSess.Insert(&dateRecord) | ||||
if err != nil { | if err != nil { | ||||
log.Info("insert daterecord failed." + err.Error()) | log.Info("insert daterecord failed." + err.Error()) | ||||
@@ -785,18 +879,71 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, | |||||
//insert userMetrics table | //insert userMetrics table | ||||
var useMetrics UserMetrics | var useMetrics UserMetrics | ||||
useMetrics.CountDate = CountDate.Unix() | useMetrics.CountDate = CountDate.Unix() | ||||
useMetrics.DataDate = DataDate | |||||
statictisSess.Delete(&useMetrics) | statictisSess.Delete(&useMetrics) | ||||
useMetrics.ActivateRegistUser = getMapKeyStringValue("ActivateRegistUser", userMetrics) | useMetrics.ActivateRegistUser = getMapKeyStringValue("ActivateRegistUser", userMetrics) | ||||
useMetrics.HasActivityUser = getMapKeyStringValue("HasActivityUser", userMetrics) | useMetrics.HasActivityUser = getMapKeyStringValue("HasActivityUser", userMetrics) | ||||
useMetrics.RegistActivityUser = 0 | |||||
useMetrics.NotActivateRegistUser = getMapKeyStringValue("NotActivateRegistUser", userMetrics) | useMetrics.NotActivateRegistUser = getMapKeyStringValue("NotActivateRegistUser", userMetrics) | ||||
useMetrics.TotalActivateRegistUser = getMapKeyStringValue("TotalActivateRegistUser", userMetrics) | useMetrics.TotalActivateRegistUser = getMapKeyStringValue("TotalActivateRegistUser", userMetrics) | ||||
useMetrics.TotalHasActivityUser = getMapKeyStringValue("TotalHasActivityUser", userMetrics) | useMetrics.TotalHasActivityUser = getMapKeyStringValue("TotalHasActivityUser", userMetrics) | ||||
statictisSess.Insert(&useMetrics) | |||||
count, err = sess.Where("type=0").Count(new(User)) | |||||
if err != nil { | |||||
log.Info("query user error. return.") | |||||
} | |||||
useMetrics.TotalUser = int(count) | |||||
if useMetrics.ActivateRegistUser+useMetrics.NotActivateRegistUser == 0 { | |||||
useMetrics.ActivateIndex = 0 | |||||
} else { | |||||
useMetrics.ActivateIndex = float64(useMetrics.ActivateRegistUser) / float64(useMetrics.ActivateRegistUser+useMetrics.NotActivateRegistUser) | |||||
} | |||||
statictisSess.Insert(&useMetrics) | |||||
//update new user activity | |||||
updateNewUserAcitivity(userNewAddActivity, statictisSess) | |||||
return nil | return nil | ||||
} | } | ||||
func updateNewUserAcitivity(currentUserActivity map[int64]map[int64]int64, statictisSess *xorm.Session) { | |||||
for key, value := range currentUserActivity { | |||||
useMetrics := &UserMetrics{CountDate: key} | |||||
has, err := statictisSess.Get(useMetrics) | |||||
if err == nil && has { | |||||
userIdArrays := strings.Split(useMetrics.HasActivityUserJson, ",") | |||||
for _, userIdStr := range userIdArrays { | |||||
userIdInt, err := strconv.ParseInt(userIdStr, 10, 64) | |||||
if err == nil { | |||||
value[userIdInt] = userIdInt | |||||
} | |||||
} | |||||
userIdArray := "" | |||||
for _, tmpValue := range value { | |||||
userIdArray += fmt.Sprint(tmpValue) + "," | |||||
} | |||||
useMetrics.HasActivityUser = len(value) | |||||
if len(userIdArray) > 0 { | |||||
useMetrics.HasActivityUserJson = userIdArray[0 : len(userIdArray)-1] | |||||
} | |||||
updateSql := "update public.user_metrics set has_activity_user_json=" + useMetrics.HasActivityUserJson + ",regist_activity_user=" + fmt.Sprint(useMetrics.HasActivityUser) + " where count_date=" + fmt.Sprint(key) | |||||
statictisSess.Exec(updateSql) | |||||
} | |||||
} | |||||
} | |||||
func addUserToMap(currentUserActivity map[int64]map[int64]int64, registDate timeutil.TimeStamp, userId int64) { | |||||
CountDateTime := time.Date(registDate.Year(), registDate.AsTime().Month(), registDate.AsTime().Day(), 0, 1, 0, 0, registDate.AsTime().Location()) | |||||
CountDate := CountDateTime.Unix() | |||||
if _, ok := currentUserActivity[CountDate]; !ok { | |||||
userIdMap := make(map[int64]int64, 0) | |||||
userIdMap[userId] = userId | |||||
currentUserActivity[CountDate] = userIdMap | |||||
} else { | |||||
currentUserActivity[CountDate][userId] = userId | |||||
} | |||||
} | |||||
func setUserMetrics(userMetrics map[string]int, user *User, start_time int64, end_time int64, dateRecord UserBusinessAnalysis) { | func setUserMetrics(userMetrics map[string]int, user *User, start_time int64, end_time int64, dateRecord UserBusinessAnalysis) { | ||||
//ActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` | //ActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` | ||||
//NotActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` | //NotActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` | ||||
@@ -400,10 +400,19 @@ type UserAnalysisPara struct { | |||||
} | } | ||||
type UserMetrics struct { | type UserMetrics struct { | ||||
CountDate int64 `xorm:"pk"` | |||||
ActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` | |||||
NotActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` | |||||
HasActivityUser int `xorm:"NOT NULL DEFAULT 0"` | |||||
TotalActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` | |||||
TotalHasActivityUser int `xorm:"NOT NULL DEFAULT 0"` | |||||
CountDate int64 `xorm:"pk"` | |||||
ActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` | |||||
NotActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` | |||||
ActivateIndex float64 `xorm:"NOT NULL DEFAULT 0"` | |||||
RegistActivityUser int `xorm:"NOT NULL DEFAULT 0"` | |||||
HasActivityUser int `xorm:"NOT NULL DEFAULT 0"` | |||||
TotalUser int `xorm:"NOT NULL DEFAULT 0"` | |||||
TotalRegistUser int `xorm:"-"` | |||||
TotalActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` | |||||
TotalNotActivateRegistUser int `xorm:"-"` | |||||
TotalHasActivityUser int `xorm:"NOT NULL DEFAULT 0"` | |||||
DisplayDate string `xorm:"-"` | |||||
DataDate string `xorm:"NULL"` | |||||
DaysForMonth int `xorm:"NOT NULL DEFAULT 0"` | |||||
HasActivityUserJson string `xorm:"text NULL"` | |||||
} | } |
@@ -740,3 +740,9 @@ type CreateCourseForm struct { | |||||
func (f *CreateCourseForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | func (f *CreateCourseForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | ||||
return validate(errs, ctx.Data, f, ctx.Locale) | return validate(errs, ctx.Data, f, ctx.Locale) | ||||
} | } | ||||
// RenameRepoFileForm form for renaming repository file | |||||
type RenameRepoFileForm struct { | |||||
TreePath string `binding:"Required;MaxSize(500)"` | |||||
LastCommit string | |||||
} |
@@ -50,6 +50,11 @@ type HookPostReceiveBranchResult struct { | |||||
URL string | URL string | ||||
} | } | ||||
// HookEnvResult | |||||
type HookEnvResult struct { | |||||
Config map[string]string | |||||
} | |||||
// HookPreReceive check whether the provided commits are allowed | // HookPreReceive check whether the provided commits are allowed | ||||
func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) { | func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) { | ||||
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s", | reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s", | ||||
@@ -122,3 +127,28 @@ func SetDefaultBranch(ownerName, repoName, branch string) error { | |||||
} | } | ||||
return nil | return nil | ||||
} | } | ||||
// GetHookConfig get hook config to set environment for hook script | |||||
func GetHookConfig(ownerName, repoName string) (map[string]string, string) { | |||||
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/env/%s/%s", | |||||
url.PathEscape(ownerName), | |||||
url.PathEscape(repoName), | |||||
) | |||||
req := newInternalRequest(reqURL, "GET") | |||||
req = req.Header("Content-Type", "application/json") | |||||
req.SetTimeout(60*time.Second, time.Duration(60)*time.Second) | |||||
resp, err := req.Response() | |||||
if err != nil { | |||||
return nil, fmt.Sprintf("Unable to contact gitea: %v", err.Error()) | |||||
} | |||||
defer resp.Body.Close() | |||||
if resp.StatusCode != http.StatusOK { | |||||
return nil, decodeJSONError(resp).Err | |||||
} | |||||
res := &HookEnvResult{} | |||||
_ = json.NewDecoder(resp.Body).Decode(res) | |||||
return res.Config, "" | |||||
} |
@@ -109,6 +109,34 @@ func (t *TemporaryUploadRepository) LsFiles(filenames ...string) ([]string, erro | |||||
return filelist, nil | return filelist, nil | ||||
} | } | ||||
// LsFilesStage list all files with stage format in index for the given paths | |||||
// if the given path is directory ,then return all files under it | |||||
// if the given path is file ,then return the file | |||||
func (t *TemporaryUploadRepository) LsFilesStage(paths ...string) ([]string, error) { | |||||
stdOut := new(bytes.Buffer) | |||||
stdErr := new(bytes.Buffer) | |||||
cmdArgs := []string{"ls-files", "-z", "-s", "--"} | |||||
for _, arg := range paths { | |||||
if arg != "" { | |||||
cmdArgs = append(cmdArgs, arg) | |||||
} | |||||
} | |||||
if err := git.NewCommand(cmdArgs...).RunInDirPipeline(t.basePath, stdOut, stdErr); err != nil { | |||||
log.Error("Unable to run git ls-files for temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String()) | |||||
err = fmt.Errorf("Unable to run git ls-files for temporary repo of: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String()) | |||||
return nil, err | |||||
} | |||||
filelist := make([]string, 0) | |||||
for _, line := range bytes.Split(stdOut.Bytes(), []byte{'\000'}) { | |||||
filelist = append(filelist, string(line)) | |||||
} | |||||
return filelist, nil | |||||
} | |||||
// RemoveFilesFromIndex removes the given files from the index | // RemoveFilesFromIndex removes the given files from the index | ||||
func (t *TemporaryUploadRepository) RemoveFilesFromIndex(filenames ...string) error { | func (t *TemporaryUploadRepository) RemoveFilesFromIndex(filenames ...string) error { | ||||
stdOut := new(bytes.Buffer) | stdOut := new(bytes.Buffer) | ||||
@@ -756,3 +756,210 @@ func createCommitRepoActions(repo *models.Repository, gitRepo *git.Repository, o | |||||
} | } | ||||
return actions, nil | return actions, nil | ||||
} | } | ||||
// RenameRepoFileOptions | |||||
type RenameRepoFileOptions struct { | |||||
LastCommitID string | |||||
BranchName string | |||||
TreePath string | |||||
FromTreePath string | |||||
Message string | |||||
Author *IdentityOptions | |||||
Committer *IdentityOptions | |||||
} | |||||
// RenameRepoFile rename file in the given repository | |||||
func RenameRepoFile(repo *models.Repository, doer *models.User, opts *RenameRepoFileOptions) error { | |||||
// Branch must exist for this operation | |||||
if _, err := repo_module.GetBranch(repo, opts.BranchName); err != nil { | |||||
return err | |||||
} | |||||
//make sure user can commit to the given branch | |||||
if err := checkBranchProtection(doer, repo, opts.BranchName, opts.TreePath); err != nil { | |||||
return err | |||||
} | |||||
// Check that the path given in opts.treePath is valid (not a git path) | |||||
treePath := CleanUploadFileName(opts.TreePath) | |||||
if treePath == "" { | |||||
return models.ErrFilenameInvalid{ | |||||
Path: opts.TreePath, | |||||
} | |||||
} | |||||
// If there is a fromTreePath (we are copying it), also clean it up | |||||
fromTreePath := CleanUploadFileName(opts.FromTreePath) | |||||
if fromTreePath == "" && opts.FromTreePath != "" { | |||||
return models.ErrFilenameInvalid{ | |||||
Path: opts.FromTreePath, | |||||
} | |||||
} | |||||
author, committer := GetAuthorAndCommitterUsers(opts.Author, opts.Committer, doer) | |||||
t, err := NewTemporaryUploadRepository(repo) | |||||
if err != nil { | |||||
log.Error("%v", err) | |||||
} | |||||
defer t.Close() | |||||
if err := t.Clone(opts.BranchName); err != nil { | |||||
return err | |||||
} | |||||
if err := t.SetDefaultIndex(); err != nil { | |||||
return err | |||||
} | |||||
// Get the commit of the original branch | |||||
commit, err := t.GetBranchCommit(opts.BranchName) | |||||
if err != nil { | |||||
return err // Couldn't get a commit for the branch | |||||
} | |||||
lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID) | |||||
if err != nil { | |||||
return fmt.Errorf("DeleteRepoFile: Invalid last commit ID: %v", err) | |||||
} | |||||
opts.LastCommitID = lastCommitID.String() | |||||
if opts.LastCommitID == "" { | |||||
// When updating a file, a lastCommitID needs to be given to make sure other commits | |||||
// haven't been made. We throw an error if one wasn't provided. | |||||
return models.ErrSHAOrCommitIDNotProvided{} | |||||
} | |||||
//if fromTreePath not exist,return error | |||||
_, err = commit.GetTreeEntryByPath(fromTreePath) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
// If a lastCommitID was given and it doesn't match the commitID of the head of the branch throw | |||||
// an error. | |||||
if commit.ID.String() != opts.LastCommitID { | |||||
if changed, err := commit.FileChangedSinceCommit(fromTreePath, opts.LastCommitID); err != nil { | |||||
return err | |||||
} else if changed { | |||||
return models.ErrCommitIDDoesNotMatch{ | |||||
GivenCommitID: opts.LastCommitID, | |||||
CurrentCommitID: opts.LastCommitID, | |||||
} | |||||
} | |||||
} | |||||
//if treePath has been exist,return error | |||||
_, err = commit.GetTreeEntryByPath(treePath) | |||||
if err == nil || !git.IsErrNotExist(err) { | |||||
// Means the file has been exist in new path | |||||
return models.ErrFilePathInvalid{ | |||||
Message: fmt.Sprintf("a file exists where you’re trying to create a subdirectory [path: %s]", treePath), | |||||
Path: treePath, | |||||
Name: treePath, | |||||
Type: git.EntryModeBlob, | |||||
} | |||||
} | |||||
//move and add files to index | |||||
if err = moveAndAddFiles(fromTreePath, treePath, t); err != nil { | |||||
return err | |||||
} | |||||
// Now write the tree | |||||
treeHash, err := t.WriteTree() | |||||
if err != nil { | |||||
return err | |||||
} | |||||
// Now commit the tree | |||||
message := strings.TrimSpace(opts.Message) | |||||
commitHash, err := t.CommitTree(author, committer, treeHash, message) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
// Then push this tree to NewBranch | |||||
if err := t.Push(doer, commitHash, opts.BranchName); err != nil { | |||||
log.Error("%T %v", err, err) | |||||
return err | |||||
} | |||||
return nil | |||||
} | |||||
func checkBranchProtection(doer *models.User, repo *models.Repository, branchName, treePath string) error { | |||||
//make sure user can commit to the given branch | |||||
protectedBranch, err := repo.GetBranchProtection(branchName) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
if protectedBranch != nil { | |||||
if !protectedBranch.CanUserPush(doer.ID) { | |||||
return models.ErrUserCannotCommit{ | |||||
UserName: doer.LowerName, | |||||
} | |||||
} | |||||
if protectedBranch.RequireSignedCommits { | |||||
_, _, err := repo.SignCRUDAction(doer, repo.RepoPath(), branchName) | |||||
if err != nil { | |||||
if !models.IsErrWontSign(err) { | |||||
return err | |||||
} | |||||
return models.ErrUserCannotCommit{ | |||||
UserName: doer.LowerName, | |||||
} | |||||
} | |||||
} | |||||
patterns := protectedBranch.GetProtectedFilePatterns() | |||||
for _, pat := range patterns { | |||||
if pat.Match(strings.ToLower(treePath)) { | |||||
return models.ErrFilePathProtected{ | |||||
Path: treePath, | |||||
} | |||||
} | |||||
} | |||||
} | |||||
return nil | |||||
} | |||||
func moveAndAddFiles(oldTreePath, newTreePath string, t *TemporaryUploadRepository) error { | |||||
array, err := t.LsFilesStage(oldTreePath) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
if len(array) == 0 { | |||||
return git.ErrNotExist{RelPath: oldTreePath} | |||||
} | |||||
stdOut := new(bytes.Buffer) | |||||
stdErr := new(bytes.Buffer) | |||||
stdIn := new(bytes.Buffer) | |||||
//write all files in stage format to the stdin, | |||||
//for each file,remove old tree path and add new tree path | |||||
//see the update-index help document at https://git-scm.com/docs/git-update-index | |||||
//especially see the content of "USING --INDEX-INFO" | |||||
for _, v := range array { | |||||
if v == "" { | |||||
continue | |||||
} | |||||
//example for v(mode SHA-1 stage file) | |||||
//100755 d294c88235ac05d3dece028d8a65590f28ec46ac 0 custom/conf/app.ini | |||||
v = strings.ReplaceAll(v, "0\t", "") | |||||
tmpArray := strings.Split(v, " ") | |||||
oldPath := tmpArray[2] | |||||
newPath := newTreePath + strings.TrimPrefix(oldPath, oldTreePath) | |||||
// mode 0 means remove file | |||||
stdIn.WriteString("0 0000000000000000000000000000000000000000\t") | |||||
stdIn.WriteString(oldPath) | |||||
stdIn.WriteByte('\000') | |||||
stdIn.WriteString(tmpArray[0] + " ") | |||||
stdIn.WriteString(tmpArray[1] + "\t") | |||||
stdIn.WriteString(newPath) | |||||
stdIn.WriteByte('\000') | |||||
} | |||||
if err := git.NewCommand("update-index", "--replace", "-z", "--index-info").RunInDirFullPipeline(t.basePath, stdOut, stdErr, stdIn); err != nil { | |||||
log.Error("Unable to update-index for temporary repo: %s (%s) Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), t.basePath, err, stdOut.String(), stdErr.String()) | |||||
return fmt.Errorf("Unable to update-index for temporary repo: %s Error: %v\nstdout: %s\nstderr: %s", t.repo.FullName(), err, stdOut.String(), stdErr.String()) | |||||
} | |||||
return nil | |||||
} |
@@ -36,7 +36,7 @@ func getHookTemplates() (hookNames, hookTpls, giteaHookTpls, sizeLimitTpls []str | |||||
fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf), | fmt.Sprintf("#!/usr/bin/env %s\n\"%s\" hook --config='%s' post-receive\n", setting.ScriptType, setting.AppPath, setting.CustomConf), | ||||
} | } | ||||
sizeLimitTpls = []string{ | sizeLimitTpls = []string{ | ||||
fmt.Sprintf("#!/usr/bin/env %s\n\n\nset -o pipefail\n\nreadonly DEFAULT_FILE_MAXSIZE_MB=\"30\" \nreadonly CONFIG_NAME=\"hooks.maxfilesize\"\nreadonly NULLSHA=\"0000000000000000000000000000000000000000\"\nreadonly EXIT_SUCCESS=0\nreadonly EXIT_FAILURE=1\nreadonly DEFAULT_REPO_MAXSIZE_MB=\"1024\" \nreadonly CHECK_FLAG_ON=1\n\n\nstatus=\"$EXIT_SUCCESS\"\n\n# skip this hook entirely if shell check is not open\ncheck_flag=${PUSH_SIZE_CHECK_FLAG}\nif [[ $check_flag != $CHECK_FLAG_ON ]]; then\nexit $EXIT_SUCCESS\nfi\n\n\n#######################################\n# check the file max size limit\n#######################################\n\n# get maximum filesize (from repository-specific config)\nmaxsize_mb=\"${REPO_MAX_FILE_SIZE}\"\n\nif [[ \"$?\" != $EXIT_SUCCESS ]]; then\necho \"failed to get ${CONFIG_NAME} from config\"\nexit \"$EXIT_FAILURE\"\nfi\n\npush_size=\"0\"\n# read lines from stdin (format: \"<oldref> <newref> <refname>\\n\")\nwhile read oldref newref refname; do\n# skip branch deletions\nif [[ \"$newref\" == \"$NULLSHA\" ]]; then\n continue\nfi\n\n# find large objects\n# check all objects from $oldref (possible $NULLSHA) to $newref, but\n# skip all objects that have already been accepted (i.e. are referenced by\n# another branch or tag).\n\nif [[ \"$oldref\" == \"$NULLSHA\" ]]; then\n target=\"$newref\"\nelse\n target=\"${oldref}..${newref}\"\nfi\nmaxsize=`expr $maxsize_mb \\* 1048576` \n\n# find objects in this push_size\n# print like:\n# 08da8e2ab9ae4095bf94dd71ac913132b880b463 commit 214\n# 43e993b768ede5740e8c65de2ed6edec25053ea1 tree 185\n# 4476971d76569039df7569af1b8d03c288f6b193 blob 20167318 b0417e6593a1.zip\nfiles=\"$(git rev-list --objects \"$target\" --tags=\\* | \\\n git cat-file $'--batch-check=%%(objectname) %%(objecttype) %%(objectsize) %%(rest)')\"\n \nif [[ \"$?\" != $EXIT_SUCCESS ]]; then\n echo \"failed to check for large files in ref ${refname}\"\n continue\nfi\n\n# rewrite IFS to seperate line in $files\nIFS=$'\\n'\nfor file in $files; do\n # if don't unset IFS,temp_array=(${file}) will get error answer\n unset IFS\n temp_array=(${file})\n # add all commit files size\n push_size=`expr $push_size + ${temp_array[2]}`\n if [[ ${temp_array[2]} -gt $maxsize ]]; then\n\t if [[ \"$status\" == $EXIT_SUCCESS ]]; then\n\t\techo -e \"Error: Your push was rejected because it contains files larger than $(numfmt --to=iec \"$maxsize_mb\") Mb\"\n\t\techo \"oversize files:\"\n\t\tstatus=\"$EXIT_FAILURE\"\n\t fi\n\t echo -e \"\\033[31m- ${temp_array[3]} \\033[0m (ref: ${refname}) \"\n fi\ndone\n\nif [[ \"$status\" != $EXIT_SUCCESS ]]; then\n\texit \"$status\"\nfi\n\ndone\n\n#######################################\n# check the repo max size limit\n#######################################\nif [[ $push_size -eq \"0\" ]]; then\n\texit $EXIT_SUCCESS\nfi\n\n\nsizelimit_mb=\"${REPO_MAX_SIZE}\"\nlet sizelimit_b=$sizelimit_mb*1024*1024\n\n# repo size at here means the size of repo directory in server \nreposize_b=${REPO_CURRENT_SIZE}\n\ntotal=`expr $push_size + $reposize_b`\n\nif [ $total -gt $sizelimit_b ]; then\n echo \"Error: Your push was rejected because the repository size is large than $sizelimit_mb Mb\"\n exit $EXIT_FAILURE\nfi\n\n\nexit $EXIT_SUCCESS\n", setting.ScriptType, setting.CustomConf), | |||||
fmt.Sprintf("#!/usr/bin/env %s\n\n\nset -o pipefail\n\nreadonly DEFAULT_FILE_MAXSIZE_MB=\"30\" \nreadonly CONFIG_NAME=\"hooks.maxfilesize\"\nreadonly NULLSHA=\"0000000000000000000000000000000000000000\"\nreadonly EXIT_SUCCESS=0\nreadonly EXIT_FAILURE=1\nreadonly DEFAULT_REPO_MAXSIZE_MB=\"1024\" \nreadonly CHECK_FLAG_ON=1\n\n\nstatus=\"$EXIT_SUCCESS\"\n\n# skip this hook entirely if shell check is not open\ncheck_flag=${PUSH_SIZE_CHECK_FLAG}\nif [[ $check_flag != $CHECK_FLAG_ON ]]; then\nexit $EXIT_SUCCESS\nfi\n\n\n#######################################\n# check the file max size limit\n#######################################\n\n# get maximum filesize (from repository-specific config)\nmaxsize_mb=\"${REPO_MAX_FILE_SIZE}\"\n\nif [[ \"$?\" != $EXIT_SUCCESS ]]; then\necho \"failed to get ${CONFIG_NAME} from config\"\nexit \"$EXIT_FAILURE\"\nfi\n\npush_size=\"0\"\n# read lines from stdin (format: \"<oldref> <newref> <refname>\\n\")\nwhile read oldref newref refname; do\n# skip branch deletions\nif [[ \"$newref\" == \"$NULLSHA\" ]]; then\n continue\nfi\n\n# find large objects\n# check all objects from $oldref (possible $NULLSHA) to $newref, but\n# skip all objects that have already been accepted (i.e. are referenced by\n# another branch or tag).\n\nnew_branch_flag=0\nif [[ \"$oldref\" == \"$NULLSHA\" ]]; then\n target=\"$newref\"\n new_branch_flag=1\n echo \"You are creating a new remote branch,openI will check all files in commit history to find oversize files\"\nelse\n target=\"${oldref}..${newref}\"\nfi\nmaxsize=`expr $maxsize_mb \\* 1048576` \n\n# find objects in this push_size\n# print like:\n# 08da8e2ab9ae4095bf94dd71ac913132b880b463 commit 214\n# 43e993b768ede5740e8c65de2ed6edec25053ea1 tree 185\n# 4476971d76569039df7569af1b8d03c288f6b193 blob 20167318 b0417e6593a1.zip\nfiles=\"$(git rev-list --objects \"$target\" | \\\n git cat-file $'--batch-check=%%(objectname) %%(objecttype) %%(objectsize) %%(rest)' | \\\n awk -F ' ' -v maxbytes=\"$maxsize\" 'BEGIN {totalIn=0} {if( $3 > maxbytes && $2 == \"blob\") { totalIn+=$3; print $4} else { totalIn+=$3}} END { printf (\"totalIn=\\t%%s\",totalIn)}' )\"\n \nif [[ \"$?\" != $EXIT_SUCCESS ]]; then\n echo \"failed to check for large files in ref ${refname}\"\n continue\nfi\n\nIFS=$'\\n'\n# rewrite IFS to seperate line in $files\nfor file in $files; do\n # if don't unset IFS,temp_array=(${file}) will get error answer\n \n if [[ ${file} == totalIn=* ]]; then\n\tIFS=$'\\t'\n\ttemp_array=(${file})\n\tpush_size=${temp_array[1]}\n\tcontinue\n fi\n\tunset IFS\n if [[ \"$status\" == $EXIT_SUCCESS ]]; then\n\t\techo -e \"Error: Your push was rejected because it contains files larger than $(numfmt --to=iec \"$maxsize_mb\") Mb\"\n\t\techo \"help document -- https://git.openi.org.cn/zeizei/OpenI_Learning/src/branch/master/docs/git/repository_capacity_help.md\"\n\t\techo \"oversize files:\"\n\t\tstatus=\"$EXIT_FAILURE\"\t\n fi\n echo -e \"\\033[31m- ${file}\\033[0m \"\ndone\n\nif [[ \"$status\" != $EXIT_SUCCESS ]]; then\n\texit \"$status\"\nfi\n\ndone\n\n#######################################\n# check the repo max size limit\n#######################################\nif [[ $push_size -eq \"0\" ]]; then\n\texit $EXIT_SUCCESS\nfi\n\n# if create new branch or tag,use count-objects -v to get pack size\nif [[ $new_branch_flag -eq 1 ]]; then\n size_kb=`git count-objects -v | grep 'size-pack' | sed 's/.*\\(size-pack:\\).//'`\n size_pack_kb=`git count-objects -v | grep 'size:' | sed 's/.*\\(size:\\).//'`\n\ttotal_kb=`expr $size_kb + $size_pack_kb`\n\tlet push_size=$total_kb*1024\nfi\n\nsizelimit_mb=\"${REPO_MAX_SIZE}\"\nlet sizelimit_b=$sizelimit_mb*1024*1024\n\n# repo size at here means the size of repo directory in server \nreposize_b=${REPO_CURRENT_SIZE}\n\ntotal=`expr $push_size + $reposize_b`\n\nif [ $total -gt $sizelimit_b ]; then\n echo \"Error: Your push was rejected because the repository size is large than $sizelimit_mb Mb\"\n echo \"see the help document--https://git.openi.org.cn/zeizei/OpenI_Learning/src/branch/master/docs/git/repository_capacity_help.md\"\n exit $EXIT_FAILURE\nfi\n\n\nexit $EXIT_SUCCESS", setting.ScriptType), | |||||
fmt.Sprintf(""), | fmt.Sprintf(""), | ||||
fmt.Sprintf(""), | fmt.Sprintf(""), | ||||
} | } | ||||
@@ -5,6 +5,7 @@ | |||||
package ssh | package ssh | ||||
import ( | import ( | ||||
"code.gitea.io/gitea/services/repository" | |||||
"crypto/rand" | "crypto/rand" | ||||
"crypto/rsa" | "crypto/rsa" | ||||
"crypto/x509" | "crypto/x509" | ||||
@@ -74,7 +75,7 @@ func sessionHandler(session ssh.Session) { | |||||
models.EnvPushSizeCheckFlag+"="+fmt.Sprint(setting.Repository.Upload.ShellFlag), | models.EnvPushSizeCheckFlag+"="+fmt.Sprint(setting.Repository.Upload.ShellFlag), | ||||
) | ) | ||||
if strings.HasPrefix(command, "git-receive-pack") { | |||||
if strings.HasPrefix(command, "git-receive-pack") && setting.Repository.Upload.ShellFlag == repository.SHELL_FLAG_ON { | |||||
repo := getRepoFromCommandStr(command) | repo := getRepoFromCommandStr(command) | ||||
if repo != nil { | if repo != nil { | ||||
cmd.Env = append(cmd.Env, models.EnvRepoSize+"="+fmt.Sprint(repo.Size)) | cmd.Env = append(cmd.Env, models.EnvRepoSize+"="+fmt.Sprint(repo.Size)) | ||||
@@ -237,6 +237,8 @@ page_recommend_repo_desc=Excellent AI projects recommendation. To show your proj | |||||
page_recommend_repo_commit=Click here to submit. | page_recommend_repo_commit=Click here to submit. | ||||
page_recommend_repo_go=Click here to | page_recommend_repo_go=Click here to | ||||
page_recommend_repo_more=explore more projects. | page_recommend_repo_more=explore more projects. | ||||
page_recommend_activity=Community Activities | |||||
page_recommend_activity_desc=The community has prepared a wealth of activities, waiting for you to participate! | |||||
page_dev_env=Collaborative Development Environment | page_dev_env=Collaborative Development Environment | ||||
page_dev_env_desc=Provide a collaborative development environment for AI development, which is the biggest highlight that distinguishes the OpenI AI Collaboration Platform from other traditional Git platforms. | page_dev_env_desc=Provide a collaborative development environment for AI development, which is the biggest highlight that distinguishes the OpenI AI Collaboration Platform from other traditional Git platforms. | ||||
page_dev_env_desc_title=Unified Management of Development Elements | page_dev_env_desc_title=Unified Management of Development Elements | ||||
@@ -261,7 +263,7 @@ search_issue=Issue | |||||
search_pr=Pull Request | search_pr=Pull Request | ||||
search_user=User | search_user=User | ||||
search_org=Organization | search_org=Organization | ||||
search_finded=Find | |||||
search_finded=Find | |||||
search_related=related | search_related=related | ||||
search_maybe=maybe | search_maybe=maybe | ||||
search_ge= | search_ge= | ||||
@@ -274,7 +276,7 @@ use_plt__fuction = To use the AI collaboration functions provided by this platfo | |||||
provide_resoure = Computing resources of CPU/GPU/NPU are provided freely for various types of AI tasks. | provide_resoure = Computing resources of CPU/GPU/NPU are provided freely for various types of AI tasks. | ||||
activity = Activity | activity = Activity | ||||
no_events = There are no events related | no_events = There are no events related | ||||
or_t = or | |||||
or_t = or | |||||
[explore] | [explore] | ||||
repos = Repositories | repos = Repositories | ||||
@@ -525,6 +527,19 @@ static.public.user_business_analysis_last30_day=Last_30_day | |||||
static.public.user_business_analysis_last_month=Last_Month | static.public.user_business_analysis_last_month=Last_Month | ||||
static.public.user_business_analysis_yesterday=Yesterday | static.public.user_business_analysis_yesterday=Yesterday | ||||
static.public.user_business_analysis_all=All | static.public.user_business_analysis_all=All | ||||
metrics.sheetname=User Trend Analysis | |||||
metrics.date=Count Date | |||||
metrics.newregistuser=New registered user | |||||
metrics.newregistandactiveuser=New activated | |||||
metrics.hasactivateuser=New contributing activities | |||||
metrics.newregistnotactiveuser=New inactive | |||||
metrics.averageuser=Average new users | |||||
metrics.newuseractiveindex=Activation rate of new users | |||||
metrics.totalregistuser=Cumulative registered users | |||||
metrics.totalactiveduser=Cumulative activated users | |||||
metrics.totalhasactivityuser=Cumulative active users | |||||
[settings] | [settings] | ||||
profile = Profile | profile = Profile | ||||
account = Account | account = Account | ||||
@@ -945,6 +960,15 @@ model_manager = Model | |||||
model_noright=No right | model_noright=No right | ||||
model_rename=Duplicate model name, please modify model name. | model_rename=Duplicate model name, please modify model name. | ||||
date=Date | |||||
repo_add=Project Increment | |||||
repo_total=Project Total | |||||
repo_public_add=Public Project Increment | |||||
repo_private_add=Private Project Increment | |||||
repo_fork_add=Fork Project Increment | |||||
repo_mirror_add=Mirror Project Increment | |||||
repo_self_add=Custom Project Increment | |||||
debug=Debug | debug=Debug | ||||
debug_again=Restart | debug_again=Restart | ||||
stop=Stop | stop=Stop | ||||
@@ -1009,7 +1033,9 @@ get_repo_stat_error=Can not get the statistics of the repository. | |||||
get_repo_info_error=Can not get the information of the repository. | get_repo_info_error=Can not get the information of the repository. | ||||
generate_statistic_file_error=Failed to generate file. | generate_statistic_file_error=Failed to generate file. | ||||
repo_stat_inspect=ProjectAnalysis | repo_stat_inspect=ProjectAnalysis | ||||
repo_stat_develop=ProjectGrowthAnalysis | |||||
all=All | all=All | ||||
current_year=Current_Year | |||||
computing.all = All | computing.all = All | ||||
computing.Introduction=Introduction | computing.Introduction=Introduction | ||||
@@ -1305,6 +1331,8 @@ editor.require_signed_commit = Branch requires a signed commit | |||||
editor.repo_too_large = Repository can not exceed %d MB | editor.repo_too_large = Repository can not exceed %d MB | ||||
editor.repo_file_invalid = Upload files are invalid | editor.repo_file_invalid = Upload files are invalid | ||||
editor.upload_file_too_much = Can not upload more than %d files at a time | editor.upload_file_too_much = Can not upload more than %d files at a time | ||||
editor.rename = rename "%s" to %s" | |||||
editor.file_changed_while_renaming=The version of the file or folder to be renamed has changed. Please refresh the page and try again | |||||
commits.desc = Browse source code change history. | commits.desc = Browse source code change history. | ||||
@@ -1369,7 +1397,7 @@ issues.add_milestone_at = `added this to the <b>%s</b> milestone %s` | |||||
issues.change_milestone_at = `modified the milestone from <b>%s</b> to <b>%s</b> %s` | issues.change_milestone_at = `modified the milestone from <b>%s</b> to <b>%s</b> %s` | ||||
issues.remove_milestone_at = `removed this from the <b>%s</b> milestone %s` | issues.remove_milestone_at = `removed this from the <b>%s</b> milestone %s` | ||||
issues.add_branch_at=`added this to the <b>%s</b> branch %s` | |||||
issues.add_branch_at=`added this to the <b>%s</b> branch %s` | |||||
issues.add_tag_at =`added this to the <b>%s</b> tag %s` | issues.add_tag_at =`added this to the <b>%s</b> tag %s` | ||||
issues.change_branch_tag_at= `modified the branch/tag from <b>%s</b> to <b>%s</b> %s` | issues.change_branch_tag_at= `modified the branch/tag from <b>%s</b> to <b>%s</b> %s` | ||||
issues.remove_branch_at=`removed this from the <b>%s</b> branch %s` | issues.remove_branch_at=`removed this from the <b>%s</b> branch %s` | ||||
@@ -3022,4 +3050,4 @@ BRAINSCORE = BENCHMARK | |||||
TRAIN = TRAIN | TRAIN = TRAIN | ||||
INFERENCE = INFERENCE | INFERENCE = INFERENCE | ||||
BENCHMARK = BENCHMARK | BENCHMARK = BENCHMARK | ||||
brain_area = Brain Area | |||||
brain_area = Brain Area |
@@ -239,6 +239,8 @@ page_recommend_repo_desc=优秀的AI项目推荐;你的项目也想展示到 | |||||
page_recommend_repo_commit=点此提交 | page_recommend_repo_commit=点此提交 | ||||
page_recommend_repo_go=。进入 | page_recommend_repo_go=。进入 | ||||
page_recommend_repo_more=项目广场 | page_recommend_repo_more=项目广场 | ||||
page_recommend_activity=社区活动 | |||||
page_recommend_activity_desc=社区准备了丰富的活动,等你来参加! | |||||
page_dev_env=协同开发环境 | page_dev_env=协同开发环境 | ||||
page_dev_env_desc=启智AI协作开发平台与传统git平台最大的不同就在于提供了面向AI开发的协同开发环境 | page_dev_env_desc=启智AI协作开发平台与传统git平台最大的不同就在于提供了面向AI开发的协同开发环境 | ||||
page_dev_env_desc_title=开发要素统一管理 | page_dev_env_desc_title=开发要素统一管理 | ||||
@@ -269,7 +271,7 @@ search_maybe=约为 | |||||
search_ge=个 | search_ge=个 | ||||
wecome_AI_plt=欢迎来到启智AI协作平台! | wecome_AI_plt=欢迎来到启智AI协作平台! | ||||
explore_AI = 探索更好的AI,来这里发现更有意思的 | |||||
explore_AI = 探索更好的AI,来这里发现更有意思的 | |||||
datasets = 数据集 | datasets = 数据集 | ||||
repositories = 项目 | repositories = 项目 | ||||
use_plt__fuction = 使用本平台提供的AI协作功能,如:托管代码、共享数据、调试算法或训练模型,请先 | use_plt__fuction = 使用本平台提供的AI协作功能,如:托管代码、共享数据、调试算法或训练模型,请先 | ||||
@@ -277,7 +279,7 @@ provide_resoure = 平台目前免费提供CPU、GPU、NPU的算力资源,可 | |||||
create_pro = 创建项目 | create_pro = 创建项目 | ||||
activity = 活动 | activity = 活动 | ||||
no_events = 还没有与您相关的活动 | no_events = 还没有与您相关的活动 | ||||
or_t = 或 | |||||
or_t = 或 | |||||
[explore] | [explore] | ||||
@@ -530,6 +532,19 @@ static.public.user_business_analysis_last30_day=近30天 | |||||
static.public.user_business_analysis_last_month=上月 | static.public.user_business_analysis_last_month=上月 | ||||
static.public.user_business_analysis_yesterday=昨天 | static.public.user_business_analysis_yesterday=昨天 | ||||
static.public.user_business_analysis_all=所有 | static.public.user_business_analysis_all=所有 | ||||
metrics.sheetname=用户趋势分析 | |||||
metrics.date=日期 | |||||
metrics.newregistuser=新增注册用户 | |||||
metrics.newregistandactiveuser=新增已激活 | |||||
metrics.hasactivateuser=新增有贡献活动 | |||||
metrics.newregistnotactiveuser=新增未激活 | |||||
metrics.averageuser=平均新增用户 | |||||
metrics.newuseractiveindex=新增用户激活率 | |||||
metrics.totalregistuser=累计注册用户 | |||||
metrics.totalactiveduser=累计已激活 | |||||
metrics.totalhasactivityuser=累计有贡献活动 | |||||
[settings] | [settings] | ||||
profile=个人信息 | profile=个人信息 | ||||
account=账号 | account=账号 | ||||
@@ -946,6 +961,16 @@ model_manager = 模型 | |||||
model_noright=无权限操作 | model_noright=无权限操作 | ||||
model_rename=模型名称重复,请修改模型名称 | model_rename=模型名称重复,请修改模型名称 | ||||
date=日期 | |||||
repo_add=新增项目 | |||||
repo_total=累计项目 | |||||
repo_public_add=新增公开项目 | |||||
repo_private_add=新增私有项目 | |||||
repo_fork_add=新增派生项目 | |||||
repo_mirror_add=新增镜像项目 | |||||
repo_self_add=新增自建项目 | |||||
debug=调试 | debug=调试 | ||||
debug_again=再次调试 | debug_again=再次调试 | ||||
stop=停止 | stop=停止 | ||||
@@ -1017,7 +1042,9 @@ get_repo_stat_error=查询当前仓库的统计信息失败。 | |||||
get_repo_info_error=查询当前仓库信息失败。 | get_repo_info_error=查询当前仓库信息失败。 | ||||
generate_statistic_file_error=生成文件失败。 | generate_statistic_file_error=生成文件失败。 | ||||
repo_stat_inspect=项目分析 | repo_stat_inspect=项目分析 | ||||
repo_stat_develop=项目增长趋势 | |||||
all=所有 | all=所有 | ||||
current_year=今年 | |||||
computing.all=全部 | computing.all=全部 | ||||
computing.Introduction=简介 | computing.Introduction=简介 | ||||
@@ -1316,6 +1343,8 @@ editor.require_signed_commit=分支需要签名提交 | |||||
editor.repo_too_large = 代码仓总大小不能超过%dMB | editor.repo_too_large = 代码仓总大小不能超过%dMB | ||||
editor.repo_file_invalid = 提交的文件非法 | editor.repo_file_invalid = 提交的文件非法 | ||||
editor.upload_file_too_much = 不能同时提交超过%d个文件 | editor.upload_file_too_much = 不能同时提交超过%d个文件 | ||||
editor.rename = 重命名"%s"为"%s" | |||||
editor.file_changed_while_renaming=待重命名的文件或文件夹版本已发生变化,请您刷新页面后重试 | |||||
commits.desc=浏览代码修改历史 | commits.desc=浏览代码修改历史 | ||||
commits.commits=次代码提交 | commits.commits=次代码提交 | ||||
@@ -6,6 +6,7 @@ if(isEmpty(token)){ | |||||
token = meta.attr("content"); | token = meta.attr("content"); | ||||
} | } | ||||
} | } | ||||
var swiperNewMessage = new Swiper(".newslist", { | var swiperNewMessage = new Swiper(".newslist", { | ||||
direction: "vertical", | direction: "vertical", | ||||
slidesPerView: 10, | slidesPerView: 10, | ||||
@@ -15,6 +16,18 @@ var swiperNewMessage = new Swiper(".newslist", { | |||||
disableOnInteraction: false, | disableOnInteraction: false, | ||||
}, | }, | ||||
}); | }); | ||||
var swiperEvent = new Swiper(".event-list", { | |||||
slidesPerView: 2, | |||||
spaceBetween: 30, | |||||
pagination: { | |||||
el: ".swiper-pagination", | |||||
clickable: true, | |||||
}, | |||||
autoplay: { | |||||
delay: 2500, | |||||
disableOnInteraction: false, | |||||
}, | |||||
}); | |||||
var swiperRepo = new Swiper(".homepro-list", { | var swiperRepo = new Swiper(".homepro-list", { | ||||
slidesPerView: 1, | slidesPerView: 1, | ||||
slidesPerColumn: 2, | slidesPerColumn: 2, | ||||
@@ -433,6 +446,38 @@ function queryRecommendData(){ | |||||
} | } | ||||
}); | }); | ||||
$.ajax({ | |||||
type:"GET", | |||||
url:"/recommend/imageinfo", | |||||
headers: { | |||||
authorization:token, | |||||
}, | |||||
dataType:"json", | |||||
async:false, | |||||
success:function(json){ | |||||
displayActivity(json); | |||||
}, | |||||
error:function(response) { | |||||
} | |||||
}); | |||||
} | |||||
function displayActivity(json){ | |||||
var activityDiv = document.getElementById("recommendactivity"); | |||||
var html = ""; | |||||
if (json != null && json.length > 0){ | |||||
for(var i = 0; i < json.length;i++){ | |||||
var record = json[i] | |||||
html += "<div class=\"swiper-slide\">"; | |||||
html += "<a href=\"" + record["image_link"] + "\" class=\"ui fluid card\">"; | |||||
html += " <div class=\"image\"><img src=\"" + record["url"] + "\"></div>" | |||||
html += "</a>"; | |||||
html += "</div>"; | |||||
} | |||||
} | |||||
activityDiv.innerHTML = html; | |||||
swiperEvent.updateSlides(); | |||||
swiperEvent.updateProgress(); | |||||
} | } | ||||
function displayRepo(json){ | function displayRepo(json){ | ||||
@@ -535,6 +535,9 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
m.Get("/restoreFork", repo.RestoreForkNumber) | m.Get("/restoreFork", repo.RestoreForkNumber) | ||||
m.Get("/downloadAll", repo.ServeAllProjectsPeriodStatisticsFile) | m.Get("/downloadAll", repo.ServeAllProjectsPeriodStatisticsFile) | ||||
m.Get("/downloadAllOpenI", repo.ServeAllProjectsOpenIStatisticsFile) | m.Get("/downloadAllOpenI", repo.ServeAllProjectsOpenIStatisticsFile) | ||||
m.Get("/summary", repo.GetLatestProjectsSummaryData) | |||||
m.Get("/summary/period", repo.GetProjectsSummaryData) | |||||
m.Get("/summary/download", repo.GetProjectsSummaryDataFile) | |||||
m.Group("/project", func() { | m.Group("/project", func() { | ||||
m.Get("", repo.GetAllProjectsPeriodStatistics) | m.Get("", repo.GetAllProjectsPeriodStatistics) | ||||
m.Get("/numVisit", repo.ProjectNumVisit) | m.Get("/numVisit", repo.ProjectNumVisit) | ||||
@@ -547,7 +550,15 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
}) | }) | ||||
}, operationReq) | }, operationReq) | ||||
m.Get("/query_user_metrics", operationReq, repo_ext.QueryMetrics) | |||||
m.Get("/query_metrics_current_month", operationReq, repo_ext.QueryUserMetricsCurrentMonth) | |||||
m.Get("/query_metrics_current_week", operationReq, repo_ext.QueryUserMetricsCurrentWeek) | |||||
m.Get("/query_metrics_current_year", operationReq, repo_ext.QueryUserMetricsCurrentYear) | |||||
m.Get("/query_metrics_last30_day", operationReq, repo_ext.QueryUserMetricsLast30Day) | |||||
m.Get("/query_metrics_last_month", operationReq, repo_ext.QueryUserMetricsLastMonth) | |||||
m.Get("/query_metrics_yesterday", operationReq, repo_ext.QueryUserMetricsYesterday) | |||||
m.Get("/query_metrics_all", operationReq, repo_ext.QueryUserMetricsAll) | |||||
m.Get("/query_user_metrics_page", operationReq, repo_ext.QueryUserMetricDataPage) | |||||
m.Get("/query_user_rank_list", operationReq, repo_ext.QueryRankingList) | m.Get("/query_user_rank_list", operationReq, repo_ext.QueryRankingList) | ||||
m.Get("/query_user_static_page", operationReq, repo_ext.QueryUserStaticDataPage) | m.Get("/query_user_static_page", operationReq, repo_ext.QueryUserStaticDataPage) | ||||
m.Get("/query_user_current_month", operationReq, repo_ext.QueryUserStaticCurrentMonth) | m.Get("/query_user_current_month", operationReq, repo_ext.QueryUserStaticCurrentMonth) | ||||
@@ -20,8 +20,10 @@ import ( | |||||
const DEFAULT_PAGE_SIZE = 10 | const DEFAULT_PAGE_SIZE = 10 | ||||
const DATE_FORMAT = "2006-01-02" | const DATE_FORMAT = "2006-01-02" | ||||
const MONTH_FORMAT = "2006-01" | |||||
const EXCEL_DATE_FORMAT = "20060102" | const EXCEL_DATE_FORMAT = "20060102" | ||||
const CREATE_TIME_FORMAT = "2006/01/02 15:04:05" | const CREATE_TIME_FORMAT = "2006/01/02 15:04:05" | ||||
const UPDATE_TIME_FORMAT = "2006-01-02 15:04:05" | |||||
type ProjectsPeriodData struct { | type ProjectsPeriodData struct { | ||||
RecordBeginTime string `json:"recordBeginTime"` | RecordBeginTime string `json:"recordBeginTime"` | ||||
@@ -60,6 +62,38 @@ type ProjectLatestData struct { | |||||
Top10 []UserInfo `json:"top10"` | Top10 []UserInfo `json:"top10"` | ||||
} | } | ||||
type ProjectSummaryBaseData struct { | |||||
NumReposAdd int64 `json:"numReposAdd"` | |||||
NumRepoPublicAdd int64 `json:"numRepoPublicAdd"` | |||||
NumRepoPrivateAdd int64 `json:"numRepoPrivateAdd"` | |||||
NumRepoForkAdd int64 `json:"numRepoForkAdd"` | |||||
NumRepoMirrorAdd int64 `json:"numRepoMirrorAdd"` | |||||
NumRepoSelfAdd int64 `json:"numRepoSelfAdd"` | |||||
NumRepos int64 `json:"numRepos"` | |||||
CreatTime string `json:"creatTime"` | |||||
} | |||||
type ProjectSummaryData struct { | |||||
ProjectSummaryBaseData | |||||
NumRepoPublic int64 `json:"numRepoPublic"` | |||||
NumRepoPrivate int64 `json:"numRepoPrivate"` | |||||
NumRepoFork int64 `json:"numRepoFork"` | |||||
NumRepoMirror int64 `json:"numRepoMirror"` | |||||
NumRepoSelf int64 `json:"numRepoSelf"` | |||||
NumRepoOrgAdd int64 `json:"numRepoOrgAdd"` | |||||
NumRepoNotOrgAdd int64 `json:"numRepoNotOrgAdd"` | |||||
NumRepoOrg int64 `json:"numRepoOrg"` | |||||
NumRepoNotOrg int64 `json:"numRepoNotOrg"` | |||||
} | |||||
type ProjectSummaryPeriodData struct { | |||||
RecordBeginTime string `json:"recordBeginTime"` | |||||
TotalCount int64 `json:"totalCount"` | |||||
PageRecords []*ProjectSummaryBaseData `json:"pageRecords"` | |||||
} | |||||
func RestoreForkNumber(ctx *context.Context) { | func RestoreForkNumber(ctx *context.Context) { | ||||
repos, err := models.GetAllRepositories() | repos, err := models.GetAllRepositories() | ||||
if err != nil { | if err != nil { | ||||
@@ -73,6 +107,146 @@ func RestoreForkNumber(ctx *context.Context) { | |||||
ctx.JSON(http.StatusOK, struct{}{}) | ctx.JSON(http.StatusOK, struct{}{}) | ||||
} | } | ||||
func GetLatestProjectsSummaryData(ctx *context.Context) { | |||||
stat, err := models.GetLatest2SummaryStatistic() | |||||
data := ProjectSummaryData{} | |||||
if err == nil && len(stat) > 0 { | |||||
data.NumRepos = stat[0].NumRepos | |||||
data.NumRepoOrg = stat[0].NumRepoOrg | |||||
data.NumRepoNotOrg = stat[0].NumRepos - stat[0].NumRepoOrg | |||||
data.NumRepoFork = stat[0].NumRepoFork | |||||
data.NumRepoMirror = stat[0].NumRepoMirror | |||||
data.NumRepoSelf = stat[0].NumRepoSelf | |||||
data.NumRepoPrivate = stat[0].NumRepoPrivate | |||||
data.NumRepoPublic = stat[0].NumRepoPublic | |||||
data.CreatTime = stat[0].CreatedUnix.Format(UPDATE_TIME_FORMAT) | |||||
if len(stat) == 2 { | |||||
data.NumReposAdd = stat[0].NumRepos - stat[1].NumRepos | |||||
data.NumRepoOrgAdd = stat[0].NumRepoOrg - stat[1].NumRepoOrg | |||||
data.NumRepoNotOrgAdd = (stat[0].NumRepos - stat[0].NumRepoOrg) - (stat[1].NumRepos - stat[1].NumRepoOrg) | |||||
data.NumRepoForkAdd = stat[0].NumRepoFork - stat[1].NumRepoFork | |||||
data.NumRepoMirrorAdd = stat[0].NumRepoMirror - stat[1].NumRepoMirror | |||||
data.NumRepoSelfAdd = stat[0].NumRepoSelf - stat[1].NumRepoSelf | |||||
data.NumRepoPrivateAdd = stat[0].NumRepoPrivate - stat[1].NumRepoPrivate | |||||
data.NumRepoPublicAdd = stat[0].NumRepoPublic - stat[1].NumRepoPublic | |||||
} | |||||
} | |||||
ctx.JSON(200, data) | |||||
} | |||||
func GetProjectsSummaryData(ctx *context.Context) { | |||||
var datas = make([]*ProjectSummaryBaseData, 0) | |||||
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) | |||||
beginTime = beginTime.AddDate(0, 0, -1) | |||||
queryType := ctx.QueryTrim("type") | |||||
var count int64 | |||||
if queryType == "all" || queryType == "current_year" { | |||||
dates := getEndOfMonthDates(beginTime, endTime) | |||||
count, _ = models.GetSummaryStatisticByDateCount(dates) | |||||
stats, err := models.GetAllSummaryStatisticByDates(dates) | |||||
if err != nil { | |||||
log.Warn("can not get summary data", err) | |||||
} else { | |||||
for i, v := range stats { | |||||
if i == 0 { | |||||
continue | |||||
} | |||||
data := ProjectSummaryBaseData{} | |||||
setStatisticsData(&data, v, stats[i-1]) | |||||
createTime, _ := time.Parse(DATE_FORMAT, v.Date) | |||||
data.CreatTime = createTime.Format(MONTH_FORMAT) | |||||
datas = append(datas, &data) | |||||
} | |||||
} | |||||
} else { | |||||
count, _ = models.GetSummaryStatisticByTimeCount(beginTime, endTime) | |||||
stats, err := models.GetAllSummaryStatisticByTime(beginTime, endTime) | |||||
if err != nil { | |||||
log.Warn("can not get summary data", err) | |||||
} else { | |||||
for i, v := range stats { | |||||
if i == 0 { | |||||
continue | |||||
} | |||||
data := ProjectSummaryBaseData{} | |||||
setStatisticsData(&data, v, stats[i-1]) | |||||
data.CreatTime = v.Date | |||||
datas = append(datas, &data) | |||||
} | |||||
} | |||||
} | |||||
projectSummaryPeriodData := ProjectSummaryPeriodData{ | |||||
TotalCount: count - 1, | |||||
RecordBeginTime: recordBeginTime.Format(DATE_FORMAT), | |||||
PageRecords: reverse(datas), | |||||
} | |||||
ctx.JSON(200, projectSummaryPeriodData) | |||||
} | |||||
func reverse(datas []*ProjectSummaryBaseData ) []*ProjectSummaryBaseData { | |||||
for i := 0; i < len(datas)/2; i++ { | |||||
j := len(datas) - i - 1 | |||||
datas[i], datas[j] = datas[j], datas[i] | |||||
} | |||||
return datas | |||||
} | |||||
func setStatisticsData(data *ProjectSummaryBaseData, v *models.SummaryStatistic, stats *models.SummaryStatistic) { | |||||
data.NumReposAdd = v.NumRepos - stats.NumRepos | |||||
data.NumRepoPublicAdd = v.NumRepoPublic - stats.NumRepoPublic | |||||
data.NumRepoPrivateAdd = v.NumRepoPrivate - stats.NumRepoPrivate | |||||
data.NumRepoMirrorAdd = v.NumRepoMirror - stats.NumRepoMirror | |||||
data.NumRepoForkAdd = v.NumRepoFork - stats.NumRepoFork | |||||
data.NumRepoSelfAdd = v.NumRepoSelf - stats.NumRepoSelf | |||||
data.NumRepos = v.NumRepos | |||||
} | |||||
func getEndOfMonthDates(beginTime time.Time, endTime time.Time) []string { | |||||
var dates = []string{} | |||||
date := endOfMonth(beginTime.AddDate(0, -1, 0)) | |||||
dates = append(dates, date.Format(DATE_FORMAT)) | |||||
tempDate := endOfMonth(beginTime) | |||||
for { | |||||
if tempDate.Before(endTime) { | |||||
dates = append(dates, tempDate.Format(DATE_FORMAT)) | |||||
tempDate = endOfMonth(tempDate.AddDate(0, 0, 1)) | |||||
} else { | |||||
break | |||||
} | |||||
} | |||||
return dates | |||||
} | |||||
func endOfMonth(date time.Time) time.Time { | |||||
return date.AddDate(0, 1, -date.Day()) | |||||
} | |||||
func GetAllProjectsPeriodStatistics(ctx *context.Context) { | func GetAllProjectsPeriodStatistics(ctx *context.Context) { | ||||
recordBeginTime, err := getRecordBeginTime() | recordBeginTime, err := getRecordBeginTime() | ||||
@@ -210,6 +384,122 @@ func ServeAllProjectsPeriodStatisticsFile(ctx *context.Context) { | |||||
} | } | ||||
func GetProjectsSummaryDataFile(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) | |||||
beginTime = beginTime.AddDate(0, 0, -1) | |||||
if err != nil { | |||||
log.Error("Parameter is wrong", err) | |||||
ctx.Error(http.StatusBadRequest, ctx.Tr("repo.parameter_is_wrong")) | |||||
return | |||||
} | |||||
page := ctx.QueryInt("page") | |||||
if page <= 0 { | |||||
page = 1 | |||||
} | |||||
pageSize := 100 | |||||
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 | |||||
} | |||||
var projectAnalysis = ctx.Tr("repo.repo_stat_develop") | |||||
fileName := getSummaryFileName(ctx, beginTime, endTime, projectAnalysis) | |||||
f := excelize.NewFile() | |||||
index := f.NewSheet(projectAnalysis) | |||||
f.DeleteSheet("Sheet1") | |||||
for k, v := range allProjectsPeriodSummaryHeader(ctx) { | |||||
f.SetCellValue(projectAnalysis, k, v) | |||||
} | |||||
var total int64 | |||||
queryType := ctx.QueryTrim("type") | |||||
var datas = make([]*ProjectSummaryBaseData, 0) | |||||
if queryType == "all" || queryType == "current_year" { | |||||
dates := getEndOfMonthDates(beginTime, endTime) | |||||
total, _ = models.GetSummaryStatisticByDateCount(dates) | |||||
totalPage := getTotalPage(total, pageSize) | |||||
for i := 0; i < totalPage; i++ { | |||||
stats, err := models.GetSummaryStatisticByDates(dates, i+1, pageSize) | |||||
if err != nil { | |||||
log.Warn("can not get summary data", err) | |||||
} else { | |||||
for j, v := range stats { | |||||
if j == 0 { | |||||
continue | |||||
} | |||||
data := ProjectSummaryBaseData{} | |||||
setStatisticsData(&data, v, stats[j-1]) | |||||
createTime, _ := time.Parse(DATE_FORMAT, v.Date) | |||||
data.CreatTime = createTime.Format(MONTH_FORMAT) | |||||
datas = append(datas, &data) | |||||
} | |||||
} | |||||
} | |||||
} else { | |||||
total, _ = models.GetSummaryStatisticByTimeCount(beginTime, endTime) | |||||
totalPage := getTotalPage(total, pageSize) | |||||
for i := 0; i < totalPage; i++ { | |||||
stats, err := models.GetSummaryStatisticByTime(beginTime, endTime, i+1, pageSize) | |||||
if err != nil { | |||||
log.Warn("can not get summary data", err) | |||||
} else { | |||||
for j, v := range stats { | |||||
if j == 0 { | |||||
continue | |||||
} | |||||
data := ProjectSummaryBaseData{} | |||||
setStatisticsData(&data, v, stats[j-1]) | |||||
data.CreatTime = v.Date | |||||
datas = append(datas, &data) | |||||
} | |||||
} | |||||
} | |||||
} | |||||
row := 2 | |||||
datas = reverse(datas) | |||||
for _, data := range datas { | |||||
for k, v := range allProjectsPeriodSummaryValues(row, data, ctx) { | |||||
f.SetCellValue(projectAnalysis, k, v) | |||||
} | |||||
row++ | |||||
} | |||||
f.SetActiveSheet(index) | |||||
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(fileName)) | |||||
ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||||
f.WriteTo(ctx.Resp) | |||||
} | |||||
func ServeAllProjectsOpenIStatisticsFile(ctx *context.Context) { | func ServeAllProjectsOpenIStatisticsFile(ctx *context.Context) { | ||||
page := ctx.QueryInt("page") | page := ctx.QueryInt("page") | ||||
@@ -290,6 +580,20 @@ func getFileName(ctx *context.Context, beginTime time.Time, endTime time.Time, p | |||||
return frontName | return frontName | ||||
} | } | ||||
func getSummaryFileName(ctx *context.Context, beginTime time.Time, endTime time.Time, projectAnalysis string) string { | |||||
baseName := projectAnalysis + "_" | |||||
if ctx.QueryTrim("type") == "all" { | |||||
baseName = baseName + ctx.Tr("repo.all") | |||||
} else if ctx.QueryTrim("type") == "current_year" { | |||||
baseName = baseName + ctx.Tr("repo.current_year") | |||||
} else { | |||||
baseName = baseName + beginTime.Format(EXCEL_DATE_FORMAT) + "_" + endTime.AddDate(0, 0, -1).Format(EXCEL_DATE_FORMAT) | |||||
} | |||||
frontName := baseName + ".xlsx" | |||||
return frontName | |||||
} | |||||
func allProjectsPeroidHeader(ctx *context.Context) map[string]string { | func allProjectsPeroidHeader(ctx *context.Context) map[string]string { | ||||
return map[string]string{"A1": ctx.Tr("admin.repos.id"), "B1": ctx.Tr("admin.repos.projectName"), "C1": ctx.Tr("repo.owner"), "D1": ctx.Tr("admin.repos.isPrivate"), "E1": ctx.Tr("admin.repos.openi"), "F1": ctx.Tr("admin.repos.visit"), "G1": ctx.Tr("admin.repos.download"), "H1": ctx.Tr("admin.repos.pr"), "I1": ctx.Tr("admin.repos.commit"), | return map[string]string{"A1": ctx.Tr("admin.repos.id"), "B1": ctx.Tr("admin.repos.projectName"), "C1": ctx.Tr("repo.owner"), "D1": ctx.Tr("admin.repos.isPrivate"), "E1": ctx.Tr("admin.repos.openi"), "F1": ctx.Tr("admin.repos.visit"), "G1": ctx.Tr("admin.repos.download"), "H1": ctx.Tr("admin.repos.pr"), "I1": ctx.Tr("admin.repos.commit"), | ||||
@@ -297,6 +601,19 @@ func allProjectsPeroidHeader(ctx *context.Context) map[string]string { | |||||
} | } | ||||
func allProjectsPeriodSummaryHeader(ctx *context.Context) map[string]string { | |||||
return map[string]string{"A1": ctx.Tr("repo.date"), "B1": ctx.Tr("repo.repo_add"), "C1": ctx.Tr("repo.repo_total"), "D1": ctx.Tr("repo.repo_public_add"), "E1": ctx.Tr("repo.repo_private_add"), "F1": ctx.Tr("repo.repo_self_add"), "G1": ctx.Tr("repo.repo_fork_add"), "H1": ctx.Tr("repo.repo_mirror_add")} | |||||
} | |||||
func allProjectsPeriodSummaryValues(row int, rs *ProjectSummaryBaseData, ctx *context.Context) map[string]string { | |||||
return map[string]string{getCellName("A", row): rs.CreatTime, getCellName("B", row): strconv.FormatInt(rs.NumReposAdd, 10), getCellName("C", row): strconv.FormatInt(rs.NumRepos, 10), getCellName("D", row): strconv.FormatInt(rs.NumRepoPublicAdd, 10), getCellName("E", row): strconv.FormatInt(rs.NumRepoPrivateAdd, 10), | |||||
getCellName("F", row): strconv.FormatInt(rs.NumRepoSelfAdd, 10), getCellName("G", row): strconv.FormatInt(rs.NumRepoForkAdd, 10), getCellName("H", row): strconv.FormatInt(rs.NumRepoMirrorAdd, 10), | |||||
} | |||||
} | |||||
func allProjectsPeroidValues(row int, rs *models.RepoStatistic, ctx *context.Context) map[string]string { | func allProjectsPeroidValues(row int, rs *models.RepoStatistic, ctx *context.Context) map[string]string { | ||||
return map[string]string{getCellName("A", row): strconv.FormatInt(rs.RepoID, 10), getCellName("B", row): rs.DisplayName(), getCellName("C", row): rs.OwnerName, getCellName("D", row): getBoolDisplay(rs.IsPrivate, ctx), getCellName("E", row): strconv.FormatFloat(rs.RadarTotal, 'f', 2, 64), | return map[string]string{getCellName("A", row): strconv.FormatInt(rs.RepoID, 10), getCellName("B", row): rs.DisplayName(), getCellName("C", row): rs.OwnerName, getCellName("D", row): getBoolDisplay(rs.IsPrivate, ctx), getCellName("E", row): strconv.FormatFloat(rs.RadarTotal, 'f', 2, 64), | ||||
getCellName("F", row): strconv.FormatInt(rs.NumVisits, 10), getCellName("G", row): strconv.FormatInt(rs.NumDownloads, 10), getCellName("H", row): strconv.FormatInt(rs.NumPulls, 10), getCellName("I", row): strconv.FormatInt(rs.NumCommits, 10), | getCellName("F", row): strconv.FormatInt(rs.NumVisits, 10), getCellName("G", row): strconv.FormatInt(rs.NumDownloads, 10), getCellName("H", row): strconv.FormatInt(rs.NumPulls, 10), getCellName("I", row): strconv.FormatInt(rs.NumCommits, 10), | ||||
@@ -8,6 +8,7 @@ package routers | |||||
import ( | import ( | ||||
"bytes" | "bytes" | ||||
"net/http" | "net/http" | ||||
"strconv" | |||||
"strings" | "strings" | ||||
"code.gitea.io/gitea/services/repository" | "code.gitea.io/gitea/services/repository" | ||||
@@ -92,6 +93,8 @@ func setRecommendURL(ctx *context.Context) { | |||||
ctx.Data["page_dev_yunlao_desc3"] = ctx.Tr("home.page_dev_yunlao_desc3") | ctx.Data["page_dev_yunlao_desc3"] = ctx.Tr("home.page_dev_yunlao_desc3") | ||||
ctx.Data["page_dev_yunlao_desc4"] = ctx.Tr("home.page_dev_yunlao_desc4") | ctx.Data["page_dev_yunlao_desc4"] = ctx.Tr("home.page_dev_yunlao_desc4") | ||||
ctx.Data["page_dev_yunlao_apply"] = ctx.Tr("home.page_dev_yunlao_apply") | ctx.Data["page_dev_yunlao_apply"] = ctx.Tr("home.page_dev_yunlao_apply") | ||||
ctx.Data["page_recommend_activity"] = ctx.Tr("home.page_recommend_activity") | |||||
ctx.Data["page_recommend_activity_desc"] = ctx.Tr("home.page_recommend_activity_desc") | |||||
} | } | ||||
func Dashboard(ctx *context.Context) { | func Dashboard(ctx *context.Context) { | ||||
@@ -602,7 +605,32 @@ func ExploreImages(ctx *context.Context) { | |||||
ctx.HTML(200, tplExploreImages) | ctx.HTML(200, tplExploreImages) | ||||
} | } | ||||
func ExploreDataAnalysisUserTrend(ctx *context.Context) { | |||||
ctx.Data["url_params"]="UserTrend" | |||||
ctx.HTML(200, tplExploreExploreDataAnalysis) | |||||
} | |||||
func ExploreDataAnalysisUserAnalysis(ctx *context.Context) { | |||||
ctx.Data["url_params"]="UserAnalysis" | |||||
ctx.HTML(200, tplExploreExploreDataAnalysis) | |||||
} | |||||
func ExploreDataAnalysisProTrend(ctx *context.Context) { | |||||
ctx.Data["url_params"]="ProTrend" | |||||
ctx.HTML(200, tplExploreExploreDataAnalysis) | |||||
} | |||||
func ExploreDataAnalysisProAnalysis(ctx *context.Context) { | |||||
ctx.Data["url_params"]="ProAnalysis" | |||||
ctx.HTML(200, tplExploreExploreDataAnalysis) | |||||
} | |||||
func ExploreDataAnalysisOverview(ctx *context.Context) { | |||||
ctx.Data["url_params"]="Overview" | |||||
ctx.HTML(200, tplExploreExploreDataAnalysis) | |||||
} | |||||
func ExploreDataAnalysisBrainAnalysis(ctx *context.Context) { | |||||
ctx.Data["url_params"]="BrainAnalysis" | |||||
ctx.HTML(200, tplExploreExploreDataAnalysis) | |||||
} | |||||
func ExploreDataAnalysis(ctx *context.Context) { | func ExploreDataAnalysis(ctx *context.Context) { | ||||
ctx.Data["url_params"]="" | |||||
ctx.HTML(200, tplExploreExploreDataAnalysis) | ctx.HTML(200, tplExploreExploreDataAnalysis) | ||||
} | } | ||||
@@ -640,6 +668,87 @@ func GetRecommendOrg() ([]map[string]interface{}, error) { | |||||
} | } | ||||
return resultOrg, nil | return resultOrg, nil | ||||
} | } | ||||
func GetImageInfo() ([]map[string]interface{}, error) { | |||||
url := setting.RecommentRepoAddr + "picture_info" | |||||
result, err := repository.RecommendFromPromote(url) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
imageInfo := make([]map[string]interface{}, 0) | |||||
for i := 0; i < (len(result) - 1); i++ { | |||||
line := result[i] | |||||
imageMap := make(map[string]interface{}) | |||||
if line[0:4] == "url=" { | |||||
url := line[4:] | |||||
imageMap["url"] = url | |||||
if result[i+1][0:11] == "image_link=" { | |||||
image_link := result[i+1][11:] | |||||
imageMap["image_link"] = image_link | |||||
} | |||||
} | |||||
imageInfo = append(imageInfo, imageMap) | |||||
i = i + 1 | |||||
} | |||||
return imageInfo, nil | |||||
} | |||||
func GetRankUser(index string) ([]map[string]interface{}, error) { | |||||
url := setting.RecommentRepoAddr + "user_rank_" + index | |||||
result, err := repository.RecommendFromPromote(url) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
resultOrg := make([]map[string]interface{}, 0) | |||||
for _, userRank := range result { | |||||
tmpIndex := strings.Index(userRank, " ") | |||||
userName := userRank | |||||
score := 0 | |||||
if tmpIndex != -1 { | |||||
userName = userRank[0:tmpIndex] | |||||
tmpScore, err := strconv.Atoi(userRank[tmpIndex+1:]) | |||||
if err != nil { | |||||
log.Info("convert to int error.") | |||||
} | |||||
score = tmpScore | |||||
} | |||||
user, err := models.GetUserByName(userName) | |||||
if err == nil { | |||||
userMap := make(map[string]interface{}) | |||||
userMap["Name"] = user.Name | |||||
userMap["Description"] = user.Description | |||||
userMap["FullName"] = user.FullName | |||||
userMap["HomeLink"] = user.HomeLink() | |||||
userMap["ID"] = user.ID | |||||
userMap["Avatar"] = user.RelAvatarLink() | |||||
userMap["Score"] = score | |||||
resultOrg = append(resultOrg, userMap) | |||||
} else { | |||||
log.Info("query user error," + err.Error()) | |||||
} | |||||
} | |||||
return resultOrg, nil | |||||
} | |||||
func GetImageInfoFromPromote(ctx *context.Context) { | |||||
imageInfo, err := GetImageInfo() | |||||
if err != nil { | |||||
ctx.ServerError("500", err) | |||||
return | |||||
} | |||||
ctx.JSON(200, imageInfo) | |||||
} | |||||
func GetUserRankFromPromote(ctx *context.Context) { | |||||
index := ctx.Params("index") | |||||
resultUserRank, err := GetRankUser(index) | |||||
if err != nil { | |||||
ctx.ServerError("500", err) | |||||
return | |||||
} | |||||
ctx.JSON(200, resultUserRank) | |||||
} | |||||
func RecommendOrgFromPromote(ctx *context.Context) { | func RecommendOrgFromPromote(ctx *context.Context) { | ||||
resultOrg, err := GetRecommendOrg() | resultOrg, err := GetRecommendOrg() | ||||
@@ -199,7 +199,6 @@ func HookPreReceive(ctx *macaron.Context, opts private.HookOptions) { | |||||
env = append(env, | env = append(env, | ||||
private.GitQuarantinePath+"="+opts.GitQuarantinePath) | private.GitQuarantinePath+"="+opts.GitQuarantinePath) | ||||
} | } | ||||
for i := range opts.OldCommitIDs { | for i := range opts.OldCommitIDs { | ||||
oldCommitID := opts.OldCommitIDs[i] | oldCommitID := opts.OldCommitIDs[i] | ||||
newCommitID := opts.NewCommitIDs[i] | newCommitID := opts.NewCommitIDs[i] | ||||
@@ -368,6 +367,24 @@ func HookPreReceive(ctx *macaron.Context, opts private.HookOptions) { | |||||
ctx.PlainText(http.StatusOK, []byte("ok")) | ctx.PlainText(http.StatusOK, []byte("ok")) | ||||
} | } | ||||
// HookEnv | |||||
func HookEnv(ctx *macaron.Context) { | |||||
ownerName := ctx.Params(":owner") | |||||
repoName := ctx.Params(":repo") | |||||
log.Info("try to get hook env.ownerName=%s repoName=%s", ownerName, repoName) | |||||
repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) | |||||
if err != nil { | |||||
log.Error("Unable to get repository: %s/%s Error: %v", ownerName, repoName, err) | |||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ | |||||
"err": err.Error(), | |||||
}) | |||||
return | |||||
} | |||||
result := make(map[string]string, 1) | |||||
result[models.EnvRepoSize] = fmt.Sprint(repo.Size) | |||||
ctx.JSON(http.StatusOK, &private.HookEnvResult{Config: result}) | |||||
} | |||||
// HookPostReceive updates services and users | // HookPostReceive updates services and users | ||||
func HookPostReceive(ctx *macaron.Context, opts private.HookOptions) { | func HookPostReceive(ctx *macaron.Context, opts private.HookOptions) { | ||||
ownerName := ctx.Params(":owner") | ownerName := ctx.Params(":owner") | ||||
@@ -38,6 +38,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
m.Post("/hook/pre-receive/:owner/:repo", bind(private.HookOptions{}), HookPreReceive) | m.Post("/hook/pre-receive/:owner/:repo", bind(private.HookOptions{}), HookPreReceive) | ||||
m.Post("/hook/post-receive/:owner/:repo", bind(private.HookOptions{}), HookPostReceive) | m.Post("/hook/post-receive/:owner/:repo", bind(private.HookOptions{}), HookPostReceive) | ||||
m.Post("/hook/set-default-branch/:owner/:repo/:branch", SetDefaultBranch) | m.Post("/hook/set-default-branch/:owner/:repo/:branch", SetDefaultBranch) | ||||
m.Get("/hook/env/:owner/:repo", HookEnv) | |||||
m.Get("/serv/none/:keyid", ServNoCommand) | m.Get("/serv/none/:keyid", ServNoCommand) | ||||
m.Get("/serv/command/:keyid/:owner/:repo", ServCommand) | m.Get("/serv/command/:keyid/:owner/:repo", ServCommand) | ||||
m.Post("/manager/shutdown", Shutdown) | m.Post("/manager/shutdown", Shutdown) | ||||
@@ -5,10 +5,12 @@ | |||||
package repo | package repo | ||||
import ( | import ( | ||||
"code.gitea.io/gitea/routers/response" | |||||
repo_service "code.gitea.io/gitea/services/repository" | repo_service "code.gitea.io/gitea/services/repository" | ||||
"encoding/json" | "encoding/json" | ||||
"fmt" | "fmt" | ||||
"io/ioutil" | "io/ioutil" | ||||
"net/http" | |||||
"path" | "path" | ||||
"path/filepath" | "path/filepath" | ||||
"strings" | "strings" | ||||
@@ -795,3 +797,102 @@ func GetClosestParentWithFiles(treePath string, commit *git.Commit) string { | |||||
} | } | ||||
return treePath | return treePath | ||||
} | } | ||||
// RenameFilePost response for editing file | |||||
func RenameFilePost(ctx *context.Context, form auth.RenameRepoFileForm) { | |||||
renameFilePost(ctx, form) | |||||
} | |||||
func renameFilePost(ctx *context.Context, form auth.RenameRepoFileForm) { | |||||
if form.TreePath == "" || form.LastCommit == "" { | |||||
ctx.JSON(http.StatusOK, response.ServerError("param error")) | |||||
return | |||||
} | |||||
if form.TreePath == ctx.Repo.TreePath { | |||||
ctx.JSON(http.StatusOK, response.Success()) | |||||
return | |||||
} | |||||
canCommit := renderCommitRights(ctx) | |||||
branchName := ctx.Repo.BranchName | |||||
if ctx.HasError() { | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Flash.ErrorMsg)) | |||||
return | |||||
} | |||||
// Cannot commit to a an existing branch if user doesn't have rights | |||||
if branchName == ctx.Repo.BranchName && !canCommit { | |||||
ctx.Data["Err_NewBranchName"] = true | |||||
ctx.Data["commit_choice"] = frmCommitChoiceNewBranch | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.cannot_commit_to_protected_branch", branchName))) | |||||
return | |||||
} | |||||
message := ctx.Tr("repo.editor.rename", ctx.Repo.TreePath, form.TreePath) | |||||
if err := repofiles.RenameRepoFile(ctx.Repo.Repository, ctx.User, &repofiles.RenameRepoFileOptions{ | |||||
LastCommitID: form.LastCommit, | |||||
BranchName: branchName, | |||||
FromTreePath: ctx.Repo.TreePath, | |||||
TreePath: form.TreePath, | |||||
Message: message, | |||||
}); err != nil { | |||||
// This is where we handle all the errors thrown by repofiles.CreateOrUpdateRepoFile | |||||
if git.IsErrNotExist(err) { | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.file_editing_no_longer_exists", ctx.Repo.TreePath))) | |||||
} else if models.IsErrLFSFileLocked(err) { | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.file_editing_no_longer_exists", ctx.Tr("repo.editor.upload_file_is_locked", err.(models.ErrLFSFileLocked).Path, err.(models.ErrLFSFileLocked).UserName)))) | |||||
} else if models.IsErrFilenameInvalid(err) { | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.filename_is_invalid", form.TreePath))) | |||||
} else if models.IsErrFilePathInvalid(err) { | |||||
if fileErr, ok := err.(models.ErrFilePathInvalid); ok { | |||||
switch fileErr.Type { | |||||
case git.EntryModeSymlink: | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path))) | |||||
case git.EntryModeTree: | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path))) | |||||
case git.EntryModeBlob: | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path))) | |||||
default: | |||||
ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||||
} | |||||
} else { | |||||
ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||||
} | |||||
} else if models.IsErrRepoFileAlreadyExists(err) { | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.file_already_exists", form.TreePath))) | |||||
} else if git.IsErrBranchNotExist(err) { | |||||
// For when a user adds/updates a file to a branch that no longer exists | |||||
if branchErr, ok := err.(git.ErrBranchNotExist); ok { | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.branch_does_not_exist", branchErr.Name))) | |||||
} else { | |||||
ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||||
} | |||||
} else if models.IsErrBranchAlreadyExists(err) { | |||||
// For when a user specifies a new branch that already exists | |||||
ctx.Data["Err_NewBranchName"] = true | |||||
if branchErr, ok := err.(models.ErrBranchAlreadyExists); ok { | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName))) | |||||
} else { | |||||
ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||||
ctx.Error(500, err.Error()) | |||||
} | |||||
} else if models.IsErrCommitIDDoesNotMatch(err) { | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.file_changed_while_renaming"))) | |||||
} else if git.IsErrPushOutOfDate(err) { | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.file_changed_while_renaming"))) | |||||
} else if git.IsErrPushRejected(err) { | |||||
errPushRej := err.(*git.ErrPushRejected) | |||||
if len(errPushRej.Message) == 0 { | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.push_rejected_no_message"))) | |||||
} else { | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.push_rejected", utils.SanitizeFlashErrorString(errPushRej.Message)))) | |||||
} | |||||
} else { | |||||
ctx.JSON(http.StatusOK, response.ServerError(ctx.Tr("repo.editor.fail_to_update_file", form.TreePath, utils.SanitizeFlashErrorString(err.Error())))) | |||||
} | |||||
return | |||||
} | |||||
ctx.JSON(http.StatusOK, response.Success()) | |||||
} |
@@ -60,6 +60,12 @@ func SummaryStatisticDaily(date string) { | |||||
} | } | ||||
selfRepositoryNumber := repositoryNumer - mirrorRepositoryNumber - forkRepositoryNumber | selfRepositoryNumber := repositoryNumer - mirrorRepositoryNumber - forkRepositoryNumber | ||||
organizationRepoNumber, err := models.GetAllOrgRepositoriesCount() | |||||
if err != nil { | |||||
log.Error("can not get org repository number", err) | |||||
organizationRepoNumber = 0 | |||||
} | |||||
//repository size | //repository size | ||||
repositorySize, err := models.GetAllRepositoriesSize() | repositorySize, err := models.GetAllRepositoriesSize() | ||||
if err != nil { | if err != nil { | ||||
@@ -99,6 +105,7 @@ func SummaryStatisticDaily(date string) { | |||||
NumRepoPrivate: privateRepositoryNumer, | NumRepoPrivate: privateRepositoryNumer, | ||||
NumRepoPublic: publicRepositoryNumer, | NumRepoPublic: publicRepositoryNumer, | ||||
NumRepoSelf: selfRepositoryNumber, | NumRepoSelf: selfRepositoryNumber, | ||||
NumRepoOrg: organizationRepoNumber, | |||||
NumRepoBigModel: topicsCount[0], | NumRepoBigModel: topicsCount[0], | ||||
NumRepoAI: topicsCount[1], | NumRepoAI: topicsCount[1], | ||||
NumRepoVision: topicsCount[2], | NumRepoVision: topicsCount[2], | ||||
@@ -19,6 +19,57 @@ const ( | |||||
PAGE_SIZE = 2000 | PAGE_SIZE = 2000 | ||||
) | ) | ||||
func getUserMetricsExcelHeader(ctx *context.Context) map[string]string { | |||||
excelHeader := make([]string, 0) | |||||
excelHeader = append(excelHeader, ctx.Tr("user.metrics.date")) | |||||
excelHeader = append(excelHeader, ctx.Tr("user.metrics.newregistuser")) | |||||
excelHeader = append(excelHeader, ctx.Tr("user.metrics.newregistandactiveuser")) | |||||
excelHeader = append(excelHeader, ctx.Tr("user.metrics.hasactivateuser")) | |||||
excelHeader = append(excelHeader, ctx.Tr("user.metrics.newregistnotactiveuser")) | |||||
excelHeader = append(excelHeader, ctx.Tr("user.metrics.averageuser")) | |||||
excelHeader = append(excelHeader, ctx.Tr("user.metrics.newuseractiveindex")) | |||||
excelHeader = append(excelHeader, ctx.Tr("user.metrics.totalregistuser")) | |||||
excelHeader = append(excelHeader, ctx.Tr("user.metrics.totalactiveduser")) | |||||
excelHeader = append(excelHeader, ctx.Tr("user.metrics.totalhasactivityuser")) | |||||
excelHeaderMap := make(map[string]string, 0) | |||||
var i byte | |||||
i = 0 | |||||
for _, value := range excelHeader { | |||||
excelColumn := getColumn(i) + fmt.Sprint(1) | |||||
excelHeaderMap[excelColumn] = value | |||||
i++ | |||||
} | |||||
return excelHeaderMap | |||||
} | |||||
func writeUserMetricsExcel(row int, xlsx *excelize.File, sheetName string, userMetrics *models.UserMetrics) { | |||||
rows := fmt.Sprint(row) | |||||
var tmp byte | |||||
tmp = 0 | |||||
dateTime := time.Unix(userMetrics.CountDate, 0) | |||||
//dateTime.Format("2006-01-02 15:04:05") | |||||
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, dateTime.Format("2006-01-02 15:04:05")) | |||||
tmp = tmp + 1 | |||||
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.ActivateRegistUser+userMetrics.NotActivateRegistUser) | |||||
tmp = tmp + 1 | |||||
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.ActivateRegistUser) | |||||
tmp = tmp + 1 | |||||
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.RegistActivityUser) | |||||
tmp = tmp + 1 | |||||
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.NotActivateRegistUser) | |||||
tmp = tmp + 1 | |||||
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, "") | |||||
tmp = tmp + 1 | |||||
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, fmt.Sprintf("%.2f", userMetrics.ActivateIndex)) | |||||
tmp = tmp + 1 | |||||
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.TotalUser) | |||||
tmp = tmp + 1 | |||||
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.TotalActivateRegistUser) | |||||
tmp = tmp + 1 | |||||
xlsx.SetCellValue(sheetName, getColumn(tmp)+rows, userMetrics.TotalHasActivityUser) | |||||
} | |||||
func getExcelHeader(ctx *context.Context) map[string]string { | func getExcelHeader(ctx *context.Context) map[string]string { | ||||
excelHeader := make([]string, 0) | excelHeader := make([]string, 0) | ||||
excelHeader = append(excelHeader, ctx.Tr("user.static.id")) | excelHeader = append(excelHeader, ctx.Tr("user.static.id")) | ||||
@@ -200,16 +251,61 @@ func queryUserDataPage(ctx *context.Context, tableName string, queryObj interfac | |||||
} | } | ||||
} | } | ||||
func QueryMetrics(ctx *context.Context) { | |||||
startDate := ctx.Query("startDate") | |||||
endDate := ctx.Query("endDate") | |||||
startTime, _ := time.ParseInLocation("2006-01-02", startDate, time.Local) | |||||
endTime, _ := time.ParseInLocation("2006-01-02", endDate, time.Local) | |||||
result, count := models.QueryMetrics(startTime.Unix(), endTime.Unix()) | |||||
mapInterface := make(map[string]interface{}) | |||||
mapInterface["data"] = result | |||||
mapInterface["count"] = count | |||||
ctx.JSON(http.StatusOK, mapInterface) | |||||
func queryMetrics(ctx *context.Context, tableName string, startTime time.Time, endTime time.Time) { | |||||
page := ctx.QueryInt("page") | |||||
if page <= 0 { | |||||
page = 1 | |||||
} | |||||
pageSize := ctx.QueryInt("pageSize") | |||||
if pageSize <= 0 { | |||||
pageSize = setting.UI.IssuePagingNum | |||||
} | |||||
IsReturnFile := ctx.QueryBool("IsReturnFile") | |||||
var count int64 | |||||
result := make([]*models.UserMetrics, 0) | |||||
if tableName == "public.user_business_analysis_current_year" { | |||||
result = models.QueryMetricsForYear() | |||||
count = int64(len(result)) | |||||
} else if tableName == "public.user_business_analysis_all" { | |||||
result = models.QueryMetricsForAll() | |||||
count = int64(len(result)) | |||||
} else { | |||||
result, count = models.QueryMetricsPage(startTime.Unix(), endTime.Unix(), page, pageSize) | |||||
} | |||||
if IsReturnFile { | |||||
//writer exec file. | |||||
xlsx := excelize.NewFile() | |||||
sheetName := ctx.Tr("user.metrics.sheetname") | |||||
index := xlsx.NewSheet(sheetName) | |||||
xlsx.DeleteSheet("Sheet1") | |||||
dataHeader := getUserMetricsExcelHeader(ctx) | |||||
for k, v := range dataHeader { | |||||
//设置单元格的值 | |||||
xlsx.SetCellValue(sheetName, k, v) | |||||
} | |||||
row := 1 | |||||
log.Info("return count=" + fmt.Sprint(count)) | |||||
for _, userRecord := range result { | |||||
row++ | |||||
writeUserMetricsExcel(row, xlsx, sheetName, userRecord) | |||||
} | |||||
//设置默认打开的表单 | |||||
xlsx.SetActiveSheet(index) | |||||
filename := sheetName + "_" + ctx.Tr("user.static."+tableName) + ".xlsx" | |||||
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(filename)) | |||||
ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||||
if _, err := xlsx.WriteTo(ctx.Resp); err != nil { | |||||
log.Info("writer exel error." + err.Error()) | |||||
} | |||||
} else { | |||||
mapInterface := make(map[string]interface{}) | |||||
mapInterface["data"] = result | |||||
mapInterface["count"] = count | |||||
ctx.JSON(http.StatusOK, mapInterface) | |||||
} | |||||
} | } | ||||
func QueryRankingList(ctx *context.Context) { | func QueryRankingList(ctx *context.Context) { | ||||
@@ -224,34 +320,97 @@ func QueryRankingList(ctx *context.Context) { | |||||
ctx.JSON(http.StatusOK, mapInterface) | ctx.JSON(http.StatusOK, mapInterface) | ||||
} | } | ||||
func QueryUserMetricsCurrentMonth(ctx *context.Context) { | |||||
currentTimeNow := time.Now() | |||||
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()) | |||||
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 0, 0, 0, 0, currentTimeNow.Location()) | |||||
queryMetrics(ctx, "public.user_business_analysis_current_month", pageStartTime, pageEndTime) | |||||
} | |||||
func QueryUserStaticCurrentMonth(ctx *context.Context) { | func QueryUserStaticCurrentMonth(ctx *context.Context) { | ||||
queryUserDataPage(ctx, "public.user_business_analysis_current_month", new(models.UserBusinessAnalysisCurrentMonth)) | queryUserDataPage(ctx, "public.user_business_analysis_current_month", new(models.UserBusinessAnalysisCurrentMonth)) | ||||
} | } | ||||
func QueryUserMetricsCurrentWeek(ctx *context.Context) { | |||||
currentTimeNow := time.Now() | |||||
offset := int(time.Monday - currentTimeNow.Weekday()) | |||||
if offset > 0 { | |||||
offset = -6 | |||||
} | |||||
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset) | |||||
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()) | |||||
queryMetrics(ctx, "public.user_business_analysis_current_week", pageStartTime, pageEndTime) | |||||
} | |||||
func QueryUserStaticCurrentWeek(ctx *context.Context) { | func QueryUserStaticCurrentWeek(ctx *context.Context) { | ||||
queryUserDataPage(ctx, "public.user_business_analysis_current_week", new(models.UserBusinessAnalysisCurrentWeek)) | queryUserDataPage(ctx, "public.user_business_analysis_current_week", new(models.UserBusinessAnalysisCurrentWeek)) | ||||
} | } | ||||
func QueryUserMetricsCurrentYear(ctx *context.Context) { | |||||
currentTimeNow := time.Now() | |||||
pageStartTime := time.Date(currentTimeNow.Year(), 1, 1, 0, 0, 0, 0, currentTimeNow.Location()) | |||||
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()) | |||||
queryMetrics(ctx, "public.user_business_analysis_current_year", pageStartTime, pageEndTime) | |||||
} | |||||
func QueryUserStaticCurrentYear(ctx *context.Context) { | func QueryUserStaticCurrentYear(ctx *context.Context) { | ||||
queryUserDataPage(ctx, "public.user_business_analysis_current_year", new(models.UserBusinessAnalysisCurrentYear)) | queryUserDataPage(ctx, "public.user_business_analysis_current_year", new(models.UserBusinessAnalysisCurrentYear)) | ||||
} | } | ||||
func QueryUserMetricsLast30Day(ctx *context.Context) { | |||||
currentTimeNow := time.Now() | |||||
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, -30) | |||||
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()) | |||||
queryMetrics(ctx, "public.user_business_analysis_last30_day", pageStartTime, pageEndTime) | |||||
} | |||||
func QueryUserStaticLast30Day(ctx *context.Context) { | func QueryUserStaticLast30Day(ctx *context.Context) { | ||||
queryUserDataPage(ctx, "public.user_business_analysis_last30_day", new(models.UserBusinessAnalysisLast30Day)) | queryUserDataPage(ctx, "public.user_business_analysis_last30_day", new(models.UserBusinessAnalysisLast30Day)) | ||||
} | } | ||||
func QueryUserMetricsLastMonth(ctx *context.Context) { | |||||
currentTimeNow := time.Now() | |||||
thisMonth := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 0, 0, 0, 0, currentTimeNow.Location()) | |||||
pageStartTime := thisMonth.AddDate(0, -1, 0) | |||||
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), 1, 23, 59, 59, 0, currentTimeNow.Location()).AddDate(0, 0, -1) | |||||
queryMetrics(ctx, "public.user_business_analysis_last_month", pageStartTime, pageEndTime) | |||||
} | |||||
func QueryUserStaticLastMonth(ctx *context.Context) { | func QueryUserStaticLastMonth(ctx *context.Context) { | ||||
queryUserDataPage(ctx, "public.user_business_analysis_last_month", new(models.UserBusinessAnalysisLastMonth)) | queryUserDataPage(ctx, "public.user_business_analysis_last_month", new(models.UserBusinessAnalysisLastMonth)) | ||||
} | } | ||||
func QueryUserMetricsYesterday(ctx *context.Context) { | |||||
currentTimeNow := time.Now() | |||||
pageStartTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 0, 0, 0, 0, time.Local) | |||||
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()) | |||||
queryMetrics(ctx, "public.user_business_analysis_yesterday", pageStartTime, pageEndTime) | |||||
} | |||||
func QueryUserStaticYesterday(ctx *context.Context) { | func QueryUserStaticYesterday(ctx *context.Context) { | ||||
queryUserDataPage(ctx, "public.user_business_analysis_yesterday", new(models.UserBusinessAnalysisYesterday)) | queryUserDataPage(ctx, "public.user_business_analysis_yesterday", new(models.UserBusinessAnalysisYesterday)) | ||||
} | } | ||||
func QueryUserMetricsAll(ctx *context.Context) { | |||||
currentTimeNow := time.Now() | |||||
pageStartTime := time.Date(2022, 4, 5, 0, 0, 0, 0, currentTimeNow.Location()) | |||||
pageEndTime := time.Date(currentTimeNow.Year(), currentTimeNow.Month(), currentTimeNow.Day(), 23, 59, 59, 0, currentTimeNow.Location()) | |||||
queryMetrics(ctx, "public.user_business_analysis_all", pageStartTime, pageEndTime) | |||||
} | |||||
func QueryUserStaticAll(ctx *context.Context) { | func QueryUserStaticAll(ctx *context.Context) { | ||||
queryUserDataPage(ctx, "public.user_business_analysis_all", new(models.UserBusinessAnalysisAll)) | queryUserDataPage(ctx, "public.user_business_analysis_all", new(models.UserBusinessAnalysisAll)) | ||||
} | } | ||||
func QueryUserMetricDataPage(ctx *context.Context) { | |||||
startDate := ctx.Query("startDate") | |||||
endDate := ctx.Query("endDate") | |||||
startTime, _ := time.ParseInLocation("2006-01-02", startDate, time.Local) | |||||
endTime, _ := time.ParseInLocation("2006-01-02", endDate, time.Local) | |||||
page := ctx.QueryInt("page") | |||||
if page <= 0 { | |||||
page = 1 | |||||
} | |||||
pageSize := ctx.QueryInt("pageSize") | |||||
if pageSize <= 0 { | |||||
pageSize = setting.UI.IssuePagingNum | |||||
} | |||||
result, count := models.QueryMetricsPage(startTime.Unix(), endTime.Unix(), page, pageSize) | |||||
mapInterface := make(map[string]interface{}) | |||||
mapInterface["data"] = result | |||||
mapInterface["count"] = count | |||||
ctx.JSON(http.StatusOK, mapInterface) | |||||
} | |||||
func QueryUserStaticDataPage(ctx *context.Context) { | func QueryUserStaticDataPage(ctx *context.Context) { | ||||
startDate := ctx.Query("startDate") | startDate := ctx.Query("startDate") | ||||
endDate := ctx.Query("endDate") | endDate := ctx.Query("endDate") | ||||
@@ -608,6 +608,11 @@ func getContributorInfo(contributorInfos []*ContributorInfo, email string) *Cont | |||||
// Home render repository home page | // Home render repository home page | ||||
func Home(ctx *context.Context) { | func Home(ctx *context.Context) { | ||||
if ctx.Repo.CanEnableEditor() { | |||||
ctx.Data["CanEditFile"] = true | |||||
} else { | |||||
ctx.Data["CanEditFile"] = false | |||||
} | |||||
if len(ctx.Repo.Units) > 0 { | if len(ctx.Repo.Units) > 0 { | ||||
//get repo contributors info | //get repo contributors info | ||||
contributors, err := git.GetContributors(ctx.Repo.Repository.RepoPath(), ctx.Repo.BranchName) | contributors, err := git.GetContributors(ctx.Repo.Repository.RepoPath(), ctx.Repo.BranchName) | ||||
@@ -0,0 +1,32 @@ | |||||
package response | |||||
const ( | |||||
RESPONSE_CODE_SUCCESS = 0 | |||||
RESPONSE_MSG_SUCCESS = "ok" | |||||
RESPONSE_CODE_ERROR_DEFAULT = 99 | |||||
) | |||||
type AiforgeResponse struct { | |||||
Code int | |||||
Msg string | |||||
Data interface{} | |||||
} | |||||
func Success() *AiforgeResponse { | |||||
return &AiforgeResponse{Code: RESPONSE_CODE_SUCCESS, Msg: RESPONSE_MSG_SUCCESS} | |||||
} | |||||
func Error(code int, msg string) *AiforgeResponse { | |||||
return &AiforgeResponse{Code: code, Msg: msg} | |||||
} | |||||
func ServerError(msg string) *AiforgeResponse { | |||||
return &AiforgeResponse{Code: RESPONSE_CODE_ERROR_DEFAULT, Msg: msg} | |||||
} | |||||
func SuccessWithData(data interface{}) *AiforgeResponse { | |||||
return &AiforgeResponse{Code: RESPONSE_CODE_ERROR_DEFAULT, Msg: RESPONSE_MSG_SUCCESS, Data: data} | |||||
} | |||||
func ErrorWithData(code int, msg string, data interface{}) *AiforgeResponse { | |||||
return &AiforgeResponse{Code: code, Msg: msg, Data: data} | |||||
} |
@@ -325,6 +325,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
m.Get("/action/notification", routers.ActionNotification) | m.Get("/action/notification", routers.ActionNotification) | ||||
m.Get("/recommend/org", routers.RecommendOrgFromPromote) | m.Get("/recommend/org", routers.RecommendOrgFromPromote) | ||||
m.Get("/recommend/repo", routers.RecommendRepoFromPromote) | m.Get("/recommend/repo", routers.RecommendRepoFromPromote) | ||||
m.Get("/recommend/userrank/:index", routers.GetUserRankFromPromote) | |||||
m.Get("/recommend/imageinfo", routers.GetImageInfoFromPromote) | |||||
m.Post("/all/search/", routers.Search) | m.Post("/all/search/", routers.Search) | ||||
m.Get("/all/search/", routers.EmptySearch) | m.Get("/all/search/", routers.EmptySearch) | ||||
m.Get("/all/dosearch/", routers.SearchApi) | m.Get("/all/dosearch/", routers.SearchApi) | ||||
@@ -344,6 +346,13 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
m.Get("/code", routers.ExploreCode) | m.Get("/code", routers.ExploreCode) | ||||
m.Get("/images", routers.ExploreImages) | m.Get("/images", routers.ExploreImages) | ||||
m.Get("/data_analysis", routers.ExploreDataAnalysis) | m.Get("/data_analysis", routers.ExploreDataAnalysis) | ||||
m.Get("/data_analysis/UserTrend", routers.ExploreDataAnalysisUserTrend) | |||||
m.Get("/data_analysis/UserAnalysis", routers.ExploreDataAnalysisUserAnalysis) | |||||
m.Get("/data_analysis/ProAnalysis", routers.ExploreDataAnalysisProAnalysis) | |||||
m.Get("/data_analysis/ProTrend", routers.ExploreDataAnalysisProTrend) | |||||
m.Get("/data_analysis/Overview", routers.ExploreDataAnalysisOverview) | |||||
m.Get("/data_analysis/BrainAnalysis", routers.ExploreDataAnalysisBrainAnalysis) | |||||
}, ignSignIn) | }, ignSignIn) | ||||
m.Combo("/install", routers.InstallInit).Get(routers.Install). | m.Combo("/install", routers.InstallInit).Get(routers.Install). | ||||
Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost) | Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost) | ||||
@@ -933,6 +942,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
m.Combo("/_upload/*", repo.MustBeAbleToUpload). | m.Combo("/_upload/*", repo.MustBeAbleToUpload). | ||||
Get(repo.UploadFile). | Get(repo.UploadFile). | ||||
Post(bindIgnErr(auth.UploadRepoFileForm{}), repo.UploadFilePost) | Post(bindIgnErr(auth.UploadRepoFileForm{}), repo.UploadFilePost) | ||||
m.Post("/_rename/*", bindIgnErr(auth.RenameRepoFileForm{}), repo.RenameFilePost) | |||||
}, context.RepoRefByType(context.RepoRefBranch), repo.MustBeEditable) | }, context.RepoRefByType(context.RepoRefBranch), repo.MustBeEditable) | ||||
m.Group("", func() { | m.Group("", func() { | ||||
m.Post("/upload-file", repo.UploadFileToServer) | m.Post("/upload-file", repo.UploadFileToServer) | ||||
@@ -19,6 +19,8 @@ import ( | |||||
pull_service "code.gitea.io/gitea/services/pull" | pull_service "code.gitea.io/gitea/services/pull" | ||||
) | ) | ||||
const SHELL_FLAG_ON = 1 | |||||
// CreateRepository creates a repository for the user/organization. | // CreateRepository creates a repository for the user/organization. | ||||
func CreateRepository(doer, owner *models.User, opts models.CreateRepoOptions) (*models.Repository, error) { | func CreateRepository(doer, owner *models.User, opts models.CreateRepoOptions) (*models.Repository, error) { | ||||
repo, err := repo_module.CreateRepository(doer, owner, opts) | repo, err := repo_module.CreateRepository(doer, owner, opts) | ||||
@@ -1,15 +1,21 @@ | |||||
{{template "base/head_fluid" .}} | {{template "base/head_fluid" .}} | ||||
<input id="url_params" type="hidden" value={{.url_params}}/> | |||||
<div id="data_analysis" style="height: 100%;"> | <div id="data_analysis" style="height: 100%;"> | ||||
</div> | </div> | ||||
{{template "base/footer_fluid" .}} | {{template "base/footer_fluid" .}} | ||||
<!-- <script> | |||||
localStorage.setItem("dataAnalysisURL","{{.url_params}}") | |||||
</script> --> | |||||
<style> | <style> | ||||
.full.height { | .full.height { | ||||
display: flex; | |||||
flex-flow: column wrap; | |||||
padding-bottom:0px; | |||||
/* flex-grow: 1; */ | /* flex-grow: 1; */ | ||||
padding-bottom: 53px; | |||||
/* padding-bottom: 53px; */ | |||||
} | } | ||||
</style> | </style> |
@@ -1,4 +1,4 @@ | |||||
<a href="https://openi.org.cn/html/2020/qimengxingdong_0813/450.html" target="_blank"><img class="ui mini image" src="/img/banner-qimen-4X3.jpg" style="width:100%;"></a> | |||||
<a href="https://openi.org.cn/index.php?m=content&c=index&a=lists&catid=208" target="_blank"><img class="ui mini image" src="https://openi.org.cn/uploadfile/2022/0507/e8bdd42ed598f12.jpg" style="width:100%;"></a> | |||||
<div class="ui secondary pointing menu"> | <div class="ui secondary pointing menu"> | ||||
<div class="active item"> | <div class="active item"> | ||||
@@ -37,6 +37,20 @@ | |||||
<div class="ui container homeorg"> | <div class="ui container homeorg"> | ||||
<div class="ui stackable grid"> | <div class="ui stackable grid"> | ||||
<div class="sixteen wide tablet four wide computer column homeorg-tit"> | <div class="sixteen wide tablet four wide computer column homeorg-tit"> | ||||
<h2>{{.page_recommend_activity}}</h2> | |||||
<p><span class="ui text grey">{{.page_recommend_activity_desc}}</p> | |||||
</div> | |||||
<div class="sixteen wide tablet twelve wide computer column"> | |||||
<div class="event-list"> | |||||
<div class="swiper-wrapper" id="recommendactivity"> | |||||
</div> | |||||
<div class="swiper-pagination"></div> | |||||
</div> | |||||
</div> | |||||
<div class="sixteen wide tablet four wide computer column homeorg-tit"> | |||||
<h2>{{.page_recommend_org}}</h2> | <h2>{{.page_recommend_org}}</h2> | ||||
<p><span class="ui text grey">{{.page_recommend_org_desc}} </span><a href="{{.RecommendURL}}">{{.page_recommend_org_commit}}</a></p> | <p><span class="ui text grey">{{.page_recommend_org_desc}} </span><a href="{{.RecommendURL}}">{{.page_recommend_org_commit}}</a></p> | ||||
<a href="{{AppSubUrl}}/explore/organizations" class="circular ui primary basic button">{{.page_recommend_org_more}} <i class="arrow circle right icon"></i></a> | <a href="{{AppSubUrl}}/explore/organizations" class="circular ui primary basic button">{{.page_recommend_org_more}} <i class="arrow circle right icon"></i></a> | ||||
@@ -17,20 +17,6 @@ | |||||
} | } | ||||
.width { | |||||
width: 100% !important; | |||||
} | |||||
.width80 { | |||||
width: 80.7% !important; | |||||
margin-left: 10px; | |||||
} | |||||
.width85 { | |||||
width: 85% !important; | |||||
margin-left: 4.5rem !important; | |||||
} | |||||
.width81 { | .width81 { | ||||
margin-left: 1.5rem; | margin-left: 1.5rem; | ||||
width: 81% !important; | width: 81% !important; | ||||
@@ -40,26 +26,6 @@ | |||||
width: 48.5% !important; | width: 48.5% !important; | ||||
} | } | ||||
.add { | |||||
font-size: 18px; | |||||
padding: 0.5rem; | |||||
border: 1px solid rgba(187, 187, 187, 100); | |||||
border-radius: 0px 5px 5px 0px; | |||||
line-height: 21px; | |||||
text-align: center; | |||||
color: #C2C7CC; | |||||
} | |||||
.min { | |||||
font-size: 18px; | |||||
padding: 0.5rem; | |||||
border: 1px solid rgba(187, 187, 187, 100); | |||||
border-radius: 5px 0px 0px 5px; | |||||
line-height: 21px; | |||||
text-align: center; | |||||
color: #C2C7CC; | |||||
} | |||||
.nowrapx { | .nowrapx { | ||||
white-space: nowrap !important; | white-space: nowrap !important; | ||||
} | } | ||||
@@ -87,7 +53,7 @@ | |||||
<input type="hidden" name="benchmarkMode" value="{{.benchmarkMode}}"> | <input type="hidden" name="benchmarkMode" value="{{.benchmarkMode}}"> | ||||
{{if eq .benchmarkMode "model"}} | {{if eq .benchmarkMode "model"}} | ||||
<form class="ui form model_form" action="{{.Link}}?benchmarkMode=alogrithm" method="post"> | |||||
<form class="ui form model_form" action="{{.Link}}?benchmarkMode=model" method="post"> | |||||
{{.CsrfTokenHtml}} | {{.CsrfTokenHtml}} | ||||
<input type="hidden" name="action" value="update"> | <input type="hidden" name="action" value="update"> | ||||
<div class="required unite min_title inline field"> | <div class="required unite min_title inline field"> | ||||
@@ -151,7 +117,7 @@ | |||||
data-position="right center" data-variation="mini"></i> | data-position="right center" data-variation="mini"></i> | ||||
</span> | </span> | ||||
<a id="benchmark_model_example" | <a id="benchmark_model_example" | ||||
href="https://git.openi.org.cn/yult/snn4imagenet">{{.i18n.Tr "cloudbrain.view_sample"}}</a> | |||||
href="https://git.openi.org.cn/BDIP/snn4imagenet">{{.i18n.Tr "cloudbrain.view_sample"}}</a> | |||||
</div> | </div> | ||||
<div id="images-new-cb"> | <div id="images-new-cb"> | ||||
@@ -308,10 +274,10 @@ | |||||
console.log(value, text) | console.log(value, text) | ||||
if (value === "BRAINSCORE") { | if (value === "BRAINSCORE") { | ||||
$('#brainscore_child_type').css('display', 'block') | $('#brainscore_child_type').css('display', 'block') | ||||
$('#benchmark_model_example').attr('href', 'https://git.openi.org.cn/yult/similarity2brain_ann') | |||||
$('#benchmark_model_example').attr('href', 'https://git.openi.org.cn/BDIP/similarity2brain_ann') | |||||
} else { | } else { | ||||
$('#brainscore_child_type').css('display', 'none') | $('#brainscore_child_type').css('display', 'none') | ||||
$('#benchmark_model_example').attr('href', 'https://git.openi.org.cn/yult/snn4imagenet') | |||||
$('#benchmark_model_example').attr('href', 'https://git.openi.org.cn/BDIP/snn4imagenet') | |||||
} | } | ||||
} | } | ||||
}) | }) | ||||
@@ -1,165 +1,199 @@ | |||||
{{template "base/head" .}} | {{template "base/head" .}} | ||||
<style> | <style> | ||||
.according-panel-heading{ | |||||
box-sizing: border-box; | |||||
padding: 8px 16px; | |||||
color: #252b3a; | |||||
background-color: #f2f5fc; | |||||
line-height: 1.5; | |||||
cursor: pointer; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
} | |||||
.accordion-panel-title { | |||||
margin-top: 0; | |||||
margin-bottom: 0; | |||||
color: #252b3a; | |||||
} | |||||
.accordion-panel-title-content{ | |||||
vertical-align: middle; | |||||
display: inline-block; | |||||
width: calc(100% - 32px); | |||||
cursor: default; | |||||
} | |||||
.acc-margin-bottom { | |||||
margin-bottom: 5px; | |||||
} | |||||
.title_text { | |||||
font-size: 12px; | |||||
} | |||||
.ac-display-inblock { | |||||
display: inline-block; | |||||
} | |||||
.cti-mgRight-sm { | |||||
margin-right: 8px; | |||||
} | |||||
.ac-text-normal { | |||||
font-size: 14px; | |||||
color: #575d6c; | |||||
} | |||||
.uc-accordionTitle-black { | |||||
color: #333; | |||||
} | |||||
.accordion-border{ | |||||
border:1px solid #cce2ff; | |||||
} | |||||
.padding0{ | |||||
padding: 0 !important; | |||||
} | |||||
.content-pad{ | |||||
padding: 15px 35px; | |||||
} | |||||
.content-margin{ | |||||
margin:10px 5px ; | |||||
} | |||||
.tab_2_content { | |||||
min-height: 425px; | |||||
margin-left: 10px; | |||||
} | |||||
.ac-grid { | |||||
display: block; | |||||
*zoom: 1; | |||||
} | |||||
.ac-grid-col { | |||||
float: left; | |||||
width: 100%; | |||||
} | |||||
.ac-grid-col2 .ac-grid-col { | |||||
width: 50%; | |||||
} | |||||
.ti-form { | |||||
text-align: left; | |||||
max-width: 100%; | |||||
vertical-align: middle; | |||||
} | |||||
.ti-form>tbody { | |||||
font-size: 12px; | |||||
} | |||||
.ti-form>tbody, .ti-form>tbody>tr { | |||||
vertical-align: inherit; | |||||
} | |||||
.ti-text-form-label { | |||||
padding-bottom: 20px; | |||||
padding-right: 20px; | |||||
color: #8a8e99; | |||||
font-size: 12px; | |||||
white-space: nowrap !important; | |||||
width: 80px; | |||||
line-height: 30px; | |||||
} | |||||
.ti-text-form-content{ | |||||
line-height: 30px; | |||||
padding-bottom: 20px; | |||||
} | |||||
.ti-form>tbody>tr>td { | |||||
vertical-align: top; | |||||
white-space: normal; | |||||
} | |||||
td, th { | |||||
padding: 0; | |||||
} | |||||
.ac-grid-col .text-span { | |||||
width: 450px; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
white-space: nowrap; | |||||
} | |||||
.redo-color{ | |||||
color: #3291F8; | |||||
} | |||||
.ti-action-menu-item:not(:last-child){ | |||||
margin-right: 10px; | |||||
padding-right: 11px; | |||||
text-decoration: none!important; | |||||
color: #526ecc; | |||||
cursor: pointer; | |||||
display: inline-block; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
position: relative; | |||||
} | |||||
.ti-action-menu-item:not(:last-child):after { | |||||
content: ""; | |||||
display: inline-block; | |||||
position: absolute; | |||||
height: 12px; | |||||
right: 0; | |||||
top: 50%; | |||||
-webkit-transform: translateY(-6px); | |||||
-ms-transform: translateY(-6px); | |||||
-o-transform: translateY(-6px); | |||||
transform: translateY(-6px); | |||||
border-right: 1px solid #dfe1e6; | |||||
} | |||||
.text-width80{ | |||||
width: 100px; | |||||
line-height: 30px; | |||||
} | |||||
.border-according{ | |||||
border: 1px solid #dfe1e6; | |||||
} | |||||
.disabled { | |||||
.according-panel-heading { | |||||
box-sizing: border-box; | |||||
padding: 8px 16px; | |||||
color: #252b3a; | |||||
background-color: #f2f5fc; | |||||
line-height: 1.5; | |||||
cursor: pointer; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
} | |||||
.accordion-panel-title { | |||||
margin-top: 0; | |||||
margin-bottom: 0; | |||||
color: #252b3a; | |||||
} | |||||
.accordion-panel-title-content { | |||||
vertical-align: middle; | |||||
display: inline-block; | |||||
width: calc(100% - 32px); | |||||
cursor: default; | |||||
} | |||||
.acc-margin-bottom { | |||||
margin-bottom: 5px; | |||||
} | |||||
.title_text { | |||||
font-size: 12px; | |||||
} | |||||
.ac-display-inblock { | |||||
display: inline-block; | |||||
} | |||||
.cti-mgRight-sm { | |||||
margin-right: 8px; | |||||
} | |||||
.ac-text-normal { | |||||
font-size: 14px; | |||||
color: #575d6c; | |||||
} | |||||
.uc-accordionTitle-black { | |||||
color: #333; | |||||
} | |||||
.accordion-border { | |||||
border: 1px solid #cce2ff; | |||||
} | |||||
.padding0 { | |||||
padding: 0 !important; | |||||
} | |||||
.content-pad { | |||||
padding: 15px 35px; | |||||
} | |||||
.content-margin { | |||||
margin: 10px 5px; | |||||
} | |||||
.tab_2_content { | |||||
min-height: 425px; | |||||
margin-left: 10px; | |||||
} | |||||
.ac-grid { | |||||
display: block; | |||||
*zoom: 1; | |||||
} | |||||
.ac-grid-col { | |||||
float: left; | |||||
width: 100%; | |||||
} | |||||
.ac-grid-col2 .ac-grid-col { | |||||
width: 50%; | |||||
} | |||||
.ti-form { | |||||
text-align: left; | |||||
max-width: 100%; | |||||
vertical-align: middle; | |||||
} | |||||
.ti-form>tbody { | |||||
font-size: 12px; | |||||
} | |||||
.ti-form>tbody, | |||||
.ti-form>tbody>tr { | |||||
vertical-align: inherit; | |||||
} | |||||
.ti-text-form-label { | |||||
padding-bottom: 20px; | |||||
padding-right: 20px; | |||||
color: #8a8e99; | |||||
font-size: 12px; | |||||
white-space: nowrap !important; | |||||
width: 80px; | |||||
line-height: 30px; | |||||
} | |||||
.ti-text-form-content { | |||||
line-height: 30px; | |||||
padding-bottom: 20px; | |||||
} | |||||
.ti-form>tbody>tr>td { | |||||
vertical-align: top; | |||||
white-space: normal; | |||||
} | |||||
td, | |||||
th { | |||||
padding: 0; | |||||
} | |||||
.ac-grid-col .text-span { | |||||
width: 450px; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
white-space: nowrap; | |||||
} | |||||
.redo-color { | |||||
color: #3291F8; | |||||
} | |||||
.ti-action-menu-item:not(:last-child) { | |||||
margin-right: 10px; | |||||
padding-right: 11px; | |||||
text-decoration: none !important; | |||||
color: #526ecc; | |||||
cursor: pointer; | |||||
display: inline-block; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
position: relative; | |||||
} | |||||
.ti-action-menu-item:not(:last-child):after { | |||||
content: ""; | |||||
display: inline-block; | |||||
position: absolute; | |||||
height: 12px; | |||||
right: 0; | |||||
top: 50%; | |||||
-webkit-transform: translateY(-6px); | |||||
-ms-transform: translateY(-6px); | |||||
-o-transform: translateY(-6px); | |||||
transform: translateY(-6px); | |||||
border-right: 1px solid #dfe1e6; | |||||
} | |||||
.text-width80 { | |||||
width: 100px; | |||||
line-height: 30px; | |||||
} | |||||
.border-according { | |||||
border: 1px solid #dfe1e6; | |||||
} | |||||
.disabled { | |||||
cursor: default; | cursor: default; | ||||
pointer-events: none; | pointer-events: none; | ||||
color: rgba(0,0,0,.6) !important; | |||||
color: rgba(0, 0, 0, .6) !important; | |||||
opacity: .45 !important; | opacity: .45 !important; | ||||
} | |||||
.pad20{ | |||||
border:0px !important; | |||||
} | |||||
.model_file_bread{ | |||||
margin-bottom: -0.5rem !important; | |||||
padding-left: 1rem; | |||||
padding-top: 0.5rem ; | |||||
} | |||||
} | |||||
.pad20 { | |||||
border: 0px !important; | |||||
} | |||||
.model_file_bread { | |||||
margin-bottom: -0.5rem !important; | |||||
padding-left: 1rem; | |||||
padding-top: 0.5rem; | |||||
} | |||||
</style> | </style> | ||||
<div id="mask"> | <div id="mask"> | ||||
<div id="loadingPage"> | <div id="loadingPage"> | ||||
@@ -171,7 +205,7 @@ td, th { | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="repository"> | <div class="repository"> | ||||
{{template "repo/header" .}} | |||||
{{template "repo/header" .}} | |||||
<div class="ui container"> | <div class="ui container"> | ||||
<h4 class="ui header" id="vertical-segment"> | <h4 class="ui header" id="vertical-segment"> | ||||
<div class="ui breadcrumb"> | <div class="ui breadcrumb"> | ||||
@@ -183,11 +217,12 @@ td, th { | |||||
{{$.i18n.Tr "repo.modelarts.evaluate_job"}} | {{$.i18n.Tr "repo.modelarts.evaluate_job"}} | ||||
</a> | </a> | ||||
<div class="divider"> / </div> | <div class="divider"> / </div> | ||||
<div class="active section">{{.displayJobName}}</div> | |||||
</div> | |||||
<div class="active section">{{.displayJobName}}</div> | |||||
</div> | |||||
</h4> | </h4> | ||||
{{range $k ,$v := .version_list_task}} | {{range $k ,$v := .version_list_task}} | ||||
<div class="ui accordion border-according" id="accordion{{.VersionName}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}" data-version="{{.VersionName}}"> | |||||
<div class="ui accordion border-according" id="accordion{{.VersionName}}" data-repopath="{{$.RepoRelPath}}" | |||||
data-jobid="{{.JobID}}" data-version="{{.VersionName}}"> | |||||
<input type="hidden" id="jobId_input" name="jobId_input" value="{{.JobID}}"> | <input type="hidden" id="jobId_input" name="jobId_input" value="{{.JobID}}"> | ||||
<div class="{{if eq $k 0}}active{{end}} title padding0"> | <div class="{{if eq $k 0}}active{{end}} title padding0"> | ||||
<div class="according-panel-heading"> | <div class="according-panel-heading"> | ||||
@@ -197,18 +232,23 @@ td, th { | |||||
<span> | <span> | ||||
<div class="ac-display-inblock title_text acc-margin-bottom"> | <div class="ac-display-inblock title_text acc-margin-bottom"> | ||||
<span class="cti-mgRight-sm"> | <span class="cti-mgRight-sm"> | ||||
{{if not (eq .StartTime 0)}} | |||||
<td>{{TimeSinceUnix1 .StartTime}}</td> | |||||
{{else}} | |||||
<td>{{TimeSinceUnix1 .CreatedUnix}}<td> | |||||
{{end}} | |||||
</span> | |||||
{{if not (eq .StartTime 0)}} | |||||
<td>{{TimeSinceUnix1 .StartTime}}</td> | |||||
{{else}} | |||||
<td>{{TimeSinceUnix1 .CreatedUnix}} | |||||
<td> | |||||
{{end}} | |||||
</span> | |||||
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}: | <span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}: | ||||
<span id="{{.VersionName}}-status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
<span id="{{.VersionName}}-status-span"><i id="icon" | |||||
style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" | |||||
style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
</span> | </span> | ||||
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span> | |||||
<span class="cti-mgRight-sm uc-accordionTitle-black" id="{{.VersionName}}-duration-span">{{$.duration}}</span> | |||||
<span | |||||
class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span> | |||||
<span class="cti-mgRight-sm uc-accordionTitle-black" | |||||
id="{{.VersionName}}-duration-span">{{$.duration}}</span> | |||||
</div> | </div> | ||||
</span> | </span> | ||||
@@ -219,8 +259,10 @@ td, th { | |||||
<div class="{{if eq $k 0}}active{{end}} content"> | <div class="{{if eq $k 0}}active{{end}} content"> | ||||
<div class="content-pad"> | <div class="content-pad"> | ||||
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);"> | <div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);"> | ||||
<a class="active item" data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a> | |||||
<a class="item" data-tab="second{{$k}}" onclick="loadLog({{.VersionName}})">{{$.i18n.Tr "repo.modelarts.log"}}</a> | |||||
<a class="active item" | |||||
data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a> | |||||
<a class="item" data-tab="second{{$k}}" | |||||
onclick="loadLog({{.VersionName}})">{{$.i18n.Tr "repo.modelarts.log"}}</a> | |||||
</div> | </div> | ||||
<div class="ui tab active" data-tab="first{{$k}}"> | <div class="ui tab active" data-tab="first{{$k}}"> | ||||
<div style="padding-top: 10px;"> | <div style="padding-top: 10px;"> | ||||
@@ -270,11 +312,12 @@ td, th { | |||||
</td> | </td> | ||||
<td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
<div class="text-span text-span-w" id="{{.VersionName}}-startTime"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-startTime"> | |||||
{{if not (eq .StartTime 0)}} | {{if not (eq .StartTime 0)}} | ||||
{{TimeSinceUnix1 .StartTime}} | |||||
{{TimeSinceUnix1 .StartTime}} | |||||
{{else}} | {{else}} | ||||
-- | |||||
-- | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
</td> | </td> | ||||
@@ -286,11 +329,12 @@ td, th { | |||||
</td> | </td> | ||||
<td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
<div class="text-span text-span-w" id="{{.VersionName}}-EndTime"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-EndTime"> | |||||
{{if not (eq .EndTime 0)}} | {{if not (eq .EndTime 0)}} | ||||
{{TimeSinceUnix1 .EndTime}} | |||||
{{TimeSinceUnix1 .EndTime}} | |||||
{{else}} | {{else}} | ||||
-- | |||||
-- | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
</td> | </td> | ||||
@@ -301,7 +345,8 @@ td, th { | |||||
</td> | </td> | ||||
<td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
<div class="text-span text-span-w" id="{{.VersionName}}-duration"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-duration"> | |||||
{{$.duration}} | {{$.duration}} | ||||
</div> | </div> | ||||
</td> | </td> | ||||
@@ -320,11 +365,12 @@ td, th { | |||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | <td class="ti-no-ng-animate ti-text-form-label text-width80"> | ||||
{{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_scenes"}} | {{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_scenes"}} | ||||
</td> | </td> | ||||
<td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
<div class="text-span text-span-w" id="{{.VersionName}}-BenchmarkTypeName"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-BenchmarkTypeName"> | |||||
{{.BenchmarkType}} | {{.BenchmarkType}} | ||||
</div> | </div> | ||||
</td> | </td> | ||||
@@ -332,135 +378,142 @@ td, th { | |||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | <td class="ti-no-ng-animate ti-text-form-label text-width80"> | ||||
{{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_type"}} | {{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_type"}} | ||||
</td> | </td> | ||||
<td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
<div class="text-span text-span-w" id="{{.VersionName}}-BenchmarkTypeName"> | |||||
{{.BenchmarkTypeName}} | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-BenchmarkTypeName"> | |||||
{{.BenchmarkTypeName}} | |||||
</div> | </div> | ||||
</td> | </td> | ||||
</tr> | </tr> | ||||
</tbody> | </tbody> | ||||
</table> | </table> | ||||
</div> | </div> | ||||
<div class="ac-grid-col"> | <div class="ac-grid-col"> | ||||
<table class="ti-form"> | |||||
<tbody class="ti-text-form"> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_train"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{if eq .BenchmarkType "Benchmark"}} | |||||
train.py | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_test"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{if eq .BenchmarkType "Benchmark"}} | |||||
test.py | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.description"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" title="{{.Description}}"> | |||||
{{if .Description}} | |||||
{{.Description}} | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.gpu_type"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{$.resource_type}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.standard"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{$.resource_spec}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.model_manager"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||||
{{$.datasetname}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain_creator"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||||
{{.User.Name}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_child_type"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-BenchmarkChildTypeName"> | |||||
{{if $.BenchmarkChildTypeName}} | |||||
{{$.BenchmarkChildTypeName}} | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
<table class="ti-form"> | |||||
<tbody class="ti-text-form"> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_train"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{if eq .BenchmarkType "Benchmark"}} | |||||
train.py | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_test"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{if eq .BenchmarkType "Benchmark"}} | |||||
test.py | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.description"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" title="{{.Description}}"> | |||||
{{if .Description}} | |||||
{{.Description}} | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.gpu_type"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{$.resource_type}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.standard"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{$.resource_spec}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.model_manager"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||||
{{$.datasetname}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain_creator"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||||
{{.User.Name}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{if eq .BenchmarkTypeName "BRAINSCORE"}} | |||||
{{$.i18n.Tr "cloudbrain.brain_area"}} | |||||
{{else}} | |||||
{{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_child_type"}} | |||||
{{end}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-BenchmarkChildTypeName"> | |||||
{{if $.BenchmarkChildTypeName}} | |||||
{{$.BenchmarkChildTypeName}} | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -471,9 +524,10 @@ td, th { | |||||
<div class="ui message message{{.VersionName}}" style="display: none;"> | <div class="ui message message{{.VersionName}}" style="display: none;"> | ||||
<div id="header"></div> | <div id="header"></div> | ||||
</div> | </div> | ||||
<div class="ui attached log" id="log{{.VersionName}}" style="height: 300px !important; overflow: auto;"> | |||||
<input type="hidden" name="end_line" value> | |||||
<input type="hidden" name="start_line" value> | |||||
<div class="ui attached log" id="log{{.VersionName}}" | |||||
style="height: 300px !important; overflow: auto;"> | |||||
<input type="hidden" name="end_line" value> | |||||
<input type="hidden" name="start_line" value> | |||||
<pre id="log_file{{.VersionName}}"></pre> | <pre id="log_file{{.VersionName}}"></pre> | ||||
</div> | </div> | ||||
@@ -512,19 +566,20 @@ td, th { | |||||
{{template "base/footer" .}} | {{template "base/footer" .}} | ||||
<script> | <script> | ||||
console.log({{.version_list_task }}) | |||||
$('.menu .item').tab() | $('.menu .item').tab() | ||||
$(document).ready(function(){ | |||||
$('.ui.accordion').accordion({selector:{trigger:'.icon'}}); | |||||
$(document).ready(function () { | |||||
$('.ui.accordion').accordion({ selector: { trigger: '.icon' } }); | |||||
}); | }); | ||||
$(document).ready(function(){ | |||||
$(document).ready(function () { | |||||
$('.secondary.menu .item').tab(); | $('.secondary.menu .item').tab(); | ||||
}); | }); | ||||
let userName | let userName | ||||
let repoPath | let repoPath | ||||
let jobName | let jobName | ||||
$(document).ready(function(){ | |||||
$(document).ready(function () { | |||||
let url = window.location.href; | let url = window.location.href; | ||||
let urlArr = url.split('/') | let urlArr = url.split('/') | ||||
userName = urlArr.slice(-5)[0] | userName = urlArr.slice(-5)[0] | ||||
@@ -532,17 +587,17 @@ td, th { | |||||
jobName = urlArr.slice(-1)[0] | jobName = urlArr.slice(-1)[0] | ||||
}) | }) | ||||
function loadLog(version_name){ | |||||
function loadLog(version_name) { | |||||
document.getElementById("mask").style.display = "block" | document.getElementById("mask").style.display = "block" | ||||
$.get(`/api/v1/repos/${userName}/${repoPath}/cloudbrain/${jobName}/log?version_name=${version_name}&lines=50&order=asc`, (data) => { | $.get(`/api/v1/repos/${userName}/${repoPath}/cloudbrain/${jobName}/log?version_name=${version_name}&lines=50&order=asc`, (data) => { | ||||
$('input[name=end_line]').val(data.EndLine) | $('input[name=end_line]').val(data.EndLine) | ||||
$('input[name=start_line]').val(data.StartLine) | $('input[name=start_line]').val(data.StartLine) | ||||
$(`#log_file${version_name}`).text(data.Content) | $(`#log_file${version_name}`).text(data.Content) | ||||
document.getElementById("mask").style.display = "none" | document.getElementById("mask").style.display = "none" | ||||
}).fail(function(err) { | |||||
}).fail(function (err) { | |||||
console.log(err); | console.log(err); | ||||
document.getElementById("mask").style.display = "none" | document.getElementById("mask").style.display = "none" | ||||
}); | }); | ||||
} | } | ||||
</script> | |||||
</script> |
@@ -20,8 +20,9 @@ | |||||
<span class="time-since poping up">{{.ModTime}}</span> | <span class="time-since poping up">{{.ModTime}}</span> | ||||
</td> | </td> | ||||
</tr> | </tr> | ||||
{{end}} | {{end}} | ||||
</tbody> | </tbody> | ||||
</table> | </table> | ||||
{{end}} | |||||
{{end}} |
@@ -1,171 +1,205 @@ | |||||
{{template "base/head" .}} | {{template "base/head" .}} | ||||
<style> | <style> | ||||
.according-panel-heading{ | |||||
box-sizing: border-box; | |||||
padding: 8px 16px; | |||||
color: #252b3a; | |||||
background-color: #f2f5fc; | |||||
line-height: 1.5; | |||||
cursor: pointer; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
} | |||||
.accordion-panel-title { | |||||
margin-top: 0; | |||||
margin-bottom: 0; | |||||
color: #252b3a; | |||||
} | |||||
.accordion-panel-title-content{ | |||||
vertical-align: middle; | |||||
display: inline-block; | |||||
width: calc(100% - 32px); | |||||
cursor: default; | |||||
} | |||||
.acc-margin-bottom { | |||||
margin-bottom: 5px; | |||||
} | |||||
.title_text { | |||||
font-size: 12px; | |||||
} | |||||
.ac-display-inblock { | |||||
display: inline-block; | |||||
} | |||||
.cti-mgRight-sm { | |||||
margin-right: 8px; | |||||
} | |||||
.ac-text-normal { | |||||
font-size: 14px; | |||||
color: #575d6c; | |||||
} | |||||
.uc-accordionTitle-black { | |||||
color: #333; | |||||
} | |||||
.accordion-border{ | |||||
border:1px solid #cce2ff; | |||||
} | |||||
.padding0{ | |||||
padding: 0 !important; | |||||
} | |||||
.content-pad{ | |||||
padding: 15px 35px; | |||||
} | |||||
.content-margin{ | |||||
margin:10px 5px ; | |||||
} | |||||
.tab_2_content { | |||||
min-height: 420px; | |||||
margin-left: 10px; | |||||
} | |||||
.ac-grid { | |||||
display: block; | |||||
*zoom: 1; | |||||
} | |||||
.ac-grid-col { | |||||
float: left; | |||||
width: 100%; | |||||
} | |||||
.ac-grid-col2 .ac-grid-col { | |||||
width: 50%; | |||||
} | |||||
.ti-form { | |||||
text-align: left; | |||||
max-width: 100%; | |||||
vertical-align: middle; | |||||
} | |||||
.ti-form>tbody { | |||||
font-size: 12px; | |||||
} | |||||
.ti-form>tbody, .ti-form>tbody>tr { | |||||
vertical-align: inherit; | |||||
} | |||||
.info_text { | |||||
padding-bottom: 20px; | |||||
padding-right: 20px; | |||||
font-size: 12px; | |||||
} | |||||
.ti-text-form-label { | |||||
padding-bottom: 20px; | |||||
padding-right: 20px; | |||||
color: #8a8e99; | |||||
font-size: 12px; | |||||
white-space: nowrap !important; | |||||
width: 80px; | |||||
line-height: 30px; | |||||
} | |||||
.ti-text-form-content{ | |||||
line-height: 30px; | |||||
padding-bottom: 20px; | |||||
} | |||||
.ti-form>tbody>tr>td { | |||||
vertical-align: top; | |||||
white-space: normal; | |||||
} | |||||
td, th { | |||||
padding: 0; | |||||
} | |||||
.ac-grid-col .text-span { | |||||
width: 450px; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
white-space: nowrap; | |||||
} | |||||
.redo-color{ | |||||
color: #3291F8; | |||||
} | |||||
.ti-action-menu-item:not(:last-child){ | |||||
margin-right: 10px; | |||||
padding-right: 11px; | |||||
text-decoration: none!important; | |||||
color: #526ecc; | |||||
cursor: pointer; | |||||
display: inline-block; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
position: relative; | |||||
} | |||||
.ti-action-menu-item:not(:last-child):after { | |||||
content: ""; | |||||
display: inline-block; | |||||
position: absolute; | |||||
height: 12px; | |||||
right: 0; | |||||
top: 50%; | |||||
-webkit-transform: translateY(-6px); | |||||
-ms-transform: translateY(-6px); | |||||
-o-transform: translateY(-6px); | |||||
transform: translateY(-6px); | |||||
border-right: 1px solid #dfe1e6; | |||||
} | |||||
.text-width80{ | |||||
width: 100px; | |||||
line-height: 30px; | |||||
} | |||||
.border-according{ | |||||
border: 1px solid #dfe1e6; | |||||
} | |||||
.disabled { | |||||
.according-panel-heading { | |||||
box-sizing: border-box; | |||||
padding: 8px 16px; | |||||
color: #252b3a; | |||||
background-color: #f2f5fc; | |||||
line-height: 1.5; | |||||
cursor: pointer; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
} | |||||
.accordion-panel-title { | |||||
margin-top: 0; | |||||
margin-bottom: 0; | |||||
color: #252b3a; | |||||
} | |||||
.accordion-panel-title-content { | |||||
vertical-align: middle; | |||||
display: inline-block; | |||||
width: calc(100% - 32px); | |||||
cursor: default; | |||||
} | |||||
.acc-margin-bottom { | |||||
margin-bottom: 5px; | |||||
} | |||||
.title_text { | |||||
font-size: 12px; | |||||
} | |||||
.ac-display-inblock { | |||||
display: inline-block; | |||||
} | |||||
.cti-mgRight-sm { | |||||
margin-right: 8px; | |||||
} | |||||
.ac-text-normal { | |||||
font-size: 14px; | |||||
color: #575d6c; | |||||
} | |||||
.uc-accordionTitle-black { | |||||
color: #333; | |||||
} | |||||
.accordion-border { | |||||
border: 1px solid #cce2ff; | |||||
} | |||||
.padding0 { | |||||
padding: 0 !important; | |||||
} | |||||
.content-pad { | |||||
padding: 15px 35px; | |||||
} | |||||
.content-margin { | |||||
margin: 10px 5px; | |||||
} | |||||
.tab_2_content { | |||||
min-height: 420px; | |||||
margin-left: 10px; | |||||
} | |||||
.ac-grid { | |||||
display: block; | |||||
*zoom: 1; | |||||
} | |||||
.ac-grid-col { | |||||
float: left; | |||||
width: 100%; | |||||
} | |||||
.ac-grid-col2 .ac-grid-col { | |||||
width: 50%; | |||||
} | |||||
.ti-form { | |||||
text-align: left; | |||||
max-width: 100%; | |||||
vertical-align: middle; | |||||
} | |||||
.ti-form>tbody { | |||||
font-size: 12px; | |||||
} | |||||
.ti-form>tbody, | |||||
.ti-form>tbody>tr { | |||||
vertical-align: inherit; | |||||
} | |||||
.info_text { | |||||
padding-bottom: 20px; | |||||
padding-right: 20px; | |||||
font-size: 12px; | |||||
} | |||||
.ti-text-form-label { | |||||
padding-bottom: 20px; | |||||
padding-right: 20px; | |||||
color: #8a8e99; | |||||
font-size: 12px; | |||||
white-space: nowrap !important; | |||||
width: 80px; | |||||
line-height: 30px; | |||||
} | |||||
.ti-text-form-content { | |||||
line-height: 30px; | |||||
padding-bottom: 20px; | |||||
} | |||||
.ti-form>tbody>tr>td { | |||||
vertical-align: top; | |||||
white-space: normal; | |||||
} | |||||
td, | |||||
th { | |||||
padding: 0; | |||||
} | |||||
.ac-grid-col .text-span { | |||||
width: 450px; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
white-space: nowrap; | |||||
} | |||||
.redo-color { | |||||
color: #3291F8; | |||||
} | |||||
.ti-action-menu-item:not(:last-child) { | |||||
margin-right: 10px; | |||||
padding-right: 11px; | |||||
text-decoration: none !important; | |||||
color: #526ecc; | |||||
cursor: pointer; | |||||
display: inline-block; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
position: relative; | |||||
} | |||||
.ti-action-menu-item:not(:last-child):after { | |||||
content: ""; | |||||
display: inline-block; | |||||
position: absolute; | |||||
height: 12px; | |||||
right: 0; | |||||
top: 50%; | |||||
-webkit-transform: translateY(-6px); | |||||
-ms-transform: translateY(-6px); | |||||
-o-transform: translateY(-6px); | |||||
transform: translateY(-6px); | |||||
border-right: 1px solid #dfe1e6; | |||||
} | |||||
.text-width80 { | |||||
width: 100px; | |||||
line-height: 30px; | |||||
} | |||||
.border-according { | |||||
border: 1px solid #dfe1e6; | |||||
} | |||||
.disabled { | |||||
cursor: default; | cursor: default; | ||||
pointer-events: none; | pointer-events: none; | ||||
color: rgba(0,0,0,.6) !important; | |||||
color: rgba(0, 0, 0, .6) !important; | |||||
opacity: .45 !important; | opacity: .45 !important; | ||||
} | |||||
.pad20{ | |||||
border:0px !important; | |||||
} | |||||
.model_file_bread{ | |||||
margin-bottom: -0.5rem !important; | |||||
padding-left: 1rem; | |||||
padding-top: 0.5rem ; | |||||
} | |||||
} | |||||
.pad20 { | |||||
border: 0px !important; | |||||
} | |||||
.model_file_bread { | |||||
margin-bottom: -0.5rem !important; | |||||
padding-left: 1rem; | |||||
padding-top: 0.5rem; | |||||
} | |||||
</style> | </style> | ||||
@@ -179,7 +213,7 @@ td, th { | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="repository"> | <div class="repository"> | ||||
{{template "repo/header" .}} | |||||
{{template "repo/header" .}} | |||||
<div class="ui container"> | <div class="ui container"> | ||||
<h4 class="ui header" id="vertical-segment"> | <h4 class="ui header" id="vertical-segment"> | ||||
<div class="ui breadcrumb"> | <div class="ui breadcrumb"> | ||||
@@ -191,11 +225,12 @@ td, th { | |||||
{{$.i18n.Tr "repo.modelarts.notebook"}} | {{$.i18n.Tr "repo.modelarts.notebook"}} | ||||
</a> | </a> | ||||
<div class="divider"> / </div> | <div class="divider"> / </div> | ||||
<div class="active section">{{.displayJobName}}</div> | |||||
</div> | |||||
<div class="active section">{{.displayJobName}}</div> | |||||
</div> | |||||
</h4> | </h4> | ||||
{{range $k ,$v := .version_list_task}} | {{range $k ,$v := .version_list_task}} | ||||
<div class="ui accordion border-according" id="accordion{{.VersionName}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}" data-version="{{.VersionName}}"> | |||||
<div class="ui accordion border-according" id="accordion{{.VersionName}}" | |||||
data-repopath="{{$.RepoRelPath}}/cloudbrain" data-jobid="{{.ID}}" data-version="{{.VersionName}}"> | |||||
<input type="hidden" id="jobId_input" name="jobId_input" value="{{.JobID}}"> | <input type="hidden" id="jobId_input" name="jobId_input" value="{{.JobID}}"> | ||||
<div class="{{if eq $k 0}}active{{end}} title padding0"> | <div class="{{if eq $k 0}}active{{end}} title padding0"> | ||||
<div class="according-panel-heading"> | <div class="according-panel-heading"> | ||||
@@ -205,19 +240,26 @@ td, th { | |||||
<span> | <span> | ||||
<div class="ac-display-inblock title_text acc-margin-bottom"> | <div class="ac-display-inblock title_text acc-margin-bottom"> | ||||
<span class="cti-mgRight-sm"> | <span class="cti-mgRight-sm"> | ||||
{{if not (eq .StartTime 0)}} | |||||
<td>{{TimeSinceUnix1 .StartTime}}</td> | |||||
{{else}} | |||||
<td>{{TimeSinceUnix1 .CreatedUnix}}<td> | |||||
{{end}} | |||||
</span> | |||||
{{if not (eq .StartTime 0)}} | |||||
<td>{{TimeSinceUnix1 .StartTime}}</td> | |||||
{{else}} | |||||
<td>{{TimeSinceUnix1 .CreatedUnix}} | |||||
<td> | |||||
{{end}} | |||||
</span> | |||||
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}: | <span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}: | ||||
<span id="{{.VersionName}}-status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
<span id="{{.VersionName}}-status-span"><i id="icon" | |||||
style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" | |||||
style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
</span> | </span> | ||||
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span> | |||||
<span class="cti-mgRight-sm uc-accordionTitle-black" id="{{.VersionName}}-duration-span">{{$.duration}}</span> | |||||
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}: | |||||
</span> | |||||
<span class="cti-mgRight-sm uc-accordionTitle-black" | |||||
id="{{.VersionName}}-duration-span">{{$.duration}}</span> | |||||
<span data-tooltip="刷新" style="cursor: pointer;" data-inverted="" | |||||
onclick="refreshStatus({{.VersionName}})"><i | |||||
class="redo icon redo-color"></i></span> | |||||
</div> | </div> | ||||
</span> | </span> | ||||
</span> | </span> | ||||
@@ -227,8 +269,10 @@ td, th { | |||||
<div class="{{if eq $k 0}}active{{end}} content"> | <div class="{{if eq $k 0}}active{{end}} content"> | ||||
<div class="content-pad"> | <div class="content-pad"> | ||||
<div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);"> | <div class="ui pointing secondary menu" style="border-bottom: 1px solid rgba(34,36,38,.15);"> | ||||
<a class="active item" data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a> | |||||
<a class="item" data-tab="second{{$k}}" onclick="javascript:parseLog()">{{$.i18n.Tr "repo.cloudbrain.runinfo"}}</a> | |||||
<a class="active item" | |||||
data-tab="first{{$k}}">{{$.i18n.Tr "repo.modelarts.train_job.config"}}</a> | |||||
<a class="item" data-tab="second{{$k}}" | |||||
onclick="javascript:parseLog()">{{$.i18n.Tr "repo.cloudbrain.runinfo"}}</a> | |||||
</div> | </div> | ||||
<div class="ui tab active" data-tab="first{{$k}}"> | <div class="ui tab active" data-tab="first{{$k}}"> | ||||
<div style="padding-top: 10px;"> | <div style="padding-top: 10px;"> | ||||
@@ -259,192 +303,199 @@ td, th { | |||||
</td> | </td> | ||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain_creator"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||||
{{.User.Name}} | |||||
</div> | |||||
</td> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain_creator"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||||
{{.User.Name}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.computing_resources"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-computeresource"> | |||||
{{.ComputeResource}} | |||||
</div> | |||||
</td> | |||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.computing_resources"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-computeresource"> | |||||
{{.ComputeResource}} | |||||
</div> | |||||
</td> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.task_type"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-computeresource"> | |||||
{{.JobType}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.code_version"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-code"> | |||||
{{.BranchName}} | |||||
</div> | |||||
</td> | |||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.task_type"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-computeresource"> | |||||
{{.JobType}} | |||||
</div> | |||||
</td> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.gpu_type"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{$.resource_type}} | |||||
</div> | |||||
</td> | |||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.code_version"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-code"> | |||||
{{.BranchName}} | |||||
</div> | |||||
</td> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.createtime"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-createtime"> | |||||
{{TimeSinceUnix1 .CreatedUnix}} | |||||
</div> | |||||
</td> | |||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.gpu_type"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{$.resource_type}} | |||||
</div> | |||||
</td> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-duration"> | |||||
{{$.duration}} | |||||
</div> | |||||
</td> | |||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.createtime"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-createtime"> | |||||
{{TimeSinceUnix1 .CreatedUnix}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-duration"> | |||||
{{$.duration}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
</tbody> | </tbody> | ||||
</table> | </table> | ||||
</div> | </div> | ||||
<div class="ac-grid-col"> | <div class="ac-grid-col"> | ||||
<table class="ti-form"> | |||||
<tbody class="ti-text-form"> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.mirror"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||||
{{.Image}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.dataset"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-BenchmarkTypeName"> | |||||
{{$.datasetname}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.standard"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{$.i18n.Tr "cloudbrain.gpu_num"}}:{{$.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{$.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{$.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{$.ShareMemMiB}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.dataset_storage_path"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="dataset_storage_path"> | |||||
<table class="ti-form"> | |||||
<tbody class="ti-text-form"> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.mirror"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||||
{{.Image}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.dataset"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-BenchmarkTypeName"> | |||||
{{$.datasetname}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.standard"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{$.i18n.Tr "cloudbrain.gpu_num"}}:{{$.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{$.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{$.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{$.ShareMemMiB}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.dataset_storage_path"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="dataset_storage_path"> | |||||
{{$.dataset_path}} | {{$.dataset_path}} | ||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.model_storage_path"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="model_storage_path"> | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.model_storage_path"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="model_storage_path"> | |||||
{{$.model_path}} | {{$.model_path}} | ||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.code_storage_path"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="code_storage_path"> | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.code_storage_path"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="code_storage_path"> | |||||
{{$.code_path}} | {{$.code_path}} | ||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.time.starttime"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-startTime"> | |||||
{{if not (eq .StartTime 0)}} | |||||
{{TimeSinceUnix1 .StartTime}} | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.time.endtime"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-EndTime"> | |||||
{{if not (eq .EndTime 0)}} | |||||
{{TimeSinceUnix1 .EndTime}} | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.time.starttime"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-startTime"> | |||||
{{if not (eq .StartTime 0)}} | |||||
{{TimeSinceUnix1 .StartTime}} | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.time.endtime"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-EndTime"> | |||||
{{if not (eq .EndTime 0)}} | |||||
{{TimeSinceUnix1 .EndTime}} | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -455,10 +506,11 @@ td, th { | |||||
<div class="ui message message{{.VersionName}}" style="display: none;"> | <div class="ui message message{{.VersionName}}" style="display: none;"> | ||||
<div id="header"></div> | <div id="header"></div> | ||||
</div> | </div> | ||||
<div class="ui attached log" id="log{{.VersionName}}" style="height: 390px !important; overflow: auto;"> | |||||
<div class="ui attached log" id="log{{.VersionName}}" | |||||
style="height: 390px !important; overflow: auto;"> | |||||
<input type="hidden" id="json_value" value="{{$.result.JobStatus.AppExitDiagnostics}}"> | <input type="hidden" id="json_value" value="{{$.result.JobStatus.AppExitDiagnostics}}"> | ||||
<span id="info_display" class="info_text"> | <span id="info_display" class="info_text"> | ||||
</span> | </span> | ||||
</div> | </div> | ||||
@@ -498,38 +550,71 @@ td, th { | |||||
<script> | <script> | ||||
$('.menu .item').tab() | $('.menu .item').tab() | ||||
$(document).ready(function(){ | |||||
$('.ui.accordion').accordion({selector:{trigger:'.icon'}}); | |||||
$(document).ready(function () { | |||||
$('.ui.accordion').accordion({ selector: { trigger: '.icon' } }); | |||||
}); | }); | ||||
$(document).ready(function(){ | |||||
$(document).ready(function () { | |||||
$('.secondary.menu .item').tab(); | $('.secondary.menu .item').tab(); | ||||
}); | }); | ||||
function parseLog(){ | |||||
let jsonValue = document.getElementById("json_value").value; | |||||
let jsonObj = JSON.parse(jsonValue); | |||||
let podRoleName = jsonObj["podRoleName"]; | |||||
let html = ""; | |||||
if (podRoleName != null){ | |||||
let task0 = podRoleName["task1-0"]; | |||||
let podEvents = jsonObj["podEvents"]; | |||||
let podEventArray = podEvents[task0]; | |||||
if(podEventArray != null){ | |||||
for(var i=0; i < podEventArray.length;i++){ | |||||
html +="<p><b>[" +podEventArray[i]["reason"] + "]</b></p>"; | |||||
html +="<p>" +podEventArray[i]["message"] + "</p>"; | |||||
html +="<p>" +podEventArray[i]["action"] + "</p>"; | |||||
} | |||||
} | |||||
let extras= jsonObj["extras"]; | |||||
if(extras != null){ | |||||
for(var i=0; i < extras.length;i++){ | |||||
html +="<p><b>[" +extras[i]["reason"] + "]</b></p>"; | |||||
html +="<p>" +extras[i]["message"] + "</p>"; | |||||
html +="<p>" +extras[i]["action"] + "</p>"; | |||||
function parseLog() { | |||||
let jsonValue = document.getElementById("json_value").value; | |||||
let jsonObj = JSON.parse(jsonValue); | |||||
let podRoleName = jsonObj["podRoleName"]; | |||||
let html = ""; | |||||
if (podRoleName != null) { | |||||
let task0 = podRoleName["task1-0"]; | |||||
let podEvents = jsonObj["podEvents"]; | |||||
let podEventArray = podEvents[task0]; | |||||
if (podEventArray != null) { | |||||
for (var i = 0; i < podEventArray.length; i++) { | |||||
if (podEventArray[i]["reason"] != "") { | |||||
html += "<p><b>[" + podEventArray[i]["reason"] + "]</b></p>"; | |||||
html += "<p>" + podEventArray[i]["message"] + "</p>"; | |||||
html += "<p>" + podEventArray[i]["action"] + "</p>"; | |||||
} | |||||
} | |||||
} | |||||
let extras = jsonObj["extras"]; | |||||
if (extras != null) { | |||||
for (var i = 0; i < extras.length; i++) { | |||||
if (extras[i]["reason"] != "") { | |||||
html += "<p><b>[" + extras[i]["reason"] + "]</b></p>"; | |||||
html += "<p>" + extras[i]["message"] + "</p>"; | |||||
html += "<p>" + extras[i]["action"] + "</p>"; | |||||
} | |||||
} | |||||
} | } | ||||
} | |||||
} | |||||
document.getElementById("info_display").innerHTML = html; | |||||
} | |||||
function stopBubbling(e) { | |||||
e = window.event || e; | |||||
if (e.stopPropagation) { | |||||
e.stopPropagation(); //阻止事件 冒泡传播 | |||||
} else { | |||||
e.cancelBubble = true; //ie兼容 | |||||
} | |||||
} | |||||
function refreshStatus(version_name) { | |||||
$(".ui.accordion.border-according").each((index, job) => { | |||||
const jobID = job.dataset.jobid; | |||||
const repoPath = job.dataset.repopath; | |||||
const versionname = job.dataset.version | |||||
$.get(`/api/v1/repos/${repoPath}/cloudbrain/${jobID}?version_name=${versionname}`, (data) => { | |||||
// header status and duration | |||||
//$(`#${version_name}-duration-span`).text(data.JobDuration) | |||||
$(`#${version_name}-status-span span`).text(data.JobStatus) | |||||
$(`#${version_name}-status-span i`).attr("class", data.JobStatus) | |||||
// detail status and duration | |||||
//$('#'+version_name+'-duration').text(data.JobDuration) | |||||
$('#' + version_name + '-status').text(data.JobStatus) | |||||
parseLog() | |||||
}).fail(function (err) { | |||||
console.log(err); | |||||
}); | |||||
stopBubbling(arguments.callee.caller.arguments[0]) | |||||
}) | |||||
} | } | ||||
document.getElementById("info_display").innerHTML=html; | |||||
} | |||||
</script> | </script> |
@@ -2,20 +2,23 @@ | |||||
{{template "base/head" .}} | {{template "base/head" .}} | ||||
<style> | <style> | ||||
.label_after::after{ | |||||
.label_after::after { | |||||
margin: -.2em 0 0 .2em; | margin: -.2em 0 0 .2em; | ||||
content: '\00a0'; | content: '\00a0'; | ||||
} | |||||
.selectcloudbrain .active.item{ | |||||
} | |||||
.selectcloudbrain .active.item { | |||||
color: #0087f5 !important; | color: #0087f5 !important; | ||||
border: 1px solid #0087f5; | border: 1px solid #0087f5; | ||||
margin: -1px; | margin: -1px; | ||||
background: #FFF !important; | background: #FFF !important; | ||||
} | } | ||||
#deletemodel { | #deletemodel { | ||||
width: 100%; | width: 100%; | ||||
height: 100%; | height: 100%; | ||||
} | } | ||||
/* 弹窗 */ | /* 弹窗 */ | ||||
#mask { | #mask { | ||||
@@ -73,28 +76,33 @@ | |||||
} | } | ||||
@-webkit-keyframes sk-stretchdelay { | @-webkit-keyframes sk-stretchdelay { | ||||
0%, | 0%, | ||||
40%, | 40%, | ||||
100% { | 100% { | ||||
-webkit-transform: scaleY(0.4) | -webkit-transform: scaleY(0.4) | ||||
} | } | ||||
20% { | 20% { | ||||
-webkit-transform: scaleY(1.0) | -webkit-transform: scaleY(1.0) | ||||
} | } | ||||
} | } | ||||
@keyframes sk-stretchdelay { | @keyframes sk-stretchdelay { | ||||
0%, | 0%, | ||||
40%, | 40%, | ||||
100% { | 100% { | ||||
transform: scaleY(0.4); | transform: scaleY(0.4); | ||||
-webkit-transform: scaleY(0.4); | -webkit-transform: scaleY(0.4); | ||||
} | } | ||||
20% { | 20% { | ||||
transform: scaleY(1.0); | transform: scaleY(1.0); | ||||
-webkit-transform: scaleY(1.0); | -webkit-transform: scaleY(1.0); | ||||
} | } | ||||
} | } | ||||
/* 消息框 */ | /* 消息框 */ | ||||
.alert { | .alert { | ||||
@@ -137,6 +145,7 @@ | |||||
width: calc(100% - 260px); | width: calc(100% - 260px); | ||||
box-sizing: border-box; | box-sizing: border-box; | ||||
} | } | ||||
/* 弹窗 (background) */ | /* 弹窗 (background) */ | ||||
#imageModal { | #imageModal { | ||||
@@ -151,6 +160,7 @@ | |||||
background-color: rgb(0, 0, 0); | background-color: rgb(0, 0, 0); | ||||
background-color: rgba(0, 0, 0, 0.4); | background-color: rgba(0, 0, 0, 0.4); | ||||
} | } | ||||
/* 弹窗内容 */ | /* 弹窗内容 */ | ||||
.modal-content { | .modal-content { | ||||
@@ -160,6 +170,7 @@ | |||||
border: 1px solid #888; | border: 1px solid #888; | ||||
width: 30%; | width: 30%; | ||||
} | } | ||||
/* 关闭按钮 */ | /* 关闭按钮 */ | ||||
.close { | .close { | ||||
@@ -184,12 +195,12 @@ | |||||
cursor: pointer; | cursor: pointer; | ||||
pointer-events: none; | pointer-events: none; | ||||
} | } | ||||
.time-show{ | |||||
.time-show { | |||||
font-size: 10px; | font-size: 10px; | ||||
margin-top: 0.4rem; | margin-top: 0.4rem; | ||||
display: inline-block; | display: inline-block; | ||||
} | } | ||||
</style> | </style> | ||||
<!-- 弹窗 --> | <!-- 弹窗 --> | ||||
@@ -208,49 +219,56 @@ | |||||
{{template "repo/header" .}} | {{template "repo/header" .}} | ||||
{{template "base/alert" .}} | {{template "base/alert" .}} | ||||
<!-- 提示框 --> | <!-- 提示框 --> | ||||
<div class="cloudbrain_debug" style="display: none;" data-debug="{{$.i18n.Tr "repo.debug"}}" data-debug-again="{{$.i18n.Tr "repo.debug_again"}}"></div> | |||||
<div class="cloudbrain_debug" style="display: none;" data-debug="{{$.i18n.Tr "repo.debug"}}" | |||||
data-debug-again="{{$.i18n.Tr "repo.debug_again"}}"></div> | |||||
<!-- 列表容器 --> | <!-- 列表容器 --> | ||||
<div class="ui container"> | <div class="ui container"> | ||||
<div class="ui two column stackable grid"> | <div class="ui two column stackable grid"> | ||||
<div class="column"> | |||||
<div class="ui blue small menu compact selectcloudbrain"> | |||||
<a class="active item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||||
<a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | |||||
<a class="item" href="{{.RepoLink}}/modelarts/inference-job">{{$.i18n.Tr "repo.modelarts.infer_job"}}</a> | |||||
<a class="item" href="{{.RepoLink}}/cloudbrain/benchmark">{{$.i18n.Tr "repo.modelarts.evaluate_job"}}</a> | |||||
</div> | |||||
<div class="column"> | |||||
<div class="ui blue small menu compact selectcloudbrain"> | |||||
<a class="active item" | |||||
href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a> | |||||
<a class="item" | |||||
href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a> | |||||
<a class="item" | |||||
href="{{.RepoLink}}/modelarts/inference-job">{{$.i18n.Tr "repo.modelarts.infer_job"}}</a> | |||||
<a class="item" | |||||
href="{{.RepoLink}}/cloudbrain/benchmark">{{$.i18n.Tr "repo.modelarts.evaluate_job"}}</a> | |||||
</div> | </div> | ||||
<div class="column right aligned"> | |||||
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | |||||
{{svg "octicon-server" 16}} | |||||
<div class="default text" style="color: rgba(0,0,0,.87);"></div> | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu"> | |||||
<div class="item" data-value="all">{{$.i18n.Tr "repo.gpu_type_all"}}</div> | |||||
<div class="item" data-value="CPU/GPU">CPU/GPU</div> | |||||
<div class="item" data-value="NPU">NPU</div> | |||||
</div> | |||||
</div> | |||||
<div class="column right aligned"> | |||||
<div class="ui selection dropdown" | |||||
style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | |||||
{{svg "octicon-server" 16}} | |||||
<div class="default text" style="color: rgba(0,0,0,.87);"></div> | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu"> | |||||
<div class="item" data-value="all">{{$.i18n.Tr "repo.gpu_type_all"}}</div> | |||||
<div class="item" data-value="CPU/GPU">CPU/GPU</div> | |||||
<div class="item" data-value="NPU">NPU</div> | |||||
</div> | </div> | ||||
{{if .Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
<a class="ui green button" href="{{.RepoLink}}/cloudbrain/create">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a> | |||||
{{else}} | |||||
<a class="ui disabled button">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a> | |||||
{{end}} | |||||
</div> | </div> | ||||
{{if .Permission.CanWrite $.UnitTypeCloudBrain}} | |||||
<a class="ui green button" | |||||
href="{{.RepoLink}}/cloudbrain/create">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a> | |||||
{{else}} | |||||
<a class="ui disabled button">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a> | |||||
{{end}} | |||||
</div> | |||||
</div> | </div> | ||||
{{if eq 0 (len .Tasks)}} | {{if eq 0 (len .Tasks)}} | ||||
<div class="ui placeholder segment bgtask-none"> | <div class="ui placeholder segment bgtask-none"> | ||||
<div class="ui icon header bgtask-header-pic"></div> | |||||
<div class="bgtask-content-header">{{$.i18n.Tr "repo.debug_task_not_created"}}</div> | |||||
<div class="bgtask-content"> | |||||
{{if $.RepoIsEmpty}} | |||||
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.repo_not_initialized" .RepoLink | Safe}}</div> | |||||
{{end}} | |||||
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.debug_task_running_limit"}}</div> | |||||
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.dataset_desc"}}</div> | |||||
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.platform_instructions" | Safe}}</div> | |||||
</div> | |||||
<div class="ui icon header bgtask-header-pic"></div> | |||||
<div class="bgtask-content-header">{{$.i18n.Tr "repo.debug_task_not_created"}}</div> | |||||
<div class="bgtask-content"> | |||||
{{if $.RepoIsEmpty}} | |||||
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.repo_not_initialized" .RepoLink | Safe}}</div> | |||||
{{end}} | |||||
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.debug_task_running_limit"}}</div> | |||||
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.dataset_desc"}}</div> | |||||
<div class="bgtask-content-txt">{{$.i18n.Tr "repo.platform_instructions" | Safe}}</div> | |||||
</div> | |||||
</div> | </div> | ||||
{{else}} | {{else}} | ||||
<!-- 中下列表展示区 --> | <!-- 中下列表展示区 --> | ||||
@@ -287,29 +305,40 @@ | |||||
<div class="row"> | <div class="row"> | ||||
<!-- 任务名 --> | <!-- 任务名 --> | ||||
<div class="four wide column"> | <div class="four wide column"> | ||||
<a class="title" href='{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain/{{.Cloudbrain.ID}}{{else}}{{$.RepoLink}}/modelarts/notebook/{{.Cloudbrain.ID}}{{end}}' title="{{.JobName}}" style="font-size: 14px;"> | |||||
<span class="fitted text_over" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> | |||||
<a class="title" | |||||
href='{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain/{{.Cloudbrain.ID}}{{else}}{{$.RepoLink}}/modelarts/notebook/{{.Cloudbrain.ID}}{{end}}' | |||||
title="{{.DisplayJobName}}" style="font-size: 14px;"> | |||||
<span class="fitted text_over" | |||||
style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> | |||||
</a> | </a> | ||||
</div> | </div> | ||||
<div class="two wide column text center"> | <div class="two wide column text center"> | ||||
<!--任务状态 --> | |||||
<span class="job-status" id="{{.Cloudbrain.ID}}" data-repopath="{{$.RepoRelPath}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}" data-jobid="{{.Cloudbrain.ID}}" data-resource="{{.ComputeResource}}"> | |||||
<span><i id="{{.Cloudbrain.ID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.Cloudbrain.ID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
<!--任务状态 --> | |||||
<span class="job-status" id="{{.Cloudbrain.ID}}" | |||||
data-repopath="{{$.RepoRelPath}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}" | |||||
data-jobid="{{.Cloudbrain.ID}}" data-resource="{{.ComputeResource}}"> | |||||
<span><i id="{{.Cloudbrain.ID}}-icon" style="vertical-align: middle;" | |||||
class="{{.Status}}"></i><span id="{{.Cloudbrain.ID}}-text" | |||||
style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
</span> | </span> | ||||
</div> | </div> | ||||
<div class="two wide column text center"> | <div class="two wide column text center"> | ||||
<!-- 任务创建时间 --> | <!-- 任务创建时间 --> | ||||
<span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | |||||
<span style="font-size: 12px;margin-left: 0.4rem;" | |||||
class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | |||||
</div> | </div> | ||||
<div class="two wide column text center"> | <div class="two wide column text center"> | ||||
<!-- 任务计算资源 --> | |||||
<span style="font-size: 12px;margin-left: 0.4rem;" class="">{{.ComputeResource}}</span> | |||||
<!-- 任务计算资源 --> | |||||
<span style="font-size: 12px;margin-left: 0.4rem;" | |||||
class="">{{.ComputeResource}}</span> | |||||
</div> | </div> | ||||
<div class="one wide column text center"> | <div class="one wide column text center"> | ||||
{{if .User.Name}} | {{if .User.Name}} | ||||
<a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a> | |||||
<a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img | |||||
class="ui avatar image" src="{{.User.RelAvatarLink}}"></a> | |||||
{{else}} | {{else}} | ||||
<a title="Ghost"><img class="ui avatar image" src="{{AppSubUrl}}/user/avatar/Ghost/-1"></a> | |||||
<a title="Ghost"><img class="ui avatar image" | |||||
src="{{AppSubUrl}}/user/avatar/Ghost/-1"></a> | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
<div class="five wide column text center"> | <div class="five wide column text center"> | ||||
@@ -323,79 +352,103 @@ | |||||
<form id="debugAgainForm-{{.Cloudbrain.ID}}"> | <form id="debugAgainForm-{{.Cloudbrain.ID}}"> | ||||
{{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
{{if .CanDebug}} | {{if .CanDebug}} | ||||
{{if eq .Status "RUNNING" "WAITING" "CREATING" "STARTING"}} | |||||
<a style="margin: 0 1rem;" id="ai-debug-{{.Cloudbrain.ID}}" class='ui basic ai_debug {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING"}}disabled {{else}}blue {{end}}button' data-jobid="{{.Cloudbrain.ID}}" data-repopath='{{$.RepoLink}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}/{{.Cloudbrain.ID}}/'> | |||||
{{$.i18n.Tr "repo.debug"}} | |||||
</a> | |||||
{{else}} | |||||
<a id="ai-debug-{{.Cloudbrain.ID}}" class='ui basic ai_debug {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING"}} disabled {{else}}blue {{end}}button' data-jobid="{{.Cloudbrain.ID}}" data-repopath='{{$.RepoLink}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}/{{.Cloudbrain.ID}}/' data-linkpath='{{$.Link}}'> | |||||
{{$.i18n.Tr "repo.debug_again"}} | |||||
</a> | |||||
{{end}} | |||||
{{if eq .Status "RUNNING" "WAITING" "CREATING" "STARTING"}} | |||||
<a style="margin: 0 1rem;" id="ai-debug-{{.Cloudbrain.ID}}" | |||||
class='ui basic ai_debug {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING"}}disabled {{else}}blue {{end}}button' | |||||
data-jobid="{{.Cloudbrain.ID}}" | |||||
data-repopath='{{$.RepoLink}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}/{{.Cloudbrain.ID}}/'> | |||||
{{$.i18n.Tr "repo.debug"}} | |||||
</a> | |||||
{{else}} | {{else}} | ||||
{{if eq .Status "RUNNING" "WAITING" "CREATING" "STARTING"}} | |||||
<a class="ui basic disabled button"> | |||||
{{$.i18n.Tr "repo.debug"}} | |||||
</a> | |||||
{{else}} | |||||
<a class="ui basic disabled button"> | |||||
{{$.i18n.Tr "repo.debug_again"}} | |||||
</a> | |||||
{{end}} | |||||
<a id="ai-debug-{{.Cloudbrain.ID}}" | |||||
class='ui basic ai_debug {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING"}} disabled {{else}}blue {{end}}button' | |||||
data-jobid="{{.Cloudbrain.ID}}" | |||||
data-repopath='{{$.RepoLink}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}/{{.Cloudbrain.ID}}/' | |||||
data-linkpath='{{$.Link}}'> | |||||
{{$.i18n.Tr "repo.debug_again"}} | |||||
</a> | |||||
{{end}} | |||||
{{else}} | |||||
{{if eq .Status "RUNNING" "WAITING" "CREATING" "STARTING"}} | |||||
<a class="ui basic disabled button"> | |||||
{{$.i18n.Tr "repo.debug"}} | |||||
</a> | |||||
{{else}} | |||||
<a class="ui basic disabled button"> | |||||
{{$.i18n.Tr "repo.debug_again"}} | |||||
</a> | |||||
{{end}} | |||||
{{end}} | {{end}} | ||||
</form> | </form> | ||||
<!-- 停止 --> | <!-- 停止 --> | ||||
<form id="stopForm-{{.Cloudbrain.ID}}" style="margin-left:-1px;"> | |||||
<form id="stopForm-{{.Cloudbrain.ID}}" style="margin-left:-1px;"> | |||||
{{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
{{if .CanDel}} | {{if .CanDel}} | ||||
<a id="ai-stop-{{.Cloudbrain.ID}}" class='ui basic ai_stop {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING" "SUCCEEDED"}}disabled {{else}}blue {{end}}button' data-repopath="{{$.RepoLink}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}/{{.Cloudbrain.ID}}/stop" data-jobid="{{.Cloudbrain.ID}}"> | |||||
<a id="ai-stop-{{.Cloudbrain.ID}}" | |||||
class='ui basic ai_stop {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING" "SUCCEEDED"}}disabled {{else}}blue {{end}}button' | |||||
data-repopath="{{$.RepoLink}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}/{{.Cloudbrain.ID}}/stop" | |||||
data-jobid="{{.Cloudbrain.ID}}"> | |||||
{{$.i18n.Tr "repo.stop"}} | {{$.i18n.Tr "repo.stop"}} | ||||
</a> | </a> | ||||
{{else}} | {{else}} | ||||
<a class="ui basic disabled button"> | |||||
{{$.i18n.Tr "repo.stop"}} | |||||
<a class="ui basic disabled button"> | |||||
{{$.i18n.Tr "repo.stop"}} | |||||
</a> | </a> | ||||
{{end}} | {{end}} | ||||
</form> | </form> | ||||
<!-- 删除 --> | <!-- 删除 --> | ||||
<form id="delForm-{{.Cloudbrain.ID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.Cloudbrain.ID}}/del" method="post"> | |||||
<form id="delForm-{{.Cloudbrain.ID}}" | |||||
action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.Cloudbrain.ID}}/del" | |||||
method="post"> | |||||
<input type="hidden" name="debugListType" value="{{$.ListType}}"> | <input type="hidden" name="debugListType" value="{{$.ListType}}"> | ||||
{{$.CsrfTokenHtml}} | {{$.CsrfTokenHtml}} | ||||
{{if .CanDel}} | {{if .CanDel}} | ||||
<a id="ai-delete-{{.Cloudbrain.ID}}" class='ui basic ai_delete {{if eq .Status "STOPPED" "FAILED" "START_FAILED"}}blue {{else}}disabled {{end}}button' style="border-radius: .28571429rem;"> | |||||
<a id="ai-delete-{{.Cloudbrain.ID}}" | |||||
class='ui basic ai_delete {{if eq .Status "STOPPED" "FAILED" "START_FAILED"}}blue {{else}}disabled {{end}}button' | |||||
style="border-radius: .28571429rem;"> | |||||
{{$.i18n.Tr "repo.delete"}} | {{$.i18n.Tr "repo.delete"}} | ||||
</a> | </a> | ||||
{{else}} | {{else}} | ||||
<a class="ui basic button disabled" style="border-radius: .28571429rem;"> | |||||
<a class="ui basic button disabled" style="border-radius: .28571429rem;"> | |||||
{{$.i18n.Tr "repo.delete"}} | {{$.i18n.Tr "repo.delete"}} | ||||
</a> | </a> | ||||
{{end}} | {{end}} | ||||
</form> | </form> | ||||
</div> | </div> | ||||
<div class="ui compact buttons" style="{{if eq .ComputeResource "CPU/GPU"}} visibility: visible {{else}} visibility: hidden{{end}}"> | |||||
<div class="ui dropdown" id="model_more" style="padding: .58928571em 1.125em .58928571em;"> | |||||
<div class="ui compact buttons" | |||||
style="{{if eq .ComputeResource "CPU/GPU"}} visibility: visible {{else}} visibility: hidden{{end}}"> | |||||
<div class="ui dropdown" id="model_more" | |||||
style="padding: .58928571em 1.125em .58928571em;"> | |||||
<div class="text">{{$.i18n.Tr "repo.more"}}</div> | <div class="text">{{$.i18n.Tr "repo.more"}}</div> | ||||
<i class="dropdown icon"></i> | <i class="dropdown icon"></i> | ||||
<div class="menu" style="right: auto;"> | <div class="menu" style="right: auto;"> | ||||
<div class="item" style="padding: 0 !important;"> | <div class="item" style="padding: 0 !important;"> | ||||
{{if .CanDebug}} | {{if .CanDebug}} | ||||
<a id="model-image-{{.Cloudbrain.ID}}" class='imageBtn ui basic {{if ne .Status "RUNNING"}}disabled {{else}}blue {{end}}button' href="{{$.RepoLink}}/cloudbrain/{{.Cloudbrain.ID}}/commit_image">{{$.i18n.Tr "repo.submit_image"}}</a> | |||||
<a id="model-image-{{.Cloudbrain.ID}}" | |||||
class='imageBtn ui basic {{if ne .Status "RUNNING"}}disabled {{else}}blue {{end}}button' | |||||
href="{{$.RepoLink}}/cloudbrain/{{.Cloudbrain.ID}}/commit_image">{{$.i18n.Tr "repo.submit_image"}}</a> | |||||
{{else}} | {{else}} | ||||
<a class="imageBtn ui basic disabled button">{{$.i18n.Tr "repo.submit_image"}}</a> | |||||
<a | |||||
class="imageBtn ui basic disabled button">{{$.i18n.Tr "repo.submit_image"}}</a> | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
<div class="item" style="padding: 0 !important;"> | <div class="item" style="padding: 0 !important;"> | ||||
<!-- 模型下载 --> | |||||
<!-- 模型下载 --> | |||||
{{if .CanDebug}} | {{if .CanDebug}} | ||||
<a class="ui basic blue button" href="{{$.RepoLink}}/cloudbrain/{{.Cloudbrain.ID}}/models" target="_blank">{{$.i18n.Tr "repo.download"}}</a> | |||||
<a class="ui basic blue button" | |||||
href="{{$.RepoLink}}/cloudbrain/{{.Cloudbrain.ID}}/models" | |||||
target="_blank">{{$.i18n.Tr "repo.download"}}</a> | |||||
{{else}} | {{else}} | ||||
<a class="ui basic disabled button">{{$.i18n.Tr "repo.download"}}</a> | |||||
<a | |||||
class="ui basic disabled button">{{$.i18n.Tr "repo.download"}}</a> | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
{{if and (ne .JobType "DEBUG") (eq .Cloudbrain.Type 0)}} | {{if and (ne .JobType "DEBUG") (eq .Cloudbrain.Type 0)}} | ||||
<div class="item" style="padding: 0 !important;"> | <div class="item" style="padding: 0 !important;"> | ||||
<a class="ui basic blue button" href="{{$.RepoLink}}/cloudbrain/{{.Cloudbrain.ID}}/rate" target="_blank"> | |||||
<a class="ui basic blue button" | |||||
href="{{$.RepoLink}}/cloudbrain/{{.Cloudbrain.ID}}/rate" | |||||
target="_blank"> | |||||
评分 | 评分 | ||||
</a> | </a> | ||||
</div> | </div> | ||||
@@ -405,20 +458,15 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<!-- 镜像列表弹窗 --> | <!-- 镜像列表弹窗 --> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
{{end}} | |||||
{{end}} | |||||
<div id="app" style="margin-top: 2rem;"> | <div id="app" style="margin-top: 2rem;"> | ||||
<div class="center"> | <div class="center"> | ||||
<el-pagination | |||||
background | |||||
@current-change="handleCurrentChange" | |||||
:current-page="page" | |||||
:page-sizes="[10]" | |||||
:page-size="10" | |||||
layout="total, sizes, prev, pager, next, jumper" | |||||
:total="{{.Page.Paginater.Total}}"> | |||||
<el-pagination background @current-change="handleCurrentChange" :current-page="page" | |||||
:page-sizes="[10]" :page-size="10" layout="total, sizes, prev, pager, next, jumper" | |||||
:total="{{.Page.Paginater.Total}}"> | |||||
</el-pagination> | </el-pagination> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -457,42 +505,41 @@ | |||||
{{template "base/footer" .}} | {{template "base/footer" .}} | ||||
<script> | <script> | ||||
// 调试和评分新开窗口 | // 调试和评分新开窗口 | ||||
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; | |||||
let url={{.RepoLink}} | |||||
let redirect_to = {{$.Link}} | |||||
let getParam=getQueryVariable('debugListType') | |||||
const { AppSubUrl, StaticUrlPrefix, csrf } = window.config; | |||||
let url = {{.RepoLink }} | |||||
let redirect_to = {{ $.Link }} | |||||
let getParam = getQueryVariable('debugListType') | |||||
let dropdownValue = ['all','',false].includes(getParam)? '{{$.i18n.Tr "repo.gpu_type_all"}}' : getParam | |||||
let dropdownValue = ['all', '', false].includes(getParam) ? '{{$.i18n.Tr "repo.gpu_type_all"}}' : getParam | |||||
// localStorage.setItem('all',location.href) | // localStorage.setItem('all',location.href) | ||||
function getQueryVariable(variable) | |||||
{ | |||||
function getQueryVariable(variable) { | |||||
let query = window.location.search.substring(1); | let query = window.location.search.substring(1); | ||||
let vars = query.split("&"); | let vars = query.split("&"); | ||||
for (let i=0;i<vars.length;i++) { | |||||
let pair = vars[i].split("="); | |||||
if(pair[0] == variable){return pair[1];} | |||||
for (let i = 0; i < vars.length; i++) { | |||||
let pair = vars[i].split("="); | |||||
if (pair[0] == variable) { return pair[1]; } | |||||
} | } | ||||
return(false); | |||||
return (false); | |||||
} | } | ||||
$(document).ready(function(){ | |||||
dropdownValue = dropdownValue==="CPU%2FGPU"? 'CPU/GPU' : dropdownValue | |||||
$(document).ready(function () { | |||||
dropdownValue = dropdownValue === "CPU%2FGPU" ? 'CPU/GPU' : dropdownValue | |||||
$('.default.text').text(dropdownValue) | $('.default.text').text(dropdownValue) | ||||
$('.ui.dropdown') | $('.ui.dropdown') | ||||
.dropdown({ | |||||
action: 'hide', | |||||
}) | |||||
.dropdown({ | |||||
action: 'hide', | |||||
}) | |||||
$('.ui.selection.dropdown').dropdown({ | $('.ui.selection.dropdown').dropdown({ | ||||
onChange:function(value){ | |||||
onChange: function (value) { | |||||
location.href = `${url}/debugjob?debugListType=${value}` | location.href = `${url}/debugjob?debugListType=${value}` | ||||
} | } | ||||
}) | }) | ||||
$('.message .close') | $('.message .close') | ||||
.on('click', function() { | |||||
$(this) | |||||
.closest('.message') | |||||
.transition('fade') | |||||
}) | |||||
.on('click', function () { | |||||
$(this) | |||||
.closest('.message') | |||||
.transition('fade') | |||||
}) | |||||
}) | }) | ||||
</script> | |||||
</script> |
@@ -1,102 +1,114 @@ | |||||
{{template "base/head" .}} | {{template "base/head" .}} | ||||
<style> | <style> | ||||
.repository.file.list #repo-desc { | |||||
font-size: 1.0em; | |||||
margin-bottom: 1.0rem; | |||||
} | |||||
#contributorInfo > a:nth-child(n+26){ | |||||
display:none; | |||||
} | |||||
#contributorInfo > a{ | |||||
width: 2.0em; | |||||
float: left; | |||||
margin: .25em; | |||||
} | |||||
.edit-link{ | |||||
vertical-align: top; | |||||
display: inline-block; | |||||
overflow: hidden; | |||||
word-break: keep-all; | |||||
white-space: nowrap; | |||||
text-overflow: ellipsis; | |||||
width: 16.5em; | |||||
} | |||||
#contributorInfo > a.circular{ | |||||
height: 2.0em; | |||||
padding: 0; | |||||
overflow: hidden; | |||||
letter-spacing:1.0em; | |||||
text-indent: 0.6em; | |||||
line-height: 2.0em; | |||||
text-transform:capitalize; | |||||
color: #FFF; | |||||
} | |||||
#contributorInfo > a.circular:nth-child(9n+1){ | |||||
background-color: #4ccdec; | |||||
} | |||||
#contributorInfo > a.circular:nth-child(9n+2){ | |||||
background-color: #e0b265; | |||||
} | |||||
#contributorInfo > a.circular:nth-child(9n+3){ | |||||
background-color: #d884b7; | |||||
} | |||||
#contributorInfo > a.circular:nth-child(9n+4){ | |||||
background-color: #8c6bdc; | |||||
} | |||||
#contributorInfo > a.circular:nth-child(9n+5){ | |||||
background-color: #3cb99f; | |||||
} | |||||
#contributorInfo > a.circular:nth-child(9n+6){ | |||||
background-color: #6995b9; | |||||
} | |||||
#contributorInfo > a.circular:nth-child(9n+7){ | |||||
background-color: #ab91a7; | |||||
} | |||||
#contributorInfo > a.circular:nth-child(9n+8){ | |||||
background-color: #bfd0aa; | |||||
} | |||||
.vue_menu { | |||||
cursor: auto; | |||||
position: absolute; | |||||
outline: none; | |||||
top: 100%; | |||||
margin: 0em; | |||||
padding: 0em 0em; | |||||
background: #fff; | |||||
font-size: 1em; | |||||
text-shadow: none; | |||||
text-align: left; | |||||
/* -webkit-box-shadow: 0px 2px 3px 0px rgb(34 36 38 / 15%); */ | |||||
box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); | |||||
border: 1px solid rgba(34,36,38,0.15); | |||||
border-radius: 0.28571429rem; | |||||
-webkit-transition: opacity 0.1s ease; | |||||
transition: opacity 0.1s ease; | |||||
z-index: 11; | |||||
will-change: transform, opacity; | |||||
width: 100% !important; | |||||
-webkit-animation-iteration-count: 1; | |||||
animation-iteration-count: 1; | |||||
-webkit-animation-duration: 300ms; | |||||
animation-duration: 300ms; | |||||
-webkit-animation-timing-function: ease; | |||||
animation-timing-function: ease; | |||||
-webkit-animation-fill-mode: both; | |||||
animation-fill-mode: both; | |||||
} | |||||
.repository.file.list #repo-desc { | |||||
font-size: 1.0em; | |||||
margin-bottom: 1.0rem; | |||||
} | |||||
#contributorInfo>a:nth-child(n+26) { | |||||
display: none; | |||||
} | |||||
#contributorInfo>a { | |||||
width: 2.0em; | |||||
float: left; | |||||
margin: .25em; | |||||
} | |||||
.edit-link { | |||||
vertical-align: top; | |||||
display: inline-block; | |||||
overflow: hidden; | |||||
word-break: keep-all; | |||||
white-space: nowrap; | |||||
text-overflow: ellipsis; | |||||
width: 16.5em; | |||||
} | |||||
#contributorInfo>a.circular { | |||||
height: 2.0em; | |||||
padding: 0; | |||||
overflow: hidden; | |||||
letter-spacing: 1.0em; | |||||
text-indent: 0.6em; | |||||
line-height: 2.0em; | |||||
text-transform: capitalize; | |||||
color: #FFF; | |||||
} | |||||
#contributorInfo>a.circular:nth-child(9n+1) { | |||||
background-color: #4ccdec; | |||||
} | |||||
#contributorInfo>a.circular:nth-child(9n+2) { | |||||
background-color: #e0b265; | |||||
} | |||||
#contributorInfo>a.circular:nth-child(9n+3) { | |||||
background-color: #d884b7; | |||||
} | |||||
#contributorInfo>a.circular:nth-child(9n+4) { | |||||
background-color: #8c6bdc; | |||||
} | |||||
#contributorInfo>a.circular:nth-child(9n+5) { | |||||
background-color: #3cb99f; | |||||
} | |||||
#contributorInfo>a.circular:nth-child(9n+6) { | |||||
background-color: #6995b9; | |||||
} | |||||
#contributorInfo>a.circular:nth-child(9n+7) { | |||||
background-color: #ab91a7; | |||||
} | |||||
#contributorInfo>a.circular:nth-child(9n+8) { | |||||
background-color: #bfd0aa; | |||||
} | |||||
.vue_menu { | |||||
cursor: auto; | |||||
position: absolute; | |||||
outline: none; | |||||
top: 100%; | |||||
margin: 0em; | |||||
padding: 0em 0em; | |||||
background: #fff; | |||||
font-size: 1em; | |||||
text-shadow: none; | |||||
text-align: left; | |||||
/* -webkit-box-shadow: 0px 2px 3px 0px rgb(34 36 38 / 15%); */ | |||||
box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); | |||||
border: 1px solid rgba(34, 36, 38, 0.15); | |||||
border-radius: 0.28571429rem; | |||||
-webkit-transition: opacity 0.1s ease; | |||||
transition: opacity 0.1s ease; | |||||
z-index: 11; | |||||
will-change: transform, opacity; | |||||
width: 100% !important; | |||||
-webkit-animation-iteration-count: 1; | |||||
animation-iteration-count: 1; | |||||
-webkit-animation-duration: 300ms; | |||||
animation-duration: 300ms; | |||||
-webkit-animation-timing-function: ease; | |||||
animation-timing-function: ease; | |||||
-webkit-animation-fill-mode: both; | |||||
animation-fill-mode: both; | |||||
} | |||||
</style> | </style> | ||||
<div class="repository file list"> | <div class="repository file list"> | ||||
{{template "repo/header" .}} | {{template "repo/header" .}} | ||||
<div class="ui container"> | <div class="ui container"> | ||||
<div class="ui negative message" style="display: none;"> | |||||
</div> | |||||
{{template "base/alert" .}} | {{template "base/alert" .}} | ||||
{{if and .Permission.IsAdmin (not .Repository.IsArchived)}} | {{if and .Permission.IsAdmin (not .Repository.IsArchived)}} | ||||
<!-- <div class="ui repo-topic-edit grid form segment error" id="topic_edit" style="display:none"> | |||||
<!-- <div class="ui repo-topic-edit grid form segment error" id="topic_edit" style="display:none"> | |||||
<div class="fourteen wide column"> | <div class="fourteen wide column"> | ||||
<div class="field"> | <div class="field"> | ||||
<div class="ui fluid multiple search selection dropdown"> | <div class="ui fluid multiple search selection dropdown"> | ||||
@@ -114,33 +126,33 @@ | |||||
</div> | </div> | ||||
</div> --> | </div> --> | ||||
{{end}} | |||||
<div class="hide" id="validate_prompt"> | |||||
<span id="count_prompt">{{.i18n.Tr "repo.topic.count_prompt"}}</span> | |||||
<span id="format_prompt">{{.i18n.Tr "repo.topic.format_prompt"}}</span> | |||||
</div> | |||||
{{end}} | |||||
<div class="hide" id="validate_prompt"> | |||||
<span id="count_prompt">{{.i18n.Tr "repo.topic.count_prompt"}}</span> | |||||
<span id="format_prompt">{{.i18n.Tr "repo.topic.format_prompt"}}</span> | |||||
</div> | |||||
<div class="ui repo-description stackable grid"> | <div class="ui repo-description stackable grid"> | ||||
{{if .RepoSearchEnabled}} | {{if .RepoSearchEnabled}} | ||||
<div class="ui repo-search four wide column"> | |||||
<form class="ui form ignore-dirty" action="{{.RepoLink}}/search" method="get"> | |||||
<div class="field"> | |||||
<div class="ui action input"> | |||||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "repo.search.search_repo"}}"> | |||||
<button class="ui icon button" type="submit"> | |||||
<i class="search icon"></i> | |||||
</button> | |||||
</div> | |||||
<div class="ui repo-search four wide column"> | |||||
<form class="ui form ignore-dirty" action="{{.RepoLink}}/search" method="get"> | |||||
<div class="field"> | |||||
<div class="ui action input"> | |||||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "repo.search.search_repo"}}"> | |||||
<button class="ui icon button" type="submit"> | |||||
<i class="search icon"></i> | |||||
</button> | |||||
</div> | </div> | ||||
</form> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
{{if .Repository.IsArchived}} | {{if .Repository.IsArchived}} | ||||
<div class="ui warning message"> | |||||
{{.i18n.Tr "repo.archive.title"}} | |||||
</div> | |||||
<div class="ui warning message"> | |||||
{{.i18n.Tr "repo.archive.title"}} | |||||
</div> | |||||
{{end}} | {{end}} | ||||
{{template "repo/sub_menu" .}} | {{template "repo/sub_menu" .}} | ||||
<div class="ui stackable secondary menu mobile--margin-between-items mobile--no-negative-margins"> | <div class="ui stackable secondary menu mobile--margin-between-items mobile--no-negative-margins"> | ||||
@@ -149,97 +161,122 @@ | |||||
{{ $l := Subtract $n 1}} | {{ $l := Subtract $n 1}} | ||||
<!-- If home page, show new PR. If not, show breadcrumb --> | <!-- If home page, show new PR. If not, show breadcrumb --> | ||||
{{if eq $n 0}} | {{if eq $n 0}} | ||||
{{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}} | |||||
<div class="fitted item"> | |||||
<a href="{{.BaseRepo.Link}}/compare/{{.BaseRepo.DefaultBranch | EscapePound}}...{{if ne .Repository.Owner.Name .BaseRepo.Owner.Name}}{{.Repository.Owner.Name}}:{{end}}{{.BranchName | EscapePound}}"> | |||||
<button id="new-pull-request" class="ui compact basic button">{{if .PullRequestCtx.Allowed}}{{.i18n.Tr "repo.pulls.compare_changes"}}{{else}}{{.i18n.Tr "action.compare_branch"}}{{end}}</button> | |||||
</a> | |||||
{{if and .Repository.IsFork .PullRequestCtx.Allowed}} | |||||
{{if gt .FetchUpstreamCnt 0 }} | |||||
<a href="{{.Repository.Link}}/compare/{{.BranchName | EscapePound}}...{{.BaseRepo.Owner.Name}}:{{if .UpstreamSameBranchName}}{{.BranchName | EscapePound}}{{else}}{{.BaseRepo.DefaultBranch | EscapePound}}{{end}}"> | |||||
<button id="new-pull-request" class="ui compact basic button" title="{{$.i18n.Tr (TrN $.i18n.Lang .FetchUpstreamCnt "repo.pulls.commits_count_1" "repo.pulls.commits_count_n") .FetchUpstreamCnt}}">{{.i18n.Tr "repo.pulls.fetch_upstream"}}</button> | |||||
</a> | |||||
{{else if lt .FetchUpstreamCnt 0}} | |||||
<a href="{{.Repository.Link}}/compare/{{.BranchName | EscapePound}}...{{.BaseRepo.Owner.Name}}:{{.BaseRepo.DefaultBranch | EscapePound}}"> | |||||
<button id="new-pull-request" class="ui compact basic button" title="{{.i18n.Tr "repo.pulls.upstream_error"}}">{{.i18n.Tr "repo.pulls.fetch_upstream"}}</button> | |||||
</a> | |||||
{{else}} | |||||
<a href="{{.Repository.Link}}/compare/{{.BranchName | EscapePound}}...{{.BaseRepo.Owner.Name}}:{{if .UpstreamSameBranchName}}{{.BranchName | EscapePound}}{{else}}{{.BaseRepo.DefaultBranch | EscapePound}}{{end}}"> | |||||
<button id="new-pull-request" class="ui compact basic button" title="{{.i18n.Tr "repo.pulls.upstream_up_to_date"}}">{{.i18n.Tr "repo.pulls.fetch_upstream"}}</button> | |||||
</a> | |||||
{{end}} | |||||
{{end}} | |||||
</div> | |||||
{{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}} | |||||
<div class="fitted item"> | |||||
<a | |||||
href="{{.BaseRepo.Link}}/compare/{{.BaseRepo.DefaultBranch | EscapePound}}...{{if ne .Repository.Owner.Name .BaseRepo.Owner.Name}}{{.Repository.Owner.Name}}:{{end}}{{.BranchName | EscapePound}}"> | |||||
<button id="new-pull-request" | |||||
class="ui compact basic button">{{if .PullRequestCtx.Allowed}}{{.i18n.Tr "repo.pulls.compare_changes"}}{{else}}{{.i18n.Tr "action.compare_branch"}}{{end}}</button> | |||||
</a> | |||||
{{if and .Repository.IsFork .PullRequestCtx.Allowed}} | |||||
{{if gt .FetchUpstreamCnt 0 }} | |||||
<a | |||||
href="{{.Repository.Link}}/compare/{{.BranchName | EscapePound}}...{{.BaseRepo.Owner.Name}}:{{if .UpstreamSameBranchName}}{{.BranchName | EscapePound}}{{else}}{{.BaseRepo.DefaultBranch | EscapePound}}{{end}}"> | |||||
<button id="new-pull-request" class="ui compact basic button" | |||||
title="{{$.i18n.Tr (TrN $.i18n.Lang .FetchUpstreamCnt "repo.pulls.commits_count_1" "repo.pulls.commits_count_n") .FetchUpstreamCnt}}">{{.i18n.Tr "repo.pulls.fetch_upstream"}}</button> | |||||
</a> | |||||
{{else if lt .FetchUpstreamCnt 0}} | |||||
<a | |||||
href="{{.Repository.Link}}/compare/{{.BranchName | EscapePound}}...{{.BaseRepo.Owner.Name}}:{{.BaseRepo.DefaultBranch | EscapePound}}"> | |||||
<button id="new-pull-request" class="ui compact basic button" | |||||
title="{{.i18n.Tr "repo.pulls.upstream_error"}}">{{.i18n.Tr "repo.pulls.fetch_upstream"}}</button> | |||||
</a> | |||||
{{else}} | |||||
<a | |||||
href="{{.Repository.Link}}/compare/{{.BranchName | EscapePound}}...{{.BaseRepo.Owner.Name}}:{{if .UpstreamSameBranchName}}{{.BranchName | EscapePound}}{{else}}{{.BaseRepo.DefaultBranch | EscapePound}}{{end}}"> | |||||
<button id="new-pull-request" class="ui compact basic button" | |||||
title="{{.i18n.Tr "repo.pulls.upstream_up_to_date"}}">{{.i18n.Tr "repo.pulls.fetch_upstream"}}</button> | |||||
</a> | |||||
{{end}} | |||||
{{end}} | {{end}} | ||||
</div> | |||||
{{end}} | |||||
{{else}} | {{else}} | ||||
<div class="fitted item"><span class="ui breadcrumb repo-path"><a class="section" href="{{.RepoLink}}/src/{{EscapePound .BranchNameSubURL}}" title="{{.Repository.Name}}">{{EllipsisString .Repository.Name 30}}</a>{{range $i, $v := .TreeNames}}<span class="divider">/</span>{{if eq $i $l}}<span class="active section" title="{{$v}}">{{EllipsisString $v 30}}</span>{{else}}{{ $p := index $.Paths $i}}<span class="section"><a href="{{EscapePound $.BranchLink}}/{{EscapePound $p}}" title="{{$v}}">{{EllipsisString $v 30}}</a></span>{{end}}{{end}}</span></div> | |||||
<div class="fitted item"><span class="ui breadcrumb repo-path"><a class="section" | |||||
href="{{.RepoLink}}/src/{{EscapePound .BranchNameSubURL}}" | |||||
title="{{.Repository.Name}}">{{EllipsisString .Repository.Name 30}}</a>{{range $i, $v := .TreeNames}}<span | |||||
class="divider">/</span>{{if eq $i $l}}<span class="active section" | |||||
title="{{$v}}">{{EllipsisString $v 30}}</span>{{else}}{{ $p := index $.Paths $i}}<span | |||||
class="section"><a href="{{EscapePound $.BranchLink}}/{{EscapePound $p}}" | |||||
title="{{$v}}">{{EllipsisString $v 30}}</a></span>{{end}}{{end}}</span></div> | |||||
{{end}} | {{end}} | ||||
<div class="right fitted item" id="file-buttons"> | <div class="right fitted item" id="file-buttons"> | ||||
<div class="ui tiny blue buttons"> | <div class="ui tiny blue buttons"> | ||||
{{if .Repository.CanEnableEditor}} | {{if .Repository.CanEnableEditor}} | ||||
{{if .CanAddFile}} | |||||
<a href="{{.RepoLink}}/_new/{{EscapePound .BranchName}}/{{EscapePound .TreePath}}" class="ui button"> | |||||
{{.i18n.Tr "repo.editor.new_file"}} | |||||
</a> | |||||
{{end}} | |||||
{{if .CanUploadFile}} | |||||
<a href="{{.RepoLink}}/_upload/{{EscapePound .BranchName}}/{{EscapePound .TreePath}}" class="ui button"> | |||||
{{.i18n.Tr "repo.editor.upload_file"}} | |||||
</a> | |||||
{{end}} | |||||
{{if .CanAddFile}} | |||||
<a href="{{.RepoLink}}/_new/{{EscapePound .BranchName}}/{{EscapePound .TreePath}}" | |||||
class="ui button"> | |||||
{{.i18n.Tr "repo.editor.new_file"}} | |||||
</a> | |||||
{{end}} | |||||
{{if .CanUploadFile}} | |||||
<a href="{{.RepoLink}}/_upload/{{EscapePound .BranchName}}/{{EscapePound .TreePath}}" | |||||
class="ui button"> | |||||
{{.i18n.Tr "repo.editor.upload_file"}} | |||||
</a> | |||||
{{end}} | |||||
{{end}} | {{end}} | ||||
{{if and (ne $n 0) (not .IsViewFile) (not .IsBlame) }} | {{if and (ne $n 0) (not .IsViewFile) (not .IsBlame) }} | ||||
<a href="{{.RepoLink}}/commits/{{EscapePound .BranchNameSubURL}}/{{EscapePound .TreePath}}" class="ui button"> | |||||
{{.i18n.Tr "repo.file_history"}} | |||||
</a> | |||||
<a href="{{.RepoLink}}/commits/{{EscapePound .BranchNameSubURL}}/{{EscapePound .TreePath}}" | |||||
class="ui button"> | |||||
{{.i18n.Tr "repo.file_history"}} | |||||
</a> | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="fitted item"> | <div class="fitted item"> | ||||
{{if eq $n 0}} | {{if eq $n 0}} | ||||
{{if .Repository.IsTemplate}} | |||||
<div class="ui tiny blue buttons"> | |||||
<a href="{{AppSubUrl}}/repo/create?template_id={{.Repository.ID}}" class="ui button"> | |||||
{{.i18n.Tr "repo.use_template"}} | |||||
</a> | |||||
</div> | |||||
{{end}} | |||||
{{if .Repository.IsTemplate}} | |||||
<div class="ui tiny blue buttons"> | |||||
<a href="{{AppSubUrl}}/repo/create?template_id={{.Repository.ID}}" class="ui button"> | |||||
{{.i18n.Tr "repo.use_template"}} | |||||
</a> | |||||
</div> | |||||
{{end}} | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
<div class="fitted item"> | <div class="fitted item"> | ||||
<!-- Only show clone panel in repository home page --> | <!-- Only show clone panel in repository home page --> | ||||
{{if eq $n 0}} | {{if eq $n 0}} | ||||
<div class="ui action tiny input" id="clone-panel"> | |||||
{{if not $.DisableHTTP}} | |||||
<button class="ui basic clone button" id="repo-clone-https" data-link="{{.CloneLink.HTTPS}}"> | |||||
{{if UseHTTPS}}HTTPS{{else}}HTTP{{end}} | |||||
</button> | |||||
{{end}} | |||||
{{if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}} | |||||
<button class="ui basic clone button" id="repo-clone-ssh" data-link="{{.CloneLink.SSH}}"> | |||||
SSH | |||||
</button> | |||||
{{end}} | |||||
{{if not $.DisableHTTP}} | |||||
<input id="repo-clone-url" value="{{$.CloneLink.HTTPS}}" readonly> | |||||
{{else if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}} | |||||
<input id="repo-clone-url" value="{{$.CloneLink.SSH}}" readonly> | |||||
{{end}} | |||||
{{if or (not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH))}} | |||||
<button class="ui basic icon button poping up clipboard" id="clipboard-btn" data-original="{{.i18n.Tr "repo.copy_link"}}" data-success="{{.i18n.Tr "repo.copy_link_success"}}" data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-target="#repo-clone-url"> | |||||
{{svg "octicon-clippy" 16}} | |||||
</button> | |||||
{{end}} | |||||
<div class="ui basic jump dropdown icon button poping up" data-content="{{.i18n.Tr "repo.download_archive"}}" data-variation="tiny inverted" data-position="top right"> | |||||
<i class="download icon"></i> | |||||
<div class="menu"> | |||||
<a class="item" href="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.zip">{{svg "octicon-file-zip" 16}} ZIP</a> | |||||
<a class="item" href="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.tar.gz">{{svg "octicon-file-zip" 16}} TAR.GZ</a> | |||||
</div> | |||||
<div class="ui action tiny input" id="clone-panel"> | |||||
{{if not $.DisableHTTP}} | |||||
<button class="ui basic clone button" id="repo-clone-https" data-link="{{.CloneLink.HTTPS}}"> | |||||
{{if UseHTTPS}}HTTPS{{else}}HTTP{{end}} | |||||
</button> | |||||
{{end}} | |||||
{{if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}} | |||||
<button class="ui basic clone button" id="repo-clone-ssh" data-link="{{.CloneLink.SSH}}"> | |||||
SSH | |||||
</button> | |||||
{{end}} | |||||
{{if not $.DisableHTTP}} | |||||
<input id="repo-clone-url" value="{{$.CloneLink.HTTPS}}" readonly> | |||||
{{else if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}} | |||||
<input id="repo-clone-url" value="{{$.CloneLink.SSH}}" readonly> | |||||
{{end}} | |||||
{{if or (not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH))}} | |||||
<button class="ui basic icon button poping up clipboard" id="clipboard-btn" | |||||
data-original="{{.i18n.Tr "repo.copy_link"}}" | |||||
data-success="{{.i18n.Tr "repo.copy_link_success"}}" | |||||
data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" | |||||
data-variation="inverted tiny" data-clipboard-target="#repo-clone-url"> | |||||
{{svg "octicon-clippy" 16}} | |||||
</button> | |||||
{{end}} | |||||
<div class="ui basic jump dropdown icon button poping up" | |||||
data-content="{{.i18n.Tr "repo.download_archive"}}" data-variation="tiny inverted" | |||||
data-position="top right"> | |||||
<i class="download icon"></i> | |||||
<div class="menu"> | |||||
<a class="item" | |||||
href="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.zip">{{svg "octicon-file-zip" 16}} ZIP</a> | |||||
<a class="item" | |||||
href="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.tar.gz">{{svg "octicon-file-zip" 16}} TAR.GZ</a> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -247,22 +284,24 @@ | |||||
<div class="ui mobile reversed stackable grid"> | <div class="ui mobile reversed stackable grid"> | ||||
<div class="ui ten wide tablet twelve wide computer column"> | <div class="ui ten wide tablet twelve wide computer column"> | ||||
{{if .IsViewFile}} | {{if .IsViewFile}} | ||||
{{template "repo/view_file" .}} | |||||
{{template "repo/view_file" .}} | |||||
{{else if .IsBlame}} | {{else if .IsBlame}} | ||||
{{template "repo/blame" .}} | |||||
{{template "repo/blame" .}} | |||||
{{else}} | {{else}} | ||||
{{template "repo/view_list" .}} | |||||
{{template "repo/view_list" .}} | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
<div class="ui six wide tablet four wide computer column"> | <div class="ui six wide tablet four wide computer column"> | ||||
<div id="repo-desc" data-IsAdmin= "{{.Permission.IsAdmin}}" data-IsArchived="{{.Repository.IsArchived}}" > | |||||
<h4 id="about-desc" class="ui header">简介</h4> | |||||
<input type="hidden" id="edit-alias" value="{{.Repository.Alias}}"> | |||||
<div id="repo-desc" data-IsAdmin="{{.Permission.IsAdmin}}" | |||||
data-IsArchived="{{.Repository.IsArchived}}"> | |||||
<h4 id="about-desc" class="ui header">简介</h4> | |||||
<input type="hidden" id="edit-alias" value="{{.Repository.Alias}}"> | |||||
<p> | <p> | ||||
{{if .Repository.DescriptionHTML}} | {{if .Repository.DescriptionHTML}} | ||||
<span class="description" style="word-break:break-all">{{.Repository.DescriptionHTML}}</span> | |||||
<span class="description" | |||||
style="word-break:break-all">{{.Repository.DescriptionHTML}}</span> | |||||
{{else}} | {{else}} | ||||
<span class="no-description text-italic">{{.i18n.Tr "repo.no_desc"}}</span> | |||||
<span class="no-description text-italic">{{.i18n.Tr "repo.no_desc"}}</span> | |||||
{{end}} | {{end}} | ||||
</p> | </p> | ||||
@@ -274,7 +313,8 @@ | |||||
{{if .Repository.Website}} | {{if .Repository.Website}} | ||||
<p class="ui"> | <p class="ui"> | ||||
<i class="gray linkify icon"></i> | <i class="gray linkify icon"></i> | ||||
<a class="link edit-link" target="_blank" title="{{.Repository.Website}}" href="{{.Repository.Website}}">{{.Repository.Website}}</a> | |||||
<a class="link edit-link" target="_blank" title="{{.Repository.Website}}" | |||||
href="{{.Repository.Website}}">{{.Repository.Website}}</a> | |||||
</p> | </p> | ||||
{{end}} | {{end}} | ||||
@@ -284,11 +324,13 @@ | |||||
<div id="repo-topics1" style="flex: 1;"> | <div id="repo-topics1" style="flex: 1;"> | ||||
{{range .Topics}} | {{range .Topics}} | ||||
<a class="ui repo-topic small label topic" href="{{AppSubUrl}}/explore/repos?q={{.Name}}&topic=">{{.Name}}</a> | |||||
<a class="ui repo-topic small label topic" | |||||
href="{{AppSubUrl}}/explore/repos?q={{.Name}}&topic=">{{.Name}}</a> | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
<div> | <div> | ||||
{{if and .Permission.IsAdmin (not .Repository.IsArchived)}}<i id="manage_topic" style="cursor: pointer;" class="plus icon"></i>{{end}} | |||||
{{if and .Permission.IsAdmin (not .Repository.IsArchived)}}<i id="manage_topic" | |||||
style="cursor: pointer;" class="plus icon"></i>{{end}} | |||||
</div> | </div> | ||||
<div id="topic_edit" class="vue_menu" style="display:none"> | <div id="topic_edit" class="vue_menu" style="display:none"> | ||||
<div id="topic_edit1"> | <div id="topic_edit1"> | ||||
@@ -302,7 +344,7 @@ | |||||
<p class="ui"> | <p class="ui"> | ||||
<i class="grey code icon"></i> | <i class="grey code icon"></i> | ||||
{{range .LanguageStats}} | {{range .LanguageStats}} | ||||
{{.Language}} | |||||
{{.Language}} | |||||
{{end}} | {{end}} | ||||
</p> | </p> | ||||
@@ -311,7 +353,7 @@ | |||||
{{if .LICENSE}} | {{if .LICENSE}} | ||||
<p class="ui"> | <p class="ui"> | ||||
<i class="grey clone icon"></i> | <i class="grey clone icon"></i> | ||||
{{.LICENSE}} | |||||
{{.LICENSE}} | |||||
</p> | </p> | ||||
{{end}} | {{end}} | ||||
@@ -326,19 +368,22 @@ | |||||
{{else}} | {{else}} | ||||
<strong>贡献者 ({{len .ContributorInfo}}+)</strong> | <strong>贡献者 ({{len .ContributorInfo}}+)</strong> | ||||
{{end}} | {{end}} | ||||
<div class="ui right"> | <div class="ui right"> | ||||
<!-- <a class="membersmore text grey" href="{{.RepoLink}}/contributors">全部 {{svg "octicon-chevron-right" 16}}</a> --> | <!-- <a class="membersmore text grey" href="{{.RepoLink}}/contributors">全部 {{svg "octicon-chevron-right" 16}}</a> --> | ||||
<a class="membersmore text grey" href="{{.RepoLink}}/contributors?type={{if .IsViewBranch}}branch{{else}}tag{{end}}&name={{.BranchName}}">全部 {{svg "octicon-chevron-right" 16}}</a> | |||||
<a class="membersmore text grey" | |||||
href="{{.RepoLink}}/contributors?type={{if .IsViewBranch}}branch{{else}}tag{{end}}&name={{.BranchName}}">全部 | |||||
{{svg "octicon-chevron-right" 16}}</a> | |||||
</div> | </div> | ||||
</h4> | </h4> | ||||
<div class="ui members" id="contributorInfo"> | <div class="ui members" id="contributorInfo"> | ||||
{{range .ContributorInfo}} | {{range .ContributorInfo}} | ||||
{{if .UserInfo}} | |||||
<a href="{{AppSubUrl}}/{{.UserInfo.Name}}"><img class="ui avatar image" src="{{.UserInfo.RelAvatarLink}}"></a> | |||||
{{else if .Email}} | |||||
<a href="mailto:{{.Email}}" class="circular ui button">{{.Email}}</a> | |||||
{{end}} | |||||
{{if .UserInfo}} | |||||
<a href="{{AppSubUrl}}/{{.UserInfo.Name}}"><img class="ui avatar image" | |||||
src="{{.UserInfo.RelAvatarLink}}"></a> | |||||
{{else if .Email}} | |||||
<a href="mailto:{{.Email}}" class="circular ui button">{{.Email}}</a> | |||||
{{end}} | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -357,4 +402,4 @@ | |||||
// }); | // }); | ||||
// }); | // }); | ||||
</script> | </script> | ||||
{{template "base/footer" .}} | |||||
{{template "base/footer" .}} |
@@ -1,179 +1,213 @@ | |||||
{{template "base/head" .}} | {{template "base/head" .}} | ||||
<style> | <style> | ||||
.according-panel-heading{ | |||||
box-sizing: border-box; | |||||
padding: 8px 16px; | |||||
color: #252b3a; | |||||
background-color: #f2f5fc; | |||||
line-height: 1.5; | |||||
cursor: pointer; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
} | |||||
.accordion-panel-title { | |||||
margin-top: 0; | |||||
margin-bottom: 0; | |||||
color: #252b3a; | |||||
} | |||||
.accordion-panel-title-content{ | |||||
vertical-align: middle; | |||||
display: inline-block; | |||||
width: calc(100% - 32px); | |||||
cursor: default; | |||||
} | |||||
.acc-margin-bottom { | |||||
margin-bottom: 5px; | |||||
} | |||||
.title_text { | |||||
font-size: 12px; | |||||
} | |||||
.ac-display-inblock { | |||||
display: inline-block; | |||||
} | |||||
.cti-mgRight-sm { | |||||
margin-right: 8px; | |||||
} | |||||
.ac-text-normal { | |||||
font-size: 14px; | |||||
color: #575d6c; | |||||
} | |||||
.uc-accordionTitle-black { | |||||
color: #333; | |||||
} | |||||
.accordion-border{ | |||||
border:1px solid #cce2ff; | |||||
} | |||||
.padding0{ | |||||
padding: 0 !important; | |||||
} | |||||
.content-pad{ | |||||
padding: 15px 35px; | |||||
} | |||||
.content-margin{ | |||||
margin:10px 5px ; | |||||
} | |||||
.tab_2_content { | |||||
min-height: 460px; | |||||
margin-left: 10px; | |||||
} | |||||
.ac-grid { | |||||
display: block; | |||||
*zoom: 1; | |||||
} | |||||
.ac-grid-col { | |||||
float: left; | |||||
width: 100%; | |||||
} | |||||
.ac-grid-col2 .ac-grid-col { | |||||
width: 50%; | |||||
} | |||||
.ti-form { | |||||
text-align: left; | |||||
max-width: 100%; | |||||
vertical-align: middle; | |||||
} | |||||
.ti-form>tbody { | |||||
font-size: 12px; | |||||
} | |||||
.ti-form>tbody, .ti-form>tbody>tr { | |||||
vertical-align: inherit; | |||||
} | |||||
.info_text { | |||||
padding-bottom: 20px; | |||||
padding-right: 20px; | |||||
font-size: 12px; | |||||
} | |||||
.ti-text-form-label { | |||||
padding-bottom: 20px; | |||||
padding-right: 20px; | |||||
color: #8a8e99; | |||||
font-size: 12px; | |||||
white-space: nowrap !important; | |||||
width: 80px; | |||||
line-height: 30px; | |||||
} | |||||
.ti-text-form-content{ | |||||
line-height: 30px; | |||||
padding-bottom: 20px; | |||||
} | |||||
.ti-form>tbody>tr>td { | |||||
vertical-align: top; | |||||
white-space: normal; | |||||
} | |||||
td, th { | |||||
padding: 0; | |||||
} | |||||
.ac-grid-col .text-span { | |||||
width: 450px; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
white-space: nowrap; | |||||
} | |||||
.text-span-new { | |||||
width: 800px; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
height: 20%; | |||||
word-break: break-all; | |||||
} | |||||
.redo-color{ | |||||
color: #3291F8; | |||||
} | |||||
.ti-action-menu-item:not(:last-child){ | |||||
margin-right: 10px; | |||||
padding-right: 11px; | |||||
text-decoration: none!important; | |||||
color: #526ecc; | |||||
cursor: pointer; | |||||
display: inline-block; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
position: relative; | |||||
} | |||||
.ti-action-menu-item:not(:last-child):after { | |||||
content: ""; | |||||
display: inline-block; | |||||
position: absolute; | |||||
height: 12px; | |||||
right: 0; | |||||
top: 50%; | |||||
-webkit-transform: translateY(-6px); | |||||
-ms-transform: translateY(-6px); | |||||
-o-transform: translateY(-6px); | |||||
transform: translateY(-6px); | |||||
border-right: 1px solid #dfe1e6; | |||||
} | |||||
.text-width80{ | |||||
width: 100px; | |||||
line-height: 30px; | |||||
} | |||||
.border-according{ | |||||
border: 1px solid #dfe1e6; | |||||
} | |||||
.disabled { | |||||
.according-panel-heading { | |||||
box-sizing: border-box; | |||||
padding: 8px 16px; | |||||
color: #252b3a; | |||||
background-color: #f2f5fc; | |||||
line-height: 1.5; | |||||
cursor: pointer; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
} | |||||
.accordion-panel-title { | |||||
margin-top: 0; | |||||
margin-bottom: 0; | |||||
color: #252b3a; | |||||
} | |||||
.accordion-panel-title-content { | |||||
vertical-align: middle; | |||||
display: inline-block; | |||||
width: calc(100% - 32px); | |||||
cursor: default; | |||||
} | |||||
.acc-margin-bottom { | |||||
margin-bottom: 5px; | |||||
} | |||||
.title_text { | |||||
font-size: 12px; | |||||
} | |||||
.ac-display-inblock { | |||||
display: inline-block; | |||||
} | |||||
.cti-mgRight-sm { | |||||
margin-right: 8px; | |||||
} | |||||
.ac-text-normal { | |||||
font-size: 14px; | |||||
color: #575d6c; | |||||
} | |||||
.uc-accordionTitle-black { | |||||
color: #333; | |||||
} | |||||
.accordion-border { | |||||
border: 1px solid #cce2ff; | |||||
} | |||||
.padding0 { | |||||
padding: 0 !important; | |||||
} | |||||
.content-pad { | |||||
padding: 15px 35px; | |||||
} | |||||
.content-margin { | |||||
margin: 10px 5px; | |||||
} | |||||
.tab_2_content { | |||||
min-height: 460px; | |||||
margin-left: 10px; | |||||
} | |||||
.ac-grid { | |||||
display: block; | |||||
*zoom: 1; | |||||
} | |||||
.ac-grid-col { | |||||
float: left; | |||||
width: 100%; | |||||
} | |||||
.ac-grid-col2 .ac-grid-col { | |||||
width: 50%; | |||||
} | |||||
.ti-form { | |||||
text-align: left; | |||||
max-width: 100%; | |||||
vertical-align: middle; | |||||
} | |||||
.ti-form>tbody { | |||||
font-size: 12px; | |||||
} | |||||
.ti-form>tbody, | |||||
.ti-form>tbody>tr { | |||||
vertical-align: inherit; | |||||
} | |||||
.info_text { | |||||
padding-bottom: 20px; | |||||
padding-right: 20px; | |||||
font-size: 12px; | |||||
} | |||||
.ti-text-form-label { | |||||
padding-bottom: 20px; | |||||
padding-right: 20px; | |||||
color: #8a8e99; | |||||
font-size: 12px; | |||||
white-space: nowrap !important; | |||||
width: 80px; | |||||
line-height: 30px; | |||||
} | |||||
.ti-text-form-content { | |||||
line-height: 30px; | |||||
padding-bottom: 20px; | |||||
} | |||||
.ti-form>tbody>tr>td { | |||||
vertical-align: top; | |||||
white-space: normal; | |||||
} | |||||
td, | |||||
th { | |||||
padding: 0; | |||||
} | |||||
.ac-grid-col .text-span { | |||||
width: 450px; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
white-space: nowrap; | |||||
} | |||||
.text-span-new { | |||||
width: 800px; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
height: 20%; | |||||
word-break: break-all; | |||||
} | |||||
.redo-color { | |||||
color: #3291F8; | |||||
} | |||||
.ti-action-menu-item:not(:last-child) { | |||||
margin-right: 10px; | |||||
padding-right: 11px; | |||||
text-decoration: none !important; | |||||
color: #526ecc; | |||||
cursor: pointer; | |||||
display: inline-block; | |||||
-moz-user-select: none; | |||||
-webkit-user-select: none; | |||||
-ms-user-select: none; | |||||
-khtml-user-select: none; | |||||
user-select: none; | |||||
position: relative; | |||||
} | |||||
.ti-action-menu-item:not(:last-child):after { | |||||
content: ""; | |||||
display: inline-block; | |||||
position: absolute; | |||||
height: 12px; | |||||
right: 0; | |||||
top: 50%; | |||||
-webkit-transform: translateY(-6px); | |||||
-ms-transform: translateY(-6px); | |||||
-o-transform: translateY(-6px); | |||||
transform: translateY(-6px); | |||||
border-right: 1px solid #dfe1e6; | |||||
} | |||||
.text-width80 { | |||||
width: 100px; | |||||
line-height: 30px; | |||||
} | |||||
.border-according { | |||||
border: 1px solid #dfe1e6; | |||||
} | |||||
.disabled { | |||||
cursor: default; | cursor: default; | ||||
pointer-events: none; | pointer-events: none; | ||||
color: rgba(0,0,0,.6) !important; | |||||
color: rgba(0, 0, 0, .6) !important; | |||||
opacity: .45 !important; | opacity: .45 !important; | ||||
} | |||||
.pad20{ | |||||
border:0px !important; | |||||
} | |||||
.model_file_bread{ | |||||
margin-bottom: -0.5rem !important; | |||||
padding-left: 1rem; | |||||
padding-top: 0.5rem ; | |||||
} | |||||
} | |||||
.pad20 { | |||||
border: 0px !important; | |||||
} | |||||
.model_file_bread { | |||||
margin-bottom: -0.5rem !important; | |||||
padding-left: 1rem; | |||||
padding-top: 0.5rem; | |||||
} | |||||
</style> | </style> | ||||
<div id="mask"> | <div id="mask"> | ||||
<div id="loadingPage"> | <div id="loadingPage"> | ||||
@@ -185,7 +219,7 @@ td, th { | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="repository"> | <div class="repository"> | ||||
{{template "repo/header" .}} | |||||
{{template "repo/header" .}} | |||||
<div class="ui container"> | <div class="ui container"> | ||||
<h4 class="ui header" id="vertical-segment"> | <h4 class="ui header" id="vertical-segment"> | ||||
<div class="ui breadcrumb"> | <div class="ui breadcrumb"> | ||||
@@ -194,36 +228,42 @@ td, th { | |||||
</a> | </a> | ||||
<div class="divider"> / </div> | <div class="divider"> / </div> | ||||
<a class="section backTodeBug" href="{{.RepoLink}}/debugjob?debugListType=all"> | <a class="section backTodeBug" href="{{.RepoLink}}/debugjob?debugListType=all"> | ||||
{{$.i18n.Tr "repo.modelarts.notebook"}} | |||||
{{$.i18n.Tr "repo.modelarts.notebook"}} | |||||
</a> | </a> | ||||
<div class="divider"> / </div> | <div class="divider"> / </div> | ||||
{{with .task}} | |||||
{{with .task}} | |||||
<div class="active section">{{.DisplayJobName}}</div> | <div class="active section">{{.DisplayJobName}}</div> | ||||
{{end}} | {{end}} | ||||
</div> | |||||
</div> | |||||
</h4> | </h4> | ||||
{{with .task}} | {{with .task}} | ||||
<div class="ui accordion border-according" id="accordion" data-repopath="" data-jobid="" data-version=""> | |||||
<div class="ui accordion border-according" id="accordion" data-repopath="{{$.RepoRelPath}}/modelarts/notebook" | |||||
data-jobid="{{.ID}}" data-version=""> | |||||
<div class="active title padding0"> | <div class="active title padding0"> | ||||
<div class="according-panel-heading"> | <div class="according-panel-heading"> | ||||
<div class="accordion-panel-title"> | <div class="accordion-panel-title"> | ||||
<!-- <i class="dropdown icon"></i> --> | |||||
<!-- <i class="dropdown icon"></i> --> | |||||
<span class="accordion-panel-title-content"> | <span class="accordion-panel-title-content"> | ||||
<span> | <span> | ||||
<div class="ac-display-inblock title_text acc-margin-bottom"> | <div class="ac-display-inblock title_text acc-margin-bottom"> | ||||
<span class="cti-mgRight-sm"> | <span class="cti-mgRight-sm"> | ||||
{{if not (eq .StartTime 0)}} | |||||
<td>{{TimeSinceUnix1 .StartTime}}</td> | |||||
{{else}} | |||||
<td>{{TimeSinceUnix1 .CreatedUnix}}<td> | |||||
{{end}} | |||||
</span> | |||||
{{if not (eq .StartTime 0)}} | |||||
<td>{{TimeSinceUnix1 .StartTime}}</td> | |||||
{{else}} | |||||
<td>{{TimeSinceUnix1 .CreatedUnix}} | |||||
<td> | |||||
{{end}} | |||||
</span> | |||||
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}: | <span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.status"}}: | ||||
<span id="{{.VersionName}}-status-span"><i id="icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
<span id="{{.VersionName}}-status-span"><i id="icon" | |||||
style="vertical-align: middle;" class="{{.Status}}"></i><span id="text" | |||||
style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||||
</span> | </span> | ||||
<span class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span> | |||||
<span class="cti-mgRight-sm uc-accordionTitle-black" id="{{.VersionName}}-duration-span">{{$.duration}}</span> | |||||
<span | |||||
class="cti-mgRight-sm">{{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}:</span> | |||||
<span class="cti-mgRight-sm uc-accordionTitle-black" | |||||
id="{{.VersionName}}-duration-span">{{$.duration}}</span> | |||||
</div> | </div> | ||||
</span> | </span> | ||||
@@ -265,36 +305,38 @@ td, th { | |||||
</td> | </td> | ||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain_creator"}} | |||||
</td> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain_creator"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||||
{{.User.Name}} | |||||
</div> | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-mirror"> | |||||
{{.User.Name}} | |||||
</div> | |||||
</td> | |||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.computing_resources"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-computeresource"> | |||||
{{.ComputeResource}} | |||||
</div> | |||||
</td> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.computing_resources"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-computeresource"> | |||||
{{.ComputeResource}} | |||||
</div> | |||||
</td> | |||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.createtime"}} | |||||
</td> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.createtime"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-createtime"> | |||||
{{TimeSinceUnix1 .CreatedUnix}} | |||||
</div> | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-createtime"> | |||||
{{TimeSinceUnix1 .CreatedUnix}} | |||||
</div> | |||||
</td> | |||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
@@ -303,40 +345,41 @@ td, th { | |||||
</td> | </td> | ||||
<td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
<div class="text-span text-span-w" id="{{.VersionName}}-duration"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-duration"> | |||||
{{$.duration}} | {{$.duration}} | ||||
</div> | </div> | ||||
</td> | </td> | ||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.datasetdownload"}} | |||||
</td> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.datasetdownload"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span-new" id="model_description"> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span-new" id="model_description"> | |||||
{{$.datasetDownloadLink}} | {{$.datasetDownloadLink}} | ||||
</div> | |||||
</td> | |||||
</div> | |||||
</td> | |||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.description"}} | |||||
</td> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "cloudbrain.description"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span-new" id="model_description"> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span-new" id="model_description"> | |||||
{{.Description}} | {{.Description}} | ||||
</div> | |||||
</td> | |||||
</div> | |||||
</td> | |||||
</tr> | </tr> | ||||
</tbody> | </tbody> | ||||
</table> | </table> | ||||
</div> | </div> | ||||
<div class="ac-grid-col"> | <div class="ac-grid-col"> | ||||
<table class="ti-form"> | |||||
<tbody class="ti-text-form"> | |||||
<table class="ti-form"> | |||||
<tbody class="ti-text-form"> | |||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | <td class="ti-no-ng-animate ti-text-form-label text-width80"> | ||||
@@ -350,33 +393,34 @@ td, th { | |||||
</td> | </td> | ||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.dataset"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-BenchmarkTypeName"> | |||||
{{.DatasetName}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.dataset"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-BenchmarkTypeName"> | |||||
{{.DatasetName}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.standard"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{$.resource_spec}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.modelarts.train_job.standard"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w"> | |||||
{{$.resource_spec}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | <td class="ti-no-ng-animate ti-text-form-label text-width80"> | ||||
{{$.i18n.Tr "repo.cloudbrain.time.starttime"}} | {{$.i18n.Tr "repo.cloudbrain.time.starttime"}} | ||||
@@ -384,44 +428,46 @@ td, th { | |||||
<td class="ti-text-form-content"> | <td class="ti-text-form-content"> | ||||
<div class="text-span text-span-w"> | <div class="text-span text-span-w"> | ||||
<div class="text-span text-span-w" id="{{.VersionName}}-startTime"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-startTime"> | |||||
{{if not (eq .StartTime 0)}} | {{if not (eq .StartTime 0)}} | ||||
{{TimeSinceUnix1 .StartTime}} | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
{{TimeSinceUnix1 .StartTime}} | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</td> | </td> | ||||
</tr> | </tr> | ||||
<tr class="ti-no-ng-animate"> | <tr class="ti-no-ng-animate"> | ||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.time.endtime"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" id="{{.VersionName}}-EndTime"> | |||||
{{if not (eq .EndTime 0)}} | |||||
{{TimeSinceUnix1 .EndTime}} | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
<td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||||
{{$.i18n.Tr "repo.cloudbrain.time.endtime"}} | |||||
</td> | |||||
<td class="ti-text-form-content"> | |||||
<div class="text-span text-span-w" | |||||
id="{{.VersionName}}-EndTime"> | |||||
{{if not (eq .EndTime 0)}} | |||||
{{TimeSinceUnix1 .EndTime}} | |||||
{{else}} | |||||
-- | |||||
{{end}} | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -457,24 +503,10 @@ td, th { | |||||
<script> | <script> | ||||
$('.menu .item').tab() | $('.menu .item').tab() | ||||
$(document).ready(function(){ | |||||
$('.ui.accordion').accordion({selector:{trigger:'.icon'}}); | |||||
$(document).ready(function () { | |||||
$('.ui.accordion').accordion({ selector: { trigger: '.icon' } }); | |||||
}); | }); | ||||
$(document).ready(function(){ | |||||
$(document).ready(function () { | |||||
$('.secondary.menu .item').tab(); | $('.secondary.menu .item').tab(); | ||||
}); | }); | ||||
let userName | |||||
let repoPath | |||||
let jobName | |||||
$(document).ready(function(){ | |||||
let url = window.location.href; | |||||
let urlArr = url.split('/') | |||||
userName = urlArr.slice(-5)[0] | |||||
repoPath = urlArr.slice(-4)[0] | |||||
jobName = urlArr.slice(-1)[0] | |||||
}) | |||||
</script> | |||||
</script> |
@@ -239,7 +239,7 @@ const params = new URLSearchParams(location.search) | |||||
if(!location.search){ | if(!location.search){ | ||||
$('.default.text').text(all) | $('.default.text').text(all) | ||||
}else{ | }else{ | ||||
if(params.has('listType') && params.get('listType')=='all'){ | |||||
if(!params.has('listType') || params.get('listType')=='all'){ | |||||
$('.default.text').text(all) | $('.default.text').text(all) | ||||
} | } | ||||
else{ | else{ | ||||
@@ -1,109 +1,200 @@ | |||||
<table id="repo-files-table" class="ui single line table"> | |||||
<style> | |||||
.context-menu { | |||||
z-index: 99; | |||||
position: absolute; | |||||
padding: 0; | |||||
border-radius: 4px; | |||||
border: 1px solid #e3e9ed; | |||||
-webkit-box-shadow: none; | |||||
box-shadow: none; | |||||
background: #fff; | |||||
display: none !important; | |||||
} | |||||
.context-menu.active { | |||||
display: block !important; | |||||
} | |||||
.context-menu-operation { | |||||
padding: 5px !important; | |||||
line-height: 1.78 !important; | |||||
} | |||||
.context-menu-icon { | |||||
float: left !important; | |||||
margin: 0px 5px 0px 0px !important; | |||||
} | |||||
</style> | |||||
<div id="mask"> | |||||
<div id="loadingPage"> | |||||
<div class="rect1"></div> | |||||
<div class="rect2"></div> | |||||
<div class="rect3"></div> | |||||
<div class="rect4"></div> | |||||
<div class="rect5"></div> | |||||
</div> | |||||
</div> | |||||
<table id="repo-files-table" class="ui single line table can-context-menu" data-can-editfile="{{.CanEditFile}}"> | |||||
{{.CsrfTokenHtml}} | |||||
<thead> | <thead> | ||||
<tr class="commit-list"> | <tr class="commit-list"> | ||||
<th colspan="2"> | <th colspan="2"> | ||||
{{if .LatestCommitUser}} | {{if .LatestCommitUser}} | ||||
<img class="ui avatar image img-12" src="{{.LatestCommitUser.RelAvatarLink}}" /> | |||||
{{if .LatestCommitUser.FullName}} | |||||
<a href="{{AppSubUrl}}/{{.LatestCommitUser.Name}}"><strong>{{.LatestCommitUser.FullName}}</strong></a> | |||||
{{else}} | |||||
<a href="{{AppSubUrl}}/{{.LatestCommitUser.Name}}"><strong>{{if .LatestCommit.Author}}{{.LatestCommit.Author.Name}}{{else}}{{.LatestCommitUser.Name}}{{end}}</strong></a> | |||||
{{end}} | |||||
<img class="ui avatar image img-12" src="{{.LatestCommitUser.RelAvatarLink}}" /> | |||||
{{if .LatestCommitUser.FullName}} | |||||
<a href="{{AppSubUrl}}/{{.LatestCommitUser.Name}}"><strong>{{.LatestCommitUser.FullName}}</strong></a> | |||||
{{else}} | {{else}} | ||||
{{if .LatestCommit.Author}} | |||||
<img class="ui avatar image img-12" src="{{AvatarLink .LatestCommit.Author.Email}}" /> | |||||
<strong>{{.LatestCommit.Author.Name}}</strong> | |||||
{{end}} | |||||
<a | |||||
href="{{AppSubUrl}}/{{.LatestCommitUser.Name}}"><strong>{{if .LatestCommit.Author}}{{.LatestCommit.Author.Name}}{{else}}{{.LatestCommitUser.Name}}{{end}}</strong></a> | |||||
{{end}} | {{end}} | ||||
<a rel="nofollow" class="ui sha label {{if .LatestCommit.Signature}} isSigned {{if .LatestCommitVerification.Verified }} isVerified{{if eq .LatestCommitVerification.TrustStatus "trusted"}}{{else if eq .LatestCommitVerification.TrustStatus "untrusted"}}Untrusted{{else}}Unmatched{{end}}{{else if .LatestCommitVerification.Warning}} isWarning{{end}}{{end}}" href="{{.RepoLink}}/commit/{{.LatestCommit.ID}}"> | |||||
{{else}} | |||||
{{if .LatestCommit.Author}} | |||||
<img class="ui avatar image img-12" src="{{AvatarLink .LatestCommit.Author.Email}}" /> | |||||
<strong>{{.LatestCommit.Author.Name}}</strong> | |||||
{{end}} | |||||
{{end}} | |||||
<a rel="nofollow" | |||||
class="ui sha label {{if .LatestCommit.Signature}} isSigned {{if .LatestCommitVerification.Verified }} isVerified{{if eq .LatestCommitVerification.TrustStatus "trusted"}}{{else if eq .LatestCommitVerification.TrustStatus "untrusted"}}Untrusted{{else}}Unmatched{{end}}{{else if .LatestCommitVerification.Warning}} isWarning{{end}}{{end}}" | |||||
href="{{.RepoLink}}/commit/{{.LatestCommit.ID}}"> | |||||
<span class="shortsha">{{ShortSha .LatestCommit.ID.String}}</span> | <span class="shortsha">{{ShortSha .LatestCommit.ID.String}}</span> | ||||
{{if .LatestCommit.Signature}} | {{if .LatestCommit.Signature}} | ||||
<div class="ui detail icon button"> | |||||
{{if .LatestCommitVerification.Verified}} | |||||
<div title="{{if eq .LatestCommitVerification.TrustStatus "trusted"}}{{else if eq .LatestCommitVerification.TrustStatus "untrusted"}}{{.i18n.Tr "repo.commits.signed_by_untrusted_user"}}: {{else}}{{.i18n.Tr "repo.commits.signed_by_untrusted_user_unmatched"}}: {{end}}{{.LatestCommitVerification.Reason}}"> | |||||
{{if ne .LatestCommitVerification.SigningUser.ID 0}} | |||||
<i class="lock icon"></i> | |||||
<img class="ui signature avatar image" src="{{.LatestCommitVerification.SigningUser.RelAvatarLink}}" /> | |||||
{{else}} | |||||
<i title="{{.LatestCommitVerification.Reason}}" class="icons"> | |||||
<i class="lock icon"></i> | |||||
<i class="tiny inverted cog icon centerlock"></i> | |||||
</i> | |||||
<img class="ui signature avatar image" src="{{AvatarLink .LatestCommitVerification.SigningEmail}}" /> | |||||
{{end}} | |||||
</div> | |||||
<div class="ui detail icon button"> | |||||
{{if .LatestCommitVerification.Verified}} | |||||
<div | |||||
title="{{if eq .LatestCommitVerification.TrustStatus "trusted"}}{{else if eq .LatestCommitVerification.TrustStatus "untrusted"}}{{.i18n.Tr "repo.commits.signed_by_untrusted_user"}}: {{else}}{{.i18n.Tr "repo.commits.signed_by_untrusted_user_unmatched"}}: {{end}}{{.LatestCommitVerification.Reason}}"> | |||||
{{if ne .LatestCommitVerification.SigningUser.ID 0}} | |||||
<i class="lock icon"></i> | |||||
<img class="ui signature avatar image" | |||||
src="{{.LatestCommitVerification.SigningUser.RelAvatarLink}}" /> | |||||
{{else}} | {{else}} | ||||
<i title="{{$.i18n.Tr .LatestCommitVerification.Reason}}" class="unlock icon"></i> | |||||
<i title="{{.LatestCommitVerification.Reason}}" class="icons"> | |||||
<i class="lock icon"></i> | |||||
<i class="tiny inverted cog icon centerlock"></i> | |||||
</i> | |||||
<img class="ui signature avatar image" | |||||
src="{{AvatarLink .LatestCommitVerification.SigningEmail}}" /> | |||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
{{else}} | |||||
<i title="{{$.i18n.Tr .LatestCommitVerification.Reason}}" class="unlock icon"></i> | |||||
{{end}} | |||||
</div> | |||||
{{end}} | {{end}} | ||||
</a> | </a> | ||||
{{template "repo/commit_status" .LatestCommitStatus}} | {{template "repo/commit_status" .LatestCommitStatus}} | ||||
{{ $commitLink:= printf "%s/commit/%s" .RepoLink .LatestCommit.ID }} | {{ $commitLink:= printf "%s/commit/%s" .RepoLink .LatestCommit.ID }} | ||||
<span class="grey commit-summary" title="{{.LatestCommit.Summary}}"><span class="message-wrapper">{{RenderCommitMessageLinkSubject .LatestCommit.Message $.RepoLink $commitLink $.Repository.ComposeMetas}}</span> | |||||
{{if IsMultilineCommitMessage .LatestCommit.Message}} | |||||
<button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button> | |||||
<pre class="commit-body" style="display: none;">{{RenderCommitBody .LatestCommit.Message $.RepoLink $.Repository.ComposeMetas}}</pre> | |||||
{{end}} | |||||
<span class="grey commit-summary" title="{{.LatestCommit.Summary}}"><span | |||||
class="message-wrapper">{{RenderCommitMessageLinkSubject .LatestCommit.Message $.RepoLink $commitLink $.Repository.ComposeMetas}}</span> | |||||
{{if IsMultilineCommitMessage .LatestCommit.Message}} | |||||
<button class="basic compact mini ui icon button commit-button"><i | |||||
class="ellipsis horizontal icon"></i></button> | |||||
<pre class="commit-body" | |||||
style="display: none;">{{RenderCommitBody .LatestCommit.Message $.RepoLink $.Repository.ComposeMetas}}</pre> | |||||
{{end}} | |||||
</span> | </span> | ||||
</th> | </th> | ||||
<th class="text grey right age">{{if .LatestCommit.Author}}{{TimeSince .LatestCommit.Author.When $.Lang}}{{end}}</th> | |||||
<th class="text grey right age"> | |||||
{{if .LatestCommit.Author}}{{TimeSince .LatestCommit.Author.When $.Lang}}{{end}}</th> | |||||
</tr> | </tr> | ||||
</thead> | </thead> | ||||
<tbody> | <tbody> | ||||
{{if .HasParentPath}} | {{if .HasParentPath}} | ||||
<tr class="has-parent"> | |||||
<td colspan="3">{{svg "octicon-mail-reply" 16}}<a href="{{EscapePound .BranchLink}}{{.ParentPath}}">..</a></td> | |||||
</tr> | |||||
<tr class="has-parent"> | |||||
<td colspan="3">{{svg "octicon-mail-reply" 16}}<a href="{{EscapePound .BranchLink}}{{.ParentPath}}">..</a> | |||||
</td> | |||||
</tr> | |||||
{{end}} | {{end}} | ||||
{{range $item := .Files}} | {{range $item := .Files}} | ||||
{{$entry := index $item 0}} | |||||
{{$commit := index $item 1}} | |||||
<tr> | |||||
{{if $entry.IsSubModule}} | |||||
<td> | |||||
<span class="truncate"> | |||||
{{svg "octicon-inbox" 16}} | |||||
{{$refURL := $commit.RefURL AppUrl $.Repository.FullName}} | |||||
{{if $refURL}} | |||||
<a href="{{$refURL}}">{{$entry.Name}}</a> @ <a href="{{$refURL}}/commit/{{$commit.RefID}}">{{ShortSha $commit.RefID}}</a> | |||||
{{else}} | |||||
{{$entry.Name}} @ {{ShortSha $commit.RefID}} | |||||
{{end}} | |||||
</span> | |||||
</td> | |||||
{{else}} | |||||
<td class="name four wide"> | |||||
<span class="truncate"> | |||||
{{if $entry.IsDir}} | |||||
{{$subJumpablePathName := $entry.GetSubJumpablePathName}} | |||||
{{$subJumpablePath := SubJumpablePath $subJumpablePathName}} | |||||
{{svg "octicon-file-directory" 16}} | |||||
<a href="{{EscapePound $.TreeLink}}/{{EscapePound $subJumpablePathName}}" title="{{$subJumpablePathName}}"> | |||||
{{if eq (len $subJumpablePath) 2}} | |||||
<span class="jumpable-path">{{index $subJumpablePath 0}}</span>{{index $subJumpablePath 1}} | |||||
{{else}} | |||||
{{index $subJumpablePath 0}} | |||||
{{end}} | |||||
</a> | |||||
{{else}} | |||||
{{svg (printf "octicon-%s" (EntryIcon $entry)) 16}} | |||||
<a href="{{EscapePound $.TreeLink}}/{{EscapePound $entry.Name}}" title="{{$entry.Name}}">{{$entry.Name}}</a> | |||||
{{end}} | |||||
</span> | |||||
</td> | |||||
{{end}} | |||||
<td class="message nine wide"> | |||||
<span class="truncate"> | |||||
<a href="{{$.RepoLink}}/commit/{{$commit.ID}}" title="{{$commit.Summary}}">{{$commit.Summary | RenderEmoji}}</a> | |||||
</span> | |||||
</td> | |||||
<td class="text right age three wide">{{TimeSince $commit.Committer.When $.Lang}}</td> | |||||
</tr> | |||||
{{$entry := index $item 0}} | |||||
{{$commit := index $item 1}} | |||||
<tr> | |||||
{{if $entry.IsSubModule}} | |||||
<td> | |||||
<span class="truncate"> | |||||
{{svg "octicon-inbox" 16}} | |||||
{{$refURL := $commit.RefURL AppUrl $.Repository.FullName}} | |||||
{{if $refURL}} | |||||
<a href="{{$refURL}}">{{$entry.Name}}</a> @ <a | |||||
href="{{$refURL}}/commit/{{$commit.RefID}}">{{ShortSha $commit.RefID}}</a> | |||||
{{else}} | |||||
{{$entry.Name}} @ {{ShortSha $commit.RefID}} | |||||
{{end}} | |||||
</span> | |||||
</td> | |||||
{{else}} | |||||
<td class="name four wide modified-contextmenu"> | |||||
<span class="truncate"> | |||||
{{if $entry.IsDir}} | |||||
{{$subJumpablePathName := $entry.GetSubJumpablePathName}} | |||||
{{$subJumpablePath := SubJumpablePath $subJumpablePathName}} | |||||
{{svg "octicon-file-directory" 16}} | |||||
<a href="{{EscapePound $.TreeLink}}/{{EscapePound $subJumpablePathName}}" | |||||
title="{{$subJumpablePathName}}"> | |||||
{{if eq (len $subJumpablePath) 2}} | |||||
<span class="jumpable-path">{{index $subJumpablePath 0}}</span>{{index $subJumpablePath 1}} | |||||
{{else}} | |||||
{{index $subJumpablePath 0}} | |||||
{{end}} | |||||
</a> | |||||
{{else}} | |||||
{{svg (printf "octicon-%s" (EntryIcon $entry)) 16}} | |||||
<a href="{{EscapePound $.TreeLink}}/{{EscapePound $entry.Name}}" | |||||
title="{{$entry.Name}}">{{$entry.Name}}</a> | |||||
{{end}} | |||||
</span> | |||||
</td> | |||||
{{end}} | |||||
<td class="message nine wide"> | |||||
<span class="truncate"> | |||||
<a href="{{$.RepoLink}}/commit/{{$commit.ID}}" | |||||
title="{{$commit.Summary}}">{{$commit.Summary | RenderEmoji}}</a> | |||||
</span> | |||||
</td> | |||||
<td class="text right age three wide">{{TimeSince $commit.Committer.When $.Lang}}</td> | |||||
</tr> | |||||
<tr style="display: none !important;" class="context-menu-one"> | |||||
<td colspan="12"> | |||||
<div class="ui column form" method="POST"> | |||||
<div class="two fields" style="margin: 0;"> | |||||
<div class="five wide field"> | |||||
<input class="ui input" name="new_filename" type="text" value=""> | |||||
</div> | |||||
<div class="five wide field"> | |||||
<button class="ui blue button popup-save" type="button" | |||||
data-postBasePath="{{$.RepoLink}}/_rename/{{EscapePound $.BranchName}}{{if $.TreePath}}/{{EscapePound $.TreePath}}{{end}}/{{$entry.Name}}" | |||||
data-commit="{{$.LatestCommit.ID}}" | |||||
data-treepath="{{if $.TreePath}}{{EscapePound $.TreePath}}/{{end}}">保存</button> | |||||
<button class="ui basic button popup-close" type="button">取消</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
{{end}} | {{end}} | ||||
</tbody> | </tbody> | ||||
</table> | </table> | ||||
{{if .ReadmeExist}} | {{if .ReadmeExist}} | ||||
{{template "repo/view_file" .}} | |||||
{{template "repo/view_file" .}} | |||||
{{end}} | {{end}} | ||||
<!-- 确认模态框 --> | |||||
<div id="deletemodel"> | |||||
<div class="ui basic modal context-menu-delete"> | |||||
<div class="ui icon header"> | |||||
<i class="trash icon"></i> {{.i18n.Tr "cloudbrain.delete_task"}} | |||||
</div> | |||||
<div class="content"> | |||||
<p>{{.i18n.Tr "cloudbrain.task_delete_confirm"}}</p> | |||||
</div> | |||||
<div class="actions"> | |||||
<div class="ui red basic inverted cancel button"> | |||||
<i class="remove icon"></i> {{.i18n.Tr "cloudbrain.operate_cancel"}} | |||||
</div> | |||||
<div class="ui green basic inverted ok button"> | |||||
<i class="checkmark icon"></i> {{.i18n.Tr "cloudbrain.operate_confirm"}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> |
@@ -1,108 +1,61 @@ | |||||
<template> | <template> | ||||
<div style="height:100%"> | |||||
<el-tabs tab-position="left" v-model="activeName" style="height:100%" @tab-click="handleClick" > | |||||
<el-tab-pane label="概览" name="first" > | |||||
<span slot="label"> | |||||
<el-image style="width: 13px; height: 13px" src="/img/overview_rgb.svg"> | |||||
</el-image> | |||||
概览 | |||||
</span> | |||||
<div >暂无内容.......</div> | |||||
<el-row style="height:100%;width: 100%; flex:1" > | |||||
<el-col :span="3" style="height:100%;padding-right:15px;"> | |||||
<el-menu | |||||
:default-active="this.$router.path" | |||||
class="el-menu-vertical-demo" | |||||
:router="true" style="height:100%; background-color: #F5F5F6;" > | |||||
<el-menu-item index="/Overview" > | |||||
<i class="ri-home-4-line"></i> | |||||
<span slot="title">概览</span> | |||||
</el-menu-item> | |||||
<el-submenu index="/"> | |||||
<template slot="title"> | |||||
<i class="ri-numbers-line"></i> | |||||
<span>项目分析</span> | |||||
</template> | |||||
<el-menu-item index="/ProTrend">增长趋势分析</el-menu-item> | |||||
<el-menu-item index="/ProAnalysis">详细数据</el-menu-item> | |||||
</el-submenu> | |||||
<el-submenu index="2"> | |||||
<template slot="title"> | |||||
<i class="ri-contacts-line"></i> | |||||
<span>用户分析</span> | |||||
</template> | |||||
<el-menu-item index="/UserTrend">增长趋势分析</el-menu-item> | |||||
<el-menu-item index="/UserAnalysis">活动分析</el-menu-item> | |||||
</el-submenu> | |||||
<el-menu-item index="/BrainAnalysis"> | |||||
<i class="ri-server-fill"></i> | |||||
<span slot="title">云脑分析(建设中..)</span> | |||||
</el-menu-item> | |||||
</el-menu> | |||||
</el-col> | |||||
<router-view> </router-view> | |||||
</el-row> | |||||
</template> | |||||
</el-tab-pane> | |||||
<el-tab-pane label="项目分析" name="second" id="second" > | |||||
<ProAnalysis ref='ProAnalysis'id="pro" v-if="isRouterAlive"></ProAnalysis> | |||||
<span slot="label"> | |||||
<el-image style="width: 13px; height: 13px" src="/img/pro_rgb.svg"> | |||||
</el-image> | |||||
项目分析 | |||||
</span> | |||||
</el-tab-pane> | |||||
<el-tab-pane name="third" id='third' > | |||||
<span slot='label'> | |||||
<el-image style="width: 13px; height: 13px" src="/img/user_rgb.svg"> | |||||
</el-image> | |||||
用户分析 | |||||
</span> | |||||
<UserAnalysis ref='UserAnalysis' v-if="isRouterAlive1" id ="usr"></UserAnalysis> | |||||
</el-tab-pane> | |||||
<el-tab-pane name="four" id='four' > | |||||
<BrainAnalysis ref='BrainAnalysis'id="brain" v-if="isRouterAlive"></BrainAnalysis> | |||||
<span slot="label"> | |||||
<el-image style="width: 13px; height: 13px" src="/img/pro_rgb.svg"> | |||||
</el-image> | |||||
云脑分析(建设中..) | |||||
</span> | |||||
</el-tab-pane> | |||||
</el-tabs> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
import ProAnalysis from './ProAnalysis.vue' | |||||
import UserAnalysis from './UserAnalysis.vue' | |||||
import BrainAnalysis from './BrainAnalysis.vue' | |||||
export default { | |||||
components:{ | |||||
'ProAnalysis':ProAnalysis, | |||||
'UserAnalysis':UserAnalysis, | |||||
'BrainAnalysis':BrainAnalysis, | |||||
}, | |||||
data() { | |||||
return { | |||||
activeName:"second", | |||||
loading:true, | |||||
loading1:true, | |||||
isRouterAlive: true, | |||||
isRouterAlive1: true, | |||||
isSecond:true, | |||||
isThird:false, | |||||
} | |||||
}, | |||||
methods:{ | |||||
handleClick(tab, event){ | |||||
if(tab.name=="second"){ | |||||
this.reload() | |||||
this.isSecond = true | |||||
this.isThird = false | |||||
this.$refs.ProAnalysis.getAllProList("all",7) | |||||
} | |||||
if(tab.name=="third"){ | |||||
this.reload1() | |||||
this.isSecond = false | |||||
this.isThird = true | |||||
this.$refs.UserAnalysis.getUpdateTime() | |||||
this.$refs.UserAnalysis.getUserList("all_usr",7) | |||||
} | |||||
}, | |||||
reload () { | |||||
this.isRouterAlive = false | |||||
this.$nextTick(() => (this.isRouterAlive = true)) | |||||
}, | |||||
reload1 () { | |||||
this.isRouterAlive1 = false | |||||
this.$nextTick(() => (this.isRouterAlive1 = true)) | |||||
} | |||||
}, | |||||
} | |||||
</script> | |||||
<style scoped> | |||||
<script> | |||||
export default{ | |||||
data(){ | |||||
return { | |||||
Path_router:'/' | |||||
} | |||||
}, | |||||
created(){ | |||||
var url_params = document.getElementById("url_params").value; | |||||
if (url_params!='' && url_params!=undefined && url_params!='/'){ | |||||
this.$router.path = '/'+url_params.split('/')[0] | |||||
}else{ | |||||
this.$router.path = '/ProAnalysis' | |||||
} | |||||
}, | |||||
} | |||||
</script> | |||||
<style scoped> | |||||
/deep/ .is-active{ | /deep/ .is-active{ | ||||
color: #238BFC ; | |||||
background-color: #FFFF ; | |||||
color: #238BFC ; | |||||
} | } | ||||
/deep/ .ui-container{ | /deep/ .ui-container{ | ||||
background-color: #FFFF; | background-color: #FFFF; | ||||
@@ -137,8 +90,26 @@ | |||||
/deep/ .el-tabs__item:hover .el-image{ | /deep/ .el-tabs__item:hover .el-image{ | ||||
filter:none | filter:none | ||||
} | } | ||||
/deep/ .el-image{ | |||||
filter:grayscale(100%) | |||||
.bk{ | |||||
background-color: #F5F5F6; | |||||
} | |||||
.el-menu-item.is-active { | |||||
color: #409eff; | |||||
background-color: #FFFFFF !important; | |||||
} | |||||
/deep/ .el-submenu.is-active .el-submenu__title { | |||||
color: #409eff | |||||
} | } | ||||
/deep/ .el-submenu.is-active .el-submenu__title i{ | |||||
color: #409eff | |||||
} | |||||
/deep/ .el-menu, .el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .el-menu--horizontal>.el-submenu .el-submenu__title:hover { | |||||
background-color: #F5F5F6; | |||||
} | |||||
/deep/ .el-pagination { | |||||
padding-bottom: 30px; | |||||
} | |||||
</style> | |||||
</style> |
@@ -0,0 +1,5 @@ | |||||
<template> | |||||
<div> | |||||
暂无内容 | |||||
</div> | |||||
</template> |
@@ -1,8 +1,8 @@ | |||||
<template> | <template> | ||||
<div style="width: 100%;"> | |||||
<div class="el-col el-col-21" style="padding-right:10px " > | |||||
<div id = "pro_main"> | <div id = "pro_main"> | ||||
<div style="margin-top: 10px;"> | <div style="margin-top: 10px;"> | ||||
<b class="pro_item">项目分析</b> <span class="update_time">数据更新时间:</span> <span style="font-size: 12px;">{{lastUpdatedTime}} / 从{{recordBeginTime}}开始统计</span> | |||||
<b class="pro_item">详细数据</b> <span class="update_time">数据更新时间:</span> <span style="font-size: 12px;">{{lastUpdatedTime}} / 从{{recordBeginTime}}开始统计</span> | |||||
</div> | </div> | ||||
<bar-label :width="'95%'" :height="'500px'"></bar-label> | <bar-label :width="'95%'" :height="'500px'"></bar-label> | ||||
@@ -29,11 +29,11 @@ | |||||
</span> | </span> | ||||
<span style="float:right; margin-right: 20px;"> | <span style="float:right; margin-right: 20px;"> | ||||
<div style="display:inline-block;margin-left: 20px; "> | <div style="display:inline-block;margin-left: 20px; "> | ||||
<a class="el-icon-download" v-if="tableData!=''" :href= "'../api/v1/projectboard/downloadAll/?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime+'&q='+this.params.q+'&sort=openi'" ></a> | |||||
<a class="el-icon-download" v-if="tableData!=''" :href= "'../../api/v1/projectboard/downloadAll/?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime+'&q='+this.params.q+'&sort=openi'" ></a> | |||||
<i class="el-icon-download" v-else="tableData=''" href="#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'></i> | <i class="el-icon-download" v-else="tableData=''" href="#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'></i> | ||||
<!-- <span ><a id = "download_file" :href= "'../api/v1/projectboard/downloadAll/?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime+'&q='+this.params.q+'&sort=openi'" >下载报告</a> </span> --> | <!-- <span ><a id = "download_file" :href= "'../api/v1/projectboard/downloadAll/?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime+'&q='+this.params.q+'&sort=openi'" >下载报告</a> </span> --> | ||||
<span > | <span > | ||||
<a id = "download_file" v-if="tableData!=''" :href= "'../api/v1/projectboard/downloadAll/?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime+'&q='+this.params.q+'&sort=openi'">下载报告</a> | |||||
<a id = "download_file" v-if="tableData!=''" :href= "'../../api/v1/projectboard/downloadAll/?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime+'&q='+this.params.q+'&sort=openi'">下载报告</a> | |||||
<a id = "download_file" v-else="tableData=''" href= "#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'>下载报告</a> | <a id = "download_file" v-else="tableData=''" href= "#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'>下载报告</a> | ||||
</span> | </span> | ||||
</div> | </div> | ||||
@@ -59,6 +59,7 @@ | |||||
> | > | ||||
</el-table-column> | </el-table-column> | ||||
<el-table-column | <el-table-column | ||||
fixed | |||||
label="项目名称中文" | label="项目名称中文" | ||||
align="left" | align="left" | ||||
prop="name" | prop="name" | ||||
@@ -404,8 +405,7 @@ | |||||
value_time: '', | value_time: '', | ||||
search:'', | search:'', | ||||
dynamic:7, | dynamic:7, | ||||
download_a:"", | |||||
downLoadSrc:'', | |||||
//单个项目参数 | //单个项目参数 | ||||
@@ -652,7 +652,7 @@ | |||||
getAllProList(type_val,index){ | getAllProList(type_val,index){ | ||||
console.log("类型:"+type_val) | |||||
// console.log("类型:"+type_val) | |||||
this.dynamic = index | this.dynamic = index | ||||
if (typeof type_val=="undefined" || type_val=="null" || type_val==""){ | if (typeof type_val=="undefined" || type_val=="null" || type_val==""){ | ||||
this.params.type='' | this.params.type='' | ||||
@@ -665,7 +665,7 @@ | |||||
this.value_time=[] | this.value_time=[] | ||||
} | } | ||||
this.$axios.get('../api/v1/projectboard/project',{ | |||||
this.$axios.get('../../api/v1/projectboard/project',{ | |||||
params:this.params | params:this.params | ||||
}).then((res)=>{ | }).then((res)=>{ | ||||
@@ -720,7 +720,7 @@ | |||||
}, | }, | ||||
getOneProData(pro_id){ | getOneProData(pro_id){ | ||||
this.$axios.get('../api/v1/projectboard/project/'+pro_id,{ | |||||
this.$axios.get('../../api/v1/projectboard/project/'+pro_id,{ | |||||
}).then((res)=>{ | }).then((res)=>{ | ||||
this.tableDataIDTotal = res.data | this.tableDataIDTotal = res.data | ||||
this.tableDataContTop10=res.data.top10 | this.tableDataContTop10=res.data.top10 | ||||
@@ -731,7 +731,7 @@ | |||||
}, | }, | ||||
getOneProList(pro_id,type_val,bool_val,index){ | getOneProList(pro_id,type_val,bool_val,index){ | ||||
this.dynamic_pro=index | this.dynamic_pro=index | ||||
console.log("日期类型:"+type_val) | |||||
// console.log("日期类型:"+type_val) | |||||
if (typeof type_val=="undefined" || type_val=="null" || type_val==""){ | if (typeof type_val=="undefined" || type_val=="null" || type_val==""){ | ||||
this.paramsID.type='' | this.paramsID.type='' | ||||
this.paramsID.beginTime= this.formatDate(this.create_time_pro[0].getFullYear(),this.create_time_pro[0].getMonth() + 1,this.create_time_pro[0].getDate()) | this.paramsID.beginTime= this.formatDate(this.create_time_pro[0].getFullYear(),this.create_time_pro[0].getMonth() + 1,this.create_time_pro[0].getDate()) | ||||
@@ -743,7 +743,7 @@ | |||||
this.paramsID.endTime='' | this.paramsID.endTime='' | ||||
} | } | ||||
this.paramsID.openi=bool_val | this.paramsID.openi=bool_val | ||||
this.$axios.get('../api/v1/projectboard/project/'+pro_id+"/period",{ | |||||
this.$axios.get('../../api/v1/projectboard/project/'+pro_id+"/period",{ | |||||
params:this.paramsID | params:this.paramsID | ||||
}).then((res)=>{ | }).then((res)=>{ | ||||
if (bool_val){ | if (bool_val){ | ||||
@@ -923,12 +923,24 @@ | |||||
type : 'category', | type : 'category', | ||||
boundaryGap: false, | boundaryGap: false, | ||||
data : xdata_openI, | data : xdata_openI, | ||||
axisLine: { | |||||
show: false, //x轴线消失 | |||||
}, | |||||
axisTick:{ | |||||
show:false//刻度隐藏 | |||||
} | |||||
} | } | ||||
], | ], | ||||
yAxis : [ | yAxis : [ | ||||
{ | { | ||||
type : 'value', | type : 'value', | ||||
axisLine: { | |||||
show: false, //x轴线消失 | |||||
}, | |||||
axisTick:{ | |||||
show:false//刻度隐藏 | |||||
} | |||||
} | } | ||||
], | ], | ||||
@@ -1011,6 +1023,12 @@ | |||||
}, | }, | ||||
legend: { | legend: { | ||||
data:['浏览量','下载量','commit'], | data:['浏览量','下载量','commit'], | ||||
selected:{ | |||||
// '浏览量':true, | |||||
// '下载量':true, | |||||
// 'commit':true, | |||||
} | |||||
// orient: 'vertical', | // orient: 'vertical', | ||||
// top:'top', | // top:'top', | ||||
}, | }, | ||||
@@ -1029,12 +1047,24 @@ | |||||
{ | { | ||||
type : 'category', | type : 'category', | ||||
data : xdata, | data : xdata, | ||||
axisLine: { | |||||
show: false, //x轴线消失 | |||||
}, | |||||
axisTick:{ | |||||
show:false//刻度隐藏 | |||||
} | |||||
} | } | ||||
], | ], | ||||
yAxis : [ | yAxis : [ | ||||
{ | { | ||||
type : 'value', | |||||
type : 'value', | |||||
axisLine: { | |||||
show: false, //x轴线消失 | |||||
}, | |||||
axisTick:{ | |||||
show:false//刻度隐藏 | |||||
} | |||||
} | } | ||||
], | ], | ||||
series : [ | series : [ | ||||
@@ -1059,6 +1089,16 @@ | |||||
] | ] | ||||
}; | }; | ||||
// this.echartsSelectData.resize() | // this.echartsSelectData.resize() | ||||
var checkboxs=document.getElementsByName('checkboxchart'); | |||||
for(var i=0; i<checkboxs.length; i++){ | |||||
// console.log("selectArr[i]:",this.option.legend.data[i]) | |||||
if(checkboxs[i].checked){ | |||||
this.option.legend.selected[this.option.legend.data[i]]=true; | |||||
}else{ | |||||
this.option.legend.selected[this.option.legend.data[i]]=false; | |||||
} | |||||
} | |||||
this.echartsSelectData.setOption(this.option) | this.echartsSelectData.setOption(this.option) | ||||
// setTimeout(function (){ | // setTimeout(function (){ | ||||
// window.onresize = function () { | // window.onresize = function () { | ||||
@@ -1299,6 +1339,9 @@ | |||||
/deep/ .el-range-separator{ | /deep/ .el-range-separator{ | ||||
width: 20% !important; | width: 20% !important; | ||||
} | } | ||||
/deep/ .el-pagination { | |||||
padding-bottom: 30px; | |||||
} | |||||
.colorChange { | .colorChange { | ||||
background-color: #1684FC; | background-color: #1684FC; | ||||
@@ -0,0 +1,903 @@ | |||||
<template> | |||||
<div class="el-col el-col-21" style="padding-right:10px "> | |||||
<div id='pro_tend' > | |||||
<div style="margin-top: 10px;"> | |||||
<b class="pro_item">增长趋势分析</b> <span class="update_time">数据更新时间:</span> <span style="font-size: 12px;">{{lastUpdatedTime}} / 从{{recordBeginTime}}开始统计</span> | |||||
</div> | |||||
<div style="margin-top:20px"> | |||||
<el-row> | |||||
<el-col :span='1' class ='item_list_first'> | |||||
<el-row class="item_title_h"> | |||||
| |||||
</el-row> | |||||
<el-row class="item_h"> | |||||
昨天 | |||||
</el-row> | |||||
<el-row class="item_h"> | |||||
累计 | |||||
</el-row> | |||||
</el-col> | |||||
<el-col span='23' > | |||||
<el-col :span='3' class ='item_list'> | |||||
<el-row class="item_title_h"> | |||||
项目 | |||||
</el-row> | |||||
<el-row class="item_h num_color"> | |||||
{{tableDataSummary.numReposAdd}} | |||||
</el-row> | |||||
<el-row class="item_h"> | |||||
{{ tableDataSummary.numRepos}} | |||||
</el-row> | |||||
</el-col> | |||||
<el-col :span='3' > | |||||
<el-row class ='item_list_p item_title_h'> | |||||
公开 | |||||
</el-row> | |||||
<el-row class="item_h num_color"> | |||||
{{tableDataSummary.numRepoPublicAdd}} | |||||
</el-row > | |||||
<el-row class="item_h"> | |||||
{{tableDataSummary.numRepoPublic}} | |||||
</el-row> | |||||
</el-col> | |||||
<el-col :span='3' class ='item_list'> | |||||
<el-row class="item_title_h"> | |||||
私有 | |||||
</el-row> | |||||
<el-row class="item_h num_color"> | |||||
{{tableDataSummary.numRepoPrivateAdd}} | |||||
</el-row> | |||||
<el-row class="item_h"> | |||||
{{tableDataSummary.numRepoPrivate}} | |||||
</el-row> | |||||
</el-col> | |||||
<el-col :span='3'> | |||||
<el-row class ='item_list_p item_title_h'> | |||||
自建 | |||||
</el-row> | |||||
<el-row class="item_h num_color"> | |||||
{{tableDataSummary.numRepoSelfAdd}} | |||||
</el-row > | |||||
<el-row class="item_h"> | |||||
{{tableDataSummary.numRepoSelf}} | |||||
</el-row> | |||||
</el-col> | |||||
<el-col :span='3' > | |||||
<el-row class ='item_list_p item_title_h'> | |||||
派生 | |||||
</el-row> | |||||
<el-row class="item_h num_color"> | |||||
{{tableDataSummary.numRepoForkAdd}} | |||||
</el-row > | |||||
<el-row class="item_h"> | |||||
{{tableDataSummary.numRepoFork}} | |||||
</el-row> | |||||
</el-col> | |||||
<el-col :span='3' class ='item_list '> | |||||
<el-row class="item_title_h"> | |||||
镜像 | |||||
</el-row> | |||||
<el-row class="item_h num_color"> | |||||
{{tableDataSummary.numRepoMirrorAdd}} | |||||
</el-row> | |||||
<el-row class="item_h"> | |||||
{{tableDataSummary.numRepoMirror}} | |||||
</el-row> | |||||
</el-col> | |||||
<el-col :span='3'> | |||||
<el-row class ='item_list_p item_title_h'> | |||||
组织 | |||||
</el-row> | |||||
<el-row class="item_h num_color"> | |||||
{{tableDataSummary.numRepoOrgAdd}} | |||||
</el-row> | |||||
<el-row class="item_h"> | |||||
{{tableDataSummary.numRepoOrg}} | |||||
</el-row> | |||||
</el-col> | |||||
<el-col :span='2'> | |||||
<el-row class="item_title_h"> | |||||
个人 | |||||
</el-row> | |||||
<el-row class="item_h num_color"> | |||||
{{tableDataSummary.numRepoNotOrgAdd}} | |||||
</el-row> | |||||
<el-row class="item_h"> | |||||
{{tableDataSummary.numRepoNotOrg}} | |||||
</el-row> | |||||
</el-col> | |||||
</el-col> | |||||
</el-row> | |||||
</div> | |||||
<div style="margin-top: 20px;"> | |||||
<span class="sta_iterm">统计周期:</span> | |||||
<!-- <button type="button" class='btnFirst' id ="yesterday" v-bind:class="{colorChange:1==dynamic}" @click="resetPage(),getPeriodProList('yesterday',1)">昨天</button> --> | |||||
<button type="button" class='btn' id = "current_week" v-bind:class="{colorChange:1==dynamic}" @click="resetPage(),getPeriodProList('current_week',1)">本周</button> | |||||
<button type="button" class='btn' id = "current_month" v-bind:class="{colorChange:2==dynamic}" @click="resetPage(),getPeriodProList('current_month',2)">本月</button> | |||||
<button type="button" class='btn' id = "last_month" v-bind:class="{colorChange:3==dynamic}" @click="resetPage(),getPeriodProList('last_month',3)">上月</button> | |||||
<button type="button" class='btn' id = "monthly" v-bind:class="{colorChange:4==dynamic}" @click="resetPage(),getPeriodProList('monthly',4)">近30天</button> | |||||
<button type="button" class='btn' id = "current_year" v-bind:class="{colorChange:5==dynamic}" @click="resetPage(),getPeriodProList('current_year',5)">今年</button> | |||||
<button type="button" class='btnLast' id = "all" v-bind:class="{colorChange:6==dynamic}" @click="resetPage(),getPeriodProList('all',6)">所有</button> | |||||
<span style="margin-left: 20px;"> | |||||
<el-date-picker | |||||
v-model="value_time" | |||||
prefix-icon="el-icon-time" | |||||
@change="resetPage(),getPeriodProList('',0)" | |||||
type="daterange" | |||||
size='small' | |||||
range-separator="至" | |||||
start-placeholder="开始日期" | |||||
end-placeholder="结束日期"> | |||||
</el-date-picker> | |||||
</span> | |||||
<span style="float:right; margin-right: 20px;"> | |||||
<div style="display:inline-block;margin-left: 20px; "> | |||||
<a class="el-icon-download" v-if="tableData!=''" :href= "'../../api/v1/projectboard/downloadAll/?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime+'&q='+this.params.q+'&sort=openi'" ></a> | |||||
<i class="el-icon-download" v-else="tableData=''" href="#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'></i> | |||||
<!-- <span ><a id = "download_file" :href= "'../api/v1/projectboard/downloadAll/?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime+'&q='+this.params.q+'&sort=openi'" >下载报告</a> </span> --> | |||||
<span > | |||||
<a id = "download_file" v-if="tableData!=''" :href= "'../../api/v1/projectboard/summary/download?type='+this.params.type+'&beginTime='+this.params.beginTime+'&endTime='+this.params.endTime">下载报告</a> | |||||
<a id = "download_file" v-else="tableData=''" href= "#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'>下载报告</a> | |||||
</span> | |||||
</div> | |||||
</span> | |||||
</div> | |||||
<div class="item_echart" id ='linecharts'> | |||||
<div style="margin: 15px 10px 30px;"> | |||||
<label for="label" @change='clickCheckBox'> | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="新增项目"/> 新增项目 | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="新增公开项目"/>新增公开项目 | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="新增私有项目"/>新增私有项目 | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="新增自建项目"/>新增自建项目 | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="新增派生项目"/>新增派生项目 | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="新增镜像项目"/>新增镜像项目 | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="累计项目"/>累计项目 | |||||
</label> | |||||
</div> | |||||
<div id ="selectData" style="height: 300px;"> | |||||
</div> | |||||
</div> | |||||
<div style="margin-top: 30px;"> | |||||
<el-table | |||||
:data="tableData.slice((page-1)*pageSize,page*pageSize)" | |||||
style="width: 100%" | |||||
:header-cell-style="tableHeaderStyle" | |||||
:cell-style='cellStyle'> | |||||
<el-table-column | |||||
label="日期" | |||||
align="left" | |||||
prop="creatTime" | |||||
> | |||||
</el-table-column> | |||||
<el-table-column | |||||
label="新增项目" | |||||
align="center" | |||||
prop="numReposAdd" | |||||
> | |||||
</el-table-column> | |||||
<el-table-column | |||||
label="累计项目" | |||||
align="center" | |||||
prop="numRepos" | |||||
> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="numRepoPublicAdd" | |||||
label="新增公开项目" | |||||
align="center"> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="numRepoPrivateAdd" | |||||
label="新增私有项目" | |||||
align="center"> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="numRepoSelfAdd" | |||||
label="新增自建项目" | |||||
align="center"> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="numRepoForkAdd" | |||||
label="新增派生项目" | |||||
align="center"> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="numRepoMirrorAdd" | |||||
label="新增镜像项目" | |||||
align="center"> | |||||
</el-table-column> | |||||
</el-table> | |||||
</div> | |||||
<div style="margin-top:50px;text-align:center"> | |||||
<el-pagination | |||||
background | |||||
@size-change="handleSizeChange" | |||||
@current-change="handleCurrentChange" | |||||
:current-page="page" | |||||
:page-size="pageSize" | |||||
:page-sizes="[5,10,20]" | |||||
layout="total, sizes,prev, pager, next,jumper" | |||||
:total="tableData.length"> | |||||
</el-pagination> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
// import barLabel from './basic/barLabel.vue'; | |||||
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; | |||||
import { export2Excel } from '../excel/util.js' | |||||
export default{ | |||||
name:'ProAnalysis', | |||||
components: { | |||||
// barLabel, | |||||
}, | |||||
data() { | |||||
return { | |||||
recordBeginTime:'', | |||||
lastUpdatedTime:'', | |||||
page:1, | |||||
pageSize:10, | |||||
params:{type:'monthly',page:1,pagesize:10,beginTime:'',endTime:''}, | |||||
tableData: [], | |||||
tableDataSummary:{}, | |||||
totalPage:0, | |||||
totalNum:0, | |||||
pickerOptions: { | |||||
}, | |||||
value_time: '', | |||||
dynamic:4, | |||||
echartsSelectData:'', | |||||
option:'', | |||||
}; | |||||
}, | |||||
methods: { | |||||
// download_file(){ | |||||
// this.params.type='all' | |||||
// }, | |||||
popMark(){ | |||||
alert("数据为空时,不能下载!") | |||||
}, | |||||
exportData(){ | |||||
// this.getOneProList(this.pro_id,'all',true,7) | |||||
// this.getOneProList(this.pro_id,'all',false,7) | |||||
// this.fileName() | |||||
if (this.tableData!=''){ | |||||
this.page=1 | |||||
var saveFileName = this.getFileName() | |||||
export2Excel(this.columns,this.tableData,saveFileName) | |||||
}else{ | |||||
alert("数据为空时,不能下载!") | |||||
} | |||||
}, | |||||
getFileName(){ | |||||
var now = new Date(); // 当前日期 | |||||
var nowDayOfWeek = now.getDay(); // 今天本周的第几天 | |||||
var nowDay = now.getDate(); // 当前日 | |||||
var nowMonth = now.getMonth(); // 当前月 | |||||
var nowYear = now.getFullYear(); // 当前年 | |||||
var today = this.saveFormatDate(nowYear,nowMonth+1,nowDay); | |||||
var tmp = new Date(now.setTime(now.getTime()-24*60*60*1000)); | |||||
var yesterday = this.saveFormatDate(tmp.getFullYear(),tmp.getMonth()+1,tmp.getDate()); | |||||
var yesterday_tmp = this.formatDate(tmp.getFullYear(),tmp.getMonth()+1,tmp.getDate()) | |||||
var startDate='' | |||||
var endDate='' | |||||
var saveFileName = '' | |||||
if (typeof this.paramsID.type=="undefined" || this.paramsID.type=="null" || this.paramsID.type==""){ | |||||
// startDate= this.saveFormatDate(this.create_time_pro[0].getFullYear(),this.create_time_pro[0].getMonth() + 1,this.create_time_pro[0].getDate()); | |||||
endDate = this.saveFormatDate(this.create_time_pro[1].getFullYear(),this.create_time_pro[1].getMonth() + 1,this.create_time_pro[1].getDate()); | |||||
var tmp = this.formatDate(this.create_time_pro[0].getFullYear(),this.create_time_pro[0].getMonth() + 1,this.create_time_pro[0].getDate()) | |||||
startDate = this.comparedate(tmp,this.recordBeginTime) | |||||
console.log("comparedate:"+startDate) | |||||
saveFileName = this.alias+"_"+startDate+'_'+endDate | |||||
}else{ | |||||
switch(this.paramsID.type){ | |||||
case "yesterday":{ | |||||
startDate = this.comparedate(yesterday_tmp,this.recordBeginTime) | |||||
endDate = startDate | |||||
saveFileName = this.alias+"_"+startDate+'_'+ endDate | |||||
break | |||||
} | |||||
case "current_week":{ | |||||
var now = new Date(); // 当前日期 | |||||
var nowDayOfWeek = now.getDay(); // 今天本周的第几天 | |||||
var day = nowDayOfWeek || 7; | |||||
startDate = this.formatDate(now.getFullYear(), nowMonth+1, nowDay + 1 - day); | |||||
startDate = this.comparedate(startDate,this.recordBeginTime) | |||||
endDate = yesterday | |||||
saveFileName = this.alias+"_"+startDate+'_'+ endDate | |||||
break | |||||
} | |||||
case "current_month":{ | |||||
startDate = this.formatDate(nowYear,nowMonth+1,1); | |||||
startDate = this.comparedate(startDate,this.recordBeginTime) | |||||
endDate = yesterday | |||||
saveFileName = this.alias+"_"+startDate+'_'+ endDate | |||||
break | |||||
} | |||||
case "last_month":{ | |||||
let lastMonthDate = new Date(); // 上月日期 | |||||
lastMonthDate.setDate(1); | |||||
lastMonthDate.setMonth(lastMonthDate.getMonth()-1); | |||||
let lastYear = lastMonthDate.getFullYear(); | |||||
let lastMonth = lastMonthDate.getMonth(); | |||||
startDate=this.formatDate(lastYear, lastMonth+1, 1); | |||||
startDate = this.comparedate(startDate,this.recordBeginTime) | |||||
var monthStartDate = new Date(lastYear, lastMonth, 1); | |||||
var monthEndDate = new Date(lastYear, lastMonth+1, 1); | |||||
var days = (monthEndDate - monthStartDate) / (1000 * 60 * 60 * 24) | |||||
endDate=this.saveFormatDate(lastYear, lastMonth+1, days); //月份从0开始,所以+1保存月份 | |||||
saveFileName = this.alias+"_"+startDate+'_'+ endDate | |||||
break | |||||
} | |||||
case "monthly":{ | |||||
var temp=new Date(now - 1000 * 60 * 60 * 24 * 30) | |||||
startDate = this.formatDate(temp.getFullYear(),temp.getMonth()+1,temp.getDate()); | |||||
startDate = this.comparedate(startDate,this.recordBeginTime) | |||||
endDate = yesterday | |||||
saveFileName = this.alias+"_"+startDate+'_'+ endDate | |||||
break | |||||
} | |||||
case "current_year":{ | |||||
startDate = this.formatDate(now.getFullYear(), 1, 1); | |||||
startDate = this.comparedate(startDate,this.recordBeginTime) | |||||
endDate = yesterday | |||||
saveFileName = this.alias+"_"+startDate+'_'+ endDate | |||||
break | |||||
} | |||||
case "all":{ | |||||
console.log("e:"+today) | |||||
startDate = 'all' | |||||
endDate = yesterday | |||||
saveFileName = this.alias+'_所有' | |||||
break | |||||
} | |||||
} | |||||
} | |||||
return saveFileName | |||||
}, | |||||
resetPage(){ | |||||
this.page=1 | |||||
this.params.page = 1 | |||||
}, | |||||
resetCurrentPage(){ | |||||
this.page=1 | |||||
}, | |||||
handleSizeChange(val){ | |||||
this.pageSize = val | |||||
}, | |||||
handleCurrentChange(val){ | |||||
this.page = val; | |||||
}, | |||||
saveFormatDate(myyear,mymonth,myweekday) { | |||||
// var myyear = this.date.getFullYear(); | |||||
// var mymonth = this.date.getMonth() + 1; | |||||
// var myweekday = this.date.getDate(); | |||||
if (mymonth < 10) { | |||||
mymonth = "0" + mymonth; | |||||
} | |||||
if (myweekday < 10) { | |||||
myweekday = "0" + myweekday; | |||||
} | |||||
console.log((myyear +''+ mymonth +''+ myweekday)) | |||||
return (myyear +''+ mymonth +''+ myweekday); | |||||
}, | |||||
formatDate(myyear,mymonth,myweekday) { | |||||
// var myyear = this.date.getFullYear(); | |||||
// var mymonth = this.date.getMonth() + 1; | |||||
// var myweekday = this.date.getDate(); | |||||
if (mymonth < 10) { | |||||
mymonth = "0" + mymonth; | |||||
} | |||||
if (myweekday < 10) { | |||||
myweekday = "0" + myweekday; | |||||
} | |||||
return (myyear +'-'+ mymonth +'-'+ myweekday); | |||||
}, | |||||
//获得某月的天数 | |||||
getPeriodProList(type_val,index){ | |||||
// console.log("类型:"+type_val) | |||||
this.dynamic = index | |||||
if (typeof type_val=="undefined" || type_val=="null" || type_val==""){ | |||||
this.params.type='' | |||||
this.params.beginTime=this.formatDate(this.value_time[0].getFullYear(),this.value_time[0].getMonth() + 1,this.value_time[0].getDate()) | |||||
this.params.endTime=this.formatDate(this.value_time[1].getFullYear(),this.value_time[1].getMonth() + 1,this.value_time[1].getDate()) | |||||
}else{ | |||||
this.params.type=type_val | |||||
this.params.beginTime='' | |||||
this.params.endTime='' | |||||
this.value_time=[] | |||||
} | |||||
// console.log("params:",this.params) | |||||
this.$axios.get('../../api/v1/projectboard/summary/period',{ | |||||
params:this.params | |||||
}).then((res)=>{ | |||||
this.recordBeginTime=res.data.recordBeginTime | |||||
// this.lastUpdatedTime=res.data.creatTime | |||||
this.tableData = res.data.pageRecords | |||||
this.totalPage=res.data.totalPage | |||||
// this.totalNum = res.data.totalCount//this.totalPage*this.params.pagesize | |||||
// console.log("res.data:"+res.data) | |||||
this.drawSelectData() | |||||
}) | |||||
}, | |||||
getSummaryPro(){ | |||||
this.$axios.get('../../api/v1/projectboard/summary',{ | |||||
}).then((res)=>{ | |||||
this.tableDataSummary = res.data | |||||
this.lastUpdatedTime = res.data.creatTime | |||||
}) | |||||
}, | |||||
tableHeaderStyle({row,column,rowIndex,columnIndex}){ | |||||
if(rowIndex===0){ | |||||
return 'background:#f5f5f6;color:#606266' | |||||
} | |||||
}, | |||||
cellStyle({row,column,rowIndex,columnIndex}){ | |||||
if(rowIndex%2 === 1){ | |||||
return 'background:#f5f5f6;color:#606266' | |||||
} | |||||
}, | |||||
drawSelectData(){ | |||||
// $("#selectData").removeAttr("selectData").empty(); | |||||
var xdata=[] | |||||
var ydata_add_pro=[] | |||||
var ydata_add_public_pro=[] | |||||
var ydata_add_private_pro=[] | |||||
var ydata_add_self=[] | |||||
var ydata_add_fork=[] | |||||
var ydata_add_mirror=[] | |||||
var ydata_cumulative_pro=[] | |||||
// if () | |||||
for(var i =0;i<this.tableData.length;i++){ | |||||
xdata.push(this.tableData[this.tableData.length-1-i].creatTime); | |||||
ydata_add_pro.push(this.tableData[this.tableData.length-1-i].numReposAdd) | |||||
ydata_add_public_pro.push(this.tableData[this.tableData.length-1-i].numRepoPublicAdd) | |||||
ydata_add_private_pro.push(this.tableData[this.tableData.length-1-i].numRepoPrivateAdd) | |||||
ydata_add_self.push(this.tableData[this.tableData.length-1-i].numRepoSelfAdd) | |||||
ydata_add_fork.push(this.tableData[this.tableData.length-1-i].numRepoForkAdd) | |||||
ydata_add_mirror.push(this.tableData[this.tableData.length-1-i].numRepoMirrorAdd) | |||||
ydata_cumulative_pro.push(this.tableData[this.tableData.length-1-i].numRepos) | |||||
} | |||||
// console.log("ydata_openI:"+ydata_add_pro) | |||||
// console.log(xdata) | |||||
this.option = { | |||||
title : { | |||||
text: '', | |||||
textStyle: { | |||||
fontSize: 12, | |||||
}, | |||||
left:'center', | |||||
top:'bottom', | |||||
subtext: '', | |||||
}, | |||||
tooltip : { | |||||
trigger: 'axis', | |||||
backgroundColor:'rgba(255,255,255,0.8)', | |||||
color:'black', | |||||
borderWidth:'1', | |||||
borderColor:'gray', | |||||
textStyle:{ | |||||
color:'black' | |||||
}, | |||||
}, | |||||
legend: { | |||||
data:['新增项目','新增公开项目','新增私有项目','新增自建项目','新增派生项目','新增镜像项目','累计项目'], | |||||
selected:{ | |||||
// '新增项目':true, | |||||
// '新增公开项目':true, | |||||
// '新增私有项目':true, | |||||
// '新增自建项目':false, | |||||
// '新增派生项目':false, | |||||
// '新增镜像项目':false, | |||||
// '累计项目':false | |||||
} | |||||
// orient: 'vertical', | |||||
// top:'top', | |||||
}, | |||||
toolbox: { | |||||
show : false, | |||||
feature : { | |||||
mark : {show: true}, | |||||
dataView : {show: false, readOnly: false}, | |||||
magicType : {show: true, type: ['line', 'bar']}, | |||||
restore : {show: false}, | |||||
saveAsImage : {show: true} | |||||
} | |||||
}, | |||||
calculable : true, | |||||
xAxis : [ | |||||
{ | |||||
type : 'category', | |||||
data : xdata, | |||||
axisLine: { | |||||
show: false, //x轴线消失 | |||||
}, | |||||
axisTick:{ | |||||
show:false//刻度隐藏 | |||||
} | |||||
} | |||||
], | |||||
yAxis : [ | |||||
{ | |||||
type : 'value', | |||||
axisLine: { | |||||
show: false, //y轴线消失 | |||||
}, | |||||
axisTick:{ | |||||
show:false//刻度隐藏 | |||||
} | |||||
} | |||||
], | |||||
series : [ | |||||
{ name:"新增项目", | |||||
data: ydata_add_pro, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#3894FF", | |||||
}, | |||||
color:"#3894FF", | |||||
} | |||||
}, | |||||
}, | |||||
{ | |||||
name:"新增公开项目", | |||||
data: ydata_add_public_pro, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#67B3BB", | |||||
}, | |||||
color:"#67B3BB", | |||||
} | |||||
}, | |||||
}, | |||||
{ | |||||
name:"新增私有项目", | |||||
data: ydata_add_private_pro, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#58A55C", | |||||
}, | |||||
color:"#58A55C", | |||||
} | |||||
}, | |||||
}, | |||||
{ | |||||
name:"新增自建项目", | |||||
data: ydata_add_self, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#F2BD42", | |||||
}, | |||||
color:"#F2BD42", | |||||
} | |||||
}, | |||||
}, | |||||
{ | |||||
name:"新增派生项目", | |||||
data: ydata_add_fork, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#DAA67B", | |||||
}, | |||||
color:"#DAA67B", | |||||
} | |||||
}, | |||||
}, | |||||
{ | |||||
name:"新增镜像项目", | |||||
data: ydata_add_mirror, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#2E4552", | |||||
}, | |||||
color:"#2E4552", | |||||
} | |||||
}, | |||||
}, | |||||
{ | |||||
name:"累计项目", | |||||
data: ydata_cumulative_pro, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#4786B4", | |||||
}, | |||||
color:"#4786B4", | |||||
} | |||||
}, | |||||
}, | |||||
] | |||||
}; | |||||
// this.echartsSelectData.resize() | |||||
var checkboxs=document.getElementsByName('checkboxchart'); | |||||
for(var i=0; i<checkboxs.length; i++){ | |||||
// console.log("selectArr[i]:",this.option.legend.data[i]) | |||||
if(checkboxs[i].checked){ | |||||
this.option.legend.selected[this.option.legend.data[i]]=true; | |||||
}else{ | |||||
this.option.legend.selected[this.option.legend.data[i]]=false; | |||||
} | |||||
} | |||||
this.echartsSelectData.setOption(this.option) | |||||
// setTimeout(function (){ | |||||
// window.onresize = function () { | |||||
// this.echartsSelectData.resize; | |||||
// } | |||||
// },200) | |||||
// // 使用刚指定的选择项数据显示图表。 | |||||
// var selectArr = this.echartsSelectData.getOption().legend[0].data;//legend所有值 | |||||
// var checkboxs=document.getElementsByName('checkboxchart'); | |||||
// $(".checkboxchart").click(function(){ | |||||
// var obj = {}; | |||||
// for(var i=0; i<checkboxs.length; i++){ | |||||
// if(checkboxs[i].checked){ | |||||
// obj[selectArr[i]] = true; | |||||
// }else{ | |||||
// obj[selectArr[i]] = false; | |||||
// } | |||||
// } | |||||
// option.legend.selected = obj; | |||||
// this.echartsSelectData.setOption(option); | |||||
// }); | |||||
}, | |||||
clickCheckBox(){ | |||||
// 使用刚指定的选择项数据显示图表。 | |||||
var selectArr = this.echartsSelectData.getOption().legend[0].data;//legend所有值 | |||||
var checkboxs=document.getElementsByName('checkboxchart'); | |||||
// $(".checkboxchart").click(function(){ | |||||
var obj = {}; | |||||
for(var i=0; i<checkboxs.length; i++){ | |||||
if(checkboxs[i].checked){ | |||||
obj[selectArr[i]] = true; | |||||
}else{ | |||||
obj[selectArr[i]] = false; | |||||
} | |||||
} | |||||
this.option.legend.selected = obj; | |||||
this.echartsSelectData.setOption(this.option); | |||||
// }); | |||||
}, | |||||
comparedate(date1,date2){ | |||||
// console.log("date1:"+date1) | |||||
// console.log("date1:"+date2) | |||||
var oDate1 = new Date(date1); | |||||
var oDate2 = new Date(date2); | |||||
if(oDate1.getTime() < oDate2.getTime()){ | |||||
var data = date2.split('-') | |||||
return data[0]+''+data[1]+''+data[2] | |||||
} else { | |||||
var data = date1.split('-') | |||||
return data[0]+''+data[1]+''+data[2] | |||||
} | |||||
}, | |||||
}, | |||||
filters:{ | |||||
}, | |||||
mounted() { | |||||
this.getPeriodProList("monthly",4); | |||||
this.getSummaryPro(); | |||||
document.getElementById('selectData').style.width = document.getElementById('pro_tend').offsetWidth*0.8+'px' | |||||
this.echartsSelectData = this.$echarts.init(document.getElementById('selectData')) | |||||
}, | |||||
watch:{ | |||||
}, | |||||
created() { | |||||
this.getSummaryPro(); | |||||
this.getPeriodProList("monthly",4); | |||||
}, | |||||
updated(){ | |||||
if(document.querySelectorAll('img[avatar]').length!==0){ | |||||
window.LetterAvatar.transform() | |||||
} | |||||
} | |||||
} | |||||
</script> | |||||
<style scoped> | |||||
.item_list_first{ | |||||
border-right: 1px solid rgba(219,219,219,100); | |||||
padding-right: 10px; | |||||
} | |||||
.item_list{ | |||||
border-right: 1px solid rgba(219,219,219,100); | |||||
padding:0px 10px; | |||||
} | |||||
.item_list_p{ | |||||
border-right: 1px solid rgba(219,219,219,100); | |||||
padding:0px 10px; | |||||
} | |||||
.item_h{ | |||||
line-height: 40px; | |||||
text-align: center; | |||||
} | |||||
.item_title_h{ | |||||
line-height: 28px; | |||||
text-align: center; | |||||
} | |||||
.num_color{ | |||||
color: #0366D6; | |||||
font-weight: bold; | |||||
} | |||||
.pro_item{ | |||||
font-size: 16px; | |||||
color: rgba(16, 16, 16, 100); | |||||
font-family: SourceHanSansSC-bold; | |||||
} | |||||
.sta_item{ | |||||
font-size: 14px; | |||||
color: rgb(0 0 0); | |||||
font-family: SourceHanSansSC-bold; | |||||
} | |||||
.update_time{ | |||||
line-height: 17px; | |||||
font-size: 12px; | |||||
color:rgba(187, 187, 187, 100); | |||||
margin-left: 10px; | |||||
} | |||||
.btnFirst{ | |||||
line-height: 1.5; | |||||
margin: -3.5px; | |||||
border: 1px solid rgba(22, 132, 252, 100); | |||||
border-right: none; | |||||
background: #FFFF; | |||||
color: #1684FC; | |||||
width: 60px; | |||||
height: 30px; | |||||
border-radius:4px 0px 0px 4px; | |||||
} | |||||
.btn{ | |||||
line-height: 1.5; | |||||
margin: -3.5px; | |||||
border: 1px solid rgba(22, 132, 252, 100); | |||||
border-right: none; | |||||
background: #FFFF; | |||||
color: #1684FC; | |||||
width: 60px; | |||||
height: 30px; | |||||
} | |||||
.btnLast{ | |||||
line-height: 1.5; | |||||
margin: -3.5px; | |||||
border: 1px solid rgba(22, 132, 252, 100); | |||||
/* border-right: none; */ | |||||
background: #FFFF; | |||||
color: #1684FC; | |||||
width: 60px; | |||||
height: 30px; | |||||
border-radius:0px 4px 4px 0px; | |||||
} | |||||
.btnFirst, .btn, .btnLast { | |||||
cursor: pointer; | |||||
} | |||||
/deep/ .el-table tbody tr:hover>td { | |||||
background-color:#D3D3D3!important; | |||||
opacity:1 | |||||
} | |||||
/deep/ .el-table { | |||||
font-size: 12px; | |||||
} | |||||
/deep/ .el-range-separator{ | |||||
width: 20% !important; | |||||
} | |||||
/deep/ .el-pagination { | |||||
padding-bottom: 30px; | |||||
} | |||||
.colorChange { | |||||
background-color: #1684FC; | |||||
color: #FFFF; | |||||
cursor: default; | |||||
} | |||||
.items{ | |||||
text-align: center; | |||||
border-right:1px solid rgba(219, 219, 219, 100); | |||||
} | |||||
.item_l{ | |||||
margin-right: 5px; | |||||
border:1px solid rgba(219, 219, 219, 100); | |||||
height: 370px; | |||||
width: 100%; | |||||
} | |||||
.item_r{ | |||||
margin-right:5px; | |||||
border:1px solid rgba(219, 219, 219, 100); | |||||
height: 370px; | |||||
overflow:auto | |||||
} | |||||
.item_echart{ | |||||
margin-top: 10px; | |||||
margin-right: 5px; | |||||
border:1px solid rgba(219, 219, 219, 100); | |||||
height: 350px; | |||||
width: 100%; | |||||
} | |||||
.item_content{ | |||||
color:#0366D6; | |||||
margin-top: 10px; | |||||
font-weight:bold; | |||||
} | |||||
</style> |
@@ -1,7 +1,7 @@ | |||||
<template> | <template> | ||||
<div> | |||||
<div class="el-col el-col-21" style="padding-right:10px"> | |||||
<div style="margin-top: 10px;"> | <div style="margin-top: 10px;"> | ||||
<b class="pro_item">用户分析</b> <span class="update_time">数据更新时间:</span><span style="font-size: 12px;">{{lastUpdatedTime}}  / 从{{recordBeginTime}}开始统计</span> | |||||
<b class="pro_item">活动分析</b> <span class="update_time">数据更新时间:</span><span style="font-size: 12px;">{{lastUpdatedTime}}  / 从{{recordBeginTime}}开始统计</span> | |||||
</div> | </div> | ||||
<div style="margin-top: 20px;"> | <div style="margin-top: 20px;"> | ||||
<span class="sta_iterm">统计周期:</span> | <span class="sta_iterm">统计周期:</span> | ||||
@@ -54,6 +54,7 @@ | |||||
> | > | ||||
</el-table-column> | </el-table-column> | ||||
<el-table-column | <el-table-column | ||||
fixed | |||||
label="用户名" | label="用户名" | ||||
align="left" | align="left" | ||||
prop="Name" | prop="Name" | ||||
@@ -259,7 +260,7 @@ | |||||
params:{startDate:'',endDate:'',page:1,pageSize:10,userName:''}, | params:{startDate:'',endDate:'',page:1,pageSize:10,userName:''}, | ||||
tableData: [], | tableData: [], | ||||
totalNum:0, | totalNum:0, | ||||
dataUrl:'../api/v1/query_user_static_page', | |||||
dataUrl:'../../api/v1/query_user_static_page', | |||||
pickerOptions: { | pickerOptions: { | ||||
}, | }, | ||||
value_time: '', | value_time: '', | ||||
@@ -334,7 +335,7 @@ | |||||
return days; | return days; | ||||
}, | }, | ||||
getUpdateTime(){ | getUpdateTime(){ | ||||
this.$axios.get('../api/v1/projectboard/project',{ | |||||
this.$axios.get('../../api/v1/projectboard/project',{ | |||||
params:this.params_pro | params:this.params_pro | ||||
}).then((res)=>{ | }).then((res)=>{ | ||||
this.recordBeginTime=res.data.recordBeginTime | this.recordBeginTime=res.data.recordBeginTime | ||||
@@ -357,7 +358,7 @@ | |||||
let lastYear = lastMonthDate.getYear(); | let lastYear = lastMonthDate.getYear(); | ||||
let lastMonth = lastMonthDate.getMonth(); | let lastMonth = lastMonthDate.getMonth(); | ||||
this.dataUrl = '../api/v1/query_user_static_page'; | |||||
this.dataUrl = '../../api/v1/query_user_static_page'; | |||||
if (typeof type_val=="undefined" || type_val=="null" || type_val==""){ | if (typeof type_val=="undefined" || type_val=="null" || type_val==""){ | ||||
this.params.startDate= this.formatDate(this.value_time[0].getFullYear(),this.value_time[0].getMonth() + 1,this.value_time[0].getDate()); | this.params.startDate= this.formatDate(this.value_time[0].getFullYear(),this.value_time[0].getMonth() + 1,this.value_time[0].getDate()); | ||||
@@ -366,37 +367,37 @@ | |||||
switch(type_val){ | switch(type_val){ | ||||
case "yesterday_usr":{ | case "yesterday_usr":{ | ||||
this.value_time=[] | this.value_time=[] | ||||
this.dataUrl = '../api/v1/query_user_yesterday'; | |||||
this.dataUrl = '../../api/v1/query_user_yesterday'; | |||||
break | break | ||||
} | } | ||||
case "current_week_usr":{ | case "current_week_usr":{ | ||||
this.value_time=[] | this.value_time=[] | ||||
this.dataUrl = '../api/v1/query_user_current_week'; | |||||
this.dataUrl = '../../api/v1/query_user_current_week'; | |||||
break | break | ||||
} | } | ||||
case "current_month_usr":{ | case "current_month_usr":{ | ||||
this.value_time=[] | this.value_time=[] | ||||
this.dataUrl = '../api/v1/query_user_current_month'; | |||||
this.dataUrl = '../../api/v1/query_user_current_month'; | |||||
break | break | ||||
} | } | ||||
case "last_month_usr":{ | case "last_month_usr":{ | ||||
this.value_time=[] | this.value_time=[] | ||||
this.dataUrl = '../api/v1/query_user_last_month'; | |||||
this.dataUrl = '../../api/v1/query_user_last_month'; | |||||
break | break | ||||
} | } | ||||
case "monthly_usr":{ | case "monthly_usr":{ | ||||
this.value_time=[] | this.value_time=[] | ||||
this.dataUrl = '../api/v1/query_user_last30_day'; | |||||
this.dataUrl = '../../api/v1/query_user_last30_day'; | |||||
break | break | ||||
} | } | ||||
case "current_year_usr":{ | case "current_year_usr":{ | ||||
this.value_time=[] | this.value_time=[] | ||||
this.dataUrl = '../api/v1/query_user_current_year'; | |||||
this.dataUrl = '../../api/v1/query_user_current_year'; | |||||
break | break | ||||
} | } | ||||
case "all_usr":{ | case "all_usr":{ | ||||
this.value_time=[] | this.value_time=[] | ||||
this.dataUrl = '../api/v1/query_user_all'; | |||||
this.dataUrl = '../../api/v1/query_user_all'; | |||||
break | break | ||||
} | } | ||||
} | } | ||||
@@ -561,7 +562,9 @@ | |||||
/deep/ .el-range-separator{ | /deep/ .el-range-separator{ | ||||
width: 20% !important; | width: 20% !important; | ||||
} | } | ||||
/deep/ .el-pagination { | |||||
padding-bottom: 30px; | |||||
} | |||||
.colorChange { | .colorChange { | ||||
background-color: #1684FC; | background-color: #1684FC; | ||||
color: #FFFF; | color: #FFFF; | ||||
@@ -0,0 +1,942 @@ | |||||
<template> | |||||
<div class="el-col el-col-21" style="padding-right:10px"> | |||||
<div id='user_tend'> | |||||
<div style="margin-top: 10px;"> | |||||
<b class="pro_item">增长趋势分析</b> <span class="update_time">数据更新时间:</span><span style="font-size: 12px;">{{lastUpdatedTime}}  / 从{{recordBeginTime}}开始统计</span> | |||||
</div> | |||||
<div id = 'isShow'> | |||||
<el-col :span="11"> | |||||
<el-col id="ys_add_user" class="draw_region"> | |||||
</el-col> | |||||
<el-col :span="8" :style="{ height: '180px'}" v-if="ys_count>0"> | |||||
<span class="yesterday_blk yesterday_title" >昨日新增注册用户数 </span> | |||||
<span class="yesterday_blk yesterday_color1 yesterday_pdrt yesterday_text">未激活:<span class="bold_num">{{ tableDataYesterday.NotActivateRegistUser }}</span> 人 </span> | |||||
<span class="yesterday_blk yesterday_color2 yesterday_pdrt yesterday_text">已激活: <span class="bold_num">{{ tableDataYesterday.ActivateRegistUser }} </span>人</span> | |||||
<span class="yesterday_blk yesterday_pdrt yesterday_text">有贡献活动: <span class="bold_num">{{ tableDataYesterday.RegistActivityUser }} </span>人</span> | |||||
</el-col> | |||||
</el-col> | |||||
<el-col :span="13"> | |||||
<el-col id="ys_all_user" class="draw_region"> | |||||
</el-col> | |||||
<el-col :span="8" :style="{ height: '180px'}" v-if="ys_count>0"> | |||||
<span class="yesterday_blk yesterday_title" >注册用户数 </span> | |||||
<span class="yesterday_blk yesterday_color1 yesterday_pdrt yesterday_text">未激活:<span class="bold_num">{{ tableDataYesterday.TotalActivateRegistUser}} </span>人 </span> | |||||
<span class="yesterday_blk yesterday_color2 yesterday_pdrt yesterday_text">已激活:<span class="bold_num">{{ tableDataYesterday.TotalNotActivateRegistUser }} </span>人</span> | |||||
<span class="yesterday_blk yesterday_pdrt yesterday_text">有贡献活动:<span class="bold_num"> {{ tableDataYesterday.TotalHasActivityUser}} </span>人</span> | |||||
</el-col> | |||||
</el-col> | |||||
</div> | |||||
<div style="margin-top: 20px;"> | |||||
<span class="sta_iterm">统计周期:</span> | |||||
<button type="button" class='btn' id = "current_week_usr" v-bind:class="{colorChange:1==dynamic}" @click="resetPage(),getUserList('current_week_usr',1)">本周</button> | |||||
<button type="button" class='btn' id = "current_month_usr" v-bind:class="{colorChange:2==dynamic}" @click="resetPage(),getUserList('current_month_usr',2)">本月</button> | |||||
<button type="button" class='btn' id = "last_month_usr" v-bind:class="{colorChange:3==dynamic}" @click="resetPage(),getUserList('last_month_usr',3)">上月</button> | |||||
<button type="button" class='btn' id = "monthly_usr" v-bind:class="{colorChange:4==dynamic}" @click="resetPage(),getUserList('monthly_usr',4)">近30天</button> | |||||
<button type="button" class='btn' id = "current_year_usr" v-bind:class="{colorChange:5==dynamic}" @click="resetPage(),getUserList('current_year_usr',5)">今年</button> | |||||
<button type="button" class='btnLast' id = "all_usr" v-bind:class="{colorChange:6==dynamic}" @click="resetPage(),getUserList('all_usr',6)">所有</button> | |||||
<span style="margin-left: 20px;"> | |||||
<el-date-picker | |||||
v-model="value_time" | |||||
prefix-icon="el-icon-time" | |||||
@change="resetPage(),getUserList('',0)" | |||||
type="daterange" | |||||
size='small' | |||||
unlink-panels | |||||
range-separator="至" | |||||
start-placeholder="开始日期" | |||||
end-placeholder="结束日期"> | |||||
</el-date-picker> | |||||
</span> | |||||
<span style="float:right; margin-right: 20px;" > | |||||
<a style="display:inline-block;margin-left: 20px; " id = 'download'> | |||||
<a class="el-icon-download" v-if="tableData!=''" :href= "this.dataUrl + '?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true' " ></a> | |||||
<i class="el-icon-download" v-else="tableData=''" href="#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'></i> | |||||
<span > | |||||
<a v-if="tableData!=''" :href= "this.dataUrl + '?startDate='+this.params.startDate+'&endDate='+this.params.endDate+'&IsReturnFile=true' " >下载报告</a> | |||||
<a v-else="tableData=''" href= "#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'>下载报告</a> | |||||
</span> | |||||
</a> | |||||
<!-- <span style="display:inline-block;margin-left: 20px; "> | |||||
<el-input size="small" placeholder="输入用户名搜索" v-model="search" class="input-with-select" @keyup.enter.native="searchName() "><i slot="suffix" class="el-input__icon el-icon-search" @click="searchName() "></i> | |||||
</el-input> | |||||
</span> --> | |||||
</span> | |||||
</div> | |||||
<div class="item_echart" id ='linecharts'> | |||||
<div style="margin: 15px 10px 30px;"> | |||||
<label for="label" @change='clickCheckBox'> | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="新增项目"/> 新增注册用户 | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="新增公开项目"/>新增已激活 | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" checked="checked" value="新增私有项目"/>新增有贡献活动 | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="新增自建项目"/>新增未激活 | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="新增派生项目"/>累计注册用户 | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="新增镜像项目"/>累计已激活 | |||||
<input type="checkbox" class="checkboxchart" name="checkboxchart" value="累计项目"/>累计有贡献活动 | |||||
</label> | |||||
</div> | |||||
<div id ="selectData" style="height: 300px;"> | |||||
</div> | |||||
</div> | |||||
<div style="margin-top: 30px;"> | |||||
<el-table | |||||
:data="tableData.slice((page-1)*pageSize,page*pageSize)" | |||||
style="width: 100%" | |||||
:header-cell-style="tableHeaderStyle" | |||||
:cell-style='cellStyle'> | |||||
<el-table-column | |||||
label="日期" | |||||
prop="DisplayDate" | |||||
align="center" | |||||
stripe | |||||
> | |||||
</el-table-column> | |||||
<el-table-column | |||||
label="新增注册用户" | |||||
prop="TotalRegistUser" | |||||
align="center"> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="ActivateRegistUser" | |||||
label="新增已激活" | |||||
width="120px" | |||||
align="center"> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="RegistActivityUser" | |||||
label="新增有贡献活动" | |||||
align="center"> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="NotActivateRegistUser" | |||||
label="新增未激活" | |||||
align="center"> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="ActivateIndex" | |||||
label="新增用户激活率" | |||||
align="center"> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="TotalUser" | |||||
label="累计注册用户" | |||||
align="center"> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="TotalActivateRegistUser" | |||||
label="累计已激活" | |||||
align="center"> | |||||
</el-table-column> | |||||
<el-table-column | |||||
prop="TotalHasActivityUser" | |||||
label="累计有贡献活动" | |||||
align="center"> | |||||
</el-table-column> | |||||
</el-table> | |||||
</div> | |||||
<div style="margin-top:50px;text-align:center"> | |||||
<el-pagination | |||||
background | |||||
@size-change="handleSizeChange" | |||||
@current-change="handleCurrentChange" | |||||
:current-page="page" | |||||
:page-size="pageSize" | |||||
:page-sizes="[5,10,20]" | |||||
layout="total, sizes, prev, pager, next,jumper" | |||||
:total="tableData.length"> | |||||
</el-pagination> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
import { export2Excel } from '../excel/util.js' | |||||
export default{ | |||||
name:'UserAnalysis', | |||||
data() { | |||||
return { | |||||
type_val:'', | |||||
recordBeginTime:'', | |||||
lastUpdatedTime:'', | |||||
page:1, | |||||
pageSize:10, | |||||
params:{startDate:'',endDate:''}, | |||||
tableData: [], | |||||
totalNum:0, | |||||
dataUrl:'../../api/v1/query_user_metrics_page', | |||||
dataYesterdayUrl:'../../api/v1/query_metrics_yesterday', | |||||
ys_count:0, | |||||
tableDataYesterday: {}, | |||||
option:'', | |||||
optionYesterdayUser:'', | |||||
optionYesterdaAllUser:'', | |||||
echartsSelectData:'', | |||||
echartsYsAddUser:'', | |||||
echartsYsAllUser:'', | |||||
pickerOptions: { | |||||
}, | |||||
value_time: '', | |||||
search:'', | |||||
data:'', | |||||
// columns: [{title: 'ID',key: 'ID'},{title: '用户名',key: 'Name'},{title: 'PR数',key: 'CodeMergeCount'},{title: 'commit数',key:'CommitCount'},{title: '提出任务数',key: 'IssueCount'},{title: '评论数',key: 'CommentCount'},{title: '关注项目数',key: 'FocusRepoCount'},{title: '点赞项目数',key: 'StarRepoCount'},{title: '登录次数',key: 'LoginCount'},{title:'关注者数',key:'WatchedCount'},{title:'commit代码行数',key:'CommitCodeSize'},{title:'已解决任务数',key:'SolveIssueCount'},{title:'百科页面贡献次数',key:'EncyclopediasCount'},{title:'创建项目',key:'CreateRepoCount'},{title:'用户注册时间',key:'RegistDate'},{title:'云脑任务数',key:'CloudBrainTaskNum'},{title:'云脑运行时间(小时)',key:'CloudBrainRunTime'},{title:'上传(提交)数据集文件数',key:'CommitDatasetNum'},{title:'提交模型数',key:'CommitModelCount'},{title:'用户指数',key:'UserIndex'},{title:'系统统计时间',key:'CountDate'}], | |||||
blob:'', | |||||
fileName:'', | |||||
dynamic:4, | |||||
params_pro:{type:'all',page:1,pagesize:10,beginTime:'',endTime:'',q:'',sort:'openi'}, | |||||
}; | |||||
}, | |||||
methods: { | |||||
popMark(){ | |||||
alert("数据为空时,不能下载!") | |||||
}, | |||||
// exportData(){ | |||||
// // this.getUserList('all_usr',7) | |||||
// var saveFileName = this.getFileName() | |||||
// export2Excel(this.columns,this.tableData,saveFileName) | |||||
// }, | |||||
// getFileName(){ | |||||
// var saveFileName='' | |||||
// var Date=(this.params.startDate).split('-') | |||||
// var startDate=Date[0]+''+Date[1]+''+Date[2] | |||||
// Date=(this.params.endDate).split('-') | |||||
// var endDate=Date[0]+Date[1]+Date[2] | |||||
// saveFileName = '用户分析_'+this.search+''+startDate+'_'+endDate | |||||
// if (this.type_val=='all_usr'){ | |||||
// saveFileName = '用户分析_'+this.search+'_all' | |||||
// } | |||||
// return saveFileName | |||||
// }, | |||||
handleCurrentChange(val){ | |||||
this.page = val | |||||
}, | |||||
handleSizeChange(val){ | |||||
this.pageSize = val | |||||
}, | |||||
resetPage(){ | |||||
this.page=1 | |||||
}, | |||||
addUser(val1, val2){ | |||||
return (val1+val2) | |||||
}, | |||||
formatDate(myyear,mymonth,myweekday) { | |||||
// var myyear = this.date.getFullYear(); | |||||
// var mymonth = this.date.getMonth() + 1; | |||||
// var myweekday = this.date.getDate(); | |||||
if (mymonth < 10) { | |||||
mymonth = "0" + mymonth; | |||||
} | |||||
if (myweekday < 10) { | |||||
myweekday = "0" + myweekday; | |||||
} | |||||
return (myyear + "-" + mymonth + "-" + myweekday); | |||||
}, | |||||
// 获得某月的天数 | |||||
getMonthDays(nowYear,month){ | |||||
let monthStartDate = new Date(nowYear, month, 1); | |||||
let monthEndDate = new Date(nowYear, month + 1, 1); | |||||
let days = (monthEndDate - monthStartDate)/(1000 * 60 * 60 * 24); | |||||
return days; | |||||
}, | |||||
getUpdateTime(){ | |||||
this.$axios.get('../../api/v1/projectboard/project',{ | |||||
params:this.params_pro | |||||
}).then((res)=>{ | |||||
this.recordBeginTime=res.data.recordBeginTime | |||||
this.lastUpdatedTime=res.data.lastUpdatedTime | |||||
}) | |||||
}, | |||||
getUserList(type_val,index){ | |||||
this.type_val = type_val | |||||
this.dynamic = index; | |||||
var now = new Date(); // 当前日期 | |||||
var nowDayOfWeek = now.getDay(); // 今天本周的第几天 | |||||
var nowDay = now.getDate(); // 当前日 | |||||
var nowMonth = now.getMonth(); // 当前月 | |||||
var nowYear = now.getFullYear(); // 当前年 | |||||
var today = this.formatDate(nowYear,nowMonth+1,nowDay); | |||||
let lastMonthDate = new Date(); // 上月日期 | |||||
lastMonthDate.setDate(1); | |||||
lastMonthDate.setMonth(lastMonthDate.getMonth()-1); | |||||
let lastYear = lastMonthDate.getYear(); | |||||
let lastMonth = lastMonthDate.getMonth(); | |||||
this.dataUrl = '../../api/v1/query_user_metrics_page'; | |||||
if (typeof type_val=="undefined" || type_val=="null" || type_val==""){ | |||||
this.params.startDate= this.formatDate(this.value_time[0].getFullYear(),this.value_time[0].getMonth() + 1,this.value_time[0].getDate()); | |||||
this.params.endDate = this.formatDate(this.value_time[1].getFullYear(),this.value_time[1].getMonth() + 1,this.value_time[1].getDate()); | |||||
}else{ | |||||
switch(type_val){ | |||||
case "yesterday_usr":{ | |||||
this.value_time=[] | |||||
this.dataUrl = '../../api/v1/query_user_yesterday'; | |||||
break | |||||
} | |||||
case "current_week_usr":{ | |||||
this.value_time=[] | |||||
this.dataUrl = '../../api/v1/query_metrics_current_week'; | |||||
break | |||||
} | |||||
case "current_month_usr":{ | |||||
this.value_time=[] | |||||
this.dataUrl = '../../api/v1/query_metrics_current_month'; | |||||
break | |||||
} | |||||
case "last_month_usr":{ | |||||
this.value_time=[] | |||||
this.dataUrl = '../../api/v1/query_metrics_last_month'; | |||||
break | |||||
} | |||||
case "monthly_usr":{ | |||||
this.value_time=[] | |||||
this.dataUrl = '../../api/v1/query_metrics_last30_day'; | |||||
break | |||||
} | |||||
case "current_year_usr":{ | |||||
this.value_time=[] | |||||
this.dataUrl = '../../api/v1/query_metrics_current_year'; | |||||
break | |||||
} | |||||
case "all_usr":{ | |||||
this.value_time=[] | |||||
this.dataUrl = '../../api/v1/query_metrics_all'; | |||||
break | |||||
} | |||||
} | |||||
}; | |||||
this.$axios.get(this.dataUrl,{ | |||||
params:this.params | |||||
}).then((res)=>{ | |||||
this.tableData = res.data.data | |||||
// console.log("res.data:"+res.data.data) | |||||
this.totalNum = res.data.count | |||||
this.drawSelectData() | |||||
}) | |||||
}, | |||||
getYesterdayUser(){ | |||||
this.$axios.get(this.dataYesterdayUrl,{ | |||||
}).then((res)=>{ | |||||
this.ys_count = res.data.count | |||||
this.tableDataYesterday = res.data.data[0] | |||||
if(this.ys_count>0){ | |||||
this.drawYesterdayUser() | |||||
this.drawSumUser() | |||||
}else{ | |||||
document.getElementById("isShow").style.display='none' | |||||
} | |||||
}) | |||||
}, | |||||
drawYesterdayUser(){ | |||||
this.optionYesterdayUser = { | |||||
tooltip: { | |||||
trigger: 'item', | |||||
show:false | |||||
}, | |||||
legend: { | |||||
top: '5%', | |||||
left: 'center', | |||||
show:false | |||||
}, | |||||
// graphic:{ | |||||
// type:'text', | |||||
// left:'center', | |||||
// top:'center', | |||||
// style:{ | |||||
// text:this.tableDataYesterday.TotalRegistUser, | |||||
// fontSize:18, | |||||
// fontWeight:'bold', | |||||
// color:'#101010' | |||||
// } | |||||
// }, | |||||
color:['#5087Ec','#DBDBDB'], | |||||
series: [ | |||||
{ | |||||
name: '', | |||||
type: 'pie', | |||||
radius: ['65%', '70%'], | |||||
center:['50%','50%'], | |||||
avoidLabelOverlap: false, | |||||
label: { | |||||
normal:{ | |||||
show: true, | |||||
position: 'center', | |||||
formatter:''+this.tableDataYesterday.TotalRegistUser, | |||||
fontSize:18, | |||||
fontWeight:'bold', | |||||
color:'#101010' | |||||
} | |||||
}, | |||||
emphasis: { | |||||
label: { | |||||
show: false, | |||||
fontSize: '40', | |||||
fontWeight: 'bold' | |||||
} | |||||
}, | |||||
labelLine: { | |||||
normal:{ | |||||
show:false | |||||
} | |||||
}, | |||||
data: [ | |||||
{ value: this.tableDataYesterday.ActivateRegistUser, name: '已激活' }, | |||||
{ value: this.tableDataYesterday.NotActivateRegistUser, name: '未激活'}, | |||||
], | |||||
hoverAnimation:false, | |||||
} | |||||
] | |||||
}; | |||||
this.echartsYsAddUser.setOption(this.optionYesterdayUser) | |||||
}, | |||||
drawSumUser(){ | |||||
this.optionYesterdaAllUser = { | |||||
tooltip: { | |||||
trigger: 'item', | |||||
show:false | |||||
}, | |||||
legend: { | |||||
top: '5%', | |||||
left: 'center', | |||||
show:false | |||||
}, | |||||
// graphic:{ | |||||
// type:'text', | |||||
// left:'center', | |||||
// top:'center', | |||||
// style:{ | |||||
// text:this.tableDataYesterday.TotalRegistUser, | |||||
// fontSize:18, | |||||
// fontWeight:'bold', | |||||
// color:'#101010' | |||||
// } | |||||
// }, | |||||
color:['#5087Ec','#DBDBDB'], | |||||
series: [ | |||||
{ | |||||
name: '', | |||||
type: 'pie', | |||||
radius: ['65%', '70%'], | |||||
center:['50%','50%'], | |||||
avoidLabelOverlap: false, | |||||
label: { | |||||
normal:{ | |||||
show: true, | |||||
position: 'center', | |||||
formatter:''+this.tableDataYesterday.TotalUser, | |||||
fontSize:18, | |||||
fontWeight:'bold', | |||||
color:'#101010' | |||||
} | |||||
}, | |||||
emphasis: { | |||||
label: { | |||||
show: false, | |||||
fontSize: '40', | |||||
fontWeight: 'bold' | |||||
} | |||||
}, | |||||
labelLine: { | |||||
normal:{ | |||||
show:false | |||||
} | |||||
}, | |||||
data: [ | |||||
{ value: this.tableDataYesterday.TotalActivateRegistUser, name: '已激活' }, | |||||
{ value: this.tableDataYesterday.TotalNotActivateRegistUser, name: '未激活'}, | |||||
], | |||||
hoverAnimation:false, | |||||
} | |||||
] | |||||
}; | |||||
this.echartsYsAllUser.setOption(this.optionYesterdaAllUser) | |||||
}, | |||||
// searchName(){ | |||||
// this.params.userName = this.search | |||||
// this.params.page = 1 | |||||
// this.page=1 | |||||
// this.getUserList(this.type_val, this.dynamic) | |||||
// }, | |||||
tableHeaderStyle({row,column,rowIndex,columnIndex}){ | |||||
if(rowIndex===0){ | |||||
return 'background:#f5f5f6;color:#606266' | |||||
} | |||||
}, | |||||
cellStyle({row,column,rowIndex,columnIndex}){ | |||||
if(rowIndex%2 === 1){ | |||||
return 'background:#f5f5f6;color:#606266' | |||||
} | |||||
}, | |||||
drawSelectData(){ | |||||
// $("#selectData").removeAttr("selectData").empty(); | |||||
var xdata=[] | |||||
var ydata_TotalRegistUser=[] | |||||
var ydata_ActivateRegistUser=[] | |||||
var ydata_NotActivateRegistUser=[] | |||||
var ydata_RegistActivityUser=[] | |||||
var ydata_TotalUser=[] | |||||
var ydata_TotalActivateRegistUser=[] | |||||
var ydata_TotalHasActivityUser=[] | |||||
// if () | |||||
for(var i =0;i<this.tableData.length;i++){ | |||||
xdata.push(this.tableData[this.tableData.length-1-i].DisplayDate); | |||||
ydata_TotalRegistUser.push(this.tableData[this.tableData.length-1-i].TotalRegistUser) | |||||
ydata_ActivateRegistUser.push(this.tableData[this.tableData.length-1-i].ActivateRegistUser) | |||||
ydata_RegistActivityUser.push(this.tableData[this.tableData.length-1-i].RegistActivityUser) | |||||
ydata_NotActivateRegistUser.push(this.tableData[this.tableData.length-1-i].NotActivateRegistUser) | |||||
ydata_TotalUser.push(this.tableData[this.tableData.length-1-i].TotalUser) | |||||
ydata_TotalActivateRegistUser.push(this.tableData[this.tableData.length-1-i].TotalActivateRegistUser) | |||||
ydata_TotalHasActivityUser.push(this.tableData[this.tableData.length-1-i].TotalHasActivityUser) | |||||
} | |||||
this.option = { | |||||
title : { | |||||
text: '', | |||||
textStyle: { | |||||
fontSize: 12, | |||||
}, | |||||
left:'center', | |||||
top:'bottom', | |||||
subtext: '', | |||||
}, | |||||
tooltip : { | |||||
trigger: 'axis', | |||||
backgroundColor:'rgba(255,255,255,0.8)', | |||||
color:'black', | |||||
borderWidth:'1', | |||||
borderColor:'gray', | |||||
textStyle:{ | |||||
color:'black' | |||||
}, | |||||
}, | |||||
legend: { | |||||
data:['新增注册用户','新增已激活','新增有贡献活动','新增未激活','累计注册用户','累计已激活','累计有贡献活动'], | |||||
selected:{ | |||||
// '新增注册用户':true, | |||||
// '新增已激活':true, | |||||
// '新增有贡献活动':true, | |||||
// '新增未激活':false, | |||||
// '累计注册用户':false, | |||||
// '累计已激活':false, | |||||
// '累计有贡献活动':false | |||||
} | |||||
// orient: 'vertical', | |||||
// top:'top', | |||||
}, | |||||
toolbox: { | |||||
show : false, | |||||
feature : { | |||||
mark : {show: true}, | |||||
dataView : {show: false, readOnly: false}, | |||||
magicType : {show: true, type: ['line', 'bar']}, | |||||
restore : {show: false}, | |||||
saveAsImage : {show: true} | |||||
} | |||||
}, | |||||
calculable : true, | |||||
xAxis : [ | |||||
{ | |||||
type : 'category', | |||||
data : xdata, | |||||
axisLine: { | |||||
show: false, //x轴线消失 | |||||
}, | |||||
axisTick:{ | |||||
show:false//刻度隐藏 | |||||
} | |||||
} | |||||
], | |||||
yAxis : [ | |||||
{ | |||||
type : 'value', | |||||
axisLine: { | |||||
show: false, //y轴线消失 | |||||
}, | |||||
axisTick:{ | |||||
show:false//刻度隐藏 | |||||
} | |||||
} | |||||
], | |||||
series : [ | |||||
{ name:"新增注册用户", | |||||
data: ydata_TotalRegistUser, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#3894FF ", | |||||
}, | |||||
color:"#3894FF ", | |||||
} | |||||
}, | |||||
}, | |||||
{ | |||||
name:"新增已激活", | |||||
data: ydata_ActivateRegistUser, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#67B3BB", | |||||
}, | |||||
color:"#67B3BB", | |||||
} | |||||
}, | |||||
}, | |||||
{ | |||||
name:"新增有贡献活动", | |||||
data: ydata_RegistActivityUser, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#58A55C", | |||||
}, | |||||
color:"#58A55C", | |||||
} | |||||
}, | |||||
}, | |||||
{ | |||||
name:"新增未激活", | |||||
data: ydata_NotActivateRegistUser, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#F2BD42", | |||||
}, | |||||
color:"#F2BD42", | |||||
} | |||||
}, | |||||
}, | |||||
{ | |||||
name:"累计注册用户", | |||||
data: ydata_TotalUser, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#2E4552", | |||||
}, | |||||
color:"#2E4552", | |||||
} | |||||
}, | |||||
}, | |||||
{ | |||||
name:"累计已激活", | |||||
data: ydata_TotalActivateRegistUser, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#4786B4", | |||||
}, | |||||
color:"#4786B4", | |||||
} | |||||
}, | |||||
}, | |||||
{ | |||||
name:"累计有贡献活动", | |||||
data: ydata_TotalHasActivityUser, | |||||
type: 'line', | |||||
areaStyle: {}, | |||||
itemStyle:{ | |||||
normal:{ | |||||
lineStyle:{ | |||||
color:"#4E9C8F", | |||||
}, | |||||
color:"#4E9C8F", | |||||
} | |||||
}, | |||||
}, | |||||
] | |||||
}; | |||||
// this.echartsSelectData.resize() | |||||
var checkboxs=document.getElementsByName('checkboxchart'); | |||||
// $(".checkboxchart").click(function(){ | |||||
for(var i=0; i<checkboxs.length; i++){ | |||||
// console.log("selectArr[i]:",this.option.legend.data[i]) | |||||
if(checkboxs[i].checked){ | |||||
this.option.legend.selected[this.option.legend.data[i]]=true; | |||||
}else{ | |||||
this.option.legend.selected[this.option.legend.data[i]]=false; | |||||
} | |||||
} | |||||
this.echartsSelectData.setOption(this.option) | |||||
// this.clickCheckBox() | |||||
// setTimeout(function (){ | |||||
// window.onresize = function () { | |||||
// this.echartsSelectData.resize; | |||||
// } | |||||
// },200) | |||||
// // 使用刚指定的选择项数据显示图表。 | |||||
// var selectArr = this.echartsSelectData.getOption().legend[0].data;//legend所有值 | |||||
// var checkboxs=document.getElementsByName('checkboxchart'); | |||||
// $(".checkboxchart").click(function(){ | |||||
// var obj = {}; | |||||
// for(var i=0; i<checkboxs.length; i++){ | |||||
// if(checkboxs[i].checked){ | |||||
// obj[selectArr[i]] = true; | |||||
// }else{ | |||||
// obj[selectArr[i]] = false; | |||||
// } | |||||
// } | |||||
// option.legend.selected = obj; | |||||
// this.echartsSelectData.setOption(option); | |||||
// }); | |||||
}, | |||||
clickCheckBox(){ | |||||
// 使用刚指定的选择项数据显示图表。 | |||||
var selectArr = this.echartsSelectData.getOption().legend[0].data;//legend所有值 | |||||
var checkboxs=document.getElementsByName('checkboxchart'); | |||||
// $(".checkboxchart").click(function(){ | |||||
var obj = {}; | |||||
for(var i=0; i<checkboxs.length; i++){ | |||||
if(checkboxs[i].checked){ | |||||
obj[selectArr[i]] = true; | |||||
}else{ | |||||
obj[selectArr[i]] = false; | |||||
} | |||||
} | |||||
// console.log("obj:",obj) | |||||
this.option.legend.selected = obj; | |||||
this.echartsSelectData.setOption(this.option); | |||||
// }); | |||||
}, | |||||
}, | |||||
filters:{ | |||||
rounding (value) { | |||||
return Number(value).toFixed(2) | |||||
}, | |||||
roundingToHour (value) { | |||||
return (Number(value)/3600).toFixed(2) | |||||
}, | |||||
transformTimestamp(timestamp){ | |||||
let a = new Date(timestamp*1000); | |||||
const date = new Date(a); | |||||
const Y = date.getFullYear() + '/'; | |||||
const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '/'; | |||||
const D = (date.getDate() < 10 ? '0'+date.getDate() : date.getDate()) + ' '; | |||||
const h = (date.getHours() < 10 ? '0'+date.getHours() : date.getHours()) + ':'; | |||||
const m = (date.getMinutes() <10 ? '0'+date.getMinutes() : date.getMinutes());// + ':' ; | |||||
// const s = (date.getSeconds() <10 ? '0'+date.getSeconds() : date.getSeconds()) ; // 秒 | |||||
const dateString = Y + M + D + h + m ;//+ s; | |||||
return dateString; | |||||
}, | |||||
addUser(val1,val2){ | |||||
return val1+val2 | |||||
} | |||||
}, | |||||
mounted() { | |||||
// document.getElementById("all_usr").style.outline="none" | |||||
// document.getElementById("all_usr").focus() | |||||
this.getUpdateTime() | |||||
this.getUserList("monthly_usr",4) | |||||
this.getYesterdayUser() | |||||
document.getElementById('selectData').style.width = document.getElementById('user_tend').offsetWidth*0.8+'px' | |||||
this.echartsSelectData = this.$echarts.init(document.getElementById('selectData')) | |||||
this.echartsYsAddUser = this.$echarts.init(document.getElementById('ys_add_user')) | |||||
this.echartsYsAllUser = this.$echarts.init(document.getElementById('ys_all_user')) | |||||
}, | |||||
created() { | |||||
this.getUserList("monthly_usr",4) | |||||
this.getYesterdayUser() | |||||
}, | |||||
watch:{ | |||||
// search(val){ | |||||
// if(!val){ | |||||
// this.params.userName = this.search | |||||
// this.params.page = 1 | |||||
// this.page=1 | |||||
// this.getUserList(this.type_val, this.dynamic) | |||||
// } | |||||
// } | |||||
}, | |||||
} | |||||
</script> | |||||
<style scoped> | |||||
.pro_item{ | |||||
font-size: 16px; | |||||
color: rgba(16, 16, 16, 100); | |||||
font-family: SourceHanSansSC-bold; | |||||
} | |||||
.sta_item{ | |||||
font-size: 14px; | |||||
color: rgb(0 0 0); | |||||
font-family: SourceHanSansSC-bold; | |||||
} | |||||
.update_time{ | |||||
line-height: 17px; | |||||
font-size: 12px; | |||||
color:rgba(187, 187, 187, 100); | |||||
margin-left: 10px; | |||||
} | |||||
/* .btn{ | |||||
line-height: 1.5; | |||||
margin: -3px; | |||||
border: 1px solid #409effd6; | |||||
background: #FFFF; | |||||
color: #409eff; | |||||
width: 60px; | |||||
height: 30px; | |||||
border-radius:4px ; | |||||
} */ | |||||
.btnFirst{ | |||||
line-height: 1.5; | |||||
margin: -3.5px; | |||||
border: 1px solid rgba(22, 132, 252, 100); | |||||
border-right: none; | |||||
background: #FFFF; | |||||
color: #1684FC; | |||||
width: 60px; | |||||
height: 30px; | |||||
border-radius:4px 0px 0px 4px; | |||||
} | |||||
.btn{ | |||||
line-height: 1.5; | |||||
margin: -3.5px; | |||||
border: 1px solid rgba(22, 132, 252, 100); | |||||
border-right: none; | |||||
background: #FFFF; | |||||
color: #1684FC; | |||||
width: 60px; | |||||
height: 30px; | |||||
} | |||||
.btnLast{ | |||||
line-height: 1.5; | |||||
margin: -3.5px; | |||||
border: 1px solid rgba(22, 132, 252, 100); | |||||
/* border-right: none; */ | |||||
background: #FFFF; | |||||
color: #1684FC; | |||||
width: 60px; | |||||
height: 30px; | |||||
border-radius:0px 4px 4px 0px; | |||||
} | |||||
.btnFirst,.btn,.btnLast { | |||||
cursor: pointer; | |||||
} | |||||
/* .btn:focus, | |||||
.btn:active{ | |||||
background-color:#409effd6 ; | |||||
} */ | |||||
/* /deep/ .el-date-picker { | |||||
width: 220px; | |||||
} */ | |||||
/deep/ .el-table { | |||||
font-size: 12px; | |||||
} | |||||
/deep/ .el-table tbody tr:hover>td { | |||||
background-color:#D3D3D3!important; | |||||
opacity:1 | |||||
} | |||||
/deep/ .el-range-separator{ | |||||
width: 20% !important; | |||||
} | |||||
/deep/ .el-pagination { | |||||
padding-bottom: 30px; | |||||
} | |||||
.colorChange { | |||||
background-color: #1684FC; | |||||
color: #FFFF; | |||||
cursor: default; | |||||
} | |||||
.item_echart{ | |||||
margin-top: 10px; | |||||
margin-right: 5px; | |||||
border:1px solid rgba(219, 219, 219, 100); | |||||
height: 350px; | |||||
width: 100%; | |||||
} | |||||
.yesterday_blk{ | |||||
display: block; | |||||
margin-top:40px | |||||
} | |||||
.yesterday_pdrt{ | |||||
padding-left: 10px; | |||||
} | |||||
.yesterday_color1{ | |||||
border-left: 3px solid #DBDBDB; | |||||
} | |||||
.yesterday_color2{ | |||||
border-left: 3px solid #5087Ec; | |||||
} | |||||
.yesterday_title{ | |||||
font-size: 14px; | |||||
font-weight: bold; | |||||
} | |||||
.yesterday_text{ | |||||
font-size: 12px; | |||||
line-height: 12px; | |||||
color: #888888; | |||||
margin-top: 10px; | |||||
} | |||||
.bold_num{ | |||||
font-weight: bold; | |||||
} | |||||
.draw_region{ | |||||
width: 180px; | |||||
height: 180px; | |||||
} | |||||
</style> |
@@ -2,7 +2,9 @@ export default async function initCloudrain() { | |||||
let debug_button = $('.cloudbrain_debug').data('debug') | let debug_button = $('.cloudbrain_debug').data('debug') | ||||
let debug_again_button = $('.cloudbrain_debug').data('debug-again') | let debug_again_button = $('.cloudbrain_debug').data('debug-again') | ||||
let timeid = window.setInterval(loadJobStatus, 15000); | let timeid = window.setInterval(loadJobStatus, 15000); | ||||
let timeidShow = window.setInterval(loadShowJobStatus, 15000); | |||||
$(document).ready(loadJobStatus); | $(document).ready(loadJobStatus); | ||||
$(document).ready(loadShowJobStatus); | |||||
function loadJobStatus() { | function loadJobStatus() { | ||||
$(".job-status").each((index, job) => { | $(".job-status").each((index, job) => { | ||||
const ID = job.dataset.jobid; | const ID = job.dataset.jobid; | ||||
@@ -10,7 +12,7 @@ export default async function initCloudrain() { | |||||
// const computeResource = job.dataset.resource | // const computeResource = job.dataset.resource | ||||
const versionname = job.dataset.version | const versionname = job.dataset.version | ||||
const status_text = $(`#${ID}-text`).text() | const status_text = $(`#${ID}-text`).text() | ||||
const finalState = ['STOPPED','CREATE_FAILED','UNAVAILABLE','DELETED','RESIZE_FAILED','SUCCEEDED','IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED','SUBMIT_MODEL_FAILED','DEPLOY_SERVICE_FAILED','CHECK_FAILED'] | |||||
const finalState = ['STOPPED', 'CREATE_FAILED', 'UNAVAILABLE', 'DELETED', 'RESIZE_FAILED', 'SUCCEEDED', 'IMAGE_FAILED', 'SUBMIT_FAILED', 'DELETE_FAILED', 'KILLED', 'COMPLETED', 'FAILED', 'CANCELED', 'LOST', 'START_FAILED', 'SUBMIT_MODEL_FAILED', 'DEPLOY_SERVICE_FAILED', 'CHECK_FAILED'] | |||||
if (finalState.includes(status_text)) { | if (finalState.includes(status_text)) { | ||||
return | return | ||||
} | } | ||||
@@ -19,46 +21,83 @@ export default async function initCloudrain() { | |||||
const ID = data.ID || data.JobID | const ID = data.ID || data.JobID | ||||
const status = data.JobStatus | const status = data.JobStatus | ||||
const duration = data.JobDuration | const duration = data.JobDuration | ||||
$('#duration-'+ID).text(duration) | |||||
console.log(status,["STOPPED"].includes(status)) | |||||
$('#duration-' + ID).text(duration) | |||||
if (status != status_text) { | if (status != status_text) { | ||||
$('#' + ID+'-icon').removeClass().addClass(status) | |||||
$('#' + ID+ '-text').text(status) | |||||
$('#' + ID + '-icon').removeClass().addClass(status) | |||||
$('#' + ID + '-text').text(status) | |||||
finalState.includes(status) && $('#' + ID + '-stop').removeClass('blue').addClass('disabled') | finalState.includes(status) && $('#' + ID + '-stop').removeClass('blue').addClass('disabled') | ||||
} | } | ||||
if(status==="RUNNING"){ | |||||
$('#ai-debug-'+ID).removeClass('disabled').addClass('blue').text(debug_button).css("margin","0 1rem") | |||||
$('#model-image-'+ID).removeClass('disabled').addClass('blue') | |||||
if (status === "RUNNING") { | |||||
$('#ai-debug-' + ID).removeClass('disabled').addClass('blue').text(debug_button).css("margin", "0 1rem") | |||||
$('#model-image-' + ID).removeClass('disabled').addClass('blue') | |||||
} | } | ||||
if(status!=="RUNNING"){ | |||||
if (status !== "RUNNING") { | |||||
// $('#model-debug-'+ID).removeClass('blue') | // $('#model-debug-'+ID).removeClass('blue') | ||||
// $('#model-debug-'+ID).addClass('disabled') | // $('#model-debug-'+ID).addClass('disabled') | ||||
$('#model-image-'+ID).removeClass('blue').addClass('disabled') | |||||
$('#model-image-' + ID).removeClass('blue').addClass('disabled') | |||||
} | } | ||||
if(["CREATING","STOPPING","WAITING","STARTING"].includes(status)){ | |||||
$('#ai-debug-'+ID).removeClass('blue').addClass('disabled') | |||||
if (["CREATING", "STOPPING", "WAITING", "STARTING"].includes(status)) { | |||||
$('#ai-debug-' + ID).removeClass('blue').addClass('disabled') | |||||
} | } | ||||
if(['STOPPED','FAILED','START_FAILED','CREATE_FAILED','SUCCEEDED'].includes(status)){ | |||||
$('#ai-debug-'+ID).removeClass('disabled').addClass('blue').text(debug_again_button).css("margin","0") | |||||
} | |||||
if(["RUNNING","WAITING"].includes(status)){ | |||||
$('#ai-stop-'+ID).removeClass('disabled').addClass('blue') | |||||
if (['STOPPED', 'FAILED', 'START_FAILED', 'CREATE_FAILED', 'SUCCEEDED'].includes(status)) { | |||||
$('#ai-debug-' + ID).removeClass('disabled').addClass('blue').text(debug_again_button).css("margin", "0") | |||||
} | } | ||||
if(["CREATING","STOPPING","STARTING","STOPPED","FAILED","START_FAILED","SUCCEEDED","COMPLETED","CREATE_FAILED"].includes(status)){ | |||||
$('#ai-stop-'+ID).removeClass('blue').addClass('disabled') | |||||
if (["RUNNING", "WAITING"].includes(status)) { | |||||
$('#ai-stop-' + ID).removeClass('disabled').addClass('blue') | |||||
} | } | ||||
if(["STOPPED","FAILED","START_FAILED","KILLED","COMPLETED","SUCCEEDED"].includes(status)){ | |||||
$('#ai-delete-'+ID).removeClass('disabled').addClass('blue') | |||||
}else{ | |||||
$('#ai-delete-'+ID).removeClass('blue').addClass('disabled') | |||||
if (["CREATING", "STOPPING", "STARTING", "STOPPED", "FAILED", "START_FAILED", "SUCCEEDED", "COMPLETED", "CREATE_FAILED"].includes(status)) { | |||||
$('#ai-stop-' + ID).removeClass('blue').addClass('disabled') | |||||
} | } | ||||
}).fail(function(err) { | |||||
if (["STOPPED", "FAILED", "START_FAILED", "KILLED", "COMPLETED", "SUCCEEDED"].includes(status)) { | |||||
$('#ai-delete-' + ID).removeClass('disabled').addClass('blue') | |||||
} else { | |||||
$('#ai-delete-' + ID).removeClass('blue').addClass('disabled') | |||||
} | |||||
}).fail(function (err) { | |||||
console.log(err); | |||||
}); | |||||
}); | |||||
}; | |||||
function loadShowJobStatus() { | |||||
$(".ui.accordion.border-according").each((index, job) => { | |||||
const jobID = job.dataset.jobid; | |||||
const repoPath = job.dataset.repopath; | |||||
const versionname = job.dataset.version | |||||
// ['IMAGE_FAILED','SUBMIT_FAILED','DELETE_FAILED','KILLED','COMPLETED','FAILED','CANCELED','LOST','START_FAILED'] | |||||
// if (job.textContent.trim() == 'IMAGE_FAILED' || job.textContent.trim() == 'SUBMIT_FAILED' || job.textContent.trim() == 'DELETE_FAILED' | |||||
// || job.textContent.trim() == 'KILLED' || job.textContent.trim() == 'COMPLETED' || job.textContent.trim() == 'FAILED' | |||||
// || job.textContent.trim() == 'CANCELED' || job.textContent.trim() == 'LOST') { | |||||
// return | |||||
// } | |||||
let status = $(`#${versionname}-status-span`).text() | |||||
if (['IMAGE_FAILED', 'SUBMIT_FAILED', 'DELETE_FAILED', 'KILLED', 'COMPLETED', 'FAILED', 'CANCELED', 'LOST', 'START_FAILED', 'SUCCEEDED', 'STOPPED'].includes(status)) { | |||||
return | |||||
} | |||||
let stopArray = ["KILLED", "FAILED", "START_FAILED", "KILLING", "COMPLETED", "SUCCEEDED", "STOPPED"] | |||||
$.get(`/api/v1/repos/${repoPath}/${jobID}?version_name=${versionname}`, (data) => { | |||||
//$(`#${versionname}-duration-span`).text(data.JobDuration) | |||||
$(`#${versionname}-status-span span`).text(data.JobStatus) | |||||
$(`#${versionname}-status-span i`).attr("class", data.JobStatus) | |||||
// detail status and duration | |||||
//$('#'+versionname+'-duration').text(data.JobDuration) | |||||
$('#' + versionname + '-status').text(data.JobStatus) | |||||
if (stopArray.includes(data.JobStatus)) { | |||||
$('#' + versionname + '-stop').addClass('disabled') | |||||
} | |||||
if (data.JobStatus === "COMPLETED") { | |||||
$('#' + versionname + '-create-model').removeClass('disabled').addClass('blue') | |||||
} | |||||
}).fail(function (err) { | |||||
console.log(err); | console.log(err); | ||||
}); | }); | ||||
}); | }); | ||||
}; | }; | ||||
function assertDelete(obj,versionName,repoPath) { | |||||
function assertDelete(obj, versionName, repoPath) { | |||||
if (obj.style.color == "rgb(204, 204, 204)") { | if (obj.style.color == "rgb(204, 204, 204)") { | ||||
return | return | ||||
} else { | } else { | ||||
@@ -66,19 +105,19 @@ export default async function initCloudrain() { | |||||
let flag = 1; | let flag = 1; | ||||
$('.ui.basic.modal') | $('.ui.basic.modal') | ||||
.modal({ | .modal({ | ||||
onDeny: function() { | |||||
onDeny: function () { | |||||
flag = false | flag = false | ||||
}, | }, | ||||
onApprove: function() { | |||||
if(!versionName){ | |||||
onApprove: function () { | |||||
if (!versionName) { | |||||
document.getElementById(delId).submit() | document.getElementById(delId).submit() | ||||
} | } | ||||
else{ | |||||
deleteVersion(versionName,repoPath) | |||||
else { | |||||
deleteVersion(versionName, repoPath) | |||||
} | } | ||||
flag = true | flag = true | ||||
}, | }, | ||||
onHidden: function() { | |||||
onHidden: function () { | |||||
if (flag == false) { | if (flag == false) { | ||||
$('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut(); | $('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut(); | ||||
} | } | ||||
@@ -87,200 +126,200 @@ export default async function initCloudrain() { | |||||
.modal('show') | .modal('show') | ||||
} | } | ||||
} | } | ||||
function deleteVersion(versionName,repoPath){ | |||||
function deleteVersion(versionName, repoPath) { | |||||
const url = `/api/v1/repos/${repoPath}` | const url = `/api/v1/repos/${repoPath}` | ||||
$.post(url,{version_name:versionName},(data)=>{ | |||||
if(data.StatusOK===0){ | |||||
$.post(url, { version_name: versionName }, (data) => { | |||||
if (data.StatusOK === 0) { | |||||
location.reload() | location.reload() | ||||
} | } | ||||
}).fail(function(err) { | |||||
console.log(err); | |||||
}).fail(function (err) { | |||||
console.log(err); | |||||
}); | }); | ||||
} | } | ||||
$('.ui.basic.ai_delete').click(function() { | |||||
$('.ui.basic.ai_delete').click(function () { | |||||
const repoPath = this.dataset.repopath | const repoPath = this.dataset.repopath | ||||
const versionName = this.dataset.version | const versionName = this.dataset.version | ||||
if(repoPath && versionName){ | |||||
assertDelete(this,versionName,repoPath) | |||||
if (repoPath && versionName) { | |||||
assertDelete(this, versionName, repoPath) | |||||
} | } | ||||
else{ | |||||
else { | |||||
assertDelete(this) | assertDelete(this) | ||||
} | } | ||||
}) | }) | ||||
function stopDebug(ID,stopUrl){ | |||||
function stopDebug(ID, stopUrl) { | |||||
$.ajax({ | $.ajax({ | ||||
type:"POST", | |||||
url:stopUrl, | |||||
data:$('#stopForm-'+ID).serialize(), | |||||
success:function(res){ | |||||
if(res.result_code==="0"){ | |||||
$('#' + ID+'-icon').removeClass().addClass(res.status) | |||||
$('#' + ID+ '-text').text(res.status) | |||||
if(res.status==="STOPPED"){ | |||||
$('#ai-debug-'+ID).removeClass('disabled').addClass('blue').text(debug_again_button).css("margin","0") | |||||
$('#ai-image-'+ID).removeClass('blue').addClass('disabled') | |||||
$('#ai-model-debug-'+ID).removeClass('blue').addClass('disabled') | |||||
$('#ai-delete-'+ID).removeClass('disabled').addClass('blue') | |||||
$('#ai-stop-'+ID).removeClass('blue').addClass('disabled') | |||||
type: "POST", | |||||
url: stopUrl, | |||||
data: $('#stopForm-' + ID).serialize(), | |||||
success: function (res) { | |||||
if (res.result_code === "0") { | |||||
$('#' + ID + '-icon').removeClass().addClass(res.status) | |||||
$('#' + ID + '-text').text(res.status) | |||||
if (res.status === "STOPPED") { | |||||
$('#ai-debug-' + ID).removeClass('disabled').addClass('blue').text(debug_again_button).css("margin", "0") | |||||
$('#ai-image-' + ID).removeClass('blue').addClass('disabled') | |||||
$('#ai-model-debug-' + ID).removeClass('blue').addClass('disabled') | |||||
$('#ai-delete-' + ID).removeClass('disabled').addClass('blue') | |||||
$('#ai-stop-' + ID).removeClass('blue').addClass('disabled') | |||||
} | } | ||||
else{ | |||||
$('#ai-debug-'+ID).removeClass('blue').addClass('disabled') | |||||
$('#ai-stop-'+ID).removeClass('blue').addClass('disabled') | |||||
else { | |||||
$('#ai-debug-' + ID).removeClass('blue').addClass('disabled') | |||||
$('#ai-stop-' + ID).removeClass('blue').addClass('disabled') | |||||
} | } | ||||
}else{ | |||||
} else { | |||||
$('.alert').html(res.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(2000).fadeOut(); | $('.alert').html(res.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(2000).fadeOut(); | ||||
} | } | ||||
}, | }, | ||||
error :function(res){ | |||||
error: function (res) { | |||||
console.log(res) | console.log(res) | ||||
} | } | ||||
}) | }) | ||||
} | } | ||||
$('.ui.basic.ai_stop').click(function() { | |||||
$('.ui.basic.ai_stop').click(function () { | |||||
const ID = this.dataset.jobid | const ID = this.dataset.jobid | ||||
const repoPath = this.dataset.repopath | const repoPath = this.dataset.repopath | ||||
stopDebug(ID,repoPath) | |||||
stopDebug(ID, repoPath) | |||||
}) | }) | ||||
function stopVersion(version_name,ID,repoPath){ | |||||
function stopVersion(version_name, ID, repoPath) { | |||||
const url = `/api/v1/repos/${repoPath}/${ID}/stop_version` | const url = `/api/v1/repos/${repoPath}/${ID}/stop_version` | ||||
$.post(url,{version_name:version_name},(data)=>{ | |||||
if(data.StatusOK===0){ | |||||
$('#ai-stop-'+ID).removeClass('blue') | |||||
$('#ai-stop-'+ID).addClass('disabled') | |||||
refreshStatus(version_name,ID,repoPath) | |||||
$.post(url, { version_name: version_name }, (data) => { | |||||
if (data.StatusOK === 0) { | |||||
$('#ai-stop-' + ID).removeClass('blue') | |||||
$('#ai-stop-' + ID).addClass('disabled') | |||||
refreshStatus(version_name, ID, repoPath) | |||||
} | } | ||||
}).fail(function(err) { | |||||
console.log(err); | |||||
}).fail(function (err) { | |||||
console.log(err); | |||||
}); | }); | ||||
} | } | ||||
function refreshStatus(version_name,ID,repoPath){ | |||||
function refreshStatus(version_name, ID, repoPath) { | |||||
const url = `/api/v1/repos/${repoPath}/${ID}/?version_name${version_name}` | const url = `/api/v1/repos/${repoPath}/${ID}/?version_name${version_name}` | ||||
$.get(url,(data)=>{ | |||||
$(`#${ID}-icon`).attr("class",data.JobStatus) | |||||
$.get(url, (data) => { | |||||
$(`#${ID}-icon`).attr("class", data.JobStatus) | |||||
// detail status and duration | // detail status and duration | ||||
$(`#${ID}-text`).text(data.JobStatus) | $(`#${ID}-text`).text(data.JobStatus) | ||||
if(["STOPPED","FAILED","START_FAILED","KILLED","COMPLETED","SUCCEEDED"].includes(data.JobStatus)){ | |||||
$('#ai-delete-'+ID).removeClass('disabled').addClass('blue') | |||||
if (["STOPPED", "FAILED", "START_FAILED", "KILLED", "COMPLETED", "SUCCEEDED"].includes(data.JobStatus)) { | |||||
$('#ai-delete-' + ID).removeClass('disabled').addClass('blue') | |||||
} | } | ||||
}).fail(function(err) { | |||||
}).fail(function (err) { | |||||
console.log(err); | console.log(err); | ||||
}); | }); | ||||
} | } | ||||
$('.ui.basic.ai_stop_version').click(function() { | |||||
$('.ui.basic.ai_stop_version').click(function () { | |||||
const ID = this.dataset.jobid | const ID = this.dataset.jobid | ||||
const repoPath = this.dataset.repopath | const repoPath = this.dataset.repopath | ||||
const versionName = this.dataset.version | const versionName = this.dataset.version | ||||
stopVersion(versionName,ID,repoPath) | |||||
stopVersion(versionName, ID, repoPath) | |||||
}) | }) | ||||
function getModelInfo(repoPath,modelName,versionName,jobName){ | |||||
$.get(`${repoPath}/modelmanage/show_model_info_api?name=${modelName}`,(data)=>{ | |||||
if(data.length===0){ | |||||
function getModelInfo(repoPath, modelName, versionName, jobName) { | |||||
$.get(`${repoPath}/modelmanage/show_model_info_api?name=${modelName}`, (data) => { | |||||
if (data.length === 0) { | |||||
$(`#${jobName}`).popup('toggle') | $(`#${jobName}`).popup('toggle') | ||||
}else{ | |||||
let versionData = data.filter((item)=>{ | |||||
} else { | |||||
let versionData = data.filter((item) => { | |||||
return item.Version === versionName | return item.Version === versionName | ||||
}) | }) | ||||
if(versionData.length==0){ | |||||
if (versionData.length == 0) { | |||||
$(`#${jobName}`).popup('toggle') | $(`#${jobName}`).popup('toggle') | ||||
} | } | ||||
else{ | |||||
else { | |||||
location.href = `${repoPath}/modelmanage/show_model_info?name=${modelName}` | location.href = `${repoPath}/modelmanage/show_model_info?name=${modelName}` | ||||
} | } | ||||
} | } | ||||
}) | }) | ||||
} | } | ||||
$('.goto_modelmanage').click(function() { | |||||
$('.goto_modelmanage').click(function () { | |||||
const repoPath = this.dataset.repopath | const repoPath = this.dataset.repopath | ||||
const modelName = this.dataset.modelname | const modelName = this.dataset.modelname | ||||
const versionName = this.dataset.version | const versionName = this.dataset.version | ||||
const jobName = this.dataset.jobname | const jobName = this.dataset.jobname | ||||
getModelInfo(repoPath,modelName,versionName,jobName) | |||||
getModelInfo(repoPath, modelName, versionName, jobName) | |||||
}) | }) | ||||
function debugAgain(ID,debugUrl,redirect_to){ | |||||
if($('#' + ID+ '-text').text()==="RUNNING"){ | |||||
window.open(debugUrl+'debug') | |||||
}else{ | |||||
function debugAgain(ID, debugUrl, redirect_to) { | |||||
if ($('#' + ID + '-text').text() === "RUNNING") { | |||||
window.open(debugUrl + 'debug') | |||||
} else { | |||||
$.ajax({ | $.ajax({ | ||||
type:"POST", | |||||
url:debugUrl+'restart?redirect_to='+redirect_to, | |||||
data:$('#debugAgainForm-'+ID).serialize(), | |||||
success:function(res){ | |||||
if(res['WechatRedirectUrl']){ | |||||
window.location.href=res['WechatRedirectUrl'] | |||||
type: "POST", | |||||
url: debugUrl + 'restart?redirect_to=' + redirect_to, | |||||
data: $('#debugAgainForm-' + ID).serialize(), | |||||
success: function (res) { | |||||
if (res['WechatRedirectUrl']) { | |||||
window.location.href = res['WechatRedirectUrl'] | |||||
} | } | ||||
else if(res.result_code==="0"){ | |||||
if(res.id!==ID){ | |||||
else if (res.result_code === "0") { | |||||
if (res.id !== ID) { | |||||
location.reload() | location.reload() | ||||
}else{ | |||||
$('#' + ID+'-icon').removeClass().addClass(res.status) | |||||
$('#' + ID+ '-text').text(res.status) | |||||
$('#ai-debug-'+ID).removeClass('blue').addClass('disabled') | |||||
$('#ai-delete-'+ID).removeClass('blue').addClass('disabled') | |||||
$('#ai-debug-'+ID).text(debug_button).css("margin","0 1rem") | |||||
} else { | |||||
$('#' + ID + '-icon').removeClass().addClass(res.status) | |||||
$('#' + ID + '-text').text(res.status) | |||||
$('#ai-debug-' + ID).removeClass('blue').addClass('disabled') | |||||
$('#ai-delete-' + ID).removeClass('blue').addClass('disabled') | |||||
$('#ai-debug-' + ID).text(debug_button).css("margin", "0 1rem") | |||||
} | } | ||||
}else{ | |||||
} else { | |||||
$('.alert').html(res.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(2000).fadeOut(); | $('.alert').html(res.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(2000).fadeOut(); | ||||
} | } | ||||
}, | }, | ||||
error :function(res){ | |||||
error: function (res) { | |||||
console.log(res) | console.log(res) | ||||
} | } | ||||
}) | }) | ||||
} | } | ||||
} | } | ||||
$('.ui.basic.ai_debug').click(function() { | |||||
$('.ui.basic.ai_debug').click(function () { | |||||
const ID = this.dataset.jobid | const ID = this.dataset.jobid | ||||
const repoPath = this.dataset.repopath | const repoPath = this.dataset.repopath | ||||
const redirect_to = this.dataset.linkpath | const redirect_to = this.dataset.linkpath | ||||
debugAgain(ID,repoPath,redirect_to) | |||||
debugAgain(ID, repoPath, redirect_to) | |||||
}) | }) | ||||
} | } | ||||
function userSearchControll() { | function userSearchControll() { | ||||
if($('#userCloud').length===0){ | |||||
return | |||||
if ($('#userCloud').length === 0) { | |||||
return | |||||
} | } | ||||
const params = new URLSearchParams(window.location.search) | const params = new URLSearchParams(window.location.search) | ||||
let jobType | let jobType | ||||
if($('.cloudbrain_debug').length===1){ | |||||
if(!params.get('jobType')){ | |||||
if ($('.cloudbrain_debug').length === 1) { | |||||
if (!params.get('jobType')) { | |||||
jobType = $('.cloudbrain_debug').data('allTask') | jobType = $('.cloudbrain_debug').data('allTask') | ||||
}else{ | |||||
if(params.get('jobType') === 'DEBUG'){ | |||||
} else { | |||||
if (params.get('jobType') === 'DEBUG') { | |||||
jobType = $('.cloudbrain_debug').data('debug-task') | jobType = $('.cloudbrain_debug').data('debug-task') | ||||
}else if(params.get('jobType') === 'TRAIN'){ | |||||
} else if (params.get('jobType') === 'TRAIN') { | |||||
jobType = $('.cloudbrain_debug').data('train-task') | jobType = $('.cloudbrain_debug').data('train-task') | ||||
} | } | ||||
else if(params.get('jobType') === 'INFERENCE'){ | |||||
else if (params.get('jobType') === 'INFERENCE') { | |||||
jobType = $('.cloudbrain_debug').data('inference-task') | jobType = $('.cloudbrain_debug').data('inference-task') | ||||
} | } | ||||
else{ | |||||
else { | |||||
jobType = $('.cloudbrain_debug').data('benchmark-task') | jobType = $('.cloudbrain_debug').data('benchmark-task') | ||||
} | } | ||||
} | } | ||||
} | } | ||||
let listType = !params.get('listType')? $('.cloudbrain_debug').data('all-compute') : params.get('listType') | |||||
let jobStatus = !params.get('jobStatus')? $('.cloudbrain_debug').data('all-status') : params.get('jobStatus').toUpperCase() | |||||
const dropdownValueArray = [jobType,listType,jobStatus] | |||||
$('#userCloud .default.text ').each(function(index,e){ | |||||
let listType = !params.get('listType') ? $('.cloudbrain_debug').data('all-compute') : params.get('listType') | |||||
let jobStatus = !params.get('jobStatus') ? $('.cloudbrain_debug').data('all-status') : params.get('jobStatus').toUpperCase() | |||||
const dropdownValueArray = [jobType, listType, jobStatus] | |||||
$('#userCloud .default.text ').each(function (index, e) { | |||||
$(e).text(dropdownValueArray[index]) | $(e).text(dropdownValueArray[index]) | ||||
}) | }) | ||||
} | } | ||||
function AdaminSearchControll() { | function AdaminSearchControll() { | ||||
if($('#adminCloud').length===0){ | |||||
return | |||||
if ($('#adminCloud').length === 0) { | |||||
return | |||||
} | } | ||||
const params = new URLSearchParams(window.location.search) | const params = new URLSearchParams(window.location.search) | ||||
let jobType = !params.get('jobType')? $('.cloudbrain_debug').data('all-task') : params.get('jobType') | |||||
let listType = !params.get('listType')? $('.cloudbrain_debug').data('all-compute') : params.get('listType') | |||||
let jobStatus = !params.get('jobStatus')? $('.cloudbrain_debug').data('all-status') : params.get('jobStatus').toUpperCase() | |||||
const dropdownValueArray = [jobType,listType,jobStatus] | |||||
$('#adminCloud .default.text ').each(function(index,e){ | |||||
let jobType = !params.get('jobType') ? $('.cloudbrain_debug').data('all-task') : params.get('jobType') | |||||
let listType = !params.get('listType') ? $('.cloudbrain_debug').data('all-compute') : params.get('listType') | |||||
let jobStatus = !params.get('jobStatus') ? $('.cloudbrain_debug').data('all-status') : params.get('jobStatus').toUpperCase() | |||||
const dropdownValueArray = [jobType, listType, jobStatus] | |||||
$('#adminCloud .default.text ').each(function (index, e) { | |||||
$(e).text(dropdownValueArray[index]) | $(e).text(dropdownValueArray[index]) | ||||
}) | }) | ||||
} | } | ||||
@@ -288,4 +327,4 @@ userSearchControll() | |||||
AdaminSearchControll() | AdaminSearchControll() | ||||
@@ -0,0 +1,153 @@ | |||||
export default async function initContextMenu() { | |||||
$('.popup-close').on('click', function (e) { | |||||
$(this).parents('tr').prev().css('display', 'table-row') | |||||
$(this).closest('tr').css('cssText', 'display:none !important') | |||||
}) | |||||
function contextMenu() { | |||||
let canContextMenu = $('.ui.single.line.table.can-context-menu').data('can-editfile') | |||||
if (canContextMenu) { | |||||
$('.name.four.wide').on('contextmenu', function (e) { | |||||
let ev = window.event || e; | |||||
ev.preventDefault(); | |||||
menu.show(e) | |||||
}) | |||||
} else { | |||||
return | |||||
} | |||||
} | |||||
contextMenu() | |||||
const menu = new Menu({ | |||||
data: [ | |||||
{ | |||||
label: '新标签打开', | |||||
icon: "file outline icon context-menu-icon", | |||||
active: (e, a) => { | |||||
window.open(a.currentTarget.getElementsByTagName("a")[0].getAttribute('href')) | |||||
} | |||||
}, | |||||
{ | |||||
label: '重命名', | |||||
icon: "edit icon context-menu-icon", | |||||
active: (e, a) => { | |||||
document.querySelectorAll(".context-menu-one").forEach((ele) => { | |||||
if (ele.style.display === 'table-row') { | |||||
ele.style.display = 'none' | |||||
ele.previousElementSibling.style.display = 'table-row' | |||||
} | |||||
}) | |||||
if (a.currentTarget.parentNode.nextElementSibling) { | |||||
a.currentTarget.parentNode.style.setProperty('display', 'none', 'important') | |||||
a.currentTarget.parentNode.nextElementSibling.style.display = 'table-row' | |||||
a.currentTarget.parentNode.nextElementSibling.getElementsByTagName("input")[0].setAttribute("value", a.currentTarget.getElementsByTagName("a")[0].getAttribute('title')) | |||||
} | |||||
let btn = a.currentTarget.parentNode.nextElementSibling.getElementsByTagName("button")[0] | |||||
btn.addEventListener('click', function (e) { | |||||
let postUrl = btn.getAttribute('data-postbasepath') | |||||
let last_commit = btn.getAttribute('data-commit') | |||||
let tree_path = btn.getAttribute('data-treepath') + e.target.parentNode.previousElementSibling.getElementsByTagName("input")[0].value | |||||
let csrf = $("input[name='_csrf']").val() | |||||
$.ajax({ | |||||
url: postUrl, | |||||
type: "POST", | |||||
contentType: "application/x-www-form-urlencoded", | |||||
data: { last_commit: last_commit, tree_path: tree_path, _csrf: csrf }, | |||||
success: function (res) { | |||||
console.log("--------------") | |||||
console.log(res.Code) | |||||
console.log(res.Message) | |||||
if (res.Code === 0) { | |||||
document.getElementById("mask").style.display = "block" | |||||
location.reload() | |||||
} | |||||
else { | |||||
$('.ui.negative.message').text(res.Msg).show().delay(10000).fadeOut(); | |||||
} | |||||
} | |||||
}) | |||||
}) | |||||
}, | |||||
}, | |||||
// { | |||||
// label: '删除', | |||||
// icon: "trash icon context-menu-icon", | |||||
// active: (e, a) => { | |||||
// console.dir(a) | |||||
// $('.context-menu-delete.modal') | |||||
// .modal({ | |||||
// onApprove() { | |||||
// } | |||||
// }) | |||||
// .modal('show'); | |||||
// } | |||||
// }, | |||||
] | |||||
}) | |||||
} | |||||
class Menu { | |||||
constructor(param) { | |||||
this.target = document.createElement('div') | |||||
this.target.classList.add("ui", "menu", "compact", "vertical", "context-menu") | |||||
this.data = param.data | |||||
this.active = false | |||||
this.clickZ = this.click.bind(this) | |||||
this.closeZ = this.close2.bind(this) | |||||
document.addEventListener('click', this.closeZ) | |||||
for (let i = 0; i < this.data.length; i++) { | |||||
let div = document.createElement('a') | |||||
div.classList.add('item', 'context-menu-operation') | |||||
if (this.data[i].disabled) { | |||||
div.classList.add('disabled') | |||||
} | |||||
div.dataset.index = i.toString() | |||||
div.innerHTML = `<i class="${this.data[i].icon}"></i>${this.data[i].label}` | |||||
div.addEventListener('click', this.clickZ) | |||||
this.target.append(div) | |||||
} | |||||
document.body.append(this.target) | |||||
} | |||||
click(e) { | |||||
let index = parseInt(e.target.dataset.index) | |||||
if (this.data[index].active) { | |||||
this.data[index].active(e, this.acEvent) | |||||
} | |||||
this.close() | |||||
} | |||||
show(e) { | |||||
this.active = true | |||||
this.nodeList = this.target.querySelectorAll('.item') | |||||
for (let i = 0; i < this.data.length; i++) { | |||||
if (this.data[i].beforeDisabled) { | |||||
let t = this.data[i].beforeDisabled(e) | |||||
this.data[i].disabled = t | |||||
if (t) { | |||||
this.nodeList[i].classList.add('disabled') | |||||
} else { | |||||
this.nodeList[i].classList.remove('disabled') | |||||
} | |||||
} | |||||
} | |||||
this.acEvent = e | |||||
this.target.style.top = `${e.pageY}px` | |||||
this.target.style.left = `${e.pageX}px` | |||||
this.target.style.minWidth = '90px' | |||||
this.target.classList.add('active') | |||||
} | |||||
close() { | |||||
this.active = false | |||||
this.target.classList.remove('active') | |||||
} | |||||
close2(e) { | |||||
if (!this.target.contains(e.target) && this.active) { | |||||
this.active = false | |||||
this.target.classList.remove('active') | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,64 @@ | |||||
import Vue from 'vue' | |||||
import Router from 'vue-router' | |||||
import DataAnalysis from '../components/DataAnalysis.vue' | |||||
import ProAnalysis from '../components/ProAnalysis.vue' | |||||
import ProTrend from '../components/ProTrend.vue' | |||||
import UserTrend from '../components/UserTrend.vue' | |||||
import UserAnalysis from '../components/UserAnalysis.vue' | |||||
import BrainAnalysis from '../components/BrainAnalysis.vue' | |||||
import Overview from '../components/Overview.vue' | |||||
const originalPush = Router.prototype.push | |||||
Router.prototype.push = function push(location) { | |||||
return originalPush.call(this, location).catch(err => err) | |||||
} | |||||
Vue.use(Router) | |||||
export default new Router({ | |||||
mode: 'history', | |||||
base: '/explore/data_analysis/', //添加根目录 | |||||
scrollBehavior: () => ({ y: 0 }), | |||||
routes:[ | |||||
{ | |||||
path:'/',redirect:'/ProAnalysis', | |||||
name:'ProAnalysis', | |||||
component:ProAnalysis, | |||||
}, | |||||
{ | |||||
path:'/Overview', | |||||
name:'Overview', | |||||
component:Overview, | |||||
}, | |||||
{ | |||||
path:'/ProTrend', | |||||
name:'ProTrend', | |||||
component:ProTrend, | |||||
}, | |||||
{ | |||||
path:'/ProAnalysis', | |||||
name:'ProAnalysis', | |||||
component:ProAnalysis, | |||||
}, | |||||
{ | |||||
path:'/UserAnalysis', | |||||
name:'UserAnalysis', | |||||
component:UserAnalysis, | |||||
}, | |||||
{ | |||||
path:'/UserTrend', | |||||
name:'UserTrend', | |||||
component:UserTrend, | |||||
}, | |||||
{ | |||||
path:'/BrainAnalysis', | |||||
name:'BrainAnalysis', | |||||
component:BrainAnalysis, | |||||
}, | |||||
], | |||||
}) |