context.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import {createContext, useCallback, useContext, useMemo, useState} from 'react';
  2. import {MRI} from 'sentry/types';
  3. import {
  4. defaultMetricDisplayType,
  5. MetricDisplayType,
  6. MetricWidgetQueryParams,
  7. updateQuery,
  8. } from 'sentry/utils/metrics';
  9. import {decodeList} from 'sentry/utils/queryString';
  10. import useRouter from 'sentry/utils/useRouter';
  11. import {DEFAULT_SORT_STATE} from 'sentry/views/ddm/constants';
  12. interface DDMContextValue {
  13. addWidget: () => void;
  14. selectedWidgetIndex: number;
  15. setSelectedWidgetIndex: (index: number) => void;
  16. updateWidget: (index: number, data: Partial<MetricWidgetQueryParams>) => void;
  17. widgets: MetricWidgetQueryParams[];
  18. }
  19. export const DDMContext = createContext<DDMContextValue>({
  20. selectedWidgetIndex: 0,
  21. setSelectedWidgetIndex: () => {},
  22. addWidget: () => {},
  23. updateWidget: () => {},
  24. widgets: [],
  25. });
  26. export function useDDMContext() {
  27. return useContext(DDMContext);
  28. }
  29. const emptyWidget: MetricWidgetQueryParams = {
  30. mri: '' as MRI,
  31. op: undefined,
  32. query: '',
  33. groupBy: [],
  34. sort: DEFAULT_SORT_STATE,
  35. displayType: MetricDisplayType.LINE,
  36. };
  37. export function useMetricWidgets() {
  38. const router = useRouter();
  39. const widgets = useMemo<MetricWidgetQueryParams[]>(() => {
  40. const currentWidgets = JSON.parse(
  41. router.location.query.widgets ?? JSON.stringify([emptyWidget])
  42. );
  43. return currentWidgets.map((widget: MetricWidgetQueryParams) => {
  44. return {
  45. mri: widget.mri,
  46. op: widget.op,
  47. query: widget.query,
  48. groupBy: decodeList(widget.groupBy),
  49. displayType: widget.displayType ?? defaultMetricDisplayType,
  50. focusedSeries: widget.focusedSeries,
  51. showSummaryTable: widget.showSummaryTable ?? true, // temporary default
  52. powerUserMode: widget.powerUserMode,
  53. sort: widget.sort ?? DEFAULT_SORT_STATE,
  54. };
  55. });
  56. }, [router.location.query.widgets]);
  57. const updateWidget = useCallback(
  58. (index: number, data: Partial<MetricWidgetQueryParams>) => {
  59. const widgetsCopy = [...widgets];
  60. widgetsCopy[index] = {...widgets[index], ...data};
  61. updateQuery(router, {
  62. widgets: JSON.stringify(widgetsCopy),
  63. });
  64. },
  65. [widgets, router]
  66. );
  67. const addWidget = useCallback(() => {
  68. const widgetsCopy = [...widgets];
  69. widgetsCopy.push(emptyWidget);
  70. updateQuery(router, {
  71. widgets: JSON.stringify(widgetsCopy),
  72. });
  73. }, [widgets, router]);
  74. return {
  75. widgets,
  76. updateWidget,
  77. addWidget,
  78. };
  79. }
  80. export function DDMContextProvider({children}: {children: React.ReactNode}) {
  81. const [selectedWidgetIndex, setSelectedWidgetIndex] = useState(0);
  82. const {widgets, updateWidget, addWidget} = useMetricWidgets();
  83. const handleAddWidget = useCallback(() => {
  84. addWidget();
  85. setSelectedWidgetIndex(widgets.length);
  86. }, [addWidget, widgets.length]);
  87. const handleUpdateWidget = useCallback(
  88. (index: number, data: Partial<MetricWidgetQueryParams>) => {
  89. updateWidget(index, data);
  90. setSelectedWidgetIndex(index);
  91. },
  92. [updateWidget]
  93. );
  94. const contextValue = useMemo<DDMContextValue>(
  95. () => ({
  96. addWidget: handleAddWidget,
  97. selectedWidgetIndex:
  98. selectedWidgetIndex > widgets.length - 1 ? 0 : selectedWidgetIndex,
  99. setSelectedWidgetIndex,
  100. updateWidget: handleUpdateWidget,
  101. widgets,
  102. }),
  103. [handleAddWidget, handleUpdateWidget, selectedWidgetIndex, widgets]
  104. );
  105. return <DDMContext.Provider value={contextValue}>{children}</DDMContext.Provider>;
  106. }