github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/webapp/javascript/redux/reducers/ui.ts (about)

     1  import { createSlice, createSelector, PayloadAction } from '@reduxjs/toolkit';
     2  import { createMigrate } from 'redux-persist';
     3  import storage from 'redux-persist/lib/storage';
     4  import { PersistedState } from 'redux-persist/lib/types';
     5  import type { RootState } from '@webapp/redux/store';
     6  
     7  // Persistence Migrations
     8  // See examples on https://github.com/rt2zz/redux-persist/blob/master/docs/migrations.md
     9  export const migrations = {
    10    0: (state: PersistedState) => {
    11      if (!state) {
    12        return {} as PersistedState;
    13      }
    14  
    15      return { ...state };
    16    },
    17  };
    18  
    19  export const persistConfig = {
    20    key: 'pyroscope:ui',
    21    version: 0,
    22    storage,
    23    migrate: createMigrate(migrations, { debug: true }),
    24  };
    25  
    26  type SidebarState =
    27    // pristine means user hasn't interacted with it yet
    28    // so we default to certain heuristics (eg window size)
    29    | { state: 'pristine'; collapsed: true }
    30    | { state: 'pristine'; collapsed: false }
    31  
    32    // userInteracted means user has actively clicked on the button
    33    // so we should keep whatever state they've chosen
    34    | { state: 'userInteracted'; collapsed: true }
    35    | { state: 'userInteracted'; collapsed: false };
    36  
    37  export interface UiState {
    38    sidebar: SidebarState;
    39    time: {
    40      offset: null | number;
    41    };
    42    colorMode: 'dark' | 'light';
    43  }
    44  
    45  const initialState: UiState = {
    46    sidebar: { state: 'pristine', collapsed: window.innerWidth < 1200 },
    47    time: {
    48      offset: null,
    49    },
    50    //  sidebar: { state: 'pristine' },
    51    colorMode: 'dark',
    52  };
    53  
    54  export const uiSlice = createSlice({
    55    name: 'ui',
    56    initialState,
    57    reducers: {
    58      recalculateSidebar: (state) => {
    59        if (state.sidebar.state === 'pristine') {
    60          state.sidebar.collapsed = window.innerWidth < 1200;
    61        }
    62      },
    63      collapseSidebar: (state) => {
    64        state.sidebar = { state: 'userInteracted', collapsed: true };
    65      },
    66      uncollapseSidebar: (state) => {
    67        state.sidebar = { state: 'userInteracted', collapsed: false };
    68      },
    69      changeTimeZoneOffset: (state, action) => {
    70        state.time.offset = action.payload;
    71      },
    72      setColorMode: (state, action: PayloadAction<'dark' | 'light'>) => {
    73        state.colorMode = action.payload;
    74      },
    75    },
    76  });
    77  
    78  const selectUiState = (state: RootState) => state.ui;
    79  
    80  export const selectSidebarCollapsed = createSelector(selectUiState, (state) => {
    81    return state.sidebar.collapsed;
    82  });
    83  
    84  export const selectTimezoneOffset = createSelector(
    85    selectUiState,
    86    (state) => state.time.offset
    87  );
    88  
    89  export const selectAppColorMode = createSelector(
    90    selectUiState,
    91    (state) => state.colorMode
    92  );
    93  
    94  export const {
    95    collapseSidebar,
    96    uncollapseSidebar,
    97    recalculateSidebar,
    98    changeTimeZoneOffset,
    99    setColorMode,
   100  } = uiSlice.actions;
   101  
   102  export default uiSlice.reducer;