From 9518ad9bb407bb069065affbc55c3a4c3ec2800d Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 1 May 2022 10:30:51 +0200 Subject: [PATCH 1/5] Dropped support to send tags to the PATCH endpoint --- src/api/services/ShlinkApiClient.ts | 11 --------- src/short-urls/reducers/shortUrlEdition.ts | 10 ++------ src/utils/helpers/features.ts | 1 - test/api/services/ShlinkApiClient.test.ts | 19 --------------- .../reducers/shortUrlEdition.test.ts | 24 ++----------------- 5 files changed, 4 insertions(+), 61 deletions(-) diff --git a/src/api/services/ShlinkApiClient.ts b/src/api/services/ShlinkApiClient.ts index 552254e9..54682e06 100644 --- a/src/api/services/ShlinkApiClient.ts +++ b/src/api/services/ShlinkApiClient.ts @@ -80,17 +80,6 @@ export default class ShlinkApiClient { this.performRequest(`/short-urls/${shortCode}`, 'DELETE', { domain }) .then(() => {}); - /** - * @deprecated. If using Shlink 2.6.0 or greater, use updateShortUrl instead - */ - public readonly updateShortUrlTags = async ( - shortCode: string, - domain: OptionalString, - tags: string[], - ): Promise => - this.performRequest<{ tags: string[] }>(`/short-urls/${shortCode}/tags`, 'PUT', { domain }, { tags }) - .then(({ data }) => data.tags); - public readonly updateShortUrl = async ( shortCode: string, domain: OptionalString, diff --git a/src/short-urls/reducers/shortUrlEdition.ts b/src/short-urls/reducers/shortUrlEdition.ts index 2fdb5d92..6c530695 100644 --- a/src/short-urls/reducers/shortUrlEdition.ts +++ b/src/short-urls/reducers/shortUrlEdition.ts @@ -6,7 +6,6 @@ import { EditShortUrlData, ShortUrl } from '../data'; import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; import { ProblemDetailsError } from '../../api/types'; import { parseApiError } from '../../api/utils'; -import { supportsTagsInPatch } from '../../utils/helpers/features'; import { ApiErrorAction } from '../../api/types/actions'; export const EDIT_SHORT_URL_START = 'shlink/shortUrlEdition/EDIT_SHORT_URL_START'; @@ -42,15 +41,10 @@ export const editShortUrl = (buildShlinkApiClient: ShlinkApiClientBuilder) => ( ) => async (dispatch: Dispatch, getState: GetState) => { dispatch({ type: EDIT_SHORT_URL_START }); - const { selectedServer } = getState(); - const sendTagsSeparately = !supportsTagsInPatch(selectedServer); - const { updateShortUrl, updateShortUrlTags } = buildShlinkApiClient(getState); + const { updateShortUrl } = buildShlinkApiClient(getState); try { - const [shortUrl] = await Promise.all([ - updateShortUrl(shortCode, domain, data as any), // FIXME Parse dates - sendTagsSeparately && data.tags ? updateShortUrlTags(shortCode, domain, data.tags) : undefined, - ]); + const shortUrl = await updateShortUrl(shortCode, domain, data as any); // FIXME parse dates; dispatch({ shortUrl, type: SHORT_URL_EDITED }); } catch (e: any) { diff --git a/src/utils/helpers/features.ts b/src/utils/helpers/features.ts index 6f8f7810..54a26c7d 100644 --- a/src/utils/helpers/features.ts +++ b/src/utils/helpers/features.ts @@ -8,7 +8,6 @@ export const supportsQrCodeSizeInQuery = serverMatchesVersions({ minVersion: '2. export const supportsShortUrlTitle = serverMatchesVersions({ minVersion: '2.6.0' }); export const supportsOrphanVisits = supportsShortUrlTitle; export const supportsQrCodeMargin = supportsShortUrlTitle; -export const supportsTagsInPatch = supportsShortUrlTitle; export const supportsBotVisits = serverMatchesVersions({ minVersion: '2.7.0' }); export const supportsCrawlableVisits = supportsBotVisits; export const supportsQrErrorCorrection = serverMatchesVersions({ minVersion: '2.8.0' }); diff --git a/test/api/services/ShlinkApiClient.test.ts b/test/api/services/ShlinkApiClient.test.ts index 88bab25f..91153fb4 100644 --- a/test/api/services/ShlinkApiClient.test.ts +++ b/test/api/services/ShlinkApiClient.test.ts @@ -156,25 +156,6 @@ describe('ShlinkApiClient', () => { }); }); - describe('updateShortUrlTags', () => { - it.each(shortCodesWithDomainCombinations)('properly updates short URL tags', async (shortCode, domain) => { - const expectedTags = ['foo', 'bar']; - const axiosSpy = createAxiosMock({ - data: { tags: expectedTags }, - }); - const { updateShortUrlTags } = new ShlinkApiClient(axiosSpy, '', ''); - - const result = await updateShortUrlTags(shortCode, domain, expectedTags); - - expect(expectedTags).toEqual(result); - expect(axiosSpy).toHaveBeenCalledWith(expect.objectContaining({ - url: `/short-urls/${shortCode}/tags`, - method: 'PUT', - params: domain ? { domain } : {}, - })); - }); - }); - describe('updateShortUrl', () => { it.each(shortCodesWithDomainCombinations)('properly updates short URL meta', async (shortCode, domain) => { const meta = { diff --git a/test/short-urls/reducers/shortUrlEdition.test.ts b/test/short-urls/reducers/shortUrlEdition.test.ts index 364a32e9..313d7556 100644 --- a/test/short-urls/reducers/shortUrlEdition.test.ts +++ b/test/short-urls/reducers/shortUrlEdition.test.ts @@ -8,7 +8,7 @@ import reducer, { } from '../../../src/short-urls/reducers/shortUrlEdition'; import { ShlinkState } from '../../../src/container/types'; import { ShortUrl } from '../../../src/short-urls/data'; -import { ReachableServer, SelectedServer } from '../../../src/servers/data'; +import { SelectedServer } from '../../../src/servers/data'; describe('shortUrlEditionReducer', () => { const longUrl = 'https://shlink.io'; @@ -41,8 +41,7 @@ describe('shortUrlEditionReducer', () => { describe('editShortUrl', () => { const updateShortUrl = jest.fn().mockResolvedValue(shortUrl); - const updateShortUrlTags = jest.fn().mockResolvedValue([]); - const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrl, updateShortUrlTags }); + const buildShlinkApiClient = jest.fn().mockReturnValue({ updateShortUrl }); const dispatch = jest.fn(); const createGetState = (selectedServer: SelectedServer = null) => () => Mock.of({ selectedServer }); @@ -59,25 +58,6 @@ describe('shortUrlEditionReducer', () => { expect(dispatch).toHaveBeenNthCalledWith(2, { type: SHORT_URL_EDITED, shortUrl }); }); - it.each([ - [null, { tags: ['foo', 'bar'] }, 1], - [null, {}, 0], - [Mock.of({ version: '2.6.0' }), {}, 0], - [Mock.of({ version: '2.6.0' }), { tags: ['foo', 'bar'] }, 0], - [Mock.of({ version: '2.5.0' }), {}, 0], - [Mock.of({ version: '2.5.0' }), { tags: ['foo', 'bar'] }, 1], - ])( - 'sends tags separately when appropriate, based on selected server and the payload', - async (server, payload, expectedTagsCalls) => { - const getState = createGetState(server); - - await editShortUrl(buildShlinkApiClient)(shortCode, null, payload)(dispatch, getState); - - expect(updateShortUrl).toHaveBeenCalled(); - expect(updateShortUrlTags).toHaveBeenCalledTimes(expectedTagsCalls); - }, - ); - it('dispatches error on failure', async () => { const error = new Error(); From a949ec9e8e774242593515a8be2b920a364deb40 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 1 May 2022 10:44:12 +0200 Subject: [PATCH 2/5] Removed checks for QR code features that were not supported on versions older than 2.6 --- src/short-urls/helpers/QrCodeModal.tsx | 38 +++++++---------- src/utils/helpers/features.ts | 2 - src/utils/helpers/qrCodes.ts | 10 ++--- test/utils/helpers/qrCodes.test.ts | 56 ++++++-------------------- 4 files changed, 32 insertions(+), 74 deletions(-) diff --git a/src/short-urls/helpers/QrCodeModal.tsx b/src/short-urls/helpers/QrCodeModal.tsx index 081925e1..a16d6654 100644 --- a/src/short-urls/helpers/QrCodeModal.tsx +++ b/src/short-urls/helpers/QrCodeModal.tsx @@ -7,11 +7,7 @@ import { ShortUrlModalProps } from '../data'; import { SelectedServer } from '../../servers/data'; import { CopyToClipboardIcon } from '../../utils/CopyToClipboardIcon'; import { buildQrCodeUrl, QrCodeCapabilities, QrCodeFormat, QrErrorCorrection } from '../../utils/helpers/qrCodes'; -import { - supportsQrCodeSizeInQuery, - supportsQrCodeMargin, - supportsQrErrorCorrection, -} from '../../utils/helpers/features'; +import { supportsQrErrorCorrection } from '../../utils/helpers/features'; import { ImageDownloader } from '../../common/services/ImageDownloader'; import { ForServerVersionProps } from '../../servers/helpers/ForServerVersion'; import { QrFormatDropdown } from './qr-codes/QrFormatDropdown'; @@ -30,11 +26,9 @@ const QrCodeModal = (imageDownloader: ImageDownloader, ForServerVersion: FC('png'); const [errorCorrection, setErrorCorrection] = useState('L'); const capabilities: QrCodeCapabilities = useMemo(() => ({ - useSizeInPath: !supportsQrCodeSizeInQuery(selectedServer), - marginIsSupported: supportsQrCodeMargin(selectedServer), errorCorrectionIsSupported: supportsQrErrorCorrection(selectedServer), }), [selectedServer]); - const willRenderThreeControls = capabilities.marginIsSupported !== capabilities.errorCorrectionIsSupported; + const willRenderThreeControls = !capabilities.errorCorrectionIsSupported; const qrCodeUrl = useMemo( () => buildQrCodeUrl(shortUrl, { size, format, margin, errorCorrection }, capabilities), [shortUrl, size, format, margin, errorCorrection, capabilities], @@ -67,21 +61,19 @@ const QrCodeModal = (imageDownloader: ImageDownloader, ForServerVersion: FC setSize(Number(e.target.value))} /> - {capabilities.marginIsSupported && ( - - - setMargin(Number(e.target.value))} - /> - - )} + + + setMargin(Number(e.target.value))} + /> + diff --git a/src/utils/helpers/features.ts b/src/utils/helpers/features.ts index 54a26c7d..47887fb4 100644 --- a/src/utils/helpers/features.ts +++ b/src/utils/helpers/features.ts @@ -4,10 +4,8 @@ import { versionMatch, Versions } from './version'; const serverMatchesVersions = (versions: Versions) => (selectedServer: SelectedServer): boolean => isReachableServer(selectedServer) && versionMatch(selectedServer.version, versions); -export const supportsQrCodeSizeInQuery = serverMatchesVersions({ minVersion: '2.5.0' }); export const supportsShortUrlTitle = serverMatchesVersions({ minVersion: '2.6.0' }); export const supportsOrphanVisits = supportsShortUrlTitle; -export const supportsQrCodeMargin = supportsShortUrlTitle; export const supportsBotVisits = serverMatchesVersions({ minVersion: '2.7.0' }); export const supportsCrawlableVisits = supportsBotVisits; export const supportsQrErrorCorrection = serverMatchesVersions({ minVersion: '2.8.0' }); diff --git a/src/utils/helpers/qrCodes.ts b/src/utils/helpers/qrCodes.ts index c096f148..85feb888 100644 --- a/src/utils/helpers/qrCodes.ts +++ b/src/utils/helpers/qrCodes.ts @@ -2,8 +2,6 @@ import { isEmpty } from 'ramda'; import { stringifyQuery } from './query'; export interface QrCodeCapabilities { - useSizeInPath: boolean; - marginIsSupported: boolean; errorCorrectionIsSupported: boolean; } @@ -21,13 +19,13 @@ export interface QrCodeOptions { export const buildQrCodeUrl = ( shortUrl: string, { size, format, margin, errorCorrection }: QrCodeOptions, - { useSizeInPath, marginIsSupported, errorCorrectionIsSupported }: QrCodeCapabilities, + { errorCorrectionIsSupported }: QrCodeCapabilities, ): string => { - const baseUrl = `${shortUrl}/qr-code${useSizeInPath ? `/${size}` : ''}`; + const baseUrl = `${shortUrl}/qr-code`; const query = stringifyQuery({ - size: useSizeInPath ? undefined : size, + size, format, - margin: marginIsSupported && margin > 0 ? margin : undefined, + margin: margin > 0 ? margin : undefined, errorCorrection: errorCorrectionIsSupported ? errorCorrection : undefined, }); diff --git a/test/utils/helpers/qrCodes.test.ts b/test/utils/helpers/qrCodes.test.ts index 5a2edf22..bfd72b13 100644 --- a/test/utils/helpers/qrCodes.test.ts +++ b/test/utils/helpers/qrCodes.test.ts @@ -3,71 +3,41 @@ import { buildQrCodeUrl, QrCodeFormat, QrErrorCorrection } from '../../../src/ut describe('qrCodes', () => { describe('buildQrCodeUrl', () => { it.each([ - [ - 'foo.com', - { size: 530, format: 'svg' as QrCodeFormat, margin: 0, errorCorrection: 'L' as QrErrorCorrection }, - { useSizeInPath: true, marginIsSupported: false, errorCorrectionIsSupported: false }, - 'foo.com/qr-code/530?format=svg', - ], - [ - 'foo.com', - { size: 530, format: 'png' as QrCodeFormat, margin: 0, errorCorrection: 'L' as QrErrorCorrection }, - { useSizeInPath: true, marginIsSupported: false, errorCorrectionIsSupported: false }, - 'foo.com/qr-code/530?format=png', - ], [ 'bar.io', { size: 870, format: 'svg' as QrCodeFormat, margin: 0, errorCorrection: 'L' as QrErrorCorrection }, - { useSizeInPath: false, marginIsSupported: false, errorCorrectionIsSupported: false }, + { errorCorrectionIsSupported: false }, 'bar.io/qr-code?size=870&format=svg', ], [ 'bar.io', { size: 200, format: 'png' as QrCodeFormat, margin: 0, errorCorrection: 'L' as QrErrorCorrection }, - { useSizeInPath: false, marginIsSupported: false, errorCorrectionIsSupported: false }, + { errorCorrectionIsSupported: false }, 'bar.io/qr-code?size=200&format=png', ], [ 'bar.io', { size: 200, format: 'svg' as QrCodeFormat, margin: 0, errorCorrection: 'L' as QrErrorCorrection }, - { useSizeInPath: false, marginIsSupported: false, errorCorrectionIsSupported: false }, + { errorCorrectionIsSupported: false }, 'bar.io/qr-code?size=200&format=svg', ], - [ - 'foo.net', - { size: 480, format: 'png' as QrCodeFormat, margin: 0, errorCorrection: 'L' as QrErrorCorrection }, - { useSizeInPath: true, marginIsSupported: false, errorCorrectionIsSupported: false }, - 'foo.net/qr-code/480?format=png', - ], - [ - 'foo.net', - { size: 480, format: 'svg' as QrCodeFormat, margin: 0, errorCorrection: 'L' as QrErrorCorrection }, - { useSizeInPath: true, marginIsSupported: false, errorCorrectionIsSupported: false }, - 'foo.net/qr-code/480?format=svg', - ], - [ - 'shlink.io', - { size: 123, format: 'svg' as QrCodeFormat, margin: 10, errorCorrection: 'L' as QrErrorCorrection }, - { useSizeInPath: true, marginIsSupported: false, errorCorrectionIsSupported: false }, - 'shlink.io/qr-code/123?format=svg', - ], [ 'shlink.io', { size: 456, format: 'png' as QrCodeFormat, margin: 10, errorCorrection: 'L' as QrErrorCorrection }, - { useSizeInPath: true, marginIsSupported: true, errorCorrectionIsSupported: false }, - 'shlink.io/qr-code/456?format=png&margin=10', - ], - [ - 'shlink.io', - { size: 456, format: 'png' as QrCodeFormat, margin: 0, errorCorrection: 'L' as QrErrorCorrection }, - { useSizeInPath: true, marginIsSupported: true, errorCorrectionIsSupported: false }, - 'shlink.io/qr-code/456?format=png', + { errorCorrectionIsSupported: false }, + 'shlink.io/qr-code?size=456&format=png&margin=10', ], [ 'shlink.io', { size: 456, format: 'png' as QrCodeFormat, margin: 0, errorCorrection: 'H' as QrErrorCorrection }, - { useSizeInPath: true, marginIsSupported: true, errorCorrectionIsSupported: true }, - 'shlink.io/qr-code/456?format=png&errorCorrection=H', + { errorCorrectionIsSupported: true }, + 'shlink.io/qr-code?size=456&format=png&errorCorrection=H', + ], + [ + 'shlink.io', + { size: 999, format: 'png' as QrCodeFormat, margin: 20, errorCorrection: 'Q' as QrErrorCorrection }, + { errorCorrectionIsSupported: true }, + 'shlink.io/qr-code?size=999&format=png&margin=20&errorCorrection=Q', ], ])('builds expected URL based in params', (shortUrl, options, capabilities, expectedUrl) => { expect(buildQrCodeUrl(shortUrl, options, capabilities)).toEqual(expectedUrl); From 763ef207f1faca6afe67403f260a377804d3481a Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 1 May 2022 10:50:06 +0200 Subject: [PATCH 3/5] Removed conditional orphan visits section --- src/common/MenuLayout.tsx | 10 ++-------- src/servers/Overview.tsx | 5 ++--- src/utils/helpers/features.ts | 21 ++++++++++----------- test/common/MenuLayout.test.tsx | 1 - test/servers/Overview.test.tsx | 11 ++++++----- 5 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/common/MenuLayout.tsx b/src/common/MenuLayout.tsx index d7166288..99e0de49 100644 --- a/src/common/MenuLayout.tsx +++ b/src/common/MenuLayout.tsx @@ -5,12 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import classNames from 'classnames'; import { withSelectedServer } from '../servers/helpers/withSelectedServer'; import { useSwipeable, useToggle } from '../utils/helpers/hooks'; -import { - supportsDomainRedirects, - supportsDomainVisits, - supportsNonOrphanVisits, - supportsOrphanVisits, -} from '../utils/helpers/features'; +import { supportsDomainRedirects, supportsDomainVisits, supportsNonOrphanVisits } from '../utils/helpers/features'; import { isReachableServer } from '../servers/data'; import NotFound from './NotFound'; import { AsideMenuProps } from './AsideMenu'; @@ -51,7 +46,6 @@ const MenuLayout = ( return ; } - const addOrphanVisitsRoute = supportsOrphanVisits(selectedServer); const addNonOrphanVisitsRoute = supportsNonOrphanVisits(selectedServer); const addManageDomainsRoute = supportsDomainRedirects(selectedServer); const addDomainVisitsRoute = supportsDomainVisits(selectedServer); @@ -76,7 +70,7 @@ const MenuLayout = ( } /> } /> {addDomainVisitsRoute && } />} - {addOrphanVisitsRoute && } />} + } /> {addNonOrphanVisitsRoute && } />} } /> {addManageDomainsRoute && } />} diff --git a/src/servers/Overview.tsx b/src/servers/Overview.tsx index 9127b1ab..e9ddec8b 100644 --- a/src/servers/Overview.tsx +++ b/src/servers/Overview.tsx @@ -10,7 +10,7 @@ import { CreateShortUrlProps } from '../short-urls/CreateShortUrl'; import { VisitsOverview } from '../visits/reducers/visitsOverview'; import { Topics } from '../mercure/helpers/Topics'; import { ShlinkShortUrlsListParams } from '../api/types'; -import { supportsNonOrphanVisits, supportsOrphanVisits } from '../utils/helpers/features'; +import { supportsNonOrphanVisits } from '../utils/helpers/features'; import { getServerId, SelectedServer } from './data'; import { HighlightCard } from './helpers/HighlightCard'; import { ForServerVersionProps } from './helpers/ForServerVersion'; @@ -42,7 +42,6 @@ export const Overview = ( const { loading: loadingTags } = tagsList; const { loading: loadingVisits, visitsCount, orphanVisitsCount } = visitsOverview; const serverId = getServerId(selectedServer); - const linkToOrphanVisits = supportsOrphanVisits(selectedServer); const linkToNonOrphanVisits = supportsNonOrphanVisits(selectedServer); const navigate = useNavigate(); @@ -61,7 +60,7 @@ export const Overview = (
- + {loadingVisits ? 'Loading...' : prettify(orphanVisitsCount ?? 0)} diff --git a/src/utils/helpers/features.ts b/src/utils/helpers/features.ts index 47887fb4..8746d174 100644 --- a/src/utils/helpers/features.ts +++ b/src/utils/helpers/features.ts @@ -1,17 +1,16 @@ import { isReachableServer, SelectedServer } from '../../servers/data'; -import { versionMatch, Versions } from './version'; +import { SemVerPattern, versionMatch } from './version'; -const serverMatchesVersions = (versions: Versions) => (selectedServer: SelectedServer): boolean => - isReachableServer(selectedServer) && versionMatch(selectedServer.version, versions); +const serverMatchesMinVersion = (minVersion: SemVerPattern) => (selectedServer: SelectedServer): boolean => + isReachableServer(selectedServer) && versionMatch(selectedServer.version, { minVersion }); -export const supportsShortUrlTitle = serverMatchesVersions({ minVersion: '2.6.0' }); -export const supportsOrphanVisits = supportsShortUrlTitle; -export const supportsBotVisits = serverMatchesVersions({ minVersion: '2.7.0' }); +export const supportsShortUrlTitle = serverMatchesMinVersion('2.6.0'); +export const supportsBotVisits = serverMatchesMinVersion('2.7.0'); export const supportsCrawlableVisits = supportsBotVisits; -export const supportsQrErrorCorrection = serverMatchesVersions({ minVersion: '2.8.0' }); +export const supportsQrErrorCorrection = serverMatchesMinVersion('2.8.0'); export const supportsDomainRedirects = supportsQrErrorCorrection; -export const supportsForwardQuery = serverMatchesVersions({ minVersion: '2.9.0' }); -export const supportsDefaultDomainRedirectsEdition = serverMatchesVersions({ minVersion: '2.10.0' }); -export const supportsNonOrphanVisits = serverMatchesVersions({ minVersion: '3.0.0' }); +export const supportsForwardQuery = serverMatchesMinVersion('2.9.0'); +export const supportsDefaultDomainRedirectsEdition = serverMatchesMinVersion('2.10.0'); +export const supportsNonOrphanVisits = serverMatchesMinVersion('3.0.0'); export const supportsAllTagsFiltering = supportsNonOrphanVisits; -export const supportsDomainVisits = serverMatchesVersions({ minVersion: '3.1.0' }); +export const supportsDomainVisits = serverMatchesMinVersion('3.1.0'); diff --git a/test/common/MenuLayout.test.tsx b/test/common/MenuLayout.test.tsx index 2cf03f78..425a242c 100644 --- a/test/common/MenuLayout.test.tsx +++ b/test/common/MenuLayout.test.tsx @@ -53,7 +53,6 @@ describe('', () => { }); it.each([ - ['2.5.0' as SemVer, 9], ['2.6.0' as SemVer, 10], ['2.7.0' as SemVer, 10], ['2.8.0' as SemVer, 11], diff --git a/test/servers/Overview.test.tsx b/test/servers/Overview.test.tsx index 1dbc7bcf..28008507 100644 --- a/test/servers/Overview.test.tsx +++ b/test/servers/Overview.test.tsx @@ -77,10 +77,11 @@ describe('', () => { const wrapper = createWrapper(); const links = wrapper.find(Link); - expect(links).toHaveLength(4); - expect(links.at(0).prop('to')).toEqual(`/server/${serverId}/list-short-urls/1`); - expect(links.at(1).prop('to')).toEqual(`/server/${serverId}/manage-tags`); - expect(links.at(2).prop('to')).toEqual(`/server/${serverId}/create-short-url`); - expect(links.at(3).prop('to')).toEqual(`/server/${serverId}/list-short-urls/1`); + expect(links).toHaveLength(5); + expect(links.at(0).prop('to')).toEqual(`/server/${serverId}/orphan-visits`); + expect(links.at(1).prop('to')).toEqual(`/server/${serverId}/list-short-urls/1`); + expect(links.at(2).prop('to')).toEqual(`/server/${serverId}/manage-tags`); + expect(links.at(3).prop('to')).toEqual(`/server/${serverId}/create-short-url`); + expect(links.at(4).prop('to')).toEqual(`/server/${serverId}/list-short-urls/1`); }); }); From b970b38c296534c54f09c10b0fd0dcf21512d16e Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 1 May 2022 11:00:46 +0200 Subject: [PATCH 4/5] Removed check on title support --- src/short-urls/ShortUrlForm.tsx | 66 +++++++++++-------------- src/short-urls/ShortUrlsTable.tsx | 26 ++++------ src/utils/helpers/features.ts | 1 - test/short-urls/ShortUrlForm.test.tsx | 12 ++--- test/short-urls/ShortUrlsTable.test.tsx | 10 +--- 5 files changed, 44 insertions(+), 71 deletions(-) diff --git a/src/short-urls/ShortUrlForm.tsx b/src/short-urls/ShortUrlForm.tsx index 6c36ccbb..c6b9800d 100644 --- a/src/short-urls/ShortUrlForm.tsx +++ b/src/short-urls/ShortUrlForm.tsx @@ -2,10 +2,9 @@ import { FC, useEffect, useState } from 'react'; import { InputType } from 'reactstrap/types/lib/Input'; import { Button, FormGroup, Input, Row } from 'reactstrap'; import { cond, isEmpty, pipe, replace, trim, T } from 'ramda'; -import classNames from 'classnames'; import { parseISO } from 'date-fns'; import DateInput, { DateInputProps } from '../utils/DateInput'; -import { supportsCrawlableVisits, supportsForwardQuery, supportsShortUrlTitle } from '../utils/helpers/features'; +import { supportsCrawlableVisits, supportsForwardQuery } from '../utils/helpers/features'; import { SimpleCard } from '../utils/SimpleCard'; import { handleEventPreventingDefault, hasValue, OptionalString } from '../utils/utils'; import Checkbox from '../utils/Checkbox'; @@ -33,7 +32,6 @@ export interface ShortUrlFormProps { const normalizeTag = pipe(trim, replace(/ /g, '-')); const toDate = (date?: string | Date): Date | undefined => (typeof date === 'string' ? parseISO(date) : date); -const dynamicColClasses = (flag: boolean) => ({ 'col-sm-6': flag, 'col-sm-12': !flag }); export const ShortUrlForm = ( TagsSelector: FC, @@ -115,13 +113,9 @@ export const ShortUrlForm = ( ); - const supportsTitle = supportsShortUrlTitle(selectedServer); - const showCustomizeCard = supportsTitle || !isEdit; - const limitAccessCardClasses = classNames('mb-3', dynamicColClasses(showCustomizeCard)); const showCrawlableControl = supportsCrawlableVisits(selectedServer); const showForwardQueryControl = supportsForwardQuery(selectedServer); const showBehaviorCard = showCrawlableControl || showForwardQueryControl; - const extraChecksCardClasses = classNames('mb-3', dynamicColClasses(showBehaviorCard)); return (
@@ -133,36 +127,34 @@ export const ShortUrlForm = ( - {showCustomizeCard && ( -
- - {supportsTitle && renderOptionalInput('title', 'Title')} - {!isEdit && ( - <> - -
- {renderOptionalInput('customSlug', 'Custom slug', 'text', { - disabled: hasValue(shortUrlData.shortCodeLength), - })} -
-
- {renderOptionalInput('shortCodeLength', 'Short code length', 'number', { - min: 4, - disabled: hasValue(shortUrlData.customSlug), - })} -
-
- setShortUrlData({ ...shortUrlData, domain })} - /> - - )} -
-
- )} +
+ + {renderOptionalInput('title', 'Title')} + {!isEdit && ( + <> + +
+ {renderOptionalInput('customSlug', 'Custom slug', 'text', { + disabled: hasValue(shortUrlData.shortCodeLength), + })} +
+
+ {renderOptionalInput('shortCodeLength', 'Short code length', 'number', { + min: 4, + disabled: hasValue(shortUrlData.customSlug), + })} +
+
+ setShortUrlData({ ...shortUrlData, domain })} + /> + + )} +
+
-
+
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
@@ -174,7 +166,7 @@ export const ShortUrlForm = ( -
+
) => ({ const actionableFieldClasses = classNames({ 'short-urls-table__header-cell--with-action': !!orderByColumn }); const orderableColumnsClasses = classNames('short-urls-table__header-cell', actionableFieldClasses); const tableClasses = classNames('table table-hover responsive-table', className); - const supportsTitle = supportsShortUrlTitle(selectedServer); const renderShortUrls = () => { if (error) { @@ -70,21 +68,15 @@ export const ShortUrlsTable = (ShortUrlsRow: FC) => ({ Short URL {renderOrderIcon?.('shortCode')} - {!supportsTitle ? ( - - Long URL {renderOrderIcon?.('longUrl')} - - ) : ( - - - Title {renderOrderIcon?.('title')} - -   /   - - Long URL {renderOrderIcon?.('longUrl')} - - - )} + + + Title {renderOrderIcon?.('title')} + +   /   + + Long URL {renderOrderIcon?.('longUrl')} + + Tags Visits {renderOrderIcon?.('visits')} diff --git a/src/utils/helpers/features.ts b/src/utils/helpers/features.ts index 8746d174..20b3d589 100644 --- a/src/utils/helpers/features.ts +++ b/src/utils/helpers/features.ts @@ -4,7 +4,6 @@ import { SemVerPattern, versionMatch } from './version'; const serverMatchesMinVersion = (minVersion: SemVerPattern) => (selectedServer: SelectedServer): boolean => isReachableServer(selectedServer) && versionMatch(selectedServer.version, { minVersion }); -export const supportsShortUrlTitle = serverMatchesMinVersion('2.6.0'); export const supportsBotVisits = serverMatchesMinVersion('2.7.0'); export const supportsCrawlableVisits = supportsBotVisits; export const supportsQrErrorCorrection = serverMatchesMinVersion('2.8.0'); diff --git a/test/short-urls/ShortUrlForm.test.tsx b/test/short-urls/ShortUrlForm.test.tsx index 9469d308..13f424e4 100644 --- a/test/short-urls/ShortUrlForm.test.tsx +++ b/test/short-urls/ShortUrlForm.test.tsx @@ -66,16 +66,12 @@ describe('', () => { }); it.each([ - [null, 'create' as Mode, 4], - [null, 'create-basic' as Mode, 0], - [Mock.of({ version: '2.6.0' }), 'create' as Mode, 4], - [Mock.of({ version: '2.5.0' }), 'create' as Mode, 4], - [Mock.of({ version: '2.6.0' }), 'edit' as Mode, 4], - [Mock.of({ version: '2.5.0' }), 'edit' as Mode, 3], + ['create' as Mode, 4], + ['create-basic' as Mode, 0], ])( 'renders expected amount of cards based on server capabilities and mode', - (selectedServer, mode, expectedAmountOfCards) => { - const wrapper = createWrapper(selectedServer, mode); + (mode, expectedAmountOfCards) => { + const wrapper = createWrapper(null, mode); const cards = wrapper.find(SimpleCard); expect(cards).toHaveLength(expectedAmountOfCards); diff --git a/test/short-urls/ShortUrlsTable.test.tsx b/test/short-urls/ShortUrlsTable.test.tsx index 47651119..bf980927 100644 --- a/test/short-urls/ShortUrlsTable.test.tsx +++ b/test/short-urls/ShortUrlsTable.test.tsx @@ -4,7 +4,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { ShortUrlsTable as shortUrlsTableCreator } from '../../src/short-urls/ShortUrlsTable'; import { ShortUrlsList } from '../../src/short-urls/reducers/shortUrlsList'; import { ReachableServer, SelectedServer } from '../../src/servers/data'; -import { SemVer } from '../../src/utils/helpers/version'; import { ShortUrlsOrderableFields, SHORT_URLS_ORDERABLE_FIELDS } from '../../src/short-urls/data'; describe('', () => { @@ -61,13 +60,8 @@ describe('', () => { }); }); - it.each([ - ['2.6.0' as SemVer], - ['2.6.1' as SemVer], - ['2.7.0' as SemVer], - ['3.0.0' as SemVer], - ])('should render composed column when server supports title', (version) => { - const wrapper = createWrapper(Mock.of({ version })); + it('should render composed title column', () => { + const wrapper = createWrapper(Mock.of({ version: '2.0.0' })); const composedColumn = wrapper.find('table').find('th').at(2); const text = composedColumn.text(); From 9c5cad75714626eaffc3a7ced5d21d9fd3d2a397 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Sun, 1 May 2022 11:01:57 +0200 Subject: [PATCH 5/5] Updated changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ac74924..f7775fef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), * *Nothing* ### Removed -* *Nothing* +* [#623](https://github.com/shlinkio/shlink-web-client/pull/623) Dropped support for Shlink older than 2.6.0. ### Fixed * *Nothing*