mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Table panel: Make filter case insensitive (#39746)
* Expose FilterInput from grafana/ui * Make table filter case insensitive * Update packages/grafana-ui/src/components/Table/FilterList.tsx Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com> Co-authored-by: Oscar Kilhed <oscar.kilhed@grafana.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { escapeStringForRegex, unEscapeStringFromRegex } from '@grafana/data';
|
import { escapeStringForRegex, unEscapeStringFromRegex } from '@grafana/data';
|
||||||
import { Input, Icon, Button } from '@grafana/ui';
|
import { Button, Icon, Input } from '..';
|
||||||
|
import { useFocus } from '../Input/utils';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
value: string | undefined;
|
value: string | undefined;
|
||||||
@@ -12,9 +13,20 @@ export interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const FilterInput: FC<Props> = ({ value, placeholder, width, onChange, onKeyDown, autoFocus }) => {
|
export const FilterInput: FC<Props> = ({ value, placeholder, width, onChange, onKeyDown, autoFocus }) => {
|
||||||
|
const [inputRef, setInputFocus] = useFocus();
|
||||||
|
|
||||||
const suffix =
|
const suffix =
|
||||||
value !== '' ? (
|
value !== '' ? (
|
||||||
<Button icon="times" fill="text" size="sm" onClick={() => onChange('')}>
|
<Button
|
||||||
|
icon="times"
|
||||||
|
fill="text"
|
||||||
|
size="sm"
|
||||||
|
onClick={(e) => {
|
||||||
|
setInputFocus();
|
||||||
|
onChange('');
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
Clear
|
Clear
|
||||||
</Button>
|
</Button>
|
||||||
) : null;
|
) : null;
|
||||||
@@ -23,6 +35,7 @@ export const FilterInput: FC<Props> = ({ value, placeholder, width, onChange, on
|
|||||||
<Input
|
<Input
|
||||||
autoFocus={autoFocus ?? false}
|
autoFocus={autoFocus ?? false}
|
||||||
prefix={<Icon name="search" />}
|
prefix={<Icon name="search" />}
|
||||||
|
ref={inputRef}
|
||||||
suffix={suffix}
|
suffix={suffix}
|
||||||
width={width}
|
width={width}
|
||||||
type="text"
|
type="text"
|
||||||
@@ -4,7 +4,7 @@ import { css, cx } from '@emotion/css';
|
|||||||
import { getFocusStyle, sharedInputStyle } from '../Forms/commonStyles';
|
import { getFocusStyle, sharedInputStyle } from '../Forms/commonStyles';
|
||||||
import { stylesFactory, useTheme2 } from '../../themes';
|
import { stylesFactory, useTheme2 } from '../../themes';
|
||||||
import { Spinner } from '../Spinner/Spinner';
|
import { Spinner } from '../Spinner/Spinner';
|
||||||
import { useClientRect } from '../../utils/useClientRect';
|
import useMeasure from 'react-use/lib/useMeasure';
|
||||||
|
|
||||||
export interface Props extends Omit<HTMLProps<HTMLInputElement>, 'prefix' | 'size'> {
|
export interface Props extends Omit<HTMLProps<HTMLInputElement>, 'prefix' | 'size'> {
|
||||||
/** Sets the width to a multiple of 8px. Should only be used with inline forms. Setting width of the container is preferred in other cases.*/
|
/** Sets the width to a multiple of 8px. Should only be used with inline forms. Setting width of the container is preferred in other cases.*/
|
||||||
@@ -29,6 +29,55 @@ interface StyleDeps {
|
|||||||
width?: number;
|
width?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const Input = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
|
||||||
|
const { className, addonAfter, addonBefore, prefix, suffix, invalid, loading, width = 0, ...restProps } = props;
|
||||||
|
/**
|
||||||
|
* Prefix & suffix are positioned absolutely within inputWrapper. We use client rects below to apply correct padding to the input
|
||||||
|
* when prefix/suffix is larger than default (28px = 16px(icon) + 12px(left/right paddings)).
|
||||||
|
* Thanks to that prefix/suffix do not overflow the input element itself.
|
||||||
|
*/
|
||||||
|
const [prefixRef, prefixRect] = useMeasure<HTMLDivElement>();
|
||||||
|
const [suffixRef, suffixRect] = useMeasure<HTMLDivElement>();
|
||||||
|
|
||||||
|
const theme = useTheme2();
|
||||||
|
const styles = getInputStyles({ theme, invalid: !!invalid, width });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cx(styles.wrapper, className)}>
|
||||||
|
{!!addonBefore && <div className={styles.addon}>{addonBefore}</div>}
|
||||||
|
|
||||||
|
<div className={styles.inputWrapper}>
|
||||||
|
{prefix && (
|
||||||
|
<div className={styles.prefix} ref={prefixRef}>
|
||||||
|
{prefix}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<input
|
||||||
|
ref={ref}
|
||||||
|
className={styles.input}
|
||||||
|
{...restProps}
|
||||||
|
style={{
|
||||||
|
paddingLeft: prefixRect ? prefixRect.width + 12 : undefined,
|
||||||
|
paddingRight: suffixRect ? suffixRect.width + 12 : undefined,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{(suffix || loading) && (
|
||||||
|
<div className={styles.suffix} ref={suffixRef}>
|
||||||
|
{loading && <Spinner className={styles.loadingIndicator} inline={true} />}
|
||||||
|
{suffix}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!!addonAfter && <div className={styles.addon}>{addonAfter}</div>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Input.displayName = 'Input';
|
||||||
|
|
||||||
export const getInputStyles = stylesFactory(({ theme, invalid = false, width }: StyleDeps) => {
|
export const getInputStyles = stylesFactory(({ theme, invalid = false, width }: StyleDeps) => {
|
||||||
const prefixSuffixStaticWidth = '28px';
|
const prefixSuffixStaticWidth = '28px';
|
||||||
const prefixSuffix = css`
|
const prefixSuffix = css`
|
||||||
@@ -212,52 +261,3 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false, width }:
|
|||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export const Input = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
|
|
||||||
const { className, addonAfter, addonBefore, prefix, suffix, invalid, loading, width = 0, ...restProps } = props;
|
|
||||||
/**
|
|
||||||
* Prefix & suffix are positioned absolutely within inputWrapper. We use client rects below to apply correct padding to the input
|
|
||||||
* when prefix/suffix is larger than default (28px = 16px(icon) + 12px(left/right paddings)).
|
|
||||||
* Thanks to that prefix/suffix do not overflow the input element itself.
|
|
||||||
*/
|
|
||||||
const [prefixRect, prefixRef] = useClientRect<HTMLDivElement>();
|
|
||||||
const [suffixRect, suffixRef] = useClientRect<HTMLDivElement>();
|
|
||||||
|
|
||||||
const theme = useTheme2();
|
|
||||||
const styles = getInputStyles({ theme, invalid: !!invalid, width });
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={cx(styles.wrapper, className)}>
|
|
||||||
{!!addonBefore && <div className={styles.addon}>{addonBefore}</div>}
|
|
||||||
|
|
||||||
<div className={styles.inputWrapper}>
|
|
||||||
{prefix && (
|
|
||||||
<div className={styles.prefix} ref={prefixRef}>
|
|
||||||
{prefix}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<input
|
|
||||||
ref={ref}
|
|
||||||
className={styles.input}
|
|
||||||
{...restProps}
|
|
||||||
style={{
|
|
||||||
paddingLeft: prefixRect ? prefixRect.width : undefined,
|
|
||||||
paddingRight: suffixRect ? suffixRect.width : undefined,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{(suffix || loading) && (
|
|
||||||
<div className={styles.suffix} ref={suffixRef}>
|
|
||||||
{loading && <Spinner className={styles.loadingIndicator} inline={true} />}
|
|
||||||
{suffix}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{!!addonAfter && <div className={styles.addon}>{addonAfter}</div>}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
Input.displayName = 'Input';
|
|
||||||
|
|||||||
9
packages/grafana-ui/src/components/Input/utils.ts
Normal file
9
packages/grafana-ui/src/components/Input/utils.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { RefObject, useRef } from 'react';
|
||||||
|
|
||||||
|
export function useFocus(): [RefObject<HTMLInputElement>, () => void] {
|
||||||
|
const ref = useRef<HTMLInputElement>(null);
|
||||||
|
const setFocus = () => {
|
||||||
|
ref.current && ref.current.focus();
|
||||||
|
};
|
||||||
|
return [ref, setFocus];
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ import { css } from '@emotion/css';
|
|||||||
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme2, SelectableValue } from '@grafana/data';
|
||||||
|
|
||||||
import { stylesFactory, useTheme2 } from '../../themes';
|
import { stylesFactory, useTheme2 } from '../../themes';
|
||||||
import { Checkbox, Input, Label, VerticalGroup } from '..';
|
import { Checkbox, FilterInput, Label, VerticalGroup } from '..';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
values: SelectableValue[];
|
values: SelectableValue[];
|
||||||
@@ -19,16 +19,16 @@ export const FilterList: FC<Props> = ({ options, values, onChange }) => {
|
|||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
const styles = getStyles(theme);
|
const styles = getStyles(theme);
|
||||||
const [searchFilter, setSearchFilter] = useState('');
|
const [searchFilter, setSearchFilter] = useState('');
|
||||||
const items = useMemo(() => options.filter((option) => option.label?.indexOf(searchFilter) !== -1), [
|
const items = useMemo(
|
||||||
options,
|
() => options.filter((option) => option.label?.toLowerCase().includes(searchFilter.toLowerCase())),
|
||||||
searchFilter,
|
[options, searchFilter]
|
||||||
]);
|
);
|
||||||
const gutter = theme.spacing.gridSize;
|
const gutter = theme.spacing.gridSize;
|
||||||
const height = useMemo(() => Math.min(items.length * ITEM_HEIGHT, MIN_HEIGHT) + gutter, [gutter, items.length]);
|
const height = useMemo(() => Math.min(items.length * ITEM_HEIGHT, MIN_HEIGHT) + gutter, [gutter, items.length]);
|
||||||
|
|
||||||
const onInputChange = useCallback(
|
const onInputChange = useCallback(
|
||||||
(event: React.FormEvent<HTMLInputElement>) => {
|
(v: string) => {
|
||||||
setSearchFilter(event.currentTarget.value);
|
setSearchFilter(v);
|
||||||
},
|
},
|
||||||
[setSearchFilter]
|
[setSearchFilter]
|
||||||
);
|
);
|
||||||
@@ -46,12 +46,7 @@ export const FilterList: FC<Props> = ({ options, values, onChange }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<VerticalGroup spacing="md">
|
<VerticalGroup spacing="md">
|
||||||
<Input
|
<FilterInput placeholder="Filter values" onChange={onInputChange} value={searchFilter} />
|
||||||
placeholder="filter values"
|
|
||||||
className={styles.filterListInput}
|
|
||||||
onChange={onInputChange}
|
|
||||||
value={searchFilter}
|
|
||||||
/>
|
|
||||||
{!items.length && <Label>No values</Label>}
|
{!items.length && <Label>No values</Label>}
|
||||||
{items.length && (
|
{items.length && (
|
||||||
<List
|
<List
|
||||||
@@ -94,7 +89,4 @@ const getStyles = stylesFactory((theme: GrafanaTheme2) => ({
|
|||||||
background-color: ${theme.colors.action.hover};
|
background-color: ${theme.colors.action.hover};
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
filterListInput: css`
|
|
||||||
label: filterListInput;
|
|
||||||
`,
|
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ export { Badge, BadgeColor, BadgeProps } from './Badge/Badge';
|
|||||||
export { RadioButtonGroup } from './Forms/RadioButtonGroup/RadioButtonGroup';
|
export { RadioButtonGroup } from './Forms/RadioButtonGroup/RadioButtonGroup';
|
||||||
|
|
||||||
export { Input } from './Input/Input';
|
export { Input } from './Input/Input';
|
||||||
|
export { FilterInput } from './FilterInput/FilterInput';
|
||||||
export { FormInputSize } from './Forms/types';
|
export { FormInputSize } from './Forms/types';
|
||||||
|
|
||||||
export { Switch, InlineSwitch } from './Switch/Switch';
|
export { Switch, InlineSwitch } from './Switch/Switch';
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import { useState, useCallback } from 'react';
|
|
||||||
|
|
||||||
export const useClientRect = <T extends HTMLElement>(): [{ width: number; height: number } | null, React.Ref<T>] => {
|
|
||||||
const [rect, setRect] = useState<{ width: number; height: number } | null>(null);
|
|
||||||
const ref = useCallback((node: T) => {
|
|
||||||
if (node !== null) {
|
|
||||||
setRect(node.getBoundingClientRect());
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
return [rect, ref];
|
|
||||||
};
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import { FilterInput } from '../FilterInput/FilterInput';
|
import { LinkButton, FilterInput } from '@grafana/ui';
|
||||||
import { LinkButton } from '@grafana/ui';
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import { connect, ConnectedProps } from 'react-redux';
|
import { connect, ConnectedProps } from 'react-redux';
|
||||||
import { Pagination, Tooltip, LinkButton, Icon, RadioButtonGroup, useStyles2 } from '@grafana/ui';
|
import { Pagination, Tooltip, LinkButton, Icon, RadioButtonGroup, useStyles2, FilterInput } from '@grafana/ui';
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import Page from 'app/core/components/Page/Page';
|
import Page from 'app/core/components/Page/Page';
|
||||||
import { TagBadge } from 'app/core/components/TagFilter/TagBadge';
|
import { TagBadge } from 'app/core/components/TagFilter/TagBadge';
|
||||||
import { contextSrv } from 'app/core/core';
|
import { contextSrv } from 'app/core/core';
|
||||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
|
||||||
import { getNavModel } from '../../core/selectors/navModel';
|
import { getNavModel } from '../../core/selectors/navModel';
|
||||||
import { AccessControlAction, StoreState, UserDTO } from '../../types';
|
import { AccessControlAction, StoreState, UserDTO } from '../../types';
|
||||||
import { fetchUsers, changeQuery, changePage, changeFilter } from './state/actions';
|
import { fetchUsers, changeQuery, changePage, changeFilter } from './state/actions';
|
||||||
|
|||||||
@@ -7,11 +7,10 @@ import { getNavModel } from 'app/core/selectors/navModel';
|
|||||||
import { AlertRule, StoreState } from 'app/types';
|
import { AlertRule, StoreState } from 'app/types';
|
||||||
import { getAlertRulesAsync, togglePauseAlertRule } from './state/actions';
|
import { getAlertRulesAsync, togglePauseAlertRule } from './state/actions';
|
||||||
import { getAlertRuleItems, getSearchQuery } from './state/selectors';
|
import { getAlertRuleItems, getSearchQuery } from './state/selectors';
|
||||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
|
||||||
import { SelectableValue } from '@grafana/data';
|
import { SelectableValue } from '@grafana/data';
|
||||||
import { config, locationService } from '@grafana/runtime';
|
import { config, locationService } from '@grafana/runtime';
|
||||||
import { setSearchQuery } from './state/reducers';
|
import { setSearchQuery } from './state/reducers';
|
||||||
import { Button, LinkButton, Select, VerticalGroup } from '@grafana/ui';
|
import { Button, LinkButton, Select, VerticalGroup, FilterInput } from '@grafana/ui';
|
||||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||||
import { ShowModalReactEvent } from '../../types/events';
|
import { ShowModalReactEvent } from '../../types/events';
|
||||||
import { AlertHowToModal } from './AlertHowToModal';
|
import { AlertHowToModal } from './AlertHowToModal';
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { Button } from '@grafana/ui';
|
import { Button, FilterInput } from '@grafana/ui';
|
||||||
import { FilterInput } from '../../core/components/FilterInput/FilterInput';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { FieldConfigSource, GrafanaTheme2, PanelData, PanelPlugin, SelectableValue } from '@grafana/data';
|
import { FieldConfigSource, GrafanaTheme2, PanelData, PanelPlugin, SelectableValue } from '@grafana/data';
|
||||||
import { DashboardModel, PanelModel } from '../../state';
|
import { DashboardModel, PanelModel } from '../../state';
|
||||||
import { CustomScrollbar, RadioButtonGroup, useStyles2 } from '@grafana/ui';
|
import { CustomScrollbar, RadioButtonGroup, useStyles2, FilterInput } from '@grafana/ui';
|
||||||
import { getPanelFrameCategory } from './getPanelFrameOptions';
|
import { getPanelFrameCategory } from './getPanelFrameOptions';
|
||||||
import { getVizualizationOptions } from './getVizualizationOptions';
|
import { getVizualizationOptions } from './getVizualizationOptions';
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
|
||||||
import { OptionsPaneCategory } from './OptionsPaneCategory';
|
import { OptionsPaneCategory } from './OptionsPaneCategory';
|
||||||
import { getFieldOverrideCategories } from './getFieldOverrideElements';
|
import { getFieldOverrideCategories } from './getFieldOverrideElements';
|
||||||
import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
|
import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import React, { FC, PureComponent } from 'react';
|
import React, { FC, PureComponent } from 'react';
|
||||||
import { connect, ConnectedProps } from 'react-redux';
|
import { connect, ConnectedProps } from 'react-redux';
|
||||||
import { DataSourcePluginMeta, NavModel } from '@grafana/data';
|
import { DataSourcePluginMeta, NavModel } from '@grafana/data';
|
||||||
import { Button, LinkButton, List, PluginSignatureBadge } from '@grafana/ui';
|
import { Button, LinkButton, List, PluginSignatureBadge, FilterInput } from '@grafana/ui';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
|
|
||||||
import Page from 'app/core/components/Page/Page';
|
import Page from 'app/core/components/Page/Page';
|
||||||
import { StoreState } from 'app/types';
|
import { StoreState } from 'app/types';
|
||||||
import { addDataSource, loadDataSourcePlugins } from './state/actions';
|
import { addDataSource, loadDataSourcePlugins } from './state/actions';
|
||||||
import { getDataSourcePlugins } from './state/selectors';
|
import { getDataSourcePlugins } from './state/selectors';
|
||||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
|
||||||
import { setDataSourceTypeSearchQuery } from './state/reducers';
|
import { setDataSourceTypeSearchQuery } from './state/reducers';
|
||||||
import { Card } from 'app/core/components/Card/Card';
|
import { Card } from 'app/core/components/Card/Card';
|
||||||
import { PluginsErrorsInfo } from '../plugins/PluginsErrorsInfo';
|
import { PluginsErrorsInfo } from '../plugins/PluginsErrorsInfo';
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { uniqBy } from 'lodash';
|
|||||||
import { RichHistoryQuery, ExploreId } from 'app/types/explore';
|
import { RichHistoryQuery, ExploreId } from 'app/types/explore';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { stylesFactory, useTheme, RangeSlider, MultiSelect, Select } from '@grafana/ui';
|
import { stylesFactory, useTheme, RangeSlider, MultiSelect, Select, FilterInput } from '@grafana/ui';
|
||||||
import { GrafanaTheme, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme, SelectableValue } from '@grafana/data';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -20,7 +20,6 @@ import {
|
|||||||
// Components
|
// Components
|
||||||
import RichHistoryCard from './RichHistoryCard';
|
import RichHistoryCard from './RichHistoryCard';
|
||||||
import { sortOrderOptions } from './RichHistory';
|
import { sortOrderOptions } from './RichHistory';
|
||||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
|
||||||
import { useDebounce } from 'react-use';
|
import { useDebounce } from 'react-use';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ import { uniqBy } from 'lodash';
|
|||||||
import { RichHistoryQuery, ExploreId } from 'app/types/explore';
|
import { RichHistoryQuery, ExploreId } from 'app/types/explore';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { stylesFactory, useTheme, Select, MultiSelect } from '@grafana/ui';
|
import { stylesFactory, useTheme, Select, MultiSelect, FilterInput } from '@grafana/ui';
|
||||||
import { GrafanaTheme, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme, SelectableValue } from '@grafana/data';
|
||||||
import { filterAndSortQueries, createDatasourcesList, SortOrder } from 'app/core/utils/richHistory';
|
import { filterAndSortQueries, createDatasourcesList, SortOrder } from 'app/core/utils/richHistory';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import RichHistoryCard from './RichHistoryCard';
|
import RichHistoryCard from './RichHistoryCard';
|
||||||
import { sortOrderOptions } from './RichHistory';
|
import { sortOrderOptions } from './RichHistory';
|
||||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
|
||||||
import { useDebounce } from 'react-use';
|
import { useDebounce } from 'react-use';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import React, { useReducer } from 'react';
|
import React, { useReducer } from 'react';
|
||||||
import { HorizontalGroup, useStyles2, VerticalGroup } from '@grafana/ui';
|
import { HorizontalGroup, useStyles2, VerticalGroup, FilterInput } from '@grafana/ui';
|
||||||
import { GrafanaTheme2, PanelPluginMeta, SelectableValue } from '@grafana/data';
|
import { GrafanaTheme2, PanelPluginMeta, SelectableValue } from '@grafana/data';
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { FilterInput } from '../../../../core/components/FilterInput/FilterInput';
|
|
||||||
import { SortPicker } from '../../../../core/components/Select/SortPicker';
|
import { SortPicker } from '../../../../core/components/Select/SortPicker';
|
||||||
import { PanelTypeFilter } from '../../../../core/components/PanelTypeFilter/PanelTypeFilter';
|
import { PanelTypeFilter } from '../../../../core/components/PanelTypeFilter/PanelTypeFilter';
|
||||||
import { LibraryPanelsView } from '../LibraryPanelsView/LibraryPanelsView';
|
import { LibraryPanelsView } from '../LibraryPanelsView/LibraryPanelsView';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { FilterInput } from '@grafana/ui';
|
||||||
import React, { useState, useRef } from 'react';
|
import React, { useState, useRef } from 'react';
|
||||||
import { useDebounce } from 'react-use';
|
import { useDebounce } from 'react-use';
|
||||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
value?: string;
|
value?: string;
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import React, { FC, memo, useState } from 'react';
|
import React, { FC, memo, useState } from 'react';
|
||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { stylesFactory, useTheme, Spinner } from '@grafana/ui';
|
import { stylesFactory, useTheme, Spinner, FilterInput } from '@grafana/ui';
|
||||||
import { GrafanaTheme } from '@grafana/data';
|
import { GrafanaTheme } from '@grafana/data';
|
||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
|
||||||
import { FolderDTO } from 'app/types';
|
import { FolderDTO } from 'app/types';
|
||||||
import { useManageDashboards } from '../hooks/useManageDashboards';
|
import { useManageDashboards } from '../hooks/useManageDashboards';
|
||||||
import { SearchLayout } from '../types';
|
import { SearchLayout } from '../types';
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import Page from 'app/core/components/Page/Page';
|
import Page from 'app/core/components/Page/Page';
|
||||||
import { DeleteButton, LinkButton } from '@grafana/ui';
|
import { DeleteButton, LinkButton, FilterInput } from '@grafana/ui';
|
||||||
import { NavModel } from '@grafana/data';
|
import { NavModel } from '@grafana/data';
|
||||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||||
import { OrgRole, StoreState, Team } from 'app/types';
|
import { OrgRole, StoreState, Team } from 'app/types';
|
||||||
import { deleteTeam, loadTeams } from './state/actions';
|
import { deleteTeam, loadTeams } from './state/actions';
|
||||||
import { getSearchQuery, getTeams, getTeamsCount, isPermissionTeamAdmin } from './state/selectors';
|
import { getSearchQuery, getTeams, getTeamsCount, isPermissionTeamAdmin } from './state/selectors';
|
||||||
import { getNavModel } from 'app/core/selectors/navModel';
|
import { getNavModel } from 'app/core/selectors/navModel';
|
||||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
|
||||||
import { config } from 'app/core/config';
|
import { config } from 'app/core/config';
|
||||||
import { contextSrv, User } from 'app/core/services/context_srv';
|
import { contextSrv, User } from 'app/core/services/context_srv';
|
||||||
import { connectWithCleanUp } from '../../core/components/connectWithCleanUp';
|
import { connectWithCleanUp } from '../../core/components/connectWithCleanUp';
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ import { TagBadge } from 'app/core/components/TagFilter/TagBadge';
|
|||||||
import { TeamMember, OrgUser } from 'app/types';
|
import { TeamMember, OrgUser } from 'app/types';
|
||||||
import { addTeamMember } from './state/actions';
|
import { addTeamMember } from './state/actions';
|
||||||
import { getSearchMemberQuery, isSignedInUserTeamAdmin } from './state/selectors';
|
import { getSearchMemberQuery, isSignedInUserTeamAdmin } from './state/selectors';
|
||||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
|
||||||
import { WithFeatureToggle } from 'app/core/components/WithFeatureToggle';
|
import { WithFeatureToggle } from 'app/core/components/WithFeatureToggle';
|
||||||
import { config } from 'app/core/config';
|
import { config } from 'app/core/config';
|
||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
import TeamMemberRow from './TeamMemberRow';
|
import TeamMemberRow from './TeamMemberRow';
|
||||||
import { setSearchMemberQuery } from './state/reducers';
|
import { setSearchMemberQuery } from './state/reducers';
|
||||||
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
|
import { CloseButton } from 'app/core/components/CloseButton/CloseButton';
|
||||||
import { Button } from '@grafana/ui';
|
import { Button, FilterInput } from '@grafana/ui';
|
||||||
import { SelectableValue } from '@grafana/data';
|
import { SelectableValue } from '@grafana/data';
|
||||||
|
|
||||||
function mapStateToProps(state: any) {
|
function mapStateToProps(state: any) {
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import React, { PureComponent } from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { setUsersSearchQuery } from './state/reducers';
|
import { setUsersSearchQuery } from './state/reducers';
|
||||||
import { getInviteesCount, getUsersSearchQuery } from './state/selectors';
|
import { getInviteesCount, getUsersSearchQuery } from './state/selectors';
|
||||||
import { FilterInput } from 'app/core/components/FilterInput/FilterInput';
|
import { RadioButtonGroup, LinkButton, FilterInput } from '@grafana/ui';
|
||||||
import { RadioButtonGroup, LinkButton } from '@grafana/ui';
|
|
||||||
import { contextSrv } from 'app/core/core';
|
import { contextSrv } from 'app/core/core';
|
||||||
import { AccessControlAction } from 'app/types';
|
import { AccessControlAction } from 'app/types';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user