usePanelLatestData.ts 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import { useEffect, useRef, useState } from 'react';
  2. import { Unsubscribable } from 'rxjs';
  3. import { DataQueryError, LoadingState, PanelData } from '@grafana/data';
  4. import { GetDataOptions } from '../../../query/state/PanelQueryRunner';
  5. import { PanelModel } from '../../state';
  6. interface UsePanelLatestData {
  7. data?: PanelData;
  8. error?: DataQueryError;
  9. isLoading: boolean;
  10. hasSeries: boolean;
  11. }
  12. /**
  13. * Subscribes and returns latest panel data from PanelQueryRunner
  14. */
  15. export const usePanelLatestData = (
  16. panel: PanelModel,
  17. options: GetDataOptions,
  18. checkSchema?: boolean
  19. ): UsePanelLatestData => {
  20. const querySubscription = useRef<Unsubscribable>();
  21. const [latestData, setLatestData] = useState<PanelData>();
  22. useEffect(() => {
  23. let lastRev = -1;
  24. let lastUpdate = 0;
  25. querySubscription.current = panel
  26. .getQueryRunner()
  27. .getData(options)
  28. .subscribe({
  29. next: (data) => {
  30. if (checkSchema) {
  31. if (lastRev === data.structureRev) {
  32. const now = Date.now();
  33. const elapsed = now - lastUpdate;
  34. if (elapsed < 10000) {
  35. return; // avoid updates if the schema has not changed for 10s
  36. }
  37. lastUpdate = now;
  38. }
  39. lastRev = data.structureRev ?? -1;
  40. }
  41. setLatestData(data);
  42. },
  43. });
  44. return () => {
  45. if (querySubscription.current) {
  46. querySubscription.current.unsubscribe();
  47. }
  48. };
  49. /**
  50. * Adding separate options to dependencies array to avoid additional hook for comparing previous options with current.
  51. * Otherwise, passing different references to the same object might cause troubles.
  52. */
  53. // eslint-disable-next-line react-hooks/exhaustive-deps
  54. }, [panel, options.withFieldConfig, options.withTransforms]);
  55. return {
  56. data: latestData,
  57. error: latestData && latestData.error,
  58. isLoading: latestData ? latestData.state === LoadingState.Loading : true,
  59. hasSeries: latestData ? !!latestData.series : false,
  60. };
  61. };