Merge branch 'search-ui-update' into 'master'
Search ui update Closes #2537 See merge request !3751
This commit is contained in:
commit
31c10e0362
16 changed files with 265 additions and 149 deletions
|
@ -4,6 +4,7 @@ v 8.8.0 (unreleased)
|
||||||
- Remove future dates from contribution calendar graph.
|
- Remove future dates from contribution calendar graph.
|
||||||
- Fix error when visiting commit builds page before build was updated
|
- Fix error when visiting commit builds page before build was updated
|
||||||
- Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project
|
- Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project
|
||||||
|
- Updated search UI
|
||||||
|
|
||||||
v 8.7.1 (unreleased)
|
v 8.7.1 (unreleased)
|
||||||
- Throttle the update of `project.last_activity_at` to 1 minute. !3848
|
- Throttle the update of `project.last_activity_at` to 1 minute. !3848
|
||||||
|
|
|
@ -108,6 +108,8 @@ class Dispatcher
|
||||||
new BuildArtifacts()
|
new BuildArtifacts()
|
||||||
when 'projects:group_links:index'
|
when 'projects:group_links:index'
|
||||||
new GroupsSelect()
|
new GroupsSelect()
|
||||||
|
when 'search:show'
|
||||||
|
new Search()
|
||||||
|
|
||||||
switch path.first()
|
switch path.first()
|
||||||
when 'admin'
|
when 'admin'
|
||||||
|
|
75
app/assets/javascripts/search.js.coffee
Normal file
75
app/assets/javascripts/search.js.coffee
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
class @Search
|
||||||
|
constructor: ->
|
||||||
|
$groupDropdown = $('.js-search-group-dropdown')
|
||||||
|
$projectDropdown = $('.js-search-project-dropdown')
|
||||||
|
@eventListeners()
|
||||||
|
|
||||||
|
$groupDropdown.glDropdown(
|
||||||
|
selectable: true
|
||||||
|
filterable: true
|
||||||
|
fieldName: 'group_id'
|
||||||
|
data: (term, callback) ->
|
||||||
|
Api.groups term, null, (data) ->
|
||||||
|
data.unshift(
|
||||||
|
name: 'Any'
|
||||||
|
)
|
||||||
|
data.splice 1, 0, 'divider'
|
||||||
|
|
||||||
|
callback(data)
|
||||||
|
id: (obj) ->
|
||||||
|
obj.id
|
||||||
|
text: (obj) ->
|
||||||
|
obj.name
|
||||||
|
toggleLabel: (obj) ->
|
||||||
|
"#{$groupDropdown.data('default-label')} #{obj.name}"
|
||||||
|
clicked: =>
|
||||||
|
@submitSearch()
|
||||||
|
)
|
||||||
|
|
||||||
|
$projectDropdown.glDropdown(
|
||||||
|
selectable: true
|
||||||
|
filterable: true
|
||||||
|
fieldName: 'project_id'
|
||||||
|
data: (term, callback) ->
|
||||||
|
Api.projects term, 'id', (data) ->
|
||||||
|
data.unshift(
|
||||||
|
name_with_namespace: 'Any'
|
||||||
|
)
|
||||||
|
data.splice 1, 0, 'divider'
|
||||||
|
|
||||||
|
callback(data)
|
||||||
|
id: (obj) ->
|
||||||
|
obj.id
|
||||||
|
text: (obj) ->
|
||||||
|
obj.name_with_namespace
|
||||||
|
toggleLabel: (obj) ->
|
||||||
|
"#{$projectDropdown.data('default-label')} #{obj.name_with_namespace}"
|
||||||
|
clicked: =>
|
||||||
|
@submitSearch()
|
||||||
|
)
|
||||||
|
|
||||||
|
eventListeners: ->
|
||||||
|
$(document)
|
||||||
|
.off 'keyup', '.js-search-input'
|
||||||
|
.on 'keyup', '.js-search-input', @searchKeyUp
|
||||||
|
|
||||||
|
$(document)
|
||||||
|
.off 'click', '.js-search-clear'
|
||||||
|
.on 'click', '.js-search-clear', @clearSearchField
|
||||||
|
|
||||||
|
submitSearch: ->
|
||||||
|
$('.js-search-form').submit()
|
||||||
|
|
||||||
|
searchKeyUp: ->
|
||||||
|
$input = $(@)
|
||||||
|
|
||||||
|
if $input.val() is ''
|
||||||
|
$('.js-search-clear').addClass 'hidden'
|
||||||
|
else
|
||||||
|
$('.js-search-clear').removeClass 'hidden'
|
||||||
|
|
||||||
|
clearSearchField: ->
|
||||||
|
$('.js-search-input')
|
||||||
|
.val ''
|
||||||
|
.trigger 'keyup'
|
||||||
|
.focus()
|
|
@ -11,6 +11,7 @@
|
||||||
.prepend-top-10 { margin-top: 10px }
|
.prepend-top-10 { margin-top: 10px }
|
||||||
.prepend-top-default { margin-top: $gl-padding !important; }
|
.prepend-top-default { margin-top: $gl-padding !important; }
|
||||||
.prepend-top-20 { margin-top: 20px }
|
.prepend-top-20 { margin-top: 20px }
|
||||||
|
.prepend-left-5 { margin-left: 5px }
|
||||||
.prepend-left-10 { margin-left: 10px }
|
.prepend-left-10 { margin-left: 10px }
|
||||||
.prepend-left-default { margin-left: $gl-padding; }
|
.prepend-left-default { margin-left: $gl-padding; }
|
||||||
.prepend-left-20 { margin-left: 20px }
|
.prepend-left-20 { margin-left: 20px }
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border: 1px solid $dropdown-toggle-border-color;
|
border: 1px solid $dropdown-toggle-border-color;
|
||||||
border-radius: $dropdown-border-radius;
|
border-radius: $border-radius-base;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
padding: 10px 0;
|
padding: 10px 0;
|
||||||
background-color: $dropdown-bg;
|
background-color: $dropdown-bg;
|
||||||
border: 1px solid $dropdown-border-color;
|
border: 1px solid $dropdown-border-color;
|
||||||
border-radius: $dropdown-border-radius;
|
border-radius: $border-radius-base;
|
||||||
box-shadow: 0 2px 4px $dropdown-shadow-color;
|
box-shadow: 0 2px 4px $dropdown-shadow-color;
|
||||||
|
|
||||||
&.is-loading {
|
&.is-loading {
|
||||||
|
|
|
@ -183,7 +183,6 @@ $regular_font: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif
|
||||||
/*
|
/*
|
||||||
* Dropdowns
|
* Dropdowns
|
||||||
*/
|
*/
|
||||||
$dropdown-border-radius: 2px;
|
|
||||||
$dropdown-width: 300px;
|
$dropdown-width: 300px;
|
||||||
$dropdown-bg: #fff;
|
$dropdown-bg: #fff;
|
||||||
$dropdown-link-color: #555;
|
$dropdown-link-color: #555;
|
||||||
|
|
|
@ -10,17 +10,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-holder {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 0 auto;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
input {
|
|
||||||
border-color: #bbb;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search {
|
.search {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
|
@ -163,3 +152,81 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-holder {
|
||||||
|
@media (min-width: $screen-sm-min) {
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-field-holder {
|
||||||
|
-webkit-flex: 1 0 auto;
|
||||||
|
-ms-flex: 1 0 auto;
|
||||||
|
flex: 1 0 auto;
|
||||||
|
position: relative;
|
||||||
|
margin-right: 0;
|
||||||
|
|
||||||
|
@media (min-width: $screen-sm-min) {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
top: 10px;
|
||||||
|
color: $gray-darkest;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-text-input {
|
||||||
|
padding-left: $gl-padding + 15px;
|
||||||
|
padding-right: $gl-padding + 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-search {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 5px;
|
||||||
|
|
||||||
|
@media (min-width: $screen-sm-min) {
|
||||||
|
width: auto;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown {
|
||||||
|
@media (min-width: $screen-sm-min) {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu-toggle {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 5px;
|
||||||
|
|
||||||
|
@media (min-width: $screen-sm-min) {
|
||||||
|
width: 160px;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-clear {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 10px;
|
||||||
|
padding: 0;
|
||||||
|
color: $gray-darkest;
|
||||||
|
line-height: 0;
|
||||||
|
background: none;
|
||||||
|
border: 0;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
color: $gl-link-color;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,8 +8,6 @@ class SearchController < ApplicationController
|
||||||
def show
|
def show
|
||||||
return if params[:search].nil? || params[:search].blank?
|
return if params[:search].nil? || params[:search].blank?
|
||||||
|
|
||||||
@search_term = params[:search]
|
|
||||||
|
|
||||||
if params[:project_id].present?
|
if params[:project_id].present?
|
||||||
@project = Project.find_by(id: params[:project_id])
|
@project = Project.find_by(id: params[:project_id])
|
||||||
@project = nil unless can?(current_user, :download_code, @project)
|
@project = nil unless can?(current_user, :download_code, @project)
|
||||||
|
@ -20,6 +18,8 @@ class SearchController < ApplicationController
|
||||||
@group = nil unless can?(current_user, :read_group, @group)
|
@group = nil unless can?(current_user, :read_group, @group)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@search_term = params[:search]
|
||||||
|
|
||||||
@scope = params[:scope]
|
@scope = params[:scope]
|
||||||
@show_snippets = params[:snippets].eql? 'true'
|
@show_snippets = params[:snippets].eql? 'true'
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class SearchController < ApplicationController
|
||||||
Search::GlobalService.new(current_user, params).execute
|
Search::GlobalService.new(current_user, params).execute
|
||||||
end
|
end
|
||||||
|
|
||||||
@objects = @search_results.objects(@scope, params[:page])
|
@search_objects = @search_results.objects(@scope, params[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
def autocomplete
|
def autocomplete
|
||||||
|
|
|
@ -19,6 +19,16 @@ module SearchHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def search_entries_info(collection, scope, term)
|
||||||
|
return unless collection.count > 0
|
||||||
|
|
||||||
|
from = collection.offset_value + 1
|
||||||
|
to = collection.offset_value + collection.length
|
||||||
|
count = collection.total_count
|
||||||
|
|
||||||
|
"Showing #{from} - #{to} of #{count} #{scope.humanize(capitalize: false)} for \"#{term}\""
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Autocomplete results for various settings pages
|
# Autocomplete results for various settings pages
|
||||||
|
|
|
@ -2,50 +2,36 @@
|
||||||
- if @project
|
- if @project
|
||||||
%li{class: ("active" if @scope == 'blobs')}
|
%li{class: ("active" if @scope == 'blobs')}
|
||||||
= link_to search_filter_path(scope: 'blobs') do
|
= link_to search_filter_path(scope: 'blobs') do
|
||||||
= icon('code fw')
|
|
||||||
%span
|
|
||||||
Code
|
Code
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.blobs_count
|
= @search_results.blobs_count
|
||||||
%li{class: ("active" if @scope == 'issues')}
|
%li{class: ("active" if @scope == 'issues')}
|
||||||
= link_to search_filter_path(scope: 'issues') do
|
= link_to search_filter_path(scope: 'issues') do
|
||||||
= icon('exclamation-circle fw')
|
|
||||||
%span
|
|
||||||
Issues
|
Issues
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.issues_count
|
= @search_results.issues_count
|
||||||
%li{class: ("active" if @scope == 'merge_requests')}
|
%li{class: ("active" if @scope == 'merge_requests')}
|
||||||
= link_to search_filter_path(scope: 'merge_requests') do
|
= link_to search_filter_path(scope: 'merge_requests') do
|
||||||
= icon('tasks fw')
|
|
||||||
%span
|
|
||||||
Merge requests
|
Merge requests
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.merge_requests_count
|
= @search_results.merge_requests_count
|
||||||
%li{class: ("active" if @scope == 'milestones')}
|
%li{class: ("active" if @scope == 'milestones')}
|
||||||
= link_to search_filter_path(scope: 'milestones') do
|
= link_to search_filter_path(scope: 'milestones') do
|
||||||
= icon('clock-o fw')
|
|
||||||
%span
|
|
||||||
Milestones
|
Milestones
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.milestones_count
|
= @search_results.milestones_count
|
||||||
%li{class: ("active" if @scope == 'notes')}
|
%li{class: ("active" if @scope == 'notes')}
|
||||||
= link_to search_filter_path(scope: 'notes') do
|
= link_to search_filter_path(scope: 'notes') do
|
||||||
= icon('comments fw')
|
|
||||||
%span
|
|
||||||
Comments
|
Comments
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.notes_count
|
= @search_results.notes_count
|
||||||
%li{class: ("active" if @scope == 'wiki_blobs')}
|
%li{class: ("active" if @scope == 'wiki_blobs')}
|
||||||
= link_to search_filter_path(scope: 'wiki_blobs') do
|
= link_to search_filter_path(scope: 'wiki_blobs') do
|
||||||
= icon('book fw')
|
|
||||||
%span
|
|
||||||
Wiki
|
Wiki
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.wiki_blobs_count
|
= @search_results.wiki_blobs_count
|
||||||
%li{class: ("active" if @scope == 'commits')}
|
%li{class: ("active" if @scope == 'commits')}
|
||||||
= link_to search_filter_path(scope: 'commits') do
|
= link_to search_filter_path(scope: 'commits') do
|
||||||
= icon('history fw')
|
|
||||||
%span
|
|
||||||
Commits
|
Commits
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.commits_count
|
= @search_results.commits_count
|
||||||
|
@ -53,15 +39,11 @@
|
||||||
- elsif @show_snippets
|
- elsif @show_snippets
|
||||||
%li{class: ("active" if @scope == 'snippet_blobs')}
|
%li{class: ("active" if @scope == 'snippet_blobs')}
|
||||||
= link_to search_filter_path(scope: 'snippet_blobs', snippets: true, group_id: nil, project_id: nil) do
|
= link_to search_filter_path(scope: 'snippet_blobs', snippets: true, group_id: nil, project_id: nil) do
|
||||||
= icon('code fw')
|
|
||||||
%span
|
|
||||||
Snippet Contents
|
Snippet Contents
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.snippet_blobs_count
|
= @search_results.snippet_blobs_count
|
||||||
%li{class: ("active" if @scope == 'snippet_titles')}
|
%li{class: ("active" if @scope == 'snippet_titles')}
|
||||||
= link_to search_filter_path(scope: 'snippet_titles', snippets: true, group_id: nil, project_id: nil) do
|
= link_to search_filter_path(scope: 'snippet_titles', snippets: true, group_id: nil, project_id: nil) do
|
||||||
= icon('book fw')
|
|
||||||
%span
|
|
||||||
Titles and Filenames
|
Titles and Filenames
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.snippet_titles_count
|
= @search_results.snippet_titles_count
|
||||||
|
@ -69,30 +51,21 @@
|
||||||
- else
|
- else
|
||||||
%li{class: ("active" if @scope == 'projects')}
|
%li{class: ("active" if @scope == 'projects')}
|
||||||
= link_to search_filter_path(scope: 'projects') do
|
= link_to search_filter_path(scope: 'projects') do
|
||||||
= icon('bookmark fw')
|
|
||||||
%span
|
|
||||||
Projects
|
Projects
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.projects_count
|
= @search_results.projects_count
|
||||||
%li{class: ("active" if @scope == 'issues')}
|
%li{class: ("active" if @scope == 'issues')}
|
||||||
= link_to search_filter_path(scope: 'issues') do
|
= link_to search_filter_path(scope: 'issues') do
|
||||||
= icon('exclamation-circle fw')
|
|
||||||
%span
|
|
||||||
Issues
|
Issues
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.issues_count
|
= @search_results.issues_count
|
||||||
%li{class: ("active" if @scope == 'merge_requests')}
|
%li{class: ("active" if @scope == 'merge_requests')}
|
||||||
= link_to search_filter_path(scope: 'merge_requests') do
|
= link_to search_filter_path(scope: 'merge_requests') do
|
||||||
= icon('tasks fw')
|
|
||||||
%span
|
|
||||||
Merge requests
|
Merge requests
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.merge_requests_count
|
= @search_results.merge_requests_count
|
||||||
%li{class: ("active" if @scope == 'milestones')}
|
%li{class: ("active" if @scope == 'milestones')}
|
||||||
= link_to search_filter_path(scope: 'milestones') do
|
= link_to search_filter_path(scope: 'milestones') do
|
||||||
= icon('clock-o fw')
|
|
||||||
%span
|
|
||||||
Milestones
|
Milestones
|
||||||
%span.badge
|
%span.badge
|
||||||
= @search_results.milestones_count
|
= @search_results.milestones_count
|
||||||
|
|
||||||
|
|
|
@ -1,47 +1,33 @@
|
||||||
.dropdown.inline
|
- if params[:group_id].present?
|
||||||
%button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'}
|
= hidden_field_tag :group_id, params[:group_id]
|
||||||
%span.light Group:
|
- if params[:project_id].present?
|
||||||
|
= hidden_field_tag :project_id, params[:project_id]
|
||||||
|
.dropdown
|
||||||
|
%button.dropdown-menu-toggle.btn.js-search-group-dropdown{ type: "button", data: { toggle: "dropdown", default_label: "Group:" } }
|
||||||
|
%span.dropdown-toggle-text
|
||||||
|
Group:
|
||||||
- if @group.present?
|
- if @group.present?
|
||||||
%strong= @group.name
|
= @group.name
|
||||||
- else
|
- else
|
||||||
Any
|
Any
|
||||||
%b.caret
|
= icon("chevron-down")
|
||||||
.dropdown-menu.dropdown-select.dropdown-menu-selectable
|
.dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-align-right
|
||||||
.dropdown-title
|
= dropdown_title("Filter results by group")
|
||||||
%span Filter results by group
|
= dropdown_filter("Search groups")
|
||||||
%button.dropdown-title-button.dropdown-menu-close{aria: {label: "Close"}}
|
= dropdown_content
|
||||||
= icon('times')
|
= dropdown_loading
|
||||||
.dropdown-content
|
|
||||||
%ul
|
|
||||||
%li
|
|
||||||
= link_to search_filter_path(group_id: nil), class: ("is-active" if !params[:group_id].present?) do
|
|
||||||
Any
|
|
||||||
%li.divider
|
|
||||||
- current_user.authorized_groups.sort_by(&:name).each do |group|
|
|
||||||
%li
|
|
||||||
= link_to search_filter_path(group_id: group.id, project_id: nil), class: ("is-active" if params[:group_id] == group.id.to_s) do
|
|
||||||
= group.name
|
|
||||||
|
|
||||||
.dropdown.inline.prepend-left-10.project-filter
|
.dropdown.project-filter
|
||||||
%button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'}
|
%button.dropdown-menu-toggle.btn.js-search-project-dropdown{ type: "button", data: { toggle: "dropdown", default_label: "Project:" } }
|
||||||
%span.light Project:
|
%span.dropdown-toggle-text
|
||||||
|
Project:
|
||||||
- if @project.present?
|
- if @project.present?
|
||||||
%strong= @project.name_with_namespace
|
= @project.name_with_namespace
|
||||||
- else
|
- else
|
||||||
Any
|
Any
|
||||||
%b.caret
|
= icon("chevron-down")
|
||||||
.dropdown-menu.dropdown-select.dropdown-menu-selectable
|
.dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-align-right
|
||||||
.dropdown-title
|
= dropdown_title("Filter results by project")
|
||||||
%span Filter results by project
|
= dropdown_filter("Search projects")
|
||||||
%button.dropdown-title-button.dropdown-menu-close{aria: {label: "Close"}}
|
= dropdown_content
|
||||||
= icon('times')
|
= dropdown_loading
|
||||||
.dropdown-content
|
|
||||||
%ul
|
|
||||||
%li
|
|
||||||
= link_to search_filter_path(project_id: nil), class: ("is-active" if !params[:project_id].present?) do
|
|
||||||
Any
|
|
||||||
%li.divider
|
|
||||||
- current_user.authorized_projects.sort_by(&:name_with_namespace).each do |project|
|
|
||||||
%li
|
|
||||||
= link_to search_filter_path(project_id: project.id, group_id: nil), class: ("is-active" if params[:project_id] == project.id.to_s) do
|
|
||||||
= project.name_with_namespace
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
= form_tag search_path, method: :get do |f|
|
= form_tag search_path, method: :get, class: 'js-search-form' do |f|
|
||||||
= hidden_field_tag :project_id, params[:project_id]
|
|
||||||
= hidden_field_tag :group_id, params[:group_id]
|
|
||||||
= hidden_field_tag :snippets, params[:snippets]
|
= hidden_field_tag :snippets, params[:snippets]
|
||||||
= hidden_field_tag :scope, params[:scope]
|
= hidden_field_tag :scope, params[:scope]
|
||||||
|
|
||||||
.search-holder.clearfix
|
.search-holder
|
||||||
.input-group
|
.search-field-holder
|
||||||
= search_field_tag :search, params[:search], placeholder: "Search for projects, issues etc", class: "form-control search-text-input", id: "dashboard_search", autofocus: true, spellcheck: false
|
= search_field_tag :search, params[:search], placeholder: "Search for projects, issues etc", class: "form-control search-text-input js-search-input", id: "dashboard_search", autofocus: true, spellcheck: false
|
||||||
%span.input-group-btn
|
= icon("search", class: "search-icon")
|
||||||
= button_tag 'Search', class: "btn btn-primary"
|
%button.search-clear.js-search-clear{ class: ("hidden" if !params[:search].present?), type: "button", tabindex: "-1" }
|
||||||
|
= icon("times-circle")
|
||||||
|
%span.sr-only
|
||||||
|
Clear search
|
||||||
- unless params[:snippets].eql? 'true'
|
- unless params[:snippets].eql? 'true'
|
||||||
%br
|
|
||||||
= render 'filter' if current_user
|
= render 'filter' if current_user
|
||||||
|
= button_tag "Search", class: "btn btn-success btn-search"
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
- if @search_results.empty?
|
- if @search_objects.empty?
|
||||||
= render partial: "search/results/empty"
|
= render partial: "search/results/empty"
|
||||||
- else
|
- else
|
||||||
.gray-content-block
|
.gray-content-block
|
||||||
Search results for
|
= search_entries_info(@search_objects, @scope, @search_term)
|
||||||
%code
|
|
||||||
= @search_term
|
|
||||||
- unless @show_snippets
|
- unless @show_snippets
|
||||||
- if @project
|
- if @project
|
||||||
in project #{link_to @project.name_with_namespace, [@project.namespace.becomes(Namespace), @project]}
|
in project #{link_to @project.name_with_namespace, [@project.namespace.becomes(Namespace), @project]}
|
||||||
|
@ -15,12 +13,9 @@
|
||||||
.search-results
|
.search-results
|
||||||
- if @scope == 'projects'
|
- if @scope == 'projects'
|
||||||
.term
|
.term
|
||||||
= render 'shared/projects/list', projects: @objects
|
= render 'shared/projects/list', projects: @search_objects
|
||||||
- else
|
- else
|
||||||
= render partial: "search/results/#{@scope.singularize}", collection: @objects
|
= render partial: "search/results/#{@scope.singularize}", collection: @search_objects
|
||||||
|
|
||||||
- if @scope != 'projects'
|
- if @scope != 'projects'
|
||||||
= paginate @objects, theme: 'gitlab'
|
= paginate(@search_objects, theme: 'gitlab')
|
||||||
|
|
||||||
:javascript
|
|
||||||
$(".search-results .term").highlight("#{escape_javascript(params[:search])}");
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
- if issue.description.present?
|
- if issue.description.present?
|
||||||
.description.term
|
.description.term
|
||||||
= preserve do
|
= preserve do
|
||||||
= search_md_sanitize(markdown(issue.description, { project: issue.project }))
|
= search_md_sanitize(markdown(truncate(issue.description, length: 200, separator: " "), { project: issue.project }))
|
||||||
%span.light
|
%span.light
|
||||||
#{issue.project.name_with_namespace}
|
#{issue.project.name_with_namespace}
|
||||||
- if issue.closed?
|
- if issue.closed?
|
||||||
|
|
|
@ -30,11 +30,13 @@ Feature: Search
|
||||||
Then I should see "Foo" link in the search results
|
Then I should see "Foo" link in the search results
|
||||||
And I should not see "Bar" link in the search results
|
And I should not see "Bar" link in the search results
|
||||||
|
|
||||||
|
@javascript
|
||||||
Scenario: I should see project code I am looking for
|
Scenario: I should see project code I am looking for
|
||||||
When I click project "Shop" link
|
When I click project "Shop" link
|
||||||
And I search for "rspec"
|
And I search for "rspec"
|
||||||
Then I should see code results for project "Shop"
|
Then I should see code results for project "Shop"
|
||||||
|
|
||||||
|
@javascript
|
||||||
Scenario: I should see project issues
|
Scenario: I should see project issues
|
||||||
And project has issues
|
And project has issues
|
||||||
When I click project "Shop" link
|
When I click project "Shop" link
|
||||||
|
@ -43,6 +45,7 @@ Feature: Search
|
||||||
Then I should see "Foo" link in the search results
|
Then I should see "Foo" link in the search results
|
||||||
And I should not see "Bar" link in the search results
|
And I should not see "Bar" link in the search results
|
||||||
|
|
||||||
|
@javascript
|
||||||
Scenario: I should see project merge requests
|
Scenario: I should see project merge requests
|
||||||
And project has merge requests
|
And project has merge requests
|
||||||
When I click project "Shop" link
|
When I click project "Shop" link
|
||||||
|
@ -51,6 +54,7 @@ Feature: Search
|
||||||
Then I should see "Foo" link in the search results
|
Then I should see "Foo" link in the search results
|
||||||
And I should not see "Bar" link in the search results
|
And I should not see "Bar" link in the search results
|
||||||
|
|
||||||
|
@javascript
|
||||||
Scenario: I should see project milestones
|
Scenario: I should see project milestones
|
||||||
And project has milestones
|
And project has milestones
|
||||||
When I click project "Shop" link
|
When I click project "Shop" link
|
||||||
|
@ -59,6 +63,7 @@ Feature: Search
|
||||||
Then I should see "Foo" link in the search results
|
Then I should see "Foo" link in the search results
|
||||||
And I should not see "Bar" link in the search results
|
And I should not see "Bar" link in the search results
|
||||||
|
|
||||||
|
@javascript
|
||||||
Scenario: I should see Wiki blobs
|
Scenario: I should see Wiki blobs
|
||||||
And project has Wiki content
|
And project has Wiki content
|
||||||
When I click project "Shop" link
|
When I click project "Shop" link
|
||||||
|
|
|
@ -35,6 +35,7 @@ class Spinach::Features::Search < Spinach::FeatureSteps
|
||||||
end
|
end
|
||||||
|
|
||||||
step 'I click project "Shop" link' do
|
step 'I click project "Shop" link' do
|
||||||
|
click_button 'Project'
|
||||||
page.within '.project-filter' do
|
page.within '.project-filter' do
|
||||||
click_link project.name_with_namespace
|
click_link project.name_with_namespace
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue