From 1b7e1e2b5b864a00f81271313645f84c45466c37 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 23 Aug 2020 10:51:42 +0200 Subject: [PATCH] Tweaked server types and data --- src/container/types.ts | 3 +- src/servers/CreateServer.tsx | 4 +- src/servers/data/index.ts | 20 +++++++--- src/servers/helpers/ImportServersBtn.tsx | 4 +- .../{selectedServer.js => selectedServer.ts} | 40 ++++++++++++------- src/servers/reducers/servers.ts | 16 ++++---- src/servers/services/ServersImporter.ts | 6 +-- src/utils/services/types.ts | 9 ++++- 8 files changed, 64 insertions(+), 38 deletions(-) rename src/servers/reducers/{selectedServer.js => selectedServer.ts} (58%) diff --git a/src/container/types.ts b/src/container/types.ts index 42647c60..c8fd2ff7 100644 --- a/src/container/types.ts +++ b/src/container/types.ts @@ -1,11 +1,12 @@ import { MercureInfo } from '../mercure/reducers/mercureInfo'; import { ServersMap } from '../servers/reducers/servers'; +import { SelectedServer } from '../servers/data'; export type ConnectDecorator = (props: string[], actions?: string[]) => any; export interface ShlinkState { servers: ServersMap; - selectedServer: any; + selectedServer: SelectedServer; shortUrlsList: any; shortUrlsListParams: any; shortUrlCreationResult: any; diff --git a/src/servers/CreateServer.tsx b/src/servers/CreateServer.tsx index 2da3e601..dd140b3f 100644 --- a/src/servers/CreateServer.tsx +++ b/src/servers/CreateServer.tsx @@ -6,13 +6,13 @@ import NoMenuLayout from '../common/NoMenuLayout'; import { StateFlagTimeout } from '../utils/helpers/hooks'; import { ServerForm } from './helpers/ServerForm'; import { ImportServersBtnProps } from './helpers/ImportServersBtn'; -import { NewServerData, RegularServer } from './data'; +import { NewServerData, ServerWithId } from './data'; import './CreateServer.scss'; const SHOW_IMPORT_MSG_TIME = 4000; interface CreateServerProps extends RouterProps { - createServer: (server: RegularServer) => void; + createServer: (server: ServerWithId) => void; resetSelectedServer: Function; } diff --git a/src/servers/data/index.ts b/src/servers/data/index.ts index 448ab6c6..97ade453 100644 --- a/src/servers/data/index.ts +++ b/src/servers/data/index.ts @@ -4,15 +4,23 @@ export interface NewServerData { apiKey: string; } -export interface RegularServer extends NewServerData { +export interface ServerWithId { id: string; - version?: string; - printableVersion?: string; - serverNotReachable?: true; } -interface NotFoundServer { +export interface ReachableServer extends ServerWithId { + version: string; + printableVersion: string; +} + +export interface NonReachableServer extends ServerWithId { + serverNotReachable: true; +} + +export interface NotFoundServer { serverNotFound: true; } -export type Server = RegularServer | NotFoundServer; +export type RegularServer = ReachableServer | NonReachableServer; + +export type SelectedServer = RegularServer | NotFoundServer | null; diff --git a/src/servers/helpers/ImportServersBtn.tsx b/src/servers/helpers/ImportServersBtn.tsx index 86ba43d6..95464210 100644 --- a/src/servers/helpers/ImportServersBtn.tsx +++ b/src/servers/helpers/ImportServersBtn.tsx @@ -1,7 +1,7 @@ import React, { useRef, RefObject, ChangeEvent, MutableRefObject } from 'react'; import { UncontrolledTooltip } from 'reactstrap'; import ServersImporter from '../services/ServersImporter'; -import { Server } from '../data'; +import { NewServerData } from '../data'; type Ref = RefObject | MutableRefObject; @@ -11,7 +11,7 @@ export interface ImportServersBtnProps { } interface ImportServersBtnConnectProps extends ImportServersBtnProps { - createServers: (servers: Server[]) => void; + createServers: (servers: NewServerData[]) => void; fileRef: Ref; } diff --git a/src/servers/reducers/selectedServer.js b/src/servers/reducers/selectedServer.ts similarity index 58% rename from src/servers/reducers/selectedServer.js rename to src/servers/reducers/selectedServer.ts index 07ca284d..2848280d 100644 --- a/src/servers/reducers/selectedServer.js +++ b/src/servers/reducers/selectedServer.ts @@ -1,7 +1,11 @@ import { createAction, handleActions } from 'redux-actions'; import { identity, memoizeWith, pipe } from 'ramda'; +import { Action, Dispatch } from 'redux'; import { resetShortUrlParams } from '../../short-urls/reducers/shortUrlsListParams'; import { versionToPrintable, versionToSemVer as toSemVer } from '../../utils/helpers/version'; +import { NonReachableServer, NotFoundServer, ReachableServer, SelectedServer } from '../data'; +import { GetState } from '../../container/types'; +import { ShlinkApiClientBuilder, ShlinkHealth } from '../../utils/services/types'; /* eslint-disable padding-line-between-statements */ export const SELECT_SERVER = 'shlink/selectedServer/SELECT_SERVER'; @@ -12,22 +16,30 @@ export const MAX_FALLBACK_VERSION = '999.999.999'; export const LATEST_VERSION_CONSTRAINT = 'latest'; /* eslint-enable padding-line-between-statements */ -const initialState = null; +const initialState: SelectedServer = null; const versionToSemVer = pipe( - (version) => version === LATEST_VERSION_CONSTRAINT ? MAX_FALLBACK_VERSION : version, + (version: string) => version === LATEST_VERSION_CONSTRAINT ? MAX_FALLBACK_VERSION : version, toSemVer(MIN_FALLBACK_VERSION), ); -const getServerVersion = memoizeWith(identity, (serverId, health) => health().then(({ version }) => ({ - version: versionToSemVer(version), - printableVersion: versionToPrintable(version), -}))); +const getServerVersion = memoizeWith( + identity, + async (_serverId: string, health: () => Promise) => health().then(({ version }) => ({ + version: versionToSemVer(version), + printableVersion: versionToPrintable(version), + })), +); export const resetSelectedServer = createAction(RESET_SELECTED_SERVER); -export const selectServer = (buildShlinkApiClient, loadMercureInfo) => (serverId) => async ( - dispatch, - getState, +export const selectServer = ( + buildShlinkApiClient: ShlinkApiClientBuilder, + loadMercureInfo: () => Action, +) => ( + serverId: string, +) => async ( + dispatch: Dispatch, + getState: GetState, ) => { dispatch(resetSelectedServer()); dispatch(resetShortUrlParams()); @@ -36,7 +48,7 @@ export const selectServer = (buildShlinkApiClient, loadMercureInfo) => (serverId const selectedServer = servers[serverId]; if (!selectedServer) { - dispatch({ + dispatch({ type: SELECT_SERVER, selectedServer: { serverNotFound: true }, }); @@ -48,7 +60,7 @@ export const selectServer = (buildShlinkApiClient, loadMercureInfo) => (serverId const { health } = buildShlinkApiClient(selectedServer); const { version, printableVersion } = await getServerVersion(serverId, health); - dispatch({ + dispatch({ type: SELECT_SERVER, selectedServer: { ...selectedServer, @@ -58,14 +70,14 @@ export const selectServer = (buildShlinkApiClient, loadMercureInfo) => (serverId }); dispatch(loadMercureInfo()); } catch (e) { - dispatch({ + dispatch({ type: SELECT_SERVER, selectedServer: { ...selectedServer, serverNotReachable: true }, }); } }; -export default handleActions({ +export default handleActions({ [RESET_SELECTED_SERVER]: () => initialState, - [SELECT_SERVER]: (state, { selectedServer }) => selectedServer, + [SELECT_SERVER]: (_, { selectedServer }: any) => selectedServer, }, initialState); diff --git a/src/servers/reducers/servers.ts b/src/servers/reducers/servers.ts index 31a66085..9d97dd8c 100644 --- a/src/servers/reducers/servers.ts +++ b/src/servers/reducers/servers.ts @@ -1,7 +1,7 @@ import { handleActions } from 'redux-actions'; import { pipe, assoc, map, reduce, dissoc } from 'ramda'; import { v4 as uuid } from 'uuid'; -import { RegularServer, NewServerData } from '../data'; +import { NewServerData, ServerWithId } from '../data'; /* eslint-disable padding-line-between-statements */ export const EDIT_SERVER = 'shlink/servers/EDIT_SERVER'; @@ -9,13 +9,13 @@ export const DELETE_SERVER = 'shlink/servers/DELETE_SERVER'; export const CREATE_SERVERS = 'shlink/servers/CREATE_SERVERS'; /* eslint-enable padding-line-between-statements */ -export type ServersMap = Record; +export type ServersMap = Record; const initialState: ServersMap = {}; -const serverWithId = (server: RegularServer | NewServerData): RegularServer => { - if ((server as RegularServer).id) { - return server as RegularServer; +const serverWithId = (server: ServerWithId | NewServerData): ServerWithId => { + if ((server as ServerWithId).id) { + return server as ServerWithId; } return assoc('id', uuid(), server); @@ -29,7 +29,7 @@ export default handleActions({ : assoc(serverId, { ...state[serverId], ...serverData }, state), }, initialState); -const serversListToMap = reduce((acc, server) => assoc(server.id, server, acc), {}); +const serversListToMap = reduce((acc, server) => assoc(server.id, server, acc), {}); export const createServers = pipe( map(serverWithId), @@ -37,7 +37,7 @@ export const createServers = pipe( (newServers: ServersMap) => ({ type: CREATE_SERVERS, newServers }), ); -export const createServer = (server: RegularServer) => createServers([ server ]); +export const createServer = (server: ServerWithId) => createServers([ server ]); export const editServer = (serverId: string, serverData: Partial) => ({ type: EDIT_SERVER, @@ -45,4 +45,4 @@ export const editServer = (serverId: string, serverData: Partial) serverData, }); -export const deleteServer = ({ id }: RegularServer) => ({ type: DELETE_SERVER, serverId: id }); +export const deleteServer = ({ id }: ServerWithId) => ({ type: DELETE_SERVER, serverId: id }); diff --git a/src/servers/services/ServersImporter.ts b/src/servers/services/ServersImporter.ts index 17ab38e3..2ffe8bda 100644 --- a/src/servers/services/ServersImporter.ts +++ b/src/servers/services/ServersImporter.ts @@ -1,12 +1,12 @@ import { CsvJson } from 'csvjson'; -import { RegularServer } from '../data'; +import { NewServerData } from '../data'; const CSV_MIME_TYPE = 'text/csv'; export default class ServersImporter { public constructor(private readonly csvjson: CsvJson, private readonly fileReaderFactory: () => FileReader) {} - public importServersFromFile = async (file?: File | null): Promise => { + public importServersFromFile = async (file?: File | null): Promise => { if (!file || file.type !== CSV_MIME_TYPE) { throw new Error('No file provided or file is not a CSV'); } @@ -16,7 +16,7 @@ export default class ServersImporter { return new Promise((resolve) => { reader.addEventListener('loadend', (e: ProgressEvent) => { const content = e.target?.result?.toString() ?? ''; - const servers = this.csvjson.toObject(content); + const servers = this.csvjson.toObject(content); resolve(servers); }); diff --git a/src/utils/services/types.ts b/src/utils/services/types.ts index c5f5a474..15e3972b 100644 --- a/src/utils/services/types.ts +++ b/src/utils/services/types.ts @@ -1,11 +1,16 @@ -import { RegularServer } from '../../servers/data'; +import { ServerWithId } from '../../servers/data'; import { GetState } from '../../container/types'; import ShlinkApiClient from './ShlinkApiClient'; // FIXME Move to ShlinkApiClientBuilder -export type ShlinkApiClientBuilder = (getStateOrSelectedServer: RegularServer | GetState) => ShlinkApiClient; +export type ShlinkApiClientBuilder = (getStateOrSelectedServer: ServerWithId | GetState) => ShlinkApiClient; export interface ShlinkMercureInfo { token: string; mercureHubUrl: string; } + +export interface ShlinkHealth { + status: 'pass' | 'fail'; + version: string; +}