Commit bc8546a9 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '213699-remove-search-results-autocomplete' into 'master'

Remove search autocomplete in nav bar

See merge request gitlab-org/gitlab!31187
parents f67055cd 842b0408
/* eslint-disable no-return-assign, consistent-return, class-methods-use-this */ /* eslint-disable no-return-assign, consistent-return, class-methods-use-this */
import $ from 'jquery'; import $ from 'jquery';
import { escape, throttle } from 'lodash'; import { throttle } from 'lodash';
import { s__, __, sprintf } from '~/locale'; import { s__, __, sprintf } from '~/locale';
import { getIdenticonBackgroundClass, getIdenticonTitle } from '~/helpers/avatar_helper';
import axios from './lib/utils/axios_utils';
import { import {
isInGroupsPage, isInGroupsPage,
isInProjectPage, isInProjectPage,
...@@ -67,15 +65,11 @@ function setSearchOptions() { ...@@ -67,15 +65,11 @@ function setSearchOptions() {
} }
} }
export class SearchAutocomplete { export class GlobalSearchInput {
constructor({ wrap, optsEl, autocompletePath, projectId, projectRef } = {}) { constructor({ wrap } = {}) {
setSearchOptions(); setSearchOptions();
this.bindEventContext(); this.bindEventContext();
this.wrap = wrap || $('.search'); this.wrap = wrap || $('.search');
this.optsEl = optsEl || this.wrap.find('.search-autocomplete-opts');
this.autocompletePath = autocompletePath || this.optsEl.data('autocompletePath');
this.projectId = projectId || (this.optsEl.data('autocompleteProjectId') || '');
this.projectRef = projectRef || (this.optsEl.data('autocompleteProjectRef') || '');
this.dropdown = this.wrap.find('.dropdown'); this.dropdown = this.wrap.find('.dropdown');
this.dropdownToggle = this.wrap.find('.js-dropdown-search-toggle'); this.dropdownToggle = this.wrap.find('.js-dropdown-search-toggle');
this.dropdownMenu = this.dropdown.find('.dropdown-menu'); this.dropdownMenu = this.dropdown.find('.dropdown-menu');
...@@ -92,7 +86,7 @@ export class SearchAutocomplete { ...@@ -92,7 +86,7 @@ export class SearchAutocomplete {
// Only when user is logged in // Only when user is logged in
if (gon.current_user_id) { if (gon.current_user_id) {
this.createAutocomplete(); this.createGlobalSearchInput();
} }
this.bindEvents(); this.bindEvents();
...@@ -117,7 +111,7 @@ export class SearchAutocomplete { ...@@ -117,7 +111,7 @@ export class SearchAutocomplete {
return (this.originalState = this.serializeState()); return (this.originalState = this.serializeState());
} }
createAutocomplete() { createGlobalSearchInput() {
return this.searchInput.glDropdown({ return this.searchInput.glDropdown({
filterInputBlur: false, filterInputBlur: false,
filterable: true, filterable: true,
...@@ -149,116 +143,17 @@ export class SearchAutocomplete { ...@@ -149,116 +143,17 @@ export class SearchAutocomplete {
if (glDropdownInstance) { if (glDropdownInstance) {
glDropdownInstance.filter.options.callback(contents); glDropdownInstance.filter.options.callback(contents);
} }
this.enableAutocomplete(); this.enableDropdown();
} }
return; return;
} }
// Prevent multiple ajax calls const options = this.scopedSearchOptions(term);
if (this.loadingSuggestions) {
return;
}
this.loadingSuggestions = true;
return axios
.get(this.autocompletePath, {
params: {
project_id: this.projectId,
project_ref: this.projectRef,
term,
},
})
.then(response => {
const options = this.scopedSearchOptions(term);
// List results
let lastCategory = null;
for (let i = 0, len = response.data.length; i < len; i += 1) {
const suggestion = response.data[i];
// Add group header before list each group
if (lastCategory !== suggestion.category) {
options.push({ type: 'separator' });
options.push({
type: 'header',
content: suggestion.category,
});
lastCategory = suggestion.category;
}
// Add the suggestion
options.push({
id: `${suggestion.category.toLowerCase()}-${suggestion.id}`,
icon: this.getAvatar(suggestion),
category: suggestion.category,
text: suggestion.label,
url: suggestion.url,
});
}
callback(options);
this.loadingSuggestions = false;
this.highlightFirstRow();
this.setScrollFade();
})
.catch(() => {
this.loadingSuggestions = false;
});
}
getCategoryContents() {
const userName = gon.current_username;
const { projectOptions, groupOptions, dashboardOptions } = gl;
// Get options
let options;
if (isInProjectPage() && projectOptions) {
options = projectOptions[getProjectSlug()];
} else if (isInGroupsPage() && groupOptions) {
options = groupOptions[getGroupSlug()];
} else if (dashboardOptions) {
options = dashboardOptions;
}
const { issuesPath, mrPath, name, issuesDisabled } = options;
const baseItems = [];
if (name) {
baseItems.push({
type: 'header',
content: `${name}`,
});
}
const issueItems = [ callback(options);
{
text: s__('SearchAutocomplete|Issues assigned to me'),
url: `${issuesPath}/?assignee_username=${userName}`,
},
{
text: s__("SearchAutocomplete|Issues I've created"),
url: `${issuesPath}/?author_username=${userName}`,
},
];
const mergeRequestItems = [
{
text: s__('SearchAutocomplete|Merge requests assigned to me'),
url: `${mrPath}/?assignee_username=${userName}`,
},
{
text: s__("SearchAutocomplete|Merge requests I've created"),
url: `${mrPath}/?author_username=${userName}`,
},
];
let items; this.highlightFirstRow();
if (issuesDisabled) { this.setScrollFade();
items = baseItems.concat(mergeRequestItems);
} else {
items = baseItems.concat(...issueItems, ...mergeRequestItems);
}
return items;
} }
// Add option to proceed with the search for each // Add option to proceed with the search for each
...@@ -343,7 +238,7 @@ export class SearchAutocomplete { ...@@ -343,7 +238,7 @@ export class SearchAutocomplete {
}); });
} }
enableAutocomplete() { enableDropdown() {
this.setScrollFade(); this.setScrollFade();
// No need to enable anything if user is not logged in // No need to enable anything if user is not logged in
...@@ -360,7 +255,7 @@ export class SearchAutocomplete { ...@@ -360,7 +255,7 @@ export class SearchAutocomplete {
} }
onSearchInputChange() { onSearchInputChange() {
this.enableAutocomplete(); this.enableDropdown();
} }
onSearchInputKeyUp(e) { onSearchInputKeyUp(e) {
...@@ -369,7 +264,7 @@ export class SearchAutocomplete { ...@@ -369,7 +264,7 @@ export class SearchAutocomplete {
this.restoreOriginalState(); this.restoreOriginalState();
break; break;
case KEYCODE.ENTER: case KEYCODE.ENTER:
this.disableAutocomplete(); this.disableDropdown();
break; break;
default: default:
} }
...@@ -422,7 +317,7 @@ export class SearchAutocomplete { ...@@ -422,7 +317,7 @@ export class SearchAutocomplete {
return results; return results;
} }
disableAutocomplete() { disableDropdown() {
if (!this.searchInput.hasClass('js-autocomplete-disabled') && this.dropdown.hasClass('show')) { if (!this.searchInput.hasClass('js-autocomplete-disabled') && this.dropdown.hasClass('show')) {
this.searchInput.addClass('js-autocomplete-disabled'); this.searchInput.addClass('js-autocomplete-disabled');
this.dropdownToggle.dropdown('toggle'); this.dropdownToggle.dropdown('toggle');
...@@ -438,16 +333,8 @@ export class SearchAutocomplete { ...@@ -438,16 +333,8 @@ export class SearchAutocomplete {
onClick(item, $el, e) { onClick(item, $el, e) {
if (window.location.pathname.indexOf(item.url) !== -1) { if (window.location.pathname.indexOf(item.url) !== -1) {
if (!e.metaKey) e.preventDefault(); if (!e.metaKey) e.preventDefault();
/* eslint-disable-next-line @gitlab/require-i18n-strings */
if (item.category === 'Projects') {
this.projectInputEl.val(item.id);
}
// eslint-disable-next-line @gitlab/require-i18n-strings
if (item.category === 'Groups') {
this.groupInputEl.val(item.id);
}
$el.removeClass('is-active'); $el.removeClass('is-active');
this.disableAutocomplete(); this.disableDropdown();
return this.searchInput.val('').focus(); return this.searchInput.val('').focus();
} }
} }
...@@ -456,20 +343,58 @@ export class SearchAutocomplete { ...@@ -456,20 +343,58 @@ export class SearchAutocomplete {
this.searchInput.data('glDropdown').highlightRowAtIndex(null, 0); this.searchInput.data('glDropdown').highlightRowAtIndex(null, 0);
} }
getAvatar(item) { getCategoryContents() {
if (!Object.hasOwnProperty.call(item, 'avatar_url')) { const userName = gon.current_username;
return false; const { projectOptions, groupOptions, dashboardOptions } = gl;
// Get options
let options;
if (isInProjectPage() && projectOptions) {
options = projectOptions[getProjectSlug()];
} else if (isInGroupsPage() && groupOptions) {
options = groupOptions[getGroupSlug()];
} else if (dashboardOptions) {
options = dashboardOptions;
} }
const { label, id } = item; const { issuesPath, mrPath, name, issuesDisabled } = options;
const avatarUrl = item.avatar_url; const baseItems = [];
const avatar = avatarUrl
? `<img class="search-item-avatar" src="${avatarUrl}" />` if (name) {
: `<div class="s16 avatar identicon ${getIdenticonBackgroundClass(id)}">${getIdenticonTitle( baseItems.push({
escape(label), type: 'header',
)}</div>`; content: `${name}`,
});
}
return avatar; const issueItems = [
{
text: s__('SearchAutocomplete|Issues assigned to me'),
url: `${issuesPath}/?assignee_username=${userName}`,
},
{
text: s__("SearchAutocomplete|Issues I've created"),
url: `${issuesPath}/?author_username=${userName}`,
},
];
const mergeRequestItems = [
{
text: s__('SearchAutocomplete|Merge requests assigned to me'),
url: `${mrPath}/?assignee_username=${userName}`,
},
{
text: s__("SearchAutocomplete|Merge requests I've created"),
url: `${mrPath}/?author_username=${userName}`,
},
];
let items;
if (issuesDisabled) {
items = baseItems.concat(mergeRequestItems);
} else {
items = baseItems.concat(...issueItems, ...mergeRequestItems);
}
return items;
} }
isScrolledUp() { isScrolledUp() {
...@@ -495,6 +420,6 @@ export class SearchAutocomplete { ...@@ -495,6 +420,6 @@ export class SearchAutocomplete {
} }
} }
export default function initSearchAutocomplete(opts) { export default function initGlobalSearchInput(opts) {
return new SearchAutocomplete(opts); return new GlobalSearchInput(opts);
} }
...@@ -32,7 +32,7 @@ import initFrequentItemDropdowns from './frequent_items'; ...@@ -32,7 +32,7 @@ import initFrequentItemDropdowns from './frequent_items';
import initBreadcrumbs from './breadcrumb'; import initBreadcrumbs from './breadcrumb';
import initUsagePingConsent from './usage_ping_consent'; import initUsagePingConsent from './usage_ping_consent';
import initPerformanceBar from './performance_bar'; import initPerformanceBar from './performance_bar';
import initSearchAutocomplete from './search_autocomplete'; import initGlobalSearchInput from './global_search_input';
import GlFieldErrors from './gl_field_errors'; import GlFieldErrors from './gl_field_errors';
import initUserPopovers from './user_popovers'; import initUserPopovers from './user_popovers';
import initBroadcastNotifications from './broadcast_notification'; import initBroadcastNotifications from './broadcast_notification';
...@@ -110,7 +110,7 @@ function deferredInitialisation() { ...@@ -110,7 +110,7 @@ function deferredInitialisation() {
initFrequentItemDropdowns(); initFrequentItemDropdowns();
initPersistentUserCallouts(); initPersistentUserCallouts();
if (document.querySelector('.search')) initSearchAutocomplete(); if (document.querySelector('.search')) initGlobalSearchInput();
addSelectOnFocusBehaviour('.js-select-on-focus'); addSelectOnFocusBehaviour('.js-select-on-focus');
......
...@@ -51,21 +51,6 @@ class SearchController < ApplicationController ...@@ -51,21 +51,6 @@ class SearchController < ApplicationController
render json: { count: count } render json: { count: count }
end end
# rubocop: disable CodeReuse/ActiveRecord
def autocomplete
term = params[:term]
if params[:project_id].present?
@project = Project.find_by(id: params[:project_id])
@project = nil unless can?(current_user, :read_project, @project)
end
@ref = params[:project_ref] if params[:project_ref].present?
render json: search_autocomplete_opts(term).to_json
end
# rubocop: enable CodeReuse/ActiveRecord
private private
def preload_method def preload_method
......
...@@ -3,28 +3,6 @@ ...@@ -3,28 +3,6 @@
module SearchHelper module SearchHelper
SEARCH_PERMITTED_PARAMS = [:search, :scope, :project_id, :group_id, :repository_ref, :snippets].freeze SEARCH_PERMITTED_PARAMS = [:search, :scope, :project_id, :group_id, :repository_ref, :snippets].freeze
def search_autocomplete_opts(term)
return unless current_user
resources_results = [
groups_autocomplete(term),
projects_autocomplete(term)
].flatten
search_pattern = Regexp.new(Regexp.escape(term), "i")
generic_results = project_autocomplete + default_autocomplete + help_autocomplete
generic_results.concat(default_autocomplete_admin) if current_user.admin?
generic_results.select! { |result| result[:label] =~ search_pattern }
[
resources_results,
generic_results
].flatten.uniq do |item|
item[:label]
end
end
def search_entries_info(collection, scope, term) def search_entries_info(collection, scope, term)
return if collection.to_a.empty? return if collection.to_a.empty?
...@@ -95,91 +73,6 @@ module SearchHelper ...@@ -95,91 +73,6 @@ module SearchHelper
private private
# Autocomplete results for various settings pages
def default_autocomplete
[
{ category: "Settings", label: _("User settings"), url: profile_path },
{ category: "Settings", label: _("SSH Keys"), url: profile_keys_path },
{ category: "Settings", label: _("Dashboard"), url: root_path }
]
end
# Autocomplete results for settings pages, for admins
def default_autocomplete_admin
[
{ category: "Settings", label: _("Admin Section"), url: admin_root_path }
]
end
# Autocomplete results for internal help pages
def help_autocomplete
[
{ category: "Help", label: _("API Help"), url: help_page_path("api/README") },
{ category: "Help", label: _("Markdown Help"), url: help_page_path("user/markdown") },
{ category: "Help", label: _("Permissions Help"), url: help_page_path("user/permissions") },
{ category: "Help", label: _("Public Access Help"), url: help_page_path("public_access/public_access") },
{ category: "Help", label: _("Rake Tasks Help"), url: help_page_path("raketasks/README") },
{ category: "Help", label: _("SSH Keys Help"), url: help_page_path("ssh/README") },
{ category: "Help", label: _("System Hooks Help"), url: help_page_path("system_hooks/system_hooks") },
{ category: "Help", label: _("Webhooks Help"), url: help_page_path("user/project/integrations/webhooks") },
{ category: "Help", label: _("Workflow Help"), url: help_page_path("workflow/README") }
]
end
# Autocomplete results for the current project, if it's defined
def project_autocomplete
if @project && @project.repository.root_ref
ref = @ref || @project.repository.root_ref
[
{ category: "In this project", label: _("Files"), url: project_tree_path(@project, ref) },
{ category: "In this project", label: _("Commits"), url: project_commits_path(@project, ref) },
{ category: "In this project", label: _("Network"), url: project_network_path(@project, ref) },
{ category: "In this project", label: _("Graph"), url: project_graph_path(@project, ref) },
{ category: "In this project", label: _("Issues"), url: project_issues_path(@project) },
{ category: "In this project", label: _("Merge Requests"), url: project_merge_requests_path(@project) },
{ category: "In this project", label: _("Milestones"), url: project_milestones_path(@project) },
{ category: "In this project", label: _("Snippets"), url: project_snippets_path(@project) },
{ category: "In this project", label: _("Members"), url: project_project_members_path(@project) },
{ category: "In this project", label: _("Wiki"), url: project_wikis_path(@project) }
]
else
[]
end
end
# Autocomplete results for the current user's groups
# rubocop: disable CodeReuse/ActiveRecord
def groups_autocomplete(term, limit = 5)
current_user.authorized_groups.order_id_desc.search(term).limit(limit).map do |group|
{
category: "Groups",
id: group.id,
label: "#{search_result_sanitize(group.full_name)}",
url: group_path(group),
avatar_url: group.avatar_url || ''
}
end
end
# rubocop: enable CodeReuse/ActiveRecord
# Autocomplete results for the current user's projects
# rubocop: disable CodeReuse/ActiveRecord
def projects_autocomplete(term, limit = 5)
current_user.authorized_projects.order_id_desc.search_by_title(term)
.sorted_by_stars_desc.non_archived.limit(limit).map do |p|
{
category: "Projects",
id: p.id,
value: "#{search_result_sanitize(p.name)}",
label: "#{search_result_sanitize(p.full_name)}",
url: project_path(p),
avatar_url: p.avatar_url || ''
}
end
end
# rubocop: enable CodeReuse/ActiveRecord
def search_result_sanitize(str) def search_result_sanitize(str)
Sanitize.clean(str) Sanitize.clean(str)
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
= form_tag search_path, method: :get, class: 'form-inline' do |f| = form_tag search_path, method: :get, class: 'form-inline' do |f|
.search-input-container .search-input-container
.search-input-wrap .search-input-wrap
.dropdown{ data: { url: search_autocomplete_path } } .dropdown
= search_field_tag 'search', nil, placeholder: _('Search or jump to…'), = search_field_tag 'search', nil, placeholder: _('Search or jump to…'),
class: 'search-input dropdown-menu-toggle no-outline js-search-dashboard-options', class: 'search-input dropdown-menu-toggle no-outline js-search-dashboard-options',
spellcheck: false, spellcheck: false,
...@@ -37,6 +37,3 @@ ...@@ -37,6 +37,3 @@
-# workaround for non-JS feature specs, see spec/support/helpers/search_helpers.rb -# workaround for non-JS feature specs, see spec/support/helpers/search_helpers.rb
- if ENV['RAILS_ENV'] == 'test' - if ENV['RAILS_ENV'] == 'test'
%noscript= button_tag 'Search' %noscript= button_tag 'Search'
.search-autocomplete-opts.hide{ :'data-autocomplete-path' => search_autocomplete_path,
:'data-autocomplete-project-id' => search_context.project.try(:id),
:'data-autocomplete-project-ref' => search_context.ref }
---
title: Remove all search autocomplete for groups/projects/other
merge_request: 31187
author:
type: removed
...@@ -58,7 +58,6 @@ Rails.application.routes.draw do ...@@ -58,7 +58,6 @@ Rails.application.routes.draw do
# Search # Search
get 'search' => 'search#show' get 'search' => 'search#show'
get 'search/autocomplete' => 'search#autocomplete', as: :search_autocomplete
get 'search/count' => 'search#count', as: :search_count get 'search/count' => 'search#count', as: :search_count
# JSON Web Token # JSON Web Token
......
...@@ -983,9 +983,6 @@ msgstr "" ...@@ -983,9 +983,6 @@ msgstr ""
msgid "ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt certificate for GitLab Pages domain '%{domain}'" msgid "ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt certificate for GitLab Pages domain '%{domain}'"
msgstr "" msgstr ""
msgid "API Help"
msgstr ""
msgid "API Token" msgid "API Token"
msgstr "" msgstr ""
...@@ -1441,9 +1438,6 @@ msgstr "" ...@@ -1441,9 +1438,6 @@ msgstr ""
msgid "Admin Overview" msgid "Admin Overview"
msgstr "" msgstr ""
msgid "Admin Section"
msgstr ""
msgid "Admin mode already enabled" msgid "Admin mode already enabled"
msgstr "" msgstr ""
...@@ -13336,9 +13330,6 @@ msgstr "" ...@@ -13336,9 +13330,6 @@ msgstr ""
msgid "Markdown" msgid "Markdown"
msgstr "" msgstr ""
msgid "Markdown Help"
msgstr ""
msgid "Markdown enabled" msgid "Markdown enabled"
msgstr "" msgstr ""
...@@ -15654,9 +15645,6 @@ msgstr "" ...@@ -15654,9 +15645,6 @@ msgstr ""
msgid "Permissions" msgid "Permissions"
msgstr "" msgstr ""
msgid "Permissions Help"
msgstr ""
msgid "Permissions, LFS, 2FA" msgid "Permissions, LFS, 2FA"
msgstr "" msgstr ""
...@@ -17685,9 +17673,6 @@ msgstr "" ...@@ -17685,9 +17673,6 @@ msgstr ""
msgid "Public - The project can be accessed without any authentication." msgid "Public - The project can be accessed without any authentication."
msgstr "" msgstr ""
msgid "Public Access Help"
msgstr ""
msgid "Public deploy keys (%{deploy_keys_count})" msgid "Public deploy keys (%{deploy_keys_count})"
msgstr "" msgstr ""
...@@ -17817,9 +17802,6 @@ msgstr "" ...@@ -17817,9 +17802,6 @@ msgstr ""
msgid "README" msgid "README"
msgstr "" msgstr ""
msgid "Rake Tasks Help"
msgstr ""
msgid "Raw blob request rate limit per minute" msgid "Raw blob request rate limit per minute"
msgstr "" msgstr ""
...@@ -18861,9 +18843,6 @@ msgstr "" ...@@ -18861,9 +18843,6 @@ msgstr ""
msgid "SSH Keys" msgid "SSH Keys"
msgstr "" msgstr ""
msgid "SSH Keys Help"
msgstr ""
msgid "SSH host key fingerprints" msgid "SSH host key fingerprints"
msgstr "" msgstr ""
...@@ -21343,9 +21322,6 @@ msgstr "" ...@@ -21343,9 +21322,6 @@ msgstr ""
msgid "System Hooks" msgid "System Hooks"
msgstr "" msgstr ""
msgid "System Hooks Help"
msgstr ""
msgid "System Info" msgid "System Info"
msgstr "" msgstr ""
...@@ -23975,9 +23951,6 @@ msgstr "" ...@@ -23975,9 +23951,6 @@ msgstr ""
msgid "User restrictions" msgid "User restrictions"
msgstr "" msgstr ""
msgid "User settings"
msgstr ""
msgid "User was successfully created." msgid "User was successfully created."
msgstr "" msgstr ""
...@@ -24789,9 +24762,6 @@ msgstr "" ...@@ -24789,9 +24762,6 @@ msgstr ""
msgid "Webhooks" msgid "Webhooks"
msgstr "" msgstr ""
msgid "Webhooks Help"
msgstr ""
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
msgstr "" msgstr ""
...@@ -25058,9 +25028,6 @@ msgstr "" ...@@ -25058,9 +25028,6 @@ msgstr ""
msgid "Work in progress Limit" msgid "Work in progress Limit"
msgstr "" msgstr ""
msgid "Workflow Help"
msgstr ""
msgid "Write" msgid "Write"
msgstr "" msgstr ""
......
...@@ -211,9 +211,4 @@ describe SearchController do ...@@ -211,9 +211,4 @@ describe SearchController do
end.to raise_error(ActionController::ParameterMissing) end.to raise_error(ActionController::ParameterMissing)
end end
end end
describe 'GET #autocomplete' do
it_behaves_like 'when the user cannot read cross project', :autocomplete, { term: 'hello' }
it_behaves_like 'with external authorization service enabled', :autocomplete, { term: 'hello' }
end
end end
...@@ -8,99 +8,6 @@ describe SearchHelper do ...@@ -8,99 +8,6 @@ describe SearchHelper do
str str
end end
describe 'search_autocomplete_opts' do
context "with no current user" do
before do
allow(self).to receive(:current_user).and_return(nil)
end
it "returns nil" do
expect(search_autocomplete_opts("q")).to be_nil
end
end
context "with a standard user" do
let(:user) { create(:user) }
before do
allow(self).to receive(:current_user).and_return(user)
end
it "includes Help sections" do
expect(search_autocomplete_opts("hel").size).to eq(9)
end
it "includes default sections" do
expect(search_autocomplete_opts("dash").size).to eq(1)
end
it "does not include admin sections" do
expect(search_autocomplete_opts("admin").size).to eq(0)
end
it "does not allow regular expression in search term" do
expect(search_autocomplete_opts("(webhooks|api)").size).to eq(0)
end
it "includes the user's groups" do
create(:group).add_owner(user)
expect(search_autocomplete_opts("gro").size).to eq(1)
end
it "includes nested group" do
create(:group, :nested, name: 'foo').add_owner(user)
expect(search_autocomplete_opts('foo').size).to eq(1)
end
it "includes the user's projects" do
project = create(:project, namespace: create(:namespace, owner: user))
expect(search_autocomplete_opts(project.name).size).to eq(1)
end
it "includes the required project attrs" do
project = create(:project, namespace: create(:namespace, owner: user))
result = search_autocomplete_opts(project.name).first
expect(result.keys).to match_array(%i[category id value label url avatar_url])
end
it "includes the required group attrs" do
create(:group).add_owner(user)
result = search_autocomplete_opts("gro").first
expect(result.keys).to match_array(%i[category id label url avatar_url])
end
it "does not include the public group" do
group = create(:group)
expect(search_autocomplete_opts(group.name).size).to eq(0)
end
context "with a current project" do
before do
@project = create(:project, :repository)
end
it "includes project-specific sections" do
expect(search_autocomplete_opts("Files").size).to eq(1)
expect(search_autocomplete_opts("Commits").size).to eq(1)
end
end
end
context 'with an admin user' do
let(:admin) { create(:admin) }
before do
allow(self).to receive(:current_user).and_return(admin)
end
it "includes admin sections" do
expect(search_autocomplete_opts("admin").size).to eq(1)
end
end
end
describe 'search_entries_info' do describe 'search_entries_info' do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
import $ from 'jquery'; import $ from 'jquery';
import '~/gl_dropdown'; import '~/gl_dropdown';
import initSearchAutocomplete from '~/search_autocomplete'; import initGlobalSearchInput from '~/global_search_input';
import '~/lib/utils/common_utils'; import '~/lib/utils/common_utils';
describe('Search autocomplete dropdown', () => { describe('Global search input dropdown', () => {
let widget = null; let widget = null;
const userName = 'root'; const userName = 'root';
...@@ -112,15 +112,15 @@ describe('Search autocomplete dropdown', () => { ...@@ -112,15 +112,15 @@ describe('Search autocomplete dropdown', () => {
expect(list.find(mrsIHaveCreatedLink).text()).toBe("Merge requests I've created"); expect(list.find(mrsIHaveCreatedLink).text()).toBe("Merge requests I've created");
}; };
preloadFixtures('static/search_autocomplete.html'); preloadFixtures('static/global_search_input.html');
beforeEach(function() { beforeEach(function() {
loadFixtures('static/search_autocomplete.html'); loadFixtures('static/global_search_input.html');
window.gon = {}; window.gon = {};
window.gon.current_user_id = userId; window.gon.current_user_id = userId;
window.gon.current_username = userName; window.gon.current_username = userName;
return (widget = initSearchAutocomplete()); return (widget = initGlobalSearchInput());
}); });
afterEach(function() { afterEach(function() {
...@@ -189,25 +189,25 @@ describe('Search autocomplete dropdown', () => { ...@@ -189,25 +189,25 @@ describe('Search autocomplete dropdown', () => {
expect(submitSpy).not.toHaveBeenTriggered(); expect(submitSpy).not.toHaveBeenTriggered();
}); });
describe('disableAutocomplete', function() { describe('disableDropdown', function() {
beforeEach(function() { beforeEach(function() {
widget.enableAutocomplete(); widget.enableDropdown();
}); });
it('should close the Dropdown', function() { it('should close the Dropdown', function() {
const toggleSpy = spyOn(widget.dropdownToggle, 'dropdown'); const toggleSpy = spyOn(widget.dropdownToggle, 'dropdown');
widget.dropdown.addClass('show'); widget.dropdown.addClass('show');
widget.disableAutocomplete(); widget.disableDropdown();
expect(toggleSpy).toHaveBeenCalledWith('toggle'); expect(toggleSpy).toHaveBeenCalledWith('toggle');
}); });
}); });
describe('enableAutocomplete', function() { describe('enableDropdown', function() {
it('should open the Dropdown', function() { it('should open the Dropdown', function() {
const toggleSpy = spyOn(widget.dropdownToggle, 'dropdown'); const toggleSpy = spyOn(widget.dropdownToggle, 'dropdown');
widget.enableAutocomplete(); widget.enableDropdown();
expect(toggleSpy).toHaveBeenCalledWith('toggle'); expect(toggleSpy).toHaveBeenCalledWith('toggle');
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment