github.com/grafana/pyroscope@v1.18.0/public/app/redux/reducers/tenant.ts (about)

     1  import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
     2  import { createAsyncThunk } from '@pyroscope/redux/async-thunk';
     3  import type { RootState } from '@pyroscope/redux/store';
     4  import { isMultiTenancyEnabled } from '@pyroscope/services/tenant';
     5  import storage from 'redux-persist/lib/storage';
     6  import { PersistConfig } from 'redux-persist/lib/types';
     7  import { tenantIDFromStorage } from '@pyroscope/services/storage';
     8  
     9  export const persistConfig: PersistConfig<TenantState> = {
    10    key: 'pyroscope:tenant',
    11    version: 0,
    12    storage,
    13    whitelist: ['tenantID'],
    14  };
    15  
    16  interface TenantState {
    17    tenancy:
    18      | 'unknown'
    19      | 'loading'
    20      | 'needs_tenant_id'
    21      | 'wants_to_change'
    22      | 'single_tenant'
    23      | 'multi_tenant';
    24    tenantID?: string;
    25  }
    26  
    27  const initialState: TenantState = {
    28    tenancy: 'unknown',
    29    tenantID: undefined,
    30  };
    31  
    32  export const checkTenancyIsRequired = createAsyncThunk<
    33    { tenancy: TenantState['tenancy']; tenantID?: string },
    34    void,
    35    { state: { tenant: TenantState } }
    36  >(
    37    'checkTenancyIsRequired',
    38    async () => {
    39      const tenantID = tenantIDFromStorage();
    40  
    41      // Try to hit the server and see the response
    42      const multitenancy = await isMultiTenancyEnabled();
    43  
    44      if (multitenancy && !tenantID) {
    45        return Promise.resolve({ tenancy: 'needs_tenant_id', tenantID });
    46      }
    47  
    48      if (multitenancy && tenantID) {
    49        return Promise.resolve({ tenancy: 'multi_tenant', tenantID });
    50      }
    51  
    52      return Promise.resolve({ tenancy: 'single_tenant', tenantID: undefined });
    53    },
    54    {
    55      // This check is only valid if we don't know what's the tenancy status yet
    56      condition: (query, thunkAPI) => {
    57        const state = thunkAPI.getState().tenant;
    58  
    59        return state.tenancy === 'unknown';
    60      },
    61    }
    62  );
    63  
    64  const tenantSlice = createSlice({
    65    name: 'tenant',
    66    initialState,
    67    reducers: {
    68      deleteTenancy(state) {
    69        state.tenancy = 'unknown';
    70        state.tenantID = undefined;
    71      },
    72      setTenantID(state, action: PayloadAction<string>) {
    73        state.tenancy = 'multi_tenant';
    74        state.tenantID = action.payload;
    75      },
    76      setWantsToChange(state) {
    77        state.tenancy = 'wants_to_change';
    78      },
    79    },
    80    extraReducers: (builder) => {
    81      // This thunk will never reject
    82      builder.addCase(checkTenancyIsRequired.fulfilled, (state, action) => {
    83        state.tenancy = action.payload?.tenancy;
    84        state.tenantID = action.payload?.tenantID;
    85      });
    86      builder.addCase(checkTenancyIsRequired.pending, (state) => {
    87        state.tenancy = 'loading';
    88      });
    89    },
    90  });
    91  
    92  export const { actions } = tenantSlice;
    93  
    94  export const selectTenancy = (state: RootState) => state.tenant?.tenancy;
    95  
    96  export const selectIsMultiTenant = (state: RootState) =>
    97    state.tenant?.tenancy === 'multi_tenant' ||
    98    state.tenant?.tenancy === 'wants_to_change';
    99  
   100  export const selectTenantID = (state: RootState) => state.tenant?.tenantID;
   101  
   102  export default tenantSlice.reducer;