| @@ -1059,50 +1059,50 @@ RESULT_BACKEND = redis://localhost:6379 | |||
| [cloudbrain] | |||
| USERNAME = | |||
| PASSWORD = | |||
| REST_SERVER_HOST = http://192.168.202.73 | |||
| JOB_PATH = /datasets/minio/data/opendata/jobs/ | |||
| DEBUG_SERVER_HOST = http://192.168.202.73/ | |||
| REST_SERVER_HOST = | |||
| JOB_PATH = | |||
| DEBUG_SERVER_HOST = | |||
| ; cloudbrain visit opendata | |||
| USER = cW4cMtH24eoWPE7X | |||
| PWD = 4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DA.C | |||
| GPU_TYPE_DEFAULT = openidebug | |||
| GPU_TYPES = {"gpu_type":[{"id":1,"queue":"openidebug","value":"T4"},{"id":2,"queue":"openidgx","value":"V100"}]} | |||
| USER = | |||
| PWD = | |||
| GPU_TYPE_DEFAULT = | |||
| GPU_TYPES = | |||
| [benchmark] | |||
| ENABLED = true | |||
| BENCHMARKCODE = https://yangzhx:justfortest123@git.openi.org.cn/yangzhx/detection_benchmark_script.git | |||
| HOST = http://192.168.202.90:3366/ | |||
| ENABLED = | |||
| BENCHMARKCODE = | |||
| HOST = | |||
| [snn4imagenet] | |||
| ENABLED = true | |||
| SNN4IMAGENETCODE = https://yult:eh2Ten4iLYjFkbj@git.openi.org.cn/ylt/snn4imagenet.git | |||
| HOST = http://192.168.202.90:3366/ | |||
| ENABLED = | |||
| SNN4IMAGENETCODE = | |||
| HOST = | |||
| [decompress] | |||
| HOST = http://192.168.207.34:39987 | |||
| USER = cW4cMtH24eoWPE7X | |||
| PASSWORD = 4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DAC | |||
| HOST = | |||
| USER = | |||
| PASSWORD = | |||
| [blockchain] | |||
| HOST = http://192.168.207.84:3002/ | |||
| COMMIT_VALID_DATE = 2021-01-15 | |||
| HOST = | |||
| COMMIT_VALID_DATE = | |||
| [obs] | |||
| ENDPOINT = https://obs.cn-south-222.ai.pcl.cn | |||
| ACCESS_KEY_ID = FDP3LRMHLB9S77VWEHE3 | |||
| SECRET_ACCESS_KEY = LyM82Wk80pgjhs2z7AdDcsdpCWhbsJtSzQ7hkESN | |||
| BUCKET = testopendata | |||
| LOCATION = cn-south-222 | |||
| BASE_PATH = attachment/ | |||
| ENDPOINT = | |||
| ACCESS_KEY_ID = | |||
| SECRET_ACCESS_KEY = | |||
| BUCKET = | |||
| LOCATION = | |||
| BASE_PATH = | |||
| [modelarts] | |||
| ORGANIZATION = modelarts | |||
| ENDPOINT = https://modelarts.cn-south-222.ai.pcl.cn | |||
| PROJECT_ID = edfccf24aace4e17a56da6bcbb55a5aa | |||
| PROJECT_NAME = cn-south-222_test | |||
| USERNAME = test1 | |||
| PASSWORD = Qizhi@test. | |||
| DOMAIN = cn-south-222 | |||
| ORGANIZATION = | |||
| ENDPOINT = | |||
| PROJECT_ID = | |||
| PROJECT_NAME = | |||
| USERNAME = | |||
| PASSWORD = | |||
| DOMAIN = | |||
| [radar_map] | |||
| impact=0.3 | |||
| @@ -91,6 +91,7 @@ type Cloudbrain struct { | |||
| DeletedAt time.Time `xorm:"deleted"` | |||
| CanDebug bool `xorm:"-"` | |||
| CanDel bool `xorm:"-"` | |||
| CanModify bool `xorm:"-"` | |||
| Type int | |||
| VersionID int64 //版本id | |||
| @@ -145,7 +145,7 @@ type User struct { | |||
| AllowImportLocal bool // Allow migrate repository by local path | |||
| AllowCreateOrganization bool `xorm:"DEFAULT true"` | |||
| ProhibitLogin bool `xorm:"NOT NULL DEFAULT false"` | |||
| IsOperator bool `xorm:"NOT NULL DEFAULT false"` //运营人员 | |||
| IsOperator bool `xorm:"NOT NULL DEFAULT false"` //运营人员 | |||
| // Avatar | |||
| Avatar string `xorm:"VARCHAR(2048) NOT NULL"` | |||
| @@ -929,8 +929,17 @@ var ( | |||
| "template", | |||
| "user", | |||
| "vendor", | |||
| } | |||
| reservedUserPatterns = []string{"*.keys", "*.gpg"} | |||
| "dashbord", | |||
| "operation", | |||
| "blockchain", | |||
| "avatar", | |||
| "swagger.v1.json", | |||
| "secure", | |||
| "serviceworker.js", | |||
| "self", | |||
| "repo-avatars", | |||
| } | |||
| reservedUserPatterns = []string{"*.keys", "*.gpg", "*.png"} | |||
| ) | |||
| // isUsableName checks if name is reserved or pattern of name is not allowed | |||
| @@ -1552,11 +1561,11 @@ func GetUserByActivateEmail(email string) (*User, error) { | |||
| if err := ctx.e.Join("INNER", "email_address", "email_address.uid = \"user\".id"). | |||
| Where("email_address.email= ?", email). | |||
| Find(&users); err != nil { | |||
| return nil,err | |||
| return nil, err | |||
| } | |||
| if len(users) >= 1 { | |||
| return &users[0],nil | |||
| }else { | |||
| return &users[0], nil | |||
| } else { | |||
| // Finally, if email address is the protected email address:用户邮件地址设置为隐藏电子邮件地址 | |||
| if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) { | |||
| username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) | |||
| @@ -1572,6 +1581,7 @@ func GetUserByActivateEmail(email string) (*User, error) { | |||
| return nil, errors.New("cannot find user by email") | |||
| } | |||
| } | |||
| // GetUserByEmail returns the user object by given e-mail if exists. | |||
| func GetUserByEmail(email string) (*User, error) { | |||
| return GetUserByEmailContext(DefaultDBContext(), email) | |||
| @@ -29,9 +29,7 @@ var ( | |||
| ResourceSpecs *models.ResourceSpecs | |||
| ) | |||
| func isAdminOrOwnerOrJobCreater(ctx *context.Context, jobId string) bool { | |||
| job, err := models.GetCloudbrainByJobID(jobId) | |||
| func isAdminOrOwnerOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { | |||
| if err != nil { | |||
| return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() | |||
| @@ -41,9 +39,29 @@ func isAdminOrOwnerOrJobCreater(ctx *context.Context, jobId string) bool { | |||
| } | |||
| func isAdminOrJobCreater(ctx *context.Context, jobId string) bool { | |||
| 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 { | |||
| return isAdminOrOwnerOrJobCreater(ctx, job, nil) | |||
| } | |||
| func CanCreateOrDebugJob(ctx *context.Context) bool { | |||
| return ctx.Repo.CanWrite(models.UnitTypeCloudBrain) | |||
| } | |||
| func CanModifyJob(ctx *context.Context, job *models.Cloudbrain) bool { | |||
| job, err := models.GetCloudbrainByJobID(jobId) | |||
| return isAdminOrJobCreater(ctx, job, nil) | |||
| } | |||
| func isAdminOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { | |||
| if err != nil { | |||
| return ctx.IsUserSiteAdmin() | |||
| @@ -57,7 +75,9 @@ func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) { | |||
| var jobID = ctx.Params(":jobid") | |||
| if !isAdminOrOwnerOrJobCreater(ctx, jobID) { | |||
| job, err := models.GetCloudbrainByJobID(jobID) | |||
| if !isAdminOrOwnerOrJobCreater(ctx, job, err) { | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| } | |||
| @@ -67,8 +87,8 @@ func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) { | |||
| func AdminOrJobCreaterRight(ctx *context.Context) { | |||
| var jobID = ctx.Params(":jobid") | |||
| if !isAdminOrJobCreater(ctx, jobID) { | |||
| job, err := models.GetCloudbrainByJobID(jobID) | |||
| if !isAdminOrJobCreater(ctx, job, err) { | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| } | |||
| @@ -442,14 +442,15 @@ var ( | |||
| DecompressOBSTaskName string | |||
| //cloudbrain config | |||
| CBAuthUser string | |||
| CBAuthPassword string | |||
| RestServerHost string | |||
| JobPath string | |||
| JobType string | |||
| GpuTypes string | |||
| DebugServerHost string | |||
| ResourceSpecs string | |||
| CBAuthUser string | |||
| CBAuthPassword string | |||
| RestServerHost string | |||
| JobPath string | |||
| CBCodePathPrefix string | |||
| JobType string | |||
| GpuTypes string | |||
| DebugServerHost string | |||
| ResourceSpecs string | |||
| //benchmark config | |||
| IsBenchmarkEnabled bool | |||
| @@ -1219,8 +1220,8 @@ func NewContext() { | |||
| sec = Cfg.Section("decompress") | |||
| DecompressAddress = sec.Key("HOST").MustString("http://192.168.207.34:39987") | |||
| AuthUser = sec.Key("USER").MustString("cW4cMtH24eoWPE7X") | |||
| AuthPassword = sec.Key("PASSWORD").MustString("4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DAC") | |||
| AuthUser = sec.Key("USER").MustString("") | |||
| AuthPassword = sec.Key("PASSWORD").MustString("") | |||
| sec = Cfg.Section("labelsystem") | |||
| LabelTaskName = sec.Key("LabelTaskName").MustString("LabelRedisQueue") | |||
| @@ -1231,10 +1232,11 @@ func NewContext() { | |||
| RecommentRepoAddr = sec.Key("Address").MustString("https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/") | |||
| sec = Cfg.Section("cloudbrain") | |||
| CBAuthUser = sec.Key("USER").MustString("cW4cMtH24eoWPE7X") | |||
| CBAuthPassword = sec.Key("PWD").MustString("4BPmgvK2hb2Eywwyp4YZRY4B7yQf4DAC") | |||
| CBAuthUser = sec.Key("USER").MustString("") | |||
| CBAuthPassword = sec.Key("PWD").MustString("") | |||
| RestServerHost = sec.Key("REST_SERVER_HOST").MustString("http://192.168.202.73") | |||
| JobPath = sec.Key("JOB_PATH").MustString("/datasets/minio/data/opendata/jobs/") | |||
| CBCodePathPrefix = sec.Key("CODE_PATH_PREFIX").MustString("jobs/") | |||
| DebugServerHost = sec.Key("DEBUG_SERVER_HOST").MustString("http://192.168.202.73") | |||
| JobType = sec.Key("GPU_TYPE_DEFAULT").MustString("openidebug") | |||
| GpuTypes = sec.Key("GPU_TYPES").MustString("") | |||
| @@ -1242,31 +1244,31 @@ func NewContext() { | |||
| sec = Cfg.Section("benchmark") | |||
| IsBenchmarkEnabled = sec.Key("ENABLED").MustBool(false) | |||
| BenchmarkCode = sec.Key("BENCHMARKCODE").MustString("https://yangzhx:justfortest123@git.openi.org.cn/yangzhx/detection_benchmark_script.git") | |||
| BenchmarkServerHost = sec.Key("HOST").MustString("http://192.168.202.90:3366/") | |||
| BenchmarkCode = sec.Key("BENCHMARKCODE").MustString("") | |||
| BenchmarkServerHost = sec.Key("HOST").MustString("") | |||
| BenchmarkCategory = sec.Key("CATEGORY").MustString("") | |||
| sec = Cfg.Section("snn4imagenet") | |||
| IsSnn4imagenetEnabled = sec.Key("ENABLED").MustBool(false) | |||
| Snn4imagenetCode = sec.Key("SNN4IMAGENETCODE").MustString("https://yult:19910821ylt@git.openi.org.cn/yult/snn4imagenet_script.git") | |||
| Snn4imagenetServerHost = sec.Key("HOST").MustString("http://192.168.207.76:8080/") | |||
| Snn4imagenetCode = sec.Key("SNN4IMAGENETCODE").MustString("") | |||
| Snn4imagenetServerHost = sec.Key("HOST").MustString("") | |||
| sec = Cfg.Section("brainscore") | |||
| IsBrainScoreEnabled = sec.Key("ENABLED").MustBool(false) | |||
| BrainScoreCode = sec.Key("BRAINSCORECODE").MustString("https://yult:19910821ylt@git.openi.org.cn/yult/brainscore_script.git") | |||
| BrainScoreServerHost = sec.Key("HOST").MustString("http://192.168.207.76:8080/") | |||
| BrainScoreCode = sec.Key("BRAINSCORECODE").MustString("") | |||
| BrainScoreServerHost = sec.Key("HOST").MustString("") | |||
| sec = Cfg.Section("blockchain") | |||
| BlockChainHost = sec.Key("HOST").MustString("http://192.168.136.66:3302/") | |||
| CommitValidDate = sec.Key("COMMIT_VALID_DATE").MustString("2021-01-15") | |||
| sec = Cfg.Section("obs") | |||
| Endpoint = sec.Key("ENDPOINT").MustString("112.95.163.82") | |||
| Endpoint = sec.Key("ENDPOINT").MustString("") | |||
| AccessKeyID = sec.Key("ACCESS_KEY_ID").MustString("") | |||
| SecretAccessKey = sec.Key("SECRET_ACCESS_KEY").MustString("") | |||
| Bucket = sec.Key("BUCKET").MustString("testopendata") | |||
| Location = sec.Key("LOCATION").MustString("cn-south-222") | |||
| BasePath = sec.Key("BASE_PATH").MustString("attachment/") | |||
| Bucket = sec.Key("BUCKET").MustString("") | |||
| Location = sec.Key("LOCATION").MustString("") | |||
| BasePath = sec.Key("BASE_PATH").MustString("") | |||
| TrainJobModelPath = sec.Key("TrainJobModel_Path").MustString("job/") | |||
| OutPutPath = sec.Key("Output_Path").MustString("output/") | |||
| CodePathPrefix = sec.Key("CODE_PATH_PREFIX").MustString("code/") | |||
| @@ -1274,17 +1276,17 @@ func NewContext() { | |||
| PROXYURL = sec.Key("PROXY_URL").MustString("") | |||
| sec = Cfg.Section("modelarts") | |||
| ModelArtsHost = sec.Key("ENDPOINT").MustString("112.95.163.80") | |||
| IamHost = sec.Key("IAMHOST").MustString("112.95.163.80") | |||
| ModelArtsHost = sec.Key("ENDPOINT").MustString("") | |||
| IamHost = sec.Key("IAMHOST").MustString("") | |||
| ProjectID = sec.Key("PROJECT_ID").MustString("") | |||
| ProjectName = sec.Key("PROJECT_NAME").MustString("") | |||
| ModelArtsUsername = sec.Key("USERNAME").MustString("") | |||
| ModelArtsPassword = sec.Key("PASSWORD").MustString("") | |||
| ModelArtsDomain = sec.Key("DOMAIN").MustString("cn-south-222") | |||
| ModelArtsDomain = sec.Key("DOMAIN").MustString("") | |||
| AllowedOrg = sec.Key("ORGANIZATION").MustString("") | |||
| ProfileID = sec.Key("PROFILE_ID").MustString("") | |||
| PoolInfos = sec.Key("POOL_INFOS").MustString("") | |||
| Flavor = sec.Key("FLAVOR").MustString("modelarts.bm.910.arm.public.2") | |||
| Flavor = sec.Key("FLAVOR").MustString("") | |||
| ResourcePools = sec.Key("Resource_Pools").MustString("") | |||
| Engines = sec.Key("Engines").MustString("") | |||
| EngineVersions = sec.Key("Engine_Versions").MustString("") | |||
| @@ -1292,10 +1294,10 @@ func NewContext() { | |||
| TrainJobFLAVORINFOS = sec.Key("TrainJob_FLAVOR_INFOS").MustString("") | |||
| sec = Cfg.Section("elk") | |||
| ElkUrl = sec.Key("ELKURL").MustString("http://192.168.207.35:5601/internal/bsearch") | |||
| ElkUser = sec.Key("ELKUSER").MustString("Qizhi") | |||
| ElkPassword = sec.Key("ELKPASSWORD").MustString("Pcl2020") | |||
| Index = sec.Key("INDEX").MustString("filebeat-7.3.2*") | |||
| ElkUrl = sec.Key("ELKURL").MustString("") | |||
| ElkUser = sec.Key("ELKUSER").MustString("") | |||
| ElkPassword = sec.Key("ELKPASSWORD").MustString("") | |||
| Index = sec.Key("INDEX").MustString("") | |||
| TimeField = sec.Key("TIMEFIELD").MustString(" @timestamptest") | |||
| ElkTimeFormat = sec.Key("ELKTIMEFORMAT").MustString("date_time") | |||
| @@ -76,3 +76,7 @@ func (l *LocalStorage) PresignedPutURL(path string) (string, error) { | |||
| func (l *LocalStorage) HasObject(path string) (bool, error) { | |||
| return false, nil | |||
| } | |||
| func (l *LocalStorage) UploadObject(fileName, filePath string) error { | |||
| return nil | |||
| } | |||
| @@ -122,3 +122,9 @@ func (m *MinioStorage) HasObject(path string) (bool, error) { | |||
| return hasObject, nil | |||
| } | |||
| //upload object | |||
| func (m *MinioStorage) UploadObject(fileName, filePath string) error { | |||
| _, err := m.client.FPutObject(m.bucket, fileName, filePath, minio.PutObjectOptions{}) | |||
| return err | |||
| } | |||
| @@ -26,6 +26,7 @@ type ObjectStorage interface { | |||
| PresignedGetURL(path string, fileName string) (string, error) | |||
| PresignedPutURL(path string) (string, error) | |||
| HasObject(path string) (bool, error) | |||
| UploadObject(fileName, filePath string) error | |||
| } | |||
| // Copy copys a file from source ObjectStorage to dest ObjectStorage | |||
| @@ -74,12 +74,13 @@ func CloudBrainIndex(ctx *context.Context) { | |||
| timestamp := time.Now().Unix() | |||
| for i, task := range ciTasks { | |||
| if task.Status == string(models.JobRunning) && (timestamp-int64(task.Cloudbrain.CreatedUnix) > 10) { | |||
| ciTasks[i].CanDebug = true | |||
| ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx) | |||
| } else { | |||
| ciTasks[i].CanDebug = false | |||
| } | |||
| ciTasks[i].CanDel = models.CanDelJob(ctx.IsSigned, ctx.User, task) | |||
| ciTasks[i].CanDel = cloudbrain.CanDeleteDebugJob(ctx, &task.Cloudbrain) | |||
| } | |||
| pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||
| @@ -88,6 +89,7 @@ func CloudBrainIndex(ctx *context.Context) { | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| ctx.Data["Tasks"] = ciTasks | |||
| ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx) | |||
| ctx.HTML(200, tplCloudBrainIndex) | |||
| } | |||
| @@ -247,6 +249,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
| } | |||
| repo := ctx.Repo.Repository | |||
| downloadCode(repo, codePath) | |||
| uploadCodeToMinio(codePath + "/", jobName, "/code/") | |||
| modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath | |||
| err = os.MkdirAll(modelPath, os.ModePerm) | |||
| @@ -265,16 +268,19 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
| } | |||
| } | |||
| downloadRateCode(repo, jobName, setting.BenchmarkCode, benchmarkPath, form.BenchmarkCategory, gpuType) | |||
| uploadCodeToMinio(benchmarkPath + "/", jobName, cloudbrain.BenchMarkMountPath + "/") | |||
| } | |||
| snn4imagenetPath := setting.JobPath + jobName + cloudbrain.Snn4imagenetMountPath | |||
| if setting.IsSnn4imagenetEnabled && jobType == string(models.JobTypeSnn4imagenet) { | |||
| downloadRateCode(repo, jobName, setting.Snn4imagenetCode, snn4imagenetPath, "", "") | |||
| uploadCodeToMinio(snn4imagenetPath + "/", jobName, cloudbrain.Snn4imagenetMountPath + "/") | |||
| } | |||
| brainScorePath := setting.JobPath + jobName + cloudbrain.BrainScoreMountPath | |||
| if setting.IsBrainScoreEnabled && jobType == string(models.JobTypeBrainScore) { | |||
| downloadRateCode(repo, jobName, setting.BrainScoreCode, brainScorePath, "", "") | |||
| uploadCodeToMinio(brainScorePath + "/", jobName, cloudbrain.BrainScoreMountPath + "/") | |||
| } | |||
| err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue, resourceSpecId) | |||
| @@ -701,8 +707,8 @@ func downloadRateCode(repo *models.Repository, taskName, gitPath, codePath, benc | |||
| command := "git clone " + gitPath + " " + codePath | |||
| cmd := exec.Command("/bin/bash", "-c", command) | |||
| output, err := cmd.Output() | |||
| log.Info(string(output)) | |||
| _, err = cmd.Output() | |||
| if err != nil { | |||
| log.Error("exec.Command(%s) failed:%v", command, err) | |||
| return err | |||
| @@ -739,6 +745,33 @@ func downloadRateCode(repo *models.Repository, taskName, gitPath, codePath, benc | |||
| return nil | |||
| } | |||
| func uploadCodeToMinio(codePath, jobName, parentDir string) error { | |||
| files, err := readDir(codePath) | |||
| if err != nil { | |||
| log.Error("readDir(%s) failed: %s", codePath, err.Error()) | |||
| return err | |||
| } | |||
| for _, file := range files { | |||
| if file.IsDir() { | |||
| if err = uploadCodeToMinio(codePath+file.Name()+"/", jobName, parentDir+file.Name()+"/"); err != nil { | |||
| log.Error("uploadCodeToMinio(%s) failed: %s", file.Name(), err.Error()) | |||
| return err | |||
| } | |||
| } else { | |||
| destObject := setting.CBCodePathPrefix + jobName + parentDir + file.Name() | |||
| sourceFile := codePath + file.Name() | |||
| err = storage.Attachments.UploadObject(destObject, sourceFile) | |||
| if err != nil { | |||
| log.Error("UploadObject(%s) failed: %s", file.Name(), err.Error()) | |||
| return err | |||
| } | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| func SyncCloudbrainStatus() { | |||
| cloudBrains, err := models.GetCloudBrainUnStoppedJob() | |||
| if err != nil { | |||
| @@ -11,6 +11,8 @@ import ( | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/cloudbrain" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/auth" | |||
| "code.gitea.io/gitea/modules/base" | |||
| @@ -68,10 +70,11 @@ func NotebookIndex(ctx *context.Context) { | |||
| for i, task := range ciTasks { | |||
| if task.Status == string(models.JobRunning) { | |||
| ciTasks[i].CanDebug = true | |||
| ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx) | |||
| } else { | |||
| ciTasks[i].CanDebug = false | |||
| } | |||
| ciTasks[i].CanDel = cloudbrain.CanDeleteDebugJob(ctx, &task.Cloudbrain) | |||
| } | |||
| pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||
| @@ -80,6 +83,7 @@ func NotebookIndex(ctx *context.Context) { | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| ctx.Data["Tasks"] = ciTasks | |||
| ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx) | |||
| ctx.HTML(200, tplModelArtsNotebookIndex) | |||
| } | |||
| @@ -301,12 +305,18 @@ func TrainJobIndex(ctx *context.Context) { | |||
| return | |||
| } | |||
| for i, task := range tasks { | |||
| tasks[i].CanDel = cloudbrain.CanDeleteTrainJob(ctx, &task.Cloudbrain) | |||
| tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain) | |||
| } | |||
| pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||
| pager.SetDefaultParams(ctx) | |||
| ctx.Data["Page"] = pager | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| ctx.Data["Tasks"] = tasks | |||
| ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx) | |||
| ctx.HTML(200, tplModelArtsTrainJobIndex) | |||
| } | |||
| @@ -17,19 +17,23 @@ | |||
| {{if .IsSigned}} | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "index"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| <div class=" item" > | |||
| <div class="dropdown-menu"> | |||
| <a class=" item" href="/dashboard"> | |||
| <span > {{.i18n.Tr "index"}}   <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"> | |||
| <div class="ui dropdown item" id='dropdown_explore'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| @@ -43,24 +47,26 @@ | |||
| </div> | |||
| </div> | |||
| {{else if .IsLandingPageHome}} | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "home"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <!-- 未登录跳转登录界面 --> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| <div class=" item"> | |||
| <div class="dropdown-menu"> | |||
| <a class=" item" href="/user/login"> | |||
| <span > {{.i18n.Tr "home"}}   <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"> | |||
| <div class="ui dropdown item" id='dropdown_PageHome'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <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> | |||
| @@ -17,18 +17,22 @@ | |||
| {{if .IsSigned}} | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "index"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| <div class="item" > | |||
| <div class="dropdown-menu"> | |||
| <a class=" item" href="/dashboard"> | |||
| <span > {{.i18n.Tr "index"}}   <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"> | |||
| <div class="ui dropdown item" id='dropdown_explore'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| @@ -42,19 +46,22 @@ | |||
| </div> | |||
| </div> | |||
| {{else if .IsLandingPageHome}} | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "home"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <!-- 未登录跳转登录界面 --> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| <div class="item" > | |||
| <div class="dropdown-menu"> | |||
| <a class=" item" href="/user/login"> | |||
| <span > {{.i18n.Tr "home"}}   <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"> | |||
| <div class="ui dropdown item" id='dropdown_PageHome'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| @@ -9,18 +9,22 @@ | |||
| </div> | |||
| {{if .IsSigned}} | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "index"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| <div class="item" > | |||
| <div class="dropdown-menu"> | |||
| <a class=" item" href="/dashboard"> | |||
| <span > {{.i18n.Tr "index"}}   <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"> | |||
| <div class="ui dropdown item" id='dropdown_explore'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| @@ -34,21 +38,23 @@ | |||
| </div> | |||
| </div> | |||
| {{else if .IsLandingPageHome}} | |||
| <div class="ui dropdown item"> | |||
| {{.i18n.Tr "home"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <!-- 未登录跳转登录界面 --> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a class="item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| <div class="item" > | |||
| <div class="dropdown-menu"> | |||
| <a class=" item" href="/user/login"> | |||
| <span > {{.i18n.Tr "home"}}   <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"> | |||
| <div class="ui dropdown item" id='dropdown_PageHome'> | |||
| {{.i18n.Tr "explore"}} | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| @@ -2935,6 +2935,7 @@ $(document).ready(async () => { | |||
| initNotificationsTable(); | |||
| initNotificationCount(); | |||
| initTribute(); | |||
| initDropDown(); | |||
| // Repo clone url. | |||
| if ($('#repo-clone-url').length > 0) { | |||
| @@ -4116,3 +4117,11 @@ $.get(`${window.config.StaticUrlPrefix}/img/svg/icons.svg`, (data) => { | |||
| div.innerHTML = new XMLSerializer().serializeToString(data.documentElement); | |||
| document.body.insertBefore(div, document.body.childNodes[0]); | |||
| }); | |||
| function initDropDown() { | |||
| $("#dropdown_PageHome").dropdown({ | |||
| on:'hover' ,//鼠标悬浮显示,默认值是click | |||
| }); | |||
| $("#dropdown_explore").dropdown({ | |||
| on:'hover' ,//鼠标悬浮显示,默认值是click | |||
| }); | |||
| } | |||