Browse Source

Merge branch 'V20211213' of git.openi.org.cn:OpenI/aiforge into fix597

pull/1075/head
lewis 3 years ago
parent
commit
b25015deeb
31 changed files with 1322 additions and 449 deletions
  1. +21
    -22
      models/ai_model_manage.go
  2. +2
    -1
      models/cloudbrain.go
  3. +4
    -0
      models/dataset.go
  4. +18
    -0
      models/repo.go
  5. +1
    -1
      models/user.go
  6. +553
    -313
      models/user_business_analysis.go
  7. +18
    -14
      modules/cloudbrain/cloudbrain.go
  8. +3
    -3
      modules/cron/tasks_basic.go
  9. +20
    -6
      modules/setting/setting.go
  10. +2
    -0
      options/locale/locale_en-US.ini
  11. +3
    -3
      options/locale/locale_zh-CN.ini
  12. +1
    -0
      public/img/member.svg
  13. +1
    -0
      public/img/pro_num.svg
  14. +42
    -0
      routers/home.go
  15. +43
    -9
      routers/repo/ai_model_manage.go
  16. +65
    -28
      routers/repo/cloudbrain.go
  17. +4
    -7
      routers/repo/modelarts.go
  18. +1
    -0
      routers/repo/repo.go
  19. +3
    -9
      routers/repo/user_data_analysis.go
  20. +2
    -0
      routers/routes/routes.go
  21. +5
    -0
      routers/user/profile.go
  22. +6
    -5
      templates/base/head_navbar.tmpl
  23. +2
    -2
      templates/base/head_navbar_fluid.tmpl
  24. +2
    -2
      templates/base/head_navbar_home.tmpl
  25. +216
    -0
      templates/base/head_navbar_pro.tmpl
  26. +208
    -0
      templates/base/head_pro.tmpl
  27. +1
    -1
      templates/explore/repos.tmpl
  28. +7
    -2
      templates/repo/header.tmpl
  29. +8
    -9
      templates/repo/settings/options.tmpl
  30. +53
    -11
      templates/user/profile.tmpl
  31. +7
    -1
      web_src/less/openi.less

+ 21
- 22
models/ai_model_manage.go View File

@@ -11,30 +11,30 @@ import (
) )


