diff --git a/.betterer.results b/.betterer.results index ba09360a954..3433ae08502 100644 --- a/.betterer.results +++ b/.betterer.results @@ -4422,6 +4422,17 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "23"], [0, 0, 0, "No untranslated strings. Wrap text with ", "24"] ], + "public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFiltersTags.tsx:5381": [ + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "2"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "3"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "4"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "5"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "6"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "7"], + [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "8"] + ], "public/app/features/explore/TraceView/components/TracePageHeader/SpanGraph/ViewingLayer.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"] ], diff --git a/public/app/features/explore/TraceView/TraceView.tsx b/public/app/features/explore/TraceView/TraceView.tsx index 93a5a33d989..0366c74ba20 100644 --- a/public/app/features/explore/TraceView/TraceView.tsx +++ b/public/app/features/explore/TraceView/TraceView.tsx @@ -40,7 +40,7 @@ import { createSpanLinkFactory } from './createSpanLink'; import { useChildrenState } from './useChildrenState'; import { useDetailState } from './useDetailState'; import { useHoverIndentGuide } from './useHoverIndentGuide'; -import { useSearch } from './useSearch'; +import { SearchProps, useSearch } from './useSearch'; import { useViewRange } from './useViewRange'; const getStyles = (theme: GrafanaTheme2) => ({ @@ -66,6 +66,7 @@ type Props = { createSpanLink?: SpanLinkFunc; focusedSpanId?: string; createFocusSpanLink?: (traceId: string, spanId: string) => LinkModel; + spanFilters?: SearchProps; }; export function TraceView(props: Props) { @@ -77,6 +78,7 @@ export function TraceView(props: Props) { createSpanLink: createSpanLinkFromProps, focusedSpanId: focusedSpanIdFromProps, createFocusSpanLink: createFocusSpanLinkFromProps, + spanFilters, } = props; const { @@ -95,11 +97,9 @@ export function TraceView(props: Props) { const { removeHoverIndentGuideId, addHoverIndentGuideId, hoverIndentGuideIds } = useHoverIndentGuide(); const { viewRange, updateViewRangeTime, updateNextViewRangeTime } = useViewRange(); const { expandOne, collapseOne, childrenToggle, collapseAll, childrenHiddenIDs, expandAll } = useChildrenState(); - const { search, setSearch, spanFilterMatches } = useSearch(traceProp?.spans); + const { search, setSearch, spanFilterMatches } = useSearch(traceProp?.spans, spanFilters); const [focusedSpanIdForSearch, setFocusedSpanIdForSearch] = useState(''); const [showSpanFilters, setShowSpanFilters] = useToggle(false); - const [showSpanFilterMatchesOnly, setShowSpanFilterMatchesOnly] = useState(false); - const [showCriticalPathSpansOnly, setShowCriticalPathSpansOnly] = useState(false); const [headerHeight, setHeaderHeight] = useState(100); const [traceFlameGraphs, setTraceFlameGraphs] = useState({}); const [redrawListView, setRedrawListView] = useState({}); @@ -183,10 +183,6 @@ export function TraceView(props: Props) { setSearch={setSearch} showSpanFilters={showSpanFilters} setShowSpanFilters={setShowSpanFilters} - showSpanFilterMatchesOnly={showSpanFilterMatchesOnly} - setShowSpanFilterMatchesOnly={setShowSpanFilterMatchesOnly} - showCriticalPathSpansOnly={showCriticalPathSpansOnly} - setShowCriticalPathSpansOnly={setShowCriticalPathSpansOnly} setFocusedSpanIdForSearch={setFocusedSpanIdForSearch} spanFilterMatches={spanFilterMatches} datasourceType={datasourceType} @@ -232,8 +228,8 @@ export function TraceView(props: Props) { scrollElement={scrollElement} focusedSpanId={focusedSpanId} focusedSpanIdForSearch={focusedSpanIdForSearch} - showSpanFilterMatchesOnly={showSpanFilterMatchesOnly} - showCriticalPathSpansOnly={showCriticalPathSpansOnly} + showSpanFilterMatchesOnly={search.matchesOnly} + showCriticalPathSpansOnly={search.criticalPathOnly} createFocusSpanLink={createFocusSpanLink} topOfViewRef={topOfViewRef} headerHeight={headerHeight} diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/TracePageSearchBar.tsx b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/TracePageSearchBar.tsx index ee8a81024f7..4be50e499a2 100644 --- a/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/TracePageSearchBar.tsx +++ b/public/app/features/explore/TraceView/components/TracePageHeader/SearchBar/TracePageSearchBar.tsx @@ -29,9 +29,7 @@ export type TracePageSearchBarProps = { trace: Trace; search: SearchProps; spanFilterMatches: Set | undefined; - showSpanFilterMatchesOnly: boolean; setShowSpanFilterMatchesOnly: (showMatchesOnly: boolean) => void; - showCriticalPathSpansOnly: boolean; setShowCriticalPathSpansOnly: (showCriticalPath: boolean) => void; focusedSpanIndexForSearch: number; setFocusedSpanIndexForSearch: Dispatch>; @@ -46,9 +44,7 @@ export default memo(function TracePageSearchBar(props: TracePageSearchBarProps) trace, search, spanFilterMatches, - showSpanFilterMatchesOnly, setShowSpanFilterMatchesOnly, - showCriticalPathSpansOnly, setShowCriticalPathSpansOnly, focusedSpanIndexForSearch, setFocusedSpanIndexForSearch, @@ -70,17 +66,9 @@ export default memo(function TracePageSearchBar(props: TracePageSearchBarProps) return tag.key; }) || (search.query && search.query !== '') || - showSpanFilterMatchesOnly + search.matchesOnly ); - }, [ - search.serviceName, - search.spanName, - search.from, - search.to, - search.tags, - search.query, - showSpanFilterMatchesOnly, - ]); + }, [search.serviceName, search.spanName, search.from, search.to, search.tags, search.query, search.matchesOnly]); return (
@@ -99,13 +87,13 @@ export default memo(function TracePageSearchBar(props: TracePageSearchBarProps)
setShowSpanFilterMatchesOnly(value.currentTarget.checked ?? false)} label="Show matches only switch" disabled={!spanFilterMatches?.size} />
setShowCriticalPathSpansOnly(value.currentTarget.checked ?? false)} label="Show critical path only switch" />
); diff --git a/public/app/plugins/panel/traces/module.tsx b/public/app/plugins/panel/traces/module.tsx index 19fae657d5f..9c1696ab137 100644 --- a/public/app/plugins/panel/traces/module.tsx +++ b/public/app/plugins/panel/traces/module.tsx @@ -1,6 +1,107 @@ -import { PanelPlugin } from '@grafana/data'; +import { PanelPlugin, toOption } from '@grafana/data'; +import { getTraceServiceNames, getTraceSpanNames } from '../../../features/explore/TraceView/utils/tags'; +import { transformDataFrames } from '../../../features/explore/TraceView/utils/transform'; + +import { TagsEditor } from './TagsEditor'; import { TracesPanel } from './TracesPanel'; import { TracesSuggestionsSupplier } from './suggestions'; -export const plugin = new PanelPlugin(TracesPanel).setSuggestionsSupplier(new TracesSuggestionsSupplier()); +export const plugin = new PanelPlugin(TracesPanel) + .setPanelOptions((builder, context) => { + const category = ['Span filters']; + const trace = transformDataFrames(context?.data?.[0]); + + // Find + builder + .addTextInput({ + path: 'spanFilters.query', + name: 'Find in trace', + category, + }) + .addBooleanSwitch({ + path: 'spanFilters.matchesOnly', + name: 'Show matches only', + defaultValue: false, + category, + }) + .addBooleanSwitch({ + path: 'spanFilters.criticalPathOnly', + name: 'Show critical path only', + defaultValue: false, + category, + }); + + // Service name + builder + .addSelect({ + path: 'spanFilters.serviceName', + name: 'Service name', + category, + settings: { + options: trace ? getTraceServiceNames(trace).map(toOption) : [], + allowCustomValue: true, + isClearable: true, + }, + }) + .addRadio({ + path: 'spanFilters.serviceNameOperator', + name: 'Service name operator', + defaultValue: '=', + settings: { + options: [ + { value: '=', label: '=' }, + { value: '!=', label: '!=' }, + ], + }, + category, + }); + + // Span name + builder + .addSelect({ + path: 'spanFilters.spanName', + name: 'Span name', + category, + settings: { + options: trace ? getTraceSpanNames(trace).map(toOption) : [], + allowCustomValue: true, + isClearable: true, + }, + }) + .addRadio({ + path: 'spanFilters.spanNameOperator', + name: 'Span name operator', + defaultValue: '=', + settings: { + options: [ + { value: '=', label: '=' }, + { value: '!=', label: '!=' }, + ], + }, + category, + }); + + // Duration + builder + .addTextInput({ + path: 'spanFilters.from', + name: 'Min duration', + category, + }) + .addTextInput({ + path: 'spanFilters.to', + name: 'Max duration', + category, + }); + + builder.addCustomEditor({ + id: 'tags', + name: 'Tags', + path: 'spanFilters', + category, + editor: TagsEditor, + defaultValue: undefined, + }); + }) + .setSuggestionsSupplier(new TracesSuggestionsSupplier());