@@ -11,30 +11,30 @@ import ( | |||
) | |||
type AiModelManage struct { | |||
ID string `xorm:"pk"` | |||
Name string `xorm:"NOT NULL"` | |||
Version string `xorm:"NOT NULL"` | |||
VersionCount int `xorm:"NOT NULL DEFAULT 0"` | |||
New int `xorm:"NOT NULL"` | |||
Type int `xorm:"NOT NULL"` | |||
Size int64 `xorm:"NOT NULL"` | |||
Description string `xorm:"varchar(2000)"` | |||
Label string `xorm:"varchar(1000)"` | |||
Path string `xorm:"varchar(400) NOT NULL"` | |||
DownloadCount int `xorm:"NOT NULL DEFAULT 0"` | |||
Engine int64 `xorm:"NOT NULL DEFAULT 0"` | |||
Status int `xorm:"NOT NULL DEFAULT 0"` | |||
Accuracy string `xorm:"varchar(1000)"` | |||
AttachmentId string `xorm:"NULL"` | |||
RepoId int64 `xorm:"NULL"` | |||
CodeBranch string `xorm:"varchar(400) NULL"` | |||
CodeCommitID string `xorm:"NULL"` | |||
UserId int64 `xorm:"NOT NULL"` | |||
UserName string `xorm:"NULL"` | |||
ID string `xorm:"pk"` | |||
Name string `xorm:"INDEX NOT NULL"` | |||
Version string `xorm:"NOT NULL"` | |||
VersionCount int `xorm:"NOT NULL DEFAULT 0"` | |||
New int `xorm:"NOT NULL"` | |||
Type int `xorm:"NOT NULL"` | |||
Size int64 `xorm:"NOT NULL"` | |||
Description string `xorm:"varchar(2000)"` | |||
Label string `xorm:"varchar(1000)"` | |||
Path string `xorm:"varchar(400) NOT NULL"` | |||
DownloadCount int `xorm:"NOT NULL DEFAULT 0"` | |||
Engine int64 `xorm:"NOT NULL DEFAULT 0"` | |||
Status int `xorm:"NOT NULL DEFAULT 0"` | |||
Accuracy string `xorm:"varchar(1000)"` | |||
AttachmentId string `xorm:"NULL"` | |||
RepoId int64 `xorm:"INDEX NULL"` | |||
CodeBranch string `xorm:"varchar(400) NULL"` | |||
CodeCommitID string `xorm:"NULL"` | |||
UserId int64 `xorm:"NOT NULL"` | |||
UserName string | |||
UserRelAvatarLink string `xorm:"NULL"` | |||
TrainTaskInfo string `xorm:"text NULL"` | |||
CreatedUnix timeutil.TimeStamp `xorm:"created"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | |||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | |||
IsCanOper bool | |||
} | |||
@@ -197,7 +197,6 @@ func QueryModel(opts *AiModelQueryOptions) ([]*AiModelManage, int64, error) { | |||
Find(&aiModelManages); err != nil { | |||
return nil, 0, fmt.Errorf("Find: %v", err) | |||
} | |||
sess.Close() | |||
return aiModelManages, count, nil | |||
} |
@@ -1110,7 +1110,8 @@ func UpdateJob(job *Cloudbrain) error { | |||
func updateJob(e Engine, job *Cloudbrain) error { | |||
var sess *xorm.Session | |||
sess = e.Where("job_id = ?", job.JobID) | |||
_, err := sess.Cols("status", "container_id", "container_ip").Update(job) | |||
//_, err := sess.Cols("status", "container_id", "container_ip").Update(job) | |||
_, err := sess.Update(job) | |||
return err | |||
} | |||
@@ -93,6 +93,7 @@ type SearchDatasetOptions struct { | |||
IncludePublic bool | |||
ListOptions | |||
SearchOrderBy | |||
IsOwner bool | |||
} | |||
func CreateDataset(dataset *Dataset) (err error) { | |||
@@ -150,6 +151,9 @@ func SearchDatasetCondition(opts *SearchDatasetOptions) builder.Cond { | |||
} | |||
} else if opts.OwnerID > 0 { | |||
cond = cond.And(builder.Eq{"repository.owner_id": opts.OwnerID}) | |||
if !opts.IsOwner { | |||
cond = cond.And(builder.Eq{"dataset.status": DatasetStatusPublic}) | |||
} | |||
} | |||
return cond | |||
@@ -11,6 +11,7 @@ import ( | |||
"errors" | |||
"fmt" | |||
"html/template" | |||
"xorm.io/xorm" | |||
"code.gitea.io/gitea/modules/blockchain" | |||
@@ -1632,6 +1633,9 @@ func DeleteRepository(doer *User, uid, repoID int64) error { | |||
releaseAttachments = append(releaseAttachments, attachments[i].RelativePath()) | |||
} | |||
// Delete dataset attachment record and remove related files | |||
deleteDatasetAttachmentByRepoId(sess, repoID) | |||
if err = deleteBeans(sess, | |||
&Access{RepoID: repo.ID}, | |||
&Action{RepoID: repo.ID}, | |||
@@ -1817,6 +1821,20 @@ func DeleteRepository(doer *User, uid, repoID int64) error { | |||
return nil | |||
} | |||
func deleteDatasetAttachmentByRepoId(sess *xorm.Session, repoId int64) error { | |||
attachments := make([]*Attachment, 0) | |||
if err := sess.Join("INNER", "dataset", "dataset.id = attachment.dataset_id"). | |||
Where("dataset.repo_id = ?", repoId). | |||
Find(&attachments); err != nil { | |||
return err | |||
} | |||
if len(attachments) == 0 { | |||
return nil | |||
} | |||
_, err := DeleteAttachments(attachments, true) | |||
return err | |||
} | |||
// GetRepositoryByOwnerAndName returns the repository by given ownername and reponame. | |||
func GetRepositoryByOwnerAndName(ownerName, repoName string) (*Repository, error) { | |||
return getRepositoryByOwnerAndName(x, ownerName, repoName) | |||
@@ -929,7 +929,7 @@ var ( | |||
"template", | |||
"user", | |||
"vendor", | |||
"dashbord", | |||
"dashboard", | |||
"operation", | |||
"blockchain", | |||
"avatar", | |||
@@ -2,6 +2,7 @@ package cloudbrain | |||
import ( | |||
"errors" | |||
"strconv" | |||
"code.gitea.io/gitea/modules/setting" | |||
@@ -30,29 +31,30 @@ var ( | |||
) | |||
func isAdminOrOwnerOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { | |||
if !ctx.IsSigned { | |||
return false | |||
} | |||
log.Info("is repo owner:" + strconv.FormatBool(ctx.IsUserRepoOwner())) | |||
log.Info("is user admin:" + strconv.FormatBool(ctx.IsUserSiteAdmin())) | |||
if err != nil { | |||
return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() | |||
} else { | |||
log.Info("is job creator:" + strconv.FormatBool(ctx.User.ID == job.UserID)) | |||
return ctx.IsUserRepoOwner() || ctx.IsUserSiteAdmin() || ctx.User.ID == job.UserID | |||
} | |||
} | |||
func CanDeleteDebugJob(ctx *context.Context, job *models.Cloudbrain) bool { | |||
if job.Status != string(models.JobStopped) && job.Status != string(models.JobFailed) && job.Status != string(models.ModelArtsStartFailed) && job.Status != string(models.ModelArtsCreateFailed) { | |||
return false | |||
} | |||
return isAdminOrOwnerOrJobCreater(ctx, job, nil) | |||
} | |||
func CanDeleteTrainJob(ctx *context.Context, job *models.Cloudbrain) bool { | |||
func CanDeleteJob(ctx *context.Context, job *models.Cloudbrain) bool { | |||
return isAdminOrOwnerOrJobCreater(ctx, job, nil) | |||
} | |||
func CanCreateOrDebugJob(ctx *context.Context) bool { | |||
if !ctx.IsSigned { | |||
return false | |||
} | |||
return ctx.Repo.CanWrite(models.UnitTypeCloudBrain) | |||
} | |||
@@ -62,7 +64,9 @@ func CanModifyJob(ctx *context.Context, job *models.Cloudbrain) bool { | |||
} | |||
func isAdminOrJobCreater(ctx *context.Context, job *models.Cloudbrain, err error) bool { | |||
if !ctx.IsSigned { | |||
return false | |||
} | |||
if err != nil { | |||
return ctx.IsUserSiteAdmin() | |||
} else { | |||
@@ -113,7 +117,7 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath, | |||
log.Error("no such resourceSpecId(%d)", resourceSpecId, ctx.Data["MsgID"]) | |||
return errors.New("no such resourceSpec") | |||
} | |||
jobResult, err := CreateJob(jobName, models.CreateJobParams{ | |||
JobName: jobName, | |||
RetryCount: 1, | |||
@@ -198,8 +202,8 @@ func GenerateTask(ctx *context.Context, jobName, image, command, uuid, codePath, | |||
JobName: jobName, | |||
SubTaskName: SubTaskName, | |||
JobType: jobType, | |||
Type: models.TypeCloudBrainOne, | |||
Uuid: uuid, | |||
Type: models.TypeCloudBrainOne, | |||
Uuid: uuid, | |||
}) | |||
if err != nil { | |||
@@ -134,7 +134,7 @@ func registerHandleBlockChainUnSuccessRepos() { | |||
RegisterTaskFatal("handle_blockchain_unsuccess_repos", &BaseConfig{ | |||
Enabled: true, | |||
RunAtStart: true, | |||
Schedule: "@every 1m", | |||
Schedule: "@every 10m", | |||
}, func(ctx context.Context, _ *models.User, _ Config) error { | |||
repo.HandleBlockChainUnSuccessRepos() | |||
return nil | |||
@@ -145,7 +145,7 @@ func registerHandleBlockChainMergedPulls() { | |||
RegisterTaskFatal("handle_blockchain_merged_pull", &BaseConfig{ | |||
Enabled: true, | |||
RunAtStart: true, | |||
Schedule: "@every 1m", | |||
Schedule: "@every 10m", | |||
}, func(ctx context.Context, _ *models.User, _ Config) error { | |||
repo.HandleBlockChainMergedPulls() | |||
return nil | |||
@@ -156,7 +156,7 @@ func registerHandleBlockChainUnSuccessCommits() { | |||
RegisterTaskFatal("handle_blockchain_unsuccess_commits", &BaseConfig{ | |||
Enabled: true, | |||
RunAtStart: true, | |||
Schedule: "@every 3m", | |||
Schedule: "@every 10m", | |||
}, func(ctx context.Context, _ *models.User, _ Config) error { | |||
repo.HandleBlockChainUnSuccessCommits() | |||
return nil | |||
@@ -433,6 +433,9 @@ var ( | |||
AuthUser string | |||
AuthPassword string | |||
//home page | |||
RecommentRepoAddr string | |||
//labelsystem config | |||
LabelTaskName string | |||
LabelDatasetDeleteQueue string | |||
@@ -448,21 +451,25 @@ var ( | |||
GpuTypes string | |||
DebugServerHost string | |||
ResourceSpecs string | |||
MaxDuration int64 | |||
//benchmark config | |||
IsBenchmarkEnabled bool | |||
BenchmarkCode string | |||
BenchmarkOwner string | |||
BenchmarkName string | |||
BenchmarkServerHost string | |||
BenchmarkCategory string | |||
//snn4imagenet config | |||
IsSnn4imagenetEnabled bool | |||
Snn4imagenetCode string | |||
Snn4imagenetOwner string | |||
Snn4imagenetName string | |||
Snn4imagenetServerHost string | |||
//snn4imagenet config | |||
IsBrainScoreEnabled bool | |||
BrainScoreCode string | |||
BrainScoreOwner string | |||
BrainScoreName string | |||
BrainScoreServerHost string | |||
//blockchain config | |||
@@ -1225,6 +1232,9 @@ func NewContext() { | |||
LabelDatasetDeleteQueue = sec.Key("LabelDatasetDeleteQueue").MustString("LabelDatasetDeleteQueue") | |||
DecompressOBSTaskName = sec.Key("DecompressOBSTaskName").MustString("LabelDecompressOBSQueue") | |||
sec = Cfg.Section("homepage") | |||
RecommentRepoAddr = sec.Key("Address").MustString("https://git.openi.org.cn/OpenIOSSG/promote/raw/branch/master/") | |||
sec = Cfg.Section("cloudbrain") | |||
CBAuthUser = sec.Key("USER").MustString("") | |||
CBAuthPassword = sec.Key("PWD").MustString("") | |||
@@ -1235,21 +1245,25 @@ func NewContext() { | |||
JobType = sec.Key("GPU_TYPE_DEFAULT").MustString("openidebug") | |||
GpuTypes = sec.Key("GPU_TYPES").MustString("") | |||
ResourceSpecs = sec.Key("RESOURCE_SPECS").MustString("") | |||
MaxDuration = sec.Key("MAX_DURATION").MustInt64(14400) | |||
sec = Cfg.Section("benchmark") | |||
IsBenchmarkEnabled = sec.Key("ENABLED").MustBool(false) | |||
BenchmarkCode = sec.Key("BENCHMARKCODE").MustString("") | |||
BenchmarkOwner = sec.Key("OWNER").MustString("") | |||
BenchmarkName = sec.Key("NAME").MustString("") | |||
BenchmarkServerHost = sec.Key("HOST").MustString("") | |||
BenchmarkCategory = sec.Key("CATEGORY").MustString("") | |||
sec = Cfg.Section("snn4imagenet") | |||
IsSnn4imagenetEnabled = sec.Key("ENABLED").MustBool(false) | |||
Snn4imagenetCode = sec.Key("SNN4IMAGENETCODE").MustString("") | |||
Snn4imagenetOwner = sec.Key("OWNER").MustString("") | |||
Snn4imagenetName = sec.Key("NAME").MustString("") | |||
Snn4imagenetServerHost = sec.Key("HOST").MustString("") | |||
sec = Cfg.Section("brainscore") | |||
IsBrainScoreEnabled = sec.Key("ENABLED").MustBool(false) | |||
BrainScoreCode = sec.Key("BRAINSCORECODE").MustString("") | |||
BrainScoreOwner = sec.Key("OWNER").MustString("") | |||
BrainScoreName = sec.Key("NAME").MustString("") | |||
BrainScoreServerHost = sec.Key("HOST").MustString("") | |||
sec = Cfg.Section("blockchain") | |||
@@ -778,6 +778,8 @@ datasets = Datasets | |||
datasets.desc = Enable Dataset | |||
cloudbrain_helper=Use GPU/NPU resources to open notebooks, model training tasks, etc. | |||
model_manager = Model | |||
debug=Debug | |||
stop=Stop | |||
delete=Delete | |||
@@ -782,7 +782,7 @@ datasets=数据集 | |||
datasets.desc=数据集功能 | |||
cloudbrain_helper=使用GPU/NPU资源,开启Notebook、模型训练任务等 | |||
model_manager = 模型管理 | |||
model_manager = 模型 | |||
model_noright=无权限操作 | |||
debug=调试 | |||
@@ -857,7 +857,7 @@ modelarts.train_job.description=任务描述 | |||
modelarts.train_job.parameter_setting=参数设置 | |||
modelarts.train_job.parameter_setting_info=参数信息 | |||
modelarts.train_job.fast_parameter_setting=一键式参数配置 | |||
modelarts.train_job.fast_parameter_setting_config=如您已保存过参数配置,可单击 | |||
modelarts.train_job.fast_parameter_setting_config=如您已保存过参数配置,可单击 | |||
modelarts.train_job.fast_parameter_setting_config_link=这里 | |||
modelarts.train_job.frames=常用框架 | |||
modelarts.train_job.algorithm_origin=算法来源 | |||
@@ -1987,7 +1987,7 @@ team_unit_desc=允许访问项目单元 | |||
team_unit_disabled=(已禁用) | |||
form.name_reserved=组织名称 '%s' 是被保留的。 | |||
form.name_pattern_not_allowed=项目名称中不允许使用 "%s"。 | |||
form.name_pattern_not_allowed=组织名称中不允许使用 "%s"。 | |||
form.create_org_not_allowed=此账号禁止创建组织 | |||
settings=组织设置 | |||
@@ -0,0 +1 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="120" height="120"><path fill="none" d="M0 0h24v24H0z"/><path d="M20 22h-2v-2a3 3 0 0 0-3-3H9a3 3 0 0 0-3 3v2H4v-2a5 5 0 0 1 5-5h6a5 5 0 0 1 5 5v2zm-8-9a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8z" fill="rgba(0,0,0,0.4)"/></svg> |
@@ -0,0 +1 @@ | |||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="120" height="120"><path fill="none" d="M0 0h24v24H0z"/><path d="M20 3l2 4v13a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V7.004L4 3h16zm0 6H4v10h16V9zm-8 1l4 4h-3v4h-2v-4H8l4-4zm6.764-5H5.236l-.999 2h15.527l-1-2z" fill="rgba(0,0,0,0.4)"/></svg> |
@@ -7,6 +7,8 @@ package routers | |||
import ( | |||
"bytes" | |||
"fmt" | |||
"io/ioutil" | |||
"net/http" | |||
"strings" | |||
@@ -511,3 +513,43 @@ func NotFound(ctx *context.Context) { | |||
ctx.Data["Title"] = "Page Not Found" | |||
ctx.NotFound("home.NotFound", nil) | |||
} | |||
func RecommendOrgFromPromote(ctx *context.Context) { | |||
url := setting.RecommentRepoAddr + "organizations" | |||
recommendFromPromote(ctx, url) | |||
} | |||
func recommendFromPromote(ctx *context.Context, url string) { | |||
resp, err := http.Get(url) | |||
if err != nil { | |||
log.Info("Get organizations url error=" + err.Error()) | |||
ctx.ServerError("QueryTrainJobList:", err) | |||
return | |||
} | |||
bytes, err := ioutil.ReadAll(resp.Body) | |||
resp.Body.Close() | |||
if err != nil { | |||
log.Info("Get organizations url error=" + err.Error()) | |||
ctx.ServerError("QueryTrainJobList:", err) | |||
return | |||
} | |||
allLineStr := string(bytes) | |||
lines := strings.Split(allLineStr, "\n") | |||
result := make([]string, len(lines)) | |||
for i, line := range lines { | |||
tmpIndex := strings.Index(line, ".") | |||
log.Info("i=" + fmt.Sprint(i) + " line=" + line + " tmpIndex=" + fmt.Sprint(tmpIndex)) | |||
if tmpIndex == -1 { | |||
result[i] = strings.Trim(line, " ") | |||
} else { | |||
result[i] = strings.Trim(line[tmpIndex+1:], " ") | |||
} | |||
} | |||
ctx.JSON(http.StatusOK, result) | |||
} | |||
func RecommendRepoFromPromote(ctx *context.Context) { | |||
url := setting.RecommentRepoAddr + "projects" | |||
recommendFromPromote(ctx, url) | |||
} |
@@ -28,7 +28,6 @@ const ( | |||
func saveModelByParameters(jobId string, versionName string, name string, version string, label string, description string, ctx *context.Context) error { | |||
aiTask, err := models.GetCloudbrainByJobIDAndVersionName(jobId, versionName) | |||
//aiTask, err := models.GetCloudbrainByJobID(jobId) | |||
if err != nil { | |||
log.Info("query task error." + err.Error()) | |||
return err | |||
@@ -56,7 +55,7 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||
cloudType = aiTask.Type | |||
//download model zip //train type | |||
if cloudType == models.TypeCloudBrainTwo { | |||
modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "") | |||
modelPath, modelSize, err = downloadModelFromCloudBrainTwo(id, aiTask.JobName, "", aiTask.TrainUrl) | |||
if err != nil { | |||
log.Info("download model from CloudBrainTwo faild." + err.Error()) | |||
return err | |||
@@ -71,7 +70,6 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||
log.Info("accuracyJson=" + string(accuracyJson)) | |||
aiTaskJson, _ := json.Marshal(aiTask) | |||
//taskConfigInfo,err := models.GetCloudbrainByJobIDAndVersionName(jobId,aiTask.VersionName) | |||
model := &models.AiModelManage{ | |||
ID: id, | |||
Version: version, | |||
@@ -86,7 +84,6 @@ func saveModelByParameters(jobId string, versionName string, name string, versio | |||
AttachmentId: aiTask.Uuid, | |||
RepoId: aiTask.RepoID, | |||
UserId: ctx.User.ID, | |||
UserName: ctx.User.Name, | |||
UserRelAvatarLink: ctx.User.RelAvatarLink(), | |||
CodeBranch: aiTask.BranchName, | |||
CodeCommitID: aiTask.CommitID, | |||
@@ -144,9 +141,12 @@ func SaveModel(ctx *context.Context) { | |||
log.Info("save model end.") | |||
} | |||
func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir string) (string, int64, error) { | |||
func downloadModelFromCloudBrainTwo(modelUUID string, jobName string, parentDir string, trainUrl string) (string, int64, error) { | |||
objectkey := strings.TrimPrefix(path.Join(setting.TrainJobModelPath, jobName, setting.OutPutPath, parentDir), "/") | |||
if trainUrl != "" { | |||
objectkey = strings.Trim(trainUrl[len(setting.Bucket)+1:], "/") | |||
} | |||
modelDbResult, err := storage.GetOneLevelAllObjectUnderDir(setting.Bucket, objectkey, "") | |||
log.Info("bucket=" + setting.Bucket + " objectkey=" + objectkey) | |||
if err != nil { | |||
@@ -395,15 +395,42 @@ func ShowSingleModel(ctx *context.Context) { | |||
ctx.JSON(http.StatusOK, models) | |||
} | |||
func queryUserName(intSlice []int64) map[int64]string { | |||
keys := make(map[int64]string) | |||
uniqueElements := []int64{} | |||
for _, entry := range intSlice { | |||
if _, value := keys[entry]; !value { | |||
keys[entry] = "" | |||
uniqueElements = append(uniqueElements, entry) | |||
} | |||
} | |||
userNames, err := models.GetUserNamesByIDs(uniqueElements) | |||
if err == nil { | |||
for i, userName := range userNames { | |||
keys[uniqueElements[i]] = userName | |||
} | |||
} | |||
return keys | |||
} | |||
func ShowOneVersionOtherModel(ctx *context.Context) { | |||
repoId := ctx.Repo.Repository.ID | |||
name := ctx.Query("name") | |||
aimodels := models.QueryModelByName(name, repoId) | |||
for _, model := range aimodels { | |||
userIds := make([]int64, len(aimodels)) | |||
for i, model := range aimodels { | |||
log.Info("model=" + model.Name) | |||
log.Info("model.UserId=" + fmt.Sprint(model.UserId)) | |||
model.IsCanOper = isOper(ctx, model.UserId) | |||
userIds[i] = model.UserId | |||
} | |||
userNameMap := queryUserName(userIds) | |||
for _, model := range aimodels { | |||
model.UserName = userNameMap[model.UserId] | |||
} | |||
if len(aimodels) > 0 { | |||
ctx.JSON(200, aimodels[1:]) | |||
} else { | |||
@@ -431,7 +458,7 @@ func isOper(ctx *context.Context, modelUserId int64) bool { | |||
if ctx.User == nil { | |||
return false | |||
} | |||
if ctx.User.IsAdmin || ctx.Repo.IsAdmin() || ctx.Repo.IsOwner() || ctx.User.ID == modelUserId { | |||
if ctx.User.IsAdmin || ctx.Repo.IsOwner() || ctx.User.ID == modelUserId { | |||
return true | |||
} | |||
return false | |||
@@ -463,10 +490,17 @@ func ShowModelPageInfo(ctx *context.Context) { | |||
return | |||
} | |||
for _, model := range modelResult { | |||
userIds := make([]int64, len(modelResult)) | |||
for i, model := range modelResult { | |||
log.Info("model=" + model.Name) | |||
log.Info("model.UserId=" + fmt.Sprint(model.UserId)) | |||
model.IsCanOper = isOper(ctx, model.UserId) | |||
userIds[i] = model.UserId | |||
} | |||
userNameMap := queryUserName(userIds) | |||
for _, model := range modelResult { | |||
model.UserName = userNameMap[model.UserId] | |||
} | |||
mapInterface := make(map[string]interface{}) | |||
@@ -8,7 +8,6 @@ import ( | |||
"io" | |||
"net/http" | |||
"os" | |||
"os/exec" | |||
"regexp" | |||
"sort" | |||
"strconv" | |||
@@ -71,15 +70,9 @@ func CloudBrainIndex(ctx *context.Context) { | |||
return | |||
} | |||
timestamp := time.Now().Unix() | |||
for i, task := range ciTasks { | |||
if task.Status == string(models.JobRunning) && (timestamp-int64(task.Cloudbrain.CreatedUnix) > 10) { | |||
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx) | |||
} else { | |||
ciTasks[i].CanDebug = false | |||
} | |||
ciTasks[i].CanDel = cloudbrain.CanDeleteDebugJob(ctx, &task.Cloudbrain) | |||
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx) | |||
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) | |||
} | |||
@@ -251,13 +244,9 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
downloadCode(repo, codePath) | |||
uploadCodeToMinio(codePath + "/", jobName, "/code/") | |||
modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath | |||
err = os.MkdirAll(modelPath, os.ModePerm) | |||
if err != nil { | |||
cloudBrainNewDataPrepare(ctx) | |||
ctx.RenderWithErr(err.Error(), tplCloudBrainNew, &form) | |||
return | |||
} | |||
modelPath := setting.JobPath + jobName + cloudbrain.ModelMountPath + "/" | |||
mkModelPath(modelPath) | |||
uploadCodeToMinio(modelPath, jobName, cloudbrain.ModelMountPath + "/") | |||
benchmarkPath := setting.JobPath + jobName + cloudbrain.BenchMarkMountPath | |||
if setting.IsBenchmarkEnabled && jobType == string(models.JobTypeBenchmark) { | |||
@@ -267,23 +256,25 @@ func CloudBrainCreate(ctx *context.Context, form auth.CreateCloudBrainForm) { | |||
gpuType = gpuInfo.Value | |||
} | |||
} | |||
downloadRateCode(repo, jobName, setting.BenchmarkCode, benchmarkPath, form.BenchmarkCategory, gpuType) | |||
downloadRateCode(repo, jobName, setting.BenchmarkOwner, setting.BrainScoreName, benchmarkPath, form.BenchmarkCategory, gpuType) | |||
uploadCodeToMinio(benchmarkPath + "/", jobName, cloudbrain.BenchMarkMountPath + "/") | |||
} | |||
snn4imagenetPath := setting.JobPath + jobName + cloudbrain.Snn4imagenetMountPath | |||
if setting.IsSnn4imagenetEnabled && jobType == string(models.JobTypeSnn4imagenet) { | |||
downloadRateCode(repo, jobName, setting.Snn4imagenetCode, snn4imagenetPath, "", "") | |||
downloadRateCode(repo, jobName, setting.Snn4imagenetOwner, setting.Snn4imagenetName, snn4imagenetPath, "", "") | |||
uploadCodeToMinio(snn4imagenetPath + "/", jobName, cloudbrain.Snn4imagenetMountPath + "/") | |||
} | |||
brainScorePath := setting.JobPath + jobName + cloudbrain.BrainScoreMountPath | |||
if setting.IsBrainScoreEnabled && jobType == string(models.JobTypeBrainScore) { | |||
downloadRateCode(repo, jobName, setting.BrainScoreCode, brainScorePath, "", "") | |||
downloadRateCode(repo, jobName, setting.BrainScoreOwner, setting.BrainScoreName, brainScorePath, "", "") | |||
uploadCodeToMinio(brainScorePath + "/", jobName, cloudbrain.BrainScoreMountPath + "/") | |||
} | |||
err = cloudbrain.GenerateTask(ctx, jobName, image, command, uuid, codePath, modelPath, benchmarkPath, snn4imagenetPath, brainScorePath, 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) | |||
@@ -607,7 +598,7 @@ func getImages(ctx *context.Context, imageType string) { | |||
func GetModelDirs(jobName string, parentDir string) (string, error) { | |||
var req string | |||
modelActualPath := setting.JobPath + jobName + "/model/" | |||
modelActualPath := getMinioPath(jobName, cloudbrain.ModelMountPath + "/") | |||
if parentDir == "" { | |||
req = "baseDir=" + modelActualPath | |||
} else { | |||
@@ -617,6 +608,10 @@ func GetModelDirs(jobName string, parentDir string) (string, error) { | |||
return getDirs(req) | |||
} | |||
func getMinioPath(jobName, suffixPath string) string { | |||
return setting.Attachment.Minio.RealPath + setting.Attachment.Minio.Bucket + "/" + setting.CBCodePathPrefix + jobName + suffixPath | |||
} | |||
func CloudBrainDownloadModel(ctx *context.Context) { | |||
parentDir := ctx.Query("parentDir") | |||
fileName := ctx.Query("fileName") | |||
@@ -698,19 +693,21 @@ func downloadCode(repo *models.Repository, codePath string) error { | |||
return nil | |||
} | |||
func downloadRateCode(repo *models.Repository, taskName, gitPath, codePath, benchmarkCategory, gpuType string) error { | |||
func downloadRateCode(repo *models.Repository, taskName, rateOwnerName, rateRepoName, codePath, benchmarkCategory, gpuType string) error { | |||
err := os.MkdirAll(codePath, os.ModePerm) | |||
if err != nil { | |||
log.Error("mkdir codePath failed", err.Error()) | |||
return err | |||
} | |||
command := "git clone " + gitPath + " " + codePath | |||
cmd := exec.Command("/bin/bash", "-c", command) | |||
_, err = cmd.Output() | |||
repoExt, err := models.GetRepositoryByOwnerAndName(rateOwnerName, rateRepoName) | |||
if err != nil { | |||
log.Error("exec.Command(%s) failed:%v", command, err) | |||
log.Error("GetRepositoryByOwnerAndName(%s) failed", rateRepoName, err.Error()) | |||
return err | |||
} | |||
if err := git.Clone(repoExt.RepoPath(), codePath, git.CloneRepoOptions{}); err != nil { | |||
log.Error("Failed to clone repository: %s (%v)", repoExt.FullName(), err) | |||
return err | |||
} | |||
@@ -772,6 +769,32 @@ func uploadCodeToMinio(codePath, jobName, parentDir string) error { | |||
return nil | |||
} | |||
func mkModelPath(modelPath string) error { | |||
err := os.MkdirAll(modelPath, os.ModePerm) | |||
if err != nil { | |||
log.Error("MkdirAll(%s) failed:%v", modelPath, err) | |||
return err | |||
} | |||
fileName := modelPath + "README" | |||
f, err := os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) | |||
if err != nil { | |||
log.Error("OpenFile failed", err.Error()) | |||
return err | |||
} | |||
defer f.Close() | |||
_, err = f.WriteString("You can put the model file into this directory and download it by the web page.") | |||
if err != nil { | |||
log.Error("WriteString failed", err.Error()) | |||
return err | |||
} | |||
return nil | |||
} | |||
func SyncCloudbrainStatus() { | |||
cloudBrains, err := models.GetCloudBrainUnStoppedJob() | |||
if err != nil { | |||
@@ -793,10 +816,24 @@ func SyncCloudbrainStatus() { | |||
taskRes, _ := models.ConvertToTaskPod(taskRoles[cloudbrain.SubTaskName].(map[string]interface{})) | |||
task.Status = taskRes.TaskStatuses[0].State | |||
if task.Status != string(models.JobWaiting) { | |||
task.Duration = time.Now().Unix() - taskRes.TaskStatuses[0].StartAt.Unix() | |||
err = models.UpdateJob(task) | |||
if err != nil { | |||
log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||
continue | |||
} | |||
if task.Duration >= setting.MaxDuration { | |||
log.Info("begin to stop job(%s), because of the duration", task.JobName) | |||
err = cloudbrain.StopJob(task.JobID) | |||
if err != nil { | |||
log.Error("StopJob(%s) failed:%v", task.JobName, err) | |||
continue | |||
} | |||
task.Status = string(models.JobStopped) | |||
err = models.UpdateJob(task) | |||
if err != nil { | |||
log.Error("UpdateJob(%s) failed:%v", task.JobName, err) | |||
} | |||
} | |||
} | |||
} | |||
@@ -69,12 +69,9 @@ func NotebookIndex(ctx *context.Context) { | |||
} | |||
for i, task := range ciTasks { | |||
if task.Status == string(models.JobRunning) { | |||
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx) | |||
} else { | |||
ciTasks[i].CanDebug = false | |||
} | |||
ciTasks[i].CanDel = cloudbrain.CanDeleteDebugJob(ctx, &task.Cloudbrain) | |||
ciTasks[i].CanDebug = cloudbrain.CanCreateOrDebugJob(ctx) | |||
ciTasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) | |||
} | |||
pager := context.NewPagination(int(count), setting.UI.IssuePagingNum, page, 5) | |||
@@ -306,7 +303,7 @@ func TrainJobIndex(ctx *context.Context) { | |||
} | |||
for i, task := range tasks { | |||
tasks[i].CanDel = cloudbrain.CanDeleteTrainJob(ctx, &task.Cloudbrain) | |||
tasks[i].CanDel = cloudbrain.CanDeleteJob(ctx, &task.Cloudbrain) | |||
tasks[i].CanModify = cloudbrain.CanModifyJob(ctx, &task.Cloudbrain) | |||
} | |||
@@ -532,6 +532,7 @@ func Download(ctx *context.Context) { | |||
} | |||
ctx.Repo.Repository.IncreaseCloneCnt() | |||
ctx.Repo.Repository.IncreaseGitCloneCnt() | |||
ctx.ServeFile(archivePath, ctx.Repo.Repository.Name+"-"+refName+ext) | |||
} | |||
@@ -148,11 +148,6 @@ func QueryUserStaticDataPage(ctx *context.Context) { | |||
func TimingCountDataByDateAndReCount(date string, isReCount bool) { | |||
if date == "refreshAll" { | |||
models.RefreshUserStaticAllTabel() | |||
return | |||
} | |||
t, _ := time.Parse("2006-01-02", date) | |||
startTime := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) | |||
@@ -205,10 +200,9 @@ func TimingCountDataByDateAndReCount(date string, isReCount bool) { | |||
log.Error("count user info error." + err.Error()) | |||
mailer.SendWarnNotifyMail(setting.Warn_Notify_Mails, warnEmailMessage) | |||
} | |||
if isReCount { | |||
models.RefreshUserStaticAllTabel() | |||
} | |||
log.Info("start to count all user info data") | |||
//models.RefreshUserStaticAllTabel(wikiMap) | |||
log.Info("end to count all user info data") | |||
} | |||
func TimingCountDataByDate(date string) { | |||
@@ -315,6 +315,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
}) | |||
m.Get("/", routers.Home) | |||
m.Get("/dashboard", routers.Dashboard) | |||
m.Get("/recommend/org", routers.RecommendOrgFromPromote) | |||
m.Get("/recommend/repo", routers.RecommendRepoFromPromote) | |||
m.Group("/explore", func() { | |||
m.Get("", func(ctx *context.Context) { | |||
ctx.Redirect(setting.AppSubURL + "/explore/repos") | |||
@@ -214,10 +214,15 @@ func Profile(ctx *context.Context) { | |||
total = int(count) | |||
case "datasets": | |||
var isOwner = false | |||
if ctx.User != nil && ctx.User.ID == ctxUser.ID { | |||
isOwner = true | |||
} | |||
datasetSearchOptions := &models.SearchDatasetOptions{ | |||
Keyword: keyword, | |||
OwnerID: ctxUser.ID, | |||
SearchOrderBy: orderBy, | |||
IsOwner: isOwner, | |||
ListOptions: models.ListOptions{ | |||
Page: page, | |||
PageSize: setting.UI.ExplorePagingNum, | |||
@@ -17,7 +17,7 @@ | |||
{{if .IsSigned}} | |||
<div class=" item" > | |||
<div class=" item edge"> | |||
<div class="dropdown-menu"> | |||
<a class=" item" href="/dashboard"> | |||
<span > {{.i18n.Tr "index"}}   <i class="dropdown icon"></i></span> | |||
@@ -47,7 +47,7 @@ | |||
</div> | |||
</div> | |||
{{else if .IsLandingPageHome}} | |||
<div class=" item"> | |||
<div class="item edge"> | |||
<div class="dropdown-menu"> | |||
<a class=" item" href="/user/login"> | |||
<span > {{.i18n.Tr "home"}}   <i class="dropdown icon"></i></span> | |||
@@ -94,13 +94,13 @@ | |||
*/}} | |||
{{if .IsSigned}} | |||
<div class="right stackable menu"> | |||
<div class="right stackable menu"> | |||
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<input type="hidden" name="sort" value="{{$.SortType}}"> | |||
<input type="hidden" name="sort" value="hot"> | |||
<button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||
</button> | |||
<!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||
@@ -190,12 +190,13 @@ | |||
<!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | |||
<div class="right stackable menu"> | |||
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<input type="hidden" name="sort" value="{{$.SortType}}"> | |||
<input type="hidden" name="sort" value="hot"> | |||
<button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||
</button> | |||
<!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||
@@ -17,7 +17,7 @@ | |||
{{if .IsSigned}} | |||
<div class="item" > | |||
<div class="item edge" > | |||
<div class="dropdown-menu"> | |||
<a class=" item" href="/dashboard"> | |||
<span > {{.i18n.Tr "index"}}   <i class="dropdown icon"></i></span> | |||
@@ -46,7 +46,7 @@ | |||
</div> | |||
</div> | |||
{{else if .IsLandingPageHome}} | |||
<div class="item" > | |||
<div class="item edge" > | |||
<div class="dropdown-menu"> | |||
<a class=" item" href="/user/login"> | |||
<span > {{.i18n.Tr "home"}}   <i class="dropdown icon"></i></span> | |||
@@ -9,7 +9,7 @@ | |||
</div> | |||
{{if .IsSigned}} | |||
<div class="item" > | |||
<div class="item edge" > | |||
<div class="dropdown-menu"> | |||
<a class=" item" href="/dashboard"> | |||
<span > {{.i18n.Tr "index"}}   <i class="dropdown icon"></i></span> | |||
@@ -38,7 +38,7 @@ | |||
</div> | |||
</div> | |||
{{else if .IsLandingPageHome}} | |||
<div class="item" > | |||
<div class="item edge" > | |||
<div class="dropdown-menu"> | |||
<a class=" item" href="/user/login"> | |||
<span > {{.i18n.Tr "home"}}   <i class="dropdown icon"></i></span> | |||
@@ -0,0 +1,216 @@ | |||
<div class="ui container" id="navbar"> | |||
<div class="item brand" style="justify-content: space-between;"> | |||
<a href="https://openi.org.cn/"> | |||
<img class="ui mini image" src="{{StaticUrlPrefix}}/img/logo-w.svg"> | |||
</a> | |||
<div class="ui basic icon button mobile-only" id="navbar-expand-toggle"> | |||
<i class="sidebar icon"></i> | |||
</div> | |||
</div> | |||
<div style="width:1px;background:#606266;height:80%;margin:auto 0.5rem"></div> | |||
<div class="item brand" style="margin-left: 0.9rem;"> | |||
<a href="/"> | |||
<img class="ui mini image" style="height: 1.3rem;" src="{{StaticUrlPrefix}}/img/git-logo.svg"> | |||
</a> | |||
</div> | |||
{{if .IsSigned}} | |||
<div class=" item edge" > | |||
<div class="dropdown-menu"> | |||
<a class=" item" href="/dashboard"> | |||
<span > {{.i18n.Tr "index"}}   <i class="dropdown icon"></i></span> | |||
</a> | |||
<div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||
<a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/issues">{{.i18n.Tr "issues"}}</a> | |||
<a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/pulls">{{.i18n.Tr "pull_requests"}}</a> | |||
<a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/milestones">{{.i18n.Tr "milestones"}}</a> | |||
</div> | |||
</div> | |||
</div> | |||
<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
<div class="ui dropdown item" id='dropdown_explore'> | |||
{{.i18n.Tr "explore"}} | |||
<i class="dropdown icon"></i> | |||
<div class="menu"> | |||
<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> | |||
{{if .IsOperator}} | |||
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
{{end}} | |||
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
</div> | |||
</div> | |||
{{else if .IsLandingPageHome}} | |||
<div class="item edge"> | |||
<div class="dropdown-menu"> | |||
<a class=" item" href="/user/login"> | |||
<span > {{.i18n.Tr "home"}}   <i class="dropdown icon"></i></span> | |||
</a> | |||
<div class="dropdown-content" style="min-width: 110px;border-radius:4px"> | |||
<a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "issues"}}</a> | |||
<a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "pull_requests"}}</a> | |||
<a style="border: none;color: #000;" class=" item" href="{{AppSubUrl}}/user/login">{{.i18n.Tr "milestones"}}</a> | |||
</div> | |||
</div> | |||
</div> | |||
<a class="item" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "custom.head.project"}}</a> | |||
<a class="item" href="{{AppSubUrl}}/explore/datasets">{{.i18n.Tr "custom.head.dataset"}}</a> | |||
<div class="ui dropdown item" id='dropdown_PageHome'> | |||
{{.i18n.Tr "explore"}} | |||
<i class="dropdown icon"></i> | |||
<div class="menu" > | |||
<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> | |||
{{if .IsOperator}} | |||
<a class="item" href="{{AppSubUrl}}/explore/data_analysis">{{.i18n.Tr "explore.data_analysis"}}</a> | |||
{{end}} | |||
<a class="item" href="{{AppSubUrl}}/OpenI">{{.i18n.Tr "custom.head.openi"}}</a> | |||
</div> | |||
</div> | |||
{{else if .IsLandingPageExplore}} | |||
<a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/repos">{{.i18n.Tr "home"}}</a> | |||
{{else if .IsLandingPageOrganizations}} | |||
<a class="item {{if .PageIsExplore}}active{{end}}" href="{{AppSubUrl}}/explore/organizations">{{.i18n.Tr "home"}}</a> | |||
{{end}} | |||
{{template "custom/extra_links" .}} | |||
{{/* | |||
<div class="item"> | |||
<div class="ui icon input"> | |||
<input class="searchbox" type="text" placeholder="{{.i18n.Tr "search_project"}}"> | |||
<i class="search icon"></i> | |||
</div> | |||
</div> | |||
*/}} | |||
{{if .IsSigned}} | |||
<div class="right stackable menu"> | |||
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<input type="hidden" name="sort" value="{{$.SortType}}"> | |||
<button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||
</button> | |||
<!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||
</div> | |||
</form> | |||
<a href="{{AppSubUrl}}/notifications" class="item poping up" data-content='{{.i18n.Tr "notifications"}}' data-variation="tiny inverted"> | |||
<span class="text"> | |||
<span class="fitted">{{svg "octicon-bell" 16}}</span> | |||
<span class="sr-mobile-only">{{.i18n.Tr "notifications"}}</span> | |||
{{$notificationUnreadCount := 0}} | |||
{{if .NotificationUnreadCount}}{{$notificationUnreadCount = call .NotificationUnreadCount}}{{end}} | |||
<span class="ui red label {{if not $notificationUnreadCount}}hidden{{end}} notification_count"> | |||
{{$notificationUnreadCount}} | |||
</span> | |||
</span> | |||
</a> | |||
<div class="ui dropdown jump item poping up" data-content="{{.i18n.Tr "create_new"}}" data-variation="tiny inverted"> | |||
<span class="text"> | |||
<span class="fitted">{{svg "octicon-plus" 16}}</span> | |||
<span class="sr-mobile-only">{{.i18n.Tr "create_new"}}</span> | |||
<span class="fitted not-mobile">{{svg "octicon-triangle-down" 16}}</span> | |||
</span> | |||
<div class="menu"> | |||
<a class="item" href="{{AppSubUrl}}/repo/create"> | |||
<span class="fitted">{{svg "octicon-plus" 16}}</span> {{.i18n.Tr "new_repo"}} | |||
</a> | |||
<a class="item" href="{{AppSubUrl}}/repo/migrate"> | |||
<span class="fitted">{{svg "octicon-repo-clone" 16}}</span> {{.i18n.Tr "new_migrate"}} | |||
</a> | |||
{{if .SignedUser.CanCreateOrganization}} | |||
<a class="item" href="{{AppSubUrl}}/org/create"> | |||
<span class="fitted">{{svg "octicon-organization" 16}}</span> {{.i18n.Tr "new_org"}} | |||
</a> | |||
{{end}} | |||
</div><!-- end content create new menu --> | |||
</div><!-- end dropdown menu create new --> | |||
<div class="ui dropdown jump item poping up" tabindex="-1" data-content="{{.i18n.Tr "user_profile_and_more"}}" data-variation="tiny inverted"> | |||
<span class="text"> | |||
<img class="ui tiny avatar image" width="24" height="24" src="{{.SignedUser.RelAvatarLink}}"> | |||
<span class="sr-only">{{.i18n.Tr "user_profile_and_more"}}</span> | |||
<span class="mobile-only">{{.SignedUser.Name}}</span> | |||
<span class="fitted not-mobile" tabindex="-1">{{svg "octicon-triangle-down" 16}}</span> | |||
</span> | |||
<div class="menu user-menu" tabindex="-1"> | |||
<div class="ui header"> | |||
{{.i18n.Tr "signed_in_as"}} <strong>{{.SignedUser.Name}}</strong> | |||
</div> | |||
<div class="divider"></div> | |||
<a class="item" href="{{AppSubUrl}}/{{.SignedUser.Name}}"> | |||
{{svg "octicon-person" 16}} | |||
{{.i18n.Tr "your_profile"}}<!-- Your profile --> | |||
</a> | |||
<a class="item" href="{{AppSubUrl}}/{{.SignedUser.Name}}?tab=stars"> | |||
{{svg "octicon-star" 16}} | |||
{{.i18n.Tr "your_starred"}} | |||
</a> | |||
<a class="{{if .PageIsUserSettings}}active{{end}} item" href="{{AppSubUrl}}/user/settings"> | |||
{{svg "octicon-settings" 16}} | |||
{{.i18n.Tr "your_settings"}}<!-- Your settings --> | |||
</a> | |||
<!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io"> | |||
{{svg "octicon-question" 16}} | |||
{{.i18n.Tr "help"}}<!-- Help --> | |||
</a--> | |||
{{if .IsAdmin}} | |||
<div class="divider"></div> | |||
<a class="{{if .PageIsAdmin}}active{{end}} item" href="{{AppSubUrl}}/admin"> | |||
<i class="icon settings"></i> | |||
{{.i18n.Tr "admin_panel"}}<!-- Admin Panel --> | |||
</a> | |||
{{end}} | |||
<div class="divider"></div> | |||
<a class="item link-action" href data-url="{{AppSubUrl}}/user/logout" data-redirect="{{AppSubUrl}}/"> | |||
{{svg "octicon-sign-out" 16}} | |||
{{.i18n.Tr "sign_out"}}<!-- Sign Out --> | |||
</a> | |||
</div><!-- end content avatar menu --> | |||
</div><!-- end dropdown avatar menu --> | |||
</div><!-- end signed user right menu --> | |||
{{else}} | |||
<!--a class="item" target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io">{{.i18n.Tr "help"}}</a--> | |||
<div class="right stackable menu"> | |||
<form class="fourteen wide mobile ten wide tablet ten wide computer column ui form ignore-dirty" style="margin:auto" action="/explore/repos"> | |||
<div class="ui fluid action input" style="background:#363840 ;border-radius: 5px;width: 200px;height:30px;border: #888888 solid 1px;"> | |||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search_pro"}}..." | |||
style="transition: background-color 5000s ease-in-out 0s;-webkit-text-fill-color:#888888;background:#363840 ;color:#888888;border: none;outline: none;"> | |||
<input type="hidden" name="tab" value="{{$.TabName}}"> | |||
<input type="hidden" name="sort" value="{{$.SortType}}"> | |||
<button style="border: none;background-color: #363840;outline: none;border-radius:5px"><img type = "submit" style="width: 25px; height: 25px;margin: auto;" src="/img/search.svg" > | |||
</button> | |||
<!-- <button class="ui green button">{{.i18n.Tr "explore.search"}}</button> --> | |||
</div> | |||
</form> | |||
{{if .ShowRegistrationButton}} | |||
<a class="item{{if .PageIsSignUp}} active{{end}}" href="{{AppSubUrl}}/user/sign_up"> | |||
{{svg "octicon-person" 16}} {{.i18n.Tr "register"}} | |||
</a> | |||
{{end}} | |||
<a class="item{{if .PageIsSignIn}} active{{end}}" rel="nofollow" href="{{AppSubUrl}}/user/login"> | |||
{{svg "octicon-sign-in" 16}} {{.i18n.Tr "sign_in"}} | |||
</a> | |||
</div><!-- end anonymous right menu --> | |||
{{end}} | |||
</div> |
@@ -0,0 +1,208 @@ | |||
<!DOCTYPE html> | |||
<html lang="{{.Language}}"> | |||
<head data-suburl="{{AppSubUrl}}"> | |||
<meta charset="utf-8"> | |||
<meta name="viewport" content="width=device-width, initial-scale=1"> | |||
<meta http-equiv="x-ua-compatible" content="ie=edge"> | |||
<title>{{if .Title}}{{.Title}} - {{end}} {{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}}</title> | |||
<link rel="manifest" href="{{AppSubUrl}}/manifest.json" crossorigin="use-credentials"> | |||
{{if UseServiceWorker}} | |||
<script> | |||
if ('serviceWorker' in navigator) { | |||
navigator.serviceWorker.register('{{AppSubUrl}}/serviceworker.js').then(function(registration) { | |||
// Registration was successful | |||
console.info('ServiceWorker registration successful with scope: ', registration.scope); | |||
}, function(err) { | |||
// registration failed :( | |||
console.info('ServiceWorker registration failed: ', err); | |||
}); | |||
} | |||
</script> | |||
{{else}} | |||
<script> | |||
if ('serviceWorker' in navigator) { | |||
navigator.serviceWorker.getRegistrations().then(function(registrations) { | |||
registrations.forEach(function(registration) { | |||
registration.unregister(); | |||
console.info('ServiceWorker unregistered'); | |||
}); | |||
}); | |||
} | |||
</script> | |||
{{end}} | |||
<meta name="theme-color" content="{{ThemeColorMetaTag}}"> | |||
<meta name="author" content="{{if .Repository}}{{.Owner.Name}}{{else}}{{MetaAuthor}}{{end}}" /> | |||
<meta name="description" content="{{if .Repository}}{{.Repository.Name}}{{if .Repository.Description}} - {{.Repository.Description}}{{end}}{{else}}{{MetaDescription}}{{end}}" /> | |||
<meta name="keywords" content="{{MetaKeywords}}"> | |||
<meta name="referrer" content="no-referrer" /> | |||
<meta name="_csrf" content="{{.CsrfToken}}" /> | |||
{{if .IsSigned}} | |||
<meta name="_uid" content="{{.SignedUser.ID}}" /> | |||
{{end}} | |||
{{if .ContextUser}} | |||
<meta name="_context_uid" content="{{.ContextUser.ID}}" /> | |||
{{end}} | |||
{{if .SearchLimit}} | |||
<meta name="_search_limit" content="{{.SearchLimit}}" /> | |||
{{end}} | |||
{{if .GoGetImport}} | |||
<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}"> | |||
<meta name="go-source" content="{{.GoGetImport}} _ {{.GoDocDirectory}} {{.GoDocFile}}"> | |||
{{end}} | |||
<script> | |||
{{SafeJS `/* | |||
@licstart The following is the entire license notice for the | |||
JavaScript code in this page. | |||
Copyright (c) 2016 The Gitea Authors | |||
Copyright (c) 2015 The Gogs Authors | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is | |||
furnished to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in | |||
all copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
THE SOFTWARE. | |||
--- | |||
Licensing information for additional javascript libraries can be found at: | |||
{{StaticUrlPrefix}}/vendor/librejs.html | |||
@licend The above is the entire license notice | |||
for the JavaScript code in this page. | |||
*/`}} | |||
</script> | |||
<script> | |||
window.config = { | |||
AppSubUrl: '{{AppSubUrl}}', | |||
StaticUrlPrefix: '{{StaticUrlPrefix}}', | |||
csrf: '{{.CsrfToken}}', | |||
HighlightJS: {{if .RequireHighlightJS}}true{{else}}false{{end}}, | |||
Minicolors: {{if .RequireMinicolors}}true{{else}}false{{end}}, | |||
SimpleMDE: {{if .RequireSimpleMDE}}true{{else}}false{{end}}, | |||
Tribute: {{if .RequireTribute}}true{{else}}false{{end}}, | |||
U2F: {{if .RequireU2F}}true{{else}}false{{end}}, | |||
Heatmap: {{if .EnableHeatmap}}true{{else}}false{{end}}, | |||
heatmapUser: {{if .HeatmapUser}}'{{.HeatmapUser}}'{{else}}null{{end}}, | |||
NotificationSettings: { | |||
MinTimeout: {{NotificationSettings.MinTimeout}}, | |||
TimeoutStep: {{NotificationSettings.TimeoutStep}}, | |||
MaxTimeout: {{NotificationSettings.MaxTimeout}}, | |||
EventSourceUpdateTime: {{NotificationSettings.EventSourceUpdateTime}}, | |||
}, | |||
{{if .RequireTribute}} | |||
tributeValues: [ | |||
{{ range .Assignees }} | |||
{key: '{{.Name}} {{.FullName}}', value: '{{.Name}}', | |||
name: '{{.Name}}', fullname: '{{.FullName}}', avatar: '{{.RelAvatarLink}}'}, | |||
{{ end }} | |||
], | |||
{{end}} | |||
}; | |||
</script> | |||
<link rel="shortcut icon" href="{{StaticUrlPrefix}}/img/favicon.png"> | |||
<link rel="mask-icon" href="{{StaticUrlPrefix}}/img/openi-safari.svg" color="#609926"> | |||
<link rel="fluid-icon" href="{{StaticUrlPrefix}}/img/gitea-lg.png" title="{{AppName}}"> | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/assets/font-awesome/css/font-awesome.min.css"> | |||
<link rel="preload" as="font" href="{{StaticUrlPrefix}}/fomantic/themes/default/assets/fonts/icons.woff2" type="font/woff2" crossorigin="anonymous"> | |||
<link rel="preload" as="font" href="{{StaticUrlPrefix}}/fomantic/themes/default/assets/fonts/outline-icons.woff2" type="font/woff2" crossorigin="anonymous"> | |||
{{if .RequireSimpleMDE}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/simplemde/simplemde.min.css"> | |||
{{end}} | |||
{{if .RequireTribute}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/tribute/tribute.css"> | |||
{{end}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/fomantic/semantic.min.css?v={{MD5 AppVer}}"> | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/index.css?v={{MD5 AppVer}}"> | |||
<noscript> | |||
<style> | |||
.dropdown:hover > .menu { display: block; } | |||
.ui.secondary.menu .dropdown.item > .menu { margin-top: 0; } | |||
</style> | |||
</noscript> | |||
{{if .RequireMinicolors}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/vendor/plugins/jquery.minicolors/jquery.minicolors.css"> | |||
{{end}} | |||
<style class="list-search-style"></style> | |||
{{if .PageIsUserProfile}} | |||
<meta property="og:title" content="{{.Owner.Name}}" /> | |||
<meta property="og:type" content="profile" /> | |||
<meta property="og:image" content="{{.Owner.AvatarLink}}" /> | |||
<meta property="og:url" content="{{.Owner.HTMLURL}}" /> | |||
{{if .Owner.Description}} | |||
<meta property="og:description" content="{{.Owner.Description}}"> | |||
{{end}} | |||
{{else if .Repository}} | |||
{{if .Issue}} | |||
<meta property="og:title" content="{{.Issue.Title}}" /> | |||
<meta property="og:url" content="{{.Issue.HTMLURL}}" /> | |||
{{if .Issue.Content}} | |||
<meta property="og:description" content="{{.Issue.Content}}" /> | |||
{{end}} | |||
{{else}} | |||
<meta property="og:title" content="{{.Repository.Name}}" /> | |||
<meta property="og:url" content="{{.Repository.HTMLURL}}" /> | |||
{{if .Repository.Description}} | |||
<meta property="og:description" content="{{.Repository.Description}}" /> | |||
{{end}} | |||
{{end}} | |||
<meta property="og:type" content="object" /> | |||
<meta property="og:image" content="{{.Repository.Owner.AvatarLink}}" /> | |||
{{else}} | |||
<meta property="og:title" content="{{AppName}}"> | |||
<meta property="og:type" content="website" /> | |||
<meta property="og:image" content="{{StaticUrlPrefix}}/img/gitea-lg.png" /> | |||
<meta property="og:url" content="{{AppUrl}}" /> | |||
<meta property="og:description" content="{{MetaDescription}}"> | |||
{{end}} | |||
<meta property="og:site_name" content="{{AppName}}" /> | |||
{{if .IsSigned }} | |||
{{ if ne .SignedUser.Theme "gitea" }} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/theme-{{.SignedUser.Theme}}.css?v={{MD5 AppVer}}"> | |||
{{end}} | |||
{{else if ne DefaultTheme "gitea"}} | |||
<link rel="stylesheet" href="{{StaticUrlPrefix}}/css/theme-{{DefaultTheme}}.css?v={{MD5 AppVer}}"> | |||
{{end}} | |||
{{template "custom/header" .}} | |||
<script> | |||
var _hmt = _hmt || []; | |||
(function() { | |||
var hm = document.createElement("script"); | |||
hm.src = "https://hm.baidu.com/hm.js?46149a0b61fdeddfe427ff4de63794ba"; | |||
var s = document.getElementsByTagName("script")[0]; | |||
s.parentNode.insertBefore(hm, s); | |||
})(); | |||
</script> | |||
<script src="/self/func.js" type="text/javascript"></script> | |||
</head> | |||
<body> | |||
{{template "custom/body_outer_pre" .}} | |||
<div class="full height"> | |||
<noscript>{{.i18n.Tr "enable_javascript"}}</noscript> | |||
{{template "custom/body_inner_pre" .}} | |||
{{if not .PageIsInstall}} | |||
<div class="ui top secondary stackable main menu following bar dark"> | |||
{{template "base/head_navbar_pro" .}} | |||
</div><!-- end bar --> | |||
{{end}} | |||
{{/* | |||
</div> | |||
</body> | |||
</html> | |||
*/}} |
@@ -1,4 +1,4 @@ | |||
{{template "base/head" .}} | |||
{{template "base/head_pro" .}} | |||
<div class="explore repositories"> | |||
{{template "explore/repo_search" .}} | |||
@@ -134,7 +134,8 @@ | |||
{{if .Permission.CanRead $.UnitTypeDatasets}} | |||
<a class="{{if .PageIsDataset}}active{{end}} item" href="{{.RepoLink}}/datasets?type=0"> | |||
{{svg "octicon-inbox" 16}} {{.i18n.Tr "datasets"}} | |||
<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="M20.083 15.2l1.202.721a.5.5 0 0 1 0 .858l-8.77 5.262a1 1 0 0 1-1.03 0l-8.77-5.262a.5.5 0 0 1 0-.858l1.202-.721L12 20.05l8.083-4.85zm0-4.7l1.202.721a.5.5 0 0 1 0 .858L12 17.65l-9.285-5.571a.5.5 0 0 1 0-.858l1.202-.721L12 15.35l8.083-4.85zm-7.569-9.191l8.771 5.262a.5.5 0 0 1 0 .858L12 13 2.715 7.429a.5.5 0 0 1 0-.858l8.77-5.262a1 1 0 0 1 1.03 0zM12 3.332L5.887 7 12 10.668 18.113 7 12 3.332z"/></svg> | |||
{{.i18n.Tr "datasets"}} | |||
</a> | |||
{{end}} | |||
{{if .Permission.CanRead $.UnitTypeModelManage}} | |||
@@ -145,7 +146,11 @@ | |||
{{end}} | |||
{{if .Permission.CanRead $.UnitTypeCloudBrain}} | |||
<a class="{{if .PageIsCloudBrain}}active{{end}} item" href="{{.RepoLink}}/cloudbrain"> | |||
<span>{{svg "octicon-server" 16}} {{.i18n.Tr "repo.cloudbrain"}}<i class="question circle icon link cloudbrain-question" data-content={{.i18n.Tr "repo.cloudbrain_helper"}} data-position="top center" data-variation="mini"></i></span> | |||
<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"}} | |||
<i class="question circle icon link cloudbrain-question" data-content={{.i18n.Tr "repo.cloudbrain_helper"}} data-position="top center" data-variation="mini"></i> | |||
</span> | |||
</a> | |||
{{end}} | |||
<!-- {{if .IsSigned}} | |||
@@ -149,15 +149,6 @@ | |||
<label>{{.i18n.Tr "repo.settings.dataset_desc"}}</label> | |||
</div> | |||
</div> | |||
{{$isCloudBrainEnabled := .Repository.UnitEnabled $.UnitTypeCloudBrain }} | |||
<div class="inline field"> | |||
<label>{{.i18n.Tr "repo.cloudbrain"}}</label> | |||
<div class="ui checkbox"> | |||
<input class="enable-system" name="enable_cloud_brain" type="checkbox" {{if $isCloudBrainEnabled}}checked{{end}}> | |||
<label>{{.i18n.Tr "repo.settings.cloudbrain_desc"}}</label> | |||
</div> | |||
</div> | |||
{{$isModelMangeEnabled := .Repository.UnitEnabled $.UnitTypeModelManage }} | |||
<div class="inline field"> | |||
<label>{{.i18n.Tr "repo.model_manager"}}</label> | |||
@@ -166,6 +157,14 @@ | |||
<label>{{.i18n.Tr "repo.settings.model_desc"}}</label> | |||
</div> | |||
</div> | |||
{{$isCloudBrainEnabled := .Repository.UnitEnabled $.UnitTypeCloudBrain }} | |||
<div class="inline field"> | |||
<label>{{.i18n.Tr "repo.cloudbrain"}}</label> | |||
<div class="ui checkbox"> | |||
<input class="enable-system" name="enable_cloud_brain" type="checkbox" {{if $isCloudBrainEnabled}}checked{{end}}> | |||
<label>{{.i18n.Tr "repo.settings.cloudbrain_desc"}}</label> | |||
</div> | |||
</div> | |||
{{$isWikiEnabled := or (.Repository.UnitEnabled $.UnitTypeWiki) (.Repository.UnitEnabled $.UnitTypeExternalWiki)}} | |||
<div class="inline field"> | |||
<label>{{.i18n.Tr "repo.wiki"}}</label> | |||
@@ -50,16 +50,46 @@ | |||
{{end}} | |||
<li>{{svg "octicon-clock" 16}} {{.i18n.Tr "user.join_on"}} {{.Owner.CreatedUnix.FormatShort}}</li> | |||
{{if and .Orgs .HasOrgsVisible}} | |||
<li> | |||
<ul class="user-orgs"> | |||
<li style="border-bottom: none;padding-bottom: 0;"><div style="border-bottom: 1px solid #eaeaea;padding-top: 5px;padding-bottom:5px"> <b> 组织</b></div></li> | |||
<li style="padding-bottom: 0px;"> | |||
<!-- <ul class="user-orgs"> | |||
{{range .Orgs}} | |||
{{if (or .Visibility.IsPublic (and ($.SignedUser) (or .Visibility.IsLimited (and (.IsUserPartOfOrg $.SignedUserID) .Visibility.IsPrivate) ($.IsAdmin))))}} | |||
<li> | |||
<a href="{{.HomeLink}}"><img class="ui image poping up" src="{{.RelAvatarLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a> | |||
<ul> | |||
<a href="{{.HomeLink}}"><img class="ui image poping up" src="{{.RelAvatarLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a> | |||
<span>{{.Name}}</span> | |||
</ul> | |||
</li> | |||
{{end}} | |||
{{end}} | |||
</ul> | |||
</ul> --> | |||
{{range .Orgs}} | |||
<ul class="user-orgs"> | |||
{{if (or .Visibility.IsPublic (and ($.SignedUser) (or .Visibility.IsLimited (and (.IsUserPartOfOrg $.SignedUserID) .Visibility.IsPrivate) ($.IsAdmin))))}} | |||
<li class="infor" style="width: 15%;" > | |||
<a href="{{.HomeLink}}"><img class="ui image poping up" src="{{.RelAvatarLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted"></a> | |||
</li> | |||
<li class="infor" style="width: 35%;"> | |||
<a class="ui image poping up" style="color: #0366D6;overflow: hidden; white-space: nowrap; text-overflow: ellipsis;" href="{{.HomeLink}}" data-content="{{.Name}}" data-position="top center" data-variation="tiny inverted">{{.Name}}</a> | |||
</li> | |||
<li class="infor" style="width: 25%;"> | |||
<img style="width: 14px; height: 14px;border: none;" src="/img/member.svg" > | |||
<span style="color: rgba(0,0,0,.4);padding-left: 5px;">{{.NumMembers}}</span> | |||
</li> | |||
<li class="infor" style="width: 25%;"> | |||
<img style="width: 14px; height: 14px" src="/img/pro_num.svg" > | |||
<span style="color: rgba(0,0,0,.4);padding-left: 5px;">{{.NumRepos}}</span> | |||
</li> | |||
{{end}} | |||
</ul> | |||
{{end}} | |||
</li> | |||
{{end}} | |||
{{if and .IsSigned (ne .SignedUserName .Owner.Name)}} | |||
@@ -79,13 +109,6 @@ | |||
{{end}} | |||
</ul> | |||
</div> | |||
<div > | |||
<ul> | |||
<li> | |||
<ul></ul><ul></ul> | |||
</li> | |||
</ul> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="ui eleven wide column"> | |||
@@ -155,3 +178,22 @@ | |||
</div> | |||
</div> | |||
{{template "base/footer" .}} | |||
<style> | |||
.infor{ | |||
margin: auto 0; | |||
} | |||
.user-orgs{ | |||
padding: 10px 0px; | |||
} | |||
.user-orgs li{ | |||
max-width: 50%; | |||
float: right; | |||
} | |||
.user.profile .ui.card .extra.content ul { | |||
padding: 5px 0; | |||
} | |||
</style> |
@@ -518,4 +518,10 @@ display: block; | |||
} | |||
.letf2{ | |||
margin-left: -2px; | |||
} | |||
} | |||
.edge{ | |||
margin-left:0 !important; | |||
margin-right: 0 !important; | |||
padding-left:0 !important; | |||
padding-right:0 !important; | |||
} |