Dropped support for Shlink 1

This commit is contained in:
Alejandro Celaya 2020-12-12 13:33:21 +01:00
parent b9905c8bf4
commit df6f1b984f
14 changed files with 45 additions and 145 deletions

View file

@ -20,7 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
* *Nothing*
### Removed
* *Nothing*
* [#344](https://github.com/shlinkio/shlink-web-client/issues/344) Dropped support for Shlink v1.
### Fixed
* *Nothing*

View file

@ -115,7 +115,6 @@ const CreateShortUrl = (
);
const currentServerVersion = isReachableServer(selectedServer) ? selectedServer.version : '';
const disableDomain = !versionMatch(currentServerVersion, { minVersion: '1.19.0-beta.1' });
const showDomainSelector = versionMatch(currentServerVersion, { minVersion: '2.4.0' });
const disableShortCodeLength = !versionMatch(currentServerVersion, { minVersion: '2.1.0' });
@ -141,10 +140,7 @@ const CreateShortUrl = (
title: 'Shlink 2.1.0 or higher is required to be able to provide the short code length',
},
})}
{!showDomainSelector && renderOptionalInput('domain', 'Domain', 'text', {
disabled: disableDomain,
...disableDomain && { title: 'Shlink 1.19.0 or higher is required to be able to provide the domain' },
})}
{!showDomainSelector && renderOptionalInput('domain', 'Domain', 'text')}
{showDomainSelector && (
<FormGroup>
<DomainSelector
@ -165,36 +161,34 @@ const CreateShortUrl = (
</div>
</div>
<ForServerVersion minVersion="1.16.0">
<SimpleCard title="Extra validations" className="mb-3">
<p>
Make sure the long URL is valid, or ensure an existing short URL is returned if it matches all
provided data.
</p>
<ForServerVersion minVersion="2.4.0">
<p>
<Checkbox
inline
checked={shortUrlCreation.validateUrl}
onChange={(validateUrl) => setShortUrlCreation({ ...shortUrlCreation, validateUrl })}
>
Validate URL
</Checkbox>
</p>
</ForServerVersion>
<SimpleCard title="Extra validations" className="mb-3">
<p>
Make sure the long URL is valid, or ensure an existing short URL is returned if it matches all
provided data.
</p>
<ForServerVersion minVersion="2.4.0">
<p>
<Checkbox
inline
className="mr-2"
checked={shortUrlCreation.findIfExists}
onChange={(findIfExists) => setShortUrlCreation({ ...shortUrlCreation, findIfExists })}
checked={shortUrlCreation.validateUrl}
onChange={(validateUrl) => setShortUrlCreation({ ...shortUrlCreation, validateUrl })}
>
Use existing URL if found
Validate URL
</Checkbox>
<UseExistingIfFoundInfoIcon />
</p>
</SimpleCard>
</ForServerVersion>
</ForServerVersion>
<p>
<Checkbox
inline
className="mr-2"
checked={shortUrlCreation.findIfExists}
onChange={(findIfExists) => setShortUrlCreation({ ...shortUrlCreation, findIfExists })}
>
Use existing URL if found
</Checkbox>
<UseExistingIfFoundInfoIcon />
</p>
</SimpleCard>
</>
)}

View file

@ -1,6 +1,5 @@
import { faTags as tagsIcon } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { FC } from 'react';
import { isEmpty, pipe } from 'ramda';
import moment from 'moment';
import SearchField from '../utils/SearchField';
@ -8,7 +7,6 @@ import Tag from '../tags/helpers/Tag';
import DateRangeRow from '../utils/DateRangeRow';
import { formatDate } from '../utils/helpers/date';
import ColorGenerator from '../utils/services/ColorGenerator';
import { Versions } from '../utils/helpers/version';
import { ShortUrlsListParams } from './reducers/shortUrlsListParams';
import './SearchBar.scss';
@ -19,9 +17,7 @@ interface SearchBarProps {
const dateOrNull = (date?: string) => date ? moment(date) : null;
const SearchBar = (colorGenerator: ColorGenerator, ForServerVersion: FC<Versions>) => (
{ listShortUrls, shortUrlsListParams }: SearchBarProps,
) => {
const SearchBar = (colorGenerator: ColorGenerator) => ({ listShortUrls, shortUrlsListParams }: SearchBarProps) => {
const selectedTags = shortUrlsListParams.tags ?? [];
const setDate = (dateName: 'startDate' | 'endDate') => pipe(
formatDate(),
@ -36,20 +32,18 @@ const SearchBar = (colorGenerator: ColorGenerator, ForServerVersion: FC<Versions
}
/>
<ForServerVersion minVersion="1.21.0">
<div className="mt-3">
<div className="row">
<div className="col-lg-8 offset-lg-4 col-xl-6 offset-xl-6">
<DateRangeRow
startDate={dateOrNull(shortUrlsListParams.startDate)}
endDate={dateOrNull(shortUrlsListParams.endDate)}
onStartDateChange={setDate('startDate')}
onEndDateChange={setDate('endDate')}
/>
</div>
<div className="mt-3">
<div className="row">
<div className="col-lg-8 offset-lg-4 col-xl-6 offset-xl-6">
<DateRangeRow
startDate={dateOrNull(shortUrlsListParams.startDate)}
endDate={dateOrNull(shortUrlsListParams.endDate)}
onStartDateChange={setDate('startDate')}
onEndDateChange={setDate('endDate')}
/>
</div>
</div>
</ForServerVersion>
</div>
{!isEmpty(selectedTags) && (
<h4 className="search-bar__selected-tag mt-3">

View file

@ -21,7 +21,7 @@ const DeleteShortUrlModal = (
useEffect(() => resetDeleteShortUrl, []);
const { error, errorData } = shortUrlDeletion;
const errorCode = error && (errorData?.type || errorData?.error);
const errorCode = error && errorData?.type;
const hasThresholdError = errorCode === THRESHOLD_REACHED;
const hasErrorOtherThanThreshold = error && errorCode !== THRESHOLD_REACHED;
const close = pipe(resetDeleteShortUrl, toggle);

View file

@ -1,13 +0,0 @@
@import '../../utils/mixins/horizontal-align';
.preview-modal__img {
max-width: 100%;
position: relative;
z-index: 2;
}
.preview-modal__loader {
@include horizontal-align();
z-index: 1;
top: 1rem;
}

View file

@ -1,20 +0,0 @@
import { Modal, ModalBody, ModalHeader } from 'reactstrap';
import { ExternalLink } from 'react-external-link';
import { ShortUrlModalProps } from '../data';
import './PreviewModal.scss';
const PreviewModal = ({ shortUrl: { shortUrl }, toggle, isOpen }: ShortUrlModalProps) => (
<Modal isOpen={isOpen} toggle={toggle} size="lg">
<ModalHeader toggle={toggle}>
Preview for <ExternalLink href={shortUrl}>{shortUrl}</ExternalLink>
</ModalHeader>
<ModalBody>
<div className="text-center">
<p className="preview-modal__loader">Loading...</p>
<img src={`${shortUrl}/preview`} className="preview-modal__img" alt="Preview" />
</div>
</ModalBody>
</Modal>
);
export default PreviewModal;

View file

@ -1,4 +1,3 @@
import { faImage as pictureIcon } from '@fortawesome/free-regular-svg-icons';
import {
faTags as tagsIcon,
faChartPie as pieChartIcon,
@ -15,7 +14,6 @@ import { useToggle } from '../../utils/helpers/hooks';
import { ShortUrl, ShortUrlModalProps } from '../data';
import { Versions } from '../../utils/helpers/version';
import { SelectedServer } from '../../servers/data';
import PreviewModal from './PreviewModal';
import QrCodeModal from './QrCodeModal';
import VisitStatsLink from './VisitStatsLink';
import './ShortUrlsRowMenu.scss';
@ -35,7 +33,6 @@ const ShortUrlsRowMenu = (
) => ({ shortUrl, selectedServer }: ShortUrlsRowMenuProps) => {
const [ isOpen, toggle ] = useToggle();
const [ isQrModalOpen, toggleQrCode ] = useToggle();
const [ isPreviewModalOpen, togglePreview ] = useToggle();
const [ isTagsModalOpen, toggleTags ] = useToggle();
const [ isMetaModalOpen, toggleMeta ] = useToggle();
const [ isDeleteModalOpen, toggleDelete ] = useToggle();
@ -56,12 +53,10 @@ const ShortUrlsRowMenu = (
</DropdownItem>
<EditTagsModal shortUrl={shortUrl} isOpen={isTagsModalOpen} toggle={toggleTags} />
<ForServerVersion minVersion="1.18.0">
<DropdownItem onClick={toggleMeta}>
<FontAwesomeIcon icon={editIcon} fixedWidth /> Edit metadata
</DropdownItem>
<EditMetaModal shortUrl={shortUrl} isOpen={isMetaModalOpen} toggle={toggleMeta} />
</ForServerVersion>
<DropdownItem onClick={toggleMeta}>
<FontAwesomeIcon icon={editIcon} fixedWidth /> Edit metadata
</DropdownItem>
<EditMetaModal shortUrl={shortUrl} isOpen={isMetaModalOpen} toggle={toggleMeta} />
<ForServerVersion minVersion="2.1.0">
<DropdownItem onClick={toggleEdit}>
@ -75,13 +70,6 @@ const ShortUrlsRowMenu = (
</DropdownItem>
<QrCodeModal shortUrl={shortUrl} isOpen={isQrModalOpen} toggle={toggleQrCode} />
<ForServerVersion maxVersion="1.x">
<DropdownItem onClick={togglePreview}>
<FontAwesomeIcon icon={pictureIcon} fixedWidth /> Preview
</DropdownItem>
<PreviewModal shortUrl={shortUrl} isOpen={isPreviewModalOpen} toggle={togglePreview} />
</ForServerVersion>
<DropdownItem divider />
<DropdownItem className="short-urls-row-menu__dropdown-item--danger" onClick={toggleDelete}>

View file

@ -70,7 +70,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
bottle.decorator('EditShortUrlModal', connect([ 'shortUrlEdition' ], [ 'editShortUrl' ]));
// Services
bottle.serviceFactory('SearchBar', SearchBar, 'ColorGenerator', 'ForServerVersion');
bottle.serviceFactory('SearchBar', SearchBar, 'ColorGenerator');
bottle.decorator('SearchBar', connect([ 'shortUrlsListParams' ], [ 'listShortUrls' ]));
// Actions

View file

@ -125,7 +125,7 @@ export default class ShlinkApiClient {
// When the request is not invalid or we have already tried both API versions, throw the error and let the
// caller handle it
if (!apiVersionIsNotSupported || this.apiVersion === 1) {
if (!apiVersionIsNotSupported || this.apiVersion === 2) {
throw e;
}

View file

@ -65,8 +65,6 @@ export interface ProblemDetailsError {
detail: string;
title: string;
status: number;
error?: string; // Deprecated
message?: string; // Deprecated
[extraProps: string]: any;
}

View file

@ -9,7 +9,7 @@ import ColorGenerator from '../../src/utils/services/ColorGenerator';
describe('<SearchBar />', () => {
let wrapper: ShallowWrapper;
const listShortUrlsMock = jest.fn();
const SearchBar = searchBarCreator(Mock.all<ColorGenerator>(), () => null);
const SearchBar = searchBarCreator(Mock.all<ColorGenerator>());
afterEach(jest.clearAllMocks);
afterEach(() => wrapper?.unmount());

View file

@ -33,18 +33,10 @@ describe('<DeleteShortUrlModal />', () => {
afterEach(jest.clearAllMocks);
it.each([
[
{ error: 'INVALID_SHORTCODE_DELETION' },
'This short URL has received too many visits, and therefore, it cannot be deleted.',
],
[
{ type: 'INVALID_SHORTCODE_DELETION' },
'This short URL has received too many visits, and therefore, it cannot be deleted.',
],
[
{ error: 'INVALID_SHORTCODE_DELETION', threshold: 35 },
'This short URL has received more than 35 visits, and therefore, it cannot be deleted.',
],
[
{ type: 'INVALID_SHORTCODE_DELETION', threshold: 8 },
'This short URL has received more than 8 visits, and therefore, it cannot be deleted.',
@ -67,7 +59,7 @@ describe('<DeleteShortUrlModal />', () => {
loading: false,
error: true,
shortCode: 'abc123',
errorData: Mock.of<ProblemDetailsError>({ error: 'OTHER_ERROR' }),
errorData: Mock.of<ProblemDetailsError>({ type: 'OTHER_ERROR' }),
});
const error = wrapper.find('.bg-danger');

View file

@ -1,29 +0,0 @@
import { shallow, ShallowWrapper } from 'enzyme';
import { ExternalLink } from 'react-external-link';
import { Mock } from 'ts-mockery';
import PreviewModal from '../../../src/short-urls/helpers/PreviewModal';
import { ShortUrl } from '../../../src/short-urls/data';
describe('<PreviewModal />', () => {
let wrapper: ShallowWrapper;
const shortUrl = 'https://doma.in/abc123';
beforeEach(() => {
wrapper = shallow(<PreviewModal shortUrl={Mock.of<ShortUrl>({ shortUrl })} isOpen={true} toggle={() => {}} />);
});
afterEach(() => wrapper.unmount());
it('shows an external link to the URL', () => {
const externalLink = wrapper.find(ExternalLink);
expect(externalLink).toHaveLength(1);
expect(externalLink.prop('href')).toEqual(shortUrl);
});
it('displays an image with the preview of the URL', () => {
const img = wrapper.find('img');
expect(img).toHaveLength(1);
expect(img.prop('src')).toEqual(`${shortUrl}/preview`);
});
});

View file

@ -2,7 +2,6 @@ import { shallow, ShallowWrapper } from 'enzyme';
import { ButtonDropdown, DropdownItem } from 'reactstrap';
import { Mock } from 'ts-mockery';
import createShortUrlsRowMenu from '../../../src/short-urls/helpers/ShortUrlsRowMenu';
import PreviewModal from '../../../src/short-urls/helpers/PreviewModal';
import QrCodeModal from '../../../src/short-urls/helpers/QrCodeModal';
import { ReachableServer } from '../../../src/servers/data';
import { ShortUrl } from '../../../src/short-urls/data';
@ -38,13 +37,11 @@ describe('<ShortUrlsRowMenu />', () => {
const wrapper = createWrapper();
const deleteShortUrlModal = wrapper.find(DeleteShortUrlModal);
const editTagsModal = wrapper.find(EditTagsModal);
const previewModal = wrapper.find(PreviewModal);
const qrCodeModal = wrapper.find(QrCodeModal);
const editModal = wrapper.find(EditShortUrlModal);
expect(deleteShortUrlModal).toHaveLength(1);
expect(editTagsModal).toHaveLength(1);
expect(previewModal).toHaveLength(1);
expect(qrCodeModal).toHaveLength(1);
expect(editModal).toHaveLength(1);
});
@ -53,7 +50,7 @@ describe('<ShortUrlsRowMenu />', () => {
const wrapper = createWrapper();
const items = wrapper.find(DropdownItem);
expect(items).toHaveLength(8);
expect(items).toHaveLength(7);
expect(items.find('[divider]')).toHaveLength(1);
});
@ -68,7 +65,6 @@ describe('<ShortUrlsRowMenu />', () => {
it('DeleteShortUrlModal', () => assert(DeleteShortUrlModal));
it('EditTagsModal', () => assert(EditTagsModal));
it('PreviewModal', () => assert(PreviewModal));
it('QrCodeModal', () => assert(QrCodeModal));
it('EditShortUrlModal', () => assert(EditShortUrlModal));
it('EditShortUrlModal', () => assert(ButtonDropdown));