Migrated selectedServer reducer to RTK

This commit is contained in:
Alejandro Celaya 2022-11-11 19:31:05 +01:00
parent 6221f9ed05
commit d44fe945d8
5 changed files with 55 additions and 41 deletions

View file

@ -18,7 +18,8 @@ export const setUpStore = (container: IContainer) => configureStore({
devTools: !isProduction,
reducer: reducer(container),
preloadedState,
middleware: (defaultMiddlewaresIncludingReduxThunk) => defaultMiddlewaresIncludingReduxThunk(
{ immutableCheck: false, serializableCheck: false }, // State is too big for these
).prepend(container.selectServerListener.middleware).concat(save(localStorageConfig)),
middleware: (defaultMiddlewaresIncludingReduxThunk) =>
defaultMiddlewaresIncludingReduxThunk({ immutableCheck: false, serializableCheck: false })// State is too big for these
.prepend(container.selectServerListener.middleware)
.concat(save(localStorageConfig)),
});

View file

@ -1,7 +1,6 @@
import { IContainer } from 'bottlejs';
import { combineReducers } from '@reduxjs/toolkit';
import { serversReducer } from '../servers/reducers/servers';
import selectedServerReducer from '../servers/reducers/selectedServer';
import shortUrlVisitsReducer from '../visits/reducers/shortUrlVisits';
import tagVisitsReducer from '../visits/reducers/tagVisits';
import domainVisitsReducer from '../visits/reducers/domainVisits';
@ -15,7 +14,7 @@ import { ShlinkState } from '../container/types';
export default (container: IContainer) => combineReducers<ShlinkState>({
servers: serversReducer,
selectedServer: selectedServerReducer,
selectedServer: container.selectedServerReducer,
shortUrlsList: container.shortUrlsListReducer,
shortUrlCreation: container.shortUrlCreationReducer,
shortUrlDeletion: container.shortUrlDeletionReducer,

View file

@ -1,20 +1,17 @@
import { createAction, createListenerMiddleware, PayloadAction } from '@reduxjs/toolkit';
import { createAction, createListenerMiddleware, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { identity, memoizeWith, pipe } from 'ramda';
import { versionToPrintable, versionToSemVer as toSemVer } from '../../utils/helpers/version';
import { isReachableServer, SelectedServer } from '../data';
import { ShlinkHealth } from '../../api/types';
import { buildReducer, createAsyncThunk } from '../../utils/helpers/redux';
import { createAsyncThunk } from '../../utils/helpers/redux';
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
export const SELECT_SERVER = 'shlink/selectedServer/selectServer';
export const RESET_SELECTED_SERVER = 'shlink/selectedServer/resetSelectedServer';
const REDUCER_PREFIX = 'shlink/selectedServer';
export const MIN_FALLBACK_VERSION = '1.0.0';
export const MAX_FALLBACK_VERSION = '999.999.999';
export const LATEST_VERSION_CONSTRAINT = 'latest';
export type SelectServerAction = PayloadAction<SelectedServer>;
const versionToSemVer = pipe(
(version: string) => (version === LATEST_VERSION_CONSTRAINT ? MAX_FALLBACK_VERSION : version),
toSemVer(MIN_FALLBACK_VERSION),
@ -30,42 +27,39 @@ const getServerVersion = memoizeWith(
const initialState: SelectedServer = null;
export default buildReducer<SelectedServer, SelectServerAction>({
[RESET_SELECTED_SERVER]: () => initialState,
[SELECT_SERVER]: (_, { payload }) => payload,
[`${SELECT_SERVER}/fulfilled`]: (_, { payload }) => payload,
}, initialState);
export const resetSelectedServer = createAction<void>(`${REDUCER_PREFIX}/resetSelectedServer`);
export const resetSelectedServer = createAction<void>(RESET_SELECTED_SERVER);
export const selectServer = (buildShlinkApiClient: ShlinkApiClientBuilder) => createAsyncThunk(
`${REDUCER_PREFIX}/selectServer`,
async (serverId: string, { dispatch, getState }): Promise<SelectedServer> => {
dispatch(resetSelectedServer());
export const selectServer = (
buildShlinkApiClient: ShlinkApiClientBuilder,
) => createAsyncThunk(SELECT_SERVER, async (serverId: string, { dispatch, getState }): Promise<SelectedServer> => {
dispatch(resetSelectedServer());
const { servers } = getState();
const selectedServer = servers[serverId];
const { servers } = getState();
const selectedServer = servers[serverId];
if (!selectedServer) {
return { serverNotFound: true };
}
if (!selectedServer) {
return { serverNotFound: true };
}
try {
const { health } = buildShlinkApiClient(selectedServer);
const { version, printableVersion } = await getServerVersion(serverId, health);
try {
const { health } = buildShlinkApiClient(selectedServer);
const { version, printableVersion } = await getServerVersion(serverId, health);
return {
...selectedServer,
version,
printableVersion,
};
} catch (e) {
return { ...selectedServer, serverNotReachable: true };
}
},
);
return {
...selectedServer,
version,
printableVersion,
};
} catch (e) {
return { ...selectedServer, serverNotReachable: true };
}
});
type SelectServerThunk = ReturnType<typeof selectServer>;
export const selectServerListener = (
selectServerThunk: ReturnType<typeof selectServer>,
selectServerThunk: SelectServerThunk,
loadMercureInfo: () => PayloadAction<any>, // TODO Consider setting actual type, if relevant
) => {
const listener = createListenerMiddleware();
@ -79,3 +73,13 @@ export const selectServerListener = (
return listener;
};
export const selectedServerReducerCreator = (selectServerThunk: SelectServerThunk) => createSlice({
name: REDUCER_PREFIX,
initialState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(resetSelectedServer, () => initialState);
builder.addCase(selectServerThunk.fulfilled, (_, { payload }) => payload as any);
},
});

View file

@ -1,3 +1,4 @@
import { prop } from 'ramda';
import Bottle from 'bottlejs';
import { CreateServer } from '../CreateServer';
import { ServersDropdown } from '../ServersDropdown';
@ -5,7 +6,12 @@ import { DeleteServerModal } from '../DeleteServerModal';
import { DeleteServerButton } from '../DeleteServerButton';
import { EditServer } from '../EditServer';
import { ImportServersBtn } from '../helpers/ImportServersBtn';
import { resetSelectedServer, selectServer, selectServerListener } from '../reducers/selectedServer';
import {
resetSelectedServer,
selectedServerReducerCreator,
selectServer,
selectServerListener,
} from '../reducers/selectedServer';
import { createServers, deleteServer, editServer, setAutoConnect } from '../reducers/servers';
import { fetchServers } from '../reducers/remoteServers';
import { ServerError } from '../helpers/ServerError';
@ -80,6 +86,8 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
// Reducers
bottle.serviceFactory('selectServerListener', selectServerListener, 'selectServer', 'loadMercureInfo');
bottle.serviceFactory('selectedServerReducerCreator', selectedServerReducerCreator, 'selectServer');
bottle.serviceFactory('selectedServerReducer', prop('reducer'), 'selectedServerReducerCreator');
};
export default provideServices;

View file

@ -1,8 +1,9 @@
import { v4 as uuid } from 'uuid';
import { Mock } from 'ts-mockery';
import reducer, {
import {
selectServer as selectServerCreator,
resetSelectedServer,
selectedServerReducerCreator,
MAX_FALLBACK_VERSION,
MIN_FALLBACK_VERSION,
} from '../../../src/servers/reducers/selectedServer';
@ -14,6 +15,7 @@ describe('selectedServerReducer', () => {
const health = jest.fn();
const buildApiClient = jest.fn().mockReturnValue(Mock.of<ShlinkApiClient>({ health }));
const selectServer = selectServerCreator(buildApiClient);
const { reducer } = selectedServerReducerCreator(selectServer);
afterEach(jest.clearAllMocks);