CSVExportPage.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import { saveAs } from 'file-saver';
  2. import React, { Component } from 'react';
  3. import { connect, ConnectedProps } from 'react-redux';
  4. import { applyFieldOverrides, PanelData, dateTimeFormat, toCSV, LoadingState } from '@grafana/data';
  5. import { config } from '@grafana/runtime';
  6. import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
  7. import { SoloPanel } from 'app/features/dashboard/containers/SoloPanelPage';
  8. import { PanelModel, DashboardModel } from 'app/features/dashboard/state';
  9. import { initDashboard } from 'app/features/dashboard/state/initDashboard';
  10. import { StoreState } from 'app/types';
  11. export interface DashboardPageRouteParams {
  12. uid?: string;
  13. type?: string;
  14. slug?: string;
  15. }
  16. export interface OwnProps extends GrafanaRouteComponentProps<DashboardPageRouteParams, { panelId?: string }> {
  17. dashboard: DashboardModel | null;
  18. }
  19. export interface State {
  20. panel: PanelModel | null;
  21. notFound: boolean;
  22. }
  23. const mapStateToProps = (state: StoreState) => ({
  24. dashboard: state.dashboard.getModel(),
  25. });
  26. const mapDispatchToProps = {
  27. initDashboard,
  28. };
  29. const connector = connect(mapStateToProps, mapDispatchToProps);
  30. export type Props = ConnectedProps<typeof connector> & OwnProps;
  31. export class CSVExportPage extends Component<Props, State> {
  32. state: State = {
  33. panel: null,
  34. notFound: false,
  35. };
  36. componentDidMount() {
  37. const { match, route } = this.props;
  38. this.props.initDashboard({
  39. urlSlug: match.params.slug,
  40. urlUid: match.params.uid,
  41. urlType: match.params.type,
  42. routeName: route.routeName,
  43. fixUrl: false,
  44. });
  45. }
  46. getPanelId(): number {
  47. return parseInt(this.props.queryParams.panelId ?? '0', 10);
  48. }
  49. componentDidUpdate(prevProps: Props) {
  50. const { dashboard } = this.props;
  51. if (!dashboard) {
  52. return;
  53. }
  54. // we just got a new dashboard
  55. if (!prevProps.dashboard || prevProps.dashboard.uid !== dashboard.uid) {
  56. const panel = dashboard.getPanelByUrlId(this.props.queryParams.panelId!);
  57. if (!panel) {
  58. this.setState({ notFound: true });
  59. return;
  60. }
  61. this.setState({ panel });
  62. panel
  63. .getQueryRunner()
  64. .getData({ withTransforms: true, withFieldConfig: true })
  65. .subscribe({
  66. next: (data) => this.onDataUpdate(data),
  67. });
  68. }
  69. }
  70. onDataUpdate(panelData: PanelData) {
  71. const { panel } = this.state;
  72. if (!panelData || !panel || panelData.state !== LoadingState.Done) {
  73. return;
  74. }
  75. const { dashboard } = this.props;
  76. const data = panelData.series;
  77. // We need to apply field config even though it was already applied in the PanelQueryRunner.
  78. // That's because transformers create new fields and data frames, so i.e. display processor is no longer there
  79. const dataFrames = applyFieldOverrides({
  80. data,
  81. theme: config.theme2,
  82. fieldConfig: panel.fieldConfig,
  83. replaceVariables: (value: string) => {
  84. return value;
  85. },
  86. timeZone: dashboard?.timezone,
  87. });
  88. const dataFrameCsv = toCSV([dataFrames[0]], {});
  89. const blob = new Blob([String.fromCharCode(0xfeff), dataFrameCsv], {
  90. type: 'text/csv;charset=utf-8',
  91. });
  92. const fileName = `${panel?.getDisplayTitle()}-data-${dateTimeFormat(new Date())}.csv`;
  93. saveAs(blob, fileName);
  94. }
  95. render() {
  96. return (
  97. <SoloPanel
  98. dashboard={this.props.dashboard}
  99. notFound={this.state.notFound}
  100. panel={this.state.panel}
  101. panelId={this.getPanelId()}
  102. />
  103. );
  104. }
  105. }
  106. export default connector(CSVExportPage);