Browse Source

Merge remote-tracking branch 'origin/V20211213' into zouap_static

tags/v1.21.12.1^2
zouap 4 years ago
parent
commit
9547ced1f0
24 changed files with 517 additions and 1392 deletions
  1. +8
    -4
      modules/modelarts/modelarts.go
  2. +1
    -1
      options/locale/locale_zh-CN.ini
  3. +18
    -16
      routers/api/v1/repo/modelarts.go
  4. +5
    -1
      routers/repo/ai_model_manage.go
  5. +12
    -51
      routers/repo/cloudbrain.go
  6. +39
    -22
      routers/repo/modelarts.go
  7. +4
    -2
      routers/routes/routes.go
  8. +34
    -0
      routers/user/profile.go
  9. +0
    -641
      templates/repo/cloudbrain/index.tmpl
  10. +18
    -0
      templates/repo/cloudbrain/new.tmpl
  11. +2
    -2
      templates/repo/cloudbrain/show.tmpl
  12. +98
    -52
      templates/repo/debugjob/index.tmpl
  13. +1
    -1
      templates/repo/header.tmpl
  14. +0
    -370
      templates/repo/modelarts/notebook/index.tmpl
  15. +17
    -0
      templates/repo/modelarts/notebook/new.tmpl
  16. +2
    -2
      templates/repo/modelarts/notebook/show.tmpl
  17. +18
    -91
      templates/repo/modelarts/trainjob/index.tmpl
  18. +6
    -7
      templates/repo/modelarts/trainjob/show.tmpl
  19. +9
    -81
      templates/repo/modelmanage/index.tmpl
  20. +92
    -41
      templates/repo/modelmanage/showinfo.tmpl
  21. +77
    -4
      web_src/js/components/Model.vue
  22. +7
    -1
      web_src/js/index.js
  23. +1
    -0
      web_src/less/_svg.less
  24. +48
    -2
      web_src/less/openi.less

+ 8
- 4
modules/modelarts/modelarts.go View File

@@ -48,8 +48,12 @@ const (
PerPage = 10
IsLatestVersion = "1"
NotLatestVersion = "0"
ComputeResource = "NPU"
VersionCount = 1
// ComputeResource = "NPU"
NPUResource = "NPU"
GPUResource = "CPU/GPU"
AllResource = "all"
DebugType = -1
VersionCount = 1

SortByCreateTime = "create_time"
ConfigTypeCustom = "custom"
@@ -273,7 +277,7 @@ func GenerateTrainJob(ctx *context.Context, req *GenerateTrainJobReq) (err error
DatasetName: attach.Name,
CommitID: req.CommitID,
IsLatestVersion: req.IsLatestVersion,
ComputeResource: ComputeResource,
ComputeResource: NPUResource,
EngineID: req.EngineID,
TrainUrl: req.TrainUrl,
BranchName: req.BranchName,
@@ -356,7 +360,7 @@ func GenerateTrainJobVersion(ctx *context.Context, req *GenerateTrainJobReq, job
CommitID: req.CommitID,
IsLatestVersion: req.IsLatestVersion,
PreVersionName: req.PreVersionName,
ComputeResource: ComputeResource,
ComputeResource: NPUResource,
EngineID: req.EngineID,
TrainUrl: req.TrainUrl,
BranchName: req.BranchName,


+ 1
- 1
options/locale/locale_zh-CN.ini View File

@@ -839,7 +839,7 @@ modelarts.train_job.new_place=描述字数不超过256个字符
modelarts.model_name=模型名称
modelarts.model_size=模型大小
modelarts.import_model=导入模型
modelarts.train_job.new_place=描述字数不超过255个字符
modelarts.train_job.label_place=输入标签,多个标签用空格区分
modelarts.modify=修改
modelarts.current_version=当前版本
modelarts.parent_version=父版本


+ 18
- 16
routers/api/v1/repo/modelarts.go View File

@@ -240,26 +240,28 @@ func DelTrainJobVersion(ctx *context.APIContext) {
ctx.ServerError("get VersionListCount faild", err)
return
}

// 判断当前删掉的任务是否是最新版本,若是,将排序后的TotalVersionCount置为删掉的最新版本的TotalVersionCount,若不是,按时间排序后的版本列表的第一个版本设置为最新版本,TotalVersionCount不变
if task.IsLatestVersion == modelarts.IsLatestVersion {
err = models.SetVersionCountAndLatestVersion(jobID, VersionTaskList[0].Cloudbrain.VersionName, VersionListCount, modelarts.IsLatestVersion, task.TotalVersionCount)
if err != nil {
ctx.ServerError("UpdateJobVersionCount failed", err)
return
}
} else {
err = models.SetVersionCountAndLatestVersion(jobID, VersionTaskList[0].VersionName, VersionListCount, modelarts.IsLatestVersion, VersionTaskList[0].Cloudbrain.TotalVersionCount)
if err != nil {
ctx.ServerError("UpdateJobVersionCount failed", err)
return
if VersionListCount > 0 {
// 判断当前删掉的任务是否是最新版本,若是,将排序后的TotalVersionCount置为删掉的最新版本的TotalVersionCount,若不是,按时间排序后的版本列表的第一个版本设置为最新版本,TotalVersionCount不变
if task.IsLatestVersion == modelarts.IsLatestVersion {
err = models.SetVersionCountAndLatestVersion(jobID, VersionTaskList[0].Cloudbrain.VersionName, VersionListCount, modelarts.IsLatestVersion, task.TotalVersionCount)
if err != nil {
ctx.ServerError("UpdateJobVersionCount failed", err)
return
}
} else {
err = models.SetVersionCountAndLatestVersion(jobID, VersionTaskList[0].VersionName, VersionListCount, modelarts.IsLatestVersion, VersionTaskList[0].Cloudbrain.TotalVersionCount)
if err != nil {
ctx.ServerError("UpdateJobVersionCount failed", err)
return
}
}
}

ctx.JSON(http.StatusOK, map[string]interface{}{
"JobID": jobID,
"VersionName": versionName,
"StatusOK": 0,
"JobID": jobID,
"VersionName": versionName,
"StatusOK": 0,
"VersionListCount": VersionListCount,
})
}



+ 5
- 1
routers/repo/ai_model_manage.go View File

@@ -478,12 +478,16 @@ func ShowModelPageInfo(ctx *context.Context) {
if page <= 0 {
page = 1
}
pageSize := ctx.QueryInt("pageSize")
if pageSize <= 0 {
pageSize = setting.UI.IssuePagingNum
}
repoId := ctx.Repo.Repository.ID
Type := -1
modelResult, count, err := models.QueryModel(&models.AiModelQueryOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
PageSize: pageSize,
},
RepoID: repoId,
Type: Type,


+ 12
- 51
routers/repo/cloudbrain.go View File

@@ -49,42 +49,6 @@ func MustEnableCloudbrain(ctx *context.Context) {
return
}
}
func CloudBrainIndex(ctx *context.Context) {
MustEnableCloudbrain(ctx)
repo := ctx.Repo.Repository
page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}

ciTasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
},
RepoID: repo.ID,
Type: models.TypeCloudBrainOne,
})
if err != nil {
ctx.ServerError("Cloudbrain", err)
return
}

for i, task := range ciTasks {
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)

}

pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5)
pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager

ctx.Data["PageIsCloudBrain"] = true
ctx.Data["Tasks"] = ciTasks
ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx)
ctx.HTML(200, tplCloudBrainIndex)
}

func cutString(str string, lens int) string {
if len(str) < lens {
@@ -242,11 +206,11 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
}
repo := ctx.Repo.Repository
downloadCode(repo, codePath)
uploadCodeToMinio(codePath + "/", jobName, "/code/")
uploadCodeToMinio(codePath+"/", jobName, "/code/")

modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath + "/"
mkModelPath(modelPath)
uploadCodeToMinio(modelPath, jobName, cloudbrain.ModelMountPath + "/")
uploadCodeToMinio(modelPath, jobName, cloudbrain.ModelMountPath+"/")

benchmarkPath := setting.JobPath + jobName + cloudbrain.BenchMarkMountPath
if setting.IsBenchmarkEnabled && jobType == string(models.JobTypeBenchmark) {
@@ -257,30 +221,30 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) {
}
}
downloadRateCode(repo, jobName, setting.BenchmarkOwner, setting.BrainScoreName, benchmarkPath, form.BenchmarkCategory, gpuType)
uploadCodeToMinio(benchmarkPath + "/", jobName, cloudbrain.BenchMarkMountPath + "/")
uploadCodeToMinio(benchmarkPath+"/", jobName, cloudbrain.BenchMarkMountPath+"/")
}

snn4imagenetPath := setting.JobPath + jobName + cloudbrain.Snn4imagenetMountPath
if setting.IsSnn4imagenetEnabled && jobType == string(models.JobTypeSnn4imagenet) {
downloadRateCode(repo, jobName, setting.Snn4imagenetOwner, setting.Snn4imagenetName, snn4imagenetPath, "", "")
uploadCodeToMinio(snn4imagenetPath + "/", jobName, cloudbrain.Snn4imagenetMountPath + "/")
uploadCodeToMinio(snn4imagenetPath+"/", jobName, cloudbrain.Snn4imagenetMountPath+"/")
}

brainScorePath := setting.JobPath + jobName + cloudbrain.BrainScoreMountPath
if setting.IsBrainScoreEnabled && jobType == string(models.JobTypeBrainScore) {
downloadRateCode(repo, jobName, setting.BrainScoreOwner, setting.BrainScoreName, brainScorePath, "", "")
uploadCodeToMinio(brainScorePath + "/", jobName, cloudbrain.BrainScoreMountPath + "/")
uploadCodeToMinio(brainScorePath+"/", jobName, cloudbrain.BrainScoreMountPath+"/")
}

