@@ -2,7 +2,7 @@ | |||
<h1><img src="public/img/favicon.png" alt="logo" width="30" height="30">AiForge - 启智AI开发协作平台</h1> | |||
[](https://git.openi.org.cn/OpenI/aiforge/releases/latest) | |||
[](https://git.openi.org.cn/OpenI/aiforge/releases/latest) | |||
[](https://opensource.org/licenses/MIT) | |||
@@ -52,6 +52,7 @@ require ( | |||
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 | |||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 | |||
github.com/golang/protobuf v1.4.1 // indirect | |||
github.com/gomodule/redigo v2.0.0+incompatible | |||
github.com/google/go-github/v24 v24.0.1 | |||
github.com/gorilla/context v1.1.1 | |||
github.com/hashicorp/go-retryablehttp v0.6.6 // indirect | |||
@@ -5,11 +5,12 @@ import ( | |||
"fmt" | |||
"strings" | |||
"time" | |||
"xorm.io/builder" | |||
"xorm.io/xorm" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/modules/setting" | |||
"code.gitea.io/gitea/modules/timeutil" | |||
"xorm.io/builder" | |||
) | |||
type CloudbrainStatus string | |||
@@ -59,12 +60,18 @@ type Cloudbrain struct { | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
DeletedAt time.Time `xorm:"deleted"` | |||
CanDebug bool `xorm:"-"` | |||
CanDel bool `xorm:"-"` | |||
Type int `xorm:"INDEX DEFAULT 0"` | |||
User *User `xorm:"-"` | |||
Repo *Repository `xorm:"-"` | |||
} | |||
type CloudbrainInfo struct { | |||
Cloudbrain `xorm:"extends"` | |||
User `xorm:"extends"` | |||
} | |||
type CloudBrainLoginResult struct { | |||
Code string | |||
Msg string | |||
@@ -523,7 +530,7 @@ type NotebookDelResult struct { | |||
InstanceID string `json:"instance_id"` | |||
} | |||
func Cloudbrains(opts *CloudbrainsOptions) ([]*Cloudbrain, int64, error) { | |||
func Cloudbrains(opts *CloudbrainsOptions) ([]*CloudbrainInfo, int64, error) { | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
@@ -583,8 +590,10 @@ func Cloudbrains(opts *CloudbrainsOptions) ([]*Cloudbrain, int64, error) { | |||
} | |||
sess.OrderBy("cloudbrain.created_unix DESC") | |||
cloudbrains := make([]*Cloudbrain, 0, setting.UI.IssuePagingNum) | |||
if err := sess.Where(cond).Find(&cloudbrains); err != nil { | |||
cloudbrains := make([]*CloudbrainInfo, 0, setting.UI.IssuePagingNum) | |||
if err := sess.Table(&Cloudbrain{}).Where(cond). | |||
Join("left", "`user`", "cloudbrain.user_id = `user`.id"). | |||
Find(&cloudbrains); err != nil { | |||
return nil, 0, fmt.Errorf("Find: %v", err) | |||
} | |||
sess.Close() | |||
@@ -622,13 +631,13 @@ func GetCloudbrainByJobID(jobID string) (*Cloudbrain, error) { | |||
func GetCloudbrainsNeededStopByUserID(userID int64) ([]*Cloudbrain, error) { | |||
cloudBrains := make([]*Cloudbrain, 0) | |||
err := x.Cols("job_id", "status", "type").Where("user_id=? AND (status =? OR status=?)", userID, string(JobRunning), string(JobWaiting)).Find(&cloudBrains) | |||
err := x.Cols("job_id", "status", "type").Where("user_id=? AND status !=?", userID, string(JobStopped)).Find(&cloudBrains) | |||
return cloudBrains, err | |||
} | |||
func GetCloudbrainsNeededStopByRepoID(repoID int64) ([]*Cloudbrain, error) { | |||
cloudBrains := make([]*Cloudbrain, 0) | |||
err := x.Cols("job_id", "status", "type").Where("repo_id=? AND (status =? OR status=?)", repoID, string(JobRunning), string(JobWaiting)).Find(&cloudBrains) | |||
err := x.Cols("job_id", "status", "type").Where("repo_id=? AND status !=?", repoID, string(JobStopped)).Find(&cloudBrains) | |||
return cloudBrains, err | |||
} | |||
@@ -662,3 +671,24 @@ func GetCloudbrainByName(jobName string) (*Cloudbrain, error) { | |||
cb := &Cloudbrain{JobName: jobName} | |||
return getRepoCloudBrain(cb) | |||
} | |||
func CanDelJob(isSigned bool, user *User, job *CloudbrainInfo) bool { | |||
if !isSigned || job.Status != string(JobStopped) { | |||
return false | |||
} | |||
repo, err := GetRepositoryByID(job.RepoID) | |||
if err != nil { | |||
log.Error("GetRepositoryByID failed:%v", err.Error()) | |||
return false | |||
} | |||
permission, _ := GetUserRepoPermission(repo, user) | |||
if err != nil { | |||
log.Error("GetUserRepoPermission failed:%v", err.Error()) | |||
return false | |||
} | |||
if user.ID == job.UserID || user.IsAdmin || permission.AccessMode >= AccessModeAdmin { | |||
return true | |||
} | |||
return false | |||
} |
@@ -3,7 +3,11 @@ package models | |||
import "code.gitea.io/gitea/modules/git" | |||
func GetRepoKPIStats(repo *Repository) (*git.RepoKPIStats, error) { | |||
return git.GetRepoKPIStats(repo.RepoPath()) | |||
wikiPath := "" | |||
if repo.HasWiki() { | |||
wikiPath = repo.WikiPath() | |||
} | |||
return git.GetRepoKPIStats(repo.RepoPath(), wikiPath) | |||
} | |||
func GetAllUserKPIStats() (map[string]*git.UserKPIStats, error) { | |||
@@ -166,6 +166,8 @@ type SearchRepoOptions struct { | |||
Archived util.OptionalBool | |||
// only search topic name | |||
TopicOnly bool | |||
//search by Specific TopicName | |||
TopicName string | |||
// include description in keyword search | |||
IncludeDescription bool | |||
// None -> include has milestones AND has no milestone | |||
@@ -327,6 +329,18 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { | |||
} | |||
cond = cond.And(keywordCond) | |||
} | |||
if opts.TopicName != "" { | |||
var subQueryCond = builder.NewCond() | |||
subQueryCond = subQueryCond.Or(builder.Eq{"topic.name": opts.TopicName}) | |||
subQuery := builder.Select("repo_topic.repo_id").From("repo_topic"). | |||
Join("INNER", "topic", "topic.id = repo_topic.topic_id"). | |||
Where(subQueryCond). | |||
GroupBy("repo_topic.repo_id") | |||
var topicNameCond = builder.In("id", subQuery) | |||
cond = cond.And(topicNameCond) | |||
} | |||
if opts.Fork != util.OptionalBoolNone { | |||
cond = cond.And(builder.Eq{"is_fork": opts.Fork == util.OptionalBoolTrue}) | |||
@@ -1556,6 +1556,18 @@ func GetUserByActivateEmail(email string) (*User, error) { | |||
if len(users) >= 1 { | |||
return &users[0],nil | |||
}else { | |||
// Finally, if email address is the protected email address:用户邮件地址设置为隐藏电子邮件地址 | |||
if strings.HasSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) { | |||
username := strings.TrimSuffix(email, fmt.Sprintf("@%s", setting.Service.NoReplyAddress)) | |||
user := &User{LowerName: username} | |||
has, err := ctx.e.Get(user) | |||
if err != nil { | |||
return nil, err | |||
} | |||
if has { | |||
return user, nil | |||
} | |||
} | |||
return nil, errors.New("cannot find user by email") | |||
} | |||
} | |||
@@ -4,18 +4,23 @@ import ( | |||
"bufio" | |||
"bytes" | |||
"fmt" | |||
"net/url" | |||
"sort" | |||
"strconv" | |||
"strings" | |||
"time" | |||
Log "code.gitea.io/gitea/modules/log" | |||
) | |||
type RepoKPIStats struct { | |||
Contributors int64 | |||
KeyContributors int64 | |||
DevelopAge int64 | |||
ContributorsAdded int64 | |||
CommitsAdded int64 | |||
CommitLinesModified int64 | |||
WikiPages int64 | |||
Authors []*UserKPITypeStats | |||
} | |||
@@ -30,7 +35,7 @@ type UserKPITypeStats struct { | |||
isNewContributor bool //是否是4个月内的新增贡献者 | |||
} | |||
func GetRepoKPIStats(repoPath string) (*RepoKPIStats, error) { | |||
func GetRepoKPIStats(repoPath string, wikiPath string) (*RepoKPIStats, error) { | |||
stats := &RepoKPIStats{} | |||
contributors, err := GetContributors(repoPath) | |||
@@ -66,15 +71,42 @@ func GetRepoKPIStats(repoPath string) (*RepoKPIStats, error) { | |||
} | |||
err = setDevelopAge(repoPath, stats) | |||
if err != nil { | |||
return nil, fmt.Errorf("FillFromGit: %v", err) | |||
} | |||
err = setRepoKPIStats(repoPath, fourMonthAgo, stats, newContributersDict) | |||
if err != nil { | |||
return nil, fmt.Errorf("FillFromGit: %v", err) | |||
} | |||
setWikiPages(wikiPath, stats) | |||
return stats, nil | |||
} | |||
func setDevelopAge(repoPath string, stats *RepoKPIStats) error { | |||
args := []string{"log", "--no-merges", "--branches=*", "--format=%cd", "--date=short"} | |||
stdout, err := NewCommand(args...).RunInDirBytes(repoPath) | |||
if err != nil { | |||
return err | |||
} | |||
scanner := bufio.NewScanner(bytes.NewReader(stdout)) | |||
scanner.Split(bufio.ScanLines) | |||
developMonth := make(map[string]struct{}) | |||
for scanner.Scan() { | |||
l := strings.TrimSpace(scanner.Text()) | |||
month := l[0:strings.LastIndex(l, "-")] | |||
if _, ok := developMonth[month]; !ok { | |||
developMonth[month] = struct{}{} | |||
} | |||
} | |||
stats.DevelopAge = int64(len(developMonth)) | |||
return nil | |||
} | |||
//获取一天内的用户贡献指标 | |||
func GetUserKPIStats(repoPath string) (map[string]*UserKPIStats, error) { | |||
timeUntil := time.Now() | |||
@@ -256,3 +288,82 @@ func getContributors(repoPath string, fromTime time.Time) ([]Contributor, error) | |||
} | |||
return nil, nil | |||
} | |||
func setWikiPages(wikiPath string, stats *RepoKPIStats) { | |||
wikiPages := 0 | |||
if wikiPath == "" { | |||
stats.WikiPages = int64(wikiPages) | |||
return | |||
} | |||
wikiRepo, commit, err := findWikiRepoCommit(wikiPath) | |||
if err != nil { | |||
if !IsErrNotExist(err) { | |||
Log.Warn("GetBranchCommit", err) | |||
} | |||
stats.WikiPages = int64(wikiPages) | |||
return | |||
} | |||
// Get page list. | |||
entries, err := commit.ListEntries() | |||
if err != nil { | |||
if wikiRepo != nil { | |||
wikiRepo.Close() | |||
} | |||
Log.Warn("GetBranchCommit", err) | |||
stats.WikiPages = int64(wikiPages) | |||
return | |||
} | |||
for _, entry := range entries { | |||
if !entry.IsRegular() { | |||
continue | |||
} | |||
wikiName, err := filenameToName(entry.Name()) | |||
if err != nil || wikiName == "_Sidebar" || wikiName == "_Footer" { | |||
continue | |||
} | |||
wikiPages += 1 | |||
} | |||
//确保wikiRepo用完被关闭 | |||
defer func() { | |||
if wikiRepo != nil { | |||
wikiRepo.Close() | |||
} | |||
}() | |||
stats.WikiPages = int64(wikiPages) | |||
return | |||
} | |||
func filenameToName(filename string) (string, error) { | |||
if !strings.HasSuffix(filename, ".md") { | |||
return "", fmt.Errorf("invalid file") | |||
} | |||
basename := filename[:len(filename)-3] | |||
unescaped, err := url.QueryUnescape(basename) | |||
if err != nil { | |||
return "", err | |||
} | |||
return strings.Replace(unescaped, "-", " ", -1), nil | |||
} | |||
func findWikiRepoCommit(wikiPath string) (*Repository, *Commit, error) { | |||
wikiRepo, err := OpenRepository(wikiPath) | |||
if err != nil { | |||
return nil, nil, err | |||
} | |||
commit, err := wikiRepo.GetBranchCommit("master") | |||
if err != nil { | |||
return wikiRepo, nil, err | |||
} | |||
return wikiRepo, commit, nil | |||
} |
@@ -0,0 +1,312 @@ | |||
package repository | |||
import ( | |||
"bytes" | |||
"encoding/base64" | |||
"encoding/json" | |||
"fmt" | |||
"io/ioutil" | |||
"net/http" | |||
"code.gitea.io/gitea/modules/setting" | |||
) | |||
//输入elk的json结构begin | |||
type InputInfo struct { | |||
Batch []Batch `json:"batch"` | |||
} | |||
type Fields struct { | |||
Field string `json:"field"` | |||
Format string `json:"format"` | |||
} | |||
type MatchPhrase struct { | |||
Message string `json:"message"` | |||
} | |||
type Should struct { | |||
MatchPhrase MatchPhrase `json:"match_phrase"` | |||
} | |||
type Bool struct { | |||
Should []Should `json:"should"` | |||
MinimumShouldMatch int `json:"minimum_should_match"` | |||
} | |||
type Timestamptest struct { | |||
// Gte time.Time `json:"gte"` | |||
Gte string `json:"gte"` | |||
Lte string `json:"lte"` | |||
Format string `json:"format"` | |||
} | |||
type Range struct { | |||
Timestamptest Timestamptest `json:"@timestamptest"` | |||
} | |||
type FilterMatchPhrase struct { | |||
UserName string `json:"userName.keyword,omitempty"` | |||
ProjectName string `json:"projectName.keyword,omitempty"` | |||
TagName string `json:"tagName.keyword,omitempty"` | |||
} | |||
type Filter struct { | |||
Bool *Bool `json:"bool,omitempty"` | |||
Range *Range `json:"range,omitempty"` | |||
FilterMatchPhrase *FilterMatchPhrase `json:"match_phrase,omitempty"` | |||
} | |||
type MustNotMatchPhrase struct { | |||
ProjectName string `json:"projectName"` | |||
} | |||
type MustNot struct { | |||
MustNotMatchPhrase MustNotMatchPhrase `json:"match_phrase"` | |||
} | |||
type BoolIn struct { | |||
Filter []Filter `json:"filter"` | |||
MustNot []MustNot `json:"must_not"` | |||
} | |||
type Query struct { | |||
BoolIn BoolIn `json:"bool"` | |||
} | |||
type Body struct { | |||
Size int `json:"size"` | |||
Fields []Fields `json:"fields"` | |||
Query Query `json:"query"` | |||
} | |||
type Params struct { | |||
Index string `json:"index"` | |||
Body Body `json:"body"` | |||
} | |||
type Request struct { | |||
Params Params `json:"params"` | |||
} | |||
type Batch struct { | |||
Request Request `json:"request"` | |||
} | |||
//输入elk的json结构end | |||
//elk输出的json结构begin | |||
type Hits struct { | |||
Total int `json:"total"` | |||
} | |||
type RawResponse struct { | |||
Hits Hits `json:"hits"` | |||
} | |||
type Result struct { | |||
RawResponse RawResponse `json:"rawResponse"` | |||
Loaded int `json:"loaded"` | |||
} | |||
type ResultInfo struct { | |||
Id int `json:"id"` | |||
Result Result `json:"result"` | |||
} | |||
//elk输出的json结构end | |||
//发送post请求到elk | |||
func SendReqToElk(jsonStr []byte) (content string) { | |||
ElkBase64Init := setting.ElkUser + ":" + setting.ElkPassword | |||
ElkBase64 := base64.StdEncoding.EncodeToString([]byte(ElkBase64Init)) | |||
BasicElkBase64 := "Basic" + " " + ElkBase64 | |||
url := setting.ElkUrl | |||
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) | |||
req.Header.Set("Content-Type", "application/json") | |||
req.Header.Set("kbn-version", "7.13.2") | |||
req.Header.Set("Authorization", BasicElkBase64) | |||
client := &http.Client{} | |||
resp, err := client.Do(req) | |||
if err != nil { | |||
panic(err) | |||
} | |||
defer resp.Body.Close() | |||
body, _ := ioutil.ReadAll(resp.Body) | |||
return string(body) | |||
} | |||
//处理返回的elk数据,只保留totalView,即访问量;loaded是分片载入次数,用来判断返回的数据是否准确 | |||
func GetResultFromElk(resultinfo ResultInfo, jobResult string) (loaded int, totalView int) { | |||
var resultTest ResultInfo | |||
errs := json.Unmarshal([]byte(jobResult), &resultTest) | |||
fmt.Println(errs) | |||
return resultTest.Result.Loaded, resultTest.Result.RawResponse.Hits.Total | |||
} | |||
//初始化传给elk的数据结构,给定用户名和项目名,查询的起止时间,返回初始化后的结构 | |||
func ProjectViewInit(User string, Project string, Gte string, Lte string) (projectViewInit InputInfo) { | |||
var inputStruct InputInfo | |||
inputStruct.Batch = make([]Batch, 1) | |||
inputStruct.Batch[0].Request.Params.Index = setting.Index | |||
inputStruct.Batch[0].Request.Params.Body.Size = 0 | |||
inputStruct.Batch[0].Request.Params.Body.Fields = make([]Fields, 1) | |||
inputStruct.Batch[0].Request.Params.Body.Fields[0].Field = setting.TimeField | |||
inputStruct.Batch[0].Request.Params.Body.Fields[0].Format = setting.ElkTimeFormat | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter = make([]Filter, 3) | |||
//限定查询时间 | |||
var timeRange Range | |||
timeRange.Timestamptest.Gte = Gte | |||
timeRange.Timestamptest.Lte = Lte | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[0].Range = &timeRange | |||
//限定用户 | |||
var userName FilterMatchPhrase | |||
userName.UserName = User | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[1].FilterMatchPhrase = &userName | |||
//限定项目 | |||
var projectName FilterMatchPhrase | |||
projectName.ProjectName = Project | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[2].FilterMatchPhrase = &projectName | |||
return inputStruct | |||
} | |||
//初始化传给elk的数据结构,给定查询信息和非项目名,查询的起止时间,返回初始化后的结构 | |||
func AllProjectViewInit(MessageInfo string, NotProject string, Gte string, Lte string) (allProjectViewInit InputInfo) { | |||
var inputStruct InputInfo | |||
inputStruct.Batch = make([]Batch, 1) | |||
inputStruct.Batch[0].Request.Params.Index = setting.Index | |||
inputStruct.Batch[0].Request.Params.Body.Size = 0 | |||
inputStruct.Batch[0].Request.Params.Body.Fields = make([]Fields, 1) | |||
inputStruct.Batch[0].Request.Params.Body.Fields[0].Field = setting.TimeField | |||
inputStruct.Batch[0].Request.Params.Body.Fields[0].Format = setting.ElkTimeFormat | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter = make([]Filter, 2) | |||
//限定message | |||
var bool Bool | |||
bool.Should = make([]Should, 1) | |||
bool.Should[0].MatchPhrase.Message = MessageInfo | |||
bool.MinimumShouldMatch = 1 | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[0].Bool = &bool | |||
//限定查询时间 | |||
var timeRange Range | |||
timeRange.Timestamptest.Gte = Gte | |||
timeRange.Timestamptest.Lte = Lte | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[1].Range = &timeRange | |||
//限定非项目 | |||
// var boolIn BoolIn | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.MustNot = make([]MustNot, 1) | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.MustNot[0].MustNotMatchPhrase.ProjectName = NotProject | |||
return inputStruct | |||
} | |||
//初始化传给elk的数据结构,给定查询信息和tagName,查询的起止时间,返回初始化后的结构 | |||
func TagNameInit(MessageInfo string, Tagname string, Gte string, Lte string) (projectViewInit InputInfo) { | |||
var inputStruct InputInfo | |||
inputStruct.Batch = make([]Batch, 1) | |||
inputStruct.Batch[0].Request.Params.Index = setting.Index | |||
inputStruct.Batch[0].Request.Params.Body.Size = 0 | |||
inputStruct.Batch[0].Request.Params.Body.Fields = make([]Fields, 1) | |||
inputStruct.Batch[0].Request.Params.Body.Fields[0].Field = setting.TimeField | |||
inputStruct.Batch[0].Request.Params.Body.Fields[0].Format = setting.ElkTimeFormat | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter = make([]Filter, 3) | |||
//限定message | |||
var bool Bool | |||
bool.Should = make([]Should, 1) | |||
bool.Should[0].MatchPhrase.Message = MessageInfo | |||
bool.MinimumShouldMatch = 1 | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[0].Bool = &bool | |||
//限定tagName | |||
var tagName FilterMatchPhrase | |||
tagName.TagName = Tagname | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[1].FilterMatchPhrase = &tagName | |||
//限定查询时间 | |||
var timeRange Range | |||
timeRange.Timestamptest.Gte = Gte | |||
timeRange.Timestamptest.Lte = Lte | |||
inputStruct.Batch[0].Request.Params.Body.Query.BoolIn.Filter[2].Range = &timeRange | |||
return inputStruct | |||
} | |||
//向elk发送请求,将获取的结果只保留访问量,输入是初始化后的数据结构,返回访问量 | |||
func ViewInfo(viewInfo InputInfo) (totalView int) { | |||
jsons, errs := json.Marshal(viewInfo) | |||
if errs != nil { | |||
fmt.Println("errs:", errs.Error()) | |||
} | |||
// fmt.Println("viewInfoInit:",string(jsons)) | |||
var jsonStr = []byte(jsons) | |||
var resultInfo ResultInfo | |||
loaded, totalView := GetResultFromElk(resultInfo, SendReqToElk(jsonStr)) | |||
time := 0 | |||
for { | |||
if loaded == 0 { | |||
loaded_next, totalView := GetResultFromElk(resultInfo, SendReqToElk(jsonStr)) | |||
time++ | |||
if loaded_next != 0 && time < 100 { | |||
fmt.Println("totalView:", totalView) | |||
return totalView | |||
} | |||
if time > 100 { | |||
break | |||
} | |||
} else { | |||
break | |||
} | |||
} | |||
fmt.Println("loaded:", loaded) | |||
return totalView | |||
} | |||
// @title ProjectView | |||
// @description 获取指定用户和项目的访问量 | |||
// @param User string "用户名" | |||
// @param Project string "项目名" | |||
// @param Gte string "起始时间" 如time.Now().AddDate(0, 0, -1).Format(time.RFC3339) | |||
// @param Lte string "结束时间" 如time.Now().Format(time.RFC3339) | |||
// @return totalView int "访问量" | |||
func AppointProjectView(User string, Project string, Gte string, Lte string) (totalView int) { | |||
InitInfo := ProjectViewInit(User, Project, Gte, Lte) | |||
return ViewInfo(InitInfo) | |||
} | |||
//统计项目相关页面的访问量 | |||
type ProjectInfo struct { | |||
/* 统计所有项目中该页面的浏览情况,不需要区分项目。以aiforge项目为例 */ | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/datasets?type=0 | |||
Project_dataset_type_0 int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/datasets?type=1 | |||
Project_dataset_type_1 int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/issues | |||
Project_issues int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/labels | |||
Project_labels int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/milestones | |||
Project_milestones int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/pulls | |||
Project_pulls int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/release | |||
Project_release int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/wiki | |||
Project_wiki int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/activity | |||
Project_activity int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/cloudbrain | |||
Project_cloudbrain int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/modelarts | |||
Project_modelarts int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/blockchain | |||
Project_blockchain int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/watchers | |||
Project_watchers int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/stars | |||
Project_stars int | |||
//地址:https://git.openi.org.cn/OpenI/aiforge/forks | |||
Project_forks int | |||
} | |||
// @title AllProjectView | |||
// @description 获取指定用户和项目的访问量 | |||
// @param Gte string "起始时间" 如time.Now().AddDate(0, 0, -1).Format(time.RFC3339) | |||
// @param Lte string "结束时间" | |||
// @return projectInfo ProjectInfo "统计所有项目中页面的浏览情况,不需要区分项目" | |||
func AllProjectView(Gte string, Lte string) (projectInfo ProjectInfo) { | |||
projectInfo.Project_dataset_type_0 = ViewInfo(AllProjectViewInit("/datasets?type=0", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_dataset_type_1 = ViewInfo(AllProjectViewInit("/datasets?type=1", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_issues = ViewInfo(AllProjectViewInit("/issues HTTP/2.0", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_labels = ViewInfo(TagNameInit("/labels HTTP/2.0", "labels", Gte, Lte)) | |||
projectInfo.Project_milestones = ViewInfo(AllProjectViewInit("/milestones HTTP/2.0", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_pulls = ViewInfo(AllProjectViewInit("/pulls HTTP/2.0", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_release = ViewInfo(AllProjectViewInit("/release HTTP/2.0", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_wiki = ViewInfo(AllProjectViewInit("/wiki HTTP/2.0", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_activity = ViewInfo(AllProjectViewInit("/activity HTTP/2.0", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_cloudbrain = ViewInfo(AllProjectViewInit("/cloudbrain HTTP/2.0", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_modelarts = ViewInfo(AllProjectViewInit("/modelarts HTTP/2.0", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_blockchain = ViewInfo(AllProjectViewInit("/blockchain HTTP/2.0", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_watchers = ViewInfo(AllProjectViewInit("/watchers HTTP/2.0", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_stars = ViewInfo(AllProjectViewInit("/stars HTTP/2.0", "%{[request][2]}", Gte, Lte)) | |||
projectInfo.Project_forks = ViewInfo(AllProjectViewInit("/forks HTTP/2.0", "%{[request][2]}", Gte, Lte)) | |||
return projectInfo | |||
} |
@@ -482,6 +482,14 @@ var ( | |||
PoolInfos string | |||
Flavor string | |||
FlavorInfos string | |||
//elk config | |||
ElkUrl string | |||
ElkUser string | |||
ElkPassword string | |||
Index string | |||
TimeField string | |||
ElkTimeFormat string | |||
) | |||
// DateLang transforms standard language locale name to corresponding value in datetime plugin. | |||
@@ -1201,6 +1209,14 @@ func NewContext() { | |||
PoolInfos = sec.Key("POOL_INFOS").MustString("") | |||
Flavor = sec.Key("FLAVOR").MustString("") | |||
FlavorInfos = sec.Key("FLAVOR_INFOS").MustString("") | |||
sec = Cfg.Section("elk") | |||
ElkUrl = sec.Key("ELKURL").MustString("http://192.168.207.35:5601/internal/bsearch") | |||
ElkUser = sec.Key("ELKUSER").MustString("Qizhi") | |||
ElkPassword = sec.Key("ELKPASSWORD").MustString("Pcl2020") | |||
Index = sec.Key("INDEX").MustString("filebeat-7.3.2*") | |||
TimeField = sec.Key("TIMEFIELD").MustString(" @timestamptest") | |||
ElkTimeFormat = sec.Key("ELKTIMEFORMAT").MustString("date_time") | |||
} | |||
func loadInternalToken(sec *ini.Section) string { | |||
@@ -87,7 +87,7 @@ write = Write | |||
preview = Preview | |||
loading = Loading… | |||
error404_index = Request forbidden by administrative rules | |||
error404_index = Request forbidden by administrative rules | |||
error500_index = Internal Server Error | |||
error404 = The page you are trying to reach either <strong>does not exist</strong> or <strong>you are not authorized</strong> to view it. | |||
error500= Sorry, the site has encountered some problems, we are trying to <strong>fix the page</strong>, please try again later. | |||
@@ -573,7 +573,7 @@ authorized_oauth2_applications_description = You've granted access to your perso | |||
revoke_key = Revoke | |||
revoke_oauth2_grant = Revoke Access | |||
revoke_oauth2_grant_description = Revoking access for this third party application will prevent this application from accessing your data. Are you sure? | |||
revoke_oauth2_grant_success = You've revoked access successfully. | |||
revoke_oauth2_grant_success = You have revoked access successfully. | |||
twofa_desc = Two-factor authentication enhances the security of your account. | |||
twofa_is_enrolled = Your account is currently <strong>enrolled</strong> in two-factor authentication. | |||
@@ -770,6 +770,10 @@ cloudbrain_selection = select cloudbrain | |||
cloudbrain_platform_selection = Select the cloudbrain platform you want to use: | |||
confirm_choice = confirm | |||
cloudbran1_tips = Only data in zip format can create cloudbrain tasks | |||
cloudbrain_creator=Creator | |||
cloudbrain_task = Task Name | |||
cloudbrain_operate = Operate | |||
cloudbrain_status_createtime = Status/Createtime | |||
template.items = Template Items | |||
template.git_content = Git Content (Default Branch) | |||
@@ -831,6 +835,7 @@ fork = Fork | |||
download_archive = Download Repository | |||
no_desc = No Description | |||
no_label = No labels | |||
quick_guide = Quick Guide | |||
clone_this_repo = Clone this repository | |||
create_new_repo_command = Creating a new repository on the command line | |||
@@ -845,6 +850,7 @@ filter_branch_and_tag = Filter branch or tag | |||
branches = Branches | |||
tags = Tags | |||
issues = Issues | |||
issues_detail = Detail | |||
pulls = Pull Requests | |||
labels = Labels | |||
org_labels_desc = Organization level labels that can be used with <strong>all repositories</strong> under this organization | |||
@@ -1241,6 +1247,11 @@ pulls.reject_count_1 = "%d change request" | |||
pulls.reject_count_n = "%d change requests" | |||
pulls.waiting_count_1 = "%d waiting review" | |||
pulls.waiting_count_n = "%d waiting reviews" | |||
pulls.commits_count_1=This branch is %d commit behind the upstream. | |||
pulls.commits_count_n=This branch is %d commit behind the upstream. | |||
pulls.fetch_upstream=Fetch upstream | |||
pulls.upstream_up_to_date=No new commits to fetch | |||
pulls.upstream_error=Cannot get upstream info | |||
pulls.no_merge_desc = This pull request cannot be merged because all repository merge options are disabled. | |||
pulls.no_merge_helper = Enable merge options in the repository settings or merge the pull request manually. | |||
@@ -772,6 +772,10 @@ cloudbrain_selection=云脑选择 | |||
cloudbrain_platform_selection=选择您准备使用的云脑平台: | |||
confirm_choice=确定 | |||
cloudbran1_tips=只有zip格式的数据集才能发起云脑任务 | |||
cloudbrain_creator=创建者 | |||
cloudbrain_task=任务名称 | |||
cloudbrain_operate=操作 | |||
cloudbrain_status_createtime=状态/创建时间 | |||
template.items=模板选项 | |||
template.git_content=Git数据(默认分支) | |||
@@ -833,6 +837,7 @@ fork=派生 | |||
download_archive=下载此项目 | |||
no_desc=暂无描述 | |||
no_label = 暂无标签 | |||
quick_guide=快速帮助 | |||
clone_this_repo=克隆当前项目 | |||
create_new_repo_command=从命令行创建一个新的项目 | |||
@@ -847,6 +852,7 @@ filter_branch_and_tag=过滤分支或标签 | |||
branches=分支列表 | |||
tags=标签列表 | |||
issues=任务 | |||
issues_detail=详情 | |||
pulls=合并请求 | |||
labels=标签 | |||
org_labels_desc=组织级别的标签,可以被本组织下的 <strong>所有项目</strong> 使用 | |||
@@ -1243,6 +1249,11 @@ pulls.reject_count_1=%d 变更请求 | |||
pulls.reject_count_n=%d 变更请求 | |||
pulls.waiting_count_1=%d 个正在等待审核 | |||
pulls.waiting_count_n=%d 个正在等待审核 | |||
pulls.commits_count_1=当前分支落后上游分支 %d 个提交 | |||
pulls.commits_count_n=当前分支落后上游分支 %d 个提交 | |||
pulls.fetch_upstream=拉取上游更新 | |||
pulls.upstream_up_to_date=上游分支没有新的更新 | |||
pulls.upstream_error=获取上游分支信息错误 | |||
pulls.no_merge_desc=由于未启用合并选项,此合并请求无法被合并。 | |||
pulls.no_merge_helper=在项目设置中启用合并选项或者手工合并请求。 | |||
@@ -149,8 +149,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { | |||
//todo:support other topics | |||
keyword := strings.Trim(ctx.Query("q"), " ") | |||
topicOnly := ctx.QueryBool("topic") | |||
ctx.Data["TopicOnly"] = topicOnly | |||
topic := strings.Trim(ctx.Query("topic"), " ") | |||
repos, count, err = models.SearchRepository(&models.SearchRepoOptions{ | |||
ListOptions: models.ListOptions{ | |||
@@ -164,7 +163,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { | |||
OwnerID: opts.OwnerID, | |||
AllPublic: true, | |||
AllLimited: true, | |||
TopicOnly: topicOnly, | |||
TopicName: topic, | |||
IncludeDescription: setting.UI.SearchRepoDescription, | |||
}) | |||
if err != nil { | |||
@@ -177,6 +176,8 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { | |||
repo.Active = int64(repo.NumIssues) + int64(repo.NumPulls) + int64(repo.NumCommit) | |||
} | |||
ctx.Data["Keyword"] = keyword | |||
ctx.Data["Topic"] = topic | |||
ctx.Data["Total"] = count | |||
ctx.Data["Repos"] = repos | |||
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled | |||
@@ -4,6 +4,7 @@ import ( | |||
"bufio" | |||
"encoding/json" | |||
"errors" | |||
"fmt" | |||
"io" | |||
"net/http" | |||
"os" | |||
@@ -69,11 +70,13 @@ func CloudBrainIndex(ctx *context.Context) { | |||
timestamp := time.Now().Unix() | |||
for i, task := range ciTasks { | |||
if task.Status == string(models.JobRunning) && (timestamp-int64(task.CreatedUnix) > 10) { | |||
if task.Status == string(models.JobRunning) && (timestamp-int64(task.Cloudbrain.CreatedUnix) > 10) { | |||
ciTasks[i].CanDebug = true | |||
} else { | |||
ciTasks[i].CanDebug = false | |||
} | |||
ciTasks[i].CanDel = models.CanDelJob(ctx.IsSigned, ctx.User, task) | |||
} | |||
pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||
@@ -390,19 +393,39 @@ func StopJobs(cloudBrains []*models.Cloudbrain) { | |||
for _, taskInfo := range cloudBrains { | |||
if taskInfo.Type == models.TypeCloudBrainOne { | |||
err := cloudbrain.StopJob(taskInfo.JobID) | |||
err := retry(3, time.Second*30, func() error { | |||
return cloudbrain.StopJob(taskInfo.JobID) | |||
}) | |||
logErrorAndUpdateJobStatus(err, taskInfo) | |||
} else { | |||
param := models.NotebookAction{ | |||
Action: models.ActionStop, | |||
} | |||
_, err := modelarts.StopJob(taskInfo.JobID, param) | |||
err := retry(3, time.Second*30, func() error { | |||
_, err := modelarts.StopJob(taskInfo.JobID, param) | |||
return err | |||
}) | |||
logErrorAndUpdateJobStatus(err, taskInfo) | |||
} | |||
} | |||
} | |||
func retry(attempts int, sleep time.Duration, f func() error) (err error) { | |||
for i := 0; i < attempts; i++ { | |||
if i > 0 { | |||
log.Warn("retrying after error:", err) | |||
time.Sleep(sleep) | |||
} | |||
err = f() | |||
if err == nil { | |||
return nil | |||
} | |||
} | |||
return fmt.Errorf("after %d attempts, last error: %s", attempts, err) | |||
} | |||
func logErrorAndUpdateJobStatus(err error, taskInfo *models.Cloudbrain) { | |||
if err != nil { | |||
log.Warn("Failed to stop cloudBrain job:"+taskInfo.JobID, err) | |||
@@ -57,6 +57,8 @@ func ModelArtsIndex(ctx *context.Context) { | |||
} else { | |||
ciTasks[i].CanDebug = false | |||
} | |||
ciTasks[i].CanDel = models.CanDelJob(ctx.IsSigned, ctx.User, task) | |||
} | |||
pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||
@@ -790,6 +790,46 @@ func renderCode(ctx *context.Context) { | |||
} | |||
} | |||
//如果是fork的仓库 | |||
if ctx.Repo.Repository.IsFork { | |||
//获得fetchUpstream对应的分支参数 | |||
/* | |||
// 1. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headBranch} | |||
// 2. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headOwner}:{:headBranch} | |||
// 3. /{:baseOwner}/{:baseRepoName}/compare/{:baseBranch}...{:headOwner}/{:headRepoName}:{:headBranch} | |||
*/ | |||
baseGitRepo, err := git.OpenRepository(ctx.Repo.Repository.BaseRepo.RepoPath()) | |||
defer baseGitRepo.Close() | |||
if err != nil { | |||
log.Error("error open baseRepo:%s",ctx.Repo.Repository.BaseRepo.RepoPath()) | |||
ctx.Data["FetchUpstreamCnt"] = -1 // minus value indicates error | |||
}else{ | |||
if _,error:= baseGitRepo.GetBranch(ctx.Repo.BranchName);error==nil{ | |||
//base repo has the same branch, then compare between current repo branch and base repo's branch | |||
compareUrl := ctx.Repo.BranchName + "..." + ctx.Repo.Repository.BaseRepo.OwnerName + "/" + ctx.Repo.Repository.BaseRepo.Name + ":" + ctx.Repo.BranchName | |||
ctx.SetParams("*",compareUrl) | |||
ctx.Data["UpstreamSameBranchName"] = true | |||
}else{ | |||
//else, compare between current repo branch and base repo's default branch | |||
compareUrl := ctx.Repo.BranchName + "..." + ctx.Repo.Repository.BaseRepo.OwnerName + "/" + ctx.Repo.Repository.BaseRepo.Name + ":" + ctx.Repo.Repository.BaseRepo.DefaultBranch | |||
ctx.SetParams("*",compareUrl) | |||
ctx.Data["UpstreamSameBranchName"] = false | |||
} | |||
_, _, headGitRepo, compareInfo, _, _ := ParseCompareInfo(ctx) | |||
defer headGitRepo.Close() | |||
if compareInfo!= nil { | |||
if compareInfo.Commits!=nil { | |||
log.Info("compareInfoCommits数量:%d",compareInfo.Commits.Len()) | |||
ctx.Data["FetchUpstreamCnt"] = compareInfo.Commits.Len() | |||
}else{ | |||
log.Info("compareInfo nothing different") | |||
ctx.Data["FetchUpstreamCnt"] = 0 | |||
} | |||
}else{ | |||
ctx.Data["FetchUpstreamCnt"] = -1 // minus value indicates error | |||
} | |||
} | |||
} | |||
ctx.Data["Paths"] = paths | |||
ctx.Data["TreeLink"] = treeLink | |||
ctx.Data["TreeNames"] = treeNames | |||
@@ -7,6 +7,7 @@ package secure | |||
import ( | |||
"net/http" | |||
"net/mail" | |||
"strings" | |||
"code.gitea.io/gitea/models" | |||
@@ -63,6 +64,14 @@ func CreateUser(ctx *context.Context, form api.CreateUserOption) { | |||
// "422": | |||
// "$ref": "#/responses/validationError" | |||
_, err1 := mail.ParseAddress(form.Email) | |||
if err1 != nil { | |||
ctx.JSON(http.StatusBadRequest, map[string]string{ | |||
"error_msg": "Email format is wrong.", | |||
}) | |||
return | |||
} | |||
u := &models.User{ | |||
Name: form.Username, | |||
FullName: form.FullName, | |||
@@ -154,7 +154,7 @@ | |||
{{svg "octicon-person" 16}} {{.i18n.Tr "register"}} | |||
</a> | |||
{{end}} | |||
<a class="item{{if .PageIsSignIn}} active{{end}}" rel="nofollow" href="{{AppSubUrl}}/user/login?redirect_to={{.Link}}"> | |||
<a class="item{{if .PageIsSignIn}} active{{end}}" rel="nofollow" href="{{AppSubUrl}}/user/login"> | |||
{{svg "octicon-sign-in" 16}} {{.i18n.Tr "sign_in"}} | |||
</a> | |||
</div><!-- end anonymous right menu --> | |||
@@ -154,7 +154,7 @@ | |||
{{svg "octicon-person" 16}} {{.i18n.Tr "register"}} | |||
</a> | |||
{{end}} | |||
<a class="item{{if .PageIsSignIn}} active{{end}}" rel="nofollow" href="{{AppSubUrl}}/user/login?redirect_to={{.Link}}"> | |||
<a class="item{{if .PageIsSignIn}} active{{end}}" rel="nofollow" href="{{AppSubUrl}}/user/login"> | |||
{{svg "octicon-sign-in" 16}} {{.i18n.Tr "sign_in"}} | |||
</a> | |||
</div><!-- end anonymous right menu --> | |||
@@ -1,12 +1,12 @@ | |||
<div class="repos--seach"> | |||
<div class="ui container"> | |||
<div class="ui two column centered grid"> | |||
<form class="mobile ten wide tablet computer column ui form ignore-dirty"> | |||
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty"> | |||
<div class="ui fluid action input"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<input type="hidden" name="sort" value="{{$.SortType}}"> | |||
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button> | |||
<button class="ui green button">{{.i18n.Tr "explore.search"}}</button> | |||
</div> | |||
</form> | |||
</div> | |||
@@ -6,67 +6,67 @@ | |||
</svg> | |||
全部领域 | |||
</a> | |||
<a class="{{if eq $.Keyword "大模型"}}active {{end}}item" href="/explore/repos?q=大模型&topic=1&sort={{.SortType}}"> | |||
<a class="{{if eq $.Topic "大模型"}}active {{end}}item" href="/explore/repos?q=&topic=大模型&sort={{.SortType}}"> | |||
<svg class="svg octicon-inbox" width="16" height="16" viewBox="0 0 24 24"> | |||
<path fill="currentColor" d="M19 3H5C3.89 3 3 3.89 3 5V19C3 20.11 3.9 21 5 21H19C20.11 21 21 20.11 21 19V5C21 3.89 20.1 3 19 3M16.1 15.9C15.07 15.9 14.09 15.5 13.35 14.76L12.71 14.12L14.13 12.71L14.76 13.34C15.12 13.7 15.6 13.9 16.11 13.9C17.15 13.9 18 13.05 18 12S17.15 10.1 16.1 10.1C15.6 10.1 15.12 10.3 14.76 10.66L10.65 14.76C9.91 15.5 8.94 15.9 7.9 15.9C5.75 15.9 4 14.15 4 12S5.75 8.1 7.9 8.1C8.94 8.1 9.91 8.5 10.65 9.24L11.29 9.88L9.87 11.3L9.24 10.66C8.88 10.3 8.4 10.1 7.9 10.1C6.85 10.1 6 10.95 6 12S6.85 13.9 7.9 13.9C8.4 13.9 8.88 13.7 9.24 13.34L13.35 9.24C14.09 8.5 15.06 8.1 16.1 8.1C18.25 8.1 20 9.85 20 12S18.25 15.9 16.1 15.9Z" /> | |||
</svg> | |||
大模型 | |||
</a> | |||
<a class="{{if eq $.Keyword "AI开发工具"}}active {{end}}item" href="/explore/repos?q=AI开发工具&topic=1&sort={{.SortType}}"> | |||
<a class="{{if eq $.Topic "AI开发工具"}}active {{end}}item" href="/explore/repos?q=&topic=AI开发工具&sort={{.SortType}}"> | |||
<svg class="svg octicon-inbox" width="16" height="16" viewBox="0 0 24 24"> | |||
<path fill="currentColor" d="M19 3H5C3.9 3 3 3.9 3 5V19C3 20.1 3.9 21 5 21H19C20.1 21 21 20.1 21 19V5C21 3.9 20.1 3 19 3M11 8H9V10C9 11.1 8.1 12 7 12C8.1 12 9 12.9 9 14V16H11V18H9C7.9 18 7 17.1 7 16V15C7 13.9 6.1 13 5 13V11C6.1 11 7 10.1 7 9V8C7 6.9 7.9 6 9 6H11V8M19 13C17.9 13 17 13.9 17 15V16C17 17.1 16.1 18 15 18H13V16H15V14C15 12.9 15.9 12 17 12C15.9 12 15 11.1 15 10V8H13V6H15C16.1 6 17 6.9 17 8V9C17 10.1 17.9 11 19 11V13Z" /> | |||
</svg> | |||
AI开发工具 | |||
</a> | |||
<a class="{{if eq $.Keyword "计算机视觉"}}active {{end}}item" href="/explore/repos?q=计算机视觉&topic=1&sort={{.SortType}}"> | |||
<a class="{{if eq $.Topic "计算机视觉"}}active {{end}}item" href="/explore/repos?q=&topic=计算机视觉&sort={{.SortType}}"> | |||
<svg class="svg octicon-inbox" width="16" height="16" viewBox="0 0 24 24"> | |||
<path fill="currentColor" d="M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9M12,17A5,5 0 0,1 7,12A5,5 0 0,1 12,7A5,5 0 0,1 17,12A5,5 0 0,1 12,17M12,4.5C7,4.5 2.73,7.61 1,12C2.73,16.39 7,19.5 12,19.5C17,19.5 21.27,16.39 23,12C21.27,7.61 17,4.5 12,4.5Z" /> | |||
</svg> | |||
计算机视觉 | |||
</a> | |||
<a class="{{if eq $.Keyword "自然语言处理"}}active {{end}}item" href="/explore/repos?q=自然语言处理&topic=1&sort={{.SortType}}"> | |||
<a class="{{if eq $.Topic "自然语言处理"}}active {{end}}item" href="/explore/repos?q=&topic=自然语言处理&sort={{.SortType}}"> | |||
<svg class="svg octicon-inbox" width="16" height="16" viewBox="0 0 24 24"> | |||
<path fill="currentColor" d="M9,5A4,4 0 0,1 13,9A4,4 0 0,1 9,13A4,4 0 0,1 5,9A4,4 0 0,1 9,5M9,15C11.67,15 17,16.34 17,19V21H1V19C1,16.34 6.33,15 9,15M16.76,5.36C18.78,7.56 18.78,10.61 16.76,12.63L15.08,10.94C15.92,9.76 15.92,8.23 15.08,7.05L16.76,5.36M20.07,2C24,6.05 23.97,12.11 20.07,16L18.44,14.37C21.21,11.19 21.21,6.65 18.44,3.63L20.07,2Z" /> | |||
</svg> | |||
自然语言处理 | |||
</a> | |||
<a class="{{if eq $.Keyword "机器学习"}}active {{end}}item" href="/explore/repos?q=机器学习&topic=1&sort={{.SortType}}"> | |||
<a class="{{if eq $.Topic "机器学习"}}active {{end}}item" href="/explore/repos?q=&topic=机器学习&sort={{.SortType}}"> | |||
<svg class="svg octicon-inbox" width="16" height="16" viewBox="0 0 24 24"> | |||
<path fill="currentColor" d="M19,12V13.5A4,4 0 0,1 23,17.5C23,18.32 22.75,19.08 22.33,19.71L21.24,18.62C21.41,18.28 21.5,17.9 21.5,17.5A2.5,2.5 0 0,0 19,15V16.5L16.75,14.25L19,12M19,23V21.5A4,4 0 0,1 15,17.5C15,16.68 15.25,15.92 15.67,15.29L16.76,16.38C16.59,16.72 16.5,17.1 16.5,17.5A2.5,2.5 0 0,0 19,20V18.5L21.25,20.75L19,23M12,3C16.42,3 20,4.79 20,7C20,9.21 16.42,11 12,11C7.58,11 4,9.21 4,7C4,4.79 7.58,3 12,3M4,9C4,11.21 7.58,13 12,13C13.11,13 14.17,12.89 15.14,12.68C14.19,13.54 13.5,14.67 13.18,15.96L12,16C7.58,16 4,14.21 4,12V9M20,9V11H19.5L18.9,11.03C19.6,10.43 20,9.74 20,9M4,14C4,16.21 7.58,18 12,18L13,17.97C13.09,19.03 13.42,20 13.95,20.88L12,21C7.58,21 4,19.21 4,17V14Z" /> | |||
</svg> | |||
机器学习 | |||
</a> | |||
<a class="{{if eq $.Keyword "神经网络"}}active {{end}}item" href="/explore/repos?q=神经网络&topic=1&sort={{.SortType}}"> | |||
<a class="{{if eq $.Topic "神经网络"}}active {{end}}item" href="/explore/repos?q=&topic=神经网络&sort={{.SortType}}"> | |||
<svg class="svg octicon-inbox" width="16" height="16" viewBox="0 0 24 24"> | |||
<path fill="currentColor" d="M13 3C9.23 3 6.19 5.95 6 9.66L4.08 12.19C3.84 12.5 4.08 13 4.5 13H6V16C6 17.11 6.89 18 8 18H9V21H16V16.31C18.37 15.19 20 12.8 20 10C20 6.14 16.88 3 13 3M17.06 9.57L15.1 10.09L16.54 11.54C16.89 11.88 16.89 12.46 16.54 12.81C16.19 13.16 15.61 13.16 15.27 12.81L13.81 11.37L13.3 13.33C13.18 13.82 12.68 14.1 12.21 13.97C11.72 13.84 11.44 13.35 11.57 12.87L12.1 10.9L10.13 11.43C9.65 11.56 9.15 11.28 9.03 10.79C8.9 10.32 9.18 9.82 9.67 9.7L11.63 9.19L10.19 7.73C9.84 7.39 9.84 6.82 10.19 6.46C10.54 6.11 11.12 6.11 11.46 6.46L12.91 7.9L13.43 5.94C13.55 5.46 14.04 5.18 14.5 5.3C15 5.43 15.28 5.92 15.16 6.41L14.63 8.37L16.59 7.84C17.08 7.72 17.57 8 17.7 8.5C17.82 8.96 17.54 9.45 17.06 9.57Z" /> | |||
</svg> | |||
神经网络 | |||
</a> | |||
<a class="{{if eq $.Keyword "自动驾驶"}}active {{end}}item" href="/explore/repos?q=自动驾驶&topic=1&sort={{.SortType}}"> | |||
<a class="{{if eq $.Topic "自动驾驶"}}active {{end}}item" href="/explore/repos?q=&topic=自动驾驶&sort={{.SortType}}"> | |||
<svg class="svg octicon-inbox" width="16" height="16" viewBox="0 0 24 24"> | |||
<path fill="currentColor" d="M5,14H19L17.5,9.5H6.5L5,14M17.5,19A1.5,1.5 0 0,0 19,17.5A1.5,1.5 0 0,0 17.5,16A1.5,1.5 0 0,0 16,17.5A1.5,1.5 0 0,0 17.5,19M6.5,19A1.5,1.5 0 0,0 8,17.5A1.5,1.5 0 0,0 6.5,16A1.5,1.5 0 0,0 5,17.5A1.5,1.5 0 0,0 6.5,19M18.92,9L21,15V23A1,1 0 0,1 20,24H19A1,1 0 0,1 18,23V22H6V23A1,1 0 0,1 5,24H4A1,1 0 0,1 3,23V15L5.08,9C5.28,8.42 5.85,8 6.5,8H17.5C18.15,8 18.72,8.42 18.92,9M12,0C14.12,0 16.15,0.86 17.65,2.35L16.23,3.77C15.11,2.65 13.58,2 12,2C10.42,2 8.89,2.65 7.77,3.77L6.36,2.35C7.85,0.86 9.88,0 12,0M12,4C13.06,4 14.07,4.44 14.82,5.18L13.4,6.6C13.03,6.23 12.53,6 12,6C11.5,6 10.97,6.23 10.6,6.6L9.18,5.18C9.93,4.44 10.94,4 12,4Z" /> | |||
</svg> | |||
自动驾驶 | |||
</a> | |||
<a class="{{if eq $.Keyword "机器人"}}active {{end}}item" href="/explore/repos?q=机器人&topic=1&sort={{.SortType}}"> | |||
<a class="{{if eq $.Topic "机器人"}}active {{end}}item" href="/explore/repos?q=&topic=机器人&sort={{.SortType}}"> | |||
<svg class="svg octicon-inbox" width="16" height="16" viewBox="0 0 24 24"> | |||
<path fill="currentColor" d="M12,2A2,2 0 0,1 14,4C14,4.74 13.6,5.39 13,5.73V7H14A7,7 0 0,1 21,14H22A1,1 0 0,1 23,15V18A1,1 0 0,1 22,19H21V20A2,2 0 0,1 19,22H5A2,2 0 0,1 3,20V19H2A1,1 0 0,1 1,18V15A1,1 0 0,1 2,14H3A7,7 0 0,1 10,7H11V5.73C10.4,5.39 10,4.74 10,4A2,2 0 0,1 12,2M7.5,13A2.5,2.5 0 0,0 5,15.5A2.5,2.5 0 0,0 7.5,18A2.5,2.5 0 0,0 10,15.5A2.5,2.5 0 0,0 7.5,13M16.5,13A2.5,2.5 0 0,0 14,15.5A2.5,2.5 0 0,0 16.5,18A2.5,2.5 0 0,0 19,15.5A2.5,2.5 0 0,0 16.5,13Z" /> | |||
</svg> | |||
机器人 | |||
</a> | |||
<a class="{{if eq $.Keyword "联邦学习"}}active {{end}}item" href="/explore/repos?q=联邦学习&topic=1&sort={{.SortType}}"> | |||
<a class="{{if eq $.Topic "联邦学习"}}active {{end}}item" href="/explore/repos?q=&topic=联邦学习&sort={{.SortType}}"> | |||
<svg class="svg octicon-inbox" width="16" height="16" viewBox="0 0 24 24"> | |||
<path fill="currentColor" d="M3 11H11V3H3M5 5H9V9H5M13 21H21V13H13M15 15H19V19H15M3 21H11V13H3M5 15H9V19H5M13 3V11H21V3M19 9H15V5H19Z" /> | |||
</svg> | |||
联邦学习 | |||
</a> | |||
<a class="{{if eq $.Keyword "数据挖掘"}}active {{end}}item" href="/explore/repos?q=数据挖掘&topic=1&sort={{.SortType}}"> | |||
<a class="{{if eq $.Topic "数据挖掘"}}active {{end}}item" href="/explore/repos?q=&topic=数据挖掘&sort={{.SortType}}"> | |||
<svg class="svg octicon-inbox" width="16" height="16" viewBox="0 0 24 24"> | |||
<path fill="currentColor" d="M18.36,2.64C20,2.64 21.36,4 21.36,5.64C21.36,7.29 20,8.64 18.36,8.64C16.71,8.64 15.36,7.29 15.36,5.64C15.36,5.34 15.41,5.06 15.5,4.8C14.43,4.29 13.25,4 12,4A8,8 0 0,0 4,12L4.04,12.84L2.05,13.05L2,12A10,10 0 0,1 12,2C13.69,2 15.28,2.42 16.67,3.16C17.16,2.83 17.74,2.64 18.36,2.64M18.36,4.64A1,1 0 0,0 17.36,5.64A1,1 0 0,0 18.36,6.64C18.92,6.64 19.36,6.19 19.36,5.64C19.36,5.08 18.92,4.64 18.36,4.64M5.64,15.36C7.29,15.36 8.64,16.71 8.64,18.36C8.64,18.66 8.59,18.94 8.5,19.2C9.57,19.71 10.75,20 12,20A8,8 0 0,0 20,12L19.96,11.16L21.95,10.95L22,12A10,10 0 0,1 12,22C10.31,22 8.72,21.58 7.33,20.84C6.84,21.17 6.26,21.36 5.64,21.36C4,21.36 2.64,20 2.64,18.36C2.64,16.71 4,15.36 5.64,15.36M5.64,17.36C5.08,17.36 4.64,17.81 4.64,18.36C4.64,18.92 5.08,19.36 5.64,19.36A1,1 0 0,0 6.64,18.36A1,1 0 0,0 5.64,17.36M12,8A4,4 0 0,1 16,12A4,4 0 0,1 12,16A4,4 0 0,1 8,12A4,4 0 0,1 12,8Z" /> | |||
</svg> | |||
数据挖掘 | |||
</a> | |||
<a class="{{if eq $.Keyword "RISC-V"}}active {{end}}item" href="/explore/repos?q=RISC-V&topic=1&sort={{.SortType}}"> | |||
<a class="{{if eq $.Topic "RISC-V"}}active {{end}}item" href="/explore/repos?q=&topic=RISC-V&sort={{.SortType}}"> | |||
<svg class="svg octicon-inbox" width="16" height="16" viewBox="0 0 24 24"> | |||
<path fill="currentColor" d="M17,17H7V7H17M21,11V9H19V7C19,5.89 18.1,5 17,5H15V3H13V5H11V3H9V5H7C5.89,5 5,5.89 5,7V9H3V11H5V13H3V15H5V17A2,2 0 0,0 7,19H9V21H11V19H13V21H15V19H17A2,2 0 0,0 19,17V15H21V13H19V11M13,13H11V11H13M15,9H9V15H15V9Z" /> | |||
</svg> | |||
@@ -40,20 +40,20 @@ | |||
<div class="ui secondary pointing tabular top attached borderless menu navbar"> | |||
{{if .PageIsExplore}} | |||
<a class="{{if eq .SortType "hot"}}active{{end}} item" href="{{$.Link}}?sort=hot&q={{$.Keyword}}&tab={{$.TabName}}"> | |||
<a class="{{if eq .SortType "hot"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=hot"> | |||
<svg class="svg octicon-repo" width="16" height="16" aria-hidden="true"> | |||
<use xlink:href="#octicon-repo" /> | |||
</svg> | |||
热门{{.i18n.Tr "explore.repos"}} | |||
</a> | |||
<a class="{{if eq .SortType "active"}}active{{end}} item" href="{{$.Link}}?sort=active&q={{$.Keyword}}&tab={{$.TabName}}"> | |||
<a class="{{if eq .SortType "active"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=active"> | |||
<svg class="svg octicon-inbox" width="16" height="16" aria-hidden="true"> | |||
<use xlink:href="#octicon-inbox" /> | |||
</svg> | |||
活跃{{.i18n.Tr "explore.repos"}} | |||
</a> | |||
{{end}} | |||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&tab={{$.TabName}}"> | |||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?q={{$.Keyword}}&topic={{$.Topic}}&sort=recentupdate"> | |||
<svg class="svg octicon-organization" width="16" height="16" aria-hidden="true"> | |||
<use xlink:href="#octicon-organization" /> | |||
</svg> {{.i18n.Tr "repo.issues.filter_sort.recentupdate"}} | |||
@@ -67,16 +67,16 @@ | |||
<i class="dropdown icon"></i> | |||
</span> | |||
<div class="menu"> | |||
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a> | |||
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a> | |||
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a> | |||
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a> | |||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&tab={{$.TabName}}">{{.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}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a> | |||
<a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a> | |||
<a class="{{if eq .SortType "feweststars"}}active{{end}} item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.feweststars"}}</a> | |||
<a class="{{if eq .SortType "mostforks"}}active{{end}} item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.mostforks"}}</a> | |||
<a class="{{if eq .SortType "fewestforks"}}active{{end}} item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.fewestforks"}}</a> | |||
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a> | |||
<a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a> | |||
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a> | |||
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a> | |||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a> | |||
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a> | |||
<a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a> | |||
<a class="{{if eq .SortType "feweststars"}}active{{end}} item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.feweststars"}}</a> | |||
<a class="{{if eq .SortType "mostforks"}}active{{end}} item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.mostforks"}}</a> | |||
<a class="{{if eq .SortType "fewestforks"}}active{{end}} item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&topic={{$.Topic}}">{{.i18n.Tr "repo.issues.filter_sort.fewestforks"}}</a> | |||
</div> | |||
</div> | |||
</div> | |||
@@ -143,7 +143,7 @@ | |||
{{if .Topics }} | |||
<div class="ui tags"> | |||
{{range .Topics}} | |||
{{if ne . "" }}<a href="{{AppSubUrl}}/explore/repos?q={{.}}&topic=1"><div class="ui small label topic">{{.}}</div></a>{{end}} | |||
{{if ne . "" }}<a href="{{AppSubUrl}}/explore/repos?q=&topic={{.}}"><div class="ui small label topic">{{.}}</div></a>{{end}} | |||
{{end}} | |||
</div> | |||
{{end}} | |||
@@ -9,7 +9,7 @@ | |||
<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 "explore.search"}}..." autofocus> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<input type="hidden" name="topic" value="{{$.Topic}}"> | |||
<input type="hidden" name="sort" value="{{$.SortType}}"> | |||
<button class="ui green button">{{.i18n.Tr "explore.search"}}</button> | |||
</div> | |||
@@ -1,11 +1,11 @@ | |||
<div class="repos--seach"> | |||
<div class="ui container"> | |||
<div class="ui two column centered grid"> | |||
<form class="sixteen wide mobile eight fourteen tablet fourteen wide computer column ui form ignore-dirty"> | |||
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty"> | |||
<div class="ui fluid action input"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button> | |||
<button class="ui green button">{{.i18n.Tr "explore.search"}}</button> | |||
</div> | |||
</form> | |||
</div> | |||
@@ -187,6 +187,12 @@ | |||
cursor: pointer; | |||
pointer-events: none; | |||
} | |||
.time-show{ | |||
font-size: 10px; | |||
margin-top: 0.4rem; | |||
display: inline-block; | |||
} | |||
</style> | |||
<!-- 弹窗 --> | |||
@@ -235,45 +241,87 @@ | |||
<div class="ui sixteen wide column"> | |||
<!-- 排序区 --> | |||
<div class="ui sixteen wide column"> | |||
<!-- <div class="ui sixteen wide column"> | |||
<div class="ui two column stackable grid"> | |||
<div class="column"> | |||
</div> | |||
<!-- <div class="column right aligned"> | |||
<div class="column right aligned"> | |||
<div class="ui right dropdown type jump item"> | |||
<span class="text"> | |||
{{.i18n.Tr "repo.issues.filter_sort"}}<i class="dropdown icon"></i> | |||
</span> | |||
</div> | |||
</div> --> | |||
</div> | |||
</div> | |||
</div> | |||
</div> --> | |||
<!-- 任务展示 --> | |||
<!-- 表头 --> | |||
<div class="dataset list"> | |||
<div class="ui grid stackable" style="background: #f0f0f0;;"> | |||
<div class="row"> | |||
<div class="five wide column"> | |||
<span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | |||
</div> | |||
<div class="three wide column"> | |||
<span>{{$.i18n.Tr "repo.cloudbrain_status_createtime"}}</span> | |||
</div> | |||
<div class="one wide column"> | |||
<span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span> | |||
</div> | |||
<div class="seven wide column text center"> | |||
<span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | |||
</div> | |||
</div> | |||
</div> | |||
{{range .Tasks}} | |||
<div class="ui grid stackable item"> | |||
<div class="row"> | |||
<!-- 任务名 --> | |||
<div class="six wide column"> | |||
<a class="title" href="{{$.Link}}/{{.JobID}}"> | |||
<span class="fitted">{{svg "octicon-tasklist" 16}}</span> | |||
<span class="fitted">{{.JobName}}</span> | |||
<div class="five wide column"> | |||
<a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.JobName}}" style="font-size: 15px;"> | |||
<span class="fitted" style="vertical-align: middle;">{{svg "octicon-tasklist" 16}}</span> | |||
<span class="fitted text_over" style="width: 90%;vertical-align: middle;margin-left: 0.4rem;">{{.JobName}}</span> | |||
</a> | |||
</div> | |||
<div class="three wide column"> | |||
<!--任务状态 --> | |||
<span class="ui compact button job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||
{{.Status}} | |||
<span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||
<!-- {{.Status}} --> | |||
<!-- {{if eq .Status "RUNNING"}} | |||
<span style="display:flex;position: relative; justify-content: flex-start;"><i class="i-round i-bg-stop"></i><span style="margin-left: 0.4em;font-size: 12px;">运行中</span></span> | |||
<span style="display:flex;position: relative; justify-content: flex-start;"><i class="i-round i-bg-stop"></i><span style="margin-left: 0.4em;font-size: 12px;">运行中</span></span> | |||
{{else}} | |||
{{.Status}} | |||
{{end}} --> | |||
<span><i style="vertical-align: middle;" class="{{.Status}}"></i><span style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||
</span> | |||
<!-- <span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}" > | |||
{{if eq .Status "STOPPED"}} | |||
<span style="display:flex;position: relative; justify-content: flex-start;"><i class="i-round i-bg-stop"></i><span style="margin-left: 0.4em;font-size: 12px;">已停止</span></span> | |||
{{else if eq .Status "RUNNING"}} | |||
<span style="display:flex;position: relative; justify-content: flex-start;"><i class="i-round i-bg-running"></i><span style="margin-left: 0.4em;font-size: 12px;">运行中</span></span> | |||
{{else if eq .Status "FAILED"}} | |||
<span style="display:flex;position: relative; justify-content: flex-start;"><i class="i-round i-bg-running"></i><span style="margin-left: 0.4em;font-size: 12px;">运行失败</span></span> | |||
{{else if eq .Status "WAITING"}} | |||
<span style="display:flex;position: relative; justify-content: flex-start;"><i class="showCircle"></i><span style="margin-left: 0.4em;font-size: 12px;">初始化等待</span></span> | |||
{{end}} | |||
</span> --> | |||
<!-- 任务创建时间 --> | |||
<span class="">{{TimeSinceUnix .CreatedUnix $.Lang}}</span> | |||
<span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | |||
</div> | |||
<div class="one wide column"> | |||
<a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a> | |||
</div> | |||
<div class="seven wide column text right"> | |||
<div class="ui compact buttons" style="margin-right:10px;"> | |||
<div class="ui compact buttons"> | |||
{{if and (ne .Status "WAITING") (ne .JobType "DEBUG")}} | |||
<a class="ui basic button" href="{{$.Link}}/{{.JobID}}/rate" target="_blank"> | |||
评分 | |||
@@ -304,10 +352,10 @@ | |||
</div> | |||
<!-- 删除镜像 --> | |||
<form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{if ne .Status "STOPPED"}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/del{{end}}" method="post"> | |||
<!-- 删除任务 --> | |||
<form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{if not .CanDel}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/del{{end}}" method="post"> | |||
{{$.CsrfTokenHtml}} | |||
<a class="ui compact {{if ne .Status "STOPPED"}}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||
<a class="ui compact {{if not .CanDel}}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||
删除 | |||
</a> | |||
</form> | |||
@@ -436,15 +484,18 @@ | |||
$(document).ready(loadJobStatus); | |||
function loadJobStatus() { | |||
$(".job-status").each((index, job) => { | |||
console.log("---------",index,job) | |||
const jobID = job.dataset.jobid; | |||
const repoPath = job.dataset.repopath; | |||
if (job.textContent.trim() == 'STOPPED') { | |||
return | |||
} | |||
$.get(`/api/v1/repos/${repoPath}/cloudbrain/${jobID}`, (data) => { | |||
const jobID = data.JobID | |||
const status = data.JobStatus | |||
console.log("status",status) | |||
if (status != job.textContent.trim()) { | |||
//$('#' + jobID).text(status) | |||
//if (status == 'STOPPED') { | |||
@@ -1,63 +1,52 @@ | |||
<style> | |||
</style> | |||
{{if .Attachments}} | |||
{{range .Attachments}} | |||
<div class="ui grid item" id="{{.UUID}}"> | |||
<div class="row"> | |||
<div class="{{if $.Permission.CanWrite $.UnitTypeDatasets}}five{{else}}nine{{end}} wide column"> | |||
<div class="eight wide column"> | |||
<span class="ui right">{{.Size | FileSize}}</span> | |||
<a class="title" href="{{.DownloadURL}}?type={{$.Type}}"> | |||
<span class="fitted">{{svg "octicon-cloud-download" 16}}</span> {{.Name}} | |||
{{svg "octicon-cloud-download" 16}} {{.Name}} | |||
</a> | |||
</div> | |||
<div class="two wide column"> | |||
{{.Size | FileSize}} | |||
</div> | |||
<div class="two wide column"> | |||
<span class="ui text center" data-tooltip='{{$.i18n.Tr "dataset.download_count"}}' data-position="bottom right">{{svg "octicon-flame" 16}} {{(.DownloadCount | PrettyNumber)}}</span> | |||
</div> | |||
<div class="one wide column" style="{{if ne $.Type 0}}visibility: hidden;{{end}}"> | |||
<span class="ui text center clipboard" data-clipboard-text="{{.DownloadURL}}" data-tooltip='{{$.i18n.Tr "dataset.copy_url"}}' data-clipboard-action="copy">{{svg "octicon-file" 16}}</span> | |||
</div> | |||
<div class="one wide column"> | |||
<span class="ui text center clipboard" data-clipboard-text="{{.FileChunk.Md5}}" data-tooltip='{{$.i18n.Tr "dataset.copy_md5"}}' data-clipboard-action="copy">{{svg "octicon-file-binary" 16}}</span> | |||
</div> | |||
<div class="wide column one" style="{{if ne .DecompressState 1}}visibility: hidden;{{end}}"> | |||
<a class="ui text center" href="datasets/dirs/{{.UUID}}?type={{$.Type}}" data-tooltip='{{$.i18n.Tr "dataset.directory"}}'>{{svg "octicon-file-directory" 16}}</a> | |||
</div> | |||
{{if $.IsSigned}} | |||
<div class="wide column one" style="{{if ne .DecompressState 1}}visibility: hidden;{{end}}"> | |||
<a class="ui text center" href="datasets/label/{{.UUID}}?type={{$.Type}}" data-tooltip='{{$.i18n.Tr "dataset.create_label_task"}}'><i class="fa fa-pencil-square-o" aria-hidden="true"></i></a> | |||
<div class="eight wide column right aligned"> | |||
<div class="ui left mini icon buttons"> | |||
<span class="ui basic button" data-tooltip='{{$.i18n.Tr "dataset.download_count"}}' data-position="bottom right">{{svg "octicon-flame" 16}} {{(.DownloadCount | PrettyNumber)}}</span> | |||
<span class="ui basic basic button clipboard" data-clipboard-text="{{.DownloadURL}}" data-tooltip='{{$.i18n.Tr "dataset.copy_url"}}' data-clipboard-action="copy"{{if ne $.Type 0}} style="display:none;"{{end}}>{{svg "octicon-file" 16}}</span> | |||
<span class="ui basic basic button clipboard" data-clipboard-text="{{.FileChunk.Md5}}" data-tooltip='{{$.i18n.Tr "dataset.copy_md5"}}' data-clipboard-action="copy">{{svg "octicon-file-binary" 16}}</span> | |||
</div> | |||
{{end}} | |||
{{if not .CanDel}} | |||
<div class="two wide column"> | |||
<a class="ui button mini" disabled='true'>{{if .IsPrivate}} {{$.i18n.Tr "dataset.private"}} {{else}} {{$.i18n.Tr "dataset.public"}} {{end}}</a> | |||
{{if ne .DecompressState 0}} | |||
<div class="ui left mini icon buttons"> | |||
<a class="ui basic blue button" href="datasets/dirs/{{.UUID}}?type={{$.Type}}" data-tooltip='{{$.i18n.Tr "dataset.directory"}}'>{{svg "octicon-file-directory" 16}}</a> | |||
{{if $.IsSigned}} | |||
<a class="ui basic blue button" href="datasets/label/{{.UUID}}?type={{$.Type}}" data-tooltip='{{$.i18n.Tr "dataset.create_label_task"}}'>{{svg "octicon-pencil" 16}}</a> | |||
{{end}} | |||
</div> | |||
{{else}} | |||
{{if $.Permission.CanWrite $.UnitTypeDatasets}} | |||
{{end}} | |||
{{if not .CanDel}} | |||
<a class="ui right small disabled button">{{$.i18n.Tr "dataset.delete"}}</a> | |||
<span style="margin-right: 10px;line-height: 34px;" class="ui text{{if .IsPrivate}} red{{else}} green{{end}}">{{if .IsPrivate}} {{$.i18n.Tr "dataset.private"}} {{else}} {{$.i18n.Tr "dataset.public"}} {{end}}</span> | |||
{{else}} | |||
{{if $.Permission.CanWrite $.UnitTypeDatasets}} | |||
<a class="ui right small red button" href="javascript:void(0)" data-uuid={{.UUID}} data-dataset-delete data-remove-url="{{AppSubUrl}}/attachments/delete" data-csrf="{{$.CsrfToken}}">{{$.i18n.Tr "dataset.delete"}}</a> | |||
{{if $.Repository.IsPrivate}} | |||
<div class="two wide column"> | |||
<a class="ui button mini" disabled='true' data-tooltip='{{$.i18n.Tr "dataset.how_to_public"}}'>{{$.i18n.Tr "dataset.private"}}</a> | |||
</div> | |||
{{ else }} | |||
<div class="two wide column"> | |||
<div class="ui buttons mini"> | |||
<a class="ui button mini {{if .IsPrivate}}positive active{{end}}" href="javascript:void(0)" data-dataset-status="true-{{.UUID}}" data-csrf="{{$.CsrfToken}}" data-url="{{AppSubUrl}}/attachments/private" data-uuid={{.UUID}} data-private="true" data-is-private={{.IsPrivate}}>{{$.i18n.Tr "dataset.private"}}</a> | |||
<span data-tooltip='{{$.i18n.Tr "dataset.how_to_public"}}' style="margin-right: 10px; line-height: 34px;" class="ui text red">{{$.i18n.Tr "dataset.private"}}</span> | |||
{{else}} | |||
<div class="compact small ui buttons" style="margin-right: 10px;"> | |||
<a class="ui button{{if .IsPrivate}} positive active{{end}}" href="javascript:void(0)" data-dataset-status="true-{{.UUID}}" data-csrf="{{$.CsrfToken}}" data-url="{{AppSubUrl}}/attachments/private" data-uuid={{.UUID}} data-private="true" data-is-private={{.IsPrivate}}>{{$.i18n.Tr "dataset.private"}}</a> | |||
<div class="or"></div> | |||
<a class="ui button mini {{if not .IsPrivate}}positive active{{end}}" href="javascript:void(0)" data-dataset-status="false-{{.UUID}}" data-csrf="{{$.CsrfToken}}" data-url="{{AppSubUrl}}/attachments/private" data-uuid={{.UUID}} data-private="false" data-is-private={{.IsPrivate}}>{{$.i18n.Tr "dataset.public"}}</a> | |||
<a class="ui button{{if not .IsPrivate}} positive active{{end}}" href="javascript:void(0)" data-dataset-status="false-{{.UUID}}" data-csrf="{{$.CsrfToken}}" data-url="{{AppSubUrl}}/attachments/private" data-uuid={{.UUID}} data-private="false" data-is-private={{.IsPrivate}}>{{$.i18n.Tr "dataset.public"}}</a> | |||
</div> | |||
</div> | |||
{{end}} | |||
{{else}} | |||
<a class="ui right small disabled button">{{$.i18n.Tr "dataset.delete"}}</a> | |||
<span style="margin-right: 10px;line-height: 34px;" class="ui text{{if .IsPrivate}} red{{else}} green{{end}}">{{if .IsPrivate}} {{$.i18n.Tr "dataset.private"}} {{else}} {{$.i18n.Tr "dataset.public"}} {{end}}</span> | |||
{{end}} | |||
<div class="two wide column right aligned"> | |||
<a class="ui red button mini" href="javascript:void(0)" data-uuid={{.UUID}} data-dataset-delete data-remove-url="{{AppSubUrl}}/attachments/delete" data-csrf="{{$.CsrfToken}}">{{$.i18n.Tr "dataset.delete"}}</a> | |||
</div> | |||
{{else}} | |||
<div class="two wide column"> | |||
<a class="ui button mini" disabled='true'>{{if .IsPrivate}} {{$.i18n.Tr "dataset.private"}} {{else}} {{$.i18n.Tr "dataset.public"}} {{end}}</a> | |||
</div> | |||
{{end}} | |||
{{end}} | |||
</div> | |||
</div> | |||
</div> | |||
{{end}} | |||
@@ -37,7 +37,7 @@ | |||
</div> | |||
{{if .Permission.CanWrite $.UnitTypeDatasets}} | |||
<div class="column four wide right aligned"> | |||
<a class="ui button primary" href="javascript:void(0)" id="dataset-edit"> | |||
<a class="ui green button" href="javascript:void(0)" id="dataset-edit"> | |||
{{.i18n.Tr "dataset.edit"}} | |||
</a> | |||
</div> | |||
@@ -66,7 +66,7 @@ | |||
<input name="type" value="{{.Type}}" type="hidden" /> | |||
<div class="sixteen wide column"> | |||
<a class="ui button" id="cancel">{{.i18n.Tr "cancel"}}</a> | |||
<button class="ui primary button" id="submit">{{.i18n.Tr "dataset.update_dataset"}}</button> | |||
<button class="ui green button" id="submit">{{.i18n.Tr "dataset.update_dataset"}}</button> | |||
</div> | |||
</div> | |||
@@ -80,7 +80,7 @@ | |||
<div class="ui sixteen wide column"> | |||
<div class="ui two column stackable grid"> | |||
<div class="column"> | |||
<h2>{{if eq .Type 0}}{{.i18n.Tr "repo.cloudbrain1"}}{{else}}{{.i18n.Tr "repo.cloudbrain2"}}{{end}}-{{.i18n.Tr "datasets"}}</h2> | |||
<strong>{{if eq .Type 0}}{{.i18n.Tr "repo.cloudbrain1"}}{{else}}{{.i18n.Tr "repo.cloudbrain2"}}{{end}}-{{.i18n.Tr "datasets"}}</strong> | |||
</div> | |||
<div class="column right aligned" style="z-index:1"> | |||
<div class="ui right dropdown type jump item"> | |||
@@ -55,14 +55,48 @@ | |||
#contributorInfo > a.circular:nth-child(9n+8){ | |||
background-color: #bfd0aa; | |||
} | |||
.vue_menu { | |||
cursor: auto; | |||
position: absolute; | |||
outline: none; | |||
top: 100%; | |||
margin: 0em; | |||
padding: 0em 0em; | |||
background: #fff; | |||
font-size: 1em; | |||
text-shadow: none; | |||
text-align: left; | |||
/* -webkit-box-shadow: 0px 2px 3px 0px rgb(34 36 38 / 15%); */ | |||
box-shadow: 0px 2px 3px 0px rgba(34, 36, 38, 0.15); | |||
border: 1px solid rgba(34,36,38,0.15); | |||
border-radius: 0.28571429rem; | |||
-webkit-transition: opacity 0.1s ease; | |||
transition: opacity 0.1s ease; | |||
z-index: 11; | |||
will-change: transform, opacity; | |||
width: 100% !important; | |||
-webkit-animation-iteration-count: 1; | |||
animation-iteration-count: 1; | |||
-webkit-animation-duration: 300ms; | |||
animation-duration: 300ms; | |||
-webkit-animation-timing-function: ease; | |||
animation-timing-function: ease; | |||
-webkit-animation-fill-mode: both; | |||
animation-fill-mode: both; | |||
} | |||
</style> | |||
<div class="repository file list"> | |||
{{template "repo/header" .}} | |||
<div class="ui container"> | |||
{{template "base/alert" .}} | |||
{{if and .Permission.IsAdmin (not .Repository.IsArchived)}} | |||
<div class="ui repo-topic-edit grid form segment error" id="topic_edit" style="display:none"> | |||
<!-- <div class="ui repo-topic-edit grid form segment error" id="topic_edit" style="display:none"> | |||
<div class="fourteen wide column"> | |||
<div class="field"> | |||
<div class="ui fluid multiple search selection dropdown"> | |||
@@ -78,13 +112,14 @@ | |||
<a class="ui button primary" href="javascript:;" id="save_topic" | |||
data-link="{{.RepoLink}}/topics">{{.i18n.Tr "repo.topic.done"}}</a> | |||
</div> | |||
</div> | |||
</div> --> | |||
{{end}} | |||
<div class="hide" id="validate_prompt"> | |||
<span id="count_prompt">{{.i18n.Tr "repo.topic.count_prompt"}}</span> | |||
<span id="format_prompt">{{.i18n.Tr "repo.topic.format_prompt"}}</span> | |||
</div> | |||
<div class="ui repo-description stackable grid"> | |||
<div class="ui repo-description stackable grid"> | |||
{{if .RepoSearchEnabled}} | |||
<div class="ui repo-search four wide column"> | |||
@@ -101,7 +136,7 @@ | |||
</div> | |||
{{end}} | |||
</div> | |||
{{if .Repository.IsArchived}} | |||
<div class="ui warning message"> | |||
{{.i18n.Tr "repo.archive.title"}} | |||
@@ -119,6 +154,21 @@ | |||
<a href="{{.BaseRepo.Link}}/compare/{{.BaseRepo.DefaultBranch | EscapePound}}...{{if ne .Repository.Owner.Name .BaseRepo.Owner.Name}}{{.Repository.Owner.Name}}:{{end}}{{.BranchName | EscapePound}}"> | |||
<button id="new-pull-request" class="ui compact basic button">{{if .PullRequestCtx.Allowed}}{{.i18n.Tr "repo.pulls.compare_changes"}}{{else}}{{.i18n.Tr "action.compare_branch"}}{{end}}</button> | |||
</a> | |||
{{if and .Repository.IsFork .PullRequestCtx.Allowed}} | |||
{{if gt .FetchUpstreamCnt 0 }} | |||
<a href="{{.Repository.Link}}/compare/{{.BranchName | EscapePound}}...{{.BaseRepo.Owner.Name}}:{{if .UpstreamSameBranchName}}{{.BranchName | EscapePound}}{{else}}{{.BaseRepo.DefaultBranch | EscapePound}}{{end}}"> | |||
<button id="new-pull-request" class="ui compact basic button" title="{{$.i18n.Tr (TrN $.i18n.Lang .FetchUpstreamCnt "repo.pulls.commits_count_1" "repo.pulls.commits_count_n") .FetchUpstreamCnt}}">{{.i18n.Tr "repo.pulls.fetch_upstream"}}</button> | |||
</a> | |||
{{else if lt .FetchUpstreamCnt 0}} | |||
<a href="{{.Repository.Link}}/compare/{{.BranchName | EscapePound}}...{{.BaseRepo.Owner.Name}}:{{.BaseRepo.DefaultBranch | EscapePound}}"> | |||
<button id="new-pull-request" class="ui compact basic button" title="{{.i18n.Tr "repo.pulls.upstream_error"}}">{{.i18n.Tr "repo.pulls.fetch_upstream"}}</button> | |||
</a> | |||
{{else}} | |||
<a href="{{.Repository.Link}}/compare/{{.BranchName | EscapePound}}...{{.BaseRepo.Owner.Name}}:{{if .UpstreamSameBranchName}}{{.BranchName | EscapePound}}{{else}}{{.BaseRepo.DefaultBranch | EscapePound}}{{end}}"> | |||
<button id="new-pull-request" class="ui compact basic button" title="{{.i18n.Tr "repo.pulls.upstream_up_to_date"}}">{{.i18n.Tr "repo.pulls.fetch_upstream"}}</button> | |||
</a> | |||
{{end}} | |||
{{end}} | |||
</div> | |||
{{end}} | |||
{{else}} | |||
@@ -204,7 +254,7 @@ | |||
{{template "repo/view_list" .}} | |||
{{end}} | |||
</div> | |||
<div class="ui six wide tablet four wide computer column"> | |||
<div class="ui six wide tablet four wide computer column"> | |||
<div id="repo-desc"> | |||
<h4 id="about-desc" class="ui header">简介 | |||
<!-- <a class="edit-icon" href="javascript:void(0)"> | |||
@@ -217,28 +267,47 @@ | |||
{{else}} | |||
<span class="no-description text-italic">{{.i18n.Tr "repo.no_desc"}}</span> | |||
{{end}} | |||
</p> | |||
</div> | |||
{{if .Repository.Website}} | |||
<p class="ui"> | |||
<i class="gray linkify icon"></i> | |||
<a class="link edit-link" target="_blank" title="{{.Repository.Website}}" href="{{.Repository.Website}}">{{.Repository.Website}}</a> | |||
</p> | |||
{{end}} | |||
<p class="ui" id="repo-topics"> | |||
<i class="grey bookmark icon"></i> | |||
{{range .Topics}}<a class="ui repo-topic small label topic" href="{{AppSubUrl}}/explore/repos?q={{.Name}}&topic=1">{{.Name}}</a>{{end}} | |||
{{if and .Permission.IsAdmin (not .Repository.IsArchived)}}<a id="manage_topic">{{.i18n.Tr "repo.topic.manage_topics"}}</a>{{end}} | |||
</p> | |||
{{end}} | |||
<div class="ui" id="repo-topics" style="display: flex;position: relative;margin-bottom: 1.0rem;"> | |||
<i class="grey bookmark icon"></i> | |||
<div id="repo-topics1" style="flex: 1;"> | |||
<!-- {{if not .Topics}} | |||
<span class="no-description text-italic">{{.i18n.Tr "repo.no_desc"}}</span> | |||
{{end}} --> | |||
{{range .Topics}} | |||
<a class="ui repo-topic small label topic" href="{{AppSubUrl}}/explore/repos?q={{.Name}}&topic=1">{{.Name}}</a> | |||
{{end}} | |||
</div> | |||
<div> | |||
{{if and .Permission.IsAdmin (not .Repository.IsArchived)}}<i id="manage_topic" style="cursor: pointer;" class="plus icon"></i>{{end}} | |||
</div> | |||
<div id="topic_edit" class="vue_menu" style="display:none"> | |||
<div id="topic_edit1"> | |||
</div> | |||
</div> | |||
</div> | |||
<p class="ui"> | |||
<i class="grey code icon"></i> | |||
{{range .LanguageStats}} | |||
@@ -246,14 +315,14 @@ | |||
{{end}} | |||
</p> | |||
{{if .LICENSE}} | |||
<p class="ui"> | |||
<i class="grey clone icon"></i> | |||
{{.LICENSE}} | |||
</p> | |||
{{end}} | |||
<div class="ui divider"></div> | |||
@@ -269,22 +338,22 @@ | |||
{{range .ContributorInfo}} | |||
{{if .UserInfo}} | |||
<a href="{{AppSubUrl}}/{{.UserInfo.Name}}"><img class="ui avatar image" src="{{.UserInfo.RelAvatarLink}}"></a> | |||
{{else if .Email}} | |||
{{else if .Email}} | |||
<a href="mailto:{{.Email}}" class="circular ui button">{{.Email}}</a> | |||
{{end}} | |||
{{end}} | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<script type="text/javascript"> | |||
$(document).ready(function(){ | |||
$(document).ready(function(){ | |||
$(".membersmore").click(function(){ | |||
$("#contributorInfo > a:nth-child(n+25)").show(); | |||
}); | |||
@@ -2,14 +2,24 @@ | |||
<div class="repository labels"> | |||
{{template "repo/header" .}} | |||
<div class="ui container"> | |||
<div class="navbar"> | |||
{{template "repo/issue/navbar" .}} | |||
{{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}} | |||
<div class="ui right"> | |||
<div class="ui green new-label button">{{.i18n.Tr "repo.issues.new_label"}}</div> | |||
</div> | |||
{{end}} | |||
</div> | |||
<div class="ui two column stackable grid"> | |||
<div class="column" style="display: flex;align-items: center;"> | |||
<div class="ui large breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}/issues">{{.i18n.Tr "repo.issues"}}</a> | |||
<div class="divider"> / </div> | |||
<div class="action section">{{.Title | RenderEmoji}}</div> | |||
</div> | |||
</div> | |||
<div class="column right aligned"> | |||
{{template "repo/issue/navbar" .}} | |||
{{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}} | |||
<div class="ui right"> | |||
<div class="ui green new-label button">{{.i18n.Tr "repo.issues.new_label"}}</div> | |||
</div> | |||
{{end}} | |||
</div> | |||
</div> | |||
<div class="ui divider"></div> | |||
{{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}} | |||
{{template "repo/issue/labels/label_new" .}} | |||
@@ -3,14 +3,14 @@ | |||
{{template "repo/header" .}} | |||
<div class="ui container"> | |||
<div class="ui three column stackable grid"> | |||
<div class="column"> | |||
{{template "repo/issue/navbar" .}} | |||
<div class="column" style="display: flex;align-items: center;"> | |||
</div> | |||
<div class="column center aligned"> | |||
{{template "repo/issue/search" .}} | |||
</div> | |||
{{if not .Repository.IsArchived}} | |||
<div class="column right aligned"> | |||
{{template "repo/issue/navbar" .}} | |||
{{if .PageIsIssueList}} | |||
<a class="ui green button" href="{{.RepoLink}}/issues/new">{{.i18n.Tr "repo.issues.new"}}</a> | |||
{{else}} | |||
@@ -3,8 +3,14 @@ | |||
{{template "repo/header" .}} | |||
<div class="ui container"> | |||
<div class="ui three column stackable grid"> | |||
<div class="column"> | |||
<h3>{{.Milestone.Name}}</h3> | |||
<div class="column" style="display: flex;align-items: center;"> | |||
<div class="ui large breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}/issues">{{.i18n.Tr "repo.issues"}}</a> | |||
<div class="divider"> / </div> | |||
<a class="section" href="{{.RepoLink}}/milestones">{{.i18n.Tr "repo.milestones"}}</a> | |||
<div class="divider"> / </div> | |||
<div class="action section">{{.Milestone.Name}}</div> | |||
</div> | |||
</div> | |||
<div class="column center aligned"> | |||
@@ -2,13 +2,29 @@ | |||
<div class="repository new milestone"> | |||
{{template "repo/header" .}} | |||
<div class="ui container"> | |||
<div class="navbar"> | |||
{{template "repo/issue/navbar" .}} | |||
{{if and (or .CanWriteIssues .CanWritePulls) .PageIsEditMilestone}} | |||
<div class="ui right floated secondary menu"> | |||
<a class="ui green button" href="{{$.RepoLink}}/milestones/new">{{.i18n.Tr "repo.milestones.new"}}</a> | |||
<div class="ui two column stackable grid"> | |||
<div class="column" style="display: flex;align-items: center;"> | |||
<div class="ui large breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}/issues">{{.i18n.Tr "repo.issues"}}</a> | |||
<div class="divider"> / </div> | |||
<a class="section" href="{{.RepoLink}}/milestones">{{.i18n.Tr "repo.milestones"}}</a> | |||
<div class="divider"> / </div> | |||
{{if .PageIsEditMilestone}} | |||
<div class="action section">{{.i18n.Tr "repo.milestones.edit"}}</div> | |||
{{else}} | |||
<div class="action section">{{.i18n.Tr "repo.milestones.new"}}</div> | |||
{{end}} | |||
</div> | |||
</div> | |||
{{end}} | |||
<div class="column right aligned"> | |||
{{template "repo/issue/navbar" .}} | |||
{{if and (or .CanWriteIssues .CanWritePulls) .PageIsEditMilestone}} | |||
<div class="ui right floated secondary menu"> | |||
<a class="ui green button" href="{{$.RepoLink}}/milestones/new">{{.i18n.Tr "repo.milestones.new"}}</a> | |||
</div> | |||
{{end}} | |||
</div> | |||
</div> | |||
<div class="ui divider"></div> | |||
<h2 class="ui dividing header"> | |||
@@ -2,14 +2,25 @@ | |||
<div class="repository milestones"> | |||
{{template "repo/header" .}} | |||
<div class="ui container"> | |||
<div class="navbar"> | |||
{{template "repo/issue/navbar" .}} | |||
{{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}} | |||
<div class="ui right"> | |||
<a class="ui green button" href="{{$.Link}}/new">{{.i18n.Tr "repo.milestones.new"}}</a> | |||
</div> | |||
{{end}} | |||
</div> | |||
<div class="ui two column stackable grid"> | |||
<div class="column" style="display: flex;align-items: center;"> | |||
<div class="ui large breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}/issues">{{.i18n.Tr "repo.issues"}}</a> | |||
<div class="divider"> / </div> | |||
<div class="action section">{{.Title | RenderEmoji}}</div> | |||
</div> | |||
</div> | |||
{{if not .Repository.IsArchived}} | |||
<div class="column right aligned"> | |||
{{template "repo/issue/navbar" .}} | |||
{{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}} | |||
<div class="ui right"> | |||
<a class="ui green button" href="{{$.Link}}/new">{{.i18n.Tr "repo.milestones.new"}}</a> | |||
</div> | |||
{{end}} | |||
</div> | |||
{{end}} | |||
</div> | |||
<div class="ui divider"></div> | |||
{{template "base/alert" .}} | |||
<div class="ui tiny basic buttons"> | |||
@@ -1,4 +1,4 @@ | |||
<div class="ui compact left small menu"> | |||
<div class="ui compact small menu" style="margin-right: 1rem;"> | |||
<a class="{{if .PageIsLabels}}active{{end}} item" href="{{.RepoLink}}/labels">{{.i18n.Tr "repo.labels"}}</a> | |||
<a class="{{if .PageIsMilestones}}active{{end}} item" href="{{.RepoLink}}/milestones">{{.i18n.Tr "repo.milestones"}}</a> | |||
</div> |
@@ -2,9 +2,21 @@ | |||
<div class="repository new issue"> | |||
{{template "repo/header" .}} | |||
<div class="ui container"> | |||
<div class="navbar"> | |||
{{template "repo/issue/navbar" .}} | |||
</div> | |||
<div class="ui two column stackable grid"> | |||
<div class="column" style="display: flex;align-items: center;"> | |||
<div class="ui large breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}/issues">{{.i18n.Tr "repo.issues"}}</a> | |||
<div class="divider"> / </div> | |||
<div class="action section">{{.i18n.Tr "repo.issues.new"}}</div> | |||
</div> | |||
</div> | |||
<div class="column right aligned"> | |||
{{template "repo/issue/navbar" .}} | |||
</div> | |||
</div> | |||
<div class="ui divider"></div> | |||
{{template "repo/issue/new_form" .}} | |||
</div> | |||
@@ -7,7 +7,7 @@ | |||
<input type="hidden" name="assignee" value="{{$.AssigneeID}}"/> | |||
<div class="ui search action input"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus> | |||
<button class="ui blue button" type="submit">{{.i18n.Tr "explore.search"}}</button> | |||
<button class="ui green button" type="submit">{{.i18n.Tr "explore.search"}}</button> | |||
</div> | |||
</div> | |||
</form> |
@@ -3,11 +3,24 @@ | |||
{{template "repo/header" .}} | |||
<div class="ui container"> | |||
<div class="ui two column stackable grid"> | |||
<div class="column"> | |||
{{template "repo/issue/navbar" .}} | |||
<div class="column" style="display: flex;align-items: center;"> | |||
{{if .PageIsIssueList}} | |||
<div class="ui large breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}/issues">{{.i18n.Tr "repo.issues"}}</a> | |||
<div class="divider"> / </div> | |||
<div class="action section">{{.i18n.Tr "repo.issues_detail"}}</div> | |||
</div> | |||
{{else}} | |||
<div class="ui large breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}/pulls">{{.i18n.Tr "repo.pulls"}}</a> | |||
<div class="divider"> / </div> | |||
<div class="action section">{{.i18n.Tr "repo.issues_detail"}}</div> | |||
</div> | |||
{{end}} | |||
</div> | |||
{{if not .Repository.IsArchived}} | |||
<div class="column right aligned"> | |||
{{template "repo/issue/navbar" .}} | |||
{{if .PageIsIssueList}} | |||
<a class="ui green button" href="{{.RepoLink}}/issues/new">{{.i18n.Tr "repo.issues.new"}}</a> | |||
{{else}} | |||
@@ -228,41 +228,71 @@ | |||
<div class="ui sixteen wide column"> | |||
<!-- 排序区 --> | |||
<div class="ui sixteen wide column"> | |||
<!-- <div class="ui sixteen wide column"> | |||
<div class="ui two column stackable grid"> | |||
<div class="column"> | |||
</div> | |||
<!-- <div class="column right aligned"> | |||
<div class="column right aligned"> | |||
<div class="ui right dropdown type jump item"> | |||
<span class="text"> | |||
{{.i18n.Tr "repo.issues.filter_sort"}}<i class="dropdown icon"></i> | |||
</span> | |||
</div> | |||
</div> --> | |||
</div> | |||
</div> | |||
</div> | |||
</div> --> | |||
<!-- 任务展示 --> | |||
<div class="dataset list"> | |||
<!-- 表头 --> | |||
<div class="ui grid stackable" style="background: #f0f0f0;;"> | |||
<div class="row"> | |||
<div class="five wide column"> | |||
<span style="margin:0 6px">{{$.i18n.Tr "repo.cloudbrain_task"}}</span> | |||
</div> | |||
<div class="three wide column"> | |||
<span>{{$.i18n.Tr "repo.cloudbrain_status_createtime"}}</span> | |||
</div> | |||
<div class="one wide column"> | |||
<span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span> | |||
</div> | |||
<div class="seven wide column text center"> | |||
<span style="margin-left: 10rem;">{{$.i18n.Tr "repo.cloudbrain_operate"}}</span> | |||
</div> | |||
</div> | |||
</div> | |||
{{range .Tasks}} | |||
<div class="ui grid stackable item"> | |||
<div class="row"> | |||
<!-- 任务名 --> | |||
<div class="six wide column"> | |||
<a class="title" href="{{$.Link}}/{{.JobID}}"> | |||
<span class="fitted">{{svg "octicon-tasklist" 16}}</span> | |||
<span class="fitted">{{.JobName}}</span> | |||
<div class="five wide column"> | |||
<a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.JobName}}" style="font-size: 15px;"> | |||
<span class="fitted" style="vertical-align: middle;">{{svg "octicon-tasklist" 16}}</span> | |||
<span class="fitted" style="width: 90%;vertical-align: middle;margin-left: 0.4rem;">{{.JobName}}</span> | |||
</a> | |||
</div> | |||
<div class="three wide column"> | |||
<!--任务状态 --> | |||
<span class="ui compact button job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||
<!-- <span class="ui compact button job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||
{{.Status}} | |||
</span> --> | |||
<span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}"> | |||
<span><i style="vertical-align: middle;" class="{{.Status}}"></i><span style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span> | |||
</span> | |||
<!-- 任务创建时间 --> | |||
<span class="">{{TimeSinceUnix .CreatedUnix $.Lang}}</span> | |||
<span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span> | |||
</div> | |||
<div class="one wide column"> | |||
<a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a> | |||
</div> | |||
<div class="seven wide column text right"> | |||
@@ -270,7 +300,7 @@ | |||
<a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}"> | |||
查看 | |||
</a> | |||
<a class="ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.Link}}/{{.JobID}}/debug"> | |||
<a class="ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank"> | |||
调试 | |||
</a> | |||
<form id="stopForm-{{.JobID}}" action="{{if ne .Status "RUNNING"}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/stop{{end}}" method="post" style="margin-left:-1px;"> | |||
@@ -282,9 +312,9 @@ | |||
</div> | |||
<!-- 删除任务 --> | |||
<form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{if ne .Status "STOPPED"}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/del{{end}}" method="post"> | |||
<form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{if not .CanDel}}javascript:void(0){{else}}{{$.Link}}/{{.JobID}}/del{{end}}" method="post"> | |||
{{$.CsrfTokenHtml}} | |||
<a class="ui compact {{if ne .Status "STOPPED"}}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||
<a class="ui compact {{if not .CanDel}}disabled {{else}}red {{end}}button" onclick="assertDelete(this)" style="border-radius: .28571429rem;"> | |||
删除 | |||
</a> | |||
</form> | |||
@@ -2,11 +2,25 @@ | |||
<div class="repository view issue pull commits"> | |||
{{template "repo/header" .}} | |||
<div class="ui container"> | |||
<div class="navbar"> | |||
<!-- <div class="navbar"> | |||
{{template "repo/issue/navbar" .}} | |||
<div class="ui right"> | |||
<a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | EscapePound}}...{{.PullRequestCtx.HeadInfo | EscapePound}}">{{.i18n.Tr "repo.pulls.new"}}</a> | |||
</div> | |||
</div> --> | |||
<div class="ui two column stackable grid"> | |||
<div class="column" style="display: flex;align-items: center;"> | |||
<div class="ui large breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}/pulls">{{.i18n.Tr "repo.pulls"}}</a> | |||
<div class="divider"> / </div> | |||
<div class="action section">{{.i18n.Tr "repo.issues_detail"}}</div> | |||
</div> | |||
</div> | |||
<div class="column right aligned"> | |||
{{template "repo/issue/navbar" .}} | |||
<a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | EscapePound}}...{{.PullRequestCtx.HeadInfo | EscapePound}}">{{.i18n.Tr "repo.pulls.new"}}</a> | |||
</div> | |||
</div> | |||
<div class="ui divider"></div> | |||
{{template "repo/issue/view_title" .}} | |||
@@ -2,11 +2,25 @@ | |||
<div class="repository view issue pull files diff"> | |||
{{template "repo/header" .}} | |||
<div class="ui container {{if .IsSplitStyle}}fluid padded{{end}}"> | |||
<div class="navbar"> | |||
<!-- <div class="navbar"> | |||
{{template "repo/issue/navbar" .}} | |||
<div class="ui right"> | |||
<a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | EscapePound}}...{{.PullRequestCtx.HeadInfo | EscapePound}}">{{.i18n.Tr "repo.pulls.new"}}</a> | |||
</div> | |||
</div> --> | |||
<div class="ui two column stackable grid"> | |||
<div class="column" style="display: flex;align-items: center;"> | |||
<div class="ui large breadcrumb"> | |||
<a class="section" href="{{.RepoLink}}/pulls">{{.i18n.Tr "repo.pulls"}}</a> | |||
<div class="divider"> / </div> | |||
<div class="action section">{{.i18n.Tr "repo.issues_detail"}}</div> | |||
</div> | |||
</div> | |||
<div class="column right aligned"> | |||
{{template "repo/issue/navbar" .}} | |||
<a class="ui green button {{if not .PullRequestCtx.Allowed}}disabled{{end}}" href="{{.RepoLink}}/compare/{{.BranchName | EscapePound}}...{{.PullRequestCtx.HeadInfo | EscapePound}}">{{.i18n.Tr "repo.pulls.new"}}</a> | |||
</div> | |||
</div> | |||
<div class="ui divider"></div> | |||
{{template "repo/issue/view_title" .}} | |||
@@ -74,7 +74,7 @@ | |||
<input type="hidden" name="state" value="{{$.State}}"/> | |||
<div class="ui search action input"> | |||
<input name="q" value="{{$.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus> | |||
<button class="ui blue button" type="submit">{{.i18n.Tr "explore.search"}}</button> | |||
<button class="ui green button" type="submit">{{.i18n.Tr "explore.search"}}</button> | |||
</div> | |||
</div> | |||
</form> | |||
@@ -0,0 +1,477 @@ | |||
<template> | |||
<div> | |||
<div class="input-search"> | |||
<el-input v-model="input" clearable :autofocus="true" @input="changeValue" id="topics_input" @keyup.enter.native="postTopic" placeholder="搜索或创建标签"> | |||
</el-input> | |||
<div class="scrolling-menu"> | |||
<div v-if="showSearchTopic" class="item-text" v-for="(arr,i) in array" @click="addTopics(i,arr)"> | |||
<div class="icon-wrapper"> | |||
<i style="line-height: 1.5;color: #303643;font-weight: 900;" v-if="showInitTopic[i]" class="el-icon-check" ></i> | |||
</div> | |||
<div class="text">{{arr.topic_name}} </div> | |||
</div> | |||
<div v-if="showInputValue" class="addition item-text" @click="postTopic"> | |||
点击或回车添加<b class="user-add-label-text">{{input}}</b>标签 | |||
</div> | |||
<div v-if="showAddTopic" class="item-text" @click="addPostTopic"> | |||
<div class="icon-wrapper"> | |||
<i style="line-height: 1.5;color: #303643;font-weight: 900;" v-if="showAddFlage" class="el-icon-check" ></i> | |||
</div> | |||
<div class="text">{{input}}</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
const {AppSubUrl, StaticUrlPrefix, csrf} = window.config; | |||
import $ from 'jquery' | |||
export default { | |||
data() { | |||
return { | |||
input:'', | |||
params:{}, | |||
showInputValue:false, | |||
showFlag:-1, | |||
array:[], | |||
showAddTopic:false, | |||
showAddFlage:false, | |||
showSearchTopic:true, | |||
postUrl:'', | |||
arrayTopics:[], | |||
showInitTopic:[], | |||
}; | |||
}, | |||
methods: { | |||
addTopics(item,array){ | |||
if(!this.showInitTopic[item]){ | |||
if(this.arrayTopics.includes(array.topic_name)){ | |||
return | |||
} | |||
else{ | |||
this.arrayTopics.push(array.topic_name) | |||
let topics = this.arrayTopics | |||
let strTopics = topics.join(',') | |||
let data = this.qs.stringify({ | |||
_csrf:csrf, | |||
topics:strTopics | |||
}) | |||
this.Post(data,topics) | |||
this.$set(this.showInitTopic,item,true) | |||
$('#repo-topics1').children('span').remove() | |||
} | |||
}else{ | |||
this.arrayTopics=this.arrayTopics.filter(ele=>{ | |||
return ele !== array.topic_name | |||
}) | |||
let topics = this.arrayTopics | |||
let strTopics = topics.join(',') | |||
let data = this.qs.stringify({ | |||
_csrf:csrf, | |||
topics:strTopics | |||
}) | |||
this.Post(data,topics) | |||
this.$set(this.showInitTopic,item,false) | |||
if(this.arrayTopics.length===0){ | |||
$('#repo-topics1').append('<span class="no-description text-italic">暂无标签</span>') | |||
}else{ | |||
$('#repo-topics1').children('span').remove() | |||
} | |||
} | |||
}, | |||
changeValue(){ | |||
if (this.input === ''){ | |||
this.array = this.arrayTopics | |||
let data = [] | |||
this.showInitTopic = [] | |||
this.array.forEach((element,index) => { | |||
let item = {} | |||
item.topic_name = element | |||
data.push(item) | |||
this.showInitTopic.push(true) | |||
}); | |||
this.array = data | |||
this.showInputValue = false | |||
this.showSearchTopic = true | |||
} | |||
else if(this.arrayTopics.indexOf(this.input)>-1){ | |||
this.showInputValue = false | |||
this.showSearchTopic = false | |||
}else{ | |||
this.showInitTopic = [] | |||
let timestamp=new Date().getTime() | |||
this.params.q = this.input | |||
this.params._ = timestamp | |||
this.$axios.get('/api/v1/topics/search',{ | |||
params:this.params | |||
}).then((res)=>{ | |||
this.array = res.data.topics | |||
this.array.forEach((element,index) => { | |||
if (this.arrayTopics.indexOf(element.topic_name)>-1){ | |||
this.showInitTopic.push(true) | |||
}else{ | |||
this.showInitTopic.push(false) | |||
} | |||
}); | |||
}) | |||
this.showInputValue = true | |||
this.showSearchTopic = true | |||
} | |||
this.showAddTopic = false | |||
}, | |||
Post(data,topics){ | |||
this.$axios.post(this.postUrl,data).then(res=>{ | |||
const viewDiv = $('#repo-topics1'); | |||
viewDiv.children('.topic').remove(); | |||
if (topics.length) { | |||
const topicArray = topics; | |||
const last = viewDiv.children('a').last(); | |||
for (let i = 0; i < topicArray.length; i++) { | |||
const link = $('<a class="ui repo-topic small label topic"></a>'); | |||
link.attr( | |||
'href', | |||
`${AppSubUrl}/explore/repos?q=${encodeURIComponent( | |||
topicArray[i] | |||
)}&topic=1` | |||
); | |||
link.text(topicArray[i]); | |||
// link.insertBefore(last); | |||
viewDiv.append(link) | |||
} | |||
} | |||
viewDiv.show(); | |||
}) | |||
}, | |||
postTopic(){ | |||
const patter = /^[\u4e00-\u9fa5a-zA-Z0-9][\u4e00-\u9fa5a-zA-Z0-9-]{0,34}$/ | |||
let regexp = patter.test(this.input) | |||
if(!regexp){ | |||
this.$notify({ | |||
message: '标签名必须以中文、字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符', | |||
duration: 3000, | |||
type:'error' | |||
}); | |||
return | |||
}else{ | |||
let topic = this.input | |||
if(this.arrayTopics.includes(topic)){ | |||
return | |||
} | |||
else{ | |||
this.arrayTopics.push(topic) | |||
let topics = this.arrayTopics | |||
let strTopics = topics.join(',') | |||
let data = this.qs.stringify({ | |||
_csrf:csrf, | |||
topics:strTopics | |||
}) | |||
this.Post(data,topics) | |||
$('#repo-topics1').children('span').remove() | |||
this.showInputValue = false | |||
this.showAddTopic = true | |||
this.showAddFlage = true | |||
} | |||
} | |||
}, | |||
addPostTopic(){ | |||
if(this.showAddFlage){ | |||
this.arrayTopics.pop() | |||
let topics = this.arrayTopics | |||
let strTopics = topics.join(',') | |||
let data = this.qs.stringify({ | |||
_csrf:csrf, | |||
topics:strTopics | |||
}) | |||
this.Post(data,topics) | |||
if(this.arrayTopics.length===0){ | |||
console.log("add postTopic") | |||
$('#repo-topics1').append('<span class="no-description text-italic">暂无标签</span>') | |||
}else{ | |||
$('#repo-topics1').children('span').remove() | |||
} | |||
} | |||
else if(!this.showAddFlage){ | |||
let topic = this.input | |||
this.arrayTopics.push(topic) | |||
let topics = this.arrayTopics | |||
let strTopics = topics.join(',') | |||
let data = this.qs.stringify({ | |||
_csrf:csrf, | |||
topics:strTopics | |||
}) | |||
this.Post(data,topics) | |||
$('#repo-topics1').children('span').remove() | |||
} | |||
this.showAddFlage = !this.showAddFlage | |||
}, | |||
initTopics(){ | |||
const mgrBtn = $('#manage_topic'); | |||
const editDiv = $('#topic_edit'); | |||
mgrBtn.on('click', (e) => { | |||
// viewDiv.hide(); | |||
editDiv.css('display', ''); // show Semantic UI Grid | |||
this.input = '' | |||
if (this.input === ''){ | |||
this.array = this.arrayTopics | |||
let data = [] | |||
this.showInitTopic = [] | |||
this.array.forEach((element,index) => { | |||
let item = {} | |||
item.topic_name = element | |||
data.push(item) | |||
this.showInitTopic.push(true) | |||
}); | |||
this.array = data | |||
this.showInputValue = false | |||
this.showSearchTopic = true | |||
} | |||
stopPropagation(e); | |||
}); | |||
$(document).bind('click',function(){ | |||
editDiv.css('display','none'); | |||
}) | |||
editDiv.click(function(e){ | |||
stopPropagation(e); | |||
}) | |||
function stopPropagation(e) { | |||
var ev = e || window.event; | |||
if (ev.stopPropagation) { | |||
ev.stopPropagation(); | |||
} | |||
else if (window.event) { | |||
window.event.cancelBubble = true;//兼容IE | |||
} | |||
} | |||
} | |||
}, | |||
computed:{ | |||
}, | |||
watch: { | |||
input(newValue){ | |||
if (newValue === ''){ | |||
this.array = this.arrayTopics | |||
let data = [] | |||
this.showInitTopic = [] | |||
this.array.forEach((element,index) => { | |||
let item = {} | |||
item.topic_name = element | |||
data.push(item) | |||
this.showInitTopic.push(true) | |||
}); | |||
this.array = data | |||
this.showInputValue = false | |||
this.showSearchTopic = true | |||
} | |||
} | |||
}, | |||
mounted() { | |||
const context = this | |||
this.postUrl = `${window.location.pathname}/topics`; | |||
$('#repo-topics1').children('a').each(function(){ | |||
context.arrayTopics.push($(this).text()) | |||
}); | |||
if(this.arrayTopics.length===0){ | |||
$('#repo-topics1').append('<span class="no-description text-italic">暂无标签</span>') | |||
} | |||
this.changeValue() | |||
} , | |||
created(){ | |||
this.initTopics(); | |||
this.input='' | |||
} | |||
}; | |||
</script> | |||
<style scoped> | |||
.input-search { | |||
width: 100%; | |||
display: -webkit-box; | |||
display: -ms-flexbox; | |||
display: flex; | |||
min-width: 10rem; | |||
white-space: nowrap; | |||
font-size: 1rem; | |||
position: relative; | |||
display: inline-block; | |||
color: rgba(0,0,0,0.8); | |||
padding: 8px; | |||
} | |||
/deep/ .el-input__inner{ | |||
border-color: #409eff; | |||
} | |||
.scrolling-menu{ | |||
border-top: none !important; | |||
padding-top: 0 !important; | |||
padding-bottom: 0 !important; | |||
display: block; | |||
position: static; | |||
overflow-y: auto; | |||
border: none; | |||
-webkit-box-shadow: none !important; | |||
box-shadow: none !important; | |||
border-radius: 0 !important; | |||
margin: 0 !important; | |||
min-width: 100% !important; | |||
width: auto !important; | |||
border-top: 1px solid rgba(34,36,38,0.15); | |||
} | |||
.item-text{ | |||
border-top: none; | |||
padding-right: calc(1.14285714rem + 17px ) !important; | |||
line-height: 1.333; | |||
padding-top: 0.7142857rem !important; | |||
padding-bottom: 0.7142857rem !important; | |||
position: relative; | |||
cursor: pointer; | |||
display: block; | |||
border: none; | |||
height: auto; | |||
text-align: left; | |||
border-top: none; | |||
line-height: 1em; | |||
color: rgba(0,0,0,0.87); | |||
padding: 0.78571429rem 1.14285714rem !important; | |||
font-size: 1rem; | |||
text-transform: none; | |||
font-weight: normal; | |||
-webkit-box-shadow: none; | |||
box-shadow: none; | |||
-webkit-touch-callout: none; | |||
display: -webkit-box; | |||
display: -ms-flexbox; | |||
display: flex; | |||
-webkit-box-align: center; | |||
-ms-flex-align: center; | |||
align-items: center; | |||
display: -webkit-box !important; | |||
display: -ms-flexbox !important; | |||
display: flex !important; | |||
} | |||
.icon-wrapper{ | |||
text-align: left; | |||
width: 24px; | |||
height: 20px; | |||
-ms-flex-negative: 0; | |||
flex-shrink: 0; | |||
} | |||
.text{ | |||
max-width: 80%; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
font-size: 12px; | |||
font-weight: 400; | |||
color: #40485b; | |||
} | |||
.addition{ | |||
background: #f6f6f6; | |||
} | |||
.user-add-label-text{ | |||
max-width: 80%; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
margin: 0 4px; | |||
} | |||
</style> |
@@ -1,17 +1,16 @@ | |||
<template> | |||
<div class="dropzone-wrapper dataset-files"> | |||
<div class="ui pointing below red basic label"> | |||
<i class="icon info circle"></i>只有zip格式的数据集才能发起云脑任务 | |||
</div> | |||
<div | |||
id="dataset" | |||
class="dropzone" | |||
/> | |||
<p class="upload-info"> | |||
{{ file_status_text }} | |||
<span class="success">{{ status }}</span> | |||
<strong class="success text red">{{ status }}</strong> | |||
</p> | |||
<p>云脑1提供 <span class="text blue">CPU / GPU</span> 资源,云脑2提供 <span class="text blue">Ascend NPU</span> 资源;调试使用的数据集也需要上传到对应的环境。</p> | |||
<p>说明:<br> | |||
- 只有zip格式的数据集才能发起云脑任务;<br> | |||
- 云脑1提供 <span class="text blue">CPU / GPU</span> 资源,云脑2提供 <span class="text blue">Ascend NPU</span> 资源;调试使用的数据集也需要上传到对应的环境。</p> | |||
</div> | |||
</template> | |||
@@ -6,9 +6,12 @@ | |||
/> | |||
<p class="upload-info"> | |||
{{ file_status_text }} | |||
<span class="success">{{ status }}</span> | |||
<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> | |||
<p>云脑1提供 <span class="text blue">CPU / GPU</span> 资源,云脑2提供 <span class="text blue">Ascend NPU</span> 资源;调试使用的数据集也需要上传到对应的环境。</p> | |||
</div> | |||
</template> | |||
@@ -36,6 +36,7 @@ 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 EditTopics from './components/EditTopics.vue' | |||
Vue.use(ElementUI); | |||
Vue.prototype.$axios = axios; | |||
@@ -2967,11 +2968,13 @@ $(document).ready(async () => { | |||
initVueUploader(); | |||
initObsUploader(); | |||
initVueEditAbout(); | |||
initVueEditTopic(); | |||
initVueImages(); | |||
initTeamSettings(); | |||
initCtrlEnterSubmit(); | |||
initNavbarContentToggle(); | |||
initTopicbar(); | |||
// initTopicbar(); | |||
// closeTopicbar(); | |||
initU2FAuth(); | |||
initU2FRegister(); | |||
initIssueList(); | |||
@@ -3666,7 +3669,19 @@ function initVueEditAbout() { | |||
}); | |||
} | |||
function initVueEditTopic() { | |||
const el = document.getElementById('topic_edit1'); | |||
if (!el) { | |||
return; | |||
} | |||
new Vue({ | |||
el:'#topic_edit1', | |||
render:h=>h(EditTopics) | |||
}) | |||
} | |||
function initVueImages() { | |||
const el = document.getElementById('images'); | |||
console.log("el",el) | |||
@@ -3677,6 +3692,7 @@ function initVueImages() { | |||
new Vue({ | |||
el: '#images', | |||
render: h => h(Images) | |||
}); | |||
} | |||
@@ -3932,218 +3948,243 @@ function initNavbarContentToggle() { | |||
}); | |||
} | |||
function initTopicbar() { | |||
const mgrBtn = $('#manage_topic'); | |||
const editDiv = $('#topic_edit'); | |||
const viewDiv = $('#repo-topics'); | |||
const saveBtn = $('#save_topic'); | |||
const topicDropdown = $('#topic_edit .dropdown'); | |||
const topicForm = $('#topic_edit.ui.form'); | |||
const topicPrompts = getPrompts(); | |||
mgrBtn.on('click', () => { | |||
viewDiv.hide(); | |||
editDiv.css('display', ''); // show Semantic UI Grid | |||
}); | |||
function getPrompts() { | |||
const hidePrompt = $('div.hide#validate_prompt'); | |||
const prompts = { | |||
countPrompt: hidePrompt.children('#count_prompt').text(), | |||
formatPrompt: hidePrompt.children('#format_prompt').text() | |||
}; | |||
hidePrompt.remove(); | |||
return prompts; | |||
} | |||
saveBtn.on('click', () => { | |||
const topics = $('input[name=topics]').val(); | |||
$.post( | |||
saveBtn.data('link'), | |||
{ | |||
_csrf: csrf, | |||
topics | |||
}, | |||
(_data, _textStatus, xhr) => { | |||
if (xhr.responseJSON.status === 'ok') { | |||
viewDiv.children('.topic').remove(); | |||
if (topics.length) { | |||
const topicArray = topics.split(','); | |||
const last = viewDiv.children('a').last(); | |||
for (let i = 0; i < topicArray.length; i++) { | |||
const link = $('<a class="ui repo-topic small label topic"></a>'); | |||
link.attr( | |||
'href', | |||
`${AppSubUrl}/explore/repos?q=${encodeURIComponent( | |||
topicArray[i] | |||
)}&topic=1` | |||
); | |||
link.text(topicArray[i]); | |||
link.insertBefore(last); | |||
} | |||
} | |||
editDiv.css('display', 'none'); | |||
viewDiv.show(); | |||
} | |||
} | |||
) | |||
.fail((xhr) => { | |||
if (xhr.status === 422) { | |||
if (xhr.responseJSON.invalidTopics.length > 0) { | |||
topicPrompts.formatPrompt = xhr.responseJSON.message; | |||
const {invalidTopics} = xhr.responseJSON; | |||
const topicLables = topicDropdown.children('a.ui.label'); | |||
topics.split(',').forEach((value, index) => { | |||
for (let i = 0; i < invalidTopics.length; i++) { | |||
if (invalidTopics[i] === value) { | |||
topicLables | |||
.eq(index) | |||
.removeClass('green') | |||
.addClass('red'); | |||
} | |||
} | |||
}); | |||
} else { | |||
topicPrompts.countPrompt = xhr.responseJSON.message; | |||
} | |||
} | |||
}) | |||
.always(() => { | |||
topicForm.form('validate form'); | |||
}); | |||
}); | |||
topicDropdown.dropdown({ | |||
allowAdditions: true, | |||
forceSelection: false, | |||
fields: {name: 'description', value: 'data-value'}, | |||
saveRemoteData: false, | |||
label: { | |||
transition: 'horizontal flip', | |||
duration: 200, | |||
variation: false, | |||
blue: true, | |||
basic: true | |||
}, | |||
className: { | |||
label: 'ui small label' | |||
}, | |||
apiSettings: { | |||
url: `${AppSubUrl}/api/v1/topics/search?q={query}`, | |||
throttle: 500, | |||
cache: false, | |||
onResponse(res) { | |||
const formattedResponse = { | |||
success: false, | |||
results: [] | |||
}; | |||
const stripTags = function (text) { | |||
return text.replace(/<[^>]*>?/gm, ''); | |||
}; | |||
const query = stripTags(this.urlData.query.trim()); | |||
let found_query = false; | |||
const current_topics = []; | |||
topicDropdown | |||
.find('div.label.visible.topic,a.label.visible') | |||
.each((_, e) => { | |||
current_topics.push(e.dataset.value); | |||
}); | |||
if (res.topics) { | |||
let found = false; | |||
for (let i = 0; i < res.topics.length; i++) { | |||
// skip currently added tags | |||
if (current_topics.includes(res.topics[i].topic_name)) { | |||
continue; | |||
} | |||
if ( | |||
res.topics[i].topic_name.toLowerCase() === query.toLowerCase() | |||
) { | |||
found_query = true; | |||
} | |||
formattedResponse.results.push({ | |||
description: res.topics[i].topic_name, | |||
'data-value': res.topics[i].topic_name | |||
}); | |||
found = true; | |||
} | |||
formattedResponse.success = found; | |||
} | |||
if (query.length > 0 && !found_query) { | |||
formattedResponse.success = true; | |||
formattedResponse.results.unshift({ | |||
description: query, | |||
'data-value': query | |||
}); | |||
} else if (query.length > 0 && found_query) { | |||
formattedResponse.results.sort((a, b) => { | |||
if (a.description.toLowerCase() === query.toLowerCase()) return -1; | |||
if (b.description.toLowerCase() === query.toLowerCase()) return 1; | |||
if (a.description > b.description) return -1; | |||
if (a.description < b.description) return 1; | |||
return 0; | |||
}); | |||
} | |||
return formattedResponse; | |||
} | |||
}, | |||
onLabelCreate(value) { | |||
value = value.toLowerCase().trim(); | |||
this.attr('data-value', value) | |||
.contents() | |||
.first() | |||
.replaceWith(value); | |||
return $(this); | |||
}, | |||
onAdd(addedValue, _addedText, $addedChoice) { | |||
addedValue = addedValue.toLowerCase().trim(); | |||
$($addedChoice).attr('data-value', addedValue); | |||
$($addedChoice).attr('data-text', addedValue); | |||
} | |||
}); | |||
$.fn.form.settings.rules.validateTopic = function (_values, regExp) { | |||
const topics = topicDropdown.children('a.ui.label'); | |||
const status = | |||
topics.length === 0 || (topics.last().attr('data-value').match(regExp) !== null && topics.last().attr('data-value').length <= 35); | |||
if (!status) { | |||
topics | |||
.last() | |||
.removeClass('green') | |||
.addClass('red'); | |||
} | |||
return status && topicDropdown.children('a.ui.label.red').length === 0; | |||
}; | |||
topicForm.form({ | |||
on: 'change', | |||
inline: true, | |||
fields: { | |||
topics: { | |||
identifier: 'topics', | |||
rules: [ | |||
{ | |||
type: 'validateTopic', | |||
value: /^[\u4e00-\u9fa5a-z0-9][\u4e00-\u9fa5a-z0-9-]{0,105}$/, | |||
prompt: topicPrompts.formatPrompt | |||
}, | |||
{ | |||
type: 'maxCount[25]', | |||
prompt: topicPrompts.countPrompt | |||
} | |||
] | |||
} | |||
} | |||
}); | |||
} | |||
// function initTopicbar() { | |||
// const mgrBtn = $('#manage_topic'); | |||
// const editDiv = $('#topic_edit'); | |||
// const viewDiv = $('#repo-topics'); | |||
// const saveBtn = $('#save_topic'); | |||
// const topicDropdown = $('#topic_edit .dropdown'); | |||
// const topicForm = $('#topic_edit.ui.form'); | |||
// const topicInput = $("#topics_input") | |||
// const topicPrompts = getPrompts(); | |||
// mgrBtn.on('click', (e) => { | |||
// // viewDiv.hide(); | |||
// editDiv.css('display', ''); // show Semantic UI Grid | |||
// topicInput.val('') | |||
// console.log("-----------------asdasd",$("#topics_input"),$("#topics_input").val()) | |||
// stopPropagation(e); | |||
// }); | |||
// $(document).bind('click',function(){ | |||
// editDiv.css('display','none'); | |||
// }) | |||
// editDiv.click(function(e){ | |||
// stopPropagation(e); | |||
// }) | |||
// function getPrompts() { | |||
// const hidePrompt = $('div.hide#validate_prompt'); | |||
// const prompts = { | |||
// countPrompt: hidePrompt.children('#count_prompt').text(), | |||
// formatPrompt: hidePrompt.children('#format_prompt').text() | |||
// }; | |||
// hidePrompt.remove(); | |||
// return prompts; | |||
// } | |||
// function stopPropagation(e) { | |||
// var ev = e || window.event; | |||
// if (ev.stopPropagation) { | |||
// ev.stopPropagation(); | |||
// } | |||
// else if (window.event) { | |||
// window.event.cancelBubble = true;//兼容IE | |||
// } | |||
// } | |||
// saveBtn.on('click', () => { | |||
// const topics = $('input[name=topics]').val(); | |||
// $.post( | |||
// saveBtn.data('link'), | |||
// { | |||
// _csrf: csrf, | |||
// topics | |||
// }, | |||
// (_data, _textStatus, xhr) => { | |||
// if (xhr.responseJSON.status === 'ok') { | |||
// console.log("--------saveBtn------------") | |||
// viewDiv.children('.topic').remove(); | |||
// if (topics.length) { | |||
// const topicArray = topics.split(','); | |||
// const last = viewDiv.children('a').last(); | |||
// for (let i = 0; i < topicArray.length; i++) { | |||
// const link = $('<a class="ui repo-topic small label topic"></a>'); | |||
// link.attr( | |||
// 'href', | |||
// `${AppSubUrl}/explore/repos?q=${encodeURIComponent( | |||
// topicArray[i] | |||
// )}&topic=1` | |||
// ); | |||
// link.text(topicArray[i]); | |||
// link.insertBefore(last); | |||
// } | |||
// } | |||
// editDiv.css('display', 'none'); | |||
// viewDiv.show(); | |||
// } | |||
// } | |||
// ) | |||
// .fail((xhr) => { | |||
// if (xhr.status === 422) { | |||
// if (xhr.responseJSON.invalidTopics.length > 0) { | |||
// topicPrompts.formatPrompt = xhr.responseJSON.message; | |||
// const {invalidTopics} = xhr.responseJSON; | |||
// const topicLables = topicDropdown.children('a.ui.label'); | |||
// topics.split(',').forEach((value, index) => { | |||
// for (let i = 0; i < invalidTopics.length; i++) { | |||
// if (invalidTopics[i] === value) { | |||
// topicLables | |||
// .eq(index) | |||
// .removeClass('green') | |||
// .addClass('red'); | |||
// } | |||
// } | |||
// }); | |||
// } else { | |||
// topicPrompts.countPrompt = xhr.responseJSON.message; | |||
// } | |||
// } | |||
// }) | |||
// .always(() => { | |||
// topicForm.form('validate form'); | |||
// }); | |||
// }); | |||
// topicDropdown.dropdown({ | |||
// allowAdditions: true, | |||
// forceSelection: false, | |||
// fields: {name: 'description', value: 'data-value'}, | |||
// saveRemoteData: false, | |||
// label: { | |||
// transition: 'horizontal flip', | |||
// duration: 200, | |||
// variation: false, | |||
// blue: true, | |||
// basic: true | |||
// }, | |||
// className: { | |||
// label: 'ui small label' | |||
// }, | |||
// apiSettings: { | |||
// url: `${AppSubUrl}/api/v1/topics/search?q={query}`, | |||
// throttle: 500, | |||
// cache: false, | |||
// onResponse(res) { | |||
// const formattedResponse = { | |||
// success: false, | |||
// results: [] | |||
// }; | |||
// const stripTags = function (text) { | |||
// return text.replace(/<[^>]*>?/gm, ''); | |||
// }; | |||
// const query = stripTags(this.urlData.query.trim()); | |||
// let found_query = false; | |||
// const current_topics = []; | |||
// topicDropdown | |||
// .find('div.label.visible.topic,a.label.visible') | |||
// .each((_, e) => { | |||
// current_topics.push(e.dataset.value); | |||
// }); | |||
// if (res.topics) { | |||
// let found = false; | |||
// for (let i = 0; i < res.topics.length; i++) { | |||
// // skip currently added tags | |||
// if (current_topics.includes(res.topics[i].topic_name)) { | |||
// continue; | |||
// } | |||
// if ( | |||
// res.topics[i].topic_name.toLowerCase() === query.toLowerCase() | |||
// ) { | |||
// found_query = true; | |||
// } | |||
// formattedResponse.results.push({ | |||
// description: res.topics[i].topic_name, | |||
// 'data-value': res.topics[i].topic_name | |||
// }); | |||
// found = true; | |||
// } | |||
// formattedResponse.success = found; | |||
// } | |||
// if (query.length > 0 && !found_query) { | |||
// formattedResponse.success = true; | |||
// formattedResponse.results.unshift({ | |||
// description: query, | |||
// 'data-value': query | |||
// }); | |||
// } else if (query.length > 0 && found_query) { | |||
// formattedResponse.results.sort((a, b) => { | |||
// if (a.description.toLowerCase() === query.toLowerCase()) return -1; | |||
// if (b.description.toLowerCase() === query.toLowerCase()) return 1; | |||
// if (a.description > b.description) return -1; | |||
// if (a.description < b.description) return 1; | |||
// return 0; | |||
// }); | |||
// } | |||
// return formattedResponse; | |||
// } | |||
// }, | |||
// onLabelCreate(value) { | |||
// value = value.toLowerCase().trim(); | |||
// this.attr('data-value', value) | |||
// .contents() | |||
// .first() | |||
// .replaceWith(value); | |||
// return $(this); | |||
// }, | |||
// onAdd(addedValue, _addedText, $addedChoice) { | |||
// addedValue = addedValue.toLowerCase().trim(); | |||
// $($addedChoice).attr('data-value', addedValue); | |||
// $($addedChoice).attr('data-text', addedValue); | |||
// } | |||
// }); | |||
// $.fn.form.settings.rules.validateTopic = function (_values, regExp) { | |||
// const topics = topicDropdown.children('a.ui.label'); | |||
// const status = | |||
// topics.length === 0 || (topics.last().attr('data-value').match(regExp) !== null && topics.last().attr('data-value').length <= 35); | |||
// if (!status) { | |||
// topics | |||
// .last() | |||
// .removeClass('green') | |||
// .addClass('red'); | |||
// } | |||
// return status && topicDropdown.children('a.ui.label.red').length === 0; | |||
// }; | |||
// topicForm.form({ | |||
// on: 'change', | |||
// inline: true, | |||
// fields: { | |||
// topics: { | |||
// identifier: 'topics', | |||
// rules: [ | |||
// { | |||
// type: 'validateTopic', | |||
// value: /^[\u4e00-\u9fa5a-z0-9][\u4e00-\u9fa5a-z0-9-]{0,105}$/, | |||
// prompt: topicPrompts.formatPrompt | |||
// }, | |||
// { | |||
// type: 'maxCount[25]', | |||
// prompt: topicPrompts.countPrompt | |||
// } | |||
// ] | |||
// } | |||
// } | |||
// }); | |||
// } | |||
window.toggleDeadlineForm = function () { | |||
$('#deadlineForm').fadeToggle(150); | |||
@@ -140,19 +140,32 @@ | |||
border: 1px solid #ffffff; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
.item { | |||
border-bottom: 1px solid rgba(34,36,38,.15); | |||
.ui.buttons { | |||
.button { | |||
box-shadow: none !important; | |||
} | |||
} | |||
} | |||
.ui.grid > .row { | |||
align-items: center; | |||
} | |||
.title { | |||
font-size: 16px; | |||
font-weight: bold; | |||
margin: 0 6px; | |||
margin: 0 6px; | |||
overflow: hidden; | |||
padding-right: 15px; | |||
white-space: nowrap; | |||
text-overflow: ellipsis; | |||
display: block; | |||
} | |||
.directory-seperator { | |||
padding: 0 4px; | |||
@@ -220,3 +220,25 @@ footer .column{margin-bottom:0!important; padding-bottom:0!important;} | |||
.ui.vertical.menu .dropdown.item .menu { | |||
left: 50%; | |||
} | |||
// icon cloudbrain | |||
.i-round{display:inline-block;width:18px;height:18px;background:url("/img/icons.svg");background-position: -496px -52px;} | |||
.i-bg-organ{background-position: -496px -52px;} | |||
.STOPPED{display:inline-block;width:18px;height:18px;background:url("/img/icons.svg");background-position: -496px -52px;background-position: -459px -52px;} | |||
.RUNNING{display:inline-block;width:18px;height:18px;background:url("/img/icons.svg");background-position: -496px -52px;background-position: -478px -52px;} | |||
.i-bg-orange{background-position: -495px -51px;} | |||
.FAILED{display:inline-block;width:18px;height:18px;background:url("/img/icons.svg");background-position: -496px -52px;background-position: -532px -52px;} | |||
.i-bg-green{background-position: -441px -52px;} | |||
.i-bg-used{background-position: -514px -52px;} | |||
.icon-bind{background-position: -550px -52px;} | |||
.icon-unbind{background-position: -568px -52px;} | |||
.CREATING, .STOPPING, .DELETING, .STARTING, .WAITING{display:inline-block;background-image:url('/img/loading.gif');background-repeat:no-repeat;width:16px;height:16px;background-size:16px 16px;margin-right:5px;} | |||
.text_over{ | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
-o-text-overflow: ellipsis; | |||
white-space: nowrap; | |||
display: inline-block; | |||
width: 100%; | |||
} | |||