Commit 59582477 authored by Simon Knox's avatar Simon Knox

Merge branch '353029-non-js-header-search' into 'master'

Global Search - Support Non-JS searches

See merge request gitlab-org/gitlab!80964
parents 278994a2 65317192
......@@ -5,7 +5,7 @@ import createStore from './store';
Vue.use(Translate);
export const initHeaderSearchApp = () => {
export const initHeaderSearchApp = (search = '') => {
const el = document.getElementById('js-header-search');
if (!el) {
......@@ -18,7 +18,7 @@ export const initHeaderSearchApp = () => {
return new Vue({
el,
store: createStore({ searchPath, issuesPath, mrPath, autocompletePath, searchContext }),
store: createStore({ searchPath, issuesPath, mrPath, autocompletePath, searchContext, search }),
render(createElement) {
return createElement(HeaderSearchApp);
},
......
......@@ -13,11 +13,12 @@ export const getStoreConfig = ({
mrPath,
autocompletePath,
searchContext,
search,
}) => ({
actions,
getters,
mutations,
state: createState({ searchPath, issuesPath, mrPath, autocompletePath, searchContext }),
state: createState({ searchPath, issuesPath, mrPath, autocompletePath, searchContext, search }),
});
const createStore = (config) => new Vuex.Store(getStoreConfig(config));
......
const createState = ({ searchPath, issuesPath, mrPath, autocompletePath, searchContext }) => ({
const createState = ({
searchPath,
issuesPath,
mrPath,
autocompletePath,
searchContext,
search: '',
search,
}) => ({
searchPath,
issuesPath,
mrPath,
autocompletePath,
searchContext,
search,
autocompleteOptions: [],
autocompleteError: false,
loading: false,
......
......@@ -116,16 +116,18 @@ function deferredInitialisation() {
);
}
const search = document.querySelector('#search');
if (search) {
search.addEventListener(
const searchInputBox = document.querySelector('#search');
if (searchInputBox) {
searchInputBox.addEventListener(
'focus',
() => {
if (gon.features?.newHeaderSearch) {
import(/* webpackChunkName: 'globalSearch' */ '~/header_search')
.then(async ({ initHeaderSearchApp }) => {
await initHeaderSearchApp();
document.querySelector('#search').focus();
// In case the user started searching before we bootstrapped, let's pass the search along.
const initialSearchValue = searchInputBox.value;
await initHeaderSearchApp(initialSearchValue);
searchInputBox.focus();
})
.catch(() => {});
} else {
......
#js-header-search.header-search{ data: { 'search-context' => header_search_context.to_json,
'search-path' => search_path,
'issues-path' => issues_dashboard_path,
'mr-path' => merge_requests_dashboard_path,
'autocomplete-path' => search_autocomplete_path } }
= form_tag search_path, method: :get do |_f|
.gl-search-box-by-type
= sprite_icon('search', css_class: 'gl-search-box-by-type-search-icon gl-icon')
%input{ id: 'search', name: 'search', type: "text", placeholder: s_('GlobalSearch|Search GitLab'), class: 'form-control gl-form-input gl-search-box-by-type-input', autocomplete: 'off' }
= hidden_field_tag :group_id, header_search_context[:group][:id] if header_search_context[:group]
= hidden_field_tag :project_id, header_search_context[:project][:id] if header_search_context[:project]
- if header_search_context[:group] || header_search_context[:project]
= hidden_field_tag :scope, header_search_context[:scope]
= hidden_field_tag :search_code, header_search_context[:code_search]
= hidden_field_tag :snippets, header_search_context[:for_snippets]
= hidden_field_tag :repository_ref, header_search_context[:ref]
= hidden_field_tag :nav_source, 'navbar'
-# workaround for non-JS feature specs, see spec/support/helpers/search_helpers.rb
- if ENV['RAILS_ENV'] == 'test'
%noscript= button_tag 'Search'
......@@ -41,14 +41,7 @@
%li.nav-item.header-search-new.d-none.d-lg-block.m-auto
- unless current_controller?(:search)
- if Feature.enabled?(:new_header_search)
#js-header-search.header-search{ data: { 'search-context' => header_search_context.to_json,
'search-path' => search_path,
'issues-path' => issues_dashboard_path,
'mr-path' => merge_requests_dashboard_path,
'autocomplete-path' => search_autocomplete_path } }
.gl-search-box-by-type
= sprite_icon('search', css_class: 'gl-search-box-by-type-search-icon gl-icon')
%input{ type: "text", placeholder: s_('GlobalSearch|Search GitLab'), class: 'form-control gl-form-input gl-search-box-by-type-input', id: 'search', autocomplete: 'off' }
= render 'layouts/header_search'
- else
= render 'layouts/search'
%li.nav-item{ class: 'd-none d-sm-inline-block d-lg-none' }
......
......@@ -72,6 +72,10 @@ RSpec.describe 'Global search' do
# TODO: Remove this along with feature flag #339348
stub_feature_flags(new_header_search: true)
visit dashboard_projects_path
# intialize javascript loaded input search input field
find('#search').click
find('body').click
end
it 'renders updated search bar' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'layouts/_header_search' do
let(:project) { nil }
let(:group) { nil }
let(:scope) { nil }
let(:ref) { nil }
let(:code_search) { false }
let(:for_snippets) { false}
let(:header_search_context) do
{
project: project,
group: group,
scope: scope,
ref: ref,
code_search: code_search,
for_snippets: for_snippets
}
end
before do
allow(view).to receive(:header_search_context).and_return(header_search_context)
end
shared_examples 'hidden fields are properly set' do
context 'when search_context has a scope value' do
let(:scope) { 'issues' }
it 'sets scope input to issues' do
render
expect(rendered).to have_css("input[name='scope'][value='#{scope}']", count: 1, visible: false)
end
end
context 'when search_context has a code_search value' do
let(:code_search) { true }
it 'sets search_code input to true' do
render
expect(rendered).to have_css("input[name='search_code'][value='#{code_search}']", count: 1, visible: false)
end
end
context 'when search_context has a ref value' do
let(:ref) { 'test-branch' }
it 'sets repository_ref input to test-branch' do
render
expect(rendered).to have_css("input[name='repository_ref'][value='#{ref}']", count: 1, visible: false)
end
end
context 'when search_context has a for_snippets value' do
let(:for_snippets) { true }
it 'sets for_snippets input to true' do
render
expect(rendered).to have_css("input[name='snippets'][value='#{for_snippets}']", count: 1, visible: false)
end
end
context 'nav_source' do
it 'always set to navbar' do
render
expect(rendered).to have_css("input[name='nav_source'][value='navbar']", count: 1, visible: false)
end
end
context 'submit button' do
it 'always renders for specs' do
render
expect(rendered).to have_css('noscript button', text: 'Search')
end
end
end
context 'when doing a project level search' do
let(:project) do
{ id: 123, name: 'foo' }
end
it 'sets project_id field' do
render
expect(rendered).to have_css("input[name='project_id'][value='#{project[:id]}']", count: 1, visible: false)
end
it_behaves_like 'hidden fields are properly set'
end
context 'when doing a group level search' do
let(:group) do
{ id: 123, name: 'bar' }
end
it 'sets group_id field' do
render
expect(rendered).to have_css("input[name='group_id'][value='#{group[:id]}']", count: 1, visible: false)
end
it_behaves_like 'hidden fields are properly set'
end
end
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