visualizes.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import type {Location} from 'history';
  2. import {Expression} from 'sentry/components/arithmeticBuilder/expression';
  3. import type {Organization} from 'sentry/types/organization';
  4. import {defined} from 'sentry/utils';
  5. import {parseFunction} from 'sentry/utils/discover/fields';
  6. import {
  7. ALLOWED_EXPLORE_VISUALIZE_AGGREGATES,
  8. ALLOWED_EXPLORE_VISUALIZE_FIELDS,
  9. } from 'sentry/utils/fields';
  10. import {decodeList} from 'sentry/utils/queryString';
  11. import {ChartType} from 'sentry/views/insights/common/components/chart';
  12. export const MAX_VISUALIZES = 4;
  13. export const DEFAULT_VISUALIZATION_AGGREGATE = ALLOWED_EXPLORE_VISUALIZE_AGGREGATES[0]!;
  14. export const DEFAULT_VISUALIZATION_FIELD = ALLOWED_EXPLORE_VISUALIZE_FIELDS[0]!;
  15. export const DEFAULT_VISUALIZATION = `${DEFAULT_VISUALIZATION_AGGREGATE}(${DEFAULT_VISUALIZATION_FIELD})`;
  16. export function defaultVisualizes(): Visualize[] {
  17. return [
  18. {
  19. chartType: ChartType.LINE,
  20. yAxes: [DEFAULT_VISUALIZATION],
  21. label: 'A',
  22. },
  23. ];
  24. }
  25. export interface BaseVisualize {
  26. chartType: ChartType;
  27. yAxes: string[];
  28. }
  29. export interface Visualize extends BaseVisualize {
  30. label: string;
  31. }
  32. export function getVisualizesFromLocation(
  33. location: Location,
  34. organization: Organization
  35. ): Visualize[] {
  36. const rawVisualizes = decodeList(location.query.visualize);
  37. const result: Visualize[] = rawVisualizes
  38. .map(raw => parseVisualizes(raw, organization))
  39. .filter(defined)
  40. .filter(parsed => parsed.yAxes.length > 0)
  41. .map((parsed, i) => {
  42. return {
  43. chartType: parsed.chartType,
  44. yAxes: parsed.yAxes,
  45. label: String.fromCharCode(65 + i), // starts from 'A'
  46. };
  47. });
  48. return result.length ? result : defaultVisualizes();
  49. }
  50. function parseVisualizes(raw: string, organization: Organization): BaseVisualize | null {
  51. try {
  52. const parsed = JSON.parse(raw);
  53. if (!defined(parsed) || !Array.isArray(parsed.yAxes)) {
  54. return null;
  55. }
  56. const yAxes = organization.features.includes('visibility-explore-equations')
  57. ? parsed.yAxes.filter((yAxis: string) => {
  58. const expression = new Expression(yAxis);
  59. return expression.isValid;
  60. })
  61. : parsed.yAxes.filter(parseFunction);
  62. if (yAxes.length <= 0) {
  63. return null;
  64. }
  65. let chartType = Number(parsed.chartType);
  66. if (isNaN(chartType) || !Object.values(ChartType).includes(chartType)) {
  67. chartType = ChartType.LINE;
  68. }
  69. return {yAxes, chartType};
  70. } catch (error) {
  71. return null;
  72. }
  73. }
  74. export function updateLocationWithVisualizes(
  75. location: Location,
  76. visualizes: BaseVisualize[] | null | undefined
  77. ) {
  78. if (defined(visualizes)) {
  79. location.query.visualize = visualizes.map(visualize =>
  80. JSON.stringify({
  81. chartType: visualize.chartType,
  82. yAxes: visualize.yAxes,
  83. })
  84. );
  85. } else if (visualizes === null) {
  86. delete location.query.visualize;
  87. }
  88. }