TableContainer.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import React, { PureComponent } from 'react';
  2. import { connect, ConnectedProps } from 'react-redux';
  3. import { ValueLinkConfig, applyFieldOverrides, TimeZone } from '@grafana/data';
  4. import { Collapse, Table } from '@grafana/ui';
  5. import { FilterItem } from '@grafana/ui/src/components/Table/types';
  6. import { config } from 'app/core/config';
  7. import { PANEL_BORDER } from 'app/core/constants';
  8. import { StoreState } from 'app/types';
  9. import { ExploreId, ExploreItemState } from 'app/types/explore';
  10. import { MetaInfoText } from './MetaInfoText';
  11. import { splitOpen } from './state/main';
  12. import { getFieldLinksForExplore } from './utils/links';
  13. interface TableContainerProps {
  14. ariaLabel?: string;
  15. exploreId: ExploreId;
  16. width: number;
  17. timeZone: TimeZone;
  18. onCellFilterAdded?: (filter: FilterItem) => void;
  19. }
  20. function mapStateToProps(state: StoreState, { exploreId }: TableContainerProps) {
  21. const explore = state.explore;
  22. // @ts-ignore
  23. const item: ExploreItemState = explore[exploreId];
  24. const { loading: loadingInState, tableResult, range } = item;
  25. const loading = tableResult && tableResult.length > 0 ? false : loadingInState;
  26. return { loading, tableResult, range };
  27. }
  28. const mapDispatchToProps = {
  29. splitOpen,
  30. };
  31. const connector = connect(mapStateToProps, mapDispatchToProps);
  32. type Props = TableContainerProps & ConnectedProps<typeof connector>;
  33. export class TableContainer extends PureComponent<Props> {
  34. getTableHeight() {
  35. const { tableResult } = this.props;
  36. if (!tableResult || tableResult.length === 0) {
  37. return 200;
  38. }
  39. // tries to estimate table height
  40. return Math.max(Math.min(600, tableResult.length * 35) + 35);
  41. }
  42. render() {
  43. const { loading, onCellFilterAdded, tableResult, width, splitOpen, range, ariaLabel, timeZone } = this.props;
  44. const height = this.getTableHeight();
  45. const tableWidth = width - config.theme.panelPadding * 2 - PANEL_BORDER;
  46. let dataFrame = tableResult;
  47. if (dataFrame?.length) {
  48. dataFrame = applyFieldOverrides({
  49. data: [dataFrame],
  50. timeZone,
  51. theme: config.theme2,
  52. replaceVariables: (v: string) => v,
  53. fieldConfig: {
  54. defaults: {},
  55. overrides: [],
  56. },
  57. })[0];
  58. // Bit of code smell here. We need to add links here to the frame modifying the frame on every render.
  59. // Should work fine in essence but still not the ideal way to pass props. In logs container we do this
  60. // differently and sidestep this getLinks API on a dataframe
  61. for (const field of dataFrame.fields) {
  62. field.getLinks = (config: ValueLinkConfig) => {
  63. return getFieldLinksForExplore({
  64. field,
  65. rowIndex: config.valueRowIndex!,
  66. splitOpenFn: splitOpen,
  67. range,
  68. dataFrame: dataFrame!,
  69. });
  70. };
  71. }
  72. }
  73. return (
  74. <Collapse label="Table" loading={loading} isOpen>
  75. {dataFrame?.length ? (
  76. <Table
  77. ariaLabel={ariaLabel}
  78. data={dataFrame}
  79. width={tableWidth}
  80. height={height}
  81. onCellFilterAdded={onCellFilterAdded}
  82. />
  83. ) : (
  84. <MetaInfoText metaItems={[{ value: '0 series returned' }]} />
  85. )}
  86. </Collapse>
  87. );
  88. }
  89. }
  90. export default connector(TableContainer);