NodeGraph: Show node graph collapsed by default with trace view (#34491)

* Show node graph collapsed by default with trace view

* Fix rename variable

* Change the message

* Add test

* Fix e2e test

* Remove expect in exemplars test

* Align icon

* review fixes
This commit is contained in:
Andrej Ocenas 2021-05-26 15:11:47 +02:00 committed by GitHub
parent 96da84ca49
commit 9dafd4f863
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 94 additions and 17 deletions

View File

@ -65,8 +65,6 @@ describe('Exemplars', () => {
e2e.components.DataSource.Prometheus.exemplarMarker().first().trigger('mouseover');
e2e().contains('Query with gdev-tempo').click();
e2e().get('[aria-label="Node: app"]').should('be.visible');
e2e.components.TraceViewer.spanBar().should('have.length', 11);
});
});

View File

@ -29,7 +29,7 @@ describe('Trace view', () => {
e2e.pages.Explore.General.scrollBar().scrollTo('center');
// After scrolling we should have 139 spans instead of the first 100
e2e.components.TraceViewer.spanBar().should('have.length', 139);
// After scrolling we should load more spans
e2e.components.TraceViewer.spanBar().should('have.length', 140);
});
});

View File

@ -76,6 +76,10 @@ const getStyles = (theme: GrafanaTheme2) => ({
margin-right: ${theme.spacing(1)};
font-size: ${theme.typography.size.md};
`,
icon: css`
label: collapse__icon;
margin-left: -5px;
`,
});
export interface Props {
@ -133,7 +137,7 @@ export const Collapse: FunctionComponent<Props> = ({
return (
<div className={panelClass}>
<div className={headerClass} onClick={onClickToggle}>
{collapsible && <Icon name={isOpen ? 'angle-up' : 'angle-down'} />}
{collapsible && <Icon className={style.icon} name={isOpen ? 'angle-up' : 'angle-down'} />}
<div className={cx([style.headerLabel])}>{label}</div>
</div>
{isOpen && (

View File

@ -271,7 +271,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
<NodeGraphContainer
dataFrames={this.getNodeGraphDataFrames(queryResponse.series)}
exploreId={exploreId}
short={showTrace}
withTraceView={showTrace}
/>
);
}

View File

@ -0,0 +1,55 @@
import React from 'react';
import { render } from '@testing-library/react';
import { UnconnectedNodeGraphContainer } from './NodeGraphContainer';
import { getDefaultTimeRange, MutableDataFrame } from '@grafana/data';
import { ExploreId } from '../../types';
describe('NodeGraphContainer', () => {
it('is collapsed if shown with traces', () => {
const { container } = render(
<UnconnectedNodeGraphContainer
dataFrames={[emptyFrame]}
exploreId={ExploreId.left}
range={getDefaultTimeRange()}
splitOpen={(() => {}) as any}
withTraceView={true}
/>
);
// Make sure we only show header in the collapsible
expect(container.firstChild?.childNodes.length).toBe(1);
});
it('shows the graph if not with trace view', () => {
const { container } = render(
<UnconnectedNodeGraphContainer
dataFrames={[nodes]}
exploreId={ExploreId.left}
range={getDefaultTimeRange()}
splitOpen={(() => {}) as any}
/>
);
expect(container.firstChild?.childNodes.length).toBe(2);
expect(container.querySelector('svg')).toBeInTheDocument();
});
});
const emptyFrame = new MutableDataFrame();
export const nodes = new MutableDataFrame({
fields: toFields([
['id', ['3fa414edcef6ad90']],
['title', ['tempo-querier']],
['subTitle', ['HTTP GET - api_traces_traceid']],
['mainStat', ['1049.14ms (100%)']],
['secondaryStat', ['1047.29ms (99.82%)']],
['color', [0.9982395121342127]],
]),
});
export function toFields(fields: Array<[string, any[]]>) {
return fields.map(([name, values]) => {
return { name, values };
});
}

View File

@ -1,11 +1,22 @@
import React, { useState } from 'react';
import { Badge, Collapse } from '@grafana/ui';
import { DataFrame, TimeRange } from '@grafana/data';
import React from 'react';
import { useToggle } from 'react-use';
import { Badge, Collapse, useStyles2 } from '@grafana/ui';
import { DataFrame, GrafanaTheme2, TimeRange } from '@grafana/data';
import { css } from '@emotion/css';
import { ExploreId, StoreState } from '../../types';
import { splitOpen } from './state/main';
import { connect, ConnectedProps } from 'react-redux';
import { useLinks } from './utils/links';
import { NodeGraph } from '../../plugins/panel/nodeGraph';
import { useCategorizeFrames } from '../../plugins/panel/nodeGraph/useCategorizeFrames';
const getStyles = (theme: GrafanaTheme2) => ({
warningText: css`
label: warningText;
font-size: ${theme.typography.bodySmall.fontSize};
color: ${theme.colors.text.secondary};
`,
});
interface Props {
// Edges and Nodes are separate frames
@ -13,26 +24,35 @@ interface Props {
exploreId: ExploreId;
range: TimeRange;
splitOpen: typeof splitOpen;
short?: boolean;
// When showing the node graph together with trace view we do some changes so it works better.
withTraceView?: boolean;
}
export function UnconnectedNodeGraphContainer(props: Props & ConnectedProps<typeof connector>) {
const { dataFrames, range, splitOpen, short } = props;
const { dataFrames, range, splitOpen, withTraceView } = props;
const getLinks = useLinks(range, splitOpen);
const styles = useStyles2(getStyles);
const [open, setOpen] = useState(true);
const { nodes } = useCategorizeFrames(dataFrames);
const [open, toggleOpen] = useToggle(false);
const countWarning =
withTraceView && nodes[0]?.length > 1000 ? (
<span className={styles.warningText}> ({nodes[0].length} nodes, can be slow to load)</span>
) : null;
return (
<Collapse
label={
<span>
Node graph <Badge text={'Beta'} color={'blue'} icon={'rocket'} tooltip={'This visualization is in beta'} />
Node graph{countWarning}{' '}
<Badge text={'Beta'} color={'blue'} icon={'rocket'} tooltip={'This visualization is in beta'} />
</span>
}
collapsible={short}
isOpen={short ? open : true}
onToggle={short ? () => setOpen(!open) : undefined}
collapsible={withTraceView}
// We allow collapsing this only when it is shown together with trace view.
isOpen={withTraceView ? open : true}
onToggle={withTraceView ? () => toggleOpen() : undefined}
>
<div style={{ height: short ? 300 : 600 }}>
<div style={{ height: withTraceView ? 500 : 600 }}>
<NodeGraph dataFrames={dataFrames} getLinks={getLinks} />
</div>
</Collapse>