From c13ec0fc1507ea0fe909b7710a96dc8b836370f0 Mon Sep 17 00:00:00 2001 From: Joey <90795735+joey-grafana@users.noreply.github.com> Date: Wed, 19 Apr 2023 11:58:00 +0100 Subject: [PATCH] Tracing: Span filters reset filters and button (#66781) * Reset filters and button * Add tests --- .../NewTracePageSearchBar.test.tsx | 13 ++- .../TracePageHeader/NewTracePageSearchBar.tsx | 97 +++++++++++++------ .../SpanFilters/SpanFilters.test.tsx | 23 +++++ .../SpanFilters/SpanFilters.tsx | 23 ++++- 4 files changed, 117 insertions(+), 39 deletions(-) diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/NewTracePageSearchBar.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/NewTracePageSearchBar.test.tsx index 5fd328bbe29..fdc550211d9 100644 --- a/public/app/features/explore/TraceView/components/TracePageHeader/NewTracePageSearchBar.test.tsx +++ b/public/app/features/explore/TraceView/components/TracePageHeader/NewTracePageSearchBar.test.tsx @@ -27,22 +27,25 @@ const defaultProps = { describe('', () => { it('renders buttons', () => { render(); - 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(); - 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); diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/NewTracePageSearchBar.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/NewTracePageSearchBar.tsx index e6788659b47..c0ffd8460d3 100644 --- a/public/app/features/explore/TraceView/components/TracePageHeader/NewTracePageSearchBar.tsx +++ b/public/app/features/explore/TraceView/components/TracePageHeader/NewTracePageSearchBar.tsx @@ -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>; 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 (
- <> - - - +
+ <> +
+ +
+
+ + +
+ +
); }); @@ -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; + } `, }; }; diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.test.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.test.tsx index 12672b5c20a..857398e7739 100644 --- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.test.tsx +++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.test.tsx @@ -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(); + 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, elem: HTMLElement, text: string) => { diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx index cf082ed06e1..829c1778fb5 100644 --- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx +++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx @@ -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>>(); const [tagValues, setTagValues] = useState<{ [key: string]: Array> }>({}); + 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} /> @@ -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} /> @@ -309,7 +321,7 @@ export const SpanFilters = memo((props: SpanFilterProps) => { onOpenMenu={getTagKeys} options={tagKeys} placeholder="Select tag" - value={tag.key} + value={tag.key || null} />