Commit 49c71733 authored by Zack Cuddy's avatar Zack Cuddy Committed by Mike Greiling

Global Search - Header Search Refactor Init

parent 5415f835
<script>
import { GlSearchBoxByType } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
name: 'HeaderSearchApp',
i18n: {
searchPlaceholder: __('Search or jump to...'),
},
components: {
GlSearchBoxByType,
},
};
</script>
<template>
<section class="header-search">
<gl-search-box-by-type autocomplete="off" :placeholder="$options.i18n.searchPlaceholder" />
</section>
</template>
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
import HeaderSearchApp from './components/app.vue';
Vue.use(Translate);
export const initHeaderSearchApp = () => {
const el = document.getElementById('js-header-search');
if (!el) {
return false;
}
return new Vue({
el,
render(createElement) {
return createElement(HeaderSearchApp);
},
});
};
......@@ -35,6 +35,7 @@ import GlFieldErrors from './gl_field_errors';
import initUserPopovers from './user_popovers';
import initBroadcastNotifications from './broadcast_notification';
import { initTopNav } from './nav';
import { initHeaderSearchApp } from '~/header_search';
import 'ee_else_ce/main_ee';
import 'jh_else_ce/main_jh';
......@@ -95,20 +96,24 @@ function deferredInitialisation() {
initDefaultTrackers();
initFeatureHighlight();
const search = document.querySelector('#search');
if (search) {
search.addEventListener(
'focus',
() => {
import(/* webpackChunkName: 'globalSearch' */ './search_autocomplete')
.then(({ default: initSearchAutocomplete }) => {
const searchDropdown = initSearchAutocomplete();
searchDropdown.onSearchInputFocus();
})
.catch(() => {});
},
{ once: true },
);
if (gon.features?.newHeaderSearch) {
initHeaderSearchApp();
} else {
const search = document.querySelector('#search');
if (search) {
search.addEventListener(
'focus',
() => {
import(/* webpackChunkName: 'globalSearch' */ './search_autocomplete')
.then(({ default: initSearchAutocomplete }) => {
const searchDropdown = initSearchAutocomplete();
searchDropdown.onSearchInputFocus();
})
.catch(() => {});
},
{ once: true },
);
}
}
addSelectOnFocusBehaviour('.js-select-on-focus');
......
......@@ -44,6 +44,17 @@ body.gl-dark {
}
}
.header-search {
background-color: var(--gray-100) !important;
box-shadow: inset 0 0 0 1px var(--border-color) !important;
&:active,
&:hover {
background-color: var(--gray-100) !important;
box-shadow: inset 0 0 0 1px var(--blue-200) !important;
}
}
.search {
form {
background-color: var(--gray-100);
......
......@@ -37,6 +37,16 @@ input[type='checkbox']:hover {
0 0 0 1px lighten($dropdown-input-focus-shadow, 20%);
}
.header-search {
width: 320px;
input,
svg {
transition: border-color ease-in-out $default-transition-duration,
background-color ease-in-out $default-transition-duration;
}
}
.search {
margin: 0 8px;
......
......@@ -375,6 +375,38 @@ h1 {
.m-auto {
margin: auto !important;
}
.gl-form-input,
.gl-form-input.form-control {
background-color: #333;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Noto Sans", Ubuntu, Cantarell, "Helvetica Neue", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 0.875rem;
line-height: 1rem;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
padding-left: 0.75rem;
padding-right: 0.75rem;
height: auto;
color: #fafafa;
box-shadow: inset 0 0 0 1px #868686;
border-style: none;
appearance: none;
-moz-appearance: none;
}
.gl-form-input:disabled,
.gl-form-input:not(.form-control-plaintext):not([type="color"]):read-only,
.gl-form-input.form-control:disabled,
.gl-form-input.form-control:not(.form-control-plaintext):not([type="color"]):read-only {
background-color: #1f1f1f;
color: #868686;
box-shadow: inset 0 0 0 1px #404040;
cursor: not-allowed;
}
.gl-form-input::placeholder,
.gl-form-input.form-control::placeholder {
color: #868686;
}
.gl-button {
display: inline-flex;
}
......@@ -1410,6 +1442,9 @@ svg.s12 {
svg.s16 {
vertical-align: -3px;
}
.header-search {
width: 320px;
}
.search {
margin: 0 8px;
}
......@@ -1636,6 +1671,22 @@ body.gl-dark
.notification-dot {
background-color: #fafafa;
}
body.gl-dark .header-search {
background-color: rgba(250, 250, 250, 0.2) !important;
}
body.gl-dark .header-search svg {
color: rgba(250, 250, 250, 0.8) !important;
}
body.gl-dark .header-search input {
background-color: transparent;
color: rgba(250, 250, 250, 0.8);
}
body.gl-dark .header-search input::placeholder {
color: rgba(250, 250, 250, 0.8);
}
body.gl-dark .header-search input:active::placeholder {
color: #fafafa;
}
body.gl-dark .search form {
background-color: rgba(250, 250, 250, 0.2);
}
......@@ -1669,6 +1720,14 @@ body.gl-dark .navbar-gitlab .navbar-nav li.active > button {
color: var(--gl-text-color);
background-color: var(--gray-200);
}
body.gl-dark .navbar-gitlab .header-search {
background-color: var(--gray-100) !important;
box-shadow: inset 0 0 0 1px var(--border-color) !important;
}
body.gl-dark .navbar-gitlab .header-search:active {
background-color: var(--gray-100) !important;
box-shadow: inset 0 0 0 1px var(--blue-200) !important;
}
body.gl-dark .navbar-gitlab .search form {
background-color: var(--gray-100);
box-shadow: inset 0 0 0 1px var(--border-color);
......
......@@ -355,6 +355,38 @@ h1 {
.m-auto {
margin: auto !important;
}
.gl-form-input,
.gl-form-input.form-control {
background-color: #fff;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Noto Sans", Ubuntu, Cantarell, "Helvetica Neue", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 0.875rem;
line-height: 1rem;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
padding-left: 0.75rem;
padding-right: 0.75rem;
height: auto;
color: #303030;
box-shadow: inset 0 0 0 1px #868686;
border-style: none;
appearance: none;
-moz-appearance: none;
}
.gl-form-input:disabled,
.gl-form-input:not(.form-control-plaintext):not([type="color"]):read-only,
.gl-form-input.form-control:disabled,
.gl-form-input.form-control:not(.form-control-plaintext):not([type="color"]):read-only {
background-color: #fafafa;
color: #868686;
box-shadow: inset 0 0 0 1px #dbdbdb;
cursor: not-allowed;
}
.gl-form-input::placeholder,
.gl-form-input.form-control::placeholder {
color: #868686;
}
.gl-button {
display: inline-flex;
}
......@@ -1390,6 +1422,9 @@ svg.s12 {
svg.s16 {
vertical-align: -3px;
}
.header-search {
width: 320px;
}
.search {
margin: 0 8px;
}
......
......@@ -140,6 +140,34 @@
}
}
.header-search {
background-color: rgba($search-and-nav-links, 0.2) !important;
&:hover {
background-color: rgba($search-and-nav-links, 0.3) !important;
}
svg {
color: rgba($search-and-nav-links, 0.8) !important;
}
input {
background-color: transparent;
color: rgba($search-and-nav-links, 0.8);
&::placeholder {
color: rgba($search-and-nav-links, 0.8);
}
&:focus,
&:active {
&::placeholder {
color: $search-and-nav-links;
}
}
}
}
.search {
form {
background-color: rgba($search-and-nav-links, 0.2);
......
......@@ -45,6 +45,16 @@ body {
}
}
.header-search {
background-color: $white !important;
box-shadow: inset 0 0 0 1px $border-color !important;
&:hover {
background-color: $white !important;
box-shadow: inset 0 0 0 1px $blue-200 !important;
}
}
.search {
form {
background-color: $white;
......
......@@ -29,7 +29,12 @@
- if top_nav_show_search
- search_menu_item = top_nav_search_menu_item_attrs
%li.nav-item.d-none.d-lg-block.m-auto
= render 'layouts/search' unless current_controller?(:search)
- unless current_controller?(:search)
- if Feature.enabled?(:new_header_search)
#js-header-search.header-search{ }
%input{ type: "text", placeholder: _('Search or jump to...'), class: 'form-control gl-form-input' }
- else
= render 'layouts/search'
%li.nav-item{ class: 'd-none d-sm-inline-block d-lg-none' }
= link_to search_menu_item.fetch(:href), title: search_menu_item.fetch(:title), aria: { label: search_menu_item.fetch(:title) }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon(search_menu_item.fetch(:icon))
......
---
name: new_header_search
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68681
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339348
milestone: '14.3'
type: development
group: group::global search
default_enabled: false
......@@ -375,6 +375,38 @@ h1 {
.m-auto {
margin: auto !important;
}
.gl-form-input,
.gl-form-input.form-control {
background-color: #333;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Noto Sans", Ubuntu, Cantarell, "Helvetica Neue", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 0.875rem;
line-height: 1rem;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
padding-left: 0.75rem;
padding-right: 0.75rem;
height: auto;
color: #fafafa;
box-shadow: inset 0 0 0 1px #868686;
border-style: none;
appearance: none;
-moz-appearance: none;
}
.gl-form-input:disabled,
.gl-form-input:not(.form-control-plaintext):not([type="color"]):read-only,
.gl-form-input.form-control:disabled,
.gl-form-input.form-control:not(.form-control-plaintext):not([type="color"]):read-only {
background-color: #1f1f1f;
color: #868686;
box-shadow: inset 0 0 0 1px #404040;
cursor: not-allowed;
}
.gl-form-input::placeholder,
.gl-form-input.form-control::placeholder {
color: #868686;
}
.gl-button {
display: inline-flex;
}
......@@ -1410,6 +1442,9 @@ svg.s12 {
svg.s16 {
vertical-align: -3px;
}
.header-search {
width: 320px;
}
.search {
margin: 0 8px;
}
......@@ -1636,6 +1671,22 @@ body.gl-dark
.notification-dot {
background-color: #fafafa;
}
body.gl-dark .header-search {
background-color: rgba(250, 250, 250, 0.2) !important;
}
body.gl-dark .header-search svg {
color: rgba(250, 250, 250, 0.8) !important;
}
body.gl-dark .header-search input {
background-color: transparent;
color: rgba(250, 250, 250, 0.8);
}
body.gl-dark .header-search input::placeholder {
color: rgba(250, 250, 250, 0.8);
}
body.gl-dark .header-search input:active::placeholder {
color: #fafafa;
}
body.gl-dark .search form {
background-color: rgba(250, 250, 250, 0.2);
}
......@@ -1669,6 +1720,14 @@ body.gl-dark .navbar-gitlab .navbar-nav li.active > button {
color: var(--gl-text-color);
background-color: var(--gray-200);
}
body.gl-dark .navbar-gitlab .header-search {
background-color: var(--gray-100) !important;
box-shadow: inset 0 0 0 1px var(--border-color) !important;
}
body.gl-dark .navbar-gitlab .header-search:active {
background-color: var(--gray-100) !important;
box-shadow: inset 0 0 0 1px var(--blue-200) !important;
}
body.gl-dark .navbar-gitlab .search form {
background-color: var(--gray-100);
box-shadow: inset 0 0 0 1px var(--border-color);
......
......@@ -355,6 +355,38 @@ h1 {
.m-auto {
margin: auto !important;
}
.gl-form-input,
.gl-form-input.form-control {
background-color: #fff;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Noto Sans", Ubuntu, Cantarell, "Helvetica Neue", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 0.875rem;
line-height: 1rem;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
padding-left: 0.75rem;
padding-right: 0.75rem;
height: auto;
color: #303030;
box-shadow: inset 0 0 0 1px #868686;
border-style: none;
appearance: none;
-moz-appearance: none;
}
.gl-form-input:disabled,
.gl-form-input:not(.form-control-plaintext):not([type="color"]):read-only,
.gl-form-input.form-control:disabled,
.gl-form-input.form-control:not(.form-control-plaintext):not([type="color"]):read-only {
background-color: #fafafa;
color: #868686;
box-shadow: inset 0 0 0 1px #dbdbdb;
cursor: not-allowed;
}
.gl-form-input::placeholder,
.gl-form-input.form-control::placeholder {
color: #868686;
}
.gl-button {
display: inline-flex;
}
......@@ -1390,6 +1422,9 @@ svg.s12 {
svg.s16 {
vertical-align: -3px;
}
.header-search {
width: 320px;
}
.search {
margin: 0 8px;
}
......
......@@ -54,6 +54,7 @@ module Gitlab
push_frontend_feature_flag(:usage_data_api, type: :ops, default_enabled: :yaml)
push_frontend_feature_flag(:security_auto_fix, default_enabled: false)
push_frontend_feature_flag(:improved_emoji_picker, default_enabled: :yaml)
push_frontend_feature_flag(:new_header_search, default_enabled: :yaml)
end
# Exposes the state of a feature flag to the frontend code.
......
......@@ -29342,6 +29342,9 @@ msgstr ""
msgid "Search or filter results…"
msgstr ""
msgid "Search or jump to..."
msgstr ""
msgid "Search project"
msgstr ""
......
......@@ -50,6 +50,7 @@ const createMainOutput = ({ outFile, cssKeys, type }) => ({
htmlPaths: [
path.join(FIXTURES_ROOT, `startup_css/project-${type}.html`),
path.join(FIXTURES_ROOT, `startup_css/project-${type}-signed-out.html`),
path.join(FIXTURES_ROOT, `startup_css/project-${type}-search-ff-on.html`),
],
cssKeys,
purgeOptions: {
......
......@@ -11,40 +11,64 @@ RSpec.describe 'Global search' do
before do
project.add_maintainer(user)
sign_in(user)
visit dashboard_projects_path
end
it 'increases usage ping searches counter' do
expect(Gitlab::UsageDataCounters::SearchCounter).to receive(:count).with(:navbar_searches)
expect(Gitlab::UsageDataCounters::SearchCounter).to receive(:count).with(:all_searches)
describe 'when new_header_search feature is disabled' do
before do
# TODO: Remove this along with feature flag #339348
stub_feature_flags(new_header_search: false)
visit dashboard_projects_path
end
submit_search('foobar')
end
it 'increases usage ping searches counter' do
expect(Gitlab::UsageDataCounters::SearchCounter).to receive(:count).with(:navbar_searches)
expect(Gitlab::UsageDataCounters::SearchCounter).to receive(:count).with(:all_searches)
describe 'I search through the issues and I see pagination' do
before do
allow_next(SearchService).to receive(:per_page).and_return(1)
create_list(:issue, 2, project: project, title: 'initial')
submit_search('foobar')
end
it "has a pagination" do
submit_search('initial')
select_search_scope('Issues')
describe 'I search through the issues and I see pagination' do
before do
allow_next(SearchService).to receive(:per_page).and_return(1)
create_list(:issue, 2, project: project, title: 'initial')
end
it "has a pagination" do
submit_search('initial')
select_search_scope('Issues')
expect(page).to have_selector('.gl-pagination .next')
expect(page).to have_selector('.gl-pagination .next')
end
end
end
it 'closes the dropdown on blur', :js do
find('#search').click
fill_in 'search', with: "a"
it 'closes the dropdown on blur', :js do
find('#search').click
fill_in 'search', with: "a"
expect(page).to have_selector("div[data-testid='dashboard-search-options'].show")
expect(page).to have_selector("div[data-testid='dashboard-search-options'].show")
find('#search').send_keys(:backspace)
find('body').click
find('#search').send_keys(:backspace)
find('body').click
expect(page).to have_no_selector("div[data-testid='dashboard-search-options'].show")
end
it 'renders legacy search bar' do
expect(page).to have_selector('.search-form')
expect(page).to have_no_selector('#js-header-search')
end
end
expect(page).to have_no_selector("div[data-testid='dashboard-search-options'].show")
describe 'when new_header_search feature is enabled' do
before do
# TODO: Remove this along with feature flag #339348
stub_feature_flags(new_header_search: true)
visit dashboard_projects_path
end
it 'renders updated search bar' do
expect(page).to have_no_selector('.search-form')
expect(page).to have_selector('#js-header-search')
end
end
end
......@@ -40,6 +40,21 @@ RSpec.describe 'Startup CSS fixtures', type: :controller do
expect(response).to be_successful
end
# This Feature Flag is off by default
# This ensures that the correct css is generated
# When the feature flag is off, the general startup will capture it
# This will be removed as part of https://gitlab.com/gitlab-org/gitlab/-/issues/339348
it "startup_css/project-#{type}-search-ff-on.html" do
stub_feature_flags(new_header_search: true)
get :show, params: {
namespace_id: project.namespace.to_param,
id: project
}
expect(response).to be_successful
end
end
describe ProjectsController, '(Startup CSS fixtures)', type: :controller do
......
import { GlSearchBoxByType } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import HeaderSearchApp from '~/header_search/components/app.vue';
describe('HeaderSearchApp', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMount(HeaderSearchApp);
};
afterEach(() => {
wrapper.destroy();
});
const findHeaderSearchInput = () => wrapper.findComponent(GlSearchBoxByType);
describe('template', () => {
beforeEach(() => {
createComponent();
});
it('renders Header Search Input always', () => {
expect(findHeaderSearchInput().exists()).toBe(true);
});
});
});
......@@ -303,6 +303,11 @@ RSpec.configure do |config|
# For more information check https://gitlab.com/gitlab-com/gl-infra/production/-/issues/4321
stub_feature_flags(block_issue_repositioning: false)
# Disable the refactored top nav search until there is functionality
# Can be removed once all existing functionality has been replicated
# For more information check https://gitlab.com/gitlab-org/gitlab/-/issues/339348
stub_feature_flags(new_header_search: false)
allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(enable_rugged)
else
unstub_all_feature_flags
......
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