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 {
 | 
						if opts.LabelIDs != nil {
 | 
				
			||||||
		for i, labelID := range opts.LabelIDs {
 | 
							for i, labelID := range opts.LabelIDs {
 | 
				
			||||||
			sess.Join("INNER", fmt.Sprintf("issue_label il%d", i),
 | 
								if labelID > 0 {
 | 
				
			||||||
				fmt.Sprintf("issue.id = il%[1]d.issue_id AND il%[1]d.label_id = %[2]d", i, labelID))
 | 
									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:"-"`
 | 
						IsChecked       bool   `xorm:"-"`
 | 
				
			||||||
	QueryString     string `xorm:"-"`
 | 
						QueryString     string `xorm:"-"`
 | 
				
			||||||
	IsSelected      bool   `xorm:"-"`
 | 
						IsSelected      bool   `xorm:"-"`
 | 
				
			||||||
 | 
						IsExcluded      bool   `xorm:"-"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// APIFormat converts a Label to the api.Label format
 | 
					// APIFormat converts a Label to the api.Label format
 | 
				
			||||||
| 
						 | 
					@ -97,7 +98,10 @@ func (label *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64)
 | 
				
			||||||
	for _, s := range currentSelectedLabels {
 | 
						for _, s := range currentSelectedLabels {
 | 
				
			||||||
		if s == label.ID {
 | 
							if s == label.ID {
 | 
				
			||||||
			labelSelected = true
 | 
								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))
 | 
								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.open_tab = %d Open
 | 
				
			||||||
issues.close_tab = %d Closed
 | 
					issues.close_tab = %d Closed
 | 
				
			||||||
issues.filter_label = Label
 | 
					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_label_no_select = All labels
 | 
				
			||||||
issues.filter_milestone = Milestone
 | 
					issues.filter_milestone = Milestone
 | 
				
			||||||
issues.filter_milestone_no_select = All milestones
 | 
					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 .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 .octicon{float:left;margin:5px -7px 0 -5px;width:16px}
 | 
				
			||||||
.repository .filter.menu.labels .octicon{margin:-2px -7px 0 -5px}
 | 
					.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 .text{margin-left:.9em}
 | 
				
			||||||
.repository .filter.menu .menu{max-height:300px;overflow-x:auto;right:0!important;left:auto!important}
 | 
					.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}
 | 
					.repository .filter.menu .dropdown.item{margin:1px;padding-right:0}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3278,8 +3278,39 @@ function initIssueList() {
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            fullTextSearch: true
 | 
					            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) {
 | 
					function cancelCodeComment(btn) {
 | 
				
			||||||
    const form = $(btn).closest("form");
 | 
					    const form = $(btn).closest("form");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -158,6 +158,23 @@
 | 
				
			||||||
            margin: -2px -7px 0 -5px;
 | 
					            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 {
 | 
					        .text {
 | 
				
			||||||
            margin-left: 0.9em;
 | 
					            margin-left: 0.9em;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,15 +42,16 @@
 | 
				
			||||||
			<div class="ten wide right aligned column">
 | 
								<div class="ten wide right aligned column">
 | 
				
			||||||
				<div class="ui secondary filter stackable menu labels">
 | 
									<div class="ui secondary filter stackable menu labels">
 | 
				
			||||||
					<!-- Label -->
 | 
										<!-- 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">
 | 
											<span class="text">
 | 
				
			||||||
							{{.i18n.Tr "repo.issues.filter_label"}}
 | 
												{{.i18n.Tr "repo.issues.filter_label"}}
 | 
				
			||||||
							<i class="dropdown icon"></i>
 | 
												<i class="dropdown icon"></i>
 | 
				
			||||||
						</span>
 | 
											</span>
 | 
				
			||||||
						<div class="menu">
 | 
											<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>
 | 
												<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}}
 | 
												{{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}}
 | 
												{{end}}
 | 
				
			||||||
						</div>
 | 
											</div>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue