From 72ee613468c6dee53b98ed1469ce9781a942dbe9 Mon Sep 17 00:00:00 2001 From: Peter Amstutz Date: Wed, 27 Nov 2019 14:37:10 -0500 Subject: [PATCH] 15803: INIT->INIT_USER, CONFIG->SET_CONFIG, remove config reducer I realized there was mostly do-nothing "config" reducer, whereas most all the other cluster configuration was stored on the "auth" reducer, so I moved config over to auth and got rid of the config reducer. Added some comments to auth-middleware.ts. Arvados-DCO-1.1-Signed-off-by: Peter Amstutz --- src/store/auth/auth-action.test.ts | 7 ++++++ src/store/auth/auth-action.ts | 8 +++---- src/store/auth/auth-middleware.ts | 24 ++++++++++++++++--- src/store/auth/auth-reducer.test.ts | 4 +++- src/store/auth/auth-reducer.ts | 11 +++++---- src/store/config/config-action.ts | 12 ---------- src/store/config/config-reducer.ts | 17 ------------- .../link-account-panel-actions.ts | 2 +- .../public-favorites-middleware-service.ts | 4 ++-- .../public-favorites-actions.ts | 4 ++-- src/store/store.ts | 2 -- src/store/tree-picker/tree-picker-actions.ts | 2 +- src/store/users/users-actions.ts | 2 +- .../main-app-bar/account-menu.tsx | 2 +- src/views/inactive-panel/inactive-panel.tsx | 2 +- src/views/login-panel/login-panel.tsx | 2 +- src/views/main-panel/main-panel.tsx | 2 +- 17 files changed, 53 insertions(+), 54 deletions(-) delete mode 100644 src/store/config/config-action.ts delete mode 100644 src/store/config/config-reducer.ts diff --git a/src/store/auth/auth-action.test.ts b/src/store/auth/auth-action.test.ts index f721e760..f7aa5c4c 100644 --- a/src/store/auth/auth-action.test.ts +++ b/src/store/auth/auth-action.test.ts @@ -81,6 +81,13 @@ describe('auth-actions', () => { try { expect(auth).toEqual({ apiToken: "token", + config: { + remoteHosts: { + "xc59z": "xc59z.arvadosapi.com", + }, + rootUrl: "https://zzzzz.arvadosapi.com", + uuidPrefix: "zzzzz", + }, sshKeys: [], homeCluster: "zzzzz", localCluster: "zzzzz", diff --git a/src/store/auth/auth-action.ts b/src/store/auth/auth-action.ts index 8fb5c5e9..1d8a01c6 100644 --- a/src/store/auth/auth-action.ts +++ b/src/store/auth/auth-action.ts @@ -19,8 +19,8 @@ import { WORKBENCH_LOADING_SCREEN } from '~/store/workbench/workbench-actions'; export const authActions = unionize({ LOGIN: {}, LOGOUT: ofType<{ deleteLinkData: boolean }>(), - CONFIG: ofType<{ config: Config }>(), - INIT: ofType<{ user: User, token: string }>(), + SET_CONFIG: ofType<{ config: Config }>(), + INIT_USER: ofType<{ user: User, token: string }>(), USER_DETAILS_REQUEST: {}, USER_DETAILS_SUCCESS: ofType(), SET_SSH_KEYS: ofType(), @@ -54,7 +54,7 @@ const init = (config: Config) => (dispatch: Dispatch, getState: () => RootState, if (homeCluster && !config.remoteHosts[homeCluster]) { homeCluster = undefined; } - dispatch(authActions.CONFIG({ config })); + dispatch(authActions.SET_CONFIG({ config })); dispatch(authActions.SET_HOME_CLUSTER(config.loginCluster || homeCluster || config.uuidPrefix)); if (token && token !== "undefined") { @@ -77,7 +77,7 @@ export const saveApiToken = (token: string) => (dispatch: Dispatch, getState: () const svc = createServices(config, { progressFn: () => { }, errorFn: () => { } }); setAuthorizationHeader(svc, token); return svc.authService.getUserDetails().then((user: User) => { - dispatch(authActions.INIT({ user, token })); + dispatch(authActions.INIT_USER({ user, token })); }); }; diff --git a/src/store/auth/auth-middleware.ts b/src/store/auth/auth-middleware.ts index 817ddd2e..76f85984 100644 --- a/src/store/auth/auth-middleware.ts +++ b/src/store/auth/auth-middleware.ts @@ -12,9 +12,17 @@ import { progressIndicatorActions } from "~/store/progress-indicator/progress-in import { WORKBENCH_LOADING_SCREEN } from '~/store/workbench/workbench-actions'; export const authMiddleware = (services: ServiceRepository): Middleware => store => next => action => { + // Middleware to update external state (local storage, window + // title) to ensure that they stay in sync with redux state. + authActions.match(action, { - INIT: ({ user, token }) => { + INIT_USER: ({ user, token }) => { + // The "next" method passes the action to the next + // middleware in the chain, or the reducer. That means + // after next() returns, the action has (presumably) been + // applied by the reducer to update the state. next(action); + const state: RootState = store.getState(); if (state.auth.apiToken) { @@ -27,16 +35,26 @@ export const authMiddleware = (services: ServiceRepository): Middleware => store store.dispatch(initSessions(services.authService, state.auth.remoteHostsConfig[state.auth.localCluster], user)); if (!user.isActive) { + // As a special case, if the user is inactive, they + // may be able to self-activate using the "activate" + // method. Note, for this to work there can't be any + // unsigned user agreements, we assume the API server is just going to + // rubber-stamp our activation request. At some point in the future we'll + // want to either add support for displaying/signing user + // agreements or get rid of self-activation. + // For more details, see: + // https://doc.arvados.org/master/admin/user-management.html + store.dispatch(progressIndicatorActions.START_WORKING(WORKBENCH_LOADING_SCREEN)); services.userService.activate(user.uuid).then((user: User) => { - store.dispatch(authActions.INIT({ user, token })); + store.dispatch(authActions.INIT_USER({ user, token })); store.dispatch(progressIndicatorActions.STOP_WORKING(WORKBENCH_LOADING_SCREEN)); }).catch(() => { store.dispatch(progressIndicatorActions.STOP_WORKING(WORKBENCH_LOADING_SCREEN)); }); } }, - CONFIG: ({ config }) => { + SET_CONFIG: ({ config }) => { document.title = `Arvados Workbench (${config.uuidPrefix})`; next(action); }, diff --git a/src/store/auth/auth-reducer.test.ts b/src/store/auth/auth-reducer.test.ts index e862a313..756feeeb 100644 --- a/src/store/auth/auth-reducer.test.ts +++ b/src/store/auth/auth-reducer.test.ts @@ -35,9 +35,10 @@ describe('auth-reducer', () => { isAdmin: false, isActive: true }; - const state = reducer(initialState, authActions.INIT({ user, token: "token" })); + const state = reducer(initialState, authActions.INIT_USER({ user, token: "token" })); expect(state).toEqual({ apiToken: "token", + config: mockConfig({}), user, sshKeys: [], sessions: [], @@ -67,6 +68,7 @@ describe('auth-reducer', () => { const state = reducer(initialState, authActions.USER_DETAILS_SUCCESS(user)); expect(state).toEqual({ apiToken: undefined, + config: mockConfig({}), sshKeys: [], sessions: [], homeCluster: "uuid", diff --git a/src/store/auth/auth-reducer.ts b/src/store/auth/auth-reducer.ts index da3c223f..946407fe 100644 --- a/src/store/auth/auth-reducer.ts +++ b/src/store/auth/auth-reducer.ts @@ -7,7 +7,7 @@ import { User } from "~/models/user"; import { ServiceRepository } from "~/services/services"; import { SshKeyResource } from '~/models/ssh-key'; import { Session } from "~/models/session"; -import { Config } from '~/common/config'; +import { Config, mockConfig } from '~/common/config'; export interface AuthState { user?: User; @@ -19,6 +19,7 @@ export interface AuthState { loginCluster: string; remoteHosts: { [key: string]: string }; remoteHostsConfig: { [key: string]: Config }; + config: Config; } const initialState: AuthState = { @@ -30,14 +31,16 @@ const initialState: AuthState = { homeCluster: "", loginCluster: "", remoteHosts: {}, - remoteHostsConfig: {} + remoteHostsConfig: {}, + config: mockConfig({}) }; export const authReducer = (services: ServiceRepository) => (state = initialState, action: AuthAction) => { return authActions.match(action, { - CONFIG: ({ config }) => { + SET_CONFIG: ({ config }) => { return { ...state, + config, localCluster: config.uuidPrefix, remoteHosts: { ...config.remoteHosts, [config.uuidPrefix]: new URL(config.rootUrl).host }, homeCluster: config.loginCluster || config.uuidPrefix, @@ -51,7 +54,7 @@ export const authReducer = (services: ServiceRepository) => (state = initialStat remoteHostsConfig: { ...state.remoteHostsConfig, [config.uuidPrefix]: config }, }; }, - INIT: ({ user, token }) => { + INIT_USER: ({ user, token }) => { return { ...state, user, apiToken: token, homeCluster: user.uuid.substr(0, 5) }; }, LOGIN: () => { diff --git a/src/store/config/config-action.ts b/src/store/config/config-action.ts deleted file mode 100644 index fd792948..00000000 --- a/src/store/config/config-action.ts +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -import { ofType, unionize, UnionOf } from '~/common/unionize'; -import { Config } from '~/common/config'; - -export const configActions = unionize({ - CONFIG: ofType<{ config: Config }>(), -}); - -export type ConfigAction = UnionOf; diff --git a/src/store/config/config-reducer.ts b/src/store/config/config-reducer.ts deleted file mode 100644 index f0b76b14..00000000 --- a/src/store/config/config-reducer.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) The Arvados Authors. All rights reserved. -// -// SPDX-License-Identifier: AGPL-3.0 - -import { configActions, ConfigAction } from "./config-action"; -import { mockConfig } from '~/common/config'; - -export const configReducer = (state = mockConfig({}), action: ConfigAction) => { - return configActions.match(action, { - CONFIG: ({ config }) => { - return { - ...state, ...config - }; - }, - default: () => state - }); -}; diff --git a/src/store/link-account-panel/link-account-panel-actions.ts b/src/store/link-account-panel/link-account-panel-actions.ts index 6540ee69..1e94fcfa 100644 --- a/src/store/link-account-panel/link-account-panel-actions.ts +++ b/src/store/link-account-panel/link-account-panel-actions.ts @@ -91,7 +91,7 @@ export const checkForLinkStatus = () => export const switchUser = (user: UserResource, token: string) => (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { - dispatch(authActions.INIT({ user, token })); + dispatch(authActions.INIT_USER({ user, token })); }; export const linkFailed = () => diff --git a/src/store/public-favorites-panel/public-favorites-middleware-service.ts b/src/store/public-favorites-panel/public-favorites-middleware-service.ts index be7f5285..a15fe975 100644 --- a/src/store/public-favorites-panel/public-favorites-middleware-service.ts +++ b/src/store/public-favorites-panel/public-favorites-middleware-service.ts @@ -53,7 +53,7 @@ export class PublicFavoritesMiddlewareService extends DataExplorerMiddlewareServ } try { api.dispatch(progressIndicatorActions.START_WORKING(this.getId())); - const uuidPrefix = api.getState().config.uuidPrefix; + const uuidPrefix = api.getState().auth.config.uuidPrefix; const uuid = `${uuidPrefix}-j7d0g-fffffffffffffff`; const responseLinks = await this.services.linkService.list({ limit: dataExplorer.rowsPerPage, @@ -129,4 +129,4 @@ const couldNotFetchPublicFavorites = () => snackbarActions.OPEN_SNACKBAR({ message: 'Could not fetch public favorites contents.', kind: SnackbarKind.ERROR - }); \ No newline at end of file + }); diff --git a/src/store/public-favorites/public-favorites-actions.ts b/src/store/public-favorites/public-favorites-actions.ts index 50b9070b..d5a5cd46 100644 --- a/src/store/public-favorites/public-favorites-actions.ts +++ b/src/store/public-favorites/public-favorites-actions.ts @@ -21,7 +21,7 @@ export type PublicFavoritesAction = UnionOf; export const togglePublicFavorite = (resource: { uuid: string; name: string }) => (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository): Promise => { dispatch(progressIndicatorActions.START_WORKING("togglePublicFavorite")); - const uuidPrefix = getState().config.uuidPrefix; + const uuidPrefix = getState().auth.config.uuidPrefix; const uuid = `${uuidPrefix}-j7d0g-fffffffffffffff`; dispatch(publicFavoritesActions.TOGGLE_PUBLIC_FAVORITE({ resourceUuid: resource.uuid })); const isPublicFavorite = checkPublicFavorite(resource.uuid, getState().publicFavorites); @@ -57,7 +57,7 @@ export const togglePublicFavorite = (resource: { uuid: string; name: string }) = export const updatePublicFavorites = (resourceUuids: string[]) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { - const uuidPrefix = getState().config.uuidPrefix; + const uuidPrefix = getState().auth.config.uuidPrefix; const uuid = `${uuidPrefix}-j7d0g-fffffffffffffff`; dispatch(publicFavoritesActions.CHECK_PRESENCE_IN_PUBLIC_FAVORITES(resourceUuids)); services.favoriteService diff --git a/src/store/store.ts b/src/store/store.ts index 1b7173fd..7e69a728 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -9,7 +9,6 @@ import { History } from "history"; import { authReducer } from "./auth/auth-reducer"; import { authMiddleware } from "./auth/auth-middleware"; -import { configReducer } from "./config/config-reducer"; import { dataExplorerReducer } from './data-explorer/data-explorer-reducer'; import { detailsPanelReducer } from './details-panel/details-panel-reducer'; import { contextMenuReducer } from './context-menu/context-menu-reducer'; @@ -148,7 +147,6 @@ export function configureStore(history: History, services: ServiceRepository): R const createRootReducer = (services: ServiceRepository) => combineReducers({ auth: authReducer(services), - config: configReducer, collectionPanel: collectionPanelReducer, collectionPanelFiles: collectionPanelFilesReducer, contextMenu: contextMenuReducer, diff --git a/src/store/tree-picker/tree-picker-actions.ts b/src/store/tree-picker/tree-picker-actions.ts index 3fc718ff..7229bf63 100644 --- a/src/store/tree-picker/tree-picker-actions.ts +++ b/src/store/tree-picker/tree-picker-actions.ts @@ -264,7 +264,7 @@ export const loadFavoritesProject = (params: LoadFavoritesProjectParams) => export const loadPublicFavoritesProject = (params: LoadFavoritesProjectParams) => async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => { const { pickerId, includeCollections = false, includeFiles = false } = params; - const uuidPrefix = getState().config.uuidPrefix; + const uuidPrefix = getState().auth.config.uuidPrefix; const uuid = `${uuidPrefix}-j7d0g-fffffffffffffff`; if (uuid) { diff --git a/src/store/users/users-actions.ts b/src/store/users/users-actions.ts index 8d7d0dcd..26c942d6 100644 --- a/src/store/users/users-actions.ts +++ b/src/store/users/users-actions.ts @@ -56,7 +56,7 @@ export const loginAs = (uuid: string) => const data = getResource(uuid)(resources); const client = await services.apiClientAuthorizationService.create({ ownerUuid: uuid }); if (data) { - dispatch(authActions.INIT({ user: data, token: `v2/${client.uuid}/${client.apiToken}` })); + dispatch(authActions.INIT_USER({ user: data, token: `v2/${client.uuid}/${client.apiToken}` })); location.reload(); dispatch(navigateToRootProject); } diff --git a/src/views-components/main-app-bar/account-menu.tsx b/src/views-components/main-app-bar/account-menu.tsx index 72218053..346a9ef0 100644 --- a/src/views-components/main-app-bar/account-menu.tsx +++ b/src/views-components/main-app-bar/account-menu.tsx @@ -32,7 +32,7 @@ interface AccountMenuProps { const mapStateToProps = (state: RootState): AccountMenuProps => ({ user: state.auth.user, currentRoute: state.router.location ? state.router.location.pathname : '', - workbenchURL: state.config.workbenchUrl, + workbenchURL: state.auth.config.workbenchUrl, apiToken: state.auth.apiToken, localCluster: state.auth.localCluster }); diff --git a/src/views/inactive-panel/inactive-panel.tsx b/src/views/inactive-panel/inactive-panel.tsx index 91b4a51d..42262deb 100644 --- a/src/views/inactive-panel/inactive-panel.tsx +++ b/src/views/inactive-panel/inactive-panel.tsx @@ -54,7 +54,7 @@ export interface InactivePanelStateProps { type InactivePanelProps = WithStyles & InactivePanelActionProps & InactivePanelStateProps; export const InactivePanel = connect((state: RootState) => ({ - inactivePageText: state.config.clusterConfig.Workbench.InactivePageHTML + inactivePageText: state.auth.config.clusterConfig.Workbench.InactivePageHTML }), mapDispatchToProps)(withStyles(styles)((({ classes, startLinking, inactivePageText }: InactivePanelProps) => { uuidPrefix: state.auth.localCluster, isNotLinking: state.linkAccountPanel.status === LinkAccountPanelStatus.NONE || state.linkAccountPanel.status === LinkAccountPanelStatus.INITIAL, isLinkingPath: state.router.location ? matchLinkAccountRoute(state.router.location.pathname) !== null : false, - siteBanner: state.config.clusterConfig.Workbench.SiteName + siteBanner: state.auth.config.clusterConfig.Workbench.SiteName }; }; -- 2.39.5