From cf1239cf6e2912cf1b36815d91459a7cb9c17841 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Tue, 18 Dec 2018 19:45:09 +0100 Subject: [PATCH] Moved all server-related services to its own service provider --- src/container/index.js | 62 ++++++-------------- src/servers/reducers/selectedServer.js | 7 +-- src/servers/reducers/server.js | 25 +++----- src/servers/services/provideServices.js | 47 +++++++++++++++ src/short-urls/reducers/shortUrlsList.js | 7 +-- test/servers/reducers/selectedServer.test.js | 8 +-- test/servers/reducers/server.test.js | 16 ++--- 7 files changed, 88 insertions(+), 84 deletions(-) create mode 100644 src/servers/services/provideServices.js diff --git a/src/container/index.js b/src/container/index.js index 70ba82dc..a5e8ceda 100644 --- a/src/container/index.js +++ b/src/container/index.js @@ -2,17 +2,13 @@ import Bottle from 'bottlejs'; import { withRouter } from 'react-router-dom'; import { connect as reduxConnect } from 'react-redux'; import { assoc, pick } from 'ramda'; -import csvjson from 'csvjson'; import axios from 'axios'; import App from '../App'; import ScrollToTop from '../common/ScrollToTop'; import MainHeader from '../common/MainHeader'; -import { resetSelectedServer, selectServer } from '../servers/reducers/selectedServer'; +import { resetSelectedServer } from '../servers/reducers/selectedServer'; import Home from '../common/Home'; import MenuLayout from '../common/MenuLayout'; -import { createServer, createServers, deleteServer, listServers } from '../servers/reducers/server'; -import CreateServer from '../servers/CreateServer'; -import ServersDropdown from '../servers/ServersDropdown'; import ShortUrls from '../short-urls/ShortUrls'; import SearchBar from '../short-urls/SearchBar'; import { listShortUrls } from '../short-urls/reducers/shortUrlsList'; @@ -22,14 +18,7 @@ import { ColorGenerator } from '../utils/ColorGenerator'; import { Storage } from '../utils/Storage'; import ShortUrlsRow from '../short-urls/helpers/ShortUrlsRow'; import ShortUrlsRowMenu from '../short-urls/helpers/ShortUrlsRowMenu'; -import ShlinkApiClient from '../api/ShlinkApiClient'; -import DeleteServerModal from '../servers/DeleteServerModal'; -import DeleteServerButton from '../servers/DeleteServerButton'; import AsideMenu from '../common/AsideMenu'; -import ImportServersBtn from '../servers/helpers/ImportServersBtn'; -import { ServersImporter } from '../servers/services/ServersImporter'; -import { ServersExporter } from '../servers/services/ServersExporter'; -import { ServersService } from '../servers/services/ServersService'; import CreateShortUrl from '../short-urls/CreateShortUrl'; import { createShortUrl, resetCreateShortUrl } from '../short-urls/reducers/shortUrlCreation'; import DeleteShortUrlModal from '../short-urls/helpers/DeleteShortUrlModal'; @@ -37,6 +26,7 @@ import { deleteShortUrl, resetDeleteShortUrl, shortUrlDeleted } from '../short-u import EditTagsModal from '../short-urls/helpers/EditTagsModal'; import { editShortUrlTags, resetShortUrlsTags, shortUrlTagsEdited } from '../short-urls/reducers/shortUrlTags'; import buildShlinkApiClient from '../api/ShlinkApiClientBuilder'; +import provideServersServices from '../servers/services/provideServices'; import provideVisitsServices from '../visits/services/provideServices'; import provideTagsServices from '../tags/services/provideServices'; @@ -51,13 +41,15 @@ const mapActionService = (map, actionName) => ({ }); const connect = (propsFromState, actionServiceNames) => reduxConnect( - pick(propsFromState), + propsFromState ? pick(propsFromState) : null, Array.isArray(actionServiceNames) ? actionServiceNames.reduce(mapActionService, {}) : actionServiceNames ); bottle.constant('ScrollToTop', ScrollToTop); bottle.decorator('ScrollToTop', withRouter); +bottle.serviceFactory('App', App, 'MainHeader', 'Home', 'MenuLayout', 'CreateServer'); + bottle.serviceFactory('MainHeader', MainHeader, 'ServersDropdown'); bottle.decorator('MainHeader', withRouter); @@ -73,16 +65,17 @@ bottle.serviceFactory( 'CreateShortUrl', 'ShortUrlVisits' ); -bottle.decorator('MenuLayout', connect([ 'selectedServer', 'shortUrlsListParams' ], { selectServer })); +bottle.decorator('MenuLayout', connect([ 'selectedServer', 'shortUrlsListParams' ], [ 'selectServer' ])); bottle.decorator('MenuLayout', withRouter); -bottle.serviceFactory('CreateServer', CreateServer, 'ImportServersBtn'); -bottle.decorator('CreateServer', connect([ 'selectedServer' ], { createServer, resetSelectedServer })); +bottle.serviceFactory('AsideMenu', AsideMenu, 'DeleteServerButton'); -bottle.serviceFactory('App', App, 'MainHeader', 'Home', 'MenuLayout', 'CreateServer'); +bottle.constant('localStorage', global.localStorage); +bottle.service('Storage', Storage, 'localStorage'); +bottle.service('ColorGenerator', ColorGenerator, 'Storage'); -bottle.serviceFactory('ServersDropdown', ServersDropdown, 'ServersExporter'); -bottle.decorator('ServersDropdown', connect([ 'servers', 'selectedServer' ], { listServers, selectServer })); +bottle.constant('axios', axios); +bottle.serviceFactory('buildShlinkApiClient', buildShlinkApiClient, 'axios'); bottle.serviceFactory('ShortUrls', ShortUrls, 'SearchBar', 'ShortUrlsList'); bottle.decorator('ShortUrls', reduxConnect( @@ -95,38 +88,13 @@ bottle.decorator('SearchBar', connect([ 'shortUrlsListParams' ], { listShortUrls bottle.serviceFactory('ShortUrlsList', ShortUrlsList, 'ShortUrlsRow'); bottle.decorator('ShortUrlsList', connect( [ 'selectedServer', 'shortUrlsListParams' ], - { listShortUrls, resetShortUrlParams } + [ 'listShortUrls', 'resetShortUrlParams' ] )); -bottle.constant('localStorage', global.localStorage); -bottle.service('Storage', Storage, 'localStorage'); -bottle.service('ColorGenerator', ColorGenerator, 'Storage'); - -bottle.serviceFactory('buildShlinkApiClient', buildShlinkApiClient, 'axios'); - bottle.serviceFactory('ShortUrlsRow', ShortUrlsRow, 'ShortUrlsRowMenu', 'ColorGenerator'); bottle.serviceFactory('ShortUrlsRowMenu', ShortUrlsRowMenu, 'DeleteShortUrlModal', 'EditTagsModal'); -bottle.constant('axios', axios); -bottle.service('ShlinkApiClient', ShlinkApiClient, 'axios'); - -bottle.serviceFactory('DeleteServerModal', () => DeleteServerModal); -bottle.decorator('DeleteServerModal', withRouter); -bottle.decorator('DeleteServerModal', reduxConnect(null, { deleteServer })); - -bottle.serviceFactory('DeleteServerButton', DeleteServerButton, 'DeleteServerModal'); -bottle.serviceFactory('AsideMenu', AsideMenu, 'DeleteServerButton'); - -bottle.serviceFactory('ImportServersBtn', ImportServersBtn, 'ServersImporter'); -bottle.decorator('ImportServersBtn', reduxConnect(null, { createServers })); - -bottle.constant('csvjson', csvjson); -bottle.constant('window', global.window); -bottle.service('ServersImporter', ServersImporter, 'csvjson'); -bottle.service('ServersService', ServersService, 'Storage'); -bottle.service('ServersExporter', ServersExporter, 'ServersService', 'window', 'csvjson'); - bottle.serviceFactory('CreateShortUrl', CreateShortUrl, 'TagsSelector'); bottle.decorator('CreateShortUrl', connect([ 'shortUrlCreationResult' ], { createShortUrl, @@ -149,6 +117,10 @@ bottle.serviceFactory('editShortUrlTags', editShortUrlTags, 'buildShlinkApiClien bottle.serviceFactory('resetShortUrlsTags', () => resetShortUrlsTags); bottle.serviceFactory('shortUrlTagsEdited', () => shortUrlTagsEdited); +bottle.serviceFactory('listShortUrls', listShortUrls, 'buildShlinkApiClient'); +bottle.serviceFactory('resetShortUrlParams', () => resetShortUrlParams); + +provideServersServices(bottle, connect, withRouter); provideTagsServices(bottle, connect); provideVisitsServices(bottle, connect); diff --git a/src/servers/reducers/selectedServer.js b/src/servers/reducers/selectedServer.js index d53f21c3..dfee15ec 100644 --- a/src/servers/reducers/selectedServer.js +++ b/src/servers/reducers/selectedServer.js @@ -1,4 +1,3 @@ -import serversService from '../../servers/services/ServersService'; import { resetShortUrlParams } from '../../short-urls/reducers/shortUrlsListParams'; /* eslint-disable padding-line-between-statements, newline-after-var */ @@ -21,9 +20,11 @@ export default function reducer(state = defaultState, action) { export const resetSelectedServer = () => ({ type: RESET_SELECTED_SERVER }); -export const _selectServer = (serversService) => (serverId) => (dispatch) => { +export const selectServer = (serversService) => (serverId) => (dispatch) => { dispatch(resetShortUrlParams()); + console.log('Setting server'); + const selectedServer = serversService.findServerById(serverId); dispatch({ @@ -31,5 +32,3 @@ export const _selectServer = (serversService) => (serverId) => (dispatch) => { selectedServer, }); }; - -export const selectServer = _selectServer(serversService); diff --git a/src/servers/reducers/server.js b/src/servers/reducers/server.js index cf2db109..503b303e 100644 --- a/src/servers/reducers/server.js +++ b/src/servers/reducers/server.js @@ -1,6 +1,3 @@ -import { curry } from 'ramda'; -import serversService from '../services/ServersService'; - export const FETCH_SERVERS = 'shlink/servers/FETCH_SERVERS'; export default function reducer(state = {}, action) { @@ -12,33 +9,25 @@ export default function reducer(state = {}, action) { } } -export const _listServers = (serversService) => ({ +export const listServers = (serversService) => () => ({ type: FETCH_SERVERS, servers: serversService.listServers(), }); -export const listServers = () => _listServers(serversService); - -export const _createServer = (serversService, server) => { +export const createServer = (serversService) => (server) => { serversService.createServer(server); - return _listServers(serversService); + return listServers(serversService)(); }; -export const createServer = curry(_createServer)(serversService); - -export const _deleteServer = (serversService, server) => { +export const deleteServer = (serversService) => (server) => { serversService.deleteServer(server); - return _listServers(serversService); + return listServers(serversService)(); }; -export const deleteServer = curry(_deleteServer)(serversService); - -export const _createServers = (serversService, servers) => { +export const createServers = (serversService) => (servers) => { serversService.createServers(servers); - return _listServers(serversService); + return listServers(serversService)(); }; - -export const createServers = curry(_createServers)(serversService); diff --git a/src/servers/services/provideServices.js b/src/servers/services/provideServices.js new file mode 100644 index 00000000..bbc026fc --- /dev/null +++ b/src/servers/services/provideServices.js @@ -0,0 +1,47 @@ +import csvjson from 'csvjson'; +import CreateServer from '../CreateServer'; +import ServersDropdown from '../ServersDropdown'; +import DeleteServerModal from '../DeleteServerModal'; +import DeleteServerButton from '../DeleteServerButton'; +import ImportServersBtn from '../helpers/ImportServersBtn'; +import { resetSelectedServer, selectServer } from '../reducers/selectedServer'; +import { createServer, createServers, deleteServer, listServers } from '../reducers/server'; +import { ServersImporter } from './ServersImporter'; +import { ServersService } from './ServersService'; +import { ServersExporter } from './ServersExporter'; + +const provideServices = (bottle, connect, withRouter) => { + // Components + bottle.serviceFactory('CreateServer', CreateServer, 'ImportServersBtn'); + bottle.decorator('CreateServer', connect([ 'selectedServer' ], [ 'createServer', 'resetSelectedServer' ])); + + bottle.serviceFactory('ServersDropdown', ServersDropdown, 'ServersExporter'); + bottle.decorator('ServersDropdown', connect([ 'servers', 'selectedServer' ], [ 'listServers', 'selectServer' ])); + + bottle.serviceFactory('DeleteServerModal', () => DeleteServerModal); + bottle.decorator('DeleteServerModal', withRouter); + bottle.decorator('DeleteServerModal', connect(null, [ 'deleteServer' ])); + + bottle.serviceFactory('DeleteServerButton', DeleteServerButton, 'DeleteServerModal'); + + bottle.serviceFactory('ImportServersBtn', ImportServersBtn, 'ServersImporter'); + bottle.decorator('ImportServersBtn', connect(null, [ 'createServers' ])); + + // Services + bottle.constant('csvjson', csvjson); + bottle.constant('window', global.window); + bottle.service('ServersImporter', ServersImporter, 'csvjson'); + bottle.service('ServersService', ServersService, 'Storage'); + bottle.service('ServersExporter', ServersExporter, 'ServersService', 'window', 'csvjson'); + + // Actions + bottle.serviceFactory('selectServer', selectServer, 'ServersService'); + bottle.serviceFactory('createServer', createServer, 'ServersService'); + bottle.serviceFactory('createServers', createServers, 'ServersService'); + bottle.serviceFactory('deleteServer', deleteServer, 'ServersService'); + bottle.serviceFactory('listServers', listServers, 'ServersService'); + + bottle.serviceFactory('resetSelectedServer', () => resetSelectedServer); +}; + +export default provideServices; diff --git a/src/short-urls/reducers/shortUrlsList.js b/src/short-urls/reducers/shortUrlsList.js index de1df19e..eec4983f 100644 --- a/src/short-urls/reducers/shortUrlsList.js +++ b/src/short-urls/reducers/shortUrlsList.js @@ -1,6 +1,5 @@ import { assoc, assocPath, reject } from 'ramda'; import PropTypes from 'prop-types'; -import { buildShlinkApiClientWithAxios as buildShlinkApiClient } from '../../api/ShlinkApiClientBuilder'; import { SHORT_URL_TAGS_EDITED } from './shortUrlTags'; import { SHORT_URL_DELETED } from './shortUrlDeletion'; @@ -55,10 +54,10 @@ export default function reducer(state = initialState, action) { } } -export const _listShortUrls = (buildShlinkApiClient, params = {}) => async (dispatch, getState) => { +export const listShortUrls = (buildShlinkApiClient) => (params = {}) => async (dispatch, getState) => { dispatch({ type: LIST_SHORT_URLS_START }); - const { selectedServer } = getState(); + const { selectedServer = {} } = getState(); const shlinkApiClient = buildShlinkApiClient(selectedServer); try { @@ -69,5 +68,3 @@ export const _listShortUrls = (buildShlinkApiClient, params = {}) => async (disp dispatch({ type: LIST_SHORT_URLS_ERROR, params }); } }; - -export const listShortUrls = (params = {}) => _listShortUrls(buildShlinkApiClient, params); diff --git a/test/servers/reducers/selectedServer.test.js b/test/servers/reducers/selectedServer.test.js index 2b99d5d7..2316e583 100644 --- a/test/servers/reducers/selectedServer.test.js +++ b/test/servers/reducers/selectedServer.test.js @@ -1,8 +1,8 @@ import * as sinon from 'sinon'; import reducer, { - _selectServer, - RESET_SELECTED_SERVER, + selectServer, resetSelectedServer, + RESET_SELECTED_SERVER, SELECT_SERVER, } from '../../../src/servers/reducers/selectedServer'; import { RESET_SHORT_URL_PARAMS } from '../../../src/short-urls/reducers/shortUrlsListParams'; @@ -45,7 +45,7 @@ describe('selectedServerReducer', () => { const dispatch = sinon.spy(); const expectedDispatchCalls = 2; - _selectServer(ServersServiceMock)(serverId)(dispatch); + selectServer(ServersServiceMock)(serverId)(dispatch); expect(dispatch.callCount).toEqual(expectedDispatchCalls); expect(dispatch.firstCall.calledWith({ type: RESET_SHORT_URL_PARAMS })).toEqual(true); @@ -56,7 +56,7 @@ describe('selectedServerReducer', () => { }); it('invokes dependencies', () => { - _selectServer(ServersServiceMock)(serverId)(() => {}); + selectServer(ServersServiceMock)(serverId)(() => {}); expect(ServersServiceMock.findServerById.callCount).toEqual(1); }); diff --git a/test/servers/reducers/server.test.js b/test/servers/reducers/server.test.js index 2449aba4..9e87236b 100644 --- a/test/servers/reducers/server.test.js +++ b/test/servers/reducers/server.test.js @@ -1,10 +1,10 @@ import * as sinon from 'sinon'; import { values } from 'ramda'; import reducer, { - _createServer, - _deleteServer, - _listServers, - _createServers, + createServer, + deleteServer, + listServers, + createServers, FETCH_SERVERS, } from '../../../src/servers/reducers/server'; @@ -38,7 +38,7 @@ describe('serverReducer', () => { describe('listServers', () => { it('fetches servers and returns them as part of the action', () => { - const result = _listServers(ServersServiceMock); + const result = listServers(ServersServiceMock)(); expect(result).toEqual({ type: FETCH_SERVERS, servers }); expect(ServersServiceMock.listServers.callCount).toEqual(1); @@ -51,7 +51,7 @@ describe('serverReducer', () => { describe('createServer', () => { it('adds new server and then fetches servers again', () => { const serverToCreate = { id: 'abc123' }; - const result = _createServer(ServersServiceMock, serverToCreate); + const result = createServer(ServersServiceMock)(serverToCreate); expect(result).toEqual({ type: FETCH_SERVERS, servers }); expect(ServersServiceMock.listServers.callCount).toEqual(1); @@ -65,7 +65,7 @@ describe('serverReducer', () => { describe('deleteServer', () => { it('deletes a server and then fetches servers again', () => { const serverToDelete = { id: 'abc123' }; - const result = _deleteServer(ServersServiceMock, serverToDelete); + const result = deleteServer(ServersServiceMock)(serverToDelete); expect(result).toEqual({ type: FETCH_SERVERS, servers }); expect(ServersServiceMock.listServers.callCount).toEqual(1); @@ -79,7 +79,7 @@ describe('serverReducer', () => { describe('createServer', () => { it('creates multiple servers and then fetches servers again', () => { const serversToCreate = values(servers); - const result = _createServers(ServersServiceMock, serversToCreate); + const result = createServers(ServersServiceMock)(serversToCreate); expect(result).toEqual({ type: FETCH_SERVERS, servers }); expect(ServersServiceMock.listServers.callCount).toEqual(1);