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'; ...@@ -35,6 +35,7 @@ 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';
import { initTopNav } from './nav'; import { initTopNav } from './nav';
import { initHeaderSearchApp } from '~/header_search';
import 'ee_else_ce/main_ee'; import 'ee_else_ce/main_ee';
import 'jh_else_ce/main_jh'; import 'jh_else_ce/main_jh';
...@@ -95,20 +96,24 @@ function deferredInitialisation() { ...@@ -95,20 +96,24 @@ function deferredInitialisation() {
initDefaultTrackers(); initDefaultTrackers();
initFeatureHighlight(); initFeatureHighlight();
const search = document.querySelector('#search'); if (gon.features?.newHeaderSearch) {
if (search) { initHeaderSearchApp();
search.addEventListener( } else {
'focus', const search = document.querySelector('#search');
() => { if (search) {
import(/* webpackChunkName: 'globalSearch' */ './search_autocomplete') search.addEventListener(
.then(({ default: initSearchAutocomplete }) => { 'focus',
const searchDropdown = initSearchAutocomplete(); () => {
searchDropdown.onSearchInputFocus(); import(/* webpackChunkName: 'globalSearch' */ './search_autocomplete')
}) .then(({ default: initSearchAutocomplete }) => {
.catch(() => {}); const searchDropdown = initSearchAutocomplete();
}, searchDropdown.onSearchInputFocus();
{ once: true }, })
); .catch(() => {});
},
{ once: true },
);
}
} }
addSelectOnFocusBehaviour('.js-select-on-focus'); addSelectOnFocusBehaviour('.js-select-on-focus');
......
...@@ -44,6 +44,17 @@ body.gl-dark { ...@@ -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 { .search {
form { form {
background-color: var(--gray-100); background-color: var(--gray-100);
......
...@@ -37,6 +37,16 @@ input[type='checkbox']:hover { ...@@ -37,6 +37,16 @@ input[type='checkbox']:hover {
0 0 0 1px lighten($dropdown-input-focus-shadow, 20%); 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 { .search {
margin: 0 8px; margin: 0 8px;
......
...@@ -375,6 +375,38 @@ h1 { ...@@ -375,6 +375,38 @@ h1 {
.m-auto { .m-auto {
margin: auto !important; 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 { .gl-button {
display: inline-flex; display: inline-flex;
} }
...@@ -1410,6 +1442,9 @@ svg.s12 { ...@@ -1410,6 +1442,9 @@ svg.s12 {
svg.s16 { svg.s16 {
vertical-align: -3px; vertical-align: -3px;
} }
.header-search {
width: 320px;
}
.search { .search {
margin: 0 8px; margin: 0 8px;
} }
...@@ -1636,6 +1671,22 @@ body.gl-dark ...@@ -1636,6 +1671,22 @@ body.gl-dark
.notification-dot { .notification-dot {
background-color: #fafafa; 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 { body.gl-dark .search form {
background-color: rgba(250, 250, 250, 0.2); background-color: rgba(250, 250, 250, 0.2);
} }
...@@ -1669,6 +1720,14 @@ body.gl-dark .navbar-gitlab .navbar-nav li.active > button { ...@@ -1669,6 +1720,14 @@ body.gl-dark .navbar-gitlab .navbar-nav li.active > button {
color: var(--gl-text-color); color: var(--gl-text-color);
background-color: var(--gray-200); 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 { body.gl-dark .navbar-gitlab .search form {
background-color: var(--gray-100); background-color: var(--gray-100);
box-shadow: inset 0 0 0 1px var(--border-color); box-shadow: inset 0 0 0 1px var(--border-color);
......
...@@ -355,6 +355,38 @@ h1 { ...@@ -355,6 +355,38 @@ h1 {
.m-auto { .m-auto {
margin: auto !important; 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 { .gl-button {
display: inline-flex; display: inline-flex;
} }
...@@ -1390,6 +1422,9 @@ svg.s12 { ...@@ -1390,6 +1422,9 @@ svg.s12 {
svg.s16 { svg.s16 {
vertical-align: -3px; vertical-align: -3px;
} }
.header-search {
width: 320px;
}
.search { .search {
margin: 0 8px; margin: 0 8px;
} }
......
...@@ -140,6 +140,34 @@ ...@@ -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 { .search {
form { form {
background-color: rgba($search-and-nav-links, 0.2); background-color: rgba($search-and-nav-links, 0.2);
......
...@@ -45,6 +45,16 @@ body { ...@@ -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 { .search {
form { form {
background-color: $white; background-color: $white;
......
...@@ -29,7 +29,12 @@ ...@@ -29,7 +29,12 @@
- if top_nav_show_search - if top_nav_show_search
- search_menu_item = top_nav_search_menu_item_attrs - search_menu_item = top_nav_search_menu_item_attrs
%li.nav-item.d-none.d-lg-block.m-auto %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' } %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 = 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)) = 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 { ...@@ -375,6 +375,38 @@ h1 {
.m-auto { .m-auto {
margin: auto !important; 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 { .gl-button {
display: inline-flex; display: inline-flex;
} }
...@@ -1410,6 +1442,9 @@ svg.s12 { ...@@ -1410,6 +1442,9 @@ svg.s12 {
svg.s16 { svg.s16 {
vertical-align: -3px; vertical-align: -3px;
} }
.header-search {
width: 320px;
}
.search { .search {
margin: 0 8px; margin: 0 8px;
} }
...@@ -1636,6 +1671,22 @@ body.gl-dark ...@@ -1636,6 +1671,22 @@ body.gl-dark
.notification-dot { .notification-dot {
background-color: #fafafa; 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 { body.gl-dark .search form {
background-color: rgba(250, 250, 250, 0.2); background-color: rgba(250, 250, 250, 0.2);
} }
...@@ -1669,6 +1720,14 @@ body.gl-dark .navbar-gitlab .navbar-nav li.active > button { ...@@ -1669,6 +1720,14 @@ body.gl-dark .navbar-gitlab .navbar-nav li.active > button {
color: var(--gl-text-color); color: var(--gl-text-color);
background-color: var(--gray-200); 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 { body.gl-dark .navbar-gitlab .search form {
background-color: var(--gray-100); background-color: var(--gray-100);
box-shadow: inset 0 0 0 1px var(--border-color); box-shadow: inset 0 0 0 1px var(--border-color);
......
...@@ -355,6 +355,38 @@ h1 { ...@@ -355,6 +355,38 @@ h1 {
.m-auto { .m-auto {
margin: auto !important; 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 { .gl-button {
display: inline-flex; display: inline-flex;
} }
...@@ -1390,6 +1422,9 @@ svg.s12 { ...@@ -1390,6 +1422,9 @@ svg.s12 {
svg.s16 { svg.s16 {
vertical-align: -3px; vertical-align: -3px;
} }
.header-search {
width: 320px;
}
.search { .search {
margin: 0 8px; margin: 0 8px;
} }
......
...@@ -54,6 +54,7 @@ module Gitlab ...@@ -54,6 +54,7 @@ module Gitlab
push_frontend_feature_flag(:usage_data_api, type: :ops, default_enabled: :yaml) 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(:security_auto_fix, default_enabled: false)
push_frontend_feature_flag(:improved_emoji_picker, default_enabled: :yaml) push_frontend_feature_flag(:improved_emoji_picker, default_enabled: :yaml)
push_frontend_feature_flag(:new_header_search, default_enabled: :yaml)
end end
# Exposes the state of a feature flag to the frontend code. # Exposes the state of a feature flag to the frontend code.
......
...@@ -29342,6 +29342,9 @@ msgstr "" ...@@ -29342,6 +29342,9 @@ msgstr ""
msgid "Search or filter results…" msgid "Search or filter results…"
msgstr "" msgstr ""
msgid "Search or jump to..."
msgstr ""
msgid "Search project" msgid "Search project"
msgstr "" msgstr ""
......
...@@ -50,6 +50,7 @@ const createMainOutput = ({ outFile, cssKeys, type }) => ({ ...@@ -50,6 +50,7 @@ const createMainOutput = ({ outFile, cssKeys, type }) => ({
htmlPaths: [ htmlPaths: [
path.join(FIXTURES_ROOT, `startup_css/project-${type}.html`), 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}-signed-out.html`),
path.join(FIXTURES_ROOT, `startup_css/project-${type}-search-ff-on.html`),
], ],
cssKeys, cssKeys,
purgeOptions: { purgeOptions: {
......
...@@ -11,40 +11,64 @@ RSpec.describe 'Global search' do ...@@ -11,40 +11,64 @@ RSpec.describe 'Global search' do
before do before do
project.add_maintainer(user) project.add_maintainer(user)
sign_in(user) sign_in(user)
visit dashboard_projects_path
end end
it 'increases usage ping searches counter' do describe 'when new_header_search feature is disabled' do
expect(Gitlab::UsageDataCounters::SearchCounter).to receive(:count).with(:navbar_searches) before do
expect(Gitlab::UsageDataCounters::SearchCounter).to receive(:count).with(:all_searches) # TODO: Remove this along with feature flag #339348
stub_feature_flags(new_header_search: false)
visit dashboard_projects_path
end
submit_search('foobar') it 'increases usage ping searches counter' do
end 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 submit_search('foobar')
before do
allow_next(SearchService).to receive(:per_page).and_return(1)
create_list(:issue, 2, project: project, title: 'initial')
end end
it "has a pagination" do describe 'I search through the issues and I see pagination' do
submit_search('initial') before do
select_search_scope('Issues') 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
end
it 'closes the dropdown on blur', :js do it 'closes the dropdown on blur', :js do
find('#search').click find('#search').click
fill_in 'search', with: "a" 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) expect(page).to have_no_selector("div[data-testid='dashboard-search-options'].show")
find('body').click 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
end end
...@@ -40,6 +40,21 @@ RSpec.describe 'Startup CSS fixtures', type: :controller do ...@@ -40,6 +40,21 @@ RSpec.describe 'Startup CSS fixtures', type: :controller do
expect(response).to be_successful expect(response).to be_successful
end 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 end
describe ProjectsController, '(Startup CSS fixtures)', type: :controller do 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| ...@@ -303,6 +303,11 @@ RSpec.configure do |config|
# For more information check https://gitlab.com/gitlab-com/gl-infra/production/-/issues/4321 # For more information check https://gitlab.com/gitlab-com/gl-infra/production/-/issues/4321
stub_feature_flags(block_issue_repositioning: false) 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) allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(enable_rugged)
else else
unstub_all_feature_flags 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