Add 'Alt + click' feature to exclude labels (#8199)
Add 'Alt + click' and 'Alt +enter' feature to exclude particular labels on searching for issues.
This commit is contained in:
		
							parent
							
								
									637e3219ab
								
							
						
					
					
						commit
						dbd9d8dd54
					
				
					 7 changed files with 67 additions and 7 deletions
				
			
		|  | @ -1248,8 +1248,12 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) { | |||
| 
 | ||||
| 	if opts.LabelIDs != nil { | ||||
| 		for i, labelID := range opts.LabelIDs { | ||||
| 			sess.Join("INNER", fmt.Sprintf("issue_label il%d", i), | ||||
| 				fmt.Sprintf("issue.id = il%[1]d.issue_id AND il%[1]d.label_id = %[2]d", i, labelID)) | ||||
| 			if labelID > 0 { | ||||
| 				sess.Join("INNER", fmt.Sprintf("issue_label il%d", i), | ||||
| 					fmt.Sprintf("issue.id = il%[1]d.issue_id AND il%[1]d.label_id = %[2]d", i, labelID)) | ||||
| 			} else { | ||||
| 				sess.Where("issue.id not in (select issue_id from issue_label where label_id = ?)", -labelID) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -72,6 +72,7 @@ type Label struct { | |||
| 	IsChecked       bool   `xorm:"-"` | ||||
| 	QueryString     string `xorm:"-"` | ||||
| 	IsSelected      bool   `xorm:"-"` | ||||
| 	IsExcluded      bool   `xorm:"-"` | ||||
| } | ||||
| 
 | ||||
| // APIFormat converts a Label to the api.Label format
 | ||||
|  | @ -97,7 +98,10 @@ func (label *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64) | |||
| 	for _, s := range currentSelectedLabels { | ||||
| 		if s == label.ID { | ||||
| 			labelSelected = true | ||||
| 		} else if s > 0 { | ||||
| 		} else if -s == label.ID { | ||||
| 			labelSelected = true | ||||
| 			label.IsExcluded = true | ||||
| 		} else if s != 0 { | ||||
| 			labelQuerySlice = append(labelQuerySlice, strconv.FormatInt(s, 10)) | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
|  | @ -802,6 +802,7 @@ issues.delete_branch_at = `deleted branch <b>%s</b> %s` | |||
| issues.open_tab = %d Open | ||||
| issues.close_tab = %d Closed | ||||
| issues.filter_label = Label | ||||
| issues.filter_label_exclude = `Use <code>alt</code> + <code>click/enter</code> to exclude labels` | ||||
| issues.filter_label_no_select = All labels | ||||
| issues.filter_milestone = Milestone | ||||
| issues.filter_milestone_no_select = All milestones | ||||
|  |  | |||
|  | @ -458,6 +458,8 @@ i.icon.centerlock{top:1.5em} | |||
| .repository .filter.menu .label.color{border-radius:3px;margin-left:15px;padding:0 8px} | ||||
| .repository .filter.menu .octicon{float:left;margin:5px -7px 0 -5px;width:16px} | ||||
| .repository .filter.menu.labels .octicon{margin:-2px -7px 0 -5px} | ||||
| .repository .filter.menu.labels .label-filter .menu .info{display:inline-block;padding:9px 7px 7px 7px;text-align:center;border-bottom:1px solid #ccc;font-size:12px} | ||||
| .repository .filter.menu.labels .label-filter .menu .info code{border:1px solid #ccc;border-radius:3px;padding:3px 2px 1px 2px;font-size:11px} | ||||
| .repository .filter.menu .text{margin-left:.9em} | ||||
| .repository .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important} | ||||
| .repository .filter.menu .dropdown.item{margin:1px;padding-right:0} | ||||
|  |  | |||
|  | @ -3278,8 +3278,39 @@ function initIssueList() { | |||
|             }, | ||||
| 
 | ||||
|             fullTextSearch: true | ||||
|         }) | ||||
|     ; | ||||
|         }); | ||||
| 
 | ||||
|     $(".menu a.label-filter-item").each(function() { | ||||
|         $(this).click(function(e) { | ||||
|             if (e.altKey) { | ||||
|                 const href = $(this).attr("href"); | ||||
|                 const id = $(this).data("label-id"); | ||||
| 
 | ||||
|                 const regStr = "labels=(-?[0-9]+%2c)*(" + id + ")(%2c-?[0-9]+)*&"; | ||||
|                 const newStr = "labels=$1-$2$3&"; | ||||
| 
 | ||||
|                 window.location = href.replace(new RegExp(regStr), newStr); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| 
 | ||||
|     $(".menu .ui.dropdown.label-filter").keydown(function(e) { | ||||
|         if (e.altKey && e.keyCode == 13) { | ||||
|             const selectedItems = $(".menu .ui.dropdown.label-filter .menu .item.selected"); | ||||
| 
 | ||||
|             if (selectedItems.length > 0) { | ||||
|                 const item = $(selectedItems[0]); | ||||
| 
 | ||||
|                 const href = item.attr("href"); | ||||
|                 const id = item.data("label-id"); | ||||
| 
 | ||||
|                 const regStr = "labels=(-?[0-9]+%2c)*(" + id + ")(%2c-?[0-9]+)*&"; | ||||
|                 const newStr = "labels=$1-$2$3&"; | ||||
| 
 | ||||
|                 window.location = href.replace(new RegExp(regStr), newStr); | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| function cancelCodeComment(btn) { | ||||
|     const form = $(btn).closest("form"); | ||||
|  |  | |||
|  | @ -158,6 +158,23 @@ | |||
|             margin: -2px -7px 0 -5px; | ||||
|         } | ||||
| 
 | ||||
|         &.labels { | ||||
|             .label-filter .menu .info { | ||||
|                 display: inline-block; | ||||
|                 padding: 9px 7px 7px 7px; | ||||
|                 text-align: center; | ||||
|                 border-bottom: 1px solid #cccccc; | ||||
|                 font-size: 12px; | ||||
| 
 | ||||
|                 code { | ||||
|                     border: 1px solid #cccccc; | ||||
|                     border-radius: 3px; | ||||
|                     padding: 3px 2px 1px 2px; | ||||
|                     font-size: 11px; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         .text { | ||||
|             margin-left: 0.9em; | ||||
|         } | ||||
|  |  | |||
|  | @ -42,15 +42,16 @@ | |||
| 			<div class="ten wide right aligned column"> | ||||
| 				<div class="ui secondary filter stackable menu labels"> | ||||
| 					<!-- Label --> | ||||
| 					<div class="ui {{if not .Labels}}disabled{{end}} dropdown jump item" style="margin-left: auto"> | ||||
| 					<div class="ui {{if not .Labels}}disabled{{end}} dropdown jump item label-filter" style="margin-left: auto"> | ||||
| 						<span class="text"> | ||||
| 							{{.i18n.Tr "repo.issues.filter_label"}} | ||||
| 							<i class="dropdown icon"></i> | ||||
| 						</span> | ||||
| 						<div class="menu"> | ||||
| 							<span class="info">{{.i18n.Tr "repo.issues.filter_label_exclude" | Safe}}</span> | ||||
| 							<a class="item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}">{{.i18n.Tr "repo.issues.filter_label_no_select"}}</a> | ||||
| 							{{range .Labels}} | ||||
| 								<a class="item has-emoji" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}"><span class="octicon {{if .IsSelected}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a> | ||||
| 								<a class="item has-emoji label-filter-item" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&sort={{$.SortType}}&state={{$.State}}&labels={{.QueryString}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}" data-label-id="{{.ID}}"><span class="octicon {{if .IsExcluded}}octicon-circle-slash{{else if .IsSelected}}octicon-check{{end}}"></span><span class="label color" style="background-color: {{.Color}}"></span> {{.Name}}</a> | ||||
| 							{{end}} | ||||
| 						</div> | ||||
| 					</div> | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue