mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2026-03-11 18:13:47 +00:00
Removed duplicated code when building ShlinkApiClient
This commit is contained in:
@@ -20,9 +20,7 @@ const MenuLayout = (TagsList, ShortUrls, AsideMenu, CreateShortUrl, ShortUrlVisi
|
|||||||
|
|
||||||
state = { showSideBar: false };
|
state = { showSideBar: false };
|
||||||
|
|
||||||
// FIXME Shouldn't use componentWillMount, but this code has to be run before children components are rendered
|
componentDidMount() {
|
||||||
/* eslint react/no-deprecated: "off" */
|
|
||||||
componentWillMount() {
|
|
||||||
const { match, selectServer } = this.props;
|
const { match, selectServer } = this.props;
|
||||||
const { params: { serverId } } = match;
|
const { params: { serverId } } = match;
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const ShortUrlsRowMenu = (DeleteShortUrlModal, EditTagsModal) => class ShortUrls
|
|||||||
toggle = () => this.setState(({ isOpen }) => ({ isOpen: !isOpen }));
|
toggle = () => this.setState(({ isOpen }) => ({ isOpen: !isOpen }));
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { onCopyToClipboard, shortUrl, selectedServer: { id } } = this.props;
|
const { onCopyToClipboard, shortUrl, selectedServer } = this.props;
|
||||||
const completeShortUrl = shortUrl && shortUrl.shortUrl ? shortUrl.shortUrl : '';
|
const completeShortUrl = shortUrl && shortUrl.shortUrl ? shortUrl.shortUrl : '';
|
||||||
const toggleModal = (prop) => () => this.setState((prevState) => ({ [prop]: !prevState[prop] }));
|
const toggleModal = (prop) => () => this.setState((prevState) => ({ [prop]: !prevState[prop] }));
|
||||||
const toggleQrCode = toggleModal('isQrModalOpen');
|
const toggleQrCode = toggleModal('isQrModalOpen');
|
||||||
@@ -49,7 +49,7 @@ const ShortUrlsRowMenu = (DeleteShortUrlModal, EditTagsModal) => class ShortUrls
|
|||||||
<FontAwesomeIcon icon={menuIcon} />
|
<FontAwesomeIcon icon={menuIcon} />
|
||||||
</DropdownToggle>
|
</DropdownToggle>
|
||||||
<DropdownMenu right>
|
<DropdownMenu right>
|
||||||
<DropdownItem tag={Link} to={`/server/${id}/short-code/${shortUrl.shortCode}/visits`}>
|
<DropdownItem tag={Link} to={`/server/${selectedServer ? selectedServer.id : ''}/short-code/${shortUrl.shortCode}/visits`}>
|
||||||
<FontAwesomeIcon icon={pieChartIcon} /> Visit stats
|
<FontAwesomeIcon icon={pieChartIcon} /> Visit stats
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
|
|
||||||
|
|||||||
@@ -32,11 +32,10 @@ export default handleActions({
|
|||||||
export const createShortUrl = (buildShlinkApiClient) => (data) => async (dispatch, getState) => {
|
export const createShortUrl = (buildShlinkApiClient) => (data) => async (dispatch, getState) => {
|
||||||
dispatch({ type: CREATE_SHORT_URL_START });
|
dispatch({ type: CREATE_SHORT_URL_START });
|
||||||
|
|
||||||
const { selectedServer } = getState();
|
const { createShortUrl } = await buildShlinkApiClient(getState);
|
||||||
const shlinkApiClient = buildShlinkApiClient(selectedServer);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await shlinkApiClient.createShortUrl(data);
|
const result = await createShortUrl(data);
|
||||||
|
|
||||||
dispatch({ type: CREATE_SHORT_URL, result });
|
dispatch({ type: CREATE_SHORT_URL, result });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -36,8 +36,7 @@ export default handleActions({
|
|||||||
export const deleteShortUrl = (buildShlinkApiClient) => (shortCode) => async (dispatch, getState) => {
|
export const deleteShortUrl = (buildShlinkApiClient) => (shortCode) => async (dispatch, getState) => {
|
||||||
dispatch({ type: DELETE_SHORT_URL_START });
|
dispatch({ type: DELETE_SHORT_URL_START });
|
||||||
|
|
||||||
const { selectedServer } = getState();
|
const { deleteShortUrl } = await buildShlinkApiClient(getState);
|
||||||
const { deleteShortUrl } = buildShlinkApiClient(selectedServer);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await deleteShortUrl(shortCode);
|
await deleteShortUrl(shortCode);
|
||||||
|
|||||||
@@ -33,11 +33,10 @@ export default handleActions({
|
|||||||
|
|
||||||
export const editShortUrlTags = (buildShlinkApiClient) => (shortCode, tags) => async (dispatch, getState) => {
|
export const editShortUrlTags = (buildShlinkApiClient) => (shortCode, tags) => async (dispatch, getState) => {
|
||||||
dispatch({ type: EDIT_SHORT_URL_TAGS_START });
|
dispatch({ type: EDIT_SHORT_URL_TAGS_START });
|
||||||
const { selectedServer } = getState();
|
const { updateShortUrlTags } = await buildShlinkApiClient(getState);
|
||||||
const shlinkApiClient = buildShlinkApiClient(selectedServer);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const normalizedTags = await shlinkApiClient.updateShortUrlTags(shortCode, tags);
|
const normalizedTags = await updateShortUrlTags(shortCode, tags);
|
||||||
|
|
||||||
dispatch({ tags: normalizedTags, shortCode, type: EDIT_SHORT_URL_TAGS });
|
dispatch({ tags: normalizedTags, shortCode, type: EDIT_SHORT_URL_TAGS });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -45,8 +45,7 @@ export default handleActions({
|
|||||||
export const listShortUrls = (buildShlinkApiClient) => (params = {}) => async (dispatch, getState) => {
|
export const listShortUrls = (buildShlinkApiClient) => (params = {}) => async (dispatch, getState) => {
|
||||||
dispatch({ type: LIST_SHORT_URLS_START });
|
dispatch({ type: LIST_SHORT_URLS_START });
|
||||||
|
|
||||||
const { selectedServer = {} } = getState();
|
const { listShortUrls } = await buildShlinkApiClient(getState);
|
||||||
const { listShortUrls } = buildShlinkApiClient(selectedServer);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const shortUrls = await listShortUrls(params);
|
const shortUrls = await listShortUrls(params);
|
||||||
|
|||||||
@@ -27,11 +27,10 @@ export default handleActions({
|
|||||||
export const deleteTag = (buildShlinkApiClient) => (tag) => async (dispatch, getState) => {
|
export const deleteTag = (buildShlinkApiClient) => (tag) => async (dispatch, getState) => {
|
||||||
dispatch({ type: DELETE_TAG_START });
|
dispatch({ type: DELETE_TAG_START });
|
||||||
|
|
||||||
const { selectedServer } = getState();
|
const { deleteTags } = await buildShlinkApiClient(getState);
|
||||||
const shlinkApiClient = buildShlinkApiClient(selectedServer);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await shlinkApiClient.deleteTags([ tag ]);
|
await deleteTags([ tag ]);
|
||||||
dispatch({ type: DELETE_TAG });
|
dispatch({ type: DELETE_TAG });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dispatch({ type: DELETE_TAG_ERROR });
|
dispatch({ type: DELETE_TAG_ERROR });
|
||||||
|
|||||||
@@ -32,11 +32,10 @@ export const editTag = (buildShlinkApiClient, colorGenerator) => (oldName, newNa
|
|||||||
) => {
|
) => {
|
||||||
dispatch({ type: EDIT_TAG_START });
|
dispatch({ type: EDIT_TAG_START });
|
||||||
|
|
||||||
const { selectedServer } = getState();
|
const { editTag } = await buildShlinkApiClient(getState);
|
||||||
const shlinkApiClient = buildShlinkApiClient(selectedServer);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await shlinkApiClient.editTag(oldName, newName);
|
await editTag(oldName, newName);
|
||||||
colorGenerator.setColorForKey(newName, color);
|
colorGenerator.setColorForKey(newName, color);
|
||||||
dispatch({ type: EDIT_TAG, oldName, newName });
|
dispatch({ type: EDIT_TAG, oldName, newName });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { handleActions } from 'redux-actions';
|
import { handleActions } from 'redux-actions';
|
||||||
import { isEmpty, reject } from 'ramda';
|
import { isEmpty, reject } from 'ramda';
|
||||||
import { buildShlinkApiClientWithAxios as buildShlinkApiClient } from '../../utils/services/ShlinkApiClientBuilder';
|
|
||||||
import { TAG_DELETED } from './tagDelete';
|
import { TAG_DELETED } from './tagDelete';
|
||||||
import { TAG_EDITED } from './tagEdit';
|
import { TAG_EDITED } from './tagEdit';
|
||||||
|
|
||||||
@@ -41,8 +40,8 @@ export default handleActions({
|
|||||||
}),
|
}),
|
||||||
}, initialState);
|
}, initialState);
|
||||||
|
|
||||||
export const _listTags = (buildShlinkApiClient, force = false) => async (dispatch, getState) => {
|
export const listTags = (buildShlinkApiClient, force = true) => () => async (dispatch, getState) => {
|
||||||
const { tagsList, selectedServer } = getState();
|
const { tagsList } = getState();
|
||||||
|
|
||||||
if (!force && (tagsList.loading || !isEmpty(tagsList.tags))) {
|
if (!force && (tagsList.loading || !isEmpty(tagsList.tags))) {
|
||||||
return;
|
return;
|
||||||
@@ -51,8 +50,8 @@ export const _listTags = (buildShlinkApiClient, force = false) => async (dispatc
|
|||||||
dispatch({ type: LIST_TAGS_START });
|
dispatch({ type: LIST_TAGS_START });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const shlinkApiClient = buildShlinkApiClient(selectedServer);
|
const { listTags } = await buildShlinkApiClient(getState);
|
||||||
const tags = await shlinkApiClient.listTags();
|
const tags = await listTags();
|
||||||
|
|
||||||
dispatch({ tags, type: LIST_TAGS });
|
dispatch({ tags, type: LIST_TAGS });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -60,10 +59,6 @@ export const _listTags = (buildShlinkApiClient, force = false) => async (dispatc
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const listTags = () => _listTags(buildShlinkApiClient);
|
|
||||||
|
|
||||||
export const forceListTags = () => _listTags(buildShlinkApiClient, true);
|
|
||||||
|
|
||||||
export const filterTags = (searchTerm) => ({
|
export const filterTags = (searchTerm) => ({
|
||||||
type: FILTER_TAGS,
|
type: FILTER_TAGS,
|
||||||
searchTerm,
|
searchTerm,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import TagCard from '../TagCard';
|
|||||||
import DeleteTagConfirmModal from '../helpers/DeleteTagConfirmModal';
|
import DeleteTagConfirmModal from '../helpers/DeleteTagConfirmModal';
|
||||||
import EditTagModal from '../helpers/EditTagModal';
|
import EditTagModal from '../helpers/EditTagModal';
|
||||||
import TagsList from '../TagsList';
|
import TagsList from '../TagsList';
|
||||||
import { filterTags, forceListTags, listTags } from '../reducers/tagsList';
|
import { filterTags, listTags } from '../reducers/tagsList';
|
||||||
import { deleteTag, tagDeleted } from '../reducers/tagDelete';
|
import { deleteTag, tagDeleted } from '../reducers/tagDelete';
|
||||||
import { editTag, tagEdited } from '../reducers/tagEdit';
|
import { editTag, tagEdited } from '../reducers/tagEdit';
|
||||||
|
|
||||||
@@ -24,9 +24,11 @@ const provideServices = (bottle, connect) => {
|
|||||||
bottle.decorator('TagsList', connect([ 'tagsList' ], [ 'forceListTags', 'filterTags' ]));
|
bottle.decorator('TagsList', connect([ 'tagsList' ], [ 'forceListTags', 'filterTags' ]));
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
|
const listTagsActionFactory = (force) => ({ buildShlinkApiClient }) => listTags(buildShlinkApiClient, force);
|
||||||
|
|
||||||
|
bottle.factory('listTags', listTagsActionFactory(false));
|
||||||
|
bottle.factory('forceListTags', listTagsActionFactory(true));
|
||||||
bottle.serviceFactory('filterTags', () => filterTags);
|
bottle.serviceFactory('filterTags', () => filterTags);
|
||||||
bottle.serviceFactory('forceListTags', () => forceListTags);
|
|
||||||
bottle.serviceFactory('listTags', () => listTags);
|
|
||||||
bottle.serviceFactory('tagDeleted', () => tagDeleted);
|
bottle.serviceFactory('tagDeleted', () => tagDeleted);
|
||||||
bottle.serviceFactory('tagEdited', () => tagEdited);
|
bottle.serviceFactory('tagEdited', () => tagEdited);
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,20 @@
|
|||||||
import * as axios from 'axios';
|
import { wait } from '../utils';
|
||||||
import ShlinkApiClient from './ShlinkApiClient';
|
import ShlinkApiClient from './ShlinkApiClient';
|
||||||
|
|
||||||
const apiClients = {};
|
const apiClients = {};
|
||||||
|
|
||||||
const buildShlinkApiClient = (axios) => ({ url, apiKey }) => {
|
const getSelectedServerFromState = async (getState) => {
|
||||||
|
const { selectedServer } = getState();
|
||||||
|
|
||||||
|
if (!selectedServer) {
|
||||||
|
return wait(250).then(() => getSelectedServerFromState(getState));
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedServer;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildShlinkApiClient = (axios) => async (getState) => {
|
||||||
|
const { url, apiKey } = await getSelectedServerFromState(getState);
|
||||||
const clientKey = `${url}_${apiKey}`;
|
const clientKey = `${url}_${apiKey}`;
|
||||||
|
|
||||||
if (!apiClients[clientKey]) {
|
if (!apiClients[clientKey]) {
|
||||||
@@ -14,5 +25,3 @@ const buildShlinkApiClient = (axios) => ({ url, apiKey }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default buildShlinkApiClient;
|
export default buildShlinkApiClient;
|
||||||
|
|
||||||
export const buildShlinkApiClientWithAxios = buildShlinkApiClient(axios);
|
|
||||||
|
|||||||
@@ -51,3 +51,5 @@ export const useToggle = (initialValue = false) => {
|
|||||||
|
|
||||||
return [ flag, () => setFlag(!flag) ];
|
return [ flag, () => setFlag(!flag) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const wait = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds));
|
||||||
|
|||||||
@@ -29,11 +29,10 @@ export default handleActions({
|
|||||||
export const getShortUrlDetail = (buildShlinkApiClient) => (shortCode) => async (dispatch, getState) => {
|
export const getShortUrlDetail = (buildShlinkApiClient) => (shortCode) => async (dispatch, getState) => {
|
||||||
dispatch({ type: GET_SHORT_URL_DETAIL_START });
|
dispatch({ type: GET_SHORT_URL_DETAIL_START });
|
||||||
|
|
||||||
const { selectedServer } = getState();
|
const { getShortUrl } = await buildShlinkApiClient(getState);
|
||||||
const shlinkApiClient = buildShlinkApiClient(selectedServer);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const shortUrl = await shlinkApiClient.getShortUrl(shortCode);
|
const shortUrl = await getShortUrl(shortCode);
|
||||||
|
|
||||||
dispatch({ shortUrl, type: GET_SHORT_URL_DETAIL });
|
dispatch({ shortUrl, type: GET_SHORT_URL_DETAIL });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -52,8 +52,7 @@ export default handleActions({
|
|||||||
export const getShortUrlVisits = (buildShlinkApiClient) => (shortCode, dates) => async (dispatch, getState) => {
|
export const getShortUrlVisits = (buildShlinkApiClient) => (shortCode, dates) => async (dispatch, getState) => {
|
||||||
dispatch({ type: GET_SHORT_URL_VISITS_START });
|
dispatch({ type: GET_SHORT_URL_VISITS_START });
|
||||||
|
|
||||||
const { selectedServer } = getState();
|
const { getShortUrlVisits } = await buildShlinkApiClient(getState);
|
||||||
const { getShortUrlVisits } = buildShlinkApiClient(selectedServer);
|
|
||||||
const itemsPerPage = 5000;
|
const itemsPerPage = 5000;
|
||||||
const isLastPage = ({ currentPage, pagesCount }) => currentPage >= pagesCount;
|
const isLastPage = ({ currentPage, pagesCount }) => currentPage >= pagesCount;
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,33 @@
|
|||||||
import buildShlinkApiClient from '../../../src/utils/services/ShlinkApiClientBuilder';
|
import buildShlinkApiClient from '../../../src/utils/services/ShlinkApiClientBuilder';
|
||||||
|
|
||||||
describe('ShlinkApiClientBuilder', () => {
|
describe('ShlinkApiClientBuilder', () => {
|
||||||
const builder = buildShlinkApiClient({});
|
const createBuilder = () => {
|
||||||
|
const builder = buildShlinkApiClient({});
|
||||||
|
|
||||||
it('creates new instances when provided params are different', () => {
|
return (selectedServer) => builder(() => ({ selectedServer }));
|
||||||
const firstApiClient = builder({ url: 'foo', apiKey: 'bar' });
|
};
|
||||||
const secondApiClient = builder({ url: 'bar', apiKey: 'bar' });
|
|
||||||
const thirdApiClient = builder({ url: 'bar', apiKey: 'foo' });
|
it('creates new instances when provided params are different', async () => {
|
||||||
|
const builder = createBuilder();
|
||||||
|
const [ firstApiClient, secondApiClient, thirdApiClient ] = await Promise.all([
|
||||||
|
builder({ url: 'foo', apiKey: 'bar' }),
|
||||||
|
builder({ url: 'bar', apiKey: 'bar' }),
|
||||||
|
builder({ url: 'bar', apiKey: 'foo' }),
|
||||||
|
]);
|
||||||
|
|
||||||
expect(firstApiClient).not.toBe(secondApiClient);
|
expect(firstApiClient).not.toBe(secondApiClient);
|
||||||
expect(firstApiClient).not.toBe(thirdApiClient);
|
expect(firstApiClient).not.toBe(thirdApiClient);
|
||||||
expect(secondApiClient).not.toBe(thirdApiClient);
|
expect(secondApiClient).not.toBe(thirdApiClient);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns existing instances when provided params are the same', () => {
|
it('returns existing instances when provided params are the same', async () => {
|
||||||
const params = { url: 'foo', apiKey: 'bar' };
|
const builder = createBuilder();
|
||||||
const firstApiClient = builder(params);
|
const selectedServer = { url: 'foo', apiKey: 'bar' };
|
||||||
const secondApiClient = builder(params);
|
const [ firstApiClient, secondApiClient, thirdApiClient ] = await Promise.all([
|
||||||
const thirdApiClient = builder(params);
|
builder(selectedServer),
|
||||||
|
builder(selectedServer),
|
||||||
|
builder(selectedServer),
|
||||||
|
]);
|
||||||
|
|
||||||
expect(firstApiClient).toBe(secondApiClient);
|
expect(firstApiClient).toBe(secondApiClient);
|
||||||
expect(firstApiClient).toBe(thirdApiClient);
|
expect(firstApiClient).toBe(thirdApiClient);
|
||||||
|
|||||||
Reference in New Issue
Block a user