diff --git a/src/common/MenuLayout.tsx b/src/common/MenuLayout.tsx index 871a0f97..6672583e 100644 --- a/src/common/MenuLayout.tsx +++ b/src/common/MenuLayout.tsx @@ -5,7 +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, supportsOrphanVisits, supportsTagVisits } from '../utils/helpers/features'; +import { supportsDomainRedirects, supportsOrphanVisits } from '../utils/helpers/features'; import { isReachableServer } from '../servers/data'; import NotFound from './NotFound'; import { AsideMenuProps } from './AsideMenu'; @@ -32,7 +32,6 @@ const MenuLayout = ( return ; } - const addTagsVisitsRoute = supportsTagVisits(selectedServer); const addOrphanVisitsRoute = supportsOrphanVisits(selectedServer); const addManageDomainsRoute = supportsDomainRedirects(selectedServer); const burgerClasses = classNames('menu-layout__burger-icon', { 'menu-layout__burger-icon--active': sidebarVisible }); @@ -54,7 +53,7 @@ const MenuLayout = ( - {addTagsVisitsRoute && } + {addOrphanVisitsRoute && } {addManageDomainsRoute && } diff --git a/src/short-urls/ShortUrlForm.tsx b/src/short-urls/ShortUrlForm.tsx index 96fc6eea..b09a70cb 100644 --- a/src/short-urls/ShortUrlForm.tsx +++ b/src/short-urls/ShortUrlForm.tsx @@ -5,13 +5,7 @@ import { isEmpty, pipe, replace, trim } from 'ramda'; import classNames from 'classnames'; import { parseISO } from 'date-fns'; import DateInput, { DateInputProps } from '../utils/DateInput'; -import { - supportsCrawlableVisits, - supportsListingDomains, - supportsSettingShortCodeLength, - supportsShortUrlTitle, - supportsValidateUrl, -} from '../utils/helpers/features'; +import { supportsCrawlableVisits, supportsShortUrlTitle } from '../utils/helpers/features'; import { SimpleCard } from '../utils/SimpleCard'; import { handleEventPreventingDefault, hasValue } from '../utils/utils'; import Checkbox from '../utils/Checkbox'; @@ -102,17 +96,13 @@ export const ShortUrlForm = ( ); - const showDomainSelector = supportsListingDomains(selectedServer); - const disableShortCodeLength = !supportsSettingShortCodeLength(selectedServer); const supportsTitle = supportsShortUrlTitle(selectedServer); const showCustomizeCard = supportsTitle || !isEdit; const limitAccessCardClasses = classNames('mb-3', { 'col-sm-6': showCustomizeCard, 'col-sm-12': !showCustomizeCard, }); - const showValidateUrl = supportsValidateUrl(selectedServer); const showCrawlableControl = supportsCrawlableVisits(selectedServer); - const showExtraValidationsCard = showValidateUrl || showCrawlableControl || !isEdit; return (
@@ -139,22 +129,16 @@ export const ShortUrlForm = (
{renderOptionalInput('shortCodeLength', 'Short code length', 'number', { min: 4, - disabled: disableShortCodeLength || hasValue(shortUrlData.customSlug), - ...disableShortCodeLength && { - title: 'Shlink 2.1.0 or higher is required to be able to provide the short code length', - }, + disabled: hasValue(shortUrlData.customSlug), })}
- {!showDomainSelector && renderOptionalInput('domain', 'Domain', 'text')} - {showDomainSelector && ( - - setShortUrlData({ ...shortUrlData, domain })} - /> - - )} + + setShortUrlData({ ...shortUrlData, domain })} + /> + )} @@ -170,41 +154,37 @@ export const ShortUrlForm = ( - {showExtraValidationsCard && ( - - {showValidateUrl && ( - setShortUrlData({ ...shortUrlData, validateUrl })} + + setShortUrlData({ ...shortUrlData, validateUrl })} + > + Validate URL + + {showCrawlableControl && ( + setShortUrlData({ ...shortUrlData, crawlable })} + > + Make it crawlable + + )} + {!isEdit && ( +

+ setShortUrlData({ ...shortUrlData, findIfExists })} > - Validate URL - - )} - {showCrawlableControl && ( - setShortUrlData({ ...shortUrlData, crawlable })} - > - Make it crawlable - - )} - {!isEdit && ( -

- setShortUrlData({ ...shortUrlData, findIfExists })} - > - Use existing URL if found - - -

- )} -
- )} + Use existing URL if found + + +

