traceStateProvider.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import type React from 'react';
  2. import {createContext, useContext, useLayoutEffect, useMemo} from 'react';
  3. import * as qs from 'query-string';
  4. import {t} from 'sentry/locale';
  5. import {
  6. type DispatchingReducerEmitter,
  7. useDispatchingReducer,
  8. } from 'sentry/utils/useDispatchingReducer';
  9. import {useHasTraceNewUi} from '../useHasTraceNewUi';
  10. import {TraceReducer, type TraceReducerAction, type TraceReducerState} from './index';
  11. import {storeTraceViewPreferences, type TracePreferencesState} from './tracePreferences';
  12. interface TraceStateContext {}
  13. export const TraceStateContext = createContext<TraceReducerState | null>(null);
  14. export const TraceStateDispatchContext =
  15. createContext<React.Dispatch<TraceReducerAction> | null>(null);
  16. export const TraceStateEmitterContext = createContext<DispatchingReducerEmitter<
  17. typeof TraceReducer
  18. > | null>(null);
  19. export function useTraceState(): TraceReducerState {
  20. const context = useContext(TraceStateContext);
  21. if (!context) {
  22. throw new Error('useTraceState must be used within a TraceStateProvider');
  23. }
  24. return context;
  25. }
  26. export function useTraceStateDispatch(): React.Dispatch<TraceReducerAction> {
  27. const context = useContext(TraceStateDispatchContext);
  28. if (!context) {
  29. throw new Error('useTraceStateDispatch must be used within a TraceStateProvider');
  30. }
  31. return context;
  32. }
  33. export function useTraceStateEmitter(): DispatchingReducerEmitter<typeof TraceReducer> {
  34. const context = useContext(TraceStateEmitterContext);
  35. if (!context) {
  36. throw new Error('useTraceStateEmitter must be used within a TraceStateProvider');
  37. }
  38. return context;
  39. }
  40. const TRACE_TAB: TraceReducerState['tabs']['tabs'][0] = {
  41. node: 'trace',
  42. label: t('Trace'),
  43. };
  44. const STATIC_DRAWER_TABS: TraceReducerState['tabs']['tabs'] = [TRACE_TAB];
  45. interface TraceStateProviderProps {
  46. children: React.ReactNode;
  47. initialPreferences: TracePreferencesState;
  48. preferencesStorageKey?: string;
  49. }
  50. export function TraceStateProvider(props: TraceStateProviderProps): React.ReactNode {
  51. const hasTraceNewUi = useHasTraceNewUi();
  52. const initialQuery = useMemo((): string | undefined => {
  53. const query = qs.parse(location.search);
  54. if (typeof query.search === 'string') {
  55. return query.search;
  56. }
  57. return undefined;
  58. // We only want to decode on load
  59. }, []);
  60. const [traceState, traceDispatch, traceStateEmitter] = useDispatchingReducer(
  61. TraceReducer,
  62. {
  63. rovingTabIndex: {
  64. index: null,
  65. items: null,
  66. node: null,
  67. },
  68. search: {
  69. node: null,
  70. query: initialQuery,
  71. resultIteratorIndex: null,
  72. resultIndex: null,
  73. results: null,
  74. status: undefined,
  75. resultsLookup: new Map(),
  76. },
  77. preferences: props.initialPreferences,
  78. tabs: {
  79. tabs: hasTraceNewUi ? [] : STATIC_DRAWER_TABS,
  80. current_tab: hasTraceNewUi ? null : STATIC_DRAWER_TABS[0] ?? null,
  81. last_clicked_tab: null,
  82. },
  83. }
  84. );
  85. useLayoutEffect(() => {
  86. if (props.preferencesStorageKey) {
  87. storeTraceViewPreferences(props.preferencesStorageKey, traceState.preferences);
  88. }
  89. }, [traceState.preferences, props.preferencesStorageKey]);
  90. return (
  91. <TraceStateContext.Provider value={traceState}>
  92. <TraceStateDispatchContext.Provider value={traceDispatch}>
  93. <TraceStateEmitterContext.Provider value={traceStateEmitter}>
  94. {props.children}
  95. </TraceStateEmitterContext.Provider>
  96. </TraceStateDispatchContext.Provider>
  97. </TraceStateContext.Provider>
  98. );
  99. }