mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 01:20:24 +03:00
Dropped support for Shlink 1
This commit is contained in:
parent
b9905c8bf4
commit
df6f1b984f
14 changed files with 45 additions and 145 deletions
|
@ -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*
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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}>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -65,8 +65,6 @@ export interface ProblemDetailsError {
|
|||
detail: string;
|
||||
title: string;
|
||||
status: number;
|
||||
error?: string; // Deprecated
|
||||
message?: string; // Deprecated
|
||||
[extraProps: string]: any;
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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');
|
||||
|
||||
|
|
|
@ -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`);
|
||||
});
|
||||
});
|
|
@ -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));
|
||||
|
|
Loading…
Reference in a new issue