mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Traces: Only show filtered spans (#66986)
* Only show filtered spans * Add & update tests
This commit is contained in:
parent
61e3bbb858
commit
d949aa778b
@ -99,6 +99,7 @@ export function TraceView(props: Props) {
|
||||
);
|
||||
const [newTraceViewHeaderFocusedSpanIdForSearch, setNewTraceViewHeaderFocusedSpanIdForSearch] = useState('');
|
||||
const [showSpanFilters, setShowSpanFilters] = useToggle(false);
|
||||
const [showSpanFilterMatchesOnly, setShowSpanFilterMatchesOnly] = useState(false);
|
||||
const [headerHeight, setHeaderHeight] = useState(0);
|
||||
|
||||
const styles = useStyles2(getStyles);
|
||||
@ -163,6 +164,8 @@ export function TraceView(props: Props) {
|
||||
setSearch={setNewTraceViewHeaderSearch}
|
||||
showSpanFilters={showSpanFilters}
|
||||
setShowSpanFilters={setShowSpanFilters}
|
||||
showSpanFilterMatchesOnly={showSpanFilterMatchesOnly}
|
||||
setShowSpanFilterMatchesOnly={setShowSpanFilterMatchesOnly}
|
||||
focusedSpanIdForSearch={newTraceViewHeaderFocusedSpanIdForSearch}
|
||||
setFocusedSpanIdForSearch={setNewTraceViewHeaderFocusedSpanIdForSearch}
|
||||
spanFilterMatches={spanFilterMatches}
|
||||
@ -226,6 +229,7 @@ export function TraceView(props: Props) {
|
||||
? newTraceViewHeaderFocusedSpanIdForSearch
|
||||
: props.focusedSpanIdForSearch!
|
||||
}
|
||||
showSpanFilterMatchesOnly={showSpanFilterMatchesOnly}
|
||||
createFocusSpanLink={createFocusSpanLink}
|
||||
topOfViewRef={topOfViewRef}
|
||||
topOfViewRefType={topOfViewRefType}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React, { createRef } from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { getDefaultTimeRange, LoadingState } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { ExploreId } from 'app/types';
|
||||
|
||||
import { configureStore } from '../../../store/configureStore';
|
||||
@ -47,37 +48,48 @@ function renderTraceViewContainer(frames = [frameOld]) {
|
||||
}
|
||||
|
||||
describe('TraceViewContainer', () => {
|
||||
let user: ReturnType<typeof userEvent.setup>;
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
// Need to use delay: null here to work with fakeTimers
|
||||
// see https://github.com/testing-library/user-event/issues/833
|
||||
user = userEvent.setup({ delay: null });
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('toggles children visibility', async () => {
|
||||
renderTraceViewContainer();
|
||||
expect(screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' }).length).toBe(3);
|
||||
await userEvent.click(screen.getAllByText('', { selector: 'span[data-testid="SpanTreeOffset--indentGuide"]' })[0]);
|
||||
await user.click(screen.getAllByText('', { selector: 'span[data-testid="SpanTreeOffset--indentGuide"]' })[0]);
|
||||
expect(screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' }).length).toBe(1);
|
||||
|
||||
await userEvent.click(screen.getAllByText('', { selector: 'span[data-testid="SpanTreeOffset--indentGuide"]' })[0]);
|
||||
await user.click(screen.getAllByText('', { selector: 'span[data-testid="SpanTreeOffset--indentGuide"]' })[0]);
|
||||
expect(screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' }).length).toBe(3);
|
||||
});
|
||||
|
||||
it('toggles collapses and expands one level of spans', async () => {
|
||||
renderTraceViewContainer();
|
||||
expect(screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' }).length).toBe(3);
|
||||
await userEvent.click(screen.getByLabelText('Collapse +1'));
|
||||
await user.click(screen.getByLabelText('Collapse +1'));
|
||||
expect(screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' }).length).toBe(2);
|
||||
await userEvent.click(screen.getByLabelText('Expand +1'));
|
||||
await user.click(screen.getByLabelText('Expand +1'));
|
||||
expect(screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' }).length).toBe(3);
|
||||
});
|
||||
|
||||
it('toggles collapses and expands all levels', async () => {
|
||||
renderTraceViewContainer();
|
||||
expect(screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' }).length).toBe(3);
|
||||
await userEvent.click(screen.getByLabelText('Collapse All'));
|
||||
await user.click(screen.getByLabelText('Collapse All'));
|
||||
expect(screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' }).length).toBe(1);
|
||||
await userEvent.click(screen.getByLabelText('Expand All'));
|
||||
await user.click(screen.getByLabelText('Expand All'));
|
||||
expect(screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' }).length).toBe(3);
|
||||
});
|
||||
|
||||
it('searches for spans', async () => {
|
||||
renderTraceViewContainer();
|
||||
await userEvent.type(screen.getByPlaceholderText('Find...'), '1ed38015486087ca');
|
||||
await user.type(screen.getByPlaceholderText('Find...'), '1ed38015486087ca');
|
||||
expect(
|
||||
screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' })[0].parentElement!.className
|
||||
).toContain('rowMatchingFilter');
|
||||
@ -85,40 +97,58 @@ describe('TraceViewContainer', () => {
|
||||
|
||||
it('can select next/prev results', async () => {
|
||||
renderTraceViewContainer();
|
||||
await userEvent.type(screen.getByPlaceholderText('Find...'), 'logproto');
|
||||
await user.type(screen.getByPlaceholderText('Find...'), 'logproto');
|
||||
const nextResultButton = screen.getByRole('button', { name: 'Next results button' });
|
||||
const prevResultButton = screen.getByRole('button', { name: 'Prev results button' });
|
||||
const suffix = screen.getByLabelText('Search bar suffix');
|
||||
|
||||
await userEvent.click(nextResultButton);
|
||||
await user.click(nextResultButton);
|
||||
expect(suffix.textContent).toBe('1 of 2');
|
||||
expect(
|
||||
screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' })[1].parentElement!.className
|
||||
).toContain('rowFocused');
|
||||
await userEvent.click(nextResultButton);
|
||||
await user.click(nextResultButton);
|
||||
expect(suffix.textContent).toBe('2 of 2');
|
||||
expect(
|
||||
screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' })[2].parentElement!.className
|
||||
).toContain('rowFocused');
|
||||
await userEvent.click(nextResultButton);
|
||||
await user.click(nextResultButton);
|
||||
expect(suffix.textContent).toBe('1 of 2');
|
||||
expect(
|
||||
screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' })[1].parentElement!.className
|
||||
).toContain('rowFocused');
|
||||
await userEvent.click(prevResultButton);
|
||||
await user.click(prevResultButton);
|
||||
expect(suffix.textContent).toBe('2 of 2');
|
||||
expect(
|
||||
screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' })[2].parentElement!.className
|
||||
).toContain('rowFocused');
|
||||
await userEvent.click(prevResultButton);
|
||||
await user.click(prevResultButton);
|
||||
expect(suffix.textContent).toBe('1 of 2');
|
||||
expect(
|
||||
screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' })[1].parentElement!.className
|
||||
).toContain('rowFocused');
|
||||
await userEvent.click(prevResultButton);
|
||||
await user.click(prevResultButton);
|
||||
expect(suffix.textContent).toBe('2 of 2');
|
||||
expect(
|
||||
screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' })[2].parentElement!.className
|
||||
).toContain('rowFocused');
|
||||
});
|
||||
|
||||
it('show matches only works as expected', async () => {
|
||||
config.featureToggles.newTraceViewHeader = true;
|
||||
renderTraceViewContainer();
|
||||
const spanFiltersButton = screen.getByRole('button', { name: 'Span Filters' });
|
||||
await user.click(spanFiltersButton);
|
||||
|
||||
await user.click(screen.getByLabelText('Select tag key'));
|
||||
const tagOption = screen.getByText('http.status_code');
|
||||
await waitFor(() => expect(tagOption).toBeInTheDocument());
|
||||
await user.click(tagOption);
|
||||
|
||||
expect(screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' }).length).toBe(3);
|
||||
const matchesSwitch = screen.getByRole('checkbox', { name: 'Show matches only switch' });
|
||||
expect(matchesSwitch).toBeInTheDocument();
|
||||
await user.click(matchesSwitch);
|
||||
expect(screen.queryAllByText('', { selector: 'div[data-testid="span-view"]' }).length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
@ -30,6 +30,8 @@ const setup = () => {
|
||||
setSearch: jest.fn(),
|
||||
showSpanFilters: true,
|
||||
setShowSpanFilters: jest.fn(),
|
||||
showSpanFilterMatchesOnly: false,
|
||||
setShowSpanFilterMatchesOnly: jest.fn(),
|
||||
spanFilterMatches: undefined,
|
||||
focusedSpanIdForSearch: '',
|
||||
setFocusedSpanIdForSearch: jest.fn(),
|
||||
|
@ -39,6 +39,8 @@ export type TracePageHeaderProps = {
|
||||
setSearch: React.Dispatch<React.SetStateAction<SearchProps>>;
|
||||
showSpanFilters: boolean;
|
||||
setShowSpanFilters: (isOpen: boolean) => void;
|
||||
showSpanFilterMatchesOnly: boolean;
|
||||
setShowSpanFilterMatchesOnly: (showMatchesOnly: boolean) => void;
|
||||
focusedSpanIdForSearch: string;
|
||||
setFocusedSpanIdForSearch: React.Dispatch<React.SetStateAction<string>>;
|
||||
spanFilterMatches: Set<string> | undefined;
|
||||
@ -54,6 +56,8 @@ export const NewTracePageHeader = memo((props: TracePageHeaderProps) => {
|
||||
setSearch,
|
||||
showSpanFilters,
|
||||
setShowSpanFilters,
|
||||
showSpanFilterMatchesOnly,
|
||||
setShowSpanFilterMatchesOnly,
|
||||
focusedSpanIdForSearch,
|
||||
setFocusedSpanIdForSearch,
|
||||
spanFilterMatches,
|
||||
@ -131,6 +135,8 @@ export const NewTracePageHeader = memo((props: TracePageHeaderProps) => {
|
||||
trace={trace}
|
||||
showSpanFilters={showSpanFilters}
|
||||
setShowSpanFilters={setShowSpanFilters}
|
||||
showSpanFilterMatchesOnly={showSpanFilterMatchesOnly}
|
||||
setShowSpanFilterMatchesOnly={setShowSpanFilterMatchesOnly}
|
||||
search={search}
|
||||
setSearch={setSearch}
|
||||
spanFilterMatches={spanFilterMatches}
|
||||
|
@ -22,6 +22,8 @@ import NewTracePageSearchBar, { TracePageSearchBarProps } from './NewTracePageSe
|
||||
const defaultProps = {
|
||||
search: defaultFilters,
|
||||
setFocusedSpanIdForSearch: jest.fn(),
|
||||
showSpanFilterMatchesOnly: false,
|
||||
setShowSpanFilterMatchesOnly: jest.fn(),
|
||||
};
|
||||
|
||||
describe('<NewTracePageSearchBar>', () => {
|
||||
@ -51,4 +53,10 @@ describe('<NewTracePageSearchBar>', () => {
|
||||
expect((nextResButton as HTMLButtonElement)['disabled']).toBe(false);
|
||||
expect((prevResButton as HTMLButtonElement)['disabled']).toBe(false);
|
||||
});
|
||||
|
||||
it('renders show span filter matches only switch', async () => {
|
||||
render(<NewTracePageSearchBar {...(defaultProps as unknown as TracePageSearchBarProps)} />);
|
||||
const matchesSwitch = screen.getByRole('checkbox', { name: 'Show matches only switch' });
|
||||
expect(matchesSwitch).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -16,7 +16,7 @@ import { css } from '@emotion/css';
|
||||
import React, { memo, Dispatch, SetStateAction, useEffect, useMemo } from 'react';
|
||||
|
||||
import { config, reportInteraction } from '@grafana/runtime';
|
||||
import { Button, useStyles2 } from '@grafana/ui';
|
||||
import { Button, Switch, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { SearchProps } from '../../useSearch';
|
||||
import { convertTimeFilter } from '../utils/filter-spans';
|
||||
@ -25,6 +25,8 @@ export type TracePageSearchBarProps = {
|
||||
search: SearchProps;
|
||||
setSearch: React.Dispatch<React.SetStateAction<SearchProps>>;
|
||||
spanFilterMatches: Set<string> | undefined;
|
||||
showSpanFilterMatchesOnly: boolean;
|
||||
setShowSpanFilterMatchesOnly: (showMatchesOnly: boolean) => void;
|
||||
focusedSpanIdForSearch: string;
|
||||
setFocusedSpanIdForSearch: Dispatch<SetStateAction<string>>;
|
||||
datasourceType: string;
|
||||
@ -32,7 +34,16 @@ export type TracePageSearchBarProps = {
|
||||
};
|
||||
|
||||
export default memo(function NewTracePageSearchBar(props: TracePageSearchBarProps) {
|
||||
const { search, spanFilterMatches, focusedSpanIdForSearch, setFocusedSpanIdForSearch, datasourceType, reset } = props;
|
||||
const {
|
||||
search,
|
||||
spanFilterMatches,
|
||||
focusedSpanIdForSearch,
|
||||
setFocusedSpanIdForSearch,
|
||||
datasourceType,
|
||||
reset,
|
||||
showSpanFilterMatchesOnly,
|
||||
setShowSpanFilterMatchesOnly,
|
||||
} = props;
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
useEffect(() => {
|
||||
@ -108,6 +119,14 @@ export default memo(function NewTracePageSearchBar(props: TracePageSearchBarProp
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
<div className={styles.matchesOnly}>
|
||||
<Switch
|
||||
value={showSpanFilterMatchesOnly}
|
||||
onChange={(value) => setShowSpanFilterMatchesOnly(value.currentTarget.checked ?? false)}
|
||||
label="Show matches only switch"
|
||||
/>
|
||||
<span onClick={() => setShowSpanFilterMatchesOnly(!showSpanFilterMatchesOnly)}>Show matches only</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.nextPrevButtons}>
|
||||
<Button
|
||||
@ -142,6 +161,16 @@ export const getStyles = () => {
|
||||
searchBar: css`
|
||||
display: inline;
|
||||
`,
|
||||
matchesOnly: css`
|
||||
display: inline-flex;
|
||||
margin: 0 0 0 10px;
|
||||
vertical-align: middle;
|
||||
|
||||
span {
|
||||
cursor: pointer;
|
||||
margin: -3px 0 0 5px;
|
||||
}
|
||||
`,
|
||||
buttons: css`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
@ -43,6 +43,8 @@ describe('SpanFilters', () => {
|
||||
trace: trace,
|
||||
showSpanFilters: true,
|
||||
setShowSpanFilters: jest.fn(),
|
||||
showSpanFilterMatchesOnly: false,
|
||||
setShowSpanFilterMatchesOnly: jest.fn(),
|
||||
search: search,
|
||||
setSearch: setSearch,
|
||||
spanFilterMatches: undefined,
|
||||
|
@ -40,6 +40,8 @@ export type SpanFilterProps = {
|
||||
setSearch: React.Dispatch<React.SetStateAction<SearchProps>>;
|
||||
showSpanFilters: boolean;
|
||||
setShowSpanFilters: (isOpen: boolean) => void;
|
||||
showSpanFilterMatchesOnly: boolean;
|
||||
setShowSpanFilterMatchesOnly: (showMatchesOnly: boolean) => void;
|
||||
focusedSpanIdForSearch: string;
|
||||
setFocusedSpanIdForSearch: React.Dispatch<React.SetStateAction<string>>;
|
||||
spanFilterMatches: Set<string> | undefined;
|
||||
@ -53,6 +55,8 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
|
||||
setSearch,
|
||||
showSpanFilters,
|
||||
setShowSpanFilters,
|
||||
showSpanFilterMatchesOnly,
|
||||
setShowSpanFilterMatchesOnly,
|
||||
focusedSpanIdForSearch,
|
||||
setFocusedSpanIdForSearch,
|
||||
spanFilterMatches,
|
||||
@ -384,6 +388,8 @@ export const SpanFilters = memo((props: SpanFilterProps) => {
|
||||
search={search}
|
||||
setSearch={setSearch}
|
||||
spanFilterMatches={spanFilterMatches}
|
||||
showSpanFilterMatchesOnly={showSpanFilterMatchesOnly}
|
||||
setShowSpanFilterMatchesOnly={setShowSpanFilterMatchesOnly}
|
||||
focusedSpanIdForSearch={focusedSpanIdForSearch}
|
||||
setFocusedSpanIdForSearch={setFocusedSpanIdForSearch}
|
||||
datasourceType={datasourceType}
|
||||
|
@ -461,7 +461,7 @@ export default class ListView extends React.Component<TListViewProps> {
|
||||
end = dataLength - 1;
|
||||
}
|
||||
} else {
|
||||
start = this._startIndexDrawn;
|
||||
start = this._startIndexDrawn > dataLength - 1 ? 0 : this._startIndexDrawn;
|
||||
end = this._endIndexDrawn > dataLength - 1 ? dataLength - 1 : this._endIndexDrawn;
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ const nameWrapperMatchingFilterClassName = 'nameWrapperMatchingFilter';
|
||||
const viewClassName = 'jaegerView';
|
||||
const nameColumnClassName = 'nameColumn';
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme2) => {
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme2, showSpanFilterMatchesOnly: boolean) => {
|
||||
const animations = {
|
||||
label: 'flash',
|
||||
flash: keyframes`
|
||||
@ -50,6 +50,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme2) => {
|
||||
}
|
||||
`,
|
||||
};
|
||||
const backgroundColor = showSpanFilterMatchesOnly ? '' : autoColor(theme, '#fffce4');
|
||||
|
||||
return {
|
||||
nameWrapper: css`
|
||||
@ -60,7 +61,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme2) => {
|
||||
`,
|
||||
nameWrapperMatchingFilter: css`
|
||||
label: nameWrapperMatchingFilter;
|
||||
background-color: ${autoColor(theme, '#fffce4')};
|
||||
background-color: ${backgroundColor};
|
||||
`,
|
||||
nameColumn: css`
|
||||
label: nameColumn;
|
||||
@ -164,7 +165,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme2) => {
|
||||
`,
|
||||
rowMatchingFilter: css`
|
||||
label: rowMatchingFilter;
|
||||
background-color: ${autoColor(theme, '#fffbde')};
|
||||
// background-color: ${autoColor(theme, '#fffbde')};
|
||||
&:hover .${nameWrapperClassName} {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
@ -297,6 +298,7 @@ export type SpanBarRowProps = {
|
||||
isDetailExpanded: boolean;
|
||||
isMatchingFilter: boolean;
|
||||
isFocused: boolean;
|
||||
showSpanFilterMatchesOnly: boolean;
|
||||
onDetailToggled: (spanID: string) => void;
|
||||
onChildrenToggled: (spanID: string) => void;
|
||||
numTicks: number;
|
||||
@ -360,6 +362,7 @@ export class UnthemedSpanBarRow extends React.PureComponent<SpanBarRowProps> {
|
||||
isChildrenExpanded,
|
||||
isDetailExpanded,
|
||||
isMatchingFilter,
|
||||
showSpanFilterMatchesOnly,
|
||||
isFocused,
|
||||
numTicks,
|
||||
rpc,
|
||||
@ -388,7 +391,7 @@ export class UnthemedSpanBarRow extends React.PureComponent<SpanBarRowProps> {
|
||||
const viewBounds = getViewedBounds(span.startTime, span.startTime + span.duration);
|
||||
const viewStart = viewBounds.start;
|
||||
const viewEnd = viewBounds.end;
|
||||
const styles = getStyles(theme);
|
||||
const styles = getStyles(theme, showSpanFilterMatchesOnly);
|
||||
|
||||
const labelDetail = `${serviceName}::${operationName}`;
|
||||
let longLabel;
|
||||
|
@ -113,6 +113,7 @@ type TVirtualizedTraceViewOwnProps = {
|
||||
scrollElement?: Element;
|
||||
focusedSpanId?: string;
|
||||
focusedSpanIdForSearch: string;
|
||||
showSpanFilterMatchesOnly: boolean;
|
||||
createFocusSpanLink: (traceId: string, spanId: string) => LinkModel;
|
||||
topOfViewRef?: RefObject<HTMLDivElement>;
|
||||
topOfViewRefType?: TopOfViewRefType;
|
||||
@ -134,11 +135,17 @@ const NUM_TICKS = 5;
|
||||
function generateRowStates(
|
||||
spans: TraceSpan[] | TNil,
|
||||
childrenHiddenIDs: Set<string>,
|
||||
detailStates: Map<string, DetailState | TNil>
|
||||
detailStates: Map<string, DetailState | TNil>,
|
||||
findMatchesIDs: Set<string> | TNil,
|
||||
showSpanFilterMatchesOnly: boolean
|
||||
): RowState[] {
|
||||
if (!spans) {
|
||||
return [];
|
||||
}
|
||||
if (showSpanFilterMatchesOnly && findMatchesIDs) {
|
||||
spans = spans.filter((span) => findMatchesIDs.has(span.spanID));
|
||||
}
|
||||
|
||||
let collapseDepth = null;
|
||||
const rowStates = [];
|
||||
for (let i = 0; i < spans.length; i++) {
|
||||
@ -185,9 +192,13 @@ function getClipping(currentViewRange: [number, number]) {
|
||||
function generateRowStatesFromTrace(
|
||||
trace: Trace | TNil,
|
||||
childrenHiddenIDs: Set<string>,
|
||||
detailStates: Map<string, DetailState | TNil>
|
||||
detailStates: Map<string, DetailState | TNil>,
|
||||
findMatchesIDs: Set<string> | TNil,
|
||||
showSpanFilterMatchesOnly: boolean
|
||||
): RowState[] {
|
||||
return trace ? generateRowStates(trace.spans, childrenHiddenIDs, detailStates) : [];
|
||||
return trace
|
||||
? generateRowStates(trace.spans, childrenHiddenIDs, detailStates, findMatchesIDs, showSpanFilterMatchesOnly)
|
||||
: [];
|
||||
}
|
||||
|
||||
const memoizedGenerateRowStates = memoizeOne(generateRowStatesFromTrace);
|
||||
@ -263,8 +274,8 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
||||
}
|
||||
|
||||
getRowStates(): RowState[] {
|
||||
const { childrenHiddenIDs, detailStates, trace } = this.props;
|
||||
return memoizedGenerateRowStates(trace, childrenHiddenIDs, detailStates);
|
||||
const { childrenHiddenIDs, detailStates, trace, findMatchesIDs, showSpanFilterMatchesOnly } = this.props;
|
||||
return memoizedGenerateRowStates(trace, childrenHiddenIDs, detailStates, findMatchesIDs, showSpanFilterMatchesOnly);
|
||||
}
|
||||
|
||||
getClipping(): { left: boolean; right: boolean } {
|
||||
@ -397,6 +408,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
||||
createSpanLink,
|
||||
focusedSpanId,
|
||||
focusedSpanIdForSearch,
|
||||
showSpanFilterMatchesOnly,
|
||||
theme,
|
||||
datasourceType,
|
||||
} = this.props;
|
||||
@ -451,6 +463,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
||||
isDetailExpanded={isDetailExpanded}
|
||||
isMatchingFilter={isMatchingFilter}
|
||||
isFocused={isFocused}
|
||||
showSpanFilterMatchesOnly={showSpanFilterMatchesOnly}
|
||||
numTicks={NUM_TICKS}
|
||||
onDetailToggled={detailToggle}
|
||||
onChildrenToggled={childrenToggle}
|
||||
|
@ -110,6 +110,7 @@ export type TProps = TExtractUiFindFromStateReturn & {
|
||||
scrollElement?: Element;
|
||||
focusedSpanId?: string;
|
||||
focusedSpanIdForSearch: string;
|
||||
showSpanFilterMatchesOnly: boolean;
|
||||
createFocusSpanLink: (traceId: string, spanId: string) => LinkModel;
|
||||
topOfViewRef?: RefObject<HTMLDivElement>;
|
||||
topOfViewRefType?: TopOfViewRefType;
|
||||
|
Loading…
Reference in New Issue
Block a user