Skip to content
Snippets Groups Projects
Commit 25f5089d authored by Tomas Bulva's avatar Tomas Bulva Committed by Zack Cuddy
Browse files

Remove the new_header_search FF

Changelog: changed
parent 99eb7103
No related branches found
No related tags found
3 merge requests!118700Remove refactor_vulnerability_filters feature flag,!116602Draft: Resolve "Remove the possibility to set redis_slot in known_events",!113859Remove the :new_header_search feature Flag
Showing
with 19 additions and 1103 deletions
......@@ -2,29 +2,18 @@ import * as Sentry from '@sentry/browser';
import { HEADER_INIT_EVENTS } from './constants';
async function eventHandler(callback = () => {}) {
if (this.newHeaderSearchFeatureFlag) {
const { initHeaderSearchApp } = await import(
/* webpackChunkName: 'globalSearch' */ '~/header_search'
).catch((error) => Sentry.captureException(error));
// In case the user started searching before we bootstrapped,
// let's pass the search along.
const initialSearchValue = this.searchInputBox.value;
initHeaderSearchApp(initialSearchValue);
// this is new #search input element. We need to re-find it.
// And re-focus in it.
document.querySelector('#search').focus();
callback();
return;
}
const { default: initSearchAutocomplete } = await import(
/* webpackChunkName: 'globalSearch' */ '../search_autocomplete'
const { initHeaderSearchApp } = await import(
/* webpackChunkName: 'globalSearch' */ '~/header_search'
).catch((error) => Sentry.captureException(error));
const searchDropdown = initSearchAutocomplete();
searchDropdown.onSearchInputFocus();
// In case the user started searching before we bootstrapped,
// let's pass the search along.
const initialSearchValue = this.searchInputBox.value;
initHeaderSearchApp(initialSearchValue);
// this is new #search input element. We need to re-find it.
// And re-focus in it.
document.querySelector('#search').focus();
callback();
}
......@@ -40,10 +29,7 @@ function initHeaderSearch() {
HEADER_INIT_EVENTS.forEach((eventType) => {
searchInputBox?.addEventListener(
eventType,
eventHandler.bind(
{ searchInputBox, newHeaderSearchFeatureFlag: gon?.features?.newHeaderSearch },
cleanEventListeners,
),
eventHandler.bind({ searchInputBox }, cleanEventListeners),
{ once: true },
);
});
......
<script>
import { mapState, mapGetters } from 'vuex';
import ScopeNavigation from '~/search/sidebar/components/scope_navigation.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { SCOPE_ISSUES, SCOPE_MERGE_REQUESTS, SCOPE_BLOB } from '../constants';
import ResultsFilters from './results_filters.vue';
import LanguageFilter from './language_filter.vue';
......@@ -13,7 +12,6 @@ export default {
ScopeNavigation,
LanguageFilter,
},
mixins: [glFeatureFlagsMixin()],
computed: {
...mapState(['urlQuery']),
...mapGetters(['currentScope']),
......
/* eslint-disable no-return-assign, consistent-return, class-methods-use-this */
import $ from 'jquery';
import { escape, throttle } from 'lodash';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
import { getIdenticonBackgroundClass, getIdenticonTitle } from '~/helpers/avatar_helper';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import { s__, __, sprintf } from '~/locale';
import Tracking from '~/tracking';
import axios from './lib/utils/axios_utils';
import { spriteIcon } from './lib/utils/common_utils';
import {
isInGroupsPage,
isInProjectPage,
getGroupSlug,
getProjectSlug,
} from './search_autocomplete_utils';
/**
* Search input in top navigation bar.
* On click, opens a dropdown
* As the user types it filters the results
* When the user clicks `x` button it cleans the input and closes the dropdown.
*/
const KEYCODE = {
ESCAPE: 27,
BACKSPACE: 8,
ENTER: 13,
UP: 38,
DOWN: 40,
};
function setSearchOptions() {
const $projectOptionsDataEl = $('.js-search-project-options');
const $groupOptionsDataEl = $('.js-search-group-options');
const $dashboardOptionsDataEl = $('.js-search-dashboard-options');
if ($projectOptionsDataEl.length) {
gl.projectOptions = gl.projectOptions || {};
const projectPath = $projectOptionsDataEl.data('projectPath');
gl.projectOptions[projectPath] = {
name: $projectOptionsDataEl.data('name'),
issuesPath: $projectOptionsDataEl.data('issuesPath'),
issuesDisabled: $projectOptionsDataEl.data('issuesDisabled'),
mrPath: $projectOptionsDataEl.data('mrPath'),
};
}
if ($groupOptionsDataEl.length) {
gl.groupOptions = gl.groupOptions || {};
const groupPath = $groupOptionsDataEl.data('groupPath');
gl.groupOptions[groupPath] = {
name: $groupOptionsDataEl.data('name'),
issuesPath: $groupOptionsDataEl.data('issuesPath'),
mrPath: $groupOptionsDataEl.data('mrPath'),
};
}
if ($dashboardOptionsDataEl.length) {
gl.dashboardOptions = {
name: s__('SearchAutocomplete|All GitLab'),
issuesPath: $dashboardOptionsDataEl.data('issuesPath'),
mrPath: $dashboardOptionsDataEl.data('mrPath'),
};
}
}
export class SearchAutocomplete {
constructor({ wrap, optsEl, autocompletePath, projectId, projectRef } = {}) {
setSearchOptions();
this.bindEventContext();
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.dropdownToggle = this.wrap.find('.js-dropdown-search-toggle');
this.dropdownMenu = this.dropdown.find('.dropdown-menu');
this.dropdownContent = this.dropdown.find('.dropdown-content');
this.scopeInputEl = this.getElement('#scope');
this.searchInput = this.getElement('.search-input');
this.projectInputEl = this.getElement('#search_project_id');
this.groupInputEl = this.getElement('#group_id');
this.searchCodeInputEl = this.getElement('#search_code');
this.repositoryInputEl = this.getElement('#repository_ref');
this.clearInput = this.getElement('.js-clear-input');
this.scrollFadeInitialized = false;
this.saveOriginalState();
// Only when user is logged in
if (gon.current_user_id) {
this.createAutocomplete();
}
this.bindEvents();
this.dropdownToggle.dropdown();
this.searchInput.addClass('js-autocomplete-disabled');
}
// Finds an element inside wrapper element
bindEventContext() {
this.onSearchInputBlur = this.onSearchInputBlur.bind(this);
this.onClearInputClick = this.onClearInputClick.bind(this);
this.onSearchInputFocus = this.onSearchInputFocus.bind(this);
this.onSearchInputKeyUp = this.onSearchInputKeyUp.bind(this);
this.onSearchInputChange = this.onSearchInputChange.bind(this);
this.setScrollFade = this.setScrollFade.bind(this);
}
getElement(selector) {
return this.wrap.find(selector);
}
saveOriginalState() {
return (this.originalState = this.serializeState());
}
createAutocomplete() {
return initDeprecatedJQueryDropdown(this.searchInput, {
filterInputBlur: false,
filterable: true,
filterRemote: true,
highlight: true,
icon: true,
enterCallback: false,
filterInput: 'input#search',
search: {
fields: ['text'],
},
id: this.getSearchText,
data: this.getData.bind(this),
selectable: true,
clicked: this.onClick.bind(this),
trackSuggestionClickedLabel: 'search_autocomplete_suggestion',
});
}
getSearchText(selectedObject) {
return selectedObject.id ? selectedObject.text : '';
}
getData(term, callback) {
if (!term) {
const contents = this.getCategoryContents();
if (contents) {
const deprecatedJQueryDropdownInstance = this.searchInput.data('deprecatedJQueryDropdown');
if (deprecatedJQueryDropdownInstance) {
deprecatedJQueryDropdownInstance.filter.options.callback(contents);
}
this.enableAutocomplete();
}
return;
}
// Prevent multiple ajax calls
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 = [
{
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 that I'm a reviewer"),
url: `${mrPath}/?reviewer_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;
}
// Add option to proceed with the search for each
// scope that is currently available, namely:
//
// - Search in this project
// - Search in this group (or project's group)
// - Search in all GitLab
scopedSearchOptions(term) {
const icon = spriteIcon('search', 's16 inline-search-icon');
const projectId = this.projectInputEl.val();
const groupId = this.groupInputEl.val();
const options = [];
if (projectId) {
const projectOptions = gl.projectOptions[getProjectSlug()];
const url = groupId
? `${gon.relative_url_root}/search?search=${term}&project_id=${projectId}&group_id=${groupId}&nav_source=navbar`
: `${gon.relative_url_root}/search?search=${term}&project_id=${projectId}&nav_source=navbar`;
options.push({
icon,
text: term,
template: sprintf(
s__(`SearchAutocomplete|in project %{projectName}`),
{
projectName: `<i>${projectOptions.name}</i>`,
},
false,
),
url,
});
}
if (groupId) {
const groupOptions = gl.groupOptions[getGroupSlug()];
options.push({
icon,
text: term,
template: sprintf(
s__(`SearchAutocomplete|in group %{groupName}`),
{
groupName: `<i>${groupOptions.name}</i>`,
},
false,
),
url: `${gon.relative_url_root}/search?search=${term}&group_id=${groupId}&nav_source=navbar`,
});
}
options.push({
icon,
text: term,
template: s__('SearchAutocomplete|in all GitLab'),
url: `${gon.relative_url_root}/search?search=${term}&nav_source=navbar`,
});
return options;
}
serializeState() {
return {
// Search Criteria
search_project_id: this.projectInputEl.val(),
group_id: this.groupInputEl.val(),
search_code: this.searchCodeInputEl.val(),
repository_ref: this.repositoryInputEl.val(),
scope: this.scopeInputEl.val(),
};
}
bindEvents() {
this.searchInput.on('input', this.onSearchInputChange);
this.searchInput.on('keyup', this.onSearchInputKeyUp);
this.searchInput.on('focus', this.onSearchInputFocus);
this.searchInput.on('blur', this.onSearchInputBlur);
this.clearInput.on('click', this.onClearInputClick);
this.dropdownContent.on(
'scroll',
throttle(this.setScrollFade, DEFAULT_DEBOUNCE_AND_THROTTLE_MS),
);
this.searchInput.on('click', (e) => {
e.stopPropagation();
});
}
enableAutocomplete() {
this.setScrollFade();
// No need to enable anything if user is not logged in
if (!gon.current_user_id) {
return;
}
// If the dropdown is closed, we'll open it
if (!this.dropdown.hasClass('show')) {
this.loadingSuggestions = false;
this.dropdownToggle.dropdown('toggle');
const trackEvent = 'click_search_bar';
const trackCategory = undefined; // will be default set in event method
Tracking.event(trackCategory, trackEvent, {
label: 'main_navigation',
property: 'navigation',
});
return this.searchInput.removeClass('js-autocomplete-disabled');
}
}
onSearchInputChange() {
this.enableAutocomplete();
}
onSearchInputKeyUp(e) {
switch (e.keyCode) {
case KEYCODE.ESCAPE:
this.restoreOriginalState();
break;
case KEYCODE.ENTER:
this.disableAutocomplete();
break;
default:
}
this.wrap.toggleClass('has-value', Boolean(e.target.value));
}
onSearchInputFocus() {
this.isFocused = true;
this.wrap.addClass('search-active');
if (this.getValue() === '') {
return this.getData();
}
}
getValue() {
return this.searchInput.val();
}
onClearInputClick(e) {
e.preventDefault();
this.wrap.toggleClass('has-value', Boolean(e.target.value));
return this.searchInput.val('').focus();
}
onSearchInputBlur() {
this.isFocused = false;
this.wrap.removeClass('search-active');
// If input is blank then restore state
if (this.searchInput.val() === '') {
this.restoreOriginalState();
}
this.dropdownMenu.removeClass('show');
}
restoreOriginalState() {
const inputs = Object.keys(this.originalState);
for (let i = 0, len = inputs.length; i < len; i += 1) {
const input = inputs[i];
this.getElement(`#${input}`).val(this.originalState[input]);
}
}
resetSearchState() {
const inputs = Object.keys(this.originalState);
const results = [];
for (let i = 0, len = inputs.length; i < len; i += 1) {
const input = inputs[i];
results.push(this.getElement(`#${input}`).val(''));
}
return results;
}
disableAutocomplete() {
if (!this.searchInput.hasClass('js-autocomplete-disabled') && this.dropdown.hasClass('show')) {
this.searchInput.addClass('js-autocomplete-disabled');
this.dropdownToggle.dropdown('toggle');
this.restoreMenu();
}
}
restoreMenu() {
const html = `<ul><li class="dropdown-menu-empty-item"><a>${__('Loading...')}</a></li></ul>`;
return this.dropdownContent.html(html);
}
onClick(item, $el, e) {
if (window.location.pathname.indexOf(item.url) !== -1) {
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');
this.disableAutocomplete();
return this.searchInput.val('').focus();
}
}
highlightFirstRow() {
this.searchInput.data('deprecatedJQueryDropdown').highlightRowAtIndex(null, 0);
}
getAvatar(item) {
if (!Object.prototype.hasOwnProperty.call(item, 'avatar_url')) {
return false;
}
const { label, id } = item;
const avatarUrl = item.avatar_url;
const avatar = avatarUrl
? `<img class="search-item-avatar" src="${avatarUrl}" />`
: `<div class="s16 avatar identicon ${getIdenticonBackgroundClass(id)}">${getIdenticonTitle(
escape(label),
)}</div>`;
return avatar;
}
isScrolledUp() {
const el = this.dropdownContent[0];
const currentPosition = this.contentClientHeight + el.scrollTop;
return currentPosition < this.maxPosition;
}
initScrollFade() {
const el = this.dropdownContent[0];
this.scrollFadeInitialized = true;
this.contentClientHeight = el.clientHeight;
this.maxPosition = el.scrollHeight;
this.dropdownMenu.addClass('dropdown-content-faded-mask');
}
setScrollFade() {
this.initScrollFade();
this.dropdownMenu.toggleClass('fade-out', !this.isScrolledUp());
}
}
export default function initSearchAutocomplete(opts) {
return new SearchAutocomplete(opts);
}
import { getPagePath } from './lib/utils/common_utils';
export const isInGroupsPage = () => getPagePath() === 'groups';
export const isInProjectPage = () => getPagePath() === 'projects';
export const getProjectSlug = () => {
if (isInProjectPage()) {
return document?.body?.dataset?.project;
}
return null;
};
export const getGroupSlug = () => {
if (isInProjectPage() || isInGroupsPage()) {
return document?.body?.dataset?.group;
}
return null;
};
......@@ -140,18 +140,6 @@ kbd kbd {
background-color: #24232a;
opacity: 1;
}
.form-inline {
display: flex;
flex-flow: row wrap;
align-items: center;
}
@media (min-width: 576px) {
.form-inline .form-control {
display: inline-block;
width: auto;
vertical-align: middle;
}
}
.btn {
display: inline-block;
font-weight: 400;
......@@ -562,17 +550,13 @@ strong {
svg {
vertical-align: baseline;
}
.form-control,
.search form {
.form-control {
font-size: 0.875rem;
}
.hidden {
display: none !important;
visibility: hidden !important;
}
.hide {
display: none;
}
.badge:not(.gl-badge) {
padding: 4px 5px;
font-size: 12px;
......@@ -638,37 +622,6 @@ html {
.dropdown {
position: relative;
}
.dropdown-menu-toggle:active {
box-shadow: 0 0 0 1px #333238, 0 0 0 3px #1f75cb;
outline: none;
}
.search-input-container .dropdown-menu {
margin-top: 11px;
}
.dropdown-menu-toggle {
padding: 6px 8px 6px 10px;
background-color: #333238;
color: #ececef;
font-size: 14px;
text-align: left;
border: 1px solid #535158;
border-radius: 0.25rem;
white-space: nowrap;
}
.dropdown-menu-toggle.no-outline {
outline: 0;
}
.dropdown-menu-toggle.dropdown-menu-toggle {
justify-content: flex-start;
overflow: hidden;
padding-top: 7px;
padding-bottom: 7px;
padding-right: 25px;
position: relative;
text-overflow: ellipsis;
line-height: 16px;
width: 160px;
}
.dropdown-menu {
display: none;
position: absolute;
......@@ -750,11 +703,6 @@ html {
min-width: 100%;
}
}
@media (max-width: 767.98px) {
.dropdown-menu-toggle.dropdown-menu-toggle {
width: 100%;
}
}
input {
border-radius: 0.25rem;
color: #ececef;
......@@ -1667,7 +1615,6 @@ svg.s16 {
--gray-200: #535158;
--gray-700: #bfbfc3;
--gray-900: #ececef;
--gl-text-color: #ececef;
--border-color: #434248;
--white: #333238;
--black: #fff;
......@@ -1779,16 +1726,6 @@ body.gl-dark .header-search .keyboard-shortcut-helper {
color: #ececef;
background-color: rgba(236, 236, 239, 0.2);
}
body.gl-dark .search form {
background-color: rgba(236, 236, 239, 0.2);
}
body.gl-dark .search .search-input::placeholder {
color: rgba(236, 236, 239, 0.8);
}
body.gl-dark .search .search-input-wrap .search-icon,
body.gl-dark .search .search-input-wrap .clear-icon {
fill: rgba(236, 236, 239, 0.8);
}
body.gl-dark .nav-sidebar li.active > a {
color: #ececef;
}
......@@ -1817,17 +1754,6 @@ 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);
}
body.gl-dark .navbar-gitlab .search form:active {
background-color: var(--gray-100);
box-shadow: inset 0 0 0 1px var(--blue-200);
}
body.gl-dark .navbar-gitlab .search form .search-input {
color: var(--gl-text-color);
}
.tab-width-8 {
tab-size: 8;
......
......@@ -140,18 +140,6 @@ kbd kbd {
background-color: #fbfafd;
opacity: 1;
}
.form-inline {
display: flex;
flex-flow: row wrap;
align-items: center;
}
@media (min-width: 576px) {
.form-inline .form-control {
display: inline-block;
width: auto;
vertical-align: middle;
}
}
.btn {
display: inline-block;
font-weight: 400;
......@@ -562,17 +550,13 @@ strong {
svg {
vertical-align: baseline;
}
.form-control,
.search form {
.form-control {
font-size: 0.875rem;
}
.hidden {
display: none !important;
visibility: hidden !important;
}
.hide {
display: none;
}
.badge:not(.gl-badge) {
padding: 4px 5px;
font-size: 12px;
......@@ -638,37 +622,6 @@ html {
.dropdown {
position: relative;
}
.dropdown-menu-toggle:active {
box-shadow: 0 0 0 1px #fff, 0 0 0 3px #428fdc;
outline: none;
}
.search-input-container .dropdown-menu {
margin-top: 11px;
}
.dropdown-menu-toggle {
padding: 6px 8px 6px 10px;
background-color: #fff;
color: #333238;
font-size: 14px;
text-align: left;
border: 1px solid #bfbfc3;
border-radius: 0.25rem;
white-space: nowrap;
}
.dropdown-menu-toggle.no-outline {
outline: 0;
}
.dropdown-menu-toggle.dropdown-menu-toggle {
justify-content: flex-start;
overflow: hidden;
padding-top: 7px;
padding-bottom: 7px;
padding-right: 25px;
position: relative;
text-overflow: ellipsis;
line-height: 16px;
width: 160px;
}
.dropdown-menu {
display: none;
position: absolute;
......@@ -750,11 +703,6 @@ html {
min-width: 100%;
}
}
@media (max-width: 767.98px) {
.dropdown-menu-toggle.dropdown-menu-toggle {
width: 100%;
}
}
input {
border-radius: 0.25rem;
color: #333238;
......
.search.search-form{ data: { track_label: "navbar_search", track_action: "activate_form_input", track_value: "" } }
= form_tag search_path, method: :get, class: 'form-inline form-control' do |_f|
.search-input-container
.search-input-wrap
.dropdown{ data: { url: search_autocomplete_path } }
= search_field_tag 'search', nil, placeholder: _('Search GitLab'),
class: 'search-input dropdown-menu-toggle no-outline js-search-dashboard-options',
spellcheck: false,
autocomplete: 'off',
data: { issues_path: issues_dashboard_path,
mr_path: merge_requests_dashboard_path,
qa_selector: 'search_term_field' },
aria: { label: _('Search GitLab') }
%button.hidden.js-dropdown-search-toggle{ type: 'button', data: { toggle: 'dropdown' } }
.dropdown-menu.dropdown-select{ data: { testid: 'dashboard-search-options' } }
= dropdown_content do
%ul
%li.dropdown-menu-empty-item
%a
= _('Loading...')
= dropdown_loading
= sprite_icon('search', css_class: 'search-icon')
= sprite_icon('close', css_class: 'clear-icon js-clear-input')
= hidden_field_tag :group_id, search_context.for_group? ? search_context.group.id : '', class: 'js-search-group-options', data: search_context.group_metadata
= hidden_field_tag :project_id, search_context.for_project? ? search_context.project.id : '', id: 'search_project_id', class: 'js-search-project-options', data: search_context.project_metadata
- if search_context.for_project? || search_context.for_group?
= hidden_field_tag :scope, search_context.scope
= hidden_field_tag :search_code, search_context.code_search?
- ref = search_context.ref if can?(current_user, :read_code, search_context.project)
= hidden_field_tag :snippets, search_context.for_snippets?
= hidden_field_tag :repository_ref, 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'
.search-autocomplete-opts.hide{ :'data-autocomplete-path' => search_autocomplete_path,
:'data-autocomplete-project-id' => search_context.project.try(:id),
:'data-autocomplete-project-ref' => ref }
......@@ -31,10 +31,7 @@
%ul.nav.navbar-nav.gl-w-full.gl-align-items-center
%li.nav-item.header-search-new.gl-display-none.gl-lg-display-block.gl-w-full
- unless current_controller?(:search)
- if Feature.enabled?(:new_header_search)
= render 'layouts/header_search'
- else
= render 'layouts/search'
= render 'layouts/header_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',
......
---
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: true
......@@ -140,18 +140,6 @@ kbd kbd {
background-color: #24232a;
opacity: 1;
}
.form-inline {
display: flex;
flex-flow: row wrap;
align-items: center;
}
@media (min-width: 576px) {
.form-inline .form-control {
display: inline-block;
width: auto;
vertical-align: middle;
}
}
.btn {
display: inline-block;
font-weight: 400;
......@@ -562,17 +550,13 @@ strong {
svg {
vertical-align: baseline;
}
.form-control,
.search form {
.form-control {
font-size: 0.875rem;
}
.hidden {
display: none !important;
visibility: hidden !important;
}
.hide {
display: none;
}
.badge:not(.gl-badge) {
padding: 4px 5px;
font-size: 12px;
......@@ -638,37 +622,6 @@ html {
.dropdown {
position: relative;
}
.dropdown-menu-toggle:active {
box-shadow: 0 0 0 1px #333238, 0 0 0 3px #1f75cb;
outline: none;
}
.search-input-container .dropdown-menu {
margin-top: 11px;
}
.dropdown-menu-toggle {
padding: 6px 8px 6px 10px;
background-color: #333238;
color: #ececef;
font-size: 14px;
text-align: left;
border: 1px solid #535158;
border-radius: 0.25rem;
white-space: nowrap;
}
.dropdown-menu-toggle.no-outline {
outline: 0;
}
.dropdown-menu-toggle.dropdown-menu-toggle {
justify-content: flex-start;
overflow: hidden;
padding-top: 7px;
padding-bottom: 7px;
padding-right: 25px;
position: relative;
text-overflow: ellipsis;
line-height: 16px;
width: 160px;
}
.dropdown-menu {
display: none;
position: absolute;
......@@ -750,11 +703,6 @@ html {
min-width: 100%;
}
}
@media (max-width: 767.98px) {
.dropdown-menu-toggle.dropdown-menu-toggle {
width: 100%;
}
}
input {
border-radius: 0.25rem;
color: #ececef;
......@@ -1667,7 +1615,6 @@ svg.s16 {
--gray-200: #535158;
--gray-700: #bfbfc3;
--gray-900: #ececef;
--gl-text-color: #ececef;
--border-color: #434248;
--white: #333238;
--black: #fff;
......@@ -1779,16 +1726,6 @@ body.gl-dark .header-search .keyboard-shortcut-helper {
color: #ececef;
background-color: rgba(236, 236, 239, 0.2);
}
body.gl-dark .search form {
background-color: rgba(236, 236, 239, 0.2);
}
body.gl-dark .search .search-input::placeholder {
color: rgba(236, 236, 239, 0.8);
}
body.gl-dark .search .search-input-wrap .search-icon,
body.gl-dark .search .search-input-wrap .clear-icon {
fill: rgba(236, 236, 239, 0.8);
}
body.gl-dark .nav-sidebar li.active > a {
color: #ececef;
}
......@@ -1817,17 +1754,6 @@ 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);
}
body.gl-dark .navbar-gitlab .search form:active {
background-color: var(--gray-100);
box-shadow: inset 0 0 0 1px var(--blue-200);
}
body.gl-dark .navbar-gitlab .search form .search-input {
color: var(--gl-text-color);
}
.tab-width-8 {
tab-size: 8;
......
......@@ -140,18 +140,6 @@ kbd kbd {
background-color: #fbfafd;
opacity: 1;
}
.form-inline {
display: flex;
flex-flow: row wrap;
align-items: center;
}
@media (min-width: 576px) {
.form-inline .form-control {
display: inline-block;
width: auto;
vertical-align: middle;
}
}
.btn {
display: inline-block;
font-weight: 400;
......@@ -562,17 +550,13 @@ strong {
svg {
vertical-align: baseline;
}
.form-control,
.search form {
.form-control {
font-size: 0.875rem;
}
.hidden {
display: none !important;
visibility: hidden !important;
}
.hide {
display: none;
}
.badge:not(.gl-badge) {
padding: 4px 5px;
font-size: 12px;
......@@ -638,37 +622,6 @@ html {
.dropdown {
position: relative;
}
.dropdown-menu-toggle:active {
box-shadow: 0 0 0 1px #fff, 0 0 0 3px #428fdc;
outline: none;
}
.search-input-container .dropdown-menu {
margin-top: 11px;
}
.dropdown-menu-toggle {
padding: 6px 8px 6px 10px;
background-color: #fff;
color: #333238;
font-size: 14px;
text-align: left;
border: 1px solid #bfbfc3;
border-radius: 0.25rem;
white-space: nowrap;
}
.dropdown-menu-toggle.no-outline {
outline: 0;
}
.dropdown-menu-toggle.dropdown-menu-toggle {
justify-content: flex-start;
overflow: hidden;
padding-top: 7px;
padding-bottom: 7px;
padding-right: 25px;
position: relative;
text-overflow: ellipsis;
line-height: 16px;
width: 160px;
}
.dropdown-menu {
display: none;
position: absolute;
......@@ -750,11 +703,6 @@ html {
min-width: 100%;
}
}
@media (max-width: 767.98px) {
.dropdown-menu-toggle.dropdown-menu-toggle {
width: 100%;
}
}
input {
border-radius: 0.25rem;
color: #333238;
......
......@@ -6,14 +6,8 @@
let(:public_project) { create(:project, :public) }
let(:authorized_user) { create(:user) }
let(:authorized_project) { create(:project, namespace: authorized_user.namespace) }
let(:new_header_search) { false }
before do
# This feature is diabled by default in spec_helper.rb.
# We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
# This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
stub_feature_flags(new_header_search: new_header_search)
stub_ee_application_setting(elasticsearch_search: true, elasticsearch_indexing: true)
authorized_project.add_maintainer(authorized_user)
......@@ -153,27 +147,7 @@
end
end
context 'when :new_header_search is false' do
context 'when searching titles' do
before do
submit_search('snippet')
end
it_behaves_like 'expected snippet search results'
end
context 'when searching descriptions' do
before do
submit_search('snippet description')
end
it_behaves_like 'expected snippet search results'
end
end
context 'when :new_header_search is true' do
let(:new_header_search) { true }
context 'when header search' do
context 'when searching titles' do
before do
submit_search('snippet')
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'layouts/_search' do
let(:group) { create(:group) }
let(:project) { nil }
let(:scope) { 'epics' }
let(:search_context) do
instance_double(Gitlab::SearchContext,
project: project,
group: group,
scope: scope,
ref: nil,
snippets: [],
search_url: '/search',
project_metadata: {},
group_metadata: {})
end
before do
allow(view).to receive(:search_context).and_return(search_context)
allow(search_context).to receive(:code_search?).and_return(false)
allow(search_context).to receive(:for_snippets?).and_return(false)
allow(search_context).to receive(:for_project?).and_return(false)
allow(search_context).to receive(:for_group?).and_return(true)
end
context 'when doing group level search' do
context 'when on epics' do
it 'sets scope to epics' do
render
expect(rendered).to have_css("input[name='scope'][value='epics']", count: 1, visible: false)
end
end
end
end
......@@ -63,7 +63,6 @@ def add_gon_variables
# made globally available to the frontend
push_frontend_feature_flag(:usage_data_api, type: :ops)
push_frontend_feature_flag(:security_auto_fix)
push_frontend_feature_flag(:new_header_search)
push_frontend_feature_flag(:source_editor_toolbar)
push_frontend_feature_flag(:vscode_web_ide, current_user)
push_frontend_feature_flag(:full_path_project_search, current_user)
......
......@@ -38443,9 +38443,6 @@ msgstr ""
msgid "Search"
msgstr ""
 
msgid "Search GitLab"
msgstr ""
msgid "Search Within"
msgstr ""
 
......@@ -38569,33 +38566,6 @@ msgstr ""
msgid "Search your projects"
msgstr ""
 
msgid "SearchAutocomplete|All GitLab"
msgstr ""
msgid "SearchAutocomplete|Issues I've created"
msgstr ""
msgid "SearchAutocomplete|Issues assigned to me"
msgstr ""
msgid "SearchAutocomplete|Merge requests I've created"
msgstr ""
msgid "SearchAutocomplete|Merge requests assigned to me"
msgstr ""
msgid "SearchAutocomplete|Merge requests that I'm a reviewer"
msgstr ""
msgid "SearchAutocomplete|in all GitLab"
msgstr ""
msgid "SearchAutocomplete|in group %{groupName}"
msgstr ""
msgid "SearchAutocomplete|in project %{projectName}"
msgstr ""
msgid "SearchCodeResults|of %{link_to_project}"
msgstr ""
 
......@@ -56,10 +56,6 @@ class Menu < Page::Base
element :menu_item_link
end
view 'app/views/layouts/_search.html.haml' do
element :search_term_field
end
view 'app/views/layouts/_header_search.html.haml' do
element :search_box
end
......
......@@ -51,7 +51,6 @@ 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-off.html`),
path.join(FIXTURES_ROOT, `startup_css/project-${type}-super-sidebar.html`),
],
cssKeys,
......
......@@ -13,64 +13,8 @@
sign_in(user)
end
describe 'when new_header_search feature is disabled' do
describe 'when header search' do
before do
# TODO: Remove this along with feature flag #339348
stub_feature_flags(new_header_search: false)
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)
submit_search('foobar')
end
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')
end
end
it 'closes the dropdown on blur' do
find('#search').click
fill_in 'search', with: "a"
expect(page).to have_selector("div[data-testid='dashboard-search-options'].show")
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
it 'focuses search input when shortcut "s" is pressed' do
expect(page).not_to have_selector('#search:focus')
find('body').native.send_key('s')
expect(page).to have_selector('#search:focus')
end
end
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
......
......@@ -99,64 +99,11 @@
end
end
context 'when :new_header_search is true' do
context 'when header search' do
context 'search code within refs' do
let(:ref_name) { 'v1.0.0' }
before do
# This feature is disabled by default in spec_helper.rb.
# We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
# This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
stub_feature_flags(new_header_search: true)
visit(project_tree_path(project, ref_name))
submit_search('gitlab-grack')
select_search_scope('Code')
end
it 'shows ref switcher in code result summary' do
expect(find('.ref-selector')).to have_text(ref_name)
end
it 'persists branch name across search' do
find('.gl-search-box-by-click-search-button').click
expect(find('.ref-selector')).to have_text(ref_name)
end
# this example is use to test the design that the refs is not
# only represent the branch as well as the tags.
it 'ref switcher list all the branches and tags' do
find('.ref-selector').click
wait_for_requests
page.within('.ref-selector') do
expect(page).to have_selector('li', text: 'add-ipython-files')
expect(page).to have_selector('li', text: 'v1.0.0')
end
end
it 'search result changes when refs switched' do
expect(find('.results')).not_to have_content('path = gitlab-grack')
find('.ref-selector').click
wait_for_requests
select_listbox_item('add-ipython-files')
expect(page).to have_selector('.results', text: 'path = gitlab-grack')
end
end
end
context 'when :new_header_search is false' do
context 'search code within refs' do
let(:ref_name) { 'v1.0.0' }
before do
# This feature is disabled by default in spec_helper.rb.
# We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
# This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
stub_feature_flags(new_header_search: false)
visit(project_tree_path(project, ref_name))
submit_search('gitlab-grack')
......
......@@ -40,21 +40,6 @@
expect(response).to be_successful
end
# This Feature Flag is on by default
# This ensures that the correct css is generated
# When the feature flag is on, 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-off.html" do
stub_feature_flags(new_header_search: false)
get :show, params: {
namespace_id: project.namespace.to_param,
id: project
}
expect(response).to be_successful
end
# This Feature Flag is off by default
# This ensures that the correct css is generated for super sidebar
# When the feature flag is off, the general startup will capture it
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment