tracePreferences.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import * as Sentry from '@sentry/react';
  2. import {traceReducerExhaustiveActionCheck} from 'sentry/views/performance/newTraceDetails/traceState';
  3. type TraceLayoutPreferences = 'drawer left' | 'drawer bottom' | 'drawer right';
  4. type TracePreferencesAction =
  5. | {payload: TraceLayoutPreferences; type: 'set layout'}
  6. | {
  7. payload: number;
  8. type: 'set drawer dimension';
  9. }
  10. | {payload: number; type: 'set list width'}
  11. | {payload: boolean; type: 'minimize drawer'};
  12. type TraceDrawerPreferences = {
  13. minimized: boolean;
  14. sizes: {
  15. [key in TraceLayoutPreferences]: number;
  16. };
  17. };
  18. type TracePreferencesState = {
  19. drawer: TraceDrawerPreferences;
  20. layout: TraceLayoutPreferences;
  21. list: {
  22. width: number;
  23. };
  24. };
  25. export const TRACE_DRAWER_DEFAULT_SIZES: TraceDrawerPreferences['sizes'] = {
  26. 'drawer left': 0.33,
  27. 'drawer right': 0.33,
  28. 'drawer bottom': 0.5,
  29. };
  30. const DEFAULT_TRACE_VIEW_PREFERENCES: TracePreferencesState = {
  31. drawer: {
  32. minimized: false,
  33. sizes: {
  34. 'drawer left': 0.33,
  35. 'drawer right': 0.33,
  36. 'drawer bottom': 0.5,
  37. },
  38. },
  39. layout: 'drawer right',
  40. list: {
  41. width: 0.5,
  42. },
  43. };
  44. export function storeTraceViewPreferences(state: TracePreferencesState): void {
  45. // Make sure we dont fire this during a render phase
  46. window.requestAnimationFrame(() => {
  47. try {
  48. localStorage.setItem('trace-view-preferences', JSON.stringify(state));
  49. } catch (e) {
  50. Sentry.captureException(e);
  51. }
  52. });
  53. }
  54. function isInt(value: any): value is number {
  55. return typeof value === 'number' && !isNaN(value);
  56. }
  57. export function loadTraceViewPreferences(): TracePreferencesState {
  58. const stored = localStorage.getItem('trace-view-preferences');
  59. if (stored) {
  60. try {
  61. const parsed = JSON.parse(stored);
  62. // We need a more robust way to validate the stored preferences.
  63. // Since we dont have a schema validation lib, just do it manually for now.
  64. if (
  65. parsed?.drawer &&
  66. typeof parsed.drawer.minimized === 'boolean' &&
  67. parsed.drawer.sizes &&
  68. isInt(parsed.drawer.sizes['drawer left']) &&
  69. isInt(parsed.drawer.sizes['drawer right']) &&
  70. isInt(parsed.drawer.sizes['drawer bottom']) &&
  71. parsed.layout &&
  72. typeof parsed.layout === 'string' &&
  73. parsed.list &&
  74. isInt(parsed.list.width)
  75. ) {
  76. return parsed;
  77. }
  78. } catch (e) {
  79. Sentry.captureException(e);
  80. }
  81. }
  82. return DEFAULT_TRACE_VIEW_PREFERENCES;
  83. }
  84. export function tracePreferencesReducer(
  85. state: TracePreferencesState,
  86. action: TracePreferencesAction
  87. ): TracePreferencesState {
  88. switch (action.type) {
  89. case 'minimize drawer':
  90. return {...state, drawer: {...state.drawer, minimized: action.payload}};
  91. case 'set layout':
  92. return {
  93. ...state,
  94. layout: action.payload,
  95. drawer: {...state.drawer, minimized: false},
  96. };
  97. case 'set drawer dimension':
  98. return {
  99. ...state,
  100. drawer: {
  101. ...state.drawer,
  102. sizes: {
  103. ...state.drawer.sizes,
  104. [state.layout]:
  105. action.payload < 0 ? 0 : action.payload > 1 ? 1 : action.payload,
  106. },
  107. },
  108. };
  109. case 'set list width':
  110. return {
  111. ...state,
  112. list: {
  113. width: action.payload < 0 ? 0 : action.payload > 1 ? 1 : action.payload,
  114. },
  115. };
  116. default:
  117. traceReducerExhaustiveActionCheck(action);
  118. return state;
  119. }
  120. }