mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Search: Enable filtering dashboards in search by current folder (#16790)
* Added search-query-parser package * Migrate search input field to react and enable current folter filtering * Reveiw changes * FIx tags * Fix event handlers passed to html elements directly * noImplicitAny fix * Debounce search method in search controller * Search: have clear reset query as well
This commit is contained in:
committed by
Torkel Ödegaard
parent
2e326d1cb8
commit
7194c6d9bf
@@ -218,6 +218,7 @@
|
|||||||
"reselect": "4.0.0",
|
"reselect": "4.0.0",
|
||||||
"rst2html": "github:thoward/rst2html#990cb89",
|
"rst2html": "github:thoward/rst2html#990cb89",
|
||||||
"rxjs": "6.4.0",
|
"rxjs": "6.4.0",
|
||||||
|
"search-query-parser": "1.5.2",
|
||||||
"slate": "0.33.8",
|
"slate": "0.33.8",
|
||||||
"slate-plain-serializer": "0.5.41",
|
"slate-plain-serializer": "0.5.41",
|
||||||
"slate-prism": "0.5.0",
|
"slate-prism": "0.5.0",
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { MetricSelect } from './components/Select/MetricSelect';
|
|||||||
import AppNotificationList from './components/AppNotifications/AppNotificationList';
|
import AppNotificationList from './components/AppNotifications/AppNotificationList';
|
||||||
import { ColorPicker, SeriesColorPickerPopoverWithTheme, SecretFormField } from '@grafana/ui';
|
import { ColorPicker, SeriesColorPickerPopoverWithTheme, SecretFormField } from '@grafana/ui';
|
||||||
import { FunctionEditor } from 'app/plugins/datasource/graphite/FunctionEditor';
|
import { FunctionEditor } from 'app/plugins/datasource/graphite/FunctionEditor';
|
||||||
|
import { SearchField } from './components/search/SearchField';
|
||||||
|
|
||||||
export function registerAngularDirectives() {
|
export function registerAngularDirectives() {
|
||||||
react2AngularDirective('passwordStrength', PasswordStrength, ['password']);
|
react2AngularDirective('passwordStrength', PasswordStrength, ['password']);
|
||||||
@@ -20,6 +21,12 @@ export function registerAngularDirectives() {
|
|||||||
react2AngularDirective('pageHeader', PageHeader, ['model', 'noTabs']);
|
react2AngularDirective('pageHeader', PageHeader, ['model', 'noTabs']);
|
||||||
react2AngularDirective('emptyListCta', EmptyListCTA, ['model']);
|
react2AngularDirective('emptyListCta', EmptyListCTA, ['model']);
|
||||||
react2AngularDirective('searchResult', SearchResult, []);
|
react2AngularDirective('searchResult', SearchResult, []);
|
||||||
|
react2AngularDirective('searchField', SearchField, [
|
||||||
|
'query',
|
||||||
|
'autoFocus',
|
||||||
|
['onChange', { watchDepth: 'reference' }],
|
||||||
|
['onKeyDown', { watchDepth: 'reference' }],
|
||||||
|
]);
|
||||||
react2AngularDirective('tagFilter', TagFilter, [
|
react2AngularDirective('tagFilter', TagFilter, [
|
||||||
'tags',
|
'tags',
|
||||||
['onChange', { watchDepth: 'reference' }],
|
['onChange', { watchDepth: 'reference' }],
|
||||||
|
|||||||
95
public/app/core/components/search/SearchField.tsx
Normal file
95
public/app/core/components/search/SearchField.tsx
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import React, { useContext } from 'react';
|
||||||
|
import tinycolor from 'tinycolor2';
|
||||||
|
import { SearchQuery } from './search';
|
||||||
|
import { css, cx } from 'emotion';
|
||||||
|
import { ThemeContext, GrafanaTheme, selectThemeVariant } from '@grafana/ui';
|
||||||
|
|
||||||
|
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||||
|
|
||||||
|
interface SearchFieldProps extends Omit<React.HTMLAttributes<HTMLInputElement>, 'onChange'> {
|
||||||
|
query: SearchQuery;
|
||||||
|
onChange: (query: string) => void;
|
||||||
|
onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSearchFieldStyles = (theme: GrafanaTheme) => ({
|
||||||
|
wrapper: css`
|
||||||
|
width: 100%;
|
||||||
|
height: 55px; /* this variable is not part of GrafanaTheme yet*/
|
||||||
|
display: flex;
|
||||||
|
background-color: ${selectThemeVariant(
|
||||||
|
{
|
||||||
|
light: theme.colors.white,
|
||||||
|
dark: theme.colors.dark4,
|
||||||
|
},
|
||||||
|
theme.type
|
||||||
|
)};
|
||||||
|
position: relative;
|
||||||
|
`,
|
||||||
|
input: css`
|
||||||
|
max-width: 653px;
|
||||||
|
padding: ${theme.spacing.md} ${theme.spacing.md} ${theme.spacing.sm} ${theme.spacing.md};
|
||||||
|
height: 51px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
outline: none;
|
||||||
|
background: ${selectThemeVariant(
|
||||||
|
{
|
||||||
|
light: theme.colors.dark1,
|
||||||
|
dark: theme.colors.black,
|
||||||
|
},
|
||||||
|
theme.type
|
||||||
|
)};
|
||||||
|
background-color: ${selectThemeVariant(
|
||||||
|
{
|
||||||
|
light: tinycolor(theme.colors.white)
|
||||||
|
.lighten(4)
|
||||||
|
.toString(),
|
||||||
|
dark: theme.colors.dark4,
|
||||||
|
},
|
||||||
|
theme.type
|
||||||
|
)};
|
||||||
|
flex-grow: 10;
|
||||||
|
`,
|
||||||
|
spacer: css`
|
||||||
|
flex-grow: 1;
|
||||||
|
`,
|
||||||
|
icon: cx(
|
||||||
|
css`
|
||||||
|
font-size: ${theme.typography.size.lg};
|
||||||
|
padding: ${theme.spacing.md} ${theme.spacing.md} ${theme.spacing.sm} ${theme.spacing.md};
|
||||||
|
`,
|
||||||
|
'pointer'
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const SearchField: React.FunctionComponent<SearchFieldProps> = ({ query, onChange, ...inputProps }) => {
|
||||||
|
const theme = useContext(ThemeContext);
|
||||||
|
const styles = getSearchFieldStyles(theme);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* search-field-wrapper class name left on purpose until we migrate entire search to React */}
|
||||||
|
{/* based on it GrafanaCtrl (L256) decides whether or not hide search */}
|
||||||
|
<div className={`${styles.wrapper} search-field-wrapper`}>
|
||||||
|
<div className={styles.icon}>
|
||||||
|
<i className="fa fa-search" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Find dashboards by name"
|
||||||
|
value={query.query}
|
||||||
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
onChange(event.currentTarget.value);
|
||||||
|
}}
|
||||||
|
tabIndex={1}
|
||||||
|
spellCheck={false}
|
||||||
|
{...inputProps}
|
||||||
|
className={styles.input}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className={styles.spacer} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -3,19 +3,13 @@
|
|||||||
|
|
||||||
<div class="search-container" ng-if="ctrl.isOpen">
|
<div class="search-container" ng-if="ctrl.isOpen">
|
||||||
|
|
||||||
<div class="search-field-wrapper">
|
<search-field
|
||||||
<div class="search-field-icon pointer" ng-click="ctrl.closeSearch()"><i class="fa fa-search"></i></div>
|
query="ctrl.query"
|
||||||
|
autoFocus="ctrl.giveSearchFocus"
|
||||||
|
on-change="ctrl.onQueryChange"
|
||||||
|
on-key-down="ctrl.onKeyDown"
|
||||||
|
/>
|
||||||
|
|
||||||
<input type="text" placeholder="Find dashboards by name" give-focus="ctrl.giveSearchFocus" tabindex="1"
|
|
||||||
ng-keydown="ctrl.keyDown($event)"
|
|
||||||
ng-model="ctrl.query.query"
|
|
||||||
ng-model-options="{ debounce: 500 }"
|
|
||||||
spellcheck='false'
|
|
||||||
ng-change="ctrl.search()"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="search-field-spacer"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="search-dropdown">
|
<div class="search-dropdown">
|
||||||
<div class="search-dropdown__col_1">
|
<div class="search-dropdown__col_1">
|
||||||
@@ -41,7 +35,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<tag-filter tags="ctrl.query.tag" tagOptions="ctrl.getTags" onChange="ctrl.onTagFiltersChanged">
|
<tag-filter tags="ctrl.query.tags" tagOptions="ctrl.getTags" on-change="ctrl.onTagFiltersChanged">
|
||||||
</tag-filter>
|
</tag-filter>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,41 @@
|
|||||||
import _ from 'lodash';
|
import _, { debounce } from 'lodash';
|
||||||
import coreModule from '../../core_module';
|
import coreModule from '../../core_module';
|
||||||
import { SearchSrv } from 'app/core/services/search_srv';
|
import { SearchSrv } from 'app/core/services/search_srv';
|
||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
|
|
||||||
import appEvents from 'app/core/app_events';
|
import appEvents from 'app/core/app_events';
|
||||||
|
import { parse, SearchParserOptions, SearchParserResult } from 'search-query-parser';
|
||||||
|
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||||
|
export interface SearchQuery {
|
||||||
|
query: string;
|
||||||
|
parsedQuery: SearchParserResult;
|
||||||
|
tags: string[];
|
||||||
|
starred: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SearchQueryParser {
|
||||||
|
config: SearchParserOptions;
|
||||||
|
constructor(config: SearchParserOptions) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse(query: string) {
|
||||||
|
const parsedQuery = parse(query, this.config);
|
||||||
|
|
||||||
|
if (typeof parsedQuery === 'string') {
|
||||||
|
return {
|
||||||
|
text: parsedQuery,
|
||||||
|
} as SearchParserResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedQuery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class SearchCtrl {
|
export class SearchCtrl {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
query: any;
|
query: SearchQuery;
|
||||||
giveSearchFocus: number;
|
giveSearchFocus: boolean;
|
||||||
selectedIndex: number;
|
selectedIndex: number;
|
||||||
results: any;
|
results: any;
|
||||||
currentSearchId: number;
|
currentSearchId: number;
|
||||||
@@ -18,21 +46,48 @@ export class SearchCtrl {
|
|||||||
initialFolderFilterTitle: string;
|
initialFolderFilterTitle: string;
|
||||||
isEditor: string;
|
isEditor: string;
|
||||||
hasEditPermissionInFolders: boolean;
|
hasEditPermissionInFolders: boolean;
|
||||||
|
queryParser: SearchQueryParser;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor($scope, private $location, private $timeout, private searchSrv: SearchSrv) {
|
constructor($scope, private $location, private $timeout, private searchSrv: SearchSrv) {
|
||||||
appEvents.on('show-dash-search', this.openSearch.bind(this), $scope);
|
appEvents.on('show-dash-search', this.openSearch.bind(this), $scope);
|
||||||
appEvents.on('hide-dash-search', this.closeSearch.bind(this), $scope);
|
appEvents.on('hide-dash-search', this.closeSearch.bind(this), $scope);
|
||||||
|
appEvents.on('search-query', debounce(this.search.bind(this), 500), $scope);
|
||||||
|
|
||||||
this.initialFolderFilterTitle = 'All';
|
this.initialFolderFilterTitle = 'All';
|
||||||
this.isEditor = contextSrv.isEditor;
|
this.isEditor = contextSrv.isEditor;
|
||||||
this.hasEditPermissionInFolders = contextSrv.hasEditPermissionInFolders;
|
this.hasEditPermissionInFolders = contextSrv.hasEditPermissionInFolders;
|
||||||
|
this.onQueryChange = this.onQueryChange.bind(this);
|
||||||
|
this.onKeyDown = this.onKeyDown.bind(this);
|
||||||
|
this.query = {
|
||||||
|
query: '',
|
||||||
|
parsedQuery: { text: '' },
|
||||||
|
tags: [],
|
||||||
|
starred: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.queryParser = new SearchQueryParser({
|
||||||
|
keywords: ['folder'],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
closeSearch() {
|
closeSearch() {
|
||||||
this.isOpen = this.ignoreClose;
|
this.isOpen = this.ignoreClose;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onQueryChange(query: SearchQuery | string) {
|
||||||
|
if (typeof query === 'string') {
|
||||||
|
this.query = {
|
||||||
|
...this.query,
|
||||||
|
parsedQuery: this.queryParser.parse(query),
|
||||||
|
query: query,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
this.query = query;
|
||||||
|
}
|
||||||
|
appEvents.emit('search-query');
|
||||||
|
}
|
||||||
|
|
||||||
openSearch(evt, payload) {
|
openSearch(evt, payload) {
|
||||||
if (this.isOpen) {
|
if (this.isOpen) {
|
||||||
this.closeSearch();
|
this.closeSearch();
|
||||||
@@ -40,10 +95,15 @@ export class SearchCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.isOpen = true;
|
this.isOpen = true;
|
||||||
this.giveSearchFocus = 0;
|
this.giveSearchFocus = true;
|
||||||
this.selectedIndex = -1;
|
this.selectedIndex = -1;
|
||||||
this.results = [];
|
this.results = [];
|
||||||
this.query = { query: '', tag: [], starred: false };
|
this.query = {
|
||||||
|
query: evt ? `${evt.query} ` : '',
|
||||||
|
parsedQuery: this.queryParser.parse(evt && evt.query),
|
||||||
|
tags: [],
|
||||||
|
starred: false,
|
||||||
|
};
|
||||||
this.currentSearchId = 0;
|
this.currentSearchId = 0;
|
||||||
this.ignoreClose = true;
|
this.ignoreClose = true;
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
@@ -54,12 +114,12 @@ export class SearchCtrl {
|
|||||||
|
|
||||||
this.$timeout(() => {
|
this.$timeout(() => {
|
||||||
this.ignoreClose = false;
|
this.ignoreClose = false;
|
||||||
this.giveSearchFocus = this.giveSearchFocus + 1;
|
this.giveSearchFocus = true;
|
||||||
this.search();
|
this.search();
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
keyDown(evt) {
|
onKeyDown(evt: KeyboardEvent) {
|
||||||
if (evt.keyCode === 27) {
|
if (evt.keyCode === 27) {
|
||||||
this.closeSearch();
|
this.closeSearch();
|
||||||
}
|
}
|
||||||
@@ -94,7 +154,7 @@ export class SearchCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onFilterboxClick() {
|
onFilterboxClick() {
|
||||||
this.giveSearchFocus = 0;
|
this.giveSearchFocus = false;
|
||||||
this.preventClose();
|
this.preventClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,40 +215,54 @@ export class SearchCtrl {
|
|||||||
this.results[selectedItem.folderIndex].selected = true;
|
this.results[selectedItem.folderIndex].selected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
searchDashboards() {
|
searchDashboards(folderContext?: string) {
|
||||||
this.currentSearchId = this.currentSearchId + 1;
|
this.currentSearchId = this.currentSearchId + 1;
|
||||||
const localSearchId = this.currentSearchId;
|
const localSearchId = this.currentSearchId;
|
||||||
|
const folderIds = [];
|
||||||
|
|
||||||
|
const { parsedQuery } = this.query;
|
||||||
|
|
||||||
|
if (folderContext === 'current') {
|
||||||
|
folderIds.push(getDashboardSrv().getCurrent().meta.folderId);
|
||||||
|
}
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
...this.query,
|
...this.query,
|
||||||
tag: this.query.tag,
|
query: parsedQuery.text,
|
||||||
|
tag: this.query.tags,
|
||||||
|
folderIds,
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.searchSrv.search(query).then(results => {
|
return this.searchSrv
|
||||||
if (localSearchId < this.currentSearchId) {
|
.search({
|
||||||
return;
|
...query,
|
||||||
}
|
})
|
||||||
this.results = results || [];
|
.then(results => {
|
||||||
this.isLoading = false;
|
if (localSearchId < this.currentSearchId) {
|
||||||
this.moveSelection(1);
|
return;
|
||||||
});
|
}
|
||||||
|
this.results = results || [];
|
||||||
|
this.isLoading = false;
|
||||||
|
this.moveSelection(1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
queryHasNoFilters() {
|
queryHasNoFilters() {
|
||||||
const query = this.query;
|
const query = this.query;
|
||||||
return query.query === '' && query.starred === false && query.tag.length === 0;
|
return query.query === '' && query.starred === false && query.tags.length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
filterByTag(tag) {
|
filterByTag(tag) {
|
||||||
if (_.indexOf(this.query.tag, tag) === -1) {
|
if (_.indexOf(this.query.tags, tag) === -1) {
|
||||||
this.query.tag.push(tag);
|
this.query.tags.push(tag);
|
||||||
this.search();
|
this.search();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTag(tag, evt) {
|
removeTag(tag, evt) {
|
||||||
this.query.tag = _.without(this.query.tag, tag);
|
this.query.tags = _.without(this.query.tags, tag);
|
||||||
this.search();
|
this.search();
|
||||||
this.giveSearchFocus = this.giveSearchFocus + 1;
|
this.giveSearchFocus = true;
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
}
|
}
|
||||||
@@ -198,32 +272,36 @@ export class SearchCtrl {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onTagFiltersChanged = (tags: string[]) => {
|
onTagFiltersChanged = (tags: string[]) => {
|
||||||
this.query.tag = tags;
|
this.query.tags = tags;
|
||||||
this.search();
|
this.search();
|
||||||
};
|
};
|
||||||
|
|
||||||
clearSearchFilter() {
|
clearSearchFilter() {
|
||||||
this.query.tag = [];
|
this.query.query = '';
|
||||||
|
this.query.tags = [];
|
||||||
this.search();
|
this.search();
|
||||||
}
|
}
|
||||||
|
|
||||||
showStarred() {
|
showStarred() {
|
||||||
this.query.starred = !this.query.starred;
|
this.query.starred = !this.query.starred;
|
||||||
this.giveSearchFocus = this.giveSearchFocus + 1;
|
this.giveSearchFocus = true;
|
||||||
this.search();
|
this.search();
|
||||||
}
|
}
|
||||||
|
|
||||||
search() {
|
search() {
|
||||||
this.showImport = false;
|
this.showImport = false;
|
||||||
this.selectedIndex = -1;
|
this.selectedIndex = -1;
|
||||||
this.searchDashboards();
|
this.searchDashboards(this.query.parsedQuery['folder']);
|
||||||
}
|
}
|
||||||
|
|
||||||
folderExpanding() {
|
folderExpanding() {
|
||||||
this.moveSelection(0);
|
this.moveSelection(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getFlattenedResultForNavigation() {
|
private getFlattenedResultForNavigation(): Array<{
|
||||||
|
folderIndex: number;
|
||||||
|
dashboardIndex: number;
|
||||||
|
}> {
|
||||||
let folderIndex = 0;
|
let folderIndex = 0;
|
||||||
|
|
||||||
return _.flatMap(this.results, s => {
|
return _.flatMap(this.results, s => {
|
||||||
|
|||||||
@@ -61,7 +61,16 @@ export class DashNav extends PureComponent<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onOpenSearch = () => {
|
onOpenSearch = () => {
|
||||||
appEvents.emit('show-dash-search');
|
const { dashboard } = this.props;
|
||||||
|
const haveFolder = dashboard.meta.folderId > 0;
|
||||||
|
appEvents.emit(
|
||||||
|
'show-dash-search',
|
||||||
|
haveFolder
|
||||||
|
? {
|
||||||
|
query: 'folder:current',
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
onClose = () => {
|
onClose = () => {
|
||||||
@@ -142,8 +151,7 @@ export class DashNav extends PureComponent<Props> {
|
|||||||
<a className="navbar-page-btn" onClick={this.onOpenSearch}>
|
<a className="navbar-page-btn" onClick={this.onOpenSearch}>
|
||||||
{!this.isInFullscreenOrSettings && <i className="gicon gicon-dashboard" />}
|
{!this.isInFullscreenOrSettings && <i className="gicon gicon-dashboard" />}
|
||||||
{haveFolder && <span className="navbar-page-btn--folder">{folderTitle} / </span>}
|
{haveFolder && <span className="navbar-page-btn--folder">{folderTitle} / </span>}
|
||||||
{dashboard.title}
|
{dashboard.title} <i className="fa fa-caret-down" />
|
||||||
<i className="fa fa-caret-down" />
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{this.isSettings && <span className="navbar-settings-title"> / Settings</span>}
|
{this.isSettings && <span className="navbar-settings-title"> / Settings</span>}
|
||||||
|
|||||||
@@ -19,34 +19,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Search
|
// Search
|
||||||
.search-field-wrapper {
|
|
||||||
width: 100%;
|
|
||||||
height: $navbarHeight;
|
|
||||||
display: flex;
|
|
||||||
background-color: $navbarBackground;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
& > input {
|
|
||||||
max-width: 653px;
|
|
||||||
padding: $space-md $space-md $space-sm $space-md;
|
|
||||||
height: 51px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
outline: none;
|
|
||||||
background: $side-menu-bg;
|
|
||||||
background-color: $navbarButtonBackground;
|
|
||||||
flex-grow: 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-field-spacer {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-field-icon {
|
|
||||||
font-size: $font-size-lg;
|
|
||||||
padding: $space-md $space-md $space-sm $space-md;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-dropdown {
|
.search-dropdown {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -15245,6 +15245,11 @@ scss-tokenizer@^0.2.3:
|
|||||||
js-base64 "^2.1.8"
|
js-base64 "^2.1.8"
|
||||||
source-map "^0.4.2"
|
source-map "^0.4.2"
|
||||||
|
|
||||||
|
search-query-parser@1.5.2:
|
||||||
|
version "1.5.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/search-query-parser/-/search-query-parser-1.5.2.tgz#f6c8c9ecbde439cbbce75110045944c3cb5fe546"
|
||||||
|
integrity sha512-PcvjC0eJMmFIYAxUaeaRVLnPHctzsymtMJUSGKv6xJtctGrunihoCItrQ3AcM5eO7q90pNeIVTrLwuqW0LIzyg==
|
||||||
|
|
||||||
select-hose@^2.0.0:
|
select-hose@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
|
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
|
||||||
|
|||||||
Reference in New Issue
Block a user