+ )} +
)} diff --git a/src/short-urls/helpers/QrCodeModal.tsx b/src/short-urls/helpers/QrCodeModal.tsx index 6521e5e1..053c5e11 100644 --- a/src/short-urls/helpers/QrCodeModal.tsx +++ b/src/short-urls/helpers/QrCodeModal.tsx @@ -10,7 +10,6 @@ import { CopyToClipboardIcon } from '../../utils/CopyToClipboardIcon'; import { buildQrCodeUrl, QrCodeCapabilities, QrCodeFormat, QrErrorCorrection } from '../../utils/helpers/qrCodes'; import { supportsQrCodeSizeInQuery, - supportsQrCodeSvgFormat, supportsQrCodeMargin, supportsQrErrorCorrection, } from '../../utils/helpers/features'; @@ -33,10 +32,10 @@ const QrCodeModal = (imageDownloader: ImageDownloader, ForServerVersion: FC('L'); const capabilities: QrCodeCapabilities = useMemo(() => ({ useSizeInPath: !supportsQrCodeSizeInQuery(selectedServer), - svgIsSupported: supportsQrCodeSvgFormat(selectedServer), marginIsSupported: supportsQrCodeMargin(selectedServer), errorCorrectionIsSupported: supportsQrErrorCorrection(selectedServer), }), [ selectedServer ]); + const willRenderThreeControls = capabilities.marginIsSupported !== capabilities.errorCorrectionIsSupported; const qrCodeUrl = useMemo( () => buildQrCodeUrl(shortUrl, { size, format, margin, errorCorrection }, capabilities), [ shortUrl, size, format, margin, errorCorrection, capabilities ], @@ -58,11 +57,7 @@ const QrCodeModal = (imageDownloader: ImageDownloader, ForServerVersion: FC {capabilities.marginIsSupported && ( - + )} - {capabilities.svgIsSupported && ( - - - - )} + + + {capabilities.errorCorrectionIsSupported && ( diff --git a/src/utils/helpers/features.ts b/src/utils/helpers/features.ts index 68651fcc..120926f8 100644 --- a/src/utils/helpers/features.ts +++ b/src/utils/helpers/features.ts @@ -4,16 +4,6 @@ import { versionMatch, Versions } from './version'; const serverMatchesVersions = (versions: Versions) => (selectedServer: SelectedServer): boolean => isReachableServer(selectedServer) && versionMatch(selectedServer.version, versions); -export const supportsSettingShortCodeLength = serverMatchesVersions({ minVersion: '2.1.0' }); - -export const supportsTagVisits = serverMatchesVersions({ minVersion: '2.2.0' }); - -export const supportsListingDomains = serverMatchesVersions({ minVersion: '2.4.0' }); - -export const supportsQrCodeSvgFormat = supportsListingDomains; - -export const supportsValidateUrl = supportsListingDomains; - export const supportsQrCodeSizeInQuery = serverMatchesVersions({ minVersion: '2.5.0' }); export const supportsShortUrlTitle = serverMatchesVersions({ minVersion: '2.6.0' }); diff --git a/src/utils/helpers/qrCodes.ts b/src/utils/helpers/qrCodes.ts index fb94350a..c096f148 100644 --- a/src/utils/helpers/qrCodes.ts +++ b/src/utils/helpers/qrCodes.ts @@ -3,7 +3,6 @@ import { stringifyQuery } from './query'; export interface QrCodeCapabilities { useSizeInPath: boolean; - svgIsSupported: boolean; marginIsSupported: boolean; errorCorrectionIsSupported: boolean; } @@ -22,12 +21,12 @@ export interface QrCodeOptions { export const buildQrCodeUrl = ( shortUrl: string, { size, format, margin, errorCorrection }: QrCodeOptions, - { useSizeInPath, svgIsSupported, marginIsSupported, errorCorrectionIsSupported }: QrCodeCapabilities, + { useSizeInPath, marginIsSupported, errorCorrectionIsSupported }: QrCodeCapabilities, ): string => { const baseUrl = `${shortUrl}/qr-code${useSizeInPath ? `/${size}` : ''}`; const query = stringifyQuery({ size: useSizeInPath ? undefined : size, - format: svgIsSupported ? format : undefined, + format, margin: marginIsSupported && margin > 0 ? margin : undefined, errorCorrection: errorCorrectionIsSupported ? errorCorrection : undefined, }); diff --git a/test/common/MenuLayout.test.tsx b/test/common/MenuLayout.test.tsx index 439bb81f..e45dfb3d 100644 --- a/test/common/MenuLayout.test.tsx +++ b/test/common/MenuLayout.test.tsx @@ -49,8 +49,6 @@ describe('', () => { }); it.each([ - [ '2.1.0' as SemVer, 7 ], - [ '2.2.0' as SemVer, 8 ], [ '2.5.0' as SemVer, 8 ], [ '2.6.0' as SemVer, 9 ], [ '2.7.0' as SemVer, 9 ], diff --git a/test/short-urls/ShortUrlForm.test.tsx b/test/short-urls/ShortUrlForm.test.tsx index 380d1309..66ae1fc1 100644 --- a/test/short-urls/ShortUrlForm.test.tsx +++ b/test/short-urls/ShortUrlForm.test.tsx @@ -13,9 +13,10 @@ import { parseDate } from '../../src/utils/helpers/date'; describe('', () => { let wrapper: ShallowWrapper; const TagsSelector = () => null; + const DomainSelector = () => null; const createShortUrl = jest.fn(async () => Promise.resolve()); const createWrapper = (selectedServer: SelectedServer = null, mode: Mode = 'create') => { - const ShortUrlForm = createShortUrlForm(TagsSelector, () => null); + const ShortUrlForm = createShortUrlForm(TagsSelector, DomainSelector); wrapper = shallow( ', () => { wrapper.find(Input).first().simulate('change', { target: { value: 'https://long-domain.com/foo/bar' } }); wrapper.find('TagsSelector').simulate('change', [ 'tag_foo', 'tag_bar' ]); wrapper.find('#customSlug').simulate('change', { target: { value: 'my-slug' } }); - wrapper.find('#domain').simulate('change', { target: { value: 'example.com' } }); + wrapper.find(DomainSelector).simulate('change', 'example.com'); wrapper.find('#maxVisits').simulate('change', { target: { value: '20' } }); wrapper.find('#shortCodeLength').simulate('change', { target: { value: 15 } }); wrapper.find(DateInput).at(0).simulate('change', validSince); @@ -68,12 +69,8 @@ describe('', () => { [ 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.4.0' }), 'create' as Mode, 4 ], - [ Mock.of({ version: '2.3.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 ], - [ Mock.of({ version: '2.4.0' }), 'edit' as Mode, 3 ], - [ Mock.of({ version: '2.3.0' }), 'edit' as Mode, 2 ], ])( 'renders expected amount of cards based on server capabilities and mode', (selectedServer, mode, expectedAmountOfCards) => { diff --git a/test/short-urls/helpers/QrCodeModal.test.tsx b/test/short-urls/helpers/QrCodeModal.test.tsx index aa8b5160..900e90e2 100644 --- a/test/short-urls/helpers/QrCodeModal.test.tsx +++ b/test/short-urls/helpers/QrCodeModal.test.tsx @@ -43,9 +43,6 @@ describe('', () => { }); it.each([ - [ '2.3.0' as SemVer, 0, '/qr-code/300' ], - [ '2.4.0' as SemVer, 0, '/qr-code/300?format=png' ], - [ '2.4.0' as SemVer, 10, '/qr-code/300?format=png' ], [ '2.5.0' as SemVer, 0, '/qr-code?size=300&format=png' ], [ '2.6.0' as SemVer, 0, '/qr-code?size=300&format=png' ], [ '2.6.0' as SemVer, 10, '/qr-code?size=300&format=png&margin=10' ], @@ -90,8 +87,6 @@ describe('', () => { }); it.each([ - [ '2.3.0' as SemVer, 0, 'col-12' ], - [ '2.4.0' as SemVer, 1, 'col-md-6' ], [ '2.6.0' as SemVer, 1, 'col-md-4' ], [ '2.8.0' as SemVer, 2, 'col-md-6' ], ])('shows expected components based on server version', (version, expectedAmountOfDropdowns, expectedRangeClass) => { diff --git a/test/utils/helpers/qrCodes.test.ts b/test/utils/helpers/qrCodes.test.ts index c9d7bcbe..5a2edf22 100644 --- a/test/utils/helpers/qrCodes.test.ts +++ b/test/utils/helpers/qrCodes.test.ts @@ -6,67 +6,67 @@ describe('qrCodes', () => { [ 'foo.com', { size: 530, format: 'svg' as QrCodeFormat, margin: 0, errorCorrection: 'L' as QrErrorCorrection }, - { useSizeInPath: true, svgIsSupported: true, marginIsSupported: false, errorCorrectionIsSupported: false }, + { 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, svgIsSupported: true, marginIsSupported: false, errorCorrectionIsSupported: false }, + { 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, svgIsSupported: false, marginIsSupported: false, errorCorrectionIsSupported: false }, - 'bar.io/qr-code?size=870', + { useSizeInPath: false, marginIsSupported: 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, svgIsSupported: true, marginIsSupported: false, errorCorrectionIsSupported: false }, + { useSizeInPath: false, marginIsSupported: 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, svgIsSupported: true, marginIsSupported: false, errorCorrectionIsSupported: false }, + { useSizeInPath: false, marginIsSupported: 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, svgIsSupported: false, marginIsSupported: false, errorCorrectionIsSupported: false }, - 'foo.net/qr-code/480', + { 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, svgIsSupported: false, marginIsSupported: false, errorCorrectionIsSupported: false }, - 'foo.net/qr-code/480', + { 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, svgIsSupported: false, marginIsSupported: false, errorCorrectionIsSupported: false }, - 'shlink.io/qr-code/123', + { 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, svgIsSupported: true, marginIsSupported: true, errorCorrectionIsSupported: false }, + { 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, svgIsSupported: true, marginIsSupported: true, errorCorrectionIsSupported: false }, + { useSizeInPath: true, marginIsSupported: true, errorCorrectionIsSupported: false }, 'shlink.io/qr-code/456?format=png', ], [ 'shlink.io', { size: 456, format: 'png' as QrCodeFormat, margin: 0, errorCorrection: 'H' as QrErrorCorrection }, - { useSizeInPath: true, svgIsSupported: true, marginIsSupported: true, errorCorrectionIsSupported: true }, + { useSizeInPath: true, marginIsSupported: true, errorCorrectionIsSupported: true }, 'shlink.io/qr-code/456?format=png&errorCorrection=H', ], ])('builds expected URL based in params', (shortUrl, options, capabilities, expectedUrl) => {