err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, getMinioPath(jobName, cloudbrain.ModelMountPath + "/"),
getMinioPath(jobName, cloudbrain.BenchMarkMountPath + "/"), getMinioPath(jobName, cloudbrain.Snn4imagenetMountPath + "/"),
getMinioPath(jobName, cloudbrain.BrainScoreMountPath + "/"), jobType, gpuQueue, resourceSpecId)
err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, getMinioPath(jobName, cloudbrain.ModelMountPath+"/"),
getMinioPath(jobName, cloudbrain.BenchMarkMountPath+"/"), getMinioPath(jobName, cloudbrain.Snn4imagenetMountPath+"/"),
getMinioPath(jobName, cloudbrain.BrainScoreMountPath+"/"), jobType, gpuQueue, resourceSpecId)
if err != nil {
cloudBrainNewDataPrepare(ctx)
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form)
return
}
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/cloudbrain")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
}

func CloudBrainShow(ctx *context.Context) {
@@ -412,8 +376,7 @@ func CloudBrainStop(ctx *context.Context) {
ctx.ServerError("UpdateJob failed", err)
return
}

ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/cloudbrain")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
}

func StopJobsByUserID(userID int64) {
@@ -515,8 +478,7 @@ func CloudBrainDel(ctx *context.Context) {
ctx.ServerError("DeleteJob failed", err)
return
}

ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/cloudbrain")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
}

func CloudBrainShowModels(ctx *context.Context) {
@@ -598,7 +560,7 @@ func getImages(ctx *context.Context, imageType string) {

func GetModelDirs(jobName string, parentDir string) (string, error) {
var req string
modelActualPath := getMinioPath(jobName, cloudbrain.ModelMountPath + "/")
modelActualPath := getMinioPath(jobName, cloudbrain.ModelMountPath+"/")
if parentDir == "" {
req = "baseDir=" + modelActualPath
} else {
@@ -794,7 +756,6 @@ func mkModelPath(modelPath string) error {
return nil
}


func SyncCloudbrainStatus() {
cloudBrains, err := models.GetCloudBrainUnStoppedJob()
if err != nil {


+ 39
- 22
routers/repo/modelarts.go View File

@@ -28,6 +28,8 @@ import (
)

const (
tplDebugJobIndex base.TplName = "repo/debugjob/index"

tplModelArtsNotebookIndex base.TplName = "repo/modelarts/notebook/index"
tplModelArtsNotebookNew base.TplName = "repo/modelarts/notebook/new"
tplModelArtsNotebookShow base.TplName = "repo/modelarts/notebook/show"
@@ -38,21 +40,23 @@ const (
tplModelArtsTrainJobVersionNew base.TplName = "repo/modelarts/trainjob/version_new"
)

// MustEnableDataset check if repository enable internal cb
func MustEnableModelArts(ctx *context.Context) {
if !ctx.Repo.CanRead(models.UnitTypeCloudBrain) {
ctx.NotFound("MustEnableCloudbrain", nil)
return
}
}

func NotebookIndex(ctx *context.Context) {
MustEnableModelArts(ctx)
func DebugJobIndex(ctx *context.Context) {
debugListType := ctx.Query("debugListType")
MustEnableCloudbrain(ctx)
repo := ctx.Repo.Repository
page := ctx.QueryInt("page")
if page <= 0 {
page = 1
}
debugType := modelarts.DebugType
jobType := string(models.JobTypeDebug)
if debugListType == modelarts.GPUResource {
debugType = models.TypeCloudBrainOne
jobType = ""
}
if debugListType == modelarts.NPUResource {
debugType = models.TypeCloudBrainTwo
}

ciTasks, count, err := models.Cloudbrains(&models.CloudbrainsOptions{
ListOptions: models.ListOptions{
@@ -60,28 +64,43 @@ func NotebookIndex(ctx *context.Context) {
PageSize: setting.UI.IssuePagingNum,
},
RepoID: repo.ID,
Type: models.TypeCloudBrainTwo,
JobType: string(models.JobTypeDebug),
Type: debugType,
JobType: jobType,
})
if err != nil {
ctx.ServerError("Cloudbrain", err)
ctx.ServerError("Get debugjob faild:", err)
return
}

for i, task := range ciTasks {
if task.Cloudbrain.Type == models.TypeCloudBrainOne {
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = modelarts.GPUResource
}
if task.Cloudbrain.Type == models.TypeCloudBrainTwo {
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
ciTasks[i].Cloudbrain.ComputeResource = modelarts.NPUResource
}

ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx)
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain)
}

pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5)
pager.SetDefaultParams(ctx)
ctx.Data["Page"] = pager

ctx.Data["PageIsCloudBrain"] = true
ctx.Data["Tasks"] = ciTasks
ctx.Data["CanCreate"] = cloudbrain.CanCreateOrDebugJob(ctx)
ctx.HTML(200, tplModelArtsNotebookIndex)
ctx.HTML(200, tplDebugJobIndex)
}

// MustEnableDataset check if repository enable internal cb
func MustEnableModelArts(ctx *context.Context) {
if !ctx.Repo.CanRead(models.UnitTypeCloudBrain) {
ctx.NotFound("MustEnableCloudbrain", nil)
return
}
}

func NotebookNew(ctx *context.Context) {
@@ -136,8 +155,7 @@ func NotebookCreate(ctx *context.Context, form auth.CreateModelArtsNotebookForm)
ctx.RenderWithErr(err.Error(), tplModelArtsNotebookNew, &form)
return
}

ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/notebook")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
}

func NotebookShow(ctx *context.Context) {
@@ -244,8 +262,7 @@ func NotebookStop(ctx *context.Context) {
ctx.ServerError("UpdateJob failed", err)
return
}

ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/notebook")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
}

func NotebookDel(ctx *context.Context) {
@@ -275,7 +292,7 @@ func NotebookDel(ctx *context.Context) {
return
}

ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/modelarts/notebook")
ctx.Redirect(setting.AppSubURL + ctx.Repo.RepoLink + "/debugjob")
}

func TrainJobIndex(ctx *context.Context) {


+ 4
- 2
routers/routes/routes.go View File

@@ -960,7 +960,6 @@ func RegisterRoutes(m *macaron.Macaron) {
}, context.RepoRef())

m.Group("/cloudbrain", func() {
m.Get("", reqRepoCloudBrainReader, repo.CloudBrainIndex)
m.Group("/:jobid", func() {
m.Get("", reqRepoCloudBrainReader, repo.CloudBrainShow)
m.Get("/debug", reqRepoCloudBrainWriter, repo.CloudBrainDebug)
@@ -992,9 +991,12 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/downloadall", repo.DownloadMultiModelFile)
}, context.RepoRef())

m.Group("/debugjob", func() {
m.Get("", reqRepoCloudBrainReader, repo.DebugJobIndex)
}, context.RepoRef())

m.Group("/modelarts", func() {
m.Group("/notebook", func() {
m.Get("", reqRepoCloudBrainReader, repo.NotebookIndex)
m.Group("/:jobid", func() {
m.Get("", reqRepoCloudBrainReader, repo.NotebookShow)
m.Get("/debug", reqRepoCloudBrainWriter, repo.NotebookDebug)


+ 34
- 0
routers/user/profile.go View File

@@ -104,6 +104,40 @@ func Profile(ctx *context.Context) {
return
}

for _, org := range orgs {
_, repoCount, err := models.SearchRepository(&models.SearchRepoOptions{
OwnerID: org.ID,
Private: ctx.IsSigned,
Actor: ctx.User,
})
if err != nil {
ctx.ServerError("SearchRepository", err)
return
}

var opts = models.FindOrgMembersOpts{
OrgID: org.ID,
PublicOnly: true,
}

if ctx.User != nil {
isMember, err := org.IsOrgMember(ctx.User.ID)
if err != nil {
ctx.Error(500, "IsOrgMember")
return
}
opts.PublicOnly = !isMember && !ctx.User.IsAdmin
}

membersCount, err := models.CountOrgMembers(opts)
if err != nil {
ctx.ServerError("CountOrgMembers", err)
return
}
org.NumMembers = int(membersCount)
org.NumRepos = int(repoCount)
}

ctx.Data["Orgs"] = orgs
ctx.Data["HasOrgsVisible"] = models.HasOrgsVisible(orgs, ctx.User)



+ 0
- 641
templates/repo/cloudbrain/index.tmpl View File

@@ -1,641 +0,0 @@
<!-- 头部导航栏 -->
{{template "base/head" .}}

<style>
.label_after::after{
margin: -.2em 0 0 .2em;
content: '\00a0';
}
.selectcloudbrain .active.item{
color: #0087f5 !important;
border: 1px solid #0087f5;
margin: -1px;
background: #FFF !important;
}
#deletemodel {
width: 100%;
height: 100%;
}
/* 弹窗 */

#mask {
position: fixed;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
filter: alpha(opacity=60);
background-color: #777;
z-index: 1000;
display: none;
opacity: 0.8;
-moz-opacity: 0.5;
padding-top: 100px;
color: #000000
}

#loadingPage {
margin: 200px auto;
width: 50px;
height: 40px;
text-align: center;
font-size: 10px;
display: block;
}

#loadingPage>div {
background-color: green;
height: 100%;
width: 6px;
display: inline-block;
-webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out;
animation: sk-stretchdelay 1.2s infinite ease-in-out;
}

#loadingPage .rect2 {
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s;
}

#loadingPage .rect3 {
-webkit-animation-delay: -1.0s;
animation-delay: -1.0s;
}

#loadingPage .rect4 {
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s;
}

#loadingPage .rect5 {
-webkit-animation-delay: -0.8s;
animation-delay: -0.8s;
}

@-webkit-keyframes sk-stretchdelay {
0%,
40%,
100% {
-webkit-transform: scaleY(0.4)
}
20% {
-webkit-transform: scaleY(1.0)
}
}

@keyframes sk-stretchdelay {
0%,
40%,
100% {
transform: scaleY(0.4);
-webkit-transform: scaleY(0.4);
}
20% {
transform: scaleY(1.0);
-webkit-transform: scaleY(1.0);
}
}
/* 消息框 */

.alert {
display: none;
position: fixed;
width: 100%;
z-index: 1001;
padding: 15px;
border: 1px solid transparent;
border-radius: 4px;
text-align: center;
font-weight: bold;
}

.alert-success {
color: #3c763d;
background-color: #dff0d8;
border-color: #d6e9c6;
}

.alert-info {
color: #31708f;
background-color: #d9edf7;
border-color: #bce8f1;
}

.alert-warning {
color: #8a6d3b;
background-color: #fcf8e3;
border-color: #faebcc;
}

.alert-danger {
color: #a94442;
background-color: #f2dede;
border-color: #ebccd1;
}

.pusher {
width: calc(100% - 260px);
box-sizing: border-box;
}
/* 弹窗 (background) */

#imageModal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.4);
}
/* 弹窗内容 */

.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 30%;
}
/* 关闭按钮 */

.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}

.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}

.dis {
margin-bottom: 20px;
}

.disabled {
cursor: pointer;
pointer-events: none;
}
.time-show{
font-size: 10px;
margin-top: 0.4rem;
display: inline-block;
}
</style>

<!-- 弹窗 -->
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>

<!-- 提示框 -->
<div class="alert"></div>

<div class="repository release dataset-list view">
{{template "repo/header" .}}
<!-- 列表容器 -->
<div class="ui container">

<!-- 中间云脑和新建任务按钮 -->
<!-- <div class="ui three column stack able grid">
<div class="column">
<h2>{{.i18n.Tr "repo.cloudbrain1"}}</h2>
</div>

<div class="column">
</div>

<div class="column right aligned">
{{if .Permission.CanWrite $.UnitTypeCloudBrain}}
<a class="ui green button" href="{{.RepoLink}}/cloudbrain/create">{{.i18n.Tr "repo.cloudbrain.new"}}</a> {{end}}
</div>
</div>

<p>使用鹏城云脑计算资源进行调试,云脑1提供CPU / GPU资源,云脑2提供Ascend NPU资源;调试使用的数据集也需要上传到对应的环境。</p>
<div class="ui blue mini menu selectcloudbrain">
<a class="active item" href="{{.RepoLink}}/cloudbrain">{{svg "octicon-server" 16}} CPU / GPU</a>
<a class="item" href="{{.RepoLink}}/modelarts">{{svg "octicon-server" 16}} Ascend NPU</a>
</div> -->

<div class="ui two column stackable grid ">

<div class="column">
<div class="ui blue small menu compact selectcloudbrain">
<a class="active item" href="{{.RepoLink}}/cloudbrain">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
<a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a>
</div>
</div>
<div class="column right aligned">
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
{{svg "octicon-server" 16}}
<div class="default text" style="color: rgba(0,0,0,.87);"> CPU / GPU</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{.RepoLink}}/cloudbrain" data-value="11">CPU / GPU</a>
<a class="item" href="{{.RepoLink}}/modelarts/notebook" data-value="22">Ascend NPU</a>
</div>
</div>
{{if .Permission.CanWrite $.UnitTypeCloudBrain}}
<a class="ui green button" href="{{.RepoLink}}/cloudbrain/create">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a>{{end}}
</div>
</div>

