Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracing: Span filters reset filters and button #66781

Merged
merged 2 commits into from
Apr 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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(() => {
Expand Down Expand Up @@ -77,47 +79,84 @@ 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>
);
});

export const getStyles = () => {
return {
searchBar: css`
display: inline;
`,
buttons: css`
display: flex;
justify-content: flex-end;
margin-top: 5px;
margin: 5px 0 0 0;
`,
resetButton: css`
order: 1;
`,
button: css`
margin-left: 8px;
nextPrevButtons: css`
margin-left: auto;
order: 2;

button {
margin-left: 8px;
}
`,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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';

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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>
Expand All @@ -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>
Expand Down Expand Up @@ -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`}
Expand Down Expand Up @@ -374,6 +386,7 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
focusedSpanIdForSearch={focusedSpanIdForSearch}
setFocusedSpanIdForSearch={setFocusedSpanIdForSearch}
datasourceType={datasourceType}
reset={reset}
/>
</Collapse>
</div>
Expand Down
Loading