diff --git a/custom/conf/app.ini.sample b/custom/conf/app.ini.sample index d294c8823..7a4298f6b 100755 --- a/custom/conf/app.ini.sample +++ b/custom/conf/app.ini.sample @@ -1141,3 +1141,9 @@ growth_issue=0.2 growth_contributors=0.2 growth_commit=0.2 growth_comments=0.2 + + +[grampus] +USERNAME = +PASSWORD = +SERVER_HOST = diff --git a/models/action.go b/models/action.go index 9b92b4192..288186b2c 100755 --- a/models/action.go +++ b/models/action.go @@ -50,14 +50,16 @@ const ( ActionRejectPullRequest // 22 ActionCommentPull // 23 - ActionUploadAttachment //24 - ActionCreateDebugGPUTask //25 - ActionCreateDebugNPUTask //26 - ActionCreateTrainTask //27 - ActionCreateInferenceTask // 28 - ActionCreateBenchMarkTask //29 - ActionCreateNewModelTask //30 - ActionCreateGPUTrainTask //31 + ActionUploadAttachment //24 + ActionCreateDebugGPUTask //25 + ActionCreateDebugNPUTask //26 + ActionCreateTrainTask //27 + ActionCreateInferenceTask // 28 + ActionCreateBenchMarkTask //29 + ActionCreateNewModelTask //30 + ActionCreateGPUTrainTask //31 + ActionCreateGrampusNPUTrainTask //32 + ActionCreateGrampusGPUTrainTask //33 ) // Action represents user operation type and other information to diff --git a/models/attachment.go b/models/attachment.go index 6fb98a07d..3503dcb73 100755 --- a/models/attachment.go +++ b/models/attachment.go @@ -110,8 +110,15 @@ func (a *Attachment) IncreaseDownloadCount() error { } func IncreaseAttachmentUseNumber(uuid string) error { + + uuidArray := strings.Split(uuid, ";") + for i := range uuidArray { + uuidArray[i] = "'" + uuidArray[i] + "'" + } + + uuidInCondition := "(" + strings.Join(uuidArray, ",") + ")" // Update use number. - if _, err := x.Exec("UPDATE `attachment` SET use_number=use_number+1 WHERE uuid=?", uuid); err != nil { + if _, err := x.Exec("UPDATE `attachment` SET use_number=use_number+1 WHERE uuid in " + uuidInCondition); err != nil { return fmt.Errorf("increase attachment use count: %v", err) } @@ -560,6 +567,36 @@ func GetAttachmentSizeByDatasetID(datasetID int64) (int64, error) { return total, nil } +func AttachmentsByDatasetOption(datasets []int64, opts *SearchDatasetOptions) ([]*Attachment, error) { + sess := x.NewSession() + defer sess.Close() + var cond = builder.NewCond() + cond = cond.And(builder.In("attachment.dataset_id", datasets)) + if opts.JustNeedZipFile { + cond = cond.And(builder.Gt{"attachment.decompress_state": 0}) + } + if opts.PublicOnly { + cond = cond.And(builder.Eq{"attachment.is_private": false}) + } + if opts.CloudBrainType >= 0 { + cond = cond.And(builder.Eq{"attachment.type": opts.CloudBrainType}) + } + if opts.UploadAttachmentByMe { + cond = cond.And( + builder.Eq{"attachment.uploader_id": opts.User.ID}, + ) + } + + + attachments := make([]*Attachment, 0) + if err := sess.Table(&Attachment{}).Where(cond).Desc("id"). + Find(&attachments); err != nil { + return nil, fmt.Errorf("Find: %v", err) + } + return attachments, nil + +} + func GetAllAttachmentSize() (int64, error) { return x.SumInt(&Attachment{}, "size") } diff --git a/models/cloudbrain.go b/models/cloudbrain.go index 4b4c2c099..8e1b94a97 100755 --- a/models/cloudbrain.go +++ b/models/cloudbrain.go @@ -2,6 +2,7 @@ package models import ( "encoding/json" + "errors" "fmt" "strconv" "strings" @@ -24,7 +25,7 @@ type ModelArtsJobStatus string const ( TypeCloudBrainOne int = iota TypeCloudBrainTwo - TypeIntelligentNet + TypeC2Net //智算网络 TypeCloudBrainAll = -1 ) @@ -99,6 +100,15 @@ const ( ModelArtsTrainJobCheckFailed ModelArtsJobStatus = "CHECK_FAILED" //审核作业失败 DURATION_STR_ZERO = "00:00:00" + + //grampus + GrampusStatusPending = "pending" + GrampusStatusRunning = "RUNNING" + GrampusStatusFailed = "FAILED" + GrampusStatusSucceeded = "SUCCEEDED" + GrampusStatusStopped = "STOPPED" + GrampusStatusUnknown = "UNKNOWN" + GrampusStatusWaiting = "WAITING" ) type Cloudbrain struct { @@ -138,6 +148,8 @@ type Cloudbrain struct { PreVersionName string //父版本名称 ComputeResource string //计算资源,例如npu EngineID int64 //引擎id + ImageID string //grampus image_id + AiCenter string //grampus ai center: center_id+center_name TrainUrl string //输出模型的obs路径 BranchName string //分支名称 @@ -206,7 +218,7 @@ func ConvertDurationToStr(duration int64) string { } func IsTrainJobTerminal(status string) bool { - return status == string(ModelArtsTrainJobCompleted) || status == string(ModelArtsTrainJobFailed) || status == string(ModelArtsTrainJobKilled) + return status == string(ModelArtsTrainJobCompleted) || status == string(ModelArtsTrainJobFailed) || status == string(ModelArtsTrainJobKilled) || status == GrampusStatusFailed || status == GrampusStatusStopped || status == GrampusStatusSucceeded } func IsModelArtsDebugJobTerminal(status string) bool { @@ -554,6 +566,17 @@ type FlavorInfo struct { Desc string `json:"desc"` } +type SpecialPools struct { + Pools []*SpecialPool `json:"pools"` +} +type SpecialPool struct { + Org string `json:"org"` + Type string `json:"type"` + IsExclusive bool `json:"isExclusive"` + Pool []*GpuInfo `json:"pool"` + JobType []string `json:"jobType"` +} + type ImageInfosModelArts struct { ImageInfo []*ImageInfoModelArts `json:"image_info"` } @@ -977,6 +1000,16 @@ type Parameter struct { type Parameters struct { Parameter []Parameter `json:"parameter"` } +type Datasurl struct { + DatasetUrl string `json:"dataset_url"` + DatasetName string `json:"dataset_name"` +} + +type DatasetDownload struct { + DatasetName string `json:"dataset_name"` + DatasetDownloadLink string `json:"dataset_download_link"` + RepositoryLink string `json:"repository_link"` +} type DataSource struct { DatasetID string `json:"dataset_id"` @@ -1156,6 +1189,88 @@ type LogFile struct { Name string } +//Grampus +type GrampusResult struct { + ErrorCode int `json:"errorCode"` + ErrorMsg string `json:"errorMsg"` +} + +type GrampusJobInfo struct { + StartedAt int64 `json:"startedAt"` + RunSec int64 `json:"runSec"` + CompletedAt int64 `json:"completedAt"` + CreatedAt int64 `json:"createdAt"` + UpdatedAt int64 `json:"updatedAt"` + Desc string `json:"desc"` + JobID string `json:"id"` + Name string `json:"name"` + Status string `json:"status"` + UserID string `json:"userId"` + Tasks []GrampusTasks `json:"tasks"` +} +type Center struct { + ID string `json:"id"` + Name string `json:"name"` +} +type GrampusSpec struct { + CreatedAt int64 `json:"createdAt"` + UpdatedAt int64 `json:"updatedAt"` + ID string `json:"id"` + Name string `json:"name"` + ProcessorType string `json:"processorType"` + Centers []Center `json:"centers"` +} + +type GetGrampusResourceSpecsResult struct { + GrampusResult + Infos []GrampusSpec `json:"resourceSpecs"` +} + +type GrampusImage struct { + CreatedAt int64 `json:"createdAt"` + UpdatedAt int64 `json:"updatedAt"` + ID string `json:"id"` + Name string `json:"name"` + ProcessorType string `json:"processorType"` +} + +type GetGrampusImagesResult struct { + GrampusResult + TotalSize int `json:"totalSize"` + Infos []GrampusImage `json:"images"` +} + +type CreateGrampusJobResponse struct { + GrampusResult + JobInfo GrampusJobInfo `json:"otJob"` +} + +type GetGrampusJobResponse struct { + GrampusResult + JobInfo GrampusJobInfo `json:"otJob"` +} + +type GrampusStopJobResponse struct { + GrampusResult + StoppedAt int64 `json:"stoppedAt"` +} + +type GrampusTasks struct { + Command string `json:"command"` + Name string `json:"name"` + ImageId string `json:"imageId"` + ResourceSpecId string `json:"resourceSpecId"` + ImageUrl string `json:"imageUrl"` + CenterID []string `json:"centerID"` + CenterName []string `json:"centerName"` + ReplicaNum int `json:"replicaNum"` +} + +type CreateGrampusJobRequest struct { + Name string `json:"name"` + Tasks []GrampusTasks `json:"tasks"` +} + type GetTrainJobMetricStatisticResult struct { TrainJobResult Interval int `json:"interval"` //查询的时间间隔,单位为分钟 @@ -1201,6 +1316,12 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { ) } + if len(opts.ComputeResource) > 0 { + cond = cond.And( + builder.Eq{"cloudbrain.compute_resource": opts.ComputeResource}, + ) + } + if len(opts.JobTypes) > 0 { if opts.JobTypeNot { cond = cond.And( @@ -1456,6 +1577,11 @@ func GetCloudbrainByJobID(jobID string) (*Cloudbrain, error) { return getRepoCloudBrain(cb) } +func GetCloudbrainByJobIDWithDeleted(jobID string) (*Cloudbrain, error) { + cb := &Cloudbrain{JobID: jobID} + return getRepoCloudBrainWithDeleted(cb) +} + func GetCloudbrainByID(id string) (*Cloudbrain, error) { idInt64, _ := strconv.ParseInt(id, 10, 64) cb := &Cloudbrain{ID: idInt64} @@ -1634,6 +1760,11 @@ func GetCloudbrainInferenceJobCountByUserID(userID int64) (int, error) { return int(count), err } +func GetGrampusCountByUserID(userID int64, jobType, computeResource string) (int, error) { + count, err := x.In("status", GrampusStatusWaiting, GrampusStatusRunning).And("job_type = ? and user_id = ? and type = ?", jobType, userID, TypeC2Net).And("compute_resource = ?", computeResource).Count(new(Cloudbrain)) + return int(count), err +} + func UpdateInferenceJob(job *Cloudbrain) error { return updateInferenceJob(x, job) } @@ -1839,3 +1970,51 @@ func CloudbrainAllStatic(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, er } return cloudbrains, count, nil } + +type DatasetInfo struct { + DataLocalPath string + Name string +} + +func GetDatasetInfo(uuidStr string) (map[string]DatasetInfo, string, error) { + var datasetNames string + uuids := strings.Split(uuidStr, ";") + if len(uuids) > setting.MaxDatasetNum { + log.Error("the dataset count(%d) exceed the limit", len(uuids)) + return nil, datasetNames, errors.New("the dataset count exceed the limit") + } + + datasetInfos := make(map[string]DatasetInfo) + attachs, err := GetAttachmentsByUUIDs(uuids) + if err != nil { + log.Error("GetAttachmentsByUUIDs failed: %v", err) + return nil, datasetNames, err + } + for i, attach := range attachs { + fileName := strings.TrimSuffix(strings.TrimSuffix(strings.TrimSuffix(attach.Name, ".zip"), ".tar.gz"), ".tgz") + for _, datasetInfo := range datasetInfos { + if fileName == datasetInfo.Name { + log.Error("the dataset name is same: %v", attach.Name) + return nil, datasetNames, errors.New("the dataset name is same") + } + } + + dataLocalPath := setting.Attachment.Minio.RealPath + + setting.Attachment.Minio.Bucket + "/" + + setting.Attachment.Minio.BasePath + + AttachmentRelativePath(attach.UUID) + + attach.UUID + + datasetInfos[attach.UUID] = DatasetInfo{ + DataLocalPath: dataLocalPath, + Name: fileName, + } + if i == 0 { + datasetNames = attach.Name + } else { + datasetNames += ";" + attach.Name + } + } + + return datasetInfos, datasetNames, nil +} diff --git a/models/cloudbrain_image.go b/models/cloudbrain_image.go old mode 100644 new mode 100755 index f72c6a27c..71f0c2c94 --- a/models/cloudbrain_image.go +++ b/models/cloudbrain_image.go @@ -68,6 +68,7 @@ type SearchImageOptions struct { IncludeCustom bool IncludeOwnerOnly bool Topics string + CloudbrainType int ListOptions SearchOrderBy } @@ -411,6 +412,10 @@ func SearchImageCondition(opts *SearchImageOptions) builder.Cond { } + if opts.CloudbrainType > 0 { + cond = cond.And(builder.Eq{"cloudbrain_type": opts.CloudbrainType}) + } + return cond } diff --git a/models/custom_migrations.go b/models/custom_migrations.go old mode 100644 new mode 100755 index 412bedce1..65b53f0f4 --- a/models/custom_migrations.go +++ b/models/custom_migrations.go @@ -15,13 +15,9 @@ type CustomMigrationStatic struct { Migrate func(*xorm.Engine, *xorm.Engine) error } -var customMigrations = []CustomMigration{ - {"Custom v1 Topic struct change to support chinese", syncTopicStruct}, -} +var customMigrations []CustomMigration -var customMigrationsStatic = []CustomMigrationStatic{ - {"update issue_fixed_rate to 1 if num_issues is 0 ", updateIssueFixedRate}, -} +var customMigrationsStatic []CustomMigrationStatic func MigrateCustom(x *xorm.Engine) { diff --git a/models/dataset.go b/models/dataset.go index b7186ac0b..7f049f068 100755 --- a/models/dataset.go +++ b/models/dataset.go @@ -81,12 +81,14 @@ func (datasets DatasetList) loadAttributes(e Engine) error { if err := e. Where("id > 0"). In("id", keysInt64(userIdSet)). + Cols("id", "lower_name", "name", "full_name", "email"). Find(&users); err != nil { return fmt.Errorf("find users: %v", err) } if err := e. Where("id > 0"). In("id", keysInt64(set)). + Cols("id", "owner_id", "owner_name", "lower_name", "name", "description", "alias", "lower_alias","is_private"). Find(&repos); err != nil { return fmt.Errorf("find repos: %v", err) } @@ -98,19 +100,94 @@ func (datasets DatasetList) loadAttributes(e Engine) error { return nil } +func (datasets DatasetList) loadAttachmentAttributes(opts *SearchDatasetOptions) error { + if len(datasets) == 0 { + return nil + } + datasetIDs := make([]int64, len(datasets)) + for i := range datasets { + datasetIDs[i] = datasets[i].ID + } + attachments, err := AttachmentsByDatasetOption(datasetIDs, opts) + if err != nil { + return fmt.Errorf("GetAttachmentsByDatasetIds failed error: %v", err) + } + + permissionMap := make(map[int64]bool, len(datasets)) + + for _, attachment := range attachments { + + for i := range datasets { + if attachment.DatasetID == datasets[i].ID { + if opts.StarByMe { + + permission,ok := permissionMap[datasets[i].ID]; + if !ok { + + permission = false + datasets[i].Repo.GetOwner() + if datasets[i].Repo.Owner.IsOrganization() { + if datasets[i].Repo.Owner.IsUserPartOfOrg(opts.User.ID) { + log.Info("user is member of org.") + permission = true + } + } + if !permission { + isCollaborator, _ := datasets[i].Repo.IsCollaborator(opts.User.ID) + if isCollaborator { + log.Info("Collaborator user may visit the attach.") + permission = true + } + } + + permissionMap[datasets[i].ID]=permission + } + + if permission{ + datasets[i].Attachments = append(datasets[i].Attachments, attachment) + } else if !attachment.IsPrivate { + datasets[i].Attachments = append(datasets[i].Attachments, attachment) + } + } else { + datasets[i].Attachments = append(datasets[i].Attachments, attachment) + } + + } + + } + + } + + for i := range datasets { + if datasets[i].Attachments==nil{ + datasets[i].Attachments=[]*Attachment{} + } + datasets[i].Repo.Owner = nil + } + return nil + +} + type SearchDatasetOptions struct { Keyword string OwnerID int64 + User *User RepoID int64 IncludePublic bool RecommendOnly bool Category string Task string License string - DatasetIDs []int64 + DatasetIDs []int64 // 目前只在StarByMe为true时起作用 ListOptions SearchOrderBy - IsOwner bool + IsOwner bool + StarByMe bool + CloudBrainType int //0 cloudbrain 1 modelarts -1 all + PublicOnly bool + JustNeedZipFile bool + NeedAttachment bool + UploadAttachmentByMe bool } func CreateDataset(dataset *Dataset) (err error) { @@ -159,29 +236,40 @@ func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond { if opts.RepoID > 0 { cond = cond.And(builder.Eq{"dataset.repo_id": opts.RepoID}) } - if opts.IncludePublic { + + if opts.PublicOnly { + cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic}) + cond = cond.And(builder.Eq{"attachment.is_private": false}) + } else if opts.IncludePublic { cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic}) cond = cond.And(builder.Eq{"attachment.is_private": false}) if opts.OwnerID > 0 { - subCon := builder.NewCond() subCon = subCon.And(builder.Eq{"repository.owner_id": opts.OwnerID}) subCon = generateFilterCond(opts, subCon) cond = cond.Or(subCon) } - } else if opts.OwnerID > 0 { + } else if opts.OwnerID > 0 && !opts.StarByMe && !opts.UploadAttachmentByMe { cond = cond.And(builder.Eq{"repository.owner_id": opts.OwnerID}) if !opts.IsOwner { cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic}) cond = cond.And(builder.Eq{"attachment.is_private": false}) } } - if len(opts.DatasetIDs) > 0 { - subCon := builder.NewCond() - subCon = subCon.And(builder.In("dataset.id", opts.DatasetIDs)) - cond = cond.Or(subCon) + if opts.StarByMe { + cond = cond.And(builder.In("dataset.id", opts.DatasetIDs)) + } else { + subCon := builder.NewCond() + subCon = subCon.And(builder.In("dataset.id", opts.DatasetIDs)) + subCon = generateFilterCond(opts, subCon) + cond = cond.Or(subCon) + } + } else { + if opts.StarByMe { + cond = cond.And(builder.Eq{"dataset.id": -1}) + } } return cond @@ -207,6 +295,17 @@ func generateFilterCond(opts *SearchDatasetOptions, cond builder.Cond) builder.C cond = cond.And(builder.Eq{"dataset.recommend": opts.RecommendOnly}) } + if opts.JustNeedZipFile { + cond = cond.And(builder.Gt{"attachment.decompress_state": 0}) + } + + if opts.CloudBrainType >= 0 { + cond = cond.And(builder.Eq{"attachment.type": opts.CloudBrainType}) + } + if opts.UploadAttachmentByMe { + cond = cond.And(builder.Eq{"attachment.uploader_id": opts.User.ID}) + } + return cond } @@ -233,7 +332,6 @@ func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (Da sess.Select(selectColumnsSql).Join("INNER", "repository", "repository.id = dataset.repo_id"). Join("INNER", "attachment", "attachment.dataset_id=dataset.id"). Where(cond).OrderBy(opts.SearchOrderBy.String()) - if opts.PageSize > 0 { sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) } @@ -245,6 +343,12 @@ func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (Da return nil, 0, fmt.Errorf("LoadAttributes: %v", err) } + if opts.NeedAttachment { + if err = datasets.loadAttachmentAttributes(opts); err != nil { + return nil, 0, fmt.Errorf("LoadAttributes: %v", err) + } + } + return datasets, count, nil } @@ -361,10 +465,22 @@ func UpdateDataset(ctx DBContext, rel *Dataset) error { func IncreaseDatasetUseCount(uuid string) { IncreaseAttachmentUseNumber(uuid) + attachments, _ := GetAttachmentsByUUIDs(strings.Split(uuid, ";")) + + countMap := make(map[int64]int) + + for _, attachment := range attachments { + value, ok := countMap[attachment.DatasetID] + if ok { + countMap[attachment.DatasetID] = value + 1 + } else { + countMap[attachment.DatasetID] = 1 + } + + } - attachment, _ := GetAttachmentByUUID(uuid) - if attachment != nil { - x.Exec("UPDATE `dataset` SET use_count=use_count+1 WHERE id=?", attachment.DatasetID) + for key, value := range countMap { + x.Exec("UPDATE `dataset` SET use_count=use_count+? WHERE id=?", value, key) } } @@ -460,5 +576,12 @@ func GetCollaboratorDatasetIdsByUserID(userID int64) []int64 { _ = x.Table("dataset").Join("INNER", "collaboration", "dataset.repo_id = collaboration.repo_id and collaboration.mode>0 and collaboration.user_id=?", userID). Cols("dataset.id").Find(&datasets) return datasets +} +func GetTeamDatasetIdsByUserID(userID int64) []int64 { + var datasets []int64 + _ = x.Table("dataset").Join("INNER", "team_repo", "dataset.repo_id = team_repo.repo_id"). + Join("INNER", "team_user", "team_repo.team_id=team_user.team_id and team_user.uid=?", userID). + Cols("dataset.id").Find(&datasets) + return datasets } diff --git a/models/dataset_star.go b/models/dataset_star.go index 4b22c2855..2cbd9dc8d 100644 --- a/models/dataset_star.go +++ b/models/dataset_star.go @@ -68,3 +68,10 @@ func isDatasetStaring(e Engine, userID, datasetID int64) bool { has, _ := e.Get(&DatasetStar{0, userID, datasetID, 0}) return has } + +func GetDatasetIdsStarByUser(userID int64) []int64 { + var datasets []int64 + _ = x.Table("dataset_star").Where("uid=?", userID). + Cols("dataset_star.dataset_id").Find(&datasets) + return datasets +} diff --git a/models/repo.go b/models/repo.go index db2694617..4770e5415 100755 --- a/models/repo.go +++ b/models/repo.go @@ -2749,15 +2749,10 @@ func ReadLatestFileInRepo(userName, repoName, refName, treePath string) (*RepoFi log.Error("ReadLatestFileInRepo: Close: %v", err) } }() - - buf := make([]byte, 1024) - n, _ := reader.Read(buf) - if n >= 0 { - buf = buf[:n] - } + d, _ := ioutil.ReadAll(reader) commitId := "" if blob != nil { commitId = fmt.Sprint(blob.ID) } - return &RepoFile{CommitId: commitId, Content: buf}, nil + return &RepoFile{CommitId: commitId, Content: d}, nil } diff --git a/models/user_business_analysis.go b/models/user_business_analysis.go index 4cd3539d7..e058c0df8 100644 --- a/models/user_business_analysis.go +++ b/models/user_business_analysis.go @@ -955,6 +955,8 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, return err } userNewAddActivity := make(map[int64]map[int64]int64) + userAcitvateJsonMap := make(map[int64]map[int64]int64) + userCurrentDayRegistMap := make(map[int64]map[int64]int64) ParaWeight := getParaWeight() userMetrics := make(map[string]int) var indexTotal int64 @@ -1028,7 +1030,10 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, log.Info("has activity." + userRecord.Name) addUserToMap(userNewAddActivity, userRecord.CreatedUnix, dateRecord.ID) } - + if userRecord.IsActive { + addUserToMap(userAcitvateJsonMap, userRecord.CreatedUnix, dateRecord.ID) + } + addUserToMap(userCurrentDayRegistMap, userRecord.CreatedUnix, dateRecord.ID) } indexTotal += PAGE_SIZE @@ -1064,36 +1069,61 @@ func CounDataByDateAndReCount(wikiCountMap map[string]int, startTime time.Time, } statictisSess.Insert(&useMetrics) //update new user activity - updateNewUserAcitivity(userNewAddActivity, statictisSess) + updateNewUserAcitivity(userNewAddActivity, userAcitvateJsonMap, userCurrentDayRegistMap, statictisSess) return nil } -func updateNewUserAcitivity(currentUserActivity map[int64]map[int64]int64, statictisSess *xorm.Session) { - for key, value := range currentUserActivity { +func updateNewUserAcitivity(currentUserActivity map[int64]map[int64]int64, userAcitvateJsonMap map[int64]map[int64]int64, userCurrentDayRegistMap map[int64]map[int64]int64, statictisSess *xorm.Session) { + for key, value := range userCurrentDayRegistMap { useMetrics := &UserMetrics{CountDate: key} + userAcitvateValue := userAcitvateJsonMap[key] + HuodongValue := currentUserActivity[key] has, err := statictisSess.Get(useMetrics) if err == nil && has { - userIdArrays := strings.Split(useMetrics.HasActivityUserJson, ",") - for _, userIdStr := range userIdArrays { - userIdInt, err := strconv.ParseInt(userIdStr, 10, 64) - if err == nil { - value[userIdInt] = userIdInt - } - } - userIdArray := "" - for _, tmpValue := range value { - userIdArray += fmt.Sprint(tmpValue) + "," - } - useMetrics.HasActivityUser = len(value) - if len(userIdArray) > 0 { - useMetrics.HasActivityUserJson = userIdArray[0 : len(userIdArray)-1] - } - updateSql := "update public.user_metrics set has_activity_user_json='" + useMetrics.HasActivityUserJson + "',regist_activity_user=" + fmt.Sprint(useMetrics.HasActivityUser) + " where count_date=" + fmt.Sprint(key) + ActivityUserArray, HuodongTotal := setUniqueUserId(useMetrics.HasActivityUserJson, HuodongValue) + useMetrics.HasActivityUser = HuodongTotal + useMetrics.HasActivityUserJson = ActivityUserArray + + useMetrics.CurrentDayRegistUser = len(value) + + RegistUserArray, lenRegistUser := setUniqueUserId(useMetrics.ActivityUserJson, userAcitvateValue) + useMetrics.ActivityUserJson = RegistUserArray + useMetrics.ActivateRegistUser = lenRegistUser + + updateSql := "update public.user_metrics set has_activity_user_json='" + useMetrics.HasActivityUserJson + + "',regist_activity_user=" + fmt.Sprint(useMetrics.HasActivityUser) + + ",activity_user_json='" + useMetrics.ActivityUserJson + "'" + + ",activate_regist_user=" + fmt.Sprint(useMetrics.ActivateRegistUser) + + ",not_activate_regist_user=" + fmt.Sprint(useMetrics.CurrentDayRegistUser-useMetrics.ActivateRegistUser) + + ",current_day_regist_user=" + fmt.Sprint(useMetrics.CurrentDayRegistUser) + + " where count_date=" + fmt.Sprint(key) + statictisSess.Exec(updateSql) } } } +func setUniqueUserId(jsonString string, value map[int64]int64) (string, int) { + if value == nil { + value = make(map[int64]int64, 0) + } + userIdArrays := strings.Split(jsonString, ",") + for _, userIdStr := range userIdArrays { + userIdInt, err := strconv.ParseInt(userIdStr, 10, 64) + if err == nil { + value[userIdInt] = userIdInt + } + } + userIdArray := "" + for _, tmpValue := range value { + userIdArray += fmt.Sprint(tmpValue) + "," + } + if len(userIdArray) > 0 { + return userIdArray[0 : len(userIdArray)-1], len(value) + } + return userIdArray, len(value) +} + func addUserToMap(currentUserActivity map[int64]map[int64]int64, registDate timeutil.TimeStamp, userId int64) { CountDateTime := time.Date(registDate.Year(), registDate.AsTime().Month(), registDate.AsTime().Day(), 0, 1, 0, 0, registDate.AsTime().Location()) CountDate := CountDateTime.Unix() @@ -1104,7 +1134,6 @@ func addUserToMap(currentUserActivity map[int64]map[int64]int64, registDate time } else { currentUserActivity[CountDate][userId] = userId } - } func setUserMetrics(userMetrics map[string]int, user *User, start_time int64, end_time int64, dateRecord UserBusinessAnalysis) { diff --git a/models/user_business_struct.go b/models/user_business_struct.go index fec361bca..870a64bc7 100644 --- a/models/user_business_struct.go +++ b/models/user_business_struct.go @@ -467,11 +467,11 @@ type UserAnalysisPara struct { type UserMetrics struct { CountDate int64 `xorm:"pk"` - ActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` - NotActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` - ActivateIndex float64 `xorm:"NOT NULL DEFAULT 0"` - RegistActivityUser int `xorm:"NOT NULL DEFAULT 0"` - HasActivityUser int `xorm:"NOT NULL DEFAULT 0"` + ActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` //当天激活用户 + NotActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` //当天未激活用户 + ActivateIndex float64 `xorm:"NOT NULL DEFAULT 0"` //激活比率 + RegistActivityUser int `xorm:"NOT NULL DEFAULT 0"` //当天注册激活的人中,有贡献活动的人 + HasActivityUser int `xorm:"NOT NULL DEFAULT 0"` //当天有贡献活动的人 TotalUser int `xorm:"NOT NULL DEFAULT 0"` TotalRegistUser int `xorm:"-"` TotalActivateRegistUser int `xorm:"NOT NULL DEFAULT 0"` @@ -480,5 +480,7 @@ type UserMetrics struct { DisplayDate string `xorm:"-"` DataDate string `xorm:"NULL"` DaysForMonth int `xorm:"NOT NULL DEFAULT 0"` - HasActivityUserJson string `xorm:"text NULL"` + HasActivityUserJson string `xorm:"text NULL"` //贡献活动用户列表 + ActivityUserJson string `xorm:"text NULL"` //激活用户列表 + CurrentDayRegistUser int `xorm:"NOT NULL DEFAULT 0"` //当天注册用户 } diff --git a/modules/auth/grampus.go b/modules/auth/grampus.go new file mode 100755 index 000000000..ebf0defde --- /dev/null +++ b/modules/auth/grampus.go @@ -0,0 +1,26 @@ +package auth + +import ( + "gitea.com/macaron/binding" + "gitea.com/macaron/macaron" +) + +type CreateGrampusTrainJobForm struct { + DisplayJobName string `form:"display_job_name" binding:"Required"` + JobName string `form:"job_name" binding:"Required"` + Attachment string `form:"attachment" binding:"Required"` + BootFile string `form:"boot_file" binding:"Required"` + ImageID string `form:"image_id" binding:"Required"` + FlavorID string `form:"flavor" binding:"Required"` + Params string `form:"run_para_list" binding:"Required"` + Description string `form:"description"` + BranchName string `form:"branch_name" binding:"Required"` + FlavorName string `form:"flavor_name" binding:"Required"` + EngineName string `form:"engine_name" binding:"Required"` + WorkServerNumber int `form:"work_server_number" binding:"Required"` + Image string `form:"image"` +} + +func (f *CreateGrampusTrainJobForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { + return validate(errs, ctx.Data, f, ctx.Locale) +} diff --git a/modules/auth/wechat/auto_reply.go b/modules/auth/wechat/auto_reply.go new file mode 100644 index 000000000..440f6de6a --- /dev/null +++ b/modules/auth/wechat/auto_reply.go @@ -0,0 +1,139 @@ +package wechat + +import ( + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "encoding/json" + "github.com/patrickmn/go-cache" + "strings" + "time" +) + +var WechatReplyCache = cache.New(2*time.Minute, 1*time.Minute) + +const ( + WECHAT_REPLY_CACHE_KEY = "wechat_response" +) + +const ( + ReplyTypeText = "text" + ReplyTypeImage = "image" + ReplyTypeVoice = "voice" + ReplyTypeVideo = "video" + ReplyTypeMusic = "music" + ReplyTypeNews = "news" +) + +type ReplyConfigType string + +const ( + SubscribeReply ReplyConfigType = "subscribe" + AutoMsgReply ReplyConfigType = "autoMsg" +) + +func (r ReplyConfigType) Name() string { + switch r { + case SubscribeReply: + return "subscribe" + case AutoMsgReply: + return "autoMsg" + } + return "" +} + +func (r ReplyConfigType) TreePath() string { + switch r { + case SubscribeReply: + return setting.TreePathOfSubscribe + case AutoMsgReply: + return setting.TreePathOfAutoMsgReply + } + return "" +} + +type WechatReplyContent struct { + Reply *ReplyContent + ReplyType string + KeyWords []string + IsFullMatch int +} + +type ReplyContent struct { + Content string + MediaId string + Title string + Description string + MusicUrl string + HQMusicUrl string + ThumbMediaId string + Articles []ArticlesContent +} + +func GetAutomaticReply(msg string) *WechatReplyContent { + r, err := LoadReplyFromCacheAndDisk(AutoMsgReply) + if err != nil { + return nil + } + if r == nil || len(r) == 0 { + return nil + } + for i := 0; i < len(r); i++ { + if r[i].IsFullMatch == 0 { + for _, v := range r[i].KeyWords { + if strings.Contains(msg, v) { + return r[i] + } + } + } else if r[i].IsFullMatch > 0 { + for _, v := range r[i].KeyWords { + if msg == v { + return r[i] + } + } + } + } + return nil + +} + +func loadReplyFromDisk(replyConfig ReplyConfigType) ([]*WechatReplyContent, error) { + log.Info("LoadReply from disk") + repo, err := models.GetRepositoryByOwnerAndAlias(setting.UserNameOfWechatReply, setting.RepoNameOfWechatReply) + if err != nil { + log.Error("get AutomaticReply repo failed, error=%v", err) + return nil, err + } + repoFile, err := models.ReadLatestFileInRepo(setting.UserNameOfWechatReply, repo.Name, setting.RefNameOfWechatReply, replyConfig.TreePath()) + if err != nil { + log.Error("get AutomaticReply failed, error=%v", err) + return nil, err + } + res := make([]*WechatReplyContent, 0) + json.Unmarshal(repoFile.Content, &res) + if res == nil || len(res) == 0 { + return nil, err + } + return res, nil +} + +func LoadReplyFromCacheAndDisk(replyConfig ReplyConfigType) ([]*WechatReplyContent, error) { + v, success := WechatReplyCache.Get(replyConfig.Name()) + if success { + log.Info("LoadReply from cache,value = %v", v) + if v == nil { + return nil, nil + } + n := v.([]*WechatReplyContent) + return n, nil + } + + content, err := loadReplyFromDisk(replyConfig) + if err != nil { + log.Error("LoadReply failed, error=%v", err) + WechatReplyCache.Set(replyConfig.Name(), nil, 30*time.Second) + return nil, err + } + WechatReplyCache.Set(replyConfig.Name(), content, 60*time.Second) + return content, nil +} diff --git a/modules/auth/wechat/client.go b/modules/auth/wechat/client.go index 6734977a1..9ed4b543f 100644 --- a/modules/auth/wechat/client.go +++ b/modules/auth/wechat/client.go @@ -17,7 +17,8 @@ var ( const ( GRANT_TYPE = "client_credential" ACCESS_TOKEN_PATH = "/cgi-bin/token" - QR_CODE_Path = "/cgi-bin/qrcode/create" + QR_CODE_PATH = "/cgi-bin/qrcode/create" + GET_MATERIAL_PATH = "/cgi-bin/material/batchget_material" ACTION_QR_STR_SCENE = "QR_STR_SCENE" ERR_CODE_ACCESSTOKEN_EXPIRE = 42001 @@ -40,6 +41,11 @@ type QRCodeRequest struct { Action_info ActionInfo `json:"action_info"` Expire_seconds int `json:"expire_seconds"` } +type MaterialRequest struct { + Type string `json:"type"` + Offset int `json:"offset"` + Count int `json:"count"` +} type ActionInfo struct { Scene Scene `json:"scene"` @@ -97,7 +103,7 @@ func callQRCodeCreate(sceneStr string) (*QRCodeResponse, bool) { SetQueryParam("access_token", GetWechatAccessToken()). SetBody(bodyJson). SetResult(&result). - Post(setting.WechatApiHost + QR_CODE_Path) + Post(setting.WechatApiHost + QR_CODE_PATH) if err != nil { log.Error("create QR code failed,e=%v", err) return nil, false @@ -113,6 +119,37 @@ func callQRCodeCreate(sceneStr string) (*QRCodeResponse, bool) { return &result, false } +//getMaterial +// api doc: https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Get_materials_list.html +func getMaterial(mType string, offset, count int) (interface{}, bool) { + client := getWechatRestyClient() + + body := &MaterialRequest{ + Type: mType, + Offset: offset, + Count: count, + } + bodyJson, _ := json.Marshal(body) + r, err := client.R(). + SetHeader("Content-Type", "application/json"). + SetQueryParam("access_token", GetWechatAccessToken()). + SetBody(bodyJson). + Post(setting.WechatApiHost + GET_MATERIAL_PATH) + if err != nil { + log.Error("create QR code failed,e=%v", err) + return nil, false + } + a := r.Body() + resultMap := make(map[string]interface{}, 0) + json.Unmarshal(a, &resultMap) + errcode := resultMap["errcode"] + if errcode == fmt.Sprint(ERR_CODE_ACCESSTOKEN_EXPIRE) || errcode == fmt.Sprint(ERR_CODE_ACCESSTOKEN_INVALID) { + return nil, true + } + log.Info("%v", r) + return &resultMap, false +} + func getErrorCodeFromResponse(r *resty.Response) int { a := r.Body() resultMap := make(map[string]interface{}, 0) diff --git a/modules/auth/wechat/event_handle.go b/modules/auth/wechat/event_handle.go index b40ab3101..27edf7343 100644 --- a/modules/auth/wechat/event_handle.go +++ b/modules/auth/wechat/event_handle.go @@ -18,7 +18,7 @@ import ( // // // -type WechatEvent struct { +type WechatMsg struct { ToUserName string FromUserName string CreateTime int64 @@ -26,9 +26,13 @@ type WechatEvent struct { Event string EventKey string Ticket string + Content string + MsgId string + MsgDataId string + Idx string } -type EventReply struct { +type MsgReply struct { XMLName xml.Name `xml:"xml"` ToUserName string FromUserName string @@ -37,16 +41,97 @@ type EventReply struct { Content string } +type TextMsgReply struct { + XMLName xml.Name `xml:"xml"` + ToUserName string + FromUserName string + CreateTime int64 + MsgType string + Content string +} +type ImageMsgReply struct { + XMLName xml.Name `xml:"xml"` + ToUserName string + FromUserName string + CreateTime int64 + MsgType string + Image ImageContent +} +type VoiceMsgReply struct { + XMLName xml.Name `xml:"xml"` + ToUserName string + FromUserName string + CreateTime int64 + MsgType string + Voice VoiceContent +} +type VideoMsgReply struct { + XMLName xml.Name `xml:"xml"` + ToUserName string + FromUserName string + CreateTime int64 + MsgType string + Video VideoContent +} +type MusicMsgReply struct { + XMLName xml.Name `xml:"xml"` + ToUserName string + FromUserName string + CreateTime int64 + MsgType string + Music MusicContent +} +type NewsMsgReply struct { + XMLName xml.Name `xml:"xml"` + ToUserName string + FromUserName string + CreateTime int64 + MsgType string + ArticleCount int + Articles ArticleItem +} + +type ArticleItem struct { + Item []ArticlesContent +} + +type ImageContent struct { + MediaId string +} +type VoiceContent struct { + MediaId string +} +type VideoContent struct { + MediaId string + Title string + Description string +} +type MusicContent struct { + Title string + Description string + MusicUrl string + HQMusicUrl string + ThumbMediaId string +} +type ArticlesContent struct { + XMLName xml.Name `xml:"item"` + Title string + Description string + PicUrl string + Url string +} + const ( WECHAT_EVENT_SUBSCRIBE = "subscribe" WECHAT_EVENT_SCAN = "SCAN" ) const ( - WECHAT_MSG_TYPE_TEXT = "text" + WECHAT_MSG_TYPE_TEXT = "text" + WECHAT_MSG_TYPE_EVENT = "event" ) -func HandleSubscribeEvent(we WechatEvent) string { +func HandleScanEvent(we WechatMsg) string { eventKey := we.EventKey if eventKey == "" { return "" @@ -74,3 +159,11 @@ func HandleSubscribeEvent(we WechatEvent) string { return BIND_REPLY_SUCCESS } + +func HandleSubscribeEvent(we WechatMsg) *WechatReplyContent { + r, err := LoadReplyFromCacheAndDisk(SubscribeReply) + if err != nil || len(r) == 0 { + return nil + } + return r[0] +} diff --git a/modules/auth/wechat/material.go b/modules/auth/wechat/material.go new file mode 100644 index 000000000..526156af5 --- /dev/null +++ b/modules/auth/wechat/material.go @@ -0,0 +1,13 @@ +package wechat + +import "code.gitea.io/gitea/modules/log" + +func GetWechatMaterial(mType string, offset, count int) interface{} { + result, retryFlag := getMaterial(mType, offset, count) + if retryFlag { + log.Info("retryGetWechatMaterial calling") + refreshAccessToken() + result, _ = getMaterial(mType, offset, count) + } + return result +} diff --git a/modules/cloudbrain/cloudbrain.go b/modules/cloudbrain/cloudbrain.go index 8fb13ca4c..430304dd5 100755 --- a/modules/cloudbrain/cloudbrain.go +++ b/modules/cloudbrain/cloudbrain.go @@ -44,17 +44,40 @@ var ( TrainResourceSpecs *models.ResourceSpecs ) +type GenerateCloudBrainTaskReq struct { + Ctx *context.Context + DisplayJobName string + JobName string + Image string + Command string + CodePath string + ModelPath string + BenchmarkPath string + Snn4ImageNetPath string + BrainScorePath string + JobType string + GpuQueue string + Description string + BranchName string + BootFile string + Params string + CommitID string + Uuids string + DatasetNames string + DatasetInfos map[string]models.DatasetInfo + BenchmarkTypeID int + BenchmarkChildTypeID int + ResourceSpecId int +} + 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 { return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() } else { - log.Info("is job creator:" + strconv.FormatBool(ctx.User.ID == job.UserID)) return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() || ctx.User.ID == job.UserID } @@ -187,23 +210,17 @@ func AdminOrImageCreaterRight(ctx *context.Context) { } -func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue, description, branchName, bootFile, params, commitID string, benchmarkTypeID, benchmarkChildTypeID, resourceSpecId int) error { - - dataActualPath := setting.Attachment.Minio.RealPath + - setting.Attachment.Minio.Bucket + "/" + - setting.Attachment.Minio.BasePath + - models.AttachmentRelativePath(uuid) + - uuid - +func GenerateTask(req GenerateCloudBrainTaskReq) error { var resourceSpec *models.ResourceSpec var versionCount int - if jobType == string(models.JobTypeTrain) { + + if req.JobType == string(models.JobTypeTrain) { versionCount = 1 if TrainResourceSpecs == nil { json.Unmarshal([]byte(setting.TrainResourceSpecs), &TrainResourceSpecs) } for _, spec := range TrainResourceSpecs.ResourceSpec { - if resourceSpecId == spec.Id { + if req.ResourceSpecId == spec.Id { resourceSpec = spec } } @@ -212,7 +229,7 @@ func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command, json.Unmarshal([]byte(setting.ResourceSpecs), &ResourceSpecs) } for _, spec := range ResourceSpecs.ResourceSpec { - if resourceSpecId == spec.Id { + if req.ResourceSpecId == spec.Id { resourceSpec = spec } } @@ -220,25 +237,74 @@ func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command, } if resourceSpec == nil { - log.Error("no such resourceSpecId(%d)", resourceSpecId, ctx.Data["MsgID"]) + log.Error("no such resourceSpecId(%d)", req.ResourceSpecId, req.Ctx.Data["MsgID"]) return errors.New("no such resourceSpec") } - var datasetName string - attach, err := models.GetAttachmentByUUID(uuid) - if err != nil { - //for benchmark, do not return error - log.Error("GetAttachmentByUUID failed:%v", err) + volumes := []models.Volume{ + { + HostPath: models.StHostPath{ + Path: req.CodePath, + MountPath: CodeMountPath, + ReadOnly: false, + }, + }, + { + HostPath: models.StHostPath{ + Path: req.ModelPath, + MountPath: ModelMountPath, + ReadOnly: false, + }, + }, + { + HostPath: models.StHostPath{ + Path: req.BenchmarkPath, + MountPath: BenchMarkMountPath, + ReadOnly: true, + }, + }, + { + HostPath: models.StHostPath{ + Path: req.Snn4ImageNetPath, + MountPath: Snn4imagenetMountPath, + ReadOnly: true, + }, + }, + { + HostPath: models.StHostPath{ + Path: req.BrainScorePath, + MountPath: BrainScoreMountPath, + ReadOnly: true, + }, + }, + } + + if len(req.DatasetInfos) == 1 { + volumes = append(volumes, models.Volume{ + HostPath: models.StHostPath{ + Path: req.DatasetInfos[req.Uuids].DataLocalPath, + MountPath: DataSetMountPath, + ReadOnly: true, + }, + }) } else { - datasetName = attach.Name + for _, dataset := range req.DatasetInfos { + volumes = append(volumes, models.Volume{ + HostPath: models.StHostPath{ + Path: dataset.DataLocalPath, + MountPath: DataSetMountPath + "/" + dataset.Name, + ReadOnly: true, + }, + }) + } } createTime := timeutil.TimeStampNow() - jobResult, err := CreateJob(jobName, models.CreateJobParams{ - JobName: jobName, + jobResult, err := CreateJob(req.JobName, models.CreateJobParams{ + JobName: req.JobName, RetryCount: 1, - GpuType: gpuQueue, - Image: image, + GpuType: req.GpuQueue, + Image: req.Image, TaskRoles: []models.TaskRole{ { Name: SubTaskName, @@ -249,94 +315,51 @@ func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command, GPUNumber: resourceSpec.GpuNum, MemoryMB: resourceSpec.MemMiB, ShmMB: resourceSpec.ShareMemMiB, - Command: command, + Command: req.Command, NeedIBDevice: false, IsMainRole: false, UseNNI: false, }, }, - Volumes: []models.Volume{ - { - HostPath: models.StHostPath{ - Path: codePath, - MountPath: CodeMountPath, - ReadOnly: false, - }, - }, - { - HostPath: models.StHostPath{ - Path: dataActualPath, - MountPath: DataSetMountPath, - ReadOnly: true, - }, - }, - { - HostPath: models.StHostPath{ - Path: modelPath, - MountPath: ModelMountPath, - ReadOnly: false, - }, - }, - { - HostPath: models.StHostPath{ - Path: benchmarkPath, - MountPath: BenchMarkMountPath, - ReadOnly: true, - }, - }, - { - HostPath: models.StHostPath{ - Path: snn4imagenetPath, - MountPath: Snn4imagenetMountPath, - ReadOnly: true, - }, - }, - { - HostPath: models.StHostPath{ - Path: brainScorePath, - MountPath: BrainScoreMountPath, - ReadOnly: true, - }, - }, - }, + Volumes: volumes, }) if err != nil { - log.Error("CreateJob failed:", err.Error(), ctx.Data["MsgID"]) + log.Error("CreateJob failed:", err.Error(), req.Ctx.Data["MsgID"]) return err } if jobResult.Code != Success { - log.Error("CreateJob(%s) failed:%s", jobName, jobResult.Msg, ctx.Data["MsgID"]) + log.Error("CreateJob(%s) failed:%s", req.JobName, jobResult.Msg, req.Ctx.Data["MsgID"]) return errors.New(jobResult.Msg) } var jobID = jobResult.Payload["jobId"].(string) err = models.CreateCloudbrain(&models.Cloudbrain{ Status: string(models.JobWaiting), - UserID: ctx.User.ID, - RepoID: ctx.Repo.Repository.ID, + UserID: req.Ctx.User.ID, + RepoID: req.Ctx.Repo.Repository.ID, JobID: jobID, - JobName: jobName, - DisplayJobName: displayJobName, + JobName: req.JobName, + DisplayJobName: req.DisplayJobName, SubTaskName: SubTaskName, - JobType: jobType, + JobType: req.JobType, Type: models.TypeCloudBrainOne, - Uuid: uuid, - Image: image, - GpuQueue: gpuQueue, - ResourceSpecId: resourceSpecId, + Uuid: req.Uuids, + Image: req.Image, + GpuQueue: req.GpuQueue, + ResourceSpecId: req.ResourceSpecId, ComputeResource: models.GPUResource, - BenchmarkTypeID: benchmarkTypeID, - BenchmarkChildTypeID: benchmarkChildTypeID, - Description: description, + BenchmarkTypeID: req.BenchmarkTypeID, + BenchmarkChildTypeID: req.BenchmarkChildTypeID, + Description: req.Description, IsLatestVersion: "1", VersionCount: versionCount, - BranchName: branchName, - BootFile: bootFile, - DatasetName: datasetName, - Parameters: params, + BranchName: req.BranchName, + BootFile: req.BootFile, + DatasetName: req.DatasetNames, + Parameters: req.Params, CreatedUnix: createTime, UpdatedUnix: createTime, - CommitID: commitID, + CommitID: req.CommitID, }) if err != nil { @@ -345,17 +368,17 @@ func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command, task, err := models.GetCloudbrainByJobID(jobID) if err != nil { - log.Error("GetCloudbrainByName failed: %v", err.Error()) + log.Error("GetCloudbrainByJobID failed: %v", err.Error()) return err } stringId := strconv.FormatInt(task.ID, 10) - if IsBenchmarkJob(jobType) { - notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateBenchMarkTask) - } else if string(models.JobTypeTrain) == jobType { - notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, jobID, displayJobName, models.ActionCreateGPUTrainTask) + if IsBenchmarkJob(req.JobType) { + notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, stringId, req.DisplayJobName, models.ActionCreateBenchMarkTask) + } else if string(models.JobTypeTrain) == req.JobType { + notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, jobID, req.DisplayJobName, models.ActionCreateGPUTrainTask) } else { - notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, stringId, displayJobName, models.ActionCreateDebugGPUTask) + notification.NotifyOtherTask(req.Ctx.User, req.Ctx.Repo.Repository, stringId, req.DisplayJobName, models.ActionCreateDebugGPUTask) } return nil @@ -366,11 +389,6 @@ func IsBenchmarkJob(jobType string) bool { } func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) error { - dataActualPath := setting.Attachment.Minio.RealPath + - setting.Attachment.Minio.Bucket + "/" + - setting.Attachment.Minio.BasePath + - models.AttachmentRelativePath(task.Uuid) + - task.Uuid jobName := task.JobName var resourceSpec *models.ResourceSpec @@ -388,6 +406,70 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e return errors.New("no such resourceSpec") } + datasetInfos, _, err := models.GetDatasetInfo(task.Uuid) + if err != nil { + log.Error("GetDatasetInfo failed:%v", err, ctx.Data["MsgID"]) + return err + } + + volumes := []models.Volume{ + { + HostPath: models.StHostPath{ + Path: storage.GetMinioPath(jobName, CodeMountPath+"/"), + MountPath: CodeMountPath, + ReadOnly: false, + }, + }, + { + HostPath: models.StHostPath{ + Path: storage.GetMinioPath(jobName, ModelMountPath+"/"), + MountPath: ModelMountPath, + ReadOnly: false, + }, + }, + { + HostPath: models.StHostPath{ + Path: storage.GetMinioPath(jobName, BenchMarkMountPath+"/"), + MountPath: BenchMarkMountPath, + ReadOnly: true, + }, + }, + { + HostPath: models.StHostPath{ + Path: storage.GetMinioPath(jobName, Snn4imagenetMountPath+"/"), + MountPath: Snn4imagenetMountPath, + ReadOnly: true, + }, + }, + { + HostPath: models.StHostPath{ + Path: storage.GetMinioPath(jobName, BrainScoreMountPath+"/"), + MountPath: BrainScoreMountPath, + ReadOnly: true, + }, + }, + } + + if len(datasetInfos) == 1 { + volumes = append(volumes, models.Volume{ + HostPath: models.StHostPath{ + Path: datasetInfos[task.Uuid].DataLocalPath, + MountPath: DataSetMountPath, + ReadOnly: true, + }, + }) + } else { + for _, dataset := range datasetInfos { + volumes = append(volumes, models.Volume{ + HostPath: models.StHostPath{ + Path: dataset.DataLocalPath, + MountPath: DataSetMountPath + "/" + dataset.Name, + ReadOnly: true, + }, + }) + } + } + createTime := timeutil.TimeStampNow() jobResult, err := CreateJob(jobName, models.CreateJobParams{ JobName: jobName, @@ -410,50 +492,7 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e UseNNI: false, }, }, - Volumes: []models.Volume{ - { - HostPath: models.StHostPath{ - Path: storage.GetMinioPath(jobName, CodeMountPath+"/"), - MountPath: CodeMountPath, - ReadOnly: false, - }, - }, - { - HostPath: models.StHostPath{ - Path: dataActualPath, - MountPath: DataSetMountPath, - ReadOnly: true, - }, - }, - { - HostPath: models.StHostPath{ - Path: storage.GetMinioPath(jobName, ModelMountPath+"/"), - MountPath: ModelMountPath, - ReadOnly: false, - }, - }, - { - HostPath: models.StHostPath{ - Path: storage.GetMinioPath(jobName, BenchMarkMountPath+"/"), - MountPath: BenchMarkMountPath, - ReadOnly: true, - }, - }, - { - HostPath: models.StHostPath{ - Path: storage.GetMinioPath(jobName, Snn4imagenetMountPath+"/"), - MountPath: Snn4imagenetMountPath, - ReadOnly: true, - }, - }, - { - HostPath: models.StHostPath{ - Path: storage.GetMinioPath(jobName, BrainScoreMountPath+"/"), - MountPath: BrainScoreMountPath, - ReadOnly: true, - }, - }, - }, + Volumes: volumes, }) if err != nil { log.Error("CreateJob failed:%v", err.Error(), ctx.Data["MsgID"]) @@ -476,6 +515,7 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e JobType: task.JobType, Type: task.Type, Uuid: task.Uuid, + DatasetName: task.DatasetName, Image: task.Image, GpuQueue: task.GpuQueue, ResourceSpecId: task.ResourceSpecId, diff --git a/modules/grampus/grampus.go b/modules/grampus/grampus.go new file mode 100755 index 000000000..caaae4e8e --- /dev/null +++ b/modules/grampus/grampus.go @@ -0,0 +1,217 @@ +package grampus + +import ( + "encoding/json" + "strings" + + "code.gitea.io/gitea/modules/setting" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/notification" + "code.gitea.io/gitea/modules/timeutil" +) + +const ( + JobPath = "job/" + + ProcessorTypeNPU = "npu.huawei.com/NPU" + ProcessorTypeGPU = "nvidia.com/gpu" + + GpuWorkDir = "/tmp/" + NpuWorkDir = "/cache/" + + CommandPrepareScript = ";mkdir -p output;mkdir -p code;mkdir -p dataset;echo \"start loading script\";wget -q https://git.openi.org.cn/OpenIOSSG/script_for_grampus/archive/master.zip;" + + "echo \"finish loading script\";unzip -q master.zip;cd script_for_grampus;chmod 777 downloader_for_obs uploader_for_obs downloader_for_minio uploader_for_minio;" + //CommandPrepareScript = "pwd;cd /cache;mkdir -p output;mkdir -p code;mkdir -p dataset;echo \"start loading script\";wget -q https://git.openi.org.cn/OpenIOSSG/script_for_grampus/archive/master.zip;" + + // "echo \"finish loading script\";unzip -q master.zip;cd script_for_grampus;chmod 777 downloader_for_obs uploader_for_obs downloader_for_minio uploader_for_minio;" + + CodeArchiveName = "master.zip" +) + +var ( + poolInfos *models.PoolInfos + FlavorInfos *models.FlavorInfos + ImageInfos *models.ImageInfosModelArts + + SpecialPools *models.SpecialPools +) + +type GenerateTrainJobReq struct { + JobName string + Command string + ResourceSpecId string + ImageUrl string //与image_id二选一,都有的情况下优先image_url + ImageId string + + DisplayJobName string + Uuid string + Description string + CodeObsPath string + BootFile string + BootFileUrl string + DataUrl string + TrainUrl string + WorkServerNumber int + EngineID int64 + CommitID string + IsLatestVersion string + BranchName string + PreVersionId int64 + PreVersionName string + FlavorName string + VersionCount int + EngineName string + TotalVersionCount int + ComputeResource string + ProcessType string + DatasetName string + Params string +} + +func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error) { + createTime := timeutil.TimeStampNow() + + centerID, centerName := getCentersParamter(ctx, req) + + jobResult, err := createJob(models.CreateGrampusJobRequest{ + Name: req.JobName, + Tasks: []models.GrampusTasks{ + { + Name: req.JobName, + Command: req.Command, + ResourceSpecId: req.ResourceSpecId, + ImageId: req.ImageId, + ImageUrl: req.ImageUrl, + CenterID: centerID, + CenterName: centerName, + ReplicaNum: 1, + }, + }, + }) + if err != nil { + log.Error("createJob failed: %v", err.Error()) + return err + } + + jobID := jobResult.JobInfo.JobID + err = models.CreateCloudbrain(&models.Cloudbrain{ + Status: TransTrainJobStatus(jobResult.JobInfo.Status), + UserID: ctx.User.ID, + RepoID: ctx.Repo.Repository.ID, + JobID: jobID, + JobName: req.JobName, + DisplayJobName: req.DisplayJobName, + JobType: string(models.JobTypeTrain), + Type: models.TypeC2Net, + Uuid: req.Uuid, + DatasetName: req.DatasetName, + CommitID: req.CommitID, + IsLatestVersion: req.IsLatestVersion, + ComputeResource: req.ComputeResource, + ImageID: req.ImageId, + TrainUrl: req.TrainUrl, + BranchName: req.BranchName, + Parameters: req.Params, + BootFile: req.BootFile, + DataUrl: req.DataUrl, + FlavorCode: req.ResourceSpecId, + Description: req.Description, + WorkServerNumber: req.WorkServerNumber, + FlavorName: req.FlavorName, + EngineName: req.EngineName, + VersionCount: req.VersionCount, + TotalVersionCount: req.TotalVersionCount, + CreatedUnix: createTime, + UpdatedUnix: createTime, + }) + + if err != nil { + log.Error("CreateCloudbrain(%s) failed:%v", req.DisplayJobName, err.Error()) + return err + } + + var actionType models.ActionType + if req.ComputeResource == models.NPUResource { + actionType = models.ActionCreateGrampusNPUTrainTask + } else if req.ComputeResource == models.GPUResource { + actionType = models.ActionCreateGrampusGPUTrainTask + } + notification.NotifyOtherTask(ctx.User, ctx.Repo.Repository, jobID, req.DisplayJobName, actionType) + + return nil +} + +func getCentersParamter(ctx *context.Context, req *GenerateTrainJobReq) ([]string, []string) { + var centerID []string + var centerName []string + + includeCenters := make(map[string]string) + excludeCenters := make(map[string]string) + + if SpecialPools != nil { + for _, pool := range SpecialPools.Pools { + if !pool.IsExclusive && strings.Contains(req.ComputeResource, pool.Type) { + org, _ := models.GetOrgByName(pool.Org) + if org != nil { + isOrgMember, _ := models.IsOrganizationMember(org.ID, ctx.User.ID) + if isOrgMember { + for _, info := range pool.Pool { + includeCenters[info.Queue] = info.Value + } + } else { + for _, info := range pool.Pool { + excludeCenters[info.Queue] = info.Value + } + } + } + } + } + + } + + if len(includeCenters) > 0 { + //如果有专属资源池,根据专属资源池指定智算中心 + for k, v := range includeCenters { + centerID = append(centerID, k) + centerName = append(centerName, v) + } + } else if len(excludeCenters) > 0 { + //否则,有要排除的中心,先获取所有中心,删除其中的排除中心,得到指定的智算中心 + allCenters := make(map[string]string) + specs, err := GetResourceSpecs(req.ProcessType) + if err == nil { + for _, info := range specs.Infos { + for _, center := range info.Centers { + allCenters[center.ID] = center.Name + } + + } + } + + for k, _ := range excludeCenters { + delete(allCenters, k) + } + + for k, v := range allCenters { + centerID = append(centerID, k) + centerName = append(centerName, v) + } + + } + return centerID, centerName +} + +func TransTrainJobStatus(status string) string { + if status == models.GrampusStatusPending { + status = models.GrampusStatusWaiting + } + + return strings.ToUpper(status) +} +func InitSpecialPool() { + if SpecialPools == nil && setting.Grampus.SpecialPools != "" { + json.Unmarshal([]byte(setting.Grampus.SpecialPools), &SpecialPools) + } +} diff --git a/modules/grampus/resty.go b/modules/grampus/resty.go new file mode 100755 index 000000000..5e8722b4b --- /dev/null +++ b/modules/grampus/resty.go @@ -0,0 +1,277 @@ +package grampus + +import ( + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "crypto/tls" + "encoding/json" + "fmt" + "github.com/go-resty/resty/v2" + "net/http" +) + +var ( + restyClient *resty.Client + HOST string + TOKEN string +) + +const ( + urlOpenApiV1 = "/openapi/v1/" + + urlGetToken = urlOpenApiV1 + "token" + urlTrainJob = urlOpenApiV1 + "trainjob" + urlGetResourceSpecs = urlOpenApiV1 + "resourcespec" + urlGetImages = urlOpenApiV1 + "image" + + errorIllegalToken = 1005 +) + +type GetTokenParams struct { + UserName string `json:"username"` + Password string `json:"password"` +} + +type GetTokenResult struct { + Token string `json:"token"` + Expiration int64 `json:"expiration"` +} + +func getRestyClient() *resty.Client { + if restyClient == nil { + restyClient = resty.New() + restyClient.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) + } + return restyClient +} + +func checkSetting() { + if len(HOST) != 0 && len(TOKEN) != 0 && restyClient != nil { + return + } + + err := getToken() + if err != nil { + log.Error("getToken failed:%v", err) + } +} + +func getToken() error { + HOST = setting.Grampus.Host + + client := getRestyClient() + params := GetTokenParams{ + UserName: setting.Grampus.UserName, + Password: setting.Grampus.Password, + } + + var result GetTokenResult + res, err := client.R(). + SetHeader("Content-Type", "application/json"). + SetBody(params). + SetResult(&result). + Post(HOST + urlGetToken) + if err != nil { + return fmt.Errorf("resty getToken: %v", err) + } + + if res.StatusCode() != http.StatusOK { + return fmt.Errorf("getToken failed:%s", res.String()) + } + + TOKEN = result.Token + + return nil +} + +func createJob(req models.CreateGrampusJobRequest) (*models.CreateGrampusJobResponse, error) { + checkSetting() + client := getRestyClient() + var result models.CreateGrampusJobResponse + + retry := 0 + +sendjob: + _, err := client.R(). + SetHeader("Content-Type", "application/json"). + SetAuthToken(TOKEN). + SetBody(req). + SetResult(&result). + Post(HOST + urlTrainJob) + + if err != nil { + return nil, fmt.Errorf("resty CreateJob: %s", err) + } + + if result.ErrorCode == errorIllegalToken && retry < 1 { + retry++ + _ = getToken() + goto sendjob + } + + if result.ErrorCode != 0 { + log.Error("CreateJob failed(%d): %s", result.ErrorCode, result.ErrorMsg) + return &result, fmt.Errorf("CreateJob failed(%d): %s", result.ErrorCode, result.ErrorMsg) + } + + return &result, nil +} + +func GetJob(jobID string) (*models.GetGrampusJobResponse, error) { + checkSetting() + client := getRestyClient() + var result models.GetGrampusJobResponse + + retry := 0 + +sendjob: + _, err := client.R(). + SetAuthToken(TOKEN). + SetResult(&result). + Get(HOST + urlTrainJob + "/" + jobID) + + if err != nil { + return nil, fmt.Errorf("resty GetJob: %v", err) + } + + if result.ErrorCode == errorIllegalToken && retry < 1 { + retry++ + log.Info("retry get token") + _ = getToken() + goto sendjob + } + + if result.ErrorCode != 0 { + log.Error("GetJob failed(%d): %s", result.ErrorCode, result.ErrorMsg) + return nil, fmt.Errorf("GetJob failed(%d): %s", result.ErrorCode, result.ErrorMsg) + } + + return &result, nil +} + +func GetResourceSpecs(processorType string) (*models.GetGrampusResourceSpecsResult, error) { + checkSetting() + client := getRestyClient() + var result models.GetGrampusResourceSpecsResult + + retry := 0 + +sendjob: + _, err := client.R(). + SetAuthToken(TOKEN). + SetResult(&result). + Get(HOST + urlGetResourceSpecs + "?processorType=" + processorType) + + if err != nil { + return nil, fmt.Errorf("resty GetResourceSpecs: %v", err) + } + + if result.ErrorCode == errorIllegalToken && retry < 1 { + retry++ + log.Info("retry get token") + _ = getToken() + goto sendjob + } + + if result.ErrorCode != 0 { + log.Error("GetResourceSpecs failed(%d): %s", result.ErrorCode, result.ErrorMsg) + return &result, fmt.Errorf("GetResourceSpecs failed(%d): %s", result.ErrorCode, result.ErrorMsg) + } + + return &result, nil +} + +func GetImages(processorType string) (*models.GetGrampusImagesResult, error) { + checkSetting() + client := getRestyClient() + var result models.GetGrampusImagesResult + + retry := 0 + +sendjob: + _, err := client.R(). + SetAuthToken(TOKEN). + SetResult(&result). + Get(HOST + urlGetImages + "?processorType=" + processorType) + + if err != nil { + return nil, fmt.Errorf("resty GetImages: %v", err) + } + + if result.ErrorCode == errorIllegalToken && retry < 1 { + retry++ + log.Info("retry get token") + _ = getToken() + goto sendjob + } + + if result.ErrorCode != 0 { + log.Error("GetImages failed(%d): %s", result.ErrorCode, result.ErrorMsg) + return &result, fmt.Errorf("GetImages failed(%d): %s", result.ErrorCode, result.ErrorMsg) + } + + return &result, nil +} + +func GetTrainJobLog(jobID string) (string, error) { + checkSetting() + client := getRestyClient() + var logContent string + + res, err := client.R(). + SetAuthToken(TOKEN). + SetResult(&logContent). + Get(HOST + urlTrainJob + "/" + jobID + "/task/0/replica/0/log") + + if err != nil { + return logContent, fmt.Errorf("resty GetTrainJobLog: %v", err) + } + + if res.StatusCode() != http.StatusOK { + var temp models.GrampusResult + if err = json.Unmarshal([]byte(res.String()), &temp); err != nil { + log.Error("json.Unmarshal failed(%s): %v", res.String(), err.Error()) + return logContent, fmt.Errorf("json.Unmarshal failed(%s): %v", res.String(), err.Error()) + } + log.Error("GetTrainJobLog failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) + return logContent, fmt.Errorf("GetTrainJobLog failed(%d):%s(%s)", res.StatusCode(), temp.ErrorCode, temp.ErrorMsg) + } + + logContent = res.String() + + return logContent, nil +} + +func StopJob(jobID string) (*models.GrampusStopJobResponse, error) { + checkSetting() + client := getRestyClient() + var result models.GrampusStopJobResponse + + retry := 0 + +sendjob: + _, err := client.R(). + //SetHeader("Content-Type", "application/json"). + SetAuthToken(TOKEN). + SetResult(&result). + Post(HOST + urlTrainJob + "/" + jobID + "/stop") + + if err != nil { + return &result, fmt.Errorf("resty StopTrainJob: %v", err) + } + + if result.ErrorCode == errorIllegalToken && retry < 1 { + retry++ + log.Info("retry get token") + _ = getToken() + goto sendjob + } + + if result.ErrorCode != 0 { + log.Error("GetJob failed(%d): %s", result.ErrorCode, result.ErrorMsg) + return &result, fmt.Errorf("GetJob failed(%d): %s", result.ErrorCode, result.ErrorMsg) + } + + return &result, nil +} diff --git a/modules/modelarts/modelarts.go b/modules/modelarts/modelarts.go index 78b40fd56..79aeb4cb0 100755 --- a/modules/modelarts/modelarts.go +++ b/modules/modelarts/modelarts.go @@ -1,13 +1,14 @@ package modelarts import ( - "code.gitea.io/gitea/modules/timeutil" "encoding/json" "errors" "fmt" "path" "strconv" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" @@ -50,6 +51,7 @@ const ( Lines = 500 TrainUrl = "train_url" DataUrl = "data_url" + MultiDataUrl = "multi_data_url" ResultUrl = "result_url" CkptUrl = "ckpt_url" DeviceTarget = "device_target" @@ -96,6 +98,7 @@ type GenerateTrainJobReq struct { VersionCount int EngineName string TotalVersionCount int + DatasetName string } type GenerateInferenceJobReq struct { @@ -335,11 +338,6 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error return err } - attach, err := models.GetAttachmentByUUID(req.Uuid) - if err != nil { - log.Error("GetAttachmentByUUID(%s) failed:%v", strconv.FormatInt(jobResult.JobID, 10), err.Error()) - return err - } jobId := strconv.FormatInt(jobResult.JobID, 10) err = models.CreateCloudbrain(&models.Cloudbrain{ Status: TransTrainJobStatus(jobResult.Status), @@ -353,7 +351,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error VersionID: jobResult.VersionID, VersionName: jobResult.VersionName, Uuid: req.Uuid, - DatasetName: attach.Name, + DatasetName: req.DatasetName, CommitID: req.CommitID, IsLatestVersion: req.IsLatestVersion, ComputeResource: models.NPUResource, @@ -408,12 +406,6 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job return err } - attach, err := models.GetAttachmentByUUID(req.Uuid) - if err != nil { - log.Error("GetAttachmentByUUID(%s) failed:%v", strconv.FormatInt(jobResult.JobID, 10), err.Error()) - return err - } - var jobTypes []string jobTypes = append(jobTypes, string(models.JobTypeTrain)) repo := ctx.Repo.Repository @@ -441,7 +433,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job VersionID: jobResult.VersionID, VersionName: jobResult.VersionName, Uuid: req.Uuid, - DatasetName: attach.Name, + DatasetName: req.DatasetName, CommitID: req.CommitID, IsLatestVersion: req.IsLatestVersion, PreVersionName: req.PreVersionName, diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 6bdf299af..506e31ba3 100755 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -465,6 +465,7 @@ var ( MaxDuration int64 TrainGpuTypes string TrainResourceSpecs string + MaxDatasetNum int //benchmark config IsBenchmarkEnabled bool @@ -528,6 +529,15 @@ var ( FlavorInfos string TrainJobFLAVORINFOS string + //grampus config + Grampus = struct { + Env string + Host string + UserName string + Password string + SpecialPools string + }{} + //elk config ElkUrl string ElkUser string @@ -545,6 +555,13 @@ var ( WechatQRCodeExpireSeconds int WechatAuthSwitch bool + //wechat auto reply config + UserNameOfWechatReply string + RepoNameOfWechatReply string + RefNameOfWechatReply string + TreePathOfAutoMsgReply string + TreePathOfSubscribe string + //nginx proxy PROXYURL string RadarMap = struct { @@ -1294,6 +1311,7 @@ func NewContext() { MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400) TrainGpuTypes = sec.Key("TRAIN_GPU_TYPES").MustString("") TrainResourceSpecs = sec.Key("TRAIN_RESOURCE_SPECS").MustString("") + MaxDatasetNum = sec.Key("MAX_DATASET_NUM").MustInt(5) sec = Cfg.Section("benchmark") IsBenchmarkEnabled = sec.Key("ENABLED").MustBool(false) @@ -1372,6 +1390,11 @@ func NewContext() { WechatAppSecret = sec.Key("APP_SECRET").MustString("e48e13f315adc32749ddc7057585f198") WechatQRCodeExpireSeconds = sec.Key("QR_CODE_EXPIRE_SECONDS").MustInt(120) WechatAuthSwitch = sec.Key("AUTH_SWITCH").MustBool(true) + UserNameOfWechatReply = sec.Key("AUTO_REPLY_USER_NAME").MustString("OpenIOSSG") + RepoNameOfWechatReply = sec.Key("AUTO_REPLY_REPO_NAME").MustString("promote") + RefNameOfWechatReply = sec.Key("AUTO_REPLY_REF_NAME").MustString("master") + TreePathOfAutoMsgReply = sec.Key("AUTO_REPLY_TREE_PATH").MustString("wechat/auto_reply.json") + TreePathOfSubscribe = sec.Key("SUBSCRIBE_TREE_PATH").MustString("wechat/subscribe_reply.json") SetRadarMapConfig() @@ -1382,6 +1405,18 @@ func NewContext() { Course.OrgName = sec.Key("org_name").MustString("") Course.TeamName = sec.Key("team_name").MustString("") + GetGrampusConfig() +} + +func GetGrampusConfig() { + sec := Cfg.Section("grampus") + + Grampus.Env = sec.Key("ENV").MustString("TEST") + Grampus.Host = sec.Key("SERVER_HOST").MustString("") + Grampus.UserName = sec.Key("USERNAME").MustString("") + Grampus.Password = sec.Key("PASSWORD").MustString("") + Grampus.SpecialPools = sec.Key("SPECIAL_POOL").MustString("") + } func SetRadarMapConfig() { diff --git a/modules/setting/webhook.go b/modules/setting/webhook.go index 34cf8a62d..a14ad949f 100644 --- a/modules/setting/webhook.go +++ b/modules/setting/webhook.go @@ -6,6 +6,7 @@ package setting import ( "net/url" + "strings" "code.gitea.io/gitea/modules/log" ) @@ -13,14 +14,18 @@ import ( var ( // Webhook settings Webhook = struct { - QueueLength int - DeliverTimeout int - SkipTLSVerify bool - Types []string - PagingNum int - ProxyURL string - ProxyURLFixed *url.URL - ProxyHosts []string + QueueLength int + DeliverTimeout int + SkipTLSVerify bool + Types []string + PagingNum int + ProxyURL string + ProxyURLFixed *url.URL + ProxyHosts []string + Socks5Proxy string + Socks5UserName string + Socks5Password string + Socks5ProxyHosts []string }{ QueueLength: 1000, DeliverTimeout: 5, @@ -39,6 +44,10 @@ func newWebhookService() { Webhook.Types = []string{"gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams", "feishu", "matrix"} Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10) Webhook.ProxyURL = sec.Key("PROXY_URL").MustString("") + Webhook.Socks5Proxy = sec.Key("SOCKS5_PROXY_URL").MustString("") + Webhook.Socks5UserName = sec.Key("SOCKS5_USER_NAME").MustString("") + Webhook.Socks5Password = sec.Key("SOCKS5_PASSWORD").MustString("") + Webhook.Socks5ProxyHosts = strings.Split(sec.Key("SOCKS5_PROXY_HOST").MustString(""), ";") if Webhook.ProxyURL != "" { var err error Webhook.ProxyURLFixed, err = url.Parse(Webhook.ProxyURL) diff --git a/modules/util/path.go b/modules/util/path.go old mode 100644 new mode 100755 index 2b198eb6d..1db6e4379 --- a/modules/util/path.go +++ b/modules/util/path.go @@ -31,3 +31,13 @@ func GetDirectorySize(path string) (int64, error) { }) return size, err } + +// check whether the path is dir +func IsDir(path string) bool { + s, err := os.Stat(path) + if err != nil { + return false + } + + return s.IsDir() +} diff --git a/modules/util/util.go b/modules/util/util.go index 134fd1296..87dd5b700 100755 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -115,7 +115,7 @@ func AddZero(t int64) (m string) { func ConvertDisplayJobNameToJobName(DisplayName string) (JobName string) { t := time.Now() - JobName = "openi" + strings.ToLower(cutNameString(DisplayName, 15)) + "t" + t.Format("20060102150405")[4:] + strconv.Itoa(int(rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(100000))) + JobName = strings.ToLower(cutNameString(DisplayName, 15)) + "t" + t.Format("20060102150405")[10:] + strconv.Itoa(int(rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(100000))) return JobName } diff --git a/modules/webhook/deliver.go b/modules/webhook/deliver.go index 7b0c65173..8348e8641 100644 --- a/modules/webhook/deliver.go +++ b/modules/webhook/deliver.go @@ -16,6 +16,8 @@ import ( "sync" "time" + "golang.org/x/net/proxy" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" @@ -137,8 +139,10 @@ func Deliver(t *models.HookTask) error { return } }() + match := isSocks5ProxyUrlMatch(req) + + resp, err := makeReq(req, match) - resp, err := webhookHTTPClient.Do(req) if err != nil { t.ResponseInfo.Body = fmt.Sprintf("Delivery: %v", err) return err @@ -161,6 +165,23 @@ func Deliver(t *models.HookTask) error { return nil } +func makeReq(req *http.Request, proxyMatch bool) (*http.Response, error) { + if proxyMatch { + return webhookSocks5PoxyHTTPClient.Do(req) + } + return webhookHTTPClient.Do(req) +} + +func isSocks5ProxyUrlMatch(req *http.Request) bool { + + for _, v := range socks5HostMatchers { + if v.Match(req.URL.Host) { + return true + } + } + return false +} + // DeliverHooks checks and delivers undelivered hooks. // FIXME: graceful: This would likely benefit from either a worker pool with dummy queue // or a full queue. Then more hooks could be sent at same time. @@ -225,9 +246,11 @@ func DeliverHooks(ctx context.Context) { } var ( - webhookHTTPClient *http.Client - once sync.Once - hostMatchers []glob.Glob + webhookHTTPClient *http.Client + once sync.Once + hostMatchers []glob.Glob + webhookSocks5PoxyHTTPClient *http.Client + socks5HostMatchers []glob.Glob ) func webhookProxy() func(req *http.Request) (*url.URL, error) { @@ -274,5 +297,31 @@ func InitDeliverHooks() { }, } + if setting.Webhook.Socks5Proxy != "" { + auth := proxy.Auth{ + User: setting.Webhook.Socks5UserName, + Password: setting.Webhook.Socks5Password, + } + + dialSocksProxy, err := proxy.SOCKS5("tcp", setting.Webhook.Socks5Proxy, &auth, proxy.Direct) + if err != nil { + fmt.Println("Error connecting to proxy:", err) + } + tr := &http.Transport{Dial: dialSocksProxy.Dial} + + webhookSocks5PoxyHTTPClient = &http.Client{ + Transport: tr, + } + + for _, h := range setting.Webhook.Socks5ProxyHosts { + if g, err := glob.Compile(h); err == nil { + socks5HostMatchers = append(socks5HostMatchers, g) + } else { + log.Error("glob.Compile %s failed: %v", h, err) + } + } + + } + go graceful.GetManager().RunWithShutdownContext(DeliverHooks) } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 18ff5472f..c4f1a4648 100755 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -940,6 +940,7 @@ unzip_successed=Unzip Successed unzip_failed=Unzip Failed unzip_stared=Unzipping unzip_status=Unzip Status +collection_num=Collection Nums [repo] owner = Owner repo_name = Repository Name @@ -1034,6 +1035,7 @@ image_delete_fail=Failed to delete image, please try again later. image_overwrite=You had submitted the same name image before, are you sure to overwrite the original image? download=Download score=Score +file_limit_100 = Display up to 100 files or folders in a single directory images.name = Image Tag images.name_placerholder = Please enter the image name @@ -1214,6 +1216,11 @@ model.manage.sava_model = Sava Model model.manage.model_manage = ModelManage model.manage.model_accuracy = Model Accuracy +grampus.train_job.ai_center = AI Center +grampus.dataset_path_rule = The code is storaged in /cache/code;the dataset is storaged in /cache/dataset;and please put your model into /cache/output, then you can download it online。 +grampus.gpu_dataset_path_rule = The code is storaged in /tmp/code;the dataset is storaged in /tmp/dataset;and please put your model into /tmp/output, then you can download it online。 +grampus.no_operate_right = You have no right to do this operation. + template.items = Template Items template.git_content = Git Content (Default Branch) template.git_hooks = Git Hooks @@ -2974,6 +2981,8 @@ task_inferencejob=`created reasoning task %s` task_createmodel=`created new model %s` task_gputrainjob=`created CPU/GPU training task%s` +task_c2netnputrainjob=`created NPU training task%s` +task_c2netgputrainjob=`created CPU/GPU training task%s` [tool] ago = %s ago @@ -3062,6 +3071,9 @@ Platform_Tutorial = Tutorial foot.advice_feedback = Feedback [cloudbrain] +resource_cluster = Resource Cluster +resource_cluster_openi = OpenI Resource Cluster +resource_cluster_c2net = China Computing NET compute_resource = Computing resources task_name = Task name task_type = Task type @@ -3107,3 +3119,5 @@ TRAIN = TRAIN INFERENCE = INFERENCE BENCHMARK = BENCHMARK brain_area = Brain Area + +error.dataset_select = dataset select error:the count exceed the limit or has same name \ No newline at end of file diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 4242f1fec..016db899e 100755 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -945,7 +945,7 @@ unzip_successed=解压成功 unzip_failed=解压失败 unzip_stared=解压中 unzip_status=解压状态 - +collection_num=收藏数量 [repo] owner=拥有者 repo_name=项目名称 @@ -1035,7 +1035,7 @@ image_delete_fail=删除镜像失败,请稍后再试。 image_overwrite=您已经提交过相同名称的镜像,您确定要覆盖原来提交的镜像吗? download=模型下载 score=评分 - +file_limit_100 = 单目录下最多显示100个文件或文件夹 images.name = 镜像Tag images.name_placerholder = 请输入镜像Tag @@ -1228,6 +1228,12 @@ model.manage.sava_model = 保存模型 model.manage.model_manage = 模型管理 model.manage.model_accuracy = 模型精度 +grampus.train_job.ai_center=智算中心 +grampus.dataset_path_rule = 训练脚本存储在/cache/code中,数据集存储在/cache/dataset中,训练输出请存储在/cache/output中以供后续下载。 +grampus.gpu_dataset_path_rule = 训练脚本存储在/tmp/code中,数据集存储在/tmp/dataset中,训练输出请存储在/tmp/output中以供后续下载。 + +grampus.no_operate_right = 您没有权限创建这类任务。 + template.items=模板选项 template.git_content=Git数据(默认分支) template.git_hooks=Git 钩子 @@ -1458,7 +1464,7 @@ issues.label_templates.helper=选择标签模板 issues.label_templates.use=使用标签集 issues.label_templates.fail_to_load_file=加载标签模板文件 '%s' 时发生错误:%v issues.add_label_at=添加了标签
%s
%s -issues.remove_label_at=删除了
%s
label %s 标签 +issues.remove_label_at=删除了标签
%s
%s issues.add_milestone_at=` %[2]s 添加了里程碑 %[1]s` issues.change_milestone_at=`%[3]s 修改了里程碑从 %[1]s%[2]s` issues.remove_milestone_at=`%[2]s 删除了里程碑 %[1]s` @@ -1506,7 +1512,7 @@ issues.filter_sort.mostforks=派生由多到少 issues.filter_sort.fewestforks=派生由少到多 issues.filter_sort.downloadtimes=下载次数 issues.filter_sort.citations=引用次数 -issues.filter_sort.moststars=收藏数量 +issues.filter_sort.moststars=点赞由多到少 issues.filter_sort.mostusecount=最多引用 issues.filter_sort.fewestusecount=最少引用 @@ -2989,6 +2995,8 @@ task_inferencejob=`创建了推理任务 %s` task_createmodel=`导入了新模型 %s` task_gputrainjob=`创建了CPU/GPU类型训练任务 %s` +task_c2netnputrainjob=`创建了NPU类型训练任务 %s` +task_c2netgputrainjob=`创建了CPU/GPU类型训练任务 %s` [tool] ago=%s前 @@ -3077,6 +3085,9 @@ Platform_Tutorial=新手指引 foot.advice_feedback = 意见反馈 [cloudbrain] +resource_cluster = 算力集群 +resource_cluster_openi = 启智集群 +resource_cluster_c2net = 智算网络集群 compute_resource = 计算资源 task_name = 任务名称 task_type = 任务类型 @@ -3123,3 +3134,4 @@ INFERENCE = 推理任务 BENCHMARK = 评测任务 brain_area = 脑区 +error.dataset_select = 数据集选择错误:数量超过限制或者有同名数据集 \ No newline at end of file diff --git a/public/home/home.js b/public/home/home.js index 7343dba0b..95ea3da4c 100755 --- a/public/home/home.js +++ b/public/home/home.js @@ -74,28 +74,30 @@ var swiperOrg = new Swiper(".homeorg-list", { }, }); -var output = document.getElementById("newmessage"); -var url = "ws://" + document.location.host + "/action/notification"; -if(document.location.host == "git.openi.org.cn" || document.URL.startsWith("https")){ - url = "wss://" + document.location.host + "/action/notification" -} -var socket = new WebSocket(url); - -socket.onopen = function () { - messageQueue = []; - console.log("message has connected."); -}; - var maxSize = 20; var html =document.documentElement; var lang = html.attributes["lang"] var isZh = true; if(lang != null && lang.nodeValue =="en-US" ){ isZh=false; -}else{ } -socket.onmessage = function (e) { +document.onreadystatechange = function () { + queryRecommendData(); + + var output = document.getElementById("newmessage"); + var url = "ws://" + document.location.host + "/action/notification"; + if(document.location.host == "git.openi.org.cn" || document.URL.startsWith("https")){ + url = "wss://" + document.location.host + "/action/notification" + } + var socket = new WebSocket(url); + + socket.onopen = function () { + messageQueue = []; + console.log("message has connected."); + }; + + socket.onmessage = function (e) { var data =JSON.parse(e.data) var html = ""; if (data != null){ @@ -154,7 +156,7 @@ socket.onmessage = function (e) { html += recordPrefix + actionName; html += " " + getRepotext(record) + "" } - else if(record.OpType == "24" || record.OpType == "26" || record.OpType == "27" || record.OpType == "28" || record.OpType == "30" || record.OpType == "31"){ + else if(record.OpType == "24" || record.OpType == "26" || record.OpType == "27" || record.OpType == "28" || record.OpType == "30" || record.OpType == "31" || record.OpType == "32" || record.OpType == "33"){ html += recordPrefix + actionName; html += " " + record.RefName + "" } @@ -176,7 +178,10 @@ socket.onmessage = function (e) { output.innerHTML = html; swiperNewMessage.updateSlides(); swiperNewMessage.updateProgress(); -}; + }; +} + + function getTaskLink(record){ var re = getRepoLink(record); @@ -196,6 +201,8 @@ function getTaskLink(record){ re = re + "/modelmanage/show_model_info?name=" + record.RefName; }else if(record.OpType == 31){ re = re + "/cloudbrain/train-job/" + record.Content; + }else if(record.OpType == 32 || record.OpType == 33){ + re = re + "/grampus/train-job/" + record.Content; } re = encodeURI(re); return re; @@ -369,7 +376,9 @@ var actionNameZH={ "28":"创建了推理任务", "29":"创建了评测任务", "30":"导入了新模型", - "31":"创建了CPU/GPU类型训练任务" + "31":"创建了CPU/GPU类型训练任务", + "32":"创建了NPU类型训练任务", + "33":"创建了CPU/GPU类型训练任务" }; var actionNameEN={ @@ -396,6 +405,8 @@ var actionNameEN={ "29":" created profiling task", "30":" created new model", "31":" created CPU/GPU type training task", + "32":" created NPU type training task", + "33":" created CPU/GPU type training task" }; var repoAndOrgZH={ @@ -437,7 +448,9 @@ function getAction(opType,isZh){ } } -queryRecommendData(); + + + function queryRecommendData(){ $.ajax({ diff --git a/public/home/search.js b/public/home/search.js index f9e815da3..86b2ad06e 100644 --- a/public/home/search.js +++ b/public/home/search.js @@ -918,6 +918,8 @@ function LetterAvatar(name, size, color) { } else { initials = nameSplit[0].charAt(0) + nameSplit[1].charAt(0); } + let initials1 = initials.toUpperCase(); + initials.toUpperCase(); if (w.devicePixelRatio) { size = size * w.devicePixelRatio; } @@ -934,7 +936,7 @@ function LetterAvatar(name, size, color) { context.font = Math.round(canvas.width / 2) + "px 'Microsoft Yahei'"; context.textAlign = "center"; context.fillStyle = "#FFF"; - context.fillText(initials, size / 2, size / 1.5); + context.fillText(initials1, size / 2, size / 1.5); dataURI = canvas.toDataURL(); canvas = null; return dataURI; @@ -1009,9 +1011,9 @@ function displayRepoResult(page, jsonResult, onlyReturnNum, keyword) { var recordMap = data[i]; html += '
'; if (recordMap["avatar"]) { - html += ``; + html += ``; } else { - html += ``; + html += ``; } html += '
'; diff --git a/routers/admin/cloudbrains.go b/routers/admin/cloudbrains.go index 0481e6743..8cfe10795 100755 --- a/routers/admin/cloudbrains.go +++ b/routers/admin/cloudbrains.go @@ -43,12 +43,6 @@ func CloudBrains(ctx *context.Context) { if page <= 0 { page = 1 } - debugType := models.TypeCloudBrainAll - if listType == models.GPUResource { - debugType = models.TypeCloudBrainOne - } else if listType == models.NPUResource { - debugType = models.TypeCloudBrainTwo - } var jobTypes []string jobTypeNot := false @@ -77,13 +71,14 @@ func CloudBrains(ctx *context.Context) { PageSize: setting.UI.IssuePagingNum, }, Keyword: keyword, - Type: debugType, JobTypeNot: jobTypeNot, JobStatusNot: jobStatusNot, JobStatus: jobStatuses, JobTypes: jobTypes, NeedRepoInfo: true, IsLatestVersion: modelarts.IsLatestVersion, + ComputeResource: listType, + Type: models.TypeCloudBrainAll, }) if err != nil { ctx.ServerError("Get job failed:", err) diff --git a/routers/admin/dataset.go b/routers/admin/dataset.go index d1a8f2780..9651233b3 100644 --- a/routers/admin/dataset.go +++ b/routers/admin/dataset.go @@ -77,9 +77,10 @@ func Datasets(ctx *context.Context) { Page: page, PageSize: setting.UI.ExplorePagingNum, }, - Keyword: keyword, - RecommendOnly: ctx.QueryBool("recommend"), - SearchOrderBy: orderBy, + Keyword: keyword, + RecommendOnly: ctx.QueryBool("recommend"), + CloudBrainType: -1, + SearchOrderBy: orderBy, }) if err != nil { ctx.ServerError("SearchDataset", err) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 0c280b0cb..e6c572e73 100755 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -947,6 +947,15 @@ func RegisterRoutes(m *macaron.Macaron) { }) }) }, reqRepoReader(models.UnitTypeCloudBrain)) + m.Group("/grampus", func() { + m.Group("/train-job", func() { + m.Group("/:jobid", func() { + m.Get("", repo.GetModelArtsTrainJobVersion) + m.Post("/stop_version", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo_ext.GrampusStopJob) + m.Get("/log", repo_ext.GrampusGetLog) + }) + }) + }, reqRepoReader(models.UnitTypeCloudBrain)) }, repoAssignment()) }) @@ -1046,6 +1055,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/prd/event", authentication.ValidEventSource) m.Post("/prd/event", authentication.AcceptWechatEvent) }) + m.Get("/wechat/material", authentication.GetMaterial) }, securityHeaders(), context.APIContexter(), sudo()) } diff --git a/routers/api/v1/repo/cloudbrain_dashboard.go b/routers/api/v1/repo/cloudbrain_dashboard.go old mode 100644 new mode 100755 index f102a0f05..cc125c97f --- a/routers/api/v1/repo/cloudbrain_dashboard.go +++ b/routers/api/v1/repo/cloudbrain_dashboard.go @@ -103,7 +103,7 @@ func GetAllCloudbrainsOverview(ctx *context.Context) { if cloudbrain.Cloudbrain.Type == models.TypeCloudBrainTwo { cloudBrainTwoDuration = cloudBrainTwoDuration + cloudbrain.Cloudbrain.Duration } - if cloudbrain.Cloudbrain.Type == models.TypeIntelligentNet { + if cloudbrain.Cloudbrain.Type == models.TypeC2Net { intelligentNetDuration = intelligentNetDuration + cloudbrain.Cloudbrain.Duration } @@ -540,7 +540,7 @@ func GetAllCloudbrainsPeriodDistribution(ctx *context.Context) { cloudTwoJobTypeRes[cloudbrain.JobType] += 1 } } - if cloudbrain.Cloudbrain.Type == models.TypeIntelligentNet { + if cloudbrain.Cloudbrain.Type == models.TypeC2Net { if _, ok := intelligentNetJobTypeRes[cloudbrain.JobType]; !ok { intelligentNetJobTypeRes[cloudbrain.JobType] = 1 } else { @@ -1287,7 +1287,7 @@ func getCloudbrainType(rs *models.CloudbrainInfo, ctx *context.Context) string { return ctx.Tr("repo.cloudbrain1") } else if rs.Cloudbrain.Type == models.TypeCloudBrainTwo { return ctx.Tr("repo.cloudbrain2") - } else if rs.Cloudbrain.Type == models.TypeIntelligentNet { + } else if rs.Cloudbrain.Type == models.TypeC2Net { return ctx.Tr("repo.intelligent_net") } else { return ctx.Tr("repo.cloudbrain_untype") diff --git a/routers/api/v1/repo/modelarts.go b/routers/api/v1/repo/modelarts.go index c14976282..2a0ce19db 100755 --- a/routers/api/v1/repo/modelarts.go +++ b/routers/api/v1/repo/modelarts.go @@ -6,6 +6,8 @@ package repo import ( + "code.gitea.io/gitea/modules/grampus" + "encoding/json" "net/http" "strconv" "strings" @@ -125,7 +127,8 @@ func GetModelArtsTrainJob(ctx *context.APIContext) { func GetModelArtsTrainJobVersion(ctx *context.APIContext) { var ( - err error + err error + aiCenterName string ) jobID := ctx.Params(":jobid") @@ -167,7 +170,7 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { log.Error("UpdateJob failed:", err) } } - } else { + } else if job.Type == models.TypeCloudBrainTwo { result, err := modelarts.GetTrainJob(jobID, strconv.FormatInt(job.VersionID, 10)) if err != nil { ctx.NotFound(err) @@ -189,12 +192,50 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { if err != nil { log.Error("UpdateJob failed:", err) } + } else if job.Type == models.TypeC2Net { + result, err := grampus.GetJob(jobID) + if err != nil { + log.Error("GetJob(%s) failed:%v", job.JobName, err) + ctx.NotFound(err) + return + } + + if job.StartTime == 0 && result.JobInfo.StartedAt > 0 { + job.StartTime = timeutil.TimeStamp(result.JobInfo.StartedAt) + } + job.Status = grampus.TransTrainJobStatus(result.JobInfo.Status) + job.Duration = result.JobInfo.RunSec + job.TrainJobDuration = models.ConvertDurationToStr(job.Duration) + + if job.EndTime == 0 && models.IsTrainJobTerminal(job.Status) && job.StartTime > 0 { + job.EndTime = job.StartTime.Add(job.Duration) + } + job.CorrectCreateUnix() + + if len(job.AiCenter) == 0 { + if len(result.JobInfo.Tasks) > 0 { + if len(result.JobInfo.Tasks[0].CenterID) > 0 && len(result.JobInfo.Tasks[0].CenterName) > 0 { + job.AiCenter = result.JobInfo.Tasks[0].CenterID[0] + "+" + result.JobInfo.Tasks[0].CenterName[0] + aiCenterName = result.JobInfo.Tasks[0].CenterName[0] + } + } + } else { + temp := strings.Split(job.AiCenter, "+") + if len(temp) > 1 { + aiCenterName = temp[1] + } + } + err = models.UpdateTrainJobVersion(job) + if err != nil { + log.Error("UpdateJob failed:", err) + } } ctx.JSON(http.StatusOK, map[string]interface{}{ "JobID": jobID, "JobStatus": job.Status, "JobDuration": job.TrainJobDuration, + "AiCenter": aiCenterName, }) } @@ -373,11 +414,29 @@ func ModelList(ctx *context.APIContext) { log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) return } - models, err := storage.GetObsListObject(task.JobName, "output/", parentDir, versionName) - if err != nil { - log.Info("get TrainJobListModel failed:", err) - ctx.ServerError("GetObsListObject:", err) - return + + var fileInfos []storage.FileInfo + if task.ComputeResource == models.NPUResource { + fileInfos, err = storage.GetObsListObject(task.JobName, "output/", parentDir, versionName) + if err != nil { + log.Info("get TrainJobListModel failed:", err) + ctx.ServerError("GetObsListObject:", err) + return + } + } else if task.ComputeResource == models.GPUResource { + files, err := routerRepo.GetModelDirs(task.JobName, parentDir) + if err != nil { + log.Info("GetModelDirs failed:", err) + ctx.ServerError("GetModelDirs:", err) + return + } + + err = json.Unmarshal([]byte(files), &fileInfos) + if err != nil { + log.Error("json.Unmarshal failed:%v", err.Error(), ctx.Data["msgID"]) + ctx.ServerError("json.Unmarshal failed:", err) + return + } } ctx.JSON(http.StatusOK, map[string]interface{}{ @@ -385,7 +444,7 @@ func ModelList(ctx *context.APIContext) { "VersionName": versionName, "StatusOK": 0, "Path": dirArray, - "Dirs": models, + "Dirs": fileInfos, "task": task, "PageIsCloudBrain": true, }) diff --git a/routers/api/v1/repo/repo_dashbord.go b/routers/api/v1/repo/repo_dashbord.go index b19c93371..b3a01cff1 100644 --- a/routers/api/v1/repo/repo_dashbord.go +++ b/routers/api/v1/repo/repo_dashbord.go @@ -887,19 +887,12 @@ func getTimePeroid(ctx *context.Context, recordBeginTime time.Time) (time.Time, if queryType == "all" { beginTime = recordBeginTimeTemp endTime = now - } else if queryType == "today" { + } else if queryType == "yesterday" { endTime = now beginTime = time.Date(endTime.Year(), endTime.Month(), endTime.Day(), 0, 0, 0, 0, now.Location()) - } else if queryType == "yesterday" { - endTime = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) - beginTime = endTime.AddDate(0, 0, -1) - } else if queryType == "last_7day" { - beginTime = now.AddDate(0, 0, -7) - beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location()) - endTime = now - } else if queryType == "last_30day" { - beginTime = now.AddDate(0, 0, -30) + } else if queryType == "current_week" { + beginTime = now.AddDate(0, 0, -int(time.Now().Weekday())+2) //begin from monday beginTime = time.Date(beginTime.Year(), beginTime.Month(), beginTime.Day(), 0, 0, 0, 0, now.Location()) endTime = now } else if queryType == "current_month" { diff --git a/routers/authentication/wechat.go b/routers/authentication/wechat.go index 72871afb3..f4a31ea0c 100644 --- a/routers/authentication/wechat.go +++ b/routers/authentication/wechat.go @@ -8,9 +8,11 @@ import ( "code.gitea.io/gitea/modules/redis/redis_client" "code.gitea.io/gitea/modules/redis/redis_key" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/routers/response" "encoding/json" "errors" gouuid "github.com/satori/go.uuid" + "strconv" "time" ) @@ -124,3 +126,23 @@ func createQRCode4Bind(userId int64) (*QRCodeResponse, error) { } return result, nil } + +// GetMaterial +func GetMaterial(ctx *context.Context) { + mType := ctx.Query("type") + offsetStr := ctx.Query("offset") + countStr := ctx.Query("count") + var offset, count int + if offsetStr == "" { + offset = 0 + } else { + offset, _ = strconv.Atoi(offsetStr) + } + if countStr == "" { + count = 20 + } else { + count, _ = strconv.Atoi(countStr) + } + r := wechat.GetWechatMaterial(mType, offset, count) + ctx.JSON(200, response.SuccessWithData(r)) +} diff --git a/routers/authentication/wechat_event.go b/routers/authentication/wechat_event.go index 9b1cebec6..887bfba0d 100644 --- a/routers/authentication/wechat_event.go +++ b/routers/authentication/wechat_event.go @@ -14,24 +14,48 @@ import ( // https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html func AcceptWechatEvent(ctx *context.Context) { b, _ := ioutil.ReadAll(ctx.Req.Request.Body) - we := wechat.WechatEvent{} + we := wechat.WechatMsg{} xml.Unmarshal(b, &we) - + switch we.MsgType { + case wechat.WECHAT_MSG_TYPE_EVENT: + HandleEventMsg(ctx, we) + case wechat.WECHAT_MSG_TYPE_TEXT: + HandleTextMsg(ctx, we) + } log.Info("accept wechat event= %+v", we) - var replyStr string - switch we.Event { - case wechat.WECHAT_EVENT_SUBSCRIBE, wechat.WECHAT_EVENT_SCAN: - replyStr = wechat.HandleSubscribeEvent(we) - break + +} + +// ValidEventSource +func ValidEventSource(ctx *context.Context) { + echostr := ctx.Query("echostr") + ctx.Write([]byte(echostr)) + return +} + +func HandleEventMsg(ctx *context.Context, msg wechat.WechatMsg) { + switch msg.Event { + case wechat.WECHAT_EVENT_SCAN: + HandleEventScan(ctx, msg) + case wechat.WECHAT_EVENT_SUBSCRIBE: + if msg.EventKey != "" { + HandleEventScan(ctx, msg) + } else { + HandleEventSubscribe(ctx, msg) + } + } +} +func HandleEventScan(ctx *context.Context, msg wechat.WechatMsg) { + replyStr := wechat.HandleScanEvent(msg) if replyStr == "" { log.Info("reply str is empty") return } - reply := &wechat.EventReply{ - ToUserName: we.FromUserName, - FromUserName: we.ToUserName, + reply := &wechat.MsgReply{ + ToUserName: msg.FromUserName, + FromUserName: msg.ToUserName, CreateTime: time.Now().Unix(), MsgType: wechat.WECHAT_MSG_TYPE_TEXT, Content: replyStr, @@ -39,9 +63,99 @@ func AcceptWechatEvent(ctx *context.Context) { ctx.XML(200, reply) } -// ValidEventSource -func ValidEventSource(ctx *context.Context) { - echostr := ctx.Query("echostr") - ctx.Write([]byte(echostr)) - return +func HandleEventSubscribe(ctx *context.Context, msg wechat.WechatMsg) { + r := wechat.HandleSubscribeEvent(msg) + if r == nil { + return + } + reply := buildReplyContent(msg, r) + ctx.XML(200, reply) +} + +func HandleTextMsg(ctx *context.Context, msg wechat.WechatMsg) { + r := wechat.GetAutomaticReply(msg.Content) + if r == nil { + log.Info("TextMsg reply is empty") + return + } + reply := buildReplyContent(msg, r) + ctx.XML(200, reply) +} + +func buildReplyContent(msg wechat.WechatMsg, r *wechat.WechatReplyContent) interface{} { + reply := &wechat.MsgReply{ + ToUserName: msg.FromUserName, + FromUserName: msg.ToUserName, + CreateTime: time.Now().Unix(), + MsgType: r.ReplyType, + } + switch r.ReplyType { + case wechat.ReplyTypeText: + return &wechat.TextMsgReply{ + ToUserName: msg.FromUserName, + FromUserName: msg.ToUserName, + CreateTime: time.Now().Unix(), + MsgType: r.ReplyType, + Content: r.Reply.Content, + } + + case wechat.ReplyTypeImage: + return &wechat.ImageMsgReply{ + ToUserName: msg.FromUserName, + FromUserName: msg.ToUserName, + CreateTime: time.Now().Unix(), + MsgType: r.ReplyType, + Image: wechat.ImageContent{ + MediaId: r.Reply.MediaId, + }, + } + case wechat.ReplyTypeVoice: + return &wechat.VoiceMsgReply{ + ToUserName: msg.FromUserName, + FromUserName: msg.ToUserName, + CreateTime: time.Now().Unix(), + MsgType: r.ReplyType, + Voice: wechat.VoiceContent{ + MediaId: r.Reply.MediaId, + }, + } + case wechat.ReplyTypeVideo: + return &wechat.VideoMsgReply{ + ToUserName: msg.FromUserName, + FromUserName: msg.ToUserName, + CreateTime: time.Now().Unix(), + MsgType: r.ReplyType, + Video: wechat.VideoContent{ + MediaId: r.Reply.MediaId, + Title: r.Reply.Title, + Description: r.Reply.Description, + }, + } + case wechat.ReplyTypeMusic: + return &wechat.MusicMsgReply{ + ToUserName: msg.FromUserName, + FromUserName: msg.ToUserName, + CreateTime: time.Now().Unix(), + MsgType: r.ReplyType, + Music: wechat.MusicContent{ + Title: r.Reply.Title, + Description: r.Reply.Description, + MusicUrl: r.Reply.MusicUrl, + HQMusicUrl: r.Reply.HQMusicUrl, + ThumbMediaId: r.Reply.ThumbMediaId, + }, + } + case wechat.ReplyTypeNews: + return &wechat.NewsMsgReply{ + ToUserName: msg.FromUserName, + FromUserName: msg.ToUserName, + CreateTime: time.Now().Unix(), + MsgType: r.ReplyType, + ArticleCount: len(r.Reply.Articles), + Articles: wechat.ArticleItem{ + Item: r.Reply.Articles}, + } + + } + return reply } diff --git a/routers/home.go b/routers/home.go index aff538f9d..85057c3a1 100755 --- a/routers/home.go +++ b/routers/home.go @@ -350,19 +350,22 @@ func ExploreDatasets(ctx *context.Context) { var datasetsIds []int64 if ownerID > 0 { - datasetsIds = models.GetCollaboratorDatasetIdsByUserID(ownerID) + collaboratorDatasetsIds := models.GetCollaboratorDatasetIdsByUserID(ownerID) + teamDatasetsIds := models.GetTeamDatasetIdsByUserID(ownerID) + datasetsIds = append(collaboratorDatasetsIds, teamDatasetsIds...) } opts := &models.SearchDatasetOptions{ - Keyword: keyword, - IncludePublic: true, - SearchOrderBy: orderBy, - Category: category, - Task: task, - License: license, - OwnerID: ownerID, - DatasetIDs: datasetsIds, - RecommendOnly: ctx.QueryBool("recommend"), + Keyword: keyword, + IncludePublic: true, + SearchOrderBy: orderBy, + Category: category, + Task: task, + License: license, + OwnerID: ownerID, + DatasetIDs: datasetsIds, + RecommendOnly: ctx.QueryBool("recommend"), + CloudBrainType: -1, ListOptions: models.ListOptions{ Page: page, PageSize: 30, diff --git a/routers/repo/cloudbrain.go b/routers/repo/cloudbrain.go index eb2ddc93b..5a3d0a6f8 100755 --- a/routers/repo/cloudbrain.go +++ b/routers/repo/cloudbrain.go @@ -2,6 +2,7 @@ package repo import ( "bufio" + "code.gitea.io/gitea/modules/grampus" "encoding/json" "errors" "fmt" @@ -186,7 +187,7 @@ func cloudBrainNewDataPrepare(ctx *context.Context) error { ctx.Data["brainscore_path"] = cloudbrain.BrainScoreMountPath ctx.Data["is_brainscore_enabled"] = setting.IsBrainScoreEnabled - ctx.Data["cloudbraintype"] = models.TypeCloudBrainOne + ctx.Data["datasetType"] = models.TypeCloudBrainOne ctx.Data["benchmarkMode"] = ctx.Query("benchmarkMode") @@ -207,27 +208,14 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { displayJobName := form.DisplayJobName jobName := util.ConvertDisplayJobNameToJobName(displayJobName) image := strings.TrimSpace(form.Image) - uuid := form.Attachment + uuids := form.Attachment jobType := form.JobType gpuQueue := form.GpuType codePath := setting.JobPath + jobName + cloudbrain.CodeMountPath resourceSpecId := form.ResourceSpecId branchName := form.BranchName repo := ctx.Repo.Repository - tpl := tplCloudBrainNew - command := cloudbrain.Command - if jobType == string(models.JobTypeTrain) { - tpl = tplCloudBrainTrainJobNew - commandTrain, err := getTrainJobCommand(form) - if err != nil { - log.Error("getTrainJobCommand failed: %v", err) - ctx.RenderWithErr(err.Error(), tpl, &form) - return - } - - command = commandTrain - } tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, jobType, displayJobName) if err == nil { @@ -273,6 +261,27 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { } } + datasetInfos, datasetNames, err := models.GetDatasetInfo(uuids) + if err != nil { + log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tpl, &form) + return + } + + command := cloudbrain.Command + if jobType == string(models.JobTypeTrain) { + tpl = tplCloudBrainTrainJobNew + commandTrain, err := getTrainJobCommand(form) + if err != nil { + log.Error("getTrainJobCommand failed: %v", err) + ctx.RenderWithErr(err.Error(), tpl, &form) + return + } + + command = commandTrain + } + if branchName == "" { branchName = cloudbrain.DefaultBranchName } @@ -285,11 +294,33 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { commitID, _ := ctx.Repo.GitRepo.GetBranchCommitID(branchName) - err = cloudbrain.GenerateTask(ctx, displayJobName, jobName, image, command, uuid, storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), - storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"), - storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), - storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, form.Description, branchName, form.BootFile, form.Params, - commitID, 0, 0, resourceSpecId) + req := cloudbrain.GenerateCloudBrainTaskReq{ + Ctx: ctx, + DisplayJobName: displayJobName, + JobName: jobName, + Image: image, + Command: command, + Uuids: uuids, + DatasetNames: datasetNames, + DatasetInfos: datasetInfos, + CodePath: storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), + ModelPath: storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"), + BenchmarkPath: storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), + Snn4ImageNetPath: storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), + BrainScorePath: storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), + JobType: jobType, + GpuQueue: gpuQueue, + Description: form.Description, + BranchName: branchName, + BootFile: form.BootFile, + Params: form.Params, + CommitID: commitID, + BenchmarkTypeID: 0, + BenchmarkChildTypeID: 0, + ResourceSpecId: resourceSpecId, + } + + err = cloudbrain.GenerateTask(req) if err != nil { cloudBrainNewDataPrepare(ctx) ctx.RenderWithErr(err.Error(), tpl, &form) @@ -574,12 +605,6 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo } } - attachment, err := models.GetAttachmentByUUID(task.Uuid) - if err == nil { - ctx.Data["datasetname"] = attachment.Name - } else { - ctx.Data["datasetname"] = "" - } ctx.Data["task"] = task ctx.Data["jobName"] = task.JobName @@ -1036,6 +1061,7 @@ func GetPublicImages(ctx *context.Context) { IncludeOfficialOnly: ctx.QueryBool("recommend"), SearchOrderBy: "type desc, num_stars desc,id desc", Status: models.IMAGE_STATUS_SUCCESS, + CloudbrainType: ctx.QueryInt("cloudbrainType"), } getImages(ctx, &opts) @@ -1471,7 +1497,34 @@ func SyncCloudbrainStatus() { } else { log.Error("task.JobType(%s) is error:%s", task.JobName, task.JobType) } + } else if task.Type == models.TypeC2Net { + result, err := grampus.GetJob(task.JobID) + if err != nil { + log.Error("GetTrainJob(%s) failed:%v", task.JobName, err) + continue + } + if result != nil { + if len(result.JobInfo.Tasks[0].CenterID) == 1 && len(result.JobInfo.Tasks[0].CenterName) == 1 { + task.AiCenter = result.JobInfo.Tasks[0].CenterID[0] + "+" + result.JobInfo.Tasks[0].CenterName[0] + } + task.Status = grampus.TransTrainJobStatus(result.JobInfo.Status) + task.Duration = result.JobInfo.RunSec + task.TrainJobDuration = models.ConvertDurationToStr(task.Duration) + + if task.StartTime == 0 && result.JobInfo.StartedAt > 0 { + task.StartTime = timeutil.TimeStamp(result.JobInfo.StartedAt) + } + if task.EndTime == 0 && models.IsTrainJobTerminal(task.Status) && task.StartTime > 0 { + task.EndTime = task.StartTime.Add(task.Duration) + } + task.CorrectCreateUnix() + err = models.UpdateJob(task) + if err != nil { + log.Error("UpdateJob(%s) failed:%v", task.JobName, err) + continue + } + } } else { log.Error("task.Type(%s) is error:%d", task.JobName, task.Type) } @@ -1982,11 +2035,42 @@ func BenchMarkAlgorithmCreate(ctx *context.Context, form auth.CreateCloudBrainFo //return } - err = cloudbrain.GenerateTask(ctx, displayJobName, jobName, image, command, childInfo.Attachment, storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), - storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"), - storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), - storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), string(models.JobTypeBenchmark), gpuQueue, form.Description, cloudbrain.DefaultBranchName, "", "", - "", benchmarkTypeID, benchmarkChildTypeID, resourceSpecId) + uuid := childInfo.Attachment + datasetInfos, datasetNames, err := models.GetDatasetInfo(uuid) + if err != nil { + log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tplCloudBrainBenchmarkNew, &form) + return + } + + req := cloudbrain.GenerateCloudBrainTaskReq{ + Ctx: ctx, + DisplayJobName: displayJobName, + JobName: jobName, + Image: image, + Command: command, + Uuids: uuid, + DatasetNames: datasetNames, + DatasetInfos: datasetInfos, + CodePath: storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), + ModelPath: storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"), + BenchmarkPath: storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), + Snn4ImageNetPath: storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), + BrainScorePath: storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), + JobType: string(models.JobTypeBenchmark), + GpuQueue: gpuQueue, + Description: form.Description, + BranchName: cloudbrain.DefaultBranchName, + BootFile: "", + Params: "", + CommitID: "", + BenchmarkTypeID: benchmarkTypeID, + BenchmarkChildTypeID: benchmarkChildTypeID, + ResourceSpecId: resourceSpecId, + } + + err = cloudbrain.GenerateTask(req) if err != nil { cloudBrainNewDataPrepare(ctx) ctx.RenderWithErr(err.Error(), tplCloudBrainBenchmarkNew, &form) @@ -2080,11 +2164,41 @@ func ModelBenchmarkCreate(ctx *context.Context, form auth.CreateCloudBrainForm) command = fmt.Sprintf(cloudbrain.BrainScoreCommand, getBrainRegion(benchmarkChildTypeID), displayJobName, trimSpaceNewlineInString(form.Description)) } - err = cloudbrain.GenerateTask(ctx, displayJobName, jobName, image, command, uuid, storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), - storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"), - storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), - storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, form.Description, branchName, form.BootFile, form.Params, - "", 0, benchmarkChildTypeID, resourceSpecId) + datasetInfos, datasetNames, err := models.GetDatasetInfo(uuid) + if err != nil { + log.Error("GetDatasetInfo failed: %v", err, ctx.Data["MsgID"]) + cloudBrainNewDataPrepare(ctx) + ctx.RenderWithErr(ctx.Tr("cloudbrain.error.dataset_select"), tpl, &form) + return + } + + req := cloudbrain.GenerateCloudBrainTaskReq{ + Ctx: ctx, + DisplayJobName: displayJobName, + JobName: jobName, + Image: image, + Command: command, + Uuids: uuid, + DatasetNames: datasetNames, + DatasetInfos: datasetInfos, + CodePath: storage.GetMinioPath(jobName, cloudbrain.CodeMountPath+"/"), + ModelPath: storage.GetMinioPath(jobName, cloudbrain.ModelMountPath+"/"), + BenchmarkPath: storage.GetMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), + Snn4ImageNetPath: storage.GetMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"), + BrainScorePath: storage.GetMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), + JobType: jobType, + GpuQueue: gpuQueue, + Description: form.Description, + BranchName: branchName, + BootFile: form.BootFile, + Params: form.Params, + CommitID: "", + BenchmarkTypeID: 0, + BenchmarkChildTypeID: benchmarkChildTypeID, + ResourceSpecId: resourceSpecId, + } + + err = cloudbrain.GenerateTask(req) if err != nil { cloudBrainNewDataPrepare(ctx) ctx.RenderWithErr(err.Error(), tpl, &form) diff --git a/routers/repo/dataset.go b/routers/repo/dataset.go index 19cd6e6dc..4dde646a6 100755 --- a/routers/repo/dataset.go +++ b/routers/repo/dataset.go @@ -410,6 +410,84 @@ func MyDatasets(ctx *context.Context) { }) } +func datasetMultiple(ctx *context.Context, opts *models.SearchDatasetOptions) { + page := ctx.QueryInt("page") + cloudbrainType := ctx.QueryInt("type") + keyword := strings.Trim(ctx.Query("q"), " ") + orderBy := models.SearchOrderByRecentUpdated + opts.Keyword = keyword + opts.SearchOrderBy = orderBy + opts.RecommendOnly = ctx.QueryBool("recommend") + opts.CloudBrainType = cloudbrainType + opts.ListOptions = models.ListOptions{ + Page: page, + PageSize: setting.UI.DatasetPagingNum, + } + opts.NeedAttachment = true + opts.JustNeedZipFile = true + opts.User = ctx.User + + datasets, count, err := models.SearchDataset(opts) + + if err != nil { + ctx.ServerError("datasets", err) + return + } + + data, err := json.Marshal(datasets) + if err != nil { + log.Error("json.Marshal failed:", err.Error()) + ctx.JSON(200, map[string]string{ + "result_code": "-1", + "error_msg": err.Error(), + "data": "", + }) + return + } + ctx.JSON(200, map[string]string{ + "result_code": "0", + "data": string(data), + "count": strconv.FormatInt(count, 10), + }) + +} + +func CurrentRepoDatasetMultiple(ctx *context.Context) { + + opts := &models.SearchDatasetOptions{ + RepoID: ctx.Repo.Repository.ID, + } + datasetMultiple(ctx, opts) + +} + +func MyDatasetsMultiple(ctx *context.Context) { + + opts := &models.SearchDatasetOptions{ + UploadAttachmentByMe: true, + } + datasetMultiple(ctx, opts) + +} + +func PublicDatasetMultiple(ctx *context.Context) { + + opts := &models.SearchDatasetOptions{ + PublicOnly: true, + } + datasetMultiple(ctx, opts) + +} + +func MyFavoriteDatasetMultiple(ctx *context.Context) { + + opts := &models.SearchDatasetOptions{ + StarByMe: true, + DatasetIDs: models.GetDatasetIdsStarByUser(ctx.User.ID), + } + datasetMultiple(ctx, opts) +} + func PublicDataset(ctx *context.Context) { page := ctx.QueryInt("page") cloudbrainType := ctx.QueryInt("type") diff --git a/routers/repo/grampus.go b/routers/repo/grampus.go new file mode 100755 index 000000000..2e084b535 --- /dev/null +++ b/routers/repo/grampus.go @@ -0,0 +1,843 @@ +package repo + +import ( + "code.gitea.io/gitea/modules/auth" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/grampus" + "code.gitea.io/gitea/modules/modelarts" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" + "encoding/json" + "errors" + "github.com/unknwon/com" + "io/ioutil" + "net/http" + "os" + "path" + "strconv" + "strings" + "time" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/cloudbrain" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" +) + +const ( + tplGrampusTrainJobShow base.TplName = "repo/grampus/trainjob/show" + + //GPU + tplGrampusTrainJobGPUNew base.TplName = "repo/grampus/trainjob/gpu/new" + + //NPU + tplGrampusTrainJobNPUNew base.TplName = "repo/grampus/trainjob/npu/new" +) + +func GrampusTrainJobGPUNew(ctx *context.Context) { + ctx.Data["datasetType"] = models.TypeCloudBrainOne + err := grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + if err != nil { + ctx.ServerError("get new train-job info failed", err) + return + } + ctx.HTML(http.StatusOK, tplGrampusTrainJobGPUNew) +} + +func GrampusTrainJobNPUNew(ctx *context.Context) { + ctx.Data["datasetType"] = models.TypeCloudBrainTwo + err := grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + if err != nil { + ctx.ServerError("get new train-job info failed", err) + return + } + ctx.HTML(200, tplGrampusTrainJobNPUNew) +} + +func grampusTrainJobNewDataPrepare(ctx *context.Context, processType string) error { + ctx.Data["PageIsCloudBrain"] = true + + t := time.Now() + var displayJobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] + ctx.Data["display_job_name"] = displayJobName + + //get valid images + images, err := grampus.GetImages(processType) + if err != nil { + log.Error("GetImages failed:", err.Error()) + } else { + ctx.Data["images"] = images.Infos + } + + grampus.InitSpecialPool() + + ctx.Data["GPUEnabled"] = true + ctx.Data["NPUEnabled"] = true + includeCenters := make(map[string]struct{}) + excludeCenters := make(map[string]struct{}) + if grampus.SpecialPools != nil { + for _, pool := range grampus.SpecialPools.Pools { + if pool.IsExclusive { + if !IsUserInOrgPool(ctx.User.ID, pool) { + ctx.Data[pool.Type+"Enabled"] = false + } + } else { + if strings.Contains(strings.ToLower(processType), strings.ToLower(pool.Type)) { + if IsUserInOrgPool(ctx.User.ID, pool) { + for _, center := range pool.Pool { + includeCenters[center.Queue] = struct{}{} + } + } else { + for _, center := range pool.Pool { + excludeCenters[center.Queue] = struct{}{} + } + + } + + } + + } + } + } + + //get valid resource specs + specs, err := grampus.GetResourceSpecs(processType) + + grampusSpecs := getFilterSpecBySpecialPool(specs, includeCenters, excludeCenters) + + if err != nil { + log.Error("GetResourceSpecs failed:", err.Error()) + } else { + ctx.Data["flavor_infos"] = grampusSpecs + } + + //get branches + branches, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) + if err != nil { + log.Error("GetBranches error:", err.Error()) + } else { + ctx.Data["branches"] = branches + } + + ctx.Data["branchName"] = ctx.Repo.BranchName + + if processType == grampus.ProcessorTypeGPU { + ctx.Data["datasetType"] = models.TypeCloudBrainOne + } else if processType == grampus.ProcessorTypeNPU { + ctx.Data["datasetType"] = models.TypeCloudBrainTwo + } + + return nil +} + +func getFilterSpecBySpecialPool(specs *models.GetGrampusResourceSpecsResult, includeCenters map[string]struct{}, excludeCenters map[string]struct{}) []models.GrampusSpec { + if len(includeCenters) == 0 && len(excludeCenters) == 0 { + return specs.Infos + } + var grampusSpecs []models.GrampusSpec + for _, info := range specs.Infos { + if isInIncludeCenters(info, includeCenters) || (len(excludeCenters) != 0 && isNotAllInExcludeCenters(info, excludeCenters)) { + grampusSpecs = append(grampusSpecs, info) + } + + } + return grampusSpecs +} + +func isInIncludeCenters(grampusSpec models.GrampusSpec, centers map[string]struct{}) bool { + for _, center := range grampusSpec.Centers { + if _, ok := centers[center.ID]; ok { + return true + } + } + return false +} +func isNotAllInExcludeCenters(grampusSpec models.GrampusSpec, centers map[string]struct{}) bool { + for _, center := range grampusSpec.Centers { + if _, ok := centers[center.ID]; !ok { + return true + } + } + return false +} + +func IsUserInOrgPool(userId int64, pool *models.SpecialPool) bool { + org, _ := models.GetOrgByName(pool.Org) + if org != nil { + isOrgMember, _ := models.IsOrganizationMember(org.ID, userId) + return isOrgMember + } + return false +} + +func grampusParamCheckCreateTrainJob(form auth.CreateGrampusTrainJobForm) error { + if !strings.HasSuffix(strings.TrimSpace(form.BootFile), ".py") { + log.Error("the boot file(%s) must be a python file", form.BootFile) + return errors.New("启动文件必须是python文件") + } + + if form.BranchName == "" { + log.Error("the branch must not be null!", form.BranchName) + return errors.New("代码分支不能为空!") + } + + return nil +} + +func GrampusTrainJobGpuCreate(ctx *context.Context, form auth.CreateGrampusTrainJobForm) { + displayJobName := form.DisplayJobName + jobName := util.ConvertDisplayJobNameToJobName(displayJobName) + uuid := form.Attachment + description := form.Description + bootFile := strings.TrimSpace(form.BootFile) + params := form.Params + repo := ctx.Repo.Repository + codeLocalPath := setting.JobPath + jobName + cloudbrain.CodeMountPath + "/" + codeMinioPath := setting.CBCodePathPrefix + jobName + cloudbrain.CodeMountPath + "/" + dataMinioPath := setting.Attachment.Minio.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + branchName := form.BranchName + flavorName := form.FlavorName + image := strings.TrimSpace(form.Image) + + if !jobNamePattern.MatchString(displayJobName) { + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplGrampusTrainJobGPUNew, &form) + return + } + + errStr := checkSpecialPool(ctx, "GPU") + if errStr != "" { + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr(errStr, tplGrampusTrainJobGPUNew, &form) + return + } + + //check count limit + count, err := models.GetGrampusCountByUserID(ctx.User.ID, string(models.JobTypeTrain), models.GPUResource) + if err != nil { + log.Error("GetGrampusCountByUserID failed:%v", err, ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr("system error", tplGrampusTrainJobGPUNew, &form) + return + } else { + if count >= 1 { + log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplGrampusTrainJobGPUNew, &form) + return + } + } + + //check param + if err := grampusParamCheckCreateTrainJob(form); err != nil { + log.Error("paramCheckCreateTrainJob failed:(%v)", err, ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr(err.Error(), tplGrampusTrainJobGPUNew, &form) + return + } + + //check whether the task name in the project is duplicated + tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, string(models.JobTypeTrain), displayJobName) + if err == nil { + if len(tasks) != 0 { + log.Error("the job name did already exist", ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr("the job name did already exist", tplGrampusTrainJobGPUNew, &form) + return + } + } else { + if !models.IsErrJobNotExist(err) { + log.Error("system error, %v", err, ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr("system error", tplGrampusTrainJobGPUNew, &form) + return + } + } + + //check dataset + attachment, err := models.GetAttachmentByUUID(uuid) + if err != nil { + log.Error("GetAttachmentByUUID failed:", err.Error(), ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr("dataset is not exist", tplGrampusTrainJobGPUNew, &form) + return + } + + //prepare code and out path + _, err = ioutil.ReadDir(codeLocalPath) + if err == nil { + os.RemoveAll(codeLocalPath) + } + + if err := downloadZipCode(ctx, codeLocalPath, branchName); err != nil { + log.Error("downloadZipCode failed, server timed out: %s (%v)", repo.FullName(), err, ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr("Create task failed, internal error", tplGrampusTrainJobGPUNew, &form) + return + } + + //todo: upload code (send to file_server todo this work?) + //upload code + if err := uploadCodeToMinio(codeLocalPath+"/", jobName, cloudbrain.CodeMountPath+"/"); err != nil { + log.Error("Failed to uploadCodeToMinio: %s (%v)", repo.FullName(), err, ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr("Create task failed, internal error", tplGrampusTrainJobGPUNew, &form) + return + } + + modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath + "/" + if err := mkModelPath(modelPath); err != nil { + log.Error("Failed to mkModelPath: %s (%v)", repo.FullName(), err, ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr("Create task failed, internal error", tplGrampusTrainJobGPUNew, &form) + return + } + + //init model readme + if err := uploadCodeToMinio(modelPath, jobName, cloudbrain.ModelMountPath+"/"); err != nil { + log.Error("Failed to uploadCodeToMinio: %s (%v)", repo.FullName(), err, ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr("Create task failed, internal error", tplGrampusTrainJobGPUNew, &form) + return + } + + //prepare command + command, err := generateCommand(repo.Name, grampus.ProcessorTypeGPU, codeMinioPath+cloudbrain.DefaultBranchName+".zip", dataMinioPath, bootFile, params, setting.CBCodePathPrefix+jobName+cloudbrain.ModelMountPath+"/", attachment.Name) + if err != nil { + log.Error("Failed to generateCommand: %s (%v)", displayJobName, err, ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr("Create task failed, internal error", tplGrampusTrainJobGPUNew, &form) + return + } + + commitID, _ := ctx.Repo.GitRepo.GetBranchCommitID(branchName) + + req := &grampus.GenerateTrainJobReq{ + JobName: jobName, + DisplayJobName: displayJobName, + ComputeResource: models.GPUResource, + ProcessType: grampus.ProcessorTypeGPU, + Command: command, + ResourceSpecId: form.FlavorID, + ImageUrl: image, + Description: description, + BootFile: bootFile, + Uuid: uuid, + CommitID: commitID, + BranchName: branchName, + Params: form.Params, + FlavorName: flavorName, + EngineName: image, + DatasetName: attachment.Name, + IsLatestVersion: modelarts.IsLatestVersion, + VersionCount: modelarts.VersionCount, + WorkServerNumber: 1, + } + + err = grampus.GenerateTrainJob(ctx, req) + if err != nil { + log.Error("GenerateTrainJob failed:%v", err.Error(), ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeGPU) + ctx.RenderWithErr(err.Error(), tplGrampusTrainJobGPUNew, &form) + return + } + ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") +} + +func checkSpecialPool(ctx *context.Context, resourceType string) string { + grampus.InitSpecialPool() + if grampus.SpecialPools != nil { + for _, pool := range grampus.SpecialPools.Pools { + + if pool.IsExclusive && pool.Type == resourceType { + + org, _ := models.GetOrgByName(pool.Org) + if org != nil { + isOrgMember, _ := models.IsOrganizationMember(org.ID, ctx.User.ID) + if !isOrgMember { + return ctx.Tr("repo.grampus.no_operate_right") + } + } + } + + } + + } + return "" +} + +func GrampusTrainJobNpuCreate(ctx *context.Context, form auth.CreateGrampusTrainJobForm) { + displayJobName := form.DisplayJobName + jobName := util.ConvertDisplayJobNameToJobName(displayJobName) + uuid := form.Attachment + description := form.Description + bootFile := strings.TrimSpace(form.BootFile) + params := form.Params + repo := ctx.Repo.Repository + codeLocalPath := setting.JobPath + jobName + modelarts.CodePath + codeObsPath := grampus.JobPath + jobName + modelarts.CodePath + dataObsPath := setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + "/" + branchName := form.BranchName + isLatestVersion := modelarts.IsLatestVersion + flavorName := form.FlavorName + versionCount := modelarts.VersionCount + engineName := form.EngineName + + if !jobNamePattern.MatchString(displayJobName) { + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr(ctx.Tr("repo.cloudbrain_jobname_err"), tplGrampusTrainJobNPUNew, &form) + return + } + + errStr := checkSpecialPool(ctx, "NPU") + if errStr != "" { + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr(errStr, tplGrampusTrainJobGPUNew, &form) + return + } + + //check count limit + count, err := models.GetGrampusCountByUserID(ctx.User.ID, string(models.JobTypeTrain), models.NPUResource) + if err != nil { + log.Error("GetGrampusCountByUserID failed:%v", err, ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr("system error", tplGrampusTrainJobNPUNew, &form) + return + } else { + if count >= 1 { + log.Error("the user already has running or waiting task", ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr("you have already a running or waiting task, can not create more", tplGrampusTrainJobNPUNew, &form) + return + } + } + + //check param + if err := grampusParamCheckCreateTrainJob(form); err != nil { + log.Error("paramCheckCreateTrainJob failed:(%v)", err) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr(err.Error(), tplGrampusTrainJobNPUNew, &form) + return + } + + //check whether the task name in the project is duplicated + tasks, err := models.GetCloudbrainsByDisplayJobName(repo.ID, string(models.JobTypeTrain), displayJobName) + if err == nil { + if len(tasks) != 0 { + log.Error("the job name did already exist", ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr("the job name did already exist", tplGrampusTrainJobNPUNew, &form) + return + } + } else { + if !models.IsErrJobNotExist(err) { + log.Error("system error, %v", err, ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr("system error", tplGrampusTrainJobNPUNew, &form) + return + } + } + + //check dataset + attachment, err := models.GetAttachmentByUUID(uuid) + if err != nil { + log.Error("GetAttachmentByUUID failed:", err.Error(), ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr("dataset is not exist", tplGrampusTrainJobNPUNew, &form) + return + } + + //prepare code and out path + _, err = ioutil.ReadDir(codeLocalPath) + if err == nil { + os.RemoveAll(codeLocalPath) + } + + if err := downloadZipCode(ctx, codeLocalPath, branchName); err != nil { + log.Error("downloadZipCode failed, server timed out: %s (%v)", repo.FullName(), err) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr("Create task failed, server timed out", tplGrampusTrainJobNPUNew, &form) + return + } + + //todo: upload code (send to file_server todo this work?) + if err := obsMkdir(setting.CodePathPrefix + jobName + modelarts.OutputPath); err != nil { + log.Error("Failed to obsMkdir_output: %s (%v)", repo.FullName(), err) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr("Failed to obsMkdir_output", tplGrampusTrainJobNPUNew, &form) + return + } + + if err := uploadCodeToObs(codeLocalPath, jobName, ""); err != nil { + log.Error("Failed to uploadCodeToObs: %s (%v)", repo.FullName(), err) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr("Failed to uploadCodeToObs", tplGrampusTrainJobNPUNew, &form) + return + } + + //prepare command + command, err := generateCommand(repo.Name, grampus.ProcessorTypeNPU, codeObsPath+cloudbrain.DefaultBranchName+".zip", dataObsPath+"'"+attachment.Name+"'", bootFile, params, setting.CodePathPrefix+jobName+modelarts.OutputPath, attachment.Name) + if err != nil { + log.Error("Failed to generateCommand: %s (%v)", displayJobName, err, ctx.Data["MsgID"]) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr("Create task failed, internal error", tplGrampusTrainJobNPUNew, &form) + return + } + + commitID, _ := ctx.Repo.GitRepo.GetBranchCommitID(branchName) + + req := &grampus.GenerateTrainJobReq{ + JobName: jobName, + DisplayJobName: displayJobName, + ComputeResource: models.NPUResource, + ProcessType: grampus.ProcessorTypeNPU, + Command: command, + ResourceSpecId: form.FlavorID, + ImageId: form.ImageID, + DataUrl: dataObsPath, + Description: description, + CodeObsPath: codeObsPath, + BootFileUrl: codeObsPath + bootFile, + BootFile: bootFile, + WorkServerNumber: form.WorkServerNumber, + Uuid: uuid, + CommitID: commitID, + IsLatestVersion: isLatestVersion, + BranchName: branchName, + Params: form.Params, + FlavorName: flavorName, + EngineName: engineName, + VersionCount: versionCount, + TotalVersionCount: modelarts.TotalVersionCount, + DatasetName: attachment.Name, + } + + err = grampus.GenerateTrainJob(ctx, req) + if err != nil { + log.Error("GenerateTrainJob failed:%v", err.Error()) + grampusTrainJobNewDataPrepare(ctx, grampus.ProcessorTypeNPU) + ctx.RenderWithErr(err.Error(), tplGrampusTrainJobNPUNew, &form) + return + } + ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job") +} + +func GrampusStopJob(ctx *context.Context) { + var ID = ctx.Params(":jobid") + var resultCode = "0" + var errorMsg = "" + var status = "" + + task := ctx.Cloudbrain + for { + if task.Status == string(models.GrampusStatusStopped) || task.Status == string(models.GrampusStatusFailed) || task.Status == string(models.GrampusStatusSucceeded) { + log.Error("the job(%s) has been stopped", task.JobName, ctx.Data["msgID"]) + resultCode = "-1" + errorMsg = "system error" + break + } + + res, err := grampus.StopJob(task.JobID) + if err != nil { + log.Error("StopJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"]) + resultCode = strconv.Itoa(res.ErrorCode) + errorMsg = res.ErrorMsg + break + } + + task.Status = string(models.GrampusStatusStopped) + if task.EndTime == 0 { + task.EndTime = timeutil.TimeStampNow() + } + task.ComputeAndSetDuration() + err = models.UpdateJob(task) + if err != nil { + log.Error("UpdateJob(%s) failed:%v", task.JobName, err, ctx.Data["msgID"]) + resultCode = "-1" + errorMsg = "system error" + break + } + + status = task.Status + break + } + + ctx.JSON(200, map[string]interface{}{ + "result_code": resultCode, + "error_msg": errorMsg, + "status": status, + "id": ID, + "StatusOK": 0, + }) +} + +func GrampusTrainJobDel(ctx *context.Context) { + var listType = ctx.Query("listType") + if err := deleteGrampusJob(ctx); err != nil { + log.Error("deleteGrampusJob failed: %v", err, ctx.Data["msgID"]) + ctx.ServerError(err.Error(), err) + return + } + + var isAdminPage = ctx.Query("isadminpage") + var isHomePage = ctx.Query("ishomepage") + if ctx.IsUserSiteAdmin() && isAdminPage == "true" { + ctx.Redirect(setting.AppSubURL + "/admin" + "/cloudbrains") + } else if isHomePage == "true" { + ctx.Redirect(setting.AppSubURL + "/cloudbrains") + } else { + ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/train-job?listType=" + listType) + } +} + +func deleteGrampusJob(ctx *context.Context) error { + task := ctx.Cloudbrain + + if task.Status != string(models.GrampusStatusStopped) && task.Status != string(models.GrampusStatusSucceeded) && task.Status != string(models.GrampusStatusFailed) { + log.Error("the job(%s) has not been stopped", task.JobName, ctx.Data["msgID"]) + return errors.New("the job has not been stopped") + } + + err := models.DeleteJob(task) + if err != nil { + log.Error("DeleteJob failed: %v", err, ctx.Data["msgID"]) + return err + } + + storageType := models.TypeCloudBrainOne + if task.ComputeResource == models.NPUResource { + storageType = models.TypeCloudBrainTwo + } + deleteJobStorage(task.JobName, storageType) + + return nil +} + +func GrampusTrainJobShow(ctx *context.Context) { + ctx.Data["PageIsCloudBrain"] = true + + var task *models.Cloudbrain + task, err := models.GetCloudbrainByJobIDWithDeleted(ctx.Params(":jobid")) + if err != nil { + log.Error("GetCloudbrainByJobID failed:" + err.Error()) + ctx.ServerError("system error", err) + return + } + + if task.DeletedAt.IsZero() { //normal record + result, err := grampus.GetJob(task.JobID) + if err != nil { + log.Error("GetJob failed:" + err.Error()) + //ctx.ServerError("GetJob failed", err) + //return + } + + if result != nil { + if len(result.JobInfo.Tasks[0].CenterID) == 1 && len(result.JobInfo.Tasks[0].CenterName) == 1 { + task.AiCenter = result.JobInfo.Tasks[0].CenterID[0] + "+" + result.JobInfo.Tasks[0].CenterName[0] + } + task.Status = grampus.TransTrainJobStatus(result.JobInfo.Status) + if task.Status != result.JobInfo.Status || result.JobInfo.Status == models.GrampusStatusRunning { + task.Duration = result.JobInfo.RunSec + task.TrainJobDuration = models.ConvertDurationToStr(task.Duration) + + if task.StartTime == 0 && result.JobInfo.StartedAt > 0 { + task.StartTime = timeutil.TimeStamp(result.JobInfo.StartedAt) + } + if task.EndTime == 0 && models.IsTrainJobTerminal(task.Status) && task.StartTime > 0 { + task.EndTime = task.StartTime.Add(task.Duration) + } + task.CorrectCreateUnix() + err = models.UpdateJob(task) + if err != nil { + log.Error("UpdateJob failed:" + err.Error()) + } + } + } + } + + if len(task.Parameters) > 0 { + var parameters models.Parameters + err := json.Unmarshal([]byte(task.Parameters), ¶meters) + if err != nil { + log.Error("Failed to Unmarshal Parameters: %s (%v)", task.Parameters, err) + ctx.ServerError("system error", err) + return + } + + if len(parameters.Parameter) > 0 { + paramTemp := "" + for _, Parameter := range parameters.Parameter { + param := Parameter.Label + " = " + Parameter.Value + "; " + paramTemp = paramTemp + param + } + task.Parameters = paramTemp[:len(paramTemp)-2] + } else { + task.Parameters = "" + } + } + + taskList := make([]*models.Cloudbrain, 0) + taskList = append(taskList, task) + ctx.Data["version_list_task"] = taskList + + ctx.Data["canDownload"] = cloudbrain.CanModifyJob(ctx, task) + ctx.Data["displayJobName"] = task.DisplayJobName + + aiCenterInfo := strings.Split(task.AiCenter, "+") + if len(aiCenterInfo) == 2 { + ctx.Data["ai_center"] = aiCenterInfo[1] + } + + ctx.HTML(http.StatusOK, tplGrampusTrainJobShow) +} + +func GrampusGetLog(ctx *context.Context) { + jobID := ctx.Params(":jobid") + job, err := models.GetCloudbrainByJobID(jobID) + if err != nil { + log.Error("GetCloudbrainByJobID failed: %v", err, ctx.Data["MsgID"]) + ctx.ServerError(err.Error(), err) + return + } + + content, err := grampus.GetTrainJobLog(job.JobID) + if err != nil { + log.Error("GetTrainJobLog failed: %v", err, ctx.Data["MsgID"]) + ctx.ServerError(err.Error(), err) + return + } + + ctx.JSON(http.StatusOK, map[string]interface{}{ + "JobName": job.JobName, + "Content": content, + }) + + return +} + +func generateCommand(repoName, processorType, codeRemotePath, dataRemotePath, bootFile, paramSrc, outputRemotePath, datasetName string) (string, error) { + var command string + + workDir := grampus.NpuWorkDir + if processorType == grampus.ProcessorTypeGPU { + workDir = grampus.GpuWorkDir + } + + command += "pwd;cd " + workDir + grampus.CommandPrepareScript + //download code & dataset + if processorType == grampus.ProcessorTypeNPU { + commandDownload := "./downloader_for_obs " + setting.Bucket + " " + codeRemotePath + " " + grampus.CodeArchiveName + " " + dataRemotePath + " '" + datasetName + "';" + command += commandDownload + } else if processorType == grampus.ProcessorTypeGPU { + commandDownload := "./downloader_for_minio " + setting.Grampus.Env + " " + codeRemotePath + " " + grampus.CodeArchiveName + " " + dataRemotePath + " '" + datasetName + "';" + command += commandDownload + } + + //check download result + commandCheckRes := "bash -c \"[[ $? -eq 0 ]] && exit 0 || exit -1;\";" + command += commandCheckRes + + //unzip code & dataset + toolUnzip := "unzip -q '" + if strings.HasSuffix(datasetName, ".tar.gz") { + toolUnzip = "tar -zxvf '" + } + commandUnzip := "cd " + workDir + "code;unzip -q master.zip;echo \"start to unzip dataset\";cd " + workDir + "dataset;" + toolUnzip + datasetName + "';" + command += commandUnzip + + //check unzip result + commandCheckRes = "bash -c \"[[ $? -eq 0 ]] && exit 0 || exit -1;\";" + command += commandCheckRes + + command += "echo \"unzip finished;start to exec code;\";" + + //exec code + var parameters models.Parameters + var paramCode string + param := make([]models.Parameter, 0) + if len(paramSrc) != 0 { + err := json.Unmarshal([]byte(paramSrc), ¶meters) + if err != nil { + log.Error("Failed to Unmarshal params: %s (%v)", paramSrc, err) + return command, err + } + + for _, parameter := range parameters.Parameter { + param = append(param, models.Parameter{ + Label: parameter.Label, + Value: parameter.Value, + }) + paramCode += " --" + parameter.Label + "=" + parameter.Value + } + } + + commandCode := "cd " + workDir + "code/" + strings.ToLower(repoName) + ";python " + bootFile + paramCode + ";" + command += commandCode + + //get exec result + commandGetRes := "result=$?;" + command += commandGetRes + + //upload models + if processorType == grampus.ProcessorTypeNPU { + commandUpload := "cd " + workDir + "script_for_grampus/;./uploader_for_obs " + setting.Bucket + " " + outputRemotePath + " " + workDir + "output/;" + command += commandUpload + } else if processorType == grampus.ProcessorTypeGPU { + commandUpload := "cd " + workDir + "script_for_grampus/;./uploader_for_minio " + setting.Grampus.Env + " " + outputRemotePath + " " + workDir + "output/;" + command += commandUpload + } + + //check exec result + commandCheckRes = "bash -c \"[[ $result -eq 0 ]] && exit 0 || exit -1\"" + command += commandCheckRes + + return command, nil +} + +func downloadZipCode(ctx *context.Context, codePath, branchName string) error { + archiveType := git.ZIP + archivePath := codePath + + if !com.IsDir(archivePath) { + if err := os.MkdirAll(archivePath, os.ModePerm); err != nil { + log.Error("MkdirAll failed:" + err.Error()) + return err + } + } + + // Get corresponding commit. + var ( + commit *git.Commit + err error + ) + + gitRepo := ctx.Repo.GitRepo + if err != nil { + log.Error("OpenRepository failed:" + err.Error()) + return err + } + + if gitRepo.IsBranchExist(branchName) { + commit, err = gitRepo.GetBranchCommit(branchName) + if err != nil { + log.Error("GetBranchCommit failed:" + err.Error()) + return err + } + } + + archivePath = path.Join(archivePath, grampus.CodeArchiveName) + if !com.IsFile(archivePath) { + if err := commit.CreateArchive(archivePath, git.CreateArchiveOpts{ + Format: archiveType, + Prefix: setting.Repository.PrefixArchiveFiles, + }); err != nil { + log.Error("CreateArchive failed:" + err.Error()) + return err + } + } + + return nil +} diff --git a/routers/repo/modelarts.go b/routers/repo/modelarts.go index 12a5a0623..d1d00d095 100755 --- a/routers/repo/modelarts.go +++ b/routers/repo/modelarts.go @@ -146,7 +146,7 @@ func notebookNewDataPrepare(ctx *context.Context) error { } ctx.Data["flavors"] = modelarts.FlavorInfos.FlavorInfo - ctx.Data["cloudbraintype"] = models.TypeCloudBrainTwo + ctx.Data["datasetType"] = models.TypeCloudBrainTwo return nil } @@ -285,14 +285,37 @@ func NotebookShow(ctx *context.Context) { } } - datasetDownloadLink := "" + datasetDownload := make([]models.DatasetDownload, 0) if ctx.IsSigned { if task.Uuid != "" && task.UserID == ctx.User.ID { - attachment, err := models.GetAttachmentByUUID(task.Uuid) - if err == nil { - task.DatasetName = attachment.Name - datasetDownloadLink = attachment.S3DownloadURL() + uuidList := strings.Split(task.Uuid, ";") + for _, uuidStr := range uuidList { + attachment, err := models.GetAttachmentByUUID(uuidStr) + if err != nil { + log.Error("GetAttachmentByUUID failed:%v", err.Error()) + return + } + dataset, err := models.GetDatasetByID(attachment.DatasetID) + if err != nil { + log.Error("GetDatasetByID failed:%v", err.Error()) + return + } + repo, err := models.GetRepositoryByID(dataset.RepoID) + if err != nil { + log.Error("GetRepositoryByID failed:%v", err.Error()) + return + } + datasetDownload = append(datasetDownload, models.DatasetDownload{ + DatasetName: attachment.Name, + DatasetDownloadLink: attachment.S3DownloadURL(), + RepositoryLink: repo.Link() + "/datasets", + }) + } + // datasetName, err := GetDatasetNameByUUID(task.Uuid) + // if err == nil { + // task.DatasetName = datasetName + // } } } user, err := models.GetUserByID(task.UserID) @@ -324,7 +347,7 @@ func NotebookShow(ctx *context.Context) { task.TrainJobDuration = models.ConvertDurationToStr(task.Duration) } ctx.Data["duration"] = task.TrainJobDuration - ctx.Data["datasetDownloadLink"] = datasetDownloadLink + ctx.Data["datasetDownload"] = datasetDownload ctx.Data["task"] = task ctx.Data["ID"] = ID ctx.Data["jobName"] = task.JobName @@ -559,24 +582,11 @@ func TrainJobIndex(ctx *context.Context) { } listType := ctx.Query("listType") - if len(listType) == 0 { - listType = models.AllResource - } ctx.Data["ListType"] = listType - typeCloudBrain := models.TypeCloudBrainAll - if listType == models.GPUResource { - typeCloudBrain = models.TypeCloudBrainOne - } else if listType == models.NPUResource { - typeCloudBrain = models.TypeCloudBrainTwo - } else if listType == models.AllResource { - typeCloudBrain = models.TypeCloudBrainAll + if listType == models.AllResource { + listType = "" } - //else { - // log.Error("listType(%s) error", listType) - // ctx.ServerError("listType error", errors.New("listType error")) - // return - //} var jobTypes []string jobTypes = append(jobTypes, string(models.JobTypeTrain)) @@ -586,10 +596,11 @@ func TrainJobIndex(ctx *context.Context) { PageSize: setting.UI.IssuePagingNum, }, RepoID: repo.ID, - Type: typeCloudBrain, JobTypeNot: false, JobTypes: jobTypes, IsLatestVersion: modelarts.IsLatestVersion, + ComputeResource: listType, + Type: models.TypeCloudBrainAll, }) if err != nil { ctx.ServerError("Cloudbrain", err) @@ -599,11 +610,6 @@ func TrainJobIndex(ctx *context.Context) { for i, task := range tasks { tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain) - if task.Cloudbrain.Type == models.TypeCloudBrainOne { - tasks[i].ComputeResource = models.GPUResource - } else if task.Cloudbrain.Type == models.TypeCloudBrainTwo { - tasks[i].ComputeResource = models.NPUResource - } } pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) @@ -690,7 +696,7 @@ func trainJobNewDataPrepare(ctx *context.Context) error { return err } ctx.Data["config_list"] = configList.ParaConfigs - ctx.Data["cloudbraintype"] = models.TypeCloudBrainTwo + ctx.Data["datasetType"] = models.TypeCloudBrainTwo return nil } @@ -764,7 +770,7 @@ func trainJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModelArts ctx.Data["bootFile"] = form.BootFile ctx.Data["uuid"] = form.Attachment ctx.Data["branch_name"] = form.BranchName - ctx.Data["cloudbraintype"] = models.TypeCloudBrainTwo + ctx.Data["datasetType"] = models.TypeCloudBrainTwo return nil } @@ -858,7 +864,7 @@ func trainJobNewVersionDataPrepare(ctx *context.Context) error { ctx.Data["uuid"] = task.Uuid ctx.Data["flavor_code"] = task.FlavorCode ctx.Data["engine_id"] = task.EngineID - ctx.Data["cloudbraintype"] = models.TypeCloudBrainTwo + ctx.Data["datasetType"] = models.TypeCloudBrainTwo configList, err := getConfigList(modelarts.PerPage, 1, modelarts.SortByCreateTime, "desc", "", modelarts.ConfigTypeCustom) if err != nil { @@ -955,7 +961,7 @@ func versionErrorDataPrepare(ctx *context.Context, form auth.CreateModelArtsTrai return err } ctx.Data["config_list"] = configList.ParaConfigs - ctx.Data["cloudbraintype"] = models.TypeCloudBrainTwo + ctx.Data["datasetType"] = models.TypeCloudBrainTwo return nil } @@ -979,7 +985,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath + VersionOutputPath + "/" logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath + VersionOutputPath + "/" - dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/" + // dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/" branch_name := form.BranchName isLatestVersion := modelarts.IsLatestVersion FlavorName := form.FlavorName @@ -1095,6 +1101,27 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) Value: modelarts.Ascend, }) } + datasUrlList, dataUrl, datasetNames, isMultiDataset, err := getDatasUrlListByUUIDS(uuid) + if err != nil { + log.Error("Failed to getDatasUrlListByUUIDS: %v", err) + trainJobErrorNewDataPrepare(ctx, form) + ctx.RenderWithErr("Failed to getDatasUrlListByUUIDS:"+err.Error(), tplModelArtsTrainJobNew, &form) + return + } + dataPath := dataUrl + jsondatas, err := json.Marshal(datasUrlList) + if err != nil { + log.Error("Failed to Marshal: %v", err) + trainJobErrorNewDataPrepare(ctx, form) + ctx.RenderWithErr("json error:"+err.Error(), tplModelArtsTrainJobNew, &form) + return + } + if isMultiDataset { + param = append(param, models.Parameter{ + Label: modelarts.MultiDataUrl, + Value: string(jsondatas), + }) + } //save param config if isSaveParam == "on" { @@ -1161,6 +1188,7 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) EngineName: EngineName, VersionCount: VersionCount, TotalVersionCount: modelarts.TotalVersionCount, + DatasetName: datasetNames, } //将params转换Parameters.Parameter,出错时返回给前端 @@ -1222,7 +1250,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ codeObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.CodePath + VersionOutputPath + "/" outputObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.OutputPath + VersionOutputPath + "/" logObsPath := "/" + setting.Bucket + modelarts.JobPath + jobName + modelarts.LogPath + VersionOutputPath + "/" - dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/" + // dataPath := "/" + setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + uuid + "/" branch_name := form.BranchName PreVersionName := form.VersionName FlavorName := form.FlavorName @@ -1314,6 +1342,28 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ }) } + datasUrlList, dataUrl, datasetNames, isMultiDataset, err := getDatasUrlListByUUIDS(uuid) + if err != nil { + log.Error("Failed to getDatasUrlListByUUIDS: %v", err) + versionErrorDataPrepare(ctx, form) + ctx.RenderWithErr("Failed to getDatasUrlListByUUIDS:"+err.Error(), tplModelArtsTrainJobVersionNew, &form) + return + } + dataPath := dataUrl + jsondatas, err := json.Marshal(datasUrlList) + if err != nil { + log.Error("Failed to Marshal: %v", err) + versionErrorDataPrepare(ctx, form) + ctx.RenderWithErr("json error:"+err.Error(), tplModelArtsTrainJobVersionNew, &form) + return + } + if isMultiDataset { + param = append(param, models.Parameter{ + Label: modelarts.MultiDataUrl, + Value: string(jsondatas), + }) + } + //save param config if isSaveParam == "on" { saveparams := append(param, models.Parameter{ @@ -1386,6 +1436,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ EngineName: EngineName, PreVersionName: PreVersionName, TotalVersionCount: latestTask.TotalVersionCount + 1, + DatasetName: datasetNames, } err = modelarts.GenerateTrainJobVersion(ctx, req, jobID) @@ -2111,7 +2162,7 @@ func inferenceJobNewDataPrepare(ctx *context.Context) error { New: MODEL_LATEST, }) ctx.Data["MODEL_COUNT"] = model_count - ctx.Data["cloudbraintype"] = models.TypeCloudBrainTwo + ctx.Data["datasetType"] = models.TypeCloudBrainTwo return nil } @@ -2177,7 +2228,7 @@ func inferenceJobErrorNewDataPrepare(ctx *context.Context, form auth.CreateModel ctx.Data["model_version"] = form.ModelVersion ctx.Data["ckpt_name"] = form.CkptName ctx.Data["train_url"] = form.TrainUrl - ctx.Data["cloudbraintype"] = models.TypeCloudBrainTwo + ctx.Data["datasetType"] = models.TypeCloudBrainTwo return nil } @@ -2247,24 +2298,35 @@ func ModelDownload(ctx *context.Context) { err error ) - var jobID = ctx.Params(":jobid") + jobID := ctx.Params(":jobid") versionName := ctx.Query("version_name") parentDir := ctx.Query("parent_dir") fileName := ctx.Query("file_name") task, err := models.GetCloudbrainByJobIDAndVersionName(jobID, versionName) if err != nil { - log.Error("GetCloudbrainByJobID(%s) failed:%v", task.JobName, err.Error()) + log.Error("GetCloudbrainByJobIDAndVersionName(%s) failed:%v", task.JobName, err.Error()) return } - path := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, task.JobName, setting.OutPutPath, versionName, parentDir, fileName), "/") - - url, err := storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path) - if err != nil { - log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) - ctx.ServerError("GetObsCreateSignedUrl", err) - return + var url string + if task.ComputeResource == models.NPUResource { + path := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, task.JobName, setting.OutPutPath, versionName, parentDir, fileName), "/") + url, err = storage.GetObsCreateSignedUrlByBucketAndKey(setting.Bucket, path) + if err != nil { + log.Error("GetObsCreateSignedUrl failed: %v", err.Error(), ctx.Data["msgID"]) + ctx.ServerError("GetObsCreateSignedUrl", err) + return + } + } else if task.ComputeResource == models.GPUResource { + filePath := setting.CBCodePathPrefix + task.JobName + cloudbrain.ModelMountPath + "/" + parentDir + url, err = storage.Attachments.PresignedGetURL(filePath, fileName) + if err != nil { + log.Error("PresignedGetURL failed: %v", err.Error(), ctx.Data["msgID"]) + ctx.ServerError("PresignedGetURL", err) + return + } } + ctx.Resp.Header().Set("Cache-Control", "max-age=0") http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) } @@ -2420,3 +2482,50 @@ func TrainJobDownloadLogFile(ctx *context.Context) { ctx.Resp.Header().Set("Cache-Control", "max-age=0") http.Redirect(ctx.Resp, ctx.Req.Request, url, http.StatusMovedPermanently) } +func getDatasUrlListByUUIDS(uuidStr string) ([]models.Datasurl, string, string, bool, error) { + var isMultiDataset bool + var dataUrl string + var datasetNames string + var datasUrlList []models.Datasurl + uuids := strings.Split(uuidStr, ";") + if len(uuids) > setting.MaxDatasetNum { + log.Error("the dataset count(%d) exceed the limit", len(uuids)) + return datasUrlList, dataUrl, datasetNames, isMultiDataset, errors.New("the dataset count exceed the limit") + } + + datasetInfos := make(map[string]models.DatasetInfo) + attachs, err := models.GetAttachmentsByUUIDs(uuids) + if err != nil { + log.Error("GetAttachmentsByUUIDs failed: %v", err) + return datasUrlList, dataUrl, datasetNames, isMultiDataset, errors.New("GetAttachmentsByUUIDs failed") + } + for i, attach := range attachs { + fileName := strings.TrimSuffix(strings.TrimSuffix(strings.TrimSuffix(attach.Name, ".zip"), ".tar.gz"), ".tgz") + for _, datasetInfo := range datasetInfos { + if fileName == datasetInfo.Name { + log.Error("the dataset name is same: %v", attach.Name) + return datasUrlList, dataUrl, datasetNames, isMultiDataset, errors.New("the dataset name is same") + } + } + if len(attachs) <= 1 { + dataUrl = "/" + setting.Bucket + "/" + setting.BasePath + path.Join(attach.UUID[0:1], attach.UUID[1:2]) + "/" + attach.UUID + attach.UUID + "/" + isMultiDataset = false + } else { + dataUrl = "/" + setting.Bucket + "/" + setting.BasePath + path.Join(attachs[0].UUID[0:1], attachs[0].UUID[1:2]) + "/" + attachs[0].UUID + attachs[0].UUID + "/" + datasetUrl := "s3://" + setting.Bucket + "/" + setting.BasePath + path.Join(attach.UUID[0:1], attach.UUID[1:2]) + "/" + attach.UUID + attach.UUID + "/" + datasUrlList = append(datasUrlList, models.Datasurl{ + DatasetUrl: datasetUrl, + DatasetName: fileName, + }) + isMultiDataset = true + } + + if i == 0 { + datasetNames = attach.Name + } else { + datasetNames += ";" + attach.Name + } + } + + return datasUrlList, dataUrl, datasetNames, isMultiDataset, nil +} diff --git a/routers/routes/routes.go b/routers/routes/routes.go index e1272a359..980eb51d5 100755 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -1041,6 +1041,11 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/public_datasets", repo.PublicDataset) m.Get("/my_favorite", repo.MyFavoriteDataset) + m.Get("/current_repo_m", repo.CurrentRepoDatasetMultiple) + m.Get("/my_datasets_m", repo.MyDatasetsMultiple) + m.Get("/public_datasets_m", repo.PublicDatasetMultiple) + m.Get("/my_favorite_m", repo.MyFavoriteDatasetMultiple) + m.Group("/status", func() { m.Get("/:uuid", repo.GetDatasetStatus) }) @@ -1101,6 +1106,24 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateCloudBrainForm{}), repo.CloudBrainCreate) }) }, context.RepoRef()) + m.Group("/grampus", func() { + m.Group("/train-job", func() { + m.Group("/:jobid", func() { + m.Get("", reqRepoCloudBrainReader, repo.GrampusTrainJobShow) + m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.GrampusStopJob) + m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRightForTrain, repo.GrampusTrainJobDel) + m.Get("/model_download", cloudbrain.AdminOrJobCreaterRightForTrain, repo.ModelDownload) + }) + m.Group("/gpu", func() { + m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, repo.GrampusTrainJobGPUNew) + m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateGrampusTrainJobForm{}), repo.GrampusTrainJobGpuCreate) + }) + m.Group("/npu", func() { + m.Get("/create", reqWechatBind, reqRepoCloudBrainWriter, repo.GrampusTrainJobNPUNew) + m.Post("/create", reqWechatBind, reqRepoCloudBrainWriter, bindIgnErr(auth.CreateGrampusTrainJobForm{}), repo.GrampusTrainJobNpuCreate) + }) + }) + }, context.RepoRef()) m.Group("/modelmanage", func() { m.Post("/create_model", reqRepoModelManageWriter, repo.SaveModel) m.Post("/create_new_model", repo.SaveNewNameModel) diff --git a/routers/user/home.go b/routers/user/home.go index 53aff19b8..ab64e707f 100755 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -769,12 +769,6 @@ func Cloudbrains(ctx *context.Context) { if page <= 0 { page = 1 } - debugType := models.TypeCloudBrainAll - if listType == models.GPUResource { - debugType = models.TypeCloudBrainOne - } else if listType == models.NPUResource { - debugType = models.TypeCloudBrainTwo - } var jobTypes []string jobTypeNot := false @@ -821,7 +815,6 @@ func Cloudbrains(ctx *context.Context) { }, Keyword: keyword, UserID: ctxUser.ID, - Type: debugType, JobTypeNot: jobTypeNot, JobStatusNot: jobStatusNot, JobStatus: jobStatuses, @@ -829,6 +822,8 @@ func Cloudbrains(ctx *context.Context) { NeedRepoInfo: true, IsLatestVersion: modelarts.IsLatestVersion, RepoIDList: repoIDList, + ComputeResource: listType, + Type: models.TypeCloudBrainAll, }) if err != nil { ctx.ServerError("Get job failed:", err) diff --git a/routers/user/profile.go b/routers/user/profile.go index f82c03a75..30808f235 100755 --- a/routers/user/profile.go +++ b/routers/user/profile.go @@ -263,6 +263,7 @@ func Profile(ctx *context.Context) { Page: page, PageSize: setting.UI.ExplorePagingNum, }, + CloudBrainType: -1, } if len(datasetSearchOptions.SearchOrderBy) == 0 { diff --git a/services/socketwrap/clientManager.go b/services/socketwrap/clientManager.go index 6ffa96933..98bcc8a85 100755 --- a/services/socketwrap/clientManager.go +++ b/services/socketwrap/clientManager.go @@ -10,7 +10,7 @@ import ( "github.com/elliotchance/orderedmap" ) -var opTypes = []int{1, 2, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31} +var opTypes = []int{1, 2, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33} type ClientsManager struct { Clients *orderedmap.OrderedMap diff --git a/templates/admin/cloudbrain/list.tmpl b/templates/admin/cloudbrain/list.tmpl index 4c63b167a..347b5658d 100755 --- a/templates/admin/cloudbrain/list.tmpl +++ b/templates/admin/cloudbrain/list.tmpl @@ -102,7 +102,7 @@ {{else if eq .JobType "TRAIN"}} {{.DisplayJobName}} @@ -204,7 +204,7 @@ {{else}} {{$.i18n.Tr "repo.stop"}} @@ -212,7 +212,7 @@
{{$.CsrfTokenHtml}}
-
+ data-dataset-type="{{.datasetType}}">
+
- {{if eq .cloudbraintype 0}} + {{if eq .datasetType 0}} {{else}} @@ -18,7 +18,7 @@
- +
diff --git a/templates/custom/select_dataset_train.tmpl b/templates/custom/select_dataset_train.tmpl old mode 100644 new mode 100755 index f1d2abaf3..a6ad0d873 --- a/templates/custom/select_dataset_train.tmpl +++ b/templates/custom/select_dataset_train.tmpl @@ -1,11 +1,11 @@ -
+ data-dataset-type="{{.datasetType}}">
+
{{if or (.benchmarkMode) (.newInference)}}       {{else}}{{.i18n.Tr "dataset.dataset"}}    {{end}} {{else}} -     + {{end}} @@ -22,7 +22,7 @@
- +
diff --git a/templates/explore/datasets.tmpl b/templates/explore/datasets.tmpl index 327c4fb98..17164cfed 100644 --- a/templates/explore/datasets.tmpl +++ b/templates/explore/datasets.tmpl @@ -154,7 +154,7 @@ {{.i18n.Tr "repo.issues.filter_sort.downloadtimes"}} {{.i18n.Tr "repo.issues.filter_sort.moststars"}} + href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}&recommend={{$.Recommend}}">{{.i18n.Tr "dataset.collection_num"}} {{.i18n.Tr "repo.issues.filter_sort.mostusecount"}}
diff --git a/templates/repo/cloudbrain/benchmark/show.tmpl b/templates/repo/cloudbrain/benchmark/show.tmpl index c79f6f268..59ce3c471 100755 --- a/templates/repo/cloudbrain/benchmark/show.tmpl +++ b/templates/repo/cloudbrain/benchmark/show.tmpl @@ -474,7 +474,7 @@
- {{$.datasetname}} + {{.DatasetName}}
diff --git a/templates/repo/cloudbrain/new.tmpl b/templates/repo/cloudbrain/new.tmpl index 107415e04..295fe0435 100755 --- a/templates/repo/cloudbrain/new.tmpl +++ b/templates/repo/cloudbrain/new.tmpl @@ -104,6 +104,7 @@ top: 14px; z-index: 2; */ } +
@@ -119,8 +120,8 @@
{{template "repo/header" .}}
-
+ {{template "base/alert" .}}

@@ -218,8 +219,10 @@
+
- {{template "custom/select_dataset" .}} +
+
@@ -206,13 +208,17 @@ 查看样例
+
+ +
+ - {{template "custom/select_dataset_train" .}} + 训练脚本存储在/code中,数据集存储在/dataset中,训练输出请存储在/model中以供后续下载。 -
- + style="margin-left: 11.5rem;margin-bottom: 1rem;">训练脚本存储在/code中,数据集存储在/dataset中,训练输出请存储在/model中以供后续下载。 +
+ {{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}} @@ -239,8 +245,8 @@
-
- +
+
-
+
+ @@ -274,7 +281,11 @@ $('.menu .item') .tab(); - + $(document).keydown(function(event){ + switch(event.keyCode){ + case 13:return false; + } + }); let sever_num = $('#trainjob_work_server_num') $('.add').click(function () { sever_num.val(parseInt(sever_num.val()) + 1) diff --git a/templates/repo/cloudbrain/trainjob/show.tmpl b/templates/repo/cloudbrain/trainjob/show.tmpl index f1087abcf..05d678016 100755 --- a/templates/repo/cloudbrain/trainjob/show.tmpl +++ b/templates/repo/cloudbrain/trainjob/show.tmpl @@ -474,6 +474,10 @@
+
+ + {{$.i18n.Tr "repo.file_limit_100"}} +
diff --git a/templates/repo/grampus/trainjob/gpu/new.tmpl b/templates/repo/grampus/trainjob/gpu/new.tmpl new file mode 100755 index 000000000..3570d6226 --- /dev/null +++ b/templates/repo/grampus/trainjob/gpu/new.tmpl @@ -0,0 +1,440 @@ +{{template "base/head" .}} + + +
+
+
+
+
+
+
+
+
+
+ {{template "repo/header" .}} +
+ {{template "base/alert" .}} +

+ {{.i18n.Tr "repo.modelarts.train_job.new"}} +

+
+ + + {{.CsrfTokenHtml}} + + + +

{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:

+ +
+ + +
+
+ + + {{.i18n.Tr "cloudbrain.job_name_rule"}} +
+ +
+ + +
+
+ +

{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:

+ + +
+ + +
+ +
+
+ +
+ + {{if .bootFile}} + + {{else}} + + {{end}} + + + + 查看样例 +
+ + + {{template "custom/select_dataset_train" .}} + {{.i18n.Tr "repo.grampus.gpu_dataset_path_rule"}} +
+ + {{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}} + +
+ {{if .params}} + {{if ne 0 (len .params)}} + {{range $k ,$v := .params}} +
+
+ +
+
+ +
+ + + + +
+ {{end}} + {{end}} + {{end}} +
+
+ +
+ + +
+ +
+ + + {{.i18n.Tr "repo.cloudbrain.cancel"}} +
+ + + + +
+
+
+{{template "base/footer" .}} + + \ No newline at end of file diff --git a/templates/repo/grampus/trainjob/npu/new.tmpl b/templates/repo/grampus/trainjob/npu/new.tmpl new file mode 100755 index 000000000..d318777a4 --- /dev/null +++ b/templates/repo/grampus/trainjob/npu/new.tmpl @@ -0,0 +1,431 @@ +{{template "base/head" .}} + + +
+
+
+
+
+
+
+
+
+
+ {{template "repo/header" .}} +
+ {{template "base/alert" .}} +

+ {{.i18n.Tr "repo.modelarts.train_job.new"}} +

+
+ +
+ {{.CsrfTokenHtml}} + + + +

{{.i18n.Tr "repo.modelarts.train_job.basic_info"}}:

+ +
+ + +
+
+ + + {{.i18n.Tr "cloudbrain.job_name_rule"}} +
+ +
+ + +
+
+ +

{{.i18n.Tr "repo.modelarts.train_job.parameter_setting"}}:

+ + +
+ + +
+ +
+ + +
+ +
+ + {{if .bootFile}} + + {{else}} + + {{end}} + + + + {{.i18n.Tr "cloudbrain.view_sample"}} +
+ + {{template "custom/select_dataset_train" .}} + {{.i18n.Tr "repo.grampus.dataset_path_rule"}} +
+ + {{.i18n.Tr "repo.modelarts.train_job.add_run_parameter"}} + +
+
+
+ +
+ + +
+
+ + +
+ + +
+ +
+ +
+
+ +
+ + + {{.i18n.Tr "repo.cloudbrain.cancel"}} +
+ + + +
+
+
+
+{{template "base/footer" .}} + + diff --git a/templates/repo/grampus/trainjob/show.tmpl b/templates/repo/grampus/trainjob/show.tmpl new file mode 100755 index 000000000..579e83693 --- /dev/null +++ b/templates/repo/grampus/trainjob/show.tmpl @@ -0,0 +1,982 @@ +{{template "base/head" .}} + +
+
+
+
+
+
+
+
+
+
+ {{template "repo/header" .}} +
+

+ +

+ {{range $k ,$v := .version_list_task}} +
+
+
+
+ + + +
+ {{$.CsrfTokenHtml}} + +
+
+ + + {{if not (eq .StartTime 0)}} + {{TimeSinceUnix1 .StartTime}} + {{else}} + {{TimeSinceUnix1 .CreatedUnix}} + {{end}} + + {{$.i18n.Tr "repo.modelarts.current_version"}}:{{.VersionName}} + + {{$.i18n.Tr "repo.modelarts.parent_version"}}:{{.PreVersionName}} + {{$.i18n.Tr "repo.modelarts.status"}}: + {{.Status}} + + {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}}: + {{.TrainJobDuration}} + + +
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {{$.i18n.Tr "repo.cloudbrain_task"}} + +
+ {{.DisplayJobName}} +
+
+ {{$.i18n.Tr "repo.modelarts.status"}} + +
+ {{.Status}} +
+
+ {{$.i18n.Tr "repo.modelarts.run_version"}} + +
+ {{.VersionName}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.start_time"}} + +
+ + {{if not (eq .StartTime 0)}} + {{TimeSinceUnix1 .StartTime}} + {{else}} + {{TimeSinceUnix1 .CreatedUnix}} + {{end}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} + +
+ {{.TrainJobDuration}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.standard"}} + +
+ {{.FlavorName}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.compute_node"}} + +
+ {{.WorkServerNumber}} +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {{$.i18n.Tr "repo.modelarts.train_job.AI_driver"}} + +
+ {{.EngineName}} +
+
+ {{$.i18n.Tr "repo.modelarts.code_version"}} + +
+ {{.BranchName}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.start_file"}} + +
+ {{.BootFile}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.train_dataset"}} + +
+ {{.DatasetName}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.run_parameter"}} + +
+ {{.Parameters}} +
+
+ {{$.i18n.Tr "repo.grampus.train_job.ai_center"}} + +
+ {{$.ai_center}} +
+
+ {{$.i18n.Tr "repo.modelarts.train_job.description"}} + +
+ {{.Description}} +
+
+
+
+
+ +
+
+
+
+ +
+ + +

+                            
+ +
+ +
+
+ + + +
+ +
+
+ +
+
+
+ {{end}} {{template "base/paginate" .}} +
+ +
+ +
+ +
+ +
+
+{{template "base/footer" .}} + + \ No newline at end of file diff --git a/templates/repo/modelarts/notebook/new.tmpl b/templates/repo/modelarts/notebook/new.tmpl index 61ece0f8d..4e2b3951d 100755 --- a/templates/repo/modelarts/notebook/new.tmpl +++ b/templates/repo/modelarts/notebook/new.tmpl @@ -18,6 +18,7 @@ {{template "repo/header" .}}
+ {{template "base/alert" .}}

@@ -59,7 +60,9 @@ {{end}}
- {{template "custom/select_dataset" .}} +
+ +
- + {{.DisplayJobName}} @@ -153,18 +153,18 @@
{{$.CsrfTokenHtml}} {{if .CanDel}} - + {{$.i18n.Tr "repo.stop"}} {{else}} - + {{$.i18n.Tr "repo.stop"}} {{end}}
-
+ {{$.CsrfTokenHtml}} {{if .CanDel}} diff --git a/templates/repo/modelarts/trainjob/new.tmpl b/templates/repo/modelarts/trainjob/new.tmpl index 9d6a45e83..5022bd41b 100755 --- a/templates/repo/modelarts/trainjob/new.tmpl +++ b/templates/repo/modelarts/trainjob/new.tmpl @@ -1,59 +1,58 @@ {{template "base/head" .}} {{$.CsrfTokenHtml}} {{if or (eq .GetOpType 5) (eq .GetOpType 18)}} @@ -107,11 +111,11 @@ {{index .GetIssueInfos 1 | RenderEmoji}} {{else if or (eq .GetOpType 10) (eq .GetOpType 21) (eq .GetOpType 22) (eq .GetOpType 23)}} {{.GetIssueTitle | RenderEmoji}} -

{{index .GetIssueInfos 1 | RenderEmoji}}

+

{{index .GetIssueInfos 1 | RenderEmoji}}

{{else if eq .GetOpType 11}} -

{{index .GetIssueInfos 1}}

+

{{index .GetIssueInfos 1}}

{{else if or (eq .GetOpType 12) (eq .GetOpType 13) (eq .GetOpType 14) (eq .GetOpType 15)}} - {{.GetIssueTitle | RenderEmoji}} + {{.GetIssueTitle | RenderEmoji}} {{end}}

{{TimeSince .GetCreate $.i18n.Lang}}

diff --git a/web_src/js/components/dataset/selectDataset.vue b/web_src/js/components/dataset/selectDataset.vue new file mode 100755 index 000000000..4c056094e --- /dev/null +++ b/web_src/js/components/dataset/selectDataset.vue @@ -0,0 +1,1155 @@ + + + + + diff --git a/web_src/js/components/images/Images.vue b/web_src/js/components/images/Images.vue old mode 100644 new mode 100755 index 5c50f38d7..456bf27e9 --- a/web_src/js/components/images/Images.vue +++ b/web_src/js/components/images/Images.vue @@ -672,7 +672,7 @@ export default { }, filters:{ transformType(val){ - if(val==0){ + if(val==0 || val==2){ return "GPU" } }, diff --git a/web_src/js/components/images/selectGrampusImages.vue b/web_src/js/components/images/selectGrampusImages.vue new file mode 100755 index 000000000..5bbc3a43e --- /dev/null +++ b/web_src/js/components/images/selectGrampusImages.vue @@ -0,0 +1,292 @@ + + + + + diff --git a/web_src/js/components/images/selectImages.vue b/web_src/js/components/images/selectImages.vue old mode 100644 new mode 100755 index fad9e9a5d..148b98890 --- a/web_src/js/components/images/selectImages.vue +++ b/web_src/js/components/images/selectImages.vue @@ -1,376 +1,569 @@ - - \ No newline at end of file + diff --git a/web_src/js/features/images.js b/web_src/js/features/images.js old mode 100644 new mode 100755 index 0cafb3901..4a88a29e0 --- a/web_src/js/features/images.js +++ b/web_src/js/features/images.js @@ -1,6 +1,7 @@ import Images from '../components/images/Images.vue'; import adminImages from '../components/images/adminImages.vue'; import selectImages from '../components/images/selectImages.vue'; +import selectGrampusImages from '../components/images/selectGrampusImages.vue'; import Vue from 'vue'; export default async function initImage(){ function validate() { @@ -209,7 +210,19 @@ export default async function initImage(){ render: h => h(selectImages) }); } + function initVueselectGrampusImages() { + const el = document.getElementById('images-new-grampus'); + if (!el) { + return; + } + + new Vue({ + el:el, + render: h => h(selectGrampusImages) + }); + } initVueImages() initVueAdminImages() initVueselectImages() + initVueselectGrampusImages() } \ No newline at end of file diff --git a/web_src/js/features/letteravatar.js b/web_src/js/features/letteravatar.js index 9ec12b60f..3092149d9 100644 --- a/web_src/js/features/letteravatar.js +++ b/web_src/js/features/letteravatar.js @@ -1,74 +1,100 @@ /** * LetterAvatar - * + * * Artur Heinze * Create Letter avatar based on Initials * based on https://gist.github.com/leecrossley/6027780 */ -(function(w, d){ - function LetterAvatar (name, size, color) { - name = name || ''; - size = size || 60; - var colours = [ - "#1abc9c", "#2ecc71", "#3498db", "#9b59b6", "#34495e", "#16a085", "#27ae60", "#2980b9", "#8e44ad", "#2c3e50", - "#f1c40f", "#e67e22", "#e74c3c", "#00bcd4", "#95a5a6", "#f39c12", "#d35400", "#c0392b", "#bdc3c7", "#7f8c8d" - ], - nameSplit = String(name).split(' '), - initials, charIndex, colourIndex, canvas, context, dataURI; - if (nameSplit.length == 1) { - initials = nameSplit[0] ? nameSplit[0].charAt(0):'?'; - } else { - initials = nameSplit[0].charAt(0) + nameSplit[1].charAt(0); - } - if (w.devicePixelRatio) { - size = (size * w.devicePixelRatio); - } - - charIndex = (initials == '?' ? 72 : initials.charCodeAt(0)) - 64; - colourIndex = charIndex % 20; - canvas = d.createElement('canvas'); - canvas.width = size; - canvas.height = size; - context = canvas.getContext("2d"); - - context.fillStyle = color ? color : colours[colourIndex - 1]; - context.fillRect (0, 0, canvas.width, canvas.height); - context.font = Math.round(canvas.width/2)+"px 'Microsoft Yahei'"; - context.textAlign = "center"; - context.fillStyle = "#FFF"; - context.fillText(initials, size / 2, size / 1.5); - dataURI = canvas.toDataURL(); - canvas = null; - return dataURI; +(function (w, d) { + function LetterAvatar(name, size, color) { + name = name || ""; + size = size || 60; + var colours = [ + "#1abc9c", + "#2ecc71", + "#3498db", + "#9b59b6", + "#34495e", + "#16a085", + "#27ae60", + "#2980b9", + "#8e44ad", + "#2c3e50", + "#f1c40f", + "#e67e22", + "#e74c3c", + "#00bcd4", + "#95a5a6", + "#f39c12", + "#d35400", + "#c0392b", + "#bdc3c7", + "#7f8c8d", + ], + nameSplit = String(name).split(" "), + initials, + charIndex, + colourIndex, + canvas, + context, + dataURI; + if (nameSplit.length == 1) { + initials = nameSplit[0] ? nameSplit[0].charAt(0) : "?"; + } else { + initials = nameSplit[0].charAt(0) + nameSplit[1].charAt(0); + } + let initials1 = initials.toUpperCase(); + if (w.devicePixelRatio) { + size = size * w.devicePixelRatio; } - LetterAvatar.transform = function() { - Array.prototype.forEach.call(d.querySelectorAll('img[avatar]'), function(img, name, color) { - name = img.getAttribute('avatar'); - color = img.getAttribute('color'); - img.src = LetterAvatar(name, img.getAttribute('width'), color); - img.removeAttribute('avatar'); - img.setAttribute('alt', name); - }); - }; - // AMD support - if (typeof define === 'function' && define.amd) { - - define(function () { return LetterAvatar; }); - + + charIndex = (initials == "?" ? 72 : initials.charCodeAt(0)) - 64; + colourIndex = charIndex % 20; + canvas = d.createElement("canvas"); + canvas.width = size; + canvas.height = size; + context = canvas.getContext("2d"); + + context.fillStyle = color ? color : colours[colourIndex - 1]; + context.fillRect(0, 0, canvas.width, canvas.height); + context.font = Math.round(canvas.width / 2) + "px 'Microsoft Yahei'"; + context.textAlign = "center"; + context.fillStyle = "#FFF"; + context.fillText(initials1, size / 2, size / 1.5); + dataURI = canvas.toDataURL(); + canvas = null; + return dataURI; + } + LetterAvatar.transform = function () { + Array.prototype.forEach.call( + d.querySelectorAll("img[avatar]"), + function (img, name, color) { + name = img.getAttribute("avatar"); + color = img.getAttribute("color"); + img.src = LetterAvatar(name, img.getAttribute("width"), color); + img.removeAttribute("avatar"); + img.setAttribute("alt", name); + } + ); + }; + // AMD support + if (typeof define === "function" && define.amd) { + define(function () { + return LetterAvatar; + }); + // CommonJS and Node.js module support. - } else if (typeof exports !== 'undefined') { - - // Support Node.js specific `module.exports` (which can be a function) - if (typeof module != 'undefined' && module.exports) { - exports = module.exports = LetterAvatar; - } - // But always support CommonJS module 1.1.1 spec (`exports` cannot be a function) - exports.LetterAvatar = LetterAvatar; - } else { - - window.LetterAvatar = LetterAvatar; - d.addEventListener('DOMContentLoaded', function(event) { - LetterAvatar.transform(); - }); + } else if (typeof exports !== "undefined") { + // Support Node.js specific `module.exports` (which can be a function) + if (typeof module != "undefined" && module.exports) { + exports = module.exports = LetterAvatar; } -})(window, document); \ No newline at end of file + // But always support CommonJS module 1.1.1 spec (`exports` cannot be a function) + exports.LetterAvatar = LetterAvatar; + } else { + window.LetterAvatar = LetterAvatar; + d.addEventListener("DOMContentLoaded", function (event) { + LetterAvatar.transform(); + }); + } +})(window, document); diff --git a/web_src/js/index.js b/web_src/js/index.js index ef12b4158..754d6ca76 100755 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -2,65 +2,66 @@ /* exported timeAddManual, toggleStopwatch, cancelStopwatch */ /* exported toggleDeadlineForm, setDeadline, updateDeadline, deleteDependencyModal, cancelCodeComment, onOAuthLoginClick */ -import './publicpath.js'; -import './polyfills.js'; -import './features/letteravatar.js' -import Vue from 'vue'; -import ElementUI from 'element-ui'; -import 'element-ui/lib/theme-chalk/index.css'; -import axios from 'axios'; -import qs from 'qs'; -import Cookies from 'js-cookie' -import 'jquery.are-you-sure'; -import './vendor/semanticdropdown.js'; -import { svg } from './utils.js'; -import echarts from 'echarts' -import initContextPopups from './features/contextpopup.js'; -import initGitGraph from './features/gitgraph.js'; -import initClipboard from './features/clipboard.js'; -import initUserHeatmap from './features/userheatmap.js'; -import initDateTimePicker from './features/datetimepicker.js'; -import initContextMenu from './features/contexmenu.js'; +import "./publicpath.js"; +import "./polyfills.js"; +import "./features/letteravatar.js"; +import Vue from "vue"; +import ElementUI from "element-ui"; +import "element-ui/lib/theme-chalk/index.css"; +import axios from "axios"; +import qs from "qs"; +import Cookies from "js-cookie"; +import "jquery.are-you-sure"; +import "./vendor/semanticdropdown.js"; +import { svg } from "./utils.js"; +import echarts from "echarts"; +import initContextPopups from "./features/contextpopup.js"; +import initGitGraph from "./features/gitgraph.js"; +import initClipboard from "./features/clipboard.js"; +import initUserHeatmap from "./features/userheatmap.js"; +import initDateTimePicker from "./features/datetimepicker.js"; +import initContextMenu from "./features/contexmenu.js"; import { initTribute, issuesTribute, - emojiTribute -} from './features/tribute.js'; -import createDropzone from './features/dropzone.js'; -import highlight from './features/highlight.js'; -import ActivityTopAuthors from './components/ActivityTopAuthors.vue'; + emojiTribute, +} from "./features/tribute.js"; +import createDropzone from "./features/dropzone.js"; +import highlight from "./features/highlight.js"; +import ActivityTopAuthors from "./components/ActivityTopAuthors.vue"; import { initNotificationsTable, - initNotificationCount -} from './features/notification.js'; -import { createCodeEditor } from './features/codeeditor.js'; -import MinioUploader from './components/MinioUploader.vue'; -import EditAboutInfo from './components/EditAboutInfo.vue'; + initNotificationCount, +} from "./features/notification.js"; +import { createCodeEditor } from "./features/codeeditor.js"; +import MinioUploader from "./components/MinioUploader.vue"; +import EditAboutInfo from "./components/EditAboutInfo.vue"; // import Images from './components/Images.vue'; -import EditTopics from './components/EditTopics.vue'; -import DataAnalysis from './components/DataAnalysis.vue' -import Contributors from './components/Contributors.vue' -import Model from './components/Model.vue'; -import WxAutorize from './components/WxAutorize.vue' -import initCloudrain from './features/cloudrbanin.js' -import initImage from './features/images.js' +import EditTopics from "./components/EditTopics.vue"; +import DataAnalysis from "./components/DataAnalysis.vue"; +import Contributors from "./components/Contributors.vue"; +import Model from "./components/Model.vue"; +import WxAutorize from "./components/WxAutorize.vue"; +import initCloudrain from "./features/cloudrbanin.js"; +import initImage from "./features/images.js"; +import selectDataset from "./components/dataset/selectDataset.vue"; // import $ from 'jquery.js' -import router from './router/index.js' +import router from "./router/index.js"; +import { Message } from "element-ui"; Vue.use(ElementUI); Vue.prototype.$axios = axios; Vue.prototype.$Cookies = Cookies; Vue.prototype.qs = qs; +Vue.prototype.$message = Message; const { AppSubUrl, StaticUrlPrefix, csrf } = window.config; -Object.defineProperty(Vue.prototype, '$echarts', { - value: echarts -}) +Object.defineProperty(Vue.prototype, "$echarts", { + value: echarts, +}); function htmlEncode(text) { - return jQuery('
') - .text(text) - .html(); + return jQuery("
").text(text).html(); } let previewFileModes; @@ -70,28 +71,28 @@ const commentMDEditors = {}; $.fn.tab.settings.silent = true; function initCommentPreviewTab($form) { - const $tabMenu = $form.find('.tabular.menu'); - $tabMenu.find('.item').tab(); + const $tabMenu = $form.find(".tabular.menu"); + $tabMenu.find(".item").tab(); $tabMenu - .find(`.item[data-tab="${$tabMenu.data('preview')}"]`) - .on('click', function () { + .find(`.item[data-tab="${$tabMenu.data("preview")}"]`) + .on("click", function () { const $this = $(this); $.post( - $this.data('url'), + $this.data("url"), { _csrf: csrf, - mode: 'gfm', - context: $this.data('context'), + mode: "gfm", + context: $this.data("context"), text: $form - .find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`) - .val() + .find(`.tab[data-tab="${$tabMenu.data("write")}"] textarea`) + .val(), }, (data) => { const $previewPanel = $form.find( - `.tab[data-tab="${$tabMenu.data('preview')}"]` + `.tab[data-tab="${$tabMenu.data("preview")}"]` ); $previewPanel.html(data); - $('pre code', $previewPanel[0]).each(function () { + $("pre code", $previewPanel[0]).each(function () { highlight(this); }); } @@ -102,37 +103,37 @@ function initCommentPreviewTab($form) { } function initEditPreviewTab($form) { - const $tabMenu = $form.find('.tabular.menu'); - $tabMenu.find('.item').tab(); + const $tabMenu = $form.find(".tabular.menu"); + $tabMenu.find(".item").tab(); const $previewTab = $tabMenu.find( - `.item[data-tab="${$tabMenu.data('preview')}"]` + `.item[data-tab="${$tabMenu.data("preview")}"]` ); if ($previewTab.length) { - previewFileModes = $previewTab.data('preview-file-modes').split(','); - $previewTab.on('click', function () { + previewFileModes = $previewTab.data("preview-file-modes").split(","); + $previewTab.on("click", function () { const $this = $(this); - let context = `${$this.data('context')}/`; - const treePathEl = $form.find('input#tree_path'); + let context = `${$this.data("context")}/`; + const treePathEl = $form.find("input#tree_path"); if (treePathEl.length > 0) { context += treePathEl.val(); } - context = context.substring(0, context.lastIndexOf('/')); + context = context.substring(0, context.lastIndexOf("/")); $.post( - $this.data('url'), + $this.data("url"), { _csrf: csrf, - mode: 'gfm', + mode: "gfm", context, text: $form - .find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`) - .val() + .find(`.tab[data-tab="${$tabMenu.data("write")}"] textarea`) + .val(), }, (data) => { const $previewPanel = $form.find( - `.tab[data-tab="${$tabMenu.data('preview')}"]` + `.tab[data-tab="${$tabMenu.data("preview")}"]` ); $previewPanel.html(data); - $('pre code', $previewPanel[0]).each(function () { + $("pre code", $previewPanel[0]).each(function () { highlight(this); }); } @@ -142,24 +143,24 @@ function initEditPreviewTab($form) { } function initEditDiffTab($form) { - const $tabMenu = $form.find('.tabular.menu'); - $tabMenu.find('.item').tab(); + const $tabMenu = $form.find(".tabular.menu"); + $tabMenu.find(".item").tab(); $tabMenu - .find(`.item[data-tab="${$tabMenu.data('diff')}"]`) - .on('click', function () { + .find(`.item[data-tab="${$tabMenu.data("diff")}"]`) + .on("click", function () { const $this = $(this); $.post( - $this.data('url'), + $this.data("url"), { _csrf: csrf, - context: $this.data('context'), + context: $this.data("context"), content: $form - .find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`) - .val() + .find(`.tab[data-tab="${$tabMenu.data("write")}"] textarea`) + .val(), }, (data) => { const $diffPreviewPanel = $form.find( - `.tab[data-tab="${$tabMenu.data('diff')}"]` + `.tab[data-tab="${$tabMenu.data("diff")}"]` ); $diffPreviewPanel.html(data); } @@ -168,66 +169,64 @@ function initEditDiffTab($form) { } function initEditForm() { - if ($('.edit.form').length === 0) { + if ($(".edit.form").length === 0) { return; } - initEditPreviewTab($('.edit.form')); - initEditDiffTab($('.edit.form')); + initEditPreviewTab($(".edit.form")); + initEditDiffTab($(".edit.form")); } function initBranchSelector() { - const $selectBranch = $('.ui.select-branch'); - const $branchMenu = $selectBranch.find('.reference-list-menu'); - $branchMenu.find('.item:not(.no-select)').click(function () { - $($(this).data('id-selector')).val($(this).data('id')); - $selectBranch.find('.ui .branch-name').text($(this).data('name')); + const $selectBranch = $(".ui.select-branch"); + const $branchMenu = $selectBranch.find(".reference-list-menu"); + $branchMenu.find(".item:not(.no-select)").click(function () { + $($(this).data("id-selector")).val($(this).data("id")); + $selectBranch.find(".ui .branch-name").text($(this).data("name")); }); - $selectBranch.find('.reference.column').on('click', function () { - $selectBranch.find('.scrolling.reference-list-menu').css('display', 'none'); - $selectBranch.find('.reference .text').addClass('black'); - $($(this).data('target')).css('display', 'block'); - $(this) - .find('.text.black') - .removeClass('black'); + $selectBranch.find(".reference.column").on("click", function () { + $selectBranch.find(".scrolling.reference-list-menu").css("display", "none"); + $selectBranch.find(".reference .text").addClass("black"); + $($(this).data("target")).css("display", "block"); + $(this).find(".text.black").removeClass("black"); return false; }); } function initLabelEdit() { // Create label - const $newLabelPanel = $('.new-label.segment'); - $('.new-label.button').on('click', () => { + const $newLabelPanel = $(".new-label.segment"); + $(".new-label.button").on("click", () => { $newLabelPanel.show(); }); - $('.new-label.segment .cancel').on('click', () => { + $(".new-label.segment .cancel").on("click", () => { $newLabelPanel.hide(); }); - $('.color-picker').each(function () { + $(".color-picker").each(function () { $(this).minicolors(); }); - $('.precolors .color').on('click', function () { - const color_hex = $(this).data('color-hex'); - $('.color-picker').val(color_hex); - $('.minicolors-swatch-color').css('background-color', color_hex); + $(".precolors .color").on("click", function () { + const color_hex = $(this).data("color-hex"); + $(".color-picker").val(color_hex); + $(".minicolors-swatch-color").css("background-color", color_hex); }); - $('.edit-label-button').on('click', function () { - $('#label-modal-id').val($(this).data('id')); - $('.edit-label .new-label-input').val($(this).data('title')); - $('.edit-label .new-label-desc-input').val($(this).data('description')); - $('.edit-label .color-picker').val($(this).data('color')); - $('.minicolors-swatch-color').css( - 'background-color', - $(this).data('color') + $(".edit-label-button").on("click", function () { + $("#label-modal-id").val($(this).data("id")); + $(".edit-label .new-label-input").val($(this).data("title")); + $(".edit-label .new-label-desc-input").val($(this).data("description")); + $(".edit-label .color-picker").val($(this).data("color")); + $(".minicolors-swatch-color").css( + "background-color", + $(this).data("color") ); - $('.edit-label.modal') + $(".edit-label.modal") .modal({ onApprove() { - $('.edit-label.form').trigger('submit'); - } + $(".edit-label.form").trigger("submit"); + }, }) - .modal('show'); + .modal("show"); return false; }); } @@ -235,7 +234,7 @@ function initLabelEdit() { function updateIssuesMeta(url, action, issueIds, elementId, isAdd) { return new Promise((resolve) => { $.ajax({ - type: 'POST', + type: "POST", url, data: { _csrf: csrf, @@ -244,25 +243,24 @@ function updateIssuesMeta(url, action, issueIds, elementId, isAdd) { id: elementId, is_add: isAdd, }, - success: resolve + success: resolve, }); }); } - function initRepoStatusChecker() { - const migrating = $('#repo_migrating'); - $('#repo_migrating_failed').hide(); + const migrating = $("#repo_migrating"); + $("#repo_migrating_failed").hide(); if (migrating) { - const repo_name = migrating.attr('repo'); - if (typeof repo_name === 'undefined') { + const repo_name = migrating.attr("repo"); + if (typeof repo_name === "undefined") { return; } $.ajax({ - type: 'GET', + type: "GET", url: `${AppSubUrl}/${repo_name}/status`, data: { - _csrf: csrf + _csrf: csrf, }, complete(xhr) { if (xhr.status === 200) { @@ -278,65 +276,63 @@ function initRepoStatusChecker() { return; } } - $('#repo_migrating_progress').hide(); - $('#repo_migrating_failed').show(); - } + $("#repo_migrating_progress").hide(); + $("#repo_migrating_failed").show(); + }, }); } } function initReactionSelector(parent) { - let reactions = ''; + let reactions = ""; if (!parent) { parent = $(document); - reactions = '.reactions > '; + reactions = ".reactions > "; } parent.find(`${reactions}a.label`).popup({ - position: 'bottom left', - metadata: { content: 'title', title: 'none' } + position: "bottom left", + metadata: { content: "title", title: "none" }, }); parent .find(`.select-reaction > .menu > .item, ${reactions}a.label`) - .on('click', function (e) { + .on("click", function (e) { const vm = this; e.preventDefault(); - if ($(this).hasClass('disabled')) return; + if ($(this).hasClass("disabled")) return; - const actionURL = $(this).hasClass('item') ? - $(this) - .closest('.select-reaction') - .data('action-url') : - $(this).data('action-url'); + const actionURL = $(this).hasClass("item") + ? $(this).closest(".select-reaction").data("action-url") + : $(this).data("action-url"); const url = `${actionURL}/${ - $(this).hasClass('blue') ? 'unreact' : 'react' - }`; + $(this).hasClass("blue") ? "unreact" : "react" + }`; $.ajax({ - type: 'POST', + type: "POST", url, data: { _csrf: csrf, - content: $(this).data('content') - } + content: $(this).data("content"), + }, }).done((resp) => { if (resp && (resp.html || resp.empty)) { - const content = $(vm).closest('.content'); - let react = content.find('.segment.reactions'); + const content = $(vm).closest(".content"); + let react = content.find(".segment.reactions"); if (!resp.empty && react.length > 0) { react.remove(); } if (!resp.empty) { react = $('
'); - const attachments = content.find('.segment.bottom:first'); + const attachments = content.find(".segment.bottom:first"); if (attachments.length > 0) { react.insertBefore(attachments); } else { react.appendTo(content); } react.html(resp.html); - react.find('.dropdown').dropdown(); + react.find(".dropdown").dropdown(); initReactionSelector(react); } } @@ -377,15 +373,15 @@ function retrieveImageFromClipboardAsBlob(pasteEvent, callback) { } const { items } = pasteEvent.clipboardData; - if (typeof items === 'undefined') { + if (typeof items === "undefined") { return; } for (let i = 0; i < items.length; i++) { - if (!items[i].type.includes('image')) continue; + if (!items[i].type.includes("image")) continue; const blob = items[i].getAsFile(); - if (typeof callback === 'function') { + if (typeof callback === "function") { pasteEvent.preventDefault(); pasteEvent.stopPropagation(); callback(blob); @@ -396,16 +392,16 @@ function retrieveImageFromClipboardAsBlob(pasteEvent, callback) { function uploadFile(file, callback) { const xhr = new XMLHttpRequest(); - xhr.addEventListener('load', () => { + xhr.addEventListener("load", () => { if (xhr.status === 200) { callback(xhr.responseText); } }); - xhr.open('post', `${AppSubUrl}/attachments`, true); - xhr.setRequestHeader('X-Csrf-Token', csrf); + xhr.open("post", `${AppSubUrl}/attachments`, true); + xhr.setRequestHeader("X-Csrf-Token", csrf); const formData = new FormData(); - formData.append('file', file, file.name); + formData.append("file", file, file.name); xhr.send(formData); } @@ -417,10 +413,10 @@ function initImagePaste(target) { target.each(function () { const field = this; field.addEventListener( - 'paste', + "paste", (event) => { retrieveImageFromClipboardAsBlob(event, (img) => { - const name = img.name.substr(0, img.name.lastIndexOf('.')); + const name = img.name.substr(0, img.name.lastIndexOf(".")); insertAtCursor(field, `![${name}]()`); uploadFile(img, (res) => { const data = JSON.parse(res); @@ -432,7 +428,7 @@ function initImagePaste(target) { const input = $( `` ).val(data.uuid); - $('.files').append(input); + $(".files").append(input); }); }); }, @@ -442,9 +438,9 @@ function initImagePaste(target) { } function initSimpleMDEImagePaste(simplemde, files) { - simplemde.codemirror.on('paste', (_, event) => { + simplemde.codemirror.on("paste", (_, event) => { retrieveImageFromClipboardAsBlob(event, (img) => { - const name = img.name.substr(0, img.name.lastIndexOf('.')); + const name = img.name.substr(0, img.name.lastIndexOf(".")); uploadFile(img, (res) => { const data = JSON.parse(res); const pos = simplemde.codemirror.getCursor(); @@ -464,38 +460,38 @@ function initSimpleMDEImagePaste(simplemde, files) { let autoSimpleMDE; function initCommentForm() { - if ($('.comment.form').length === 0) { + if ($(".comment.form").length === 0) { return; } autoSimpleMDE = setCommentSimpleMDE( - $('.comment.form textarea:not(.review-textarea)') + $(".comment.form textarea:not(.review-textarea)") ); initBranchSelector(); - initCommentPreviewTab($('.comment.form')); - initImagePaste($('.comment.form textarea')); + initCommentPreviewTab($(".comment.form")); + initImagePaste($(".comment.form textarea")); // Listsubmit function initListSubmits(selector, outerSelector) { const $list = $(`.ui.${outerSelector}.list`); - const $noSelect = $list.find('.no-select'); + const $noSelect = $list.find(".no-select"); const $listMenu = $(`.${selector} .menu`); - let hasLabelUpdateAction = $listMenu.data('action') === 'update'; + let hasLabelUpdateAction = $listMenu.data("action") === "update"; const labels = {}; - $(`.${selector}`).dropdown('setting', 'onHide', () => { - hasLabelUpdateAction = $listMenu.data('action') === 'update'; // Update the var + $(`.${selector}`).dropdown("setting", "onHide", () => { + hasLabelUpdateAction = $listMenu.data("action") === "update"; // Update the var if (hasLabelUpdateAction) { const promises = []; Object.keys(labels).forEach((elementId) => { const label = labels[elementId]; - console.log("label:", label) + console.log("label:", label); const promise = updateIssuesMeta( - label['update-url'], + label["update-url"], label.action, - label['issue-id'], + label["issue-id"], elementId, - label['is-checked'], + label["is-checked"] ); promises.push(promise); }); @@ -503,74 +499,66 @@ function initCommentForm() { } }); - $listMenu.find('.item:not(.no-select)').on('click', function () { + $listMenu.find(".item:not(.no-select)").on("click", function () { // we don't need the action attribute when updating assignees if ( - selector === 'select-assignees-modify' || - selector === 'select-reviewers-modify' + selector === "select-assignees-modify" || + selector === "select-reviewers-modify" ) { // UI magic. We need to do this here, otherwise it would destroy the functionality of // adding/removing labels - if ($(this).data('can-change') === 'block') { + if ($(this).data("can-change") === "block") { return false; } - if ($(this).hasClass('checked')) { - $(this).removeClass('checked'); - $(this) - .find('.octicon-check') - .addClass('invisible'); - $(this).data('is-checked', 'remove'); + if ($(this).hasClass("checked")) { + $(this).removeClass("checked"); + $(this).find(".octicon-check").addClass("invisible"); + $(this).data("is-checked", "remove"); } else { - $(this).addClass('checked'); - $(this) - .find('.octicon-check') - .removeClass('invisible'); - $(this).data('is-checked', 'add'); + $(this).addClass("checked"); + $(this).find(".octicon-check").removeClass("invisible"); + $(this).data("is-checked", "add"); } updateIssuesMeta( - $listMenu.data('update-url'), - '', - $listMenu.data('issue-id'), - $(this).data('id'), - $(this).data('is-checked'), + $listMenu.data("update-url"), + "", + $listMenu.data("issue-id"), + $(this).data("id"), + $(this).data("is-checked") ); - $listMenu.data('action', 'update'); // Update to reload the page when we updated items + $listMenu.data("action", "update"); // Update to reload the page when we updated items return false; } - if ($(this).hasClass('checked')) { - $(this).removeClass('checked'); - $(this) - .find('.octicon-check') - .addClass('invisible'); + if ($(this).hasClass("checked")) { + $(this).removeClass("checked"); + $(this).find(".octicon-check").addClass("invisible"); if (hasLabelUpdateAction) { - if (!($(this).data('id') in labels)) { - labels[$(this).data('id')] = { - 'update-url': $listMenu.data('update-url'), - action: 'detach', - 'issue-id': $listMenu.data('issue-id') + if (!($(this).data("id") in labels)) { + labels[$(this).data("id")] = { + "update-url": $listMenu.data("update-url"), + action: "detach", + "issue-id": $listMenu.data("issue-id"), }; } else { - delete labels[$(this).data('id')]; + delete labels[$(this).data("id")]; } } } else { - $(this).addClass('checked'); - $(this) - .find('.octicon-check') - .removeClass('invisible'); + $(this).addClass("checked"); + $(this).find(".octicon-check").removeClass("invisible"); if (hasLabelUpdateAction) { - if (!($(this).data('id') in labels)) { - labels[$(this).data('id')] = { - 'update-url': $listMenu.data('update-url'), - action: 'attach', - 'issue-id': $listMenu.data('issue-id') + if (!($(this).data("id") in labels)) { + labels[$(this).data("id")] = { + "update-url": $listMenu.data("update-url"), + action: "attach", + "issue-id": $listMenu.data("issue-id"), }; } else { - delete labels[$(this).data('id')]; + delete labels[$(this).data("id")]; } } } @@ -578,88 +566,77 @@ function initCommentForm() { const listIds = []; $(this) .parent() - .find('.item') + .find(".item") .each(function () { - if ($(this).hasClass('checked')) { - listIds.push($(this).data('id')); - $($(this).data('id-selector')).removeClass('hide'); + if ($(this).hasClass("checked")) { + listIds.push($(this).data("id")); + $($(this).data("id-selector")).removeClass("hide"); } else { - $($(this).data('id-selector')).addClass('hide'); + $($(this).data("id-selector")).addClass("hide"); } }); if (listIds.length === 0) { - $noSelect.removeClass('hide'); + $noSelect.removeClass("hide"); } else { - $noSelect.addClass('hide'); + $noSelect.addClass("hide"); } - $( - $(this) - .parent() - .data('id') - ).val(listIds.join(',')); + $($(this).parent().data("id")).val(listIds.join(",")); return false; }); - $listMenu.find('.no-select.item').on('click', function () { - if (hasLabelUpdateAction || selector === 'select-assignees-modify') { + $listMenu.find(".no-select.item").on("click", function () { + if (hasLabelUpdateAction || selector === "select-assignees-modify") { updateIssuesMeta( - $listMenu.data('update-url'), - 'clear', - $listMenu.data('issue-id'), - '', - '' - + $listMenu.data("update-url"), + "clear", + $listMenu.data("issue-id"), + "", + "" ).then(reload); } $(this) .parent() - .find('.item') + .find(".item") .each(function () { - $(this).removeClass('checked'); - $(this) - .find('.octicon') - .addClass('invisible'); - $(this).data('is-checked', 'remove'); + $(this).removeClass("checked"); + $(this).find(".octicon").addClass("invisible"); + $(this).data("is-checked", "remove"); }); - $list.find('.item').each(function () { - $(this).addClass('hide'); + $list.find(".item").each(function () { + $(this).addClass("hide"); }); - $noSelect.removeClass('hide'); - $( - $(this) - .parent() - .data('id') - ).val(''); + $noSelect.removeClass("hide"); + $($(this).parent().data("id")).val(""); }); } // Init labels and assignees - initListSubmits('select-label', 'labels'); - initListSubmits('select-assignees', 'assignees'); - initListSubmits('select-assignees-modify', 'assignees'); - initListSubmits('select-reviewers-modify', 'assignees'); + initListSubmits("select-label", "labels"); + initListSubmits("select-assignees", "assignees"); + initListSubmits("select-assignees-modify", "assignees"); + initListSubmits("select-reviewers-modify", "assignees"); function selectItem(select_id, input_id) { let $menu; - if (select_id == '.select-branch') { + if (select_id == ".select-branch") { $menu = $(`${select_id} .menu`).eq(1); } else { $menu = $(`${select_id} .menu`); } const $list = $(`.ui${select_id}.list`); - const hasUpdateAction = $menu.data('action') === 'update'; + const hasUpdateAction = $menu.data("action") === "update"; - $menu.find('.item:not(.no-select)').on('click', function () { + $menu.find(".item:not(.no-select)").on("click", function () { $(this) .parent() - .find('.item') + .find(".item") .each(function () { - $(this).removeClass('selected active'); + $(this).removeClass("selected active"); }); - $(this).addClass('selected active'); + $(this).addClass("selected active"); if (hasUpdateAction) { //let ref = '' //if (select_id=='.select-branch'){ @@ -667,176 +644,176 @@ function initCommentForm() { // } updateIssuesMeta( - $menu.data('update-url'), - '', - $menu.data('issue-id'), - $(this).data('id'), - $(this).data('is-checked'), + $menu.data("update-url"), + "", + $menu.data("issue-id"), + $(this).data("id"), + $(this).data("is-checked") ).then(reload); } switch (input_id) { - case '#milestone_id': + case "#milestone_id": $list - .find('.selected') + .find(".selected") .html( - `${htmlEncode( + `${htmlEncode( $(this).text() )}` ); break; - case '#assignee_id': + case "#assignee_id": $list - .find('.selected') + .find(".selected") .html( - `` + - `${htmlEncode($(this).text())}` + `` + + `${htmlEncode($(this).text())}` ); } - $(`.ui${select_id}.list .no-select`).addClass('hide'); - $(input_id).val($(this).data('id')); + $(`.ui${select_id}.list .no-select`).addClass("hide"); + $(input_id).val($(this).data("id")); }); - $menu.find('.no-select.item').on('click', function () { + $menu.find(".no-select.item").on("click", function () { $(this) .parent() - .find('.item:not(.no-select)') + .find(".item:not(.no-select)") .each(function () { - $(this).removeClass('selected active'); + $(this).removeClass("selected active"); }); if (hasUpdateAction) { updateIssuesMeta( - $menu.data('update-url'), - '', - $menu.data('issue-id'), - $(this).data('id'), - $(this).data('is-checked') + $menu.data("update-url"), + "", + $menu.data("issue-id"), + $(this).data("id"), + $(this).data("is-checked") ).then(reload); } - $list.find('.selected').html(''); - $list.find('.no-select').removeClass('hide'); - $(input_id).val(''); + $list.find(".selected").html(""); + $list.find(".no-select").removeClass("hide"); + $(input_id).val(""); }); } // Milestone and assignee - selectItem('.select-milestone', '#milestone_id'); - selectItem('.select-assignee', '#assignee_id'); - selectItem('.select-branch', ''); + selectItem(".select-milestone", "#milestone_id"); + selectItem(".select-assignee", "#assignee_id"); + selectItem(".select-branch", ""); } function initInstall() { - if ($('.install').length === 0) { + if ($(".install").length === 0) { return; } - if ($('#db_host').val() === '') { - $('#db_host').val('127.0.0.1:3306'); - $('#db_user').val('gitea'); - $('#db_name').val('gitea'); + if ($("#db_host").val() === "") { + $("#db_host").val("127.0.0.1:3306"); + $("#db_user").val("gitea"); + $("#db_name").val("gitea"); } // Database type change detection. - $('#db_type').on('change', function () { - const sqliteDefault = 'data/gitea.db'; - const tidbDefault = 'data/gitea_tidb'; + $("#db_type").on("change", function () { + const sqliteDefault = "data/gitea.db"; + const tidbDefault = "data/gitea_tidb"; const dbType = $(this).val(); - if (dbType === 'SQLite3') { - $('#sql_settings').hide(); - $('#pgsql_settings').hide(); - $('#mysql_settings').hide(); - $('#sqlite_settings').show(); - - if (dbType === 'SQLite3' && $('#db_path').val() === tidbDefault) { - $('#db_path').val(sqliteDefault); + if (dbType === "SQLite3") { + $("#sql_settings").hide(); + $("#pgsql_settings").hide(); + $("#mysql_settings").hide(); + $("#sqlite_settings").show(); + + if (dbType === "SQLite3" && $("#db_path").val() === tidbDefault) { + $("#db_path").val(sqliteDefault); } return; } const dbDefaults = { - MySQL: '127.0.0.1:3306', - PostgreSQL: '127.0.0.1:5432', - MSSQL: '127.0.0.1:1433' + MySQL: "127.0.0.1:3306", + PostgreSQL: "127.0.0.1:5432", + MSSQL: "127.0.0.1:1433", }; - $('#sqlite_settings').hide(); - $('#sql_settings').show(); + $("#sqlite_settings").hide(); + $("#sql_settings").show(); - $('#pgsql_settings').toggle(dbType === 'PostgreSQL'); - $('#mysql_settings').toggle(dbType === 'MySQL'); + $("#pgsql_settings").toggle(dbType === "PostgreSQL"); + $("#mysql_settings").toggle(dbType === "MySQL"); $.each(dbDefaults, (_type, defaultHost) => { - if ($('#db_host').val() === defaultHost) { - $('#db_host').val(dbDefaults[dbType]); + if ($("#db_host").val() === defaultHost) { + $("#db_host").val(dbDefaults[dbType]); return false; } }); }); // TODO: better handling of exclusive relations. - $('#offline-mode input').on('change', function () { - if ($(this).is(':checked')) { - $('#disable-gravatar').checkbox('check'); - $('#federated-avatar-lookup').checkbox('uncheck'); + $("#offline-mode input").on("change", function () { + if ($(this).is(":checked")) { + $("#disable-gravatar").checkbox("check"); + $("#federated-avatar-lookup").checkbox("uncheck"); } }); - $('#disable-gravatar input').on('change', function () { - if ($(this).is(':checked')) { - $('#federated-avatar-lookup').checkbox('uncheck'); + $("#disable-gravatar input").on("change", function () { + if ($(this).is(":checked")) { + $("#federated-avatar-lookup").checkbox("uncheck"); } else { - $('#offline-mode').checkbox('uncheck'); + $("#offline-mode").checkbox("uncheck"); } }); - $('#federated-avatar-lookup input').on('change', function () { - if ($(this).is(':checked')) { - $('#disable-gravatar').checkbox('uncheck'); - $('#offline-mode').checkbox('uncheck'); + $("#federated-avatar-lookup input").on("change", function () { + if ($(this).is(":checked")) { + $("#disable-gravatar").checkbox("uncheck"); + $("#offline-mode").checkbox("uncheck"); } }); - $('#enable-openid-signin input').on('change', function () { - if ($(this).is(':checked')) { - if (!$('#disable-registration input').is(':checked')) { - $('#enable-openid-signup').checkbox('check'); + $("#enable-openid-signin input").on("change", function () { + if ($(this).is(":checked")) { + if (!$("#disable-registration input").is(":checked")) { + $("#enable-openid-signup").checkbox("check"); } } else { - $('#enable-openid-signup').checkbox('uncheck'); + $("#enable-openid-signup").checkbox("uncheck"); } }); - $('#disable-registration input').on('change', function () { - if ($(this).is(':checked')) { - $('#enable-captcha').checkbox('uncheck'); - $('#enable-openid-signup').checkbox('uncheck'); + $("#disable-registration input").on("change", function () { + if ($(this).is(":checked")) { + $("#enable-captcha").checkbox("uncheck"); + $("#enable-openid-signup").checkbox("uncheck"); } else { - $('#enable-openid-signup').checkbox('check'); + $("#enable-openid-signup").checkbox("check"); } }); - $('#enable-captcha input').on('change', function () { - if ($(this).is(':checked')) { - $('#disable-registration').checkbox('uncheck'); + $("#enable-captcha input").on("change", function () { + if ($(this).is(":checked")) { + $("#disable-registration").checkbox("uncheck"); } }); } function initIssueComments() { - if ($('.repository.view.issue .timeline').length === 0) return; + if ($(".repository.view.issue .timeline").length === 0) return; - $('.re-request-review').on('click', function (event) { - const url = $(this).data('update-url'); - const issueId = $(this).data('issue-id'); - const id = $(this).data('id'); - const isChecked = $(this).data('is-checked'); + $(".re-request-review").on("click", function (event) { + const url = $(this).data("update-url"); + const issueId = $(this).data("issue-id"); + const id = $(this).data("id"); + const isChecked = $(this).data("is-checked"); //const ref = $(this).data('name'); event.preventDefault(); - updateIssuesMeta(url, '', issueId, id, isChecked).then(reload); + updateIssuesMeta(url, "", issueId, id, isChecked).then(reload); }); - $(document).on('click', (event) => { - const urlTarget = $(':target'); + $(document).on("click", (event) => { + const urlTarget = $(":target"); if (urlTarget.length === 0) return; - const urlTargetId = urlTarget.attr('id'); + const urlTargetId = urlTarget.attr("id"); if (!urlTargetId) return; if (!/^(issue|pull)(comment)?-\d+$/.test(urlTargetId)) return; @@ -844,15 +821,15 @@ function initIssueComments() { if ($target.closest(`#${urlTargetId}`).length === 0) { const scrollPosition = $(window).scrollTop(); - window.location.hash = ''; + window.location.hash = ""; $(window).scrollTop(scrollPosition); - window.history.pushState(null, null, ' '); + window.history.pushState(null, null, " "); } }); } async function initRepository() { - if ($('.repository').length === 0) { + if ($(".repository").length === 0) { return; } @@ -862,105 +839,105 @@ async function initRepository() { fullTextSearch: true, selectOnKeydown: false, onChange(_text, _value, $choice) { - if ($choice.data('url')) { - window.location.href = $choice.data('url'); + if ($choice.data("url")) { + window.location.href = $choice.data("url"); } }, - message: { noResults: $dropdown.data('no-results') } + message: { noResults: $dropdown.data("no-results") }, }); } // File list and commits if ( - $('.repository.file.list').length > 0 || - '.repository.commits'.length > 0 + $(".repository.file.list").length > 0 || + ".repository.commits".length > 0 ) { - initFilterBranchTagDropdown('.choose.reference .dropdown'); + initFilterBranchTagDropdown(".choose.reference .dropdown"); } // Wiki - if ($('.repository.wiki.view').length > 0) { - initFilterSearchDropdown('.choose.page .dropdown'); + if ($(".repository.wiki.view").length > 0) { + initFilterSearchDropdown(".choose.page .dropdown"); } // Options - if ($('.repository.settings.options').length > 0) { + if ($(".repository.settings.options").length > 0) { // Enable or select internal/external wiki system and issue tracker. - $('.enable-system').on('change', function () { + $(".enable-system").on("change", function () { if (this.checked) { - $($(this).data('target')).removeClass('disabled'); - if (!$(this).data('context')) { - $($(this).data('context')).addClass('disabled'); + $($(this).data("target")).removeClass("disabled"); + if (!$(this).data("context")) { + $($(this).data("context")).addClass("disabled"); } } else { - $($(this).data('target')).addClass('disabled'); - if (!$(this).data('context')) { - $($(this).data('context')).removeClass('disabled'); + $($(this).data("target")).addClass("disabled"); + if (!$(this).data("context")) { + $($(this).data("context")).removeClass("disabled"); } } }); - $('.enable-system-radio').on('change', function () { - if (this.value === 'false') { - $($(this).data('target')).addClass('disabled'); - if (typeof $(this).data('context') !== 'undefined') { - $($(this).data('context')).removeClass('disabled'); + $(".enable-system-radio").on("change", function () { + if (this.value === "false") { + $($(this).data("target")).addClass("disabled"); + if (typeof $(this).data("context") !== "undefined") { + $($(this).data("context")).removeClass("disabled"); } - } else if (this.value === 'true') { - $($(this).data('target')).removeClass('disabled'); - if (typeof $(this).data('context') !== 'undefined') { - $($(this).data('context')).addClass('disabled'); + } else if (this.value === "true") { + $($(this).data("target")).removeClass("disabled"); + if (typeof $(this).data("context") !== "undefined") { + $($(this).data("context")).addClass("disabled"); } } }); } // Labels - if ($('.repository.labels').length > 0) { + if ($(".repository.labels").length > 0) { initLabelEdit(); } // Milestones - if ($('.repository.new.milestone').length > 0) { - const $datepicker = $('.milestone.datepicker'); + if ($(".repository.new.milestone").length > 0) { + const $datepicker = $(".milestone.datepicker"); - await initDateTimePicker($datepicker.data('lang')); + await initDateTimePicker($datepicker.data("lang")); $datepicker.datetimepicker({ inline: true, timepicker: false, - startDate: $datepicker.data('start-date'), + startDate: $datepicker.data("start-date"), onSelectDate(date) { - $('#deadline').val(date.toISOString().substring(0, 10)); - } + $("#deadline").val(date.toISOString().substring(0, 10)); + }, }); - $('#clear-date').on('click', () => { - $('#deadline').val(''); + $("#clear-date").on("click", () => { + $("#deadline").val(""); return false; }); } // Issues - if ($('.repository.view.issue').length > 0) { + if ($(".repository.view.issue").length > 0) { // Edit issue title - const $issueTitle = $('#issue-title'); - const $editInput = $('#edit-title-input input'); + const $issueTitle = $("#issue-title"); + const $editInput = $("#edit-title-input input"); const editTitleToggle = function () { $issueTitle.toggle(); - $('.not-in-edit').toggle(); - $('#edit-title-input').toggle(); - $('#pull-desc').toggle(); - $('#pull-desc-edit').toggle(); - $('.in-edit').toggle(); + $(".not-in-edit").toggle(); + $("#edit-title-input").toggle(); + $("#pull-desc").toggle(); + $("#pull-desc-edit").toggle(); + $(".in-edit").toggle(); $editInput.focus(); return false; }; const changeBranchSelect = function () { - const selectionTextField = $('#pull-target-branch'); + const selectionTextField = $("#pull-target-branch"); - const baseName = selectionTextField.data('basename'); - const branchNameNew = $(this).data('branch'); - const branchNameOld = selectionTextField.data('branch'); + const baseName = selectionTextField.data("basename"); + const branchNameNew = $(this).data("branch"); + const branchNameOld = selectionTextField.data("branch"); // Replace branch name to keep translation from HTML template selectionTextField.html( @@ -971,24 +948,24 @@ async function initRepository() { `${baseName}:${branchNameNew}` ) ); - selectionTextField.data('branch', branchNameNew); // update branch name in setting + selectionTextField.data("branch", branchNameNew); // update branch name in setting }; - $('#branch-select > .item').on('click', changeBranchSelect); + $("#branch-select > .item").on("click", changeBranchSelect); - $('#edit-title').on('click', editTitleToggle); - $('#cancel-edit-title').on('click', editTitleToggle); - $('#save-edit-title') - .on('click', editTitleToggle) - .on('click', function () { + $("#edit-title").on("click", editTitleToggle); + $("#cancel-edit-title").on("click", editTitleToggle); + $("#save-edit-title") + .on("click", editTitleToggle) + .on("click", function () { const pullrequest_targetbranch_change = function (update_url) { - const targetBranch = $('#pull-target-branch').data('branch'); - const $branchTarget = $('#branch_target'); + const targetBranch = $("#pull-target-branch").data("branch"); + const $branchTarget = $("#branch_target"); if (targetBranch === $branchTarget.text()) { return false; } $.post(update_url, { _csrf: csrf, - target_branch: targetBranch + target_branch: targetBranch, }) .done((data) => { $branchTarget.text(data.base_branch); @@ -998,7 +975,7 @@ async function initRepository() { }); }; - const pullrequest_target_update_url = $(this).data('target-update-url'); + const pullrequest_target_update_url = $(this).data("target-update-url"); if ( $editInput.val().length === 0 || $editInput.val() === $issueTitle.text() @@ -1007,10 +984,10 @@ async function initRepository() { pullrequest_targetbranch_change(pullrequest_target_update_url); } else { $.post( - $(this).data('update-url'), + $(this).data("update-url"), { _csrf: csrf, - title: $editInput.val() + title: $editInput.val(), }, (data) => { $editInput.val(data.title); @@ -1027,35 +1004,30 @@ async function initRepository() { initIssueComments(); // Issue/PR Context Menus - $('.context-dropdown').dropdown({ - action: 'hide' + $(".context-dropdown").dropdown({ + action: "hide", }); // Quote reply - $('.quote-reply').on('click', function (event) { - $(this) - .closest('.dropdown') - .find('.menu') - .toggle('visible'); - const target = $(this).data('target'); - const quote = $(`#comment-${target}`) - .text() - .replace(/\n/g, '\n> '); + $(".quote-reply").on("click", function (event) { + $(this).closest(".dropdown").find(".menu").toggle("visible"); + const target = $(this).data("target"); + const quote = $(`#comment-${target}`).text().replace(/\n/g, "\n> "); const content = `> ${quote}\n\n`; let $content; - if ($(this).hasClass('quote-reply-diff')) { - const $parent = $(this).closest('.comment-code-cloud'); - $parent.find('button.comment-form-reply').trigger('click'); + if ($(this).hasClass("quote-reply-diff")) { + const $parent = $(this).closest(".comment-code-cloud"); + $parent.find("button.comment-form-reply").trigger("click"); $content = $parent.find('[name="content"]'); - if ($content.val() !== '') { + if ($content.val() !== "") { $content.val(`${$content.val()}\n\n${content}`); } else { $content.val(`${content}`); } $content.focus(); } else if (autoSimpleMDE !== null) { - if (autoSimpleMDE.value() !== '') { + if (autoSimpleMDE.value() !== "") { autoSimpleMDE.value(`${autoSimpleMDE.value()}\n\n${content}`); } else { autoSimpleMDE.value(`${content}`); @@ -1065,99 +1037,94 @@ async function initRepository() { }); // Edit issue or comment content - $('.edit-content').on('click', async function (event) { - $(this) - .closest('.dropdown') - .find('.menu') - .toggle('visible'); - const $segment = $(this) - .closest('.header') - .next(); - const $editContentZone = $segment.find('.edit-content-zone'); - const $renderContent = $segment.find('.render-content'); - const $rawContent = $segment.find('.raw-content'); + $(".edit-content").on("click", async function (event) { + $(this).closest(".dropdown").find(".menu").toggle("visible"); + const $segment = $(this).closest(".header").next(); + const $editContentZone = $segment.find(".edit-content-zone"); + const $renderContent = $segment.find(".render-content"); + const $rawContent = $segment.find(".raw-content"); let $textarea; let $simplemde; // Setup new form if ($editContentZone.html().length === 0) { - $editContentZone.html($('#edit-content-form').html()); - $textarea = $editContentZone.find('textarea'); + $editContentZone.html($("#edit-content-form").html()); + $textarea = $editContentZone.find("textarea"); issuesTribute.attach($textarea.get()); emojiTribute.attach($textarea.get()); let dz; - const $dropzone = $editContentZone.find('.dropzone'); - const $files = $editContentZone.find('.comment-files'); + const $dropzone = $editContentZone.find(".dropzone"); + const $files = $editContentZone.find(".comment-files"); if ($dropzone.length > 0) { - $dropzone.data('saved', false); + $dropzone.data("saved", false); const filenameDict = {}; dz = await createDropzone($dropzone[0], { - url: $dropzone.data('upload-url'), - headers: { 'X-Csrf-Token': csrf }, - maxFiles: $dropzone.data('max-file'), - maxFilesize: $dropzone.data('max-size'), + url: $dropzone.data("upload-url"), + headers: { "X-Csrf-Token": csrf }, + maxFiles: $dropzone.data("max-file"), + maxFilesize: $dropzone.data("max-size"), acceptedFiles: - $dropzone.data('accepts') === '*/*' ? - null : - $dropzone.data('accepts'), + $dropzone.data("accepts") === "*/*" + ? null + : $dropzone.data("accepts"), addRemoveLinks: true, - dictDefaultMessage: $dropzone.data('default-message'), - dictInvalidFileType: $dropzone.data('invalid-input-type'), - dictFileTooBig: $dropzone.data('file-too-big'), - dictRemoveFile: $dropzone.data('remove-file'), + dictDefaultMessage: $dropzone.data("default-message"), + dictInvalidFileType: $dropzone.data("invalid-input-type"), + dictFileTooBig: $dropzone.data("file-too-big"), + dictRemoveFile: $dropzone.data("remove-file"), init() { - this.on('success', (file, data) => { + this.on("success", (file, data) => { filenameDict[file.name] = { uuid: data.uuid, - submitted: false + submitted: false, }; const input = $( `` ).val(data.uuid); $files.append(input); }); - this.on('removedfile', (file) => { + this.on("removedfile", (file) => { if (!(file.name in filenameDict)) { return; } $(`#${filenameDict[file.name].uuid}`).remove(); if ( - $dropzone.data('remove-url') && - $dropzone.data('csrf') && + $dropzone.data("remove-url") && + $dropzone.data("csrf") && !filenameDict[file.name].submitted ) { - $.post($dropzone.data('remove-url'), { + $.post($dropzone.data("remove-url"), { file: filenameDict[file.name].uuid, - _csrf: $dropzone.data('csrf') + _csrf: $dropzone.data("csrf"), }); } }); - this.on('submit', () => { + this.on("submit", () => { $.each(filenameDict, (name) => { filenameDict[name].submitted = true; }); }); - this.on('reload', () => { - $.getJSON($editContentZone.data('attachment-url'), (data) => { + this.on("reload", () => { + $.getJSON($editContentZone.data("attachment-url"), (data) => { dz.removeAllFiles(true); $files.empty(); $.each(data, function () { - const imgSrc = `${$dropzone.data('upload-url')}/${ + const imgSrc = `${$dropzone.data("upload-url")}/${ this.uuid - }`; - dz.emit('addedfile', this); - dz.emit('thumbnail', this, imgSrc); - dz.emit('complete', this); + }`; + dz.emit("addedfile", this); + dz.emit("thumbnail", this, imgSrc); + dz.emit("complete", this); dz.files.push(this); filenameDict[this.name] = { submitted: true, - uuid: this.uuid + uuid: this.uuid, }; $dropzone .find(`img[src='${imgSrc}']`) - .css('max-width', '100%'); + .css("max-width", "100%"); const input = $( `` ).val(this.uuid); @@ -1165,92 +1132,90 @@ async function initRepository() { }); }); }); - } + }, }); - dz.emit('reload'); + dz.emit("reload"); } // Give new write/preview data-tab name to distinguish from others - const $editContentForm = $editContentZone.find('.ui.comment.form'); - const $tabMenu = $editContentForm.find('.tabular.menu'); - $tabMenu.attr('data-write', $editContentZone.data('write')); - $tabMenu.attr('data-preview', $editContentZone.data('preview')); + const $editContentForm = $editContentZone.find(".ui.comment.form"); + const $tabMenu = $editContentForm.find(".tabular.menu"); + $tabMenu.attr("data-write", $editContentZone.data("write")); + $tabMenu.attr("data-preview", $editContentZone.data("preview")); $tabMenu - .find('.write.item') - .attr('data-tab', $editContentZone.data('write')); + .find(".write.item") + .attr("data-tab", $editContentZone.data("write")); $tabMenu - .find('.preview.item') - .attr('data-tab', $editContentZone.data('preview')); + .find(".preview.item") + .attr("data-tab", $editContentZone.data("preview")); $editContentForm - .find('.write') - .attr('data-tab', $editContentZone.data('write')); + .find(".write") + .attr("data-tab", $editContentZone.data("write")); $editContentForm - .find('.preview') - .attr('data-tab', $editContentZone.data('preview')); + .find(".preview") + .attr("data-tab", $editContentZone.data("preview")); $simplemde = setCommentSimpleMDE($textarea); - commentMDEditors[$editContentZone.data('write')] = $simplemde; + commentMDEditors[$editContentZone.data("write")] = $simplemde; initCommentPreviewTab($editContentForm); initSimpleMDEImagePaste($simplemde, $files); - $editContentZone.find('.cancel.button').on('click', () => { + $editContentZone.find(".cancel.button").on("click", () => { $renderContent.show(); $editContentZone.hide(); - dz.emit('reload'); + dz.emit("reload"); }); - $editContentZone.find('.save.button').on('click', () => { + $editContentZone.find(".save.button").on("click", () => { $renderContent.show(); $editContentZone.hide(); const $attachments = $files - .find('[name=files]') + .find("[name=files]") .map(function () { return $(this).val(); }) .get(); $.post( - $editContentZone.data('update-url'), + $editContentZone.data("update-url"), { _csrf: csrf, content: $textarea.val(), - context: $editContentZone.data('context'), - files: $attachments + context: $editContentZone.data("context"), + files: $attachments, }, (data) => { - if (data.length === 0 || data.content === '') { - $renderContent.html($('#no-content').html()); + if (data.length === 0 || data.content === "") { + $renderContent.html($("#no-content").html()); } else { $renderContent.html(data.content); - $('pre code', $renderContent[0]).each(function () { + $("pre code", $renderContent[0]).each(function () { highlight(this); }); } - let imageShow = '' + let imageShow = ""; const $content = $segment.parent(); - if (!$content.find('.ui.small.images').length) { - if (data.attachments !== '' && data.attachments) { - if ($content.find('.ui.middle.aligned').length === 0) { - imageShow += '
' - imageShow += '
' - imageShow += data.attachments - imageShow += '
' - $content.find('.ui.attached.segment').append(imageShow) + if (!$content.find(".ui.small.images").length) { + if (data.attachments !== "" && data.attachments) { + if ($content.find(".ui.middle.aligned").length === 0) { + imageShow += '
'; + imageShow += '
'; + imageShow += data.attachments; + imageShow += "
"; + $content.find(".ui.attached.segment").append(imageShow); + } else { + $content.find(".ui.middle.aligned").html(data.attachments); } - else { $content.find('.ui.middle.aligned').html(data.attachments) } } - } else if (data.attachments === '') { - $content - .find('.ui.small.images') - .parent() - .remove(); + } else if (data.attachments === "") { + $content.find(".ui.small.images").parent().remove(); } else { - $content.find('.ui.small.images').html(data.attachments); + $content.find(".ui.small.images").html(data.attachments); } - dz.emit('submit'); - dz.emit('reload'); + dz.emit("submit"); + dz.emit("reload"); } ); }); } else { - $textarea = $segment.find('textarea'); - $simplemde = commentMDEditors[$editContentZone.data('write')]; + $textarea = $segment.find("textarea"); + $simplemde = commentMDEditors[$editContentZone.data("write")]; } // Show write/preview tab and copy raw content as needed @@ -1266,390 +1231,367 @@ async function initRepository() { }); // Delete comment - $('.delete-comment').on('click', function () { + $(".delete-comment").on("click", function () { const $this = $(this); - if (window.confirm($this.data('locale'))) { - $.post($this.data('url'), { - _csrf: csrf + if (window.confirm($this.data("locale"))) { + $.post($this.data("url"), { + _csrf: csrf, }).done(() => { - $(`#${$this.data('comment-id')}`).remove(); + $(`#${$this.data("comment-id")}`).remove(); }); } return false; }); // Change status - const $statusButton = $('#status-button'); - $('#comment-form .edit_area').on('keyup', function () { + const $statusButton = $("#status-button"); + $("#comment-form .edit_area").on("keyup", function () { if ($(this).val().length === 0) { - $statusButton.text($statusButton.data('status')); + $statusButton.text($statusButton.data("status")); } else { - $statusButton.text($statusButton.data('status-and-comment')); + $statusButton.text($statusButton.data("status-and-comment")); } }); - $statusButton.on('click', () => { - $('#status').val($statusButton.data('status-val')); - $('#comment-form').trigger('submit'); + $statusButton.on("click", () => { + $("#status").val($statusButton.data("status-val")); + $("#comment-form").trigger("submit"); }); // Pull Request merge button - const $mergeButton = $('.merge-button > button'); - $mergeButton.on('click', function (e) { + const $mergeButton = $(".merge-button > button"); + $mergeButton.on("click", function (e) { e.preventDefault(); - $(`.${$(this).data('do')}-fields`).show(); - $(this) - .parent() - .hide(); + $(`.${$(this).data("do")}-fields`).show(); + $(this).parent().hide(); }); - $('.merge-button > .dropdown').dropdown({ + $(".merge-button > .dropdown").dropdown({ onChange(_text, _value, $choice) { - if ($choice.data('do')) { - $mergeButton.find('.button-text').text($choice.text()); - $mergeButton.data('do', $choice.data('do')); + if ($choice.data("do")) { + $mergeButton.find(".button-text").text($choice.text()); + $mergeButton.data("do", $choice.data("do")); } - } + }, }); - $('.merge-cancel').on('click', function (e) { + $(".merge-cancel").on("click", function (e) { e.preventDefault(); - $(this) - .closest('.form') - .hide(); + $(this).closest(".form").hide(); $mergeButton.parent().show(); }); initReactionSelector(); } // Datasets - if ($('.repository.dataset-list.view').length > 0) { + if ($(".repository.dataset-list.view").length > 0) { const editContentToggle = function () { - $('#dataset-content').toggle(); - $('#dataset-content-edit').toggle(); - $('#dataset-content input').focus(); + $("#dataset-content").toggle(); + $("#dataset-content-edit").toggle(); + $("#dataset-content input").focus(); return false; }; - $('[data-dataset-status]').on('click', function () { + $("[data-dataset-status]").on("click", function () { const $this = $(this); - const $private = $this.data('private'); - const $is_private = $this.data('is-private'); + const $private = $this.data("private"); + const $is_private = $this.data("is-private"); if ($is_private === $private) { return; } - const $uuid = $this.data('uuid'); - $.post($this.data('url'), { - _csrf: $this.data('csrf'), + const $uuid = $this.data("uuid"); + $.post($this.data("url"), { + _csrf: $this.data("csrf"), file: $uuid, - is_private: $private + is_private: $private, }) .done((_data) => { - $(`[data-uuid='${$uuid}']`).removeClass('positive active'); - $(`[data-uuid='${$uuid}']`).data('is-private', $private); - $this.addClass('positive active'); + $(`[data-uuid='${$uuid}']`).removeClass("positive active"); + $(`[data-uuid='${$uuid}']`).data("is-private", $private); + $this.addClass("positive active"); }) .fail(() => { window.location.reload(); }); }); - $('[data-dataset-delete]').on('click', function () { + $("[data-dataset-delete]").on("click", function () { const $this = $(this); - $('#data-dataset-delete-modal') + $("#data-dataset-delete-modal") .modal({ closable: false, onApprove() { - $.post($this.data('remove-url'), { - _csrf: $this.data('csrf'), - file: $this.data('uuid') + $.post($this.data("remove-url"), { + _csrf: $this.data("csrf"), + file: $this.data("uuid"), }) .done((_data) => { - $(`#${$this.data('uuid')}`).hide(); + $(`#${$this.data("uuid")}`).hide(); }) .fail(() => { window.location.reload(); }); - } + }, }) - .modal('show'); + .modal("show"); }); - $('[data-category-id]').on('click', function () { - const category = $(this).data('category-id'); - $('#category').val(category); - $('#submit').click(); + $("[data-category-id]").on("click", function () { + const category = $(this).data("category-id"); + $("#category").val(category); + $("#submit").click(); }); - $('[data-task-id]').on('click', function () { - const task = $(this).data('task-id'); - $('#task').val(task); - $('#submit').click(); + $("[data-task-id]").on("click", function () { + const task = $(this).data("task-id"); + $("#task").val(task); + $("#submit").click(); }); - $('[data-license-id]').on('click', function () { - const license = $(this).data('license-id'); - $('#license').val(license); - $('#submit').click(); + $("[data-license-id]").on("click", function () { + const license = $(this).data("license-id"); + $("#license").val(license); + $("#submit").click(); }); - $('#dataset-edit').on('click', editContentToggle); - $('#cancel').on('click', editContentToggle); + $("#dataset-edit").on("click", editContentToggle); + $("#cancel").on("click", editContentToggle); } // Diff - if ($('.repository.diff').length > 0) { - $('.diff-counter').each(function () { + if ($(".repository.diff").length > 0) { + $(".diff-counter").each(function () { const $item = $(this); - const addLine = $item.find('span[data-line].add').data('line'); - const delLine = $item.find('span[data-line].del').data('line'); + const addLine = $item.find("span[data-line].add").data("line"); + const delLine = $item.find("span[data-line].del").data("line"); const addPercent = (parseFloat(addLine) / (parseFloat(addLine) + parseFloat(delLine))) * 100; - $item.find('.bar .add').css('width', `${addPercent}%`); + $item.find(".bar .add").css("width", `${addPercent}%`); }); } // Quick start and repository home - $('#repo-clone-ssh').on('click', function () { - $('.clone-url').text($(this).data('link')); - $('#repo-clone-url').val($(this).data('link')); - $(this).addClass('blue'); - $('#repo-clone-https').removeClass('blue'); - localStorage.setItem('repo-clone-protocol', 'ssh'); + $("#repo-clone-ssh").on("click", function () { + $(".clone-url").text($(this).data("link")); + $("#repo-clone-url").val($(this).data("link")); + $(this).addClass("blue"); + $("#repo-clone-https").removeClass("blue"); + localStorage.setItem("repo-clone-protocol", "ssh"); }); - $('#repo-clone-https').on('click', function () { - $('.clone-url').text($(this).data('link')); - $('#repo-clone-url').val($(this).data('link')); - $(this).addClass('blue'); - $('#repo-clone-ssh').removeClass('blue'); - localStorage.setItem('repo-clone-protocol', 'https'); + $("#repo-clone-https").on("click", function () { + $(".clone-url").text($(this).data("link")); + $("#repo-clone-url").val($(this).data("link")); + $(this).addClass("blue"); + $("#repo-clone-ssh").removeClass("blue"); + localStorage.setItem("repo-clone-protocol", "https"); }); - $('#repo-clone-url').on('click', function () { + $("#repo-clone-url").on("click", function () { $(this).select(); }); // Pull request - const $repoComparePull = $('.repository.compare.pull'); + const $repoComparePull = $(".repository.compare.pull"); if ($repoComparePull.length > 0) { - initFilterSearchDropdown('.choose.branch .dropdown'); + initFilterSearchDropdown(".choose.branch .dropdown"); // show pull request form - $repoComparePull.find('button.show-form').on('click', function (e) { + $repoComparePull.find("button.show-form").on("click", function (e) { e.preventDefault(); - $repoComparePull.find('.pullrequest-form').show(); + $repoComparePull.find(".pullrequest-form").show(); autoSimpleMDE.codemirror.refresh(); - $(this) - .parent() - .hide(); + $(this).parent().hide(); }); } // Branches - if ($('.repository.settings.branches').length > 0) { - initFilterSearchDropdown('.protected-branches .dropdown'); - $('.enable-protection, .enable-whitelist, .enable-statuscheck').on( - 'change', + if ($(".repository.settings.branches").length > 0) { + initFilterSearchDropdown(".protected-branches .dropdown"); + $(".enable-protection, .enable-whitelist, .enable-statuscheck").on( + "change", function () { if (this.checked) { - $($(this).data('target')).removeClass('disabled'); + $($(this).data("target")).removeClass("disabled"); } else { - $($(this).data('target')).addClass('disabled'); + $($(this).data("target")).addClass("disabled"); } } ); - $('.disable-whitelist').on('change', function () { + $(".disable-whitelist").on("change", function () { if (this.checked) { - $($(this).data('target')).addClass('disabled'); + $($(this).data("target")).addClass("disabled"); } }); } // Language stats - if ($('.language-stats').length > 0) { - $('.language-stats').on('click', (e) => { + if ($(".language-stats").length > 0) { + $(".language-stats").on("click", (e) => { e.preventDefault(); - $('.language-stats-details, .repository-menu').slideToggle(); + $(".language-stats-details, .repository-menu").slideToggle(); }); } } function initMigration() { const toggleMigrations = function () { - const authUserName = $('#auth_username').val(); - const cloneAddr = $('#clone_addr').val(); + const authUserName = $("#auth_username").val(); + const cloneAddr = $("#clone_addr").val(); if ( - !$('#mirror').is(':checked') && + !$("#mirror").is(":checked") && authUserName && authUserName.length > 0 && cloneAddr !== undefined && - (cloneAddr.startsWith('https://github.com') || - cloneAddr.startsWith('http://github.com') || - cloneAddr.startsWith('http://gitlab.com') || - cloneAddr.startsWith('https://gitlab.com')) + (cloneAddr.startsWith("https://github.com") || + cloneAddr.startsWith("http://github.com") || + cloneAddr.startsWith("http://gitlab.com") || + cloneAddr.startsWith("https://gitlab.com")) ) { - $('#migrate_items').show(); + $("#migrate_items").show(); } else { - $('#migrate_items').hide(); + $("#migrate_items").hide(); } }; toggleMigrations(); - $('#clone_addr').on('input', toggleMigrations); - $('#auth_username').on('input', toggleMigrations); - $('#mirror').on('change', toggleMigrations); + $("#clone_addr").on("input", toggleMigrations); + $("#auth_username").on("input", toggleMigrations); + $("#mirror").on("change", toggleMigrations); } function initPullRequestReview() { - $('.show-outdated').on('click', function (e) { + $(".show-outdated").on("click", function (e) { e.preventDefault(); - const id = $(this).data('comment'); - $(this).addClass('hide'); - $(`#code-comments-${id}`).removeClass('hide'); - $(`#code-preview-${id}`).removeClass('hide'); - $(`#hide-outdated-${id}`).removeClass('hide'); + const id = $(this).data("comment"); + $(this).addClass("hide"); + $(`#code-comments-${id}`).removeClass("hide"); + $(`#code-preview-${id}`).removeClass("hide"); + $(`#hide-outdated-${id}`).removeClass("hide"); }); - $('.hide-outdated').on('click', function (e) { + $(".hide-outdated").on("click", function (e) { e.preventDefault(); - const id = $(this).data('comment'); - $(this).addClass('hide'); - $(`#code-comments-${id}`).addClass('hide'); - $(`#code-preview-${id}`).addClass('hide'); - $(`#show-outdated-${id}`).removeClass('hide'); + const id = $(this).data("comment"); + $(this).addClass("hide"); + $(`#code-comments-${id}`).addClass("hide"); + $(`#code-preview-${id}`).addClass("hide"); + $(`#show-outdated-${id}`).removeClass("hide"); }); - $('button.comment-form-reply').on('click', function (e) { + $("button.comment-form-reply").on("click", function (e) { e.preventDefault(); $(this).hide(); - const form = $(this) - .parent() - .find('.comment-form'); - form.removeClass('hide'); - assingMenuAttributes(form.find('.menu')); + const form = $(this).parent().find(".comment-form"); + form.removeClass("hide"); + assingMenuAttributes(form.find(".menu")); }); // The following part is only for diff views - if ($('.repository.pull.diff').length === 0) { + if ($(".repository.pull.diff").length === 0) { return; } - $('.diff-detail-box.ui.sticky').sticky(); + $(".diff-detail-box.ui.sticky").sticky(); - $('.btn-review') - .on('click', function (e) { + $(".btn-review") + .on("click", function (e) { e.preventDefault(); - $(this) - .closest('.dropdown') - .find('.menu') - .toggle('visible'); + $(this).closest(".dropdown").find(".menu").toggle("visible"); }) - .closest('.dropdown') - .find('.link.close') - .on('click', function (e) { + .closest(".dropdown") + .find(".link.close") + .on("click", function (e) { e.preventDefault(); - $(this) - .closest('.menu') - .toggle('visible'); + $(this).closest(".menu").toggle("visible"); }); - $('.code-view .lines-code,.code-view .lines-num') - .on('mouseenter', function () { - const parent = $(this).closest('td'); + $(".code-view .lines-code,.code-view .lines-num") + .on("mouseenter", function () { + const parent = $(this).closest("td"); $(this) - .closest('tr') + .closest("tr") .addClass( - parent.hasClass('lines-num-old') || parent.hasClass('lines-code-old') ? - 'focus-lines-old' : - 'focus-lines-new' + parent.hasClass("lines-num-old") || parent.hasClass("lines-code-old") + ? "focus-lines-old" + : "focus-lines-new" ); }) - .on('mouseleave', function () { - $(this) - .closest('tr') - .removeClass('focus-lines-new focus-lines-old'); + .on("mouseleave", function () { + $(this).closest("tr").removeClass("focus-lines-new focus-lines-old"); }); - $('.add-code-comment').on('click', function (e) { + $(".add-code-comment").on("click", function (e) { // https://github.com/go-gitea/gitea/issues/4745 - if ($(e.target).hasClass('btn-add-single')) { + if ($(e.target).hasClass("btn-add-single")) { return; } e.preventDefault(); - const isSplit = $(this) - .closest('.code-diff') - .hasClass('code-diff-split'); - const side = $(this).data('side'); - const idx = $(this).data('idx'); - const path = $(this).data('path'); - const form = $('#pull_review_add_comment').html(); - const tr = $(this).closest('tr'); + const isSplit = $(this).closest(".code-diff").hasClass("code-diff-split"); + const side = $(this).data("side"); + const idx = $(this).data("idx"); + const path = $(this).data("path"); + const form = $("#pull_review_add_comment").html(); + const tr = $(this).closest("tr"); let ntr = tr.next(); - if (!ntr.hasClass('add-comment')) { + if (!ntr.hasClass("add-comment")) { ntr = $( `${ - isSplit ? - '' : - '' + isSplit + ? '' + : '' }` ); tr.after(ntr); } const td = ntr.find(`.add-comment-${side}`); - let commentCloud = td.find('.comment-code-cloud'); + let commentCloud = td.find(".comment-code-cloud"); if (commentCloud.length === 0) { td.html(form); - commentCloud = td.find('.comment-code-cloud'); - assingMenuAttributes(commentCloud.find('.menu')); + commentCloud = td.find(".comment-code-cloud"); + assingMenuAttributes(commentCloud.find(".menu")); td.find("input[name='line']").val(idx); td.find("input[name='side']").val( - side === 'left' ? 'previous' : 'proposed' + side === "left" ? "previous" : "proposed" ); td.find("input[name='path']").val(path); } - commentCloud.find('textarea').focus(); + commentCloud.find("textarea").focus(); }); } function assingMenuAttributes(menu) { const id = Math.floor(Math.random() * Math.floor(1000000)); - menu.attr('data-write', menu.attr('data-write') + id); - menu.attr('data-preview', menu.attr('data-preview') + id); - menu.find('.item').each(function () { - const tab = $(this).attr('data-tab') + id; - $(this).attr('data-tab', tab); + menu.attr("data-write", menu.attr("data-write") + id); + menu.attr("data-preview", menu.attr("data-preview") + id); + menu.find(".item").each(function () { + const tab = $(this).attr("data-tab") + id; + $(this).attr("data-tab", tab); }); - menu - .parent() - .find("*[data-tab='write']") - .attr('data-tab', `write${id}`); - menu - .parent() - .find("*[data-tab='preview']") - .attr('data-tab', `preview${id}`); - initCommentPreviewTab(menu.parent('.form')); + menu.parent().find("*[data-tab='write']").attr("data-tab", `write${id}`); + menu.parent().find("*[data-tab='preview']").attr("data-tab", `preview${id}`); + initCommentPreviewTab(menu.parent(".form")); return id; } function initRepositoryCollaboration() { // Change collaborator access mode - $('.access-mode.menu .item').on('click', function () { + $(".access-mode.menu .item").on("click", function () { const $menu = $(this).parent(); - $.post($menu.data('url'), { + $.post($menu.data("url"), { _csrf: csrf, - uid: $menu.data('uid'), - mode: $(this).data('value') + uid: $menu.data("uid"), + mode: $(this).data("value"), }); }); } function initTeamSettings() { // Change team access mode - $('.organization.new.team input[name=permission]').on('change', () => { + $(".organization.new.team input[name=permission]").on("change", () => { const val = $( - 'input[name=permission]:checked', - '.organization.new.team' + "input[name=permission]:checked", + ".organization.new.team" ).val(); - if (val === 'admin') { - $('.organization.new.team .team-units').hide(); + if (val === "admin") { + $(".organization.new.team .team-units").hide(); } else { - $('.organization.new.team .team-units').show(); + $(".organization.new.team .team-units").show(); } }); } function initWikiForm() { - const $editArea = $('.repository.wiki textarea#edit_area'); + const $editArea = $(".repository.wiki textarea#edit_area"); let sideBySideChanges = 0; let sideBySideTimeout = null; if ($editArea.length > 0) { @@ -1668,17 +1610,17 @@ function initWikiForm() { sideBySideTimeout = null; } $.post( - $editArea.data('url'), + $editArea.data("url"), { _csrf: csrf, - mode: 'gfm', - context: $editArea.data('context'), - text: plainText + mode: "gfm", + context: $editArea.data("context"), + text: plainText, }, (data) => { preview.innerHTML = `
${data}
`; $(preview) - .find('pre code') + .find("pre code") .each((_, e) => { highlight(e); }); @@ -1702,29 +1644,29 @@ function initWikiForm() { } }, 0); if (!simplemde.isSideBySideActive()) { - return 'Loading...'; + return "Loading..."; } return preview.innerHTML; }, renderingConfig: { - singleLineBreaks: false + singleLineBreaks: false, }, indentWithTabs: false, tabSize: 4, spellChecker: false, toolbar: [ - 'bold', - 'italic', - 'strikethrough', - '|', - 'heading-1', - 'heading-2', - 'heading-3', - 'heading-bigger', - 'heading-smaller', - '|', + "bold", + "italic", + "strikethrough", + "|", + "heading-1", + "heading-2", + "heading-3", + "heading-bigger", + "heading-smaller", + "|", { - name: 'code-inline', + name: "code-inline", action(e) { const cm = e.codemirror; const selection = cm.getSelection(); @@ -1735,96 +1677,96 @@ function initWikiForm() { } cm.focus(); }, - className: 'fa fa-angle-right', - title: 'Add Inline Code' + className: "fa fa-angle-right", + title: "Add Inline Code", }, - 'code', - 'quote', - '|', + "code", + "quote", + "|", { - name: 'checkbox-empty', + name: "checkbox-empty", action(e) { const cm = e.codemirror; cm.replaceSelection(`\n- [ ] ${cm.getSelection()}`); cm.focus(); }, - className: 'fa fa-square-o', - title: 'Add Checkbox (empty)' + className: "fa fa-square-o", + title: "Add Checkbox (empty)", }, { - name: 'checkbox-checked', + name: "checkbox-checked", action(e) { const cm = e.codemirror; cm.replaceSelection(`\n- [x] ${cm.getSelection()}`); cm.focus(); }, - className: 'fa fa-check-square-o', - title: 'Add Checkbox (checked)' + className: "fa fa-check-square-o", + title: "Add Checkbox (checked)", }, - '|', - 'unordered-list', - 'ordered-list', - '|', - 'link', - 'image', - 'table', - 'horizontal-rule', - '|', - 'clean-block', - 'preview', - 'fullscreen', - 'side-by-side', - '|', + "|", + "unordered-list", + "ordered-list", + "|", + "link", + "image", + "table", + "horizontal-rule", + "|", + "clean-block", + "preview", + "fullscreen", + "side-by-side", + "|", { - name: 'revert-to-textarea', + name: "revert-to-textarea", action(e) { e.toTextArea(); }, - className: 'fa fa-file', - title: 'Revert to simple textarea' - } - ] + className: "fa fa-file", + title: "Revert to simple textarea", + }, + ], }); - $(simplemde.codemirror.getInputField()).addClass('js-quick-submit'); + $(simplemde.codemirror.getInputField()).addClass("js-quick-submit"); setTimeout(() => { const $bEdit = $('.repository.wiki.new .previewtabs a[data-tab="write"]'); const $bPrev = $( '.repository.wiki.new .previewtabs a[data-tab="preview"]' ); - const $toolbar = $('.editor-toolbar'); - const $bPreview = $('.editor-toolbar a.fa-eye'); - const $bSideBySide = $('.editor-toolbar a.fa-columns'); - $bEdit.on('click', () => { - if ($toolbar.hasClass('disabled-for-preview')) { - $bPreview.trigger('click'); + const $toolbar = $(".editor-toolbar"); + const $bPreview = $(".editor-toolbar a.fa-eye"); + const $bSideBySide = $(".editor-toolbar a.fa-columns"); + $bEdit.on("click", () => { + if ($toolbar.hasClass("disabled-for-preview")) { + $bPreview.trigger("click"); } }); - $bPrev.on('click', () => { - if (!$toolbar.hasClass('disabled-for-preview')) { - $bPreview.trigger('click'); + $bPrev.on("click", () => { + if (!$toolbar.hasClass("disabled-for-preview")) { + $bPreview.trigger("click"); } }); - $bPreview.on('click', () => { + $bPreview.on("click", () => { setTimeout(() => { - if ($toolbar.hasClass('disabled-for-preview')) { - if ($bEdit.hasClass('active')) { - $bEdit.removeClass('active'); + if ($toolbar.hasClass("disabled-for-preview")) { + if ($bEdit.hasClass("active")) { + $bEdit.removeClass("active"); } - if (!$bPrev.hasClass('active')) { - $bPrev.addClass('active'); + if (!$bPrev.hasClass("active")) { + $bPrev.addClass("active"); } } else { - if (!$bEdit.hasClass('active')) { - $bEdit.addClass('active'); + if (!$bEdit.hasClass("active")) { + $bEdit.addClass("active"); } - if ($bPrev.hasClass('active')) { - $bPrev.removeClass('active'); + if ($bPrev.hasClass("active")) { + $bPrev.removeClass("active"); } } }, 0); }); - $bSideBySide.on('click', () => { + $bSideBySide.on("click", () => { sideBySideChanges = 10; }); }, 0); @@ -1835,13 +1777,13 @@ function initWikiForm() { $.fn.getCursorPosition = function () { const el = $(this).get(0); let pos = 0; - if ('selectionStart' in el) { + if ("selectionStart" in el) { pos = el.selectionStart; - } else if ('selection' in document) { + } else if ("selection" in document) { el.focus(); const Sel = document.selection.createRange(); const SelLength = document.selection.createRange().text.length; - Sel.moveStart('character', -el.value.length); + Sel.moveStart("character", -el.value.length); pos = Sel.text.length - SelLength; } return pos; @@ -1853,47 +1795,47 @@ function setCommentSimpleMDE($editArea) { element: $editArea[0], forceSync: true, renderingConfig: { - singleLineBreaks: false + singleLineBreaks: false, }, indentWithTabs: false, tabSize: 4, spellChecker: false, toolbar: [ - 'bold', - 'italic', - 'strikethrough', - '|', - 'heading-1', - 'heading-2', - 'heading-3', - 'heading-bigger', - 'heading-smaller', - '|', - 'code', - 'quote', - '|', - 'unordered-list', - 'ordered-list', - '|', - 'link', - 'image', - 'table', - 'horizontal-rule', - '|', - 'clean-block', - '|', + "bold", + "italic", + "strikethrough", + "|", + "heading-1", + "heading-2", + "heading-3", + "heading-bigger", + "heading-smaller", + "|", + "code", + "quote", + "|", + "unordered-list", + "ordered-list", + "|", + "link", + "image", + "table", + "horizontal-rule", + "|", + "clean-block", + "|", { - name: 'revert-to-textarea', + name: "revert-to-textarea", action(e) { e.toTextArea(); }, - className: 'fa fa-file', - title: 'Revert to simple textarea' - } - ] + className: "fa fa-file", + title: "Revert to simple textarea", + }, + ], }); - $(simplemde.codemirror.getInputField()).addClass('js-quick-submit'); - simplemde.codemirror.setOption('extraKeys', { + $(simplemde.codemirror.getInputField()).addClass("js-quick-submit"); + simplemde.codemirror.setOption("extraKeys", { Enter: () => { if (!(issuesTribute.isActive || emojiTribute.isActive)) { return CodeMirror.Pass; @@ -1901,10 +1843,10 @@ function setCommentSimpleMDE($editArea) { }, Backspace: (cm) => { if (cm.getInputField().trigger) { - cm.getInputField().trigger('input'); + cm.getInputField().trigger("input"); } - cm.execCommand('delCharBefore'); - } + cm.execCommand("delCharBefore"); + }, }); issuesTribute.attach(simplemde.codemirror.getInputField()); emojiTribute.attach(simplemde.codemirror.getInputField()); @@ -1912,32 +1854,29 @@ function setCommentSimpleMDE($editArea) { } async function initEditor() { - $('.js-quick-pull-choice-option').on('change', function () { - if ($(this).val() === 'commit-to-new-branch') { - $('.quick-pull-branch-name').show(); - $('.quick-pull-branch-name input').prop('required', true); + $(".js-quick-pull-choice-option").on("change", function () { + if ($(this).val() === "commit-to-new-branch") { + $(".quick-pull-branch-name").show(); + $(".quick-pull-branch-name input").prop("required", true); } else { - $('.quick-pull-branch-name').hide(); - $('.quick-pull-branch-name input').prop('required', false); + $(".quick-pull-branch-name").hide(); + $(".quick-pull-branch-name input").prop("required", false); } - $('#commit-button').text($(this).attr('button_text')); + $("#commit-button").text($(this).attr("button_text")); }); - const $editFilename = $('#file-name'); + const $editFilename = $("#file-name"); $editFilename - .on('keyup', function (e) { - const $section = $('.breadcrumb span.section'); - const $divider = $('.breadcrumb div.divider'); + .on("keyup", function (e) { + const $section = $(".breadcrumb span.section"); + const $divider = $(".breadcrumb div.divider"); let value; let parts; if (e.keyCode === 8) { if ($(this).getCursorPosition() === 0) { if ($section.length > 0) { - value = $section - .last() - .find('a') - .text(); + value = $section.last().find("a").text(); $(this).val(value + $(this).val()); $(this)[0].setSelectionRange(value.length, value.length); $section.last().remove(); @@ -1946,9 +1885,7 @@ async function initEditor() { } } if (e.keyCode === 191) { - parts = $(this) - .val() - .split('/'); + parts = $(this).val().split("/"); for (let i = 0; i < parts.length; ++i) { value = parts[i]; if (i < parts.length - 1) { @@ -1965,77 +1902,71 @@ async function initEditor() { } } parts = []; - $('.breadcrumb span.section').each(function () { + $(".breadcrumb span.section").each(function () { const element = $(this); - if (element.find('a').length) { - parts.push(element.find('a').text()); + if (element.find("a").length) { + parts.push(element.find("a").text()); } else { parts.push(element.text()); } }); if ($(this).val()) parts.push($(this).val()); - $('#tree_path').val(parts.join('/')); + $("#tree_path").val(parts.join("/")); }) - .trigger('keyup'); + .trigger("keyup"); - const $editArea = $('.repository.editor textarea#edit_area'); + const $editArea = $(".repository.editor textarea#edit_area"); if (!$editArea.length) return; await createCodeEditor($editArea[0], $editFilename[0], previewFileModes); // Using events from https://github.com/codedance/jquery.AreYouSure#advanced-usage // to enable or disable the commit button - const $commitButton = $('#commit-button'); - const $editForm = $('.ui.edit.form'); - const dirtyFileClass = 'dirty-file'; + const $commitButton = $("#commit-button"); + const $editForm = $(".ui.edit.form"); + const dirtyFileClass = "dirty-file"; // Disabling the button at the start - $commitButton.prop('disabled', true); + $commitButton.prop("disabled", true); // Registering a custom listener for the file path and the file content $editForm.areYouSure({ silent: true, dirtyClass: dirtyFileClass, - fieldSelector: ':input:not(.commit-form-wrapper :input)', + fieldSelector: ":input:not(.commit-form-wrapper :input)", change() { const dirty = $(this).hasClass(dirtyFileClass); - $commitButton.prop('disabled', !dirty); - } + $commitButton.prop("disabled", !dirty); + }, }); - $commitButton.on('click', (event) => { + $commitButton.on("click", (event) => { // A modal which asks if an empty file should be committed if ($editArea.val().length === 0) { - $('#edit-empty-content-modal') + $("#edit-empty-content-modal") .modal({ onApprove() { - $('.edit.form').trigger('submit'); - } + $(".edit.form").trigger("submit"); + }, }) - .modal('show'); + .modal("show"); event.preventDefault(); } }); } function initOrganization() { - if ($('.organization').length === 0) { + if ($(".organization").length === 0) { return; } // Options - if ($('.organization.settings.options').length > 0) { - $('#org_name').on('keyup', function () { - const $prompt = $('#org-name-change-prompt'); + if ($(".organization.settings.options").length > 0) { + $("#org_name").on("keyup", function () { + const $prompt = $("#org-name-change-prompt"); if ( - $(this) - .val() - .toString() - .toLowerCase() !== - $(this) - .data('org-name') - .toString() - .toLowerCase() + $(this).val().toString().toLowerCase() !== + $(this).data("org-name").toString().toLowerCase() ) { $prompt.show(); } else { @@ -2045,25 +1976,19 @@ function initOrganization() { } // Labels - if ($('.organization.settings.labels').length > 0) { + if ($(".organization.settings.labels").length > 0) { initLabelEdit(); } } function initUserSettings() { // Options - if ($('.user.settings.profile').length > 0) { - $('#username').on('keyup', function () { - const $prompt = $('#name-change-prompt'); + if ($(".user.settings.profile").length > 0) { + $("#username").on("keyup", function () { + const $prompt = $("#name-change-prompt"); if ( - $(this) - .val() - .toString() - .toLowerCase() !== - $(this) - .data('name') - .toString() - .toLowerCase() + $(this).val().toString().toLowerCase() !== + $(this).data("name").toString().toLowerCase() ) { $prompt.show(); } else { @@ -2074,307 +1999,294 @@ function initUserSettings() { } function initGithook() { - if ($('.edit.githook').length === 0) { + if ($(".edit.githook").length === 0) { return; } CodeMirror.autoLoadMode( - CodeMirror.fromTextArea($('#content')[0], { + CodeMirror.fromTextArea($("#content")[0], { lineNumbers: true, - mode: 'shell' + mode: "shell", }), - 'shell' + "shell" ); } function initWebhook() { - if ($('.new.webhook').length === 0) { + if ($(".new.webhook").length === 0) { return; } - $('.events.checkbox input').on('change', function () { - if ($(this).is(':checked')) { - $('.events.fields').show(); + $(".events.checkbox input").on("change", function () { + if ($(this).is(":checked")) { + $(".events.fields").show(); } }); - $('.non-events.checkbox input').on('change', function () { - if ($(this).is(':checked')) { - $('.events.fields').hide(); + $(".non-events.checkbox input").on("change", function () { + if ($(this).is(":checked")) { + $(".events.fields").hide(); } }); const updateContentType = function () { - const visible = $('#http_method').val() === 'POST'; - $('#content_type') - .parent() - .parent() - [visible ? 'show' : 'hide'](); + const visible = $("#http_method").val() === "POST"; + $("#content_type").parent().parent()[visible ? "show" : "hide"](); }; updateContentType(); - $('#http_method').on('change', () => { + $("#http_method").on("change", () => { updateContentType(); }); // Test delivery - $('#test-delivery').on('click', function () { + $("#test-delivery").on("click", function () { const $this = $(this); - $this.addClass('loading disabled'); - $.post($this.data('link'), { - _csrf: csrf + $this.addClass("loading disabled"); + $.post($this.data("link"), { + _csrf: csrf, }).done( setTimeout(() => { - window.location.href = $this.data('redirect'); + window.location.href = $this.data("redirect"); }, 5000) ); }); } function initAdmin() { - if ($('.admin').length === 0) { + if ($(".admin").length === 0) { return; } // New user - if ($('.admin.new.user').length > 0 || $('.admin.edit.user').length > 0) { - $('#login_type').on('change', function () { - if ( - $(this) - .val() - .substring(0, 1) === '0' - ) { - $('#login_name').removeAttr('required'); - $('.non-local').hide(); - $('.local').show(); - $('#user_name').focus(); - - if ($(this).data('password') === 'required') { - $('#password').attr('required', 'required'); + if ($(".admin.new.user").length > 0 || $(".admin.edit.user").length > 0) { + $("#login_type").on("change", function () { + if ($(this).val().substring(0, 1) === "0") { + $("#login_name").removeAttr("required"); + $(".non-local").hide(); + $(".local").show(); + $("#user_name").focus(); + + if ($(this).data("password") === "required") { + $("#password").attr("required", "required"); } } else { - $('#login_name').attr('required', 'required'); - $('.non-local').show(); - $('.local').hide(); - $('#login_name').focus(); + $("#login_name").attr("required", "required"); + $(".non-local").show(); + $(".local").hide(); + $("#login_name").focus(); - $('#password').removeAttr('required'); + $("#password").removeAttr("required"); } }); } function onSecurityProtocolChange() { - if ($('#security_protocol').val() > 0) { - $('.has-tls').show(); + if ($("#security_protocol").val() > 0) { + $(".has-tls").show(); } else { - $('.has-tls').hide(); + $(".has-tls").hide(); } } function onUsePagedSearchChange() { - if ($('#use_paged_search').prop('checked')) { - $('.search-page-size') - .show() - .find('input') - .attr('required', 'required'); + if ($("#use_paged_search").prop("checked")) { + $(".search-page-size").show().find("input").attr("required", "required"); } else { - $('.search-page-size') - .hide() - .find('input') - .removeAttr('required'); + $(".search-page-size").hide().find("input").removeAttr("required"); } } function onOAuth2Change() { - $('.open_id_connect_auto_discovery_url, .oauth2_use_custom_url').hide(); - $('.open_id_connect_auto_discovery_url input[required]').removeAttr( - 'required' + $(".open_id_connect_auto_discovery_url, .oauth2_use_custom_url").hide(); + $(".open_id_connect_auto_discovery_url input[required]").removeAttr( + "required" ); - const provider = $('#oauth2_provider').val(); + const provider = $("#oauth2_provider").val(); switch (provider) { - case 'github': - case 'gitlab': - case 'gitea': - case 'nextcloud': - $('.oauth2_use_custom_url').show(); + case "github": + case "gitlab": + case "gitea": + case "nextcloud": + $(".oauth2_use_custom_url").show(); break; - case 'openidConnect': - $('.open_id_connect_auto_discovery_url input').attr( - 'required', - 'required' + case "openidConnect": + $(".open_id_connect_auto_discovery_url input").attr( + "required", + "required" ); - $('.open_id_connect_auto_discovery_url').show(); + $(".open_id_connect_auto_discovery_url").show(); break; } onOAuth2UseCustomURLChange(); } function onOAuth2UseCustomURLChange() { - const provider = $('#oauth2_provider').val(); - $('.oauth2_use_custom_url_field').hide(); - $('.oauth2_use_custom_url_field input[required]').removeAttr('required'); + const provider = $("#oauth2_provider").val(); + $(".oauth2_use_custom_url_field").hide(); + $(".oauth2_use_custom_url_field input[required]").removeAttr("required"); - if ($('#oauth2_use_custom_url').is(':checked')) { - $('#oauth2_token_url').val($(`#${provider}_token_url`).val()); - $('#oauth2_auth_url').val($(`#${provider}_auth_url`).val()); - $('#oauth2_profile_url').val($(`#${provider}_profile_url`).val()); - $('#oauth2_email_url').val($(`#${provider}_email_url`).val()); + if ($("#oauth2_use_custom_url").is(":checked")) { + $("#oauth2_token_url").val($(`#${provider}_token_url`).val()); + $("#oauth2_auth_url").val($(`#${provider}_auth_url`).val()); + $("#oauth2_profile_url").val($(`#${provider}_profile_url`).val()); + $("#oauth2_email_url").val($(`#${provider}_email_url`).val()); switch (provider) { - case 'github': + case "github": $( - '.oauth2_token_url input, .oauth2_auth_url input, .oauth2_profile_url input, .oauth2_email_url input' - ).attr('required', 'required'); + ".oauth2_token_url input, .oauth2_auth_url input, .oauth2_profile_url input, .oauth2_email_url input" + ).attr("required", "required"); $( - '.oauth2_token_url, .oauth2_auth_url, .oauth2_profile_url, .oauth2_email_url' + ".oauth2_token_url, .oauth2_auth_url, .oauth2_profile_url, .oauth2_email_url" ).show(); break; - case 'nextcloud': - case 'gitea': - case 'gitlab': + case "nextcloud": + case "gitea": + case "gitlab": $( - '.oauth2_token_url input, .oauth2_auth_url input, .oauth2_profile_url input' - ).attr('required', 'required'); - $('.oauth2_token_url, .oauth2_auth_url, .oauth2_profile_url').show(); - $('#oauth2_email_url').val(''); + ".oauth2_token_url input, .oauth2_auth_url input, .oauth2_profile_url input" + ).attr("required", "required"); + $(".oauth2_token_url, .oauth2_auth_url, .oauth2_profile_url").show(); + $("#oauth2_email_url").val(""); break; } } } // New authentication - if ($('.admin.new.authentication').length > 0) { - $('#auth_type').on('change', function () { + if ($(".admin.new.authentication").length > 0) { + $("#auth_type").on("change", function () { $( - '.ldap, .dldap, .smtp, .pam, .oauth2, .has-tls, .search-page-size, .sspi' + ".ldap, .dldap, .smtp, .pam, .oauth2, .has-tls, .search-page-size, .sspi" ).hide(); $( - '.ldap input[required], .binddnrequired input[required], .dldap input[required], .smtp input[required], .pam input[required], .oauth2 input[required], .has-tls input[required], .sspi input[required]' - ).removeAttr('required'); - $('.binddnrequired').removeClass('required'); + ".ldap input[required], .binddnrequired input[required], .dldap input[required], .smtp input[required], .pam input[required], .oauth2 input[required], .has-tls input[required], .sspi input[required]" + ).removeAttr("required"); + $(".binddnrequired").removeClass("required"); const authType = $(this).val(); switch (authType) { - case '2': // LDAP - $('.ldap').show(); - $('.binddnrequired input, .ldap div.required:not(.dldap) input').attr( - 'required', - 'required' + case "2": // LDAP + $(".ldap").show(); + $(".binddnrequired input, .ldap div.required:not(.dldap) input").attr( + "required", + "required" ); - $('.binddnrequired').addClass('required'); + $(".binddnrequired").addClass("required"); break; - case '3': // SMTP - $('.smtp').show(); - $('.has-tls').show(); - $('.smtp div.required input, .has-tls').attr('required', 'required'); + case "3": // SMTP + $(".smtp").show(); + $(".has-tls").show(); + $(".smtp div.required input, .has-tls").attr("required", "required"); break; - case '4': // PAM - $('.pam').show(); - $('.pam input').attr('required', 'required'); + case "4": // PAM + $(".pam").show(); + $(".pam input").attr("required", "required"); break; - case '5': // LDAP - $('.dldap').show(); - $('.dldap div.required:not(.ldap) input').attr( - 'required', - 'required' + case "5": // LDAP + $(".dldap").show(); + $(".dldap div.required:not(.ldap) input").attr( + "required", + "required" ); break; - case '6': // OAuth2 - $('.oauth2').show(); + case "6": // OAuth2 + $(".oauth2").show(); $( - '.oauth2 div.required:not(.oauth2_use_custom_url,.oauth2_use_custom_url_field,.open_id_connect_auto_discovery_url) input' - ).attr('required', 'required'); + ".oauth2 div.required:not(.oauth2_use_custom_url,.oauth2_use_custom_url_field,.open_id_connect_auto_discovery_url) input" + ).attr("required", "required"); onOAuth2Change(); break; - case '7': // SSPI - $('.sspi').show(); - $('.sspi div.required input').attr('required', 'required'); + case "7": // SSPI + $(".sspi").show(); + $(".sspi div.required input").attr("required", "required"); break; } - if (authType === '2' || authType === '5') { + if (authType === "2" || authType === "5") { onSecurityProtocolChange(); } - if (authType === '2') { + if (authType === "2") { onUsePagedSearchChange(); } }); - $('#auth_type').trigger('change'); - $('#security_protocol').on('change', onSecurityProtocolChange); - $('#use_paged_search').on('change', onUsePagedSearchChange); - $('#oauth2_provider').on('change', onOAuth2Change); - $('#oauth2_use_custom_url').on('change', onOAuth2UseCustomURLChange); + $("#auth_type").trigger("change"); + $("#security_protocol").on("change", onSecurityProtocolChange); + $("#use_paged_search").on("change", onUsePagedSearchChange); + $("#oauth2_provider").on("change", onOAuth2Change); + $("#oauth2_use_custom_url").on("change", onOAuth2UseCustomURLChange); } // Edit authentication - if ($('.admin.edit.authentication').length > 0) { - const authType = $('#auth_type').val(); - if (authType === '2' || authType === '5') { - $('#security_protocol').on('change', onSecurityProtocolChange); - if (authType === '2') { - $('#use_paged_search').on('change', onUsePagedSearchChange); + if ($(".admin.edit.authentication").length > 0) { + const authType = $("#auth_type").val(); + if (authType === "2" || authType === "5") { + $("#security_protocol").on("change", onSecurityProtocolChange); + if (authType === "2") { + $("#use_paged_search").on("change", onUsePagedSearchChange); } - } else if (authType === '6') { - $('#oauth2_provider').on('change', onOAuth2Change); - $('#oauth2_use_custom_url').on('change', onOAuth2UseCustomURLChange); + } else if (authType === "6") { + $("#oauth2_provider").on("change", onOAuth2Change); + $("#oauth2_use_custom_url").on("change", onOAuth2UseCustomURLChange); onOAuth2Change(); } } // Notice - if ($('.admin.notice')) { - const $detailModal = $('#detail-modal'); + if ($(".admin.notice")) { + const $detailModal = $("#detail-modal"); // Attach view detail modals - $('.view-detail').on('click', function () { - $detailModal.find('.content pre').text($(this).data('content')); - $detailModal.modal('show'); + $(".view-detail").on("click", function () { + $detailModal.find(".content pre").text($(this).data("content")); + $detailModal.modal("show"); return false; }); // Select actions - const $checkboxes = $('.select.table .ui.checkbox'); - $('.select.action').on('click', function () { - switch ($(this).data('action')) { - case 'select-all': - $checkboxes.checkbox('check'); + const $checkboxes = $(".select.table .ui.checkbox"); + $(".select.action").on("click", function () { + switch ($(this).data("action")) { + case "select-all": + $checkboxes.checkbox("check"); break; - case 'deselect-all': - $checkboxes.checkbox('uncheck'); + case "deselect-all": + $checkboxes.checkbox("uncheck"); break; - case 'inverse': - $checkboxes.checkbox('toggle'); + case "inverse": + $checkboxes.checkbox("toggle"); break; } }); - $('#delete-selection').on('click', function () { + $("#delete-selection").on("click", function () { const $this = $(this); - $this.addClass('loading disabled'); + $this.addClass("loading disabled"); const ids = []; $checkboxes.each(function () { - if ($(this).checkbox('is checked')) { - ids.push($(this).data('id')); + if ($(this).checkbox("is checked")) { + ids.push($(this).data("id")); } }); - $.post($this.data('link'), { + $.post($this.data("link"), { _csrf: csrf, - ids + ids, }).done(() => { - window.location.href = $this.data('redirect'); + window.location.href = $this.data("redirect"); }); }); } } function buttonsClickOnEnter() { - $('.ui.button').on('keypress', function (e) { + $(".ui.button").on("keypress", function (e) { if (e.keyCode === 13 || e.keyCode === 32) { // enter key or space bar - $(this).trigger('click'); + $(this).trigger("click"); } }); } function searchUsers() { - const $searchUserBox = $('#search-user-box'); + const $searchUserBox = $("#search-user-box"); $searchUserBox.search({ minCharacters: 2, apiSettings: { @@ -2388,135 +2300,135 @@ function searchUsers() { } items.push({ title, - image: item.avatar_url + image: item.avatar_url, }); }); return { results: items }; - } + }, }, - searchFields: ['login', 'full_name'], - showNoResults: false + searchFields: ["login", "full_name"], + showNoResults: false, }); } function searchTeams() { - const $searchTeamBox = $('#search-team-box'); + const $searchTeamBox = $("#search-team-box"); $searchTeamBox.search({ minCharacters: 2, apiSettings: { url: `${AppSubUrl}/api/v1/orgs/${$searchTeamBox.data( - 'org' + "org" )}/teams/search?q={query}`, - headers: { 'X-Csrf-Token': csrf }, + headers: { "X-Csrf-Token": csrf }, onResponse(response) { const items = []; $.each(response.data, (_i, item) => { const title = `${item.name} (${item.permission} access)`; items.push({ - title + title, }); }); return { results: items }; - } + }, }, - searchFields: ['name', 'description'], - showNoResults: false + searchFields: ["name", "description"], + showNoResults: false, }); } function searchRepositories() { - const $searchRepoBox = $('#search-repo-box'); + const $searchRepoBox = $("#search-repo-box"); $searchRepoBox.search({ minCharacters: 2, apiSettings: { url: `${AppSubUrl}/api/v1/repos/search?q={query}&uid=${$searchRepoBox.data( - 'uid' + "uid" )}`, onResponse(response) { const items = []; $.each(response.data, (_i, item) => { items.push({ - title: item.full_display_name.split('/')[1], - description: item.full_display_name + title: item.full_display_name.split("/")[1], + description: item.full_display_name, }); }); return { results: items }; - } + }, }, - searchFields: ['full_name'], - showNoResults: false + searchFields: ["full_name"], + showNoResults: false, }); } function initCodeView() { - if ($('.code-view .linenums').length > 0) { - $(document).on('click', '.lines-num span', function (e) { + if ($(".code-view .linenums").length > 0) { + $(document).on("click", ".lines-num span", function (e) { const $select = $(this); const $list = $select .parent() - .siblings('.lines-code') - .find('ol.linenums > li'); + .siblings(".lines-code") + .find("ol.linenums > li"); selectRange( $list, - $list.filter(`[rel=${$select.attr('id')}]`), - e.shiftKey ? $list.filter('.active').eq(0) : null + $list.filter(`[rel=${$select.attr("id")}]`), + e.shiftKey ? $list.filter(".active").eq(0) : null ); deSelect(); }); $(window) - .on('hashchange', () => { + .on("hashchange", () => { let m = window.location.hash.match(/^#(L\d+)-(L\d+)$/); - const $list = $('.code-view ol.linenums > li'); + const $list = $(".code-view ol.linenums > li"); let $first; if (m) { $first = $list.filter(`.${m[1]}`); selectRange($list, $first, $list.filter(`.${m[2]}`)); - $('html, body').scrollTop($first.offset().top - 200); + $("html, body").scrollTop($first.offset().top - 200); return; } m = window.location.hash.match(/^#(L|n)(\d+)$/); if (m) { $first = $list.filter(`.L${m[2]}`); selectRange($list, $first); - $('html, body').scrollTop($first.offset().top - 200); + $("html, body").scrollTop($first.offset().top - 200); } }) - .trigger('hashchange'); + .trigger("hashchange"); } - $('.fold-code').on('click', ({ target }) => { - const box = target.closest('.file-content'); - const folded = box.dataset.folded !== 'true'; - target.classList.add(`fa-chevron-${folded ? 'right' : 'down'}`); - target.classList.remove(`fa-chevron-${folded ? 'down' : 'right'}`); + $(".fold-code").on("click", ({ target }) => { + const box = target.closest(".file-content"); + const folded = box.dataset.folded !== "true"; + target.classList.add(`fa-chevron-${folded ? "right" : "down"}`); + target.classList.remove(`fa-chevron-${folded ? "down" : "right"}`); box.dataset.folded = String(folded); }); function insertBlobExcerpt(e) { const $blob = $(e.target); const $row = $blob.parent().parent(); $.get( - `${$blob.data('url')}?${$blob.data('query')}&anchor=${$blob.data( - 'anchor' + `${$blob.data("url")}?${$blob.data("query")}&anchor=${$blob.data( + "anchor" )}`, (blob) => { $row.replaceWith(blob); - $(`[data-anchor="${$blob.data('anchor')}"]`).on('click', (e) => { + $(`[data-anchor="${$blob.data("anchor")}"]`).on("click", (e) => { insertBlobExcerpt(e); }); - $('.diff-detail-box.ui.sticky').sticky(); + $(".diff-detail-box.ui.sticky").sticky(); } ); } - $('.ui.blob-excerpt').on('click', (e) => { + $(".ui.blob-excerpt").on("click", (e) => { insertBlobExcerpt(e); }); } function initU2FAuth() { - if ($('#wait-for-key').length === 0) { + if ($("#wait-for-key").length === 0) { return; } u2fApi @@ -2543,10 +2455,10 @@ function initU2FAuth() { function u2fSigned(resp) { $.ajax({ url: `${AppSubUrl}/user/u2f/sign`, - type: 'POST', - headers: { 'X-Csrf-Token': csrf }, + type: "POST", + headers: { "X-Csrf-Token": csrf }, data: JSON.stringify(resp), - contentType: 'application/json; charset=utf-8' + contentType: "application/json; charset=utf-8", }) .done((res) => { window.location.replace(res); @@ -2562,21 +2474,21 @@ function u2fRegistered(resp) { } $.ajax({ url: `${AppSubUrl}/user/settings/security/u2f/register`, - type: 'POST', - headers: { 'X-Csrf-Token': csrf }, + type: "POST", + headers: { "X-Csrf-Token": csrf }, data: JSON.stringify(resp), - contentType: 'application/json; charset=utf-8', + contentType: "application/json; charset=utf-8", success() { reload(); }, fail() { u2fError(1); - } + }, }); } function checkError(resp) { - if (!('errorCode' in resp)) { + if (!("errorCode" in resp)) { return false; } if (resp.errorCode === 0) { @@ -2588,33 +2500,33 @@ function checkError(resp) { function u2fError(errorType) { const u2fErrors = { - browser: $('#unsupported-browser'), - 1: $('#u2f-error-1'), - 2: $('#u2f-error-2'), - 3: $('#u2f-error-3'), - 4: $('#u2f-error-4'), - 5: $('.u2f-error-5') + browser: $("#unsupported-browser"), + 1: $("#u2f-error-1"), + 2: $("#u2f-error-2"), + 3: $("#u2f-error-3"), + 4: $("#u2f-error-4"), + 5: $(".u2f-error-5"), }; - u2fErrors[errorType].removeClass('hide'); + u2fErrors[errorType].removeClass("hide"); Object.keys(u2fErrors).forEach((type) => { if (type !== errorType) { - u2fErrors[type].addClass('hide'); + u2fErrors[type].addClass("hide"); } }); - $('#u2f-error').modal('show'); + $("#u2f-error").modal("show"); } function initU2FRegister() { - $('#register-device').modal({ allowMultiple: false }); - $('#u2f-error').modal({ allowMultiple: false }); - $('#register-security-key').on('click', (e) => { + $("#register-device").modal({ allowMultiple: false }); + $("#u2f-error").modal({ allowMultiple: false }); + $("#register-security-key").on("click", (e) => { e.preventDefault(); u2fApi .ensureSupport() .then(u2fRegisterRequest) .catch(() => { - u2fError('browser'); + u2fError("browser"); }); }); } @@ -2622,13 +2534,11 @@ function initU2FRegister() { function u2fRegisterRequest() { $.post(`${AppSubUrl}/user/settings/security/u2f/request_register`, { _csrf: csrf, - name: $('#nickname').val() + name: $("#nickname").val(), }) .done((req) => { - $('#nickname') - .closest('div.field') - .removeClass('error'); - $('#register-device').modal('show'); + $("#nickname").closest("div.field").removeClass("error"); + $("#register-device").modal("show"); if (req.registeredKeys === null) { req.registeredKeys = []; } @@ -2645,23 +2555,18 @@ function u2fRegisterRequest() { }) .fail((xhr) => { if (xhr.status === 409) { - $('#nickname') - .closest('div.field') - .addClass('error'); + $("#nickname").closest("div.field").addClass("error"); } }); } function initWipTitle() { - $('.title_wip_desc > a').on('click', (e) => { + $(".title_wip_desc > a").on("click", (e) => { e.preventDefault(); - const $issueTitle = $('#issue_title'); + const $issueTitle = $("#issue_title"); $issueTitle.focus(); - const value = $issueTitle - .val() - .trim() - .toUpperCase(); + const value = $issueTitle.val().trim().toUpperCase(); for (const i in wipPrefixes) { if (value.startsWith(wipPrefixes[i].toUpperCase())) { @@ -2674,11 +2579,11 @@ function initWipTitle() { } function initTemplateSearch() { - const $repoTemplate = $('#repo_template'); + const $repoTemplate = $("#repo_template"); const checkTemplate = function () { - const $templateUnits = $('#template_units'); - const $nonTemplate = $('#non_template'); - if ($repoTemplate.val() !== '' && $repoTemplate.val() !== '0') { + const $templateUnits = $("#template_units"); + const $nonTemplate = $("#non_template"); + if ($repoTemplate.val() !== "" && $repoTemplate.val() !== "0") { $templateUnits.show(); $nonTemplate.hide(); } else { @@ -2686,92 +2591,92 @@ function initTemplateSearch() { $nonTemplate.show(); } }; - $repoTemplate.on('change', checkTemplate); + $repoTemplate.on("change", checkTemplate); checkTemplate(); const changeOwner = function () { - $('#repo_template_search').dropdown({ + $("#repo_template_search").dropdown({ apiSettings: { url: `${AppSubUrl}/api/v1/repos/search?q={query}&template=true&priority_owner_id=${$( - '#uid' + "#uid" ).val()}`, onResponse(response) { const filteredResponse = { success: true, results: [] }; filteredResponse.results.push({ - name: '', - value: '' + name: "", + value: "", }); // Parse the response from the api to work with our dropdown $.each(response.data, (_r, repo) => { filteredResponse.results.push({ name: htmlEncode(repo.full_display_name), - value: repo.id + value: repo.id, }); }); return filteredResponse; }, - cache: false + cache: false, }, - fullTextSearch: true + fullTextSearch: true, }); }; - $('#uid').on('change', changeOwner); + $("#uid").on("change", changeOwner); changeOwner(); } $(document).ready(async () => { // Show exact time - $('.time-since').each(function () { + $(".time-since").each(function () { $(this) - .addClass('poping up') - .attr('data-content', $(this).attr('title')) - .attr('data-variation', 'inverted tiny') - .attr('title', ''); + .addClass("poping up") + .attr("data-content", $(this).attr("title")) + .attr("data-variation", "inverted tiny") + .attr("title", ""); }); // Semantic UI modules. - $('.dropdown:not(.custom)').dropdown(); - $('.jump.dropdown').dropdown({ - action: 'hide', + $(".dropdown:not(.custom)").dropdown(); + $(".jump.dropdown").dropdown({ + action: "hide", onShow() { - $('.poping.up').popup('hide'); - } + $(".poping.up").popup("hide"); + }, }); - $('.slide.up.dropdown').dropdown({ - transition: 'slide up' + $(".slide.up.dropdown").dropdown({ + transition: "slide up", }); - $('.upward.dropdown').dropdown({ - direction: 'upward' + $(".upward.dropdown").dropdown({ + direction: "upward", }); - $('.ui.accordion').accordion(); - $('.ui.checkbox').checkbox(); - $('.ui.progress').progress({ - showActivity: false + $(".ui.accordion").accordion(); + $(".ui.checkbox").checkbox(); + $(".ui.progress").progress({ + showActivity: false, }); - $('.poping.up').popup(); - $('.top.menu .poping.up').popup({ + $(".poping.up").popup(); + $(".top.menu .poping.up").popup({ onShow() { - if ($('.top.menu .menu.transition').hasClass('visible')) { + if ($(".top.menu .menu.transition").hasClass("visible")) { return false; } - } + }, }); - $('.tabular.menu .item').tab(); - $('.tabable.menu .item').tab(); + $(".tabular.menu .item").tab(); + $(".tabable.menu .item").tab(); - $('.toggle.button').on('click', function () { - $($(this).data('target')).slideToggle(100); + $(".toggle.button").on("click", function () { + $($(this).data("target")).slideToggle(100); }); // make table element clickable like a link - $('tr[data-href]').on('click', function () { - window.location = $(this).data('href'); + $("tr[data-href]").on("click", function () { + window.location = $(this).data("href"); }); // make table element clickable like a link - $('td[data-href]').click(function () { - window.location = $(this).data('href'); + $("td[data-href]").click(function () { + window.location = $(this).data("href"); }); // 在String原型对象上添加format方法 String.prototype.format = function () { @@ -2780,156 +2685,161 @@ $(document).ready(async () => { return str; } else { Object.keys(arguments).forEach((item, index) => { - str = str.replace(/\?/, arguments[item]) - }) - return str + str = str.replace(/\?/, arguments[item]); + }); + return str; } - } + }; // Dropzone - const $dropzone = $('#dropzone'); + const $dropzone = $("#dropzone"); if ($dropzone.length > 0) { const filenameDict = {}; - let maxFileTooltips - let maxSizeTooltips - if ($dropzone.data('max-file-tooltips') && $dropzone.data('max-size-tooltips')) { - maxFileTooltips = $dropzone.data('max-file-tooltips').format($dropzone.data('max-file'), $dropzone.data('max-size')) - maxSizeTooltips = $dropzone.data('max-size-tooltips').format($dropzone.data('max-file')) + let maxFileTooltips; + let maxSizeTooltips; + if ( + $dropzone.data("max-file-tooltips") && + $dropzone.data("max-size-tooltips") + ) { + maxFileTooltips = $dropzone + .data("max-file-tooltips") + .format($dropzone.data("max-file"), $dropzone.data("max-size")); + maxSizeTooltips = $dropzone + .data("max-size-tooltips") + .format($dropzone.data("max-file")); } - await createDropzone('#dropzone', { - url: $dropzone.data('upload-url'), - headers: { 'X-Csrf-Token': csrf }, - maxFiles: $dropzone.data('max-file'), - maxFilesize: $dropzone.data('max-size'), + await createDropzone("#dropzone", { + url: $dropzone.data("upload-url"), + headers: { "X-Csrf-Token": csrf }, + maxFiles: $dropzone.data("max-file"), + maxFilesize: $dropzone.data("max-size"), acceptedFiles: - $dropzone.data('accepts') === '*/*' ? null : $dropzone.data('accepts'), + $dropzone.data("accepts") === "*/*" ? null : $dropzone.data("accepts"), addRemoveLinks: true, - dictDefaultMessage: $dropzone.data('default-message'), - dictInvalidFileType: $dropzone.data('invalid-input-type'), - dictFileTooBig: $dropzone.data('file-too-big'), - dictRemoveFile: $dropzone.data('remove-file'), + dictDefaultMessage: $dropzone.data("default-message"), + dictInvalidFileType: $dropzone.data("invalid-input-type"), + dictFileTooBig: $dropzone.data("file-too-big"), + dictRemoveFile: $dropzone.data("remove-file"), init() { - this.on('success', (file, data) => { + this.on("success", (file, data) => { filenameDict[file.name] = data.uuid; const input = $( `` ).val(data.uuid); - $('.files').append(input); + $(".files").append(input); }); - this.on('removedfile', (file) => { + this.on("removedfile", (file) => { if (file.name in filenameDict) { $(`#${filenameDict[file.name]}`).remove(); } - if ($dropzone.data('remove-url') && $dropzone.data('csrf')) { - $.post($dropzone.data('remove-url'), { + if ($dropzone.data("remove-url") && $dropzone.data("csrf")) { + $.post($dropzone.data("remove-url"), { file: filenameDict[file.name], - _csrf: $dropzone.data('csrf') + _csrf: $dropzone.data("csrf"), }); } }); - this.on('addedfile', (file) => { - if (file.size / (1000 * 1000) > $dropzone.data('max-size')) { - this.removeFile(file) + this.on("addedfile", (file) => { + if (file.size / (1000 * 1000) > $dropzone.data("max-size")) { + this.removeFile(file); if (maxFileTooltips) { - $('.maxfilesize.ui.red.message').text(maxFileTooltips) - $('.maxfilesize.ui.red.message').css('display', 'block') + $(".maxfilesize.ui.red.message").text(maxFileTooltips); + $(".maxfilesize.ui.red.message").css("display", "block"); } } else { if (maxFileTooltips) { - $('.maxfilesize.ui.red.message').css('display', 'none') + $(".maxfilesize.ui.red.message").css("display", "none"); } } - }); - this.on('maxfilesexceeded', (file) => { - this.removeFile(file) + this.on("maxfilesexceeded", (file) => { + this.removeFile(file); if (maxSizeTooltips) { - $('.maxfilesize.ui.red.message').text(maxSizeTooltips) - $('.maxfilesize.ui.red.message').css('display', 'block') + $(".maxfilesize.ui.red.message").text(maxSizeTooltips); + $(".maxfilesize.ui.red.message").css("display", "block"); } - }) - - } + }); + }, }); } // Helpers. - $('.delete-button').on('click', showDeletePopup); - $('.add-all-button').on('click', showAddAllPopup); - $('.link-action').on('click', linkAction); - $('.link-email-action').on('click', linkEmailAction); + $(".delete-button").on("click", showDeletePopup); + $(".add-all-button").on("click", showAddAllPopup); + $(".link-action").on("click", linkAction); + $(".link-email-action").on("click", linkEmailAction); - $('.delete-branch-button').on('click', showDeletePopup); + $(".delete-branch-button").on("click", showDeletePopup); - $('.undo-button').on('click', function () { + $(".undo-button").on("click", function () { const $this = $(this); - $.post($this.data('url'), { + $.post($this.data("url"), { _csrf: csrf, - id: $this.data('id') + id: $this.data("id"), }).done((data) => { window.location.href = data.redirect; }); }); - $('.show-panel.button').on('click', function () { - $($(this).data('panel')).show(); + $(".show-panel.button").on("click", function () { + $($(this).data("panel")).show(); }); - $('.show-modal.button').on('click', function () { - $($(this).data('modal')).modal('show'); + $(".show-modal.button").on("click", function () { + $($(this).data("modal")).modal("show"); }); - $('.delete-post.button').on('click', function () { + $(".delete-post.button").on("click", function () { const $this = $(this); - $.post($this.data('request-url'), { - _csrf: csrf + $.post($this.data("request-url"), { + _csrf: csrf, }).done(() => { - window.location.href = $this.data('done-url'); + window.location.href = $this.data("done-url"); }); }); // Set anchor. - $('.markdown').each(function () { + $(".markdown").each(function () { $(this) - .find('h1, h2, h3, h4, h5, h6') + .find("h1, h2, h3, h4, h5, h6") .each(function () { let node = $(this); node = node.wrap('
'); node.append( `${svg('octicon-link', 16)}` + node.attr("id") + )}">${svg("octicon-link", 16)}` ); }); }); - $('.issue-checkbox').on('click', () => { - const numChecked = $('.issue-checkbox').children('input:checked').length; + $(".issue-checkbox").on("click", () => { + const numChecked = $(".issue-checkbox").children("input:checked").length; if (numChecked > 0) { - $('#issue-filters').addClass('hide'); - $('#issue-actions').removeClass('hide'); + $("#issue-filters").addClass("hide"); + $("#issue-actions").removeClass("hide"); } else { - $('#issue-filters').removeClass('hide'); - $('#issue-actions').addClass('hide'); + $("#issue-filters").removeClass("hide"); + $("#issue-actions").addClass("hide"); } }); - $('.issue-action').on('click', function () { + $(".issue-action").on("click", function () { let { action } = this.dataset; let { elementId } = this.dataset; - const issueIDs = $('.issue-checkbox') - .children('input:checked') + const issueIDs = $(".issue-checkbox") + .children("input:checked") .map(function () { return this.dataset.issueId; }) .get() .join(); - console.log("this:", this) + console.log("this:", this); const { url } = this.dataset; - if (elementId === '0' && url.substr(-9) === '/assignee') { - elementId = ''; - action = 'clear'; + if (elementId === "0" && url.substr(-9) === "/assignee") { + elementId = ""; + action = "clear"; } - updateIssuesMeta(url, action, issueIDs, elementId, '').then(() => { + updateIssuesMeta(url, action, issueIDs, elementId, "").then(() => { // NOTICE: This reset of checkbox state targets Firefox caching behaviour, as the checkboxes stay checked after reload - if (action === 'close' || action === 'open') { + if (action === "close" || action === "open") { // uncheck all checkboxes $('.issue-checkbox input[type="checkbox"]').each((_, e) => { e.checked = false; @@ -2945,19 +2855,19 @@ $(document).ready(async () => { .first() .each((_, e) => { e.checked = false; - $(e).trigger('click'); + $(e).trigger("click"); }); - $('.resolve-conversation').on('click', function (e) { + $(".resolve-conversation").on("click", function (e) { e.preventDefault(); - const id = $(this).data('comment-id'); - const action = $(this).data('action'); - const url = $(this).data('update-url'); + const id = $(this).data("comment-id"); + const action = $(this).data("action"); + const url = $(this).data("update-url"); $.post(url, { _csrf: csrf, action, - comment_id: id + comment_id: id, }).then(reload); }); @@ -2988,10 +2898,11 @@ $(document).ready(async () => { initVueModel(); initVueDataAnalysis(); initVueWxAutorize(); + initVueselectDataset(); initTeamSettings(); initCtrlEnterSubmit(); initNavbarContentToggle(); - // initTopicbar();vim + // initTopicbar();vim // closeTopicbar(); initU2FAuth(); initU2FRegister(); @@ -3010,22 +2921,22 @@ $(document).ready(async () => { initContextMenu(); // Repo clone url. - if ($('#repo-clone-url').length > 0) { - switch (localStorage.getItem('repo-clone-protocol')) { - case 'ssh': - if ($('#repo-clone-ssh').length === 0) { - $('#repo-clone-https').trigger('click'); + if ($("#repo-clone-url").length > 0) { + switch (localStorage.getItem("repo-clone-protocol")) { + case "ssh": + if ($("#repo-clone-ssh").length === 0) { + $("#repo-clone-https").trigger("click"); } break; default: - $('#repo-clone-https').trigger('click'); + $("#repo-clone-https").trigger("click"); break; } } const routes = { - 'div.user.settings': initUserSettings, - 'div.repository.settings.collaboration': initRepositoryCollaboration + "div.user.settings": initUserSettings, + "div.repository.settings.collaboration": initRepositoryCollaboration, }; let selector; @@ -3036,32 +2947,38 @@ $(document).ready(async () => { } } - const $cloneAddr = $('#clone_addr'); - $cloneAddr.on('change', () => { - const $repoName = $('#alias'); - const $owner = $('#ownerDropdown div.text').attr("title") - const $urlAdd = location.href.split('/')[0] + '//' + location.href.split('/')[2] + const $cloneAddr = $("#clone_addr"); + $cloneAddr.on("change", () => { + const $repoName = $("#alias"); + const $owner = $("#ownerDropdown div.text").attr("title"); + const $urlAdd = + location.href.split("/")[0] + "//" + location.href.split("/")[2]; if ($cloneAddr.val().length > 0 && $repoName.val().length === 0) { // Only modify if repo_name input is blank - const repoValue = $cloneAddr.val().match(/^(.*\/)?((.+?)(\.git)?)$/)[3] + const repoValue = $cloneAddr.val().match(/^(.*\/)?((.+?)(\.git)?)$/)[3]; $repoName.val($cloneAddr.val().match(/^(.*\/)?((.+?)(\.git)?)$/)[3]); - $.get(`${window.config.AppSubUrl}/repo/check_name?q=${repoValue}&owner=${$owner}`, (data) => { - const repo_name = data.name - $('#repo_name').val(repo_name) - repo_name && $('#repo_name').parent().removeClass('error') - $('#repoAdress').css("display", "flex") - $('#repoAdress span').text($urlAdd + '/' + $owner + '/' + $('#repo_name').val() + '.git') - $('#repo_name').attr("placeholder", "") - }) + $.get( + `${window.config.AppSubUrl}/repo/check_name?q=${repoValue}&owner=${$owner}`, + (data) => { + const repo_name = data.name; + $("#repo_name").val(repo_name); + repo_name && $("#repo_name").parent().removeClass("error"); + $("#repoAdress").css("display", "flex"); + $("#repoAdress span").text( + $urlAdd + "/" + $owner + "/" + $("#repo_name").val() + ".git" + ); + $("#repo_name").attr("placeholder", ""); + } + ); } }); // parallel init of lazy-loaded features await Promise.all([ - highlight(document.querySelectorAll('pre code')), + highlight(document.querySelectorAll("pre code")), initGitGraph(), initClipboard(), - initUserHeatmap() + initUserHeatmap(), ]); }); @@ -3082,10 +2999,10 @@ function deSelect() { } function selectRange($list, $select, $from) { - $list.removeClass('active'); + $list.removeClass("active"); if ($from) { - let a = parseInt($select.attr('rel').substr(1)); - let b = parseInt($from.attr('rel').substr(1)); + let a = parseInt($select.attr("rel").substr(1)); + let b = parseInt($from.attr("rel").substr(1)); let c; if (a !== b) { if (a > b) { @@ -3097,29 +3014,27 @@ function selectRange($list, $select, $from) { for (let i = a; i <= b; i++) { classes.push(`.L${i}`); } - $list.filter(classes.join(',')).addClass('active'); + $list.filter(classes.join(",")).addClass("active"); changeHash(`#L${a}-L${b}`); return; } } - $select.addClass('active'); - changeHash(`#${$select.attr('rel')}`); + $select.addClass("active"); + changeHash(`#${$select.attr("rel")}`); } $(() => { // Warn users that try to leave a page after entering data into a form. // Except on sign-in pages, and for forms marked as 'ignore-dirty'. - if ($('.user.signin').length === 0) { - $('form:not(.ignore-dirty)').areYouSure(); + if ($(".user.signin").length === 0) { + $("form:not(.ignore-dirty)").areYouSure(); } // Parse SSH Key - $('#ssh-key-content').on('change paste keyup', function () { - const arrays = $(this) - .val() - .split(' '); - const $title = $('#ssh-key-title'); - if ($title.val() === '' && arrays.length === 3 && arrays[2] !== '') { + $("#ssh-key-content").on("change paste keyup", function () { + const arrays = $(this).val().split(" "); + const $title = $("#ssh-key-title"); + if ($title.val() === "" && arrays.length === 3 && arrays[2] !== "") { $title.val(arrays[2]); } }); @@ -3127,72 +3042,72 @@ $(() => { function showDeletePopup() { const $this = $(this); - let filter = ''; - if ($this.attr('id')) { - filter += `#${$this.attr('id')}`; + let filter = ""; + if ($this.attr("id")) { + filter += `#${$this.attr("id")}`; } const dialog = $(`.delete.modal${filter}`); - dialog.find('.name').text($this.data('name')); + dialog.find(".name").text($this.data("name")); dialog .modal({ closable: false, onApprove() { - if ($this.data('type') === 'form') { - $($this.data('form')).trigger('submit'); + if ($this.data("type") === "form") { + $($this.data("form")).trigger("submit"); return; } - $.post($this.data('url'), { + $.post($this.data("url"), { _csrf: csrf, - id: $this.data('id') + id: $this.data("id"), }).done((data) => { window.location.href = data.redirect; }); - } + }, }) - .modal('show'); + .modal("show"); return false; } function showAddAllPopup() { const $this = $(this); - let filter = ''; - if ($this.attr('id')) { - filter += `#${$this.attr('id')}`; + let filter = ""; + if ($this.attr("id")) { + filter += `#${$this.attr("id")}`; } const dialog = $(`.addall.modal${filter}`); - dialog.find('.name').text($this.data('name')); + dialog.find(".name").text($this.data("name")); dialog .modal({ closable: false, onApprove() { - if ($this.data('type') === 'form') { - $($this.data('form')).trigger('submit'); + if ($this.data("type") === "form") { + $($this.data("form")).trigger("submit"); return; } - $.post($this.data('url'), { + $.post($this.data("url"), { _csrf: csrf, - id: $this.data('id') + id: $this.data("id"), }).done((data) => { window.location.href = data.redirect; }); - } + }, }) - .modal('show'); + .modal("show"); return false; } function linkAction(e) { e.preventDefault(); const $this = $(this); - const redirect = $this.data('redirect'); - $.post($this.data('url'), { - _csrf: csrf + const redirect = $this.data("redirect"); + $.post($this.data("url"), { + _csrf: csrf, }).done((data) => { if (data.redirect) { window.location.href = data.redirect; @@ -3206,87 +3121,87 @@ function linkAction(e) { function linkEmailAction(e) { const $this = $(this); - $('#form-uid').val($this.data('uid')); - $('#form-email').val($this.data('email')); - $('#form-primary').val($this.data('primary')); - $('#form-activate').val($this.data('activate')); - $('#form-uid').val($this.data('uid')); - $('#change-email-modal').modal('show'); + $("#form-uid").val($this.data("uid")); + $("#form-email").val($this.data("email")); + $("#form-primary").val($this.data("primary")); + $("#form-activate").val($this.data("activate")); + $("#form-uid").val($this.data("uid")); + $("#change-email-modal").modal("show"); e.preventDefault(); } function initVueComponents() { - const vueDelimeters = ['${', '}']; + const vueDelimeters = ["${", "}"]; - Vue.component('repo-search', { + Vue.component("repo-search", { delimiters: vueDelimeters, props: { searchLimit: { type: Number, - default: 10 + default: 10, }, suburl: { type: String, - required: true + required: true, }, uid: { type: Number, - required: true + required: true, }, organizations: { type: Array, - default: [] + default: [], }, isOrganization: { type: Boolean, - default: true + default: true, }, canCreateOrganization: { type: Boolean, - default: false + default: false, }, organizationsTotalCount: { type: Number, - default: 0 + default: 0, }, moreReposLink: { type: String, - default: '' - } + default: "", + }, }, data() { const params = new URLSearchParams(window.location.search); - let tab = params.get('repo-search-tab'); + let tab = params.get("repo-search-tab"); if (!tab) { - tab = 'repos'; + tab = "repos"; } - let reposFilter = params.get('repo-search-filter'); + let reposFilter = params.get("repo-search-filter"); if (!reposFilter) { - reposFilter = 'all'; + reposFilter = "all"; } - let privateFilter = params.get('repo-search-private'); + let privateFilter = params.get("repo-search-private"); if (!privateFilter) { - privateFilter = 'both'; + privateFilter = "both"; } - let archivedFilter = params.get('repo-search-archived'); + let archivedFilter = params.get("repo-search-archived"); if (!archivedFilter) { - archivedFilter = 'unarchived'; + archivedFilter = "unarchived"; } - let searchQuery = params.get('repo-search-query'); + let searchQuery = params.get("repo-search-query"); if (!searchQuery) { - searchQuery = ''; + searchQuery = ""; } let page = 1; try { - page = parseInt(params.get('repo-search-page')); + page = parseInt(params.get("repo-search-page")); } catch { // noop } @@ -3309,21 +3224,21 @@ function initVueComponents() { counts: {}, repoTypes: { all: { - searchMode: '' + searchMode: "", }, forks: { - searchMode: 'fork' + searchMode: "fork", }, mirrors: { - searchMode: 'mirror' + searchMode: "mirror", }, sources: { - searchMode: 'source' + searchMode: "source", }, collaborative: { - searchMode: 'collaborative' - } - } + searchMode: "collaborative", + }, + }, }; }, @@ -3332,39 +3247,35 @@ function initVueComponents() { return ( this.repos.length > 0 && this.repos.length < - this.counts[ - `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}` - ] + this.counts[ + `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}` + ] ); }, searchURL() { return `${ this.suburl - }/api/v1/repos/search?sort=updated&order=desc&uid=${this.uid}&q=${ + }/api/v1/repos/search?sort=updated&order=desc&uid=${this.uid}&q=${ this.searchQuery - }&page=${this.page}&limit=${this.searchLimit}&mode=${ + }&page=${this.page}&limit=${this.searchLimit}&mode=${ this.repoTypes[this.reposFilter].searchMode - }${this.reposFilter !== 'all' ? '&exclusive=1' : ''}${ - this.archivedFilter === 'archived' ? '&archived=true' : '' - }${this.archivedFilter === 'unarchived' ? '&archived=false' : ''}${ - this.privateFilter === 'private' ? '&onlyPrivate=true' : '' - }${this.privateFilter === 'public' ? '&private=false' : ''}`; + }${this.reposFilter !== "all" ? "&exclusive=1" : ""}${ + this.archivedFilter === "archived" ? "&archived=true" : "" + }${this.archivedFilter === "unarchived" ? "&archived=false" : ""}${ + this.privateFilter === "private" ? "&onlyPrivate=true" : "" + }${this.privateFilter === "public" ? "&private=false" : ""}`; }, repoTypeCount() { return this.counts[ `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}` ]; - } + }, }, mounted() { this.searchRepos(this.reposFilter); - $(this.$el) - .find('.poping.up') - .popup(); - $(this.$el) - .find('.dropdown') - .dropdown(); + $(this.$el).find(".poping.up").popup(); + $(this.$el).find(".dropdown").dropdown(); this.setCheckboxes(); const self = this; Vue.nextTick(() => { @@ -3379,33 +3290,33 @@ function initVueComponents() { setCheckboxes() { switch (this.archivedFilter) { - case 'unarchived': - $('#archivedFilterCheckbox').checkbox('set unchecked'); + case "unarchived": + $("#archivedFilterCheckbox").checkbox("set unchecked"); break; - case 'archived': - $('#archivedFilterCheckbox').checkbox('set checked'); + case "archived": + $("#archivedFilterCheckbox").checkbox("set checked"); break; - case 'both': - $('#archivedFilterCheckbox').checkbox('set indeterminate'); + case "both": + $("#archivedFilterCheckbox").checkbox("set indeterminate"); break; default: - this.archivedFilter = 'unarchived'; - $('#archivedFilterCheckbox').checkbox('set unchecked'); + this.archivedFilter = "unarchived"; + $("#archivedFilterCheckbox").checkbox("set unchecked"); break; } switch (this.privateFilter) { - case 'public': - $('#privateFilterCheckbox').checkbox('set unchecked'); + case "public": + $("#privateFilterCheckbox").checkbox("set unchecked"); break; - case 'private': - $('#privateFilterCheckbox').checkbox('set checked'); + case "private": + $("#privateFilterCheckbox").checkbox("set checked"); break; - case 'both': - $('#privateFilterCheckbox').checkbox('set indeterminate'); + case "both": + $("#privateFilterCheckbox").checkbox("set indeterminate"); break; default: - this.privateFilter = 'both'; - $('#privateFilterCheckbox').checkbox('set indeterminate'); + this.privateFilter = "both"; + $("#privateFilterCheckbox").checkbox("set indeterminate"); break; } }, @@ -3425,58 +3336,58 @@ function initVueComponents() { updateHistory() { const params = new URLSearchParams(window.location.search); - if (this.tab === 'repos') { - params.delete('repo-search-tab'); + if (this.tab === "repos") { + params.delete("repo-search-tab"); } else { - params.set('repo-search-tab', this.tab); + params.set("repo-search-tab", this.tab); } - if (this.reposFilter === 'all') { - params.delete('repo-search-filter'); + if (this.reposFilter === "all") { + params.delete("repo-search-filter"); } else { - params.set('repo-search-filter', this.reposFilter); + params.set("repo-search-filter", this.reposFilter); } - if (this.privateFilter === 'both') { - params.delete('repo-search-private'); + if (this.privateFilter === "both") { + params.delete("repo-search-private"); } else { - params.set('repo-search-private', this.privateFilter); + params.set("repo-search-private", this.privateFilter); } - if (this.archivedFilter === 'unarchived') { - params.delete('repo-search-archived'); + if (this.archivedFilter === "unarchived") { + params.delete("repo-search-archived"); } else { - params.set('repo-search-archived', this.archivedFilter); + params.set("repo-search-archived", this.archivedFilter); } - if (this.searchQuery === '') { - params.delete('repo-search-query'); + if (this.searchQuery === "") { + params.delete("repo-search-query"); } else { - params.set('repo-search-query', this.searchQuery); + params.set("repo-search-query", this.searchQuery); } if (this.page === 1) { - params.delete('repo-search-page'); + params.delete("repo-search-page"); } else { - params.set('repo-search-page', `${this.page}`); + params.set("repo-search-page", `${this.page}`); } - window.history.replaceState({}, '', `?${params.toString()}`); + window.history.replaceState({}, "", `?${params.toString()}`); }, toggleArchivedFilter() { switch (this.archivedFilter) { - case 'both': - this.archivedFilter = 'unarchived'; + case "both": + this.archivedFilter = "unarchived"; break; - case 'unarchived': - this.archivedFilter = 'archived'; + case "unarchived": + this.archivedFilter = "archived"; break; - case 'archived': - this.archivedFilter = 'both'; + case "archived": + this.archivedFilter = "both"; break; default: - this.archivedFilter = 'unarchived'; + this.archivedFilter = "unarchived"; break; } this.page = 1; @@ -3492,17 +3403,17 @@ function initVueComponents() { togglePrivateFilter() { switch (this.privateFilter) { - case 'both': - this.privateFilter = 'public'; + case "both": + this.privateFilter = "public"; break; - case 'public': - this.privateFilter = 'private'; + case "public": + this.privateFilter = "private"; break; - case 'private': - this.privateFilter = 'both'; + case "private": + this.privateFilter = "both"; break; default: - this.privateFilter = 'both'; + this.privateFilter = "both"; break; } this.page = 1; @@ -3535,11 +3446,11 @@ function initVueComponents() { showArchivedRepo(repo) { switch (this.archivedFilter) { - case 'both': + case "both": return true; - case 'unarchived': + case "unarchived": return !repo.archived; - case 'archived': + case "archived": return repo.archived; default: return !repo.archived; @@ -3548,11 +3459,11 @@ function initVueComponents() { showPrivateRepo(repo) { switch (this.privateFilter) { - case 'both': + case "both": return true; - case 'public': + case "public": return !repo.private; - case 'private': + case "private": return repo.private; default: return true; @@ -3561,13 +3472,13 @@ function initVueComponents() { showFilteredRepo(repo) { switch (this.reposFilter) { - case 'sources': + case "sources": return repo.owner.id === this.uid && !repo.mirror && !repo.fork; - case 'forks': + case "forks": return repo.owner.id === this.uid && !repo.mirror && repo.fork; - case 'mirrors': + case "mirrors": return repo.mirror; - case 'collaborative': + case "collaborative": return repo.owner.id !== this.uid && !repo.mirror; default: return true; @@ -3594,11 +3505,11 @@ function initVueComponents() { $.getJSON(searchedURL, (result, _textStatus, request) => { if (searchedURL === self.searchURL) { self.repos = result.data; - const count = request.getResponseHeader('X-Total-Count'); + const count = request.getResponseHeader("X-Total-Count"); if ( - searchedQuery === '' && - searchedMode === '' && - self.archivedFilter === 'both' + searchedQuery === "" && + searchedMode === "" && + self.archivedFilter === "both" ) { self.reposTotalCount = count; } @@ -3619,38 +3530,36 @@ function initVueComponents() { repoClass(repo) { if (repo.fork) { - return 'octicon-repo-forked'; + return "octicon-repo-forked"; } if (repo.mirror) { - return 'octicon-repo-clone'; + return "octicon-repo-clone"; } if (repo.template) { - return `octicon-repo-template${repo.private ? '-private' : ''}`; + return `octicon-repo-template${repo.private ? "-private" : ""}`; } if (repo.private) { - return 'octicon-lock'; + return "octicon-lock"; } - return 'octicon-repo'; - } - } + return "octicon-repo"; + }, + }, }); } function initCtrlEnterSubmit() { - $('.js-quick-submit').on('keydown', function (e) { + $(".js-quick-submit").on("keydown", function (e) { if ( ((e.ctrlKey && !e.altKey) || e.metaKey) && (e.keyCode === 13 || e.keyCode === 10) ) { - $(this) - .closest('form') - .trigger('submit'); + $(this).closest("form").trigger("submit"); } }); } function initVueApp() { - const el = document.getElementById('app'); + const el = document.getElementById("app"); if (!el) { return; } @@ -3658,198 +3567,223 @@ function initVueApp() { initVueComponents(); new Vue({ - delimiters: ['${', '}'], + delimiters: ["${", "}"], el, data: { - page: parseInt(new URLSearchParams(window.location.search).get('page')), + page: parseInt(new URLSearchParams(window.location.search).get("page")), searchLimit: Number( - (document.querySelector('meta[name=_search_limit]') || {}).content + (document.querySelector("meta[name=_search_limit]") || {}).content ), page: 1, suburl: AppSubUrl, uid: Number( - (document.querySelector('meta[name=_context_uid]') || {}).content + (document.querySelector("meta[name=_context_uid]") || {}).content ), activityTopAuthors: window.ActivityTopAuthors || [], - localHref: '' + localHref: "", }, components: { - ActivityTopAuthors + ActivityTopAuthors, }, mounted() { - this.page = parseInt(new URLSearchParams(window.location.search).get('page')) - this.localHref = location.href - + this.page = parseInt( + new URLSearchParams(window.location.search).get("page") + ); + this.localHref = location.href; }, methods: { handleCurrentChange: function (val) { - const searchParams = new URLSearchParams(window.location.search) + const searchParams = new URLSearchParams(window.location.search); if (!window.location.search) { - window.location.href = this.localHref + '?page=' + val - } else if (searchParams.has('page')) { - window.location.href = this.localHref.replace(/page=[0-9]+/g, 'page=' + val) + window.location.href = this.localHref + "?page=" + val; + } else if (searchParams.has("page")) { + window.location.href = this.localHref.replace( + /page=[0-9]+/g, + "page=" + val + ); } else { - window.location.href = location.href + '&page=' + val + window.location.href = location.href + "&page=" + val; } - this.page = val - } - } + this.page = val; + }, + }, }); } function initVueUploader() { - const el = document.getElementById('minioUploader'); + const el = document.getElementById("minioUploader"); if (!el) { return; } new Vue({ - el: '#minioUploader', + el: "#minioUploader", components: { MinioUploader }, - template: '' + template: "", }); } function initVueEditAbout() { - const el = document.getElementById('about-desc'); + const el = document.getElementById("about-desc"); if (!el) { return; } new Vue({ - el: '#about-desc', - render: h => h(EditAboutInfo) + el: "#about-desc", + render: (h) => h(EditAboutInfo), }); } function initVueDataset() { - if ($('#dataset_check').length) { - if (location.search.indexOf('recommend=true') !== -1) { - $('#dataset_check').checkbox('set checked') + if ($("#dataset_check").length) { + if (location.search.indexOf("recommend=true") !== -1) { + $("#dataset_check").checkbox("set checked"); } else { - $('#dataset_check').checkbox('set unchecked') + $("#dataset_check").checkbox("set unchecked"); } - $('#dataset_check').checkbox({ + $("#dataset_check").checkbox({ onChecked: function () { if (location.search) { - const params = new URLSearchParams(location.search) - if (params.has('recommend')) { - params.delete('recommend') - location.href = AppSubUrl + location.pathname + '?' + params.toString() + '&recommend=true' + const params = new URLSearchParams(location.search); + if (params.has("recommend")) { + params.delete("recommend"); + location.href = + AppSubUrl + + location.pathname + + "?" + + params.toString() + + "&recommend=true"; } else { - location.href = `${window.config.AppSubUrl}/admin/datasets${location.search}&recommend=true` + location.href = `${window.config.AppSubUrl}/admin/datasets${location.search}&recommend=true`; } } else { - location.href = `${window.config.AppSubUrl}/admin/datasets?recommend=true` + location.href = `${window.config.AppSubUrl}/admin/datasets?recommend=true`; } }, onUnchecked: function () { - if (location.search == '?recommend=true') { - location.href = AppSubUrl + location.pathname + if (location.search == "?recommend=true") { + location.href = AppSubUrl + location.pathname; } else { - const params = new URLSearchParams(location.search) - params.delete('recommend') - location.href = AppSubUrl + location.pathname + '?' + params.toString() + const params = new URLSearchParams(location.search); + params.delete("recommend"); + location.href = + AppSubUrl + location.pathname + "?" + params.toString(); } }, - }) + }); } - $('.set_dataset').on('click', function () { + $(".set_dataset").on("click", function () { const $this = $(this); - let link = $this.data('url') + let link = $this.data("url"); $.ajax({ url: link, - type: 'PUT', + type: "PUT", success: function (res) { - console.log(res) + console.log(res); if (res.Code == 0) { - window.location.href = '/admin/datasets' + window.location.href = "/admin/datasets"; } else { - $('.ui.negative.message').text(res.Message).show().delay(1500).fadeOut(); + $(".ui.negative.message") + .text(res.Message) + .show() + .delay(1500) + .fadeOut(); } }, error: function (xhr) { // 隐藏 loading // 只有请求不正常(状态码不为200)才会执行 - $('.ui.negative.message').html(xhr.responseText).show().delay(1500).fadeOut(); - console.log(xhr) + $(".ui.negative.message") + .html(xhr.responseText) + .show() + .delay(1500) + .fadeOut(); + console.log(xhr); }, complete: function (xhr) { // $("#mask").css({"display":"none","z-index":"1"}) - } - }) - + }, + }); }); - const el = document.getElementById('dataset-base'); + const el = document.getElementById("dataset-base"); if (!el) { return; } let link = $('#square-link').data('link') let repolink = $('.dataset-repolink').data('repolink') - let cloudbrainType = $('.dataset-repolink').data('cloudranin-type') + let datasetType = $('.dataset-repolink').data('dataset-type') const clearBtn = document.getElementsByClassName("clear_dataset_value"); - const params = new URLSearchParams(location.search) + const params = new URLSearchParams(location.search); for (let i = 0; i < clearBtn.length; i++) { - clearBtn[i].addEventListener('click', function (e) { - let searchType = e.target.getAttribute("data-clear-value") + clearBtn[i].addEventListener("click", function (e) { + let searchType = e.target.getAttribute("data-clear-value"); if (params.has(searchType)) { - params.delete(searchType) - let clearSearch = params.toString() - location.href = link + '?' + clearSearch + params.delete(searchType); + let clearSearch = params.toString(); + location.href = link + "?" + clearSearch; } - }) + }); } - const items = [] - const zipStatus = [] - $('#dataset-range-value').find('.item').each(function () { - items.push($(this).data('private')) - zipStatus.push($(this).data('decompress-state')) - }) - let num_stars = $('#dataset-range-value').data('num-stars') - let star_active = $('#dataset-range-value').data('star-active') - const ruleForm = {} - if (document.getElementById('dataset-edit-value')) { - let $this = $('#dataset-edit-value') - ruleForm.title = $this.data('edit-title') || '' - ruleForm.description = $this.data('edit-description') || '' - ruleForm.category = $this.data('edit-category') || '' - ruleForm.task = $this.data('edit-task') || '' - ruleForm.license = $this.data('edit-license') || '' - ruleForm.id = $this.data('edit-id') || '' - ruleForm._csrf = csrf + const items = []; + const zipStatus = []; + $("#dataset-range-value") + .find(".item") + .each(function () { + items.push($(this).data("private")); + zipStatus.push($(this).data("decompress-state")); + }); + let num_stars = $("#dataset-range-value").data("num-stars"); + let star_active = $("#dataset-range-value").data("star-active"); + const ruleForm = {}; + if (document.getElementById("dataset-edit-value")) { + let $this = $("#dataset-edit-value"); + ruleForm.title = $this.data("edit-title") || ""; + ruleForm.description = $this.data("edit-description") || ""; + ruleForm.category = $this.data("edit-category") || ""; + ruleForm.task = $this.data("edit-task") || ""; + ruleForm.license = $this.data("edit-license") || ""; + ruleForm.id = $this.data("edit-id") || ""; + ruleForm._csrf = csrf; } - const starItems = [] - const starActives = [] - $('#datasets-square-range-value').find('.item').each(function () { - starItems.push($(this).data('num-stars')) - starActives.push($(this).data('star-active')) - }) - const taskLists = [] - const licenseLists = [] - $('#task-square-range-value').find('.item').each(function () { - taskLists.push($(this).data('task')) - }) - $('#task-square-range-value').find('.item').each(function () { - licenseLists.push($(this).data('license')) - }) - let dataset_file_desc - if (document.getElementById('dataset-file-desc')) { - dataset_file_desc = document.getElementById('dataset-file-desc').value + const starItems = []; + const starActives = []; + $("#datasets-square-range-value") + .find(".item") + .each(function () { + starItems.push($(this).data("num-stars")); + starActives.push($(this).data("star-active")); + }); + const taskLists = []; + const licenseLists = []; + $("#task-square-range-value") + .find(".item") + .each(function () { + taskLists.push($(this).data("task")); + }); + $("#task-square-range-value") + .find(".item") + .each(function () { + licenseLists.push($(this).data("license")); + }); + let dataset_file_desc; + if (document.getElementById("dataset-file-desc")) { + dataset_file_desc = document.getElementById("dataset-file-desc").value; } new Vue({ - delimiters: ['${', '}'], + delimiters: ["${", "}"], el, data: { suburl: AppSubUrl, - url: '', + url: "", checked: false, clusterFlag: false, type: 0, - desc: '', - descfile: '', - datasetType: '', + desc: "", + descfile: "", + datasetType: "", privates: [], zipStatus: [], starItems: [], @@ -3863,42 +3797,46 @@ function initVueDataset() { star_active: false, num_stars: 0, dialogVisible: false, - activeName: 'first', - searchDataItem: '', + activeName: "first", + searchDataItem: "", currentRepoDataset: [], myDataset: [], publicDataset: [], myFavoriteDataset: [], page: 1, totalnums: 0, - repolink: '', - cloudbrainType: 0, - dataset_uuid: '', - dataset_name: '', + repolink: "", + datasetType: 0, + dataset_uuid: "", + dataset_name: "", loadingDataIndex: false, timer: null, ruleForm: { - title: '', - description: '', - category: '', - task: '', - license: '', + title: "", + description: "", + category: "", + task: "", + license: "", _csrf: csrf, - }, ruleForm1: { - title: '', - description: '', - category: '', - task: '', - license: '', - _csrf: '', - id: '' + title: "", + description: "", + category: "", + task: "", + license: "", + _csrf: "", + id: "", }, rules: { title: [ - { required: true, message: '请输入数据集名称', trigger: 'blur' }, - { min: 1, max: 100, message: '长度在 1 到 100 个字符', trigger: 'blur' }, + { required: true, message: "请输入数据集名称", trigger: "blur" }, + { + min: 1, + max: 100, + message: "长度在 1 到 100 个字符", + trigger: "blur", + }, // {required:true,message:'test',pattern:'/^[a-zA-Z0-9-_]{1,100}[^-]$/',trigger:'blur'}, { validator: (rule, value, callback) => { @@ -3907,17 +3845,22 @@ function initVueDataset() { } else { callback(); } - }, trigger: 'blur' - } + }, + trigger: "blur", + }, ], description: [ - { required: true, message: '请输入数据集描述详情', trigger: 'blur' } + { required: true, message: "请输入数据集描述详情", trigger: "blur" }, ], category: [ - { required: true, message: '请选择分类', trigger: 'change' } + { required: true, message: "请选择分类", trigger: "change" }, ], task: [ - { required: true, message: '请选择研究方向/应用领域', trigger: 'change' } + { + required: true, + message: "请选择研究方向/应用领域", + trigger: "change", + }, ], // license: [ // { required: true, message: '请选择活动区域', trigger: 'change' } @@ -3925,32 +3868,33 @@ function initVueDataset() { }, }, components: { - MinioUploader + MinioUploader, }, mounted() { - this.getTypeList() + this.getTypeList(); if (!!document.getElementById('dataset-repolink-init')) { - this.cloudbrainType = location.href.indexOf('cloudbrain') !== -1 ? 0 : 1 - this.getCurrentRepoDataset(this.repolink, this.cloudbrainType) + // this.datasetType = location.href.indexOf('cloudbrain') !== -1 ? 0 : 1 + this.datasetType = $('#dataset-repolink-init').data("dataset-type") + this.getCurrentRepoDataset(this.repolink, this.datasetType) } - const params = new URLSearchParams(location.search) - if (params.has('recommend') && params.get('recommend') == 'true') { - this.checked = true + const params = new URLSearchParams(location.search); + if (params.has("recommend") && params.get("recommend") == "true") { + this.checked = true; } else { - this.checked = false + this.checked = false; } }, created() { - if (document.getElementById('postPath')) { - this.url = document.getElementById('postPath').value + if (document.getElementById("postPath")) { + this.url = document.getElementById("postPath").value; } - this.privates = items - this.zipStatus = zipStatus - this.num_stars = num_stars - this.star_active = star_active - this.ruleForm1 = ruleForm + this.privates = items; + this.zipStatus = zipStatus; + this.num_stars = num_stars; + this.star_active = star_active; + this.ruleForm1 = ruleForm; // this.getEditInit() this.starItems = starItems @@ -3959,206 +3903,210 @@ function initVueDataset() { this.licenseLists = licenseLists this.descfile = dataset_file_desc this.repolink = repolink - this.cloudbrainType = cloudbrainType + this.datasetType = datasetType }, methods: { copyUrl(url) { - const cInput = document.createElement('input') - cInput.value = url - document.body.appendChild(cInput) - cInput.select() - document.execCommand('Copy') - cInput.remove() - $('body') - .toast({ - message: '复制成功!', - showProgress: 'bottom', - showIcon: 'check circle', - class: 'info', - position: 'top right', - }) - ; + const cInput = document.createElement("input"); + cInput.value = url; + document.body.appendChild(cInput); + cInput.select(); + document.execCommand("Copy"); + cInput.remove(); + $("body").toast({ + message: "复制成功!", + showProgress: "bottom", + showIcon: "check circle", + class: "info", + position: "top right", + }); }, handleCurrentChange(val) { - this.page = val + this.page = val; switch (this.activeName) { case 'first': - this.getCurrentRepoDataset(this.repolink, this.cloudbrainType) - + this.getCurrentRepoDataset(this.repolink, this.datasetType) break case 'second': - this.getMyDataset(this.repolink, this.cloudbrainType) + this.getMyDataset(this.repolink, this.datasetType) break case 'third': - this.getPublicDataset(this.repolink, this.cloudbrainType) + this.getPublicDataset(this.repolink, this.datasetType) break case 'fourth': - this.getStarDataset(this.repolink, this.cloudbrainType) + this.getStarDataset(this.repolink, this.datasetType) break } - }, handleCheckedChange(val) { if (val) { if (location.search) { - const params = new URLSearchParams(location.search) - if (params.has('recommend')) { - params.delete('recommend') - let search = params.toString() - location.href = `${AppSubUrl}/explore/datasets?${search}&recommend=${val}` + const params = new URLSearchParams(location.search); + if (params.has("recommend")) { + params.delete("recommend"); + let search = params.toString(); + location.href = `${AppSubUrl}/explore/datasets?${search}&recommend=${val}`; } else { - location.href = `${AppSubUrl}/explore/datasets${location.search}&recommend=${val}` + location.href = `${AppSubUrl}/explore/datasets${location.search}&recommend=${val}`; } } else { - location.href = `${AppSubUrl}/explore/datasets?recommend=${val}` + location.href = `${AppSubUrl}/explore/datasets?recommend=${val}`; } } else { - if (location.search == '?recommend=true') { - location.href = AppSubUrl + location.pathname + if (location.search == "?recommend=true") { + location.href = AppSubUrl + location.pathname; } else { - const params = new URLSearchParams(location.search) - params.delete('recommend') - location.href = AppSubUrl + location.pathname + '?' + params.toString() + const params = new URLSearchParams(location.search); + params.delete("recommend"); + location.href = + AppSubUrl + location.pathname + "?" + params.toString(); } } }, createDataset(formName) { - let _this = this + let _this = this; this.$refs[formName].validate((valid) => { if (valid) { - document.getElementById("mask").style.display = "block" - _this.$axios.post(_this.url, _this.qs.stringify(_this.ruleForm)).then((res) => { - if (res.data.Code === 0) { - document.getElementById("mask").style.display = "none" - location.href = _this.url.split('/create')[0] + '?type=-1' - } else { - console.log(res.data.Message) - } - document.getElementById("mask").style.display = "none" - }).catch(error => { - console.log(error) - }) - } - else { - return false + document.getElementById("mask").style.display = "block"; + _this.$axios + .post(_this.url, _this.qs.stringify(_this.ruleForm)) + .then((res) => { + if (res.data.Code === 0) { + document.getElementById("mask").style.display = "none"; + location.href = _this.url.split("/create")[0] + "?type=-1"; + } else { + console.log(res.data.Message); + } + document.getElementById("mask").style.display = "none"; + }) + .catch((error) => { + console.log(error); + }); + } else { + return false; } - }) + }); }, cancelDataset(getpage, attachment) { if (getpage && !attachment) { - if (getpage === 'create') { - location.href = this.url.split('/create')[0] + '?type=-1' - } else if (getpage === 'edit') { - location.href = this.url.split('/edit')[0] + '?type=-1' + if (getpage === "create") { + location.href = this.url.split("/create")[0] + "?type=-1"; + } else if (getpage === "edit") { + location.href = this.url.split("/edit")[0] + "?type=-1"; } else { - location.href = '/' + location.href = "/"; } + } else { + location.href = `${AppSubUrl}${attachment}/datasets`; } - else { - location.href = `${AppSubUrl}${attachment}/datasets` - - } - }, gotoUpload(repolink, datsetId) { // location.href = `${AppSubUrl}${repolink}/datasets/attachments/upload?datasetId=${datsetId}` - window.open(`${AppSubUrl}${repolink}/datasets/attachments/upload?datasetId=${datsetId}`, '_blank') + window.open( + `${AppSubUrl}${repolink}/datasets/attachments/upload?datasetId=${datsetId}`, + "_blank" + ); }, gotoDataset(datsetUrl) { - location.href = datsetUrl + location.href = datsetUrl; }, gotoAnnotate(repolink, uuid, type) { - location.href = `${AppSubUrl}${repolink}/datasets/label/${uuid}?type=${type}` + location.href = `${AppSubUrl}${repolink}/datasets/label/${uuid}?type=${type}`; }, setcluster(val) { - this.clusterFlag = val + this.clusterFlag = val; }, uploadGpu() { - this.type = 0 + this.type = 0; }, uploadNpu() { - this.type = 1 + this.type = 1; }, sortAble(dom) { - const params = new URLSearchParams(location.search) - if (params.toString() === '') { - location.href = `${location.href}?sort=${dom}Asc` - } - else if (!params.get('sort')) { - location.href = `${location.href}&sort=${dom}Asc` - } - else if (params.get('sort') === `${dom}Desc` || params.get('sort').indexOf(`${dom}`) === -1) { - params.set("sort", `${dom}Asc`) - let asc = params.toString() - location.search = asc - } - else { - params.set("sort", `${dom}Desc`) - let desc = params.toString() - location.search = desc + const params = new URLSearchParams(location.search); + if (params.toString() === "") { + location.href = `${location.href}?sort=${dom}Asc`; + } else if (!params.get("sort")) { + location.href = `${location.href}&sort=${dom}Asc`; + } else if ( + params.get("sort") === `${dom}Desc` || + params.get("sort").indexOf(`${dom}`) === -1 + ) { + params.set("sort", `${dom}Asc`); + let asc = params.toString(); + location.search = asc; + } else { + params.set("sort", `${dom}Desc`); + let desc = params.toString(); + location.search = desc; } }, sortIcon(dom, sort) { - const params = new URLSearchParams(location.search) + const params = new URLSearchParams(location.search); if (sort === "up") { - if (params.toString() === '') { - location.href = `${location.href}?sort=${dom}Asc` - } - else if (!params.get('sort')) { - location.href = `${location.href}&sort=${dom}Asc` - } else if (params.get('sort') && params.get('sort').indexOf(`${dom}Asc`) !== -1) { - params.delete('sort') - location.search = params.toString() + if (params.toString() === "") { + location.href = `${location.href}?sort=${dom}Asc`; + } else if (!params.get("sort")) { + location.href = `${location.href}&sort=${dom}Asc`; + } else if ( + params.get("sort") && + params.get("sort").indexOf(`${dom}Asc`) !== -1 + ) { + params.delete("sort"); + location.search = params.toString(); } else { - params.set("sort", `${dom}Asc`) - let asc = params.toString() - location.search = asc + params.set("sort", `${dom}Asc`); + let asc = params.toString(); + location.search = asc; } - } - else if (sort === "down") { - if (params.toString() === '') { - location.href = `${location.href}?sort=${dom}Desc` - } - else if (!params.get('sort')) { - location.href = `${location.href}&sort=${dom}Desc` - } - else if (params.get('sort') && params.get('sort').indexOf(`${dom}Desc`) !== -1) { - params.delete('sort') - location.search = params.toString() + } else if (sort === "down") { + if (params.toString() === "") { + location.href = `${location.href}?sort=${dom}Desc`; + } else if (!params.get("sort")) { + location.href = `${location.href}&sort=${dom}Desc`; + } else if ( + params.get("sort") && + params.get("sort").indexOf(`${dom}Desc`) !== -1 + ) { + params.delete("sort"); + location.search = params.toString(); } else { - params.set("sort", `${dom}Desc`) - let asc = params.toString() - location.search = asc + params.set("sort", `${dom}Desc`); + let asc = params.toString(); + location.search = asc; } - - } - }, setPrivate(uuid, privateFlag, index) { - const params = { _csrf: csrf, file: uuid, is_private: privateFlag } - this.$axios.post('/attachments/private', this.qs.stringify(params)).then((res) => { - this.$set(this.privates, index, privateFlag) - }).catch(error => { - console.log(error) - }) + const params = { _csrf: csrf, file: uuid, is_private: privateFlag }; + this.$axios + .post("/attachments/private", this.qs.stringify(params)) + .then((res) => { + this.$set(this.privates, index, privateFlag); + }) + .catch((error) => { + console.log(error); + }); }, delDataset(uuid) { - let _this = this - const params = { _csrf: csrf, file: uuid } - $('#data-dataset-delete-modal') + let _this = this; + const params = { _csrf: csrf, file: uuid }; + $("#data-dataset-delete-modal") .modal({ closable: false, onApprove() { - _this.$axios.post('/attachments/delete', _this.qs.stringify(params)).then((res) => { - // $('#'+uuid).hide() - location.reload() - }).catch(error => { - console.log(error) - }) - } + _this.$axios + .post("/attachments/delete", _this.qs.stringify(params)) + .then((res) => { + // $('#'+uuid).hide() + location.reload(); + }) + .catch((error) => { + console.log(error); + }); + }, }) - .modal('show'); + .modal("show"); }, // getEditInit(){ // if($('#dataset-edit-value')){ @@ -4172,352 +4120,357 @@ function initVueDataset() { // } // }, editDataset(formName, id) { - let _this = this - this.url = this.url.split(`/${id}`)[0] + let _this = this; + this.url = this.url.split(`/${id}`)[0]; this.$refs[formName].validate((valid) => { if (valid) { - document.getElementById("mask").style.display = "block" - _this.$axios.post(_this.url, _this.qs.stringify(_this.ruleForm1)).then((res) => { - if (res.data.Code === 0) { - document.getElementById("mask").style.display = "none" - location.href = _this.url.split('/edit')[0] + '?type=-1' - } else { - console.log(res.data.Message) - } - document.getElementById("mask").style.display = "none" - }).catch((err) => { - console.log(err) - }) - } - else { - return false + document.getElementById("mask").style.display = "block"; + _this.$axios + .post(_this.url, _this.qs.stringify(_this.ruleForm1)) + .then((res) => { + if (res.data.Code === 0) { + document.getElementById("mask").style.display = "none"; + location.href = _this.url.split("/edit")[0] + "?type=-1"; + } else { + console.log(res.data.Message); + } + document.getElementById("mask").style.display = "none"; + }) + .catch((err) => { + console.log(err); + }); + } else { + return false; } - }) - + }); }, editDatasetFile(id, backurl) { - let url = '/attachments/edit' - const params = { id: id, description: this.descfile, _csrf: csrf } + let url = "/attachments/edit"; + const params = { id: id, description: this.descfile, _csrf: csrf }; // document.getElementById("mask").style.display = "block" - this.$axios.post(url, this.qs.stringify(params)).then((res) => { - if (res.data.Code === 0) { - location.href = `${AppSubUrl}${backurl}/datasets` - } else { - console.log(res.data.Message) - } - }).catch((err) => { - console.log(err) - }) + this.$axios + .post(url, this.qs.stringify(params)) + .then((res) => { + if (res.data.Code === 0) { + location.href = `${AppSubUrl}${backurl}/datasets`; + } else { + console.log(res.data.Message); + } + }) + .catch((err) => { + console.log(err); + }); }, postStar(id, link) { if (this.star_active) { - let url = link + '/' + id + '/unstar' + let url = link + "/" + id + "/unstar"; this.$axios.put(url).then((res) => { if (res.data.Code === 0) { - this.star_active = false - this.num_stars = this.num_stars - 1 + this.star_active = false; + this.num_stars = this.num_stars - 1; } - }) + }); } else { - let url = link + '/' + id + '/star' + let url = link + "/" + id + "/star"; this.$axios.put(url).then((res) => { if (res.data.Code === 0) { - this.star_active = true - this.num_stars = this.num_stars + 1 + this.star_active = true; + this.num_stars = this.num_stars + 1; } - }) + }); } }, postSquareStar(id, link, index) { if (this.starActives[index]) { - let url = link + '/' + id + '/unstar' + let url = link + "/" + id + "/unstar"; this.$axios.put(url).then((res) => { if (res.data.Code === 0) { - this.$set(this.starActives, index, false) - this.$set(this.starItems, index, this.starItems[index] - 1) + this.$set(this.starActives, index, false); + this.$set(this.starItems, index, this.starItems[index] - 1); } - }) + }); } else { - let url = link + '/' + id + '/star' + let url = link + "/" + id + "/star"; this.$axios.put(url).then((res) => { if (res.data.Code === 0) { - this.$set(this.starActives, index, true) - this.$set(this.starItems, index, this.starItems[index] + 1) - + this.$set(this.starActives, index, true); + this.$set(this.starItems, index, this.starItems[index] + 1); } - }) + }); } }, getTypeList() { - const params = new URLSearchParams(window.location.search) - if (window.location.search && params.has('type')) { - if (params.get('type') == 0) { - this.datasetType = '0' + const params = new URLSearchParams(window.location.search); + if (window.location.search && params.has("type")) { + if (params.get("type") == 0) { + this.datasetType = "0"; } - if (params.get('type') == 1) { - this.datasetType = '1' + if (params.get("type") == 1) { + this.datasetType = "1"; } - if (params.get('type') == -1) { - this.datasetType = '-1' + if (params.get("type") == -1) { + this.datasetType = "-1"; } } else { - this.datasetType = '-1' + this.datasetType = "-1"; } }, changeDatasetType(val) { - const searchParams = new URLSearchParams(window.location.search) + const searchParams = new URLSearchParams(window.location.search); if (!window.location.search) { - window.location.href = window.location.href + '?type=' + val - } else if (searchParams.has('type')) { - window.location.href = window.location.href.replace(/type=([0-9]|-[0-9])/g, 'type=' + val) + window.location.href = window.location.href + "?type=" + val; + } else if (searchParams.has("type")) { + window.location.href = window.location.href.replace( + /type=([0-9]|-[0-9])/g, + "type=" + val + ); } else { - window.location.href = window.location.href + '&type=' + val + window.location.href = window.location.href + "&type=" + val; } - - }, gotoDatasetEidt(repolink, id) { - location.href = `${repolink}/datasets/attachments/edit/${id}` - + location.href = `${repolink}/datasets/attachments/edit/${id}`; }, handleClick(repoLink, tabName, type) { if (tabName == "first") { - this.page = 1 - this.searchDataItem = '' - this.getCurrentRepoDataset(repoLink, type) - + this.page = 1; + this.searchDataItem = ""; + this.getCurrentRepoDataset(repoLink, type); } if (tabName == "second") { - this.page = 1 - this.searchDataItem = '' - this.getMyDataset(repoLink, type) + this.page = 1; + this.searchDataItem = ""; + this.getMyDataset(repoLink, type); } if (tabName == "third") { - this.page = 1 - this.searchDataItem = '' - this.getPublicDataset(repoLink, type) + this.page = 1; + this.searchDataItem = ""; + this.getPublicDataset(repoLink, type); } if (tabName == "fourth") { - this.page = 1 - this.searchDataItem = '' - this.getStarDataset(repoLink, type) + this.page = 1; + this.searchDataItem = ""; + this.getStarDataset(repoLink, type); } }, polling(checkStatuDataset, repoLink) { this.timer = window.setInterval(() => { setTimeout(() => { - this.getDatasetStatus(checkStatuDataset, repoLink) - }, 0) - }, 15000) - + this.getDatasetStatus(checkStatuDataset, repoLink); + }, 0); + }, 15000); }, getDatasetStatus(checkStatuDataset, repoLink) { const getmap = checkStatuDataset.map((item) => { - let url = `${AppSubUrl}${repolink}/datasets/status/${item.UUID}` - return this.$axios.get(url) - }) - this.$axios.all(getmap) - .then((res) => { - let flag = res.some((item) => { - return item.data.AttachmentStatus == 1 - }) - flag && clearInterval(this.timer) - flag && this.refreshStatusDataset() - - } - ) - + let url = `${AppSubUrl}${repolink}/datasets/status/${item.UUID}`; + return this.$axios.get(url); + }); + this.$axios.all(getmap).then((res) => { + let flag = res.some((item) => { + return item.data.AttachmentStatus == 1; + }); + flag && clearInterval(this.timer); + flag && this.refreshStatusDataset(); + }); }, refreshStatusDataset() { switch (this.activeName) { case 'first': - this.getCurrentRepoDataset(this.repolink, this.cloudbrainType) + this.getCurrentRepoDataset(this.repolink, this.datasetType) break case 'second': - this.getMyDataset(this.repolink, this.cloudbrainType) + this.getMyDataset(this.repolink, this.datasetType) break case 'third': - this.getPublicDataset(this.repolink, this.cloudbrainType) + this.getPublicDataset(this.repolink, this.datasetType) break case 'fourth': - this.getStarDataset(this.repolink, this.cloudbrainType) + this.getStarDataset(this.repolink, this.datasetType) break } }, getCurrentRepoDataset(repoLink, type) { - - clearInterval(this.timer) - this.loadingDataIndex = true - let url = repoLink + '/datasets/current_repo' - this.$axios.get(url, { - params: { - type: type, - page: this.page, - q: this.searchDataItem - } - }).then((res) => { - if (res.data.result_code == '0') { - this.currentRepoDataset = JSON.parse(res.data.data) - const checkStatuDataset = this.currentRepoDataset.filter(item => item.DecompressState === 2) - if (checkStatuDataset.length > 0) { - this.polling(checkStatuDataset, repoLink) + clearInterval(this.timer); + this.loadingDataIndex = true; + let url = repoLink + "/datasets/current_repo"; + this.$axios + .get(url, { + params: { + type: type, + page: this.page, + q: this.searchDataItem, + }, + }) + .then((res) => { + if (res.data.result_code == "0") { + this.currentRepoDataset = JSON.parse(res.data.data); + const checkStatuDataset = this.currentRepoDataset.filter( + (item) => item.DecompressState === 2 + ); + if (checkStatuDataset.length > 0) { + this.polling(checkStatuDataset, repoLink); + } + this.totalnums = parseInt(res.data.count); + } else { + this.totalnums = 0; } - this.totalnums = parseInt(res.data.count) - } else { - this.totalnums = 0 - } - this.loadingDataIndex = false - }) + this.loadingDataIndex = false; + }); }, getMyDataset(repoLink, type) { - clearInterval(this.timer) - this.loadingDataIndex = true - let url = repoLink + '/datasets/my_datasets' - this.$axios.get(url, { - params: { - type: type, - page: this.page, - q: this.searchDataItem - } - }).then((res) => { - this.myDataset = JSON.parse(res.data.data) - const checkStatuDataset = this.myDataset.filter(item => item.DecompressState === 2) - if (checkStatuDataset.length > 0) { - this.polling(checkStatuDataset, repoLink) - } - this.totalnums = parseInt(res.data.count) - this.loadingDataIndex = false - }) - + clearInterval(this.timer); + this.loadingDataIndex = true; + let url = repoLink + "/datasets/my_datasets"; + this.$axios + .get(url, { + params: { + type: type, + page: this.page, + q: this.searchDataItem, + }, + }) + .then((res) => { + this.myDataset = JSON.parse(res.data.data); + const checkStatuDataset = this.myDataset.filter( + (item) => item.DecompressState === 2 + ); + if (checkStatuDataset.length > 0) { + this.polling(checkStatuDataset, repoLink); + } + this.totalnums = parseInt(res.data.count); + this.loadingDataIndex = false; + }); }, getPublicDataset(repoLink, type) { - clearInterval(this.timer) - this.loadingDataIndex = true - let url = repoLink + '/datasets/public_datasets' - this.$axios.get(url, { - params: { - type: type, - page: this.page, - q: this.searchDataItem - } - }).then((res) => { - this.publicDataset = JSON.parse(res.data.data) - const checkStatuDataset = this.publicDataset.filter(item => item.DecompressState === 2) - if (checkStatuDataset.length > 0) { - this.polling(checkStatuDataset, repoLink) - } - this.totalnums = parseInt(res.data.count) - this.loadingDataIndex = false - }) - + clearInterval(this.timer); + this.loadingDataIndex = true; + let url = repoLink + "/datasets/public_datasets"; + this.$axios + .get(url, { + params: { + type: type, + page: this.page, + q: this.searchDataItem, + }, + }) + .then((res) => { + this.publicDataset = JSON.parse(res.data.data); + const checkStatuDataset = this.publicDataset.filter( + (item) => item.DecompressState === 2 + ); + if (checkStatuDataset.length > 0) { + this.polling(checkStatuDataset, repoLink); + } + this.totalnums = parseInt(res.data.count); + this.loadingDataIndex = false; + }); }, getStarDataset(repoLink, type) { - clearInterval(this.timer) - this.loadingDataIndex = true - let url = repoLink + '/datasets/my_favorite' - this.$axios.get(url, { - params: { - type: type, - page: this.page, - q: this.searchDataItem - } - }).then((res) => { - this.myFavoriteDataset = JSON.parse(res.data.data) - const checkStatuDataset = this.myFavoriteDataset.filter(item => item.DecompressState === 2) - if (checkStatuDataset.length > 0) { - this.polling(checkStatuDataset, repoLink) - } - this.totalnums = parseInt(res.data.count) - this.loadingDataIndex = false - }) - + clearInterval(this.timer); + this.loadingDataIndex = true; + let url = repoLink + "/datasets/my_favorite"; + this.$axios + .get(url, { + params: { + type: type, + page: this.page, + q: this.searchDataItem, + }, + }) + .then((res) => { + this.myFavoriteDataset = JSON.parse(res.data.data); + const checkStatuDataset = this.myFavoriteDataset.filter( + (item) => item.DecompressState === 2 + ); + if (checkStatuDataset.length > 0) { + this.polling(checkStatuDataset, repoLink); + } + this.totalnums = parseInt(res.data.count); + this.loadingDataIndex = false; + }); }, selectDataset(uuid, name) { - this.dataset_uuid = uuid - this.dataset_name = name - this.dialogVisible = false + this.dataset_uuid = uuid; + this.dataset_name = name; + this.dialogVisible = false; }, searchDataset() { switch (this.activeName) { case 'first': this.page = 1 - this.getCurrentRepoDataset(this.repolink, this.cloudbrainType) + this.getCurrentRepoDataset(this.repolink, this.datasetType) break case 'second': this.page = 1 - this.getMyDataset(this.repolink, this.cloudbrainType) + this.getMyDataset(this.repolink, this.datasetType) break case 'third': this.page = 1 - this.getPublicDataset(this.repolink, this.cloudbrainType) + this.getPublicDataset(this.repolink, this.datasetType) break case 'fourth': this.page = 1 - this.getStarDataset(this.repolink, this.cloudbrainType) + this.getStarDataset(this.repolink, this.datasetType) break } - } + }, }, watch: { searchDataItem() { switch (this.activeName) { case 'first': this.page = 1 - this.getCurrentRepoDataset(this.repolink, this.cloudbrainType) + this.getCurrentRepoDataset(this.repolink, this.datasetType) break case 'second': this.page = 1 - this.getMyDataset(this.repolink, this.cloudbrainType) + this.getMyDataset(this.repolink, this.datasetType) break case 'third': this.page = 1 - this.getPublicDataset(this.repolink, this.cloudbrainType) + this.getPublicDataset(this.repolink, this.datasetType) break case 'fourth': this.page = 1 - this.getStarDataset(this.repolink, this.cloudbrainType) + this.getStarDataset(this.repolink, this.datasetType) break } - } - + }, }, }); - } function initVueEditTopic() { - const el = document.getElementById('topic_edit1'); + const el = document.getElementById("topic_edit1"); if (!el) { return; } new Vue({ - el: '#topic_edit1', - render: h => h(EditTopics) - }) + el: "#topic_edit1", + render: (h) => h(EditTopics), + }); } function initVueContributors() { - const el = document.getElementById('Contributors'); + const el = document.getElementById("Contributors"); if (!el) { return; } new Vue({ - el: '#Contributors', - render: h => h(Contributors) - }) + el: "#Contributors", + render: (h) => h(Contributors), + }); } - // function initVueImages() { // const el = document.getElementById('images'); - // if (!el) { // return; // } @@ -4529,8 +4482,7 @@ function initVueContributors() { // }); // } function initVueModel() { - const el = document.getElementById('model_list'); - + const el = document.getElementById("model_list"); if (!el) { return; @@ -4539,91 +4491,100 @@ function initVueModel() { new Vue({ el: el, - render: h => h(Model) + render: (h) => h(Model), }); } function initVueDataAnalysis() { - const el = document.getElementById('data_analysis'); + const el = document.getElementById("data_analysis"); if (!el) { return; } new Vue({ - el: '#data_analysis', + el: "#data_analysis", router, - render: h => h(DataAnalysis) + render: (h) => h(DataAnalysis), }); } function initVueWxAutorize() { - const el = document.getElementById('WxAutorize'); + const el = document.getElementById("WxAutorize"); if (!el) { return; } new Vue({ el: el, - render: h => h(WxAutorize) + render: (h) => h(WxAutorize), + }); +} +function initVueselectDataset() { + const el = document.getElementById("select-multi-dataset"); + if (!el) { + return; + } + new Vue({ + el: el, + render: (h) => h(selectDataset), }); } - window.timeAddManual = function () { - $('.mini.modal') + $(".mini.modal") .modal({ duration: 200, onApprove() { - $('#add_time_manual_form').trigger('submit'); - } + $("#add_time_manual_form").trigger("submit"); + }, }) - .modal('show'); + .modal("show"); }; window.toggleStopwatch = function () { - $('#toggle_stopwatch_form').trigger('submit'); + $("#toggle_stopwatch_form").trigger("submit"); }; window.cancelStopwatch = function () { - $('#cancel_stopwatch_form').trigger('submit'); + $("#cancel_stopwatch_form").trigger("submit"); }; function initFilterBranchTagDropdown(selector) { $(selector).each(function () { const $dropdown = $(this); - const $data = $dropdown.find('.data'); + const $data = $dropdown.find(".data"); const data = { items: [], - mode: $data.data('mode'), - searchTerm: '', - noResults: '', + mode: $data.data("mode"), + searchTerm: "", + noResults: "", canCreateBranch: false, menuVisible: false, - active: 0 + active: 0, }; - $data.find('.item').each(function () { + $data.find(".item").each(function () { data.items.push({ name: $(this).text(), - url: $(this).data('url'), - branch: $(this).hasClass('branch'), - tag: $(this).hasClass('tag'), - selected: $(this).hasClass('selected') + url: $(this).data("url"), + branch: $(this).hasClass("branch"), + tag: $(this).hasClass("tag"), + selected: $(this).hasClass("selected"), }); }); $data.remove(); new Vue({ - delimiters: ['${', '}'], + delimiters: ["${", "}"], el: this, data, beforeMount() { const vm = this; - this.noResults = vm.$el.getAttribute('data-no-results'); + this.noResults = vm.$el.getAttribute("data-no-results"); this.canCreateBranch = - vm.$el.getAttribute('data-can-create-branch') === 'true'; + vm.$el.getAttribute("data-can-create-branch") === "true"; - document.body.addEventListener('click', (event) => { + document.body.addEventListener("click", (event) => { if (vm.$el.contains(event.target)) { return; } if (vm.menuVisible) { - Vue.set(vm, 'menuVisible', false); + Vue.set(vm, "menuVisible", false); } }); }, @@ -4633,7 +4594,7 @@ function initFilterBranchTagDropdown(selector) { if (visible) { this.focusSearchField(); } - } + }, }, computed: { @@ -4642,8 +4603,8 @@ function initFilterBranchTagDropdown(selector) { const items = vm.items.filter((item) => { return ( - ((vm.mode === 'branches' && item.branch) || - (vm.mode === 'tags' && item.tag)) && + ((vm.mode === "branches" && item.branch) || + (vm.mode === "tags" && item.tag)) && (!vm.searchTerm || item.name.toLowerCase().includes(vm.searchTerm.toLowerCase())) ); @@ -4658,7 +4619,7 @@ function initFilterBranchTagDropdown(selector) { }, showCreateNewBranch() { const vm = this; - if (!this.canCreateBranch || !vm.searchTerm || vm.mode === 'tags') { + if (!this.canCreateBranch || !vm.searchTerm || vm.mode === "tags") { return false; } @@ -4667,7 +4628,7 @@ function initFilterBranchTagDropdown(selector) { (item) => item.name.toLowerCase() === vm.searchTerm.toLowerCase() ).length === 0 ); - } + }, }, methods: { @@ -4683,7 +4644,7 @@ function initFilterBranchTagDropdown(selector) { if (!this.showCreateNewBranch) { return; } - $(this.$refs.newBranchForm).trigger('submit'); + $(this.$refs.newBranchForm).trigger("submit"); }, focusSearchField() { const vm = this; @@ -4771,111 +4732,107 @@ function initFilterBranchTagDropdown(selector) { event.preventDefault(); vm.menuVisible = false; } - } - } + }, + }, }); }); } -$('.commit-button').on('click', function (e) { +$(".commit-button").on("click", function (e) { e.preventDefault(); - $(this) - .parent() - .find('.commit-body') - .toggle(); + $(this).parent().find(".commit-body").toggle(); }); function initNavbarContentToggle() { - const content = $('#navbar'); - const toggle = $('#navbar-expand-toggle'); + const content = $("#navbar"); + const toggle = $("#navbar-expand-toggle"); let isExpanded = false; - toggle.on('click', () => { + toggle.on("click", () => { isExpanded = !isExpanded; if (isExpanded) { - content.addClass('shown'); - toggle.addClass('active'); + content.addClass("shown"); + toggle.addClass("active"); } else { - content.removeClass('shown'); - toggle.removeClass('active'); + content.removeClass("shown"); + toggle.removeClass("active"); } }); } - window.toggleDeadlineForm = function () { - $('#deadlineForm').fadeToggle(150); + $("#deadlineForm").fadeToggle(150); }; window.setDeadline = function () { - const deadline = $('#deadlineDate').val(); + const deadline = $("#deadlineDate").val(); window.updateDeadline(deadline); }; window.updateDeadline = function (deadlineString) { - $('#deadline-err-invalid-date').hide(); - $('#deadline-loader').addClass('loading'); + $("#deadline-err-invalid-date").hide(); + $("#deadline-loader").addClass("loading"); let realDeadline = null; - if (deadlineString !== '') { + if (deadlineString !== "") { const newDate = Date.parse(deadlineString); if (Number.isNaN(newDate)) { - $('#deadline-loader').removeClass('loading'); - $('#deadline-err-invalid-date').show(); + $("#deadline-loader").removeClass("loading"); + $("#deadline-err-invalid-date").show(); return false; } realDeadline = new Date(newDate); } - $.ajax(`${$('#update-issue-deadline-form').attr('action')}/deadline`, { + $.ajax(`${$("#update-issue-deadline-form").attr("action")}/deadline`, { data: JSON.stringify({ - due_date: realDeadline + due_date: realDeadline, }), headers: { - 'X-Csrf-Token': csrf, - 'X-Remote': true + "X-Csrf-Token": csrf, + "X-Remote": true, }, - contentType: 'application/json', - type: 'POST', + contentType: "application/json", + type: "POST", success() { reload(); }, error() { - $('#deadline-loader').removeClass('loading'); - $('#deadline-err-invalid-date').show(); - } + $("#deadline-loader").removeClass("loading"); + $("#deadline-err-invalid-date").show(); + }, }); }; window.deleteDependencyModal = function (id, type) { - $('.remove-dependency') + $(".remove-dependency") .modal({ closable: false, duration: 200, onApprove() { - $('#removeDependencyID').val(id); - $('#dependencyType').val(type); - $('#removeDependencyForm').trigger('submit'); - } + $("#removeDependencyID").val(id); + $("#dependencyType").val(type); + $("#removeDependencyForm").trigger("submit"); + }, }) - .modal('show'); + .modal("show"); }; function initIssueList() { - const repolink = $('#repolink').val(); - const repoId = $('#repoId').val(); - const crossRepoSearch = $('#crossRepoSearch').val(); - const tp = $('#type').val(); + const repolink = $("#repolink").val(); + const repoId = $("#repoId").val(); + const crossRepoSearch = $("#crossRepoSearch").val(); + const tp = $("#type").val(); let issueSearchUrl = `${AppSubUrl}/api/v1/repos/${repolink}/issues?q={query}&type=${tp}`; - if (crossRepoSearch === 'true') { + if (crossRepoSearch === "true") { issueSearchUrl = `${AppSubUrl}/api/v1/repos/issues/search?q={query}&priority_repo_id=${repoId}&type=${tp}`; } - $('#new-dependency-drop-list').dropdown({ + $("#new-dependency-drop-list").dropdown({ apiSettings: { url: issueSearchUrl, onResponse(response) { const filteredResponse = { success: true, results: [] }; - const currIssueId = $('#new-dependency-drop-list').data('issue-id'); + const currIssueId = $("#new-dependency-drop-list").data("issue-id"); // Parse the response from the api to work with our dropdown $.each(response, (_i, issue) => { // Don't list current issue in the dependency list. @@ -4888,47 +4845,47 @@ function initIssueList() { )}
${htmlEncode( issue.repository.full_name )}
`, - value: issue.id + value: issue.id, }); }); return filteredResponse; }, - cache: false + cache: false, }, - fullTextSearch: true + fullTextSearch: true, }); - $('.menu a.label-filter-item').each(function () { - $(this).on('click', function (e) { + $(".menu a.label-filter-item").each(function () { + $(this).on("click", function (e) { if (e.altKey) { e.preventDefault(); - const href = $(this).attr('href'); - const id = $(this).data('label-id'); + const href = $(this).attr("href"); + const id = $(this).data("label-id"); const regStr = `labels=(-?[0-9]+%2c)*(${id})(%2c-?[0-9]+)*&`; - const newStr = 'labels=$1-$2$3&'; + const newStr = "labels=$1-$2$3&"; window.location = href.replace(new RegExp(regStr), newStr); } }); }); - $('.menu .ui.dropdown.label-filter').on('keydown', (e) => { + $(".menu .ui.dropdown.label-filter").on("keydown", (e) => { if (e.altKey && e.keyCode === 13) { const selectedItems = $( - '.menu .ui.dropdown.label-filter .menu .item.selected' + ".menu .ui.dropdown.label-filter .menu .item.selected" ); if (selectedItems.length > 0) { const item = $(selectedItems[0]); - const href = item.attr('href'); - const id = item.data('label-id'); + const href = item.attr("href"); + const id = item.data("label-id"); const regStr = `labels=(-?[0-9]+%2c)*(${id})(%2c-?[0-9]+)*&`; - const newStr = 'labels=$1-$2$3&'; + const newStr = "labels=$1-$2$3&"; window.location = href.replace(new RegExp(regStr), newStr); } @@ -4936,36 +4893,33 @@ function initIssueList() { }); } window.cancelCodeComment = function (btn) { - const form = $(btn).closest('form'); - if (form.length > 0 && form.hasClass('comment-form')) { - form.addClass('hide'); - form - .parent() - .find('button.comment-form-reply') - .show(); + const form = $(btn).closest("form"); + if (form.length > 0 && form.hasClass("comment-form")) { + form.addClass("hide"); + form.parent().find("button.comment-form-reply").show(); } else { - form.closest('.comment-code-cloud').remove(); + form.closest(".comment-code-cloud").remove(); } }; window.submitReply = function (btn) { - const form = $(btn).closest('form'); - if (form.length > 0 && form.hasClass('comment-form')) { - form.trigger('submit'); + const form = $(btn).closest("form"); + if (form.length > 0 && form.hasClass("comment-form")) { + form.trigger("submit"); } }; window.onOAuthLoginClick = function () { - const oauthLoader = $('#oauth2-login-loader'); - const oauthNav = $('#oauth2-login-navigator'); + const oauthLoader = $("#oauth2-login-loader"); + const oauthNav = $("#oauth2-login-navigator"); oauthNav.hide(); - oauthLoader.removeClass('disabled'); + oauthLoader.removeClass("disabled"); setTimeout(() => { // recover previous content to let user try again // usually redirection will be performed before this action - oauthLoader.addClass('disabled'); + oauthLoader.addClass("disabled"); oauthNav.show(); }, 5000); }; @@ -4973,24 +4927,29 @@ window.onOAuthLoginClick = function () { // Pull SVGs via AJAX to workaround CORS issues with tags // https://css-tricks.com/ajaxing-svg-sprite/ $.get(`${window.config.StaticUrlPrefix}/img/svg/icons.svg`, (data) => { - const div = document.createElement('div'); - div.style.display = 'none'; + const div = document.createElement("div"); + div.style.display = "none"; div.innerHTML = new XMLSerializer().serializeToString(data.documentElement); document.body.insertBefore(div, document.body.childNodes[0]); }); function initDropDown() { $("#dropdown_PageHome").dropdown({ - on: 'hover',//鼠标悬浮显示,默认值是click + on: "hover", //鼠标悬浮显示,默认值是click }); $("#dropdown_explore").dropdown({ - on: 'hover',//鼠标悬浮显示,默认值是click + on: "hover", //鼠标悬浮显示,默认值是click }); } //云脑提示 -$('.question.circle.icon.cloudbrain-question').hover(function () { - $(this).popup('show') - $('.ui.popup.mini.top.center').css({ "border-color": 'rgba(50, 145, 248, 100)', "color": "rgba(3, 102, 214, 100)", "border-radius": "5px", "border-shadow": "none" }) +$(".question.circle.icon.cloudbrain-question").hover(function () { + $(this).popup("show"); + $(".ui.popup.mini.top.center").css({ + "border-color": "rgba(50, 145, 248, 100)", + color: "rgba(3, 102, 214, 100)", + "border-radius": "5px", + "border-shadow": "none", + }); }); //云脑详情页面跳转回上一个页面 @@ -5000,179 +4959,195 @@ $('.question.circle.icon.cloudbrain-question').hover(function () { function initcreateRepo() { let timeout; - let keydown_flag = false - const urlAdd = location.href.split('/')[0] + '//' + location.href.split('/')[2] - let owner = $('#ownerDropdown div.text').attr("title") + let keydown_flag = false; + const urlAdd = + location.href.split("/")[0] + "//" + location.href.split("/")[2]; + let owner = $("#ownerDropdown div.text").attr("title"); $(document).ready(function () { - $('#ownerDropdown').dropdown({ + $("#ownerDropdown").dropdown({ onChange: function (value, text, $choice) { - owner = $choice[0].getAttribute("title") - $('#repoAdress').css("display", "flex") - $('#repoAdress span').text(urlAdd + '/' + owner + '/' + $('#repo_name').val() + '.git') - } + owner = $choice[0].getAttribute("title"); + $("#repoAdress").css("display", "flex"); + $("#repoAdress span").text( + urlAdd + "/" + owner + "/" + $("#repo_name").val() + ".git" + ); + }, }); - }) - $('#repo_name').keyup(function () { - keydown_flag = $('#repo_name').val() ? true : false + }); + $("#repo_name").keyup(function () { + keydown_flag = $("#repo_name").val() ? true : false; if (keydown_flag) { - $('#repoAdress').css("display", "flex") - $('#repoAdress span').text(urlAdd + '/' + owner + '/' + $('#repo_name').val() + '.git') - } - else { - $('#repoAdress').css("display", "none") - $('#repo_name').attr("placeholder", "") + $("#repoAdress").css("display", "flex"); + $("#repoAdress span").text( + urlAdd + "/" + owner + "/" + $("#repo_name").val() + ".git" + ); + } else { + $("#repoAdress").css("display", "none"); + $("#repo_name").attr("placeholder", ""); } - }) - $("#create_repo_form") - .form({ - on: 'blur', - // inline:true, - fields: { - alias: { - identifier: 'alias', - rules: [ - { - type: 'regExp[/^[\u4E00-\u9FA5A-Za-z0-9_.-]{1,100}$/]', - } - ] - }, - repo_name: { - identifier: 'repo_name', - rules: [ - { - type: 'regExp[/^[A-Za-z0-9_.-]{1,100}$/]', - - } - ] - }, + }); + $("#create_repo_form").form({ + on: "blur", + // inline:true, + fields: { + alias: { + identifier: "alias", + rules: [ + { + type: "regExp[/^[\u4E00-\u9FA5A-Za-z0-9_.-]{1,100}$/]", + }, + ], }, - onFailure: function (e) { - return false; - } - }) - $('#alias').bind('input propertychange', function (event) { - clearTimeout(timeout) + repo_name: { + identifier: "repo_name", + rules: [ + { + type: "regExp[/^[A-Za-z0-9_.-]{1,100}$/]", + }, + ], + }, + }, + onFailure: function (e) { + return false; + }, + }); + $("#alias").bind("input propertychange", function (event) { + clearTimeout(timeout); timeout = setTimeout(() => { //在此处写调用的方法,可以实现仅最后一次操作生效 - const aliasValue = $('#alias').val() + const aliasValue = $("#alias").val(); if (keydown_flag) { - $('#repo_name').attr("placeholder", "") - } - else if (aliasValue) { - $('#repo_name').attr("placeholder", "正在获取路径...") - $.get(`${window.config.AppSubUrl}/repo/check_name?q=${aliasValue}&owner=${owner}`, (data) => { - const repo_name = data.name - $('#repo_name').val(repo_name) - repo_name && $('#repo_name').parent().removeClass('error') - $('#repoAdress').css("display", "flex") - $('#repoAdress span').text(urlAdd + '/' + owner + '/' + $('#repo_name').val() + '.git') - $('#repo_name').attr("placeholder", "") - }) + $("#repo_name").attr("placeholder", ""); + } else if (aliasValue) { + $("#repo_name").attr("placeholder", "正在获取路径..."); + $.get( + `${window.config.AppSubUrl}/repo/check_name?q=${aliasValue}&owner=${owner}`, + (data) => { + const repo_name = data.name; + $("#repo_name").val(repo_name); + repo_name && $("#repo_name").parent().removeClass("error"); + $("#repoAdress").css("display", "flex"); + $("#repoAdress span").text( + urlAdd + "/" + owner + "/" + $("#repo_name").val() + ".git" + ); + $("#repo_name").attr("placeholder", ""); + } + ); } else { - $('#repo_name').val('') - $('#repo_name').attr("placeholder", "") - $('#repoAdress').css("display", "none") + $("#repo_name").val(""); + $("#repo_name").attr("placeholder", ""); + $("#repoAdress").css("display", "none"); } - }, 500) + }, 500); }); } -initcreateRepo() - +initcreateRepo(); function initChartsNpu() { - const url = window.location.href - const urlArr = url.split('/') - let userName = urlArr.slice(-5)[0] - let repoPath = urlArr.slice(-4)[0] - let jobID = urlArr.slice(-1)[0] - + const url = window.location.href; + const urlArr = url.split("/"); + let userName = urlArr.slice(-5)[0]; + let repoPath = urlArr.slice(-4)[0]; + let jobID = urlArr.slice(-1)[0]; let options = { legend: { - data: [] + data: [], }, grid: { - top: '35%', - bottom: '2%', - x: '2%', - containLabel: true + top: "35%", + bottom: "2%", + x: "2%", + containLabel: true, }, tooltip: { - trigger: 'axis', - backgroundColor: 'rgb(51, 56, 84)', - borderColor: 'rgb(51, 51, 51)', + trigger: "axis", + backgroundColor: "rgb(51, 56, 84)", + borderColor: "rgb(51, 51, 51)", borderWidth: 0, textStyle: { - color: '#fff' + color: "#fff", }, axisPointer: { - type: 'line' - } + type: "line", + }, }, xAxis: { - type: 'category', + type: "category", data: [], boundaryGap: false, axisLabel: { - interval: 'auto' + interval: "auto", }, - name: '时间(min)' + name: "时间(min)", }, yAxis: { - show: true, - name: '占有率(%)', + name: "占有率(%)", axisLine: { - show: true + show: true, }, - axisTick: { show: true } + axisTick: { show: true }, }, - series: [] + series: [], }; - const sortBy = (arr, k) => arr.concat().sort((a, b) => (a[k] > b[k] ? 1 : a[k] < b[k] ? -1 : 0)); - $('.metric_chart').click(function (e) { - let versionName = $(this).data('version') - let myCharts = echarts.init(document.getElementById(`metric-${versionName}`)) - $.get(`${window.config.AppSubUrl}/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/metric_statistics?version_name=${versionName}&statistic_type=each&metrics=`, (res) => { - let filterDta = res.MetricsInfo.filter((item) => { - - return !(['recvBytesRate', 'diskWriteRate', 'sendBytesRate', 'diskReadRate'].includes(item.metric)) - }) - filterDta = sortBy(filterDta, "metric") - let legenData = filterDta.map((item) => { - return item.metric - }) - let seriesData = filterDta.map((item) => { - let value = item.value.map((item) => { return item > 0 ? item : '0' }) - let seriesOption = { - name: item.metric, - type: 'line', - symbol: 'circle', - symbolSize: 10, - smooth: true, - showSymbol: false, - lineStyle: { - width: 2, - shadowColor: 'rgba(0,0,0,0.3)', - shadowBlur: 10, - shadowOffsetY: 8 - }, - data: value - } - return seriesOption - }) - let xLength = res.MetricsInfo[0].value.length - options.xAxis.data = Array.from({ length: xLength }, (_, index) => index) - options.legend.data = legenData - options.series = seriesData - options && myCharts.setOption(options); - - }) + const sortBy = (arr, k) => + arr.concat().sort((a, b) => (a[k] > b[k] ? 1 : a[k] < b[k] ? -1 : 0)); + $(".metric_chart").click(function (e) { + let versionName = $(this).data("version"); + let myCharts = echarts.init( + document.getElementById(`metric-${versionName}`) + ); + $.get( + `${window.config.AppSubUrl}/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/metric_statistics?version_name=${versionName}&statistic_type=each&metrics=`, + (res) => { + let filterDta = res.MetricsInfo.filter((item) => { + return ![ + "recvBytesRate", + "diskWriteRate", + "sendBytesRate", + "diskReadRate", + ].includes(item.metric); + }); + filterDta = sortBy(filterDta, "metric"); + let legenData = filterDta.map((item) => { + return item.metric; + }); + let seriesData = filterDta.map((item) => { + let value = item.value.map((item) => { + return item > 0 ? item : "0"; + }); + let seriesOption = { + name: item.metric, + type: "line", + symbol: "circle", + symbolSize: 10, + smooth: true, + showSymbol: false, + lineStyle: { + width: 2, + shadowColor: "rgba(0,0,0,0.3)", + shadowBlur: 10, + shadowOffsetY: 8, + }, + data: value, + }; + return seriesOption; + }); + let xLength = res.MetricsInfo[0].value.length; + options.xAxis.data = Array.from( + { length: xLength }, + (_, index) => index + ); + options.legend.data = legenData; + options.series = seriesData; + options && myCharts.setOption(options); + } + ); options && myCharts.setOption(options); - - }) + }); } -initChartsNpu() \ No newline at end of file +initChartsNpu(); diff --git a/web_src/less/_base.less b/web_src/less/_base.less old mode 100644 new mode 100755 index 951cd881e..8d7c052fe --- a/web_src/less/_base.less +++ b/web_src/less/_base.less @@ -489,6 +489,9 @@ code, white-space: nowrap; display: inline-block; } + &.pre-wrap{ + white-space:pre-wrap!important; + } &.thin { font-weight: normal; diff --git a/web_src/less/openi.less b/web_src/less/openi.less index 5ff09544a..deaefdb68 100644 --- a/web_src/less/openi.less +++ b/web_src/less/openi.less @@ -1,32 +1,32 @@ a { - color: #0366d6; + color: #0366d6; } -.nowrap{ - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; +.nowrap { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .ui .text.yellow a { - color: #fbbd08!important + color: #fbbd08 !important; } .ui .text.yellow a:hover { - color: #f2711c!important + color: #f2711c !important; } -.ui.small.label.topic{ - margin-bottom: 0; +.ui.small.label.topic { + margin-bottom: 0; font-weight: 400; } .mb-1 { - margin-bottom: 8px !important; + margin-bottom: 8px !important; } .mb-2 { - margin-bottom: 16px !important; + margin-bottom: 16px !important; } -.following.bar #navbar .brand{ - padding-left: 0; - padding-top: 0; - padding-bottom: 0; +.following.bar #navbar .brand { + padding-left: 0; + padding-top: 0; + padding-bottom: 0; } .following.bar .brand .ui.mini.image { width: auto; @@ -34,40 +34,45 @@ a { } .following.bar.dark { - background-color: #363840; + background-color: #363840; } -.ui.secondary.menu.dark .item{ - color: #FFF; +.ui.secondary.menu.dark .item { + color: #fff; } -.ui.secondary.menu.dark .item:hover{ - color: #40A9FF; +.ui.secondary.menu.dark .item:hover { + color: #40a9ff; } -.ui.secondary.menu .active.item{ - color: #40A9FF; - border-bottom: 1px solid #40A9FF; - border-radius: 0; +.ui.secondary.menu .active.item { + color: #40a9ff; + border-bottom: 1px solid #40a9ff; + border-radius: 0; } -.repository:not(.new), .organization:not(.new), .explore, .dashboard { +.repository:not(.new), +.organization:not(.new), +.explore, +.dashboard { padding-top: 0px; } -.dashboard .dashboard-navbar, .organization .organization-header, .explore .repos--seach{ - padding-top:15px; - padding-bottom: 15px; - padding-left: 0; - margin-bottom: 20px; - background-color:#f5f5f6 !important; - border-bottom: 1px solid rgba(34,36,38,.15); +.dashboard .dashboard-navbar, +.organization .organization-header, +.explore .repos--seach { + padding-top: 15px; + padding-bottom: 15px; + padding-left: 0; + margin-bottom: 20px; + background-color: #f5f5f6 !important; + border-bottom: 1px solid rgba(34, 36, 38, 0.15); } .following.bar .text .svg.octicon-triangle-down { - color: #3291F8; + color: #3291f8; } .ui .avatar.image { border-radius: 30px; } footer { background-color: #f5f5f6; - padding-bottom: 1.0rem; + padding-bottom: 1rem; } .repository .header-wrapper { @@ -76,227 +81,324 @@ footer { } /*moble*/ -.ui.menu:not(.vertical) .item>.button { - color: #FFF; - box-shadow: 0 0 0 1px rgba(255,255,255,.35) inset; +.ui.menu:not(.vertical) .item > .button { + color: #fff; + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.35) inset; } /*PC*/ -@media only screen and (min-width: 1200px){ - .following.bar #navbar, footer .container { - padding: 0; - } +@media only screen and (min-width: 1200px) { + .following.bar #navbar, + footer .container { + padding: 0; + } } -@media only screen and (min-width: 1600px){ - .ui.ui.ui.container:not(.fluid) { - width: 1200px; - } +@media only screen and (min-width: 1600px) { + .ui.ui.ui.container:not(.fluid) { + width: 1200px; + } } /*start page*/ -.ui.header.section--header{ +.ui.header.section--header { font-size: 50px; font-weight: 300; text-align: center; - margin-bottom: 1.0em; + margin-bottom: 1em; } .ui.header.section--header .sub.header { font-size: 20px; line-height: 30px; color: #9b9b9b; text-align: center; - color: rgba(255,255,255,.6); + color: rgba(255, 255, 255, 0.6); } -.ui.inverted.segment>.ui.header.section--header .sub.header{ - color: rgba(255,255,255,.6); +.ui.inverted.segment > .ui.header.section--header .sub.header { + color: rgba(255, 255, 255, 0.6); } #index-project { background: #002060; - color: #FFF; + color: #fff; position: relative; - padding-top: 3.0em; - padding-bottom:2.0em + padding-top: 3em; + padding-bottom: 2em; } -#index-project .ui.inverted.segment, #index-project .ui.primary.inverted.segment{ - background:none; +#index-project .ui.inverted.segment, +#index-project .ui.primary.inverted.segment { + background: none; } -.prorow{ - background: rgba(0,27,81,0.8); +.prorow { + background: rgba(0, 27, 81, 0.8); } -.flip{ - position:absolute; - left:6px; - right:6px; - top:6px; - bottom:6px; - border:2px solid #ffc000; - border-radius: 12px; - transition: transform 1s cubic-bezier(0.445, 0.05, 0.55, 0.95); - transform: perspective(800px) rotateY(0deg); - transform-style: preserve-3d; - z-index:5; +.flip { + position: absolute; + left: 6px; + right: 6px; + top: 6px; + bottom: 6px; + border: 2px solid #ffc000; + border-radius: 12px; + transition: transform 1s cubic-bezier(0.445, 0.05, 0.55, 0.95); + transform: perspective(800px) rotateY(0deg); + transform-style: preserve-3d; + z-index: 5; +} +.flip-more { + border-color: #4472c4; +} +.flip-blue { + border-color: #00b0f0; +} +.flip-green { + border-color: #00b050; +} +#index-project .ipros:hover .flip { + transform: perspective(800px) rotateY(180deg); } -.flip-more{ border-color:#4472c4} -.flip-blue{ border-color:#00b0f0} -.flip-green{ border-color:#00b050} -#index-project .ipros:hover .flip{transform: perspective(800px) rotateY(180deg);} -#index-project .ui.card{ - margin:0 auto; - background:none; - border:none; - box-shadow:none; +#index-project .ui.card { + margin: 0 auto; + background: none; + border: none; + box-shadow: none; } -#index-project .ui.card>.image>img{ - width:auto; - margin:10px auto; +#index-project .ui.card > .image > img { + width: auto; + margin: 10px auto; } -.ui.card>.extra, .ui.cards>.card>.extra{ - border-top:none !important; - padding: .5em .5em 1em; +.ui.card > .extra, +.ui.cards > .card > .extra { + border-top: none !important; + padding: 0.5em 0.5em 1em; } -#index-project .ui.card>.content, #index-project.ui.cards>.card>.content{ - padding: 0.5em 0.2em; +#index-project .ui.card > .content, +#index-project.ui.cards > .card > .content { + padding: 0.5em 0.2em; } -.ui.inverted.segment .ui.card>.content>.header, .ui.inverted.segment .ui.cards>.card>.content>.header{ - color: rgba(255,255,255,.9); +.ui.inverted.segment .ui.card > .content > .header, +.ui.inverted.segment .ui.cards > .card > .content > .header { + color: rgba(255, 255, 255, 0.9); } -.ui.inverted.segment .ui.card .meta, .ui.inverted.segment .ui.cards>.card .meta{ +.ui.inverted.segment .ui.card .meta, +.ui.inverted.segment .ui.cards > .card .meta { color: #5b9bd5; } -.ui.inverted.segment .ui.card>.extra, .ui.inverted.segment .ui.cards>.card>.extra { - color: rgba(255,255,255,.4); +.ui.inverted.segment .ui.card > .extra, +.ui.inverted.segment .ui.cards > .card > .extra { + color: rgba(255, 255, 255, 0.4); } -#particles{ width: 100%; height:100%; position: absolute; top:0; left:0; right:0; bottom:0;} +#particles { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} -footer .ui.vertical.text.menu:first-child{ margin-top: 1em} -footer .ui.vertical.menu .header.item{ background:none} -footer .column{margin-bottom:0!important; padding-bottom:0!important;} +footer .ui.vertical.text.menu:first-child { + margin-top: 1em; +} +footer .ui.vertical.menu .header.item { + background: none; +} +footer .column { + margin-bottom: 0 !important; + padding-bottom: 0 !important; +} /*explore*/ .explore .ui.secondary.vertical.pointing.menu, .explore .ui.secondary.vertical.pointing.menu .item, .organization .ui.secondary.vertical.pointing.menu, -.organization .ui.secondary.vertical.pointing.menu .item{ - border-right-width: 0; +.organization .ui.secondary.vertical.pointing.menu .item { + border-right-width: 0; } -.explore .computer.only .ui.secondary.pointing.menu .item{ - padding-left:0; +.explore .computer.only .ui.secondary.pointing.menu .item { + padding-left: 0; } -.ui.repository.list .item .ui.header .metas{ - text-align: right; +.ui.repository.list .item .ui.header .metas { + text-align: right; } -@media only screen and (max-width:767.98px){ - .explore .repository.list .ui.right.menu{ - float: none; - } +@media only screen and (max-width: 767.98px) { + .explore .repository.list .ui.right.menu { + float: none; + } } /*organization*/ -.organization-info{ - padding-top:15px; - margin-bottom:2.5rem; +.organization-info { + padding-top: 15px; + margin-bottom: 2.5rem; } -.organization-info > .container{ - overflow: auto; +.organization-info > .container { + overflow: auto; background: url(/img/org_bg.png) no-repeat center center #f5f5f6; padding-top: 30px; - padding-bottom:20px; + padding-bottom: 20px; background-size: cover; - border-radius: 5px; + border-radius: 5px; border: 1px solid #efefef; } -.organization.profile #org-info .ui.header{ - font-size: 1.71428571rem; +.organization.profile #org-info .ui.header { + font-size: 1.71428571rem; margin-bottom: 10px; - font-weight: 400; + font-weight: 400; } .organization.profile #org-avatar { width: 80px; height: 80px; - margin-left: auto; + margin-left: auto; margin-right: auto; margin-bottom: 15px; - border: solid 5px #FFF; + border: solid 5px #fff; } .organization.profile #org-info .desc { font-size: 14px; width: 80%; margin: 0 auto 10px; - color: #FFF; -} -.organization.teams .ui.attached.segment+.ui.attached.header{ margin-top:0} -@media only screen and (max-width:768px){ -.organization-info{ - padding-top:0; + color: #fff; } -.organization-info > .container{ - margin-left:0!important; - margin-right:0!important; +.organization.teams .ui.attached.segment + .ui.attached.header { + margin-top: 0; } +@media only screen and (max-width: 768px) { + .organization-info { + padding-top: 0; + } + .organization-info > .container { + margin-left: 0 !important; + margin-right: 0 !important; + } } .ui.vertical.menu .dropdown.item .menu { - left: 50%; -} - -// icon cloudbrain -.i-round{display:inline-block;width:18px;height:18px;background:url("/img/icons.svg");background-position: -496px -52px;} -.i-bg-organ{background-position: -496px -52px;} -.STOPPED, .KILLED{display:inline-block;width:18px;height:18px;background:url("/img/icons.svg");background-position: -496px -52px;background-position: -459px -52px;} -.RUNNING{display:inline-block;width:18px;height:18px;background:url("/img/icons.svg");background-position: -496px -52px;background-position: -478px -52px;} -.i-bg-orange{background-position: -495px -51px;} -.FAILED,.START_FAILED,.CREATE_FAILED{display:inline-block;width:18px;height:18px;background:url("/img/icons.svg");background-position: -496px -52px;background-position: -532px -52px;} -.i-bg-green{background-position: -441px -52px;} -.i-bg-used{background-position: -514px -52px;} -.icon-bind{background-position: -550px -52px;} -.icon-unbind{background-position: -568px -52px;} -.CREATING, .STOPPING, .DELETING, .STARTING, i.WAITING ,.INIT,.KILLING{display:inline-block;background-image:url('/img/loading.gif');background-repeat:no-repeat;width:16px;height:16px;background-size:16px 16px;margin-right:5px;} -.icon-to-top{ - background:url("/img/icons.svg"); - background-position: -540px -208px; - width: 30px; - height: 30px; - display: inline-block; - cursor: pointer; -} -.icon-to-bottom{ - background:url("/img/icons.svg"); - background-position: -574px -208px; - width: 30px; - height: 30px; - display: inline-block; - cursor: pointer; -} -i.COMPLETED,i.SUCCEEDED{display:inline-block;width:18px;height:18px;background:url("/img/icons.svg");background-position: -496px -52px;background-position: -441px -52px;} -.text_over{ - overflow: hidden; + left: 50%; +} + +// icon cloudbrain +.i-round { + display: inline-block; + width: 18px; + height: 18px; + background: url("/img/icons.svg"); + background-position: -496px -52px; +} +.i-bg-organ { + background-position: -496px -52px; +} +.STOPPED, +.KILLED { + display: inline-block; + width: 18px; + height: 18px; + background: url("/img/icons.svg"); + background-position: -496px -52px; + background-position: -459px -52px; +} +.RUNNING { + display: inline-block; + width: 18px; + height: 18px; + background: url("/img/icons.svg"); + background-position: -496px -52px; + background-position: -478px -52px; +} +.i-bg-orange { + background-position: -495px -51px; +} +.FAILED, +.START_FAILED, +.CREATE_FAILED { + display: inline-block; + width: 18px; + height: 18px; + background: url("/img/icons.svg"); + background-position: -496px -52px; + background-position: -532px -52px; +} +.i-bg-green { + background-position: -441px -52px; +} +.i-bg-used { + background-position: -514px -52px; +} +.icon-bind { + background-position: -550px -52px; +} +.icon-unbind { + background-position: -568px -52px; +} +.CREATING, +.STOPPING, +.DELETING, +.STARTING, +i.WAITING, +.INIT, +.KILLING { + display: inline-block; + background-image: url("/img/loading.gif"); + background-repeat: no-repeat; + width: 16px; + height: 16px; + background-size: 16px 16px; + margin-right: 5px; +} +.icon-to-top { + background: url("/img/icons.svg"); + background-position: -540px -208px; + width: 30px; + height: 30px; + display: inline-block; + cursor: pointer; +} +.icon-to-bottom { + background: url("/img/icons.svg"); + background-position: -574px -208px; + width: 30px; + height: 30px; + display: inline-block; + cursor: pointer; +} +i.COMPLETED, +i.SUCCEEDED { + display: inline-block; + width: 18px; + height: 18px; + background: url("/img/icons.svg"); + background-position: -496px -52px; + background-position: -441px -52px; +} +.text_over { + overflow: hidden; text-overflow: ellipsis; -o-text-overflow: ellipsis; white-space: nowrap; display: inline-block; width: 100%; } -.git-user-content{ - margin-bottom: 16px; +.git-user-content { + margin-bottom: 16px; word-break: break-all; } .row.git-user-content .ui.avatar.s16.image { width: 50px !important; height: 50px !important; vertical-align: middle; - border-radius: 500rem;} + border-radius: 500rem; +} .user-list-item { - padding: 0.3em 0px !important; - margin: 15px 0 !important; + padding: 0.3em 0px !important; + margin: 15px 0 !important; width: 220px !important; } .row.git-user-content .content { margin-left: 6px; display: inline-block; vertical-align: top !important; - overflow: hidden; + overflow: hidden; } .row.git-user-content .content .header { font-weight: bold; @@ -306,10 +408,9 @@ i.COMPLETED,i.SUCCEEDED{display:inline-block;width:18px;height:18px;background:u font-size: 16px !important; text-overflow: ellipsis; overflow: hidden; - width: 145px; - - white-space:nowrap; - + width: 145px; + + white-space: nowrap; } .item.user-list-item .header a { color: #587284 !important; @@ -317,104 +418,102 @@ i.COMPLETED,i.SUCCEEDED{display:inline-block;width:18px;height:18px;background:u .row.git-user-content .content .commit-btn { margin-top: 6px; float: left; - font-size: 11px; - color: #40485b !important; + font-size: 11px; + color: #40485b !important; } .dropdown-menu { - position: relative; - display: inline-block; - + position: relative; + display: inline-block; } -.hover_active{ - height: 100% !important; - margin-top: 1px !important; +.hover_active { + height: 100% !important; + margin-top: 1px !important; } .dropdown-menu:hover .dropdown-content { -display: block; + display: block; } .dropdown-menu:hover .hover_active { - background: #fff !important; - border-color: #d4d4d5 !important; + background: #fff !important; + border-color: #d4d4d5 !important; font-weight: 700 !important; // margin-bottom: -1px; -webkit-box-shadow: none !important; box-shadow: none !important; - border-radius: .28571429rem .28571429rem 0 0!important; - color: rgba(0,0,0,.95) !important; + border-radius: 0.28571429rem 0.28571429rem 0 0 !important; + color: rgba(0, 0, 0, 0.95) !important; border-top-width: 1px !important; - } .dropdown-menu:hover .dropdown-content { - display: block; + display: block; } -.dropdown-content{ - display: none; - position: absolute; - background-color: #ffffff; - min-width: 180px; - z-index: 999; - border: 1px solid transparent; - border-color: #d4d4d5; - border-top: none; - +.dropdown-content { + display: none; + position: absolute; + background-color: #ffffff; + min-width: 180px; + z-index: 999; + border: 1px solid transparent; + border-color: #d4d4d5; + border-top: none; } .dropdown-content a { - color: black; - padding: 12px 16px; - text-decoration: none; - display: block; + color: black; + padding: 12px 16px; + text-decoration: none; + display: block; +} +.dropdown-content a:hover { + background-color: #f1f1f1; } -.dropdown-content a:hover {background-color: #f1f1f1} -.cloudbrain-question{ - margin-left: 4px !important; - color: #3291F8; - +.cloudbrain-question { + margin-left: 4px !important; + color: #3291f8; } //缺省页 -.bgtask-none{ - background: #fff !important; - border: 0 !important; - box-shadow: none !important; - padding-bottom: 0 !important; - padding-top: 2em !important; - +.bgtask-none { + background: #fff !important; + border: 0 !important; + box-shadow: none !important; + padding-bottom: 0 !important; + padding-top: 2em !important; } .bgtask-header-pic { - height: 80px; - text-align: center; - background: url(//ai-studio-static-online.cdn.bcebos.com/aistudio/dist/1638363279337/images/search_empty.png) top no-repeat; - background-size: 80px 80px; + height: 80px; + text-align: center; + background: url(//ai-studio-static-online.cdn.bcebos.com/aistudio/dist/1638363279337/images/search_empty.png) + top no-repeat; + background-size: 80px 80px; } -.bgtask-content{ - margin: 2rem auto 0; - /* width: 500px; */ - text-align: left; +.bgtask-content { + margin: 2rem auto 0; + /* width: 500px; */ + text-align: left; } .bgtask-content-txt { - font-size: 14px; - color: #a6a6a6; - line-height: 22px; - margin-bottom: 4px; + font-size: 14px; + color: #a6a6a6; + line-height: 22px; + margin-bottom: 4px; } .bgtask-content-header { - text-align: center; - color: #3F3F40; - font-size: 18px; - margin-bottom: 1rem; + text-align: center; + color: #3f3f40; + font-size: 18px; + margin-bottom: 1rem; } -.bgtask-content-button{ - margin-top: 1em; - margin-bottom: 1em; +.bgtask-content-button { + margin-top: 1em; + margin-bottom: 1em; } -.selectcloudbrain .active.item{ - color: #0087f5 !important; - border: 1px solid #0087f5; - margin: -1px; - background: #FFF !important; +.selectcloudbrain .active.item { + color: #0087f5 !important; + border: 1px solid #0087f5; + margin: -1px; + background: #fff !important; } // #deletemodel { // width: 100%; @@ -423,648 +522,655 @@ display: block; /* 弹窗 */ #mask { - position: fixed; - top: 0px; - left: 0px; - right: 0px; - bottom: 0px; - filter: alpha(opacity=60); - background-color: #777; - z-index: 1000; - display: none; - opacity: 0.8; - -moz-opacity: 0.5; - padding-top: 100px; - color: #000000 + position: fixed; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + filter: alpha(opacity=60); + background-color: #777; + z-index: 1000; + display: none; + opacity: 0.8; + -moz-opacity: 0.5; + padding-top: 100px; + color: #000000; } #loadingPage { - margin: 200px auto; - width: 50px; - height: 40px; - text-align: center; - font-size: 10px; - display: block; + margin: 200px auto; + width: 50px; + height: 40px; + text-align: center; + font-size: 10px; + display: block; } -#loadingPage>div { - background-color: green; - height: 100%; - width: 6px; - display: inline-block; - -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; - animation: sk-stretchdelay 1.2s infinite ease-in-out; +#loadingPage > div { + background-color: green; + height: 100%; + width: 6px; + display: inline-block; + -webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out; + animation: sk-stretchdelay 1.2s infinite ease-in-out; } #loadingPage .rect2 { - -webkit-animation-delay: -1.1s; - animation-delay: -1.1s; + -webkit-animation-delay: -1.1s; + animation-delay: -1.1s; } #loadingPage .rect3 { - -webkit-animation-delay: -1.0s; - animation-delay: -1.0s; + -webkit-animation-delay: -1s; + animation-delay: -1s; } #loadingPage .rect4 { - -webkit-animation-delay: -0.9s; - animation-delay: -0.9s; + -webkit-animation-delay: -0.9s; + animation-delay: -0.9s; } #loadingPage .rect5 { - -webkit-animation-delay: -0.8s; - animation-delay: -0.8s; + -webkit-animation-delay: -0.8s; + animation-delay: -0.8s; } @-webkit-keyframes sk-stretchdelay { - 0%, - 40%, - 100% { - -webkit-transform: scaleY(0.4) - } - 20% { - -webkit-transform: scaleY(1.0) - } + 0%, + 40%, + 100% { + -webkit-transform: scaleY(0.4); + } + 20% { + -webkit-transform: scaleY(1); + } } @keyframes sk-stretchdelay { - 0%, - 40%, - 100% { - transform: scaleY(0.4); - -webkit-transform: scaleY(0.4); - } - 20% { - transform: scaleY(1.0); - -webkit-transform: scaleY(1.0); - } + 0%, + 40%, + 100% { + transform: scaleY(0.4); + -webkit-transform: scaleY(0.4); + } + 20% { + transform: scaleY(1); + -webkit-transform: scaleY(1); + } } /* 消息框 */ .alert { - display: none; - position: fixed; - width: 100%; - z-index: 1001; - padding: 15px; - border: 1px solid transparent; - border-radius: 4px; - text-align: center; - font-weight: bold; + display: none; + position: fixed; + width: 100%; + z-index: 1001; + padding: 15px; + border: 1px solid transparent; + border-radius: 4px; + text-align: center; + font-weight: bold; } .alert-success { - color: #3c763d; - background-color: #dff0d8; - border-color: #d6e9c6; + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; } .alert-info { - color: #31708f; - background-color: #d9edf7; - border-color: #bce8f1; + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; } .alert-warning { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc; + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; } .alert-danger { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1; + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; } .pusher { - width: calc(100% - 260px); - box-sizing: border-box; + width: calc(100% - 260px); + box-sizing: border-box; } /* 弹窗 (background) */ #imageModal { - display: none; - position: fixed; - z-index: 1; - left: 0; - top: 0; - width: 100%; - height: 100%; - overflow: auto; - background-color: rgb(0, 0, 0); - background-color: rgba(0, 0, 0, 0.4); + display: none; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgb(0, 0, 0); + background-color: rgba(0, 0, 0, 0.4); } /* 弹窗内容 */ .modal-content { - background-color: #fefefe; - margin: 15% auto; - padding: 20px; - border: 1px solid #888; - width: 30%; + background-color: #fefefe; + margin: 15% auto; + padding: 20px; + border: 1px solid #888; + width: 30%; } /* 关闭按钮 */ .close { - color: #aaa; - float: right; - font-size: 28px; - font-weight: bold; + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; } .close:hover, .close:focus { - color: black; - text-decoration: none; - cursor: pointer; + color: black; + text-decoration: none; + cursor: pointer; } .dis { - margin-bottom: 20px; + margin-bottom: 20px; } .disabled { - cursor: pointer; - pointer-events: none; + cursor: pointer; + pointer-events: none; } -.left2{ - margin-left: -2px !important; +.left2 { + margin-left: -2px !important; } -.width70{ +.width70 { width: 70% !important; } -.width83{ +.width83 { width: 83% !important; } -.content-padding{ +.content-padding { padding: 40px !important; } -.model_disabled{ +.model_disabled { background-color: rgba(245, 245, 246, 100) !important; color: rgba(136, 136, 136, 100) !important; } -.edge{ - margin-left:0 !important; - margin-right: 0 !important; - padding-left:0 !important; - padding-right:0 !important; - } +.edge { + margin-left: 0 !important; + margin-right: 0 !important; + padding-left: 0 !important; + padding-right: 0 !important; +} .lfpd { - padding-left:0 !important; - padding-right: 0 !important; + padding-left: 0 !important; + padding-right: 0 !important; } -.mglf{ - margin-left:0.5em !important; +.mglf { + margin-left: 0.5em !important; } -.tooltips{ - display: inline-block; +.tooltips { + display: inline-block; margin-left: 5.5rem; font-size: 12px; margin-top: 0.7rem; color: #888888; } -.tutorial_icon{ - vertical-align: middle; - margin-right: 0.75em; -} -.notic_content{ - height: 50px; - vertical-align: middle; - text-align: center; - line-height: 50px; - background: #E5F4F4 -} -.x_icon{ - float: right!important; - margin-right: 15px !important; - color: rgb(0,0,0) !important; +.tutorial_icon { + vertical-align: middle; + margin-right: 0.75em; +} +.notic_content { + height: 50px; + vertical-align: middle; + text-align: center; + line-height: 50px; + background: #e5f4f4; +} +.x_icon { + float: right !important; + margin-right: 15px !important; + color: rgb(0, 0, 0) !important; font-size: 20px !important; font-weight: bold !important; } -.a_width{ - // width: 50% !important; - margin-left: 20em; - // display:inline-block !important; +.a_width { + // width: 50% !important; + margin-left: 20em; + // display:inline-block !important; } -.a_width i{ - vertical-align:middle!important; +.a_width i { + vertical-align: middle !important; } -.footer_icon{ - display: inline-block !important; - vertical-align: middle !important; - margin-right:0.8em !important; +.footer_icon { + display: inline-block !important; + vertical-align: middle !important; + margin-right: 0.8em !important; } -.a_margin{ - margin: 0px !important; +.a_margin { + margin: 0px !important; } /*pages*/ .ui.borderless.pagination { - border:none; - margin-top: .5rem; + border: none; + margin-top: 0.5rem; } .ui.pagination.menu .item { min-width: 32px; text-align: center; height: 32px; - border-radius: .28571429rem; + border-radius: 0.28571429rem; margin: 0 5px; - background-color: #F2F2F2; + background-color: #f2f2f2; } -.ui.pagination.menu>.item:first-child, .ui.pagination.menu .item:last-child { - background-color: #FFF !important; +.ui.pagination.menu > .item:first-child, +.ui.pagination.menu .item:last-child { + background-color: #fff !important; } -.ui.ui.menu .item.disabled{ - background-color: #F2F2F2; +.ui.ui.menu .item.disabled { + background-color: #f2f2f2; } .ui.pagination.menu .active.item { - background-color: #3291F8; - color: #FFF; + background-color: #3291f8; + color: #fff; } -.ui.pagination.menu .item>.input { - margin: 0em .5em; +.ui.pagination.menu .item > .input { + margin: 0em 0.5em; width: 3em; height: 32px; } @media only screen and (max-width: 767px) { - .following.bar #navbar .brand{ - padding-top: 6px; - } - .secondary.menu + .ui.container{ - margin-left:0 !important; - margin-right:0 !important; + .following.bar #navbar .brand { + padding-top: 6px; } - .repo-title{ - position: absolute; - top: 6px; - left: 50px; - right: 70px; - height: 40px; - line-height: 40px !important; - text-align: center; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - color: #FFF; - background-color: #363840; - padding-left: 20px; - } - .repo-title a{ - color: #FFF !important; - } - .repo-title img + a{ - display: none !important; - } - .repository .header-wrapper{ - margin-bottom: 36px; - } - .header-wrapper .tabs.divider{ - margin-top: 40px !important; - } - .repository .ui.tabs.container{ - margin-top: -60px; - } - - .repo-title .divider, - .repo-title svg, - .repo-title img, - .ui.tabular.menu .item svg, - .ui.tabular.menu .item i, - .ui.tabular.menu .item .label, - .ui.tabular.menu .dropdown-content, - .repository.file .repository-summary, - .repository-summary + .menu, - .desc-home .edit-icon, - #repo-files-table .message, + .secondary.menu + .ui.container { + margin-left: 0 !important; + margin-right: 0 !important; + } + .repo-title { + position: absolute; + top: 6px; + left: 50px; + right: 70px; + height: 40px; + line-height: 40px !important; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + color: #fff; + background-color: #363840; + padding-left: 20px; + } + .repo-title a { + color: #fff !important; + } + .repo-title img + a { + display: none !important; + } + .repository .header-wrapper { + margin-bottom: 36px; + } + .header-wrapper .tabs.divider { + margin-top: 40px !important; + } + .repository .ui.tabs.container { + margin-top: -60px; + } + + .repo-title .divider, + .repo-title svg, + .repo-title img, + .ui.tabular.menu .item svg, + .ui.tabular.menu .item i, + .ui.tabular.menu .item .label, + .ui.tabular.menu .dropdown-content, + .repository.file .repository-summary, + .repository-summary + .menu, + .desc-home .edit-icon, + #repo-files-table .message, #repo-files-table .age, #repo-files-table .ui.sha.label, #repo-files-table .commit-button, - .repository .members - { - display: none !important; - } - .header-wrapper{ - display: flex; - flex-direction: column-reverse; - } - .ui.tabular.menu .item{ - padding: .5em; - } - .ui.tabular.menu .active.item{ - border: none; - background: none; - color: #000000; - border-bottom: 2px solid #000; - white-space: nowrap; - } - .repository .repo-header{ - margin-bottom: -50px; - } - .repo-header .repo-buttons{ - position: relative; - top: 1rem; - width: 100%; - display: flex; - justify-content: flex-end; - } - .repo-buttons .ui.labeled.button>.button{ - box-shadow: none !important; - width: 16px; - overflow: hidden; - white-space: nowrap; - } - .repo-buttons .ui.labeled.button>.label{ - border: none !important; - } - .repository.file.list #repo-files-table td.name{ + .repository .members { + display: none !important; + } + .header-wrapper { + display: flex; + flex-direction: column-reverse; + } + .ui.tabular.menu .item { + padding: 0.5em; + } + .ui.tabular.menu .active.item { + border: none; + background: none; + color: #000000; + border-bottom: 2px solid #000; + white-space: nowrap; + } + .repository .repo-header { + margin-bottom: -50px; + } + .repo-header .repo-buttons { + position: relative; + top: 1rem; + width: 100%; + display: flex; + justify-content: flex-end; + } + .repo-buttons .ui.labeled.button > .button { + box-shadow: none !important; + width: 16px; + overflow: hidden; + white-space: nowrap; + } + .repo-buttons .ui.labeled.button > .label { + border: none !important; + } + .repository.file.list #repo-files-table td.name { max-width: 100%; } - #repo-files-table tr{ + #repo-files-table tr { padding-top: 0; padding-bottom: 0; } - .repository .ui.attached:not(.message)+.ui.attached.segment:not(.top){ + .repository .ui.attached:not(.message) + .ui.attached.segment:not(.top) { border: none; } - .markdown:not(code).file-view{ - padding: 2em 0!important; + .markdown:not(code).file-view { + padding: 2em 0 !important; } } //elemet-ui // .el-pagination.is-background .el-pager li:not(.disabled).active { -// background-color: #5bb973 !important; +// background-color: #5bb973 !important; // color: #FFF !important; // } // .el-pagination.is-background .el-pager li:hover { // color: #5bb973 !important; // } -.tag_key{ - max-width:100%; - margin: 3px 3px; - display:inline-flex; -} -.tag_lable{ - border: 1px solid rgba(232, 232, 232, 100) ; - border-radius: 4px; - color: rgba(65, 80, 88, 100); - font-family: Microsoft Yahei; - font-size: 14px; - padding: 0.3em 0.5em; - height: 30px; - text-align: center; - margin: 0.2em; -} -.omit{ - overflow: hidden; white-space: nowrap; text-overflow: ellipsis; -} -.tag_bg{ - background-color: #0366D6 !important; - color:#FFFFFF !important; -} -.margin-bottom20{ - margin-bottom: 20px; -} -.maxheight{ - max-height: 88px; - overflow: hidden; -} -.pad-botom{ - padding-bottom:0px !important; -} -.icon_a{ - position: absolute; - right: 0; - bottom: .2em; - background: #FFF; - border: none !important; - color: #0366d6 !important; - box-shadow: -15px 0px 10px #fff; -} - -.content_top10{ - padding:10px; - padding-top:0px; -} -.re_con{ - color: rgba(136, 136, 136, 100); - font-size: 14px; - text-align: center; - font-family: SourceHanSansSC-light; - font-weight: normal !important; -} -.title_re{ - margin-top: 50px !important; +.tag_key { + max-width: 100%; + margin: 3px 3px; + display: inline-flex; +} +.tag_lable { + border: 1px solid rgba(232, 232, 232, 100); + border-radius: 4px; + color: rgba(65, 80, 88, 100); + font-family: Microsoft Yahei; + font-size: 14px; + padding: 0.3em 0.5em; + height: 30px; + text-align: center; + margin: 0.2em; +} +.omit { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.tag_bg { + background-color: #0366d6 !important; + color: #ffffff !important; +} +.margin-bottom20 { + margin-bottom: 20px; +} +.maxheight { + max-height: 88px; + overflow: hidden; +} +.pad-botom { + padding-bottom: 0px !important; +} +.icon_a { + position: absolute; + right: 0; + bottom: 0.2em; + background: #fff; + border: none !important; + color: #0366d6 !important; + box-shadow: -15px 0px 10px #fff; +} + +.content_top10 { + padding: 10px; + padding-top: 0px; +} +.re_con { + color: rgba(136, 136, 136, 100); + font-size: 14px; + text-align: center; + font-family: SourceHanSansSC-light; + font-weight: normal !important; +} +.title_re { + margin-top: 50px !important; } .card_list { - width: calc(33.33333333333333% - 2em); - margin-left: 1em; - margin-right: 1em -} -.list_title{ - height: 52px; - text-align: center -} -.star_title{ - background-color: #3291F8; -} -.memb_title{ - background-color: #706FE3; -} -.act_title{ - background-color: #13C28D; -} -.p_text{ - line-height: 50px; - text-align:left; - padding-left:15px; - font-size:18px; - color:#FFFFFF; + width: calc(33.33333333333333% - 2em); + margin-left: 1em; + margin-right: 1em; +} +.list_title { + height: 52px; + text-align: center; +} +.star_title { + background-color: #3291f8; +} +.memb_title { + background-color: #706fe3; +} +.act_title { + background-color: #13c28d; +} +.p_text { + line-height: 50px; + text-align: left; + padding-left: 15px; + font-size: 18px; + color: #ffffff; } .orgs { - display: flex; - flex-flow: row wrap; - padding: 0; - margin-top:20px + display: flex; + flex-flow: row wrap; + padding: 0; + margin-top: 20px; } .orgs li { - display: flex; - border-bottom: 0!important; - padding: 3px!important; -} -.p_score{ - line-height: 28px; - width: 100%; - - /* padding-right: 20px; */ - text-align: right; -} -.org_line_hight{ - line-height: 28px; -} -.org_icon{ - margin-top: 2px; - margin-right: 10px; - padding-left: 15px; - width: 100% ; - text-align: center ; -} -.re_style{ - color: rgba(3, 102, 214, 100) !important; - font-family:SourceHanSansSC-medium; - font-weight: 700; -} -.org_icon_color{ - color: #FA8C16; -} -.li_name{ - list-style:none; - width: 55%; -} -.li_avatar{ - list-style: none; - width: 10%; -} -.li_score{ - list-style:none; - margin-left: 2px; -} -.score{ - position:absolute; - width: 50px; - right:50px; - text-align: center; -} -.wi{ - width: 15%; - line-height: 20px; -} - -.title_icon{ - vertical-align: sub; - font-size: 24px; -} -.title_word{ - vertical-align: middle; - font-size: 18px; - margin-top:1px; + display: flex; + border-bottom: 0 !important; + padding: 3px !important; +} +.p_score { + line-height: 28px; + width: 100%; + + /* padding-right: 20px; */ + text-align: right; +} +.org_line_hight { + line-height: 28px; +} +.org_icon { + margin-top: 2px; + margin-right: 10px; + padding-left: 15px; + width: 100%; + text-align: center; +} +.re_style { + color: rgba(3, 102, 214, 100) !important; + font-family: SourceHanSansSC-medium; + font-weight: 700; +} +.org_icon_color { + color: #fa8c16; +} +.li_name { + list-style: none; + width: 55%; +} +.li_avatar { + list-style: none; + width: 10%; +} +.li_score { + list-style: none; + margin-left: 2px; +} +.score { + position: absolute; + width: 50px; + right: 50px; + text-align: center; +} +.wi { + width: 15%; + line-height: 20px; +} + +.title_icon { + vertical-align: sub; + font-size: 24px; +} +.title_word { + vertical-align: middle; + font-size: 18px; + margin-top: 1px; } /**seach**/ /**搜索导航条适配窄屏**/ -.seachnav{ - overflow-x: auto; - overflow-y: hidden; - scrollbar-width: none; /* firefox */ - -ms-overflow-style: none; /* IE 10+ */ - } - .seachnav::-webkit-scrollbar { - display: none; /* Chrome Safari */ - } - .ui.green.button, .ui.green.buttons .button{ - background-color: #5BB973; - } - .seach .repos--seach{ - padding-bottom: 0; - border-bottom: none; - } - .seach .ui.secondary.pointing.menu{ - border-bottom: none; - } - .seach .ui.secondary.pointing.menu .item > i{ - margin-right: 5px; - } - .seach .ui.secondary.pointing.menu .active.item{ - border-bottom-width: 2px; - margin: 0 0 -1px; - } - .seach .ui.menu .active.item>.label { - background: #1684FC; - color: #FFF; - } - .seach .ui.menu .item>.label:not(.active.item>.label) { - background: #e8e8e8; - color: rgba(0,0,0,.6); - } - - .highlight{ - color: red; - } - - .ui.list .list>.item>img.image+.content, .ui.list>.item>img.image+.content { - width: calc(100% - 4.0em); - margin-left: 0; - } - - .seach .ui.list .list>.item .header, .seach .ui.list>.item .header{ - margin-bottom: 0.5em; - font-size: 1.4rem !important; - font-weight: normal; - } - .seach .time, .seach .time a{ - font-size: 12px; - color: grey; - } - - .seach .list .item.members .ui.avatar.image { - width: 3.2em; - height: 3.2em; - } - .ui.list .list>.item.members>img.image+.content, .ui.list>.item.members>img.image+.content { - width: calc(100% - 4.0em); - margin-left: 0; - } - - .searchlabel{ - color: rgba(16, 16, 16, 100); - font-size: 24px; - text-align: left; - font-family: SourceHanSansSC-medium; - } - - .hiddenSearch{ - margin: auto; +.seachnav { + overflow-x: auto; + overflow-y: hidden; + scrollbar-width: none; /* firefox */ + -ms-overflow-style: none; /* IE 10+ */ +} +.seachnav::-webkit-scrollbar { + display: none; /* Chrome Safari */ +} +.ui.green.button, +.ui.green.buttons .button { + background-color: #5bb973; +} +.seach .repos--seach { + padding-bottom: 0; + border-bottom: none; +} +.seach .ui.secondary.pointing.menu { + border-bottom: none; +} +.seach .ui.secondary.pointing.menu .item > i { + margin-right: 5px; +} +.seach .ui.secondary.pointing.menu .active.item { + border-bottom-width: 2px; + margin: 0 0 -1px; +} +.seach .ui.menu .active.item > .label { + background: #1684fc; + color: #fff; +} +.seach .ui.menu .item > .label:not(.active.item > .label) { + background: #e8e8e8; + color: rgba(0, 0, 0, 0.6); +} + +.highlight { + color: red; +} + +.ui.list .list > .item > img.image + .content, +.ui.list > .item > img.image + .content { + width: calc(100% - 4em); + margin-left: 0; +} + +.seach .ui.list .list > .item .header, +.seach .ui.list > .item .header { + margin-bottom: 0.5em; + font-size: 1.4rem !important; + font-weight: normal; +} +.seach .time, +.seach .time a { + font-size: 12px; + color: grey; +} + +.seach .list .item.members .ui.avatar.image { + width: 3.2em; + height: 3.2em; +} +.ui.list .list > .item.members > img.image + .content, +.ui.list > .item.members > img.image + .content { + width: calc(100% - 4em); + margin-left: 0; +} + +.searchlabel { + color: rgba(16, 16, 16, 100); + font-size: 24px; + text-align: left; + font-family: SourceHanSansSC-medium; +} + +.hiddenSearch { + margin: auto; display: none; - } +} - #tipmsg { +#tipmsg { display: none; z-index: 9999; - width:150; - height: 80; + width: 150; + height: 80; } -.ui.toast-container .toast-box.compact, .ui.toast-container .toast-box>.compact { +.ui.toast-container .toast-box.compact, +.ui.toast-container .toast-box > .compact { width: 250px !important; } .context-menu-click { - z-index: 99; - position: absolute; - padding: 0; - border-radius: 4px; - border: 1px solid #e3e9ed; - -webkit-box-shadow: none; - box-shadow: none; - background: #fff; - display: none !important; + z-index: 99; + position: absolute; + padding: 0; + border-radius: 4px; + border: 1px solid #e3e9ed; + -webkit-box-shadow: none; + box-shadow: none; + background: #fff; + display: none !important; } .context-menu-click.active { - display: block !important; + display: block !important; } .context-menu-operation { - padding: 5px !important; - line-height: 1.78 !important; + padding: 5px !important; + line-height: 1.78 !important; } .context-menu-icon { - float: left !important; - margin: 0px 5px 0px 0px !important; + float: left !important; + margin: 0px 5px 0px 0px !important; } - .row .caret-wrapper { display: inline-flex; flex-direction: column; @@ -1074,24 +1180,39 @@ display: block; vertical-align: middle; cursor: pointer; position: relative; - } +} .row .sort-caret-up { position: absolute; top: 5px; +} - } - -.row .sort-caret-down { +.row .sort-caret-down { position: absolute; bottom: 5px; +} - } - -.row .active-up-sort { +.row .active-up-sort { border-bottom-color: #409eff; - } +} - .row .active-down-sort { +.row .active-down-sort { border-top-color: #409eff; - } \ No newline at end of file +} + +.dataset-header-vue { + display: flex; + align-items: center; +} +.inline.min_title.field:not(.required) .label-fix-width:after { + margin: -0.2em 0 0 0.2em; + content: "*"; + max-width: 6.38px; + visibility: hidden; +} +.inline.min_title.fields.required .label-fix-width:after { + margin: -0.2em 0 0 0.2em; + content: "*"; + max-width: 6.38px; + visibility: hidden; +}