<!-- 中下列表展示区 -->
<div class="ui grid">
<div class="row">
<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="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 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="five wide column">
<a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.JobName}}" style="font-size: 14px;">
<span class="fitted text_over" style="width: 90%;vertical-align: middle;">{{.JobName}}</span>
</a>
</div>

<div class="three wide column">
<!--任务状态 -->
<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 id="{{.JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
</span>
<!-- <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 style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span>
</div>

<div class="one wide column">
{{if .User.Name}}
<a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a>
{{else}}
<a title="Ghost"><img class="ui avatar image" src="{{AppSubUrl}}/user/avatar/Ghost/-1"></a>
{{end}}
</div>
<div class="seven wide column text right">
<div class="ui compact buttons">
{{if and (ne .Status "WAITING") (ne .JobType "DEBUG")}}
<a class="ui basic button" href="{{$.Link}}/{{.JobID}}/rate" target="_blank">
评分
</a>
{{end}}

<!-- 调试 -->
{{if $.Permission.CanWrite $.UnitTypeCloudBrain}}
<a id="model-debug-{{.JobID}}" class="ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank">
{{$.i18n.Tr "repo.debug"}}
</a>
{{else}}
<a class="ui basic disabled button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank">
{{$.i18n.Tr "repo.debug"}}
</a>
{{end}}
<form id="stopForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/stop" method="post" style="margin-left:-1px;">
{{$.CsrfTokenHtml}}
{{if $.Permission.CanWrite $.UnitTypeCloudBrain}}
<a id="stop-model-debug-{{.JobID}}" class="ui basic {{if or (eq .Status "STOPPED") (eq .Status "FAILED")}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
{{$.i18n.Tr "repo.stop"}}
</a>
{{else}}
<a class="ui basic disabled button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
{{$.i18n.Tr "repo.stop"}}
</a>
{{end}}
</form>
</div>
<div class="ui compact buttons">
<!-- 模型下载 -->
<a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}/models" target="_blank">
{{$.i18n.Tr "repo.download"}}
</a>
<!-- 接收结果 -->
<iframe src="" frameborder="0" name="iframeContent" style="display: none;"></iframe>
{{if $.Permission.CanWrite $.UnitTypeCloudBrain}}
<a id="model-image-{{.JobID}}" class="imageBtn ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" value="{{.CanDebug}}">{{$.i18n.Tr "repo.submit_image"}}</a>
{{else}}
<a class="imageBtn ui basic disabled button" value="{{.CanDebug}}">{{$.i18n.Tr "repo.submit_image"}}</a>
{{end}}
</div>
<!-- 删除任务 -->
<form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/del" method="post">
{{$.CsrfTokenHtml}}
{{if $.Permission.CanWrite $.UnitTypeCloudBrain}}
<a id="model-delete-{{.JobID}}" class="ui basic button {{if not .CanDel}}disabled {{else}} blue {{end}}" onclick="assertDelete(this)" style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}}
</a>
{{else}}
<a class="ui basic blue button disabled" onclick="assertDelete(this)" style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}}
</a>
{{end}}
</form>
</div>
<!-- 镜像列表弹窗 -->
<div id="imageModal" class="modal" style="display: none;">
<div class="modal-content">

<!-- 表格 -->
<div class="ui form">
<form id="commitImageForm" action="{{$.Link}}/{{.JobID}}/commit_image" method="post" target="iframeContent">
{{$.CsrfTokenHtml}}
<div class="row">
<p style="display: inline;">提交任务镜像</p>
<span class="close">&times;</span>
</div>
<div class="ui divider"></div>
<div class="inline required field dis">
<label>镜像标签:</label>
<input name="tag" id="image_tag" tabindex="3" autofocus required maxlength="254" style="width:75%">
</div>
<div class="inline field">
<label class="label_after">镜像描述:</label>
<textarea name="description" maxlength="254" rows="8" style="width:75%;margin-left: 0.2em;"></textarea>
</div>
<div class="ui divider"></div>
<div class="inline field">
<label></label>
<button class="ui green button" onclick="showmask()">
{{$.i18n.Tr "repo.cloudbrain.commit_image"}}
</button>
</div>
</form>
</div>
</div>
</div>



</div>
</div>
{{end}} {{template "base/paginate" .}}
</div>

</div>
</div>
</div>

</div>

</div>
</div>

</div>

<!-- 确认模态框 -->
<div id="deletemodel">
<div class="ui basic modal">
<div class="ui icon header">
<i class="trash icon"></i> 删除任务
</div>

<div class="content">
<p>你确认删除该任务么?此任务一旦删除不可恢复。</p>
</div>
<div class="actions">
<div class="ui red basic inverted cancel button">
<i class="remove icon"></i> 取消操作
</div>
<div class="ui green basic inverted ok button">
<i class="checkmark icon"></i> 确定操作
</div>
</div>
</div>
</div>

</div>
{{template "base/footer" .}}

<script>
// 调试和评分新开窗口
function stop(obj) {
if (obj.style.color != "rgb(204, 204, 204)") {
obj.target = '_blank'
} else {
return
}
}

// 删除时用户确认
function assertDelete(obj) {
if (obj.style.color == "rgb(204, 204, 204)") {
return
} else {
var delId = obj.parentNode.id
flag = 1;
$('.ui.basic.modal')
.modal({
onDeny: function() {
flag = false
},
onApprove: function() {
document.getElementById(delId).submit()
flag = true
},
onHidden: function() {
if (flag == false) {
$('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut();
}
}
})
.modal('show')
}
}

// 加载任务状态
var timeid = window.setInterval(loadJobStatus, 15000);
$(document).ready(loadJobStatus);
function loadJobStatus() {
$(".job-status").each((index, job) => {
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
if (job.textContent.trim() == 'STOPPED' || job.textContent.trim() == 'FAILED') {
return
}
$.get(`/api/v1/repos/${repoPath}/cloudbrain/${jobID}`, (data) => {
const jobID = data.JobID
const status = data.JobStatus
if (status != job.textContent.trim()) {
console.log("---------")
$('#' + jobID+'-icon').removeClass().addClass(status)
$('#' + jobID+ '-text').text(status)
//if (status == 'STOPPED') {
// window.location.reload()
//}
}
if(status==="RUNNING"){
$('#model-debug-'+jobID).removeClass('disabled')
$('#model-debug-'+jobID).addClass('blue')
$('#model-image-'+jobID).removeClass('disabled')
$('#model-image-'+jobID).addClass('blue')

}
if(status!=="RUNNING"){
$('#model-debug-'+jobID).removeClass('blue')
$('#model-debug-'+jobID).addClass('disabled')
$('#model-image-'+jobID).removeClass('blue')
$('#model-image-'+jobID).addClass('disabled')

}
if(status!=="STOPPED" || status!=="FAILED"){
$('#stop-model-debug-'+jobID).removeClass('disabled')
$('#stop-model-debug-'+jobID).addClass('blue')
$('#model-delete-'+jobID).removeClass('red')
$('#model-delete-'+jobID).addClass('disabled')
}
if(status=="STOPPED" || status=="FAILED"){
$('#stop-model-debug-'+jobID).removeClass('blue')
$('#stop-model-debug-'+jobID).addClass('disabled')
$('#model-delete-'+jobID).removeClass('disabled')
$('#model-delete-'+jobID).addClass('red')
}
}).fail(function(err) {
console.log(err);
});
});
};

// 获取弹窗
var modal = document.getElementById('imageModal');

// 打开弹窗的按钮对象
var btns = document.getElementsByClassName("imageBtn");

// 获取 <span> 元素,用于关闭弹窗
var spans = document.getElementsByClassName('close');

// 点击按钮打开弹窗
for (i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
modal.style.display = "block";
}
}

