@@ -72,11 +72,11 @@ type CloudBrainLoginResult struct { | |||
type TaskRole struct { | |||
Name string `json:"name"` | |||
TaskNumber int `json:"taskNumber"` | |||
MinSucceededTaskCount int `json:"minSucceededTaskCount"` | |||
MinFailedTaskCount int `json:"minFailedTaskCount"` | |||
CPUNumber int `json:"cpuNumber"` | |||
GPUNumber int `json:"gpuNumber"` | |||
TaskNumber int `json:"taskNumber"` | |||
MinSucceededTaskCount int `json:"minSucceededTaskCount"` | |||
MinFailedTaskCount int `json:"minFailedTaskCount"` | |||
CPUNumber int `json:"cpuNumber"` | |||
GPUNumber int `json:"gpuNumber"` | |||
MemoryMB int `json:"memoryMB"` | |||
ShmMB int `json:"shmMB"` | |||
Command string `json:"command"` | |||
@@ -123,8 +123,9 @@ type GetImagesResult struct { | |||
} | |||
type GetImagesPayload struct { | |||
Count int `json:"count"` | |||
ImageInfo []*ImageInfo `json:"rows"` | |||
Count int `json:"count"` | |||
TotalPages int `json:"totalPages,omitempty"` | |||
ImageInfo []*ImageInfo `json:"rows"` | |||
} | |||
type CloudbrainsOptions struct { | |||
@@ -298,6 +299,25 @@ type ResourceSpec struct { | |||
ShareMemMiB int `json:"shareMemMiB"` | |||
} | |||
type FlavorInfos struct { | |||
FlavorInfo []*FlavorInfo `json:"flavor_info"` | |||
} | |||
type FlavorInfo struct { | |||
Id int `json:"id"` | |||
Value string `json:"value"` | |||
} | |||
type PoolInfos struct { | |||
PoolInfo []*PoolInfo `json:"pool_info"` | |||
} | |||
type PoolInfo struct { | |||
PoolId string `json:"pool_id"` | |||
PoolName string `json:"pool_name"` | |||
PoolType string `json:"pool_type"` | |||
} | |||
type CommitImageParams struct { | |||
Ip string `json:"ip"` | |||
TaskContainerId string `json:"taskContainerId"` | |||
@@ -87,7 +87,7 @@ func InsertFileChunk(fileChunk *FileChunk) (_ *FileChunk, err error) { | |||
return fileChunk, nil | |||
} | |||
// UpdateAttachment updates the given attachment in database | |||
// UpdateFileChunk updates the given file_chunk in database | |||
func UpdateFileChunk(fileChunk *FileChunk) error { | |||
return updateFileChunk(x, fileChunk) | |||
} | |||
@@ -98,3 +98,13 @@ func updateFileChunk(e Engine, fileChunk *FileChunk) error { | |||
_, err := sess.Cols("is_uploaded").Update(fileChunk) | |||
return err | |||
} | |||
// DeleteFileChunk delete the given file_chunk in database | |||
func DeleteFileChunk(fileChunk *FileChunk) error { | |||
return deleteFileChunk(x, fileChunk) | |||
} | |||
func deleteFileChunk(e Engine, fileChunk *FileChunk) error { | |||
_, err := e.ID(fileChunk.ID).Delete(fileChunk) | |||
return err | |||
} |
@@ -1,9 +1,11 @@ | |||
package cloudbrain | |||
import ( | |||
"code.gitea.io/gitea/modules/log" | |||
"encoding/json" | |||
"fmt" | |||
"strings" | |||
"code.gitea.io/gitea/modules/log" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/setting" | |||
@@ -11,13 +13,16 @@ import ( | |||
) | |||
var ( | |||
restyClient *resty.Client | |||
HOST string | |||
TOKEN string | |||
restyClient *resty.Client | |||
HOST string | |||
TOKEN string | |||
ImagesUrlMap = map[string]string{Public: "/rest-server/api/v1/image/public/list/", Custom: "/rest-server/api/v1/image/list/"} | |||
) | |||
const ( | |||
JobHasBeenStopped = "S410" | |||
Public = "public" | |||
Custom = "custom" | |||
) | |||
func getRestyClient() *resty.Client { | |||
@@ -77,6 +82,12 @@ sendjob: | |||
Post(HOST + "/rest-server/api/v1/jobs/") | |||
if err != nil { | |||
if res != nil { | |||
var response models.CloudBrainResult | |||
json.Unmarshal(res.Body(), &response) | |||
log.Error("code(%s), msg(%s)", response.Code, response.Msg) | |||
return nil, fmt.Errorf(response.Msg) | |||
} | |||
return nil, fmt.Errorf("resty create job: %s", err) | |||
} | |||
@@ -126,6 +137,16 @@ sendjob: | |||
} | |||
func GetImages() (*models.GetImagesResult, error) { | |||
return GetImagesPageable(1, 100, Custom, "") | |||
} | |||
func GetPublicImages() (*models.GetImagesResult, error) { | |||
return GetImagesPageable(1, 100, Public, "") | |||
} | |||
func GetImagesPageable(page int, size int, imageType string, name string) (*models.GetImagesResult, error) { | |||
checkSetting() | |||
client := getRestyClient() | |||
var getImagesResult models.GetImagesResult | |||
@@ -136,9 +157,9 @@ sendjob: | |||
res, err := client.R(). | |||
SetHeader("Content-Type", "application/json"). | |||
SetAuthToken(TOKEN). | |||
SetQueryString("pageIndex=1&pageSize=100"). | |||
SetQueryString(getQueryString(page, size, name)). | |||
SetResult(&getImagesResult). | |||
Get(HOST + "/rest-server/api/v1/image/list/") | |||
Get(HOST + ImagesUrlMap[imageType]) | |||
if err != nil { | |||
return nil, fmt.Errorf("resty GetImages: %v", err) | |||
@@ -157,48 +178,30 @@ sendjob: | |||
goto sendjob | |||
} | |||
if len(response.Code) != 0 { | |||
log.Error("getImagesResult failed(%s): %s", response.Code, response.Msg) | |||
return &getImagesResult, fmt.Errorf("getImagesResult failed(%s): %s", response.Code, response.Msg) | |||
} | |||
if getImagesResult.Code != Success { | |||
return &getImagesResult, fmt.Errorf("getImagesResult err: %s", res.String()) | |||
} | |||
getImagesResult.Payload.TotalPages = getTotalPages(getImagesResult, size) | |||
return &getImagesResult, nil | |||
} | |||
func GetPublicImages() (*models.GetImagesResult, error) { | |||
checkSetting() | |||
client := getRestyClient() | |||
var getImagesResult models.GetImagesResult | |||
retry := 0 | |||
sendjob: | |||
res, err := client.R(). | |||
SetHeader("Content-Type", "application/json"). | |||
SetAuthToken(TOKEN). | |||
SetQueryString("pageIndex=1&pageSize=100"). | |||
SetResult(&getImagesResult). | |||
Get(HOST + "/rest-server/api/v1/image/public/list/") | |||
if err != nil { | |||
return nil, fmt.Errorf("resty GetPublicImages: %v", err) | |||
} | |||
if getImagesResult.Code == "S401" && retry < 1 { | |||
retry++ | |||
_ = loginCloudbrain() | |||
goto sendjob | |||
func getTotalPages(getImagesResult models.GetImagesResult, size int) int { | |||
totalCount := getImagesResult.Payload.Count | |||
var totalPages int | |||
if totalCount%size != 0 { | |||
totalPages = totalCount/size + 1 | |||
} else { | |||
totalPages = totalCount / size | |||
} | |||
return totalPages | |||
} | |||
if getImagesResult.Code != Success { | |||
return &getImagesResult, fmt.Errorf("getImgesResult err: %s", res.String()) | |||
func getQueryString(page int, size int, name string) string { | |||
if strings.TrimSpace(name) == "" { | |||
return fmt.Sprintf("pageIndex=%d&pageSize=%d", page, size) | |||
} | |||
return &getImagesResult, nil | |||
return fmt.Sprintf("pageIndex=%d&pageSize=%d&name=%s", page, size, name) | |||
} | |||
func CommitImage(jobID string, params models.CommitImageParams) error { | |||
@@ -2,6 +2,7 @@ package modelarts | |||
import ( | |||
"code.gitea.io/gitea/modules/setting" | |||
"encoding/json" | |||
"path" | |||
"code.gitea.io/gitea/models" | |||
@@ -12,30 +13,31 @@ import ( | |||
const ( | |||
storageTypeOBS = "obs" | |||
autoStopDuration = 4 * 60 * 60 | |||
flavor = "modelarts.kat1.xlarge" | |||
//profileID = "Python3-ascend910-arm" | |||
profileID = "efa847c0-7359-11eb-b34f-0255ac100057" | |||
poolID = "pool1328035d" | |||
poolName = "train-private-1" | |||
poolType = "USER_DEFINED" | |||
DataSetMountPath = "/home/ma-user/work" | |||
NotebookEnv = "Python3" | |||
NotebookType = "Ascend" | |||
FlavorInfo = "Ascend: 1*Ascend 910 CPU: 24 核 96GiB (modelarts.kat1.xlarge)" | |||
) | |||
var ( | |||
poolInfos *models.PoolInfos | |||
FlavorInfos *models.FlavorInfos | |||
) | |||
func GenerateTask(ctx *context.Context, jobName, uuid, description string) error { | |||
dataActualPath := setting.Bucket + "/" + setting.BasePath + path.Join(uuid[0:1], uuid[1:2]) + "/" + uuid + "/" | |||
if poolInfos == nil { | |||
json.Unmarshal([]byte(setting.PoolInfos), &poolInfos) | |||
} | |||
jobResult, err := CreateJob(models.CreateNotebookParams{ | |||
JobName: jobName, | |||
Description: description, | |||
ProfileID: profileID, | |||
Flavor: flavor, | |||
ProfileID: setting.ProfileID, | |||
Flavor: setting.Flavor, | |||
Pool: models.Pool{ | |||
ID: poolID, | |||
Name: poolName, | |||
Type: poolType, | |||
ID: poolInfos.PoolInfo[0].PoolId, | |||
Name: poolInfos.PoolInfo[0].PoolName, | |||
Type: poolInfos.PoolInfo[0].PoolType, | |||
}, | |||
Spec: models.Spec{ | |||
Storage: models.Storage{ | |||
@@ -473,6 +473,10 @@ var ( | |||
ModelArtsUsername string | |||
ModelArtsPassword string | |||
ModelArtsDomain string | |||
ProfileID string | |||
PoolInfos string | |||
Flavor string | |||
FlavorInfos string | |||
) | |||
// DateLang transforms standard language locale name to corresponding value in datetime plugin. | |||
@@ -1182,6 +1186,10 @@ func NewContext() { | |||
ModelArtsUsername = sec.Key("USERNAME").MustString("") | |||
ModelArtsPassword = sec.Key("PASSWORD").MustString("") | |||
ModelArtsDomain = sec.Key("DOMAIN").MustString("cn-south-222") | |||
ProfileID = sec.Key("PROFILE_ID").MustString("") | |||
PoolInfos = sec.Key("POOL_INFOS").MustString("") | |||
Flavor = sec.Key("FLAVOR").MustString("") | |||
FlavorInfos = sec.Key("FLAVOR_INFOS").MustString("") | |||
} | |||
func loadInternalToken(sec *ini.Section) string { | |||
@@ -223,6 +223,7 @@ issues.in_your_repos = In your repositories | |||
repos = Repositories | |||
users = Users | |||
organizations = Organizations | |||
images = CloudImages | |||
search = Search | |||
code = Code | |||
repo_no_results = No matching repositories found. | |||
@@ -767,6 +768,7 @@ cloudbrain2 = cloudbrain2 | |||
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 | |||
template.items = Template Items | |||
template.git_content = Git Content (Default Branch) | |||
@@ -224,6 +224,7 @@ issues.in_your_repos=属于该用户项目的 | |||
repos=项目 | |||
users=用户 | |||
organizations=组织 | |||
images = 云脑镜像 | |||
search=搜索 | |||
code=代码 | |||
repo_no_results=未找到匹配的项目。 | |||
@@ -478,7 +479,7 @@ add_new_email=添加新的邮箱地址 | |||
add_new_openid=添加新的 OpenID URI | |||
add_email=增加电子邮件地址 | |||
add_openid=添加 OpenID URI | |||
add_email_confirmation_sent=一封新的确认邮件已经被发送至 <b>%s</b>,请检查您的收件箱并在 %s 内完成确认注册操作。 | |||
add_email_confirmation_sent=一封新的确认邮件已经被发送至 <b>%s</b>,请检查您的收件箱并在 %s 内完成确认操作。 | |||
add_email_success=新的电子邮件地址已添加。 | |||
email_preference_set_success=电子邮件首选项已成功设置。 | |||
add_openid_success=新的 OpenID 地址已添加。 | |||
@@ -769,6 +770,7 @@ cloudbrain2=云脑2 | |||
cloudbrain_selection=云脑选择 | |||
cloudbrain_platform_selection=选择您准备使用的云脑平台: | |||
confirm_choice=确定 | |||
cloudbran1_tips=只有zip格式的数据集才能发起云脑任务 | |||
template.items=模板选项 | |||
template.git_content=Git数据(默认分支) | |||
@@ -32,7 +32,8 @@ const ( | |||
// tplExploreOrganizations explore organizations page template | |||
tplExploreOrganizations base.TplName = "explore/organizations" | |||
// tplExploreCode explore code page template | |||
tplExploreCode base.TplName = "explore/code" | |||
tplExploreCode base.TplName = "explore/code" | |||
tplExploreImages base.TplName = "explore/images" | |||
) | |||
// Home render home page | |||
@@ -475,6 +476,10 @@ func ExploreCode(ctx *context.Context) { | |||
ctx.HTML(200, tplExploreCode) | |||
} | |||
func ExploreImages(ctx *context.Context) { | |||
ctx.HTML(200, tplExploreImages) | |||
} | |||
// NotFound render 404 page | |||
func NotFound(ctx *context.Context) { | |||
ctx.Data["Title"] = "Page Not Found" | |||
@@ -483,16 +483,25 @@ func GetSuccessChunks(ctx *context.Context) { | |||
if typeCloudBrain == models.TypeCloudBrainOne { | |||
chunks, err = storage.GetPartInfos(fileChunk.UUID, fileChunk.UploadID) | |||
if err != nil { | |||
ctx.ServerError("GetPartInfos failed", err) | |||
return | |||
log.Error("GetPartInfos failed:%v", err.Error()) | |||
} | |||
} else { | |||
chunks, err = storage.GetObsPartInfos(fileChunk.UUID, fileChunk.UploadID) | |||
if err != nil { | |||
ctx.ServerError("GetObsPartInfos failed", err) | |||
return | |||
log.Error("GetObsPartInfos failed:%v", err.Error()) | |||
} | |||
} | |||
if err != nil { | |||
models.DeleteFileChunk(fileChunk) | |||
ctx.JSON(200, map[string]string{ | |||
"uuid": "", | |||
"uploaded": "0", | |||
"uploadID": "", | |||
"chunks": "", | |||
}) | |||
return | |||
} | |||
} | |||
var attachID int64 | |||
@@ -1,17 +1,21 @@ | |||
package repo | |||
import ( | |||
"code.gitea.io/gitea/modules/git" | |||
"code.gitea.io/gitea/modules/storage" | |||
"bufio" | |||
"encoding/json" | |||
"errors" | |||
"io" | |||
"net/http" | |||
"os" | |||
"os/exec" | |||
"regexp" | |||
"strconv" | |||
"strings" | |||
"time" | |||
"code.gitea.io/gitea/modules/git" | |||
"code.gitea.io/gitea/modules/storage" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/auth" | |||
"code.gitea.io/gitea/modules/base" | |||
@@ -22,10 +26,10 @@ import ( | |||
) | |||
const ( | |||
tplCloudBrainIndex base.TplName = "repo/cloudbrain/index" | |||
tplCloudBrainNew base.TplName = "repo/cloudbrain/new" | |||
tplCloudBrainShow base.TplName = "repo/cloudbrain/show" | |||
tplCloudBrainShowModels base.TplName = "repo/cloudbrain/models/index" | |||
tplCloudBrainIndex base.TplName = "repo/cloudbrain/index" | |||
tplCloudBrainNew base.TplName = "repo/cloudbrain/new" | |||
tplCloudBrainShow base.TplName = "repo/cloudbrain/show" | |||
tplCloudBrainShowModels base.TplName = "repo/cloudbrain/models/index" | |||
) | |||
var ( | |||
@@ -86,17 +90,27 @@ func cutString(str string, lens int) string { | |||
return str[:lens] | |||
} | |||
func CloudBrainNew(ctx *context.Context) { | |||
ctx.Data["PageIsCloudBrain"] = true | |||
func jobNamePrefixValid(s string) string { | |||
lowStr := strings.ToLower(s) | |||
re := regexp.MustCompile(`[^a-z0-9_\\-]+`) | |||
removeSpecial := re.ReplaceAllString(lowStr, "") | |||
re = regexp.MustCompile(`^[_\\-]+`) | |||
return re.ReplaceAllString(removeSpecial, "") | |||
} | |||
func cloudBrainNewDataPrepare(ctx *context.Context) error{ | |||
ctx.Data["PageIsCloudBrain"] = true | |||
t := time.Now() | |||
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||
var jobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||
ctx.Data["job_name"] = jobName | |||
result, err := cloudbrain.GetImages() | |||
if err != nil { | |||
ctx.Data["error"] = err.Error() | |||
log.Error("cloudbrain.GetImages failed:", err.Error(), ctx.Data["msgID"]) | |||
log.Error("cloudbrain.GetImages failed:", err.Error(), ctx.Data["MsgID"]) | |||
} | |||
for i, payload := range result.Payload.ImageInfo { | |||
@@ -112,7 +126,7 @@ func CloudBrainNew(ctx *context.Context) { | |||
resultPublic, err := cloudbrain.GetPublicImages() | |||
if err != nil { | |||
ctx.Data["error"] = err.Error() | |||
log.Error("cloudbrain.GetPublicImages failed:", err.Error(), ctx.Data["msgID"]) | |||
log.Error("cloudbrain.GetPublicImages failed:", err.Error(), ctx.Data["MsgID"]) | |||
} | |||
for i, payload := range resultPublic.Payload.ImageInfo { | |||
@@ -127,8 +141,8 @@ func CloudBrainNew(ctx *context.Context) { | |||
attachs, err := models.GetAllUserAttachments(ctx.User.ID) | |||
if err != nil { | |||
ctx.ServerError("GetAllUserAttachments failed:", err) | |||
return | |||
log.Error("GetAllUserAttachments failed: %v", err, ctx.Data["MsgID"]) | |||
return err | |||
} | |||
ctx.Data["attachments"] = attachs | |||
@@ -155,6 +169,16 @@ func CloudBrainNew(ctx *context.Context) { | |||
ctx.Data["resource_specs"] = cloudbrain.ResourceSpecs.ResourceSpec | |||
ctx.Data["snn4imagenet_path"] = cloudbrain.Snn4imagenetMountPath | |||
ctx.Data["is_snn4imagenet_enabled"] = setting.IsSnn4imagenetEnabled | |||
return nil | |||
} | |||
func CloudBrainNew(ctx *context.Context) { | |||
err := cloudBrainNewDataPrepare(ctx) | |||
if err != nil { | |||
ctx.ServerError("get new cloudbrain info failed", err) | |||
return | |||
} | |||
ctx.HTML(200, tplCloudBrainNew) | |||
} | |||
@@ -170,7 +194,8 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
resourceSpecId := form.ResourceSpecId | |||
if jobType != string(models.JobTypeBenchmark) && jobType != string(models.JobTypeDebug) && jobType != string(models.JobTypeSnn4imagenet) { | |||
log.Error("jobtype error:", jobType, ctx.Data["msgID"]) | |||
log.Error("jobtype error:", jobType, ctx.Data["MsgID"]) | |||
cloudBrainNewDataPrepare(ctx) | |||
ctx.RenderWithErr("jobtype error", tplCloudBrainNew, &form) | |||
return | |||
} | |||
@@ -178,11 +203,13 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
_, err := models.GetCloudbrainByName(jobName) | |||
if err == nil { | |||
log.Error("the job name did already exist", ctx.Data["MsgID"]) | |||
cloudBrainNewDataPrepare(ctx) | |||
ctx.RenderWithErr("the job name did already exist", tplCloudBrainNew, &form) | |||
return | |||
} else { | |||
if !models.IsErrJobNotExist(err) { | |||
log.Error("system error, %v", err, ctx.Data["MsgID"]) | |||
cloudBrainNewDataPrepare(ctx) | |||
ctx.RenderWithErr("system error", tplCloudBrainNew, &form) | |||
return | |||
} | |||
@@ -193,6 +220,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath | |||
err = os.MkdirAll(modelPath, os.ModePerm) | |||
if err != nil { | |||
cloudBrainNewDataPrepare(ctx) | |||
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) | |||
return | |||
} | |||
@@ -216,6 +244,7 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, jobType, gpuQueue, resourceSpecId) | |||
if err != nil { | |||
cloudBrainNewDataPrepare(ctx) | |||
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) | |||
return | |||
} | |||
@@ -390,6 +419,38 @@ func CloudBrainShowModels(ctx *context.Context) { | |||
ctx.HTML(200, tplCloudBrainShowModels) | |||
} | |||
func GetPublicImages(ctx *context.Context) { | |||
getImages(ctx, cloudbrain.Public) | |||
} | |||
func GetCustomImages(ctx *context.Context) { | |||
getImages(ctx, cloudbrain.Custom) | |||
} | |||
func getImages(ctx *context.Context, imageType string) { | |||
log.Info("Get images begin") | |||
page := ctx.QueryInt("page") | |||
size := ctx.QueryInt("size") | |||
name := ctx.Query("name") | |||
getImagesResult, err := cloudbrain.GetImagesPageable(page, size, imageType, name) | |||
if err != nil { | |||
log.Error("Can not get images:%v", err) | |||
ctx.JSON(http.StatusOK, models.GetImagesPayload{ | |||
Count: 0, | |||
TotalPages: 0, | |||
ImageInfo: []*models.ImageInfo{}, | |||
}) | |||
} else { | |||
ctx.JSON(http.StatusOK, getImagesResult.Payload) | |||
} | |||
log.Info("Get images end") | |||
} | |||
func getModelDirs(jobName string, parentDir string) (string, error) { | |||
var req string | |||
modelActualPath := setting.JobPath + jobName + "/model/" | |||
@@ -406,7 +467,7 @@ func CloudBrainDownloadModel(ctx *context.Context) { | |||
parentDir := ctx.Query("parentDir") | |||
fileName := ctx.Query("fileName") | |||
jobName := ctx.Query("jobName") | |||
filePath := "jobs/" +jobName + "/model/" + parentDir | |||
filePath := "jobs/" + jobName + "/model/" + parentDir | |||
url, err := storage.Attachments.PresignedGetURL(filePath, fileName) | |||
if err != nil { | |||
log.Error("PresignedGetURL failed: %v", err.Error(), ctx.Data["msgID"]) | |||
@@ -440,6 +501,45 @@ func downloadCode(repo *models.Repository, codePath string) error { | |||
return err | |||
} | |||
configFile, err := os.OpenFile(codePath + "/.git/config", os.O_RDWR, 0666) | |||
if err != nil { | |||
log.Error("open file(%s) failed:%v", codePath + "/,git/config", err) | |||
return err | |||
} | |||
defer configFile.Close() | |||
pos := int64(0) | |||
reader := bufio.NewReader(configFile) | |||
for { | |||
line, err := reader.ReadString('\n') | |||
if err != nil { | |||
if err == io.EOF { | |||
log.Error("not find the remote-url") | |||
return nil | |||
} else { | |||
log.Error("read error: %v", err) | |||
return err | |||
} | |||
} | |||
if strings.Contains(line, "url") && strings.Contains(line, ".git"){ | |||
originUrl := "\turl = " + repo.CloneLink().HTTPS + "\n" | |||
if len(line) > len(originUrl) { | |||
originUrl += strings.Repeat( " ", len(line) - len(originUrl)) | |||
} | |||
bytes := []byte(originUrl) | |||
_, err := configFile.WriteAt(bytes, pos) | |||
if err != nil { | |||
log.Error("WriteAt failed:%v", err) | |||
return err | |||
} | |||
break | |||
} | |||
pos += int64(len(line)) | |||
} | |||
return nil | |||
} | |||
@@ -2,6 +2,7 @@ package repo | |||
import ( | |||
"code.gitea.io/gitea/modules/modelarts" | |||
"encoding/json" | |||
"errors" | |||
"github.com/unknwon/com" | |||
"strconv" | |||
@@ -71,7 +72,7 @@ func ModelArtsNew(ctx *context.Context) { | |||
ctx.Data["PageIsCloudBrain"] = true | |||
t := time.Now() | |||
var jobName = cutString(ctx.User.Name, 5) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||
var jobName = jobNamePrefixValid(cutString(ctx.User.Name, 5)) + t.Format("2006010215") + strconv.Itoa(int(t.Unix()))[5:] | |||
ctx.Data["job_name"] = jobName | |||
attachs, err := models.GetModelArtsUserAttachments(ctx.User.ID) | |||
@@ -84,7 +85,10 @@ func ModelArtsNew(ctx *context.Context) { | |||
ctx.Data["dataset_path"] = modelarts.DataSetMountPath | |||
ctx.Data["env"] = modelarts.NotebookEnv | |||
ctx.Data["notebook_type"] = modelarts.NotebookType | |||
ctx.Data["flavor"] = modelarts.FlavorInfo | |||
if modelarts.FlavorInfos == nil { | |||
json.Unmarshal([]byte(setting.FlavorInfos), &modelarts.FlavorInfos) | |||
} | |||
ctx.Data["flavors"] = modelarts.FlavorInfos.FlavorInfo | |||
ctx.HTML(200, tplModelArtsNew) | |||
} | |||
@@ -6,13 +6,14 @@ package routes | |||
import ( | |||
"bytes" | |||
"code.gitea.io/gitea/routers/secure" | |||
"encoding/gob" | |||
"net/http" | |||
"path" | |||
"text/template" | |||
"time" | |||
"code.gitea.io/gitea/routers/secure" | |||
"code.gitea.io/gitea/models" | |||
"code.gitea.io/gitea/modules/auth" | |||
"code.gitea.io/gitea/modules/context" | |||
@@ -313,11 +314,14 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Get("", func(ctx *context.Context) { | |||
ctx.Redirect(setting.AppSubURL + "/explore/repos") | |||
}) | |||
m.Get("/images/public", repo.GetPublicImages) | |||
m.Get("/images/custom", repo.GetCustomImages) | |||
m.Get("/repos", routers.ExploreRepos) | |||
m.Get("/datasets", routers.ExploreDatasets) | |||
m.Get("/users", routers.ExploreUsers) | |||
m.Get("/organizations", routers.ExploreOrganizations) | |||
m.Get("/code", routers.ExploreCode) | |||
m.Get("/images", routers.ExploreImages) | |||
}, ignSignIn) | |||
m.Combo("/install", routers.InstallInit).Get(routers.Install). | |||
Post(bindIgnErr(auth.InstallForm{}), routers.InstallPost) | |||
@@ -90,23 +90,12 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) { | |||
} | |||
ctx.User.FullName = form.FullName | |||
ctx.User.Email = form.Email | |||
ctx.User.KeepEmailPrivate = form.KeepEmailPrivate | |||
ctx.User.Website = form.Website | |||
ctx.User.Location = form.Location | |||
ctx.User.Language = form.Language | |||
ctx.User.Description = form.Description | |||
isUsed, err := models.IsEmailUsed(form.Email) | |||
if err != nil { | |||
ctx.ServerError("IsEmailUsed", err) | |||
return | |||
} | |||
if isUsed { | |||
ctx.Flash.Error(ctx.Tr("form.email_been_used")) | |||
ctx.Redirect(setting.AppSubURL + "/user/settings") | |||
return | |||
} | |||
if err := models.UpdateUserSetting(ctx.User); err != nil { | |||
if _, ok := err.(models.ErrEmailAlreadyUsed); ok { | |||
@@ -59,7 +59,7 @@ func SendTestMail(email string) error { | |||
func SendUserMail(language string, u *models.User, tpl base.TplName, code, subject, info string) { | |||
data := map[string]interface{}{ | |||
"DisplayName": u.DisplayName(), | |||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, language), | |||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, "en-US"), | |||
"ResetPwdCodeLives": timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, language), | |||
"Code": code, | |||
} | |||
@@ -97,7 +97,7 @@ func SendResetPasswordMail(locale Locale, u *models.User) { | |||
func SendActivateEmailMail(locale Locale, u *models.User, email *models.EmailAddress) { | |||
data := map[string]interface{}{ | |||
"DisplayName": u.DisplayName(), | |||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale.Language()), | |||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, "en-US"), | |||
"Code": u.GenerateEmailActivateCode(email.Email), | |||
"Email": email.Email, | |||
} | |||
@@ -28,6 +28,7 @@ | |||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
</div> | |||
</div> | |||
{{else if .IsLandingPageHome}} | |||
@@ -42,6 +43,7 @@ | |||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "datasets"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
</div> | |||
</div> | |||
{{else if .IsLandingPageExplore}} | |||
@@ -28,6 +28,7 @@ | |||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
</div> | |||
</div> | |||
{{else if .IsLandingPageHome}} | |||
@@ -42,6 +43,7 @@ | |||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "datasets"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/users">{{.i18n.Tr "explore.users"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "explore.organizations"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/images">{{.i18n.Tr "explore.images"}}</a> | |||
</div> | |||
</div> | |||
{{else if .IsLandingPageExplore}} | |||
@@ -0,0 +1,7 @@ | |||
{{template "base/head" .}} | |||
<div id="images"> | |||
</div> | |||
{{template "base/footer" .}} |
@@ -110,12 +110,16 @@ | |||
<div class="rect5"></div> | |||
</div> | |||
</div> | |||
<div class="repository"> | |||
{{template "repo/header" .}} | |||
<div class="repository new repo ui middle very relaxed page grid"> | |||
<div class="column"> | |||
{{template "base/alert" .}} | |||
<form class="ui form" action="{{.Link}}" method="post"> | |||
<div class="ui positive message" id="messageInfo"> | |||
<p></p> | |||
</div> | |||
<form id="form_id" class="ui form" action="{{.Link}}" method="post"> | |||
{{.CsrfTokenHtml}} | |||
<h3 class="ui top attached header"> | |||
{{.i18n.Tr "repo.cloudbrain.new"}} | |||
@@ -161,7 +165,7 @@ | |||
<div class="inline required field"> | |||
<label>镜像</label> | |||
<input type="text" list="cloudbrain_image" placeholder="选择镜像" name="image"> | |||
<input type="text" list="cloudbrain_image" placeholder="选择镜像" name="image" required autofocus maxlength="36"> | |||
<datalist class="ui search" id="cloudbrain_image" style='width:385px;' name="image"> | |||
{{range .images}} | |||
<option name="image" value="{{.Place}}">{{.PlaceView}}</option> | |||
@@ -192,15 +196,15 @@ | |||
<div class="inline required field"> | |||
<label>数据集存放路径</label> | |||
<input name="dataset_path" id="cloudbrain_dataset_path" value="{{.dataset_path}}" tabindex="3" autofocus required maxlength="255" readonly="readonly"> | |||
<input name="dataset_path" id="cloudbrain_dataset_path" value="{{.dataset_path}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
</div> | |||
<div class="inline required field"> | |||
<label>模型存放路径</label> | |||
<input name="model_path" id="cloudbrain_model_path" value="{{.model_path}}" tabindex="3" autofocus required maxlength="255" readonly="readonly"> | |||
<input name="model_path" id="cloudbrain_model_path" value="{{.model_path}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
</div> | |||
<div class="inline required field"> | |||
<label>代码存放路径</label> | |||
<input name="code_path" id="cloudbrain_code_path" value="{{.code_path}}" tabindex="3" autofocus required maxlength="255" readonly="readonly"> | |||
<input name="code_path" id="cloudbrain_code_path" value="{{.code_path}}" tabindex="3" disabled autofocus required maxlength="255" readonly="readonly"> | |||
</div> | |||
<div class="inline required field cloudbrain_benchmark"> | |||
<label>benchmark脚本存放路径</label> | |||
@@ -217,13 +221,15 @@ | |||
<div class="inline field"> | |||
<label></label> | |||
<button class="ui green button" onclick="showmask()"> | |||
<button class="ui green button" > | |||
{{.i18n.Tr "repo.cloudbrain.new"}} | |||
</button> | |||
<a class="ui button" href="/">{{.i18n.Tr "repo.cloudbrain.cancel"}}</a> | |||
</div> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
@@ -231,9 +237,37 @@ | |||
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" /> | |||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script> | |||
<script> | |||
// 点击按钮后遮罩层显示 | |||
function showmask() { | |||
let url_href = window.location.pathname.split('create')[0] | |||
$(".ui.button").attr('href',url_href) | |||
let form = document.getElementById('form_id'); | |||
let value_image = $("input[name='image']").val() | |||
console.log("value_image",$("input[name='image']").val()) | |||
$('#messageInfo').css('display','none') | |||
form.onsubmit = function(e){ | |||
let value_task = $("input[name='job_name']").val() | |||
let value_image = $("input[name='image']").val() | |||
let re = /^[a-z0-9][a-z0-9-_]{1,36}$/ | |||
let flag = re.test(value_task) | |||
if(!flag){ | |||
$('#messageInfo').css('display','block') | |||
let str = '只能以小写字母或数字开头且只包含小写字母、数字、_和-、最长36个字符。' | |||
$('#messageInfo p').text(str) | |||
return false | |||
} | |||
if(!value_image){ | |||
return false | |||
} | |||
let min_value_task = value_task.toLowerCase() | |||
console.log(min_value_task) | |||
$("input[name='job_name']").attr("value",min_value_task) | |||
document.getElementById("mask").style.display = "block" | |||
} | |||
// 页面加载完毕后遮罩层隐藏 | |||
@@ -132,7 +132,12 @@ | |||
</div> | |||
<div class="inline required field"> | |||
<label>规格</label> | |||
<input name="flavor" id="cloudbrain_flavor" value="{{.flavor}}" tabindex="3" autofocus required maxlength="255" readonly="readonly"> | |||
<select id="cloudbrain_flavor" class="ui search dropdown" placeholder="选择规格" style='width:385px' name="flavor"> | |||
{{range .flavors}} | |||
<option name="flavor" value="{{.Value}}">{{.Value}}</option> | |||
{{end}} | |||
</select> | |||
</div> | |||
<div class="inline required field"> | |||
<label>数据集存放路径</label> | |||
@@ -23,7 +23,8 @@ | |||
</div> | |||
<div class="required field {{if .Err_Email}}error{{end}}"> | |||
<label for="email">{{.i18n.Tr "email"}}</label> | |||
<input id="email" name="email" disabled value="{{.SignedUser.Email}}"> | |||
<input type="hidden" id="email" name="email" value="{{.SignedUser.Email}}" > | |||
<input disabled value="{{.SignedUser.Email}}"> | |||
</div> | |||
<div class="inline field"> | |||
<div class="ui checkbox" id="keep-email-private"> | |||
@@ -0,0 +1,506 @@ | |||
<template> | |||
<div> | |||
<div class="header-wrapper"> | |||
<div class="ui container"> | |||
<el-row class="image_text"> | |||
<h1>云脑镜像</h1> | |||
</el-row> | |||
</div> | |||
</div> | |||
<div class="ui container" id="header"> | |||
<el-tabs v-model="activeName" @tab-click="handleClick"> | |||
<el-tab-pane label="公共镜像(云脑1)" name="first" v-loading="loading"> | |||
<div class="ui sixteen wide column"> | |||
<div class="ui two column stackable grid"> | |||
<div class="column"> | |||
<el-input placeholder="请输入镜像名称关健词" v-model="search" class="input-with-select" @keyup.enter.native="searchName()"> | |||
<el-button id="success" slot="append" icon="el-icon-search" @click="searchName()">搜索</el-button> | |||
</el-input> | |||
</div> | |||
<!-- <div class="column right aligned"> | |||
<el-dropdown> | |||
<span class="el-dropdown-link"> | |||
排序<i class="el-icon-caret-bottom"></i> | |||
</span> | |||
<el-dropdown-menu slot="dropdown"> | |||
<el-dropdown-item>最早创建</el-dropdown-item> | |||
<el-dropdown-item>最新创建</el-dropdown-item> | |||
<el-dropdown-item divided>按镜像字母顺序排序</el-dropdown-item> | |||
<el-dropdown-item>按镜像字母逆序排序</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</el-dropdown> | |||
</div> --> | |||
</div> | |||
</div> | |||
<el-row style="margin-top:15px;"> | |||
<el-table | |||
:data="tableData" | |||
style="width: 100%" | |||
:header-cell-style="tableHeaderStyle" | |||
:default-sort="{prop:'createtime',order:'descending'}"> | |||
<el-table-column | |||
label="镜像名称" | |||
width="350" | |||
align="left" | |||
prop="name" | |||
sortable | |||
> | |||
<template slot-scope="scope"> | |||
<a class="text-over" style="cursor:default;color:#426290" :title="scope.row.name">{{ scope.row.name }}</a> | |||
</template> | |||
</el-table-column> | |||
<el-table-column | |||
label="文件路径/镜像描述" | |||
width="450" | |||
align="left" | |||
> | |||
<template slot-scope="scope"> | |||
<el-tooltip class="item" effect="dark" content="点击复制文件路径" placement="top"> | |||
<a class="text-over" style="display:block;" @click="copyUrl(scope.row.place)">{{ scope.row.place }}</a> | |||
</el-tooltip> | |||
<span class="text-over" :title="scope.row.description">{{ scope.row.description | clearP}}</span> | |||
</template> | |||
</el-table-column> | |||
<el-table-column | |||
prop="provider" | |||
label="提供者" | |||
width="120" | |||
align="center" | |||
sortable> | |||
</el-table-column> | |||
<el-table-column | |||
prop="createtime" | |||
label="创建时间" | |||
align="center" | |||
sortable> | |||
<template slot-scope="scope"> | |||
{{scope.row.createtime | transformTimestamp}} | |||
</template> | |||
</el-table-column> | |||
</el-table> | |||
</el-row> | |||
<div class="ui container" style="margin-top:50px;text-align:center"> | |||
<el-pagination | |||
background | |||
@size-change="handleSizeChange" | |||
@current-change="handleCurrentChange" | |||
:current-page="currentPage" | |||
:page-size="pageSize" | |||
:page-sizes="[5,10,20]" | |||
layout="total, sizes, prev, pager, next, jumper" | |||
:total="totalNum"> | |||
</el-pagination> | |||
</div> | |||
</el-tab-pane> | |||
<el-tab-pane label="自定义镜像(云脑1)" name="second" v-loading="loading1"> | |||
<div class="ui sixteen wide column"> | |||
<div class="ui two column stackable grid"> | |||
<div class="column"> | |||
<el-input placeholder="请输入内容" v-model="search" class="input-with-select" @keyup.enter.native="searchName()"> | |||
<el-button slot="append" id="success" icon="el-icon-search" @click="searchName()">搜索</el-button> | |||
</el-input> | |||
</div> | |||
<!-- <div class="column right aligned"> | |||
<el-dropdown> | |||
<span class="el-dropdown-link"> | |||
排序<i class="el-icon-caret-bottom"></i> | |||
</span> | |||
<el-dropdown-menu slot="dropdown"> | |||
<el-dropdown-item>最早创建</el-dropdown-item> | |||
<el-dropdown-item>最新创建</el-dropdown-item> | |||
<el-dropdown-item divided>按镜像字母顺序排序</el-dropdown-item> | |||
<el-dropdown-item>按镜像字母逆序排序</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</el-dropdown> | |||
</div> --> | |||
</div> | |||
</div> | |||
<el-row style="margin-top:15px;"> | |||
<el-table | |||
:data="tableData1" | |||
style="width: 100%" | |||
:header-cell-style="tableHeaderStyle" | |||
:default-sort="{prop:'createtime',order:'descending'}"> | |||
<el-table-column | |||
label="镜像名称" | |||
width="350" | |||
align="left" | |||
prop="name" | |||
sortable | |||
> | |||
<template slot-scope="scope"> | |||
<a class="text-over" :title="scope.row.name" style="cursor:default;color:#426290">{{ scope.row.name }}</a> | |||
</template> | |||
</el-table-column> | |||
<el-table-column | |||
label="文件路径/镜像描述" | |||
width="450" | |||
align="left" | |||
> | |||
<template slot-scope="scope"> | |||
<el-tooltip class="item" effect="dark" content="点击复制文件路径" placement="top"> | |||
<a class="text-over" style="display:block;" @click="copyUrl(scope.row.place)">{{ scope.row.place }}</a> | |||
</el-tooltip> | |||
<span class="text-over" :title="scope.row.description">{{ scope.row.description | clearP }}</span> | |||
</template> | |||
</el-table-column> | |||
<el-table-column | |||
prop="provider" | |||
label="提供者" | |||
width="120" | |||
align="center" | |||
sortable> | |||
</el-table-column> | |||
<el-table-column | |||
prop="createtime" | |||
label="创建时间" | |||
align="center" | |||
sortable> | |||
<template slot-scope="scope"> | |||
{{scope.row.createtime | transformTimestamp}} | |||
</template> | |||
</el-table-column> | |||
</el-table> | |||
</el-row> | |||
<div class="ui container" style="margin-top:50px;text-align:center"> | |||
<el-pagination | |||
background | |||
@size-change="handleSizeChange1" | |||
@current-change="handleCurrentChange1" | |||
:current-page="currentPage1" | |||
:page-size="pageSize1" | |||
:page-sizes="[5,10,20]" | |||
layout="total, sizes, prev, pager, next, jumper" | |||
:total="totalNum1"> | |||
</el-pagination> | |||
</div> | |||
</el-tab-pane> | |||
<el-tab-pane label="公共镜像(云脑2)" name="third"> | |||
<div class="ui sixteen wide column"> | |||
<div class="ui two column stackable grid"> | |||
<div class="column"> | |||
<el-input placeholder="请输入内容" v-model="search" class="input-with-select"> | |||
<el-button slot="append" id="success" icon="el-icon-search">搜索</el-button> | |||
</el-input> | |||
</div> | |||
<!-- <div class="column right aligned"> | |||
<el-dropdown> | |||
<span class="el-dropdown-link"> | |||
排序<i class="el-icon-caret-bottom"></i> | |||
</span> | |||
<el-dropdown-menu slot="dropdown"> | |||
<el-dropdown-item>最早创建</el-dropdown-item> | |||
<el-dropdown-item>最新创建</el-dropdown-item> | |||
<el-dropdown-item divided>按镜像字母顺序排序</el-dropdown-item> | |||
<el-dropdown-item>按镜像字母逆序排序</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</el-dropdown> | |||
</div> --> | |||
</div> | |||
</div> | |||
<el-empty :image-size="200"></el-empty> | |||
</el-tab-pane> | |||
<el-tab-pane label="自定义镜像(云脑2)" name="fourth"> | |||
<div class="ui sixteen wide column"> | |||
<div class="ui two column stackable grid"> | |||
<div class="column"> | |||
<el-input placeholder="请输入内容" v-model="search" class="input-with-select"> | |||
<el-button slot="append" id="success" icon="el-icon-search">搜索</el-button> | |||
</el-input> | |||
</div> | |||
<!-- <div class="column right aligned"> | |||
<el-dropdown> | |||
<span class="el-dropdown-link"> | |||
排序<i class="el-icon-caret-bottom"></i> | |||
</span> | |||
<el-dropdown-menu slot="dropdown"> | |||
<el-dropdown-item>最早创建</el-dropdown-item> | |||
<el-dropdown-item>最新创建</el-dropdown-item> | |||
<el-dropdown-item divided>按镜像字母顺序排序</el-dropdown-item> | |||
<el-dropdown-item>按镜像字母逆序排序</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</el-dropdown> | |||
</div> --> | |||
</div> | |||
</div> | |||
<el-empty :image-size="200"></el-empty> | |||
</el-tab-pane> | |||
</el-tabs> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
const {_AppSubUrl, _StaticUrlPrefix, csrf} = window.config; | |||
export default { | |||
components: { | |||
}, | |||
data() { | |||
return { | |||
activeName: 'first', | |||
search:'', | |||
currentPage:1, | |||
pageSize:10, | |||
totalNum:0, | |||
params:{page:1,size:10,name:''}, | |||
tableData: [], | |||
loading:false, | |||
currentPage1:1, | |||
pageSize1:10, | |||
totalNum1:0, | |||
params1:{page:1,size:10,name:''}, | |||
tableData1: [], | |||
loading1:false | |||
}; | |||
}, | |||
methods: { | |||
handleClick(tab, event) { | |||
if(tab.name=="first"){ | |||
this.getImageList() | |||
} | |||
if(tab.name=="second"){ | |||
this.getImageList1() | |||
} | |||
}, | |||
tableHeaderStyle({row,column,rowIndex,columnIndex}){ | |||
if(rowIndex===0){ | |||
return 'background:#f5f5f6;color:#606266' | |||
} | |||
}, | |||
handleSizeChange(val){ | |||
this.params.size = val | |||
this.getImageList() | |||
}, | |||
handleCurrentChange(val){ | |||
console.log(val) | |||
this.params.page = val | |||
this.getImageList() | |||
}, | |||
handleSizeChange1(val){ | |||
this.params1.size = val | |||
this.getImageList1() | |||
}, | |||
handleCurrentChange1(val){ | |||
this.params1.page = val | |||
this.getImageList1() | |||
}, | |||
getImageList(){ | |||
this.loading = true | |||
this.$axios.get('/explore/images/public',{ | |||
params:this.params | |||
}).then((res)=>{ | |||
this.totalNum = res.data.count | |||
this.tableData = res.data.rows | |||
this.loading = false | |||
}) | |||
}, | |||
getImageList1(){ | |||
this.loading1 = true | |||
this.$axios.get('/explore/images/custom',{ | |||
params:this.params1 | |||
}).then((res)=>{ | |||
this.totalNum1 = res.data.count | |||
this.tableData1 = res.data.rows | |||
this.loading1 = false | |||
}) | |||
}, | |||
copyUrl(url){ | |||
console.log(url) | |||
const cInput = document.createElement('input') | |||
cInput.value = url | |||
document.body.appendChild(cInput) | |||
cInput.select() | |||
document.execCommand('Copy') | |||
cInput.remove() | |||
}, | |||
searchName(){ | |||
if(this.activeName=='first'){ | |||
this.params.name = this.search | |||
this.getImageList() | |||
} | |||
if(this.activeName=='second'){ | |||
this.params1.name = this.search | |||
this.getImageList1() | |||
} | |||
} | |||
}, | |||
filters:{ | |||
clearP(value){ | |||
console.log("sorce value",value) | |||
if(!value) return '' | |||
const reg = /\<\/?p\>/g; | |||
value = value.replace(reg,'') | |||
console.log("repalace:",value) | |||
return value | |||
}, | |||
transformTimestamp(timestamp){ | |||
console.log("timestamp",timestamp) | |||
let a = new Date(timestamp).getTime(); | |||
const date = new Date(a); | |||
const Y = date.getFullYear() + '-'; | |||
const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'; | |||
const D = (date.getDate() < 10 ? '0'+date.getDate() : date.getDate()) + ' '; | |||
const h = (date.getHours() < 10 ? '0'+date.getHours() : date.getHours()) + ':'; | |||
const m = (date.getMinutes() <10 ? '0'+date.getMinutes() : date.getMinutes()) + ':' ; | |||
const s = (date.getSeconds() <10 ? '0'+date.getSeconds() : date.getSeconds()) ; // 秒 | |||
const dateString = Y + M + D + h + m + s; | |||
// console.log('dateString', dateString); // > dateString 2021-07-06 14:23 | |||
return dateString; | |||
}, | |||
}, | |||
watch:{ | |||
search(val){ | |||
if(!val && this.activeName=='first'){ | |||
this.params.name = val | |||
this.getImageList() | |||
} | |||
if(!val && this.activeName=='second'){ | |||
this.params1.name = val | |||
this.getImageList1() | |||
} | |||
} | |||
}, | |||
mounted() { | |||
this.getImageList() | |||
}, | |||
created() { | |||
} | |||
}; | |||
</script> | |||
<style scoped> | |||
.header-wrapper { | |||
background-color: #f5f5f6; | |||
padding-top: 15px; | |||
} | |||
.image_text{ | |||
padding:25px 0 55px 0 ; | |||
} | |||
#header{ | |||
position: relative; | |||
top:-40px; | |||
} | |||
.el-dropdown-menu__item--divided{ | |||
border-top: 1px solid blue; | |||
} | |||
.el-table thead{ | |||
background-color: #f5f5f6; | |||
} | |||
/deep/ .el-tabs__item:hover{ | |||
color: #000; | |||
font-weight: 500; | |||
} | |||
/deep/ .el-tabs__item.is-active { | |||
color: #000; | |||
font-weight: 500; | |||
} | |||
/deep/ .el-tabs__active-bar{ | |||
background-color:#000 | |||
} | |||
/deep/ .el-pagination.is-background .el-pager li:not(.disabled).active { | |||
background-color: #5bb973; | |||
color: #FFF; | |||
} | |||
/deep/ .el-pagination.is-background .el-pager li.active { | |||
color: #fff; | |||
cursor: default; | |||
} | |||
/deep/ .el-pagination.is-background .el-pager li:hover { | |||
color: #5bb973; | |||
} | |||
/deep/ .el-pagination.is-background .el-pager li:not(.disabled):hover { | |||
color: #5bb973; | |||
} | |||
/deep/ .el-pagination.is-background .el-pager li:not(.disabled).active:hover { | |||
background-color: #5bb973; | |||
color: #FFF; | |||
} | |||
/deep/ .el-pager li.active { | |||
color: #08C0B9; | |||
cursor: default; | |||
} | |||
/deep/ .el-pagination .el-pager li:hover { | |||
color: #08C0B9; | |||
} | |||
/deep/ .el-pagination .el-pager li:not(.disabled):hover { | |||
color: #08C0B9; | |||
} | |||
/* /deep/ .el-pagination.is-background .el-pager li:not(.disabled).active{ | |||
background-color: #5bb973; | |||
color: #000; | |||
} */ | |||
/* /deep/ .el-pager li:hover{ | |||
color: #000; | |||
} */ | |||
#success{ | |||
background-color: #5bb973; | |||
color: white; | |||
} | |||
.text-over{ | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
vertical-align: middle; | |||
white-space: nowrap; | |||
} | |||
</style> |
@@ -1,5 +1,8 @@ | |||
<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" | |||
@@ -35,6 +35,7 @@ import {createCodeEditor} from './features/codeeditor.js'; | |||
import MinioUploader from './components/MinioUploader.vue'; | |||
import ObsUploader from './components/ObsUploader.vue'; | |||
import EditAboutInfo from './components/EditAboutInfo.vue'; | |||
import Images from './components/Images.vue' | |||
Vue.use(ElementUI); | |||
Vue.prototype.$axios = axios; | |||
@@ -2966,6 +2967,7 @@ $(document).ready(async () => { | |||
initVueUploader(); | |||
initObsUploader(); | |||
initVueEditAbout(); | |||
initVueImages(); | |||
initTeamSettings(); | |||
initCtrlEnterSubmit(); | |||
initNavbarContentToggle(); | |||
@@ -3653,7 +3655,7 @@ function initVueUploader() { | |||
function initVueEditAbout() { | |||
const el = document.getElementById('about-desc'); | |||
console.log(el) | |||
if (!el) { | |||
return; | |||
} | |||
@@ -3664,6 +3666,21 @@ function initVueEditAbout() { | |||
}); | |||
} | |||
function initVueImages() { | |||
const el = document.getElementById('images'); | |||
console.log("el",el) | |||
if (!el) { | |||
return; | |||
} | |||
new Vue({ | |||
el: '#images', | |||
render: h => h(Images) | |||
}); | |||
} | |||
// 新增 | |||
function initObsUploader() { | |||
const el = document.getElementById('obsUploader'); | |||