mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Tracing: Span filters reset filters and button (#66781)
* Reset filters and button * Add tests
This commit is contained in:
parent
ba92f6f98a
commit
c13ec0fc15
@ -27,22 +27,25 @@ const defaultProps = {
|
||||
describe('<NewTracePageSearchBar>', () => {
|
||||
it('renders buttons', () => {
|
||||
render(<NewTracePageSearchBar {...(defaultProps as unknown as TracePageSearchBarProps)} />);
|
||||
const nextResButton = screen.queryByRole('button', { name: 'Next result button' });
|
||||
const prevResButton = screen.queryByRole('button', { name: 'Prev result button' });
|
||||
const nextResButton = screen.getByRole('button', { name: 'Next result button' });
|
||||
const prevResButton = screen.getByRole('button', { name: 'Prev result button' });
|
||||
const resetFiltersButton = screen.getByRole('button', { name: 'Reset filters button' });
|
||||
expect(nextResButton).toBeInTheDocument();
|
||||
expect(prevResButton).toBeInTheDocument();
|
||||
expect(resetFiltersButton).toBeInTheDocument();
|
||||
expect((nextResButton as HTMLButtonElement)['disabled']).toBe(true);
|
||||
expect((prevResButton as HTMLButtonElement)['disabled']).toBe(true);
|
||||
expect((resetFiltersButton as HTMLButtonElement)['disabled']).toBe(true);
|
||||
});
|
||||
|
||||
it('renders buttons that can be used to search if filters added', () => {
|
||||
it('renders buttons that can be used to search if results found', () => {
|
||||
const props = {
|
||||
...defaultProps,
|
||||
spanFilterMatches: new Set(['2ed38015486087ca']),
|
||||
};
|
||||
render(<NewTracePageSearchBar {...(props as unknown as TracePageSearchBarProps)} />);
|
||||
const nextResButton = screen.queryByRole('button', { name: 'Next result button' });
|
||||
const prevResButton = screen.queryByRole('button', { name: 'Prev result button' });
|
||||
const nextResButton = screen.getByRole('button', { name: 'Next result button' });
|
||||
const prevResButton = screen.getByRole('button', { name: 'Prev result button' });
|
||||
expect(nextResButton).toBeInTheDocument();
|
||||
expect(prevResButton).toBeInTheDocument();
|
||||
expect((nextResButton as HTMLButtonElement)['disabled']).toBe(false);
|
||||
|
@ -13,12 +13,13 @@
|
||||
// limitations under the License.
|
||||
|
||||
import { css } from '@emotion/css';
|
||||
import React, { memo, Dispatch, SetStateAction, useEffect } from 'react';
|
||||
import React, { memo, Dispatch, SetStateAction, useEffect, useMemo } from 'react';
|
||||
|
||||
import { config, reportInteraction } from '@grafana/runtime';
|
||||
import { Button, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { SearchProps } from '../../useSearch';
|
||||
import { convertTimeFilter } from '../utils/filter-spans';
|
||||
|
||||
export type TracePageSearchBarProps = {
|
||||
search: SearchProps;
|
||||
@ -27,10 +28,11 @@ export type TracePageSearchBarProps = {
|
||||
focusedSpanIdForSearch: string;
|
||||
setFocusedSpanIdForSearch: Dispatch<SetStateAction<string>>;
|
||||
datasourceType: string;
|
||||
reset: () => void;
|
||||
};
|
||||
|
||||
export default memo(function NewTracePageSearchBar(props: TracePageSearchBarProps) {
|
||||
const { search, spanFilterMatches, focusedSpanIdForSearch, setFocusedSpanIdForSearch, datasourceType } = props;
|
||||
const { search, spanFilterMatches, focusedSpanIdForSearch, setFocusedSpanIdForSearch, datasourceType, reset } = props;
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
useEffect(() => {
|
||||
@ -77,34 +79,60 @@ export default memo(function NewTracePageSearchBar(props: TracePageSearchBarProp
|
||||
setFocusedSpanIdForSearch(spanMatches[prevMatchedIndex - 1]);
|
||||
};
|
||||
|
||||
const resetEnabled = useMemo(() => {
|
||||
return (
|
||||
(search.serviceName && search.serviceName !== '') ||
|
||||
(search.spanName && search.spanName !== '') ||
|
||||
convertTimeFilter(search.from || '') ||
|
||||
convertTimeFilter(search.to || '') ||
|
||||
search.tags.length > 1 ||
|
||||
search.tags.some((tag) => {
|
||||
return tag.key;
|
||||
})
|
||||
);
|
||||
}, [search.serviceName, search.spanName, search.from, search.to, search.tags]);
|
||||
const buttonEnabled = spanFilterMatches && spanFilterMatches?.size > 0;
|
||||
|
||||
return (
|
||||
<div className={styles.searchBar}>
|
||||
<>
|
||||
<Button
|
||||
className={styles.button}
|
||||
variant="secondary"
|
||||
disabled={!buttonEnabled}
|
||||
type="button"
|
||||
fill={'outline'}
|
||||
aria-label="Prev result button"
|
||||
onClick={prevResult}
|
||||
>
|
||||
Prev
|
||||
</Button>
|
||||
<Button
|
||||
className={styles.button}
|
||||
variant="secondary"
|
||||
disabled={!buttonEnabled}
|
||||
type="button"
|
||||
fill={'outline'}
|
||||
aria-label="Next result button"
|
||||
onClick={nextResult}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
</>
|
||||
<div className={styles.buttons}>
|
||||
<>
|
||||
<div className={styles.resetButton}>
|
||||
<Button
|
||||
variant="destructive"
|
||||
disabled={!resetEnabled}
|
||||
type="button"
|
||||
fill="outline"
|
||||
aria-label="Reset filters button"
|
||||
onClick={reset}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
</div>
|
||||
<div className={styles.nextPrevButtons}>
|
||||
<Button
|
||||
variant="secondary"
|
||||
disabled={!buttonEnabled}
|
||||
type="button"
|
||||
fill="outline"
|
||||
aria-label="Prev result button"
|
||||
onClick={prevResult}
|
||||
>
|
||||
Prev
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
disabled={!buttonEnabled}
|
||||
type="button"
|
||||
fill="outline"
|
||||
aria-label="Next result button"
|
||||
onClick={nextResult}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@ -112,12 +140,23 @@ export default memo(function NewTracePageSearchBar(props: TracePageSearchBarProp
|
||||
export const getStyles = () => {
|
||||
return {
|
||||
searchBar: css`
|
||||
display: inline;
|
||||
`,
|
||||
buttons: css`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 5px;
|
||||
margin: 5px 0 0 0;
|
||||
`,
|
||||
button: css`
|
||||
margin-left: 8px;
|
||||
resetButton: css`
|
||||
order: 1;
|
||||
`,
|
||||
nextPrevButtons: css`
|
||||
margin-left: auto;
|
||||
order: 2;
|
||||
|
||||
button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
`,
|
||||
};
|
||||
};
|
||||
|
@ -162,6 +162,29 @@ describe('SpanFilters', () => {
|
||||
jest.advanceTimersByTime(1000);
|
||||
expect(screen.getAllByLabelText('Select tag key').length).toBe(1);
|
||||
});
|
||||
|
||||
it('should allow resetting filters', async () => {
|
||||
render(<SpanFiltersWithProps />);
|
||||
const resetFiltersButton = screen.getByRole('button', { name: 'Reset filters button' });
|
||||
expect(resetFiltersButton).toBeInTheDocument();
|
||||
expect((resetFiltersButton as HTMLButtonElement)['disabled']).toBe(true);
|
||||
|
||||
const serviceValue = screen.getByLabelText('Select service name');
|
||||
const spanValue = screen.getByLabelText('Select span name');
|
||||
const tagKey = screen.getByLabelText('Select tag key');
|
||||
const tagValue = screen.getByLabelText('Select tag value');
|
||||
await selectAndCheckValue(user, serviceValue, 'Service0');
|
||||
await selectAndCheckValue(user, spanValue, 'Span0');
|
||||
await selectAndCheckValue(user, tagKey, 'TagKey0');
|
||||
await selectAndCheckValue(user, tagValue, 'TagValue0');
|
||||
|
||||
expect((resetFiltersButton as HTMLButtonElement)['disabled']).toBe(false);
|
||||
await user.click(resetFiltersButton);
|
||||
expect(screen.queryByText('Service0')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('Span0')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('TagKey0')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('TagValue0')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
const selectAndCheckValue = async (user: ReturnType<typeof userEvent.setup>, elem: HTMLElement, text: string) => {
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
import { css } from '@emotion/css';
|
||||
import { uniq } from 'lodash';
|
||||
import React, { useState, memo } from 'react';
|
||||
import React, { useState, useEffect, memo, useCallback } from 'react';
|
||||
|
||||
import { SelectableValue, toOption } from '@grafana/data';
|
||||
import { AccessoryButton } from '@grafana/experimental';
|
||||
@ -30,7 +30,7 @@ import {
|
||||
useStyles2,
|
||||
} from '@grafana/ui';
|
||||
|
||||
import { randomId, SearchProps, Tag } from '../../../useSearch';
|
||||
import { defaultFilters, randomId, SearchProps, Tag } from '../../../useSearch';
|
||||
import { Trace } from '../../types';
|
||||
import NewTracePageSearchBar from '../NewTracePageSearchBar';
|
||||
|
||||
@ -64,6 +64,18 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
|
||||
const [tagKeys, setTagKeys] = useState<Array<SelectableValue<string>>>();
|
||||
const [tagValues, setTagValues] = useState<{ [key: string]: Array<SelectableValue<string>> }>({});
|
||||
|
||||
const reset = useCallback(() => {
|
||||
setServiceNames(undefined);
|
||||
setSpanNames(undefined);
|
||||
setTagKeys(undefined);
|
||||
setTagValues({});
|
||||
setSearch(defaultFilters);
|
||||
}, [setSearch]);
|
||||
|
||||
useEffect(() => {
|
||||
reset();
|
||||
}, [reset, trace]);
|
||||
|
||||
if (!trace) {
|
||||
return null;
|
||||
}
|
||||
@ -237,7 +249,7 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
|
||||
onOpenMenu={getServiceNames}
|
||||
options={serviceNames}
|
||||
placeholder="All service names"
|
||||
value={search.serviceName}
|
||||
value={search.serviceName || null}
|
||||
/>
|
||||
</HorizontalGroup>
|
||||
</InlineField>
|
||||
@ -258,7 +270,7 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
|
||||
onOpenMenu={getSpanNames}
|
||||
options={spanNames}
|
||||
placeholder="All span names"
|
||||
value={search.spanName}
|
||||
value={search.spanName || null}
|
||||
/>
|
||||
</HorizontalGroup>
|
||||
</InlineField>
|
||||
@ -309,7 +321,7 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
|
||||
onOpenMenu={getTagKeys}
|
||||
options={tagKeys}
|
||||
placeholder="Select tag"
|
||||
value={tag.key}
|
||||
value={tag.key || null}
|
||||
/>
|
||||
<Select
|
||||
aria-label={`Select tag operator`}
|
||||
@ -374,6 +386,7 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
|
||||
focusedSpanIdForSearch={focusedSpanIdForSearch}
|
||||
setFocusedSpanIdForSearch={setFocusedSpanIdForSearch}
|
||||
datasourceType={datasourceType}
|
||||
reset={reset}
|
||||
/>
|
||||
</Collapse>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user