type AiModelManage struct { type AiModelManage struct {
ID string `xorm:"pk"`
Name string `xorm:"NOT NULL"`
Version string `xorm:"NOT NULL"`
VersionCount int `xorm:"NOT NULL DEFAULT 0"`
New int `xorm:"NOT NULL"`
Type int `xorm:"NOT NULL"`
Size int64 `xorm:"NOT NULL"`
Description string `xorm:"varchar(2000)"`
Label string `xorm:"varchar(1000)"`
Path string `xorm:"varchar(400) NOT NULL"`
DownloadCount int `xorm:"NOT NULL DEFAULT 0"`
Engine int64 `xorm:"NOT NULL DEFAULT 0"`
Status int `xorm:"NOT NULL DEFAULT 0"`
Accuracy string `xorm:"varchar(1000)"`
AttachmentId string `xorm:"NULL"`
RepoId int64 `xorm:"NULL"`
CodeBranch string `xorm:"varchar(400) NULL"`
CodeCommitID string `xorm:"NULL"`
UserId int64 `xorm:"NOT NULL"`
UserName string `xorm:"NULL"`
ID string `xorm:"pk"`
Name string `xorm:"INDEX NOT NULL"`
Version string `xorm:"NOT NULL"`
VersionCount int `xorm:"NOT NULL DEFAULT 0"`
New int `xorm:"NOT NULL"`
Type int `xorm:"NOT NULL"`
Size int64 `xorm:"NOT NULL"`
Description string `xorm:"varchar(2000)"`
Label string `xorm:"varchar(1000)"`
Path string `xorm:"varchar(400) NOT NULL"`
DownloadCount int `xorm:"NOT NULL DEFAULT 0"`
Engine int64 `xorm:"NOT NULL DEFAULT 0"`
Status int `xorm:"NOT NULL DEFAULT 0"`
Accuracy string `xorm:"varchar(1000)"`
AttachmentId string `xorm:"NULL"`
RepoId int64 `xorm:"INDEX NULL"`
CodeBranch string `xorm:"varchar(400) NULL"`
CodeCommitID string `xorm:"NULL"`
UserId int64 `xorm:"NOT NULL"`
UserName string
UserRelAvatarLink string `xorm:"NULL"` UserRelAvatarLink string `xorm:"NULL"`
TrainTaskInfo string `xorm:"text NULL"` TrainTaskInfo string `xorm:"text NULL"`
CreatedUnix timeutil.TimeStamp `xorm:"created"` CreatedUnix timeutil.TimeStamp `xorm:"created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
IsCanOper bool IsCanOper bool
} }


@@ -197,7 +197,6 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) {
Find(&aiModelManages); err != nil { Find(&aiModelManages); err != nil {
return nil, 0, fmt.Errorf("Find: %v", err) return nil, 0, fmt.Errorf("Find: %v", err)
} }
sess.Close()


return aiModelManages, count, nil return aiModelManages, count, nil
} }

+ 2
- 1
models/cloudbrain.go View File

@@ -1110,7 +1110,8 @@ func UpdateJob(job *Cloudbrain) error {
func updateJob(e Engine, job *Cloudbrain) error { func updateJob(e Engine, job *Cloudbrain) error {
var sess *xorm.Session var sess *xorm.Session
sess = e.Where("job_id = ?", job.JobID) sess = e.Where("job_id = ?", job.JobID)
_, err := sess.Cols("status", "container_id", "container_ip").Update(job)
//_, err := sess.Cols("status", "container_id", "container_ip").Update(job)
_, err := sess.Update(job)
return err return err
} }




+ 4
- 0
models/dataset.go View File

@@ -93,6 +93,7 @@ type SearchDatasetOptions struct {
IncludePublic bool IncludePublic bool
ListOptions ListOptions
SearchOrderBy SearchOrderBy
IsOwner bool
} }


func CreateDataset(dataset *Dataset) (err error) { func CreateDataset(dataset *Dataset) (err error) {
@@ -150,6 +151,9 @@ func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond {
} }
} else if opts.OwnerID > 0 { } else if opts.OwnerID > 0 {
cond = cond.And(builder.Eq{"repository.owner_id": opts.OwnerID}) cond = cond.And(builder.Eq{"repository.owner_id": opts.OwnerID})
if !opts.IsOwner {
cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic})
}
} }


return cond return cond


+ 18
- 0
models/repo.go View File

@@ -11,6 +11,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"html/template" "html/template"
"xorm.io/xorm"


"code.gitea.io/gitea/modules/blockchain" "code.gitea.io/gitea/modules/blockchain"


@@ -1632,6 +1633,9 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
releaseAttachments = append(releaseAttachments, attachments[i].RelativePath()) releaseAttachments = append(releaseAttachments, attachments[i].RelativePath())
} }


// Delete dataset attachment record and remove related files
deleteDatasetAttachmentByRepoId(sess, repoID)

if err = deleteBeans(sess, if err = deleteBeans(sess,
&Access{RepoID: repo.ID}, &Access{RepoID: repo.ID},
&Action{RepoID: repo.ID}, &Action{RepoID: repo.ID},
@@ -1817,6 +1821,20 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
return nil return nil
} }


func deleteDatasetAttachmentByRepoId(sess *xorm.Session, repoId int64) error {
attachments := make([]*Attachment, 0)
if err := sess.Join("INNER", "dataset", "dataset.id = attachment.dataset_id").
Where("dataset.repo_id = ?", repoId).
Find(&attachments); err != nil {
return err
}
if len(attachments) == 0 {
return nil
}
_, err := DeleteAttachments(attachments, true)
return err
}

// GetRepositoryByOwnerAndName returns the repository by given ownername and reponame. // GetRepositoryByOwnerAndName returns the repository by given ownername and reponame.
func GetRepositoryByOwnerAndName(ownerName, repoName string) (*Repository, error) { func GetRepositoryByOwnerAndName(ownerName, repoName string) (*Repository, error) {
return getRepositoryByOwnerAndName(x, ownerName, repoName) return getRepositoryByOwnerAndName(x, ownerName, repoName)


+ 1
- 1
models/user.go View File

@@ -929,7 +929,7 @@ var (
"template", "template",
"user", "user",
"vendor", "vendor",
"dashbord",
"dashboard",
"operation", "operation",
"blockchain", "blockchain",
"avatar", "avatar",


+ 553
- 313
models/user_business_analysis.go
File diff suppressed because it is too large
View File


+ 18
- 14
modules/cloudbrain/cloudbrain.go View File

@@ -2,6 +2,7 @@ package cloudbrain


import ( import (
"errors" "errors"
"strconv"


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


@@ -30,29 +31,30 @@ var (
) )


func isAdminOrOwnerOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { func isAdminOrOwnerOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool {

if !ctx.IsSigned {
return false
}
log.Info("is repo owner:" + strconv.FormatBool(ctx.IsUserRepoOwner()))
log.Info("is user admin:" + strconv.FormatBool(ctx.IsUserSiteAdmin()))
if err != nil { if err != nil {

return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin()
} else { } else {
log.Info("is job creator:" + strconv.FormatBool(ctx.User.ID == job.UserID))
return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() || ctx.User.ID == job.UserID return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() || ctx.User.ID == job.UserID
} }


} }


func CanDeleteDebugJob(ctx *context.Context, job *models.Cloudbrain) bool {

if job.Status != string(models.JobStopped) && job.Status != string(models.JobFailed) && job.Status != string(models.ModelArtsStartFailed) && job.Status != string(models.ModelArtsCreateFailed) {
return false
}
return isAdminOrOwnerOrJobCreater(ctx, job, nil)
}

func CanDeleteTrainJob(ctx *context.Context, job *models.Cloudbrain) bool {
func CanDeleteJob(ctx *context.Context, job *models.Cloudbrain) bool {


return isAdminOrOwnerOrJobCreater(ctx, job, nil) return isAdminOrOwnerOrJobCreater(ctx, job, nil)
} }


func CanCreateOrDebugJob(ctx *context.Context) bool { func CanCreateOrDebugJob(ctx *context.Context) bool {
if !ctx.IsSigned {
return false
}
return ctx.Repo.CanWrite(models.UnitTypeCloudBrain) return ctx.Repo.CanWrite(models.UnitTypeCloudBrain)
} }


@@ -62,7 +64,9 @@ func CanModifyJob(ctx *context.Context, job *models.Cloudbrain) bool {
} }


func isAdminOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { func isAdminOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool {

if !ctx.IsSigned {
return false
}
if err != nil { if err != nil {
return ctx.IsUserSiteAdmin() return ctx.IsUserSiteAdmin()
} else { } else {
@@ -113,7 +117,7 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath,
log.Error("no such resourceSpecId(%d)", resourceSpecId, ctx.Data["MsgID"]) log.Error("no such resourceSpecId(%d)", resourceSpecId, ctx.Data["MsgID"])
return errors.New("no such resourceSpec") return errors.New("no such resourceSpec")
} }
jobResult, err := CreateJob(jobName, models.CreateJobParams{ jobResult, err := CreateJob(jobName, models.CreateJobParams{
JobName: jobName, JobName: jobName,
RetryCount: 1, RetryCount: 1,
@@ -198,8 +202,8 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath,
JobName: jobName, JobName: jobName,
SubTaskName: SubTaskName, SubTaskName: SubTaskName,
JobType: jobType, JobType: jobType,
Type: models.TypeCloudBrainOne,
Uuid: uuid,
Type: models.TypeCloudBrainOne,
Uuid: uuid,
}) })


if err != nil { if err != nil {


+ 3
- 3
modules/cron/tasks_basic.go View File

@@ -134,7 +134,7 @@ func registerHandleBlockChainUnSuccessRepos() {
RegisterTaskFatal("handle_blockchain_unsuccess_repos", &BaseConfig{ RegisterTaskFatal("handle_blockchain_unsuccess_repos", &BaseConfig{
Enabled: true, Enabled: true,
RunAtStart: true, RunAtStart: true,
Schedule: "@every 1m",
Schedule: "@every 10m",
}, func(ctx context.Context, _ *models.User, _ Config) error { }, func(ctx context.Context, _ *models.User, _ Config) error {
repo.HandleBlockChainUnSuccessRepos() repo.HandleBlockChainUnSuccessRepos()
return nil return nil
@@ -145,7 +145,7 @@ func registerHandleBlockChainMergedPulls() {
RegisterTaskFatal("handle_blockchain_merged_pull", &BaseConfig{ RegisterTaskFatal("handle_blockchain_merged_pull", &BaseConfig{
Enabled: true, Enabled: true,
RunAtStart: true, RunAtStart: true,
Schedule: "@every 1m",
Schedule: "@every 10m",
}, func(ctx context.Context, _ *models.User, _ Config) error { }, func(ctx context.Context, _ *models.User, _ Config) error {
repo.HandleBlockChainMergedPulls() repo.HandleBlockChainMergedPulls()
return nil return nil
@@ -156,7 +156,7 @@ func registerHandleBlockChainUnSuccessCommits() {
RegisterTaskFatal("handle_blockchain_unsuccess_commits", &BaseConfig{ RegisterTaskFatal("handle_blockchain_unsuccess_commits", &BaseConfig{
Enabled: true, Enabled: true,
RunAtStart: true, RunAtStart: true,
Schedule: "@every 3m",
Schedule: "@every 10m",
}, func(ctx context.Context, _ *models.User, _ Config) error { }, func(ctx context.Context, _ *models.User, _ Config) error {
repo.HandleBlockChainUnSuccessCommits() repo.HandleBlockChainUnSuccessCommits()
return nil return nil


+ 20
- 6
modules/setting/setting.go View File

@@ -433,6 +433,9 @@ var (
AuthUser string AuthUser string
AuthPassword string AuthPassword string


//home page
RecommentRepoAddr string

//labelsystem config //labelsystem config
LabelTaskName string LabelTaskName string
LabelDatasetDeleteQueue string LabelDatasetDeleteQueue string
@@ -448,21 +451,25 @@ var (
GpuTypes string GpuTypes string
DebugServerHost string DebugServerHost string
ResourceSpecs string ResourceSpecs string
MaxDuration int64


//benchmark config //benchmark config
IsBenchmarkEnabled bool IsBenchmarkEnabled bool
BenchmarkCode string
BenchmarkOwner string
BenchmarkName string
BenchmarkServerHost string BenchmarkServerHost string
BenchmarkCategory string BenchmarkCategory string


//snn4imagenet config //snn4imagenet config
IsSnn4imagenetEnabled bool IsSnn4imagenetEnabled bool
Snn4imagenetCode string
Snn4imagenetOwner string
Snn4imagenetName string
Snn4imagenetServerHost string Snn4imagenetServerHost string


//snn4imagenet config //snn4imagenet config
IsBrainScoreEnabled bool IsBrainScoreEnabled bool
BrainScoreCode string
BrainScoreOwner string
BrainScoreName string
BrainScoreServerHost string BrainScoreServerHost string


//blockchain config //blockchain config
@@ -1225,6 +1232,9 @@ func NewContext() {
LabelDatasetDeleteQueue = sec.Key("LabelDatasetDeleteQueue").MustString("LabelDatasetDeleteQueue") LabelDatasetDeleteQueue = sec.Key("LabelDatasetDeleteQueue").MustString("LabelDatasetDeleteQueue")
DecompressOBSTaskName = sec.Key("DecompressOBSTaskName").MustString("LabelDecompressOBSQueue") DecompressOBSTaskName = sec.Key("DecompressOBSTaskName").MustString("LabelDecompressOBSQueue")


sec = Cfg.Section("homepage")
RecommentRepoAddr = sec.Key("Address").MustString("https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/")

sec = Cfg.Section("cloudbrain") sec = Cfg.Section("cloudbrain")
CBAuthUser = sec.Key("USER").MustString("") CBAuthUser = sec.Key("USER").MustString("")
CBAuthPassword = sec.Key("PWD").MustString("") CBAuthPassword = sec.Key("PWD").MustString("")
@@ -1235,21 +1245,25 @@ func NewContext() {
JobType = sec.Key("GPU_TYPE_DEFAULT").MustString("openidebug") JobType = sec.Key("GPU_TYPE_DEFAULT").MustString("openidebug")
GpuTypes = sec.Key("GPU_TYPES").MustString("") GpuTypes = sec.Key("GPU_TYPES").MustString("")
ResourceSpecs = sec.Key("RESOURCE_SPECS").MustString("") ResourceSpecs = sec.Key("RESOURCE_SPECS").MustString("")
MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400)


sec = Cfg.Section("benchmark") sec = Cfg.Section("benchmark")
IsBenchmarkEnabled = sec.Key("ENABLED").MustBool(false) IsBenchmarkEnabled = sec.Key("ENABLED").MustBool(false)
BenchmarkCode = sec.Key("BENCHMARKCODE").MustString("")
BenchmarkOwner = sec.Key("OWNER").MustString("")
BenchmarkName = sec.Key("NAME").MustString("")
BenchmarkServerHost = sec.Key("HOST").MustString("") BenchmarkServerHost = sec.Key("HOST").MustString("")
BenchmarkCategory = sec.Key("CATEGORY").MustString("") BenchmarkCategory = sec.Key("CATEGORY").MustString("")


sec = Cfg.Section("snn4imagenet") sec = Cfg.Section("snn4imagenet")
IsSnn4imagenetEnabled = sec.Key("ENABLED").MustBool(false) IsSnn4imagenetEnabled = sec.Key("ENABLED").MustBool(false)
Snn4imagenetCode = sec.Key("SNN4IMAGENETCODE").MustString("")
Snn4imagenetOwner = sec.Key("OWNER").MustString("")
Snn4imagenetName = sec.Key("NAME").MustString("")
Snn4imagenetServerHost = sec.Key("HOST").MustString("") Snn4imagenetServerHost = sec.Key("HOST").MustString("")


sec = Cfg.Section("brainscore") sec = Cfg.Section("brainscore")
IsBrainScoreEnabled = sec.Key("ENABLED").MustBool(false) IsBrainScoreEnabled = sec.Key("ENABLED").MustBool(false)
BrainScoreCode = sec.Key("BRAINSCORECODE").MustString("")
BrainScoreOwner = sec.Key("OWNER").MustString("")
BrainScoreName = sec.Key("NAME").MustString("")
BrainScoreServerHost = sec.Key("HOST").MustString("") BrainScoreServerHost = sec.Key("HOST").MustString("")


sec = Cfg.Section("blockchain") sec = Cfg.Section("blockchain")


+ 2
- 0
options/locale/locale_en-US.ini View File

@@ -778,6 +778,8 @@ datasets = Datasets
datasets.desc = Enable Dataset datasets.desc = Enable Dataset
cloudbrain_helper=Use GPU/NPU resources to open notebooks, model training tasks, etc. cloudbrain_helper=Use GPU/NPU resources to open notebooks, model training tasks, etc.


model_manager = Model

debug=Debug debug=Debug
stop=Stop stop=Stop
delete=Delete delete=Delete


+ 3
- 3
options/locale/locale_zh-CN.ini View File

@@ -782,7 +782,7 @@ datasets=数据集
datasets.desc=数据集功能 datasets.desc=数据集功能
cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等 cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等


model_manager = 模型管理
model_manager = 模型
model_noright=无权限操作 model_noright=无权限操作


debug=调试 debug=调试
@@ -857,7 +857,7 @@ modelarts.train_job.description=任务描述
modelarts.train_job.parameter_setting=参数设置 modelarts.train_job.parameter_setting=参数设置
modelarts.train_job.parameter_setting_info=参数信息 modelarts.train_job.parameter_setting_info=参数信息
modelarts.train_job.fast_parameter_setting=一键式参数配置 modelarts.train_job.fast_parameter_setting=一键式参数配置
modelarts.train_job.fast_parameter_setting_config=如您已保存过参数配置,可单击
modelarts.train_job.fast_parameter_setting_config=如您已保存过参数配置,可单击
modelarts.train_job.fast_parameter_setting_config_link=这里 modelarts.train_job.fast_parameter_setting_config_link=这里
modelarts.train_job.frames=常用框架 modelarts.train_job.frames=常用框架
modelarts.train_job.algorithm_origin=算法来源 modelarts.train_job.algorithm_origin=算法来源
@@ -1987,7 +1987,7 @@ team_unit_desc=允许访问项目单元
team_unit_disabled=(已禁用) team_unit_disabled=(已禁用)


form.name_reserved=组织名称 '%s' 是被保留的。 form.name_reserved=组织名称 '%s' 是被保留的。
form.name_pattern_not_allowed=项目名称中不允许使用 "%s"。
form.name_pattern_not_allowed=组织名称中不允许使用 "%s"。
form.create_org_not_allowed=此账号禁止创建组织 form.create_org_not_allowed=此账号禁止创建组织


settings=组织设置 settings=组织设置


+ 1
- 0
public/img/member.svg View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="120" height="120"><path fill="none" d="M0 0h24v24H0z"/><path d="M20 22h-2v-2a3 3 0 0 0-3-3H9a3 3 0 0 0-3 3v2H4v-2a5 5 0 0 1 5-5h6a5 5 0 0 1 5 5v2zm-8-9a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8z" fill="rgba(0,0,0,0.4)"/></svg>

+ 1
- 0
public/img/pro_num.svg View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="120" height="120"><path fill="none" d="M0 0h24v24H0z"/><path d="M20 3l2 4v13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7.004L4 3h16zm0 6H4v10h16V9zm-8 1l4 4h-3v4h-2v-4H8l4-4zm6.764-5H5.236l-.999 2h15.527l-1-2z" fill="rgba(0,0,0,0.4)"/></svg>

+ 42
- 0
routers/home.go View File

@@ -7,6 +7,8 @@ package routers


import ( import (
"bytes" "bytes"
"fmt"
"io/ioutil"
"net/http" "net/http"
"strings" "strings"


@@ -511,3 +513,43 @@ func NotFound(ctx *context.Context) {
ctx.Data["Title"] = "Page Not Found" ctx.Data["Title"] = "Page Not Found"
ctx.NotFound("home.NotFound", nil) ctx.NotFound("home.NotFound", nil)
} }
func RecommendOrgFromPromote(ctx *context.Context) {
url := setting.RecommentRepoAddr + "organizations"
recommendFromPromote(ctx, url)
}

func recommendFromPromote(ctx *context.Context, url string) {
resp, err := http.Get(url)
if err != nil {
log.Info("Get organizations url error=" + err.Error())
ctx.ServerError("QueryTrainJobList:", err)
return
}
bytes, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
log.Info("Get organizations url error=" + err.Error())
ctx.ServerError("QueryTrainJobList:", err)
return
}

allLineStr := string(bytes)
lines := strings.Split(allLineStr, "\n")
result := make([]string, len(lines))
for i, line := range lines {

tmpIndex := strings.Index(line, ".")
log.Info("i=" + fmt.Sprint(i) + " line=" + line + " tmpIndex=" + fmt.Sprint(tmpIndex))
if tmpIndex == -1 {
result[i] = strings.Trim(line, " ")
} else {
result[i] = strings.Trim(line[tmpIndex+1:], " ")
}
}
ctx.JSON(http.StatusOK, result)
}

func RecommendRepoFromPromote(ctx *context.Context) {
url := setting.RecommentRepoAddr + "projects"
recommendFromPromote(ctx, url)
}

+ 43
- 9
routers/repo/ai_model_manage.go View File

@@ -28,7 +28,6 @@ const (


func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, ctx *context.Context) error { func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, ctx *context.Context) error {
aiTask, err := models.GetCloudbrainByJobIDAndVersionName(jobId, versionName) aiTask, err := models.GetCloudbrainByJobIDAndVersionName(jobId, versionName)
//aiTask, err := models.GetCloudbrainByJobID(jobId)
if err != nil { if err != nil {
log.Info("query task error." + err.Error()) log.Info("query task error." + err.Error())
return err return err
@@ -56,7 +55,7 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
cloudType = aiTask.Type cloudType = aiTask.Type
//download model zip //train type //download model zip //train type
if cloudType == models.TypeCloudBrainTwo { if cloudType == models.TypeCloudBrainTwo {
modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "")
modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl)
if err != nil { if err != nil {
log.Info("download model from CloudBrainTwo faild." + err.Error()) log.Info("download model from CloudBrainTwo faild." + err.Error())
return err return err
@@ -71,7 +70,6 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
log.Info("accuracyJson=" + string(accuracyJson)) log.Info("accuracyJson=" + string(accuracyJson))
aiTaskJson, _ := json.Marshal(aiTask) aiTaskJson, _ := json.Marshal(aiTask)


//taskConfigInfo,err := models.GetCloudbrainByJobIDAndVersionName(jobId,aiTask.VersionName)
model := &models.AiModelManage{ model := &models.AiModelManage{
ID: id, ID: id,
Version: version, Version: version,
@@ -86,7 +84,6 @@ func saveModelByParameters(jobId string, versionName string, name string, versio
AttachmentId: aiTask.Uuid, AttachmentId: aiTask.Uuid,
RepoId: aiTask.RepoID, RepoId: aiTask.RepoID,
UserId: ctx.User.ID, UserId: ctx.User.ID,
UserName: ctx.User.Name,
UserRelAvatarLink: ctx.User.RelAvatarLink(), UserRelAvatarLink: ctx.User.RelAvatarLink(),
CodeBranch: aiTask.BranchName, CodeBranch: aiTask.BranchName,
CodeCommitID: aiTask.CommitID, CodeCommitID: aiTask.CommitID,
@@ -144,9 +141,12 @@ func SaveModel(ctx *context.Context) {
log.Info("save model end.") log.Info("save model end.")
} }


func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir string) (string, int64, error) {

func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir string, trainUrl string) (string, int64, error) {
objectkey := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/") objectkey := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/")
if trainUrl != "" {
objectkey = strings.Trim(trainUrl[len(setting.Bucket)+1:], "/")
}

modelDbResult, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, objectkey, "") modelDbResult, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, objectkey, "")
log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey) log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey)
if err != nil { if err != nil {
@@ -395,15 +395,42 @@ func ShowSingleModel(ctx *context.Context) {
ctx.JSON(http.StatusOK, models) ctx.JSON(http.StatusOK, models)
} }


func queryUserName(intSlice []int64) map[int64]string {
keys := make(map[int64]string)
uniqueElements := []int64{}
for _, entry := range intSlice {
if _, value := keys[entry]; !value {
keys[entry] = ""
uniqueElements = append(uniqueElements, entry)
}
}
userNames, err := models.GetUserNamesByIDs(uniqueElements)
if err == nil {
for i, userName := range userNames {
keys[uniqueElements[i]] = userName
}
}
return keys
}

func ShowOneVersionOtherModel(ctx *context.Context) { func ShowOneVersionOtherModel(ctx *context.Context) {
repoId := ctx.Repo.Repository.ID repoId := ctx.Repo.Repository.ID
name := ctx.Query("name") name := ctx.Query("name")
aimodels := models.QueryModelByName(name, repoId) aimodels := models.QueryModelByName(name, repoId)
for _, model := range aimodels {

userIds := make([]int64, len(aimodels))
for i, model := range aimodels {
log.Info("model=" + model.Name) log.Info("model=" + model.Name)
log.Info("model.UserId=" + fmt.Sprint(model.UserId)) log.Info("model.UserId=" + fmt.Sprint(model.UserId))
model.IsCanOper = isOper(ctx, model.UserId) model.IsCanOper = isOper(ctx, model.UserId)
userIds[i] = model.UserId
}
userNameMap := queryUserName(userIds)

for _, model := range aimodels {
model.UserName = userNameMap[model.UserId]
} }

if len(aimodels) > 0 { if len(aimodels) > 0 {
ctx.JSON(200, aimodels[1:]) ctx.JSON(200, aimodels[1:])
} else { } else {
@@ -431,7 +458,7 @@ func isOper(ctx *context.Context, modelUserId int64) bool {
if ctx.User == nil { if ctx.User == nil {
return false return false
} }
if ctx.User.IsAdmin || ctx.Repo.IsAdmin() || ctx.Repo.IsOwner() || ctx.User.ID == modelUserId {
if ctx.User.IsAdmin || ctx.Repo.IsOwner() || ctx.User.ID == modelUserId {
return true return true
} }
return false return false
@@ -463,10 +490,17 @@ func ShowModelPageInfo(ctx *context.Context) {
return return
} }


for _, model := range modelResult {
userIds := make([]int64, len(modelResult))
for i, model := range modelResult {
log.Info("model=" + model.Name) log.Info("model=" + model.Name)
log.Info("model.UserId=" + fmt.Sprint(model.UserId)) log.Info("model.UserId=" + fmt.Sprint(model.UserId))
model.IsCanOper = isOper(ctx, model.UserId) model.IsCanOper = isOper(ctx, model.UserId)
userIds[i] = model.UserId
}

userNameMap := queryUserName(userIds)
for _, model := range modelResult {
model.UserName = userNameMap[model.UserId]
} }


mapInterface := make(map[string]interface{}) mapInterface := make(map[string]interface{})


+ 65
- 28
routers/repo/cloudbrain.go View File

@@ -8,7 +8,6 @@ import (
"io" "io"
"net/http" "net/http"
"os" "os"
"os/exec"
"regexp" "regexp"
"sort" "sort"
"strconv" "strconv"
@@ -71,15 +70,9 @@ func CloudBrainIndex(ctx *context.Context) {
return return
} }


timestamp := time.Now().Unix()
for i, task := range ciTasks { for i, task := range ciTasks {
if task.Status == string(models.JobRunning) && (timestamp-int64(task.Cloudbrain.CreatedUnix) > 10) {
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
} else {
ciTasks[i].CanDebug = false
}

ciTasks[i].CanDel = cloudbrain.CanDeleteDebugJob(ctx, &task.Cloudbrain)
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)


} }


@@ -251,13 +244,9 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
downloadCode(repo, codePath) downloadCode(repo, codePath)
uploadCodeToMinio(codePath + "/", jobName, "/code/") uploadCodeToMinio(codePath + "/", jobName, "/code/")


modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath
err = os.MkdirAll(modelPath, os.ModePerm)
if err != nil {
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form)
return
}
modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath + "/"
mkModelPath(modelPath)
uploadCodeToMinio(modelPath, jobName, cloudbrain.ModelMountPath + "/")


benchmarkPath := setting.JobPath + jobName + cloudbrain.BenchMarkMountPath benchmarkPath := setting.JobPath + jobName + cloudbrain.BenchMarkMountPath
if setting.IsBenchmarkEnabled && jobType == string(models.JobTypeBenchmark) { if setting.IsBenchmarkEnabled && jobType == string(models.JobTypeBenchmark) {
@@ -267,23 +256,25 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
gpuType = gpuInfo.Value gpuType = gpuInfo.Value
} }
} }
downloadRateCode(repo, jobName, setting.BenchmarkCode, benchmarkPath, form.BenchmarkCategory, gpuType)
downloadRateCode(repo, jobName, setting.BenchmarkOwner, setting.BrainScoreName, benchmarkPath, form.BenchmarkCategory, gpuType)
uploadCodeToMinio(benchmarkPath + "/", jobName, cloudbrain.BenchMarkMountPath + "/") uploadCodeToMinio(benchmarkPath + "/", jobName, cloudbrain.BenchMarkMountPath + "/")
} }


snn4imagenetPath := setting.JobPath + jobName + cloudbrain.Snn4imagenetMountPath snn4imagenetPath := setting.JobPath + jobName + cloudbrain.Snn4imagenetMountPath
if setting.IsSnn4imagenetEnabled && jobType == string(models.JobTypeSnn4imagenet) { if setting.IsSnn4imagenetEnabled && jobType == string(models.JobTypeSnn4imagenet) {
downloadRateCode(repo, jobName, setting.Snn4imagenetCode, snn4imagenetPath, "", "")
downloadRateCode(repo, jobName, setting.Snn4imagenetOwner, setting.Snn4imagenetName, snn4imagenetPath, "", "")
uploadCodeToMinio(snn4imagenetPath + "/", jobName, cloudbrain.Snn4imagenetMountPath + "/") uploadCodeToMinio(snn4imagenetPath + "/", jobName, cloudbrain.Snn4imagenetMountPath + "/")
} }


brainScorePath := setting.JobPath + jobName + cloudbrain.BrainScoreMountPath brainScorePath := setting.JobPath + jobName + cloudbrain.BrainScoreMountPath
if setting.IsBrainScoreEnabled && jobType == string(models.JobTypeBrainScore) { if setting.IsBrainScoreEnabled && jobType == string(models.JobTypeBrainScore) {
downloadRateCode(repo, jobName, setting.BrainScoreCode, brainScorePath, "", "")
downloadRateCode(repo, jobName, setting.BrainScoreOwner, setting.BrainScoreName, brainScorePath, "", "")
uploadCodeToMinio(brainScorePath + "/", jobName, cloudbrain.BrainScoreMountPath + "/") uploadCodeToMinio(brainScorePath + "/", jobName, cloudbrain.BrainScoreMountPath + "/")
} }


err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue, resourceSpecId)
err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, getMinioPath(jobName, cloudbrain.ModelMountPath + "/"),
getMinioPath(jobName, cloudbrain.BenchMarkMountPath + "/"), getMinioPath(jobName, cloudbrain.Snn4imagenetMountPath + "/"),
getMinioPath(jobName, cloudbrain.BrainScoreMountPath + "/"), jobType, gpuQueue, resourceSpecId)
if err != nil { if err != nil {
cloudBrainNewDataPrepare(ctx) cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form)
@@ -607,7 +598,7 @@ func getImages(ctx *context.Context, imageType string) {


func GetModelDirs(jobName string, parentDir string) (string, error) { func GetModelDirs(jobName string, parentDir string) (string, error) {
var req string var req string
modelActualPath := setting.JobPath + jobName + "/model/"
modelActualPath := getMinioPath(jobName, cloudbrain.ModelMountPath + "/")
if parentDir == "" { if parentDir == "" {
req = "baseDir=" + modelActualPath req = "baseDir=" + modelActualPath
} else { } else {
@@ -617,6 +608,10 @@ func GetModelDirs(jobName string, parentDir string) (string, error) {
return getDirs(req) return getDirs(req)
} }


func getMinioPath(jobName, suffixPath string) string {
return setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + jobName + suffixPath
}

func CloudBrainDownloadModel(ctx *context.Context) { func CloudBrainDownloadModel(ctx *context.Context) {
parentDir := ctx.Query("parentDir") parentDir := ctx.Query("parentDir")
fileName := ctx.Query("fileName") fileName := ctx.Query("fileName")
@@ -698,19 +693,21 @@ func downloadCode(repo *models.Repository, codePath string) error {
return nil return nil
} }


func downloadRateCode(repo *models.Repository, taskName, gitPath, codePath, benchmarkCategory, gpuType string) error {
func downloadRateCode(repo *models.Repository, taskName, rateOwnerName, rateRepoName, codePath, benchmarkCategory, gpuType string) error {
err := os.MkdirAll(codePath, os.ModePerm) err := os.MkdirAll(codePath, os.ModePerm)
if err != nil { if err != nil {
log.Error("mkdir codePath failed", err.Error()) log.Error("mkdir codePath failed", err.Error())
return err return err
} }


command := "git clone " + gitPath + " " + codePath
cmd := exec.Command("/bin/bash", "-c", command)
_, err = cmd.Output()

repoExt, err := models.GetRepositoryByOwnerAndName(rateOwnerName, rateRepoName)
if err != nil { if err != nil {
log.Error("exec.Command(%s) failed:%v", command, err)
log.Error("GetRepositoryByOwnerAndName(%s) failed", rateRepoName, err.Error())
return err
}

if err := git.Clone(repoExt.RepoPath(), codePath, git.CloneRepoOptions{}); err != nil {
log.Error("Failed to clone repository: %s (%v)", repoExt.FullName(), err)
return err return err
} }


@@ -772,6 +769,32 @@ func uploadCodeToMinio(codePath, jobName, parentDir string) error {
return nil return nil
} }


func mkModelPath(modelPath string) error {
err := os.MkdirAll(modelPath, os.ModePerm)
if err != nil {
log.Error("MkdirAll(%s) failed:%v", modelPath, err)
return err
}

fileName := modelPath + "README"
f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm)
if err != nil {
log.Error("OpenFile failed", err.Error())
return err
}

defer f.Close()

_, err = f.WriteString("You can put the model file into this directory and download it by the web page.")
if err != nil {
log.Error("WriteString failed", err.Error())
return err
}

return nil
}


func SyncCloudbrainStatus() { func SyncCloudbrainStatus() {
cloudBrains, err := models.GetCloudBrainUnStoppedJob() cloudBrains, err := models.GetCloudBrainUnStoppedJob()
if err != nil { if err != nil {
@@ -793,10 +816,24 @@ func SyncCloudbrainStatus() {
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{}))
task.Status = taskRes.TaskStatuses[0].State task.Status = taskRes.TaskStatuses[0].State
if task.Status != string(models.JobWaiting) { if task.Status != string(models.JobWaiting) {
task.Duration = time.Now().Unix() - taskRes.TaskStatuses[0].StartAt.Unix()
err = models.UpdateJob(task) err = models.UpdateJob(task)
if err != nil { if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err) log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
continue
}

if task.Duration >= setting.MaxDuration {
log.Info("begin to stop job(%s), because of the duration", task.JobName)
err = cloudbrain.StopJob(task.JobID)
if err != nil {
log.Error("StopJob(%s) failed:%v", task.JobName, err)
continue
}
task.Status = string(models.JobStopped)
err = models.UpdateJob(task)
if err != nil {
log.Error("UpdateJob(%s) failed:%v", task.JobName, err)
}
} }
} }
} }


+ 4
- 7
routers/repo/modelarts.go View File

@@ -69,12 +69,9 @@ func NotebookIndex(ctx *context.Context) {
} }


for i, task := range ciTasks { for i, task := range ciTasks {
if task.Status == string(models.JobRunning) {
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
} else {
ciTasks[i].CanDebug = false
}
ciTasks[i].CanDel = cloudbrain.CanDeleteDebugJob(ctx, &task.Cloudbrain)

ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
} }


pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5)
@@ -306,7 +303,7 @@ func TrainJobIndex(ctx *context.Context) {
} }


for i, task := range tasks { for i, task := range tasks {
tasks[i].CanDel = cloudbrain.CanDeleteTrainJob(ctx, &task.Cloudbrain)
tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain) tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain)
} }




+ 1
- 0
routers/repo/repo.go View File

@@ -532,6 +532,7 @@ func Download(ctx *context.Context) {
} }


ctx.Repo.Repository.IncreaseCloneCnt() ctx.Repo.Repository.IncreaseCloneCnt()
ctx.Repo.Repository.IncreaseGitCloneCnt()


ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+refName+ext) ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+refName+ext)
} }


+ 3
- 9
routers/repo/user_data_analysis.go View File

@@ -148,11 +148,6 @@ func QueryUserStaticDataPage(ctx *context.Context) {


func TimingCountDataByDateAndReCount(date string, isReCount bool) { func TimingCountDataByDateAndReCount(date string, isReCount bool) {


if date == "refreshAll" {
models.RefreshUserStaticAllTabel()
return
}

t, _ := time.Parse("2006-01-02", date) t, _ := time.Parse("2006-01-02", date)
startTime := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) startTime := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())


@@ -205,10 +200,9 @@ func TimingCountDataByDateAndReCount(date string, isReCount bool) {
log.Error("count user info error." + err.Error()) log.Error("count user info error." + err.Error())
mailer.SendWarnNotifyMail(setting.Warn_Notify_Mails, warnEmailMessage) mailer.SendWarnNotifyMail(setting.Warn_Notify_Mails, warnEmailMessage)
} }

if isReCount {
models.RefreshUserStaticAllTabel()
}
log.Info("start to count all user info data")
//models.RefreshUserStaticAllTabel(wikiMap)
log.Info("end to count all user info data")
} }


func TimingCountDataByDate(date string) { func TimingCountDataByDate(date string) {


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

@@ -315,6 +315,8 @@ func RegisterRoutes(m *macaron.Macaron) {
}) })
m.Get("/", routers.Home) m.Get("/", routers.Home)
m.Get("/dashboard", routers.Dashboard) m.Get("/dashboard", routers.Dashboard)
m.Get("/recommend/org", routers.RecommendOrgFromPromote)
m.Get("/recommend/repo", routers.RecommendRepoFromPromote)
m.Group("/explore", func() { m.Group("/explore", func() {
m.Get("", func(ctx *context.Context) { m.Get("", func(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/explore/repos") ctx.Redirect(setting.AppSubURL + "/explore/repos")


+ 5
- 0
routers/user/profile.go View File

@@ -214,10 +214,15 @@ func Profile(ctx *context.Context) {


total = int(count) total = int(count)
case "datasets": case "datasets":
var isOwner = false
if ctx.User != nil && ctx.User.ID == ctxUser.ID {
isOwner = true
}
datasetSearchOptions := &models.SearchDatasetOptions{ datasetSearchOptions := &models.SearchDatasetOptions{
Keyword: keyword, Keyword: keyword,
OwnerID: ctxUser.ID, OwnerID: ctxUser.ID,
SearchOrderBy: orderBy, SearchOrderBy: orderBy,
IsOwner: isOwner,
ListOptions: models.ListOptions{ ListOptions: models.ListOptions{
Page: page, Page: page,
PageSize: setting.UI.ExplorePagingNum, PageSize: setting.UI.ExplorePagingNum,


+ 6
- 5
templates/base/head_navbar.tmpl View File

@@ -17,7 +17,7 @@


{{if .IsSigned}} {{if .IsSigned}}
<div class=" item" >
<div class=" item edge">
<div class="dropdown-menu"> <div class="dropdown-menu">
<a class=" item" href="/dashboard"> <a class=" item" href="/dashboard">
<span > {{.i18n.Tr "index"}} &nbsp <i class="dropdown icon"></i></span> <span > {{.i18n.Tr "index"}} &nbsp <i class="dropdown icon"></i></span>
@@ -47,7 +47,7 @@
</div> </div>
</div> </div>
{{else if .IsLandingPageHome}} {{else if .IsLandingPageHome}}
<div class=" item">
<div class="item edge">
<div class="dropdown-menu"> <div class="dropdown-menu">
<a class=" item" href="/user/login"> <a class=" item" href="/user/login">
<span > {{.i18n.Tr "home"}} &nbsp <i class="dropdown icon"></i></span> <span > {{.i18n.Tr "home"}} &nbsp <i class="dropdown icon"></i></span>
@@ -94,13 +94,13 @@
*/}} */}}


{{if .IsSigned}} {{if .IsSigned}}
<div class="right stackable menu">
<div class="right stackable menu">
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
<input type="hidden" name="tab" value="{{$.TabName}}"> <input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="{{$.SortType}}">
<input type="hidden" name="sort" value="hot">
<button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" >
</button> </button>
<!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> <!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> -->
@@ -190,12 +190,13 @@


<!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> <!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a-->
<div class="right stackable menu"> <div class="right stackable menu">
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> <div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
<input type="hidden" name="tab" value="{{$.TabName}}"> <input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="{{$.SortType}}">
<input type="hidden" name="sort" value="hot">
<button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > <button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" >
</button> </button>
<!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> <!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> -->


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

@@ -17,7 +17,7 @@


{{if .IsSigned}} {{if .IsSigned}}
<div class="item" >
<div class="item edge" >
<div class="dropdown-menu"> <div class="dropdown-menu">
<a class=" item" href="/dashboard"> <a class=" item" href="/dashboard">
<span > {{.i18n.Tr "index"}} &nbsp <i class="dropdown icon"></i></span> <span > {{.i18n.Tr "index"}} &nbsp <i class="dropdown icon"></i></span>
@@ -46,7 +46,7 @@
</div> </div>
</div> </div>
{{else if .IsLandingPageHome}} {{else if .IsLandingPageHome}}
<div class="item" >
<div class="item edge" >
<div class="dropdown-menu"> <div class="dropdown-menu">
<a class=" item" href="/user/login"> <a class=" item" href="/user/login">
<span > {{.i18n.Tr "home"}} &nbsp <i class="dropdown icon"></i></span> <span > {{.i18n.Tr "home"}} &nbsp <i class="dropdown icon"></i></span>


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

@@ -9,7 +9,7 @@
</div> </div>


{{if .IsSigned}} {{if .IsSigned}}
<div class="item" >
<div class="item edge" >
<div class="dropdown-menu"> <div class="dropdown-menu">
<a class=" item" href="/dashboard"> <a class=" item" href="/dashboard">
<span > {{.i18n.Tr "index"}} &nbsp <i class="dropdown icon"></i></span> <span > {{.i18n.Tr "index"}} &nbsp <i class="dropdown icon"></i></span>
@@ -38,7 +38,7 @@
</div> </div>
</div> </div>
{{else if .IsLandingPageHome}} {{else if .IsLandingPageHome}}
<div class="item" >
<div class="item edge" >
<div class="dropdown-menu"> <div class="dropdown-menu">
<a class=" item" href="/user/login"> <a class=" item" href="/user/login">
<span > {{.i18n.Tr "home"}} &nbsp <i class="dropdown icon"></i></span> <span > {{.i18n.Tr "home"}} &nbsp <i class="dropdown icon"></i></span>


+ 216
- 0
templates/base/head_navbar_pro.tmpl View File

@@ -0,0 +1,216 @@
<div class="ui container" id="navbar">
<div class="item brand" style="justify-content: space-between;">
<a href="https://openi.org.cn/">
<img class="ui mini image" src="{{StaticUrlPrefix}}/img/logo-w.svg">
</a>
<div class="ui basic icon button mobile-only" id="navbar-expand-toggle">
<i class="sidebar icon"></i>
</div>
</div>
<div style="width:1px;background:#606266;height:80%;margin:auto 0.5rem"></div>
<div class="item brand" style="margin-left: 0.9rem;">
<a href="/">
<img class="ui mini image" style="height: 1.3rem;" src="{{StaticUrlPrefix}}/img/git-logo.svg">
</a>
</div>


{{if .IsSigned}}
<div class=" item edge" >
<div class="dropdown-menu">
<a class=" item" href="/dashboard">
<span > {{.i18n.Tr "index"}} &nbsp <i class="dropdown icon"></i></span>
</a>
<div class="dropdown-content" style="min-width: 110px;border-radius:4px">
<a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a>
<a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a>
<a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a>
</div>
</div>
</div>

<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a>
<div class="ui dropdown item" id='dropdown_explore'>
{{.i18n.Tr "explore"}}
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
{{if .IsOperator}}
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a>
{{end}}
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a>
</div>
</div>
{{else if .IsLandingPageHome}}
<div class="item edge">
<div class="dropdown-menu">
<a class=" item" href="/user/login">
<span > {{.i18n.Tr "home"}} &nbsp <i class="dropdown icon"></i></span>
</a>
<div class="dropdown-content" style="min-width: 110px;border-radius:4px">
<a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a>
<a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a>
<a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a>
</div>
</div>
</div>

<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a>
<div class="ui dropdown item" id='dropdown_PageHome'>
{{.i18n.Tr "explore"}}
<i class="dropdown icon"></i>
<div class="menu" >
<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a>
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a>
{{if .IsOperator}}
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a>
{{end}}
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a>
</div>
</div>
{{else if .IsLandingPageExplore}}
<a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "home"}}</a>
{{else if .IsLandingPageOrganizations}}
<a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "home"}}</a>
{{end}}

{{template "custom/extra_links" .}}

{{/*
<div class="item">
<div class="ui icon input">
<input class="searchbox" type="text" placeholder="{{.i18n.Tr "search_project"}}">
<i class="search icon"></i>
</div>
</div>
*/}}

{{if .IsSigned}}
<div class="right stackable menu">
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
<input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="{{$.SortType}}">
<button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" >
</button>
<!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> -->
</div>
</form>
<a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted">
<span class="text">
<span class="fitted">{{svg "octicon-bell" 16}}</span>
<span class="sr-mobile-only">{{.i18n.Tr "notifications"}}</span>
{{$notificationUnreadCount := 0}}
{{if .NotificationUnreadCount}}{{$notificationUnreadCount = call .NotificationUnreadCount}}{{end}}
<span class="ui red label {{if not $notificationUnreadCount}}hidden{{end}} notification_count">
{{$notificationUnreadCount}}
</span>
</span>
</a>

<div class="ui dropdown jump item poping up" data-content="{{.i18n.Tr "create_new"}}" data-variation="tiny inverted">
<span class="text">
<span class="fitted">{{svg "octicon-plus" 16}}</span>
<span class="sr-mobile-only">{{.i18n.Tr "create_new"}}</span>
<span class="fitted not-mobile">{{svg "octicon-triangle-down" 16}}</span>
</span>
<div class="menu">
<a class="item" href="{{AppSubUrl}}/repo/create">
<span class="fitted">{{svg "octicon-plus" 16}}</span> {{.i18n.Tr "new_repo"}}
</a>
<a class="item" href="{{AppSubUrl}}/repo/migrate">
<span class="fitted">{{svg "octicon-repo-clone" 16}}</span> {{.i18n.Tr "new_migrate"}}
</a>
{{if .SignedUser.CanCreateOrganization}}
<a class="item" href="{{AppSubUrl}}/org/create">
<span class="fitted">{{svg "octicon-organization" 16}}</span> {{.i18n.Tr "new_org"}}
</a>
{{end}}
</div><!-- end content create new menu -->
</div><!-- end dropdown menu create new -->

<div class="ui dropdown jump item poping up" tabindex="-1" data-content="{{.i18n.Tr "user_profile_and_more"}}" data-variation="tiny inverted">
<span class="text">
<img class="ui tiny avatar image" width="24" height="24" src="{{.SignedUser.RelAvatarLink}}">
<span class="sr-only">{{.i18n.Tr "user_profile_and_more"}}</span>
<span class="mobile-only">{{.SignedUser.Name}}</span>
<span class="fitted not-mobile" tabindex="-1">{{svg "octicon-triangle-down" 16}}</span>
</span>
<div class="menu user-menu" tabindex="-1">
<div class="ui header">
{{.i18n.Tr "signed_in_as"}} <strong>{{.SignedUser.Name}}</strong>
</div>

<div class="divider"></div>
<a class="item" href="{{AppSubUrl}}/{{.SignedUser.Name}}">
{{svg "octicon-person" 16}}
{{.i18n.Tr "your_profile"}}<!-- Your profile -->
</a>
<a class="item" href="{{AppSubUrl}}/{{.SignedUser.Name}}?tab=stars">
{{svg "octicon-star" 16}}
{{.i18n.Tr "your_starred"}}
</a>
<a class="{{if .PageIsUserSettings}}active{{end}} item" href="{{AppSubUrl}}/user/settings">
{{svg "octicon-settings" 16}}
{{.i18n.Tr "your_settings"}}<!-- Your settings -->
</a>
<!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">
{{svg "octicon-question" 16}}
{{.i18n.Tr "help"}}<!-- Help -->
</a-->
{{if .IsAdmin}}
<div class="divider"></div>

<a class="{{if .PageIsAdmin}}active{{end}} item" href="{{AppSubUrl}}/admin">
<i class="icon settings"></i>
{{.i18n.Tr "admin_panel"}}<!-- Admin Panel -->
</a>
{{end}}

<div class="divider"></div>
<a class="item link-action" href data-url="{{AppSubUrl}}/user/logout" data-redirect="{{AppSubUrl}}/">
{{svg "octicon-sign-out" 16}}
{{.i18n.Tr "sign_out"}}<!-- Sign Out -->
</a>
</div><!-- end content avatar menu -->
</div><!-- end dropdown avatar menu -->
</div><!-- end signed user right menu -->

{{else}}

<!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a-->
<div class="right stackable menu">
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos">
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..."
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;">
<input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="{{$.SortType}}">
<button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" >
</button>
<!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> -->
</div>
</form>
{{if .ShowRegistrationButton}}
<a class="item{{if .PageIsSignUp}} active{{end}}" href="{{AppSubUrl}}/user/sign_up">
{{svg "octicon-person" 16}} {{.i18n.Tr "register"}}
</a>
{{end}}
<a class="item{{if .PageIsSignIn}} active{{end}}" rel="nofollow" href="{{AppSubUrl}}/user/login">
{{svg "octicon-sign-in" 16}} {{.i18n.Tr "sign_in"}}
</a>
</div><!-- end anonymous right menu -->

{{end}}
</div>

+ 208
- 0
templates/base/head_pro.tmpl View File

@@ -0,0 +1,208 @@
<!DOCTYPE html>
<html lang="{{.Language}}">
<head data-suburl="{{AppSubUrl}}">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>{{if .Title}}{{.Title}} - {{end}} {{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title>
<link rel="manifest" href="{{AppSubUrl}}/manifest.json" crossorigin="use-credentials">
{{if UseServiceWorker}}
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('{{AppSubUrl}}/serviceworker.js').then(function(registration) {
// Registration was successful
console.info('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
// registration failed :(
console.info('ServiceWorker registration failed: ', err);
});
}
</script>
{{else}}
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations().then(function(registrations) {
registrations.forEach(function(registration) {
registration.unregister();
console.info('ServiceWorker unregistered');
});
});
}
</script>
{{end}}
<meta name="theme-color" content="{{ThemeColorMetaTag}}">
<meta name="author" content="{{if .Repository}}{{.Owner.Name}}{{else}}{{MetaAuthor}}{{end}}" />
<meta name="description" content="{{if .Repository}}{{.Repository.Name}}{{if .Repository.Description}} - {{.Repository.Description}}{{end}}{{else}}{{MetaDescription}}{{end}}" />
<meta name="keywords" content="{{MetaKeywords}}">
<meta name="referrer" content="no-referrer" />
<meta name="_csrf" content="{{.CsrfToken}}" />
{{if .IsSigned}}
<meta name="_uid" content="{{.SignedUser.ID}}" />
{{end}}
{{if .ContextUser}}
<meta name="_context_uid" content="{{.ContextUser.ID}}" />
{{end}}
{{if .SearchLimit}}
<meta name="_search_limit" content="{{.SearchLimit}}" />
{{end}}
{{if .GoGetImport}}
<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">
<meta name="go-source" content="{{.GoGetImport}} _ {{.GoDocDirectory}} {{.GoDocFile}}">
{{end}}
<script>
{{SafeJS `/*
@licstart The following is the entire license notice for the
JavaScript code in this page.

Copyright (c) 2016 The Gitea Authors
Copyright (c) 2015 The Gogs Authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---
Licensing information for additional javascript libraries can be found at:
{{StaticUrlPrefix}}/vendor/librejs.html

@licend The above is the entire license notice
for the JavaScript code in this page.
*/`}}
</script>
<script>
window.config = {
AppSubUrl: '{{AppSubUrl}}',
StaticUrlPrefix: '{{StaticUrlPrefix}}',
csrf: '{{.CsrfToken}}',
HighlightJS: {{if .RequireHighlightJS}}true{{else}}false{{end}},
Minicolors: {{if .RequireMinicolors}}true{{else}}false{{end}},
SimpleMDE: {{if .RequireSimpleMDE}}true{{else}}false{{end}},
Tribute: {{if .RequireTribute}}true{{else}}false{{end}},
U2F: {{if .RequireU2F}}true{{else}}false{{end}},
Heatmap: {{if .EnableHeatmap}}true{{else}}false{{end}},
heatmapUser: {{if .HeatmapUser}}'{{.HeatmapUser}}'{{else}}null{{end}},
NotificationSettings: {
MinTimeout: {{NotificationSettings.MinTimeout}},
TimeoutStep: {{NotificationSettings.TimeoutStep}},
MaxTimeout: {{NotificationSettings.MaxTimeout}},
EventSourceUpdateTime: {{NotificationSettings.EventSourceUpdateTime}},
},
{{if .RequireTribute}}
tributeValues: [
{{ range .Assignees }}
{key: '{{.Name}} {{.FullName}}', value: '{{.Name}}',
name: '{{.Name}}', fullname: '{{.FullName}}', avatar: '{{.RelAvatarLink}}'},
{{ end }}
],
{{end}}
};
</script>
<link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png">
<link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926">
<link rel="fluid-icon" href="{{StaticUrlPrefix}}/img/gitea-lg.png" title="{{AppName}}">
<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/assets/font-awesome/css/font-awesome.min.css">
<link rel="preload" as="font" href="{{StaticUrlPrefix}}/fomantic/themes/default/assets/fonts/icons.woff2" type="font/woff2" crossorigin="anonymous">
<link rel="preload" as="font" href="{{StaticUrlPrefix}}/fomantic/themes/default/assets/fonts/outline-icons.woff2" type="font/woff2" crossorigin="anonymous">
{{if .RequireSimpleMDE}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.css">
{{end}}

{{if .RequireTribute}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/tribute/tribute.css">
{{end}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/fomantic/semantic.min.css?v={{MD5 AppVer}}">
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/index.css?v={{MD5 AppVer}}">
<noscript>
<style>
.dropdown:hover > .menu { display: block; }
.ui.secondary.menu .dropdown.item > .menu { margin-top: 0; }
</style>
</noscript>
{{if .RequireMinicolors}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/jquery.minicolors/jquery.minicolors.css">
{{end}}
<style class="list-search-style"></style>
{{if .PageIsUserProfile}}
<meta property="og:title" content="{{.Owner.Name}}" />
<meta property="og:type" content="profile" />
<meta property="og:image" content="{{.Owner.AvatarLink}}" />
<meta property="og:url" content="{{.Owner.HTMLURL}}" />
{{if .Owner.Description}}
<meta property="og:description" content="{{.Owner.Description}}">
{{end}}
{{else if .Repository}}
{{if .Issue}}
<meta property="og:title" content="{{.Issue.Title}}" />
<meta property="og:url" content="{{.Issue.HTMLURL}}" />
{{if .Issue.Content}}
<meta property="og:description" content="{{.Issue.Content}}" />
{{end}}
{{else}}
<meta property="og:title" content="{{.Repository.Name}}" />
<meta property="og:url" content="{{.Repository.HTMLURL}}" />
{{if .Repository.Description}}
<meta property="og:description" content="{{.Repository.Description}}" />
{{end}}
{{end}}
<meta property="og:type" content="object" />
<meta property="og:image" content="{{.Repository.Owner.AvatarLink}}" />
{{else}}
<meta property="og:title" content="{{AppName}}">
<meta property="og:type" content="website" />
<meta property="og:image" content="{{StaticUrlPrefix}}/img/gitea-lg.png" />
<meta property="og:url" content="{{AppUrl}}" />
<meta property="og:description" content="{{MetaDescription}}">
{{end}}
<meta property="og:site_name" content="{{AppName}}" />
{{if .IsSigned }}
{{ if ne .SignedUser.Theme "gitea" }}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/theme-{{.SignedUser.Theme}}.css?v={{MD5 AppVer}}">
{{end}}
{{else if ne DefaultTheme "gitea"}}
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/theme-{{DefaultTheme}}.css?v={{MD5 AppVer}}">
{{end}}
{{template "custom/header" .}}

<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<script src="/self/func.js" type="text/javascript"></script>

</head>
<body>
{{template "custom/body_outer_pre" .}}

<div class="full height">
<noscript>{{.i18n.Tr "enable_javascript"}}</noscript>

{{template "custom/body_inner_pre" .}}

{{if not .PageIsInstall}}
<div class="ui top secondary stackable main menu following bar dark">
{{template "base/head_navbar_pro" .}}
</div><!-- end bar -->
{{end}}
{{/*
</div>
</body>
</html>
*/}}

+ 1
- 1
templates/explore/repos.tmpl View File

@@ -1,4 +1,4 @@
{{template "base/head" .}}
{{template "base/head_pro" .}}
<div class="explore repositories"> <div class="explore repositories">


{{template "explore/repo_search" .}} {{template "explore/repo_search" .}}


+ 7
- 2
templates/repo/header.tmpl View File

@@ -134,7 +134,8 @@


{{if .Permission.CanRead $.UnitTypeDatasets}} {{if .Permission.CanRead $.UnitTypeDatasets}}
<a class="{{if .PageIsDataset}}active{{end}} item" href="{{.RepoLink}}/datasets?type=0"> <a class="{{if .PageIsDataset}}active{{end}} item" href="{{.RepoLink}}/datasets?type=0">
{{svg "octicon-inbox" 16}} {{.i18n.Tr "datasets"}}
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M20.083 15.2l1.202.721a.5.5 0 0 1 0 .858l-8.77 5.262a1 1 0 0 1-1.03 0l-8.77-5.262a.5.5 0 0 1 0-.858l1.202-.721L12 20.05l8.083-4.85zm0-4.7l1.202.721a.5.5 0 0 1 0 .858L12 17.65l-9.285-5.571a.5.5 0 0 1 0-.858l1.202-.721L12 15.35l8.083-4.85zm-7.569-9.191l8.771 5.262a.5.5 0 0 1 0 .858L12 13 2.715 7.429a.5.5 0 0 1 0-.858l8.77-5.262a1 1 0 0 1 1.03 0zM12 3.332L5.887 7 12 10.668 18.113 7 12 3.332z"/></svg>
{{.i18n.Tr "datasets"}}
</a> </a>
{{end}} {{end}}
{{if .Permission.CanRead $.UnitTypeModelManage}} {{if .Permission.CanRead $.UnitTypeModelManage}}
@@ -145,7 +146,11 @@
{{end}} {{end}}
{{if .Permission.CanRead $.UnitTypeCloudBrain}} {{if .Permission.CanRead $.UnitTypeCloudBrain}}
<a class="{{if .PageIsCloudBrain}}active{{end}} item" href="{{.RepoLink}}/cloudbrain"> <a class="{{if .PageIsCloudBrain}}active{{end}} item" href="{{.RepoLink}}/cloudbrain">
<span>{{svg "octicon-server" 16}} {{.i18n.Tr "repo.cloudbrain"}}<i class="question circle icon link cloudbrain-question" data-content={{.i18n.Tr "repo.cloudbrain_helper"}} data-position="top center" data-variation="mini"></i></span>
<span>
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"/></svg>
{{.i18n.Tr "repo.cloudbrain"}}
<i class="question circle icon link cloudbrain-question" data-content={{.i18n.Tr "repo.cloudbrain_helper"}} data-position="top center" data-variation="mini"></i>
</span>
</a> </a>
{{end}} {{end}}
<!-- {{if .IsSigned}} <!-- {{if .IsSigned}}


+ 8
- 9
templates/repo/settings/options.tmpl View File

@@ -149,15 +149,6 @@
<label>{{.i18n.Tr "repo.settings.dataset_desc"}}</label> <label>{{.i18n.Tr "repo.settings.dataset_desc"}}</label>
</div> </div>
</div> </div>

{{$isCloudBrainEnabled := .Repository.UnitEnabled $.UnitTypeCloudBrain }}
<div class="inline field">
<label>{{.i18n.Tr "repo.cloudbrain"}}</label>
<div class="ui checkbox">
<input class="enable-system" name="enable_cloud_brain" type="checkbox" {{if $isCloudBrainEnabled}}checked{{end}}>
<label>{{.i18n.Tr "repo.settings.cloudbrain_desc"}}</label>
</div>
</div>
{{$isModelMangeEnabled := .Repository.UnitEnabled $.UnitTypeModelManage }} {{$isModelMangeEnabled := .Repository.UnitEnabled $.UnitTypeModelManage }}
<div class="inline field"> <div class="inline field">
<label>{{.i18n.Tr "repo.model_manager"}}</label> <label>{{.i18n.Tr "repo.model_manager"}}</label>
@@ -166,6 +157,14 @@
<label>{{.i18n.Tr "repo.settings.model_desc"}}</label> <label>{{.i18n.Tr "repo.settings.model_desc"}}</label>
</div> </div>
</div> </div>
{{$isCloudBrainEnabled := .Repository.UnitEnabled $.UnitTypeCloudBrain }}
<div class="inline field">
<label>{{.i18n.Tr "repo.cloudbrain"}}</label>
<div class="ui checkbox">
<input class="enable-system" name="enable_cloud_brain" type="checkbox" {{if $isCloudBrainEnabled}}checked{{end}}>
<label>{{.i18n.Tr "repo.settings.cloudbrain_desc"}}</label>
</div>
</div>
{{$isWikiEnabled := or (.Repository.UnitEnabled $.UnitTypeWiki) (.Repository.UnitEnabled $.UnitTypeExternalWiki)}} {{$isWikiEnabled := or (.Repository.UnitEnabled $.UnitTypeWiki) (.Repository.UnitEnabled $.UnitTypeExternalWiki)}}
<div class="inline field"> <div class="inline field">
<label>{{.i18n.Tr "repo.wiki"}}</label> <label>{{.i18n.Tr "repo.wiki"}}</label>


+ 53
- 11
templates/user/profile.tmpl View File

@@ -50,16 +50,46 @@
{{end}} {{end}}
<li>{{svg "octicon-clock" 16}} {{.i18n.Tr "user.join_on"}} {{.Owner.CreatedUnix.FormatShort}}</li> <li>{{svg "octicon-clock" 16}} {{.i18n.Tr "user.join_on"}} {{.Owner.CreatedUnix.FormatShort}}</li>
{{if and .Orgs .HasOrgsVisible}} {{if and .Orgs .HasOrgsVisible}}
<li>
<ul class="user-orgs">
<li style="border-bottom: none;padding-bottom: 0;"><div style="border-bottom: 1px solid #eaeaea;padding-top: 5px;padding-bottom:5px"> <b> 组织</b></div></li>
<li style="padding-bottom: 0px;">
<!-- <ul class="user-orgs">
{{range .Orgs}} {{range .Orgs}}
{{if (or .Visibility.IsPublic (and ($.SignedUser) (or .Visibility.IsLimited (and (.IsUserPartOfOrg $.SignedUserID) .Visibility.IsPrivate) ($.IsAdmin))))}} {{if (or .Visibility.IsPublic (and ($.SignedUser) (or .Visibility.IsLimited (and (.IsUserPartOfOrg $.SignedUserID) .Visibility.IsPrivate) ($.IsAdmin))))}}
<li> <li>
<a href="{{.HomeLink}}"><img class="ui image poping up" src="{{.RelAvatarLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a>
<ul>
<a href="{{.HomeLink}}"><img class="ui image poping up" src="{{.RelAvatarLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a>
<span>{{.Name}}</span>
</ul>
</li> </li>
{{end}} {{end}}
{{end}} {{end}}
</ul>
</ul> -->
{{range .Orgs}}
<ul class="user-orgs">
{{if (or .Visibility.IsPublic (and ($.SignedUser) (or .Visibility.IsLimited (and (.IsUserPartOfOrg $.SignedUserID) .Visibility.IsPrivate) ($.IsAdmin))))}}
<li class="infor" style="width: 15%;" >
<a href="{{.HomeLink}}"><img class="ui image poping up" src="{{.RelAvatarLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a>
</li>
<li class="infor" style="width: 35%;">
<a class="ui image poping up" style="color: #0366D6;overflow: hidden; white-space: nowrap; text-overflow: ellipsis;" href="{{.HomeLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted">{{.Name}}</a>
</li>
<li class="infor" style="width: 25%;">
<img style="width: 14px; height: 14px;border: none;" src="/img/member.svg" >
<span style="color: rgba(0,0,0,.4);padding-left: 5px;">{{.NumMembers}}</span>
</li>
<li class="infor" style="width: 25%;">
<img style="width: 14px; height: 14px" src="/img/pro_num.svg" >
<span style="color: rgba(0,0,0,.4);padding-left: 5px;">{{.NumRepos}}</span>
</li>
{{end}}
</ul>
{{end}}
</li> </li>
{{end}} {{end}}
{{if and .IsSigned (ne .SignedUserName .Owner.Name)}} {{if and .IsSigned (ne .SignedUserName .Owner.Name)}}
@@ -79,13 +109,6 @@
{{end}} {{end}}
</ul> </ul>
</div> </div>
<div >
<ul>
<li>
<ul></ul><ul></ul>
</li>
</ul>
</div>
</div> </div>
</div> </div>
<div class="ui eleven wide column"> <div class="ui eleven wide column">
@@ -155,3 +178,22 @@
</div> </div>
</div> </div>
{{template "base/footer" .}} {{template "base/footer" .}}

<style>
.infor{
margin: auto 0;
}
.user-orgs{
padding: 10px 0px;
}
.user-orgs li{
max-width: 50%;
float: right;
}
.user.profile .ui.card .extra.content ul {
padding: 5px 0;
}

</style>

+ 7
- 1
web_src/less/openi.less View File

@@ -518,4 +518,10 @@ display: block;
} }
.letf2{ .letf2{
margin-left: -2px; margin-left: -2px;
}
}
.edge{
margin-left:0 !important;
margin-right: 0 !important;
padding-left:0 !important;
padding-right:0 !important;
}

Loading…
Cancel
Save