// 点击 <span> (x), 关闭弹窗
for (i = 0; i < spans.length; i++) {
spans[i].onclick = function() {
modal.style.display = "none";
}
}

// 在用户点击其他地方时,关闭弹窗
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}

// 显示弹窗,弹出相应的信息
function showmask() {
var image_tag = !$('#image_tag').val()
console.log("image_tag",image_tag)
if(image_tag){
return
}
$('#imageModal').css('display', 'none')
$('#mask').css('display', 'block')

$("iframe[name=iframeContent]").on("load", function() {  
var responseText = $("iframe")[0].contentDocument.body.getElementsByTagName("pre")[0].innerHTML; 
var json1 = JSON.parse(responseText)
$('#mask').css('display', 'none')
parent.location.href

if (json1.result_code === "0") {
$('.alert').html('操作成功!').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut();
} else {
$('.alert').html(json1.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(5000).fadeOut();
}
})
}
</script>

+ 18
- 0
templates/repo/cloudbrain/new.tmpl View File

@@ -129,6 +129,24 @@
{{.i18n.Tr "repo.cloudbrain.new"}}
</h3>
<div class="ui attached segment">
<div class="inline required field">
<label>计算资源</label>
<div class="ui blue small menu compact selectcloudbrain">
<a class="active item" href="{{.RepoLink}}/cloudbrain/create">
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/>
</svg>
CPU/GPU
</a>
<a class="item" href="{{.RepoLink}}/modelarts/notebook/create">
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/>
</svg>
Ascend NPU</a>
</div>
</div>
<div class="inline required field">
<label>任务名称</label>
<input name="job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.job_name}}" tabindex="3" autofocus required maxlength="254">


+ 2
- 2
templates/repo/cloudbrain/show.tmpl View File

@@ -7,11 +7,11 @@

<h4 class="ui header" id="vertical-segment">
<div class="ui breadcrumb">
<a class="section" href="{{.RepoLink}}/cloudbrain">
<a class="section" href="{{.RepoLink}}/debugjob?debugListType=all">
{{.i18n.Tr "repo.cloudbrain"}}
</a>
<div class="divider"> / </div>
<a class="section" href="{{.RepoLink}}/cloudbrain">
<a class="section" href="{{.RepoLink}}/debugjob?debugListType=CPU/GPU">
{{$.i18n.Tr "repo.modelarts.notebook"}}
</a>
<div class="divider"> / </div>


+ 98
- 52
templates/repo/debugjob/index.tmpl View File

@@ -212,25 +212,40 @@
<div class="ui two column stackable grid ">
<div class="column">
<div class="ui blue small menu compact selectcloudbrain">
<a class="active item" href="{{.RepoLink}}/debugjob">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
<a class="active item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
<a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a>
</div>
</div>
<div class="column right aligned">
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
{{svg "octicon-server" 16}}
<div class="default text" style="color: rgba(0,0,0,.87);"> 全部</div>
<div class="default text" style="color: rgba(0,0,0,.87);"></div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="active item" href="{{.RepoLink}}/debugjob" data-value="11">全部</a>
<a class="item" href="{{.RepoLink}}/cloudbrain" data-value="22">CPU / GPU</a>
<a class="item" href="{{.RepoLink}}/modelarts/notebook" data-value="33">Ascend NPU</a>
<div class="item" data-value="all">全部</div>
<div class="item" data-value="CPU/GPU">CPU/GPU</div>
<div class="item" data-value="NPU">NPU</div>
</div>
</div>
{{if .Permission.CanWrite $.UnitTypeCloudBrain}}
<a class="ui green button" href="{{.RepoLink}}/cloudbrain/create">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a>{{end}}
<a class="ui green button" href="{{.RepoLink}}/cloudbrain/create">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a>
{{else}}
<a class="ui disabled button">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a>
{{end}}
</div>
</div>
{{if eq 0 (len .Tasks)}}
<div class="ui placeholder segment bgtask-none">
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">未创建过调试任务</div>
<div class="bgtask-content">
<div class="bgtask-content-txt">代码版本:您还没有初始化代码仓库,请先<a href="{{.RepoLink}}">创建代码版本</a>;</div>
<div class="bgtask-content-txt">运行时长:最长不超过4个小时,超过4个小时将自动停止;</div>
<div class="bgtask-content-txt">数据集:云脑1提供 CPU / GPU 资源,云脑2提供 Ascend NPU 资源,调试使用的数据集也需要上传到对应的环境。</div>
<div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a href="https://git.openi.org/zeizei/OpenI_Learning">小白训练营课程</a></div>
</div>
</div>
{{else}}
<!-- 中下列表展示区 -->
<div class="ui grid">
<div class="row">
@@ -265,7 +280,7 @@
<div class="row">
<!-- 任务名 -->
<div class="four wide column">
<a class="title" href="{{$.Link}}/{{.JobID}}" title="{{.JobName}}" style="font-size: 14px;">
<a class="title" href='{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}' title="{{.JobName}}" style="font-size: 14px;">
<span class="fitted text_over" style="width: 90%;vertical-align: middle;">{{.JobName}}</span>
</a>
</div>
@@ -292,32 +307,32 @@
</div>
<div class="five wide column text center">
<div class="ui compact buttons">
{{if and (ne .Status "WAITING") (ne .JobType "DEBUG")}}
<!-- {{if and (ne .Status "WAITING") (ne .JobType "DEBUG")}}
<a class="ui basic button" href="{{$.Link}}/{{.JobID}}/rate" target="_blank">
评分
</a>
{{end}}
{{end}} -->
<!-- 调试 -->
{{if $.Permission.CanWrite $.UnitTypeCloudBrain}}
{{if .CanDebug}}
{{if eq .ComputeResource "CPU/GPU"}}
<a id="model-debug-{{.JobID}}" class="ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.RepoLink}}/cloudbrain/{{.JobID}}/debug" target="_blank">
<a id="model-debug-{{.JobID}}" class='ui basic {{if ne .Status "RUNNING"}} disabled {{else}}blue {{end}}button' href="{{$.RepoLink}}/cloudbrain/{{.JobID}}/debug" target="_blank">
{{$.i18n.Tr "repo.debug"}}
</a>
{{else}}
<a id="model-debug-{{.JobID}}" class="ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.RepoLink}}/modelarts/notebook/{{.JobID}}/debug" target="_blank">
<a id="model-debug-{{.JobID}}" class='ui basic {{if ne .Status "RUNNING"}} disabled {{else}}blue {{end}}button' href="{{$.RepoLink}}/modelarts/notebook/{{.JobID}}/debug" target="_blank">
{{$.i18n.Tr "repo.debug"}}
</a>
{{end}}
{{else}}
<a class="ui basic disabled button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank">
<a class="ui basic disabled button">
{{$.i18n.Tr "repo.debug"}}
</a>
{{end}}
<!-- 停止 -->
<form id="stopForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/stop" method="post" style="margin-left:-1px;">
{{$.CsrfTokenHtml}}
{{if $.Permission.CanWrite $.UnitTypeCloudBrain}}
<a id="stop-model-debug-{{.JobID}}" class="ui basic {{if or (eq .Status "STOPPED") (eq .Status "FAILED")}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
{{if .CanDel}}
<a id="stop-model-debug-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "STARTING"}}disabled {{else}}blue {{end}}button' onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
{{$.i18n.Tr "repo.stop"}}
</a>
{{else}}
@@ -326,39 +341,51 @@
</a>
{{end}}
<input type="hidden" name="debugListType" value="all">
</form>
<!-- 删除 -->
<form id="delForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/del" method="post">
<input type="hidden" name="debugListType" value="all">
{{$.CsrfTokenHtml}}
{{if .CanDel}}
<a id="model-delete-{{.JobID}}" class='ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED"}}blue {{else}}disabled {{end}}button' onclick="assertDelete(this)" style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}}
</a>
{{else}}
<a class="ui basic button disabled" onclick="assertDelete(this)" style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}}
</a>
{{end}}
</form>
</div>
<div class="ui compact buttons">
<!-- 模型下载 -->
<!-- <a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}/models" target="_blank">
{{$.i18n.Tr "repo.download"}}
</a> -->
<!-- 接收结果 -->
<iframe src="" frameborder="0" name="iframeContent" style="display: none;"></iframe>
{{if $.Permission.CanWrite $.UnitTypeCloudBrain}}
<a id="model-image-{{.JobID}}" style="{{if eq .ComputeResource "CPU/GPU"}} visibility: visible {{else}} visibility: hidden{{end}}" class="imageBtn ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" value="{{.CanDebug}}">{{$.i18n.Tr "repo.submit_image"}}</a>
{{else}}
<a class="imageBtn ui basic disabled button" style="{{if eq .ComputeResource "CPU/GPU"}} visibility: visible {{else}} visibility: hidden{{end}}" value="{{.CanDebug}}">{{$.i18n.Tr "repo.submit_image"}}</a>
{{end}}
</div>
{{.CanDel}}
<!-- 删除任务 -->
<form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{if eq .ComputeResource "CPU/GPU"}}{{$.RepoLink}}/cloudbrain{{else}}{{$.RepoLink}}/modelarts/notebook{{end}}/{{.JobID}}/del" method="post">
<input type="hidden" name="debugListType" value="all">
{{$.CsrfTokenHtml}}
{{if .CanDel}}
<!-- {{if not .CanDel}}disabled {{else}} blue {{end}} -->
<a id="model-delete-{{.JobID}}" class="ui basic blue button " onclick="assertDelete(this)" style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}}
</a>
{{else}}
<a class="ui basic button disabled" onclick="assertDelete(this)" style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}}
</a>
{{end}}
</form>
<div class="ui compact buttons" style="{{if eq .ComputeResource "CPU/GPU"}} visibility: visible {{else}} visibility: hidden{{end}}">
<div class="ui dropdown" id="model_more" style="padding: .58928571em 1.125em .58928571em;">
<div class="text">更多</div>
<i class="dropdown icon"></i>
<div class="menu" style="right: auto;">
<div class="item" style="padding: 0 !important;">
<!-- 接收结果 -->
<iframe src="" frameborder="0" name="iframeContent" style="display: none;"></iframe>
{{if .CanDel}}
<a id="model-image-{{.JobID}}" class='imageBtn ui basic {{if ne .Status "RUNNING"}}disabled {{else}}blue {{end}}button'>{{$.i18n.Tr "repo.submit_image"}}</a>
{{else}}
<a class="imageBtn ui basic disabled button">{{$.i18n.Tr "repo.submit_image"}}</a>
{{end}}
</div>
<div class="item" style="padding: 0 !important;">
<!-- 模型下载 -->
{{if .CanDel}}
<a class="ui basic blue button" href="{{$.RepoLink}}/cloudbrain/{{.JobID}}/models" target="_blank">{{$.i18n.Tr "repo.download"}}</a>
{{else}}
<a class="ui basic disabled button">{{$.i18n.Tr "repo.download"}}</a>
{{end}}
</div>
</div>
</div>
</div>
</div>
<!-- 镜像列表弹窗 -->
<div id="imageModal" class="modal" style="display: none;">
@@ -402,6 +429,7 @@
</div>
</div>
</div>
{{end}}
</div>
</div>
</div>
@@ -433,7 +461,9 @@

