mirror of
https://github.com/grafana/grafana.git
synced 2025-02-14 17:43:35 -06:00
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:
parent
96da84ca49
commit
9dafd4f863
@ -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);
|
||||
});
|
||||
});
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
@ -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 && (
|
||||
|
@ -271,7 +271,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
||||
<NodeGraphContainer
|
||||
dataFrames={this.getNodeGraphDataFrames(queryResponse.series)}
|
||||
exploreId={exploreId}
|
||||
short={showTrace}
|
||||
withTraceView={showTrace}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
55
public/app/features/explore/NodeGraphContainer.test.tsx
Normal file
55
public/app/features/explore/NodeGraphContainer.test.tsx
Normal 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 };
|
||||
});
|
||||
}
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user