mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 09:30:31 +03:00
Enhanced edit tags action so that it calls PATCH endpoint
This commit is contained in:
parent
f653739d50
commit
d0825089d0
7 changed files with 56 additions and 15 deletions
|
@ -63,6 +63,7 @@ export default class ShlinkApiClient {
|
|||
this.performRequest(`/short-urls/${shortCode}`, 'DELETE', { domain })
|
||||
.then(() => {});
|
||||
|
||||
/* @deprecated. If using Shlink 2.6.0 or greater, use updateShortUrlMeta instead */
|
||||
public readonly updateShortUrlTags = async (
|
||||
shortCode: string,
|
||||
domain: OptionalString,
|
||||
|
@ -75,9 +76,9 @@ export default class ShlinkApiClient {
|
|||
shortCode: string,
|
||||
domain: OptionalString,
|
||||
meta: ShlinkShortUrlMeta,
|
||||
): Promise<ShlinkShortUrlMeta> =>
|
||||
this.performRequest(`/short-urls/${shortCode}`, 'PATCH', { domain }, meta)
|
||||
.then(() => meta);
|
||||
): Promise<ShortUrl> =>
|
||||
this.performRequest<ShortUrl>(`/short-urls/${shortCode}`, 'PATCH', { domain }, meta)
|
||||
.then(({ data }) => data);
|
||||
|
||||
public readonly listTags = async (): Promise<ShlinkTags> =>
|
||||
this.performRequest<{ tags: ShlinkTagsResponse }>('/tags', 'GET', { withStats: 'true' })
|
||||
|
|
|
@ -59,6 +59,7 @@ export interface ShlinkVisitsParams {
|
|||
|
||||
export interface ShlinkShortUrlMeta extends ShortUrlMeta {
|
||||
longUrl?: string;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export interface ShlinkDomain {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Action, Dispatch } from 'redux';
|
||||
import { prop } from 'ramda';
|
||||
import { buildActionCreator, buildReducer } from '../../utils/helpers/redux';
|
||||
import { GetState } from '../../container/types';
|
||||
import { OptionalString } from '../../utils/utils';
|
||||
|
@ -6,6 +7,8 @@ import { ShortUrlIdentifier } from '../data';
|
|||
import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder';
|
||||
import { ProblemDetailsError } from '../../api/types';
|
||||
import { parseApiError } from '../../api/utils';
|
||||
import { isReachableServer } from '../../servers/data';
|
||||
import { versionMatch } from '../../utils/helpers/version';
|
||||
|
||||
/* eslint-disable padding-line-between-statements */
|
||||
export const EDIT_SHORT_URL_TAGS_START = 'shlink/shortUrlTags/EDIT_SHORT_URL_TAGS_START';
|
||||
|
@ -50,10 +53,19 @@ export const editShortUrlTags = (buildShlinkApiClient: ShlinkApiClientBuilder) =
|
|||
tags: string[],
|
||||
) => async (dispatch: Dispatch, getState: GetState) => {
|
||||
dispatch({ type: EDIT_SHORT_URL_TAGS_START });
|
||||
const { updateShortUrlTags } = buildShlinkApiClient(getState);
|
||||
const { selectedServer } = getState();
|
||||
const supportsTagsInPatch = isReachableServer(selectedServer) && versionMatch(
|
||||
selectedServer.version,
|
||||
{ minVersion: '2.6.0' },
|
||||
);
|
||||
const { updateShortUrlTags, updateShortUrlMeta } = buildShlinkApiClient(getState);
|
||||
|
||||
try {
|
||||
const normalizedTags = await updateShortUrlTags(shortCode, domain, tags);
|
||||
const normalizedTags = await (
|
||||
supportsTagsInPatch
|
||||
? updateShortUrlMeta(shortCode, domain, { tags }).then(prop('tags'))
|
||||
: updateShortUrlTags(shortCode, domain, tags)
|
||||
);
|
||||
|
||||
dispatch<EditShortUrlTagsAction>({ tags: normalizedTags, shortCode, domain, type: SHORT_URL_TAGS_EDITED });
|
||||
} catch (e) {
|
||||
|
|
|
@ -3,6 +3,7 @@ import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient';
|
|||
import { OptionalString } from '../../../src/utils/utils';
|
||||
import { Mock } from 'ts-mockery';
|
||||
import { ShlinkDomain, ShlinkVisitsOverview } from '../../../src/api/types';
|
||||
import { ShortUrl } from '../../../src/short-urls/data';
|
||||
|
||||
describe('ShlinkApiClient', () => {
|
||||
const createAxios = (data: AxiosRequestConfig) => (async () => Promise.resolve(data)) as unknown as AxiosInstance;
|
||||
|
@ -139,16 +140,17 @@ describe('ShlinkApiClient', () => {
|
|||
|
||||
describe('updateShortUrlMeta', () => {
|
||||
it.each(shortCodesWithDomainCombinations)('properly updates short URL meta', async (shortCode, domain) => {
|
||||
const expectedMeta = {
|
||||
const meta = {
|
||||
maxVisits: 50,
|
||||
validSince: '2025-01-01T10:00:00+01:00',
|
||||
};
|
||||
const axiosSpy = createAxiosMock();
|
||||
const expectedResp = Mock.of<ShortUrl>()
|
||||
const axiosSpy = createAxiosMock({ data: expectedResp });
|
||||
const { updateShortUrlMeta } = new ShlinkApiClient(axiosSpy, '', '');
|
||||
|
||||
const result = await updateShortUrlMeta(shortCode, domain, expectedMeta);
|
||||
const result = await updateShortUrlMeta(shortCode, domain, meta);
|
||||
|
||||
expect(expectedMeta).toEqual(result);
|
||||
expect(expectedResp).toEqual(result);
|
||||
expect(axiosSpy).toHaveBeenCalledWith(expect.objectContaining({
|
||||
url: `/short-urls/${shortCode}`,
|
||||
method: 'PATCH',
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { shallow, ShallowWrapper } from 'enzyme';
|
||||
import { Mock } from 'ts-mockery';
|
||||
import { Modal } from 'reactstrap';
|
||||
import createEditTagsModal from '../../../src/short-urls/helpers/EditTagsModal';
|
||||
import { ShortUrl } from '../../../src/short-urls/data';
|
||||
import { ShortUrlTags } from '../../../src/short-urls/reducers/shortUrlTags';
|
||||
import { OptionalString } from '../../../src/utils/utils';
|
||||
import { Modal } from 'reactstrap';
|
||||
|
||||
describe('<EditTagsModal />', () => {
|
||||
let wrapper: ShallowWrapper;
|
||||
|
|
|
@ -9,6 +9,7 @@ import reducer, {
|
|||
EditShortUrlTagsAction,
|
||||
} from '../../../src/short-urls/reducers/shortUrlTags';
|
||||
import { ShlinkState } from '../../../src/container/types';
|
||||
import { ReachableServer, SelectedServer } from '../../../src/servers/data';
|
||||
|
||||
describe('shortUrlTagsReducer', () => {
|
||||
const tags = [ 'foo', 'bar', 'baz' ];
|
||||
|
@ -60,9 +61,10 @@ describe('shortUrlTagsReducer', () => {
|
|||
|
||||
describe('editShortUrlTags', () => {
|
||||
const updateShortUrlTags = jest.fn();
|
||||
const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrlTags });
|
||||
const updateShortUrlMeta = jest.fn();
|
||||
const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrlTags, updateShortUrlMeta });
|
||||
const dispatch = jest.fn();
|
||||
const getState = () => Mock.all<ShlinkState>();
|
||||
const buildGetState = (selectedServer?: SelectedServer) => () => Mock.of<ShlinkState>({ selectedServer });
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
@ -71,11 +73,12 @@ describe('shortUrlTagsReducer', () => {
|
|||
|
||||
updateShortUrlTags.mockResolvedValue(normalizedTags);
|
||||
|
||||
await editShortUrlTags(buildShlinkApiClient)(shortCode, domain, tags)(dispatch, getState);
|
||||
await editShortUrlTags(buildShlinkApiClient)(shortCode, domain, tags)(dispatch, buildGetState());
|
||||
|
||||
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
||||
expect(updateShortUrlTags).toHaveBeenCalledTimes(1);
|
||||
expect(updateShortUrlTags).toHaveBeenCalledWith(shortCode, domain, tags);
|
||||
expect(updateShortUrlMeta).not.toHaveBeenCalled();
|
||||
expect(dispatch).toHaveBeenCalledTimes(2);
|
||||
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_SHORT_URL_TAGS_START });
|
||||
expect(dispatch).toHaveBeenNthCalledWith(
|
||||
|
@ -84,13 +87,35 @@ describe('shortUrlTagsReducer', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('calls updateShortUrlMeta when server is version 2.6.0 or above', async () => {
|
||||
const normalizedTags = [ 'bar', 'foo' ];
|
||||
|
||||
updateShortUrlMeta.mockResolvedValue({ tags: normalizedTags });
|
||||
|
||||
await editShortUrlTags(buildShlinkApiClient)(shortCode, undefined, tags)(
|
||||
dispatch,
|
||||
buildGetState(Mock.of<ReachableServer>({ printableVersion: '', version: '2.6.0' })),
|
||||
);
|
||||
|
||||
expect(buildShlinkApiClient).toHaveBeenCalledTimes(1);
|
||||
expect(updateShortUrlMeta).toHaveBeenCalledTimes(1);
|
||||
expect(updateShortUrlMeta).toHaveBeenCalledWith(shortCode, undefined, { tags });
|
||||
expect(updateShortUrlTags).not.toHaveBeenCalled();
|
||||
expect(dispatch).toHaveBeenCalledTimes(2);
|
||||
expect(dispatch).toHaveBeenNthCalledWith(1, { type: EDIT_SHORT_URL_TAGS_START });
|
||||
expect(dispatch).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
{ type: SHORT_URL_TAGS_EDITED, tags: normalizedTags, shortCode },
|
||||
);
|
||||
});
|
||||
|
||||
it('dispatches error on failure', async () => {
|
||||
const error = new Error();
|
||||
|
||||
updateShortUrlTags.mockRejectedValue(error);
|
||||
|
||||
try {
|
||||
await editShortUrlTags(buildShlinkApiClient)(shortCode, undefined, tags)(dispatch, getState);
|
||||
await editShortUrlTags(buildShlinkApiClient)(shortCode, undefined, tags)(dispatch, buildGetState());
|
||||
} catch (e) {
|
||||
expect(e).toBe(error);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { shallow, ShallowWrapper } from 'enzyme';
|
||||
import { Marker, Popup } from 'react-leaflet';
|
||||
import { Modal } from 'reactstrap';
|
||||
import MapModal from '../../../src/visits/helpers/MapModal';
|
||||
import { CityStats } from '../../../src/visits/types';
|
||||
import { Modal } from 'reactstrap';
|
||||
|
||||
describe('<MapModal />', () => {
|
||||
let wrapper: ShallowWrapper;
|
||||
|
|
Loading…
Reference in a new issue