<script>
// 调试和评分新开窗口
console.log({{.Tasks}})
let url={{.RepoLink}}
let getParam=location.search.split('?debugListType=').pop()
let dropdownValue = getParam==='all'||getParam==='' ? '全部' : getParam
function stop(obj) {
if (obj.style.color != "rgb(204, 204, 204)") {
obj.target = '_blank'
@@ -441,7 +471,6 @@
return
}
}

// 删除时用户确认
function assertDelete(obj) {
if (obj.style.color == "rgb(204, 204, 204)") {
@@ -501,23 +530,40 @@
$('#model-image-'+jobID).addClass('disabled')

}
if(status!=="STOPPED" || status!=="FAILED"){
if(["RUNNING","WAITING"].includes(status)){
$('#stop-model-debug-'+jobID).removeClass('disabled')
$('#stop-model-debug-'+jobID).addClass('blue')
// $('#model-delete-'+jobID).removeClass('red')
// $('#model-delete-'+jobID).addClass('disabled')
}
if(status=="STOPPED" || status=="FAILED"){
if(["CREATING","STOPPING","STARTING","STOPPED","FAILED","START_FAILED"].includes(status)){
$('#stop-model-debug-'+jobID).removeClass('blue')
$('#stop-model-debug-'+jobID).addClass('disabled')
$('#model-delete-'+jobID).removeClass('disabled')
$('#model-delete-'+jobID).addClass('red')
}
if(status==="STOPPED" || status==="FAILED"|| status==="START_FAILED"){
$('#model-delete-'+jobID).removeClass('disabled')
$('#model-delete-'+jobID).addClass('blue')
}else{
$('#model-delete-'+jobID).removeClass('blue')
$('#model-delete-'+jobID).addClass('disabled')
}
}).fail(function(err) {
console.log(err);
});
});
};
$(document).ready(function(){
$('.default.text').text(dropdownValue)
$('.ui.dropdown')
.dropdown({
action: 'hide',
})
$('.ui.selection.dropdown').dropdown({
onChange:function(value){
location.href = `${url}/debugjob?debugListType=${value}`
}
})
})

// 获取弹窗
var modal = document.getElementById('imageModal');


+ 1
- 1
templates/repo/header.tmpl View File

@@ -145,7 +145,7 @@
</a>
{{end}}
{{if .Permission.CanRead $.UnitTypeCloudBrain}}
<a class="{{if .PageIsCloudBrain}}active{{end}} item" href="{{.RepoLink}}/cloudbrain">
<a class="{{if .PageIsCloudBrain}}active{{end}} item" href="{{.RepoLink}}/debugjob?debugListType=all">
<span>
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16"><path fill="none" d="M0 0h24v24H0z"/><path d="M4 3h16a1 1 0 0 1 1 1v7H3V4a1 1 0 0 1 1-1zM3 13h18v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-7zm4 3v2h3v-2H7zM7 6v2h3V6H7z"/></svg>
{{.i18n.Tr "repo.cloudbrain"}}


+ 0
- 370
templates/repo/modelarts/notebook/index.tmpl View File

@@ -1,370 +0,0 @@
<!-- 头部导航栏 -->
{{template "base/head" .}}

<!-- 弹窗 -->
<div id="mask">
<div id="loadingPage">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>

<!-- 提示框 -->
<div class="alert"></div>

<div class="repository release dataset-list view">
{{template "repo/header" .}}
<!-- 列表容器 -->
<div class="ui container">
{{template "base/alert" .}}

<!-- 中间云脑和新建任务按钮 -->

<div class="ui two column stackable grid ">

<div class="column">
<div class="ui blue small menu compact selectcloudbrain">
<a class="active item" href="{{.RepoLink}}/modelarts/notebook">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
<a class="item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a>
</div>
</div>
<div class="column right aligned">
<div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
{{svg "octicon-server" 16}}
<div class="default text" style="color: rgba(0,0,0,.87);"> Ascend NPU</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{.RepoLink}}/cloudbrain" data-value="11">CPU / GPU</a>
<a class="item" href="{{.RepoLink}}/modelarts/notebook" data-value="22">Ascend NPU</a>
</div>
</div>
{{if .Permission.CanWrite $.UnitTypeCloudBrain}}
<a class="ui green button" href="{{.RepoLink}}/modelarts/notebook/create">{{$.i18n.Tr "repo.modelarts.train_job.new_debug"}}</a>{{end}}
</div>
</div>

<!-- 中下列表展示区 -->
<div class="ui grid">
<div class="row">
<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="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 class="dataset list">

<!-- 表头 -->
<div class="ui grid stackable" style="background: #f0f0f0;;">
<div class="row">
<div class="six 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="two wide column text center">
<span>{{$.i18n.Tr "repo.cloudbrain_creator"}}</span>
</div>
<div class="five wide column text center">
<span style="margin-left: 5rem;">{{$.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}}" title="{{.JobName}}" style="font-size: 14px;">
<span class="fitted" style="width: 90%;vertical-align: middle;">{{.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> -->
<span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}">
<span><i id="{{.JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
</span>
<!-- 任务创建时间 -->
<span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span>
</div>

<div class="two wide column text center">
{{if .User.Name}}
<a href="{{AppSubUrl}}/{{.User.Name}}" title="{{.User.Name}}"><img class="ui avatar image" src="{{.User.RelAvatarLink}}"></a>
{{else}}
<a title="Ghost"><img class="ui avatar image" src="{{AppSubUrl}}/user/avatar/Ghost/-1"></a>
{{end}}
</div>

<div class="five wide column text right">
<div class="ui compact buttons">
<!-- <a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}">
查看
</a> -->
{{if $.Permission.CanWrite $.UnitTypeCloudBrain}}
<a id="model-debug-{{.JobID}}" style="margin-right: 2rem;" class="ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank">
{{$.i18n.Tr "repo.debug"}}
</a>
{{else}}
<a style="margin-right: 2rem;" class="ui basic disabled button" href="{{$.Link}}/{{.JobID}}/debug" target="_blank">
{{$.i18n.Tr "repo.debug"}}
</a>
{{end}}

<form id="stopForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/stop" method="post" style="margin-left:-1px;">
{{$.CsrfTokenHtml}}
{{if $.Permission.CanWrite $.UnitTypeCloudBrain}}
<a id="stop-model-debug-{{.JobID}}" style="margin-right: 2rem;" class="ui basic {{if eq .Status "STOPPED" "FAILED" "START_FAILED" "STOPPING" "CREATING" "WAITING" "STARTING"}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
{{$.i18n.Tr "repo.stop"}}
</a>
{{else}}
<a style="margin-right: 2rem;" class="ui basic disabled button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
{{$.i18n.Tr "repo.stop"}}
</a>
{{end}}

</form>
</div>

<!-- <div class="ui compact buttons" style="margin-right:10px;"> -->
<!-- 模型下载 -->
<!-- <a class="ui basic blue button" href="{{$.Link}}/{{.JobID}}/models" target="_blank">
模型下载
</a> -->
<!-- 接收结果 -->
<!-- <iframe src="" frameborder="0" name="iframeContent" style="display: none;"></iframe>
<a class="imageBtn ui basic {{if not .CanDebug}}disabled {{else}}blue {{end}}button" value="{{.CanDebug}}">提交镜像</a> -->
<!-- </div> -->

<!-- 删除任务 -->
<form class="ui compact buttons" id="delForm-{{.JobID}}" action="{{$.Link}}/{{.JobID}}/del" method="post">
{{$.CsrfTokenHtml}}
{{if $.Permission.CanWrite $.UnitTypeCloudBrain}}
<a id="model-delete-{{.JobID}}" class="ui basic button {{if eq .Status "RUNNING" "CREATING" "WAITING" "STARTING" "STOPPING" }}disabled {{else}} blue {{end}}" onclick="assertDelete(this)" style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}}
</a>
{{else}}
<a class="ui basic blue button disabled" onclick="assertDelete(this)" style="border-radius: .28571429rem;">
{{$.i18n.Tr "repo.delete"}}
</a>
{{end}}
</form>
</div>



</div>
</div>
{{end}} {{template "base/paginate" .}}
</div>

</div>
</div>
</div>

</div>

</div>
</div>

</div>

<!-- 确认模态框 -->
<div id="deletemodel">
<div class="ui basic modal">
<div class="ui icon header">
<i class="trash icon"></i> 删除任务
</div>

<div class="content">
<p>你确认删除该任务么?此任务一旦删除不可恢复。</p>
</div>
<div class="actions">
<div class="ui red basic inverted cancel button">
<i class="remove icon"></i> 取消操作
</div>
<div class="ui green basic inverted ok button">
<i class="checkmark icon"></i> 确定操作
</div>
</div>
</div>
</div>

</div>
{{template "base/footer" .}}

