NodeGraphContainer.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { css } from '@emotion/css';
  2. import React from 'react';
  3. import { connect, ConnectedProps } from 'react-redux';
  4. import { useToggle } from 'react-use';
  5. import { applyFieldOverrides, DataFrame, GrafanaTheme2 } from '@grafana/data';
  6. import { reportInteraction } from '@grafana/runtime';
  7. import { Badge, Collapse, useStyles2, useTheme2 } from '@grafana/ui';
  8. import { NodeGraph } from '../../plugins/panel/nodeGraph';
  9. import { useCategorizeFrames } from '../../plugins/panel/nodeGraph/useCategorizeFrames';
  10. import { ExploreId, StoreState } from '../../types';
  11. import { splitOpen } from './state/main';
  12. import { useLinks } from './utils/links';
  13. const getStyles = (theme: GrafanaTheme2) => ({
  14. warningText: css`
  15. label: warningText;
  16. font-size: ${theme.typography.bodySmall.fontSize};
  17. color: ${theme.colors.text.secondary};
  18. `,
  19. });
  20. interface OwnProps {
  21. // Edges and Nodes are separate frames
  22. dataFrames: DataFrame[];
  23. exploreId: ExploreId;
  24. // When showing the node graph together with trace view we do some changes so it works better.
  25. withTraceView?: boolean;
  26. datasourceType: string;
  27. }
  28. type Props = OwnProps & ConnectedProps<typeof connector>;
  29. export function UnconnectedNodeGraphContainer(props: Props) {
  30. const { dataFrames, range, splitOpen, withTraceView, datasourceType } = props;
  31. const getLinks = useLinks(range, splitOpen);
  32. const theme = useTheme2();
  33. const styles = useStyles2(getStyles);
  34. // This is implicit dependency that is needed for links to work. At some point when replacing variables in the link
  35. // it requires field to have a display property which is added by the overrides even though we don't add any field
  36. // overrides in explore.
  37. const frames = applyFieldOverrides({
  38. fieldConfig: {
  39. defaults: {},
  40. overrides: [],
  41. },
  42. data: dataFrames,
  43. // We don't need proper replace here as it is only used in getLinks and we use getFieldLinks
  44. replaceVariables: (value) => value,
  45. theme,
  46. });
  47. const { nodes } = useCategorizeFrames(frames);
  48. const [open, toggleOpen] = useToggle(false);
  49. const toggled = () => {
  50. toggleOpen();
  51. reportInteraction('grafana_traces_node_graph_panel_clicked', {
  52. datasourceType: datasourceType,
  53. expanded: !open,
  54. });
  55. };
  56. const countWarning =
  57. withTraceView && nodes[0]?.length > 1000 ? (
  58. <span className={styles.warningText}> ({nodes[0].length} nodes, can be slow to load)</span>
  59. ) : null;
  60. return (
  61. <Collapse
  62. label={
  63. <span>
  64. Node graph{countWarning}{' '}
  65. <Badge text={'Beta'} color={'blue'} icon={'rocket'} tooltip={'This visualization is in beta'} />
  66. </span>
  67. }
  68. collapsible={withTraceView}
  69. // We allow collapsing this only when it is shown together with trace view.
  70. isOpen={withTraceView ? open : true}
  71. onToggle={withTraceView ? () => toggled() : undefined}
  72. >
  73. <div style={{ height: withTraceView ? 500 : 600 }}>
  74. <NodeGraph dataFrames={frames} getLinks={getLinks} />
  75. </div>
  76. </Collapse>
  77. );
  78. }
  79. function mapStateToProps(state: StoreState, { exploreId }: OwnProps) {
  80. return {
  81. range: state.explore[exploreId]!.range,
  82. };
  83. }
  84. const mapDispatchToProps = {
  85. splitOpen,
  86. };
  87. const connector = connect(mapStateToProps, mapDispatchToProps);
  88. export const NodeGraphContainer = connector(UnconnectedNodeGraphContainer);