Merge branch '21838-picker-search-race' into main. Closes #21838
[arvados.git] / services / workbench2 / src / store / store.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { createStore, applyMiddleware, compose, Middleware, combineReducers, Store, Action, Dispatch } from "redux";
6 import { routerMiddleware, routerReducer } from "react-router-redux";
7 import thunkMiddleware from "redux-thunk";
8 import { History } from "history";
9 import { handleRedirects } from "../common/redirect-to";
10
11 import { authReducer } from "./auth/auth-reducer";
12 import { authMiddleware } from "./auth/auth-middleware";
13 import { dataExplorerReducer } from "./data-explorer/data-explorer-reducer";
14 import { detailsPanelReducer } from "./details-panel/details-panel-reducer";
15 import { contextMenuReducer } from "./context-menu/context-menu-reducer";
16 import { reducer as formReducer } from "redux-form";
17 import { favoritesReducer } from "./favorites/favorites-reducer";
18 import { snackbarReducer } from "./snackbar/snackbar-reducer";
19 import { collectionPanelFilesReducer } from "./collection-panel/collection-panel-files/collection-panel-files-reducer";
20 import { dataExplorerMiddleware } from "./data-explorer/data-explorer-middleware";
21 import { FAVORITE_PANEL_ID } from "./favorite-panel/favorite-panel-action";
22 import { WORKFLOW_PROCESSES_PANEL_ID } from "./workflow-panel/workflow-panel-actions";
23 import { PROJECT_PANEL_DATA_ID, PROJECT_PANEL_RUN_ID } from "./project-panel/project-panel-action-bind";
24 import { ProjectPanelDataMiddlewareService } from "./project-panel/project-panel-data-middleware-service";
25 import { ProjectPanelRunMiddlewareService } from "./project-panel/project-panel-run-middleware-service";
26 import { FavoritePanelMiddlewareService } from "./favorite-panel/favorite-panel-middleware-service";
27 import { AllProcessesPanelMiddlewareService } from "./all-processes-panel/all-processes-panel-middleware-service";
28 import { WorkflowProcessesMiddlewareService } from "./workflow-panel/workflow-middleware-service";
29 import { collectionPanelReducer } from "./collection-panel/collection-panel-reducer";
30 import { dialogReducer } from "./dialog/dialog-reducer";
31 import { ServiceRepository } from "services/services";
32 import { treePickerReducer, treePickerSearchReducer } from "./tree-picker/tree-picker-reducer";
33 import { resourcesReducer } from "store/resources/resources-reducer";
34 import { propertiesReducer } from "./properties/properties-reducer";
35 import { fileUploaderReducer } from "./file-uploader/file-uploader-reducer";
36 import { TrashPanelMiddlewareService } from "store/trash-panel/trash-panel-middleware-service";
37 import { TRASH_PANEL_ID } from "store/trash-panel/trash-panel-action";
38 import { processLogsPanelReducer } from "./process-logs-panel/process-logs-panel-reducer";
39 import { processPanelReducer } from "store/process-panel/process-panel-reducer";
40 import { SHARED_WITH_ME_PANEL_ID } from "store/shared-with-me-panel/shared-with-me-panel-actions";
41 import { SharedWithMeMiddlewareService } from "./shared-with-me-panel/shared-with-me-middleware-service";
42 import { progressIndicatorReducer } from "./progress-indicator/progress-indicator-reducer";
43 import { runProcessPanelReducer } from "store/run-process-panel/run-process-panel-reducer";
44 import { WorkflowMiddlewareService } from "./workflow-panel/workflow-middleware-service";
45 import { WORKFLOW_PANEL_ID } from "./workflow-panel/workflow-panel-actions";
46 import { appInfoReducer } from "store/app-info/app-info-reducer";
47 import { searchBarReducer } from "./search-bar/search-bar-reducer";
48 import { SEARCH_RESULTS_PANEL_ID } from "store/search-results-panel/search-results-panel-actions";
49 import { SearchResultsMiddlewareService } from "./search-results-panel/search-results-middleware-service";
50 import { virtualMachinesReducer } from "store/virtual-machines/virtual-machines-reducer";
51 import { repositoriesReducer } from "store/repositories/repositories-reducer";
52 import { keepServicesReducer } from "store/keep-services/keep-services-reducer";
53 import { UserMiddlewareService } from "store/users/user-panel-middleware-service";
54 import { USERS_PANEL_ID } from "store/users/users-actions";
55 import { UserProfileGroupsMiddlewareService } from "store/user-profile/user-profile-groups-middleware-service";
56 import { USER_PROFILE_PANEL_ID } from "store/user-profile/user-profile-actions";
57 import { GroupsPanelMiddlewareService } from "store/groups-panel/groups-panel-middleware-service";
58 import { GROUPS_PANEL_ID } from "store/groups-panel/groups-panel-actions";
59 import { GroupDetailsPanelMembersMiddlewareService } from "store/group-details-panel/group-details-panel-members-middleware-service";
60 import { GroupDetailsPanelPermissionsMiddlewareService } from "store/group-details-panel/group-details-panel-permissions-middleware-service";
61 import { GROUP_DETAILS_MEMBERS_PANEL_ID, GROUP_DETAILS_PERMISSIONS_PANEL_ID } from "store/group-details-panel/group-details-panel-actions";
62 import { LINK_PANEL_ID } from "store/link-panel/link-panel-actions";
63 import { LinkMiddlewareService } from "store/link-panel/link-panel-middleware-service";
64 import { API_CLIENT_AUTHORIZATION_PANEL_ID } from "store/api-client-authorizations/api-client-authorizations-actions";
65 import { ApiClientAuthorizationMiddlewareService } from "store/api-client-authorizations/api-client-authorizations-middleware-service";
66 import { PublicFavoritesMiddlewareService } from "store/public-favorites-panel/public-favorites-middleware-service";
67 import { PUBLIC_FAVORITE_PANEL_ID } from "store/public-favorites-panel/public-favorites-action";
68 import { publicFavoritesReducer } from "store/public-favorites/public-favorites-reducer";
69 import { linkAccountPanelReducer } from "./link-account-panel/link-account-panel-reducer";
70 import { CollectionsWithSameContentAddressMiddlewareService } from "store/collections-content-address-panel/collections-content-address-middleware-service";
71 import { COLLECTIONS_CONTENT_ADDRESS_PANEL_ID } from "store/collections-content-address-panel/collections-content-address-panel-actions";
72 import { ownerNameReducer } from "store/owner-name/owner-name-reducer";
73 import { SubprocessMiddlewareService } from "store/subprocess-panel/subprocess-panel-middleware-service";
74 import { SUBPROCESS_PANEL_ID } from "store/subprocess-panel/subprocess-panel-actions";
75 import { ALL_PROCESSES_PANEL_ID } from "./all-processes-panel/all-processes-panel-action";
76 import { Config } from "common/config";
77 import { pluginConfig } from "plugins";
78 import { MiddlewareListReducer } from "common/plugintypes";
79 import { tooltipsMiddleware } from "./tooltips/tooltips-middleware";
80 import { sidePanelReducer } from "./side-panel/side-panel-reducer";
81 import { bannerReducer } from "./banner/banner-reducer";
82 import { multiselectReducer } from "./multiselect/multiselect-reducer";
83 import { composeWithDevTools } from "redux-devtools-extension";
84 import { selectedResourceReducer } from "./selected-resource/selected-resource-reducer";
85 import createSagaMiddleware from 'redux-saga';
86 import { rootSaga } from "./redux-saga";
87
88 declare global {
89     interface Window {
90         __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose;
91     }
92 }
93
94 export type RootState = ReturnType<ReturnType<typeof createRootReducer>>;
95
96 export type RootStore = Store<RootState, Action> & { dispatch: Dispatch<any> };
97
98 export function configureStore(history: History, services: ServiceRepository, config: Config): RootStore {
99     const rootReducer = createRootReducer(services);
100
101     const projectPanelDataMiddleware = dataExplorerMiddleware(new ProjectPanelDataMiddlewareService(services, PROJECT_PANEL_DATA_ID));
102     const projectPanelRunMiddleware = dataExplorerMiddleware(new ProjectPanelRunMiddlewareService(services, PROJECT_PANEL_RUN_ID));
103     const favoritePanelMiddleware = dataExplorerMiddleware(new FavoritePanelMiddlewareService(services, FAVORITE_PANEL_ID));
104     const allProcessessPanelMiddleware = dataExplorerMiddleware(new AllProcessesPanelMiddlewareService(services, ALL_PROCESSES_PANEL_ID));
105     const workflowProcessessPanelMiddleware = dataExplorerMiddleware(new WorkflowProcessesMiddlewareService(services, WORKFLOW_PROCESSES_PANEL_ID));
106     const trashPanelMiddleware = dataExplorerMiddleware(new TrashPanelMiddlewareService(services, TRASH_PANEL_ID));
107     const searchResultsPanelMiddleware = dataExplorerMiddleware(new SearchResultsMiddlewareService(services, SEARCH_RESULTS_PANEL_ID));
108     const sharedWithMePanelMiddleware = dataExplorerMiddleware(new SharedWithMeMiddlewareService(services, SHARED_WITH_ME_PANEL_ID));
109     const workflowPanelMiddleware = dataExplorerMiddleware(new WorkflowMiddlewareService(services, WORKFLOW_PANEL_ID));
110     const userPanelMiddleware = dataExplorerMiddleware(new UserMiddlewareService(services, USERS_PANEL_ID));
111     const userProfileGroupsMiddleware = dataExplorerMiddleware(new UserProfileGroupsMiddlewareService(services, USER_PROFILE_PANEL_ID));
112     const groupsPanelMiddleware = dataExplorerMiddleware(new GroupsPanelMiddlewareService(services, GROUPS_PANEL_ID));
113     const groupDetailsPanelMembersMiddleware = dataExplorerMiddleware(
114         new GroupDetailsPanelMembersMiddlewareService(services, GROUP_DETAILS_MEMBERS_PANEL_ID)
115     );
116     const groupDetailsPanelPermissionsMiddleware = dataExplorerMiddleware(
117         new GroupDetailsPanelPermissionsMiddlewareService(services, GROUP_DETAILS_PERMISSIONS_PANEL_ID)
118     );
119     const linkPanelMiddleware = dataExplorerMiddleware(new LinkMiddlewareService(services, LINK_PANEL_ID));
120     const apiClientAuthorizationMiddlewareService = dataExplorerMiddleware(
121         new ApiClientAuthorizationMiddlewareService(services, API_CLIENT_AUTHORIZATION_PANEL_ID)
122     );
123     const publicFavoritesMiddleware = dataExplorerMiddleware(new PublicFavoritesMiddlewareService(services, PUBLIC_FAVORITE_PANEL_ID));
124     const collectionsContentAddress = dataExplorerMiddleware(
125         new CollectionsWithSameContentAddressMiddlewareService(services, COLLECTIONS_CONTENT_ADDRESS_PANEL_ID)
126     );
127     const subprocessMiddleware = dataExplorerMiddleware(new SubprocessMiddlewareService(services, SUBPROCESS_PANEL_ID));
128
129     const redirectToMiddleware = (store: any) => (next: any) => (action: any) => {
130         const state = store.getState();
131
132         if (state.auth && state.auth.apiToken) {
133             handleRedirects(state.auth.apiToken, config);
134         }
135
136         return next(action);
137     };
138
139     const sagaMiddleware = createSagaMiddleware({
140         context: { services }
141     });
142
143     let middlewares: Middleware[] = [
144         routerMiddleware(history),
145         thunkMiddleware.withExtraArgument(services),
146         sagaMiddleware,
147         authMiddleware(services),
148         tooltipsMiddleware(services),
149         projectPanelDataMiddleware,
150         projectPanelRunMiddleware,
151         favoritePanelMiddleware,
152         allProcessessPanelMiddleware,
153         trashPanelMiddleware,
154         searchResultsPanelMiddleware,
155         sharedWithMePanelMiddleware,
156         workflowPanelMiddleware,
157         userPanelMiddleware,
158         userProfileGroupsMiddleware,
159         groupsPanelMiddleware,
160         groupDetailsPanelMembersMiddleware,
161         groupDetailsPanelPermissionsMiddleware,
162         linkPanelMiddleware,
163         apiClientAuthorizationMiddlewareService,
164         publicFavoritesMiddleware,
165         collectionsContentAddress,
166         subprocessMiddleware,
167         workflowProcessessPanelMiddleware
168     ];
169
170     const reduceMiddlewaresFn: (a: Middleware[], b: MiddlewareListReducer) => Middleware[] = (a, b) => b(a, services);
171
172     middlewares = pluginConfig.middlewares.reduce(reduceMiddlewaresFn, middlewares);
173
174     const enhancer = composeWithDevTools({
175         /* options */
176     })(applyMiddleware(redirectToMiddleware, ...middlewares));
177     const store = createStore(rootReducer, enhancer);
178
179     sagaMiddleware.run(rootSaga);
180
181     return store;
182 }
183
184 const createRootReducer = (services: ServiceRepository) =>
185     combineReducers({
186         auth: authReducer(services),
187         banner: bannerReducer,
188         collectionPanel: collectionPanelReducer,
189         collectionPanelFiles: collectionPanelFilesReducer,
190         contextMenu: contextMenuReducer,
191         dataExplorer: dataExplorerReducer,
192         detailsPanel: detailsPanelReducer,
193         dialog: dialogReducer,
194         favorites: favoritesReducer,
195         ownerName: ownerNameReducer,
196         publicFavorites: publicFavoritesReducer,
197         form: formReducer,
198         processLogsPanel: processLogsPanelReducer,
199         properties: propertiesReducer,
200         resources: resourcesReducer,
201         router: routerReducer,
202         selectedResourceUuid: selectedResourceReducer,
203         snackbar: snackbarReducer,
204         treePicker: treePickerReducer,
205         treePickerSearch: treePickerSearchReducer,
206         fileUploader: fileUploaderReducer,
207         processPanel: processPanelReducer,
208         progressIndicator: progressIndicatorReducer,
209         runProcessPanel: runProcessPanelReducer,
210         appInfo: appInfoReducer,
211         searchBar: searchBarReducer,
212         virtualMachines: virtualMachinesReducer,
213         repositories: repositoriesReducer,
214         keepServices: keepServicesReducer,
215         linkAccountPanel: linkAccountPanelReducer,
216         sidePanel: sidePanelReducer,
217         multiselect: multiselectReducer,
218     });