<script>
// 调试和评分新开窗口
function stop(obj) {
if (obj.style.color != "rgb(204, 204, 204)") {
obj.target = '_blank'
} else {
return
}
}

// 删除时用户确认
function assertDelete(obj) {
if (obj.style.color == "rgb(204, 204, 204)") {
return
} else {
var delId = obj.parentNode.id
flag = 1;
$('.ui.basic.modal')
.modal({
onDeny: function() {
flag = false
},
onApprove: function() {
document.getElementById(delId).submit()
flag = true
},
onHidden: function() {
if (flag == false) {
$('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut();
}
}
})
.modal('show')
}
}

// 加载任务状态
var timeid = window.setInterval(loadJobStatus, 15000);
$(document).ready(loadJobStatus);
function loadJobStatus() {
$(".job-status").each((index, job) => {
const jobID = job.dataset.jobid;
const repoPath = job.dataset.repopath;
if (job.textContent.trim() == 'STOPPED' || job.textContent.trim() == 'START_FAILED' || job.textContent.trim() == 'CREATE_FAILED') {
return
}

$.get(`/api/v1/repos/${repoPath}/modelarts/notebook/${jobID}`, (data) => {
const jobID = data.JobID
const status = data.JobStatus
if (status != job.textContent.trim()) {
$('#' + jobID+'-icon').removeClass().addClass(status)
$('#' + jobID+ '-text').text(status)
//if (status == 'STOPPED') {
// window.location.reload()
//}
}
if(status==="RUNNING"){
$('#model-debug-'+jobID).removeClass('disabled')
$('#model-debug-'+jobID).addClass('blue')

}
if(status!=="RUNNING"){
$('#model-debug-'+jobID).removeClass('blue')
$('#model-debug-'+jobID).addClass('disabled')

}
if(status!=="STOPPED" || status!=="FAILED"){
// $('#stop-model-debug-'+jobID).removeClass('disabled')
// $('#stop-model-debug-'+jobID).addClass('blue')
// $('#model-delete-'+jobID).removeClass('red')
// $('#model-delete-'+jobID).addClass('disabled')
}
if(status=="STOPPED" || status=="FAILED" ){
$('#stop-model-debug-'+jobID).removeClass('blue')
$('#stop-model-debug-'+jobID).addClass('disabled')
$('#model-delete-'+jobID).removeClass('disabled')
$('#model-delete-'+jobID).addClass('red')
}
if(status=="START_FAILED"){
$('#stop-model-debug-'+jobID).removeClass('blue')
$('#stop-model-debug-'+jobID).addClass('disabled')
$('#model-delete-'+jobID).removeClass('disabled')
$('#model-delete-'+jobID).addClass('red')
}
}).fail(function(err) {
console.log(err);
});
});
};

// 获取弹窗
var modal = document.getElementById('imageModal');

// 打开弹窗的按钮对象
var btns = document.getElementsByClassName("imageBtn");

// 获取 <span> 元素,用于关闭弹窗
var spans = document.getElementsByClassName('close');

// 点击按钮打开弹窗
for (i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
modal.style.display = "block";
}
}

// 点击 <span> (x), 关闭弹窗
for (i = 0; i < spans.length; i++) {
spans[i].onclick = function() {
modal.style.display = "none";
}
}

// 在用户点击其他地方时,关闭弹窗
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}

// 显示弹窗,弹出相应的信息
function showmask() {
$('#imageModal').css('display', 'none')
$('#mask').css('display', 'block')

$("iframe[name=iframeContent]").on("load", function() {  
var responseText = $("iframe")[0].contentDocument.body.getElementsByTagName("pre")[0].innerHTML; 
var json1 = JSON.parse(responseText)
$('#mask').css('display', 'none')
parent.location.href

if (json1.result_code === "0") {
$('.alert').html('操作成功!').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut();
} else {
$('.alert').html(json1.error_msg).removeClass('alert-success').addClass('alert-danger').show().delay(5000).fadeOut();
}
})
}
</script>

+ 17
- 0
templates/repo/modelarts/notebook/new.tmpl View File

@@ -29,6 +29,23 @@
</h3>
<div class="ui attached segment">
<!-- <br> -->
<div class="inline required field">
<label>计算资源</label>
<div class="ui blue small menu compact selectcloudbrain">
<a class="item" href="{{.RepoLink}}/cloudbrain/create">
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/>
</svg>
CPU/GPU</a>
<a class="active item" href="{{.RepoLink}}/modelarts/notebook/create">
<svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16">
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M3 2.992C3 2.444 3.445 2 3.993 2h16.014a1 1 0 0 1 .993.992v18.016a.993.993 0 0 1-.993.992H3.993A1 1 0 0 1 3 21.008V2.992zM19 11V4H5v7h14zm0 2H5v7h14v-7zM9 6h6v2H9V6zm0 9h6v2H9v-2z"/>
</svg>
Ascend NPU</a>
</div>
</div>
<div class="inline required field">
<label>任务名称</label>
<input name="job_name" id="cloudbrain_job_name" placeholder="任务名称" value="{{.job_name}}" tabindex="3" autofocus required maxlength="254">


+ 2
- 2
templates/repo/modelarts/notebook/show.tmpl View File

@@ -7,11 +7,11 @@

<h4 class="ui header" id="vertical-segment">
<div class="ui breadcrumb">
<a class="section" href="{{.RepoLink}}/cloudbrain">
<a class="section" href="{{.RepoLink}}/debugjob?debugListType=all">
{{.i18n.Tr "repo.cloudbrain"}}
</a>
<div class="divider"> / </div>
<a class="section" href="{{.RepoLink}}/modelarts/notebook">
<a class="section" href="{{.RepoLink}}/debugjob?debugListType=NPU">
{{$.i18n.Tr "repo.modelarts.notebook"}}
</a>
<div class="divider"> / </div>


+ 18
- 91
templates/repo/modelarts/trainjob/index.tmpl View File

@@ -29,77 +29,36 @@
<!-- 列表容器 -->
<div class="ui container">
{{template "base/alert" .}}

<!-- 中间云脑和新建任务按钮 -->
<!-- <div class="ui three column stack able grid">
<div class="column">
<h2>{{.i18n.Tr "repo.cloudbrain2"}}</h2>
</div>

<div class="column">
</div>

<div class="column right aligned">
{{if .Permission.CanWrite $.UnitTypeCloudBrain}}
<a class="ui green button" href="{{.RepoLink}}/modelarts/create">{{.i18n.Tr "repo.cloudbrain.new"}}</a> {{end}}
</div>

<div class="column right aligned">
{{if .Permission.CanWrite $.UnitTypeCloudBrain}}
<a class="ui blue button" href="{{.RepoLink}}/modelarts/train-job/create">{{.i18n.Tr "repo.cloudbrain.new"}}</a> {{end}}
</div>
</div>

<p>使用鹏城云脑计算资源进行调试,云脑1提供CPU / GPU资源,云脑2提供Ascend NPU资源;调试使用的数据集也需要上传到对应的环境。</p>
<div class="ui blue mini menu selectcloudbrain">
<a class="item" href="{{.RepoLink}}/cloudbrain">{{svg "octicon-server" 16}} CPU / GPU</a>
<a class="active item" href="{{.RepoLink}}/modelarts">{{svg "octicon-server" 16}} Ascend NPU</a>
</div> -->

<div class="ui two column stackable grid ">

<div class="column">
<div class="ui blue small menu compact selectcloudbrain">
<a class="item" href="{{.RepoLink}}/cloudbrain">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
<a class="item" href="{{.RepoLink}}/debugjob?debugListType=all">{{$.i18n.Tr "repo.modelarts.notebook"}}</a>
<a class="active item" href="{{.RepoLink}}/modelarts/train-job">{{$.i18n.Tr "repo.modelarts.train_job"}}</a>
</div>
</div>
<div class="column right aligned">
<!-- <div class="ui selection dropdown" style="min-width: 10em;min-height:2.6em;border-radius: .28571429rem;margin-right: 1em;padding: .67em 3.2em .7em 1em;">
{{svg "octicon-server" 16}}
<div class="default text" style="color: rgba(0,0,0,.87);"> Ascend NPU</div>
<i class="dropdown icon"></i>
<div class="menu">
<a class="item" href="{{.RepoLink}}/cloudbrain" data-value="11">CPU / GPU</a>
<a class="item" href="{{.RepoLink}}/modelarts/notebook" data-value="22">Ascend NPU</a>
</div>
</div> -->
{{if .Permission.CanWrite $.UnitTypeCloudBrain}}
<a class="ui green button" href="{{.RepoLink}}/modelarts/train-job/create">{{$.i18n.Tr "repo.modelarts.train_job.new_train"}}</a>{{end}}
<a class="ui green button" href="{{.RepoLink}}/modelarts/train-job/create">{{$.i18n.Tr "repo.modelarts.train_job.new_train"}}</a>
{{else}}
<a class="ui disabled button" >{{$.i18n.Tr "repo.modelarts.train_job.new_train"}}</a>
{{end}}
</div>
</div>

{{if eq 0 (len .Tasks)}}
<div class="ui placeholder segment bgtask-none">
<div class="ui icon header bgtask-header-pic"></div>
<div class="bgtask-content-header">未创建过训练任务</div>
<div class="bgtask-content">
<div class="bgtask-content-txt">代码版本:您还没有初始化代码仓库,请先<a href="{{.RepoLink}}">创建代码版本</a>;</div>
<div class="bgtask-content-txt">数据集:云脑1提供 CPU / GPU 资源,云脑2提供 Ascend NPU 资源,调试使用的数据集也需要上传到对应的环境。</div>
<div class="bgtask-content-txt">使用说明:可以参考启智AI协作平台<a href="https://git.openi.org/zeizei/OpenI_Learning">小白训练营课程</a></div>
</div>
</div>
{{else}}
<!-- 中下列表展示区 -->
<div class="ui grid">
<div class="row">
<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="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 class="dataset list">

@@ -130,13 +89,9 @@
<div class="three wide column text center padding0">
<span>{{$.i18n.Tr "repo.cloudbrain_operate"}}</span>
</div>

</div>
</div>
</div>



