| @@ -10,6 +10,7 @@ import ( | |||
| "io" | |||
| "path" | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/obs" | |||
| @@ -64,6 +65,7 @@ type AttachmentInfo struct { | |||
| Repo *Repository `xorm:"extends"` | |||
| RelAvatarLink string `xorm:"extends"` | |||
| UserName string `xorm:"extends"` | |||
| Recommend bool `xorm:"-"` | |||
| } | |||
| type AttachmentsOptions struct { | |||
| @@ -78,6 +80,7 @@ type AttachmentsOptions struct { | |||
| JustNeedZipFile bool | |||
| NeedRepoInfo bool | |||
| Keyword string | |||
| RecommendOnly bool | |||
| } | |||
| func (a *Attachment) AfterUpdate() { | |||
| @@ -104,6 +107,14 @@ func (a *Attachment) IncreaseDownloadCount() error { | |||
| return nil | |||
| } | |||
| func (a *Attachment) UpdateDatasetUpdateUnix() error { | |||
| // Update download count. | |||
| if _, err := x.Exec("UPDATE `dataset` SET updated_unix="+fmt.Sprint(time.Now().Unix())+" WHERE id=?", a.DatasetID); err != nil { | |||
| return fmt.Errorf("UpdateDatasetUpdateUnix: %v", err) | |||
| } | |||
| return nil | |||
| } | |||
| // APIFormat converts models.Attachment to api.Attachment | |||
| func (a *Attachment) APIFormat() *api.Attachment { | |||
| return &api.Attachment{ | |||
| @@ -570,6 +581,11 @@ func Attachments(opts *AttachmentsOptions) ([]*AttachmentInfo, int64, error) { | |||
| builder.Eq{"attachment.is_private": opts.IsPrivate}, | |||
| ) | |||
| } | |||
| if opts.RecommendOnly { | |||
| cond = cond.And(builder.In("attachment.id", builder.Select("attachment.id"). | |||
| From("attachment"). | |||
| Join("INNER", "dataset", "attachment.dataset_id = dataset.id and dataset.recommend=true"))) | |||
| } | |||
| if opts.JustNeedZipFile { | |||
| var DecompressState []int32 | |||
| @@ -618,6 +634,7 @@ func Attachments(opts *AttachmentsOptions) ([]*AttachmentInfo, int64, error) { | |||
| if err != nil { | |||
| return nil, 0, fmt.Errorf("GetDatasetByID failed error: %v", err) | |||
| } | |||
| attachment.Recommend = dataset.Recommend | |||
| repo, err := GetRepositoryByID(dataset.RepoID) | |||
| if err == nil { | |||
| attachment.Repo = repo | |||
| @@ -1,13 +1,14 @@ | |||
| package models | |||
| import ( | |||
| "code.gitea.io/gitea/modules/util" | |||
| "encoding/json" | |||
| "fmt" | |||
| "strconv" | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/util" | |||
| "xorm.io/builder" | |||
| "xorm.io/xorm" | |||
| @@ -111,7 +112,7 @@ type Cloudbrain struct { | |||
| SubTaskName string | |||
| ContainerID string | |||
| ContainerIp string | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
| Duration int64 `xorm:"DEFAULT 0"` //运行时长 单位秒 | |||
| TrainJobDuration string `xorm:"DEFAULT '00:00:00'"` | |||
| @@ -184,6 +185,12 @@ func (task *Cloudbrain) ComputeAndSetDuration() { | |||
| task.TrainJobDuration = ConvertDurationToStr(d) | |||
| } | |||
| func (task *Cloudbrain) CorrectCreateUnix() { | |||
| if task.StartTime > 0 && task.CreatedUnix > task.StartTime { | |||
| task.CreatedUnix = task.StartTime | |||
| } | |||
| } | |||
| func (task *Cloudbrain) IsTerminal() bool { | |||
| status := task.Status | |||
| return status == string(ModelArtsTrainJobCompleted) || status == string(ModelArtsTrainJobFailed) || status == string(ModelArtsTrainJobKilled) || status == string(ModelArtsStopped) || status == string(JobStopped) || status == string(JobFailed) || status == string(JobSucceeded) | |||
| @@ -218,9 +225,22 @@ func ParseAndSetDurationFromCloudBrainOne(result JobResultPayload, task *Cloudbr | |||
| task.EndTime = timeutil.TimeStamp(result.JobStatus.CompletedTime / 1000) | |||
| } | |||
| } | |||
| task.CorrectCreateUnix() | |||
| task.ComputeAndSetDuration() | |||
| } | |||
| func ParseAndSetDurationFromModelArtsNotebook(result *GetNotebook2Result, job *Cloudbrain) { | |||
| if job.StartTime == 0 && result.Lease.UpdateTime > 0 { | |||
| job.StartTime = timeutil.TimeStamp(result.Lease.UpdateTime / 1000) | |||
| } | |||
| job.Status = result.Status | |||
| if job.EndTime == 0 && IsModelArtsDebugJobTerminal(job.Status) { | |||
| job.EndTime = timeutil.TimeStampNow() | |||
| } | |||
| job.CorrectCreateUnix() | |||
| job.ComputeAndSetDuration() | |||
| } | |||
| type CloudbrainInfo struct { | |||
| Cloudbrain `xorm:"extends"` | |||
| User `xorm:"extends"` | |||
| @@ -306,6 +326,7 @@ type CloudbrainsOptions struct { | |||
| IsLatestVersion string | |||
| JobTypeNot bool | |||
| NeedRepoInfo bool | |||
| RepoIDList []int64 | |||
| } | |||
| type TaskPod struct { | |||
| @@ -546,13 +567,23 @@ type PoolInfo struct { | |||
| PoolType string `json:"pool_type"` | |||
| } | |||
| type CommitImageParams struct { | |||
| type CommitImageCloudBrainParams struct { | |||
| Ip string `json:"ip"` | |||
| TaskContainerId string `json:"taskContainerId"` | |||
| ImageTag string `json:"imageTag"` | |||
| ImageDescription string `json:"imageDescription"` | |||
| } | |||
| type CommitImageParams struct { | |||
| CommitImageCloudBrainParams | |||
| IsPrivate bool | |||
| Topics []string | |||
| CloudBrainType int | |||
| UID int64 | |||
| Place string | |||
| Type int | |||
| } | |||
| type CommitImageResult struct { | |||
| Code string `json:"code"` | |||
| Msg string `json:"msg"` | |||
| @@ -1178,6 +1209,12 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||
| ) | |||
| } | |||
| } | |||
| if len(opts.RepoIDList) > 0 { | |||
| cond = cond.And( | |||
| builder.In("cloudbrain.repo_id", opts.RepoIDList), | |||
| ) | |||
| } | |||
| var count int64 | |||
| var err error | |||
| @@ -1354,7 +1391,7 @@ func CloudbrainsVersionList(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int, e | |||
| func CreateCloudbrain(cloudbrain *Cloudbrain) (err error) { | |||
| cloudbrain.TrainJobDuration = DURATION_STR_ZERO | |||
| if _, err = x.Insert(cloudbrain); err != nil { | |||
| if _, err = x.NoAutoTime().Insert(cloudbrain); err != nil { | |||
| return err | |||
| } | |||
| return nil | |||
| @@ -1464,7 +1501,7 @@ func UpdateTrainJobVersion(job *Cloudbrain) error { | |||
| func updateJobTrainVersion(e Engine, job *Cloudbrain) error { | |||
| var sess *xorm.Session | |||
| sess = e.Where("job_id = ? AND version_name=?", job.JobID, job.VersionName) | |||
| _, err := sess.Cols("status", "train_job_duration", "duration", "start_time", "end_time").Update(job) | |||
| _, err := sess.Cols("status", "train_job_duration", "duration", "start_time", "end_time", "created_unix").Update(job) | |||
| return err | |||
| } | |||
| @@ -1553,7 +1590,7 @@ func UpdateInferenceJob(job *Cloudbrain) error { | |||
| func updateInferenceJob(e Engine, job *Cloudbrain) error { | |||
| var sess *xorm.Session | |||
| sess = e.Where("job_id = ?", job.JobID) | |||
| _, err := sess.Cols("status", "train_job_duration", "duration", "start_time", "end_time").Update(job) | |||
| _, err := sess.Cols("status", "train_job_duration", "duration", "start_time", "end_time", "created_unix").Update(job) | |||
| return err | |||
| } | |||
| func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) { | |||
| @@ -1569,7 +1606,7 @@ func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) { | |||
| return err | |||
| } | |||
| if _, err = sess.Insert(new); err != nil { | |||
| if _, err = sess.NoAutoTime().Insert(new); err != nil { | |||
| sess.Rollback() | |||
| return err | |||
| } | |||
| @@ -1580,3 +1617,64 @@ func RestartCloudbrain(old *Cloudbrain, new *Cloudbrain) (err error) { | |||
| return nil | |||
| } | |||
| func CloudbrainAll(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| var cond = builder.NewCond() | |||
| if (opts.Type) >= 0 { | |||
| cond = cond.And( | |||
| builder.Eq{"cloudbrain.type": opts.Type}, | |||
| ) | |||
| } | |||
| var count int64 | |||
| var err error | |||
| condition := "cloudbrain.user_id = `user`.id" | |||
| if len(opts.Keyword) == 0 { | |||
| count, err = sess.Where(cond).Count(new(Cloudbrain)) | |||
| } else { | |||
| lowerKeyWord := strings.ToLower(opts.Keyword) | |||
| cond = cond.And(builder.Or(builder.Like{"LOWER(cloudbrain.job_name)", lowerKeyWord}, builder.Like{"LOWER(cloudbrain.display_job_name)", lowerKeyWord}, builder.Like{"`user`.lower_name", lowerKeyWord})) | |||
| count, err = sess.Table(&Cloudbrain{}).Where(cond). | |||
| Join("left", "`user`", condition).Count(new(CloudbrainInfo)) | |||
| } | |||
| if err != nil { | |||
| return nil, 0, fmt.Errorf("Count: %v", err) | |||
| } | |||
| if opts.Page >= 0 && opts.PageSize > 0 { | |||
| var start int | |||
| if opts.Page == 0 { | |||
| start = 0 | |||
| } else { | |||
| start = (opts.Page - 1) * opts.PageSize | |||
| } | |||
| sess.Limit(opts.PageSize, start) | |||
| } | |||
| sess.OrderBy("cloudbrain.created_unix DESC") | |||
| cloudbrains := make([]*CloudbrainInfo, 0, setting.UI.IssuePagingNum) | |||
| if err := sess.Table(&Cloudbrain{}).Unscoped().Where(cond). | |||
| Join("left", "`user`", condition). | |||
| Find(&cloudbrains); err != nil { | |||
| return nil, 0, fmt.Errorf("Find: %v", err) | |||
| } | |||
| if opts.NeedRepoInfo { | |||
| var ids []int64 | |||
| for _, task := range cloudbrains { | |||
| ids = append(ids, task.RepoID) | |||
| } | |||
| repositoryMap, err := GetRepositoriesMapByIDs(ids) | |||
| if err == nil { | |||
| for _, task := range cloudbrains { | |||
| task.Repo = repositoryMap[task.RepoID] | |||
| } | |||
| } | |||
| } | |||
| return cloudbrains, count, nil | |||
| } | |||
| @@ -0,0 +1,583 @@ | |||
| package models | |||
| import ( | |||
| "fmt" | |||
| "strings" | |||
| "unicode/utf8" | |||
| "xorm.io/builder" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| ) | |||
| const RECOMMOND_TYPE = 5 | |||
| const NORMAL_TYPE = 0 | |||
| const IMAGE_STATUS_COMMIT = 0 | |||
| const IMAGE_STATUS_SUCCESS = 1 | |||
| const IMAGE_STATUS_Failed = 2 | |||
| type Image struct { | |||
| ID int64 `xorm:"pk autoincr" json:"id"` | |||
| Type int `xorm:"INDEX NOT NULL" json:"type"` //0 normal 5官方推荐,中间值保留为后续扩展 | |||
| CloudbrainType int `xorm:"INDEX NOT NULL" json:"cloudbrainType"` //0 云脑一 1云脑二 | |||
| UID int64 `xorm:"INDEX NOT NULL" json:"uid"` | |||
| IsPrivate bool `xorm:"INDEX NOT NULL" json:"isPrivate"` | |||
| Tag string `xorm:"varchar(100) UNIQUE" json:"tag"` | |||
| Description string `xorm:"varchar(765)" json:"description"` | |||
| Topics []string `xorm:"TEXT JSON" json:"topics"` | |||
| Place string `xorm:"varchar(300)" json:"place"` | |||
| NumStars int `xorm:"NOT NULL DEFAULT 0" json:"numStars"` | |||
| IsStar bool `xorm:"-" json:"isStar"` | |||
| UserName string `xorm:"-" json:"userName"` | |||
| RelAvatarLink string `xorm:"-" json:"relAvatarLink"` | |||
| Status int `xorm:"INDEX NOT NULL DEFAULT 0" json:"status"` //0代表正在提交,1提交完成,2提交失败 | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created" json:"createdUnix"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated" json:"updatedUnix"` | |||
| } | |||
| type ImageList []*Image | |||
| type ImageStar struct { | |||
| ID int64 `xorm:"pk autoincr"` | |||
| UID int64 `xorm:"UNIQUE(s)"` | |||
| ImageID int64 `xorm:"UNIQUE(s)"` | |||
| CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
| } | |||
| type ImageTopic struct { | |||
| ID int64 | |||
| Name string `xorm:"UNIQUE VARCHAR(105)"` | |||
| ImageCount int | |||
| CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | |||
| UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
| } | |||
| type ImageTopicRelation struct { | |||
| ImageID int64 `xorm:"UNIQUE(s)"` | |||
| TopicID int64 `xorm:"UNIQUE(s)"` | |||
| } | |||
| type SearchImageOptions struct { | |||
| Keyword string | |||
| UID int64 | |||
| Status int | |||
| IncludePublicOnly bool | |||
| IncludeOfficialOnly bool | |||
| IncludePrivateOnly bool | |||
| IncludeStarByMe bool | |||
| IncludeCustom bool | |||
| IncludeOwnerOnly bool | |||
| Topics string | |||
| ListOptions | |||
| SearchOrderBy | |||
| } | |||
| type ErrorImageTagExist struct { | |||
| Tag string | |||
| } | |||
| type ErrorImageCommitting struct { | |||
| Tag string | |||
| } | |||
| type ImagesPageResult struct { | |||
| Count int64 `json:"count"` | |||
| Images []*Image `json:"images"` | |||
| } | |||
| func (err ErrorImageTagExist) Error() string { | |||
| return fmt.Sprintf("Image already exists [tag: %s]", err.Tag) | |||
| } | |||
| func (err ErrorImageCommitting) Error() string { | |||
| return fmt.Sprintf("Image already exists [tag: %s]", err.Tag) | |||
| } | |||
| type ErrImageNotExist struct { | |||
| ID int64 | |||
| Tag string | |||
| } | |||
| func (err ErrImageNotExist) Error() string { | |||
| return fmt.Sprintf("Image does not exist [id: %d] [tag: %s]", err.ID, err.Tag) | |||
| } | |||
| func IsErrorImageCommitting(err error) bool { | |||
| _, ok := err.(ErrorImageCommitting) | |||
| return ok | |||
| } | |||
| func IsErrImageNotExist(err error) bool { | |||
| _, ok := err.(ErrImageNotExist) | |||
| return ok | |||
| } | |||
| func IsErrImageTagExist(err error) bool { | |||
| _, ok := err.(ErrorImageTagExist) | |||
| return ok | |||
| } | |||
| func IsImageExist(tag string) (bool, error) { | |||
| return x.Exist(&Image{ | |||
| Tag: tag, | |||
| }) | |||
| } | |||
| func IsImageExistByUser(tag string, uid int64) (bool, error) { | |||
| return x.Exist(&Image{ | |||
| Tag: tag, | |||
| UID: uid, | |||
| Status: IMAGE_STATUS_SUCCESS, | |||
| }) | |||
| } | |||
| type FindImageTopicOptions struct { | |||
| ListOptions | |||
| ImageID int64 | |||
| Keyword string | |||
| } | |||
| func (opts *FindImageTopicOptions) toConds() builder.Cond { | |||
| var cond = builder.NewCond() | |||
| if opts.ImageID > 0 { | |||
| cond = cond.And(builder.Eq{"image_topic_relation.image_id": opts.ImageID}) | |||
| } | |||
| if opts.Keyword != "" { | |||
| cond = cond.And(builder.Like{"image_topic.name", strings.ToLower(opts.Keyword)}) | |||
| } | |||
| return cond | |||
| } | |||
| func GetImageByID(id int64) (*Image, error) { | |||
| rel := new(Image) | |||
| has, err := x. | |||
| ID(id). | |||
| Get(rel) | |||
| if err != nil { | |||
| return nil, err | |||
| } else if !has { | |||
| return nil, ErrImageNotExist{ID: id} | |||
| } | |||
| return rel, nil | |||
| } | |||
| func GetImageByTag(tag string) (*Image, error) { | |||
| image := &Image{Tag: tag} | |||
| has, err := x. | |||
| Get(image) | |||
| if err != nil { | |||
| return nil, err | |||
| } else if !has { | |||
| return nil, ErrImageNotExist{Tag: tag} | |||
| } | |||
| return image, nil | |||
| } | |||
| func SanitizeAndValidateImageTopics(topics []string) (validTopics []string, invalidTopics []string) { | |||
| validTopics = make([]string, 0) | |||
| mValidTopics := make(map[string]struct{}) | |||
| invalidTopics = make([]string, 0) | |||
| for _, topic := range topics { | |||
| topic = strings.TrimSpace(strings.ToLower(topic)) | |||
| // ignore empty string | |||
| if len(topic) == 0 { | |||
| continue | |||
| } | |||
| // ignore same topic twice | |||
| if _, ok := mValidTopics[topic]; ok { | |||
| continue | |||
| } | |||
| if utf8.RuneCountInString(topic) <= 35 { | |||
| validTopics = append(validTopics, topic) | |||
| mValidTopics[topic] = struct{}{} | |||
| } else { | |||
| invalidTopics = append(invalidTopics, topic) | |||
| } | |||
| } | |||
| return validTopics, invalidTopics | |||
| } | |||
| func FindImageTopics(opts *FindImageTopicOptions) (topics []*ImageTopic, err error) { | |||
| sess := x.Select("image_topic.*").Where(opts.toConds()) | |||
| if opts.ImageID > 0 { | |||
| sess.Join("INNER", "image_topic_relation", "image_topic_relation.topic_id = image_topic.id") | |||
| } | |||
| if opts.PageSize != 0 && opts.Page != 0 { | |||
| sess = opts.setSessionPagination(sess) | |||
| } | |||
| return topics, sess.Desc("image_topic.image_count").Find(&topics) | |||
| } | |||
| func SaveImageTopics(imageID int64, topicNames ...string) error { | |||
| topics, err := FindImageTopics(&FindImageTopicOptions{ | |||
| ImageID: imageID, | |||
| }) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| var addedTopicNames []string | |||
| for _, topicName := range topicNames { | |||
| if strings.TrimSpace(topicName) == "" { | |||
| continue | |||
| } | |||
| var found bool | |||
| for _, t := range topics { | |||
| if strings.EqualFold(topicName, t.Name) { | |||
| found = true | |||
| break | |||
| } | |||
| } | |||
| if !found { | |||
| addedTopicNames = append(addedTopicNames, topicName) | |||
| } | |||
| } | |||
| var removeTopics []*ImageTopic | |||
| for _, t := range topics { | |||
| var found bool | |||
| for _, topicName := range topicNames { | |||
| if strings.EqualFold(topicName, t.Name) { | |||
| found = true | |||
| break | |||
| } | |||
| } | |||
| if !found { | |||
| removeTopics = append(removeTopics, t) | |||
| } | |||
| } | |||
| for _, topicName := range addedTopicNames { | |||
| _, err := addTopicByNameToImage(sess, imageID, topicName) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| } | |||
| for _, topic := range removeTopics { | |||
| err := removeTopicFromImage(sess, imageID, topic) | |||
| if err != nil { | |||
| return err | |||
| } | |||
| } | |||
| topicNames = make([]string, 0, 25) | |||
| if err := sess.Table("image_topic").Cols("name"). | |||
| Join("INNER", "image_topic_relation", "image_topic_relation.topic_id = image_topic.id"). | |||
| Where("image_topic_relation.image_id = ?", imageID).Desc("image_topic.image_count").Find(&topicNames); err != nil { | |||
| return err | |||
| } | |||
| if _, err := sess.ID(imageID).Cols("topics").Update(&Image{ | |||
| Topics: topicNames, | |||
| }); err != nil { | |||
| return err | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| func addTopicByNameToImage(e Engine, imageID int64, topicName string) (*ImageTopic, error) { | |||
| var topic ImageTopic | |||
| has, err := e.Where("name = ?", topicName).Get(&topic) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if !has { | |||
| topic.Name = topicName | |||
| topic.ImageCount = 1 | |||
| if _, err := e.Insert(&topic); err != nil { | |||
| return nil, err | |||
| } | |||
| } else { | |||
| topic.ImageCount++ | |||
| if _, err := e.ID(topic.ID).Cols("image_count").Update(&topic); err != nil { | |||
| return nil, err | |||
| } | |||
| } | |||
| if _, err := e.Insert(&ImageTopicRelation{ | |||
| ImageID: imageID, | |||
| TopicID: topic.ID, | |||
| }); err != nil { | |||
| return nil, err | |||
| } | |||
| return &topic, nil | |||
| } | |||
| func removeTopicFromImage(e Engine, imageId int64, topic *ImageTopic) error { | |||
| topic.ImageCount-- | |||
| if _, err := e.ID(topic.ID).Cols("image_count").Update(topic); err != nil { | |||
| return err | |||
| } | |||
| if _, err := e.Delete(&ImageTopicRelation{ | |||
| ImageID: imageId, | |||
| TopicID: topic.ID, | |||
| }); err != nil { | |||
| return err | |||
| } | |||
| return nil | |||
| } | |||
| func SearchImage(opts *SearchImageOptions) (ImageList, int64, error) { | |||
| cond := SearchImageCondition(opts) | |||
| return SearchImageByCondition(opts, cond) | |||
| } | |||
| func SearchImageCondition(opts *SearchImageOptions) builder.Cond { | |||
| var cond = builder.NewCond() | |||
| if len(opts.Keyword) > 0 { | |||
| var subQueryCond = builder.NewCond() | |||
| for _, v := range strings.Split(opts.Keyword, ",") { | |||
| subQueryCond = subQueryCond.Or(builder.Like{"LOWER(image_topic.name)", strings.ToLower(v)}) | |||
| } | |||
| subQuery := builder.Select("image_topic_relation.image_id").From("image_topic_relation"). | |||
| Join("INNER", "image_topic", "image_topic.id = image_topic_relation.topic_id"). | |||
| Where(subQueryCond). | |||
| GroupBy("image_topic_relation.image_id") | |||
| var keywordCond = builder.In("id", subQuery) | |||
| var likes = builder.NewCond() | |||
| for _, v := range strings.Split(opts.Keyword, ",") { | |||
| likes = likes.Or(builder.Like{"LOWER(tag)", strings.ToLower(v)}) | |||
| likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)}) | |||
| } | |||
| keywordCond = keywordCond.Or(likes) | |||
| cond = cond.And(keywordCond) | |||
| } | |||
| if len(opts.Topics) > 0 { //标签精确匹配 | |||
| var subQueryCond = builder.NewCond() | |||
| for _, v := range strings.Split(opts.Keyword, ",") { | |||
| subQueryCond = subQueryCond.Or(builder.Eq{"LOWER(image_topic.name)": strings.ToLower(v)}) | |||
| subQuery := builder.Select("image_topic_relation.image_id").From("image_topic_relation"). | |||
| Join("INNER", "image_topic", "image_topic.id = image_topic_relation.topic_id"). | |||
| Where(subQueryCond). | |||
| GroupBy("image_topic_relation.image_id") | |||
| var topicCond = builder.In("id", subQuery) | |||
| cond = cond.And(topicCond) | |||
| } | |||
| } | |||
| if opts.IncludePublicOnly { | |||
| cond = cond.And(builder.Eq{"is_private": false}) | |||
| } | |||
| if opts.IncludePrivateOnly { | |||
| cond = cond.And(builder.Eq{"is_private": true}) | |||
| } | |||
| if opts.IncludeOwnerOnly { | |||
| cond = cond.And(builder.Eq{"uid": opts.UID}) | |||
| } | |||
| if opts.IncludeOfficialOnly { | |||
| cond = cond.And(builder.Eq{"type": RECOMMOND_TYPE}) | |||
| } | |||
| if opts.Status >= 0 { | |||
| cond = cond.And(builder.Eq{"status": opts.Status}) | |||
| } | |||
| if opts.IncludeStarByMe { | |||
| subQuery := builder.Select("image_id").From("image_star"). | |||
| Where(builder.Eq{"uid": opts.UID}) | |||
| var starCond = builder.In("id", subQuery) | |||
| cond = cond.And(starCond) | |||
| } | |||
| return cond | |||
| } | |||
| func SearchImageByCondition(opts *SearchImageOptions, cond builder.Cond) (ImageList, int64, error) { | |||
| if opts.Page <= 0 { | |||
| opts.Page = 1 | |||
| } | |||
| var err error | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| images := make(ImageList, 0, opts.PageSize) | |||
| count, err := sess.Where(cond).Count(new(Image)) | |||
| if err != nil { | |||
| return nil, 0, fmt.Errorf("Count: %v", err) | |||
| } | |||
| sess.Where(cond).OrderBy(opts.SearchOrderBy.String()) | |||
| if opts.PageSize > 0 { | |||
| sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) | |||
| } | |||
| if err = sess.Find(&images); err != nil { | |||
| return nil, 0, fmt.Errorf("Images: %v", err) | |||
| } | |||
| if err = images.loadAttributes(sess, opts.UID); err != nil { | |||
| return nil, 0, fmt.Errorf("LoadAttributes: %v", err) | |||
| } | |||
| return images, count, nil | |||
| } | |||
| func (images ImageList) loadAttributes(e Engine, uid int64) error { | |||
| if len(images) == 0 { | |||
| return nil | |||
| } | |||
| set := make(map[int64]struct{}) | |||
| for i := range images { | |||
| set[images[i].UID] = struct{}{} | |||
| } | |||
| // Load creators. | |||
| users := make(map[int64]*User, len(set)) | |||
| if err := e.Table("\"user\""). | |||
| Cols("name", "lower_name", "avatar", "email"). | |||
| Where("id > 0"). | |||
| In("id", keysInt64(set)). | |||
| Find(&users); err != nil { | |||
| return fmt.Errorf("find users: %v", err) | |||
| } | |||
| for i := range images { | |||
| images[i].UserName = users[images[i].UID].Name | |||
| images[i].RelAvatarLink = users[images[i].UID].RelAvatarLink() | |||
| if uid == -1 { | |||
| images[i].IsStar = false | |||
| } else { | |||
| images[i].IsStar = isImageStaring(e, uid, images[i].ID) | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| func GetCommittingImageCount() int { | |||
| total, err := x.Where("status =?", 0).Count(new(Image)) | |||
| if err != nil { | |||
| return 0 | |||
| } | |||
| return int(total) | |||
| } | |||
| func CreateLocalImage(image *Image) error { | |||
| _, err := x.Insert(image) | |||
| return err | |||
| } | |||
| func UpdateLocalImage(image *Image) error { | |||
| _, err := x.ID(image.ID).Cols("description", "is_private", "status").Update(image) | |||
| return err | |||
| } | |||
| func UpdateLocalImageStatus(image *Image) error { | |||
| _, err := x.ID(image.ID).Cols("status").Update(image) | |||
| return err | |||
| } | |||
| func DeleteLocalImage(id int64) error { | |||
| image := new(Image) | |||
| _, err := x.ID(id).Delete(image) | |||
| return err | |||
| } | |||
| //star or unstar Image | |||
| func StarImage(userID, imageID int64, star bool) error { | |||
| sess := x.NewSession() | |||
| defer sess.Close() | |||
| if err := sess.Begin(); err != nil { | |||
| return err | |||
| } | |||
| if star { | |||
| if isImageStaring(sess, userID, imageID) { | |||
| return nil | |||
| } | |||
| if _, err := sess.Insert(&ImageStar{UID: userID, ImageID: imageID}); err != nil { | |||
| return err | |||
| } | |||
| if _, err := sess.Exec("UPDATE `image` SET num_stars = num_stars + 1 WHERE id = ?", imageID); err != nil { | |||
| return err | |||
| } | |||
| if _, err := sess.Exec("UPDATE `user` SET num_image_stars = num_image_stars + 1 WHERE id = ?", userID); err != nil { | |||
| return err | |||
| } | |||
| } else { | |||
| if !isImageStaring(sess, userID, imageID) { | |||
| return nil | |||
| } | |||
| if _, err := sess.Delete(&ImageStar{0, userID, imageID, 0}); err != nil { | |||
| return err | |||
| } | |||
| if _, err := sess.Exec("UPDATE `image` SET num_stars = num_stars - 1 WHERE id = ?", imageID); err != nil { | |||
| return err | |||
| } | |||
| if _, err := sess.Exec("UPDATE `user` SET num_image_stars = num_image_stars - 1 WHERE id = ?", userID); err != nil { | |||
| return err | |||
| } | |||
| } | |||
| return sess.Commit() | |||
| } | |||
| func IsImageStaring(userID, datasetID int64) bool { | |||
| return isImageStaring(x, userID, datasetID) | |||
| } | |||
| func isImageStaring(e Engine, userID, imageID int64) bool { | |||
| has, _ := e.Get(&ImageStar{0, userID, imageID, 0}) | |||
| return has | |||
| } | |||
| func RecommendImage(imageId int64, recommond bool) error { | |||
| image := Image{Type: GetRecommondType(recommond)} | |||
| _, err := x.ID(imageId).Cols("type").Update(image) | |||
| return err | |||
| } | |||
| func GetRecommondType(recommond bool) int { | |||
| if recommond { | |||
| return RECOMMOND_TYPE | |||
| } else { | |||
| return NORMAL_TYPE | |||
| } | |||
| } | |||
| @@ -23,7 +23,8 @@ type Dataset struct { | |||
| Category string | |||
| Description string `xorm:"TEXT"` | |||
| DownloadTimes int64 | |||
| NumStars int `xorm:"INDEX NOT NULL DEFAULT 0"` | |||
| NumStars int `xorm:"INDEX NOT NULL DEFAULT 0"` | |||
| Recommend bool `xorm:"INDEX NOT NULL DEFAULT false"` | |||
| License string | |||
| Task string | |||
| ReleaseID int64 `xorm:"INDEX"` | |||
| @@ -99,6 +100,7 @@ type SearchDatasetOptions struct { | |||
| OwnerID int64 | |||
| RepoID int64 | |||
| IncludePublic bool | |||
| RecommendOnly bool | |||
| Category string | |||
| Task string | |||
| License string | |||
| @@ -132,6 +134,13 @@ func CreateDataset(dataset *Dataset) (err error) { | |||
| } | |||
| func RecommendDataset(dataSetId int64, recommend bool) error { | |||
| dataset := Dataset{Recommend: recommend} | |||
| _, err := x.ID(dataSetId).Cols("recommend").Update(dataset) | |||
| return err | |||
| } | |||
| func SearchDataset(opts *SearchDatasetOptions) (DatasetList, int64, error) { | |||
| cond := SearchDatasetCondition(opts) | |||
| return SearchDatasetByCondition(opts, cond) | |||
| @@ -146,6 +155,9 @@ func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond { | |||
| if opts.RepoID > 0 { | |||
| cond = cond.And(builder.Eq{"dataset.repo_id": opts.RepoID}) | |||
| } | |||
| if opts.RecommendOnly { | |||
| cond = cond.And(builder.Eq{"dataset.recommend": opts.RecommendOnly}) | |||
| } | |||
| if opts.IncludePublic { | |||
| cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic}) | |||
| @@ -198,7 +210,7 @@ func SearchDatasetByCondition(opts *SearchDatasetOptions, cond builder.Cond) (Da | |||
| defer sess.Close() | |||
| datasets := make(DatasetList, 0, opts.PageSize) | |||
| selectColumnsSql := "distinct dataset.id,dataset.title, dataset.status, dataset.category, dataset.description, dataset.download_times, dataset.license, dataset.task, dataset.release_id, dataset.user_id, dataset.repo_id, dataset.created_unix,dataset.updated_unix,dataset.num_stars" | |||
| selectColumnsSql := "distinct dataset.id,dataset.title, dataset.status, dataset.category, dataset.description, dataset.download_times, dataset.license, dataset.task, dataset.release_id, dataset.user_id, dataset.repo_id, dataset.created_unix,dataset.updated_unix,dataset.num_stars,dataset.recommend" | |||
| count, err := sess.Distinct("dataset.id").Join("INNER", "repository", "repository.id = dataset.repo_id"). | |||
| Join("INNER", "attachment", "attachment.dataset_id=dataset.id"). | |||
| @@ -131,6 +131,10 @@ func init() { | |||
| new(Dataset), | |||
| new(DatasetStar), | |||
| new(Cloudbrain), | |||
| new(Image), | |||
| new(ImageStar), | |||
| new(ImageTopic), | |||
| new(ImageTopicRelation), | |||
| new(FileChunk), | |||
| new(BlockChain), | |||
| new(RecommendOrg), | |||
| @@ -193,22 +193,22 @@ func (org *User) getOrgStatistics() (int, error) { | |||
| } | |||
| func FindTopNStarsOrgs(n int) ([]*OrgScore, error) { | |||
| sql := "select a.id,sum(b.num_stars) score from \"user\" a ,repository b where a.id=b.owner_id and a.type=1 group by a.id order by score desc limit " + strconv.Itoa(n) | |||
| sql := "select a.id,sum(b.num_stars) score from \"user\" a ,repository b where a.id=b.owner_id and a.type=1 and a.visibility=0 group by a.id order by score desc limit " + strconv.Itoa(n) | |||
| return findTopNOrgs(sql) | |||
| } | |||
| func FindTopNMembersOrgs(n int) ([]*OrgScore, error) { | |||
| sql := "select id, count(user_id) score from" + | |||
| " (select org_id as id, uid as user_id from org_user " + | |||
| " (select org_id as id, uid as user_id from org_user o, \"user\" u where o.org_id=u.id and u.visibility=0 " + | |||
| "union select a.id,b.user_id from \"user\" a,collaboration b,repository c " + | |||
| "where a.type=1 and a.id=c.owner_id and b.repo_id=c.id) d " + | |||
| "where a.type=1 and a.visibility=0 and a.id=c.owner_id and b.repo_id=c.id) d " + | |||
| "group by id order by score desc limit " + strconv.Itoa(n) | |||
| return findTopNOrgs(sql) | |||
| } | |||
| func FindTopNOpenIOrgs(n int) ([]*OrgScore, error) { | |||
| sql := "select org_id id,num_score score from org_statistic order by num_score desc limit " + strconv.Itoa(n) | |||
| sql := "select org_id id,num_score score from org_statistic a, \"user\" b where a.org_id=b.id and b.visibility=0 order by num_score desc limit " + strconv.Itoa(n) | |||
| return findTopNOrgs(sql) | |||
| } | |||
| @@ -157,6 +157,7 @@ type User struct { | |||
| NumFollowing int `xorm:"NOT NULL DEFAULT 0"` | |||
| NumStars int | |||
| NumDatasetStars int `xorm:"NOT NULL DEFAULT 0"` | |||
| NumImageStars int `xorm:"NOT NULL DEFAULT 0"` | |||
| NumRepos int | |||
| // For organization | |||
| @@ -246,7 +246,7 @@ func QueryUserStaticDataByTableName(start int, pageSize int, tableName string, q | |||
| } | |||
| log.Info("query return total:" + fmt.Sprint(allCount)) | |||
| userBusinessAnalysisAllList := make([]*UserBusinessAnalysisAll, 0) | |||
| if err := statictisSess.Table(tableName).Where(cond).OrderBy("commit_count desc,id desc").Limit(pageSize, start). | |||
| if err := statictisSess.Table(tableName).Where(cond).OrderBy("user_index desc,id desc").Limit(pageSize, start). | |||
| Find(&userBusinessAnalysisAllList); err != nil { | |||
| return nil, 0 | |||
| } | |||
| @@ -448,6 +448,9 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||
| var indexTotal int64 | |||
| indexTotal = 0 | |||
| insertCount := 0 | |||
| userIndexMap := make(map[int64]float64, 0) | |||
| maxUserIndex := 0.0 | |||
| minUserIndex := 100000000.0 | |||
| dateRecordBatch := make([]UserBusinessAnalysisAll, 0) | |||
| for { | |||
| sess.Select("`user`.*").Table("user").Where(cond).OrderBy("id asc").Limit(PAGE_SIZE, int(indexTotal)) | |||
| @@ -494,7 +497,13 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||
| dateRecordAll.GpuBenchMarkJob = getMapKeyStringValue(fmt.Sprint(dateRecordAll.ID)+"_GpuBenchMarkJob", CloudBrainTaskItemMap) | |||
| dateRecordAll.CommitModelCount = getMapValue(dateRecordAll.ID, AiModelManageMap) | |||
| dateRecordAll.UserIndex = getUserIndexFromAnalysisAll(dateRecordAll, ParaWeight) | |||
| userIndexMap[dateRecordAll.ID] = dateRecordAll.UserIndex | |||
| if maxUserIndex < dateRecordAll.UserIndex { | |||
| maxUserIndex = dateRecordAll.UserIndex | |||
| } | |||
| if minUserIndex > dateRecordAll.UserIndex { | |||
| minUserIndex = dateRecordAll.UserIndex | |||
| } | |||
| dateRecordBatch = append(dateRecordBatch, dateRecordAll) | |||
| if len(dateRecordBatch) >= BATCH_INSERT_SIZE { | |||
| insertTable(dateRecordBatch, tableName, statictisSess) | |||
| @@ -523,9 +532,22 @@ func refreshUserStaticTable(wikiCountMap map[string]int, tableName string, pageS | |||
| } | |||
| } | |||
| //normalization | |||
| for k, v := range userIndexMap { | |||
| tmpResult := (v - minUserIndex) / (maxUserIndex - minUserIndex) | |||
| if tmpResult > 0.99 { | |||
| tmpResult = 0.99 | |||
| } | |||
| updateUserIndex(tableName, statictisSess, k, tmpResult) | |||
| } | |||
| log.Info("refresh data finished.tableName=" + tableName + " total record:" + fmt.Sprint(insertCount)) | |||
| } | |||
| func updateUserIndex(tableName string, statictisSess *xorm.Session, userId int64, userIndex float64) { | |||
| updateSql := "UPDATE public." + tableName + " set user_index=" + fmt.Sprint(userIndex*100) + " where id=" + fmt.Sprint(userId) | |||
| statictisSess.Exec(updateSql) | |||
| } | |||
| func insertTable(dateRecords []UserBusinessAnalysisAll, tableName string, statictisSess *xorm.Session) { | |||
| insertBatchSql := "INSERT INTO public." + tableName + | |||
| @@ -809,7 +831,12 @@ func getUserIndex(dateRecord UserBusinessAnalysis, ParaWeight map[string]float64 | |||
| result += float64(dateRecord.StarRepoCount) * getParaWeightValue("StarRepoCount", ParaWeight, 0.1) | |||
| result += float64(dateRecord.LoginCount) * getParaWeightValue("LoginCount", ParaWeight, 0.1) | |||
| result += float64(dateRecord.WatchedCount) * getParaWeightValue("WatchedCount", ParaWeight, 0.3) | |||
| result += float64(dateRecord.CommitCodeSize) * getParaWeightValue("CommitCodeSize", ParaWeight, 0.1) | |||
| codeLine := float64(dateRecord.CommitCodeSize) / 1000 | |||
| limitCodeLine := getParaWeightValue("LimitCommitCodeSize", ParaWeight, 100) | |||
| if codeLine >= limitCodeLine { | |||
| codeLine = limitCodeLine | |||
| } | |||
| result += codeLine * getParaWeightValue("CommitCodeSize", ParaWeight, 0.1) | |||
| result += float64(dateRecord.SolveIssueCount) * getParaWeightValue("SolveIssueCount", ParaWeight, 0.2) | |||
| result += float64(dateRecord.EncyclopediasCount) * getParaWeightValue("EncyclopediasCount", ParaWeight, 0.1) | |||
| result += float64(dateRecord.CreateRepoCount) * getParaWeightValue("CreateRepoCount", ParaWeight, 0.05) | |||
| @@ -27,9 +27,37 @@ type CreateCloudBrainForm struct { | |||
| type CommitImageCloudBrainForm struct { | |||
| Description string `form:"description" binding:"Required"` | |||
| Tag string `form:"tag" binding:"Required"` | |||
| Type int `form:"type" binding:"Required"` | |||
| Tag string `form:"tag" binding:"Required;MaxSize(100)" ` | |||
| IsPrivate bool `form:"isPrivate" binding:"Required"` | |||
| Topics string `form:"topics"` | |||
| } | |||
| type CommitAdminImageCloudBrainForm struct { | |||
| Description string `form:"description" binding:"Required"` | |||
| Type int `form:"type" binding:"Required"` | |||
| Tag string `form:"tag" binding:"Required;MaxSize(100)" ` | |||
| IsPrivate bool `form:"isPrivate" binding:"Required"` | |||
| Topics string `form:"topics"` | |||
| Place string `form:"place" binding:"Required"` | |||
| IsRecommend bool `form:"isRecommend" binding:"Required"` | |||
| } | |||
| type EditImageCloudBrainForm struct { | |||
| ID int64 `form:"id" binding:"Required"` | |||
| Description string `form:"description" binding:"Required"` | |||
| IsPrivate bool `form:"isPrivate" binding:"Required"` | |||
| Topics string `form:"topics"` | |||
| } | |||
| func (f *CreateCloudBrainForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| return validate(errs, ctx.Data, f, ctx.Locale) | |||
| } | |||
| func (f *CommitImageCloudBrainForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| return validate(errs, ctx.Data, f, ctx.Locale) | |||
| } | |||
| func (f *EditImageCloudBrainForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | |||
| return validate(errs, ctx.Data, f, ctx.Locale) | |||
| } | |||
| @@ -1,6 +1,7 @@ | |||
| package cloudbrain | |||
| import ( | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "encoding/json" | |||
| "errors" | |||
| "strconv" | |||
| @@ -85,6 +86,18 @@ func isAdminOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error | |||
| } | |||
| func isAdminOrImageCreater(ctx *context.Context, image *models.Image, err error) bool { | |||
| if !ctx.IsSigned { | |||
| return false | |||
| } | |||
| if err != nil { | |||
| return ctx.IsUserSiteAdmin() | |||
| } else { | |||
| return ctx.IsUserSiteAdmin() || ctx.User.ID == image.UID | |||
| } | |||
| } | |||
| func AdminOrOwnerOrJobCreaterRight(ctx *context.Context) { | |||
| var ID = ctx.Params(":id") | |||
| @@ -149,7 +162,31 @@ func AdminOrJobCreaterRightForTrain(ctx *context.Context) { | |||
| } | |||
| func AdminOrImageCreaterRight(ctx *context.Context) { | |||
| id, err := strconv.ParseInt(ctx.Params(":id"), 10, 64) | |||
| var image *models.Image | |||
| if err != nil { | |||
| log.Error("Get Image by ID failed:%v", err.Error()) | |||
| } else { | |||
| image, err = models.GetImageByID(id) | |||
| if err != nil { | |||
| log.Error("Get Image by ID failed:%v", err.Error()) | |||
| return | |||
| } | |||
| } | |||
| if !isAdminOrImageCreater(ctx, image, err) { | |||
| log.Error("!isAdminOrImageCreater error:%v", err.Error()) | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| } | |||
| } | |||
| func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, jobType, gpuQueue, description, branchName, bootFile, params string, benchmarkTypeID, benchmarkChildTypeID, resourceSpecId int) error { | |||
| dataActualPath := setting.Attachment.Minio.RealPath + | |||
| setting.Attachment.Minio.Bucket + "/" + | |||
| setting.Attachment.Minio.BasePath + | |||
| @@ -194,6 +231,7 @@ func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command, | |||
| datasetName = attach.Name | |||
| } | |||
| createTime := timeutil.TimeStampNow() | |||
| jobResult, err := CreateJob(jobName, models.CreateJobParams{ | |||
| JobName: jobName, | |||
| RetryCount: 1, | |||
| @@ -294,6 +332,8 @@ func GenerateTask(ctx *context.Context, displayJobName, jobName, image, command, | |||
| BootFile: bootFile, | |||
| DatasetName: datasetName, | |||
| Parameters: params, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| }) | |||
| if err != nil { | |||
| @@ -341,6 +381,7 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e | |||
| return errors.New("no such resourceSpec") | |||
| } | |||
| createTime := timeutil.TimeStampNow() | |||
| jobResult, err := CreateJob(jobName, models.CreateJobParams{ | |||
| JobName: jobName, | |||
| RetryCount: 1, | |||
| @@ -432,6 +473,8 @@ func RestartTask(ctx *context.Context, task *models.Cloudbrain, newID *string) e | |||
| GpuQueue: task.GpuQueue, | |||
| ResourceSpecId: task.ResourceSpecId, | |||
| ComputeResource: task.ComputeResource, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| } | |||
| err = models.RestartCloudbrain(task, newTask) | |||
| @@ -4,9 +4,11 @@ import ( | |||
| "encoding/json" | |||
| "errors" | |||
| "fmt" | |||
| "math" | |||
| "net/http" | |||
| "strconv" | |||
| "strings" | |||
| "time" | |||
| "code.gitea.io/gitea/modules/log" | |||
| @@ -28,6 +30,7 @@ const ( | |||
| Custom = "custom" | |||
| LogPageSize = 500 | |||
| LogPageTokenExpired = "5m" | |||
| pageSize = 15 | |||
| ) | |||
| func getRestyClient() *resty.Client { | |||
| @@ -210,6 +213,42 @@ func getQueryString(page int, size int, name string) string { | |||
| } | |||
| func CommitImage(jobID string, params models.CommitImageParams) error { | |||
| dbImage, err := models.GetImageByTag(params.ImageTag) | |||
| if err != nil && !models.IsErrImageNotExist(err) { | |||
| return fmt.Errorf("resty CommitImage: %v", err) | |||
| } | |||
| var createTime time.Time | |||
| var isSetCreatedUnix = false | |||
| if dbImage != nil { | |||
| if dbImage.UID != params.UID { | |||
| return models.ErrorImageTagExist{ | |||
| Tag: params.ImageTag, | |||
| } | |||
| } else { | |||
| if dbImage.Status == models.IMAGE_STATUS_COMMIT { | |||
| return models.ErrorImageCommitting{ | |||
| Tag: params.ImageTag, | |||
| } | |||
| } else { //覆盖提交 | |||
| result, err := GetImagesPageable(1, pageSize, Custom, "") | |||
| if err == nil && result.Code == "S000" { | |||
| for _, v := range result.Payload.ImageInfo { | |||
| if v.Place == dbImage.Place { | |||
| isSetCreatedUnix = true | |||
| createTime, _ = time.Parse(time.RFC3339, v.Createtime) | |||
| break | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| checkSetting() | |||
| client := getRestyClient() | |||
| var result models.CommitImageResult | |||
| @@ -220,7 +259,7 @@ sendjob: | |||
| res, err := client.R(). | |||
| SetHeader("Content-Type", "application/json"). | |||
| SetAuthToken(TOKEN). | |||
| SetBody(params). | |||
| SetBody(params.CommitImageCloudBrainParams). | |||
| SetResult(&result). | |||
| Post(HOST + "/rest-server/api/v1/jobs/" + jobID + "/commitImage") | |||
| @@ -238,7 +277,128 @@ sendjob: | |||
| return fmt.Errorf("CommitImage err: %s", res.String()) | |||
| } | |||
| return nil | |||
| image := models.Image{ | |||
| Type: models.NORMAL_TYPE, | |||
| CloudbrainType: params.CloudBrainType, | |||
| UID: params.UID, | |||
| IsPrivate: params.IsPrivate, | |||
| Tag: params.ImageTag, | |||
| Description: params.ImageDescription, | |||
| Place: setting.Cloudbrain.ImageURLPrefix + params.ImageTag, | |||
| Status: models.IMAGE_STATUS_COMMIT, | |||
| } | |||
| err = models.WithTx(func(ctx models.DBContext) error { | |||
| if dbImage != nil { | |||
| dbImage.IsPrivate = params.IsPrivate | |||
| dbImage.Description = params.ImageDescription | |||
| dbImage.Status = models.IMAGE_STATUS_COMMIT | |||
| image = *dbImage | |||
| if err := models.UpdateLocalImage(dbImage); err != nil { | |||
| log.Error("Failed to update image record.", err) | |||
| return fmt.Errorf("CommitImage err: %s", res.String()) | |||
| } | |||
| } else { | |||
| if err := models.CreateLocalImage(&image); err != nil { | |||
| log.Error("Failed to insert image record.", err) | |||
| return fmt.Errorf("CommitImage err: %s", res.String()) | |||
| } | |||
| } | |||
| if err := models.SaveImageTopics(image.ID, params.Topics...); err != nil { | |||
| log.Error("Failed to insert image record.", err) | |||
| return fmt.Errorf("CommitImage err: %s", res.String()) | |||
| } | |||
| return nil | |||
| }) | |||
| if err == nil { | |||
| go updateImageStatus(image, isSetCreatedUnix, createTime) | |||
| } | |||
| return err | |||
| } | |||
| func CommitAdminImage(params models.CommitImageParams) error { | |||
| exist, err := models.IsImageExist(params.ImageTag) | |||
| if err != nil { | |||
| return fmt.Errorf("resty CommitImage: %v", err) | |||
| } | |||
| if exist { | |||
| return models.ErrorImageTagExist{ | |||
| Tag: params.ImageTag, | |||
| } | |||
| } | |||
| image := models.Image{ | |||
| CloudbrainType: params.CloudBrainType, | |||
| UID: params.UID, | |||
| IsPrivate: params.IsPrivate, | |||
| Tag: params.ImageTag, | |||
| Description: params.ImageDescription, | |||
| Place: params.Place, | |||
| Status: models.IMAGE_STATUS_SUCCESS, | |||
| Type: params.Type, | |||
| } | |||
| err = models.WithTx(func(ctx models.DBContext) error { | |||
| if err := models.CreateLocalImage(&image); err != nil { | |||
| log.Error("Failed to insert image record.", err) | |||
| return fmt.Errorf("resty CommitImage: %v", err) | |||
| } | |||
| if err := models.SaveImageTopics(image.ID, params.Topics...); err != nil { | |||
| log.Error("Failed to insert image record.", err) | |||
| return fmt.Errorf("resty CommitImage: %v", err) | |||
| } | |||
| return nil | |||
| }) | |||
| return err | |||
| } | |||
| func updateImageStatus(image models.Image, isSetCreatedUnix bool, createTime time.Time) { | |||
| attemps := 5 | |||
| commitSuccess := false | |||
| time.Sleep(5 * time.Second) | |||
| for i := 0; i < attemps; i++ { | |||
| if commitSuccess { | |||
| break | |||
| } | |||
| result, err := GetImagesPageable(1, pageSize, Custom, "") | |||
| if err == nil && result.Code == "S000" { | |||
| for _, v := range result.Payload.ImageInfo { | |||
| if v.Place == image.Place && (!isSetCreatedUnix || (isSetCreatedUnix && createTimeUpdated(v, createTime))) { | |||
| image.Status = models.IMAGE_STATUS_SUCCESS | |||
| models.UpdateLocalImageStatus(&image) | |||
| commitSuccess = true | |||
| break | |||
| } | |||
| } | |||
| } | |||
| //第一次循环等待4秒,第二次等待4的2次方16秒,...,第5次。。。 ,总共大概是20多分钟内进行5次重试 | |||
| var sleepTime = time.Duration(int(math.Pow(4, (float64(i + 1))))) | |||
| time.Sleep(sleepTime * time.Second) | |||
| } | |||
| if !commitSuccess { | |||
| image.Status = models.IMAGE_STATUS_Failed | |||
| models.UpdateLocalImageStatus(&image) | |||
| } | |||
| } | |||
| func createTimeUpdated(v *models.ImageInfo, createTime time.Time) bool { | |||
| newTime, err := time.Parse(time.RFC3339, v.Createtime) | |||
| if err != nil { | |||
| return false | |||
| } | |||
| return newTime.After(createTime) | |||
| } | |||
| func StopJob(jobID string) error { | |||
| @@ -403,6 +403,16 @@ func ToTopicResponse(topic *models.Topic) *api.TopicResponse { | |||
| } | |||
| } | |||
| func ToImageTopicResponse(topic *models.ImageTopic) *api.ImageTopicResponse { | |||
| return &api.ImageTopicResponse{ | |||
| ID: topic.ID, | |||
| Name: topic.Name, | |||
| ImageCount: topic.ImageCount, | |||
| Created: topic.CreatedUnix.AsTime(), | |||
| Updated: topic.UpdatedUnix.AsTime(), | |||
| } | |||
| } | |||
| // ToOAuth2Application convert from models.OAuth2Application to api.OAuth2Application | |||
| func ToOAuth2Application(app *models.OAuth2Application) *api.OAuth2Application { | |||
| return &api.OAuth2Application{ | |||
| @@ -50,6 +50,7 @@ func SendDecompressAttachToLabelOBS(attach string) error { | |||
| _, err := redisclient.Do("Publish", setting.DecompressOBSTaskName, attach) | |||
| if err != nil { | |||
| log.Critical("redis Publish failed.") | |||
| return err | |||
| } | |||
| log.Info("LabelDecompressOBSQueue(%s) success", attach) | |||
| @@ -1,6 +1,7 @@ | |||
| package modelarts | |||
| import ( | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "encoding/json" | |||
| "errors" | |||
| "fmt" | |||
| @@ -197,6 +198,7 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor strin | |||
| if poolInfos == nil { | |||
| json.Unmarshal([]byte(setting.PoolInfos), &poolInfos) | |||
| } | |||
| createTime := timeutil.TimeStampNow() | |||
| jobResult, err := CreateJob(models.CreateNotebookParams{ | |||
| JobName: jobName, | |||
| Description: description, | |||
| @@ -235,6 +237,8 @@ func GenerateTask(ctx *context.Context, jobName, uuid, description, flavor strin | |||
| Type: models.TypeCloudBrainTwo, | |||
| Uuid: uuid, | |||
| ComputeResource: models.NPUResource, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| }) | |||
| if err != nil { | |||
| @@ -254,7 +258,7 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc | |||
| log.Error("GetNotebookImageName failed: %v", err.Error()) | |||
| return err | |||
| } | |||
| createTime := timeutil.TimeStampNow() | |||
| jobResult, err := createNotebook2(models.CreateNotebook2Params{ | |||
| JobName: jobName, | |||
| Description: description, | |||
| @@ -288,6 +292,8 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc | |||
| ComputeResource: models.NPUResource, | |||
| Image: imageName, | |||
| Description: description, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| }) | |||
| if err != nil { | |||
| @@ -304,6 +310,7 @@ func GenerateNotebook2(ctx *context.Context, displayJobName, jobName, uuid, desc | |||
| } | |||
| func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error) { | |||
| createTime := timeutil.TimeStampNow() | |||
| jobResult, err := createTrainJob(models.CreateTrainJobParams{ | |||
| JobName: req.JobName, | |||
| Description: req.Description, | |||
| @@ -364,6 +371,8 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||
| EngineName: req.EngineName, | |||
| VersionCount: req.VersionCount, | |||
| TotalVersionCount: req.TotalVersionCount, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| }) | |||
| if err != nil { | |||
| @@ -375,6 +384,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error | |||
| } | |||
| func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, jobId string) (err error) { | |||
| createTime := timeutil.TimeStampNow() | |||
| jobResult, err := createTrainJobVersion(models.CreateTrainJobVersionParams{ | |||
| Description: req.Description, | |||
| Config: models.TrainJobVersionConfig{ | |||
| @@ -451,6 +461,8 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job | |||
| EngineName: req.EngineName, | |||
| TotalVersionCount: VersionTaskList[0].TotalVersionCount + 1, | |||
| VersionCount: VersionListCount + 1, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| }) | |||
| if err != nil { | |||
| log.Error("CreateCloudbrain(%s) failed:%v", req.JobName, err.Error()) | |||
| @@ -526,6 +538,7 @@ func GetOutputPathByCount(TotalVersionCount int) (VersionOutputPath string) { | |||
| } | |||
| func GenerateInferenceJob(ctx *context.Context, req *GenerateInferenceJobReq) (err error) { | |||
| createTime := timeutil.TimeStampNow() | |||
| jobResult, err := createInferenceJob(models.CreateInferenceJobParams{ | |||
| JobName: req.JobName, | |||
| Description: req.Description, | |||
| @@ -591,6 +604,8 @@ func GenerateInferenceJob(ctx *context.Context, req *GenerateInferenceJobReq) (e | |||
| ModelVersion: req.ModelVersion, | |||
| CkptName: req.CkptName, | |||
| ResultUrl: req.ResultUrl, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| }) | |||
| if err != nil { | |||
| @@ -1,9 +1,10 @@ | |||
| package setting | |||
| type CloudbrainLoginConfig struct { | |||
| Username string | |||
| Password string | |||
| Host string | |||
| Username string | |||
| Password string | |||
| Host string | |||
| ImageURLPrefix string | |||
| } | |||
| var ( | |||
| @@ -15,5 +16,6 @@ func GetCloudbrainConfig() CloudbrainLoginConfig { | |||
| Cloudbrain.Username = cloudbrainSec.Key("USERNAME").MustString("") | |||
| Cloudbrain.Password = cloudbrainSec.Key("PASSWORD").MustString("") | |||
| Cloudbrain.Host = cloudbrainSec.Key("REST_SERVER_HOST").MustString("") | |||
| Cloudbrain.ImageURLPrefix = cloudbrainSec.Key("IMAGE_URL_PREFIX").MustString("") | |||
| return Cloudbrain | |||
| } | |||
| @@ -438,6 +438,7 @@ var ( | |||
| //home page | |||
| RecommentRepoAddr string | |||
| ESSearchURL string | |||
| INDEXPOSTFIX string | |||
| //notice config | |||
| UserNameOfNoticeRepo string | |||
| RepoNameOfNoticeRepo string | |||
| @@ -1268,6 +1269,7 @@ func NewContext() { | |||
| sec = Cfg.Section("homepage") | |||
| RecommentRepoAddr = sec.Key("Address").MustString("https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/") | |||
| ESSearchURL = sec.Key("ESSearchURL").MustString("http://192.168.207.94:9200") | |||
| INDEXPOSTFIX = sec.Key("INDEXPOSTFIX").MustString("") | |||
| sec = Cfg.Section("notice") | |||
| UserNameOfNoticeRepo = sec.Key("USER_NAME").MustString("OpenIOSSG") | |||
| @@ -2,6 +2,7 @@ package storage | |||
| import ( | |||
| "encoding/xml" | |||
| "errors" | |||
| "path" | |||
| "sort" | |||
| "strconv" | |||
| @@ -129,7 +130,7 @@ func NewMultiPartUpload(uuid string) (string, error) { | |||
| return core.NewMultipartUpload(bucketName, objectName, miniov6.PutObjectOptions{}) | |||
| } | |||
| func CompleteMultiPartUpload(uuid string, uploadID string) (string, error) { | |||
| func CompleteMultiPartUpload(uuid string, uploadID string, totalChunks int) (string, error) { | |||
| client, core, err := getClients() | |||
| if err != nil { | |||
| log.Error("getClients failed:", err.Error()) | |||
| @@ -146,6 +147,11 @@ func CompleteMultiPartUpload(uuid string, uploadID string) (string, error) { | |||
| return "", err | |||
| } | |||
| if len(partInfos) != totalChunks { | |||
| log.Error("ListObjectParts number(%d) is not equal the set total chunk number(%d)", len(partInfos), totalChunks) | |||
| return "", errors.New("the parts is not complete") | |||
| } | |||
| var complMultipartUpload completeMultipartUpload | |||
| for _, partInfo := range partInfos { | |||
| complMultipartUpload.Parts = append(complMultipartUpload.Parts, miniov6.CompletePart{ | |||
| @@ -30,6 +30,8 @@ type FileInfo struct { | |||
| } | |||
| type FileInfoList []FileInfo | |||
| const MAX_LIST_PARTS = 1000 | |||
| func (ulist FileInfoList) Swap(i, j int) { ulist[i], ulist[j] = ulist[j], ulist[i] } | |||
| func (ulist FileInfoList) Len() int { return len(ulist) } | |||
| func (ulist FileInfoList) Less(i, j int) bool { | |||
| @@ -57,21 +59,55 @@ func ObsHasObject(path string) (bool, error) { | |||
| return hasObject, nil | |||
| } | |||
| func listAllParts(uuid, uploadID, key string) (output *obs.ListPartsOutput, err error) { | |||
| output = &obs.ListPartsOutput{} | |||
| partNumberMarker := 0 | |||
| for { | |||
| temp, err := ObsCli.ListParts(&obs.ListPartsInput{ | |||
| Bucket: setting.Bucket, | |||
| Key: key, | |||
| UploadId: uploadID, | |||
| MaxParts: MAX_LIST_PARTS, | |||
| PartNumberMarker: partNumberMarker, | |||
| }) | |||
| if err != nil { | |||
| log.Error("ListParts failed:", err.Error()) | |||
| return output, err | |||
| } | |||
| partNumberMarker = temp.NextPartNumberMarker | |||
| log.Info("uuid:%s, MaxParts:%d, PartNumberMarker:%d, NextPartNumberMarker:%d, len:%d", uuid, temp.MaxParts, temp.PartNumberMarker, temp.NextPartNumberMarker, len(temp.Parts)) | |||
| for _, partInfo := range temp.Parts { | |||
| output.Parts = append(output.Parts, obs.Part{ | |||
| PartNumber: partInfo.PartNumber, | |||
| ETag: partInfo.ETag, | |||
| }) | |||
| } | |||
| if !temp.IsTruncated { | |||
| break | |||
| } else { | |||
| continue | |||
| } | |||
| break | |||
| } | |||
| return output, nil | |||
| } | |||
| func GetObsPartInfos(uuid, uploadID, fileName string) (string, error) { | |||
| key := strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/") | |||
| output, err := ObsCli.ListParts(&obs.ListPartsInput{ | |||
| Bucket: setting.Bucket, | |||
| Key: key, | |||
| UploadId: uploadID, | |||
| }) | |||
| allParts, err := listAllParts(uuid, uploadID, key) | |||
| if err != nil { | |||
| log.Error("ListParts failed:", err.Error()) | |||
| log.Error("listAllParts failed: %v", err) | |||
| return "", err | |||
| } | |||
| var chunks string | |||
| for _, partInfo := range output.Parts { | |||
| for _, partInfo := range allParts.Parts { | |||
| chunks += strconv.Itoa(partInfo.PartNumber) + "-" + partInfo.ETag + "," | |||
| } | |||
| @@ -92,34 +128,33 @@ func NewObsMultiPartUpload(uuid, fileName string) (string, error) { | |||
| return output.UploadId, nil | |||
| } | |||
| func CompleteObsMultiPartUpload(uuid, uploadID, fileName string) error { | |||
| func CompleteObsMultiPartUpload(uuid, uploadID, fileName string, totalChunks int) error { | |||
| input := &obs.CompleteMultipartUploadInput{} | |||
| input.Bucket = setting.Bucket | |||
| input.Key = strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, fileName)), "/") | |||
| input.UploadId = uploadID | |||
| output, err := ObsCli.ListParts(&obs.ListPartsInput{ | |||
| Bucket: setting.Bucket, | |||
| Key: input.Key, | |||
| UploadId: uploadID, | |||
| }) | |||
| allParts, err := listAllParts(uuid, uploadID, input.Key) | |||
| if err != nil { | |||
| log.Error("ListParts failed:", err.Error()) | |||
| log.Error("listAllParts failed: %v", err) | |||
| return err | |||
| } | |||
| for _, partInfo := range output.Parts { | |||
| input.Parts = append(input.Parts, obs.Part{ | |||
| PartNumber: partInfo.PartNumber, | |||
| ETag: partInfo.ETag, | |||
| }) | |||
| if len(allParts.Parts) != totalChunks { | |||
| log.Error("listAllParts number(%d) is not equal the set total chunk number(%d)", len(allParts.Parts), totalChunks) | |||
| return errors.New("the parts is not complete") | |||
| } | |||
| _, err = ObsCli.CompleteMultipartUpload(input) | |||
| input.Parts = allParts.Parts | |||
| output, err := ObsCli.CompleteMultipartUpload(input) | |||
| if err != nil { | |||
| log.Error("CompleteMultipartUpload failed:", err.Error()) | |||
| return err | |||
| } | |||
| log.Info("uuid:%s, RequestId:%s", uuid, output.RequestId) | |||
| return nil | |||
| } | |||
| @@ -17,6 +17,14 @@ type TopicResponse struct { | |||
| Updated time.Time `json:"updated"` | |||
| } | |||
| type ImageTopicResponse struct { | |||
| ID int64 `json:"id"` | |||
| Name string `json:"topic_name"` | |||
| ImageCount int `json:"image_count"` | |||
| Created time.Time `json:"created"` | |||
| Updated time.Time `json:"updated"` | |||
| } | |||
| // TopicName a list of repo topic names | |||
| type TopicName struct { | |||
| TopicNames []string `json:"topics"` | |||
| @@ -92,6 +92,7 @@ func NewFuncMap() []template.FuncMap { | |||
| "Safe": Safe, | |||
| "SafeJS": SafeJS, | |||
| "Str2html": Str2html, | |||
| "subOne": subOne, | |||
| "TimeSince": timeutil.TimeSince, | |||
| "TimeSinceUnix": timeutil.TimeSinceUnix, | |||
| "TimeSinceUnix1": timeutil.TimeSinceUnix1, | |||
| @@ -443,7 +444,10 @@ func SafeJS(raw string) template.JS { | |||
| func Str2html(raw string) template.HTML { | |||
| return template.HTML(markup.Sanitize(raw)) | |||
| } | |||
| // | |||
| func subOne(length int)int{ | |||
| return length-1 | |||
| } | |||
| // Escape escapes a HTML string | |||
| func Escape(raw string) string { | |||
| return html.EscapeString(raw) | |||
| @@ -266,6 +266,16 @@ search_related=related | |||
| search_maybe=maybe | |||
| search_ge= | |||
| wecome_AI_plt = Welcome to OpenI AI Collaboration Platform! | |||
| explore_AI = Explore better AI, come here to find more interesting | |||
| datasets = Datasets | |||
| repositories = Repositories | |||
| use_plt__fuction = To use the AI collaboration functions provided by this platform, such as: hosting code, sharing data, debugging algorithms or training models, start with | |||
| provide_resoure = Computing resources of CPU/GPU/NPU are provided freely for various types of AI tasks. | |||
| activity = Activity | |||
| no_events = There are no events related | |||
| or_t = or | |||
| [explore] | |||
| repos = Repositories | |||
| select_repos = Select the project | |||
| @@ -742,7 +752,7 @@ dataset_setting= Dataset Setting | |||
| title = Name | |||
| title_format_err=Name can only contain number,letter,'-','_' or '.', and can be up to 100 characters long. | |||
| description = Description | |||
| description_format_err=Description's length can be up to 1024 characters long. | |||
| description_format_err=Description's length can be up to %s characters long. | |||
| create_dataset = Create Dataset | |||
| create_dataset_fail=Failed to create dataset. | |||
| query_dataset_fail=Failed to query dataset. | |||
| @@ -895,7 +905,7 @@ readme_helper = Select a README file template. | |||
| auto_init = Initialize Repository (Adds .gitignore, License and README) | |||
| create_repo = Create Repository | |||
| create_course = Publish Course | |||
| failed_to_create_course=Fail to publish course, please try again later. | |||
| failed_to_create_course=Failed to publish course, please try again later. | |||
| default_branch = Default Branch | |||
| mirror_prune = Prune | |||
| mirror_prune_desc = Remove obsolete remote-tracking references | |||
| @@ -935,10 +945,28 @@ more=More | |||
| gpu_type_all=All | |||
| model_download=Model Download | |||
| submit_image=Submit Image | |||
| modify_image=Modify Image | |||
| image_exist=Image name has been used, please use a new one. | |||
| image_committing=Image is submitting, please try again later. | |||
| image_commit_fail=Failed to submit image, please try again later. | |||
| image_not_exist=Image does not exits. | |||
| image_edit_fail=Failed to edit image, please try again later. | |||
| 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 | |||
| images.name = Image Tag | |||
| images.name_placerholder = Please enter the image name | |||
| image.label_tooltips = Example Python 3.7, Tensorflow 2.0, cuda 10, pytorch 1.6 | |||
| images.public_tooltips = After the image is set to public, it can be seen by other users. | |||
| images.name_rule = Please enter letters, numbers, _ and - up to 64 characters and cannot end with a dash (-). | |||
| images.delete_task = Delete image | |||
| images.task_delete_confirm = Are you sure you want to delete this image? Once this image is deleted, it cannot be recovered. | |||
| cloudbrain=Cloudbrain | |||
| cloudbrain.task = Cloudbrain Task | |||
| cloudbrain.search = Seach Task Name | |||
| cloudbrain.new=New cloudbrain | |||
| cloudbrain.desc=Cloudbrain | |||
| cloudbrain.cancel=Cancel | |||
| @@ -971,7 +999,7 @@ total_count_get_error=Can not get the total page. | |||
| last_update_time_error=Can not get the last updated time. | |||
| get_repo_stat_error=Can not get the statistics of the repository. | |||
| get_repo_info_error=Can not get the information of the repository. | |||
| generate_statistic_file_error=Fail to generate file. | |||
| generate_statistic_file_error=Failed to generate file. | |||
| repo_stat_inspect=ProjectAnalysis | |||
| all=All | |||
| @@ -1121,7 +1149,7 @@ form.name_reserved = The repository name '%s' is reserved. | |||
| form.course_name_reserved=The course name '%s' is reserved. | |||
| form.name_pattern_not_allowed = The pattern '%s' is not allowed in a repository name. | |||
| form.course_name_pattern_not_allowed=The pattern '%s' is not allowed in a course name. | |||
| add_course_org_fail=Fail to add organization, please try again later. | |||
| add_course_org_fail=Failed to add organization, please try again later. | |||
| need_auth = Clone Authorization | |||
| migrate_type = Migration Type | |||
| @@ -1361,6 +1389,7 @@ issues.filter_sort.feweststars = Fewest stars | |||
| issues.filter_sort.mostforks = Most forks | |||
| issues.filter_sort.fewestforks = Fewest forks | |||
| issues.filter_sort.downloadtimes = Most downloaded | |||
| issues.filter_sort.moststars = Most star | |||
| issues.action_open = Open | |||
| issues.action_close = Close | |||
| issues.action_label = Label | |||
| @@ -2165,6 +2194,7 @@ topic.manage_topics = Manage Topics | |||
| topic.done = Done | |||
| topic.count_prompt = You can not select more than 25 topics | |||
| topic.format_prompt = Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long. | |||
| imagetopic.format_prompt = Topics can be up to 35 characters long. | |||
| [org] | |||
| org_name_holder = Organization Name | |||
| @@ -2473,11 +2503,15 @@ repos.contributor=Contributor | |||
| repos.yes=Yes | |||
| repos.no=No | |||
| images.recommend = Recommend | |||
| images.unrecommend = Unrecommend | |||
| datasets.dataset_manage_panel= Dataset Manage | |||
| datasets.owner=Owner | |||
| datasets.name=name | |||
| datasets.private=Private | |||
| datasets.recommend=Set recommend | |||
| datasets.unrecommend=Set unrecommend | |||
| cloudbrain.all_task_types=All Task Types | |||
| cloudbrain.all_computing_resources=All Computing Resources | |||
| @@ -2825,7 +2859,7 @@ mirror_sync_create = synced new reference <a href="%s/src/%s">%[2]s</a> to <a hr | |||
| mirror_sync_delete = synced and deleted reference <code>%[2]s</code> at <a href="%[1]s">%[3]s</a> from mirror | |||
| approve_pull_request = `approved <a href="%s/pulls/%s">%s#%[2]s</a>` | |||
| reject_pull_request = `suggested changes for <a href="%s/pulls/%s">%s#%[2]s</a>` | |||
| upload_dataset=`upload dataset <a href="%s/datasets?type=%s">%s</a>` | |||
| upload_dataset=`upload dataset <a href="%s/datasets">%s</a>` | |||
| task_gpudebugjob=`created CPU/GPU type debugging task<a href="%s/cloudbrain/%s">%s</a>` | |||
| task_npudebugjob=`created NPU type debugging task <a href="%s/modelarts/notebook/%s">%s</a>` | |||
| task_nputrainjob=`created NPU training task<a href="%s/modelarts/train-job/%s">%s</a>` | |||
| @@ -2935,6 +2969,7 @@ snn4imagenet_path = Snn4imagenet script path | |||
| brainscore_path = Brainscore script path | |||
| start_command = Start command | |||
| choose_mirror = select mirror or enter mirror path | |||
| input_mirror = Please enter image path | |||
| select_dataset = select dataset | |||
| specification = specification | |||
| select_specification = select specification | |||
| @@ -2955,3 +2990,11 @@ gpu_num = GPU | |||
| cpu_num = CPU | |||
| memory = Memory | |||
| shared_memory = Shared Memory | |||
| DEBUG = DEBUG | |||
| SNN4IMAGENET = SNN4IMAGENET | |||
| BRAINSCORE = BRAINSCORE | |||
| TRAIN = TRAIN | |||
| INFERENCE = INFERENCE | |||
| BENCHMARK = BENCHMARK | |||
| @@ -268,6 +268,18 @@ search_related=相关 | |||
| search_maybe=约为 | |||
| search_ge=个 | |||
| wecome_AI_plt=欢迎来到启智AI协作平台! | |||
| explore_AI = 探索更好的AI,来这里发现更有意思的 | |||
| datasets = 数据集 | |||
| repositories = 项目 | |||
| use_plt__fuction = 使用本平台提供的AI协作功能,如:托管代码、共享数据、调试算法或训练模型,请先 | |||
| provide_resoure = 平台目前免费提供CPU、GPU、NPU的算力资源,可进行多种类型的AI任务。 | |||
| create_pro = 创建项目 | |||
| activity = 活动 | |||
| no_events = 还没有与您相关的活动 | |||
| or_t = 或 | |||
| [explore] | |||
| repos=项目 | |||
| select_repos=精选项目 | |||
| @@ -745,7 +757,7 @@ dataset_setting=数据集设置 | |||
| title=名称 | |||
| title_format_err=名称最多允许输入100个字符,只允许字母,数字,中划线 (‘-’),下划线 (‘_’) 和点 (‘.’) 。 | |||
| description=描述 | |||
| description_format_err=描述最多允许输入1024个字符。 | |||
| description_format_err=描述最多允许输入%s个字符。 | |||
| create_dataset=创建数据集 | |||
| create_dataset_fail=创建数据集失败。 | |||
| query_dataset_fail=查询数据集失败。 | |||
| @@ -934,10 +946,29 @@ more=更多 | |||
| gpu_type_all=全部 | |||
| model_download=结果下载 | |||
| submit_image=提交镜像 | |||
| modify_image=修改镜像 | |||
| image_exist=镜像Tag已被使用,请修改镜像Tag。 | |||
| image_committing=镜像正在提交中,请稍后再试。 | |||
| image_commit_fail=提交镜像失败,请稍后再试。 | |||
| image_not_exist=镜像不存在。 | |||
| image_edit_fail=编辑镜像失败,请稍后再试。 | |||
| image_delete_fail=删除镜像失败,请稍后再试。 | |||
| image_overwrite=您已经提交过相同名称的镜像,您确定要覆盖原来提交的镜像吗? | |||
| download=模型下载 | |||
| score=评分 | |||
| images.name = 镜像Tag | |||
| images.name_placerholder = 请输入镜像Tag | |||
| image.label_tooltips = 如Python 3.7, Tensorflow 2.0, cuda 10, pytorch 1.6 | |||
| images.public_tooltips = 镜像设置为公开后,可被其他用户看到。 | |||
| images.name_rule = 请输入字母、数字、_和-,最长100个字符,且不能以中划线(-)结尾。 | |||
| images.delete_task = 删除镜像 | |||
| images.task_delete_confirm = 你确认删除该镜像么?此镜像一旦删除不可恢复。 | |||
| cloudbrain=云脑 | |||
| cloudbrain.task = 云脑任务 | |||
| cloudbrain.search = 搜索任务名称 | |||
| cloudbrain.new=新建任务 | |||
| cloudbrain.desc=云脑功能 | |||
| cloudbrain.cancel=取消 | |||
| @@ -1015,7 +1046,9 @@ modelarts.train_job.basic_info=基本信息 | |||
| modelarts.train_job.job_status=任务状态 | |||
| modelarts.train_job.job_name=任务名称 | |||
| modelarts.train_job.version=任务版本 | |||
| modelarts.train_job.start_time=开始时间 | |||
| modelarts.train_job.start_time=开始运行时间 | |||
| modelarts.train_job.end_time=运行结束时间 | |||
| modelarts.train_job.wait_time=等待时间 | |||
| modelarts.train_job.dura_time=运行时长 | |||
| modelarts.train_job.description=任务描述 | |||
| modelarts.train_job.parameter_setting=参数设置 | |||
| @@ -1368,6 +1401,7 @@ issues.filter_sort.feweststars=点赞由少到多 | |||
| issues.filter_sort.mostforks=派生由多到少 | |||
| issues.filter_sort.fewestforks=派生由少到多 | |||
| issues.filter_sort.downloadtimes=下载次数 | |||
| issues.filter_sort.moststars=收藏数量 | |||
| issues.action_open=开启 | |||
| issues.action_close=关闭 | |||
| issues.action_label=标签 | |||
| @@ -2168,8 +2202,9 @@ branch.included=已包含 | |||
| topic.manage_topics=管理主题 | |||
| topic.done=保存 | |||
| topic.count_prompt=您最多选择25个主题 | |||
| topic.format_prompt=主题必须以中文、字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符 | |||
| topic.count_prompt=您最多选择25个标签 | |||
| topic.format_prompt=标签必须以中文、字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符 | |||
| imagetopic.format_prompt=标签长度不得超过35个字符 | |||
| [org] | |||
| org_name_holder=组织名称 | |||
| @@ -2478,11 +2513,15 @@ repos.contributor=贡献者数 | |||
| repos.yes=是 | |||
| repos.no=否 | |||
| images.recommend = 推荐 | |||
| images.unrecommend = 不推荐 | |||
| datasets.dataset_manage_panel=数据集管理 | |||
| datasets.owner=所有者 | |||
| datasets.name=名称 | |||
| datasets.private=私有 | |||
| datasets.recommend=设为推荐 | |||
| datasets.unrecommend=取消推荐 | |||
| cloudbrain.all_task_types=全部任务类型 | |||
| cloudbrain.all_computing_resources=全部计算资源 | |||
| @@ -2830,7 +2869,7 @@ mirror_sync_create=从镜像同步了新的引用 <a href="%s/src/%s">%[2]s</a> | |||
| mirror_sync_delete=从镜像同步并从 <a href="%[1]s">%[3]s</a> 删除了引用 <code>%[2]s</code> | |||
| approve_pull_request=`同意了 <a href="%s/pulls/%s">%s#%[2]s</a>` | |||
| reject_pull_request=`建议变更 <a href="%s/pulls/%s">%s#%[2]s</a>` | |||
| upload_dataset=`上传了数据集文件 <a href="%s/datasets?type=%s">%s</a>` | |||
| upload_dataset=`上传了数据集文件 <a href="%s/datasets">%s</a>` | |||
| task_gpudebugjob=`创建了CPU/GPU类型调试任务 <a href="%s/cloudbrain/%s">%s</a>` | |||
| task_npudebugjob=`创建了NPU类型调试任务 <a href="%s/modelarts/notebook/%s">%s</a>` | |||
| task_nputrainjob=`创建了NPU类型训练任务 <a href="%s/modelarts/train-job/%s">%s</a>` | |||
| @@ -2940,6 +2979,7 @@ snn4imagenet_path = snn4imagenet脚本存放路径 | |||
| brainscore_path = brainscore脚本存放路径 | |||
| start_command = 启动命令 | |||
| choose_mirror = 选择镜像或输入镜像地址 | |||
| input_mirror = 请输入云脑镜像地址 | |||
| select_dataset = 选择数据集 | |||
| specification = 规格 | |||
| select_specification = 选择资源规格 | |||
| @@ -2956,8 +2996,16 @@ task_delete_confirm = 你确认删除该任务么?此任务一旦删除不可 | |||
| operate_confirm = 确定操作 | |||
| operate_cancel = 取消操作 | |||
| gpu_num = GPU数 | |||
| cpu_num = CPU数 | |||
| memory = 内存 | |||
| shared_memory = 共享内存 | |||
| DEBUG = 调试任务 | |||
| SNN4IMAGENET = 调试任务-脉冲神经网络图片分类测评 | |||
| BRAINSCORE = 调试任务-神经相似性测评 | |||
| TRAIN = 训练任务 | |||
| INFERENCE = 推理任务 | |||
| BENCHMARK = 评测任务 | |||
| @@ -99,6 +99,11 @@ socket.onmessage = function (e) { | |||
| console.log("receive action type=" + record.OpType + " name=" + actionName + " but user is null."); | |||
| continue; | |||
| } | |||
| if(record.OpType == "24"){ | |||
| if(record.Content.indexOf("true") != -1){ | |||
| continue; | |||
| } | |||
| } | |||
| var recordPrefix = getMsg(record); | |||
| if(record.OpType == "6" || record.OpType == "10" || record.OpType == "12" || record.OpType == "13"){ | |||
| html += recordPrefix + actionName; | |||
| @@ -162,7 +167,7 @@ socket.onmessage = function (e) { | |||
| function getTaskLink(record){ | |||
| var re = getRepoLink(record); | |||
| if(record.OpType == 24){ | |||
| re = re + "/datasets?type=" + record.Content; | |||
| re = re + "/datasets"; | |||
| }else if(record.OpType == 25){ | |||
| re = re + "/cloudbrain/" + record.Content; | |||
| }else if(record.OpType == 26){ | |||
| @@ -101,16 +101,20 @@ function initPageInfo(){ | |||
| function searchItem(type,sortType){ | |||
| console.log("enter item 2."); | |||
| currentSearchKeyword = document.getElementById("keyword_input").value; | |||
| if(!isEmpty(currentSearchKeyword)){ | |||
| initPageInfo(); | |||
| currentSearchTableName = itemType[type]; | |||
| currentSearchSortBy = sortBy[sortType]; | |||
| currentSearchAscending = sortAscending[sortType]; | |||
| OnlySearchLabel =false; | |||
| page(currentPage); | |||
| if(OnlySearchLabel){ | |||
| doSearchLabel(currentSearchTableName,currentSearchKeyword,sortBy[sortType],sortAscending[sortType]) | |||
| }else{ | |||
| emptySearch(); | |||
| currentSearchKeyword = document.getElementById("keyword_input").value; | |||
| if(!isEmpty(currentSearchKeyword)){ | |||
| initPageInfo(); | |||
| currentSearchTableName = itemType[type]; | |||
| currentSearchSortBy = sortBy[sortType]; | |||
| currentSearchAscending = sortAscending[sortType]; | |||
| OnlySearchLabel =false; | |||
| page(currentPage); | |||
| }else{ | |||
| emptySearch(); | |||
| } | |||
| } | |||
| } | |||
| @@ -806,17 +810,21 @@ var repoAndOrgEN={ | |||
| function page(current){ | |||
| currentPage=current; | |||
| startIndex = currentPage -1; | |||
| if(startIndex < 1){ | |||
| startIndex = 1; | |||
| } | |||
| endIndex = currentPage + 2; | |||
| if(endIndex >= totalPage){ | |||
| endIndex = totalPage; | |||
| } | |||
| doSearch(currentSearchTableName,currentSearchKeyword,current,pageSize,false,currentSearchSortBy,OnlySearchLabel); | |||
| } | |||
| function nextPage(){ | |||
| currentPage = currentPage+1; | |||
| console.log("currentPage=" + currentPage); | |||
| if(currentPage >= endIndex){ | |||
| startIndex=startIndex+1; | |||
| endIndex = endIndex +1; | |||
| } | |||
| page(currentPage); | |||
| } | |||
| @@ -824,10 +832,6 @@ function page(current){ | |||
| console.log("currentPage=" + currentPage); | |||
| if(currentPage > 1){ | |||
| currentPage = currentPage-1; | |||
| if(currentPage <= startIndex && startIndex > 1){ | |||
| startIndex = startIndex -1; | |||
| endIndex = endIndex - 1; | |||
| } | |||
| console.log("currentPage=" + (currentPage)); | |||
| page(currentPage); | |||
| } | |||
| @@ -862,7 +866,7 @@ function getYPosition(e){ | |||
| showTip(getLabel(isZh,"search_input_large_0"),"warning",left+5,top); | |||
| } | |||
| else if(goNum<=totalPage){ | |||
| page(goNum); | |||
| page(parseInt(goNum,10)); | |||
| } | |||
| else{ | |||
| showTip(getLabel(isZh,"search_input_maxed"),"warning",left+5,top); | |||
| @@ -908,6 +912,11 @@ function getYPosition(e){ | |||
| } | |||
| } | |||
| if (endIndex < totalPage-1){ | |||
| html += "..."; | |||
| html += "<a id=\"page_" + totalPage+ "\" class=\"item\" href=\"javascript:page(" + totalPage +")\">" + totalPage + "</a>"; | |||
| } | |||
| if(currentPage >=totalPage){ | |||
| html += "<a class=\"disabled item navigation\" href=\"javascript:nextPage()\"><i class=\"icon right arrow\"></i></a>"; | |||
| html += "<a class=\"disabled item navigation\" href=\"javascript:page(" + totalPage + ")\"><span class=\"navigation_label\">" + getLabel(isZh,"search_last_page") + "</span></a>"; | |||
| @@ -0,0 +1 @@ | |||
| <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15.999999999999432" height="16.000000000000455"><path d="M0 14L0 2Q0 1.90175 0.00963055 1.80397Q0.0192611 1.70619 0.0384294 1.60982Q0.0575978 1.51345 0.0861193 1.41943Q0.114641 1.32541 0.152241 1.23463Q0.189841 1.14386 0.236157 1.05721Q0.282474 0.970554 0.337061 0.888859Q0.391648 0.807164 0.453979 0.731213Q0.516311 0.655262 0.585786 0.585786Q0.655262 0.516311 0.731213 0.453979Q0.807164 0.391648 0.888859 0.337061Q0.970554 0.282474 1.05721 0.236157Q1.14386 0.189841 1.23463 0.152241Q1.32541 0.114641 1.41943 0.0861193Q1.51345 0.0575978 1.60982 0.0384294Q1.70619 0.0192611 1.80397 0.00963055Q1.90175 0 2 0L14 0Q14.0983 0 14.196 0.00963055Q14.2938 0.0192611 14.3902 0.0384294Q14.4865 0.0575978 14.5806 0.0861193Q14.6746 0.114641 14.7654 0.152241Q14.8561 0.189841 14.9428 0.236157Q15.0294 0.282474 15.1111 0.337061Q15.1928 0.391648 15.2688 0.453979Q15.3447 0.516311 15.4142 0.585786Q15.4837 0.655262 15.546 0.731213Q15.6084 0.807164 15.6629 0.888859Q15.7175 0.970554 15.7638 1.05721Q15.8102 1.14386 15.8478 1.23463Q15.8854 1.32541 15.9139 1.41943Q15.9424 1.51345 15.9616 1.60982Q15.9807 1.70619 15.9904 1.80397Q16 1.90175 16 2L16 14Q16 14.0983 15.9904 14.196Q15.9807 14.2938 15.9616 14.3902Q15.9424 14.4865 15.9139 14.5806Q15.8854 14.6746 15.8478 14.7654Q15.8102 14.8561 15.7638 14.9428Q15.7175 15.0294 15.6629 15.1111Q15.6084 15.1928 15.546 15.2688Q15.4837 15.3447 15.4142 15.4142Q15.3447 15.4837 15.2688 15.546Q15.1928 15.6084 15.1111 15.6629Q15.0294 15.7175 14.9428 15.7638Q14.8561 15.8102 14.7654 15.8478Q14.6746 15.8854 14.5806 15.9139Q14.4865 15.9424 14.3902 15.9616Q14.2938 15.9807 14.196 15.9904Q14.0983 16 14 16L2 16Q1.90175 16 1.80397 15.9904Q1.70619 15.9807 1.60982 15.9616Q1.51345 15.9424 1.41943 15.9139Q1.32541 15.8854 1.23463 15.8478Q1.14386 15.8102 1.05721 15.7638Q0.970554 15.7175 0.888859 15.6629Q0.807164 15.6084 0.731213 15.546Q0.655262 15.4837 0.585786 15.4142Q0.516311 15.3447 0.453979 15.2688Q0.391648 15.1928 0.337061 15.1111Q0.282474 15.0294 0.236157 14.9428Q0.189841 14.8561 0.152241 14.7654Q0.114641 14.6746 0.0861193 14.5806Q0.0575978 14.4865 0.0384294 14.3902Q0.0192611 14.2938 0.00963055 14.196Q0 14.0983 0 14Z" style="mix-blend-mode:normal" fill="#5ab06f"></path><path d="M354.396 154.975L354.796 154.975L355.196 154.975L355.196 154.067L358.383 154.067L358.383 154.975L358.783 154.975L359.182 154.975L359.182 154.067L361.714 154.067L361.714 153.322L359.182 153.322L359.182 152.479L358.383 152.479L358.383 153.322L355.196 153.322L355.196 152.479L354.396 152.479L354.396 153.322L351.865 153.322L351.865 154.067L354.396 154.067L354.396 154.975ZM361.613 155.88L361.613 156.251L358.544 156.251L355.475 156.251C355.12 156.874 354.708 157.452 354.264 157.983L354.264 162.601L353.486 162.601L353.486 160.704L353.486 158.807C353.066 159.216 352.632 159.593 352.155 159.904C352.055 159.75 351.768 159.406 351.589 159.248C352.765 158.527 353.787 157.495 354.564 156.251L353.26 156.251L351.955 156.251L351.955 155.508L354.995 155.508C355.174 155.175 355.34 154.831 355.475 154.476L356.261 154.687C356.139 154.964 356.017 155.243 355.884 155.508L361.613 155.508L361.613 155.88ZM361.757 159.384L360.303 159.384L358.849 159.384L358.849 158.929C359.592 158.56 360.391 158.04 360.947 157.517L360.448 157.129L360.291 157.172L355.863 157.172L355.863 157.839L357.672 157.839L359.48 157.839C359.047 158.14 358.527 158.438 358.06 158.649L358.06 159.384L356.54 159.384L355.02 159.384L355.02 160.105L358.06 160.105L358.06 161.704C358.06 161.836 358.003 161.869 357.838 161.88C357.695 161.891 357.128 161.901 356.508 161.88C356.616 162.08 356.741 162.357 356.784 162.579C357.594 162.579 358.104 162.579 358.437 162.457C358.76 162.335 358.849 162.145 358.849 161.714L358.849 160.105L361.757 160.105L361.757 159.384Z" style="mix-blend-mode:normal" fill-rule="evenodd" fill="#ffffff" transform="translate(-348.8095656435228, -149.81200615956308)"></path></svg> | |||
| @@ -20,6 +20,8 @@ import ( | |||
| const ( | |||
| tplCloudBrains base.TplName = "admin/cloudbrain/list" | |||
| tplImages base.TplName = "admin/cloudbrain/images" | |||
| tplCommitImages base.TplName = "admin/cloudbrain/imagecommit" | |||
| EXCEL_DATE_FORMAT = "20060102150405" | |||
| CREATE_TIME_FORMAT = "2006/01/02 15:04:05" | |||
| ) | |||
| @@ -107,6 +109,18 @@ func CloudBrains(ctx *context.Context) { | |||
| } | |||
| func Images(ctx *context.Context) { | |||
| ctx.Data["PageIsAdminImages"] = true | |||
| ctx.HTML(200, tplImages) | |||
| } | |||
| func CloudBrainCommitImageShow(ctx *context.Context) { | |||
| ctx.Data["PageIsAdminImages"] = true | |||
| ctx.HTML(200, tplCommitImages) | |||
| } | |||
| func DownloadCloudBrains(ctx *context.Context) { | |||
| page := 1 | |||
| @@ -1,6 +1,8 @@ | |||
| package admin | |||
| import ( | |||
| "net/http" | |||
| "strconv" | |||
| "strings" | |||
| "code.gitea.io/gitea/models" | |||
| @@ -49,6 +51,8 @@ func Datasets(ctx *context.Context) { | |||
| orderBy = models.SearchOrderBySizeReverse | |||
| case "size": | |||
| orderBy = models.SearchOrderBySize | |||
| case "downloadtimes": | |||
| orderBy = models.SearchOrderByDownloadTimes | |||
| case "moststars": | |||
| orderBy = models.SearchOrderByStarsReverse | |||
| case "feweststars": | |||
| @@ -70,6 +74,7 @@ func Datasets(ctx *context.Context) { | |||
| PageSize: setting.UI.ExplorePagingNum, | |||
| }, | |||
| Keyword: keyword, | |||
| RecommendOnly: ctx.QueryBool("recommend"), | |||
| SearchOrderBy: orderBy, | |||
| }) | |||
| if err != nil { | |||
| @@ -80,7 +85,7 @@ func Datasets(ctx *context.Context) { | |||
| ctx.Data["Keyword"] = keyword | |||
| ctx.Data["Total"] = count | |||
| ctx.Data["Datasets"] = datasets | |||
| ctx.Data["Recommend"] = ctx.QueryBool("recommend") | |||
| pager := context.NewPagination(int(count), setting.UI.ExplorePagingNum, page, 5) | |||
| pager.SetDefaultParams(ctx) | |||
| ctx.Data["Page"] = pager | |||
| @@ -88,6 +93,23 @@ func Datasets(ctx *context.Context) { | |||
| ctx.HTML(200, tplDatasets) | |||
| } | |||
| func DatasetAction(ctx *context.Context) { | |||
| var err error | |||
| datasetId, _ := strconv.ParseInt(ctx.Params(":id"), 10, 64) | |||
| switch ctx.Params(":action") { | |||
| case "recommend": | |||
| err = models.RecommendDataset(datasetId, true) | |||
| case "unrecommend": | |||
| err = models.RecommendDataset(datasetId, false) | |||
| } | |||
| if err != nil { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("repo.star_fail", ctx.Params(":action")))) | |||
| } else { | |||
| ctx.JSON(http.StatusOK, models.BaseOKMessage) | |||
| } | |||
| } | |||
| func DeleteDataset(ctx *context.Context) { | |||
| dataset, err := models.GetDatasetByID(ctx.QueryInt64("id")) | |||
| if err != nil { | |||
| @@ -557,6 +557,10 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Get("/query_user_last_month", operationReq, repo_ext.QueryUserStaticLastMonth) | |||
| m.Get("/query_user_yesterday", operationReq, repo_ext.QueryUserStaticYesterday) | |||
| m.Get("/query_user_all", operationReq, repo_ext.QueryUserStaticAll) | |||
| //cloudbrain board | |||
| m.Group("/cloudbrainboard", func() { | |||
| m.Get("/downloadAll", repo.DownloadCloudBrainBoard) | |||
| }, operationReq) | |||
| // Users | |||
| m.Group("/users", func() { | |||
| m.Get("/search", user.Search) | |||
| @@ -1007,6 +1011,9 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Group("/topics", func() { | |||
| m.Get("/search", repo.TopicSearch) | |||
| }) | |||
| m.Group("/image/topics", func() { | |||
| m.Get("/search", repo.ImageTopicSearch) | |||
| }) | |||
| m.Group("/from_wechat", func() { | |||
| m.Get("/event", authentication.ValidEventSource) | |||
| m.Post("/event", authentication.AcceptWechatEvent) | |||
| @@ -0,0 +1,135 @@ | |||
| package repo | |||
| import ( | |||
| "net/http" | |||
| "net/url" | |||
| "time" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "github.com/360EntSecGroup-Skylar/excelize/v2" | |||
| ) | |||
| func DownloadCloudBrainBoard(ctx *context.Context) { | |||
| page := 1 | |||
| pageSize := 300 | |||
| var cloudBrain = ctx.Tr("repo.cloudbrain") | |||
| fileName := getCloudbrainFileName(cloudBrain) | |||
| _, total, err := models.CloudbrainAll(&models.CloudbrainsOptions{ | |||
| ListOptions: models.ListOptions{ | |||
| Page: page, | |||
| PageSize: 1, | |||
| }, | |||
| Type: models.TypeCloudBrainAll, | |||
| NeedRepoInfo: false, | |||
| }) | |||
| if err != nil { | |||
| log.Warn("Can not get cloud brain info", err) | |||
| ctx.Error(http.StatusBadRequest, ctx.Tr("repo.cloudbrain_query_fail")) | |||
| return | |||
| } | |||
| totalPage := getTotalPage(total, pageSize) | |||
| f := excelize.NewFile() | |||
| index := f.NewSheet(cloudBrain) | |||
| f.DeleteSheet("Sheet1") | |||
| for k, v := range allCloudbrainHeader(ctx) { | |||
| f.SetCellValue(cloudBrain, k, v) | |||
| } | |||
| var row = 2 | |||
| for i := 0; i < totalPage; i++ { | |||
| pageRecords, _, err := models.CloudbrainAll(&models.CloudbrainsOptions{ | |||
| ListOptions: models.ListOptions{ | |||
| Page: page, | |||
| PageSize: pageSize, | |||
| }, | |||
| Type: models.TypeCloudBrainAll, | |||
| NeedRepoInfo: true, | |||
| }) | |||
| if err != nil { | |||
| log.Warn("Can not get cloud brain info", err) | |||
| continue | |||
| } | |||
| for _, record := range pageRecords { | |||
| for k, v := range allCloudbrainValues(row, record, ctx) { | |||
| f.SetCellValue(cloudBrain, k, v) | |||
| } | |||
| row++ | |||
| } | |||
| page++ | |||
| } | |||
| f.SetActiveSheet(index) | |||
| ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+url.QueryEscape(fileName)) | |||
| ctx.Resp.Header().Set("Content-Type", "application/octet-stream") | |||
| f.WriteTo(ctx.Resp) | |||
| } | |||
| func getCloudbrainFileName(baseName string) string { | |||
| return baseName + "_" + time.Now().Format(EXCEL_DATE_FORMAT) + ".xlsx" | |||
| } | |||
| func allCloudbrainHeader(ctx *context.Context) map[string]string { | |||
| return map[string]string{"A1": ctx.Tr("repo.cloudbrain_task"), "B1": ctx.Tr("repo.cloudbrain_task_type"), "C1": ctx.Tr("repo.modelarts.status"), | |||
| "D1": ctx.Tr("repo.modelarts.createtime"), "E1": ctx.Tr("repo.modelarts.train_job.wait_time"), "F1": ctx.Tr("repo.modelarts.train_job.dura_time"), | |||
| "G1": ctx.Tr("repo.modelarts.train_job.start_time"), | |||
| "H1": ctx.Tr("repo.modelarts.train_job.end_time"), "I1": ctx.Tr("repo.modelarts.computing_resources"), | |||
| "J1": ctx.Tr("repo.cloudbrain_creator"), "K1": ctx.Tr("repo.repo_name"), "L1": ctx.Tr("repo.cloudbrain_task_name")} | |||
| } | |||
| func allCloudbrainValues(row int, rs *models.CloudbrainInfo, ctx *context.Context) map[string]string { | |||
| return map[string]string{getCellName("A", row): rs.DisplayJobName, getCellName("B", row): rs.JobType, getCellName("C", row): rs.Status, | |||
| getCellName("D", row): time.Unix(int64(rs.Cloudbrain.CreatedUnix), 0).Format(CREATE_TIME_FORMAT), getCellName("E", row): getBrainWaitTime(rs), | |||
| getCellName("F", row): rs.TrainJobDuration, getCellName("G", row): getBrainStartTime(rs), | |||
| getCellName("H", row): getBrainEndTime(rs), | |||
| getCellName("I", row): rs.ComputeResource, getCellName("J", row): rs.Name, getCellName("K", row): getBrainRepo(rs), | |||
| getCellName("L", row): rs.JobName, | |||
| } | |||
| } | |||
| func getBrainRepo(rs *models.CloudbrainInfo) string { | |||
| if rs.Repo != nil { | |||
| return rs.Repo.OwnerName + "/" + rs.Repo.Alias | |||
| } | |||
| return "" | |||
| } | |||
| func getBrainStartTime(rs *models.CloudbrainInfo) string { | |||
| timeString := time.Unix(int64(rs.Cloudbrain.StartTime), 0).Format(CREATE_TIME_FORMAT) | |||
| if timeString != "1970/01/01 08:00:00" { | |||
| return timeString | |||
| } else { | |||
| return "0" | |||
| } | |||
| } | |||
| func getBrainEndTime(rs *models.CloudbrainInfo) string { | |||
| timeString := time.Unix(int64(rs.Cloudbrain.EndTime), 0).Format(CREATE_TIME_FORMAT) | |||
| if timeString != "1970/01/01 08:00:00" { | |||
| return timeString | |||
| } else { | |||
| return "0" | |||
| } | |||
| } | |||
| func getBrainWaitTime(rs *models.CloudbrainInfo) string { | |||
| waitTime := rs.Cloudbrain.StartTime - rs.Cloudbrain.CreatedUnix | |||
| if waitTime <= 0 { | |||
| return "0" | |||
| } else { | |||
| return models.ConvertDurationToStr(int64(waitTime)) | |||
| } | |||
| } | |||
| @@ -74,6 +74,7 @@ func GetModelArtsNotebook2(ctx *context.APIContext) { | |||
| if job.EndTime == 0 && models.IsModelArtsDebugJobTerminal(job.Status) { | |||
| job.EndTime = timeutil.TimeStampNow() | |||
| } | |||
| job.CorrectCreateUnix() | |||
| job.ComputeAndSetDuration() | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| @@ -160,6 +161,7 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||
| } | |||
| if result.JobStatus.State != string(models.JobWaiting) { | |||
| models.ParseAndSetDurationFromCloudBrainOne(result, job) | |||
| err = models.UpdateJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| @@ -177,14 +179,12 @@ func GetModelArtsTrainJobVersion(ctx *context.APIContext) { | |||
| } | |||
| job.Status = modelarts.TransTrainJobStatus(result.IntStatus) | |||
| job.Duration = result.Duration / 1000 | |||
| job.TrainJobDuration = result.TrainJobDuration | |||
| 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() | |||
| err = models.UpdateTrainJobVersion(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| @@ -417,7 +417,7 @@ func GetModelArtsInferenceJob(ctx *context.APIContext) { | |||
| if job.EndTime == 0 && models.IsTrainJobTerminal(job.Status) && job.StartTime > 0 { | |||
| job.EndTime = job.StartTime.Add(job.Duration) | |||
| } | |||
| job.CorrectCreateUnix() | |||
| err = models.UpdateInferenceJob(job) | |||
| if err != nil { | |||
| log.Error("UpdateJob failed:", err) | |||
| @@ -300,3 +300,63 @@ func TopicSearch(ctx *context.APIContext) { | |||
| "topics": topicResponses, | |||
| }) | |||
| } | |||
| func ImageTopicSearch(ctx *context.APIContext) { | |||
| // swagger:operation GET /image/topics/search image topicSearch | |||
| // --- | |||
| // summary: search topics via keyword | |||
| // produces: | |||
| // - application/json | |||
| // parameters: | |||
| // - name: q | |||
| // in: query | |||
| // description: keywords to search | |||
| // required: true | |||
| // type: string | |||
| // - name: page | |||
| // in: query | |||
| // description: page number of results to return (1-based) | |||
| // type: integer | |||
| // - name: limit | |||
| // in: query | |||
| // description: page size of results, maximum page size is 50 | |||
| // type: integer | |||
| // responses: | |||
| // "200": | |||
| // "$ref": "#/responses/TopicListResponse" | |||
| // "403": | |||
| // "$ref": "#/responses/forbidden" | |||
| if ctx.User == nil { | |||
| ctx.Error(http.StatusForbidden, "UserIsNil", "Only owners could change the topics.") | |||
| return | |||
| } | |||
| kw := ctx.Query("q") | |||
| listOptions := utils.GetListOptions(ctx) | |||
| if listOptions.Page < 1 { | |||
| listOptions.Page = 1 | |||
| } | |||
| if listOptions.PageSize < 1 { | |||
| listOptions.PageSize = 10 | |||
| } | |||
| topics, err := models.FindImageTopics(&models.FindImageTopicOptions{ | |||
| Keyword: kw, | |||
| ListOptions: listOptions, | |||
| }) | |||
| if err != nil { | |||
| log.Error("SearchImageTopics failed: %v", err) | |||
| ctx.InternalServerError(err) | |||
| return | |||
| } | |||
| topicResponses := make([]*api.ImageTopicResponse, len(topics)) | |||
| for i, topic := range topics { | |||
| topicResponses[i] = convert.ToImageTopicResponse(topic) | |||
| } | |||
| ctx.JSON(http.StatusOK, map[string]interface{}{ | |||
| "topics": topicResponses, | |||
| }) | |||
| } | |||
| @@ -331,6 +331,7 @@ func ExploreDatasets(ctx *context.Context) { | |||
| Task: task, | |||
| License: license, | |||
| OwnerID: ownerID, | |||
| RecommendOnly: ctx.QueryBool("recommend"), | |||
| ListOptions: models.ListOptions{ | |||
| Page: page, | |||
| PageSize: 30, | |||
| @@ -357,6 +358,7 @@ func ExploreDatasets(ctx *context.Context) { | |||
| ctx.Data["Category"] = category | |||
| ctx.Data["Task"] = task | |||
| ctx.Data["License"] = license | |||
| ctx.Data["Recommend"] = ctx.QueryBool("recommend") | |||
| pager.SetDefaultParams(ctx) | |||
| ctx.Data["Page"] = pager | |||
| @@ -0,0 +1,30 @@ | |||
| package image | |||
| import ( | |||
| "net/http" | |||
| "strconv" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/context" | |||
| ) | |||
| func Action(ctx *context.Context) { | |||
| var err error | |||
| imageId, _ := strconv.ParseInt(ctx.Params(":id"), 10, 64) | |||
| switch ctx.Params(":action") { | |||
| case "star": | |||
| err = models.StarImage(ctx.User.ID, imageId, true) | |||
| case "unstar": | |||
| err = models.StarImage(ctx.User.ID, imageId, false) | |||
| case "recommend": | |||
| err = models.RecommendImage(imageId, true) | |||
| case "unrecommend": | |||
| err = models.RecommendImage(imageId, false) | |||
| } | |||
| if err != nil { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("repo.star_fail", ctx.Params(":action")))) | |||
| } else { | |||
| ctx.JSON(http.StatusOK, models.BaseOKMessage) | |||
| } | |||
| } | |||
| @@ -11,7 +11,6 @@ import ( | |||
| "fmt" | |||
| "mime/multipart" | |||
| "net/http" | |||
| "path" | |||
| "strconv" | |||
| "strings" | |||
| @@ -78,7 +77,7 @@ func UploadAttachmentUI(ctx *context.Context) { | |||
| } | |||
| func EditAttachmentUI(ctx *context.Context) { | |||
| id, _ := strconv.ParseInt(ctx.Params(":id"), 10, 64) | |||
| ctx.Data["PageIsDataset"] = true | |||
| attachment, _ := models.GetAttachmentByID(id) | |||
| @@ -830,20 +829,6 @@ func GetMultipartUploadUrl(ctx *context.Context) { | |||
| }) | |||
| } | |||
| func GetObsKey(ctx *context.Context) { | |||
| uuid := gouuid.NewV4().String() | |||
| key := strings.TrimPrefix(path.Join(setting.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid, uuid)), "/") | |||
| ctx.JSON(200, map[string]string{ | |||
| "uuid": uuid, | |||
| "key": key, | |||
| "access_key_id": setting.AccessKeyID, | |||
| "secret_access_key": setting.SecretAccessKey, | |||
| "server": setting.Endpoint, | |||
| "bucket": setting.Bucket, | |||
| }) | |||
| } | |||
| func CompleteMultipart(ctx *context.Context) { | |||
| uuid := ctx.Query("uuid") | |||
| uploadID := ctx.Query("uploadID") | |||
| @@ -870,13 +855,13 @@ func CompleteMultipart(ctx *context.Context) { | |||
| } | |||
| if typeCloudBrain == models.TypeCloudBrainOne { | |||
| _, err = storage.CompleteMultiPartUpload(uuid, uploadID) | |||
| _, err = storage.CompleteMultiPartUpload(uuid, uploadID, fileChunk.TotalChunks) | |||
| if err != nil { | |||
| ctx.Error(500, fmt.Sprintf("CompleteMultiPartUpload failed: %v", err)) | |||
| return | |||
| } | |||
| } else { | |||
| err = storage.CompleteObsMultiPartUpload(uuid, uploadID, fileName) | |||
| err = storage.CompleteObsMultiPartUpload(uuid, uploadID, fileName, fileChunk.TotalChunks) | |||
| if err != nil { | |||
| ctx.Error(500, fmt.Sprintf("CompleteObsMultiPartUpload failed: %v", err)) | |||
| return | |||
| @@ -907,10 +892,9 @@ func CompleteMultipart(ctx *context.Context) { | |||
| ctx.Error(500, fmt.Sprintf("InsertAttachment: %v", err)) | |||
| return | |||
| } | |||
| attachment.UpdateDatasetUpdateUnix() | |||
| repository, _ := models.GetRepositoryByID(dataset.RepoID) | |||
| notification.NotifyOtherTask(ctx.User, repository, fmt.Sprint(attachment.Type), attachment.Name, models.ActionUploadAttachment) | |||
| notification.NotifyOtherTask(ctx.User, repository, fmt.Sprint(repository.IsPrivate, attachment.IsPrivate), attachment.Name, models.ActionUploadAttachment) | |||
| if attachment.DatasetID != 0 { | |||
| if isCanDecompress(attachment.Name) { | |||
| if typeCloudBrain == models.TypeCloudBrainOne { | |||
| @@ -947,34 +931,6 @@ func CompleteMultipart(ctx *context.Context) { | |||
| }) | |||
| } | |||
| func UpdateMultipart(ctx *context.Context) { | |||
| uuid := ctx.Query("uuid") | |||
| partNumber := ctx.QueryInt("chunkNumber") | |||
| etag := ctx.Query("etag") | |||
| fileChunk, err := models.GetFileChunkByUUID(uuid) | |||
| if err != nil { | |||
| if models.IsErrFileChunkNotExist(err) { | |||
| ctx.Error(404) | |||
| } else { | |||
| ctx.ServerError("GetFileChunkByUUID", err) | |||
| } | |||
| return | |||
| } | |||
| fileChunk.CompletedParts = append(fileChunk.CompletedParts, strconv.Itoa(partNumber)+"-"+strings.Replace(etag, "\"", "", -1)) | |||
| err = models.UpdateFileChunk(fileChunk) | |||
| if err != nil { | |||
| ctx.Error(500, fmt.Sprintf("UpdateFileChunk: %v", err)) | |||
| return | |||
| } | |||
| ctx.JSON(200, map[string]string{ | |||
| "result_code": "0", | |||
| }) | |||
| } | |||
| func HandleUnDecompressAttachment() { | |||
| attachs, err := models.GetUnDecompressAttachments() | |||
| if err != nil { | |||
| @@ -986,23 +942,29 @@ func HandleUnDecompressAttachment() { | |||
| if attach.Type == models.TypeCloudBrainOne { | |||
| err = worker.SendDecompressTask(contexExt.Background(), attach.UUID, attach.Name) | |||
| if err != nil { | |||
| log.Error("SendDecompressTask(%s) failed:%s", attach.UUID, err.Error()) | |||
| log.Error("SendDecompressTask(%s) failed:%s", attach.UUID, err.Error()) | |||
| } else { | |||
| attach.DecompressState = models.DecompressStateIng | |||
| err = models.UpdateAttachment(attach) | |||
| if err != nil { | |||
| log.Error("UpdateAttachment state(%s) failed:%s", attach.UUID, err.Error()) | |||
| } | |||
| updateAttachmentDecompressStateIng(attach) | |||
| } | |||
| } else if attach.Type == models.TypeCloudBrainTwo { | |||
| attachjson, _ := json.Marshal(attach) | |||
| labelmsg.SendDecompressAttachToLabelOBS(string(attachjson)) | |||
| err = labelmsg.SendDecompressAttachToLabelOBS(string(attachjson)) | |||
| if err != nil { | |||
| log.Error("SendDecompressTask to labelsystem (%s) failed:%s", attach.UUID, err.Error()) | |||
| } else { | |||
| updateAttachmentDecompressStateIng(attach) | |||
| } | |||
| } | |||
| } | |||
| return | |||
| } | |||
| func updateAttachmentDecompressStateIng(attach *models.Attachment) { | |||
| attach.DecompressState = models.DecompressStateIng | |||
| err := models.UpdateAttachment(attach) | |||
| if err != nil { | |||
| log.Error("UpdateAttachment state(%s) failed:%s", attach.UUID, err.Error()) | |||
| } | |||
| } | |||
| func QueryAllPublicDataset(ctx *context.Context) { | |||
| attachs, err := models.GetAllPublicAttachments() | |||
| @@ -13,6 +13,7 @@ import ( | |||
| "strconv" | |||
| "strings" | |||
| "time" | |||
| "unicode/utf8" | |||
| "code.gitea.io/gitea/modules/timeutil" | |||
| "github.com/unknwon/i18n" | |||
| @@ -39,8 +40,13 @@ const ( | |||
| tplCloudBrainBenchmarkNew base.TplName = "repo/cloudbrain/benchmark/new" | |||
| tplCloudBrainBenchmarkShow base.TplName = "repo/cloudbrain/benchmark/show" | |||
| tplCloudBrainImageSubmit base.TplName = "repo/cloudbrain/image/submit" | |||
| tplCloudBrainImageEdit base.TplName = "repo/cloudbrain/image/edit" | |||
| tplCloudBrainTrainJobNew base.TplName = "repo/cloudbrain/trainjob/new" | |||
| tplCloudBrainTrainJobShow base.TplName = "repo/cloudbrain/trainjob/show" | |||
| ) | |||
| var ( | |||
| @@ -53,6 +59,7 @@ var ( | |||
| ) | |||
| const BENCHMARK_TYPE_CODE = "repo.cloudbrain.benchmark.types" | |||
| const CLONE_FILE_PREFIX = "file:///" | |||
| var benchmarkTypesMap = make(map[string]*models.BenchmarkTypes, 0) | |||
| @@ -435,15 +442,29 @@ func cloudBrainShow(ctx *context.Context, tpName base.TplName, jobType models.Jo | |||
| return | |||
| } | |||
| if cloudbrain.ResourceSpecs == nil { | |||
| json.Unmarshal([]byte(setting.ResourceSpecs), &cloudbrain.ResourceSpecs) | |||
| } | |||
| for _, tmp := range cloudbrain.ResourceSpecs.ResourceSpec { | |||
| if tmp.Id == task.ResourceSpecId { | |||
| ctx.Data["GpuNum"] = tmp.GpuNum | |||
| ctx.Data["CpuNum"] = tmp.CpuNum | |||
| ctx.Data["MemMiB"] = tmp.MemMiB | |||
| ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB | |||
| if task.JobType == string(models.JobTypeTrain) { | |||
| if cloudbrain.TrainResourceSpecs == nil { | |||
| json.Unmarshal([]byte(setting.TrainResourceSpecs), &cloudbrain.TrainResourceSpecs) | |||
| } | |||
| for _, tmp := range cloudbrain.TrainResourceSpecs.ResourceSpec { | |||
| if tmp.Id == task.ResourceSpecId { | |||
| ctx.Data["GpuNum"] = tmp.GpuNum | |||
| ctx.Data["CpuNum"] = tmp.CpuNum | |||
| ctx.Data["MemMiB"] = tmp.MemMiB | |||
| ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB | |||
| } | |||
| } | |||
| } else { | |||
| if cloudbrain.ResourceSpecs == nil { | |||
| json.Unmarshal([]byte(setting.ResourceSpecs), &cloudbrain.ResourceSpecs) | |||
| } | |||
| for _, tmp := range cloudbrain.ResourceSpecs.ResourceSpec { | |||
| if tmp.Id == task.ResourceSpecId { | |||
| ctx.Data["GpuNum"] = tmp.GpuNum | |||
| ctx.Data["CpuNum"] = tmp.CpuNum | |||
| ctx.Data["MemMiB"] = tmp.MemMiB | |||
| ctx.Data["ShareMemMiB"] = tmp.ShareMemMiB | |||
| } | |||
| } | |||
| } | |||
| @@ -589,26 +610,212 @@ func CloudBrainDebug(ctx *context.Context) { | |||
| ctx.Redirect(debugUrl) | |||
| } | |||
| func CloudBrainCommitImageShow(ctx *context.Context) { | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| ctx.Data["Type"] = ctx.Cloudbrain.Type | |||
| ctx.HTML(200, tplCloudBrainImageSubmit) | |||
| } | |||
| func CloudBrainImageEdit(ctx *context.Context) { | |||
| ctx.Data["PageIsImageEdit"] = true | |||
| ctx.Data["PageFrom"] = ctx.Params(":from") | |||
| var ID = ctx.Params(":id") | |||
| id, err := strconv.ParseInt(ID, 10, 64) | |||
| if err != nil { | |||
| log.Error("GetImageByID failed:%v", err.Error()) | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| } | |||
| image, err := models.GetImageByID(id) | |||
| if err != nil { | |||
| log.Error("GetImageByID failed:%v", err.Error()) | |||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||
| } | |||
| ctx.Data["Image"] = image | |||
| ctx.HTML(http.StatusOK, tplCloudBrainImageEdit) | |||
| } | |||
| func CloudBrainImageEditPost(ctx *context.Context, form auth.EditImageCloudBrainForm) { | |||
| if utf8.RuneCountInString(form.Description) > 255 { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("dataset.description_format_err", 255))) | |||
| return | |||
| } | |||
| validTopics, errMessage := checkTopics(form.Topics) | |||
| if errMessage != "" { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr(errMessage))) | |||
| return | |||
| } | |||
| image, err := models.GetImageByID(form.ID) | |||
| if err != nil { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("repo.image_not_exist"))) | |||
| } | |||
| image.IsPrivate = form.IsPrivate | |||
| image.Description = form.Description | |||
| err = models.WithTx(func(ctx models.DBContext) error { | |||
| if err := models.UpdateLocalImage(image); err != nil { | |||
| return err | |||
| } | |||
| if err := models.SaveImageTopics(image.ID, validTopics...); err != nil { | |||
| return err | |||
| } | |||
| return nil | |||
| }) | |||
| if err != nil { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("repo.image_not_exist"))) | |||
| } else { | |||
| ctx.JSON(http.StatusOK, models.BaseOKMessage) | |||
| } | |||
| } | |||
| func CloudBrainImageDelete(ctx *context.Context) { | |||
| var ID = ctx.Params(":id") | |||
| id, err := strconv.ParseInt(ID, 10, 64) | |||
| if err != nil { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("repo.image_not_exist"))) | |||
| return | |||
| } | |||
| err = models.DeleteLocalImage(id) | |||
| if err != nil { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("repo.image_delete_fail"))) | |||
| } else { | |||
| ctx.JSON(http.StatusOK, models.BaseOKMessage) | |||
| } | |||
| } | |||
| func CloudBrainCommitImageCheck(ctx *context.Context, form auth.CommitImageCloudBrainForm) { | |||
| isExist, _ := models.IsImageExistByUser(form.Tag, ctx.User.ID) | |||
| if isExist { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("repo.image_overwrite"))) | |||
| } else { | |||
| ctx.JSON(http.StatusOK, models.BaseOKMessage) | |||
| } | |||
| } | |||
| func CloudBrainAdminCommitImage(ctx *context.Context, form auth.CommitAdminImageCloudBrainForm) { | |||
| if !NamePattern.MatchString(form.Tag) { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("dataset.title_format_err"))) | |||
| return | |||
| } | |||
| if utf8.RuneCountInString(form.Description) > 255 { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("dataset.description_format_err", 255))) | |||
| return | |||
| } | |||
| validTopics, errMessage := checkTopics(form.Topics) | |||
| if errMessage != "" { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr(errMessage))) | |||
| return | |||
| } | |||
| err := cloudbrain.CommitAdminImage(models.CommitImageParams{ | |||
| CommitImageCloudBrainParams: models.CommitImageCloudBrainParams{ | |||
| ImageDescription: form.Description, | |||
| ImageTag: form.Tag, | |||
| }, | |||
| IsPrivate: form.IsPrivate, | |||
| CloudBrainType: form.Type, | |||
| Topics: validTopics, | |||
| UID: ctx.User.ID, | |||
| Type: models.GetRecommondType(form.IsRecommend), | |||
| Place: form.Place, | |||
| }) | |||
| if err != nil { | |||
| log.Error("CommitImagefailed") | |||
| if models.IsErrImageTagExist(err) { | |||
| ctx.JSON(200, models.BaseErrorMessage(ctx.Tr("repo.image_exist"))) | |||
| } else if models.IsErrorImageCommitting(err) { | |||
| ctx.JSON(200, models.BaseErrorMessage(ctx.Tr("repo.image_committing"))) | |||
| } else { | |||
| ctx.JSON(200, models.BaseErrorMessage(ctx.Tr("repo.image_commit_fail"))) | |||
| } | |||
| return | |||
| } | |||
| ctx.JSON(200, models.BaseOKMessage) | |||
| } | |||
| func CloudBrainCommitImage(ctx *context.Context, form auth.CommitImageCloudBrainForm) { | |||
| if !NamePattern.MatchString(form.Tag) { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("dataset.title_format_err"))) | |||
| return | |||
| } | |||
| if utf8.RuneCountInString(form.Description) > 255 { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("dataset.description_format_err", 255))) | |||
| return | |||
| } | |||
| validTopics, errMessage := checkTopics(form.Topics) | |||
| if errMessage != "" { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr(errMessage))) | |||
| return | |||
| } | |||
| err := cloudbrain.CommitImage(ctx.Cloudbrain.JobID, models.CommitImageParams{ | |||
| Ip: ctx.Cloudbrain.ContainerIp, | |||
| TaskContainerId: ctx.Cloudbrain.ContainerID, | |||
| ImageDescription: form.Description, | |||
| ImageTag: form.Tag, | |||
| CommitImageCloudBrainParams: models.CommitImageCloudBrainParams{ | |||
| Ip: ctx.Cloudbrain.ContainerIp, | |||
| TaskContainerId: ctx.Cloudbrain.ContainerID, | |||
| ImageDescription: form.Description, | |||
| ImageTag: form.Tag, | |||
| }, | |||
| IsPrivate: form.IsPrivate, | |||
| CloudBrainType: form.Type, | |||
| Topics: validTopics, | |||
| UID: ctx.User.ID, | |||
| }) | |||
| if err != nil { | |||
| log.Error("CommitImage(%s) failed:%v", ctx.Cloudbrain.JobName, err.Error(), ctx.Data["msgID"]) | |||
| ctx.JSON(200, map[string]string{ | |||
| "result_code": "-1", | |||
| "error_msg": "CommitImage failed", | |||
| }) | |||
| if models.IsErrImageTagExist(err) { | |||
| ctx.JSON(200, models.BaseErrorMessage(ctx.Tr("repo.image_exist"))) | |||
| } else if models.IsErrorImageCommitting(err) { | |||
| ctx.JSON(200, models.BaseErrorMessage(ctx.Tr("repo.image_committing"))) | |||
| } else { | |||
| ctx.JSON(200, models.BaseErrorMessage(ctx.Tr("repo.image_commit_fail"))) | |||
| } | |||
| return | |||
| } | |||
| ctx.JSON(200, map[string]string{ | |||
| "result_code": "0", | |||
| "error_msg": "", | |||
| }) | |||
| ctx.JSON(200, models.BaseOKMessage) | |||
| } | |||
| func checkTopics(Topics string) ([]string, string) { | |||
| var topics = make([]string, 0) | |||
| var topicsStr = strings.TrimSpace(Topics) | |||
| if len(topicsStr) > 0 { | |||
| topics = strings.Split(topicsStr, ",") | |||
| } | |||
| validTopics, invalidTopics := models.SanitizeAndValidateImageTopics(topics) | |||
| if len(validTopics) > 25 { | |||
| return nil, "repo.topic.count_prompt" | |||
| } | |||
| if len(invalidTopics) > 0 { | |||
| return nil, "repo.imagetopic.format_prompt" | |||
| } | |||
| return validTopics, "" | |||
| } | |||
| func CloudBrainStop(ctx *context.Context) { | |||
| @@ -753,8 +960,11 @@ func CloudBrainDel(ctx *context.Context) { | |||
| } | |||
| 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 + "/debugjob?debugListType=" + listType) | |||
| } | |||
| @@ -825,35 +1035,106 @@ func CloudBrainShowModels(ctx *context.Context) { | |||
| } | |||
| func GetPublicImages(ctx *context.Context) { | |||
| uid := getUID(ctx) | |||
| opts := models.SearchImageOptions{ | |||
| IncludePublicOnly: true, | |||
| UID: uid, | |||
| Keyword: ctx.Query("q"), | |||
| Topics: ctx.Query("topic"), | |||
| IncludeOfficialOnly: ctx.QueryBool("recommend"), | |||
| SearchOrderBy: "type desc, num_stars desc,id desc", | |||
| Status: models.IMAGE_STATUS_SUCCESS, | |||
| } | |||
| getImages(ctx, cloudbrain.Public) | |||
| getImages(ctx, &opts) | |||
| } | |||
| func GetCustomImages(ctx *context.Context) { | |||
| uid := getUID(ctx) | |||
| opts := models.SearchImageOptions{ | |||
| UID: uid, | |||
| IncludeOwnerOnly: true, | |||
| Keyword: ctx.Query("q"), | |||
| Topics: ctx.Query("topic"), | |||
| Status: -1, | |||
| SearchOrderBy: "id desc", | |||
| } | |||
| getImages(ctx, &opts) | |||
| } | |||
| func GetStarImages(ctx *context.Context) { | |||
| getImages(ctx, cloudbrain.Custom) | |||
| uid := getUID(ctx) | |||
| opts := models.SearchImageOptions{ | |||
| UID: uid, | |||
| IncludeStarByMe: true, | |||
| Keyword: ctx.Query("q"), | |||
| Topics: ctx.Query("topic"), | |||
| Status: models.IMAGE_STATUS_SUCCESS, | |||
| SearchOrderBy: "id desc", | |||
| } | |||
| getImages(ctx, &opts) | |||
| } | |||
| func getImages(ctx *context.Context, imageType string) { | |||
| log.Info("Get images begin") | |||
| func getUID(ctx *context.Context) int64 { | |||
| var uid int64 = -1 | |||
| if ctx.IsSigned { | |||
| uid = ctx.User.ID | |||
| } | |||
| return uid | |||
| } | |||
| func GetAllImages(ctx *context.Context) { | |||
| uid := getUID(ctx) | |||
| opts := models.SearchImageOptions{ | |||
| UID: uid, | |||
| Keyword: ctx.Query("q"), | |||
| Topics: ctx.Query("topic"), | |||
| IncludeOfficialOnly: ctx.QueryBool("recommend"), | |||
| SearchOrderBy: "id desc", | |||
| Status: -1, | |||
| } | |||
| if ctx.Query("private") != "" { | |||
| if ctx.QueryBool("private") { | |||
| opts.IncludePrivateOnly = true | |||
| } else { | |||
| opts.IncludePublicOnly = true | |||
| } | |||
| } | |||
| getImages(ctx, &opts) | |||
| } | |||
| func getImages(ctx *context.Context, opts *models.SearchImageOptions) { | |||
| page := ctx.QueryInt("page") | |||
| size := ctx.QueryInt("size") | |||
| name := ctx.Query("name") | |||
| getImagesResult, err := cloudbrain.GetImagesPageable(page, size, imageType, name) | |||
| if page <= 0 { | |||
| page = 1 | |||
| } | |||
| pageSize := ctx.QueryInt("pageSize") | |||
| if pageSize <= 0 { | |||
| pageSize = 15 | |||
| } | |||
| opts.ListOptions = models.ListOptions{ | |||
| Page: page, | |||
| PageSize: pageSize, | |||
| } | |||
| imageList, total, err := models.SearchImage(opts) | |||
| if err != nil { | |||
| log.Error("Can not get images:%v", err) | |||
| ctx.JSON(http.StatusOK, models.GetImagesPayload{ | |||
| Count: 0, | |||
| TotalPages: 0, | |||
| ImageInfo: []*models.ImageInfo{}, | |||
| ctx.JSON(http.StatusOK, models.ImagesPageResult{ | |||
| Count: 0, | |||
| Images: []*models.Image{}, | |||
| }) | |||
| } else { | |||
| ctx.JSON(http.StatusOK, getImagesResult.Payload) | |||
| ctx.JSON(http.StatusOK, models.ImagesPageResult{ | |||
| Count: total, | |||
| Images: imageList, | |||
| }) | |||
| } | |||
| log.Info("Get images end") | |||
| } | |||
| func GetModelDirs(jobName string, parentDir string) (string, error) { | |||
| @@ -909,7 +1190,8 @@ func GetRate(ctx *context.Context) { | |||
| } | |||
| func downloadCode(repo *models.Repository, codePath, branchName string) error { | |||
| if err := git.Clone(repo.RepoPath(), codePath, git.CloneRepoOptions{Branch: branchName}); err != nil { | |||
| //add "file:///" prefix to make the depth valid | |||
| if err := git.Clone(CLONE_FILE_PREFIX+repo.RepoPath(), codePath, git.CloneRepoOptions{Branch: branchName, Depth: 1}); err != nil { | |||
| log.Error("Failed to clone repository: %s (%v)", repo.FullName(), err) | |||
| return err | |||
| } | |||
| @@ -969,7 +1251,7 @@ func downloadRateCode(repo *models.Repository, taskName, rateOwnerName, rateRepo | |||
| return err | |||
| } | |||
| if err := git.Clone(repoExt.RepoPath(), codePath, git.CloneRepoOptions{}); err != nil { | |||
| if err := git.Clone(CLONE_FILE_PREFIX+repoExt.RepoPath(), codePath, git.CloneRepoOptions{Depth: 1}); err != nil { | |||
| log.Error("Failed to clone repository: %s (%v)", repoExt.FullName(), err) | |||
| return err | |||
| } | |||
| @@ -1156,6 +1438,7 @@ func SyncCloudbrainStatus() { | |||
| if task.EndTime == 0 && models.IsModelArtsDebugJobTerminal(task.Status) { | |||
| task.EndTime = timeutil.TimeStampNow() | |||
| } | |||
| task.CorrectCreateUnix() | |||
| task.ComputeAndSetDuration() | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| @@ -1182,7 +1465,7 @@ func SyncCloudbrainStatus() { | |||
| 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) | |||
| @@ -1304,6 +1587,7 @@ func handleNoDurationTask(cloudBrains []*models.Cloudbrain) { | |||
| task.StartTime = timeutil.TimeStamp(startTime / 1000) | |||
| task.EndTime = task.StartTime.Add(duration) | |||
| } | |||
| task.CorrectCreateUnix() | |||
| task.ComputeAndSetDuration() | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| @@ -1693,8 +1977,11 @@ func BenchmarkDel(ctx *context.Context) { | |||
| } | |||
| 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 + "/cloudbrain/benchmark") | |||
| } | |||
| @@ -1747,8 +2034,11 @@ func CloudBrainTrainJobDel(ctx *context.Context) { | |||
| } | |||
| 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) | |||
| } | |||
| @@ -4,7 +4,6 @@ import ( | |||
| "encoding/json" | |||
| "fmt" | |||
| "net/http" | |||
| "regexp" | |||
| "sort" | |||
| "strconv" | |||
| "strings" | |||
| @@ -25,8 +24,6 @@ const ( | |||
| taskstplIndex base.TplName = "repo/datasets/tasks/index" | |||
| ) | |||
| var titlePattern = regexp.MustCompile(`^[A-Za-z0-9-_\\.]{1,100}$`) | |||
| // MustEnableDataset check if repository enable internal dataset | |||
| func MustEnableDataset(ctx *context.Context) { | |||
| if !ctx.Repo.CanRead(models.UnitTypeDatasets) { | |||
| @@ -211,12 +208,12 @@ func CreateDatasetPost(ctx *context.Context, form auth.CreateDatasetForm) { | |||
| dataset := &models.Dataset{} | |||
| if !titlePattern.MatchString(form.Title) { | |||
| if !NamePattern.MatchString(form.Title) { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("dataset.title_format_err"))) | |||
| return | |||
| } | |||
| if utf8.RuneCountInString(form.Description) > 1024 { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("dataset.description_format_err"))) | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("dataset.description_format_err", 1024))) | |||
| return | |||
| } | |||
| @@ -248,12 +245,12 @@ func EditDatasetPost(ctx *context.Context, form auth.EditDatasetForm) { | |||
| ctx.Data["Title"] = ctx.Tr("dataset.edit_dataset") | |||
| if !titlePattern.MatchString(form.Title) { | |||
| if !NamePattern.MatchString(form.Title) { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("dataset.title_format_err"))) | |||
| return | |||
| } | |||
| if utf8.RuneCountInString(form.Description) > 1024 { | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("dataset.description_format_err"))) | |||
| ctx.JSON(http.StatusOK, models.BaseErrorMessage(ctx.Tr("dataset.description_format_err", 1024))) | |||
| return | |||
| } | |||
| @@ -361,6 +358,7 @@ func MyDatasets(ctx *context.Context) { | |||
| NeedIsPrivate: false, | |||
| JustNeedZipFile: true, | |||
| NeedRepoInfo: true, | |||
| RecommendOnly: ctx.QueryBool("recommend"), | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("datasets", err) | |||
| @@ -401,6 +399,7 @@ func PublicDataset(ctx *context.Context) { | |||
| Type: cloudbrainType, | |||
| JustNeedZipFile: true, | |||
| NeedRepoInfo: true, | |||
| RecommendOnly: ctx.QueryBool("recommend"), | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("datasets", err) | |||
| @@ -457,6 +456,7 @@ func MyFavoriteDataset(ctx *context.Context) { | |||
| Type: cloudbrainType, | |||
| JustNeedZipFile: true, | |||
| NeedRepoInfo: true, | |||
| RecommendOnly: ctx.QueryBool("recommend"), | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("datasets", err) | |||
| @@ -247,7 +247,9 @@ func Notebook2Create(ctx *context.Context, form auth.CreateModelArtsNotebookForm | |||
| func NotebookShow(ctx *context.Context) { | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| debugListType := ctx.Query("debugListType") | |||
| if debugListType == "" { | |||
| debugListType = "all" | |||
| } | |||
| var ID = ctx.Params(":id") | |||
| task, err := models.GetCloudbrainByIDWithDeleted(ID) | |||
| if err != nil { | |||
| @@ -267,6 +269,7 @@ func NotebookShow(ctx *context.Context) { | |||
| if task.DeletedAt.IsZero() { //normal record | |||
| if task.Status != result.Status { | |||
| task.Status = result.Status | |||
| models.ParseAndSetDurationFromModelArtsNotebook(result, task) | |||
| err = models.UpdateJob(task) | |||
| if err != nil { | |||
| ctx.Data["error"] = err.Error() | |||
| @@ -439,6 +442,7 @@ func NotebookManage(ctx *context.Context) { | |||
| param := models.NotebookAction{ | |||
| Action: action, | |||
| } | |||
| createTime := timeutil.TimeStampNow() | |||
| res, err := modelarts.ManageNotebook2(task.JobID, param) | |||
| if err != nil { | |||
| log.Error("ManageNotebook2(%s) failed:%v", task.JobName, err.Error(), ctx.Data["MsgID"]) | |||
| @@ -465,6 +469,8 @@ func NotebookManage(ctx *context.Context) { | |||
| Image: task.Image, | |||
| ComputeResource: task.ComputeResource, | |||
| Description: task.Description, | |||
| CreatedUnix: createTime, | |||
| UpdatedUnix: createTime, | |||
| } | |||
| err = models.RestartCloudbrain(task, newTask) | |||
| @@ -530,8 +536,11 @@ func NotebookDel(ctx *context.Context) { | |||
| } | |||
| 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 + "/debugjob?debugListType=" + listType) | |||
| } | |||
| @@ -1020,10 +1029,8 @@ func TrainJobCreate(ctx *context.Context, form auth.CreateModelArtsTrainJobForm) | |||
| gitRepo, _ := git.OpenRepository(repo.RepoPath()) | |||
| commitID, _ := gitRepo.GetBranchCommitID(branch_name) | |||
| if err := git.Clone(repo.RepoPath(), codeLocalPath, git.CloneRepoOptions{ | |||
| Branch: branch_name, | |||
| }); err != nil { | |||
| log.Error("Create task failed, server timed out: %s (%v)", repo.FullName(), err) | |||
| if err := downloadCode(repo, codeLocalPath, branch_name); err != nil { | |||
| log.Error("downloadCode failed, server timed out: %s (%v)", repo.FullName(), err) | |||
| trainJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("Create task failed, server timed out", tplModelArtsTrainJobNew, &form) | |||
| return | |||
| @@ -1238,9 +1245,7 @@ func TrainJobCreateVersion(ctx *context.Context, form auth.CreateModelArtsTrainJ | |||
| gitRepo, _ := git.OpenRepository(repo.RepoPath()) | |||
| commitID, _ := gitRepo.GetBranchCommitID(branch_name) | |||
| if err := git.Clone(repo.RepoPath(), codeLocalPath, git.CloneRepoOptions{ | |||
| Branch: branch_name, | |||
| }); err != nil { | |||
| if err := downloadCode(repo, codeLocalPath, branch_name); err != nil { | |||
| log.Error("Failed git clone repo to local(!: %s (%v)", repo.FullName(), err) | |||
| versionErrorDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("Failed git clone repo to local!", tplModelArtsTrainJobVersionNew, &form) | |||
| @@ -1685,8 +1690,11 @@ func TrainJobDel(ctx *context.Context) { | |||
| } | |||
| 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) | |||
| } | |||
| @@ -1864,9 +1872,7 @@ func InferenceJobCreate(ctx *context.Context, form auth.CreateModelArtsInference | |||
| gitRepo, _ := git.OpenRepository(repo.RepoPath()) | |||
| commitID, _ := gitRepo.GetBranchCommitID(branch_name) | |||
| if err := git.Clone(repo.RepoPath(), codeLocalPath, git.CloneRepoOptions{ | |||
| Branch: branch_name, | |||
| }); err != nil { | |||
| if err := downloadCode(repo, codeLocalPath, branch_name); err != nil { | |||
| log.Error("Create task failed, server timed out: %s (%v)", repo.FullName(), err) | |||
| inferenceJobErrorNewDataPrepare(ctx, form) | |||
| ctx.RenderWithErr("Create task failed, server timed out", tplModelArtsInferenceJobNew, &form) | |||
| @@ -2037,6 +2043,7 @@ func InferenceJobNew(ctx *context.Context) { | |||
| } | |||
| func inferenceJobNewDataPrepare(ctx *context.Context) error { | |||
| ctx.Data["PageIsCloudBrain"] = true | |||
| ctx.Data["newInference"] = true | |||
| t := time.Now() | |||
| var displayJobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||
| @@ -40,25 +40,25 @@ func queryUserDataPage(ctx *context.Context, tableName string, queryObj interfac | |||
| dataHeader := map[string]string{ | |||
| "A1": ctx.Tr("user.static.id"), | |||
| "B1": ctx.Tr("user.static.name"), | |||
| "C1": ctx.Tr("user.static.codemergecount"), | |||
| "D1": ctx.Tr("user.static.commitcount"), | |||
| "E1": ctx.Tr("user.static.issuecount"), | |||
| "F1": ctx.Tr("user.static.commentcount"), | |||
| "G1": ctx.Tr("user.static.focusrepocount"), | |||
| "H1": ctx.Tr("user.static.starrepocount"), | |||
| "I1": ctx.Tr("user.static.logincount"), | |||
| "J1": ctx.Tr("user.static.watchedcount"), | |||
| "K1": ctx.Tr("user.static.commitcodesize"), | |||
| "L1": ctx.Tr("user.static.solveissuecount"), | |||
| "M1": ctx.Tr("user.static.encyclopediascount"), | |||
| "N1": ctx.Tr("user.static.createrepocount"), | |||
| "O1": ctx.Tr("user.static.openiindex"), | |||
| "P1": ctx.Tr("user.static.registdate"), | |||
| "C1": ctx.Tr("user.static.UserIndex"), | |||
| "D1": ctx.Tr("user.static.codemergecount"), | |||
| "E1": ctx.Tr("user.static.commitcount"), | |||
| "F1": ctx.Tr("user.static.issuecount"), | |||
| "G1": ctx.Tr("user.static.commentcount"), | |||
| "H1": ctx.Tr("user.static.focusrepocount"), | |||
| "I1": ctx.Tr("user.static.starrepocount"), | |||
| "J1": ctx.Tr("user.static.logincount"), | |||
| "K1": ctx.Tr("user.static.watchedcount"), | |||
| "L1": ctx.Tr("user.static.commitcodesize"), | |||
| "M1": ctx.Tr("user.static.solveissuecount"), | |||
| "N1": ctx.Tr("user.static.encyclopediascount"), | |||
| "O1": ctx.Tr("user.static.createrepocount"), | |||
| "P1": ctx.Tr("user.static.openiindex"), | |||
| "Q1": ctx.Tr("user.static.CloudBrainTaskNum"), | |||
| "R1": ctx.Tr("user.static.CloudBrainRunTime"), | |||
| "S1": ctx.Tr("user.static.CommitDatasetNum"), | |||
| "T1": ctx.Tr("user.static.CommitModelCount"), | |||
| "U1": ctx.Tr("user.static.UserIndex"), | |||
| "U1": ctx.Tr("user.static.registdate"), | |||
| "V1": ctx.Tr("user.static.countdate"), | |||
| } | |||
| for k, v := range dataHeader { | |||
| @@ -77,29 +77,26 @@ func queryUserDataPage(ctx *context.Context, tableName string, queryObj interfac | |||
| rows := fmt.Sprint(row) | |||
| xlsx.SetCellValue(sheetName, "A"+rows, userRecord.ID) | |||
| xlsx.SetCellValue(sheetName, "B"+rows, userRecord.Name) | |||
| xlsx.SetCellValue(sheetName, "C"+rows, userRecord.CodeMergeCount) | |||
| xlsx.SetCellValue(sheetName, "D"+rows, userRecord.CommitCount) | |||
| xlsx.SetCellValue(sheetName, "E"+rows, userRecord.IssueCount) | |||
| xlsx.SetCellValue(sheetName, "F"+rows, userRecord.CommentCount) | |||
| xlsx.SetCellValue(sheetName, "G"+rows, userRecord.FocusRepoCount) | |||
| xlsx.SetCellValue(sheetName, "H"+rows, userRecord.StarRepoCount) | |||
| xlsx.SetCellValue(sheetName, "I"+rows, userRecord.LoginCount) | |||
| xlsx.SetCellValue(sheetName, "J"+rows, userRecord.WatchedCount) | |||
| xlsx.SetCellValue(sheetName, "K"+rows, userRecord.CommitCodeSize) | |||
| xlsx.SetCellValue(sheetName, "L"+rows, userRecord.SolveIssueCount) | |||
| xlsx.SetCellValue(sheetName, "M"+rows, userRecord.EncyclopediasCount) | |||
| xlsx.SetCellValue(sheetName, "N"+rows, userRecord.CreateRepoCount) | |||
| xlsx.SetCellValue(sheetName, "O"+rows, fmt.Sprintf("%.2f", userRecord.OpenIIndex)) | |||
| formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05") | |||
| xlsx.SetCellValue(sheetName, "P"+rows, formatTime[0:len(formatTime)-3]) | |||
| xlsx.SetCellValue(sheetName, "C"+rows, fmt.Sprintf("%.2f", userRecord.UserIndex)) | |||
| xlsx.SetCellValue(sheetName, "D"+rows, userRecord.CodeMergeCount) | |||
| xlsx.SetCellValue(sheetName, "E"+rows, userRecord.CommitCount) | |||
| xlsx.SetCellValue(sheetName, "F"+rows, userRecord.IssueCount) | |||
| xlsx.SetCellValue(sheetName, "G"+rows, userRecord.CommentCount) | |||
| xlsx.SetCellValue(sheetName, "H"+rows, userRecord.FocusRepoCount) | |||
| xlsx.SetCellValue(sheetName, "I"+rows, userRecord.StarRepoCount) | |||
| xlsx.SetCellValue(sheetName, "J"+rows, userRecord.LoginCount) | |||
| xlsx.SetCellValue(sheetName, "K"+rows, userRecord.WatchedCount) | |||
| xlsx.SetCellValue(sheetName, "L"+rows, userRecord.CommitCodeSize) | |||
| xlsx.SetCellValue(sheetName, "M"+rows, userRecord.SolveIssueCount) | |||
| xlsx.SetCellValue(sheetName, "N"+rows, userRecord.EncyclopediasCount) | |||
| xlsx.SetCellValue(sheetName, "O"+rows, userRecord.CreateRepoCount) | |||
| xlsx.SetCellValue(sheetName, "P"+rows, fmt.Sprintf("%.2f", userRecord.OpenIIndex)) | |||
| xlsx.SetCellValue(sheetName, "Q"+rows, userRecord.CloudBrainTaskNum) | |||
| xlsx.SetCellValue(sheetName, "R"+rows, fmt.Sprintf("%.2f", float64(userRecord.CloudBrainRunTime)/3600)) | |||
| xlsx.SetCellValue(sheetName, "S"+rows, userRecord.CommitDatasetNum) | |||
| xlsx.SetCellValue(sheetName, "T"+rows, userRecord.CommitModelCount) | |||
| xlsx.SetCellValue(sheetName, "U"+rows, fmt.Sprintf("%.2f", userRecord.UserIndex)) | |||
| formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05") | |||
| xlsx.SetCellValue(sheetName, "U"+rows, formatTime[0:len(formatTime)-3]) | |||
| formatTime = userRecord.DataDate | |||
| xlsx.SetCellValue(sheetName, "V"+rows, formatTime) | |||
| } | |||
| @@ -242,25 +239,25 @@ func QueryUserStaticDataPage(ctx *context.Context) { | |||
| dataHeader := map[string]string{ | |||
| "A1": ctx.Tr("user.static.id"), | |||
| "B1": ctx.Tr("user.static.name"), | |||
| "C1": ctx.Tr("user.static.codemergecount"), | |||
| "D1": ctx.Tr("user.static.commitcount"), | |||
| "E1": ctx.Tr("user.static.issuecount"), | |||
| "F1": ctx.Tr("user.static.commentcount"), | |||
| "G1": ctx.Tr("user.static.focusrepocount"), | |||
| "H1": ctx.Tr("user.static.starrepocount"), | |||
| "I1": ctx.Tr("user.static.logincount"), | |||
| "J1": ctx.Tr("user.static.watchedcount"), | |||
| "K1": ctx.Tr("user.static.commitcodesize"), | |||
| "L1": ctx.Tr("user.static.solveissuecount"), | |||
| "M1": ctx.Tr("user.static.encyclopediascount"), | |||
| "N1": ctx.Tr("user.static.createrepocount"), | |||
| "O1": ctx.Tr("user.static.openiindex"), | |||
| "P1": ctx.Tr("user.static.registdate"), | |||
| "C1": ctx.Tr("user.static.UserIndex"), | |||
| "D1": ctx.Tr("user.static.codemergecount"), | |||
| "E1": ctx.Tr("user.static.commitcount"), | |||
| "F1": ctx.Tr("user.static.issuecount"), | |||
| "G1": ctx.Tr("user.static.commentcount"), | |||
| "H1": ctx.Tr("user.static.focusrepocount"), | |||
| "I1": ctx.Tr("user.static.starrepocount"), | |||
| "J1": ctx.Tr("user.static.logincount"), | |||
| "K1": ctx.Tr("user.static.watchedcount"), | |||
| "L1": ctx.Tr("user.static.commitcodesize"), | |||
| "M1": ctx.Tr("user.static.solveissuecount"), | |||
| "N1": ctx.Tr("user.static.encyclopediascount"), | |||
| "O1": ctx.Tr("user.static.createrepocount"), | |||
| "P1": ctx.Tr("user.static.openiindex"), | |||
| "Q1": ctx.Tr("user.static.CloudBrainTaskNum"), | |||
| "R1": ctx.Tr("user.static.CloudBrainRunTime"), | |||
| "S1": ctx.Tr("user.static.CommitDatasetNum"), | |||
| "T1": ctx.Tr("user.static.CommitModelCount"), | |||
| "U1": ctx.Tr("user.static.UserIndex"), | |||
| "U1": ctx.Tr("user.static.registdate"), | |||
| "V1": ctx.Tr("user.static.countdate"), | |||
| } | |||
| for k, v := range dataHeader { | |||
| @@ -273,27 +270,26 @@ func QueryUserStaticDataPage(ctx *context.Context) { | |||
| xlsx.SetCellValue(sheetName, "A"+rows, userRecord.ID) | |||
| xlsx.SetCellValue(sheetName, "B"+rows, userRecord.Name) | |||
| xlsx.SetCellValue(sheetName, "C"+rows, userRecord.CodeMergeCount) | |||
| xlsx.SetCellValue(sheetName, "D"+rows, userRecord.CommitCount) | |||
| xlsx.SetCellValue(sheetName, "E"+rows, userRecord.IssueCount) | |||
| xlsx.SetCellValue(sheetName, "F"+rows, userRecord.CommentCount) | |||
| xlsx.SetCellValue(sheetName, "G"+rows, userRecord.FocusRepoCount) | |||
| xlsx.SetCellValue(sheetName, "H"+rows, userRecord.StarRepoCount) | |||
| xlsx.SetCellValue(sheetName, "I"+rows, userRecord.LoginCount) | |||
| xlsx.SetCellValue(sheetName, "J"+rows, userRecord.WatchedCount) | |||
| xlsx.SetCellValue(sheetName, "K"+rows, userRecord.CommitCodeSize) | |||
| xlsx.SetCellValue(sheetName, "L"+rows, userRecord.SolveIssueCount) | |||
| xlsx.SetCellValue(sheetName, "M"+rows, userRecord.EncyclopediasCount) | |||
| xlsx.SetCellValue(sheetName, "N"+rows, userRecord.CreateRepoCount) | |||
| xlsx.SetCellValue(sheetName, "O"+rows, fmt.Sprintf("%.2f", userRecord.OpenIIndex)) | |||
| formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05") | |||
| xlsx.SetCellValue(sheetName, "P"+rows, formatTime[0:len(formatTime)-3]) | |||
| xlsx.SetCellValue(sheetName, "C"+rows, fmt.Sprintf("%.2f", userRecord.UserIndex)) | |||
| xlsx.SetCellValue(sheetName, "D"+rows, userRecord.CodeMergeCount) | |||
| xlsx.SetCellValue(sheetName, "E"+rows, userRecord.CommitCount) | |||
| xlsx.SetCellValue(sheetName, "F"+rows, userRecord.IssueCount) | |||
| xlsx.SetCellValue(sheetName, "G"+rows, userRecord.CommentCount) | |||
| xlsx.SetCellValue(sheetName, "H"+rows, userRecord.FocusRepoCount) | |||
| xlsx.SetCellValue(sheetName, "I"+rows, userRecord.StarRepoCount) | |||
| xlsx.SetCellValue(sheetName, "J"+rows, userRecord.LoginCount) | |||
| xlsx.SetCellValue(sheetName, "K"+rows, userRecord.WatchedCount) | |||
| xlsx.SetCellValue(sheetName, "L"+rows, userRecord.CommitCodeSize) | |||
| xlsx.SetCellValue(sheetName, "M"+rows, userRecord.SolveIssueCount) | |||
| xlsx.SetCellValue(sheetName, "N"+rows, userRecord.EncyclopediasCount) | |||
| xlsx.SetCellValue(sheetName, "O"+rows, userRecord.CreateRepoCount) | |||
| xlsx.SetCellValue(sheetName, "P"+rows, fmt.Sprintf("%.2f", userRecord.OpenIIndex)) | |||
| xlsx.SetCellValue(sheetName, "Q"+rows, userRecord.CloudBrainTaskNum) | |||
| xlsx.SetCellValue(sheetName, "R"+rows, fmt.Sprintf("%.2f", float64(userRecord.CloudBrainRunTime)/3600)) | |||
| xlsx.SetCellValue(sheetName, "S"+rows, userRecord.CommitDatasetNum) | |||
| xlsx.SetCellValue(sheetName, "T"+rows, userRecord.CommitModelCount) | |||
| xlsx.SetCellValue(sheetName, "U"+rows, fmt.Sprintf("%.2f", userRecord.UserIndex)) | |||
| formatTime := userRecord.RegistDate.Format("2006-01-02 15:04:05") | |||
| xlsx.SetCellValue(sheetName, "U"+rows, formatTime[0:len(formatTime)-3]) | |||
| formatTime = userRecord.DataDate | |||
| xlsx.SetCellValue(sheetName, "V"+rows, formatTime) | |||
| } | |||
| @@ -0,0 +1,5 @@ | |||
| package repo | |||
| import "regexp" | |||
| var NamePattern = regexp.MustCompile(`^[A-Za-z0-9-_\\.]{1,100}$`) | |||
| @@ -12,6 +12,8 @@ import ( | |||
| "text/template" | |||
| "time" | |||
| "code.gitea.io/gitea/routers/image" | |||
| "code.gitea.io/gitea/routers/authentication" | |||
| "code.gitea.io/gitea/modules/cloudbrain" | |||
| @@ -333,6 +335,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| }) | |||
| m.Get("/images/public", repo.GetPublicImages) | |||
| m.Get("/images/custom", repo.GetCustomImages) | |||
| m.Get("/images/star", repo.GetStarImages) | |||
| m.Get("/repos", routers.ExploreRepos) | |||
| m.Get("/datasets", routers.ExploreDatasets) | |||
| m.Get("/users", routers.ExploreUsers) | |||
| @@ -345,6 +349,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost) | |||
| m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues) | |||
| m.Get("/milestones", reqSignIn, reqMilestonesDashboardPageEnabled, user.Milestones) | |||
| m.Get("/cloudbrains", reqSignIn, user.Cloudbrains) | |||
| // ***** START: User ***** | |||
| m.Group("/user", func() { | |||
| @@ -520,12 +525,20 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Group("/datasets", func() { | |||
| m.Get("", admin.Datasets) | |||
| m.Put("/:id/action/:action", admin.DatasetAction) | |||
| // m.Post("/delete", admin.DeleteDataset) | |||
| }) | |||
| m.Group("/cloudbrains", func() { | |||
| m.Get("", admin.CloudBrains) | |||
| m.Get("/download", admin.DownloadCloudBrains) | |||
| }) | |||
| m.Group("/images", func() { | |||
| m.Get("", admin.Images) | |||
| m.Get("/data", repo.GetAllImages) | |||
| m.Get("/commit_image", admin.CloudBrainCommitImageShow) | |||
| m.Post("/commit_image", bindIgnErr(auth.CommitAdminImageCloudBrainForm{}), repo.CloudBrainAdminCommitImage) | |||
| }) | |||
| m.Put("/image/:id/action/:action", image.Action) | |||
| m.Group("/^:configType(hooks|system-hooks)$", func() { | |||
| m.Get("", admin.DefaultOrSystemWebhooks) | |||
| @@ -598,12 +611,11 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Put("/obs_proxy_multipart", repo.PutOBSProxyUpload) | |||
| m.Get("/obs_proxy_download", repo.GetOBSProxyDownload) | |||
| m.Get("/get_multipart_url", repo.GetMultipartUploadUrl) | |||
| m.Post("/complete_multipart", repo.CompleteMultipart) | |||
| m.Post("/update_chunk", repo.UpdateMultipart) | |||
| }, reqSignIn) | |||
| m.Group("/attachments", func() { | |||
| m.Post("/decompress_done_notify", repo.UpdateAttachmentDecompressState) | |||
| m.Post("/complete_multipart", repo.CompleteMultipart) | |||
| }) | |||
| m.Group("/attachments", func() { | |||
| @@ -974,6 +986,12 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Post("/topics", repo.TopicsPost) | |||
| }, context.RepoAssignment(), context.RepoMustNotBeArchived(), reqRepoAdmin) | |||
| m.Group("/image/:id", func() { | |||
| m.Get("/:from", cloudbrain.AdminOrImageCreaterRight, repo.CloudBrainImageEdit) | |||
| m.Post("", cloudbrain.AdminOrImageCreaterRight, bindIgnErr(auth.EditImageCloudBrainForm{}), repo.CloudBrainImageEditPost) | |||
| m.Delete("", cloudbrain.AdminOrImageCreaterRight, repo.CloudBrainImageDelete) | |||
| m.Put("/action/:action", reqSignIn, image.Action) | |||
| }) | |||
| m.Group("/:username/:reponame", func() { | |||
| m.Group("", func() { | |||
| m.Get("/^:type(issues|pulls)$", repo.Issues) | |||
| @@ -1015,6 +1033,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Group("/:id", func() { | |||
| m.Get("", reqRepoCloudBrainReader, repo.CloudBrainShow) | |||
| m.Get("/debug", cloudbrain.AdminOrJobCreaterRight, repo.CloudBrainDebug) | |||
| m.Get("/commit_image", cloudbrain.AdminOrJobCreaterRight, repo.CloudBrainCommitImageShow) | |||
| m.Post("/commit_image/check", cloudbrain.AdminOrJobCreaterRight, bindIgnErr(auth.CommitImageCloudBrainForm{}), repo.CloudBrainCommitImageCheck) | |||
| m.Post("/commit_image", cloudbrain.AdminOrJobCreaterRight, bindIgnErr(auth.CommitImageCloudBrainForm{}), repo.CloudBrainCommitImage) | |||
| m.Post("/stop", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainStop) | |||
| m.Post("/del", cloudbrain.AdminOrOwnerOrJobCreaterRight, repo.CloudBrainDel) | |||
| @@ -68,23 +68,23 @@ func SearchApi(ctx *context.Context) { | |||
| if OnlySearchLabel { | |||
| searchRepoByLabel(ctx, Key, Page, PageSize) | |||
| } else { | |||
| searchRepo(ctx, "repository-es-index", Key, Page, PageSize, OnlyReturnNum) | |||
| searchRepo(ctx, "repository-es-index"+setting.INDEXPOSTFIX, Key, Page, PageSize, OnlyReturnNum) | |||
| } | |||
| return | |||
| } else if TableName == "issue" { | |||
| searchIssueOrPr(ctx, "issue-es-index", Key, Page, PageSize, OnlyReturnNum, "f") | |||
| searchIssueOrPr(ctx, "issue-es-index"+setting.INDEXPOSTFIX, Key, Page, PageSize, OnlyReturnNum, "f") | |||
| return | |||
| } else if TableName == "user" { | |||
| searchUserOrOrg(ctx, "user-es-index", Key, Page, PageSize, true, OnlyReturnNum) | |||
| searchUserOrOrg(ctx, "user-es-index"+setting.INDEXPOSTFIX, Key, Page, PageSize, true, OnlyReturnNum) | |||
| return | |||
| } else if TableName == "org" { | |||
| searchUserOrOrg(ctx, "user-es-index", Key, Page, PageSize, false, OnlyReturnNum) | |||
| searchUserOrOrg(ctx, "user-es-index"+setting.INDEXPOSTFIX, Key, Page, PageSize, false, OnlyReturnNum) | |||
| return | |||
| } else if TableName == "dataset" { | |||
| searchDataSet(ctx, "dataset-es-index", Key, Page, PageSize, OnlyReturnNum) | |||
| searchDataSet(ctx, "dataset-es-index"+setting.INDEXPOSTFIX, Key, Page, PageSize, OnlyReturnNum) | |||
| return | |||
| } else if TableName == "pr" { | |||
| searchIssueOrPr(ctx, "issue-es-index", Key, Page, PageSize, OnlyReturnNum, "t") | |||
| searchIssueOrPr(ctx, "issue-es-index"+setting.INDEXPOSTFIX, Key, Page, PageSize, OnlyReturnNum, "t") | |||
| //searchPR(ctx, "issue-es-index", Key, Page, PageSize, OnlyReturnNum) | |||
| return | |||
| } | |||
| @@ -183,7 +183,7 @@ func searchRepoByLabel(ctx *context.Context, Key string, Page int, PageSize int) | |||
| topicsQuery := elastic.NewMatchQuery("topics", Key) | |||
| boolQ.Should(topicsQuery) | |||
| res, err := client.Search("repository-es-index").Query(boolQ).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Highlight(queryHighlight("topics")).Do(ctx.Req.Context()) | |||
| res, err := client.Search("repository-es-index").Query(boolQ).SortBy(getSort(SortBy, ascending, "updated_unix.keyword", false)...).From(from).Size(Size).Highlight(queryHighlight("topics")).Do(ctx.Req.Context()) | |||
| if err == nil { | |||
| searchJson, _ := json.Marshal(res) | |||
| log.Info("searchJson=" + string(searchJson)) | |||
| @@ -200,15 +200,18 @@ func searchRepoByLabel(ctx *context.Context, Key string, Page int, PageSize int) | |||
| } | |||
| } | |||
| func getSort(SortBy string, ascending bool) elastic.Sorter { | |||
| var sort elastic.Sorter | |||
| sort = elastic.NewScoreSort() | |||
| if SortBy != "" { | |||
| if SortBy == "default" { | |||
| return sort | |||
| func getSort(SortBy string, ascending bool, secondSortBy string, secondAscending bool) []elastic.Sorter { | |||
| sort := make([]elastic.Sorter, 0) | |||
| if SortBy == "default" || SortBy == "" { | |||
| sort = append(sort, elastic.NewScoreSort()) | |||
| if secondSortBy != "" { | |||
| log.Info("SortBy=" + SortBy + " secondSortBy=" + secondSortBy) | |||
| sort = append(sort, elastic.NewFieldSort(secondSortBy).Order(secondAscending)) | |||
| } | |||
| return elastic.NewFieldSort(SortBy).Order(ascending) | |||
| } else { | |||
| sort = append(sort, elastic.NewFieldSort(SortBy).Order(ascending)) | |||
| } | |||
| log.Info("sort size=" + fmt.Sprint(len(sort))) | |||
| return sort | |||
| } | |||
| @@ -308,7 +311,7 @@ func searchRepo(ctx *context.Context, TableName string, Key string, Page int, Pa | |||
| topicsQuery := elastic.NewMatchQuery("topics", Key).Boost(1).QueryName("f_third") | |||
| boolQ.Should(nameQuery, descriptionQuery, topicsQuery) | |||
| res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Highlight(queryHighlight("alias", "description", "topics")).Do(ctx.Req.Context()) | |||
| res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending, "num_stars", false)...).From(from).Size(Size).Highlight(queryHighlight("alias", "description", "topics")).Do(ctx.Req.Context()) | |||
| if err == nil { | |||
| searchJson, _ := json.Marshal(res) | |||
| log.Info("searchJson=" + string(searchJson)) | |||
| @@ -330,7 +333,7 @@ func searchRepo(ctx *context.Context, TableName string, Key string, Page int, Pa | |||
| } else { | |||
| log.Info("query all content.") | |||
| //搜索的属性要指定{"timestamp":{"unmapped_type":"date"}} | |||
| res, err := client.Search(TableName).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Do(ctx.Req.Context()) | |||
| res, err := client.Search(TableName).SortBy(getSort(SortBy, ascending, "updated_unix.keyword", false)...).From(from).Size(Size).Do(ctx.Req.Context()) | |||
| if err == nil { | |||
| searchJson, _ := json.Marshal(res) | |||
| log.Info("searchJson=" + string(searchJson)) | |||
| @@ -691,7 +694,7 @@ func searchUserOrOrg(ctx *context.Context, TableName string, Key string, Page in | |||
| boolQ.Must(UserOrOrgQuery) | |||
| } | |||
| res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending)).From((Page - 1) * PageSize).Size(PageSize).Highlight(queryHighlight("name", "full_name", "description")).Do(ctx.Req.Context()) | |||
| res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending, "updated_unix.keyword", false)...).From((Page - 1) * PageSize).Size(PageSize).Highlight(queryHighlight("name", "full_name", "description")).Do(ctx.Req.Context()) | |||
| if err == nil { | |||
| searchJson, _ := json.Marshal(res) | |||
| log.Info("searchJson=" + string(searchJson)) | |||
| @@ -849,7 +852,7 @@ func searchDataSet(ctx *context.Context, TableName string, Key string, Page int, | |||
| fileNameQuery := elastic.NewMatchQuery("file_name", Key).Boost(1).QueryName("f_third") | |||
| categoryQuery := elastic.NewMatchQuery("category", Key).Boost(1).QueryName("f_fourth") | |||
| boolQ.Should(nameQuery, descQuery, categoryQuery, fileNameQuery) | |||
| res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Highlight(queryHighlight("title", "description", "file_name", "category")).Do(ctx.Req.Context()) | |||
| res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending, "updated_unix.keyword", false)...).From(from).Size(Size).Highlight(queryHighlight("title", "description", "file_name", "category")).Do(ctx.Req.Context()) | |||
| if err == nil { | |||
| searchJson, _ := json.Marshal(res) | |||
| log.Info("searchJson=" + string(searchJson)) | |||
| @@ -864,7 +867,7 @@ func searchDataSet(ctx *context.Context, TableName string, Key string, Page int, | |||
| } else { | |||
| log.Info("query all datasets.") | |||
| //搜索的属性要指定{"timestamp":{"unmapped_type":"date"}} | |||
| res, err := client.Search(TableName).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Do(ctx.Req.Context()) | |||
| res, err := client.Search(TableName).SortBy(getSort(SortBy, ascending, "updated_unix.keyword", false)...).From(from).Size(Size).Do(ctx.Req.Context()) | |||
| if err == nil { | |||
| searchJson, _ := json.Marshal(res) | |||
| log.Info("searchJson=" + string(searchJson)) | |||
| @@ -1057,7 +1060,7 @@ func searchIssueOrPr(ctx *context.Context, TableName string, Key string, Page in | |||
| boolQ.Must(isIssueQuery) | |||
| } | |||
| res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending)).From(from).Size(Size).Highlight(queryHighlight("name", "content", "comment")).Do(ctx.Req.Context()) | |||
| res, err := client.Search(TableName).Query(boolQ).SortBy(getSort(SortBy, ascending, "updated_unix.keyword", false)...).From(from).Size(Size).Highlight(queryHighlight("name", "content", "comment")).Do(ctx.Req.Context()) | |||
| if err == nil { | |||
| searchJson, _ := json.Marshal(res) | |||
| log.Info("searchJson=" + string(searchJson)) | |||
| @@ -20,6 +20,7 @@ import ( | |||
| issue_indexer "code.gitea.io/gitea/modules/indexer/issues" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/markup/markdown" | |||
| "code.gitea.io/gitea/modules/modelarts" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/modules/util" | |||
| issue_service "code.gitea.io/gitea/services/issue" | |||
| @@ -31,10 +32,11 @@ import ( | |||
| ) | |||
| const ( | |||
| tplDashboard base.TplName = "user/dashboard/dashboard" | |||
| tplIssues base.TplName = "user/dashboard/issues" | |||
| tplMilestones base.TplName = "user/dashboard/milestones" | |||
| tplProfile base.TplName = "user/profile" | |||
| tplDashboard base.TplName = "user/dashboard/dashboard" | |||
| tplIssues base.TplName = "user/dashboard/issues" | |||
| tplMilestones base.TplName = "user/dashboard/milestones" | |||
| tplProfile base.TplName = "user/profile" | |||
| tplCloudbrains base.TplName = "user/dashboard/cloudbrains" | |||
| ) | |||
| // getDashboardContextUser finds out dashboard is viewing as which context user. | |||
| @@ -751,3 +753,111 @@ func Email2User(ctx *context.Context) { | |||
| } | |||
| ctx.Redirect(setting.AppSubURL + "/user/" + u.Name) | |||
| } | |||
| func Cloudbrains(ctx *context.Context) { | |||
| ctx.Data["Title"] = ctx.Tr("user.cloudbrains") | |||
| listType := ctx.Query("listType") | |||
| jobType := ctx.Query("jobType") | |||
| jobStatus := ctx.Query("jobStatus") | |||
| ctx.Data["ListType"] = listType | |||
| ctx.Data["JobType"] = jobType | |||
| ctx.Data["JobStatus"] = jobStatus | |||
| page := ctx.QueryInt("page") | |||
| 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 | |||
| if jobType == string(models.JobTypeDebug) { | |||
| jobTypes = append(jobTypes, string(models.JobTypeSnn4imagenet), string(models.JobTypeBrainScore), string(models.JobTypeDebug)) | |||
| } else if jobType != "all" && jobType != "" { | |||
| jobTypes = append(jobTypes, jobType) | |||
| } | |||
| var jobStatuses []string | |||
| jobStatusNot := false | |||
| if jobStatus == "other" { | |||
| jobStatusNot = true | |||
| jobStatuses = append(jobStatuses, string(models.ModelArtsTrainJobWaiting), string(models.ModelArtsTrainJobFailed), string(models.ModelArtsRunning), string(models.ModelArtsTrainJobCompleted), | |||
| string(models.ModelArtsStarting), string(models.ModelArtsRestarting), string(models.ModelArtsStartFailed), | |||
| string(models.ModelArtsStopping), string(models.ModelArtsStopped), string(models.JobSucceeded)) | |||
| } else if jobStatus != "all" && jobStatus != "" { | |||
| jobStatuses = append(jobStatuses, jobStatus) | |||
| } | |||
| keyword := strings.Trim(ctx.Query("q"), " ") | |||
| ctxUser := getDashboardContextUser(ctx) | |||
| if ctx.Written() { | |||
| return | |||
| } | |||
| repos, _, err := models.SearchRepository(&models.SearchRepoOptions{ | |||
| Actor: ctx.User, | |||
| OwnerID: ctxUser.ID, | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("SearchRepository", err) | |||
| return | |||
| } | |||
| var repoIDList []int64 | |||
| for i, _ := range repos { | |||
| repoIDList = append(repoIDList, repos[i].ID) | |||
| } | |||
| ciTasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{ | |||
| ListOptions: models.ListOptions{ | |||
| Page: page, | |||
| PageSize: setting.UI.IssuePagingNum, | |||
| }, | |||
| Keyword: keyword, | |||
| UserID: ctxUser.ID, | |||
| Type: debugType, | |||
| JobTypeNot: jobTypeNot, | |||
| JobStatusNot: jobStatusNot, | |||
| JobStatus: jobStatuses, | |||
| JobTypes: jobTypes, | |||
| NeedRepoInfo: true, | |||
| IsLatestVersion: modelarts.IsLatestVersion, | |||
| RepoIDList: repoIDList, | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("Get job failed:", err) | |||
| return | |||
| } | |||
| for i, task := range ciTasks { | |||
| ciTasks[i].CanDebug = true | |||
| ciTasks[i].CanDel = true | |||
| ciTasks[i].Cloudbrain.ComputeResource = task.ComputeResource | |||
| } | |||
| pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, getTotalPage(count, setting.UI.IssuePagingNum)) | |||
| pager.SetDefaultParams(ctx) | |||
| pager.AddParam(ctx, "listType", "ListType") | |||
| ctx.Data["Page"] = pager | |||
| ctx.Data["PageIsUserCloudBrain"] = true | |||
| ctx.Data["Tasks"] = ciTasks | |||
| ctx.Data["CanCreate"] = true | |||
| ctx.Data["Keyword"] = keyword | |||
| ctx.HTML(200, tplCloudbrains) | |||
| } | |||
| func getTotalPage(total int64, pageSize int) int { | |||
| another := 0 | |||
| if int(total)%pageSize != 0 { | |||
| another = 1 | |||
| } | |||
| return int(total)/pageSize + another | |||
| } | |||
| @@ -106,9 +106,9 @@ func Profile(ctx *context.Context) { | |||
| for _, org := range orgs { | |||
| _, repoCount, err := models.SearchRepository(&models.SearchRepoOptions{ | |||
| OwnerID: org.ID, | |||
| Private: ctx.IsSigned, | |||
| Actor: ctx.User, | |||
| OwnerID: org.ID, | |||
| Private: ctx.IsSigned, | |||
| Actor: ctx.User, | |||
| }) | |||
| if err != nil { | |||
| ctx.ServerError("SearchRepository", err) | |||
| @@ -175,6 +175,8 @@ func Profile(ctx *context.Context) { | |||
| orderBy = models.SearchOrderByAlphabeticallyReverse | |||
| case "alphabetically": | |||
| orderBy = models.SearchOrderByAlphabetically | |||
| case "downloadtimes": | |||
| orderBy = models.SearchOrderByDownloadTimes | |||
| case "moststars": | |||
| orderBy = models.SearchOrderByStarsReverse | |||
| case "feweststars": | |||
| @@ -56,6 +56,7 @@ | |||
| "tab", | |||
| "table", | |||
| "text", | |||
| "transition" | |||
| "transition", | |||
| "toast" | |||
| ] | |||
| } | |||
| @@ -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, 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} | |||
| type ClientsManager struct { | |||
| Clients *orderedmap.OrderedMap | |||
| @@ -0,0 +1,129 @@ | |||
| <style> | |||
| .label_color{ | |||
| color:#505559 !important; | |||
| width: 6% !important; | |||
| text-align: center; | |||
| } | |||
| </style> | |||
| {{template "base/head" .}} | |||
| <div id="mask"> | |||
| <div id="loadingPage"> | |||
| <div class="rect1"></div> | |||
| <div class="rect2"></div> | |||
| <div class="rect3"></div> | |||
| <div class="rect4"></div> | |||
| <div class="rect5"></div> | |||
| </div> | |||
| </div> | |||
| <div class="repository"> | |||
| {{template "repo/header" .}} | |||
| <div class="alert"></div> | |||
| <div class="ui container"> | |||
| <div> | |||
| <div class="ui negative message" style="display: none;"> | |||
| </div> | |||
| <div class="ui info message" style="display: none;"> | |||
| </div> | |||
| <div class="ui positive message" style="display: none;"> | |||
| </div> | |||
| <h4 class="ui top attached header"> | |||
| {{.i18n.Tr "repo.submit_image"}} | |||
| </h4> | |||
| <div class="submit-image-tmplvalue" style="display: none;" data-link="{{$.Link}}"></div> | |||
| <div class="ui attached segment" style="padding: 2em 3em;padding-bottom: 7rem;"> | |||
| <div class="ui form" id="form_image"> | |||
| <input type="hidden" name="edit" value="edit"> | |||
| {{.CsrfTokenHtml}} | |||
| <div class="inline field"> | |||
| <label class="label_color" for="">{{$.i18n.Tr "dataset.dataset_available_clusters"}}</label> | |||
| <div class="ui basic label" style="border: none !important;color:#3291f8;"> | |||
| <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14"><path fill="none" d="M0 0h24v24H0z"></path><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"></path></svg> | |||
| CPU/GPU | |||
| </div> | |||
| <input type="hidden" value="{{.Type}}" name="type"> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label class="label_color" for="">{{$.i18n.Tr "repo.images.name"}}</label> | |||
| <input type="text" name="tag" required placeholder="{{$.i18n.Tr "repo.images.name_placerholder"}}" style="width: 80%;" maxlength="100"> | |||
| <span class="tooltips" style="display: block;padding-left: 0.5rem;">{{.i18n.Tr "repo.images.name_rule"}}</span> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label class="label_color" for="">{{$.i18n.Tr "repo.images"}}</label> | |||
| <input type="text" name="place" required placeholder="{{$.i18n.Tr "cloudbrain.input_mirror"}}" style="width: 80%;" maxlength="100"> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label class="label_color" for="">{{$.i18n.Tr "dataset.description"}}</label> | |||
| <textarea style="width: 80%;" required id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)"></textarea> | |||
| </div> | |||
| <div class="inline field" style="display: flex;align-items: center;"> | |||
| <label class="label_color" for="">{{$.i18n.Tr "repo.model.manage.label"}}</label> | |||
| <div class="ui multiple search selection dropdown" id="dropdown_image" style="width: 80%;"> | |||
| <input type="hidden" name="topics" value="" required> | |||
| <div class="default text" id="default_text">{{.i18n.Tr "repo.repo_label_helpe"}}</div> | |||
| <div class="menu" id="course_label_item"></div> | |||
| </div> | |||
| </div> | |||
| <span class="tooltips" style="display: block;padding-left: 0.5rem;margin-top: 0.5rem;margin-bottom: 1rem;">{{.i18n.Tr "repo.image.label_tooltips"}}</span> | |||
| <div class="inline fields"> | |||
| <label class="label_color" for="" style="visibility: hidden;"></label> | |||
| <div class="field"> | |||
| <div class="ui radio checkbox"> | |||
| <input type="radio" name="isRecommend" checked="checked" value="true"> | |||
| <label>{{.i18n.Tr "admin.images.recommend"}}</label> | |||
| </div> | |||
| </div> | |||
| <div class="field" style="flex: 0.15;"> | |||
| <div class="ui radio checkbox" > | |||
| <input type="radio" name="isRecommend" value="false"> | |||
| <label>{{.i18n.Tr "admin.images.unrecommend"}}</label> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="inline fields"> | |||
| <label class="label_color" for="" style="visibility: hidden;"></label> | |||
| <div class="field"> | |||
| <div class="ui radio checkbox"> | |||
| <input type="radio" name="isPrivate" checked="checked" value="false"> | |||
| <label>{{.i18n.Tr "org.settings.visibility.public"}}</label> | |||
| </div> | |||
| </div> | |||
| <div class="field" style="flex: 0.15;"> | |||
| <div class="ui radio checkbox" > | |||
| <input type="radio" name="isPrivate" value="true"> | |||
| <label>{{.i18n.Tr "home.show_private"}}</label> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <span class="label_color">{{.i18n.Tr "repo.images.public_tooltips"}}</span> | |||
| </div> | |||
| </div> | |||
| <div class="inline required field" style="padding-top: 2rem;"> | |||
| <label class="label_color" for="" style="visibility: hidden;"></label> | |||
| <button class="ui create_image green button" type="button"> | |||
| {{.i18n.Tr "repo.cloudbrain.commit_image"}} | |||
| </button> | |||
| <a class="ui button" id="cancel_submit_image">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <!-- 确认模态框 --> | |||
| <div> | |||
| <div class="ui modal image_confirm_submit"> | |||
| <div class="header">{{.i18n.Tr "repo.submit_image"}}</div> | |||
| <div class="content text red center"> | |||
| <p><i class="exclamation icon"></i>{{.i18n.Tr "repo.image_overwrite"}}</p> | |||
| </div> | |||
| <div class="actions"> | |||
| <button class="ui deny small button">{{.i18n.Tr "cloudbrain.operate_cancel"}}</button> | |||
| <button class="ui green small approve button">{{.i18n.Tr "cloudbrain.operate_confirm"}}</button> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| @@ -0,0 +1,42 @@ | |||
| {{template "base/head" .}} | |||
| <!-- 弹窗 --> | |||
| <div id="mask"> | |||
| <div id="loadingPage"> | |||
| <div class="rect1"></div> | |||
| <div class="rect2"></div> | |||
| <div class="rect3"></div> | |||
| <div class="rect4"></div> | |||
| <div class="rect5"></div> | |||
| </div> | |||
| </div> | |||
| <!-- 提示框 --> | |||
| <div class="alert"></div> | |||
| <div class="admin user"> | |||
| {{template "admin/navbar" .}} | |||
| <div id="images-admin"> | |||
| </div> | |||
| </div> | |||
| <!-- 确认模态框 --> | |||
| <div> | |||
| <div class="ui basic modal images"> | |||
| <div class="ui icon header"> | |||
| <i class="trash icon"></i> {{.i18n.Tr "repo.images.delete_task"}} | |||
| </div> | |||
| <div class="content"> | |||
| <p>{{.i18n.Tr "repo.images.task_delete_confirm"}}</p> | |||
| </div> | |||
| <div class="actions"> | |||
| <div class="ui red basic inverted cancel button"> | |||
| <i class="remove icon"></i> {{.i18n.Tr "cloudbrain.operate_cancel"}} | |||
| </div> | |||
| <div class="ui green basic inverted ok button"> | |||
| <i class="checkmark icon"></i> {{.i18n.Tr "cloudbrain.operate_confirm"}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| @@ -12,13 +12,14 @@ | |||
| <!-- 提示框 --> | |||
| <div class="alert"></div> | |||
| <div class="admin user"> | |||
| <div class="cloudbrain_debug" style="display: none;" data-debug="{{$.i18n.Tr "repo.debug"}}" data-debug-again="{{$.i18n.Tr "repo.debug_again"}}"></div> | |||
| {{template "admin/navbar" .}} | |||
| <div class="ui container" style="width: 80%;"> | |||
| {{template "base/alert" .}} | |||
| <div class="ui grid" > | |||
| <div class="row" style="border: 1px solid #d4d4d5;margin-top: 15px;padding-top: 0;"> | |||
| {{template "admin/cloudbrain/search" .}} | |||
| <div class="ui ten wide column right aligned" style="margin: 1rem 0;"> | |||
| <div class="ui six wide column right aligned" style="margin: 1rem 0;"> | |||
| <a class="ui compact blue basic icon button" style="box-shadow: none !important; padding: 0.8em;" href="/admin/cloudbrains/download"><i class="ri-download-line middle aligned icon"></i>{{.i18n.Tr "admin.cloudbrain.download_report"}}</a> | |||
| </div> | |||
| <div class="ui sixteen wide column"> | |||
| @@ -6,7 +6,7 @@ | |||
| </div> | |||
| </form> | |||
| </div> | |||
| <div class="ui six wide column" style="margin: 1rem 0;" id="adminCloud"> | |||
| <div class="ui ten wide column" style="margin: 1rem 0;" id="adminCloud"> | |||
| <div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | |||
| <div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "admin.cloudbrain.all_task_types"}}</div> | |||
| <i class="dropdown icon"></i> | |||
| @@ -0,0 +1,66 @@ | |||
| <style> | |||
| .ui.green.button, .ui.green.buttons .button{ | |||
| background-color: #5BB973; | |||
| } | |||
| </style> | |||
| <div class="repos--seach"> | |||
| <div class="ui container"> | |||
| <div class="ui two column centered grid"> | |||
| <form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin-top:1.2rem"> | |||
| <div class="ui fluid action input"> | |||
| <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "repo.cloudbrain.search"}}..." autofocus> | |||
| <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="ui container" style="width: 80%;"> | |||
| <div class="ui grid"> | |||
| <div class="row"> | |||
| <div class="ui {{if $.PageIsUserCloudBrain}}sixteen{{else}}six{{end}} wide column" style="margin: 1rem 0;" id="adminCloud"> | |||
| <div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | |||
| <div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "admin.cloudbrain.all_task_types"}}</div> | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value='{{.i18n.Tr "admin.cloudbrain.all_task_types"}}'>{{.i18n.Tr "admin.cloudbrain.all_task_types"}}</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=DEBUG&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="DEBUG">{{.i18n.Tr "cloudbrain.DEBUG"}}</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=TRAIN&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="TRAIN">{{.i18n.Tr "cloudbrain.TRAIN"}}</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=INFERENCE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="INFERENCE">{{.i18n.Tr "cloudbrain.INFERENCE"}}</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BENCHMARK&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.BENCHMARK"}}</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=SNN4IMAGENET&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.SNN4IMAGENET"}}</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType=BRAINSCORE&listType={{$.ListType}}&jobStatus={{$.JobStatus}}" data-value="BENCHMARK">{{.i18n.Tr "cloudbrain.BRAINSCORE"}}</a> | |||
| </div> | |||
| </div> | |||
| <div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | |||
| <div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}</div> | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=&jobStatus={{$.JobStatus}}" data-value='{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}'>{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=CPU/GPU&jobStatus={{$.JobStatus}}" data-value="CPU/GPU">CPU/GPU</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType=NPU&jobStatus={{$.JobStatus}}" data-value="NPU">NPU</a> | |||
| </div> | |||
| </div> | |||
| <div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;"> | |||
| <div class="default text" style="color: rgba(0,0,0,.87);">{{.i18n.Tr "admin.cloudbrain.all_status"}}</div> | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu"> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=" data-value='{{.i18n.Tr "admin.cloudbrain.all_status"}}'>{{.i18n.Tr "admin.cloudbrain.all_status"}}</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STARTING" data-value="STARTING">STARTING</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=RUNNING" data-value="RUNNING">RUNNING</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=RESTARTING" data-value="RESTARTING">RESTARTING </a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=START_FAILED" data-value="START_FAILED">START_FAILED</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STOPPING" data-value="STOPPING">STOPPING</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=STOPPED" data-value="STOPPED">STOPPED</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=WAITING" data-value="WAITING">WAITING</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=COMPLETED" data-value="COMPLETED">COMPLETED</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=SUCCEEDED" data-value="SUCCEEDED">SUCCEEDED</a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=FAILED" data-value="FAILED">FAILED </a> | |||
| <a class="item" href="{{$.Link}}?q={{$.Keyword}}&jobType={{$.JobType}}&listType={{$.ListType}}&jobStatus=other" data-value="OTHER">OTHER</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -3,6 +3,9 @@ | |||
| {{template "admin/navbar" .}} | |||
| <div class="ui container"> | |||
| {{template "base/alert" .}} | |||
| <div class="ui negative message" style="display: none;"> | |||
| </div> | |||
| <h4 class="ui top attached header"> | |||
| {{.i18n.Tr "admin.datasets.dataset_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}}) | |||
| </h4> | |||
| @@ -24,10 +27,10 @@ | |||
| {{range .Datasets}} | |||
| <tr> | |||
| <td>{{.ID}}</td> | |||
| <td><a href="{{AppSubUrl}}/">{{.Title}}</a></td> | |||
| <td style="display: flex;align-items: center;"><a href="{{AppSubUrl}}/">{{.Title}}</a>{{if .Recommend}}<img src="/img/jian.svg" style="margin-left: 0.5rem;">{{end}}</td> | |||
| <td><i class="fa fa{{if .IsPrivate}}-check{{end}}-square-o"></i></td> | |||
| <td><span title="{{.CreatedUnix.FormatLong}}">{{.CreatedUnix.FormatShort}}</span></td> | |||
| <td></td> | |||
| <td>{{if .Recommend}}<span class="set_dataset" style="color: rgb(250, 140, 22);cursor: pointer;" data-url="{{$.Link}}/{{.ID}}/action/unrecommend">{{$.i18n.Tr "admin.datasets.unrecommend"}}</span>{{else}}<span class="set_dataset" style="color: rgb(19, 194, 141);cursor: pointer;" data-url="{{$.Link}}/{{.ID}}/action/recommend">{{$.i18n.Tr "admin.datasets.recommend"}}</span>{{end}}</td> | |||
| </tr> | |||
| {{end}} | |||
| </tbody> | |||
| @@ -37,16 +40,4 @@ | |||
| {{template "base/paginate" .}} | |||
| </div> | |||
| </div> | |||
| <div class="ui small basic delete modal"> | |||
| <div class="ui icon header"> | |||
| <i class="trash icon"></i> | |||
| {{.i18n.Tr "dataset.settings.delete"}} | |||
| </div> | |||
| <div class="content"> | |||
| <p>{{.i18n.Tr "dataset.settings.delete_desc"}}</p> | |||
| {{.i18n.Tr "dataset.settings.delete_notices_2" `<span class="name"></span>` | Safe}}<br> | |||
| </div> | |||
| {{template "base/delete_modal_actions" .}} | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| {{template "base/footer" .}} | |||
| @@ -15,7 +15,10 @@ | |||
| {{.i18n.Tr "admin.datasets"}} | |||
| </a> | |||
| <a class="{{if .PageIsAdminCloudBrains}}active{{end}} item" href="{{AppSubUrl}}/admin/cloudbrains"> | |||
| 云脑任务 | |||
| {{.i18n.Tr "repo.cloudbrain.task"}} | |||
| </a> | |||
| <a class="{{if .PageIsAdminImages}}active{{end}} item" href="{{AppSubUrl}}/admin/images"> | |||
| {{.i18n.Tr "explore.images"}} | |||
| </a> | |||
| <a class="{{if .PageIsAdminHooks}}active{{end}} item" href="{{AppSubUrl}}/admin/hooks"> | |||
| {{.i18n.Tr "admin.hooks"}} | |||
| @@ -23,10 +23,11 @@ | |||
| {{.i18n.Tr "index"}} <i class="dropdown icon mglf" ></i> | |||
| </a> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px;min-width: max-content;"> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| <a style="border: none;color: #000; white-space: nowrap;" class=" item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/cloudbrains">{{.i18n.Tr "repo.cloudbrain.task"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -53,10 +54,11 @@ | |||
| {{.i18n.Tr "home"}} <i class="dropdown icon mglf"></i> | |||
| </a> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px;min-width: max-content;"> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||
| <a style="border: none;color: #000; white-space: nowrap;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/cloudbrains">{{.i18n.Tr "repo.cloudbrain.task"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -23,10 +23,11 @@ | |||
| {{.i18n.Tr "index"}} <i class="dropdown icon mglf"></i> | |||
| </a> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px;min-width: max-content;"> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| <a style="border: none;color: #000; white-space: nowrap;" class=" item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/cloudbrains">{{.i18n.Tr "repo.cloudbrain.task"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -52,10 +53,11 @@ | |||
| {{.i18n.Tr "home"}} <i class="dropdown icon mglf"></i> | |||
| </a> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px;min-width: max-content;"> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||
| <a style="border: none;color: #000; white-space: nowrap;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/cloudbrains">{{.i18n.Tr "repo.cloudbrain.task"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -15,10 +15,11 @@ | |||
| {{.i18n.Tr "index"}} <i class="dropdown icon mglf"></i> | |||
| </a> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px;min-width: max-content;"> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| <a style="border: none;color: #000; white-space: nowrap;" class=" item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/cloudbrains">{{.i18n.Tr "repo.cloudbrain.task"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -44,10 +45,11 @@ | |||
| {{.i18n.Tr "home"}} <i class="dropdown icon mglf"></i> | |||
| </a> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px;min-width: max-content;"> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||
| <a style="border: none;color: #000; white-space: nowrap;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/cloudbrains">{{.i18n.Tr "repo.cloudbrain.task"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -24,10 +24,11 @@ | |||
| {{.i18n.Tr "index"}} <i class="dropdown icon mglf"></i> | |||
| </a> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px;min-width: max-content;"> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
| <a style="border: none;color: #000;white-space: nowrap;" class=" item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/cloudbrains">{{.i18n.Tr "repo.cloudbrain.task"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -57,7 +58,8 @@ | |||
| <div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||
| <a style="border: none;color: #000;white-space: nowrap;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
| <a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/cloudbrains">{{.i18n.Tr "repo.cloudbrain.task"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -1,7 +1,7 @@ | |||
| {{if not .IsCourse}} | |||
| {{ if .notices}} | |||
| <div class="notic_content" id ="notic_content" style="display: block; position: relative"> | |||
| <diV class="ui container"> | |||
| <div class="ui container"> | |||
| <marquee behavior="scroll" direction="left"> | |||
| {{ $firstTag := true }} | |||
| {{range .notices.Notices}} | |||
| @@ -25,7 +25,7 @@ | |||
| <div class="item right" style="position:absolute;right: 1px;top:0px;"> | |||
| <i class="ri-close-fill x_icon" onclick="closeNoice()"></i> | |||
| </div> | |||
| </diV> | |||
| </div> | |||
| </div> | |||
| {{end}} | |||
| @@ -4,26 +4,26 @@ | |||
| <label>{{.i18n.Tr "dataset.dataset"}}</label> | |||
| <input type="hidden" name="attachment" :value="dataset_uuid"> | |||
| {{if eq .cloudbraintype 0}} | |||
| <input class="disabled" type="text" :value="dataset_name" required onfocus="this.blur();"> | |||
| <input class="disabled" type="text" :value="dataset_name" placeholder="{{.i18n.Tr "cloudbrain.select_dataset"}}" required onfocus="this.blur();"> | |||
| {{else}} | |||
| <input class="disabled" type="text" :value="dataset_name"> | |||
| <input class="disabled" type="text" :value="dataset_name" placeholder="{{.i18n.Tr "cloudbrain.select_dataset"}}"> | |||
| {{end}} | |||
| <el-button type="text" @click="dialogVisible = true" icon="el-icon-plus"> {{.i18n.Tr "dataset.select_dataset"}}</el-button> | |||
| <el-button type="text" @click="dialogVisible = true" icon="el-icon-plus" style="color: #0366d6;"> {{.i18n.Tr "dataset.select_dataset"}}</el-button> | |||
| <el-dialog | |||
| title="{{.i18n.Tr "dataset.select_dataset"}}" | |||
| :visible.sync="dialogVisible" | |||
| width="50%" | |||
| > | |||
| <div class="ui icon input" style="z-index: 9999;position: absolute;right: 50px;height:30px;"> | |||
| <i class="search icon" style="cursor: pointer;pointer-events:auto" @click="searchDataset()"></i> | |||
| <input type="text" placeholder="{{.i18n.Tr "dataset.search_dataset"}}" v-model="searchDataItem" @keyup.enter="searchDataset()"> | |||
| <i class="search icon"></i> | |||
| <input type="text" placeholder="{{.i18n.Tr "dataset.search_dataset"}}" v-model="searchDataItem"> | |||
| </div> | |||
| <el-tabs v-model="activeName" @tab-click="handleClick('{{.RepoLink}}',activeName,{{.cloudbraintype}})"> | |||
| <el-tab-pane label="{{.i18n.Tr "dataset.current_project"}}" name="first"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(dataset,index) in currentRepoDataset" :key="index"> | |||
| <div style="width: 90%;"> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias} </span><span class="panel_dataset_name">${dataset.Name} </span></div> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><img v-if="dataset.Recommend" src="/img/jian.svg" style="margin-left: 0.5rem;"><span class="panel_dataset_name">${dataset.Name} </span></div> | |||
| <div style="margin-top: 8px;display: flex;"> | |||
| <a :title="dataset.UserName" style="cursor: default;"> | |||
| <img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="dataset.RelAvatarLink"> | |||
| @@ -49,7 +49,7 @@ | |||
| <el-tab-pane label="{{.i18n.Tr "dataset.owner_dataset"}}" name="second"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(dataset,index) in myDataset" :key="index"> | |||
| <div style="width: 90%;"> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><span class="panel_dataset_name">${dataset.Name}</span></div> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><img v-if="dataset.Recommend" src="/img/jian.svg" style="margin-left: 0.5rem;"><span class="panel_dataset_name">${dataset.Name}</span></div> | |||
| <div style="margin-top: 8px;display: flex;"> | |||
| <a :title="dataset.UserName" style="cursor: default;"> | |||
| <img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="dataset.RelAvatarLink"> | |||
| @@ -74,7 +74,7 @@ | |||
| <el-tab-pane label="{{.i18n.Tr "dataset.public_dataset"}}" name="third"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(dataset,index) in publicDataset" :key="index"> | |||
| <div style="width: 90%;"> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><span class="panel_dataset_name">${dataset.Name}</span></div> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><img v-if="dataset.Recommend" src="/img/jian.svg" style="margin-left: 0.5rem;"><span class="panel_dataset_name">${dataset.Name}</span></div> | |||
| <div style="margin-top: 8px;display: flex;"> | |||
| <a :title="dataset.UserName" style="cursor: default;"> | |||
| <img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="dataset.RelAvatarLink"> | |||
| @@ -99,7 +99,7 @@ | |||
| <el-tab-pane label="{{.i18n.Tr "dataset.I_liked"}}" name="fourth"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(dataset,index) in myFavoriteDataset" :key="index"> | |||
| <div style="width: 90%;"> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><span class="panel_dataset_name">${dataset.Name}</span></div> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><img v-if="dataset.Recommend" src="/img/jian.svg" style="margin-left: 0.5rem;"><span class="panel_dataset_name">${dataset.Name}</span></div> | |||
| <div style="margin-top: 8px;display: flex;"> | |||
| <a :title="dataset.UserName" style="cursor: default;"> | |||
| <img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="dataset.RelAvatarLink"> | |||
| @@ -1,9 +1,13 @@ | |||
| <div class="dataset-repolink" id="dataset-repolink-init" style="display: none;" data-repolink="{{.RepoLink}}" data-cloudranin-type="{{.cloudbraintype}}"></div> | |||
| <div class="inline required unite min_title field" id="dataset-base" style="margin-bottom: 0 !important;"> | |||
| {{if .newInference}} | |||
| <label style="font-weight: normal;">{{.i18n.Tr "dataset.dataset"}}</label> | |||
| {{else}} | |||
| <label style="font-weight: normal;">{{.i18n.Tr "dataset.dataset"}}</label> | |||
| {{end}} | |||
| <input type="hidden" name="attachment" :value="dataset_uuid"> | |||
| <input class="disabled" type="text" :value="dataset_name" required onfocus="this.blur();" style="width: 35.5%;"> | |||
| <input class="disabled" type="text" :value="dataset_name" required onfocus="this.blur();" style="width: 48.5%;"> | |||
| <el-button type="text" @click="dialogVisible = true" icon="el-icon-plus" style="color: #0366d6;"> {{.i18n.Tr "dataset.select_dataset"}}</el-button> | |||
| <el-dialog | |||
| title="{{.i18n.Tr "dataset.select_dataset"}}" | |||
| @@ -11,15 +15,15 @@ | |||
| width="50%" | |||
| > | |||
| <div class="ui icon input" style="z-index: 9999;position: absolute;right: 50px;height:30px;"> | |||
| <i class="search icon" style="cursor: pointer;pointer-events:auto" @click="searchDataset()"></i> | |||
| <input type="text" placeholder="{{.i18n.Tr "dataset.search_dataset"}}" v-model="searchDataItem" @keyup.enter="searchDataset()"> | |||
| <i class="search icon"></i> | |||
| <input type="text" placeholder="{{.i18n.Tr "dataset.search_dataset"}}" v-model="searchDataItem"> | |||
| </div> | |||
| <el-tabs v-model="activeName" @tab-click="handleClick('{{.RepoLink}}',activeName,{{.cloudbraintype}})"> | |||
| <el-tab-pane label="{{.i18n.Tr "dataset.current_project"}}" name="first"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(dataset,index) in currentRepoDataset" :key="index"> | |||
| <div style="width: 90%;"> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias} </span><span class="panel_dataset_name">${dataset.Name} </span></div> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias} </span><img v-if="dataset.Recommend" src="/img/jian.svg" style="margin-left: 0.5rem;"><span class="panel_dataset_name">${dataset.Name} </span></div> | |||
| <div style="margin-top: 8px;display: flex;"> | |||
| <a :title="dataset.UserName" style="cursor: default;"> | |||
| <img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="dataset.RelAvatarLink"> | |||
| @@ -45,7 +49,7 @@ | |||
| <el-tab-pane label="{{.i18n.Tr "dataset.owner_dataset"}}" name="second"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(dataset,index) in myDataset" :key="index"> | |||
| <div style="width: 90%;"> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><span class="panel_dataset_name">${dataset.Name}</span></div> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><img v-if="dataset.Recommend" src="/img/jian.svg" style="margin-left: 0.5rem;"><span class="panel_dataset_name">${dataset.Name}</span></div> | |||
| <div style="margin-top: 8px;display: flex;"> | |||
| <a :title="dataset.UserName" style="cursor: default;"> | |||
| <img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="dataset.RelAvatarLink"> | |||
| @@ -70,7 +74,7 @@ | |||
| <el-tab-pane label="{{.i18n.Tr "dataset.public_dataset"}}" name="third"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(dataset,index) in publicDataset" :key="index"> | |||
| <div style="width: 90%;"> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><span class="panel_dataset_name">${dataset.Name}</span></div> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><img v-if="dataset.Recommend" src="/img/jian.svg" style="margin-left: 0.5rem;"><span class="panel_dataset_name">${dataset.Name}</span></div> | |||
| <div style="margin-top: 8px;display: flex;"> | |||
| <a :title="dataset.UserName" style="cursor: default;"> | |||
| <img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="dataset.RelAvatarLink"> | |||
| @@ -95,7 +99,7 @@ | |||
| <el-tab-pane label="{{.i18n.Tr "dataset.I_liked"}}" name="fourth"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(dataset,index) in myFavoriteDataset" :key="index"> | |||
| <div style="width: 90%;"> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><span class="panel_dataset_name">${dataset.Name}</span></div> | |||
| <div style="display: flex;align-items: center;"><span class="panel_creator_reponam">${dataset.Repo.OwnerName}/${dataset.Repo.Alias}</span><img v-if="dataset.Recommend" src="/img/jian.svg" style="margin-left: 0.5rem;"><span class="panel_dataset_name">${dataset.Name}</span></div> | |||
| <div style="margin-top: 8px;display: flex;"> | |||
| <a :title="dataset.UserName" style="cursor: default;"> | |||
| <img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="dataset.RelAvatarLink"> | |||
| @@ -125,7 +125,8 @@ | |||
| <a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a> | |||
| <a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a> | |||
| <a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a> | |||
| <!-- <a class="{{if eq .SortType "downloadtimes"}}active{{end}} item" href="{{$.Link}}?sort=downloadtimes&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.downloadtimes"}}</a> --> | |||
| <a class="{{if eq .SortType "downloadtimes"}}active{{end}} item" href="{{$.Link}}?sort=downloadtimes&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}">{{.i18n.Tr "repo.issues.filter_sort.downloadtimes"}}</a> | |||
| <a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&tab={{$.TabName}}&category={{$.Category}}&task={{$.Task}}&license={{$.License}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -144,7 +145,8 @@ | |||
| <div class="ui card" @click="gotoDataset('{{.Repo.Link}}/datasets')" style="cursor: pointer;box-shadow: 0px 4px 4px 0px rgba(232,232,232,0.6);border: 1px solid rgba(232, 232, 232, 1);"> | |||
| <div class="content" style="border-bottom: none;"> | |||
| <div class="repo_dataset_header" style="display: flex;align-items: center;justify-content: space-between;"> | |||
| <a href="{{.Repo.Link}}/datasets" style="font-size: 12px;color: #3291F8;height: 24px;">{{.Repo.OwnerName}} / {{.Repo.Alias}}</a> | |||
| <a href="{{.Repo.Link}}/datasets" style="font-size: 12px;color: #3291F8;height: 24px;">{{.Repo.OwnerName}} / {{.Repo.Alias}}{{if .Recommend}}<img src="/img/jian.svg" style="margin-left: 0.5rem;">{{end}}</a> | |||
| {{if $.IsSigned}} | |||
| <span style="display: flex;align-items: center;justify-content: flex-end;cursor: pointer;" @click.stop="postSquareStar({{.ID}},'{{.Repo.Link}}/datasets',{{$k}})"> | |||
| <div style="line-height: 1;margin-right: 4px;margin-bottom: -2px;"> | |||
| @@ -163,7 +165,7 @@ | |||
| </div> | |||
| <div style="font-size: 16px;color:#0366D6;font-family: SourceHanSansSC-medium;height: 27px;font-weight: bold;">{{.Title}}</div> | |||
| {{if or (.Category) (.Task) (.License)}} | |||
| <div style="font-size: 12px;margin-top: 5px;height: 24px;"> | |||
| <div style="font-size: 12px;margin-top: 5px;"> | |||
| {{if .Category}} | |||
| {{$category := .Category}} | |||
| <a class="ui repo-topic label topic" href="{{$.Link}}?sort={{$.SortType}}&q={{$.Keyword}}&tab={{$.TabName}}&category={{.Category}}&task={{$.Task}}&license={{$.License}}">{{$.i18n.Tr (printf "dataset.category.%s" $category)}}</a> | |||
| @@ -1,7 +1,24 @@ | |||
| {{template "base/head" .}} | |||
| <div id="images"> | |||
| </div> | |||
| <!-- 确认模态框 --> | |||
| <div id="deletemodel"> | |||
| <div class="ui basic modal images"> | |||
| <div class="ui icon header"> | |||
| <i class="trash icon"></i> {{.i18n.Tr "repo.images.delete_task"}} | |||
| </div> | |||
| <div class="content"> | |||
| <p>{{.i18n.Tr "repo.images.task_delete_confirm"}}</p> | |||
| </div> | |||
| <div class="actions"> | |||
| <div class="ui red basic inverted cancel button"> | |||
| <i class="remove icon"></i> {{.i18n.Tr "cloudbrain.operate_cancel"}} | |||
| </div> | |||
| <div class="ui green basic inverted ok button"> | |||
| <i class="checkmark icon"></i> {{.i18n.Tr "cloudbrain.operate_confirm"}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| @@ -91,19 +91,19 @@ | |||
| {{if eq $i 0}} | |||
| <li class="wi"> | |||
| <div class="org_icon"> | |||
| <svg width="20px" height="20px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><defs><path id="rank1_svg__a" d="M13.69 20V9.616h-1.598l-3.139 2.61 1.027 1.218 1.95-1.804V20z"></path></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h32v32H0z"></path><g transform="translate(4 2.667)"><path fill="#D16C11" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#F7C049" cx="12" cy="14.667" r="12"></circle><circle fill="#FEE6AD" cx="12" cy="14.667" r="9.333"></circle><g fill-rule="nonzero"><use fill="#FFF" xlink:href="#rank1_svg__a"></use><use fill="#D74D03" xlink:href="#rank1_svg__a"></use></g></g></g></svg> | |||
| <svg width="24px" height="24px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><defs><path id="rank1_svg__a" d="M13.69 20V9.616h-1.598l-3.139 2.61 1.027 1.218 1.95-1.804V20z"></path></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h32v32H0z"></path><g transform="translate(4 2.667)"><path fill="#D16C11" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#F7C049" cx="12" cy="14.667" r="12"></circle><circle fill="#FEE6AD" cx="12" cy="14.667" r="9.333"></circle><g fill-rule="nonzero"><use fill="#FFF" xlink:href="#rank1_svg__a"></use><use fill="#D74D03" xlink:href="#rank1_svg__a"></use></g></g></g></svg> | |||
| </div> | |||
| </li> | |||
| {{else if eq $i 1}} | |||
| <li class="wi"> | |||
| <div class="org_icon"> | |||
| <svg width="20px" height="20px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#305269" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#BDD8F0" cx="12" cy="14.667" r="12"></circle><circle fill="#E1E9FC" cx="12" cy="14.667" r="9.333"></circle><path d="M15.817 20v-1.584h-4.81l3.212-2.977c.469-.43.853-.883 1.151-1.357.298-.474.447-1.039.447-1.694 0-.499-.088-.934-.264-1.305a2.525 2.525 0 00-.718-.917 3.169 3.169 0 00-1.064-.543 4.531 4.531 0 00-1.312-.183c-.47 0-.905.064-1.306.19-.4.128-.753.314-1.056.558-.303.244-.55.55-.74.917-.191.366-.306.79-.345 1.268l1.848.147c.059-.43.23-.772.513-1.027.284-.254.646-.381 1.086-.381.205 0 .398.032.579.095.18.064.34.154.477.272a1.262 1.262 0 01.455.997c0 .176-.035.345-.103.506a2.52 2.52 0 01-.257.462 3.476 3.476 0 01-.345.418c-.127.132-.249.257-.366.374l-4.034 3.901V20h6.952z" fill="#305269" fill-rule="nonzero"></path></g></svg> | |||
| <svg width="24px" height="24px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#305269" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#BDD8F0" cx="12" cy="14.667" r="12"></circle><circle fill="#E1E9FC" cx="12" cy="14.667" r="9.333"></circle><path d="M15.817 20v-1.584h-4.81l3.212-2.977c.469-.43.853-.883 1.151-1.357.298-.474.447-1.039.447-1.694 0-.499-.088-.934-.264-1.305a2.525 2.525 0 00-.718-.917 3.169 3.169 0 00-1.064-.543 4.531 4.531 0 00-1.312-.183c-.47 0-.905.064-1.306.19-.4.128-.753.314-1.056.558-.303.244-.55.55-.74.917-.191.366-.306.79-.345 1.268l1.848.147c.059-.43.23-.772.513-1.027.284-.254.646-.381 1.086-.381.205 0 .398.032.579.095.18.064.34.154.477.272a1.262 1.262 0 01.455.997c0 .176-.035.345-.103.506a2.52 2.52 0 01-.257.462 3.476 3.476 0 01-.345.418c-.127.132-.249.257-.366.374l-4.034 3.901V20h6.952z" fill="#305269" fill-rule="nonzero"></path></g></svg> | |||
| </div> | |||
| </li> | |||
| {{else if eq $i 2}} | |||
| <li class="wi"> | |||
| <div class="org_icon"> | |||
| <svg width="20px" height="20px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#865B45" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#E7C5AC" cx="12" cy="14.667" r="12"></circle><circle fill="#FEDDC7" cx="12" cy="14.667" r="9.333"></circle><path d="M12.239 20.176c.46 0 .902-.066 1.327-.198.425-.132.8-.328 1.122-.587.323-.259.58-.579.77-.96.19-.382.286-.822.286-1.32 0-.646-.171-1.203-.513-1.672-.343-.47-.846-.753-1.511-.851v-.03c.557-.136.992-.422 1.305-.857.313-.435.47-.932.47-1.489 0-.46-.09-.863-.272-1.21a2.547 2.547 0 00-.726-.865 3.232 3.232 0 00-1.056-.521 4.521 4.521 0 00-1.276-.176 4.52 4.52 0 00-1.1.132 3.404 3.404 0 00-.968.403 2.79 2.79 0 00-.762.697 3.181 3.181 0 00-.499.997l1.863.499c.127-.362.33-.643.608-.843.279-.2.594-.301.946-.301.44 0 .797.127 1.071.381.274.255.41.582.41.983 0 .313-.058.562-.175.748a1.17 1.17 0 01-.462.425 1.903 1.903 0 01-.646.191 6.09 6.09 0 01-.74.044h-.455v1.584h.425c.264 0 .533.02.807.059.274.039.52.115.74.227.22.112.402.274.543.484.142.21.213.482.213.814a1.533 1.533 0 01-.52 1.18 1.772 1.772 0 01-.558.33 1.88 1.88 0 01-.667.118c-.47 0-.841-.117-1.115-.352s-.464-.567-.572-.997l-1.877.498c.117.43.288.8.513 1.108.225.308.491.56.8.755.307.196.652.34 1.033.433a5.13 5.13 0 001.218.139z" fill="#865B45" fill-rule="nonzero"></path></g></svg> | |||
| <svg width="24px" height="24px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#865B45" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#E7C5AC" cx="12" cy="14.667" r="12"></circle><circle fill="#FEDDC7" cx="12" cy="14.667" r="9.333"></circle><path d="M12.239 20.176c.46 0 .902-.066 1.327-.198.425-.132.8-.328 1.122-.587.323-.259.58-.579.77-.96.19-.382.286-.822.286-1.32 0-.646-.171-1.203-.513-1.672-.343-.47-.846-.753-1.511-.851v-.03c.557-.136.992-.422 1.305-.857.313-.435.47-.932.47-1.489 0-.46-.09-.863-.272-1.21a2.547 2.547 0 00-.726-.865 3.232 3.232 0 00-1.056-.521 4.521 4.521 0 00-1.276-.176 4.52 4.52 0 00-1.1.132 3.404 3.404 0 00-.968.403 2.79 2.79 0 00-.762.697 3.181 3.181 0 00-.499.997l1.863.499c.127-.362.33-.643.608-.843.279-.2.594-.301.946-.301.44 0 .797.127 1.071.381.274.255.41.582.41.983 0 .313-.058.562-.175.748a1.17 1.17 0 01-.462.425 1.903 1.903 0 01-.646.191 6.09 6.09 0 01-.74.044h-.455v1.584h.425c.264 0 .533.02.807.059.274.039.52.115.74.227.22.112.402.274.543.484.142.21.213.482.213.814a1.533 1.533 0 01-.52 1.18 1.772 1.772 0 01-.558.33 1.88 1.88 0 01-.667.118c-.47 0-.841-.117-1.115-.352s-.464-.567-.572-.997l-1.877.498c.117.43.288.8.513 1.108.225.308.491.56.8.755.307.196.652.34 1.033.433a5.13 5.13 0 001.218.139z" fill="#865B45" fill-rule="nonzero"></path></g></svg> | |||
| </div> | |||
| </li> | |||
| {{else }} | |||
| @@ -139,19 +139,19 @@ | |||
| {{if eq $i 0}} | |||
| <li class="wi"> | |||
| <div class="org_icon"> | |||
| <svg width="20px" height="20px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><defs><path id="rank1_svg__a" d="M13.69 20V9.616h-1.598l-3.139 2.61 1.027 1.218 1.95-1.804V20z"></path></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h32v32H0z"></path><g transform="translate(4 2.667)"><path fill="#D16C11" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#F7C049" cx="12" cy="14.667" r="12"></circle><circle fill="#FEE6AD" cx="12" cy="14.667" r="9.333"></circle><g fill-rule="nonzero"><use fill="#FFF" xlink:href="#rank1_svg__a"></use><use fill="#D74D03" xlink:href="#rank1_svg__a"></use></g></g></g></svg> | |||
| <svg width="24px" height="24px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><defs><path id="rank1_svg__a" d="M13.69 20V9.616h-1.598l-3.139 2.61 1.027 1.218 1.95-1.804V20z"></path></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h32v32H0z"></path><g transform="translate(4 2.667)"><path fill="#D16C11" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#F7C049" cx="12" cy="14.667" r="12"></circle><circle fill="#FEE6AD" cx="12" cy="14.667" r="9.333"></circle><g fill-rule="nonzero"><use fill="#FFF" xlink:href="#rank1_svg__a"></use><use fill="#D74D03" xlink:href="#rank1_svg__a"></use></g></g></g></svg> | |||
| </div> | |||
| </li> | |||
| {{else if eq $i 1}} | |||
| <li class="wi"> | |||
| <div class="org_icon"> | |||
| <svg width="20px" height="20px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#305269" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#BDD8F0" cx="12" cy="14.667" r="12"></circle><circle fill="#E1E9FC" cx="12" cy="14.667" r="9.333"></circle><path d="M15.817 20v-1.584h-4.81l3.212-2.977c.469-.43.853-.883 1.151-1.357.298-.474.447-1.039.447-1.694 0-.499-.088-.934-.264-1.305a2.525 2.525 0 00-.718-.917 3.169 3.169 0 00-1.064-.543 4.531 4.531 0 00-1.312-.183c-.47 0-.905.064-1.306.19-.4.128-.753.314-1.056.558-.303.244-.55.55-.74.917-.191.366-.306.79-.345 1.268l1.848.147c.059-.43.23-.772.513-1.027.284-.254.646-.381 1.086-.381.205 0 .398.032.579.095.18.064.34.154.477.272a1.262 1.262 0 01.455.997c0 .176-.035.345-.103.506a2.52 2.52 0 01-.257.462 3.476 3.476 0 01-.345.418c-.127.132-.249.257-.366.374l-4.034 3.901V20h6.952z" fill="#305269" fill-rule="nonzero"></path></g></svg> | |||
| <svg width="24px" height="24px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#305269" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#BDD8F0" cx="12" cy="14.667" r="12"></circle><circle fill="#E1E9FC" cx="12" cy="14.667" r="9.333"></circle><path d="M15.817 20v-1.584h-4.81l3.212-2.977c.469-.43.853-.883 1.151-1.357.298-.474.447-1.039.447-1.694 0-.499-.088-.934-.264-1.305a2.525 2.525 0 00-.718-.917 3.169 3.169 0 00-1.064-.543 4.531 4.531 0 00-1.312-.183c-.47 0-.905.064-1.306.19-.4.128-.753.314-1.056.558-.303.244-.55.55-.74.917-.191.366-.306.79-.345 1.268l1.848.147c.059-.43.23-.772.513-1.027.284-.254.646-.381 1.086-.381.205 0 .398.032.579.095.18.064.34.154.477.272a1.262 1.262 0 01.455.997c0 .176-.035.345-.103.506a2.52 2.52 0 01-.257.462 3.476 3.476 0 01-.345.418c-.127.132-.249.257-.366.374l-4.034 3.901V20h6.952z" fill="#305269" fill-rule="nonzero"></path></g></svg> | |||
| </div> | |||
| </li> | |||
| {{else if eq $i 2}} | |||
| <li class="wi"> | |||
| <div class="org_icon"> | |||
| <svg width="20px" height="20px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#865B45" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#E7C5AC" cx="12" cy="14.667" r="12"></circle><circle fill="#FEDDC7" cx="12" cy="14.667" r="9.333"></circle><path d="M12.239 20.176c.46 0 .902-.066 1.327-.198.425-.132.8-.328 1.122-.587.323-.259.58-.579.77-.96.19-.382.286-.822.286-1.32 0-.646-.171-1.203-.513-1.672-.343-.47-.846-.753-1.511-.851v-.03c.557-.136.992-.422 1.305-.857.313-.435.47-.932.47-1.489 0-.46-.09-.863-.272-1.21a2.547 2.547 0 00-.726-.865 3.232 3.232 0 00-1.056-.521 4.521 4.521 0 00-1.276-.176 4.52 4.52 0 00-1.1.132 3.404 3.404 0 00-.968.403 2.79 2.79 0 00-.762.697 3.181 3.181 0 00-.499.997l1.863.499c.127-.362.33-.643.608-.843.279-.2.594-.301.946-.301.44 0 .797.127 1.071.381.274.255.41.582.41.983 0 .313-.058.562-.175.748a1.17 1.17 0 01-.462.425 1.903 1.903 0 01-.646.191 6.09 6.09 0 01-.74.044h-.455v1.584h.425c.264 0 .533.02.807.059.274.039.52.115.74.227.22.112.402.274.543.484.142.21.213.482.213.814a1.533 1.533 0 01-.52 1.18 1.772 1.772 0 01-.558.33 1.88 1.88 0 01-.667.118c-.47 0-.841-.117-1.115-.352s-.464-.567-.572-.997l-1.877.498c.117.43.288.8.513 1.108.225.308.491.56.8.755.307.196.652.34 1.033.433a5.13 5.13 0 001.218.139z" fill="#865B45" fill-rule="nonzero"></path></g></svg> | |||
| <svg width="24px" height="24px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#865B45" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#E7C5AC" cx="12" cy="14.667" r="12"></circle><circle fill="#FEDDC7" cx="12" cy="14.667" r="9.333"></circle><path d="M12.239 20.176c.46 0 .902-.066 1.327-.198.425-.132.8-.328 1.122-.587.323-.259.58-.579.77-.96.19-.382.286-.822.286-1.32 0-.646-.171-1.203-.513-1.672-.343-.47-.846-.753-1.511-.851v-.03c.557-.136.992-.422 1.305-.857.313-.435.47-.932.47-1.489 0-.46-.09-.863-.272-1.21a2.547 2.547 0 00-.726-.865 3.232 3.232 0 00-1.056-.521 4.521 4.521 0 00-1.276-.176 4.52 4.52 0 00-1.1.132 3.404 3.404 0 00-.968.403 2.79 2.79 0 00-.762.697 3.181 3.181 0 00-.499.997l1.863.499c.127-.362.33-.643.608-.843.279-.2.594-.301.946-.301.44 0 .797.127 1.071.381.274.255.41.582.41.983 0 .313-.058.562-.175.748a1.17 1.17 0 01-.462.425 1.903 1.903 0 01-.646.191 6.09 6.09 0 01-.74.044h-.455v1.584h.425c.264 0 .533.02.807.059.274.039.52.115.74.227.22.112.402.274.543.484.142.21.213.482.213.814a1.533 1.533 0 01-.52 1.18 1.772 1.772 0 01-.558.33 1.88 1.88 0 01-.667.118c-.47 0-.841-.117-1.115-.352s-.464-.567-.572-.997l-1.877.498c.117.43.288.8.513 1.108.225.308.491.56.8.755.307.196.652.34 1.033.433a5.13 5.13 0 001.218.139z" fill="#865B45" fill-rule="nonzero"></path></g></svg> | |||
| </div> | |||
| </li> | |||
| {{else }} | |||
| @@ -187,19 +187,19 @@ | |||
| {{if eq $i 0}} | |||
| <li class="wi"> | |||
| <div class="org_icon"> | |||
| <svg width="20px" height="20px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><defs><path id="rank1_svg__a" d="M13.69 20V9.616h-1.598l-3.139 2.61 1.027 1.218 1.95-1.804V20z"></path></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h32v32H0z"></path><g transform="translate(4 2.667)"><path fill="#D16C11" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#F7C049" cx="12" cy="14.667" r="12"></circle><circle fill="#FEE6AD" cx="12" cy="14.667" r="9.333"></circle><g fill-rule="nonzero"><use fill="#FFF" xlink:href="#rank1_svg__a"></use><use fill="#D74D03" xlink:href="#rank1_svg__a"></use></g></g></g></svg> | |||
| <svg width="24px" height="24px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><defs><path id="rank1_svg__a" d="M13.69 20V9.616h-1.598l-3.139 2.61 1.027 1.218 1.95-1.804V20z"></path></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h32v32H0z"></path><g transform="translate(4 2.667)"><path fill="#D16C11" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#F7C049" cx="12" cy="14.667" r="12"></circle><circle fill="#FEE6AD" cx="12" cy="14.667" r="9.333"></circle><g fill-rule="nonzero"><use fill="#FFF" xlink:href="#rank1_svg__a"></use><use fill="#D74D03" xlink:href="#rank1_svg__a"></use></g></g></g></svg> | |||
| </div> | |||
| </li> | |||
| {{else if eq $i 1}} | |||
| <li class="wi"> | |||
| <div class="org_icon"> | |||
| <svg width="20px" height="20px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#305269" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#BDD8F0" cx="12" cy="14.667" r="12"></circle><circle fill="#E1E9FC" cx="12" cy="14.667" r="9.333"></circle><path d="M15.817 20v-1.584h-4.81l3.212-2.977c.469-.43.853-.883 1.151-1.357.298-.474.447-1.039.447-1.694 0-.499-.088-.934-.264-1.305a2.525 2.525 0 00-.718-.917 3.169 3.169 0 00-1.064-.543 4.531 4.531 0 00-1.312-.183c-.47 0-.905.064-1.306.19-.4.128-.753.314-1.056.558-.303.244-.55.55-.74.917-.191.366-.306.79-.345 1.268l1.848.147c.059-.43.23-.772.513-1.027.284-.254.646-.381 1.086-.381.205 0 .398.032.579.095.18.064.34.154.477.272a1.262 1.262 0 01.455.997c0 .176-.035.345-.103.506a2.52 2.52 0 01-.257.462 3.476 3.476 0 01-.345.418c-.127.132-.249.257-.366.374l-4.034 3.901V20h6.952z" fill="#305269" fill-rule="nonzero"></path></g></svg> | |||
| <svg width="24px" height="24px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#305269" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#BDD8F0" cx="12" cy="14.667" r="12"></circle><circle fill="#E1E9FC" cx="12" cy="14.667" r="9.333"></circle><path d="M15.817 20v-1.584h-4.81l3.212-2.977c.469-.43.853-.883 1.151-1.357.298-.474.447-1.039.447-1.694 0-.499-.088-.934-.264-1.305a2.525 2.525 0 00-.718-.917 3.169 3.169 0 00-1.064-.543 4.531 4.531 0 00-1.312-.183c-.47 0-.905.064-1.306.19-.4.128-.753.314-1.056.558-.303.244-.55.55-.74.917-.191.366-.306.79-.345 1.268l1.848.147c.059-.43.23-.772.513-1.027.284-.254.646-.381 1.086-.381.205 0 .398.032.579.095.18.064.34.154.477.272a1.262 1.262 0 01.455.997c0 .176-.035.345-.103.506a2.52 2.52 0 01-.257.462 3.476 3.476 0 01-.345.418c-.127.132-.249.257-.366.374l-4.034 3.901V20h6.952z" fill="#305269" fill-rule="nonzero"></path></g></svg> | |||
| </div> | |||
| </li> | |||
| {{else if eq $i 2}} | |||
| <li class="wi"> | |||
| <div class="org_icon"> | |||
| <svg width="20px" height="20px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#865B45" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#E7C5AC" cx="12" cy="14.667" r="12"></circle><circle fill="#FEDDC7" cx="12" cy="14.667" r="9.333"></circle><path d="M12.239 20.176c.46 0 .902-.066 1.327-.198.425-.132.8-.328 1.122-.587.323-.259.58-.579.77-.96.19-.382.286-.822.286-1.32 0-.646-.171-1.203-.513-1.672-.343-.47-.846-.753-1.511-.851v-.03c.557-.136.992-.422 1.305-.857.313-.435.47-.932.47-1.489 0-.46-.09-.863-.272-1.21a2.547 2.547 0 00-.726-.865 3.232 3.232 0 00-1.056-.521 4.521 4.521 0 00-1.276-.176 4.52 4.52 0 00-1.1.132 3.404 3.404 0 00-.968.403 2.79 2.79 0 00-.762.697 3.181 3.181 0 00-.499.997l1.863.499c.127-.362.33-.643.608-.843.279-.2.594-.301.946-.301.44 0 .797.127 1.071.381.274.255.41.582.41.983 0 .313-.058.562-.175.748a1.17 1.17 0 01-.462.425 1.903 1.903 0 01-.646.191 6.09 6.09 0 01-.74.044h-.455v1.584h.425c.264 0 .533.02.807.059.274.039.52.115.74.227.22.112.402.274.543.484.142.21.213.482.213.814a1.533 1.533 0 01-.52 1.18 1.772 1.772 0 01-.558.33 1.88 1.88 0 01-.667.118c-.47 0-.841-.117-1.115-.352s-.464-.567-.572-.997l-1.877.498c.117.43.288.8.513 1.108.225.308.491.56.8.755.307.196.652.34 1.033.433a5.13 5.13 0 001.218.139z" fill="#865B45" fill-rule="nonzero"></path></g></svg> | |||
| <svg width="24px" height="24px" viewBox="0 0 32 32" class="contribution-item-img__2-fih"><g transform="translate(4 2.667)" fill="none" fill-rule="evenodd"><path fill="#865B45" d="M0 0h6.976l5.49 7.642L17.063 0H24L12 16z"></path><circle fill="#E7C5AC" cx="12" cy="14.667" r="12"></circle><circle fill="#FEDDC7" cx="12" cy="14.667" r="9.333"></circle><path d="M12.239 20.176c.46 0 .902-.066 1.327-.198.425-.132.8-.328 1.122-.587.323-.259.58-.579.77-.96.19-.382.286-.822.286-1.32 0-.646-.171-1.203-.513-1.672-.343-.47-.846-.753-1.511-.851v-.03c.557-.136.992-.422 1.305-.857.313-.435.47-.932.47-1.489 0-.46-.09-.863-.272-1.21a2.547 2.547 0 00-.726-.865 3.232 3.232 0 00-1.056-.521 4.521 4.521 0 00-1.276-.176 4.52 4.52 0 00-1.1.132 3.404 3.404 0 00-.968.403 2.79 2.79 0 00-.762.697 3.181 3.181 0 00-.499.997l1.863.499c.127-.362.33-.643.608-.843.279-.2.594-.301.946-.301.44 0 .797.127 1.071.381.274.255.41.582.41.983 0 .313-.058.562-.175.748a1.17 1.17 0 01-.462.425 1.903 1.903 0 01-.646.191 6.09 6.09 0 01-.74.044h-.455v1.584h.425c.264 0 .533.02.807.059.274.039.52.115.74.227.22.112.402.274.543.484.142.21.213.482.213.814a1.533 1.533 0 01-.52 1.18 1.772 1.772 0 01-.558.33 1.88 1.88 0 01-.667.118c-.47 0-.841-.117-1.115-.352s-.464-.567-.572-.997l-1.877.498c.117.43.288.8.513 1.108.225.308.491.56.8.755.307.196.652.34 1.033.433a5.13 5.13 0 001.218.139z" fill="#865B45" fill-rule="nonzero"></path></g></svg> | |||
| </div> | |||
| </li> | |||
| {{else }} | |||
| @@ -4,18 +4,19 @@ | |||
| <div class="ui container"> | |||
| {{template "base/alert" .}} | |||
| {{template "org/navber" .}} | |||
| <div class="ui stackable grid"> | |||
| <div class="ui stackable grid"> | |||
| <div class="ui sixteen wide computer column list"> | |||
| {{ range .Members}} | |||
| <div class="item ui grid"> | |||
| <div class="ui two wide column"> | |||
| <div class="three wide mobile two wide tablet two wide computer column"> | |||
| <img class="ui avatar" src="{{.SizedRelAvatarLink 48}}"> | |||
| </div><div class="ui three wide column"> | |||
| </div> | |||
| <div class="seven wide mobile three wide tablet three wide computer column"> | |||
| <div class="meta"><a href="{{.HomeLink}}">{{.Name}}</a></div> | |||
| <div class="meta">{{.FullName}}</div> | |||
| </div><div class="ui four wide column center"> | |||
| </div> | |||
| <div class="ui four wide column center tablet only computer only"> | |||
| <div class="meta"> | |||
| {{$.i18n.Tr "org.members.membership_visibility"}} | |||
| </div> | |||
| @@ -29,14 +30,16 @@ | |||
| {{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a class="link-action" href data-url="{{$.OrgLink}}/members/action/public?uid={{.ID}}">{{$.i18n.Tr "org.members.private_helper"}}</a>){{end}} | |||
| {{end}} | |||
| </div> | |||
| </div><div class="ui three wide column center"> | |||
| </div> | |||
| <div class="five wide mobile three wide tablet three wide computer column"> | |||
| <div class="meta"> | |||
| {{$.i18n.Tr "org.members.member_role"}} | |||
| </div> | |||
| <div class="meta"> | |||
| <strong>{{if index $.MembersIsUserOrgOwner .ID}}{{svg "octicon-shield-lock" 16}} {{$.i18n.Tr "org.members.owner"}}{{else}}{{$.i18n.Tr "org.members.member"}}{{end}}</strong> | |||
| </div> | |||
| </div><div class="ui one wide column center"> | |||
| </div> | |||
| <div class="ui one wide column center tablet only computer only"> | |||
| <div class="meta"> | |||
| 2FA | |||
| </div> | |||
| @@ -49,7 +52,8 @@ | |||
| {{end}} | |||
| </strong> | |||
| </div> | |||
| </div><div class="ui three wide column"> | |||
| </div> | |||
| <div class="ui three wide column tablet only computer only"> | |||
| <div class="text right"> | |||
| {{if eq $.SignedUser.ID .ID}} | |||
| <form method="post" action="{{$.OrgLink}}/members/action/leave"> | |||
| @@ -9,7 +9,7 @@ | |||
| <div class="ui sixteen wide computer column list"> | |||
| <div class="ui two column grid"> | |||
| <div class="ui stackable two column grid"> | |||
| {{range .Teams}} | |||
| <div class="column"> | |||
| <div class="ui top attached header"> | |||
| @@ -102,7 +102,7 @@ | |||
| <!-- 任务名 --> | |||
| <div class="three wide column padding0"> | |||
| <a class="title" href="{{$.Link}}/{{.Cloudbrain.ID}}" title="{{.Cloudbrain.ID}}" style="font-size: 14px;"> | |||
| <a class="title" href="{{$.Link}}/{{.Cloudbrain.ID}}" title="{{.DisplayJobName}}" style="font-size: 14px;"> | |||
| <span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> | |||
| </a> | |||
| </div> | |||
| @@ -177,14 +177,6 @@ | |||
| </div> | |||
| </div> | |||
| {{end}} | |||
| <!-- | |||
| <div class="" style="margin-top: 3.0em;"> | |||
| <img class="ui middle aligned tiny image" src="/img/ranking_list.jpg"> | |||
| <a class="ui blue" href="{{$.RepoLink}}/cloudbrain/123/rate?isObjectDetcionAll=true" target="_blank">目标检测算法排行榜</a> | |||
| </div> | |||
| --> | |||
| <div id="app" style="margin-top: 2rem;"> | |||
| <div class="center"> | |||
| <el-pagination | |||
| @@ -121,19 +121,8 @@ | |||
| </div> | |||
| </div> | |||
| <div class="required unite min_title inline field"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_mirror"}}</label> | |||
| <span> </span> | |||
| <input type="text" list="cloudbrain_image" placeholder="{{.i18n.Tr "cloudbrain.choose_mirror"}}" name="image" value="{{.image}}" class="required autofocus" style='width:492px;' maxlength="254"> | |||
| <i class="times circle outline icon icons" style="visibility: hidden;" onclick="clearValue()"></i> | |||
| <datalist class="ui search" id="cloudbrain_image" style='width:385px;' name="image"> | |||
| {{range .images}} | |||
| <option name="image" value="{{.Place}}">{{.PlaceView}}</option> | |||
| {{end}} | |||
| {{range .public_images}} | |||
| <option name="image" value="{{.Place}}">{{.PlaceView}}</option> | |||
| {{end}} | |||
| </datalist> | |||
| <div id="images-new-cb"> | |||
| </div> | |||
| @@ -176,7 +176,7 @@ td, th { | |||
| <h4 class="ui header" id="vertical-segment"> | |||
| <div class="ui breadcrumb"> | |||
| <a class="section" href="{{.RepoLink}}/debugjob?debugListType=all"> | |||
| {{.i18n.Tr "repo.cloudbrain"}} | |||
| {{$.i18n.Tr "repo.cloudbrain"}} | |||
| </a> | |||
| <div class="divider"> / </div> | |||
| <a class="section" href="{{$.RepoLink}}/cloudbrain/benchmark"> | |||
| @@ -281,7 +281,7 @@ td, th { | |||
| </tr> | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| {{.i18n.Tr "cloudbrain.mirror"}} | |||
| {{$.i18n.Tr "cloudbrain.mirror"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| @@ -292,7 +292,7 @@ td, th { | |||
| </tr> | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| {{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_type"}} | |||
| {{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_type"}} | |||
| </td> | |||
| @@ -314,7 +314,7 @@ td, th { | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| {{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_train"}} | |||
| {{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_train"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| @@ -325,7 +325,7 @@ td, th { | |||
| </tr> | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| {{.i18n.Tr "repo.cloudbrain.benchmark.evaluate_test"}} | |||
| {{$.i18n.Tr "repo.cloudbrain.benchmark.evaluate_test"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| @@ -413,18 +413,18 @@ td, th { | |||
| <div id="deletemodel"> | |||
| <div class="ui basic modal"> | |||
| <div class="ui icon header"> | |||
| <i class="trash icon"></i> {{.i18n.Tr "cloudbrain.delete_task"}} | |||
| <i class="trash icon"></i> {{$.i18n.Tr "cloudbrain.delete_task"}} | |||
| </div> | |||
| <div class="content"> | |||
| <p>{{.i18n.Tr "cloudbrain.task_delete_confirm"}}</p> | |||
| <p>{{$.i18n.Tr "cloudbrain.task_delete_confirm"}}</p> | |||
| </div> | |||
| <div class="actions"> | |||
| <div class="ui red basic inverted cancel button"> | |||
| <i class="remove icon"></i> {{.i18n.Tr "cloudbrain.operate_cancel"}} | |||
| <i class="remove icon"></i> {{$.i18n.Tr "cloudbrain.operate_cancel"}} | |||
| </div> | |||
| <div class="ui green basic inverted ok button"> | |||
| <i class="checkmark icon"></i> {{.i18n.Tr "cloudbrain.operate_confirm"}} | |||
| <i class="checkmark icon"></i> {{$.i18n.Tr "cloudbrain.operate_confirm"}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -0,0 +1,94 @@ | |||
| <style> | |||
| .label_color{ | |||
| color:#505559 !important; | |||
| width: 6% !important; | |||
| text-align: center; | |||
| } | |||
| </style> | |||
| {{template "base/head" .}} | |||
| <div id="mask"> | |||
| <div id="loadingPage"> | |||
| <div class="rect1"></div> | |||
| <div class="rect2"></div> | |||
| <div class="rect3"></div> | |||
| <div class="rect4"></div> | |||
| <div class="rect5"></div> | |||
| </div> | |||
| </div> | |||
| <div class="repository"> | |||
| {{template "repo/header" .}} | |||
| <div class="alert"></div> | |||
| <div class="ui container"> | |||
| <div> | |||
| <h4 class="ui top attached header"> | |||
| {{.i18n.Tr "repo.modify_image"}} | |||
| </h4> | |||
| <div class="submit-image-tmplvalue" style="display: none;" data-link="/image/{{$.Image.ID}}" data-edit-page="{{.PageFrom}}"></div> | |||
| <div class="ui attached segment" style="padding: 2em 3em;padding-bottom: 7rem;"> | |||
| <div class="ui form" id="form_image"> | |||
| <input type="hidden" name="edit" value="edit"> | |||
| {{.CsrfTokenHtml}} | |||
| <input type="hidden" name="id" value="{{.Image.ID}}"> | |||
| <div class="inline field"> | |||
| <label class="label_color" for="">{{$.i18n.Tr "dataset.dataset_available_clusters"}}</label> | |||
| <div class="ui basic label" style="border: none !important;color:#3291f8;"> | |||
| <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14"><path fill="none" d="M0 0h24v24H0z"></path><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"></path></svg> | |||
| CPU/GPU | |||
| </div> | |||
| <input type="hidden" value="{{.Type}}" name="type"> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label class="label_color" for="">{{$.i18n.Tr "repo.images.name"}}</label> | |||
| <input type="hidden" name="tag" value="{{.Image.Tag}}" > | |||
| <input disabled value="{{.Image.Tag}}" style="width: 80%;"> | |||
| <span class="tooltips" style="display: block;padding-left: 0.5rem;">{{.i18n.Tr "repo.images.name_rule"}}</span> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label class="label_color" for="">{{$.i18n.Tr "dataset.description"}}</label> | |||
| <textarea style="width: 80%;" required id="description" value="{{.Image.Description}}" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)">{{.Image.Description}}</textarea> | |||
| </div> | |||
| <div class="inline field" style="display: flex;align-items: center;"> | |||
| {{$lenTopics := len .Image.Topics}} | |||
| {{$subTopics := subOne $lenTopics}} | |||
| <label class="label_color" for="">{{$.i18n.Tr "repo.model.manage.label"}}</label> | |||
| <div class="ui multiple search selection dropdown" id="dropdown_image" style="width: 80%;"> | |||
| <input type="hidden" name="topics" value="{{range $k,$v := .Image.Topics}}{{$v}}{{if ne $k $subTopics}},{{end}}{{end}}" required> | |||
| {{range .Image.Topics}} | |||
| <a class="ui label transition visible" data-value="{{.}}" style="display: inline-block !important;">{{.}}<i class="delete icon"></i></a> | |||
| {{end}} | |||
| <div class="default text" id="default_text">{{.i18n.Tr "repo.repo_label_helpe"}}</div> | |||
| <div class="menu" id="course_label_item"></div> | |||
| </div> | |||
| </div> | |||
| <span class="tooltips" style="display: block;padding-left: 0.5rem;margin-top: 0.5rem;margin-bottom: 1rem;">{{.i18n.Tr "repo.image.label_tooltips"}}</span> | |||
| <div class="inline fields"> | |||
| <label class="label_color" for="" style="visibility: hidden;"></label> | |||
| <div class="field"> | |||
| <div class="ui radio checkbox"> | |||
| <input type="radio" name="isPrivate" {{if not .Image.IsPrivate}} checked {{end}} value="false"> | |||
| <label>{{.i18n.Tr "org.settings.visibility.public"}}</label> | |||
| </div> | |||
| </div> | |||
| <div class="field" style="flex: 0.15;"> | |||
| <div class="ui radio checkbox" > | |||
| <input type="radio" name="isPrivate" {{if .Image.IsPrivate}} checked {{end}} value="true"> | |||
| <label>{{.i18n.Tr "home.show_private"}}</label> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <span class="label_color">{{.i18n.Tr "repo.images.public_tooltips"}}</span> | |||
| </div> | |||
| </div> | |||
| <div class="inline required field" style="padding-top: 2rem;"> | |||
| <label class="label_color" for="" style="visibility: hidden;"></label> | |||
| <button class="ui create_image green button" type="button"> | |||
| {{.i18n.Tr "explore.save"}} | |||
| </button> | |||
| <a class="ui button" id="cancel_submit_image">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| @@ -0,0 +1,106 @@ | |||
| <style> | |||
| .label_color{ | |||
| color:#505559 !important; | |||
| width: 6% !important; | |||
| text-align: center; | |||
| } | |||
| </style> | |||
| {{template "base/head" .}} | |||
| <div id="mask"> | |||
| <div id="loadingPage"> | |||
| <div class="rect1"></div> | |||
| <div class="rect2"></div> | |||
| <div class="rect3"></div> | |||
| <div class="rect4"></div> | |||
| <div class="rect5"></div> | |||
| </div> | |||
| </div> | |||
| <div class="repository"> | |||
| {{template "repo/header" .}} | |||
| <div class="alert"></div> | |||
| <div class="ui container"> | |||
| <div> | |||
| <div class="ui negative message" style="display: none;"> | |||
| </div> | |||
| <div class="ui info message" style="display: none;"> | |||
| </div> | |||
| <div class="ui positive message" style="display: none;"> | |||
| </div> | |||
| <h4 class="ui top attached header"> | |||
| {{.i18n.Tr "repo.submit_image"}} | |||
| </h4> | |||
| <div class="submit-image-tmplvalue" style="display: none;" data-link="{{$.Link}}"></div> | |||
| <div class="ui attached segment" style="padding: 2em 3em;padding-bottom: 7rem;"> | |||
| <div class="ui form" id="form_image"> | |||
| {{.CsrfTokenHtml}} | |||
| <div class="inline field"> | |||
| <label class="label_color" for="">{{$.i18n.Tr "dataset.dataset_available_clusters"}}</label> | |||
| <div class="ui basic label" style="border: none !important;color:#3291f8;"> | |||
| <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14"><path fill="none" d="M0 0h24v24H0z"></path><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"></path></svg> | |||
| CPU/GPU | |||
| </div> | |||
| <input type="hidden" value="{{.Type}}" name="type"> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label class="label_color" for="">{{$.i18n.Tr "repo.images.name"}}</label> | |||
| <input type="text" name="tag" required placeholder="{{$.i18n.Tr "repo.images.name_placerholder"}}" style="width: 80%;" maxlength="100"> | |||
| <span class="tooltips" style="display: block;padding-left: 0.5rem;">{{.i18n.Tr "repo.images.name_rule"}}</span> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label class="label_color" for="">{{$.i18n.Tr "dataset.description"}}</label> | |||
| <textarea style="width: 80%;" required id="description" name="description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 255)"></textarea> | |||
| </div> | |||
| <div class="inline field" style="display: flex;align-items: center;"> | |||
| <label class="label_color" for="">{{$.i18n.Tr "repo.model.manage.label"}}</label> | |||
| <div class="ui multiple search selection dropdown" id="dropdown_image" style="width: 80%;"> | |||
| <input type="hidden" name="topics" value="" required> | |||
| <div class="default text" id="default_text">{{.i18n.Tr "repo.repo_label_helpe"}}</div> | |||
| <div class="menu" id="course_label_item"></div> | |||
| </div> | |||
| </div> | |||
| <span class="tooltips" style="display: block;padding-left: 0.5rem;margin-top: 0.5rem;margin-bottom: 1rem;">{{.i18n.Tr "repo.image.label_tooltips"}}</span> | |||
| <div class="inline fields"> | |||
| <label class="label_color" for="" style="visibility: hidden;"></label> | |||
| <div class="field"> | |||
| <div class="ui radio checkbox"> | |||
| <input type="radio" name="isPrivate" checked="checked" value="false"> | |||
| <label>{{.i18n.Tr "org.settings.visibility.public"}}</label> | |||
| </div> | |||
| </div> | |||
| <div class="field" style="flex: 0.15;"> | |||
| <div class="ui radio checkbox" > | |||
| <input type="radio" name="isPrivate" value="true"> | |||
| <label>{{.i18n.Tr "home.show_private"}}</label> | |||
| </div> | |||
| </div> | |||
| <div class="field"> | |||
| <span class="label_color">{{.i18n.Tr "repo.images.public_tooltips"}}</span> | |||
| </div> | |||
| </div> | |||
| <div class="inline required field" style="padding-top: 2rem;"> | |||
| <label class="label_color" for="" style="visibility: hidden;"></label> | |||
| <button class="ui create_image green button" type="button"> | |||
| {{.i18n.Tr "repo.cloudbrain.commit_image"}} | |||
| </button> | |||
| <a class="ui button" id="cancel_submit_image">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <!-- 确认模态框 --> | |||
| <div> | |||
| <div class="ui modal image_confirm_submit"> | |||
| <div class="header">{{.i18n.Tr "repo.submit_image"}}</div> | |||
| <div class="content text red center"> | |||
| <p><i class="exclamation icon"></i>{{.i18n.Tr "repo.image_overwrite"}}</p> | |||
| </div> | |||
| <div class="actions"> | |||
| <button class="ui deny small button">{{.i18n.Tr "cloudbrain.operate_cancel"}}</button> | |||
| <button class="ui green small approve button">{{.i18n.Tr "cloudbrain.operate_confirm"}}</button> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| @@ -179,7 +179,26 @@ | |||
| </div> | |||
| </div> | |||
| <input id="store_category" type="hidden" name="get_benchmark_category"> | |||
| <div class="inline required field"> | |||
| <label>{{.i18n.Tr "repo.modelarts.code_version"}}</label> | |||
| <select class="ui dropdown width80 left2" id="code_version" name="branch_name"> | |||
| {{if .branch_name}} | |||
| <option name="branch_name" value="{{.branch_name}}">{{.branch_name}}</option> | |||
| {{range $k, $v :=.Branches}} | |||
| {{ if ne $v $.branch_name }} | |||
| <option name="branch_name" value="{{$v}}">{{$v}}</option> | |||
| {{end}} | |||
| {{end}} | |||
| {{else}} | |||
| <option name="branch_name" value="{{.branchName}}">{{.branchName}}</option> | |||
| {{range $k, $v :=.Branches}} | |||
| {{ if ne $v $.branchName }} | |||
| <option name="branch_name" value="{{$v}}">{{$v}}</option> | |||
| {{end}} | |||
| {{end}} | |||
| {{end}} | |||
| </select> | |||
| </div> | |||
| <div class="inline required field"> | |||
| <label>{{.i18n.Tr "cloudbrain.gpu_type"}}</label> | |||
| <select id="cloudbrain_gpu_type" class="ui search dropdown" placeholder="选择GPU类型" style='width:385px' name="gpu_type"> | |||
| @@ -189,7 +208,7 @@ | |||
| </select> | |||
| </div> | |||
| <div class="inline required field" style="position: relative;"> | |||
| <!-- <div class="inline required field" style="position: relative;"> | |||
| <label>{{.i18n.Tr "cloudbrain.mirror"}}</label> | |||
| <input type="text" list="cloudbrain_image" placeholder="{{.i18n.Tr "cloudbrain.choose_mirror"}}" name="image" required autofocus maxlength="255"> | |||
| <i class="times circle outline icon icons" style="visibility: hidden;" onclick="clearValue()"></i> | |||
| @@ -201,6 +220,9 @@ | |||
| <option name="image" value="{{.Place}}">{{.PlaceView}}</option> | |||
| {{end}} | |||
| </datalist> | |||
| </div> --> | |||
| <div id="images-new-cb"> | |||
| </div> | |||
| {{template "custom/select_dataset" .}} | |||
| @@ -260,10 +282,10 @@ | |||
| <script> | |||
| let form = document.getElementById('form_id'); | |||
| let inputs = document.querySelectorAll('input[list]'); | |||
| inputs[0].addEventListener('change', function() { | |||
| $(".icon.icons").css("visibility","visible") | |||
| }); | |||
| // let inputs = document.querySelectorAll('input[list]'); | |||
| // inputs[0].addEventListener('change', function() { | |||
| // $(".icon.icons").css("visibility","visible") | |||
| // }); | |||
| $('#messageInfo').css('display','none') | |||
| function clearValue(){ | |||
| @@ -187,7 +187,7 @@ td, th { | |||
| {{.i18n.Tr "repo.cloudbrain"}} | |||
| </a> | |||
| <div class="divider"> / </div> | |||
| <a class="section backTodeBug" href="{{.RepoLink}}/debugjob?debugListType={{if eq $.debugListType "NPU"}}NPU{{else if eq $.debugListType "CPU/GPU"}}CPU/GPU{{else}}all{{end}}"> | |||
| <a class="section backTodeBug" href="{{.RepoLink}}/debugjob?debugListType=all"> | |||
| {{$.i18n.Tr "repo.modelarts.notebook"}} | |||
| </a> | |||
| <div class="divider"> / </div> | |||
| @@ -300,38 +300,32 @@ td, th { | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| <tr class="ti-no-ng-animate"> | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| {{$.i18n.Tr "repo.cloudbrain.time.starttime"}} | |||
| {{$.i18n.Tr "repo.modelarts.createtime"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-startTime"> | |||
| {{if not (eq .StartTime 0)}} | |||
| {{TimeSinceUnix1 .StartTime}} | |||
| {{else}} | |||
| -- | |||
| {{end}} | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-createtime"> | |||
| {{TimeSinceUnix1 .CreatedUnix}} | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| {{$.i18n.Tr "repo.cloudbrain.time.endtime"}} | |||
| {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-EndTime"> | |||
| {{if not (eq .EndTime 0)}} | |||
| {{TimeSinceUnix1 .EndTime}} | |||
| {{else}} | |||
| -- | |||
| {{end}} | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-duration"> | |||
| {{$.duration}} | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| </tbody> | |||
| </table> | |||
| </div> | |||
| @@ -405,18 +399,38 @@ td, th { | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| {{$.i18n.Tr "repo.modelarts.train_job.dura_time"}} | |||
| {{$.i18n.Tr "repo.cloudbrain.time.starttime"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-duration"> | |||
| {{$.duration}} | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-startTime"> | |||
| {{if not (eq .StartTime 0)}} | |||
| {{TimeSinceUnix1 .StartTime}} | |||
| {{else}} | |||
| -- | |||
| {{end}} | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| {{$.i18n.Tr "repo.cloudbrain.time.endtime"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-EndTime"> | |||
| {{if not (eq .EndTime 0)}} | |||
| {{TimeSinceUnix1 .EndTime}} | |||
| {{else}} | |||
| -- | |||
| {{end}} | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| </tbody> | |||
| </table> | |||
| @@ -152,7 +152,7 @@ | |||
| </select> | |||
| </div> | |||
| <div class="required unite min_title inline field" style="position: relative;"> | |||
| <!-- <div class="required unite min_title inline field" style="position: relative;"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "cloudbrain.mirror"}} </label> | |||
| <input class="width81" type="text" list="cloudbrain_image" placeholder="{{.i18n.Tr "cloudbrain.choose_mirror"}}" name="image" required autofocus maxlength="255"> | |||
| <i class="times circle outline icon icons" style="visibility: hidden;" onclick="clearValue()"></i> | |||
| @@ -164,14 +164,18 @@ | |||
| <option name="image" value="{{.Place}}">{{.PlaceView}}</option> | |||
| {{end}} | |||
| </datalist> | |||
| </div> --> | |||
| <div id="images-new-cb"> | |||
| </div> | |||
| <div class="inline unite min_title field required"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label> | |||
| {{if .bootFile}} | |||
| <input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" > | |||
| <input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" > | |||
| {{else}} | |||
| <input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" > | |||
| <input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" > | |||
| {{end}} | |||
| <span> | |||
| <i class="question circle icon link" data-content={{.i18n.Tr "repo.modelarts.train_job.boot_file_helper"}} data-position="right center" data-variation="mini"></i> | |||
| @@ -286,7 +286,7 @@ td, th { | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w"> | |||
| {{$.resource_spec}} | |||
| {{$.i18n.Tr "cloudbrain.gpu_num"}}:{{$.GpuNum}},{{$.i18n.Tr "cloudbrain.cpu_num"}}:{{$.CpuNum}},{{$.i18n.Tr "cloudbrain.memory"}}(MB):{{$.MemMiB}},{{$.i18n.Tr "cloudbrain.shared_memory"}}(MB):{{$.ShareMemMiB}} | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| @@ -299,7 +299,7 @@ td, th { | |||
| <tbody class="ti-text-form"> | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| 镜像 | |||
| {{$.i18n.Tr "cloudbrain.mirror"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| @@ -46,7 +46,7 @@ | |||
| <span style="flex: 1;"></span> | |||
| </div> | |||
| <div class="inline field" style="display: flex;align-items:center;"> | |||
| <div class="inline field" style="display: flex;align-items:center;"> | |||
| <label style="margin: .035714em 1em 0 0;">{{.i18n.Tr "repo.model.manage.label"}}</label> | |||
| <div class="ui multiple search selection dropdown" id="dropdown_container"> | |||
| <input type="hidden" name="topics" value=""> | |||
| @@ -281,7 +281,7 @@ | |||
| </span> | |||
| <el-dropdown-menu slot="dropdown"> | |||
| <el-dropdown-item class="clipboard" data-clipboard-text="{{.DownloadURL}}" data-clipboard-action="copy">{{$.i18n.Tr "dataset.copy_url"}}</el-dropdown-item> | |||
| <el-dropdown-item class="clipboard" data-clipboard-text="{{.Md5}}" data-clipboard-action="copy">{{$.i18n.Tr "dataset.copy_md5"}}</el-dropdown-item> | |||
| <!-- <el-dropdown-item class="clipboard" data-clipboard-text="{{.Md5}}" data-clipboard-action="copy">{{$.i18n.Tr "dataset.copy_md5"}}</el-dropdown-item>--> | |||
| {{if and ($.CanWrite) (eq .DecompressState 1) }} | |||
| <el-dropdown-item @click.native="gotoAnnotate('{{$.RepoLink}}','{{.UUID}}',{{.Type}})">{{$.i18n.Tr "dataset.annotation"}}</el-dropdown-item> | |||
| {{end}} | |||
| @@ -379,10 +379,8 @@ | |||
| <i class="dropdown icon"></i> | |||
| <div class="menu" style="right: auto;"> | |||
| <div class="item" style="padding: 0 !important;"> | |||
| <!-- 接收结果 --> | |||
| <iframe src="" frameborder="0" name="iframeContent" style="display: none;"></iframe> | |||
| {{if .CanDebug}} | |||
| <a id="model-image-{{.Cloudbrain.ID}}" class='imageBtn ui basic {{if ne .Status "RUNNING"}}disabled {{else}}blue {{end}}button'>{{$.i18n.Tr "repo.submit_image"}}</a> | |||
| <a id="model-image-{{.Cloudbrain.ID}}" class='imageBtn ui basic {{if ne .Status "RUNNING"}}disabled {{else}}blue {{end}}button' href="{{$.RepoLink}}/cloudbrain/{{.Cloudbrain.ID}}/commit_image">{{$.i18n.Tr "repo.submit_image"}}</a> | |||
| {{else}} | |||
| <a class="imageBtn ui basic disabled button">{{$.i18n.Tr "repo.submit_image"}}</a> | |||
| {{end}} | |||
| @@ -407,40 +405,7 @@ | |||
| </div> | |||
| </div> | |||
| <!-- 镜像列表弹窗 --> | |||
| <div id="imageModal" class="modal" style="display: none;"> | |||
| <div class="modal-content"> | |||
| <!-- 表格 --> | |||
| <div class="ui form"> | |||
| <form id="commitImageForm" action="{{$.RepoLink}}/cloudbrain/{{.Cloudbrain.ID}}/commit_image" method="post" target="iframeContent"> | |||
| {{$.CsrfTokenHtml}} | |||
| <div class="row"> | |||
| <p style="display: inline;">提交任务镜像</p> | |||
| <span class="close">×</span> | |||
| </div> | |||
| <div class="ui divider"></div> | |||
| <div class="inline required field dis"> | |||
| <label> {{$.i18n.Tr "repo.cloudbrain.mirror_tag"}}:</label> | |||
| <input name="tag" id="image_tag" tabindex="3" autofocus required maxlength="255" style="width:75%"> | |||
| </div> | |||
| <div class="inline field"> | |||
| <label class="label_after">{{$.i18n.Tr "repo.cloudbrain.mirror_description"}}:</label> | |||
| <textarea name="description" maxlength="255" rows="8" style="width:75%;margin-left: 0.2em;"></textarea> | |||
| </div> | |||
| <div class="ui divider"></div> | |||
| <div class="inline field"> | |||
| <label></label> | |||
| <button class="ui green button" onclick="showmask()"> | |||
| {{$.i18n.Tr "repo.cloudbrain.commit_image"}} | |||
| </button> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{end}} | |||
| @@ -529,54 +494,5 @@ | |||
| .transition('fade') | |||
| }) | |||
| }) | |||
| // 获取弹窗 | |||
| var modal = document.getElementById('imageModal'); | |||
| // 打开弹窗的按钮对象 | |||
| var btns = document.getElementsByClassName("imageBtn"); | |||
| // 获取 <span> 元素,用于关闭弹窗 | |||
| var spans = document.getElementsByClassName('close'); | |||
| // 点击按钮打开弹窗 | |||
| for (i = 0; i < btns.length; i++) { | |||
| btns[i].onclick = function() { | |||
| modal.style.display = "block"; | |||
| } | |||
| } | |||
| // 点击 <span> (x), 关闭弹窗 | |||
| for (i = 0; i < spans.length; i++) { | |||
| spans[i].onclick = function() { | |||
| modal.style.display = "none"; | |||
| } | |||
| } | |||
| // 在用户点击其他地方时,关闭弹窗 | |||
| window.onclick = function(event) { | |||
| if (event.target == modal) { | |||
| modal.style.display = "none"; | |||
| } | |||
| } | |||
| // 显示弹窗,弹出相应的信息 | |||
| function showmask() { | |||
| var image_tag = !$('#image_tag').val() | |||
| if(image_tag){ | |||
| return | |||
| } | |||
| $('#imageModal').css('display', 'none') | |||
| $('#mask').css('display', 'block') | |||
| $("iframe[name=iframeContent]").on("load", function() { | |||
| var responseText = $("iframe")[0].contentDocument.body.getElementsByTagName("pre")[0].innerHTML; | |||
| var json1 = JSON.parse(responseText) | |||
| $('#mask').css('display', 'none') | |||
| if (json1.result_code === "0") { | |||
| $('.alert').html('操作成功!').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut(); | |||
| } else { | |||
| $('.alert').html(json1.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(5000).fadeOut(); | |||
| } | |||
| }) | |||
| } | |||
| </script> | |||
| @@ -112,8 +112,8 @@ | |||
| </div> | |||
| <!-- 模型版本 --> | |||
| <!-- href="{{$.RepoLink}}/modelmanage/show_model_info?name={{.ModelName}}" --> | |||
| <div class="three wide column text center padding0"> | |||
| <a id="{{.JobName}}" class="goto_modelmanage" href="javascript:void(0);" data-variation="inverted" data-position="top center" data-content="{{$.i18n.Tr "repo.modelarts.infer_job.tooltip"}}" data-jobname={{.JobName}} data-modelname={{.ModelName}} data-version={{.ModelVersion}} data-repopath="{{$.RepoLink}}">{{.ModelName}} </a> <span style="font-size: 12px;">{{.ModelVersion}}</span> | |||
| <div class="three wide column text center padding0" style="display: flex;"> | |||
| <a id="{{.JobName}}" class="goto_modelmanage nowrap" title="{{.ModelName}}" href="javascript:void(0);" data-variation="inverted" data-position="top center" data-content="{{$.i18n.Tr "repo.modelarts.infer_job.tooltip"}}" data-jobname={{.JobName}} data-modelname={{.ModelName}} data-version={{.ModelVersion}} data-repopath="{{$.RepoLink}}">{{.ModelName}} </a> <span style="font-size: 12px;">{{.ModelVersion}}</span> | |||
| </div> | |||
| <!-- 任务状态 --> | |||
| <div class="two wide column text center padding0" > | |||
| @@ -26,7 +26,9 @@ | |||
| width: 35.5% !important; | |||
| } | |||
| .width48{ | |||
| width: 48.5% !important; | |||
| } | |||
| .nowrapx { | |||
| white-space: nowrap !important; | |||
| } | |||
| @@ -150,7 +152,7 @@ | |||
| <!-- 代码分支 --> | |||
| <div class="required unite min_title inline field"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.code_version"}}</label> | |||
| <select class="ui dropdown width35" id="code_version" name="branch_name"> | |||
| <select class="ui dropdown width48" id="code_version" name="branch_name"> | |||
| {{if .branch_name}} | |||
| <option name="branch_name" value="{{.branch_name}}">{{.branch_name}}</option> | |||
| {{range $k, $v :=.Branches}} | |||
| @@ -172,11 +174,11 @@ | |||
| {{template "custom/select_dataset_train" .}} | |||
| <span class="tooltips" style="margin-left: 11.5rem;margin-bottom: 2rem;">{{.i18n.Tr "cloudbrain.dataset_path_rule"}}</span> | |||
| <div class="inline unite min_title field required"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label> | |||
| {{if .bootFile}} | |||
| <input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" > | |||
| <input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" > | |||
| {{else}} | |||
| <input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" > | |||
| <input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" > | |||
| {{end}} | |||
| <span > | |||
| <i class="question circle icon" data-content={{.i18n.Tr "repo.modelarts.infer_job.boot_file_helper"}} data-position="top center" data-variation="inverted mini"></i> | |||
| @@ -250,6 +252,7 @@ | |||
| {{template "base/footer" .}} | |||
| <script> | |||
| console.log({{.newInference}}) | |||
| const RepoLink = {{.RepoLink}} | |||
| const url_href = window.location.pathname.split('create')[0] | |||
| let nameMap,nameList | |||
| @@ -193,7 +193,7 @@ td, th { | |||
| {{.i18n.Tr "repo.cloudbrain"}} | |||
| </a> | |||
| <div class="divider"> / </div> | |||
| <a class="section backTodeBug" href="{{.RepoLink}}/debugjob?debugListType={{if eq $.debugListType "NPU"}}NPU{{else if eq $.debugListType "CPU/GPU"}}CPU/GPU{{else}}all{{end}}"> | |||
| <a class="section backTodeBug" href="{{.RepoLink}}/debugjob?debugListType=all"> | |||
| {{$.i18n.Tr "repo.modelarts.notebook"}} | |||
| </a> | |||
| <div class="divider"> / </div> | |||
| @@ -207,7 +207,7 @@ td, th { | |||
| <div class="active title padding0"> | |||
| <div class="according-panel-heading"> | |||
| <div class="accordion-panel-title"> | |||
| <i class="dropdown icon"></i> | |||
| <!-- <i class="dropdown icon"></i> --> | |||
| <span class="accordion-panel-title-content"> | |||
| <span> | |||
| <div class="ac-display-inblock title_text acc-margin-bottom"> | |||
| @@ -285,7 +285,17 @@ td, th { | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| {{$.i18n.Tr "repo.modelarts.createtime"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| <div class="text-span text-span-w" id="{{.VersionName}}-createtime"> | |||
| {{TimeSinceUnix1 .CreatedUnix}} | |||
| </div> | |||
| </td> | |||
| </tr> | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| @@ -369,7 +379,7 @@ td, th { | |||
| </tr> | |||
| <tr class="ti-no-ng-animate"> | |||
| <td class="ti-no-ng-animate ti-text-form-label text-width80"> | |||
| {{$.i18n.Tr "repo.modelarts.train_job.start_time"}} | |||
| {{$.i18n.Tr "repo.cloudbrain.time.starttime"}} | |||
| </td> | |||
| <td class="ti-text-form-content"> | |||
| @@ -158,9 +158,9 @@ | |||
| <div class="inline unite min_title field required"> | |||
| <label style="font-weight: normal;">{{.i18n.Tr "repo.modelarts.train_job.start_file"}}</label> | |||
| {{if .bootFile}} | |||
| <input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" > | |||
| <input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="{{.bootFile}}" tabindex="3" autofocus required maxlength="255" > | |||
| {{else}} | |||
| <input style="width: 35.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" > | |||
| <input style="width: 48.5%;" name="boot_file" id="trainjob_boot_file" value="" tabindex="3" autofocus required maxlength="255" > | |||
| {{end}} | |||
| <span> | |||
| <i class="question circle icon link" data-content={{.i18n.Tr "repo.modelarts.train_job.boot_file_helper"}} data-position="right center" data-variation="mini"></i> | |||
| @@ -420,7 +420,13 @@ td, th { | |||
| </div> | |||
| </div> | |||
| <div class="ui tab" data-tab="second{{$k}}"> | |||
| <div> | |||
| <div style="position: relative;"> | |||
| <span> | |||
| <a title="滚动到顶部" style="position: absolute; right: -32px;cursor: pointer;" id="log_top"><i class="icon-to-top"></i></a> | |||
| </span> | |||
| <span> | |||
| <a title="滚动到底部" style="position: absolute; bottom: 10px;right: -32px;cursor: pointer;" id="log_bottom"><i class="icon-to-bottom"></i></a> | |||
| </span> | |||
| <div class="ui message message{{.VersionName}}" style="display: none;"> | |||
| <div id="header"></div> | |||
| </div> | |||
| @@ -879,4 +885,57 @@ td, th { | |||
| }); | |||
| } | |||
| } | |||
| function scrollAnimation(dom, currentY, targetY, currentX) { | |||
| let needScrollTop = targetY - currentY; | |||
| let _currentY = currentY; | |||
| setTimeout(() => { | |||
| // 一次调用滑动帧数,每次调用会不一样 | |||
| //取总距离的十分之一 | |||
| const dist = Math.ceil(needScrollTop / 10); | |||
| _currentY += dist; | |||
| //移动一个十分之一 | |||
| console.log(_currentY, targetY) | |||
| dom.scrollTo(currentX || 0, _currentY); | |||
| // 如果移动幅度小于十个像素,直接移动,否则递归调用,实现动画效果 | |||
| if (needScrollTop > 10 || needScrollTop < -10) { | |||
| scrollAnimation(dom, _currentY, targetY) | |||
| } else { | |||
| dom.scrollTo(0, targetY) | |||
| } | |||
| }, 1) | |||
| } | |||
| $('#log_top').click(function(){ | |||
| let logContentDom = document.querySelector('.log') | |||
| if(!logContentDom) | |||
| return | |||
| scrollAnimation(logContentDom, logContentDom.scrollTop, 0); | |||
| }) | |||
| $('#log_bottom').click(function(){ | |||
| let logContentDom = document.querySelector('.log') | |||
| if(!logContentDom) | |||
| return | |||
| //如果内容撑大到可以滚动,则触发滚动 | |||
| // if(!['10','11','12'].includes(context.taskInfo.statusCode)){ | |||
| // context.getLogContent(0, context.lines, 'goDown') | |||
| // } | |||
| if(logContentDom.scrollHeight > logContentDom.clientHeight){ | |||
| console.log("1111") | |||
| scrollAnimation(logContentDom, logContentDom.scrollTop, logContentDom.scrollHeight - logContentDom.clientHeight); | |||
| } | |||
| else{ | |||
| logScroll(version_name) | |||
| logContentDom.scrollTo(0,logContentDom.scrollTop-1); | |||
| } | |||
| // if(this.checkCurrentCanScrollBottom()){ | |||
| // // this.goDown(); | |||
| // this.scrollAnimation(logContentDom, logContentDom.scrollTop, logContentDom.scrollHeight - logContentDom.clientHeight); | |||
| // }else{ | |||
| // //如果内容不足,则往后追加内容 | |||
| // this.goDown(); | |||
| // logContentDom.scrollTo(0,logContentDom.scrollTop-1); | |||
| // } | |||
| }) | |||
| </script> | |||
| @@ -0,0 +1,328 @@ | |||
| {{template "base/head" .}} | |||
| <!-- 弹窗 --> | |||
| <div id="mask"> | |||
| <div id="loadingPage"> | |||
| <div class="rect1"></div> | |||
| <div class="rect2"></div> | |||
| <div class="rect3"></div> | |||
| <div class="rect4"></div> | |||
| <div class="rect5"></div> | |||
| </div> | |||
| </div> | |||
| <!-- 提示框 --> | |||
| <div class="alert"></div> | |||
| <div class="explore users"> | |||
| <div class="cloudbrain_debug" style="display: none;" data-debug="{{$.i18n.Tr "repo.debug"}}" data-debug-again="{{$.i18n.Tr "repo.debug_again"}}"></div> | |||
| {{template "admin/cloudbrain/search_dashboard" .}} | |||
| <div class="ui container" style="width: 80%;"> | |||
| {{template "base/alert" .}} | |||
| <div class="ui grid" > | |||
| <div class="row" > | |||
| <div class="ui sixteen wide column"> | |||
| <!-- 任务展示 --> | |||
| <div class="dataset list"> | |||
| <!-- 表头 --> | |||
| <div class="ui grid stackable" style="background: #f0f0f0;;"> | |||
| <div class="row"> | |||
| <div class="three wide column nowrap" style="width:15%"> | |||
| <span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | |||
| </div> | |||
| <div class="two wide column text center nowrap" style="width: 11% !important;"> | |||
| <span>{{$.i18n.Tr "repo.modelarts.status"}}</span> | |||
| </div> | |||
| <div class="one wide column text center nowrap" style="width:10%"> | |||
| <span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task_type"}}</span> | |||
| </div> | |||
| <div class="two wide column text center nowrap" style="width: 11% !important;"> | |||
| <span>{{$.i18n.Tr "repo.modelarts.createtime"}}</span> | |||
| </div> | |||
| <div class="one wide column text center nowrap" style="width:8.5% !important;"> | |||
| <span>{{$.i18n.Tr "repo.cloudbrain_status_runtime"}}</span> | |||
| </div> | |||
| <div class="one wide column text center nowrap" style="width:8.5% !important;"> | |||
| <span>{{$.i18n.Tr "repo.modelarts.computing_resources"}}</span> | |||
| </div> | |||
| <div class="two wide column text center nowrap" style="width: 14.5%!important;"> | |||
| <span>{{$.i18n.Tr "repository"}}</span> | |||
| </div> | |||
| <div class="three wide column text center nowrap" style="width: 21.5%!important;"> | |||
| <span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{range .Tasks}} | |||
| {{if .Repo}} | |||
| <div class="ui grid stackable item"> | |||
| <div class="row"> | |||
| <!-- 任务名 --> | |||
| {{$JobID := '0'}} | |||
| {{if eq .JobType "DEBUG" "SNN4IMAGENET" "BRAINSCORE" "BENCHMARK"}} | |||
| {{$JobID = .Cloudbrain.ID}} | |||
| {{else}} | |||
| {{$JobID = .JobID}} | |||
| {{end}} | |||
| <!-- {{$JobID}} --> | |||
| <div class="three wide column nowrap" style="width:15%"> | |||
| {{if or (eq .JobType "DEBUG") (eq .JobType "SNN4IMAGENET") (eq .JobType "BRAINSCORE")}} | |||
| <a class="title" href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain/{{$JobID}}{{else}}/modelarts/notebook/{{$JobID}}{{end}}" title="{{.DisplayJobName}}" style="font-size: 14px;"> | |||
| <span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> | |||
| </a> | |||
| {{else if eq .JobType "INFERENCE"}} | |||
| <a class="title" href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/modelarts/inference-job/{{$JobID}}" title="{{.DisplayJobName}}" style="font-size: 14px;"> | |||
| <span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> | |||
| </a> | |||
| {{else if eq .JobType "TRAIN"}} | |||
| <a class="title" href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/{{if eq .ComputeResource "NPU"}}modelarts{{else}}cloudbrain{{end}}/train-job/{{$JobID}}" title="{{.DisplayJobName}}" style="font-size: 14px;"> | |||
| <span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> | |||
| </a> | |||
| {{else if eq .JobType "BENCHMARK"}} | |||
| <a class="title" href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/cloudbrain/benchmark/{{$JobID}}" title="{{.DisplayJobName}}" style="font-size: 14px;"> | |||
| <span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> | |||
| </a> | |||
| {{end}} | |||
| </div> | |||
| <!-- 任务状态 --> | |||
| <div class="two wide column text center nowrap" style="padding-left: 2.2rem !important; width: 11% !important;"> | |||
| <span class="job-status" id="{{$JobID}}" data-repopath='{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "DEBUG"}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}{{else if eq .JobType "INFERENCE"}}/modelarts/inference-job{{else if eq .JobType "TRAIN"}}{{if eq .ComputeResource "NPU"}}/modelarts/train-job{{else}}/cloudbrain/train-job{{end}}{{else if eq .JobType "BENCHMARK"}}/cloudbrain{{end}}' data-jobid="{{$JobID}}" data-version="{{.VersionName}}"> | |||
| <span><i id="{{$JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{$JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||
| </span> | |||
| </div> | |||
| <!-- 任务类型 --> | |||
| {{$JobType := $.i18n.Tr (printf "cloudbrain.%s" .JobType)}} | |||
| <div class="one wide column text center nowrap" style="width:10%"> | |||
| <span style="font-size: 12px;" title="{{$JobType}}">{{$JobType}}</span> | |||
| </div> | |||
| <!-- 任务创建时间 --> | |||
| <div class="two wide column text center nowrap" style="width: 11% !important;"> | |||
| <span style="font-size: 12px;" class="">{{TimeSinceUnix1 .Cloudbrain.CreatedUnix}}</span> | |||
| </div> | |||
| <!-- 任务运行时间 --> | |||
| <div class="one wide column text center nowrap" style="width:8.5% !important;"> | |||
| <span style="font-size: 12px;" id="duration-{{$JobID}}">{{if .TrainJobDuration}}{{.TrainJobDuration}}{{else}}--{{end}}</span> | |||
| </div> | |||
| <!-- 计算资源 --> | |||
| <div class="one wide column text center nowrap" style="width:8.5% !important;"> | |||
| <span style="font-size: 12px;">{{if .ComputeResource}}{{.ComputeResource}}{{else}}--{{end}}</span> | |||
| </div> | |||
| <!-- 项目 --> | |||
| <div class="two wide column text center nowrap" style="width: 14.5%!important;"> | |||
| <a href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}" title="{{.Repo.OwnerName}}/{{.Repo.Alias}}">{{.Repo.OwnerName}}/{{.Repo.Alias}}</a> | |||
| </div> | |||
| <div class="three wide column text center nowrap" style="width: 21.5%!important;"> | |||
| {{if eq .JobType "DEBUG" "SNN4IMAGENET" "BRAINSCORE"}} | |||
| <div class="ui compact buttons"> | |||
| <form id="debugAgainForm-{{$JobID}}"> | |||
| {{$.CsrfTokenHtml}} | |||
| {{if eq .Status "RUNNING" "WAITING" "CREATING" "STARTING"}} | |||
| <a style="margin: 0 1rem;" id="ai-debug-{{$JobID}}" class='ui basic ai_debug {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING"}}disabled {{else}}blue {{end}}button' data-jobid="{{$JobID}}" data-repopath='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}/{{$JobID}}/'> | |||
| {{$.i18n.Tr "repo.debug"}} | |||
| </a> | |||
| {{else}} | |||
| <a id="ai-debug-{{$JobID}}" class='ui basic ai_debug {{if eq .Status "CREATING" "STOPPING" "WAITING" "STARTING"}} disabled {{else}}blue {{end}}button' data-jobid="{{$JobID}}" data-repopath='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else}}/modelarts/notebook{{end}}/{{$JobID}}/'> | |||
| {{$.i18n.Tr "repo.debug_again"}} | |||
| </a> | |||
| {{end}} | |||
| </form> | |||
| </div> | |||
| {{end}} | |||
| <!-- 停止任务 --> | |||
| <div class="ui compact buttons"> | |||
| {{if eq .JobType "DEBUG" "BENCHMARK" "SNN4IMAGENET" "BRAINSCORE"}} | |||
| <form id="stopForm-{{$JobID}}" style="margin-left:-1px;"> | |||
| {{$.CsrfTokenHtml}} | |||
| <a style="padding: 0.5rem 1rem;" id="ai-stop-{{$JobID}}" class='ui basic ai_stop {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED" "SUCCEEDED" "STOPPED" "STOPPING" "CREATE_FAILED"}}disabled {{else}} blue {{end}}button' data-repopath='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .ComputeResource "CPU/GPU"}}/cloudbrain{{else if eq .JobType "BENCHMARK" }}/cloudbrain/benchmark{{else if eq .ComputeResource "NPU" }}/modelarts/notebook{{end}}/{{$JobID}}/stop' data-jobid="{{$JobID}}"> | |||
| {{$.i18n.Tr "repo.stop"}} | |||
| </a> | |||
| </form> | |||
| {{else}} | |||
| <a style="padding: 0.5rem 1rem;" id="ai-stop-{{$JobID}}" class='ui basic ai_stop_version {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED" "STOPPED" "SUCCEEDED" "CREATE_FAILED"}}disabled {{else}} blue {{end}}button' data-repopath='{{.Repo.OwnerName}}/{{.Repo.Name}}/{{if eq .JobType "INFERENCE"}}modelarts/inference-job{{else if eq .JobType "TRAIN"}}{{if eq .ComputeResource "NPU"}}modelarts/train-job{{else}}cloudbrain/train-job{{end}}{{end}}' data-jobid="{{$JobID}}" data-version="{{.VersionName}}" > | |||
| {{$.i18n.Tr "repo.stop"}} | |||
| </a> | |||
| {{end}} | |||
| </div> | |||
| <!-- 删除任务 --> | |||
| <form class="ui compact buttons" id="delForm-{{$JobID}}" action='{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{if eq .JobType "BENCHMARK"}}/cloudbrain/benchmark{{else if eq .JobType "DEBUG"}}{{if eq .ComputeResource "NPU"}}/modelarts/notebook{{else}}/cloudbrain{{end}}{{else if eq .JobType "TRAIN"}}{{if eq .ComputeResource "NPU"}}/modelarts/train-job{{else}}/cloudbrain/train-job{{end}}{{end}}/{{$JobID}}/del?ishomepage=true' method="post"> | |||
| {{$.CsrfTokenHtml}} | |||
| <a style="padding: 0.5rem 1rem;margin-left:0.2rem" id="ai-delete-{{$JobID}}" data-repopath="{{.Repo.OwnerName}}/{{.Repo.Name}}/modelarts/inference-job/{{$JobID}}/del_version?ishomepage=true" data-version="{{.VersionName}}" class="ui basic ai_delete blue button" style="border-radius: .28571429rem;"> | |||
| {{$.i18n.Tr "repo.delete"}} | |||
| </a> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{else}} | |||
| {{$JobID := '0'}} | |||
| {{if eq .JobType "DEBUG" "SNN4IMAGENET" "BRAINSCORE" "BENCHMARK"}} | |||
| {{$JobID = .Cloudbrain.ID}} | |||
| {{else}} | |||
| {{$JobID = .JobID}} | |||
| {{end}} | |||
| <div class="ui grid stackable item"> | |||
| <div class="row"> | |||
| <!-- 任务名 --> | |||
| <div class="three wide column nowrap" style="width:15%"> | |||
| {{if eq .JobType "DEBUG"}} | |||
| <a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;"> | |||
| <span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> | |||
| </a> | |||
| {{else if eq .JobType "INFERENCE"}} | |||
| <a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;"> | |||
| <span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> | |||
| </a> | |||
| {{else if eq .JobType "TRAIN"}} | |||
| <a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;"> | |||
| <span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> | |||
| </a> | |||
| {{else if eq .JobType "BENCHMARK"}} | |||
| <a class="title" href="" title="{{.DisplayJobName}}" style="font-size: 14px;"> | |||
| <span class="fitted" style="width: 90%;vertical-align: middle;">{{.DisplayJobName}}</span> | |||
| </a> | |||
| {{end}} | |||
| </div> | |||
| <!-- 任务状态 --> | |||
| <div class="two wide column text center nowrap" style="padding-left: 2.2rem !important; width: 11% !important;"> | |||
| <span class="job-status" id="{{$JobID}}" data-jobid="{{$JobID}}" data-version="{{.VersionName}}"> | |||
| <span><i id="{{$JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{$JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||
| </span> | |||
| </div> | |||
| <!-- 任务类型 --> | |||
| {{$JobType := $.i18n.Tr (printf "cloudbrain.%s" .JobType)}} | |||
| <div class="one wide column text center nowrap" style="width:10%"> | |||
| <span style="font-size: 12px;" title="{{$JobType}}">{{$JobType}}</span> | |||
| </div> | |||
| <!-- 任务创建时间 --> | |||
| <div class="two wide column text center nowrap" style="width: 11% !important;"> | |||
| <span style="font-size: 12px;" class="">{{TimeSinceUnix1 .Cloudbrain.CreatedUnix}}</span> | |||
| </div> | |||
| <!-- 任务运行时间 --> | |||
| <div class="one wide column text center nowrap" style="width:8.5% !important;"> | |||
| <span style="font-size: 12px;" id="duration-{{$JobID}}">{{if .TrainJobDuration}}{{.TrainJobDuration}}{{else}}--{{end}}</span> | |||
| </div> | |||
| <!-- 计算资源 --> | |||
| <div class="one wide column text center nowrap" style="width:8.5% !important;"> | |||
| <span style="font-size: 12px;">{{if .ComputeResource}}{{.ComputeResource}}{{else}}--{{end}}</span> | |||
| </div> | |||
| <!-- 创建者 --> | |||
| <!-- 项目 --> | |||
| <div class="two wide column text center nowrap" style="width: 14.5%!important;"> | |||
| <a href="" title="">--</a> | |||
| </div> | |||
| <div class="three wide column text center nowrap" style="width: 21.5%!important;"> | |||
| {{if eq .JobType "DEBUG"}} | |||
| <div class="ui compact buttons"> | |||
| <form id="debugAgainForm-{{$JobID}}"> | |||
| {{$.CsrfTokenHtml}} | |||
| {{if eq .Status "RUNNING" "WAITING" "CREATING" "STARTING"}} | |||
| <a style="margin: 0 1rem;" id="ai-debug-{{$JobID}}" class='ui basic disabled button' > | |||
| {{$.i18n.Tr "repo.debug"}} | |||
| </a> | |||
| {{else}} | |||
| <a id="ai-debug-{{$JobID}}" class='ui basic disabled button' > | |||
| {{$.i18n.Tr "repo.debug_again"}} | |||
| </a> | |||
| {{end}} | |||
| </form> | |||
| </div> | |||
| {{end}} | |||
| <!-- 停止任务 --> | |||
| <div class="ui compact buttons"> | |||
| <a style="padding: 0.5rem 1rem;" id="ai-stop-{{$JobID}}" class="ui basic disabled button" data-jobid="{{$JobID}}" data-version="{{.VersionName}}" > | |||
| {{$.i18n.Tr "repo.stop"}} | |||
| </a> | |||
| </div> | |||
| <!-- 删除任务 --> | |||
| <form class="ui compact buttons" id="delForm-{{$JobID}}" action='' method="post"> | |||
| {{$.CsrfTokenHtml}} | |||
| <a style="padding: 0.5rem 1rem;margin-left:0.2rem" id="ai-delete-{{$JobID}}" class="ui basic disabled button" style="border-radius: .28571429rem;"> | |||
| {{$.i18n.Tr "repo.delete"}} | |||
| </a> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{end}} | |||
| {{end}} | |||
| <div id="app" style="margin-top: 2rem;"> | |||
| <div class="center"> | |||
| <el-pagination | |||
| background | |||
| @current-change="handleCurrentChange" | |||
| :current-page="page" | |||
| :page-sizes="[10]" | |||
| :page-size="10" | |||
| layout="total, sizes, prev, pager, next, jumper" | |||
| :total="{{.Page.Paginater.Total}}"> | |||
| </el-pagination> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <!-- 确认模态框 --> | |||
| <div id="deletemodel"> | |||
| <div class="ui basic modal"> | |||
| <div class="ui icon header"> | |||
| <i class="trash icon"></i> {{.i18n.Tr "cloudbrain.delete_task"}} | |||
| </div> | |||
| <div class="content"> | |||
| <p>{{.i18n.Tr "cloudbrain.task_delete_confirm"}}</p> | |||
| </div> | |||
| <div class="actions"> | |||
| <div class="ui red basic inverted cancel button"> | |||
| <i class="remove icon"></i> {{.i18n.Tr "cloudbrain.operate_cancel"}} | |||
| </div> | |||
| <div class="ui green basic inverted ok button"> | |||
| <i class="checkmark icon"></i> {{.i18n.Tr "cloudbrain.operate_confirm"}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| <script> | |||
| function getParams(){ | |||
| const params = new URLSearchParams(window.location.search) | |||
| params.get('jobType') | |||
| let jobType | |||
| if(!params.get('jobType')){ | |||
| jobType = '{{.i18n.Tr "admin.cloudbrain.all_task_types"}}' | |||
| }else{ | |||
| if(params.get('jobType') === 'DEBUG'){ | |||
| jobType = '{{$.i18n.Tr (printf "cloudbrain.DEBUG")}}' | |||
| }else if(params.get('jobType') === 'TRAIN'){ | |||
| jobType = '{{$.i18n.Tr (printf "cloudbrain.TRAIN")}}' | |||
| } | |||
| else if(params.get('jobType') === 'INFERENCE'){ | |||
| jobType = '{{$.i18n.Tr (printf "cloudbrain.INFERENCE")}}' | |||
| } | |||
| else if(params.get('jobType') === 'SNN4IMAGENET'){ | |||
| jobType = '{{$.i18n.Tr (printf "cloudbrain.SNN4IMAGENET")}}' | |||
| }else if(params.get('jobType') === 'BENCHMARK'){ | |||
| jobType = '{{$.i18n.Tr (printf "cloudbrain.BENCHMARK")}}' | |||
| } | |||
| else{ | |||
| jobType = '{{$.i18n.Tr (printf "cloudbrain.BRAINSCORE")}}' | |||
| } | |||
| } | |||
| let listType = !params.get('listType')? '{{.i18n.Tr "admin.cloudbrain.all_computing_resources"}}' : params.get('listType') | |||
| let jobStatus = !params.get('jobStatus')? '{{.i18n.Tr "admin.cloudbrain.all_status"}}' : params.get('jobStatus').toUpperCase() | |||
| const dropdownValueArray = [jobType,listType,jobStatus] | |||
| $('#adminCloud .default.text ').each(function(index,e){ | |||
| $(e).text(dropdownValueArray[index]) | |||
| }) | |||
| } | |||
| getParams() | |||
| </script> | |||
| @@ -5,13 +5,110 @@ | |||
| {{template "base/alert" .}} | |||
| <div class="ui mobile reversed stackable grid"> | |||
| <div class="ui container ten wide column"> | |||
| <div class="default" id = 'default_page' style="display: none;"> | |||
| <div class="w_title"> | |||
| {{.i18n.Tr "home.wecome_AI_plt"}} | |||
| </div> | |||
| <div class="content"> | |||
| <p >{{.i18n.Tr "home.explore_AI"}} <a href="{{AppSubUrl}}/explore/repos"> {{.i18n.Tr "home.repositories"}}</a> {{.i18n.Tr "home.or_t"}} <a href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "home.datasets"}}</a></p> | |||
| <p >{{.i18n.Tr "home.use_plt__fuction"}} <a class="mini ui blue button" href="{{AppSubUrl}}/repo/create{{if .ContextUser.IsOrganization}}?org={{.ContextUser.ID}}{{end}}" >{{.i18n.Tr "repo.create_repo"}}</a></p> | |||
| <p > {{.i18n.Tr "home.provide_resoure"}}</p> | |||
| </div> | |||
| <div class="guide "> | |||
| <a class="mini ui blue basic button" style="font-weight:700" href="https://git.openi.org.cn/zeizei/OpenI_Learning" target="_blank">{{.i18n.Tr "custom.Platform_Tutorial"}} <i class="ri-arrow-right-line" ></i></a> | |||
| </div> | |||
| </div> | |||
| {{if .EnableHeatmap}} | |||
| {{template "user/dashboard/heatmap" .}} | |||
| {{end}} | |||
| {{template "user/dashboard/feeds" .}} | |||
| <diV id = "activity_cont" style="display: none;"> | |||
| <div class="ui placeholder segment bgtask-none padding_none line" > | |||
| <div class="act_title" style="padding-left: 0px ;"> | |||
| {{.i18n.Tr "home.activity"}} : | |||
| </div> | |||
| <div class="ui icon header bgtask-header-pic"></div> | |||
| <p class="p_hint"> | |||
| {{.i18n.Tr "home.no_events"}} | |||
| </p> | |||
| </div> | |||
| </diV> | |||
| </div> | |||
| {{template "user/dashboard/repolist" .}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| <script> | |||
| const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; | |||
| uid_ = Number((document.querySelector('meta[name=_context_uid]') || {}).content) | |||
| // console.log("uid:",uid_) | |||
| let URL = AppSubUrl + '/api/v1/repos/search?sort=updated&order=desc&uid='+uid_ +'&q=&page=1&limit=10&mode= '; | |||
| $.getJSON(URL, (result, _textStatus, request) => { | |||
| const counts_pro = request.getResponseHeader('X-Total-Count'); | |||
| console.log("count:",counts_pro) | |||
| if (counts_pro == 0){ | |||
| document.getElementById("default_page").style.display = "block"; | |||
| document.getElementById("activity_cont").style.display = "block" | |||
| } | |||
| }) | |||
| </script> | |||
| <style> | |||
| .default{ | |||
| background-color: rgba(24, 144, 255, 0.1); | |||
| margin-bottom: 20px; | |||
| border-radius: 15px; | |||
| line-height: 20px; | |||
| padding:0px 25px; | |||
| } | |||
| .w_title{ | |||
| padding-top: 25px; | |||
| color: rgba(16, 16, 16, 100); | |||
| font-size: 20px; | |||
| text-align: left; | |||
| font-weight: 700; | |||
| } | |||
| .content{ | |||
| color: rgba(80, 85, 89, 100); | |||
| font-size: 14px; | |||
| text-align: left; | |||
| font-family: SourceHanSansSC-regular; | |||
| margin-top: 20px; | |||
| } | |||
| .guide{ | |||
| margin-top:30px; | |||
| padding-bottom: 30px; | |||
| } | |||
| .activity{ | |||
| margin-top: 20px; | |||
| } | |||
| .act_title{ | |||
| color: rgba(16, 16, 16, 100) !important; | |||
| font-size: 20px; | |||
| text-align: left; | |||
| background-color: #fff !important; | |||
| font-weight: 700; | |||
| } | |||
| .p_hint{ | |||
| color: rgba(136, 136, 136, 100); | |||
| font-size: 14px; | |||
| text-align: center; | |||
| font-family: SourceHanSansSC-regular; | |||
| } | |||
| .padding_none{ | |||
| padding: 0px !important; | |||
| } | |||
| .ui.placeholder.segment { | |||
| min-height: 15rem !important; | |||
| } | |||
| .line{ | |||
| border-top: 1px solid rgba(187, 187, 187, 0.5) !important; | |||
| margin-top: 20px !important; | |||
| } | |||
| </style> | |||
| @@ -71,7 +71,7 @@ | |||
| {{ $index := index .GetIssueInfos 0}} | |||
| {{$.i18n.Tr "action.comment_pull" .GetRepoLink $index .ShortRepoPath | Str2html}} | |||
| {{else if eq .GetOpType 24}} | |||
| {{$.i18n.Tr "action.upload_dataset" .GetRepoLink .Content .RefName | Str2html}} | |||
| {{$.i18n.Tr "action.upload_dataset" .GetRepoLink .RefName | Str2html}} | |||
| {{else if eq .GetOpType 25}} | |||
| {{$.i18n.Tr "action.task_gpudebugjob" .GetRepoLink .Content .RefName | Str2html}} | |||
| {{else if eq .GetOpType 26}} | |||
| @@ -11,7 +11,7 @@ | |||
| </div> | |||
| {{end}} | |||
| </h4> | |||
| <div class="ui attached segment orgs"> | |||
| <div class="ui attached segment"> | |||
| {{if .Orgs}} | |||
| <div class="ui middle aligned divided list"> | |||
| {{range .Orgs}} | |||
| @@ -23,7 +23,7 @@ | |||
| </form> | |||
| </div> | |||
| <img class="ui mini image" src="{{.RelAvatarLink}}"> | |||
| <div class="content"> | |||
| <div class="content-org" style="display: inline-block;width: auto;padding: 0 0 0 0.5em;"> | |||
| <a href="{{.HomeLink}}">{{.Name}}</a> | |||
| </div> | |||
| </div> | |||
| @@ -0,0 +1,86 @@ | |||
| <template> | |||
| <div style="width: 100%;"> | |||
| <div id = "pro_main"> | |||
| <div style="margin-top: 10px;"> | |||
| <b class="pro_item">云脑分析</b> <span class="update_time">数据更新时间:</span> <span style="font-size: 12px;">{{lastUpdatedTime}} / 从有记录起开始统计</span> | |||
| </div> | |||
| <bar-label :width="'95%'" :height="'500px'"></bar-label> | |||
| <div style="margin-top: 20px;"> | |||
| <span class="sta_iterm">统计周期:</span> | |||
| <button type="button" class='btnLast' id = "all" v-bind:class="{colorChange:7==dynamic}" @click="resetPage(),getAllProList('all',7)">所有</button> | |||
| <span style="float:right; margin-right: 20px;"> | |||
| <div style="display:inline-block;margin-left: 40px; "> | |||
| <a class="el-icon-download" v-if="tableData!=''" :href= "'../api/v1/cloudbrainboard/downloadAll'"></a> | |||
| <i class="el-icon-download" v-else="tableData=''" href="#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'></i> | |||
| <!-- <span ><a id = "download_file" :href= "'../api/v1/projectboard/downloadAll'" >下载报告</a> </span> --> | |||
| <span > | |||
| <a id = "download_file" v-if="tableData!=''" :href= "'../api/v1/cloudbrainboard/downloadAll'">下载报告</a> | |||
| <a id = "download_file" v-else="tableData=''" href= "#" style="color:rgba(187, 187, 187, 100);" @click='popMark()'>下载报告</a> | |||
| </span> | |||
| </div> | |||
| </span> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| // import barLabel from './basic/barLabel.vue'; | |||
| const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; | |||
| import { export2Excel } from '../excel/util.js' | |||
| export default{ | |||
| name:'ProAnalysis', | |||
| components: { | |||
| // barLabel, | |||
| }, | |||
| methods: { | |||
| popMark(){ | |||
| alert("数据为空时,不能下载!") | |||
| }, | |||
| exportData(){ | |||
| // this.getOneProList(this.pro_id,'all',true,7) | |||
| // this.getOneProList(this.pro_id,'all',false,7) | |||
| // this.fileName() | |||
| if (this.tableDataID!=''){ | |||
| this.currentPage=1 | |||
| var saveFileName = this.getFileName() | |||
| export2Excel(this.columns,this.tableDataID,saveFileName) | |||
| }else{ | |||
| alert("数据为空时,不能下载!") | |||
| } | |||
| }, | |||
| }, | |||
| } | |||
| </script> | |||
| <style scoped> | |||
| .pro_item{ | |||
| font-size: 16px; | |||
| color: rgba(16, 16, 16, 100); | |||
| font-family: SourceHanSansSC-bold; | |||
| } | |||
| .update_time{ | |||
| line-height: 17px; | |||
| font-size: 12px; | |||
| color:rgba(187, 187, 187, 100); | |||
| margin-left: 10px; | |||
| } | |||
| .btnLast{ | |||
| line-height: 1.5; | |||
| margin: -3.5px; | |||
| border: 1px solid rgba(22, 132, 252, 100); | |||
| /* border-right: none; */ | |||
| background: #FFFF; | |||
| color: #1684FC; | |||
| width: 60px; | |||
| height: 30px; | |||
| border-radius:0px 4px 4px 0px; | |||
| } | |||
| </style> | |||
| @@ -96,23 +96,3 @@ updated(){ | |||
| }; | |||
| </script> | |||
| <style scoped> | |||
| /deep/ .el-pagination.is-background .el-pager li:not(.disabled).active { | |||
| background-color: #5bb973; | |||
| color: #FFF; | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li.active { | |||
| color: #fff; | |||
| cursor: default; | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li:hover { | |||
| color: #5bb973; | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li:not(.disabled):hover { | |||
| color: #5bb973; | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li:not(.disabled).active:hover { | |||
| background-color: #5bb973; | |||
| color: #FFF; | |||
| } | |||
| </style> | |||
| @@ -26,6 +26,14 @@ | |||
| </span> | |||
| <UserAnalysis ref='UserAnalysis' v-if="isRouterAlive1" id ="usr"></UserAnalysis> | |||
| </el-tab-pane> | |||
| <el-tab-pane name="four" id='four' > | |||
| <BrainAnalysis ref='BrainAnalysis'id="brain" v-if="isRouterAlive"></BrainAnalysis> | |||
| <span slot="label"> | |||
| <el-image style="width: 13px; height: 13px" src="/img/pro_rgb.svg"> | |||
| </el-image> | |||
| 云脑分析(建设中..) | |||
| </span> | |||
| </el-tab-pane> | |||
| </el-tabs> | |||
| </div> | |||
| </template> | |||
| @@ -33,12 +41,14 @@ | |||
| <script> | |||
| import ProAnalysis from './ProAnalysis.vue' | |||
| import UserAnalysis from './UserAnalysis.vue' | |||
| import BrainAnalysis from './BrainAnalysis.vue' | |||
| export default { | |||
| components:{ | |||
| 'ProAnalysis':ProAnalysis, | |||
| 'UserAnalysis':UserAnalysis, | |||
| 'BrainAnalysis':BrainAnalysis, | |||
| }, | |||
| data() { | |||
| return { | |||
| @@ -1,503 +0,0 @@ | |||
| <template> | |||
| <div> | |||
| <div class="header-wrapper"> | |||
| <div class="ui container"> | |||
| <el-row class="image_text"> | |||
| <h1>云脑镜像</h1> | |||
| </el-row> | |||
| </div> | |||
| </div> | |||
| <div class="ui container" id="header"> | |||
| <el-tabs v-model="activeName" @tab-click="handleClick"> | |||
| <el-tab-pane label="公共镜像(云脑1)" name="first" v-loading="loading"> | |||
| <div class="ui sixteen wide column"> | |||
| <div class="ui two column stackable grid"> | |||
| <div class="column"> | |||
| <el-input placeholder="请输入镜像名称关健词" v-model="search" class="input-with-select" @keyup.enter.native="searchName()"> | |||
| <el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button> | |||
| </el-input> | |||
| </div> | |||
| <!-- <div class="column right aligned"> | |||
| <el-dropdown> | |||
| <span class="el-dropdown-link"> | |||
| 排序<i class="el-icon-caret-bottom"></i> | |||
| </span> | |||
| <el-dropdown-menu slot="dropdown"> | |||
| <el-dropdown-item>最早创建</el-dropdown-item> | |||
| <el-dropdown-item>最新创建</el-dropdown-item> | |||
| <el-dropdown-item divided>按镜像字母顺序排序</el-dropdown-item> | |||
| <el-dropdown-item>按镜像字母逆序排序</el-dropdown-item> | |||
| </el-dropdown-menu> | |||
| </el-dropdown> | |||
| </div> --> | |||
| </div> | |||
| </div> | |||
| <el-row style="margin-top:15px;"> | |||
| <el-table | |||
| :data="tableData" | |||
| style="width: 100%" | |||
| :header-cell-style="tableHeaderStyle" | |||
| :default-sort="{prop:'createtime',order:'descending'}"> | |||
| <el-table-column | |||
| label="镜像名称" | |||
| width="350" | |||
| align="left" | |||
| prop="name" | |||
| sortable | |||
| > | |||
| <template slot-scope="scope"> | |||
| <a class="text-over" style="cursor:default;color:#426290" :title="scope.row.name">{{ scope.row.name }}</a> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| label="文件路径/镜像描述" | |||
| width="450" | |||
| align="left" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-tooltip class="item" effect="dark" content="点击复制文件路径" placement="top"> | |||
| <a class="text-over" style="display:block;" @click="copyUrl(scope.row.place)">{{ scope.row.place }}</a> | |||
| </el-tooltip> | |||
| <span class="text-over" :title="scope.row.description | clearP">{{ scope.row.description | clearP}}</span> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="provider" | |||
| label="提供者" | |||
| width="120" | |||
| align="left" | |||
| sortable> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="createtime" | |||
| label="创建时间" | |||
| align="center" | |||
| sortable> | |||
| <template slot-scope="scope"> | |||
| {{scope.row.createtime | transformTimestamp}} | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| </el-row> | |||
| <div class="ui container" style="margin-top:50px;text-align:center"> | |||
| <el-pagination | |||
| background | |||
| @size-change="handleSizeChange" | |||
| @current-change="handleCurrentChange" | |||
| :current-page="currentPage" | |||
| :page-size="pageSize" | |||
| :page-sizes="[5,10,20]" | |||
| layout="total, sizes, prev, pager, next, jumper" | |||
| :total="totalNum"> | |||
| </el-pagination> | |||
| </div> | |||
| </el-tab-pane> | |||
| <el-tab-pane label="自定义镜像(云脑1)" name="second" v-loading="loading1"> | |||
| <div class="ui sixteen wide column"> | |||
| <div class="ui two column stackable grid"> | |||
| <div class="column"> | |||
| <el-input placeholder="请输入镜像名称关健词" v-model="search" class="input-with-select" @keyup.enter.native="searchName()"> | |||
| <el-button slot="append" id="success" icon="el-icon-search" @click="searchName()">搜索</el-button> | |||
| </el-input> | |||
| </div> | |||
| <!-- <div class="column right aligned"> | |||
| <el-dropdown> | |||
| <span class="el-dropdown-link"> | |||
| 排序<i class="el-icon-caret-bottom"></i> | |||
| </span> | |||
| <el-dropdown-menu slot="dropdown"> | |||
| <el-dropdown-item>最早创建</el-dropdown-item> | |||
| <el-dropdown-item>最新创建</el-dropdown-item> | |||
| <el-dropdown-item divided>按镜像字母顺序排序</el-dropdown-item> | |||
| <el-dropdown-item>按镜像字母逆序排序</el-dropdown-item> | |||
| </el-dropdown-menu> | |||
| </el-dropdown> | |||
| </div> --> | |||
| </div> | |||
| </div> | |||
| <el-row style="margin-top:15px;"> | |||
| <el-table | |||
| :data="tableData1" | |||
| style="width: 100%" | |||
| :header-cell-style="tableHeaderStyle" | |||
| :default-sort="{prop:'createtime',order:'descending'}"> | |||
| <el-table-column | |||
| label="镜像名称" | |||
| width="350" | |||
| align="left" | |||
| prop="name" | |||
| sortable | |||
| > | |||
| <template slot-scope="scope"> | |||
| <a class="text-over" :title="scope.row.name" style="cursor:default;color:#426290">{{ scope.row.name }}</a> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| label="文件路径/镜像描述" | |||
| width="450" | |||
| align="left" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-tooltip class="item" effect="dark" content="点击复制文件路径" placement="top"> | |||
| <a class="text-over" style="display:block;" @click="copyUrl(scope.row.place)">{{ scope.row.place }}</a> | |||
| </el-tooltip> | |||
| <span class="text-over" :title="scope.row.description | clearP">{{ scope.row.description | clearP }}</span> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="provider" | |||
| label="提供者" | |||
| width="120" | |||
| align="left" | |||
| sortable> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="createtime" | |||
| label="创建时间" | |||
| align="center" | |||
| sortable> | |||
| <template slot-scope="scope"> | |||
| {{scope.row.createtime | transformTimestamp}} | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| </el-row> | |||
| <div class="ui container" style="margin-top:50px;text-align:center"> | |||
| <el-pagination | |||
| background | |||
| @size-change="handleSizeChange1" | |||
| @current-change="handleCurrentChange1" | |||
| :current-page="currentPage1" | |||
| :page-size="pageSize1" | |||
| :page-sizes="[5,10,20]" | |||
| layout="total, sizes, prev, pager, next, jumper" | |||
| :total="totalNum1"> | |||
| </el-pagination> | |||
| </div> | |||
| </el-tab-pane> | |||
| <el-tab-pane label="公共镜像(云脑2)" name="third"> | |||
| <div class="ui sixteen wide column"> | |||
| <div class="ui two column stackable grid"> | |||
| <div class="column"> | |||
| <el-input placeholder="请输入镜像名称关健词" v-model="search" class="input-with-select"> | |||
| <el-button slot="append" id="success" icon="el-icon-search">搜索</el-button> | |||
| </el-input> | |||
| </div> | |||
| <!-- <div class="column right aligned"> | |||
| <el-dropdown> | |||
| <span class="el-dropdown-link"> | |||
| 排序<i class="el-icon-caret-bottom"></i> | |||
| </span> | |||
| <el-dropdown-menu slot="dropdown"> | |||
| <el-dropdown-item>最早创建</el-dropdown-item> | |||
| <el-dropdown-item>最新创建</el-dropdown-item> | |||
| <el-dropdown-item divided>按镜像字母顺序排序</el-dropdown-item> | |||
| <el-dropdown-item>按镜像字母逆序排序</el-dropdown-item> | |||
| </el-dropdown-menu> | |||
| </el-dropdown> | |||
| </div> --> | |||
| </div> | |||
| </div> | |||
| <el-empty :image-size="200"></el-empty> | |||
| </el-tab-pane> | |||
| <el-tab-pane label="自定义镜像(云脑2)" name="fourth"> | |||
| <div class="ui sixteen wide column"> | |||
| <div class="ui two column stackable grid"> | |||
| <div class="column"> | |||
| <el-input placeholder="请输入镜像名称关健词" v-model="search" class="input-with-select"> | |||
| <el-button slot="append" id="success" icon="el-icon-search">搜索</el-button> | |||
| </el-input> | |||
| </div> | |||
| <!-- <div class="column right aligned"> | |||
| <el-dropdown> | |||
| <span class="el-dropdown-link"> | |||
| 排序<i class="el-icon-caret-bottom"></i> | |||
| </span> | |||
| <el-dropdown-menu slot="dropdown"> | |||
| <el-dropdown-item>最早创建</el-dropdown-item> | |||
| <el-dropdown-item>最新创建</el-dropdown-item> | |||
| <el-dropdown-item divided>按镜像字母顺序排序</el-dropdown-item> | |||
| <el-dropdown-item>按镜像字母逆序排序</el-dropdown-item> | |||
| </el-dropdown-menu> | |||
| </el-dropdown> | |||
| </div> --> | |||
| </div> | |||
| </div> | |||
| <el-empty :image-size="200"></el-empty> | |||
| </el-tab-pane> | |||
| </el-tabs> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; | |||
| export default { | |||
| components: { | |||
| }, | |||
| data() { | |||
| return { | |||
| activeName: 'first', | |||
| search:'', | |||
| currentPage:1, | |||
| pageSize:10, | |||
| totalNum:0, | |||
| params:{page:1,size:10,name:''}, | |||
| tableData: [], | |||
| loading:false, | |||
| currentPage1:1, | |||
| pageSize1:10, | |||
| totalNum1:0, | |||
| params1:{page:1,size:10,name:''}, | |||
| tableData1: [], | |||
| loading1:false | |||
| }; | |||
| }, | |||
| methods: { | |||
| handleClick(tab, event) { | |||
| if(tab.name=="first"){ | |||
| this.getImageList() | |||
| } | |||
| if(tab.name=="second"){ | |||
| this.getImageList1() | |||
| } | |||
| }, | |||
| tableHeaderStyle({row,column,rowIndex,columnIndex}){ | |||
| if(rowIndex===0){ | |||
| return 'background:#f5f5f6;color:#606266' | |||
| } | |||
| }, | |||
| handleSizeChange(val){ | |||
| this.params.size = val | |||
| this.getImageList() | |||
| }, | |||
| handleCurrentChange(val){ | |||
| this.params.page = val | |||
| this.getImageList() | |||
| }, | |||
| handleSizeChange1(val){ | |||
| this.params1.size = val | |||
| this.getImageList1() | |||
| }, | |||
| handleCurrentChange1(val){ | |||
| this.params1.page = val | |||
| this.getImageList1() | |||
| }, | |||
| getImageList(){ | |||
| this.loading = true | |||
| this.$axios.get('/explore/images/public',{ | |||
| params:this.params | |||
| }).then((res)=>{ | |||
| this.totalNum = res.data.count | |||
| this.tableData = res.data.rows | |||
| this.loading = false | |||
| }) | |||
| }, | |||
| getImageList1(){ | |||
| this.loading1 = true | |||
| this.$axios.get('/explore/images/custom',{ | |||
| params:this.params1 | |||
| }).then((res)=>{ | |||
| this.totalNum1 = res.data.count | |||
| this.tableData1 = res.data.rows | |||
| this.loading1 = false | |||
| }) | |||
| }, | |||
| copyUrl(url){ | |||
| const cInput = document.createElement('input') | |||
| cInput.value = url | |||
| document.body.appendChild(cInput) | |||
| cInput.select() | |||
| document.execCommand('Copy') | |||
| cInput.remove() | |||
| }, | |||
| searchName(){ | |||
| if(this.activeName=='first'){ | |||
| this.params.name = this.search | |||
| this.params.page = 1 | |||
| this.getImageList() | |||
| } | |||
| if(this.activeName=='second'){ | |||
| this.params1.name = this.search | |||
| this.params1.page = 1 | |||
| this.getImageList1() | |||
| } | |||
| } | |||
| }, | |||
| filters:{ | |||
| clearP(value){ | |||
| if(!value) return '' | |||
| const reg = /\<\/?p\>/g; | |||
| value = value.replace(reg,'') | |||
| return value | |||
| }, | |||
| transformTimestamp(timestamp){ | |||
| let a = new Date(timestamp).getTime(); | |||
| const date = new Date(a); | |||
| const Y = date.getFullYear() + '-'; | |||
| const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'; | |||
| const D = (date.getDate() < 10 ? '0'+date.getDate() : date.getDate()) + ' '; | |||
| const h = (date.getHours() < 10 ? '0'+date.getHours() : date.getHours()) + ':'; | |||
| const m = (date.getMinutes() <10 ? '0'+date.getMinutes() : date.getMinutes()) + ':' ; | |||
| const s = (date.getSeconds() <10 ? '0'+date.getSeconds() : date.getSeconds()) ; // 秒 | |||
| const dateString = Y + M + D + h + m + s; | |||
| // console.log('dateString', dateString); // > dateString 2021-07-06 14:23 | |||
| return dateString; | |||
| }, | |||
| }, | |||
| watch:{ | |||
| search(val){ | |||
| if(!val && this.activeName=='first'){ | |||
| this.params.name = val | |||
| this.getImageList() | |||
| } | |||
| if(!val && this.activeName=='second'){ | |||
| this.params1.name = val | |||
| this.getImageList1() | |||
| } | |||
| } | |||
| }, | |||
| mounted() { | |||
| this.getImageList() | |||
| }, | |||
| created() { | |||
| } | |||
| }; | |||
| </script> | |||
| <style scoped> | |||
| .header-wrapper { | |||
| background-color: #f5f5f6; | |||
| padding-top: 15px; | |||
| } | |||
| .image_text{ | |||
| padding:25px 0 55px 0 ; | |||
| } | |||
| #header{ | |||
| position: relative; | |||
| top:-40px; | |||
| } | |||
| .el-dropdown-menu__item--divided{ | |||
| border-top: 1px solid blue; | |||
| } | |||
| .el-table thead{ | |||
| background-color: #f5f5f6; | |||
| } | |||
| /deep/ .el-tabs__item:hover{ | |||
| color: #000; | |||
| font-weight: 500; | |||
| } | |||
| /deep/ .el-tabs__item.is-active { | |||
| color: #000; | |||
| font-weight: 500; | |||
| } | |||
| /deep/ .el-tabs__active-bar{ | |||
| background-color:#000 | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li:not(.disabled).active { | |||
| background-color: #5bb973; | |||
| color: #FFF; | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li.active { | |||
| color: #fff; | |||
| cursor: default; | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li:hover { | |||
| color: #5bb973; | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li:not(.disabled):hover { | |||
| color: #5bb973; | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li:not(.disabled).active:hover { | |||
| background-color: #5bb973; | |||
| color: #FFF; | |||
| } | |||
| /deep/ .el-pager li.active { | |||
| color: #08C0B9; | |||
| cursor: default; | |||
| } | |||
| /deep/ .el-pagination .el-pager li:hover { | |||
| color: #08C0B9; | |||
| } | |||
| /deep/ .el-pagination .el-pager li:not(.disabled):hover { | |||
| color: #08C0B9; | |||
| } | |||
| /* /deep/ .el-pagination.is-background .el-pager li:not(.disabled).active{ | |||
| background-color: #5bb973; | |||
| color: #000; | |||
| } */ | |||
| /* /deep/ .el-pager li:hover{ | |||
| color: #000; | |||
| } */ | |||
| #success{ | |||
| background-color: #5bb973; | |||
| color: white; | |||
| } | |||
| .text-over{ | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| vertical-align: middle; | |||
| white-space: nowrap; | |||
| } | |||
| </style> | |||
| @@ -26,7 +26,8 @@ import qs from 'qs'; | |||
| import createDropzone from '../features/dropzone.js'; | |||
| const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; | |||
| // const uploadtype = 0; | |||
| const chunkSize = 1024 * 1024 * 64; | |||
| const md5ChunkSize = 1024 * 1024 * 1; | |||
| export default { | |||
| props:{ | |||
| @@ -137,7 +138,6 @@ export default { | |||
| resetStatus() { | |||
| this.progress = 0; | |||
| this.status = ''; | |||
| console.log(this.uploadtype) | |||
| }, | |||
| updateProgress(file, progress) { | |||
| console.log("progress---",progress) | |||
| @@ -165,7 +165,6 @@ export default { | |||
| .getElementById('datasetId') | |||
| .getAttribute('datasetId'); | |||
| this.resetStatus(); | |||
| console.log(this.file,!this.file?.upload) | |||
| if(!this.file?.upload){ | |||
| this.btnFlag = false | |||
| return | |||
| @@ -186,17 +185,18 @@ export default { | |||
| File.prototype.slice || | |||
| File.prototype.mozSlice || | |||
| File.prototype.webkitSlice, | |||
| chunkSize = 1024 * 1024 * 64, | |||
| chunks = Math.ceil(file.size / chunkSize), | |||
| spark = new SparkMD5.ArrayBuffer(), | |||
| fileReader = new FileReader(); | |||
| let currentChunk = 0; | |||
| const time = new Date().getTime(); | |||
| // console.log('计算MD5...') | |||
| this.status = this.dropzoneParams.data('md5-computing'); | |||
| file.totalChunkCounts = chunks; | |||
| loadNext(); | |||
| if (file.size==0) { | |||
| file.totalChunkCounts = 1 | |||
| } | |||
| loadMd5Next(); | |||
| fileReader.onload = (e) => { | |||
| fileLoaded.call(this, e); | |||
| @@ -210,13 +210,12 @@ export default { | |||
| spark.append(e.target.result); // Append array buffer | |||
| currentChunk++; | |||
| if (currentChunk < chunks) { | |||
| // console.log(`第${currentChunk}分片解析完成, 开始第${currentChunk +1}/${chunks}分片解析`); | |||
| this.status = `${this.dropzoneParams.data('loading-file')} ${( | |||
| (currentChunk / chunks) * | |||
| 100 | |||
| ).toFixed(2)}% (${currentChunk}/${chunks})`; | |||
| this.updateProgress(file, ((currentChunk / chunks) * 100).toFixed(2)); | |||
| loadNext(); | |||
| loadMd5Next(); | |||
| return; | |||
| } | |||
| @@ -238,6 +237,13 @@ export default { | |||
| start + chunkSize >= file.size ? file.size : start + chunkSize; | |||
| fileReader.readAsArrayBuffer(blobSlice.call(file, start, end)); | |||
| } | |||
| function loadMd5Next() { | |||
| const start = currentChunk * chunkSize; | |||
| const end = | |||
| start + md5ChunkSize >= file.size ? file.size : start + md5ChunkSize; | |||
| fileReader.readAsArrayBuffer(blobSlice.call(file, start, end)); | |||
| } | |||
| }, | |||
| async computeMD5Success(md5edFile) { | |||
| @@ -327,7 +333,6 @@ export default { | |||
| }, | |||
| async newMultiUpload(file) { | |||
| console.log(this.uploadtype,this) | |||
| const res = await axios.get('/attachments/new_multipart', { | |||
| params: { | |||
| totalChunkCounts: file.totalChunkCounts, | |||
| @@ -348,7 +353,6 @@ export default { | |||
| File.prototype.slice || | |||
| File.prototype.mozSlice || | |||
| File.prototype.webkitSlice, | |||
| chunkSize = 1024 * 1024 * 32, | |||
| chunks = Math.ceil(file.size / chunkSize), | |||
| fileReader = new FileReader(), | |||
| time = new Date().getTime(); | |||
| @@ -457,7 +461,6 @@ export default { | |||
| } | |||
| async function completeUpload() { | |||
| console.log(_this.uploadtype) | |||
| return await axios.post( | |||
| '/attachments/complete_multipart', | |||
| qs.stringify({ | |||
| @@ -494,7 +497,6 @@ export default { | |||
| 1}/${chunks}个分片上传` | |||
| ); | |||
| this.progress = Math.ceil((currentChunk / chunks) * 100); | |||
| console.log("((currentChunk / chunks) * 100).toFixed(2)",((currentChunk / chunks) * 100).toFixed(2)) | |||
| this.updateProgress(file, ((currentChunk / chunks) * 100).toFixed(2)); | |||
| this.status = `${this.dropzoneParams.data('uploading')} ${( | |||
| (currentChunk / chunks) * | |||
| @@ -426,42 +426,6 @@ export default { | |||
| </script> | |||
| <style scoped> | |||
| /deep/ .el-pagination.is-background .el-pager li:not(.disabled).active { | |||
| background-color: #5bb973; | |||
| color: #FFF; | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li.active { | |||
| color: #fff; | |||
| cursor: default; | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li:hover { | |||
| color: #5bb973; | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li:not(.disabled):hover { | |||
| color: #5bb973; | |||
| } | |||
| /deep/ .el-pagination.is-background .el-pager li:not(.disabled).active:hover { | |||
| background-color: #5bb973; | |||
| color: #FFF; | |||
| } | |||
| /deep/ .el-pager li.active { | |||
| color: #08C0B9; | |||
| cursor: default; | |||
| } | |||
| /deep/ .el-pagination .el-pager li:hover { | |||
| color: #08C0B9; | |||
| } | |||
| /deep/ .el-pagination .el-pager li:not(.disabled):hover { | |||
| color: #08C0B9; | |||
| } | |||
| .text-over{ | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| @@ -1,484 +0,0 @@ | |||
| <template> | |||
| <div class="dropzone-wrapper dataset-files"> | |||
| <div | |||
| id="dataset" | |||
| class="dropzone" | |||
| /> | |||
| <p class="upload-info"> | |||
| {{ file_status_text }} | |||
| <strong class="success text red">{{ status }}</strong> | |||
| </p> | |||
| <p>说明:<br> | |||
| - 只有zip格式的数据集才能发起云脑任务;<br> | |||
| - 云脑1提供 <span class="text blue">CPU / GPU</span> 资源,云脑2提供 <span class="text blue">Ascend NPU</span> 资源;调试使用的数据集也需要上传到对应的环境。 | |||
| </p> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| /* eslint-disable eqeqeq */ | |||
| // import Dropzone from 'dropzone/dist/dropzone.js'; | |||
| // import 'dropzone/dist/dropzone.css' | |||
| import SparkMD5 from 'spark-md5'; | |||
| import axios from 'axios'; | |||
| import qs from 'qs'; | |||
| import createDropzone from '../features/dropzone.js'; | |||
| const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; | |||
| const CloudBrainType = 1; | |||
| export default { | |||
| data() { | |||
| return { | |||
| dropzoneUploader: null, | |||
| maxFiles: 1, | |||
| maxFilesize: 1 * 1024 * 1024 * 1024 * 1024, | |||
| acceptedFiles: '*/*', | |||
| progress: 0, | |||
| status: '', | |||
| dropzoneParams: {}, | |||
| file_status_text: '' | |||
| }; | |||
| }, | |||
| async mounted() { | |||
| this.dropzoneParams = $('div#minioUploader-params'); | |||
| this.file_status_text = this.dropzoneParams.data('file-status'); | |||
| this.status = this.dropzoneParams.data('file-init-status'); | |||
| let previewTemplate = ''; | |||
| previewTemplate += '<div class="dz-preview dz-file-preview">\n '; | |||
| previewTemplate += ' <div class="dz-details">\n '; | |||
| previewTemplate += ' <div class="dz-filename">'; | |||
| previewTemplate += | |||
| ' <span data-dz-name data-dz-thumbnail></span>'; | |||
| previewTemplate += ' </div>\n '; | |||
| previewTemplate += ' <div class="dz-size" data-dz-size style="white-space: nowrap"></div>\n '; | |||
| previewTemplate += ' </div>\n '; | |||
| previewTemplate += ' <div class="dz-progress ui active progress">'; | |||
| previewTemplate += | |||
| ' <div class="dz-upload bar" data-dz-uploadprogress><div class="progress"></div></div>\n '; | |||
| previewTemplate += ' </div>\n '; | |||
| previewTemplate += ' <div class="dz-success-mark">'; | |||
| previewTemplate += ' <span>上传成功</span>'; | |||
| previewTemplate += ' </div>\n '; | |||
| previewTemplate += ' <div class="dz-error-mark">'; | |||
| previewTemplate += ' <span>上传失败</span>'; | |||
| previewTemplate += ' </div>\n '; | |||
| previewTemplate += ' <div class="dz-error-message">'; | |||
| previewTemplate += ' <span data-dz-errormessage></span>'; | |||
| previewTemplate += ' </div>\n'; | |||
| previewTemplate += '</div>'; | |||
| const $dropzone = $('div#dataset'); | |||
| console.log('createDropzone'); | |||
| const dropzoneUploader = await createDropzone($dropzone[0], { | |||
| url: '/todouploader', | |||
| maxFiles: this.maxFiles, | |||
| maxFilesize: this.maxFileSize, | |||
| timeout: 0, | |||
| autoQueue: false, | |||
| dictDefaultMessage: this.dropzoneParams.data('default-message'), | |||
| dictInvalidFileType: this.dropzoneParams.data('invalid-input-type'), | |||
| dictFileTooBig: this.dropzoneParams.data('file-too-big'), | |||
| dictRemoveFile: this.dropzoneParams.data('remove-file'), | |||
| previewTemplate | |||
| }); | |||
| dropzoneUploader.on('addedfile', (file) => { | |||
| setTimeout(() => { | |||
| // eslint-disable-next-line no-unused-expressions | |||
| file.accepted && this.onFileAdded(file); | |||
| }, 200); | |||
| }); | |||
| dropzoneUploader.on('maxfilesexceeded', function (file) { | |||
| if (this.files[0].status !== 'success') { | |||
| alert(this.dropzoneParams.data('waitting-uploading')); | |||
| this.removeFile(file); | |||
| return; | |||
| } | |||
| this.removeAllFiles(); | |||
| this.addFile(file); | |||
| }); | |||
| this.dropzoneUploader = dropzoneUploader; | |||
| }, | |||
| methods: { | |||
| resetStatus() { | |||
| this.progress = 0; | |||
| this.status = ''; | |||
| }, | |||
| updateProgress(file, progress) { | |||
| file.previewTemplate.querySelector( | |||
| '.dz-upload' | |||
| ).style.width = `${progress}%`; | |||
| }, | |||
| emitDropzoneSuccess(file) { | |||
| file.status = 'success'; | |||
| this.dropzoneUploader.emit('success', file); | |||
| this.dropzoneUploader.emit('complete', file); | |||
| }, | |||
| emitDropzoneFailed(file) { | |||
| this.status = this.dropzoneParams.data('falied'); | |||
| file.status = 'error'; | |||
| this.dropzoneUploader.emit('error', file); | |||
| // this.dropzoneUploader.emit('complete', file); | |||
| }, | |||
| onFileAdded(file) { | |||
| file.datasetId = document | |||
| .getElementById('datasetId') | |||
| .getAttribute('datasetId'); | |||
| this.resetStatus(); | |||
| this.computeMD5(file); | |||
| }, | |||
| finishUpload(file) { | |||
| this.emitDropzoneSuccess(file); | |||
| setTimeout(() => { | |||
| window.location.reload(); | |||
| }, 1000); | |||
| }, | |||
| computeMD5(file) { | |||
| this.resetStatus(); | |||
| const blobSlice = | |||
| File.prototype.slice || | |||
| File.prototype.mozSlice || | |||
| File.prototype.webkitSlice, | |||
| chunkSize = 1024 * 1024 * 64, | |||
| chunks = Math.ceil(file.size / chunkSize), | |||
| spark = new SparkMD5.ArrayBuffer(), | |||
| fileReader = new FileReader(); | |||
| let currentChunk = 0; | |||
| const time = new Date().getTime(); | |||
| // console.log('计算MD5...') | |||
| this.status = this.dropzoneParams.data('md5-computing'); | |||
| file.totalChunkCounts = chunks; | |||
| loadNext(); | |||
| fileReader.onload = (e) => { | |||
| fileLoaded.call(this, e); | |||
| }; | |||
| fileReader.onerror = (err) => { | |||
| console.warn('oops, something went wrong.', err); | |||
| file.cancel(); | |||
| }; | |||
| function fileLoaded(e) { | |||
| spark.append(e.target.result); // Append array buffer | |||
| currentChunk++; | |||
| if (currentChunk < chunks) { | |||
| // console.log(`第${currentChunk}分片解析完成, 开始第${currentChunk +1}/${chunks}分片解析`); | |||
| this.status = `${this.dropzoneParams.data('loading-file')} ${( | |||
| (currentChunk / chunks) * | |||
| 100 | |||
| ).toFixed(2)}% (${currentChunk}/${chunks})`; | |||
| this.updateProgress(file, ((currentChunk / chunks) * 100).toFixed(2)); | |||
| loadNext(); | |||
| return; | |||
| } | |||
| const md5 = spark.end(); | |||
| console.log( | |||
| `MD5计算完成:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${ | |||
| file.size | |||
| } 用时:${(new Date().getTime() - time) / 1000} s` | |||
| ); | |||
| spark.destroy(); // 释放缓存 | |||
| file.uniqueIdentifier = md5; // 将文件md5赋值给文件唯一标识 | |||
| file.cmd5 = false; // 取消计算md5状态 | |||
| this.computeMD5Success(file); | |||
| } | |||
| function loadNext() { | |||
| const start = currentChunk * chunkSize; | |||
| const end = | |||
| start + chunkSize >= file.size ? file.size : start + chunkSize; | |||
| fileReader.readAsArrayBuffer(blobSlice.call(file, start, end)); | |||
| } | |||
| }, | |||
| async computeMD5Success(md5edFile) { | |||
| const file = await this.getSuccessChunks(md5edFile); | |||
| try { | |||
| if (file.uploadID == '' || file.uuid == '') { | |||
| // 未上传过 | |||
| await this.newMultiUpload(file); | |||
| if (file.uploadID != '' && file.uuid != '') { | |||
| file.chunks = ''; | |||
| this.multipartUpload(file); | |||
| } else { | |||
| // 失败如何处理 | |||
| return; | |||
| } | |||
| return; | |||
| } | |||
| if (file.uploaded == '1') { | |||
| // 已上传成功 | |||
| // 秒传 | |||
| if (file.attachID == '0') { | |||
| // 删除数据集记录,未删除文件 | |||
| await addAttachment(file); | |||
| } | |||
| //不同数据集上传同一个文件 | |||
| if (file.datasetID != '' ) { | |||
| if (file.datasetName != "" && file.realName != "") { | |||
| var info = "该文件已上传,对应数据集(" + file.datasetName + ")-文件(" + file.realName + ")"; | |||
| window.alert(info); | |||
| window.location.reload(); | |||
| } | |||
| } | |||
| console.log('文件已上传完成'); | |||
| this.progress = 100; | |||
| this.status = this.dropzoneParams.data('upload-complete'); | |||
| this.finishUpload(file); | |||
| } else { | |||
| // 断点续传 | |||
| this.multipartUpload(file); | |||
| } | |||
| } catch (error) { | |||
| this.emitDropzoneFailed(file); | |||
| console.log(error); | |||
| } | |||
| async function addAttachment(file) { | |||
| return await axios.post( | |||
| '/attachments/add', | |||
| qs.stringify({ | |||
| uuid: file.uuid, | |||
| file_name: file.name, | |||
| size: file.size, | |||
| dataset_id: file.datasetId, | |||
| type: CloudBrainType, | |||
| _csrf: csrf, | |||
| }) | |||
| ); | |||
| } | |||
| }, | |||
| async getSuccessChunks(file) { | |||
| const params = { | |||
| params: { | |||
| md5: file.uniqueIdentifier, | |||
| type: CloudBrainType, | |||
| file_name: file.name, | |||
| _csrf: csrf | |||
| } | |||
| }; | |||
| try { | |||
| const response = await axios.get('/attachments/get_chunks', params); | |||
| file.uploadID = response.data.uploadID; | |||
| file.uuid = response.data.uuid; | |||
| file.uploaded = response.data.uploaded; | |||
| file.chunks = response.data.chunks; | |||
| file.attachID = response.data.attachID; | |||
| file.datasetID = response.data.datasetID; | |||
| file.datasetName = response.data.datasetName; | |||
| file.realName = response.data.fileName; | |||
| return file; | |||
| } catch (error) { | |||
| this.emitDropzoneFailed(file); | |||
| console.log('getSuccessChunks catch: ', error); | |||
| return null; | |||
| } | |||
| }, | |||
| async newMultiUpload(file) { | |||
| const res = await axios.get('/attachments/new_multipart', { | |||
| params: { | |||
| totalChunkCounts: file.totalChunkCounts, | |||
| md5: file.uniqueIdentifier, | |||
| size: file.size, | |||
| fileType: file.type, | |||
| type: CloudBrainType, | |||
| file_name: file.name, | |||
| _csrf: csrf | |||
| } | |||
| }); | |||
| file.uploadID = res.data.uploadID; | |||
| file.uuid = res.data.uuid; | |||
| }, | |||
| multipartUpload(file) { | |||
| const blobSlice = | |||
| File.prototype.slice || | |||
| File.prototype.mozSlice || | |||
| File.prototype.webkitSlice, | |||
| chunkSize = 1024 * 1024 * 64, | |||
| chunks = Math.ceil(file.size / chunkSize), | |||
| fileReader = new FileReader(), | |||
| time = new Date().getTime(); | |||
| let currentChunk = 0; | |||
| function loadNext() { | |||
| const start = currentChunk * chunkSize; | |||
| const end = | |||
| start + chunkSize >= file.size ? file.size : start + chunkSize; | |||
| fileReader.readAsArrayBuffer(blobSlice.call(file, start, end)); | |||
| } | |||
| function checkSuccessChunks() { | |||
| const index = successChunks.indexOf((currentChunk + 1).toString()); | |||
| if (index == -1) { | |||
| return false; | |||
| } | |||
| return true; | |||
| } | |||
| async function getUploadChunkUrl(currentChunk, partSize) { | |||
| const res = await axios.get('/attachments/get_multipart_url', { | |||
| params: { | |||
| uuid: file.uuid, | |||
| uploadID: file.uploadID, | |||
| size: partSize, | |||
| chunkNumber: currentChunk + 1, | |||
| type: CloudBrainType, | |||
| file_name: file.name, | |||
| _csrf: csrf | |||
| } | |||
| }); | |||
| urls[currentChunk] = res.data.url; | |||
| } | |||
| async function uploadMinio(url, e) { | |||
| let urls = []; | |||
| const res = await axios.put(url, e.target.result, { | |||
| headers: { | |||
| 'Content-Type': '' | |||
| }}); | |||
| etags[currentChunk] = res.headers.etag; | |||
| } | |||
| async function uploadMinioNewMethod(url,e){ | |||
| var xhr = new XMLHttpRequest(); | |||
| xhr.open('PUT', url, false); | |||
| xhr.setRequestHeader('Content-Type', '') | |||
| xhr.send(e.target.result); | |||
| var etagValue = xhr.getResponseHeader('ETag'); | |||
| //console.log(etagValue); | |||
| etags[currentChunk] = etagValue; | |||
| } | |||
| async function updateChunk(currentChunk) { | |||
| await axios.post( | |||
| '/attachments/update_chunk', | |||
| qs.stringify({ | |||
| uuid: file.uuid, | |||
| chunkNumber: currentChunk + 1, | |||
| etag: etags[currentChunk], | |||
| type: CloudBrainType, | |||
| _csrf: csrf | |||
| }) | |||
| ); | |||
| } | |||
| async function uploadChunk(e) { | |||
| try { | |||
| if (!checkSuccessChunks()) { | |||
| const start = currentChunk * chunkSize; | |||
| const partSize = | |||
| start + chunkSize >= file.size ? file.size - start : chunkSize; | |||
| // 获取分片上传url | |||
| await getUploadChunkUrl(currentChunk, partSize); | |||
| if (urls[currentChunk] != '') { | |||
| // 上传到minio | |||
| await uploadMinioNewMethod(urls[currentChunk], e); | |||
| if (etags[currentChunk] != '') { | |||
| // 更新数据库:分片上传结果 | |||
| //await updateChunk(currentChunk); | |||
| } else { | |||
| console.log("上传到minio uploadChunk etags[currentChunk] == ''");// TODO | |||
| } | |||
| } else { | |||
| console.log("uploadChunk urls[currentChunk] != ''");// TODO | |||
| } | |||
| } | |||
| } catch (error) { | |||
| this.emitDropzoneFailed(file); | |||
| console.log(error); | |||
| } | |||
| } | |||
| async function completeUpload() { | |||
| return await axios.post( | |||
| '/attachments/complete_multipart', | |||
| qs.stringify({ | |||
| uuid: file.uuid, | |||
| uploadID: file.uploadID, | |||
| file_name: file.name, | |||
| size: file.size, | |||
| dataset_id: file.datasetId, | |||
| type: CloudBrainType, | |||
| _csrf: csrf | |||
| }) | |||
| ); | |||
| } | |||
| const successChunks = []; | |||
| let successParts = []; | |||
| successParts = file.chunks.split(','); | |||
| for (let i = 0; i < successParts.length; i++) { | |||
| successChunks[i] = successParts[i].split('-')[0]; | |||
| } | |||
| const urls = []; // TODO const ? | |||
| const etags = []; | |||
| console.log('上传分片...'); | |||
| this.status = this.dropzoneParams.data('uploading'); | |||
| loadNext(); | |||
| fileReader.onload = async (e) => { | |||
| await uploadChunk(e); | |||
| fileReader.abort(); | |||
| currentChunk++; | |||
| if (currentChunk < chunks) { | |||
| console.log( | |||
| `第${currentChunk}个分片上传完成, 开始第${currentChunk + | |||
| 1}/${chunks}个分片上传` | |||
| ); | |||
| this.progress = Math.ceil((currentChunk / chunks) * 100); | |||
| this.updateProgress(file, ((currentChunk / chunks) * 100).toFixed(2)); | |||
| this.status = `${this.dropzoneParams.data('uploading')} ${( | |||
| (currentChunk / chunks) * | |||
| 100 | |||
| ).toFixed(2)}%`; | |||
| await loadNext(); | |||
| } else { | |||
| await completeUpload(); | |||
| console.log( | |||
| `文件上传完成:${file.name} \n分片:${chunks} 大小:${ | |||
| file.size | |||
| } 用时:${(new Date().getTime() - time) / 1000} s` | |||
| ); | |||
| this.progress = 100; | |||
| this.status = this.dropzoneParams.data('upload-complete'); | |||
| this.finishUpload(file); | |||
| } | |||
| }; | |||
| } | |||
| } | |||
| }; | |||
| </script> | |||
| <style> | |||
| .dropzone-wrapper { | |||
| margin: 0; | |||
| } | |||
| .ui .dropzone { | |||
| border: 2px dashed #0087f5; | |||
| box-shadow: none !important; | |||
| padding: 0; | |||
| min-height: 5rem; | |||
| border-radius: 4px; | |||
| } | |||
| .dataset .dataset-files #dataset .dz-preview.dz-file-preview, | |||
| .dataset .dataset-files #dataset .dz-preview.dz-processing { | |||
| display: flex; | |||
| align-items: center; | |||
| } | |||
| .dataset .dataset-files #dataset .dz-preview { | |||
| border-bottom: 1px solid #dadce0; | |||
| min-height: 0; | |||
| } | |||
| .upload-info{ | |||
| margin-top: 0.2em; | |||
| } | |||
| </style> | |||
| @@ -62,6 +62,15 @@ | |||
| <a :href="AppSubUrl +'../../../'+ scope.row.Name">{{scope.row.Name}} </a> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="UserIndex" | |||
| label="用户指数" | |||
| width="120px" | |||
| align="center"> | |||
| <template slot-scope="scope"> | |||
| {{scope.row.UserIndex | rounding}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="CodeMergeCount" | |||
| label="PR数" | |||
| @@ -125,15 +134,6 @@ | |||
| label="创建项目" | |||
| align="center"> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="RegistDate" | |||
| label="用户注册时间" | |||
| width="120px" | |||
| align="center"> | |||
| <template slot-scope="scope"> | |||
| {{scope.row.RegistDate | transformTimestamp}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="CloudBrainTaskNum" | |||
| label="云脑任务数" | |||
| @@ -161,13 +161,13 @@ | |||
| width="120px" | |||
| align="center"> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="UserIndex" | |||
| label="用户指数" | |||
| <el-table-column | |||
| prop="RegistDate" | |||
| label="用户注册时间" | |||
| width="120px" | |||
| align="center"> | |||
| <template slot-scope="scope"> | |||
| {{scope.row.UserIndex | rounding}} | |||
| {{scope.row.RegistDate | transformTimestamp}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| @@ -0,0 +1,773 @@ | |||
| <template> | |||
| <div> | |||
| <div class="header-wrapper"> | |||
| <div class="ui container"> | |||
| <el-row class="image_text"> | |||
| <h1>云脑镜像</h1> | |||
| </el-row> | |||
| </div> | |||
| </div> | |||
| <div class="ui container" id="header"> | |||
| <el-tabs v-model="activeName" @tab-click="handleClick"> | |||
| <el-tab-pane label="公开镜像" name="first" v-loading="loadingPublic"> | |||
| <template v-if="tableDataPublic.length!==0"> | |||
| <el-row style="align-items: center;display: flex;"> | |||
| <el-col :span="12"> | |||
| <div> | |||
| <el-checkbox v-model="checked">仅显示平台推荐</el-checkbox> | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="4"><div style="visibility: hidden;">TODO</div></el-col> | |||
| <el-col :span="8"> | |||
| <div> | |||
| <el-input placeholder="搜镜像Tag/描述/标签..." v-model="search" class="input-with-select" @keyup.enter.native="searchName()"> | |||
| <el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button> | |||
| </el-input> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| <el-row style="margin-top:15px;"> | |||
| <el-table | |||
| :data="tableDataPublic" | |||
| style="width: 100%" | |||
| :header-cell-style="tableHeaderStyle" | |||
| > | |||
| <el-table-column | |||
| label="镜像Tag" | |||
| min-width="19%" | |||
| align="left" | |||
| prop="tag" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div style="display: flex;align-items: center;"> | |||
| <a class="text-over image_title" :title="scope.row.tag">{{ scope.row.tag }}</a> | |||
| <img v-if="scope.row.type==5" src="/img/jian.svg" style="margin-left: 0.5rem;"> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| label="镜像描述" | |||
| min-width="28%" | |||
| align="left" | |||
| prop="description" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div class="image_desc" :title="scope.row.description">{{ scope.row.description}}</div> | |||
| <div v-if="!!scope.row.topics"> | |||
| <span v-for="(topic,index) in scope.row.topics" class="ui repo-topic label topic" style="cursor: default;">{{topic}}</span> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="cloudbrainType" | |||
| label="可用集群" | |||
| min-width="10%" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| {{scope.row.cloudbrainType | transformType}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="creator" | |||
| label="创建者" | |||
| min-width="8%" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <a :href="'/' + scope.row.userName" :title="scope.row.userName"> | |||
| <img :src="scope.row.relAvatarLink" class="ui avatar image"> | |||
| </a> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="createdUnix" | |||
| label="创建时间" | |||
| align="center" | |||
| min-width="14%" | |||
| > | |||
| <template slot-scope="scope"> | |||
| {{scope.row.createdUnix | transformTimestamp}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| align="center" | |||
| min-width="21%" | |||
| label="操作" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div style="display: flex;justify-content: flex-end;align-items: center;"> | |||
| <div style="display: flex;align-items: center;cursor:pointer;padding: 0 1rem;" @click="imageStar(scope.$index,scope.row.id,scope.row.isStar)"> | |||
| <svg width="1.4em" height="1.4em" viewBox="0 0 32 32" class="heart-stroke" :class='{stars_active:scope.row.isStar}'><path d="M4.4 6.54c-1.761 1.643-2.6 3.793-2.36 6.056.24 2.263 1.507 4.521 3.663 6.534a29110.9 29110.9 0 0010.296 9.633l10.297-9.633c2.157-2.013 3.424-4.273 3.664-6.536.24-2.264-.599-4.412-2.36-6.056-1.73-1.613-3.84-2.29-6.097-1.955-1.689.25-3.454 1.078-5.105 2.394l-.4.319-.398-.319c-1.649-1.316-3.414-2.143-5.105-2.394a7.612 7.612 0 00-1.113-.081c-1.838 0-3.541.694-4.983 2.038z"></path></svg> | |||
| <span style="line-height: 2;margin-left:0.3rem;">{{scope.row.numStars}}</span> | |||
| </div> | |||
| <span style="padding: 0 1rem;color:#0366d6;cursor:pointer;" @click="copyUrl(scope.row.place)">复制地址</span> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| </el-row> | |||
| <div class="ui container" style="margin-top:50px;text-align:center"> | |||
| <el-pagination | |||
| background | |||
| @size-change="handleSizeChangePublic" | |||
| @current-change="handleCurrentChangePublic" | |||
| :current-page="currentPagePublic" | |||
| :page-size="pageSizePublic" | |||
| :page-sizes="[5,10,15]" | |||
| layout="total, sizes, prev, pager, next, jumper" | |||
| :total="totalNumPublic"> | |||
| </el-pagination> | |||
| </div> | |||
| </template> | |||
| <template v-else> | |||
| <el-row style="align-items: center;display: flex;"> | |||
| <el-col :span="12"> | |||
| <div> | |||
| <el-checkbox v-model="checked">仅显示平台推荐</el-checkbox> | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="4"><div style="visibility: hidden;">TODO</div></el-col> | |||
| <el-col :span="8"> | |||
| <div> | |||
| <el-input placeholder="搜镜像Tag/描述/标签..." v-model="search" class="input-with-select" @keyup.enter.native="searchName()"> | |||
| <el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button> | |||
| </el-input> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| <el-empty :image-size="200"></el-empty> | |||
| </template> | |||
| </el-tab-pane> | |||
| <el-tab-pane label="我的镜像" name="second" v-loading="loadingCustom"> | |||
| <template v-if="tableDataCustom.length!==0"> | |||
| <el-row style="align-items: center;display: flex;"> | |||
| <el-col :span="12"> | |||
| <div style="visibility: hidden;"> | |||
| TODO | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="4"><div style="visibility: hidden;">TODO</div></el-col> | |||
| <el-col :span="8"> | |||
| <div> | |||
| <el-input placeholder="搜镜像Tag/描述/标签..." v-model="search" class="input-with-select" @keyup.enter.native="searchName()"> | |||
| <el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button> | |||
| </el-input> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| <el-row style="margin-top:15px;"> | |||
| <el-table | |||
| :data="tableDataCustom" | |||
| style="width: 100%" | |||
| :header-cell-style="tableHeaderStyle" | |||
| > | |||
| <el-table-column | |||
| label="镜像Tag" | |||
| min-width="19%" | |||
| align="left" | |||
| prop="tag" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div style="display: flex;align-items: center;"> | |||
| <a class="text-over image_title" :title="scope.row.tag">{{ scope.row.tag }}</a> | |||
| <i class="ri-lock-2-line" style="color: #fa8c16;" v-if="scope.row.isPrivate"></i> | |||
| <img v-if="scope.row.type==5" src="/img/jian.svg" style="margin-left: 0.5rem;"> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| label="镜像描述" | |||
| min-width="27%" | |||
| align="left" | |||
| prop="description" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div class="image_desc" :title="scope.row.description">{{ scope.row.description}}</div> | |||
| <div v-if="!!scope.row.topics"> | |||
| <span v-for="(topic,index) in scope.row.topics" class="ui repo-topic label topic" style="cursor: default;">{{topic}}</span> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="cloudbrainType" | |||
| label="可用集群" | |||
| min-width="9%" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| {{scope.row.cloudbrainType | transformType}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="isPrivate" | |||
| label="状态" | |||
| min-width="10%" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div style="display:flex;align-items: center;justify-content: center;"> | |||
| <span v-if="scope.row.isPrivate" style="color: rgb(250, 140, 22);">私有</span> | |||
| <span v-else style="color: rgb(19, 194, 141);">公开</span> | |||
| <el-tooltip class="item" effect="dark" content="镜像提交中..." placement="top"> | |||
| <i v-if="scope.row.status===0" class="CREATING" style="margin-left:0.3rem"></i> | |||
| </el-tooltip> | |||
| <el-tooltip class="item" effect="dark" content="检测提交镜像是否大小超过20G!" placement="top"> | |||
| <i v-if="scope.row.status===2" class="FAILED" style="margin-left:0.3rem"></i> | |||
| </el-tooltip> | |||
| <el-tooltip class="item" effect="dark" content="镜像提交成功" placement="top"> | |||
| <i v-if="scope.row.status===1" class="SUCCEEDED" style="margin-left:0.3rem"></i> | |||
| </el-tooltip> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="createdUnix" | |||
| label="创建时间" | |||
| align="center" | |||
| min-width="14%" | |||
| > | |||
| <template slot-scope="scope"> | |||
| {{scope.row.createdUnix | transformTimestamp}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| align="center" | |||
| min-width="21%" | |||
| label="操作" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div style="display: flex;justify-content: flex-end;align-items: center;"> | |||
| <div style="display: flex;align-items: center;cursor: default;;padding: 0 1rem;"> | |||
| <svg width="1.4em" height="1.4em" viewBox="0 0 32 32" class="heart-stroke"><path d="M4.4 6.54c-1.761 1.643-2.6 3.793-2.36 6.056.24 2.263 1.507 4.521 3.663 6.534a29110.9 29110.9 0 0010.296 9.633l10.297-9.633c2.157-2.013 3.424-4.273 3.664-6.536.24-2.264-.599-4.412-2.36-6.056-1.73-1.613-3.84-2.29-6.097-1.955-1.689.25-3.454 1.078-5.105 2.394l-.4.319-.398-.319c-1.649-1.316-3.414-2.143-5.105-2.394a7.612 7.612 0 00-1.113-.081c-1.838 0-3.541.694-4.983 2.038z"></path></svg> | |||
| <span style="line-height: 2;margin-left:0.3rem;">{{scope.row.numStars}}</span> | |||
| </div> | |||
| <span style="padding: 0 1rem;color:#0366d6;cursor:pointer;" @click="copyUrl(scope.row.place)">复制地址</span> | |||
| <div style="padding-left:1rem;cursor:pointer;"> | |||
| <el-dropdown size="medium"> | |||
| <span class="el-dropdown-link"> | |||
| 更多<i class="el-icon-arrow-down el-icon--right"></i> | |||
| </span> | |||
| <el-dropdown-menu slot="dropdown"> | |||
| <el-dropdown-item @click.native="eidtImage(scope.row.id)">编辑</el-dropdown-item> | |||
| <el-dropdown-item style="color: red;" @click.native="deleteImage(scope.row.id)">删除</el-dropdown-item> | |||
| </el-dropdown-menu> | |||
| </el-dropdown> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| </el-row> | |||
| <div class="ui container" style="margin-top:50px;text-align:center"> | |||
| <el-pagination | |||
| background | |||
| @size-change="handleSizeChangeCustom" | |||
| @current-change="handleCurrentChangeCustom" | |||
| :current-page="currentPageCustom" | |||
| :page-size="pageSizeCustom" | |||
| :page-sizes="[5,10,15]" | |||
| layout="total, sizes, prev, pager, next, jumper" | |||
| :total="totalNumCustom"> | |||
| </el-pagination> | |||
| </div> | |||
| </template> | |||
| <template v-else> | |||
| <el-row style="align-items: center;display: flex;"> | |||
| <el-col :span="12"> | |||
| <div style="visibility: hidden;"> | |||
| TODO | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="4"><div style="visibility: hidden;">TODO</div></el-col> | |||
| <el-col :span="8"> | |||
| <div> | |||
| <el-input placeholder="搜镜像Tag/描述/标签..." v-model="search" class="input-with-select" @keyup.enter.native="searchName()"> | |||
| <el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button> | |||
| </el-input> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| <el-empty :image-size="200"></el-empty> | |||
| </template> | |||
| </el-tab-pane> | |||
| <el-tab-pane label="我收藏的镜像" name="third"> | |||
| <template v-if="tableDataStar.length!==0"> | |||
| <el-row style="align-items: center;display: flex;"> | |||
| <el-col :span="12"> | |||
| <div style="visibility: hidden;"> | |||
| TODO | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="4"><div style="visibility: hidden;">TODO</div></el-col> | |||
| <el-col :span="8"> | |||
| <div> | |||
| <el-input placeholder="搜镜像Tag/描述/标签..." v-model="search" class="input-with-select" @keyup.enter.native="searchName()"> | |||
| <el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button> | |||
| </el-input> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| <el-row style="margin-top:15px;"> | |||
| <el-table | |||
| :data="tableDataStar" | |||
| style="width: 100%" | |||
| :header-cell-style="tableHeaderStyle" | |||
| > | |||
| <el-table-column | |||
| label="镜像Tag" | |||
| min-width="19%" | |||
| align="left" | |||
| prop="tag" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div style="display: flex;align-items: center;"> | |||
| <a class="text-over image_title" :title="scope.row.tag">{{ scope.row.tag }}</a> | |||
| <img v-if="scope.row.type==5" src="/img/jian.svg" style="margin-left: 0.5rem;"> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| label="镜像描述" | |||
| min-width="28%" | |||
| align="left" | |||
| prop="description" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div class="image_desc" :title="scope.row.description">{{ scope.row.description}}</div> | |||
| <div v-if="!!scope.row.topics"> | |||
| <span v-for="(topic,index) in scope.row.topics" class="ui repo-topic label topic" style="cursor: default;">{{topic}}</span> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="cloudbrainType" | |||
| label="可用集群" | |||
| min-width="10%" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| {{scope.row.cloudbrainType | transformType}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="creator" | |||
| label="创建者" | |||
| min-width="8%" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <a :href="'/' + scope.row.userName" :title="scope.row.userName"> | |||
| <img :src="scope.row.relAvatarLink" class="ui avatar image"> | |||
| </a> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="createdUnix" | |||
| label="创建时间" | |||
| align="center" | |||
| min-width="14%" | |||
| > | |||
| <template slot-scope="scope"> | |||
| {{scope.row.createdUnix | transformTimestamp}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| align="center" | |||
| min-width="21%" | |||
| label="操作" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div style="display: flex;justify-content: flex-end;align-items: center;"> | |||
| <div style="display: flex;align-items: center;cursor:pointer;padding: 0 1rem;" @click="imageUnstar(scope.row.id)"> | |||
| <svg width="1.4em" height="1.4em" viewBox="0 0 32 32" class="heart-stroke stars_active"><path d="M4.4 6.54c-1.761 1.643-2.6 3.793-2.36 6.056.24 2.263 1.507 4.521 3.663 6.534a29110.9 29110.9 0 0010.296 9.633l10.297-9.633c2.157-2.013 3.424-4.273 3.664-6.536.24-2.264-.599-4.412-2.36-6.056-1.73-1.613-3.84-2.29-6.097-1.955-1.689.25-3.454 1.078-5.105 2.394l-.4.319-.398-.319c-1.649-1.316-3.414-2.143-5.105-2.394a7.612 7.612 0 00-1.113-.081c-1.838 0-3.541.694-4.983 2.038z"></path></svg> | |||
| <span style="line-height: 2;margin-left:0.3rem;">{{scope.row.numStars}}</span> | |||
| </div> | |||
| <span style="padding: 0 1rem;color:#0366d6;cursor:pointer;" @click="copyUrl(scope.row.place)">复制地址</span> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| </el-row> | |||
| <div class="ui container" style="margin-top:50px;text-align:center"> | |||
| <el-pagination | |||
| background | |||
| @size-change="handleSizeChangeStar" | |||
| @current-change="handleCurrentChangeStar" | |||
| :current-page="currentPageStar" | |||
| :page-size="pageSizeStar" | |||
| :page-sizes="[5,10,15]" | |||
| layout="total, sizes, prev, pager, next, jumper" | |||
| :total="totalNumStar"> | |||
| </el-pagination> | |||
| </div> | |||
| </template> | |||
| <template v-else> | |||
| <el-row style="align-items: center;display: flex;"> | |||
| <el-col :span="12"> | |||
| <div style="visibility: hidden;"> | |||
| TODO | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="4"><div style="visibility: hidden;">TODO</div></el-col> | |||
| <el-col :span="8"> | |||
| <div> | |||
| <el-input placeholder="搜镜像Tag/描述/标签..." v-model="search" class="input-with-select" @keyup.enter.native="searchName()"> | |||
| <el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button> | |||
| </el-input> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| <el-empty :image-size="200"></el-empty> | |||
| </template> | |||
| </el-tab-pane> | |||
| </el-tabs> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; | |||
| export default { | |||
| components: { | |||
| }, | |||
| data() { | |||
| return { | |||
| activeName: 'first', | |||
| search:'', | |||
| checked:false, | |||
| currentPagePublic:1, | |||
| pageSizePublic:10, | |||
| totalNumPublic:0, | |||
| paramsPublic:{page:1,pageSize:10,q:'',recommend:false}, | |||
| tableDataPublic: [], | |||
| loadingPublic:false, | |||
| currentPageCustom:1, | |||
| pageSizeCustom:10, | |||
| totalNumCustom:0, | |||
| paramsCustom:{page:1,pageSize:10,q:''}, | |||
| tableDataCustom: [], | |||
| starCustom:[], | |||
| loadingCustom:false, | |||
| currentPageStar:1, | |||
| pageSizeStar:10, | |||
| totalNumStar:0, | |||
| paramsStar:{page:1,pageSize:10,q:''}, | |||
| tableDataStar: [], | |||
| loadingStar:false | |||
| }; | |||
| }, | |||
| methods: { | |||
| handleClick(tab, event) { | |||
| this.search = '' | |||
| if(tab.name=="first"){ | |||
| this.paramsPublic.q = '' | |||
| this.getImageListPublic() | |||
| } | |||
| if(tab.name=="second"){ | |||
| this.getImageListCustom() | |||
| } | |||
| if(tab.name=="third"){ | |||
| this.getImageListStar() | |||
| } | |||
| }, | |||
| tableHeaderStyle({row,column,rowIndex,columnIndex}){ | |||
| if(rowIndex===0){ | |||
| return 'background:#f5f5f6;color:#606266' | |||
| } | |||
| }, | |||
| handleSizeChangePublic(val){ | |||
| this.paramsPublic.pageSize = val | |||
| this.getImageListPublic() | |||
| }, | |||
| handleCurrentChangePublic(val){ | |||
| this.paramsPublic.page = val | |||
| this.getImageListPublic() | |||
| }, | |||
| handleSizeChangeCustom(val){ | |||
| this.paramsCustom.pageSize = val | |||
| this.getImageListCustom() | |||
| }, | |||
| handleCurrentChangeCustom(val){ | |||
| this.paramsCustom.page = val | |||
| this.getImageListCustom() | |||
| }, | |||
| handleSizeChangeStar(val){ | |||
| this.paramsStar.pageSize = val | |||
| this.getImageListStar() | |||
| }, | |||
| handleCurrentChangeStar(val){ | |||
| this.paramsStar.page = val | |||
| this.getImageListStar() | |||
| }, | |||
| getImageListPublic(){ | |||
| this.loadingPublic = true | |||
| this.$axios.get('/explore/images/public',{ | |||
| params:this.paramsPublic | |||
| }).then((res)=>{ | |||
| this.totalNumPublic = res.data.count | |||
| this.tableDataPublic = res.data.images | |||
| this.loadingPublic = false | |||
| }) | |||
| }, | |||
| getImageListCustom(){ | |||
| this.loadingCustom = true | |||
| this.$axios.get('/explore/images/custom',{ | |||
| params:this.paramsCustom | |||
| }).then((res)=>{ | |||
| this.totalNumCustom = res.data.count | |||
| this.tableDataCustom = res.data.images | |||
| this.tableDataCustom.forEach(element => { | |||
| this.starCustom.push({id:element.id,}) | |||
| }); | |||
| this.loadingCustom = false | |||
| }) | |||
| }, | |||
| getImageListStar(){ | |||
| this.loadingStar = true | |||
| this.$axios.get('/explore/images/star',{ | |||
| params:this.paramsStar | |||
| }).then((res)=>{ | |||
| this.totalNumStar = res.data.count | |||
| this.tableDataStar = res.data.images | |||
| this.loadingStar = false | |||
| }) | |||
| }, | |||
| deleteImage(id){ | |||
| let flag=1 | |||
| let _this = this | |||
| $('.ui.basic.modal.images') | |||
| .modal({ | |||
| onDeny: function() { | |||
| flag = false | |||
| }, | |||
| onApprove: function() { | |||
| _this.$axios.delete('/image/'+id).then((res)=>{ | |||
| _this.getImageListCustom() | |||
| }) | |||
| flag = true | |||
| }, | |||
| onHidden: function() { | |||
| if (flag == false) { | |||
| $('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut(); | |||
| }else{ | |||
| $('.alert').html('删除成功').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut(); | |||
| } | |||
| } | |||
| }) | |||
| .modal('show') | |||
| }, | |||
| eidtImage(id){ | |||
| location.href = `/image/${id}/imageSquare` | |||
| }, | |||
| imageStar(index,id,isStar){ | |||
| if(isStar){ | |||
| this.$axios.put(`/image/${id}/action/unstar`).then((res)=>{ | |||
| if(res.data.Code==0){ | |||
| this.tableDataPublic[index].numStars = this.tableDataPublic[index].numStars - 1 | |||
| this.tableDataPublic[index].isStar = false | |||
| }else{ | |||
| console.log(res.data.Message) | |||
| } | |||
| }) | |||
| }else{ | |||
| this.$axios.put(`/image/${id}/action/star`).then((res)=>{ | |||
| if(res.data.Code==0){ | |||
| this.tableDataPublic[index].numStars = this.tableDataPublic[index].numStars + 1 | |||
| this.tableDataPublic[index].isStar = true | |||
| }else{ | |||
| console.log(res.data.Message) | |||
| } | |||
| }) | |||
| } | |||
| }, | |||
| imageUnstar(id){ | |||
| this.$axios.put(`/image/${id}/action/unstar`).then((res)=>{ | |||
| if(res.data.Code==0){ | |||
| this.getImageListStar() | |||
| }else{ | |||
| console.log(res.data.Message) | |||
| } | |||
| }) | |||
| }, | |||
| copyUrl(url){ | |||
| const cInput = document.createElement('input') | |||
| cInput.value = url | |||
| document.body.appendChild(cInput) | |||
| cInput.select() | |||
| document.execCommand('Copy') | |||
| cInput.remove() | |||
| }, | |||
| searchName(){ | |||
| if(this.activeName=='first'){ | |||
| this.paramsPublic.q = this.search | |||
| this.paramsPublic.page = 1 | |||
| this.getImageListPublic() | |||
| } | |||
| if(this.activeName=='second'){ | |||
| this.paramsCustom.q = this.search | |||
| this.paramsCustom.page = 1 | |||
| this.getImageListCustom() | |||
| } | |||
| if(this.activeName=='third'){ | |||
| this.paramsStar.q = this.search | |||
| this.paramsStar.page = 1 | |||
| this.getImageListStar() | |||
| } | |||
| }, | |||
| }, | |||
| filters:{ | |||
| transformType(val){ | |||
| if(val==0){ | |||
| return "GPU" | |||
| } | |||
| }, | |||
| transformPravite(val){ | |||
| if(val){ | |||
| return "私有" | |||
| }else{ | |||
| return "公开" | |||
| } | |||
| }, | |||
| transformTimestamp(timestamp){ | |||
| const date = new Date(parseInt(timestamp) * 1000); | |||
| const Y = date.getFullYear() + '-'; | |||
| const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'; | |||
| const D = (date.getDate() < 10 ? '0'+date.getDate() : date.getDate()) + ' '; | |||
| const h = (date.getHours() < 10 ? '0'+date.getHours() : date.getHours()) + ':'; | |||
| const m = (date.getMinutes() <10 ? '0'+date.getMinutes() : date.getMinutes()) + ':' ; | |||
| const s = (date.getSeconds() <10 ? '0'+date.getSeconds() : date.getSeconds()) ; // 秒 | |||
| const dateString = Y + M + D + h + m + s; | |||
| return dateString; | |||
| }, | |||
| }, | |||
| watch:{ | |||
| checked(val){ | |||
| this.paramsPublic.page = 1 | |||
| this.paramsPublic.recommend = val | |||
| this.getImageListPublic() | |||
| } | |||
| }, | |||
| mounted() { | |||
| }, | |||
| created() { | |||
| const params = new URLSearchParams(location.search) | |||
| if(params.has('type')&¶ms.get('type')=='myimage'){ | |||
| this.activeName = 'second' | |||
| this.getImageListCustom() | |||
| } | |||
| else{ | |||
| this.getImageListPublic() | |||
| } | |||
| } | |||
| }; | |||
| </script> | |||
| <style scoped> | |||
| .header-wrapper { | |||
| background-color: #f5f5f6; | |||
| padding-top: 15px; | |||
| } | |||
| .image_text{ | |||
| padding:25px 0 55px 0 ; | |||
| } | |||
| #header{ | |||
| position: relative; | |||
| top:-40px; | |||
| } | |||
| .el-dropdown-menu__item--divided{ | |||
| border-top: 1px solid blue; | |||
| } | |||
| .el-table thead{ | |||
| background-color: #f5f5f6; | |||
| } | |||
| /deep/ .el-tabs__item:hover{ | |||
| color: #000; | |||
| font-weight: 500; | |||
| } | |||
| /deep/ .el-tabs__item.is-active { | |||
| color: #000; | |||
| font-weight: 500; | |||
| } | |||
| /deep/ .el-tabs__active-bar{ | |||
| background-color:#000 | |||
| } | |||
| #success{ | |||
| background-color: #5bb973; | |||
| color: white; | |||
| } | |||
| .text-over{ | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| vertical-align: middle; | |||
| white-space: nowrap; | |||
| } | |||
| .image_title{ | |||
| display: inline-block; | |||
| cursor: default; | |||
| color: rgb(66, 98, 144); | |||
| } | |||
| .image_desc{ | |||
| -webkit-line-clamp: 2; | |||
| -webkit-box-orient: vertical; | |||
| display: -webkit-box; | |||
| text-overflow: ellipsis; | |||
| overflow: hidden; | |||
| } | |||
| .heart-stroke{ | |||
| stroke: #FA8C16; | |||
| stroke-width: 2; | |||
| fill: #fff | |||
| } | |||
| .stars_active{ | |||
| fill: #FA8C16 !important; | |||
| stroke:#FA8C16 !important | |||
| } | |||
| </style> | |||
| @@ -0,0 +1,399 @@ | |||
| <template> | |||
| <div > | |||
| <div class="ui container" style="width: 80%;"> | |||
| <div class="ui grid"> | |||
| <div class="row" style="border: 1px solid #d4d4d5;margin-top: 15px;padding-top: 0;"> | |||
| <div class="ui attached segment"> | |||
| <div class="ui form ignore-dirty"> | |||
| <div class="ui fluid action input"> | |||
| <input type="text" placeholder="搜镜像Tag/描述/标签..." v-model="search" @keyup.enter="searchName()"> | |||
| <button class="ui blue button" @click="searchName()">搜索</button> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="ui ten wide column" style="margin: 1rem 0;"> | |||
| <el-checkbox v-model="checked" style="padding: 0.5rem 1rem;">仅显示平台推荐</el-checkbox> | |||
| <el-dropdown @command="handleCommand" trigger="click" style="border: 1px solid rgba(34,36,38,.15);border-radius: 4px;padding: 0.5rem 1rem;"> | |||
| <span class="el-dropdown-link"> | |||
| {{dropdownPrivate}}<i class="el-icon-caret-bottom el-icon--right"></i> | |||
| </span> | |||
| <el-dropdown-menu slot="dropdown"> | |||
| <el-dropdown-item :command="{label:'全部',private:''}">全部</el-dropdown-item> | |||
| <el-dropdown-item :command="{label:'公开',private:false}">公开</el-dropdown-item> | |||
| <el-dropdown-item :command="{label:'公开',private:true}">私有</el-dropdown-item> | |||
| </el-dropdown-menu> | |||
| </el-dropdown> | |||
| </div> | |||
| <div class="ui six wide column right aligned" style="margin: 1rem 0;"> | |||
| <a class="ui blue small button" href="/admin/images/commit_image?from=imageAdmin">创建云脑镜像</a> | |||
| </div> | |||
| <div class="ui sixteen wide column" style="padding: 0;"> | |||
| <el-table | |||
| :data="tableDataCustom" | |||
| style="width: 100%" | |||
| :header-cell-style="tableHeaderStyle" | |||
| > | |||
| <el-table-column | |||
| label="镜像Tag" | |||
| min-width="19%" | |||
| align="left" | |||
| prop="tag" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div style="display: flex;align-items: center;"> | |||
| <a class="text-over image_title" :title="scope.row.tag">{{ scope.row.tag }}</a> | |||
| <i class="ri-lock-2-line" style="color: #fa8c16;padding: 0 1rem;" v-if="scope.row.isPrivate"></i> | |||
| <img v-if="scope.row.type==5" src="/img/jian.svg" style="margin-left: 0.5rem;"> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| label="镜像描述" | |||
| min-width="28%" | |||
| align="left" | |||
| prop="description" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div class="image_desc" :title="scope.row.description">{{ scope.row.description}}</div> | |||
| <div v-if="!!scope.row.topics"> | |||
| <span v-for="(topic,index) in scope.row.topics" class="ui repo-topic label topic" style="cursor: default;">{{topic}}</span> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="cloudbrainType" | |||
| label="可用集群" | |||
| min-width="10%" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| {{scope.row.cloudbrainType | transformType}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="isPrivate" | |||
| label="状态" | |||
| min-width="8%" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <span v-if="scope.row.isPrivate" style="color: rgb(250, 140, 22);">私有</span> | |||
| <span v-else style="color: rgb(19, 194, 141);">公开</span> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="creator" | |||
| label="创建者" | |||
| min-width="7%" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <a :href="'/' + scope.row.userName" :title="scope.row.userName"> | |||
| <img :src="scope.row.relAvatarLink" class="ui avatar image"> | |||
| </a> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="createdUnix" | |||
| label="创建时间" | |||
| align="center" | |||
| min-width="13%" | |||
| > | |||
| <template slot-scope="scope"> | |||
| {{scope.row.createdUnix | transformTimestamp}} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| align="center" | |||
| min-width="23%" | |||
| label="操作" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <div style="display: flex;justify-content: flex-end;align-items: center;"> | |||
| <div style="display: flex;align-items: center;cursor: default;;padding: 0 1rem;"> | |||
| <svg width="1.4em" height="1.4em" viewBox="0 0 32 32" class="heart-stroke"><path d="M4.4 6.54c-1.761 1.643-2.6 3.793-2.36 6.056.24 2.263 1.507 4.521 3.663 6.534a29110.9 29110.9 0 0010.296 9.633l10.297-9.633c2.157-2.013 3.424-4.273 3.664-6.536.24-2.264-.599-4.412-2.36-6.056-1.73-1.613-3.84-2.29-6.097-1.955-1.689.25-3.454 1.078-5.105 2.394l-.4.319-.398-.319c-1.649-1.316-3.414-2.143-5.105-2.394a7.612 7.612 0 00-1.113-.081c-1.838 0-3.541.694-4.983 2.038z"></path></svg> | |||
| <span style="line-height: 2;margin-left:0.3rem;">{{scope.row.numStars}}</span> | |||
| </div> | |||
| <template v-if="!scope.row.isPrivate"> | |||
| <span style="padding: 0 1rem;color: rgb(250, 140, 22);cursor:pointer;" v-if="scope.row.type==5" @click="unSetRecommend(scope.$index,scope.row.id)">取消推荐</span> | |||
| <span style="padding: 0 1rem;color: rgb(19, 194, 141);cursor:pointer;" v-else @click="setRecommend(scope.$index,scope.row.id)">设为推荐</span> | |||
| </template> | |||
| <span style="padding: 0 1rem;color:#0366d6;cursor:pointer;" @click="copyUrl(scope.row.place)">复制地址</span> | |||
| <div style="padding-left:1rem;cursor:pointer;"> | |||
| <el-dropdown size="medium"> | |||
| <span class="el-dropdown-link"> | |||
| 更多<i class="el-icon-arrow-down el-icon--right"></i> | |||
| </span> | |||
| <el-dropdown-menu slot="dropdown"> | |||
| <el-dropdown-item @click.native="eidtImage(scope.row.id)">编辑</el-dropdown-item> | |||
| <el-dropdown-item style="color: red;" @click.native="deleteImage(scope.row.id)">删除</el-dropdown-item> | |||
| </el-dropdown-menu> | |||
| </el-dropdown> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| </div> | |||
| <div class="ui container" style="padding:2rem 0;text-align:center"> | |||
| <el-pagination | |||
| background | |||
| @size-change="handleSizeChangeCustom" | |||
| @current-change="handleCurrentChangeCustom" | |||
| :current-page="currentPageCustom" | |||
| :page-size="pageSizeCustom" | |||
| :page-sizes="[5,15,20]" | |||
| layout="total, sizes, prev, pager, next, jumper" | |||
| :total="totalNumCustom"> | |||
| </el-pagination> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; | |||
| export default { | |||
| components: { | |||
| }, | |||
| data() { | |||
| return { | |||
| search:'', | |||
| dropdownPrivate:'全部', | |||
| checked:false, | |||
| currentPageCustom:1, | |||
| pageSizeCustom:15, | |||
| totalNumCustom:0, | |||
| paramsCustom:{page:1,pageSize:15,q:'',recommend:false}, | |||
| tableDataCustom: [], | |||
| starCustom:[], | |||
| loadingCustom:false, | |||
| }; | |||
| }, | |||
| methods: { | |||
| tableHeaderStyle({row,column,rowIndex,columnIndex}){ | |||
| if(rowIndex===0){ | |||
| return 'background:#f5f5f6;color:#606266' | |||
| } | |||
| }, | |||
| handleSizeChangeCustom(val){ | |||
| this.paramsCustom.pageSize = val | |||
| this.getImageListCustom() | |||
| }, | |||
| handleCurrentChangeCustom(val){ | |||
| this.paramsCustom.page = val | |||
| this.getImageListCustom() | |||
| }, | |||
| getImageListCustom(){ | |||
| this.loadingCustom = true | |||
| this.$axios.get('/admin/images/data',{ | |||
| params:this.paramsCustom | |||
| }).then((res)=>{ | |||
| this.totalNumCustom = res.data.count | |||
| this.tableDataCustom = res.data.images | |||
| this.tableDataCustom.forEach(element => { | |||
| this.starCustom.push({id:element.id,}) | |||
| }); | |||
| this.loadingCustom = false | |||
| }) | |||
| }, | |||
| deleteImage(id){ | |||
| let flag=1 | |||
| let _this = this | |||
| $('.ui.basic.modal.images') | |||
| .modal({ | |||
| onDeny: function() { | |||
| flag = false | |||
| }, | |||
| onApprove: function() { | |||
| _this.$axios.delete('/image/'+id).then((res)=>{ | |||
| _this.getImageListCustom() | |||
| }) | |||
| flag = true | |||
| }, | |||
| onHidden: function() { | |||
| if (flag == false) { | |||
| $('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut(); | |||
| }else{ | |||
| $('.alert').html('删除成功').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut(); | |||
| } | |||
| } | |||
| }) | |||
| .modal('show') | |||
| }, | |||
| eidtImage(id){ | |||
| location.href = `/image/${id}/imageAdmin` | |||
| }, | |||
| imageStar(index,id,isStar){ | |||
| if(isStar){ | |||
| this.$axios.put(`/image/${id}/action/unstar`).then((res)=>{ | |||
| this.tableDataPublic[index].numStars = this.tableDataPublic[index].numStars - 1 | |||
| this.tableDataPublic[index].isStar = false | |||
| }) | |||
| }else{ | |||
| this.$axios.put(`/image/${id}/action/star`).then((res)=>{ | |||
| this.tableDataPublic[index].numStars = this.tableDataPublic[index].numStars + 1 | |||
| this.tableDataPublic[index].isStar = true | |||
| }) | |||
| } | |||
| }, | |||
| copyUrl(url){ | |||
| const cInput = document.createElement('input') | |||
| cInput.value = url | |||
| document.body.appendChild(cInput) | |||
| cInput.select() | |||
| document.execCommand('Copy') | |||
| cInput.remove() | |||
| }, | |||
| searchName(){ | |||
| this.paramsCustom.q = this.search | |||
| this.paramsCustom.page = 1 | |||
| this.getImageListCustom() | |||
| }, | |||
| setRecommend(index,id){ | |||
| this.$axios.put(`/admin/image/${id}/action/recommend`).then((res)=>{ | |||
| this.tableDataCustom[index].type = 5 | |||
| }) | |||
| }, | |||
| unSetRecommend(index,id){ | |||
| this.$axios.put(`/admin/image/${id}/action/unrecommend`).then((res)=>{ | |||
| this.tableDataCustom[index].type = 0 | |||
| }) | |||
| }, | |||
| handleCommand(command){ | |||
| this.dropdownPrivate = command.label | |||
| this.paramsCustom.private = command.private | |||
| this.getImageListCustom() | |||
| } | |||
| }, | |||
| filters:{ | |||
| transformType(val){ | |||
| if(val==0){ | |||
| return "GPU" | |||
| } | |||
| }, | |||
| transformPravite(val){ | |||
| if(val){ | |||
| return "私有" | |||
| }else{ | |||
| return "公开" | |||
| } | |||
| }, | |||
| transformTimestamp(timestamp){ | |||
| const date = new Date(parseInt(timestamp) * 1000); | |||
| const Y = date.getFullYear() + '-'; | |||
| const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'; | |||
| const D = (date.getDate() < 10 ? '0'+date.getDate() : date.getDate()) + ' '; | |||
| const h = (date.getHours() < 10 ? '0'+date.getHours() : date.getHours()) + ':'; | |||
| const m = (date.getMinutes() <10 ? '0'+date.getMinutes() : date.getMinutes()) + ':' ; | |||
| const s = (date.getSeconds() <10 ? '0'+date.getSeconds() : date.getSeconds()) ; // 秒 | |||
| const dateString = Y + M + D + h + m + s; | |||
| return dateString; | |||
| }, | |||
| }, | |||
| watch:{ | |||
| checked(val){ | |||
| this.paramsCustom.page = 1 | |||
| this.paramsCustom.recommend = val | |||
| this.getImageListCustom() | |||
| } | |||
| }, | |||
| mounted() { | |||
| this.getImageListCustom() | |||
| }, | |||
| created() { | |||
| } | |||
| }; | |||
| </script> | |||
| <style scoped> | |||
| .header-wrapper { | |||
| background-color: #f5f5f6; | |||
| padding-top: 15px; | |||
| } | |||
| .image_text{ | |||
| padding:25px 0 55px 0 ; | |||
| } | |||
| #header{ | |||
| position: relative; | |||
| top:-40px; | |||
| } | |||
| .el-dropdown-menu__item--divided{ | |||
| border-top: 1px solid blue; | |||
| } | |||
| .el-table thead{ | |||
| background-color: #f5f5f6; | |||
| } | |||
| /deep/ .el-tabs__item:hover{ | |||
| color: #000; | |||
| font-weight: 500; | |||
| } | |||
| /deep/ .el-tabs__item.is-active { | |||
| color: #000; | |||
| font-weight: 500; | |||
| } | |||
| /deep/ .el-tabs__active-bar{ | |||
| background-color:#000 | |||
| } | |||
| #success{ | |||
| background-color: #5bb973; | |||
| color: white; | |||
| } | |||
| .text-over{ | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| vertical-align: middle; | |||
| white-space: nowrap; | |||
| } | |||
| .image_title{ | |||
| display: inline-block; | |||
| cursor: default; | |||
| color: rgb(66, 98, 144); | |||
| } | |||
| .image_desc{ | |||
| -webkit-line-clamp: 2; | |||
| -webkit-box-orient: vertical; | |||
| display: -webkit-box; | |||
| text-overflow: ellipsis; | |||
| overflow: hidden; | |||
| } | |||
| .heart-stroke{ | |||
| stroke: #FA8C16; | |||
| stroke-width: 2; | |||
| fill: #fff | |||
| } | |||
| .stars_active{ | |||
| fill: #FA8C16 !important; | |||
| stroke:#FA8C16 !important | |||
| } | |||
| .header-new-drop{ | |||
| width: 100%; | |||
| } | |||
| </style> | |||
| @@ -0,0 +1,357 @@ | |||
| <template> | |||
| <div class="inline required field" :class="{ 'unite': benchmarkNew, 'min_title': benchmarkNew}"> | |||
| <label v-if="benchmarkNew" style="font-weight: normal;">镜像</label> | |||
| <label v-else>镜像</label> | |||
| <span v-if="benchmarkNew"> </span> | |||
| <input v-if="benchmarkNew" type="text" name="image" :value="imageAddress" style="width: 48.5%;" placeholder="选择镜像或输入镜像地址"> | |||
| <input v-else type="text" name="image" :value="imageAddress" placeholder="选择镜像或输入镜像地址"> | |||
| <el-button type="text" @click="dialogVisible = true" icon="el-icon-plus" style="color: #0366d6;">选择镜像</el-button> | |||
| <el-dialog | |||
| title="选择镜像" | |||
| :visible.sync="dialogVisible" | |||
| width="50%" | |||
| > | |||
| <div class="ui icon input" style="z-index: 9999;position: absolute;right: 50px;height:30px;"> | |||
| <i class="search icon" style="cursor: pointer;pointer-events:auto"></i> | |||
| <input type="text" placeholder="搜镜像Tag/描述/标签..." v-model="search"> | |||
| </div> | |||
| <el-tabs v-model="activeName" @tab-click="handleClick"> | |||
| <el-tab-pane label="公开镜像" name="first" v-loading="loadingPublic"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(publicData,index) in tableDataPublic" :key="index"> | |||
| <div style="width: 90%;"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;"> | |||
| <div style="display: flex;align-items: center;"> | |||
| <span class="panel_dataset_name text-over" style="margin-left: 0;">{{publicData.tag}} </span> | |||
| <img v-if="publicData.type==5" src="/img/jian.svg" style="margin-left: 0.5rem;"> | |||
| </div> | |||
| <div v-if="!!publicData.topics" class="text-over"> | |||
| <span v-for="(topic,index) in publicData.topics" class="ui repo-topic label topic">{{topic}}</span> | |||
| </div> | |||
| </div> | |||
| <div style="margin-top: 8px;display: flex;"> | |||
| <a :title="publicData.userName" style="cursor: default;"> | |||
| <img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="publicData.relAvatarLink"> | |||
| </a> | |||
| <span class="panel_datset_desc">{{publicData.description}}</span> | |||
| </div> | |||
| </div> | |||
| <div> | |||
| <button class="ui primary basic button mini" @click.stop.prevent="selectImages(publicData.place,publicData.tag)">使用</button> | |||
| </div> | |||
| </div> | |||
| <div class="ui container" style="margin-top:50px;text-align:center"> | |||
| <el-pagination | |||
| background | |||
| @current-change="handleCurrentChangePublic" | |||
| :current-page="currentPagePublic" | |||
| :page-size="pageSizePublic" | |||
| layout="total, prev, pager, next" | |||
| :total="totalNumPublic"> | |||
| </el-pagination> | |||
| </div> | |||
| </el-tab-pane> | |||
| <el-tab-pane label="我的镜像" name="second" v-loading="loadingCustom"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(customData,index) in tableDataCustom" :key="index"> | |||
| <div style="width: 90%;"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;"> | |||
| <span class="panel_dataset_name text-over" style="margin-left: 0;">{{customData.tag}} </span> | |||
| <div v-if="!!customData.topics" class="text-over"> | |||
| <span v-for="(topic,index) in customData.topics" class="ui repo-topic label topic">{{topic}}</span> | |||
| </div> | |||
| </div> | |||
| <div style="margin-top: 8px;display: flex;"> | |||
| <a :title="customData.userName" style="cursor: default;"> | |||
| <img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="customData.relAvatarLink"> | |||
| </a> | |||
| <span class="panel_datset_desc">{{customData.description}}</span> | |||
| </div> | |||
| </div> | |||
| <div> | |||
| <button v-if="customData.status===1" class="ui primary basic button mini" @click.stop.prevent="selectImages(customData.place,customData.tag)">使用</button> | |||
| <span v-if="customData.status===0" style="display: flex;align-items: center;"> | |||
| <i class="CREATING"></i> | |||
| <span style="margin-left: 0.4em;font-size: 12px;color: #5A5A5A;">提交中</span> | |||
| </span> | |||
| <span v-if="customData.status===2" style="display: flex;align-items: center;"> | |||
| <i class="FAILED"></i> | |||
| <el-tooltip class="item" effect="dark" content="检测提交镜像是否大小超过20G!" placement="left"> | |||
| <span style="margin-left: 0.4em;font-size: 12px;color:red;">提交失败</span> | |||
| </el-tooltip> | |||
| </span> | |||
| </div> | |||
| </div> | |||
| <div class="ui container" style="margin-top:50px;text-align:center"> | |||
| <el-pagination | |||
| background | |||
| @current-change="handleCurrentChangeCustom" | |||
| :current-page="currentPageCustom" | |||
| :page-size="pageSizeCustom" | |||
| layout="total, prev, pager, next" | |||
| :total="totalNumCustom"> | |||
| </el-pagination> | |||
| </div> | |||
| </el-tab-pane> | |||
| <el-tab-pane label="我收藏的镜像" name="third"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;padding: 1rem 0;border-bottom:1px solid #F5F5F5" v-for="(starData,index) in tableDataStar" :key="index"> | |||
| <div style="width: 90%;"> | |||
| <div style="display: flex;align-items: center;justify-content: space-between;"> | |||
| <div style="display: flex;align-items: center;"> | |||
| <span class="panel_dataset_name text-over" style="margin-left: 0;">{{starData.tag}} </span> | |||
| <img v-if="starData.type==5" src="/img/jian.svg" style="margin-left: 0.5rem;"> | |||
| </div> | |||
| <div v-if="!!starData.topics" class="text-over"> | |||
| <span v-for="(topic,index) in starData.topics" class="ui repo-topic label topic">{{topic}}</span> | |||
| </div> | |||
| </div> | |||
| <div style="margin-top: 8px;display: flex;"> | |||
| <a :title="starData.userName" style="cursor: default;"> | |||
| <img class="ui avatar mini image" style="width: 20px;height: 20px;" :src="starData.relAvatarLink"> | |||
| </a> | |||
| <span class="panel_datset_desc">{{starData.description}}</span> | |||
| </div> | |||
| </div> | |||
| <div> | |||
| <button class="ui primary basic button mini" @click.stop.prevent="selectImages(starData.place,starData.tag)">使用</button> | |||
| </div> | |||
| </div> | |||
| <div class="ui container" style="margin-top:50px;text-align:center"> | |||
| <el-pagination | |||
| background | |||
| @current-change="handleCurrentChangeStar" | |||
| :current-page="currentPageStar" | |||
| :page-size="pageSizeStar" | |||
| layout="total, prev, pager, next" | |||
| :total="totalNumStar"> | |||
| </el-pagination> | |||
| </div> | |||
| </el-tab-pane> | |||
| </el-tabs> | |||
| </el-dialog> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; | |||
| export default { | |||
| components: { | |||
| }, | |||
| data() { | |||
| return { | |||
| dialogVisible:false, | |||
| benchmarkNew:false, | |||
| imageAddress:'', | |||
| activeName: 'first', | |||
| search:'', | |||
| checked:false, | |||
| currentPagePublic:1, | |||
| pageSizePublic:5, | |||
| totalNumPublic:0, | |||
| paramsPublic:{page:1,pageSize:5,q:'',recommend:false}, | |||
| tableDataPublic: [], | |||
| loadingPublic:false, | |||
| currentPageCustom:1, | |||
| pageSizeCustom:5, | |||
| totalNumCustom:0, | |||
| paramsCustom:{page:1,pageSize:5,q:''}, | |||
| tableDataCustom: [], | |||
| starCustom:[], | |||
| loadingCustom:false, | |||
| currentPageStar:1, | |||
| pageSizeStar:5, | |||
| totalNumStar:0, | |||
| paramsStar:{page:1,pageSize:5,q:''}, | |||
| tableDataStar: [], | |||
| loadingStar:false | |||
| }; | |||
| }, | |||
| methods: { | |||
| handleClick(tab, event) { | |||
| this.search = '' | |||
| if(tab.name=="first"){ | |||
| this.paramsPublic.q = '' | |||
| this.getImageListPublic() | |||
| } | |||
| if(tab.name=="second"){ | |||
| this.getImageListCustom() | |||
| } | |||
| if(tab.name=="third"){ | |||
| this.getImageListStar() | |||
| } | |||
| }, | |||
| tableHeaderStyle({row,column,rowIndex,columnIndex}){ | |||
| if(rowIndex===0){ | |||
| return 'background:#f5f5f6;color:#606266' | |||
| } | |||
| }, | |||
| handleCurrentChangePublic(val){ | |||
| this.paramsPublic.page = val | |||
| this.getImageListPublic() | |||
| }, | |||
| handleCurrentChangeCustom(val){ | |||
| this.paramsCustom.page = val | |||
| this.getImageListCustom() | |||
| }, | |||
| handleCurrentChangeStar(val){ | |||
| this.paramsStar.page = val | |||
| this.getImageListStar() | |||
| }, | |||
| getImageListPublic(){ | |||
| this.loadingPublic = true | |||
| this.$axios.get('/explore/images/public',{ | |||
| params:this.paramsPublic | |||
| }).then((res)=>{ | |||
| this.totalNumPublic = res.data.count | |||
| this.tableDataPublic = res.data.images | |||
| this.loadingPublic = false | |||
| }) | |||
| }, | |||
| getImageListCustom(){ | |||
| this.loadingCustom = true | |||
| this.$axios.get('/explore/images/custom',{ | |||
| params:this.paramsCustom | |||
| }).then((res)=>{ | |||
| this.totalNumCustom = res.data.count | |||
| this.tableDataCustom = res.data.images | |||
| this.tableDataCustom.forEach(element => { | |||
| this.starCustom.push({id:element.id,}) | |||
| }); | |||
| this.loadingCustom = false | |||
| }) | |||
| }, | |||
| getImageListStar(){ | |||
| this.loadingStar = true | |||
| this.$axios.get('/explore/images/star',{ | |||
| params:this.paramsStar | |||
| }).then((res)=>{ | |||
| this.totalNumStar = res.data.count | |||
| this.tableDataStar = res.data.images | |||
| this.loadingStar = false | |||
| }) | |||
| }, | |||
| searchName(){ | |||
| if(this.activeName=='first'){ | |||
| this.paramsPublic.q = this.search | |||
| this.paramsPublic.page = 1 | |||
| this.getImageListPublic() | |||
| } | |||
| if(this.activeName=='second'){ | |||
| this.paramsCustom.q = this.search | |||
| this.paramsCustom.page = 1 | |||
| this.getImageListCustom() | |||
| } | |||
| if(this.activeName=='third'){ | |||
| this.paramsStar.q = this.search | |||
| this.paramsStar.page = 1 | |||
| this.getImageListStar() | |||
| } | |||
| }, | |||
| selectImages(place){ | |||
| this.imageAddress = place | |||
| this.dialogVisible = false | |||
| }, | |||
| }, | |||
| watch:{ | |||
| search(val){ | |||
| if(this.activeName=='first'){ | |||
| this.paramsPublic.q = val | |||
| this.getImageListPublic() | |||
| } | |||
| if(this.activeName=='second'){ | |||
| this.paramsCustom.q = val | |||
| this.getImageListCustom() | |||
| } | |||
| if(this.activeName=='third'){ | |||
| this.paramsStar.q = val | |||
| this.getImageListStar() | |||
| } | |||
| } | |||
| }, | |||
| mounted() { | |||
| this.getImageListPublic() | |||
| if(location.href.indexOf('benchmark')!==-1 || location.href.indexOf('train-job')!==-1){ | |||
| this.benchmarkNew = true | |||
| } | |||
| }, | |||
| created() { | |||
| } | |||
| }; | |||
| </script> | |||
| <style scoped> | |||
| .header-wrapper { | |||
| background-color: #f5f5f6; | |||
| padding-top: 15px; | |||
| } | |||
| .image_text{ | |||
| padding:25px 0 55px 0 ; | |||
| } | |||
| #header{ | |||
| position: relative; | |||
| top:-40px; | |||
| } | |||
| #success{ | |||
| background-color: #5bb973; | |||
| color: white; | |||
| } | |||
| .text-over{ | |||
| overflow: hidden; | |||
| text-overflow: ellipsis; | |||
| vertical-align: middle; | |||
| white-space: nowrap; | |||
| } | |||
| .image_title{ | |||
| display: inline-block; | |||
| width: 80%; | |||
| cursor: default; | |||
| color: rgb(66, 98, 144); | |||
| } | |||
| .image_desc{ | |||
| -webkit-line-clamp: 2; | |||
| -webkit-box-orient: vertical; | |||
| display: -webkit-box; | |||
| text-overflow: ellipsis; | |||
| overflow: hidden; | |||
| } | |||
| .heart-stroke{ | |||
| stroke: #666; | |||
| stroke-width: 2; | |||
| fill: #fff | |||
| } | |||
| .stars_active{ | |||
| fill: #FA8C16 !important; | |||
| stroke:#FA8C16 !important | |||
| } | |||
| </style> | |||
| @@ -20,6 +20,7 @@ export default async function initCloudrain() { | |||
| const status = data.JobStatus | |||
| const duration = data.JobDuration | |||
| $('#duration-'+ID).text(duration) | |||
| console.log(status,["STOPPED"].includes(status)) | |||
| if (status != status_text) { | |||
| $('#' + ID+'-icon').removeClass().addClass(status) | |||
| $('#' + ID+ '-text').text(status) | |||
| @@ -38,12 +39,12 @@ export default async function initCloudrain() { | |||
| $('#ai-debug-'+ID).removeClass('blue').addClass('disabled') | |||
| } | |||
| if(['STOPPED','FAILED','START_FAILED','CREATE_FAILED','SUCCEEDED'].includes(status)){ | |||
| $('#ai-debug-'+ID).removeClass('disabled').addClass('blue').text(debug_again_button).css("margin","0") | |||
| } | |||
| $('#ai-debug-'+ID).removeClass('disabled').addClass('blue').text(debug_again_button).css("margin","0") | |||
| } | |||
| if(["RUNNING","WAITING"].includes(status)){ | |||
| $('#ai-stop-'+ID).removeClass('disabled').addClass('blue') | |||
| } | |||
| if(["CREATING","STOPPING","STARTING","STOPPED","FAILED","START_FAILED","SUCCEEDED","COMPLETED"].includes(status)){ | |||
| if(["CREATING","STOPPING","STARTING","STOPPED","FAILED","START_FAILED","SUCCEEDED","COMPLETED","CREATE_FAILED"].includes(status)){ | |||
| $('#ai-stop-'+ID).removeClass('blue').addClass('disabled') | |||
| } | |||
| @@ -162,6 +163,9 @@ export default async function initCloudrain() { | |||
| $(`#${ID}-icon`).attr("class",data.JobStatus) | |||
| // detail status and duration | |||
| $(`#${ID}-text`).text(data.JobStatus) | |||
| if(["STOPPED","FAILED","START_FAILED","KILLED","COMPLETED","SUCCEEDED"].includes(data.JobStatus)){ | |||
| $('#ai-delete-'+ID).removeClass('disabled').addClass('blue') | |||
| } | |||
| }).fail(function(err) { | |||
| console.log(err); | |||
| }); | |||
| @@ -0,0 +1,214 @@ | |||
| import Images from '../components/images/Images.vue'; | |||
| import adminImages from '../components/images/adminImages.vue'; | |||
| import selectImages from '../components/images/selectImages.vue'; | |||
| import Vue from 'vue'; | |||
| export default async function initImage(){ | |||
| function validate() { | |||
| $("#form_image") | |||
| .form({ | |||
| on: 'blur', | |||
| // inline:true, | |||
| fields: { | |||
| tag: { | |||
| identifier : 'tag', | |||
| rules: [ | |||
| { | |||
| type: 'regExp[/^[A-Za-z0-9_.-]{1,100}[A-Za-z0-9_.]$/]', | |||
| } | |||
| ] | |||
| }, | |||
| description:{ | |||
| identifier : 'description', | |||
| rules: [ | |||
| { | |||
| type: 'empty', | |||
| } | |||
| ] | |||
| }, | |||
| place:{ | |||
| identifier : 'place', | |||
| rules: [ | |||
| { | |||
| type: 'empty', | |||
| } | |||
| ] | |||
| }, | |||
| } | |||
| }) | |||
| } | |||
| function $params(obj) { | |||
| var str = []; | |||
| for (var p in obj) { | |||
| str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); | |||
| } | |||
| return str.join("&"); | |||
| } | |||
| function initDropdown(){ | |||
| $('#dropdown_image') | |||
| .dropdown({ | |||
| allowAdditions: true, | |||
| onChange: function(value, text, $selectedItem) { | |||
| $('#course_label_item').empty() | |||
| } | |||
| }) | |||
| $('#dropdown_image input.search').bind('input propertychange', function (event) { | |||
| // $("#dropdown_container").removeAttr("style"); | |||
| const query = $('input.search').val() | |||
| if(!query){ | |||
| $('#course_label_item').empty() | |||
| }else{ | |||
| $.get(`/api/v1/image/topics/search?q=${query}`,(data)=>{ | |||
| if(data.topics.length!==0){ | |||
| let html='' | |||
| $('#course_label_item').empty() | |||
| data.topics.forEach(element => { | |||
| html += `<div class="item" data-value="${element.topic_name}">${element.topic_name}</div>` | |||
| }); | |||
| $('#course_label_item').append(html) | |||
| } | |||
| }) | |||
| } | |||
| }); | |||
| } | |||
| validate() | |||
| initDropdown() | |||
| let link = $('.submit-image-tmplvalue').data('link') | |||
| let pageform = $('.submit-image-tmplvalue').data('edit-page') || '' | |||
| function postImage(formData) { | |||
| $("#mask").css({"display":"block","z-index":"999"}) | |||
| $.ajax({ | |||
| url:link, | |||
| type:'POST', | |||
| data:formData, | |||
| success:function(res){ | |||
| console.log(res) | |||
| if(res.Code===1){ | |||
| $('.ui.negative.message').text(res.Message).show().delay(2500).fadeOut(); | |||
| }else if(res.Code==0){ | |||
| if(location.href.indexOf('imageAdmin')!==-1){ | |||
| location.href = `${window.config.AppSubUrl}/admin/images` | |||
| }else{ | |||
| location.href = `${window.config.AppSubUrl}/explore/images?type=myimage` | |||
| } | |||
| } | |||
| }, | |||
| error: function(xhr){ | |||
| // 隐藏 loading | |||
| // 只有请求不正常(状态码不为200)才会执行 | |||
| $('.ui.negative.message').html(xhr.responseText).show().delay(1500).fadeOut(); | |||
| }, | |||
| complete:function(xhr){ | |||
| $("#mask").css({"display":"none","z-index":"1"}) | |||
| } | |||
| }) | |||
| } | |||
| $('.ui.create_image.green.button').click(()=>{ | |||
| let pattenTag = new RegExp(/^[A-Za-z0-9_.-]{1,100}[A-Za-z0-9_.]$/) | |||
| if(!pattenTag.test($("input[name='tag']").val())){ | |||
| $("input[name='tag']").parent().addClass('error') | |||
| return false | |||
| } | |||
| if(!$("textarea[name='description']").val()){ | |||
| $("textarea[name='description']").parent().addClass('error') | |||
| return false | |||
| } | |||
| if($("input[name='place']").length>0&&!$("input[name='place']").val()){ | |||
| console.log("1111111",$("input[name='place']")) | |||
| $("input[name='place']").parent().addClass('error') | |||
| return false | |||
| } | |||
| const postData = { | |||
| _csrf:$("input[name='_csrf']").val(), | |||
| tag:$("input[name='tag']").val(), | |||
| description:$("textarea[name='description']").val(), | |||
| type:$("input[name='type']").val(), | |||
| isPrivate:$("input[name='isPrivate']:checked").val(), | |||
| topics:$("input[name='topics']").val(), | |||
| id:$("input[name='id']").val() | |||
| } | |||
| if($("input[name='place']").val()&&$("input[name='isRecommend']:checked").val()){ | |||
| postData.isRecommend = $("input[name='isRecommend']:checked").val() | |||
| postData.place = $("input[name='place']").val() | |||
| } | |||
| let formData = $params(postData) | |||
| if($("input[name='edit']").val()=="edit"){ | |||
| postImage(formData) | |||
| } | |||
| else{ | |||
| $.ajax({ | |||
| url:link+'/check', | |||
| type:'POST', | |||
| data:formData, | |||
| success:function(res){ | |||
| if(res.Code===1){ | |||
| $('.ui.modal.image_confirm_submit') | |||
| .modal({ | |||
| onApprove: function() { | |||
| postImage(formData) | |||
| }, | |||
| }) | |||
| .modal('show') | |||
| }else if(res.Code==0){ | |||
| postImage(formData) | |||
| } | |||
| }, | |||
| error: function(xhr){ | |||
| $('.ui.negative.message').text(xhr.responseText).show().delay(1500).fadeOut(); | |||
| } | |||
| }) | |||
| } | |||
| return false | |||
| }) | |||
| $('#cancel_submit_image').click(()=>{ | |||
| if(link.includes('cloudbrain')){ | |||
| let repoLink = link.split('cloudbrain')[0] | |||
| location.href = `${window.config.AppSubUrl}${repoLink}debugjob?debugListType=all` | |||
| }else if(pageform=='imageSquare'){ | |||
| location.href = `${window.config.AppSubUrl}/explore/images?type=myimage` | |||
| }else if(pageform=='imageAdmin'){ | |||
| location.href = `${window.config.AppSubUrl}/admin/images` | |||
| } | |||
| }) | |||
| function initVueImages() { | |||
| const el = document.getElementById('images'); | |||
| if (!el) { | |||
| return; | |||
| } | |||
| new Vue({ | |||
| el:el, | |||
| render: h => h(Images) | |||
| }); | |||
| } | |||
| function initVueAdminImages() { | |||
| const el = document.getElementById('images-admin'); | |||
| if (!el) { | |||
| return; | |||
| } | |||
| new Vue({ | |||
| el:el, | |||
| render: h => h(adminImages) | |||
| }); | |||
| } | |||
| function initVueselectImages() { | |||
| const el = document.getElementById('images-new-cb'); | |||
| if (!el) { | |||
| return; | |||
| } | |||
| new Vue({ | |||
| el:el, | |||
| render: h => h(selectImages) | |||
| }); | |||
| } | |||
| initVueImages() | |||
| initVueAdminImages() | |||
| initVueselectImages() | |||
| } | |||
| @@ -34,15 +34,15 @@ import { | |||
| } from './features/notification.js'; | |||
| import {createCodeEditor} from './features/codeeditor.js'; | |||
| import MinioUploader from './components/MinioUploader.vue'; | |||
| import ObsUploader from './components/ObsUploader.vue'; | |||
| import EditAboutInfo from './components/EditAboutInfo.vue'; | |||
| import Images from './components/Images.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 $ from 'jquery.js' | |||
| Vue.use(ElementUI); | |||
| @@ -2768,8 +2768,13 @@ $(document).ready(async () => { | |||
| const $dropzone = $('#dropzone'); | |||
| if ($dropzone.length > 0) { | |||
| const filenameDict = {}; | |||
| let maxFileTooltips=$dropzone.data('max-file-tooltips').format($dropzone.data('max-file'),$dropzone.data('max-size')) | |||
| let 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}, | |||
| @@ -2804,17 +2809,23 @@ $(document).ready(async () => { | |||
| this.on('addedfile',(file)=>{ | |||
| if(file.size/(1000*1000)>$dropzone.data('max-size')){ | |||
| this.removeFile(file) | |||
| $('.maxfilesize.ui.red.message').text(maxFileTooltips) | |||
| $('.maxfilesize.ui.red.message').css('display','block') | |||
| if(maxFileTooltips){ | |||
| $('.maxfilesize.ui.red.message').text(maxFileTooltips) | |||
| $('.maxfilesize.ui.red.message').css('display','block') | |||
| } | |||
| }else{ | |||
| $('.maxfilesize.ui.red.message').css('display','none') | |||
| if(maxFileTooltips){ | |||
| $('.maxfilesize.ui.red.message').css('display','none') | |||
| } | |||
| } | |||
| }); | |||
| this.on('maxfilesexceeded',(file)=>{ | |||
| this.removeFile(file) | |||
| $('.maxfilesize.ui.red.message').text(maxSizeTooltips) | |||
| $('.maxfilesize.ui.red.message').css('display','block') | |||
| if(maxSizeTooltips){ | |||
| $('.maxfilesize.ui.red.message').text(maxSizeTooltips) | |||
| $('.maxfilesize.ui.red.message').css('display','block') | |||
| } | |||
| }) | |||
| } | |||
| @@ -2946,12 +2957,11 @@ $(document).ready(async () => { | |||
| initCodeView(); | |||
| initVueApp(); | |||
| initVueUploader(); | |||
| initObsUploader(); | |||
| initVueDataset(); | |||
| initVueEditAbout(); | |||
| initVueEditTopic(); | |||
| initVueContributors(); | |||
| initVueImages(); | |||
| // initVueImages(); | |||
| initVueModel(); | |||
| initVueDataAnalysis(); | |||
| initVueWxAutorize(); | |||
| @@ -2973,6 +2983,7 @@ $(document).ready(async () => { | |||
| initTribute(); | |||
| initDropDown(); | |||
| initCloudrain(); | |||
| initImage(); | |||
| // Repo clone url. | |||
| if ($('#repo-clone-url').length > 0) { | |||
| @@ -3689,6 +3700,32 @@ function initVueEditAbout() { | |||
| } | |||
| function initVueDataset() { | |||
| $('.set_dataset').on('click', function(){ | |||
| const $this = $(this); | |||
| let link = $this.data('url') | |||
| $.ajax({ | |||
| url:link, | |||
| type:'PUT', | |||
| success:function(res){ | |||
| console.log(res) | |||
| if(res.Code==0){ | |||
| window.location.href = '/admin/datasets' | |||
| }else{ | |||
| $('.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) | |||
| }, | |||
| complete:function(xhr){ | |||
| // $("#mask").css({"display":"none","z-index":"1"}) | |||
| } | |||
| }) | |||
| }); | |||
| const el = document.getElementById('dataset-base'); | |||
| if (!el) { | |||
| return; | |||
| @@ -3841,8 +3878,7 @@ function initVueDataset() { | |||
| }, | |||
| }, | |||
| components: { | |||
| MinioUploader, | |||
| ObsUploader | |||
| MinioUploader | |||
| }, | |||
| mounted(){ | |||
| // if(document.getElementById('postPath')){ | |||
| @@ -4273,6 +4309,29 @@ function initVueDataset() { | |||
| } | |||
| } | |||
| }, | |||
| watch:{ | |||
| searchDataItem(){ | |||
| switch(this.activeName){ | |||
| case 'first': | |||
| this.page = 1 | |||
| this.getCurrentRepoDataset(this.repolink,this.cloudbrainType) | |||
| break | |||
| case 'second': | |||
| this.page = 1 | |||
| this.getMyDataset(this.repolink,this.cloudbrainType) | |||
| break | |||
| case 'third': | |||
| this.page = 1 | |||
| this.getPublicDataset(this.repolink,this.cloudbrainType) | |||
| break | |||
| case 'fourth': | |||
| this.page = 1 | |||
| this.getStarDataset(this.repolink,this.cloudbrainType) | |||
| break | |||
| } | |||
| } | |||
| }, | |||
| }); | |||
| } | |||
| @@ -4304,20 +4363,20 @@ function initVueContributors() { | |||
| } | |||
| function initVueImages() { | |||
| const el = document.getElementById('images'); | |||
| // function initVueImages() { | |||
| // const el = document.getElementById('images'); | |||
| if (!el) { | |||
| return; | |||
| } | |||
| // if (!el) { | |||
| // return; | |||
| // } | |||
| new Vue({ | |||
| el: '#images', | |||
| // new Vue({ | |||
| // el: '#images', | |||
| render: h => h(Images) | |||
| }); | |||
| } | |||
| // render: h => h(Images) | |||
| // }); | |||
| // } | |||
| function initVueModel() { | |||
| const el = document.getElementById('model_list'); | |||
| @@ -4344,19 +4403,6 @@ function initVueDataAnalysis() { | |||
| render: h => h(DataAnalysis) | |||
| }); | |||
| } | |||
| // 新增 | |||
| function initObsUploader() { | |||
| const el = document.getElementById('obsUploader'); | |||
| if (!el) { | |||
| return; | |||
| } | |||
| new Vue({ | |||
| el: '#obsUploader', | |||
| components: {ObsUploader}, | |||
| template: '<ObsUploader />' | |||
| }); | |||
| } | |||
| function initVueWxAutorize() { | |||
| const el = document.getElementById('WxAutorize'); | |||
| if (!el) { | |||
| @@ -1071,7 +1071,7 @@ $.fn.dropdown = function(parameters) { | |||
| ; | |||
| if(settings.allowAdditions || (hasSelected && !module.is.multiple())) { | |||
| module.debug('Forcing partial selection to selected item', $selectedItem); | |||
| $selectedItem[0].click(); | |||
| // $selectedItem[0].click(); | |||
| return; | |||
| } | |||
| else { | |||