Reviewed-on: https://git.openi.org.cn/OpenI/aiforge/pulls/478tags/v1.21.12.1
| @@ -46,6 +46,7 @@ type Attachment struct { | |||
| CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
| FileChunk *FileChunk `xorm:"-"` | |||
| CanDel bool `xorm:"-"` | |||
| } | |||
| type AttachmentUsername struct { | |||
| @@ -378,7 +379,7 @@ func GetUnDecompressAttachments() ([]*Attachment, error) { | |||
| func getUnDecompressAttachments(e Engine) ([]*Attachment, error) { | |||
| attachments := make([]*Attachment, 0, 10) | |||
| return attachments, e.Where("decompress_state = ? and dataset_id != 0 and attachment.type = ? and name like '%.zip'", DecompressStateInit, TypeCloudBrainOne).Find(&attachments) | |||
| return attachments, e.Where("decompress_state = ? and dataset_id != 0 and attachment.type = ? and (name like '%.zip' or name like '%.tar.gz' or name like '%.tgz')", DecompressStateInit, TypeCloudBrainOne).Find(&attachments) | |||
| } | |||
| func GetAllPublicAttachments() ([]*AttachmentUsername, error) { | |||
| @@ -437,3 +438,29 @@ func getModelArtsUserAttachments(e Engine, userID int64) ([]*AttachmentUsername, | |||
| func GetModelArtsUserAttachments(userID int64) ([]*AttachmentUsername, error) { | |||
| return getModelArtsUserAttachments(x, userID) | |||
| } | |||
| func CanDelAttachment(isSigned bool, user *User, attach *Attachment) bool { | |||
| if !isSigned { | |||
| return false | |||
| } | |||
| dataset, err := GetDatasetByID(attach.DatasetID) | |||
| if err != nil { | |||
| log.Error("GetDatasetByID failed:%v", err.Error()) | |||
| return false | |||
| } | |||
| repo, _ := GetRepositoryByID(dataset.RepoID) | |||
| if err != nil { | |||
| log.Error("GetRepositoryByID failed:%v", err.Error()) | |||
| return false | |||
| } | |||
| permission, _ := GetUserRepoPermission(repo, user) | |||
| if err != nil { | |||
| log.Error("GetUserRepoPermission failed:%v", err.Error()) | |||
| return false | |||
| } | |||
| if user.ID == attach.UploaderID || user.IsAdmin || permission.AccessMode >= AccessModeAdmin { | |||
| return true | |||
| } | |||
| return false | |||
| } | |||
| @@ -3,6 +3,7 @@ package models | |||
| import ( | |||
| "encoding/json" | |||
| "fmt" | |||
| "strings" | |||
| "time" | |||
| "xorm.io/xorm" | |||
| @@ -176,6 +177,10 @@ func ConvertToTaskPod(input map[string]interface{}) (TaskPod, error) { | |||
| err := json.Unmarshal(data, &taskPod) | |||
| taskPod.TaskStatuses[0].StartTime = time.Unix(taskPod.TaskStatuses[0].StartAt.Unix()+8*3600, 0).UTC().Format("2006-01-02 15:04:05") | |||
| taskPod.TaskStatuses[0].FinishedTime = time.Unix(taskPod.TaskStatuses[0].FinishedAt.Unix()+8*3600, 0).UTC().Format("2006-01-02 15:04:05") | |||
| //if the task is not finished or stopped,the cloudbrain renturns 0001-01-01 08:00:00, the finishedTime shows with - | |||
| if strings.HasPrefix(taskPod.TaskStatuses[0].FinishedTime, "0001") { | |||
| taskPod.TaskStatuses[0].FinishedTime = "-" | |||
| } | |||
| return taskPod, err | |||
| } | |||
| @@ -196,11 +196,11 @@ func (s datasetMetaSearch) Less(i, j int) bool { | |||
| return s.ID[i] < s.ID[j] | |||
| } | |||
| func GetDatasetAttachments(typeCloudBrain int, rels ...*Dataset) (err error) { | |||
| return getDatasetAttachments(x, typeCloudBrain, rels...) | |||
| func GetDatasetAttachments(typeCloudBrain int, isSigned bool, user *User, rels ...*Dataset) (err error) { | |||
| return getDatasetAttachments(x, typeCloudBrain, isSigned, user, rels...) | |||
| } | |||
| func getDatasetAttachments(e Engine, typeCloudBrain int, rels ...*Dataset) (err error) { | |||
| func getDatasetAttachments(e Engine, typeCloudBrain int, isSigned bool, user *User, rels ...*Dataset) (err error) { | |||
| if len(rels) == 0 { | |||
| return | |||
| } | |||
| @@ -243,6 +243,7 @@ func getDatasetAttachments(e Engine, typeCloudBrain int, rels ...*Dataset) (err | |||
| return err | |||
| } | |||
| attachment.FileChunk = fileChunks[0] | |||
| attachment.CanDel = CanDelAttachment(isSigned, user, attachment) | |||
| sortedRels.Rel[currentIndex].Attachments = append(sortedRels.Rel[currentIndex].Attachments, attachment) | |||
| } | |||
| @@ -1543,6 +1543,22 @@ func ValidateCommitsWithEmails(oldCommits *list.List) *list.List { | |||
| return newCommits | |||
| } | |||
| // GetUserByActivateEmail returns the user object by given e-mail if exists. | |||
| /*This function will search email table only*/ | |||
| func GetUserByActivateEmail(email string) (*User, error) { | |||
| ctx := DefaultDBContext() | |||
| var users []User | |||
| 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 | |||
| } | |||
| if len(users) >= 1 { | |||
| return &users[0],nil | |||
| }else { | |||
| 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) | |||
| @@ -47,7 +47,7 @@ func CreateRepository(doer, u *models.User, opts models.CreateRepoOptions) (_ *m | |||
| // No need for init mirror. | |||
| if !opts.IsMirror { | |||
| repoPath := models.RepoPath(u.Name, repo.Name) | |||
| if err = initRepository(ctx, repoPath, u, repo, opts); err != nil { | |||
| if err = initRepository(ctx, repoPath, doer, u, repo, opts); err != nil { | |||
| if err2 := os.RemoveAll(repoPath); err2 != nil { | |||
| log.Error("initRepository: %v", err) | |||
| return fmt.Errorf( | |||
| @@ -176,7 +176,7 @@ func checkInitRepository(repoPath string) (err error) { | |||
| } | |||
| // InitRepository initializes README and .gitignore if needed. | |||
| func initRepository(ctx models.DBContext, repoPath string, u *models.User, repo *models.Repository, opts models.CreateRepoOptions) (err error) { | |||
| func initRepository(ctx models.DBContext, repoPath string, doer *models.User, u *models.User, repo *models.Repository, opts models.CreateRepoOptions) (err error) { | |||
| if err = checkInitRepository(repoPath); err != nil { | |||
| return err | |||
| } | |||
| @@ -195,8 +195,14 @@ func initRepository(ctx models.DBContext, repoPath string, u *models.User, repo | |||
| } | |||
| // Apply changes and commit. | |||
| if err = initRepoCommit(tmpDir, repo, u, opts.DefaultBranch); err != nil { | |||
| return fmt.Errorf("initRepoCommit: %v", err) | |||
| if u.IsOrganization() { | |||
| if err = initRepoCommit(tmpDir, repo, doer, opts.DefaultBranch); err != nil { | |||
| return fmt.Errorf("initRepoCommit: %v", err) | |||
| } | |||
| } else { | |||
| if err = initRepoCommit(tmpDir, repo, u, opts.DefaultBranch); err != nil { | |||
| return fmt.Errorf("initRepoCommit: %v", err) | |||
| } | |||
| } | |||
| } | |||
| @@ -13,8 +13,8 @@ const ( | |||
| DecompressTaskName = "Decompress" | |||
| ) | |||
| func SendDecompressTask(ctx context.Context, uuid string) error { | |||
| args := []tasks.Arg{{Name: "uuid", Type: "string", Value: uuid}} | |||
| func SendDecompressTask(ctx context.Context, uuid string, name string) error { | |||
| args := []tasks.Arg{{Name: "uuid", Type: "string", Value: uuid}, {Name: "name", Type: "string", Value: name}} | |||
| task, err := tasks.NewSignature(DecompressTaskName, args) | |||
| if err != nil { | |||
| log.Error("NewSignature failed:", err.Error()) | |||
| @@ -712,7 +712,17 @@ function loadimg(){ | |||
| reset_var(); | |||
| var picturePath = labeltastresult[fileindex].pic_image_field; | |||
| img.src = ip + "/getgiteaimage?filename=" + picturePath; | |||
| var html = picturePath.substring(picturePath.lastIndexOf("/") + 1) + " "+ "(" + (tablePageData.current * pageSize + fileindex + 1) + "/" + tablePageData.total + ")" | |||
| var picIndex = picturePath.indexOf("/",70); | |||
| if(picIndex != -1){ | |||
| float_text_name = picturePath.substring(picIndex + 1); | |||
| float_text_name = float_text_name.substring(float_text_name.indexOf('/')+1); | |||
| }else{ | |||
| float_text_name = picturePath.substring(picturePath.lastIndexOf("/") + 1) | |||
| } | |||
| var html = float_text_name + " "+ "(" + (tablePageData.current * pageSize + fileindex + 1) + "/" + tablePageData.total + ")" | |||
| document.getElementById("float_text").innerHTML = html; | |||
| } | |||
| function save(){ | |||
| @@ -1640,22 +1650,31 @@ function showfilelist(){ | |||
| var htmlstr=""; | |||
| for (var i=0;i<labeltastresult.length;i++){ | |||
| var fname = labeltastresult[i].pic_image_field.substring(labeltastresult[i].pic_image_field.lastIndexOf('/') + 1); | |||
| if(labeltastresult[i].pic_image_field.length > 70){ | |||
| var tmpIndex = labeltastresult[i].pic_image_field.indexOf("/",70); | |||
| console.log(tmpIndex) | |||
| if(tmpIndex != -1){ | |||
| fname = labeltastresult[i].pic_image_field.substring(tmpIndex + 1); | |||
| fname = fname.substring(fname.indexOf('/')+1); | |||
| } | |||
| } | |||
| var isfinished = labeltastresult[i].label_status; | |||
| if(isVerified()){ | |||
| isfinished = labeltastresult[i].verify_status - 1; | |||
| } | |||
| if(isVerified()){ | |||
| isfinished = labeltastresult[i].verify_status - 1; | |||
| } | |||
| var lablebg=" style=\"cursor:pointer\""; | |||
| var classStr = "style=\"color:#FF6200;background: transparent;border: 0;\""; | |||
| var finish="未完成"; | |||
| if (isfinished=="0"){finish="已完成";classStr = "style=\"color:#27c24c;background: transparent;border: 0;\"";} | |||
| if (i==fileindex){lablebg=" style=\"color:#fff;cursor:pointer;\"";classStr = "style=\"color:#04B3E5;background: transparent;border: 0;\"";finish="标注中"} | |||
| if(isVerified()){ | |||
| htmlstr = htmlstr+"<tr onclick=\"clickfilelist("+i+");\""+ lablebg+"> <td width=\"70\"" +"style=\"vertical-align:middle\""+ classStr + ">"+"<button"+classStr+" type=\"button\" onclick=\"changeVerifyStatus("+i+");\" style=\"border:none;background:none\">"+finish +"</button>"+"</td><td>"+ fname+ "</td></tr>"; | |||
| }else{ | |||
| htmlstr = htmlstr+"<tr onclick=\"clickfilelist("+i+");\""+lablebg+"><td>"+fname+"</td><td width=\"110\""+"style=\"vertical-align:middle\">"+"<button onclick=\"changeStatus("+i+");\" "+ classStr +" style=\"border:none;background:none\">"+finish +"</button>"+"</td></tr>"; | |||
| } | |||
| if(isVerified()){ | |||
| htmlstr = htmlstr+"<tr onclick=\"clickfilelist("+i+");\""+ lablebg+"> <td width=\"70\"" +"style=\"vertical-align:middle\""+ classStr + ">"+"<button"+classStr+" type=\"button\" onclick=\"changeVerifyStatus("+i+");\" style=\"border:none;background:none\">"+finish +"</button>"+"</td><td>"+ fname+ "</td></tr>"; | |||
| }else{ | |||
| htmlstr = htmlstr+"<tr onclick=\"clickfilelist("+i+");\""+lablebg+"><td>"+fname+"</td><td width=\"110\""+"style=\"vertical-align:middle\">"+"<button onclick=\"changeStatus("+i+");\" "+ classStr +" style=\"border:none;background:none\">"+finish +"</button>"+"</td></tr>"; | |||
| } | |||
| }; | |||
| } | |||
| document.getElementById("filelist").innerHTML=htmlstr; | |||
| } | |||
| @@ -2657,7 +2676,7 @@ function setPage(pageData,pageSize){ | |||
| canvas = document.getElementById("myCanvas"); | |||
| context = canvas.getContext("2d"); | |||
| maxWidth = document.getElementById("showPic").offsetWidth; | |||
| maxWidth = document.getElementById("showPic").offsetWidth-56; | |||
| maxHeight = document.getElementById("showPic").offsetHeight-100; | |||
| canvas.width = maxWidth; | |||
| canvas.height = maxHeight; | |||
| @@ -2834,14 +2853,20 @@ function isJSON(str) { | |||
| img.onload = function(){ | |||
| loadFinished = false; | |||
| // 初始设置画布大小,最大值宽和高 | |||
| canvas.width = maxWidth;//document.getElementById("tool0").offsetWidth; | |||
| canvas.height = maxHeight;//document.getElementById("tool0").offsetWidth/1280*720; | |||
| canvas.width = img.width;// maxWidth document.getElementById("tool0").offsetWidth; | |||
| canvas.height =img.height;//maxHeight document.getElementById("tool0").offsetWidth/1280*720; | |||
| //调整画布大小 | |||
| if ((img.width/img.height)<(canvas.width/canvas.height)){ | |||
| canvas.width=canvas.height * img.width / img.height; | |||
| // if ((img.width/img.height)>(maxWidth/maxWidth)){ | |||
| // canvas.width=canvas.height * img.width / img.height; | |||
| // } | |||
| // else{ | |||
| // canvas.height=canvas.width * img.height / img.width; | |||
| // } | |||
| if(canvas.width>maxWidth){ | |||
| canvas.width = maxWidth | |||
| } | |||
| else{ | |||
| canvas.height=canvas.width * img.height / img.width; | |||
| if(canvas.height>maxHeight){ | |||
| canvas.height=maxHeight | |||
| } | |||
| maxIdNum=0; | |||
| @@ -318,7 +318,7 @@ function label_task_create(task_name, relate_task_id, taskType,assign_user_id,la | |||
| success:function(res){ | |||
| console.log(res); | |||
| if(res.code == 0){ | |||
| alert("人工校验任务创建成功!"); | |||
| alert("人工标注任务创建成功!"); | |||
| createsucced = true; | |||
| } | |||
| else{ | |||
| @@ -128,7 +128,9 @@ func DeleteAttachment(ctx *context.Context) { | |||
| ctx.Error(400, err.Error()) | |||
| return | |||
| } | |||
| if !ctx.IsSigned || (ctx.User.ID != attach.UploaderID) { | |||
| //issue 214: mod del-dataset permission | |||
| if !models.CanDelAttachment(ctx.IsSigned, ctx.User, attach) { | |||
| ctx.Error(403) | |||
| return | |||
| } | |||
| @@ -146,7 +148,7 @@ func DeleteAttachment(ctx *context.Context) { | |||
| _, err = models.DeleteFileChunkById(attach.UUID) | |||
| if err != nil { | |||
| ctx.Error(500, fmt.Sprintf("DeleteAttachment: %v", err)) | |||
| ctx.Error(500, fmt.Sprintf("DeleteFileChunkById: %v", err)) | |||
| return | |||
| } | |||
| ctx.JSON(200, map[string]string{ | |||
| @@ -384,9 +386,9 @@ func AddAttachment(ctx *context.Context) { | |||
| } | |||
| if attachment.DatasetID != 0 { | |||
| if strings.HasSuffix(attachment.Name, ".zip") { | |||
| if isCanDecompress(attachment.Name) { | |||
| if typeCloudBrain == models.TypeCloudBrainOne { | |||
| err = worker.SendDecompressTask(contexExt.Background(), uuid) | |||
| err = worker.SendDecompressTask(contexExt.Background(), uuid, attachment.Name) | |||
| if err != nil { | |||
| log.Error("SendDecompressTask(%s) failed:%s", uuid, err.Error()) | |||
| } else { | |||
| @@ -406,6 +408,13 @@ func AddAttachment(ctx *context.Context) { | |||
| }) | |||
| } | |||
| func isCanDecompress(name string) bool { | |||
| if strings.HasSuffix(name, ".zip") || strings.HasSuffix(name, ".tar.gz") || strings.HasSuffix(name, ".tgz") { | |||
| return true | |||
| } | |||
| return false | |||
| } | |||
| func UpdateAttachmentDecompressState(ctx *context.Context) { | |||
| uuid := ctx.Query("uuid") | |||
| result := ctx.Query("result") | |||
| @@ -766,9 +775,9 @@ func CompleteMultipart(ctx *context.Context) { | |||
| } | |||
| if attachment.DatasetID != 0 { | |||
| if strings.HasSuffix(attachment.Name, ".zip") { | |||
| if isCanDecompress(attachment.Name) { | |||
| if typeCloudBrain == models.TypeCloudBrainOne { | |||
| err = worker.SendDecompressTask(contexExt.Background(), uuid) | |||
| err = worker.SendDecompressTask(contexExt.Background(), uuid, attachment.Name) | |||
| if err != nil { | |||
| log.Error("SendDecompressTask(%s) failed:%s", uuid, err.Error()) | |||
| } else { | |||
| @@ -838,7 +847,7 @@ func HandleUnDecompressAttachment() { | |||
| } | |||
| for _, attach := range attachs { | |||
| err = worker.SendDecompressTask(contexExt.Background(), attach.UUID) | |||
| err = worker.SendDecompressTask(contexExt.Background(), attach.UUID, attach.Name) | |||
| if err != nil { | |||
| log.Error("SendDecompressTask(%s) failed:%s", attach.UUID, err.Error()) | |||
| } else { | |||
| @@ -67,7 +67,7 @@ func CloudBrainIndex(ctx *context.Context) { | |||
| timestamp := time.Now().Unix() | |||
| for i, task := range ciTasks { | |||
| if task.Status == string(models.JobRunning) && (timestamp-int64(task.CreatedUnix) > 30) { | |||
| if task.Status == string(models.JobRunning) && (timestamp-int64(task.CreatedUnix) > 10) { | |||
| ciTasks[i].CanDebug = true | |||
| } else { | |||
| ciTasks[i].CanDebug = false | |||
| @@ -267,6 +267,7 @@ func CloudBrainShow(ctx *context.Context) { | |||
| if result != nil { | |||
| jobRes, _ := models.ConvertToJobResultPayload(result.Payload) | |||
| jobRes.Resource.Memory = strings.ReplaceAll(jobRes.Resource.Memory, "Mi", "MB") | |||
| ctx.Data["result"] = jobRes | |||
| taskRoles := jobRes.TaskRoles | |||
| taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) | |||
| @@ -76,7 +76,7 @@ func QueryDataSet(ctx *context.Context) []*models.Attachment { | |||
| ctx.NotFound("type error", nil) | |||
| return nil | |||
| } | |||
| err = models.GetDatasetAttachments(ctx.QueryInt("type"), dataset) | |||
| err = models.GetDatasetAttachments(ctx.QueryInt("type"), ctx.IsSigned, ctx.User, dataset) | |||
| if err != nil { | |||
| ctx.ServerError("GetDatasetAttachments", err) | |||
| return nil | |||
| @@ -120,7 +120,7 @@ func DatasetIndex(ctx *context.Context) { | |||
| ctx.NotFound("type error", nil) | |||
| return | |||
| } | |||
| err = models.GetDatasetAttachments(ctx.QueryInt("type"), dataset) | |||
| err = models.GetDatasetAttachments(ctx.QueryInt("type"), ctx.IsSigned, ctx.User, dataset) | |||
| if err != nil { | |||
| ctx.ServerError("GetDatasetAttachments", err) | |||
| return | |||
| @@ -39,7 +39,8 @@ func DeleteAllUnzipFile(attachment *models.Attachment, parentDir string) { | |||
| uuid := attachment.UUID | |||
| dirArray := strings.Split(parentDir, "/") | |||
| if !strings.HasSuffix(attachment.Name, ".zip") { | |||
| //if !strings.HasSuffix(attachment.Name, ".zip") { | |||
| if !isCanDecompress(attachment.Name) { | |||
| log.Error("The file is not zip file, can not query the dir") | |||
| return | |||
| } else if attachment.DecompressState != models.DecompressStateDone { | |||
| @@ -69,7 +70,7 @@ func DeleteAllUnzipFile(attachment *models.Attachment, parentDir string) { | |||
| log.Info("fileName=" + fileInfo.FileName) | |||
| log.Info("parentDir=" + fileInfo.ParenDir) | |||
| if fileInfo.IsDir { | |||
| DeleteAllUnzipFile(attachment, fileInfo.FileName) | |||
| DeleteAllUnzipFile(attachment, fileInfo.ParenDir) | |||
| } else { | |||
| absolutepath := path.Join(attachment.RelativePath()+attachment.UUID, fileInfo.ParenDir) | |||
| log.Info("absolutepath=" + absolutepath) | |||
| @@ -127,7 +128,8 @@ func DirIndex(ctx *context.Context) { | |||
| return | |||
| } | |||
| if !strings.HasSuffix(attachment.Name, ".zip") { | |||
| //if !strings.HasSuffix(attachment.Name, ".zip") { | |||
| if !isCanDecompress(attachment.Name) { | |||
| log.Error("The file is not zip file, can not query the dir") | |||
| ctx.ServerError("The file is not zip file, can not query the dir", errors.New("The file is not zip file, can not query the dir")) | |||
| return | |||
| @@ -15,6 +15,7 @@ import ( | |||
| "net/url" | |||
| "path" | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/base" | |||
| @@ -588,39 +589,45 @@ func Home(ctx *context.Context) { | |||
| //get repo contributors info | |||
| contributors, err := git.GetContributors(ctx.Repo.Repository.RepoPath()) | |||
| if err == nil && contributors != nil { | |||
| startTime := time.Now() | |||
| var contributorInfos []*ContributorInfo | |||
| contributorInfoHash:= make(map[string]*ContributorInfo) | |||
| for _, c := range contributors { | |||
| if strings.Compare(c.Email,"") == 0 { | |||
| continue | |||
| } | |||
| // get user info from committer email | |||
| user, err := models.GetUserByEmail(c.Email) | |||
| user, err := models.GetUserByActivateEmail(c.Email) | |||
| if err == nil { | |||
| // committer is system user, get info through user's primary email | |||
| existedContributorInfo := getContributorInfo(contributorInfos,user.Email) | |||
| if existedContributorInfo != nil { | |||
| if existedContributorInfo,ok:=contributorInfoHash[user.Email];ok { | |||
| // existed: same primary email, different committer name | |||
| existedContributorInfo.CommitCnt += c.CommitCnt | |||
| }else{ | |||
| // new committer info | |||
| contributorInfos = append(contributorInfos, &ContributorInfo{ | |||
| var newContributor = &ContributorInfo{ | |||
| user, user.Email,c.CommitCnt, | |||
| }) | |||
| } | |||
| contributorInfos = append(contributorInfos, newContributor ) | |||
| contributorInfoHash[user.Email] = newContributor | |||
| } | |||
| } else { | |||
| // committer is not system user | |||
| existedContributorInfo := getContributorInfo(contributorInfos,c.Email) | |||
| if existedContributorInfo != nil { | |||
| if existedContributorInfo,ok:=contributorInfoHash[c.Email];ok { | |||
| // existed: same primary email, different committer name | |||
| existedContributorInfo.CommitCnt += c.CommitCnt | |||
| }else{ | |||
| contributorInfos = append(contributorInfos, &ContributorInfo{ | |||
| nil, c.Email,c.CommitCnt, | |||
| }) | |||
| var newContributor = &ContributorInfo{ | |||
| user, c.Email,c.CommitCnt, | |||
| } | |||
| contributorInfos = append(contributorInfos, newContributor) | |||
| contributorInfoHash[c.Email] = newContributor | |||
| } | |||
| } | |||
| } | |||
| ctx.Data["ContributorInfo"] = contributorInfos | |||
| var duration = time.Since(startTime) | |||
| log.Info("getContributorInfo cost: %v seconds",duration.Seconds()) | |||
| } | |||
| if ctx.Repo.Repository.IsBeingCreated() { | |||
| task, err := models.GetMigratingTask(ctx.Repo.Repository.ID) | |||
| @@ -39,6 +39,7 @@ | |||
| </style> | |||
| <div class="ui secondary pointing tabular top attached borderless menu navbar"> | |||
| {{if .PageIsExplore}} | |||
| <a class="{{if eq .SortType "hot"}}active{{end}} item" href="{{$.Link}}?sort=hot&q={{$.Keyword}}&tab={{$.TabName}}"> | |||
| <svg class="svg octicon-repo" width="16" height="16" aria-hidden="true"> | |||
| <use xlink:href="#octicon-repo" /> | |||
| @@ -51,7 +52,7 @@ | |||
| </svg> | |||
| 活跃{{.i18n.Tr "explore.repos"}} | |||
| </a> | |||
| {{end}} | |||
| <a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&tab={{$.TabName}}"> | |||
| <svg class="svg octicon-organization" width="16" height="16" aria-hidden="true"> | |||
| <use xlink:href="#octicon-organization" /> | |||
| @@ -1,5 +1,5 @@ | |||
| {{template "base/head" .}} | |||
| <div class="organization new org"> | |||
| <div class="organization new org" style="margin-top: 25px;"> | |||
| <div class="ui middle very relaxed page grid"> | |||
| <div class="column"> | |||
| <form class="ui form" action="{{.Link}}" method="post"> | |||
| @@ -2,6 +2,13 @@ | |||
| {{template "base/head" .}} | |||
| <style> | |||
| .label_after::after{ | |||
| margin: -.2em 0 0 .2em; | |||
| content: '\00a0'; | |||
| } | |||
| .selectcloudbrain .active.item{ | |||
| color: #0087f5 !important; | |||
| border: 1px solid #0087f5; | |||
| @@ -232,13 +239,13 @@ | |||
| <div class="ui two column stackable grid"> | |||
| <div class="column"> | |||
| </div> | |||
| <div class="column right aligned"> | |||
| <!-- <div class="column right aligned"> | |||
| <div class="ui right dropdown type jump item"> | |||
| <span class="text"> | |||
| {{.i18n.Tr "repo.issues.filter_sort"}}<i class="dropdown icon"></i> | |||
| </span> | |||
| </div> | |||
| </div> | |||
| </div> --> | |||
| </div> | |||
| </div> | |||
| @@ -249,111 +256,105 @@ | |||
| <div class="row"> | |||
| <!-- 任务名 --> | |||
| <div class="four wide column"> | |||
| <div class="six wide column"> | |||
| <a class="title" href="{{$.Link}}/{{.JobID}}"> | |||
| <span class="fitted">{{svg "octicon-tasklist" 16}}</span> | |||
| <span class="fitted">{{.JobName}}</span> | |||
| </a> | |||
| </div> | |||
| <!--任务状态 --> | |||
| <div class="two wide column job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||
| {{.Status}} | |||
| </div> | |||
| <!-- 任务创建时间 --> | |||
| <div class="three wide column"> | |||
| <span class="ui text center">{{svg "octicon-flame" 16}} {{TimeSinceUnix .CreatedUnix $.Lang}}</span> | |||
| <!--任务状态 --> | |||
| <span class="ui compact button job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||
| {{.Status}} | |||
| </span> | |||
| <!-- 任务创建时间 --> | |||
| <span class="">{{TimeSinceUnix .CreatedUnix $.Lang}}</span> | |||
| </div> | |||
| <!-- 评分 --> | |||
| <div class="one wide column"> | |||
| <div class="ui text center clipboard"> | |||
| <a class="title" onclick="stop(this)" href="{{if and (ne .Status "WAITING") (ne .JobType "DEBUG")}}{{$.Link}}/{{.JobID}}/rate{{else}}javascript:void(0);{{end}}" style="{{if and (ne .Status "WAITING") (ne .JobType "DEBUG")}}{{else}}color:#CCCCCC{{end}}"> | |||
| <span class="fitted">评分</span> | |||
| </a> | |||
| </div> | |||
| </div> | |||
| <div class="seven wide column text right"> | |||
| <div class="ui compact buttons" style="margin-right:10px;"> | |||
| {{if and (ne .Status "WAITING") (ne .JobType "DEBUG")}} | |||
| <a class="ui basic button" href="{{$.Link}}/{{.JobID}}/rate" target="_blank"> | |||
| 评分 | |||
| </a> | |||
| {{end}} | |||
| <!-- 删除镜像 --> | |||
| <div class="one wide column"> | |||
| <div class="ui text center clipboard"> | |||
| <form id="delForm-{{.JobID}}" action="{{if ne .Status "STOPPED"}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/del{{end}}" method="post"> | |||
| <!-- 调试 --> | |||
| <a class="ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank"> | |||
| 调试 | |||
| </a> | |||
| <form id="stopForm-{{.JobID}}" action="{{if eq .Status "STOPPED"}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/stop{{end}}" method="post" style="margin-left:-1px;"> | |||
| {{$.CsrfTokenHtml}} | |||
| <a class="fitted" onclick="assertDelete(this)" style="{{if ne .Status "STOPPED"}}color:#CCCCCC{{end}}; font-size:16px; font-weight:bold">删除</a> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| <!-- 调试 --> | |||
| <div class="one wide column"> | |||
| <div class="ui text center clipboard"> | |||
| <a class="title" onclick="stop(this)" href="{{if not .CanDebug}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/debug{{end}}" style="{{if not .CanDebug}}color:#CCCCCC{{end}}"> | |||
| <span class="fitted">调试</span> | |||
| </a> | |||
| <a class="ui basic {{if eq .Status "STOPPED"}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||
| 停止 | |||
| </a> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| <div class="ui compact buttons" style="margin-right:10px;"> | |||
| <!-- 模型下载 --> | |||
| <a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}/models" target="_blank"> | |||
| 模型下载 | |||
| </a> | |||
| <!-- 接收结果 --> | |||
| <iframe src="" frameborder="0" name="iframeContent" style="display: none;"></iframe> | |||
| <a class="imageBtn ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" value="{{.CanDebug}}">提交镜像</a> | |||
| <!-- 停止 --> | |||
| <div class="one wide column"> | |||
| <div class="ui text center clipboard"> | |||
| <form id="stopForm-{{.JobID}}" action="{{if eq .Status "STOPPED"}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/stop{{end}}" method="post"> | |||
| {{$.CsrfTokenHtml}} | |||
| <a class="fitted" onclick="document.getElementById('stopForm-{{.JobID}}').submit();" style="{{if eq .Status "STOPPED"}}color:#CCCCCC{{end}}; font-size:16px; font-weight:bold">停止</a> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| <!-- 模型下载 --> | |||
| <div class="two wide column"> | |||
| <span class="ui text clipboard"> | |||
| <a class="title" href="{{$.Link}}/{{.JobID}}/models"> | |||
| <span class="fitted">模型下载</span> | |||
| <!-- 删除镜像 --> | |||
| <form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{if ne .Status "STOPPED"}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/del{{end}}" method="post"> | |||
| {{$.CsrfTokenHtml}} | |||
| <a class="ui compact {{if ne .Status "STOPPED"}}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||
| 删除 | |||
| </a> | |||
| </span> | |||
| </form> | |||
| </div> | |||
| <!-- 接收结果 --> | |||
| <iframe src="" frameborder="0" name="iframeContent" style="display: none;"></iframe> | |||
| <a class="imageBtn" style="{{if not .CanDebug}}color:#CCCCCC;cursor:pointer;pointer-events:none;{{end}}; font-size:16px; font-weight:bold" value="{{.CanDebug}}">提交镜像</a> | |||
| <!-- 镜像列表弹窗 --> | |||
| <div id="imageModal" class="modal" style="display: none;"> | |||
| <div class="modal-content"> | |||
| <span class="close">×</span> | |||
| <div class="modal-content"> | |||
| <!-- 表格 --> | |||
| <form id="commitImageForm" action="{{$.Link}}/{{.JobID}}/commit_image" method="post" target="iframeContent"> | |||
| {{$.CsrfTokenHtml}} | |||
| <p>提交任务镜像</p> | |||
| <div class="ui divider"></div> | |||
| <div class="inline required field dis"> | |||
| <label>镜像标签:</label> | |||
| <input name="tag" id="image_tag" tabindex="3" autofocus required maxlength="255" style="width:75%"> | |||
| </div> | |||
| <div class="inline required field" style="position:relative;height:180px;"> | |||
| <div style="height:20px;width:75px;"> | |||
| <label>镜像描述:</label> | |||
| <div class="ui form"> | |||
| <form id="commitImageForm" action="{{$.Link}}/{{.JobID}}/commit_image" method="post" target="iframeContent"> | |||
| {{$.CsrfTokenHtml}} | |||
| <div class="row"> | |||
| <p style="display: inline;">提交任务镜像</p> | |||
| <span class="close">×</span> | |||
| </div> | |||
| <div style="position:absolute;left:75px;top:0;width:75%"> | |||
| <textarea name="description" rows="10" style="width:100%"></textarea> | |||
| <div class="ui divider"></div> | |||
| <div class="inline required field dis"> | |||
| <label>镜像标签:</label> | |||
| <input name="tag" id="image_tag" tabindex="3" autofocus required maxlength="255" style="width:75%"> | |||
| </div> | |||
| </div> | |||
| <div class="ui divider"></div> | |||
| <div class="inline field"> | |||
| <label></label> | |||
| <button class="ui green button" onclick="showmask()"> | |||
| {{$.i18n.Tr "repo.cloudbrain.commit_image"}} | |||
| </button> | |||
| </div> | |||
| </form> | |||
| <div class="inline field"> | |||
| <label class="label_after">镜像描述:</label> | |||
| <textarea name="description" rows="8" style="width:75%;margin-left: 0.2em;"></textarea> | |||
| </div> | |||
| <div class="ui divider"></div> | |||
| <div class="inline field"> | |||
| <label></label> | |||
| <button class="ui green button" onclick="showmask()"> | |||
| {{$.i18n.Tr "repo.cloudbrain.commit_image"}} | |||
| </button> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{end}} {{template "base/paginate" .}} | |||
| @@ -431,7 +432,9 @@ | |||
| } | |||
| // 加载任务状态 | |||
| $(document).ready(function() { | |||
| var timeid = window.setInterval(loadJobStatus, 15000); | |||
| $(document).ready(loadJobStatus); | |||
| function loadJobStatus() { | |||
| $(".job-status").each((index, job) => { | |||
| const jobID = job.dataset.jobid; | |||
| const repoPath = job.dataset.repopath; | |||
| @@ -442,13 +445,17 @@ | |||
| $.get(`/api/v1/repos/${repoPath}/cloudbrain/${jobID}`, (data) => { | |||
| const jobID = data.JobID | |||
| const status = data.JobStatus | |||
| $('#' + jobID).text(status) | |||
| // console.log(data) | |||
| if (status != job.textContent.trim()) { | |||
| //$('#' + jobID).text(status) | |||
| //if (status == 'STOPPED') { | |||
| window.location.reload() | |||
| //} | |||
| } | |||
| }).fail(function(err) { | |||
| console.log(err); | |||
| }); | |||
| }); | |||
| }); | |||
| }; | |||
| // 获取弹窗 | |||
| var modal = document.getElementById('imageModal'); | |||
| @@ -482,6 +489,11 @@ | |||
| // 显示弹窗,弹出相应的信息 | |||
| function showmask() { | |||
| var image_tag = !$('#image_tag').val() | |||
| console.log("image_tag",image_tag) | |||
| if(image_tag){ | |||
| return | |||
| } | |||
| $('#imageModal').css('display', 'none') | |||
| $('#mask').css('display', 'block') | |||
| @@ -177,8 +177,9 @@ | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>数据集(只有zip格式的数据集才能发起云脑任务)</label> | |||
| <select id="cloudbrain_dataset" class="ui search dropdown" placeholder="选择数据集" style='width:385px' name="attachment"> | |||
| <label>数据集</label> | |||
| <select id="cloudbrain_dataset" class="ui search dropdown" placeholder="选择数据集" style='width:385px' name="attachment" required> | |||
| {{range .attachments}} | |||
| <option name="attachment" value="{{.UUID}}">{{.Attachment.Name}}</option> | |||
| {{end}} | |||
| @@ -241,15 +242,14 @@ | |||
| let url_href = window.location.pathname.split('create')[0] | |||
| $(".ui.button").attr('href',url_href) | |||
| let form = document.getElementById('form_id'); | |||
| let value_image = $("input[name='image']").val() | |||
| console.log("value_image",$("input[name='image']").val()) | |||
| $('#messageInfo').css('display','none') | |||
| form.onsubmit = function(e){ | |||
| let value_task = $("input[name='job_name']").val() | |||
| let value_image = $("input[name='image']").val() | |||
| let value_data = $("input[name='attachment']").val() | |||
| let re = /^[a-z0-9][a-z0-9-_]{1,36}$/ | |||
| let flag = re.test(value_task) | |||
| if(!flag){ | |||
| @@ -258,13 +258,11 @@ | |||
| $('#messageInfo p').text(str) | |||
| return false | |||
| } | |||
| if(!value_image){ | |||
| return false | |||
| } | |||
| // if(!value_image || !value_data){ | |||
| // console.log("------------------------") | |||
| // return false | |||
| // } | |||
| let min_value_task = value_task.toLowerCase() | |||
| console.log(min_value_task) | |||
| $("input[name='job_name']").attr("value",min_value_task) | |||
| document.getElementById("mask").style.display = "block" | |||
| @@ -24,22 +24,6 @@ | |||
| <td class="four wide"> 状态 </td> | |||
| <td> {{.State}} </td> | |||
| </tr> | |||
| <tr> | |||
| <td> 开始时间 </td> | |||
| <td>{{.StartTime}}</td> | |||
| </tr> | |||
| <tr> | |||
| <td> 结束时间 </td> | |||
| <td>{{.FinishedTime}}</td> | |||
| </tr> | |||
| <tr> | |||
| <td> ExitCode </td> | |||
| <td>{{.ExitCode}}</td> | |||
| </tr> | |||
| <tr> | |||
| <td> 退出信息 </td> | |||
| <td>{{.ExitDiagnostics| nl2br}}</td> | |||
| </tr> | |||
| </tbody> | |||
| </table> | |||
| {{end}} | |||
| @@ -73,7 +57,7 @@ | |||
| </thead> | |||
| <tbody> | |||
| <tr> | |||
| <td class="four wide"> 状态 </td> | |||
| <td class="four wide"> 平台 </td> | |||
| <td> {{.Platform}} </td> | |||
| </tr> | |||
| <tr> | |||
| @@ -1,5 +1,5 @@ | |||
| {{template "base/head" .}} | |||
| <div class="repository new repo"> | |||
| <div class="repository new repo" style="margin-top: 40px;"> | |||
| <div class="ui middle very relaxed page grid"> | |||
| <div class="column"> | |||
| <form class="ui form" action="{{.Link}}" method="post"> | |||
| @@ -30,24 +30,33 @@ | |||
| <a class="ui text center" href="datasets/label/{{.UUID}}?type={{$.Type}}" data-tooltip='{{$.i18n.Tr "dataset.create_label_task"}}'><i class="fa fa-pencil-square-o" aria-hidden="true"></i></a> | |||
| </div> | |||
| {{end}} | |||
| {{if $.Permission.CanWrite $.UnitTypeDatasets}} | |||
| {{if $.Repository.IsPrivate}} | |||
| <div class="two wide column"> | |||
| <a class="ui button mini" disabled='true' data-tooltip='{{$.i18n.Tr "dataset.how_to_public"}}'>{{$.i18n.Tr "dataset.private"}}</a> | |||
| {{if not .CanDel}} | |||
| <div class="two wide column"> | |||
| <a class="ui button mini" disabled='true'>{{if .IsPrivate}} {{$.i18n.Tr "dataset.private"}} {{else}} {{$.i18n.Tr "dataset.public"}} {{end}}</a> | |||
| </div> | |||
| {{else}} | |||
| {{if $.Permission.CanWrite $.UnitTypeDatasets}} | |||
| {{if $.Repository.IsPrivate}} | |||
| <div class="two wide column"> | |||
| <a class="ui button mini" disabled='true' data-tooltip='{{$.i18n.Tr "dataset.how_to_public"}}'>{{$.i18n.Tr "dataset.private"}}</a> | |||
| </div> | |||
| {{ else }} | |||
| <div class="two wide column"> | |||
| <div class="ui buttons mini"> | |||
| <a class="ui button mini {{if .IsPrivate}}positive active{{end}}" href="javascript:void(0)" data-dataset-status="true-{{.UUID}}" data-csrf="{{$.CsrfToken}}" data-url="{{AppSubUrl}}/attachments/private" data-uuid={{.UUID}} data-private="true" data-is-private={{.IsPrivate}}>{{$.i18n.Tr "dataset.private"}}</a> | |||
| <div class="or"></div> | |||
| <a class="ui button mini {{if not .IsPrivate}}positive active{{end}}" href="javascript:void(0)" data-dataset-status="false-{{.UUID}}" data-csrf="{{$.CsrfToken}}" data-url="{{AppSubUrl}}/attachments/private" data-uuid={{.UUID}} data-private="false" data-is-private={{.IsPrivate}}>{{$.i18n.Tr "dataset.public"}}</a> | |||
| </div> | |||
| </div> | |||
| {{end}} | |||
| <div class="two wide column right aligned"> | |||
| <a class="ui red button mini" href="javascript:void(0)" data-uuid={{.UUID}} data-dataset-delete data-remove-url="{{AppSubUrl}}/attachments/delete" data-csrf="{{$.CsrfToken}}">{{$.i18n.Tr "dataset.delete"}}</a> | |||
| </div> | |||
| {{ else }} | |||
| {{else}} | |||
| <div class="two wide column"> | |||
| <div class="ui buttons mini"> | |||
| <a class="ui button mini {{if .IsPrivate}}positive active{{end}}" href="javascript:void(0)" data-dataset-status="true-{{.UUID}}" data-csrf="{{$.CsrfToken}}" data-url="{{AppSubUrl}}/attachments/private" data-uuid={{.UUID}} data-private="true" data-is-private={{.IsPrivate}}>{{$.i18n.Tr "dataset.private"}}</a> | |||
| <div class="or"></div> | |||
| <a class="ui button mini {{if not .IsPrivate}}positive active{{end}}" href="javascript:void(0)" data-dataset-status="false-{{.UUID}}" data-csrf="{{$.CsrfToken}}" data-url="{{AppSubUrl}}/attachments/private" data-uuid={{.UUID}} data-private="false" data-is-private={{.IsPrivate}}>{{$.i18n.Tr "dataset.public"}}</a> | |||
| </div> | |||
| <a class="ui button mini" disabled='true'>{{if .IsPrivate}} {{$.i18n.Tr "dataset.private"}} {{else}} {{$.i18n.Tr "dataset.public"}} {{end}}</a> | |||
| </div> | |||
| {{end}} | |||
| <div class="two wide column right aligned"> | |||
| <a class="ui red button mini" href="javascript:void(0)" data-uuid={{.UUID}} data-dataset-delete data-remove-url="{{AppSubUrl}}/attachments/delete" data-csrf="{{$.CsrfToken}}">{{$.i18n.Tr "dataset.delete"}}</a> | |||
| </div> | |||
| {{end}} | |||
| </div> | |||
| </div> | |||
| @@ -144,11 +144,12 @@ | |||
| {{svg "octicon-server" 16}} {{.i18n.Tr "repo.cloudbrain"}} | |||
| </a> | |||
| {{end}} | |||
| {{if .IsSigned}} | |||
| <a class="{{if .PageIsBlockChain}}active{{end}} item " href="{{.RepoLink}}/blockchain"> | |||
| {{svg "octicon-law" 16}} | |||
| {{.i18n.Tr "repo.balance"}} | |||
| </a> | |||
| {{end}} | |||
| {{template "custom/extra_tabs" .}} | |||
| @@ -1,5 +1,5 @@ | |||
| {{template "base/head" .}} | |||
| <div class="repository new migrate"> | |||
| <div class="repository new migrate" style="margin-top: 40px;"> | |||
| <div class="ui middle very relaxed page grid"> | |||
| <div class="column"> | |||
| <form class="ui form" action="{{.Link}}" method="post"> | |||
| @@ -232,13 +232,13 @@ | |||
| <div class="ui two column stackable grid"> | |||
| <div class="column"> | |||
| </div> | |||
| <div class="column right aligned"> | |||
| <!-- <div class="column right aligned"> | |||
| <div class="ui right dropdown type jump item"> | |||
| <span class="text"> | |||
| {{.i18n.Tr "repo.issues.filter_sort"}}<i class="dropdown icon"></i> | |||
| </span> | |||
| </div> | |||
| </div> | |||
| </div> --> | |||
| </div> | |||
| </div> | |||
| @@ -247,99 +247,51 @@ | |||
| {{range .Tasks}} | |||
| <div class="ui grid stackable item"> | |||
| <div class="row"> | |||
| <!-- 任务名 --> | |||
| <div class="four wide column"> | |||
| <div class="six wide column"> | |||
| <a class="title" href="{{$.Link}}/{{.JobID}}"> | |||
| <span class="fitted">{{svg "octicon-tasklist" 16}}</span> | |||
| <span class="fitted">{{.JobName}}</span> | |||
| </a> | |||
| </div> | |||
| <!--任务状态 --> | |||
| <div class="three wide column job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||
| {{.Status}} | |||
| </div> | |||
| <!-- 任务创建时间 --> | |||
| <div class="three wide column"> | |||
| <span class="ui text center">{{svg "octicon-flame" 16}} {{TimeSinceUnix .CreatedUnix $.Lang}}</span> | |||
| </div> | |||
| <!-- 查看 --> | |||
| <div class="one wide column"> | |||
| <span class="ui text clipboard"> | |||
| <a class="title" href="{{$.Link}}/{{.JobID}}"> | |||
| <span class="fitted">查看</span> | |||
| </a> | |||
| <!--任务状态 --> | |||
| <span class="ui compact button job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||
| {{.Status}} | |||
| </span> | |||
| <!-- 任务创建时间 --> | |||
| <span class="">{{TimeSinceUnix .CreatedUnix $.Lang}}</span> | |||
| </div> | |||
| <!-- 删除任务 --> | |||
| <div class="one wide column"> | |||
| <div class="ui text center clipboard"> | |||
| <form id="delForm-{{.JobID}}" action="{{if ne .Status "STOPPED"}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/del{{end}}" method="post"> | |||
| <div class="seven wide column text right"> | |||
| <div class="ui compact buttons" style="margin-right:10px;"> | |||
| <a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}"> | |||
| 查看 | |||
| </a> | |||
| <a class="ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.Link}}/{{.JobID}}/debug"> | |||
| 调试 | |||
| </a> | |||
| <form id="stopForm-{{.JobID}}" action="{{if ne .Status "RUNNING"}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/stop{{end}}" method="post" style="margin-left:-1px;"> | |||
| {{$.CsrfTokenHtml}} | |||
| <a class="fitted" onclick="assertDelete(this)" style="{{if ne .Status "STOPPED"}}color:#CCCCCC{{end}}; font-size:16px; font-weight:bold">删除</a> | |||
| <a class="ui basic {{if ne .Status "RUNNING"}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();"> | |||
| 停止 | |||
| </a> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| <!-- 调试 --> | |||
| <div class="one wide column"> | |||
| <div class="ui text center clipboard"> | |||
| <a class="title" onclick="stop(this)" href="{{if not .CanDebug}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/debug{{end}}" style="{{if not .CanDebug}}color:#CCCCCC{{end}}"> | |||
| <span class="fitted">调试</span> | |||
| </a> | |||
| </div> | |||
| <!-- 删除任务 --> | |||
| <form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{if ne .Status "STOPPED"}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/del{{end}}" method="post"> | |||
| {{$.CsrfTokenHtml}} | |||
| <a class="ui compact {{if ne .Status "STOPPED"}}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||
| 删除 | |||
| </a> | |||
| </form> | |||
| </div> | |||
| <!-- 停止 --> | |||
| <div class="one wide column"> | |||
| <div class="ui text center clipboard"> | |||
| <form id="stopForm-{{.JobID}}" action="{{if ne .Status "RUNNING"}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/stop{{end}}" method="post"> | |||
| {{$.CsrfTokenHtml}} | |||
| <a class="fitted" onclick="document.getElementById('stopForm-{{.JobID}}').submit();" style="{{if ne .Status "RUNNING"}}color:#CCCCCC{{end}}; font-size:16px; font-weight:bold">停止</a> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| <!-- 镜像列表弹窗 --> | |||
| <div id="imageModal" class="modal" style="display: none;"> | |||
| <div class="modal-content"> | |||
| <span class="close">×</span> | |||
| <!-- 表格 --> | |||
| <form id="commitImageForm" action="{{$.Link}}/{{.JobID}}/commit_image" method="post" target="iframeContent"> | |||
| {{$.CsrfTokenHtml}} | |||
| <p>提交任务镜像</p> | |||
| <div class="ui divider"></div> | |||
| <div class="inline required field dis"> | |||
| <label>镜像标签:</label> | |||
| <input name="tag" id="image_tag" tabindex="3" autofocus required maxlength="255" style="width:75%"> | |||
| </div> | |||
| <div class="inline required field" style="position:relative;height:180px;"> | |||
| <div style="height:20px;width:75px;"> | |||
| <label>镜像描述:</label> | |||
| </div> | |||
| <div style="position:absolute;left:75px;top:0;width:75%"> | |||
| <textarea name="description" rows="10" style="width:100%"></textarea> | |||
| </div> | |||
| </div> | |||
| <div class="ui divider"></div> | |||
| <div class="inline field"> | |||
| <label></label> | |||
| <button class="ui green button" onclick="showmask()"> | |||
| {{$.i18n.Tr "repo.cloudbrain.commit_image"}} | |||
| </button> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -418,7 +370,9 @@ | |||
| } | |||
| // 加载任务状态 | |||
| $(document).ready(function() { | |||
| var timeid = window.setInterval(loadJobStatus, 15000); | |||
| $(document).ready(loadJobStatus); | |||
| function loadJobStatus() { | |||
| $(".job-status").each((index, job) => { | |||
| const jobID = job.dataset.jobid; | |||
| const repoPath = job.dataset.repopath; | |||
| @@ -429,13 +383,17 @@ | |||
| $.get(`/api/v1/repos/${repoPath}/modelarts/${jobID}`, (data) => { | |||
| const jobID = data.JobID | |||
| const status = data.JobStatus | |||
| $('#' + jobID).text(status) | |||
| // console.log(data) | |||
| if (status != job.textContent.trim()) { | |||
| //$('#' + jobID).text(status) | |||
| //if (status == 'STOPPED') { | |||
| window.location.reload() | |||
| //} | |||
| } | |||
| }).fail(function(err) { | |||
| console.log(err); | |||
| }); | |||
| }); | |||
| }); | |||
| }; | |||
| // 获取弹窗 | |||
| var modal = document.getElementById('imageModal'); | |||
| @@ -100,7 +100,10 @@ | |||
| <div class="repository new repo ui middle very relaxed page grid"> | |||
| <div class="column"> | |||
| {{template "base/alert" .}} | |||
| <form class="ui form" action="{{.Link}}" method="post"> | |||
| <div class="ui positive message" id="messageInfo"> | |||
| <p></p> | |||
| </div> | |||
| <form class="ui form" id="form_id" action="{{.Link}}" method="post"> | |||
| {{.CsrfTokenHtml}} | |||
| <h3 class="ui top attached header"> | |||
| {{.i18n.Tr "repo.cloudbrain.new"}} | |||
| @@ -117,7 +120,7 @@ | |||
| <input type="text" list="cloudbrain_dataset" placeholder="选择数据集" name="" id="answerInput" autofocus maxlength="36"> | |||
| <datalist id="cloudbrain_dataset" class="ui search" style='width:385px' name="attachment"> | |||
| {{range .attachments}} | |||
| <option name="attachment" value="{{.UUID}}">{{.Attachment.Name}}</option> | |||
| <option name="attachment" data-value="{{.UUID}}">{{.Attachment.Name}}</option> | |||
| {{end}} | |||
| </datalist> | |||
| <input type="hidden" name="attachment" id="answerInput-hidden"> | |||
| @@ -125,11 +128,11 @@ | |||
| <div class="inline required field"> | |||
| <label>工作环境</label> | |||
| <input name="de" id="cloudbrain_de" value="{{.env}}" tabindex="3" autofocus required maxlength="255" readonly="readonly"> | |||
| <input name="de" id="cloudbrain_de" value="{{.env}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>类型</label> | |||
| <input name="job_type" id="cloudbrain_job_type" value="{{.notebook_type}}" tabindex="3" autofocus required maxlength="255" readonly="readonly"> | |||
| <input name="job_type" id="cloudbrain_job_type" value="{{.notebook_type}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>规格</label> | |||
| @@ -142,7 +145,7 @@ | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>数据集存放路径</label> | |||
| <input name="dataset_path" id="cloudbrain_dataset_path" value="{{.dataset_path}}" tabindex="3" autofocus required maxlength="255" readonly="readonly"> | |||
| <input name="dataset_path" id="cloudbrain_dataset_path" value="{{.dataset_path}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
| </div> | |||
| <div class="inline field"> | |||
| <label>描述</label> | |||
| @@ -150,7 +153,7 @@ | |||
| </div> | |||
| <div class="inline field"> | |||
| <label></label> | |||
| <button class="ui green button" onclick="showmask()"> | |||
| <button class="ui green button"> | |||
| {{.i18n.Tr "repo.cloudbrain.new"}} | |||
| </button> | |||
| <a class="ui button" href="/">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||
| @@ -163,10 +166,38 @@ | |||
| {{template "base/footer" .}} | |||
| <script> | |||
| // 点击按钮后遮罩层显示 | |||
| function showmask() { | |||
| // 取消创建跳转 | |||
| let url_href = window.location.pathname.split('create')[0] | |||
| $(".ui.button").attr('href',url_href) | |||
| // 判断必填选项是否填写正确 | |||
| let form = document.getElementById('form_id'); | |||
| $('#messageInfo').css('display','none') | |||
| form.onsubmit = function(e){ | |||
| let value_task = $("input[name='job_name']").val() | |||
| let re = /^[a-z0-9][a-z0-9-_]{1,36}$/ | |||
| let flag = re.test(value_task) | |||
| if(!flag){ | |||
| $('#messageInfo').css('display','block') | |||
| let str = '只能以小写字母或数字开头且只包含小写字母、数字、_和-、最长36个字符。' | |||
| $('#messageInfo p').text(str) | |||
| return false | |||
| } | |||
| let min_value_task = value_task.toLowerCase() | |||
| $("input[name='job_name']").attr("value",min_value_task) | |||
| document.getElementById("mask").style.display = "block" | |||
| } | |||
| // 点击按钮后遮罩层显示 | |||
| // function showmask() { | |||
| // document.getElementById("mask").style.display = "block" | |||
| // } | |||
| // 页面加载完毕后遮罩层隐藏 | |||
| document.onreadystatechange = function() { | |||
| @@ -223,7 +223,7 @@ export default { | |||
| } | |||
| //不同数据集上传同一个文件 | |||
| if (file.datasetID != '') { | |||
| if (Number(file.datasetID) != file.datasetId) { | |||
| if (file.datasetName != "" && file.realName != "") { | |||
| var info = "该文件已上传,对应数据集(" + file.datasetName + ")-文件(" + file.realName + ")"; | |||
| window.alert(info); | |||
| window.location.reload(); | |||
| @@ -219,8 +219,8 @@ export default { | |||
| await addAttachment(file); | |||
| } | |||
| //不同数据集上传同一个文件 | |||
| if (file.datasetID != '') { | |||
| if (Number(file.datasetID) != file.datasetId) { | |||
| if (file.datasetID != '' ) { | |||
| if (file.datasetName != "" && file.realName != "") { | |||
| var info = "该文件已上传,对应数据集(" + file.datasetName + ")-文件(" + file.realName + ")"; | |||
| window.alert(info); | |||
| window.location.reload(); | |||
| @@ -143,10 +143,9 @@ | |||
| } | |||
| } | |||
| .item { | |||
| padding-top: 15px; | |||
| padding-bottom: 10px; | |||
| border-bottom: 1px dashed #aaaaaa; | |||
| border-bottom: 1px solid rgba(34,36,38,.15); | |||
| } | |||
| .ui.grid > .row { | |||
| align-items: center; | |||
| } | |||
| @@ -79,9 +79,11 @@ | |||
| &.profile { | |||
| .members { | |||
| .ui.avatar { | |||
| width: 48px; | |||
| height: 48px; | |||
| width: 44px; | |||
| height: 44px; | |||
| margin-right: 5px; | |||
| margin-bottom: 5px; | |||
| border-radius: 22px; | |||
| } | |||
| } | |||
| } | |||
| @@ -2764,6 +2764,8 @@ tbody.commit-list { | |||
| .text { | |||
| width: 100%; | |||
| overflow: hidden; | |||
| height: 36px; | |||
| line-height: 36px; | |||
| } | |||
| } | |||