{{range .Tasks}}
<div class="ui grid stackable item">
<div class="row">
@@ -162,14 +117,6 @@
<div class="two wide column text center padding0">
<span style="font-size: 12px;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span>
</div>
<!-- <div class="two wide column">
<span class="job-status" id="{{.JobID}}" data-repopath="{{$.RepoRelPath}}" data-jobid="{{.JobID}}">
<span><i id="{{.JobID}}-icon" style="vertical-align: middle;" class="{{.Status}}"></i><span id="{{.JobID}}-text" style="margin-left: 0.4em;font-size: 12px;">{{.Status}}</span></span>
</span>
<span style="font-size: 12px;margin-left: 0.4rem;" class="">{{TimeSinceUnix .Cloudbrain.CreatedUnix $.Lang}}</span>
</div> -->
<!-- 任务运行时间 -->
<div class="two wide column text center padding0">
<span style="font-size: 12px;" id="duration-{{.JobID}}"></span>
@@ -188,27 +135,6 @@
</div>

<div class="three wide column text center padding0">
<!-- <div class="ui compact buttons">
<form id="stopForm-{{.JobID}}" action="/api/v1/repos{{$.Link}}/{{.JobID}}/stop_version" method="post">
<input type="hidden" name="version_name" value="{{.VersionName}}">
{{$.CsrfTokenHtml}}
{{if $.Permission.CanWrite $.UnitTypeCloudBrain}}
<a style="padding: 0.5rem 1rem;" id="stop-model-debug-{{.JobID}}" class="ui basic {{if eq .Status "KILLED" "FAILED" "START_FAILED" "KILLING" "COMPLETED"}}disabled {{else}}blue {{end}}button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
{{$.i18n.Tr "repo.stop"}}
</a>
{{else}}
<a style="padding: 0.5rem 1rem;" class="ui basic disabled button" onclick="document.getElementById('stopForm-{{.JobID}}').submit();">
{{$.i18n.Tr "repo.stop"}}
</a>
{{end}}
</form>
</div> -->
<!-- 模型下载 -->
<!-- <div class="ui compact buttons">
<a style="padding: 0.5rem;" class="ui basic blue button" href="{{$.Link}}/{{.JobID}}/models" target="_blank">
{{$.i18n.Tr "repo.model_download"}}
</a>
</div> -->
<!-- 删除任务 -->
<div class="ui compact buttons">
{{$.CsrfTokenHtml}}
@@ -244,6 +170,7 @@
</div>
</div>
</div>
{{end}}

</div>



+ 6
- 7
templates/repo/modelarts/trainjob/show.tmpl View File

@@ -574,7 +574,12 @@ td, th {
},
onApprove: function() {
$.post(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/del_version`,{version_name:version_name},(data)=>{
$('#accordion'+version_name).remove()
if(data.VersionListCount===0){
location.href=`/${userName}/${repoPath}/modelarts/train-job`
}else{
$('#accordion'+version_name).remove()
}
}).fail(function(err) {
console.log(err);
});
@@ -658,12 +663,6 @@ td, th {
}
}
function downloadModelFile(version_name,filename){
$.get(`/api/v1/repos/${userName}/${repoPath}/modelarts/train-job/${jobID}/model_download?version_name=${version_name}&file_name=${filename}`, (data) => {
console.log(data)

})
}
function renderDir(data,version_name){
let html=""
html += "<div class='ui grid' style='margin:0;'>"


+ 9
- 81
templates/repo/modelmanage/index.tmpl View File

@@ -1,16 +1,5 @@
<!-- 头部导航栏 -->
{{template "base/head" .}}
<style>
.width70{
width: 70% !important;
}
.width83{
width: 83% !important;
}
.content-padding{
padding: 40px !important;
}
</style>
<!-- 弹窗 -->
<div id="mask">
<div id="loadingPage">
@@ -30,7 +19,7 @@
<!-- 列表容器 -->
<div class="ui container active loader" id="loadContainer">
{{template "base/alert" .}}
<div class="ui two column stackable grid ">
<div class="ui two column stackable grid" style="display: none;">
<div class="column"></div>
<div class="column right aligned">
<!-- -->
@@ -39,7 +28,7 @@
</div>

<!-- 中下列表展示区 -->
<div class="ui grid">
<div class="ui grid" style="display: none;">
<div class="row" style="padding-top: 0;">
<div class="ui sixteen wide column">
<!-- 任务展示 -->
@@ -63,11 +52,11 @@
<div id="deletemodel">
<div class="ui basic modal first">
<div class="ui icon header">
<i class="trash icon"></i> 删除任务
<i class="trash icon"></i> 删除模型
</div>

<div class="content">
<p>你确认删除该任务么?此任务一旦删除不可恢复。</p>
<p>你确认删除该模型么?此模型一旦删除不可恢复。</p>
</div>
<div class="actions">
<div class="ui red basic inverted cancel button">
@@ -82,7 +71,7 @@
<div id="newmodel">
<div class="ui modal second">
<div class="header" style="padding: 1rem;background-color: rgba(240, 240, 240, 100);">
<h4>导入新模型</h4>
<h4 id="model_header"></h4>
</div>
<div class="content content-padding">
<form id="formId" method="POST" class="ui form">
@@ -125,11 +114,11 @@
</div>
<div class="inline field">
<label>模型标签</label>
<input style="width: 83%;margin-left: 7px;" name="Label" maxlength="255">
<input style="width: 83%;margin-left: 7px;" name="Label" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.label_place"}}'>
</div>
<div class="inline field">
<label for="description">模型描述</label>
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3" maxlength="255" placeholder={{.i18n.Tr "repo.modelarts.train_job.new_place"}} onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea>
<textarea style="width: 83%;margin-left: 7px;" id="Description" name="Description" rows="3" maxlength="255" placeholder='{{.i18n.Tr "repo.modelarts.train_job.new_place"}}' onchange="this.value=this.value.substring(0, 255)" onkeydown="this.value=this.value.substring(0, 255)" onkeyup="this.value=this.value.substring(0, 256)"></textarea>
</div>

<div class="inline field" style="margin-left: 75px;">
@@ -167,6 +156,8 @@
.modal({
centered: false,
onShow:function(){
$('#model_header').text("导入新模型")
$('input[name="Version"]').addClass('model_disabled')
$('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"})
$("#job-name").empty()
createModelName()
@@ -232,68 +223,5 @@
$(".ui.dropdown.selection.search.width70").removeClass("loading")
})
}

function check(){
let jobid = document.getElementById("JobId").value
let versionname = document.getElementById("VersionName").value
let name= document.getElementById("name").value
let version= document.getElementById("version").value
if(jobid==""){
$(".required.ten.wide.field").addClass("error")
return false
}else{
$(".required.ten.wide.field").removeClass("error")
}
if(versionname==""){
$(".required.six.widde.field").addClass("error")
return false
}else{
$(".required.six.widde.field").removeClass("error")
}
if(name==""){
$("#modelname").addClass("error")
return false
}else{
$("#modelname").removeClass("error")
}
if(versionname==""){
$("#verionname").addClass("error")
return false
}else{
$("#verionname").removeClass("error")
}
return true
}
$('#submitId').click(function(){
let flag=check()
if(flag){
let data = $("#formId").serialize()
$("#mask").css({"display":"block","z-index":"9999"})
$.ajax({
url:url_href,
type:'POST',
data:data,
success:function(res){
$('.ui.modal.second').modal('hide')
window.location.href=location.href
},
error: function(xhr){
// 隐藏 loading
// 只有请求不正常(状态码不为200)才会执行
console.log("-------------",xhr)
$('.ui.error.message').text(xhr.responseText)
$('.ui.error.message').css('display','block')
},
complete:function(xhr){
$("#mask").css({"display":"none","z-index":"1"})
}
})
}else{
return false
}
})
</script>


+ 92
- 41
templates/repo/modelmanage/showinfo.tmpl View File

@@ -78,6 +78,67 @@
</select>
</h4>
<div id="showInfo" style="border:1px solid #e2e2e2;padding: 20px 60px;margin-top:24px">
<div class="half-table">
<span class="model_header_text">基本信息</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">模型名称</td>
<td class="ti-text-form-content word-elipsis"><span id="ModelName" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">版本</td>
<td class="ti-text-form-content word-elipsis"><span id="Version" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">标签</td>
<td class="ti-text-form-content">
<div id="Label">
</div>

</td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">大小</td>
<td class="ti-text-form-content word-elipsis"><span id="Size" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">创建时间</td>
<td class="ti-text-form-content word-elipsis"><span id="CreateTime" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">模型描述</td>
<td class="ti-text-form-content" ><div id="edit-td" style="display:flex"><span id="Description" title="" class="iword-elipsis"></span><i id="edit-pencil" data-id="" data-desc="" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div></td>
</tr>
</tbody>
</table>
</div>
<div class="half-table">
<span class="model_header_text">模型精度</span>
<table class="tableStyle" style="margin-top:20px;">
<tbody>
<tr>
<td class="ti-text-form-label text-width80">准确率</td>
<td class="ti-text-form-content word-elipsis"><span id="Accuracy" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">F1</td>
<td class="ti-text-form-content word-elipsis"><span id="F1" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">精确率</td>
<td class="ti-text-form-content word-elipsis"><span id="Precision" title=""></span></td>
</tr>
<tr>
<td class="ti-text-form-label text-width80">召回率</td>
<td class="ti-text-form-content word-elipsis"><span id="Recall" title=""></span></td>
</tr>
</tbody>
</table>
</div>
<div style="clear: both;"></div>
</div>
</div>
</div>
@@ -91,10 +152,9 @@ function changeInfo(version){
let versionData = data.filter((item)=>{
return item.Version === version
})
let initObj = transObj(versionData)[0]
let initModelAcc = transObj(versionData)[1]
let id= transObj(data)[2]
$('#showInfo').empty()
let returnArray = []
returnArray = transObj(versionData)
let [initObj,initModelAcc,id] = returnArray
renderInfo(initObj,initModelAcc,id)
})
}
@@ -105,9 +165,9 @@ function loadInfo(){
html += `<option value="${data[i].Version}">${data[i].Version}</option>`
}
$('#dropdown').append(html)
let initObj = transObj(data)[0]
let initModelAcc = transObj(data)[1]
let id= transObj(data)[2]
let returnArray = []
returnArray = transObj(data)
let [initObj,initModelAcc,id] = returnArray
renderInfo(initObj,initModelAcc,id)
})
}
@@ -155,12 +215,14 @@ function tranSize(value){
size=size.toFixed(2);//保留的小数位数
return size+unitArr[index];
}
function editorFn(text,id){
function editorFn(context){
let id= context.dataset.id
let text = context.dataset.desc
$('#edit-td').replaceWith("<div id='edit-div' style='width:80%;display: inline-block;'><textarea id='textarea-value' rows='3' maxlength='255' style='width:80%;' id='edit-text'></textarea><i class='check icon' style='color: #50d4ab;' onclick='editorSure(\"" + text + "\",\"" + id + "\")'></i><i class='times icon' style='color: #f66f6a;' onclick='editorCancel(\"" + text + "\",\"" + id + "\")'></i></div>");
}
function editorCancel(text,id){
$('#edit-div').replaceWith('<div id="edit-td" style="display:flex;"><span title="\'' + text + '\'" class="iword-elipsis">'+text+'</span><i class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(\'' + text + '\',\'' + id + '\')"></div>')
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${text}" class="iword-elipsis">${text}</span><i id="edit-pencil" data-id="${id}" data-desc="${text}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
}
function editorSure(text,id){
let description=$('#textarea-value').val()
@@ -173,46 +235,35 @@ function editorSure(text,id){
type:'PUT',
data:data
}).done((res)=>{
$('#edit-div').replaceWith('<div id="edit-td" style="display:flex;"><span title="\'' + description + '\'" class="iword-elipsis">'+description+'</span><i class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(\'' + description + '\',\'' + id + '\')"></div>')
$('#edit-div').replaceWith(`<div id="edit-td" style="display:flex;"><span id="Description" title="${description}" class="iword-elipsis">${description}</span><i id="edit-pencil" data-id="${id}" data-desc="${description}" class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(this)"></div>`)
})

}
function renderInfo(obj,accObj,id){
let html = ''
html += '<div class="half-table">'
html += '<span class="model_header_text">基本信息</span>'
html += '<table class="tableStyle" style="margin-top:20px;">'
html += '<tbody>'
for(let key in obj){
html += '<tr style="font-size: 12px;">'
html += `<td class="ti-text-form-label text-width80">${key}</td>`
if(key==="Description"){
let description = obj[key]
html += '<td class="ti-text-form-content" ><div id="edit-td" style="display:flex"><span title="\'' + description + '\'" class="iword-elipsis">'+description+'</span><i class="pencil alternate icon" style="cursor:pointer;vertical-align: top;" id="editor" onclick="editorFn(\'' + description + '\',\'' + id + '\')"></div></td>'
}else{
html += `<td class="ti-text-form-content word-elipsis"><span title="${obj[key]}">${obj[key]}</span></td>`
$(`#${key}`).text(obj[key])
$(`#${key}`).attr("title",obj[key])
$('#edit-pencil').attr("data-id",id)
$('#edit-pencil').attr("data-desc",obj[key])
}
else if(key==="Label"){
let labelArray = obj[key].split(' ')
let html=''
for(let i=0;i<labelArray.length;i++){
html += `<a class="ui label">${labelArray[i]}</a>`
}
$('#Label').append(html)
}
html += '</tr>'
else{
$(`#${key}`).text(obj[key])
$(`#${key}`).attr("title",obj[key])
}
}

html += '</tbody>'
html += '</table>'
html += '</div>'
html += '<div class="half-table">'
html += '<span class="model_header_text">模型精度</span>'
html += '<table class="tableStyle" style="margin-top:20px;">'
html += '<tbody>'
for(let key in accObj){
html += '<tr style="font-size: 12px;">'
html += `<td class="ti-text-form-label text-width80">${key}</td>`
html += `<td class="ti-text-form-content word-elipsis">${accObj[key]}</td>`
html += '</tr>'
}
html += '</tbody>'
html += '</table>'
html += '</div>'
html += '<div style="clear: both;"></div>'
$('#showInfo').append(html)
$(`#${key}`).text(accObj[key])
$(`#${key}`).attr("title",accObj[key])
}
}

