useVisualizes.tsx 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import {useCallback, useMemo} from 'react';
  2. import type {Location} from 'history';
  3. import {defined} from 'sentry/utils';
  4. import {parseFunction} from 'sentry/utils/discover/fields';
  5. import {
  6. ALLOWED_EXPLORE_VISUALIZE_AGGREGATES,
  7. ALLOWED_EXPLORE_VISUALIZE_FIELDS,
  8. } from 'sentry/utils/fields';
  9. import {decodeList} from 'sentry/utils/queryString';
  10. import {useLocation} from 'sentry/utils/useLocation';
  11. import {useNavigate} from 'sentry/utils/useNavigate';
  12. import {ChartType} from 'sentry/views/insights/common/components/chart';
  13. export type Visualize = {
  14. chartType: ChartType;
  15. yAxes: string[];
  16. };
  17. interface Options {
  18. location: Location;
  19. navigate: ReturnType<typeof useNavigate>;
  20. }
  21. export const DEFAULT_VISUALIZATION = `${ALLOWED_EXPLORE_VISUALIZE_AGGREGATES[0]}(${ALLOWED_EXPLORE_VISUALIZE_FIELDS[0]})`;
  22. export function useVisualizes(): [Visualize[], (visualizes: Visualize[]) => void] {
  23. const location = useLocation();
  24. const navigate = useNavigate();
  25. const options = {location, navigate};
  26. return useVisualizesImpl(options);
  27. }
  28. function useVisualizesImpl({
  29. location,
  30. navigate,
  31. }: Options): [Visualize[], (visualizes: Visualize[]) => void] {
  32. const visualizes: Visualize[] = useMemo(() => {
  33. const rawVisualizes = decodeList(location.query.visualize);
  34. const result: Visualize[] = rawVisualizes
  35. .map(parseVisualizes)
  36. .filter(defined)
  37. .filter(parsed => parsed.yAxes.length > 0);
  38. return result.length
  39. ? result
  40. : [{yAxes: [DEFAULT_VISUALIZATION], chartType: ChartType.LINE}];
  41. }, [location.query.visualize]);
  42. const setVisualizes = useCallback(
  43. (newVisualizes: Visualize[]) => {
  44. const stringified: string[] = [];
  45. for (const visualize of newVisualizes) {
  46. stringified.push(JSON.stringify(visualize));
  47. }
  48. navigate({
  49. ...location,
  50. query: {
  51. ...location.query,
  52. visualize: stringified,
  53. },
  54. });
  55. },
  56. [location, navigate]
  57. );
  58. return [visualizes, setVisualizes];
  59. }
  60. function parseVisualizes(raw: string): Visualize | null {
  61. try {
  62. const parsed = JSON.parse(raw);
  63. if (!defined(parsed) || !Array.isArray(parsed.yAxes)) {
  64. return null;
  65. }
  66. const yAxes = parsed.yAxes.filter(parseFunction);
  67. if (yAxes.length <= 0) {
  68. return null;
  69. }
  70. let chartType = Number(parsed.chartType);
  71. if (isNaN(chartType) || !Object.values(ChartType).includes(chartType)) {
  72. chartType = ChartType.LINE;
  73. }
  74. return {yAxes, chartType};
  75. } catch (error) {
  76. return null;
  77. }
  78. }