From 4120d0922015c07aa2ebb85aa123173b1d7be49a Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sat, 5 Oct 2019 10:20:33 +0200 Subject: [PATCH] Loaded version of selected server and created component to filter content based on that version --- package-lock.json | 5 ++++ package.json | 1 + src/servers/reducers/selectedServer.js | 9 +++++-- src/servers/services/provideServices.js | 2 +- src/short-urls/CreateShortUrl.js | 28 +++++++++++++------- src/short-urls/UseExistingIfFoundInfoIcon.js | 4 +-- src/short-urls/services/provideServices.js | 2 +- src/utils/ForVersion.js | 19 +++++++++++++ src/utils/services/ShlinkApiClient.js | 2 ++ src/utils/services/ShlinkApiClientBuilder.js | 6 +++-- test/servers/reducers/selectedServer.test.js | 14 +++++++--- 11 files changed, 71 insertions(+), 21 deletions(-) create mode 100644 src/utils/ForVersion.js diff --git a/package-lock.json b/package-lock.json index 1aad2d52..d0b8d605 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4951,6 +4951,11 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "compare-versions": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.5.1.tgz", + "integrity": "sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg==" + }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz", diff --git a/package.json b/package.json index 09dc06f4..e7195a3d 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "bottlejs": "^1.7.1", "chart.js": "^2.7.2", "classnames": "^2.2.6", + "compare-versions": "^3.5.1", "csvjson": "^5.1.0", "leaflet": "^1.4.0", "moment": "^2.22.2", diff --git a/src/servers/reducers/selectedServer.js b/src/servers/reducers/selectedServer.js index bd14e80f..cef75410 100644 --- a/src/servers/reducers/selectedServer.js +++ b/src/servers/reducers/selectedServer.js @@ -10,14 +10,19 @@ const initialState = null; export const resetSelectedServer = createAction(RESET_SELECTED_SERVER); -export const selectServer = ({ findServerById }) => (serverId) => (dispatch) => { +export const selectServer = ({ findServerById }, buildShlinkApiClient) => (serverId) => async (dispatch) => { dispatch(resetShortUrlParams()); const selectedServer = findServerById(serverId); + const { health } = await buildShlinkApiClient(selectedServer); + const { version } = await health(); dispatch({ type: SELECT_SERVER, - selectedServer, + selectedServer: { + ...selectedServer, + version, + }, }); }; diff --git a/src/servers/services/provideServices.js b/src/servers/services/provideServices.js index 0b135491..12755474 100644 --- a/src/servers/services/provideServices.js +++ b/src/servers/services/provideServices.js @@ -34,7 +34,7 @@ const provideServices = (bottle, connect, withRouter) => { bottle.service('ServersExporter', ServersExporter, 'ServersService', 'window', 'csvjson'); // Actions - bottle.serviceFactory('selectServer', selectServer, 'ServersService'); + bottle.serviceFactory('selectServer', selectServer, 'ServersService', 'buildShlinkApiClient'); bottle.serviceFactory('createServer', createServer, 'ServersService', 'listServers'); bottle.serviceFactory('createServers', createServers, 'ServersService', 'listServers'); bottle.serviceFactory('deleteServer', deleteServer, 'ServersService', 'listServers'); diff --git a/src/short-urls/CreateShortUrl.js b/src/short-urls/CreateShortUrl.js index 84ab63b9..4a2aa168 100644 --- a/src/short-urls/CreateShortUrl.js +++ b/src/short-urls/CreateShortUrl.js @@ -6,6 +6,8 @@ import { Collapse } from 'reactstrap'; import * as PropTypes from 'prop-types'; import DateInput from '../utils/DateInput'; import Checkbox from '../utils/Checkbox'; +import ForVersion from '../utils/ForVersion'; +import { serverType } from '../servers/prop-types'; import { createShortUrlResultType } from './reducers/shortUrlCreation'; import UseExistingIfFoundInfoIcon from './UseExistingIfFoundInfoIcon'; @@ -17,6 +19,7 @@ const CreateShortUrl = (TagsSelector, CreateShortUrlResult) => class CreateShort createShortUrl: PropTypes.func, shortUrlCreationResult: createShortUrlResultType, resetCreateShortUrl: PropTypes.func, + selectedServer: serverType, }; state = { @@ -108,16 +111,21 @@ const CreateShortUrl = (TagsSelector, CreateShortUrlResult) => class CreateShort -
- this.setState({ findIfExists })} - > - Use existing URL if found - - -
+ +
+ this.setState({ findIfExists })} + > + Use existing URL if found + + +
+
diff --git a/src/short-urls/UseExistingIfFoundInfoIcon.js b/src/short-urls/UseExistingIfFoundInfoIcon.js index d91b0e24..851f04a5 100644 --- a/src/short-urls/UseExistingIfFoundInfoIcon.js +++ b/src/short-urls/UseExistingIfFoundInfoIcon.js @@ -23,8 +23,8 @@ const renderInfoModal = (isOpen, toggle) => ( if none is found.
  • - When long URL and custom slug are provided: Same as in previous case, but it will try to match the short URL - using both the long URL and the slug. + When long URL and custom slug and/or domain are provided: Same as in previous case, but it will try to match + the short URL using both the long URL and the slug, the long URL and the domain, or the three of them.
    If the slug is being used by another long URL, an error will be returned.
  • diff --git a/src/short-urls/services/provideServices.js b/src/short-urls/services/provideServices.js index 05518828..c0fe583b 100644 --- a/src/short-urls/services/provideServices.js +++ b/src/short-urls/services/provideServices.js @@ -39,7 +39,7 @@ const provideServices = (bottle, connect) => { bottle.serviceFactory('CreateShortUrl', CreateShortUrl, 'TagsSelector', 'CreateShortUrlResult'); bottle.decorator( 'CreateShortUrl', - connect([ 'shortUrlCreationResult' ], [ 'createShortUrl', 'resetCreateShortUrl' ]) + connect([ 'shortUrlCreationResult', 'selectedServer' ], [ 'createShortUrl', 'resetCreateShortUrl' ]) ); bottle.serviceFactory('DeleteShortUrlModal', () => DeleteShortUrlModal); diff --git a/src/utils/ForVersion.js b/src/utils/ForVersion.js new file mode 100644 index 00000000..10f9befa --- /dev/null +++ b/src/utils/ForVersion.js @@ -0,0 +1,19 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { compare } from 'compare-versions'; +import { isEmpty } from 'ramda'; + +const propTypes = { + minVersion: PropTypes.string.isRequired, + currentServerVersion: PropTypes.string.isRequired, + children: PropTypes.node.isRequired, +}; + +const ForVersion = ({ minVersion, currentServerVersion, children }) => + isEmpty(currentServerVersion) || compare(minVersion, currentServerVersion, '>') + ? null + : {children}; + +ForVersion.propTypes = propTypes; + +export default ForVersion; diff --git a/src/utils/services/ShlinkApiClient.js b/src/utils/services/ShlinkApiClient.js index 42d27512..2884b721 100644 --- a/src/utils/services/ShlinkApiClient.js +++ b/src/utils/services/ShlinkApiClient.js @@ -50,6 +50,8 @@ export default class ShlinkApiClient { this._performRequest('/tags', 'PUT', {}, { oldName, newName }) .then(() => ({ oldName, newName })); + health = () => this._performRequest('/health', 'GET').then((resp) => resp.data); + _performRequest = async (url, method = 'GET', query = {}, body = {}) => await this.axios({ method, diff --git a/src/utils/services/ShlinkApiClientBuilder.js b/src/utils/services/ShlinkApiClientBuilder.js index c239bbc6..be170789 100644 --- a/src/utils/services/ShlinkApiClientBuilder.js +++ b/src/utils/services/ShlinkApiClientBuilder.js @@ -13,8 +13,10 @@ const getSelectedServerFromState = async (getState) => { return selectedServer; }; -const buildShlinkApiClient = (axios) => async (getState) => { - const { url, apiKey } = await getSelectedServerFromState(getState); +const buildShlinkApiClient = (axios) => async (getStateOrSelectedServer) => { + const { url, apiKey } = typeof getStateOrSelectedServer === 'function' + ? await getSelectedServerFromState(getStateOrSelectedServer) + : getStateOrSelectedServer; const clientKey = `${url}_${apiKey}`; if (!apiClients[clientKey]) { diff --git a/test/servers/reducers/selectedServer.test.js b/test/servers/reducers/selectedServer.test.js index dcab78e6..63f2d87a 100644 --- a/test/servers/reducers/selectedServer.test.js +++ b/test/servers/reducers/selectedServer.test.js @@ -29,22 +29,30 @@ describe('selectedServerReducer', () => { const selectedServer = { id: serverId, }; + const version = '1.19.0'; const ServersServiceMock = { findServerById: jest.fn(() => selectedServer), }; + const apiClientMock = { + health: jest.fn().mockResolvedValue({ version }), + }; afterEach(() => { ServersServiceMock.findServerById.mockClear(); }); - it('dispatches proper actions', () => { + it('dispatches proper actions', async () => { const dispatch = jest.fn(); + const expectedSelectedServer = { + ...selectedServer, + version, + }; - selectServer(ServersServiceMock)(serverId)(dispatch); + await selectServer(ServersServiceMock, async () => apiClientMock)(serverId)(dispatch); expect(dispatch).toHaveBeenCalledTimes(2); expect(dispatch).toHaveBeenNthCalledWith(1, { type: RESET_SHORT_URL_PARAMS }); - expect(dispatch).toHaveBeenNthCalledWith(2, { type: SELECT_SERVER, selectedServer }); + expect(dispatch).toHaveBeenNthCalledWith(2, { type: SELECT_SERVER, selectedServer: expectedSelectedServer }); }); it('invokes dependencies', () => {