</script>

+ 77
- 4
web_src/js/components/Model.vue View File

@@ -119,7 +119,7 @@
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[10]"
:page-sizes="[5,10,15]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="totalNum">
@@ -149,7 +149,8 @@ export default {
fullscreenLoading: false,
url:'',
isLoading:true,
loadNodeMap:new Map()
loadNodeMap:new Map(),
submitId:{}
};
},
methods: {
@@ -179,7 +180,7 @@ export default {
}
},
handleSizeChange(val){
this.params.size = val
this.params.pageSize = val
this.getModelList()
},
handleCurrentChange(val){
@@ -191,6 +192,9 @@ export default {
.modal({
centered: false,
onShow:function(){
$('#model_header').text("创建模型新版本")
$('input[name="Name"]').addClass('model_disabled')
$('input[name="Version"]').addClass('model_disabled')
$('.ui.dimmer').css({"background-color":"rgb(136, 136, 136,0.7)"})
$("#job-name").empty()
$('#name').val(name)
@@ -207,6 +211,67 @@ export default {
})
.modal('show')
},
check(){
let jobid = document.getElementById("JobId").value
let versionname = document.getElementById("VersionName").value
let name= document.getElementById("name").value
let version= document.getElementById("version").value
if(jobid==""){
$(".required.ten.wide.field").addClass("error")
return false
}else{
$(".required.ten.wide.field").removeClass("error")
}
if(versionname==""){
$(".required.six.widde.field").addClass("error")
return false
}else{
$(".required.six.widde.field").removeClass("error")
}
if(name==""){
$("#modelname").addClass("error")
return false
}else{
$("#modelname").removeClass("error")
}
if(versionname==""){
$("#verionname").addClass("error")
return false
}else{
$("#verionname").removeClass("error")
}
return true
},
submit(){
let context = this
let flag= this.check()
console.log(flag,context)
if(flag){
let data = $("#formId").serialize()
$("#mask").css({"display":"block","z-index":"9999"})
$.ajax({
url:url_href,
type:'POST',
data:data,
success:function(res){
context.getModelList()
$('.ui.modal.second').modal('hide')
},
error: function(xhr){
// 隐藏 loading
// 只有请求不正常(状态码不为200)才会执行
$('.ui.error.message').text(xhr.responseText)
$('.ui.error.message').css('display','block')
},
complete:function(xhr){
$("#mask").css({"display":"none","z-index":"1"})
}
})
}else{
return false
}
},
deleteModel(id,name){
let tree={cName:name}
@@ -230,6 +295,8 @@ export default {
onHidden: function() {
if (flag == false) {
$('.alert').html('您已取消操作').removeClass('alert-success').addClass('alert-danger').show().delay(1500).fadeOut();
}else{
$('.alert').html('删除成功').removeClass('alert-danger').addClass('alert-success').show().delay(1500).fadeOut();
}
}
})
@@ -261,6 +328,7 @@ export default {
this.$axios.get(location.href+'_api',{
params:this.params
}).then((res)=>{
$(".ui.grid").removeAttr("style")
$("#loadContainer").removeClass("loader")
let TrainTaskInfo
this.tableData = res.data.data
@@ -314,10 +382,15 @@ export default {
},
mounted() {
this.submitId = document.getElementById("submitId")
this.getModelList()
this.url = location.href.split('show_model')[0]
}
this.submitId.addEventListener("click", this.submit)
},

beforeDestroy() { // 实例销毁之前对点击事件进行解绑
this.submitId.removeEventListener('click', this.submit);
}
};
</script>



+ 7
- 1
web_src/js/index.js View File

@@ -4124,4 +4124,10 @@ function initDropDown() {
$("#dropdown_explore").dropdown({
on:'hover' ,//鼠标悬浮显示,默认值是click
});
}
}

//云脑提示
$('.question.circle.icon').hover(function(){
$(this).popup('show')
$('.ui.popup.mini.top.center').css({"border-color":'rgba(50, 145, 248, 100)',"color":"rgba(3, 102, 214, 100)","border-radius":"5px","border-shadow":"none"})
});

+ 1
- 0
web_src/less/_svg.less View File

@@ -2,6 +2,7 @@
display: inline-block;
vertical-align: text-top;
fill: currentColor;
margin-right: 5px;

.middle & {
vertical-align: middle;


+ 48
- 2
web_src/less/openi.less View File

@@ -292,7 +292,8 @@ footer .column{margin-bottom:0!important; padding-bottom:0!important;}
}
.hover_active{
height: 100% !important;
margin-top: 1px !important;
}
.dropdown-menu:hover .dropdown-content {
display: block;
@@ -336,7 +337,39 @@ display: block;
color: #3291F8;
}
//缺省页
.bgtask-none{
background: #fff !important;
border: 0 !important;
box-shadow: none !important;
padding-bottom: 0 !important;
padding-top: 2em !important;
}
.bgtask-header-pic {
height: 80px;
text-align: center;
background: url(//ai-studio-static-online.cdn.bcebos.com/aistudio/dist/1638363279337/images/search_empty.png) top no-repeat;
background-size: 80px 80px;
}

.bgtask-content{
margin: 2rem auto 0;
/* width: 500px; */
text-align: left;
}
.bgtask-content-txt {
font-size: 14px;
color: #a6a6a6;
line-height: 22px;
margin-bottom: 4px;
}
.bgtask-content-header {
text-align: center;
color: #3F3F40;
font-size: 18px;
margin-bottom: 1rem;
}

.selectcloudbrain .active.item{
color: #0087f5 !important;
@@ -519,9 +552,22 @@ display: block;
.letf2{
margin-left: -2px;
}
.width70{
width: 70% !important;
}
.width83{
width: 83% !important;
}
.content-padding{
padding: 40px !important;
}
.model_disabled{
background-color: rgba(245, 245, 246, 100) !important;
color: rgba(136, 136, 136, 100) !important;
}
.edge{
margin-left:0 !important;
margin-right: 0 !important;
padding-left:0 !important;
padding-right:0 !important;
}
}

Loading…
Cancel
Save