Reviewed-on: https://git.openi.org.cn/OpenI/aiforge/pulls/2019 Reviewed-by: zhoupzh <zhoupzh@pcl.ac.cn> Reviewed-by: lewis <747342561@qq.com>pull/2042/head
@@ -775,6 +775,41 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) { | |||
return sess.Commit() | |||
} | |||
// ChangeRef changes issue ref, as the given user. | |||
func (issue *Issue) ChangeRef(doer *User, newRef string) (err error) { | |||
oldRef := issue.Ref | |||
issue.Ref = newRef | |||
if oldRef == newRef { | |||
return nil | |||
} | |||
sess := x.NewSession() | |||
defer sess.Close() | |||
if err = sess.Begin(); err != nil { | |||
return err | |||
} | |||
if err = updateIssueCols(sess, issue, "ref"); err != nil { | |||
sess.Rollback() | |||
return fmt.Errorf("UpdateIssueCols: %v", err) | |||
} | |||
var opts = &CreateCommentOptions{ | |||
Type: CommentTypeRef, | |||
Doer: doer, | |||
Repo: issue.Repo, | |||
Issue: issue, | |||
OldRef: oldRef, | |||
NewRef: newRef, | |||
} | |||
if _, err = createComment(sess, opts); err != nil { | |||
sess.Rollback() | |||
return err | |||
} | |||
return sess.Commit() | |||
} | |||
// GetTasks returns the amount of tasks in the issues content | |||
func (issue *Issue) GetTasks() int { | |||
return len(issueTasksPat.FindAllStringIndex(issue.Content, -1)) | |||
@@ -90,6 +90,8 @@ const ( | |||
CommentTypeReviewRequest | |||
// merge pull request | |||
CommentTypeMergePull | |||
// Ref changed | |||
CommentTypeRef | |||
) | |||
// CommentTag defines comment tag type | |||
@@ -40,6 +40,14 @@ import ( | |||
"github.com/editorconfig/editorconfig-core-go/v2" | |||
) | |||
const ( | |||
REF_HEADS_PREFIX = "refs/heads/" | |||
REF_TAGS_PREFIX = "refs/tags/" | |||
REF_TYPE_BRANCH = "branch" | |||
REF_TYPE_TAG = "tag" | |||
REF_TYPE_PATTERN = "(refs/heads/|refs/tags/)" | |||
) | |||
// Used from static.go && dynamic.go | |||
var mailSubjectSplit = regexp.MustCompile(`(?m)^-{3,}[\s]*$`) | |||
@@ -317,6 +325,8 @@ func NewFuncMap() []template.FuncMap { | |||
"DatasetPathJoin": func(arr []string, index int, seq string) string { | |||
return strings.Join(arr[1:index+1], seq) | |||
}, | |||
"GetRefType": GetRefType, | |||
"GetRefName": GetRefName, | |||
}} | |||
} | |||
@@ -444,10 +454,12 @@ func SafeJS(raw string) template.JS { | |||
func Str2html(raw string) template.HTML { | |||
return template.HTML(markup.Sanitize(raw)) | |||
} | |||
// | |||
func subOne(length int)int{ | |||
return length-1 | |||
func subOne(length int) int { | |||
return length - 1 | |||
} | |||
// Escape escapes a HTML string | |||
func Escape(raw string) string { | |||
return html.EscapeString(raw) | |||
@@ -758,3 +770,18 @@ func licenses() []string { | |||
func tasks() []string { | |||
return []string{"machine_translation", "question_answering_system", "information_retrieval", "knowledge_graph", "text_annotation", "text_categorization", "emotion_analysis", "language_modeling", "speech_recognition", "automatic_digest", "information_extraction", "description_generation", "image_classification", "face_recognition", "image_search", "target_detection", "image_description_generation", "vehicle_license_plate_recognition", "medical_image_analysis", "unmanned", "unmanned_security", "drone", "vr_ar", "2_d_vision", "2.5_d_vision", "3_d_reconstruction", "image_processing", "video_processing", "visual_input_system", "speech_coding", "speech_enhancement", "speech_synthesis"} | |||
} | |||
func GetRefType(ref string) string { | |||
if strings.HasPrefix(ref, REF_HEADS_PREFIX) { | |||
return REF_TYPE_BRANCH | |||
} | |||
if strings.HasPrefix(ref, REF_TAGS_PREFIX) { | |||
return REF_TYPE_TAG | |||
} | |||
return "" | |||
} | |||
func GetRefName(ref string) string { | |||
reg := regexp.MustCompile(REF_TYPE_PATTERN) | |||
return reg.ReplaceAllString(ref, "") | |||
} |
@@ -1332,6 +1332,7 @@ issues.new.labels = Labels | |||
issues.new.add_labels_title = Apply labels | |||
issues.new.no_label = No Label | |||
issues.new.clear_labels = Clear labels | |||
issues.new.clear_branch_tag = Clear branch or tag | |||
issues.new.no_items = No items | |||
issues.new.milestone = Milestone | |||
issues.new.add_milestone_title = Set milestone | |||
@@ -1361,6 +1362,13 @@ issues.remove_label_at = removed the <div class="ui label" style="color: %s\; ba | |||
issues.add_milestone_at = `added this to the <b>%s</b> milestone %s` | |||
issues.change_milestone_at = `modified the milestone from <b>%s</b> to <b>%s</b> %s` | |||
issues.remove_milestone_at = `removed this from the <b>%s</b> milestone %s` | |||
issues.add_branch_at=`added this to the <b>%s</b> branch %s` | |||
issues.add_tag_at =`added this to the <b>%s</b> tag %s` | |||
issues.change_branch_tag_at= `modified the branch/tag from <b>%s</b> to <b>%s</b> %s` | |||
issues.remove_branch_at=`removed this from the <b>%s</b> branch %s` | |||
issues.remove_tag_at=`removed this from the <b>%s</b> tag %s` | |||
issues.deleted_milestone = `(deleted)` | |||
issues.self_assign_at = `self-assigned this %s` | |||
issues.add_assignee_at = `was assigned by <b>%s</b> %s` | |||
@@ -1344,6 +1344,7 @@ issues.new.labels=标签 | |||
issues.new.add_labels_title=添加标签 | |||
issues.new.no_label=未选择标签 | |||
issues.new.clear_labels=清除选中标签 | |||
issues.new.clear_branch_tag=清除选中分支/标签 | |||
issues.new.no_items=无可选项 | |||
issues.new.milestone=里程碑 | |||
issues.new.add_milestone_title=设置里程碑 | |||
@@ -1373,6 +1374,13 @@ issues.remove_label_at=删除了 <div class="ui label" style="color: %s\; backgr | |||
issues.add_milestone_at=` %[2]s 添加了里程碑 <b>%[1]s</b>` | |||
issues.change_milestone_at=`%[3]s 修改了里程碑从 <b>%[1]s</b> 到 <b>%[2]s</b>` | |||
issues.remove_milestone_at=`%[2]s 删除了里程碑 <b>%[1]s</b>` | |||
issues.add_branch_at=` %[2]s 添加了分支 <b>%[1]s</b>` | |||
issues.add_tag_at =` %[2]s 添加了标签 <b>%[1]s</b>` | |||
issues.change_branch_tag_at=`%[3]s 修改了标签/分支从 <b>%[1]s</b> 到 <b>%[2]s</b>` | |||
issues.remove_branch_at=`%[2]s 删除了分支 <b>%[1]s</b>` | |||
issues.remove_tag_at=`%[2]s 删除了标签 <b>%[1]s</b>` | |||
issues.deleted_milestone= (已删除) | |||
issues.self_assign_at=`于 %s 指派给自己` | |||
issues.add_assignee_at=`于 %[2]s 被 <b>%[1]s</b> 指派` | |||
@@ -432,7 +432,7 @@ func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository, isPull boo | |||
return nil | |||
} | |||
brs, _, err := ctx.Repo.GitRepo.GetBranches(0,0) | |||
brs, _, err := ctx.Repo.GitRepo.GetBranches(0, 0) | |||
if err != nil { | |||
ctx.ServerError("GetBranches", err) | |||
return nil | |||
@@ -1302,6 +1302,35 @@ func UpdateIssueContent(ctx *context.Context) { | |||
}) | |||
} | |||
// UpdateIssueRef change issue's code reference | |||
func UpdateIssueRef(ctx *context.Context) { | |||
issues := getActionIssues(ctx) | |||
if ctx.Written() { | |||
return | |||
} | |||
issue := issues[0] | |||
if issue == nil { | |||
log.Error("UpdateIssueRef param error ") | |||
return | |||
} | |||
if !ctx.IsSigned || (ctx.User.ID != issue.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)) { | |||
ctx.Error(403) | |||
return | |||
} | |||
ref := ctx.Query("id") | |||
if err := issue_service.ChangeRef(issue, ctx.User, ref); err != nil { | |||
ctx.ServerError("ChangeRef", err) | |||
return | |||
} | |||
ctx.JSON(200, map[string]interface{}{ | |||
"ref": issue.Ref, | |||
}) | |||
} | |||
// UpdateIssueMilestone change issue's milestone | |||
func UpdateIssueMilestone(ctx *context.Context) { | |||
issues := getActionIssues(ctx) | |||
@@ -892,6 +892,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
m.Post("/labels", reqRepoIssuesOrPullsWriter, repo.UpdateIssueLabel) | |||
m.Post("/milestone", reqRepoIssuesOrPullsWriter, repo.UpdateIssueMilestone) | |||
m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee) | |||
m.Post("/ref", reqRepoIssuesOrPullsWriter, repo.UpdateIssueRef) | |||
m.Post("/request_review", reqRepoIssuesOrPullsReader, repo.UpdatePullReviewRequest) | |||
m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus) | |||
m.Post("/resolve_conversation", reqRepoIssuesOrPullsReader, repo.UpdateResolveConversation) | |||
@@ -21,3 +21,12 @@ func ChangeContent(issue *models.Issue, doer *models.User, content string) (err | |||
return nil | |||
} | |||
// ChangeRef changes issue ref, as the given user. | |||
func ChangeRef(issue *models.Issue, doer *models.User, ref string) (err error) { | |||
if err := issue.ChangeRef(doer, ref); err != nil { | |||
return err | |||
} | |||
return nil | |||
} |
@@ -14,12 +14,12 @@ | |||
<div class="ui grid"> | |||
<div class="two column row"> | |||
<a class="reference column" href="#" data-target="#branch-list"> | |||
<span class="text black"> | |||
<span class="text "> | |||
{{svg "octicon-git-branch" 16}} {{.i18n.Tr "repo.branches"}} | |||
</span> | |||
</a> | |||
<a class="reference column" href="#" data-target="#tag-list"> | |||
<span class="text"> | |||
<span class="text black"> | |||
<i class="reference tags icon"></i> {{.i18n.Tr "repo.tags"}} | |||
</span> | |||
</a> | |||
@@ -594,5 +594,40 @@ | |||
{{end}} | |||
</span> | |||
</div> | |||
{{else if eq .Type 29}} | |||
<div class="timeline-item event" id="{{.HashTag}}"> | |||
<span class="badge">{{svg "octicon-git-branch" 16}}</span> | |||
<a class="ui avatar image" href="{{.Poster.HomeLink}}"> | |||
<img src="{{.Poster.RelAvatarLink}}"> | |||
</a> | |||
<span class="text grey"> | |||
<a class="author" href="{{.Poster.HomeLink}}">{{.Poster.GetDisplayName}}</a> | |||
{{ $refOldName:= GetRefName .OldRef }} | |||
{{ $refNewName:= GetRefName .NewRef }} | |||
{{if .OldRef }} | |||
{{if .NewRef }} | |||
{{$.i18n.Tr "repo.issues.change_branch_tag_at" ($refOldName|Escape) ($refNewName|Escape) $createdStr | Safe}} | |||
{{else}} | |||
{{ $getRefOldType:= GetRefType .OldRef }} | |||
{{ if eq $getRefOldType "branch"}} | |||
{{$.i18n.Tr "repo.issues.remove_branch_at" ($refOldName|Escape) $createdStr | Safe}} | |||
{{else}} | |||
{{$.i18n.Tr "repo.issues.remove_tag_at" ($refOldName|Escape) $createdStr | Safe}} | |||
{{end}} | |||
{{end}} | |||
{{else}} | |||
{{if .NewRef}} | |||
{{ $getRefNewType:= GetRefType .NewRef }} | |||
{{ if eq $getRefNewType "branch"}} | |||
{{$.i18n.Tr "repo.issues.add_branch_at" ($refNewName|Escape) $createdStr | Safe}} | |||
{{else}} | |||
{{$.i18n.Tr "repo.issues.add_tag_at" ($refNewName|Escape) $createdStr | Safe}} | |||
{{end}} | |||
{{end}} | |||
{{end}} | |||
</span> | |||
</div> | |||
{{end}} | |||
{{end}} |
@@ -1,6 +1,52 @@ | |||
<div class="four wide column"> | |||
<div class="ui segment metas"> | |||
{{template "repo/issue/branch_selector_field" .}} | |||
<!-- {{template "repo/issue/branch_selector_field" .}} --> | |||
{{if and (not .Issue.IsPull) (not .PageIsComparePull)}} | |||
<input id="ref_selector" name="ref" type="hidden" value="{{.Issue.Ref}}"> | |||
<div class="ui {{if or (not .HasIssuesOrPullsWritePermission) .Repository.IsArchived}}disabled{{end}} floating filter select-branch dropdown" data-no-results="{{.i18n.Tr "repo.pulls.no_results"}}"> | |||
<div class="ui basic small button"> | |||
<span class="text branch-name">{{if .Issue.Ref}}{{$.RefEndName}}{{else}}{{.i18n.Tr "repo.issues.no_ref"}}{{end}}</span> | |||
<i class="dropdown icon"></i> | |||
</div> | |||
<div class="menu" data-action="update" data-issue-id="{{$.Issue.ID}}" data-update-url="{{$.RepoLink}}/issues/ref"> | |||
<div class="ui icon search input"> | |||
<i class="filter icon"></i> | |||
<input name="search" placeholder="{{.i18n.Tr "repo.filter_branch_and_tag"}}..."> | |||
</div> | |||
<div class="no-select item">{{.i18n.Tr "repo.issues.new.clear_branch_tag"}}</div> | |||
<div class="header"> | |||
<div class="ui grid"> | |||
<div class="two column row"> | |||
<a class="reference column" href="#" data-target="#branch-list"> | |||
<span class="text"> | |||
{{svg "octicon-git-branch" 16}} {{.i18n.Tr "repo.branches"}} | |||
</span> | |||
</a> | |||
<a class="reference column" href="#" data-target="#tag-list"> | |||
<span class="text black"> | |||
<i class="reference tags icon"></i> {{.i18n.Tr "repo.tags"}} | |||
</span> | |||
</a> | |||
</div> | |||
</div> | |||
</div> | |||
<div id="branch-list" class="scrolling menu reference-list-menu"> | |||
{{range .Branches}} | |||
<div class="item" data-id="refs/heads/{{.}}" data-name="{{.}}" data-id-selector="#ref_selector">{{.}}</div> | |||
{{end}} | |||
</div> | |||
<div id="tag-list" class="scrolling menu reference-list-menu" style="display: none"> | |||
{{range .Tags}} | |||
<div class="item" data-id="refs/tags/{{.}}" data-name="tags/{{.}}" data-id-selector="#ref_selector">{{.}}</div> | |||
{{end}} | |||
</div> | |||
</div> | |||
</div> | |||
<div class="ui divider"></div> | |||
{{end}} | |||
{{if .Issue.IsPull }} | |||
@@ -600,3 +646,4 @@ | |||
</div> | |||
{{end}} | |||
{{end}} | |||
@@ -183,11 +183,11 @@ function initBranchSelector() { | |||
}); | |||
$selectBranch.find('.reference.column').on('click', function () { | |||
$selectBranch.find('.scrolling.reference-list-menu').css('display', 'none'); | |||
$selectBranch.find('.reference .text').removeClass('black'); | |||
$selectBranch.find('.reference .text').addClass('black'); | |||
$($(this).data('target')).css('display', 'block'); | |||
$(this) | |||
.find('.text') | |||
.addClass('black'); | |||
.find('.text.black') | |||
.removeClass('black'); | |||
return false; | |||
}); | |||
} | |||
@@ -230,7 +230,7 @@ function initLabelEdit() { | |||
}); | |||
} | |||
function updateIssuesMeta(url, action, issueIds, elementId, isAdd) { | |||
function updateIssuesMeta(url, action, issueIds, elementId,isAdd) { | |||
return new Promise((resolve) => { | |||
$.ajax({ | |||
type: 'POST', | |||
@@ -240,13 +240,14 @@ function updateIssuesMeta(url, action, issueIds, elementId, isAdd) { | |||
action, | |||
issue_ids: issueIds, | |||
id: elementId, | |||
is_add: isAdd | |||
is_add: isAdd, | |||
}, | |||
success: resolve | |||
}); | |||
}); | |||
} | |||
function initRepoStatusChecker() { | |||
const migrating = $('#repo_migrating'); | |||
$('#repo_migrating_failed').hide(); | |||
@@ -486,12 +487,13 @@ function initCommentForm() { | |||
const promises = []; | |||
Object.keys(labels).forEach((elementId) => { | |||
const label = labels[elementId]; | |||
console.log("label:",label) | |||
const promise = updateIssuesMeta( | |||
label['update-url'], | |||
label.action, | |||
label['issue-id'], | |||
elementId, | |||
label['is-checked'] | |||
label['is-checked'], | |||
); | |||
promises.push(promise); | |||
}); | |||
@@ -531,7 +533,7 @@ function initCommentForm() { | |||
'', | |||
$listMenu.data('issue-id'), | |||
$(this).data('id'), | |||
$(this).data('is-checked') | |||
$(this).data('is-checked'), | |||
); | |||
$listMenu.data('action', 'update'); // Update to reload the page when we updated items | |||
return false; | |||
@@ -603,6 +605,7 @@ function initCommentForm() { | |||
$listMenu.data('issue-id'), | |||
'', | |||
'' | |||
).then(reload); | |||
} | |||
@@ -636,10 +639,16 @@ function initCommentForm() { | |||
initListSubmits('select-reviewers-modify', 'assignees'); | |||
function selectItem(select_id, input_id) { | |||
const $menu = $(`${select_id} .menu`); | |||
let $menu; | |||
if (select_id=='.select-branch'){ | |||
$menu = $(`${select_id} .menu`).eq(1); | |||
}else{ | |||
$menu = $(`${select_id} .menu`); | |||
} | |||
const $list = $(`.ui${select_id}.list`); | |||
const hasUpdateAction = $menu.data('action') === 'update'; | |||
$menu.find('.item:not(.no-select)').on('click', function () { | |||
$(this) | |||
.parent() | |||
@@ -650,12 +659,17 @@ function initCommentForm() { | |||
$(this).addClass('selected active'); | |||
if (hasUpdateAction) { | |||
//let ref = '' | |||
//if (select_id=='.select-branch'){ | |||
// ref = $(this).data('name'); | |||
// } | |||
updateIssuesMeta( | |||
$menu.data('update-url'), | |||
'', | |||
$menu.data('issue-id'), | |||
$(this).data('id'), | |||
$(this).data('is-checked') | |||
$(this).data('is-checked'), | |||
).then(reload); | |||
} | |||
switch (input_id) { | |||
@@ -708,6 +722,7 @@ function initCommentForm() { | |||
// Milestone and assignee | |||
selectItem('.select-milestone', '#milestone_id'); | |||
selectItem('.select-assignee', '#assignee_id'); | |||
selectItem('.select-branch', ''); | |||
} | |||
function initInstall() { | |||
@@ -810,7 +825,7 @@ function initIssueComments() { | |||
const issueId = $(this).data('issue-id'); | |||
const id = $(this).data('id'); | |||
const isChecked = $(this).data('is-checked'); | |||
//const ref = $(this).data('name'); | |||
event.preventDefault(); | |||
updateIssuesMeta(url, '', issueId, id, isChecked).then(reload); | |||
}); | |||
@@ -2899,6 +2914,7 @@ $(document).ready(async () => { | |||
}) | |||
.get() | |||
.join(); | |||
console.log("this:",this) | |||
const {url} = this.dataset; | |||
if (elementId === '0' && url.substr(-9) === '/assignee') { | |||
elementId = ''; | |||