go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/common/store/store.ts (about)

     1  // Copyright 2022 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  import { Instance, SnapshotIn, SnapshotOut, types } from 'mobx-state-tree';
    16  import { createContext, useContext } from 'react';
    17  
    18  import { createContextLink } from '@/generic_libs/tools/lit_context';
    19  
    20  import { AuthStateStore } from './auth_state';
    21  import { BuildPage } from './build_page';
    22  import { InvocationPage } from './invocation_page';
    23  import { ServicesStore } from './services';
    24  import { TestHistoryPage } from './test_history_page';
    25  import { Timestamp } from './timestamp';
    26  import { UserConfig } from './user_config';
    27  
    28  export const Store = types
    29    .model('Store', {
    30      currentTime: types.optional(Timestamp, {}),
    31      refreshTime: types.optional(Timestamp, {}),
    32  
    33      authState: types.optional(AuthStateStore, {}),
    34      userConfig: types.optional(UserConfig, {}),
    35      services: types.optional(ServicesStore, {}),
    36  
    37      buildPage: types.optional(BuildPage, {}),
    38      testHistoryPage: types.optional(TestHistoryPage, {}),
    39      invocationPage: types.optional(InvocationPage, {}),
    40    })
    41    .volatile(() => ({
    42      /**
    43       * The service worker that performs redirection.
    44       *
    45       * undefined means it's not initialized yet.
    46       * null means there's no such service worker.
    47       */
    48      redirectSw: undefined as ServiceWorkerRegistration | null | undefined,
    49    }))
    50    .actions((self) => ({
    51      setRedirectSw(redirectSw: ServiceWorkerRegistration | null) {
    52        self.redirectSw = redirectSw;
    53      },
    54      afterCreate() {
    55        self.services.setDependencies({ authState: self.authState });
    56        self.userConfig.enableCaching();
    57        self.buildPage.setDependencies({
    58          currentTime: self.currentTime,
    59          refreshTime: self.refreshTime,
    60          services: self.services,
    61          userConfig: self.userConfig,
    62        });
    63        self.testHistoryPage.setDependencies({
    64          refreshTime: self.refreshTime,
    65          services: self.services,
    66        });
    67        self.invocationPage.setDependencies({
    68          services: self.services,
    69        });
    70      },
    71    }));
    72  
    73  export type StoreInstance = Instance<typeof Store>;
    74  export type StoreSnapshotIn = SnapshotIn<typeof Store>;
    75  export type StoreSnapshotOut = SnapshotOut<typeof Store>;
    76  
    77  export const [provideStore, consumeStore] = createContextLink<StoreInstance>();
    78  
    79  export const StoreContext = createContext<StoreInstance | null>(null);
    80  export const StoreProvider = StoreContext.Provider;
    81  
    82  export function useStore() {
    83    const context = useContext(StoreContext);
    84    if (!context) {
    85      throw new Error('useStore must be used within StoreProvider');
    86    }
    87  
    88    return context;
    89  }