mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 17:40:23 +03:00
Merge pull request #220 from acelaya-forks/feature/improvements
Feature/improvements
This commit is contained in:
commit
6ac89334fd
14 changed files with 93 additions and 97 deletions
|
@ -13,6 +13,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
#### Changed
|
#### Changed
|
||||||
|
|
||||||
* [#205](https://github.com/shlinkio/shlink-web-client/issues/205) Replaced `jest-each` package by jet's native `test.each` function.
|
* [#205](https://github.com/shlinkio/shlink-web-client/issues/205) Replaced `jest-each` package by jet's native `test.each` function.
|
||||||
|
* [#209](https://github.com/shlinkio/shlink-web-client/issues/209) Replaced `Unknown` by `Direct` for visits from undetermined referrers.
|
||||||
|
* [#212](https://github.com/shlinkio/shlink-web-client/issues/212) Moved copy-to-clipboard next to short URL.
|
||||||
|
|
||||||
#### Deprecated
|
#### Deprecated
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,6 @@ body,
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nowrap {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-main {
|
.bg-main {
|
||||||
background-color: $mainColor !important;
|
background-color: $mainColor !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ const ShortUrlsList = (ShortUrlsRow) => class ShortUrlsList extends React.Compon
|
||||||
className="short-urls-list__header-cell short-urls-list__header-cell--with-action"
|
className="short-urls-list__header-cell short-urls-list__header-cell--with-action"
|
||||||
onClick={this.orderByColumn('visits')}
|
onClick={this.orderByColumn('visits')}
|
||||||
>
|
>
|
||||||
<span className="nowrap">{this.renderOrderIcon('visits')} Visits</span>
|
<span className="indivisible">{this.renderOrderIcon('visits')} Visits</span>
|
||||||
</th>
|
</th>
|
||||||
<th className="short-urls-list__header-cell"> </th>
|
<th className="short-urls-list__header-cell"> </th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -3,6 +3,9 @@ import React from 'react';
|
||||||
import Moment from 'react-moment';
|
import Moment from 'react-moment';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { ExternalLink } from 'react-external-link';
|
import { ExternalLink } from 'react-external-link';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { faCopy as copyIcon } from '@fortawesome/free-regular-svg-icons';
|
||||||
|
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||||
import { shortUrlsListParamsType } from '../reducers/shortUrlsListParams';
|
import { shortUrlsListParamsType } from '../reducers/shortUrlsListParams';
|
||||||
import { serverType } from '../../servers/prop-types';
|
import { serverType } from '../../servers/prop-types';
|
||||||
import { shortUrlType } from '../reducers/shortUrlsList';
|
import { shortUrlType } from '../reducers/shortUrlsList';
|
||||||
|
@ -10,26 +13,25 @@ import Tag from '../../tags/helpers/Tag';
|
||||||
import ShortUrlVisitsCount from './ShortUrlVisitsCount';
|
import ShortUrlVisitsCount from './ShortUrlVisitsCount';
|
||||||
import './ShortUrlsRow.scss';
|
import './ShortUrlsRow.scss';
|
||||||
|
|
||||||
const ShortUrlsRow = (
|
const propTypes = {
|
||||||
ShortUrlsRowMenu,
|
|
||||||
colorGenerator,
|
|
||||||
stateFlagTimeout
|
|
||||||
) => class ShortUrlsRow extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
refreshList: PropTypes.func,
|
refreshList: PropTypes.func,
|
||||||
shortUrlsListParams: shortUrlsListParamsType,
|
shortUrlsListParams: shortUrlsListParamsType,
|
||||||
selectedServer: serverType,
|
selectedServer: serverType,
|
||||||
shortUrl: shortUrlType,
|
shortUrl: shortUrlType,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = { copiedToClipboard: false };
|
const ShortUrlsRow = (
|
||||||
|
ShortUrlsRowMenu,
|
||||||
renderTags(tags) {
|
colorGenerator,
|
||||||
|
useStateFlagTimeout
|
||||||
|
) => {
|
||||||
|
const ShortUrlsRowComp = ({ shortUrl, selectedServer, refreshList, shortUrlsListParams }) => {
|
||||||
|
const [ copiedToClipboard, setCopiedToClipboard ] = useStateFlagTimeout(false);
|
||||||
|
const renderTags = (tags) => {
|
||||||
if (isEmpty(tags)) {
|
if (isEmpty(tags)) {
|
||||||
return <i className="nowrap"><small>No tags</small></i>;
|
return <i className="indivisible"><small>No tags</small></i>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { refreshList, shortUrlsListParams } = this.props;
|
|
||||||
const selectedTags = shortUrlsListParams.tags || [];
|
const selectedTags = shortUrlsListParams.tags || [];
|
||||||
|
|
||||||
return tags.map((tag) => (
|
return tags.map((tag) => (
|
||||||
|
@ -40,23 +42,28 @@ const ShortUrlsRow = (
|
||||||
onClick={() => refreshList({ tags: [ ...selectedTags, tag ] })}
|
onClick={() => refreshList({ tags: [ ...selectedTags, tag ] })}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
|
||||||
const { shortUrl, selectedServer } = this.props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr className="short-urls-row">
|
<tr className="short-urls-row">
|
||||||
<td className="nowrap short-urls-row__cell" data-th="Created at: ">
|
<td className="indivisible short-urls-row__cell" data-th="Created at: ">
|
||||||
<Moment format="YYYY-MM-DD HH:mm">{shortUrl.dateCreated}</Moment>
|
<Moment format="YYYY-MM-DD HH:mm">{shortUrl.dateCreated}</Moment>
|
||||||
</td>
|
</td>
|
||||||
<td className="short-urls-row__cell" data-th="Short URL: ">
|
<td className="short-urls-row__cell" data-th="Short URL: ">
|
||||||
|
<span className="indivisible short-urls-row__cell--relative">
|
||||||
<ExternalLink href={shortUrl.shortUrl} />
|
<ExternalLink href={shortUrl.shortUrl} />
|
||||||
|
<CopyToClipboard text={shortUrl.shortUrl} onCopy={setCopiedToClipboard}>
|
||||||
|
<FontAwesomeIcon icon={copyIcon} className="ml-2 short-urls-row__copy-btn" />
|
||||||
|
</CopyToClipboard>
|
||||||
|
<span className="badge badge-warning short-urls-row__copy-hint" hidden={!copiedToClipboard}>
|
||||||
|
Copied short URL!
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="short-urls-row__cell short-urls-row__cell--break" data-th="Long URL: ">
|
<td className="short-urls-row__cell short-urls-row__cell--break" data-th="Long URL: ">
|
||||||
<ExternalLink href={shortUrl.longUrl} />
|
<ExternalLink href={shortUrl.longUrl} />
|
||||||
</td>
|
</td>
|
||||||
<td className="short-urls-row__cell" data-th="Tags: ">{this.renderTags(shortUrl.tags)}</td>
|
<td className="short-urls-row__cell" data-th="Tags: ">{renderTags(shortUrl.tags)}</td>
|
||||||
<td className="short-urls-row__cell text-md-right" data-th="Visits: ">
|
<td className="short-urls-row__cell text-md-right" data-th="Visits: ">
|
||||||
<ShortUrlVisitsCount
|
<ShortUrlVisitsCount
|
||||||
visitsCount={shortUrl.visitsCount}
|
visitsCount={shortUrl.visitsCount}
|
||||||
|
@ -64,22 +71,16 @@ const ShortUrlsRow = (
|
||||||
selectedServer={selectedServer}
|
selectedServer={selectedServer}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td className="short-urls-row__cell short-urls-row__cell--relative">
|
<td className="short-urls-row__cell">
|
||||||
<small
|
<ShortUrlsRowMenu selectedServer={selectedServer} shortUrl={shortUrl} />
|
||||||
className="badge badge-warning short-urls-row__copy-hint"
|
|
||||||
hidden={!this.state.copiedToClipboard}
|
|
||||||
>
|
|
||||||
Copied short URL!
|
|
||||||
</small>
|
|
||||||
<ShortUrlsRowMenu
|
|
||||||
selectedServer={selectedServer}
|
|
||||||
shortUrl={shortUrl}
|
|
||||||
onCopyToClipboard={() => stateFlagTimeout(this.setState.bind(this), 'copiedToClipboard')}
|
|
||||||
/>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
ShortUrlsRowComp.propTypes = propTypes;
|
||||||
|
|
||||||
|
return ShortUrlsRowComp;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ShortUrlsRow;
|
export default ShortUrlsRow;
|
||||||
|
|
|
@ -43,11 +43,16 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.short-urls-row__copy-btn {
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.short-urls-row__copy-hint {
|
.short-urls-row__copy-hint {
|
||||||
@include vertical-align();
|
@include vertical-align(translateX(10px));
|
||||||
right: 100%;
|
box-shadow: 0 3px 15px rgba(0, 0, 0, .25);
|
||||||
|
|
||||||
@media (max-width: $smMax) {
|
@media (max-width: $smMax) {
|
||||||
right: calc(100% + 10px);
|
@include vertical-align(translateX(calc(-100% - 20px)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { faCopy as copyIcon, faImage as pictureIcon } from '@fortawesome/free-regular-svg-icons';
|
import { faImage as pictureIcon } from '@fortawesome/free-regular-svg-icons';
|
||||||
import {
|
import {
|
||||||
faTags as tagsIcon,
|
faTags as tagsIcon,
|
||||||
faChartPie as pieChartIcon,
|
faChartPie as pieChartIcon,
|
||||||
|
@ -9,9 +9,7 @@ import {
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
|
||||||
import { ButtonDropdown, DropdownItem, DropdownMenu, DropdownToggle } from 'reactstrap';
|
import { ButtonDropdown, DropdownItem, DropdownMenu, DropdownToggle } from 'reactstrap';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { serverType } from '../../servers/prop-types';
|
import { serverType } from '../../servers/prop-types';
|
||||||
import { shortUrlType } from '../reducers/shortUrlsList';
|
import { shortUrlType } from '../reducers/shortUrlsList';
|
||||||
import PreviewModal from './PreviewModal';
|
import PreviewModal from './PreviewModal';
|
||||||
|
@ -26,7 +24,6 @@ const ShortUrlsRowMenu = (
|
||||||
ForServerVersion
|
ForServerVersion
|
||||||
) => class ShortUrlsRowMenu extends React.Component {
|
) => class ShortUrlsRowMenu extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
onCopyToClipboard: PropTypes.func,
|
|
||||||
selectedServer: serverType,
|
selectedServer: serverType,
|
||||||
shortUrl: shortUrlType,
|
shortUrl: shortUrlType,
|
||||||
};
|
};
|
||||||
|
@ -42,7 +39,7 @@ const ShortUrlsRowMenu = (
|
||||||
toggle = () => this.setState(({ isOpen }) => ({ isOpen: !isOpen }));
|
toggle = () => this.setState(({ isOpen }) => ({ isOpen: !isOpen }));
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { onCopyToClipboard, shortUrl, selectedServer } = this.props;
|
const { shortUrl, selectedServer } = this.props;
|
||||||
const completeShortUrl = shortUrl && shortUrl.shortUrl ? shortUrl.shortUrl : '';
|
const completeShortUrl = shortUrl && shortUrl.shortUrl ? shortUrl.shortUrl : '';
|
||||||
const toggleModal = (prop) => () => this.setState((prevState) => ({ [prop]: !prevState[prop] }));
|
const toggleModal = (prop) => () => this.setState((prevState) => ({ [prop]: !prevState[prop] }));
|
||||||
const toggleQrCode = toggleModal('isQrModalOpen');
|
const toggleQrCode = toggleModal('isQrModalOpen');
|
||||||
|
@ -73,12 +70,10 @@ const ShortUrlsRowMenu = (
|
||||||
<EditMetaModal shortUrl={shortUrl} isOpen={this.state.isMetaModalOpen} toggle={toggleMeta} />
|
<EditMetaModal shortUrl={shortUrl} isOpen={this.state.isMetaModalOpen} toggle={toggleMeta} />
|
||||||
</ForServerVersion>
|
</ForServerVersion>
|
||||||
|
|
||||||
<DropdownItem className="short-urls-row-menu__dropdown-item--danger" onClick={toggleDelete}>
|
<DropdownItem onClick={toggleQrCode}>
|
||||||
<FontAwesomeIcon icon={deleteIcon} fixedWidth /> Delete short URL
|
<FontAwesomeIcon icon={qrIcon} fixedWidth /> QR code
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
<DeleteShortUrlModal shortUrl={shortUrl} isOpen={this.state.isDeleteModalOpen} toggle={toggleDelete} />
|
<QrCodeModal url={completeShortUrl} isOpen={this.state.isQrModalOpen} toggle={toggleQrCode} />
|
||||||
|
|
||||||
<DropdownItem divider />
|
|
||||||
|
|
||||||
<ForServerVersion maxVersion="1.x">
|
<ForServerVersion maxVersion="1.x">
|
||||||
<DropdownItem onClick={togglePreview}>
|
<DropdownItem onClick={togglePreview}>
|
||||||
|
@ -87,20 +82,12 @@ const ShortUrlsRowMenu = (
|
||||||
<PreviewModal url={completeShortUrl} isOpen={this.state.isPreviewModalOpen} toggle={togglePreview} />
|
<PreviewModal url={completeShortUrl} isOpen={this.state.isPreviewModalOpen} toggle={togglePreview} />
|
||||||
</ForServerVersion>
|
</ForServerVersion>
|
||||||
|
|
||||||
<DropdownItem onClick={toggleQrCode}>
|
|
||||||
<FontAwesomeIcon icon={qrIcon} fixedWidth /> QR code
|
|
||||||
</DropdownItem>
|
|
||||||
<QrCodeModal url={completeShortUrl} isOpen={this.state.isQrModalOpen} toggle={toggleQrCode} />
|
|
||||||
|
|
||||||
<ForServerVersion maxVersion="1.x">
|
|
||||||
<DropdownItem divider />
|
<DropdownItem divider />
|
||||||
</ForServerVersion>
|
|
||||||
|
|
||||||
<CopyToClipboard text={completeShortUrl} onCopy={onCopyToClipboard}>
|
<DropdownItem className="short-urls-row-menu__dropdown-item--danger" onClick={toggleDelete}>
|
||||||
<DropdownItem>
|
<FontAwesomeIcon icon={deleteIcon} fixedWidth /> Delete short URL
|
||||||
<FontAwesomeIcon icon={copyIcon} fixedWidth /> Copy to clipboard
|
|
||||||
</DropdownItem>
|
</DropdownItem>
|
||||||
</CopyToClipboard>
|
<DeleteShortUrlModal shortUrl={shortUrl} isOpen={this.state.isDeleteModalOpen} toggle={toggleDelete} />
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</ButtonDropdown>
|
</ButtonDropdown>
|
||||||
);
|
);
|
||||||
|
|
|
@ -33,7 +33,7 @@ const provideServices = (bottle, connect) => {
|
||||||
[ 'listShortUrls', 'resetShortUrlParams' ]
|
[ 'listShortUrls', 'resetShortUrlParams' ]
|
||||||
));
|
));
|
||||||
|
|
||||||
bottle.serviceFactory('ShortUrlsRow', ShortUrlsRow, 'ShortUrlsRowMenu', 'ColorGenerator', 'stateFlagTimeout');
|
bottle.serviceFactory('ShortUrlsRow', ShortUrlsRow, 'ShortUrlsRowMenu', 'ColorGenerator', 'useStateFlagTimeout');
|
||||||
|
|
||||||
bottle.serviceFactory(
|
bottle.serviceFactory(
|
||||||
'ShortUrlsRowMenu',
|
'ShortUrlsRowMenu',
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@mixin vertical-align {
|
@mixin vertical-align($extraTransforms: '') {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%) $extraTransforms;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { stateFlagTimeout } from '../utils';
|
import { stateFlagTimeout, useStateFlagTimeout } from '../utils';
|
||||||
import Storage from './Storage';
|
import Storage from './Storage';
|
||||||
import ColorGenerator from './ColorGenerator';
|
import ColorGenerator from './ColorGenerator';
|
||||||
import buildShlinkApiClient from './ShlinkApiClientBuilder';
|
import buildShlinkApiClient from './ShlinkApiClientBuilder';
|
||||||
|
@ -14,6 +14,7 @@ const provideServices = (bottle) => {
|
||||||
|
|
||||||
bottle.constant('setTimeout', global.setTimeout);
|
bottle.constant('setTimeout', global.setTimeout);
|
||||||
bottle.serviceFactory('stateFlagTimeout', stateFlagTimeout, 'setTimeout');
|
bottle.serviceFactory('stateFlagTimeout', stateFlagTimeout, 'setTimeout');
|
||||||
|
bottle.serviceFactory('useStateFlagTimeout', useStateFlagTimeout, 'setTimeout');
|
||||||
};
|
};
|
||||||
|
|
||||||
export default provideServices;
|
export default provideServices;
|
||||||
|
|
|
@ -19,6 +19,16 @@ export const stateFlagTimeout = (setTimeout) => (
|
||||||
setTimeout(() => setState({ [flagName]: !initialValue }), delay);
|
setTimeout(() => setState({ [flagName]: !initialValue }), delay);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useStateFlagTimeout = (setTimeout) => (initialValue = true, delay = DEFAULT_TIMEOUT_DELAY) => {
|
||||||
|
const [ flag, setFlag ] = useState(initialValue);
|
||||||
|
const callback = () => {
|
||||||
|
setFlag(!initialValue);
|
||||||
|
setTimeout(() => setFlag(initialValue), delay);
|
||||||
|
};
|
||||||
|
|
||||||
|
return [ flag, callback ];
|
||||||
|
};
|
||||||
|
|
||||||
export const determineOrderDir = (clickedField, currentOrderField, currentOrderDir) => {
|
export const determineOrderDir = (clickedField, currentOrderField, currentOrderDir) => {
|
||||||
if (currentOrderField !== clickedField) {
|
if (currentOrderField !== clickedField) {
|
||||||
return 'ASC';
|
return 'ASC';
|
||||||
|
|
|
@ -61,7 +61,7 @@ const updateBrowsersStatsForVisit = (browsersStats, { userAgent }) => {
|
||||||
|
|
||||||
const updateReferrersStatsForVisit = (referrersStats, { referer }) => {
|
const updateReferrersStatsForVisit = (referrersStats, { referer }) => {
|
||||||
const notHasDomain = isNil(referer) || isEmpty(referer);
|
const notHasDomain = isNil(referer) || isEmpty(referer);
|
||||||
const domain = notHasDomain ? 'Unknown' : extractDomain(referer);
|
const domain = notHasDomain ? 'Direct' : extractDomain(referer);
|
||||||
|
|
||||||
referrersStats[domain] = (referrersStats[domain] || 0) + 1;
|
referrersStats[domain] = (referrersStats[domain] || 0) + 1;
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@ import moment from 'moment';
|
||||||
import Moment from 'react-moment';
|
import Moment from 'react-moment';
|
||||||
import { assoc, toString } from 'ramda';
|
import { assoc, toString } from 'ramda';
|
||||||
import { ExternalLink } from 'react-external-link';
|
import { ExternalLink } from 'react-external-link';
|
||||||
|
import { CopyToClipboard } from 'react-copy-to-clipboard';
|
||||||
import createShortUrlsRow from '../../../src/short-urls/helpers/ShortUrlsRow';
|
import createShortUrlsRow from '../../../src/short-urls/helpers/ShortUrlsRow';
|
||||||
import Tag from '../../../src/tags/helpers/Tag';
|
import Tag from '../../../src/tags/helpers/Tag';
|
||||||
|
|
||||||
|
@ -11,7 +12,8 @@ describe('<ShortUrlsRow />', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
const mockFunction = () => '';
|
const mockFunction = () => '';
|
||||||
const ShortUrlsRowMenu = mockFunction;
|
const ShortUrlsRowMenu = mockFunction;
|
||||||
const stateFlagTimeout = jest.fn();
|
const stateFlagTimeout = jest.fn(() => true);
|
||||||
|
const useStateFlagTimeout = jest.fn(() => [ false, stateFlagTimeout ]);
|
||||||
const colorGenerator = {
|
const colorGenerator = {
|
||||||
getColorForKey: mockFunction,
|
getColorForKey: mockFunction,
|
||||||
setColorForKey: mockFunction,
|
setColorForKey: mockFunction,
|
||||||
|
@ -29,7 +31,7 @@ describe('<ShortUrlsRow />', () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const ShortUrlsRow = createShortUrlsRow(ShortUrlsRowMenu, colorGenerator, stateFlagTimeout);
|
const ShortUrlsRow = createShortUrlsRow(ShortUrlsRowMenu, colorGenerator, useStateFlagTimeout);
|
||||||
|
|
||||||
wrapper = shallow(
|
wrapper = shallow(
|
||||||
<ShortUrlsRow shortUrlsListParams={{}} refreshList={mockFunction} selecrtedServer={server} shortUrl={shortUrl} />
|
<ShortUrlsRow shortUrlsListParams={{}} refreshList={mockFunction} selecrtedServer={server} shortUrl={shortUrl} />
|
||||||
|
@ -87,20 +89,12 @@ describe('<ShortUrlsRow />', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updates state when copied to clipboard', () => {
|
it('updates state when copied to clipboard', () => {
|
||||||
const col = wrapper.find('td').at(5);
|
const col = wrapper.find('td').at(1);
|
||||||
const menu = col.find(ShortUrlsRowMenu);
|
const menu = col.find(CopyToClipboard);
|
||||||
|
|
||||||
expect(menu).toHaveLength(1);
|
expect(menu).toHaveLength(1);
|
||||||
expect(stateFlagTimeout).not.toHaveBeenCalled();
|
expect(stateFlagTimeout).not.toHaveBeenCalled();
|
||||||
menu.simulate('copyToClipboard');
|
menu.simulate('copy');
|
||||||
expect(stateFlagTimeout).toHaveBeenCalledTimes(1);
|
expect(stateFlagTimeout).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows copy hint when state prop is true', () => {
|
|
||||||
const isHidden = () => wrapper.find('td').at(5).find('.short-urls-row__copy-hint').prop('hidden');
|
|
||||||
|
|
||||||
expect(isHidden()).toEqual(true);
|
|
||||||
wrapper.setState({ copiedToClipboard: true });
|
|
||||||
expect(isHidden()).toEqual(false);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -49,8 +49,8 @@ describe('<ShortUrlsRowMenu />', () => {
|
||||||
const wrapper = createWrapper();
|
const wrapper = createWrapper();
|
||||||
const items = wrapper.find(DropdownItem);
|
const items = wrapper.find(DropdownItem);
|
||||||
|
|
||||||
expect(items).toHaveLength(9);
|
expect(items).toHaveLength(7);
|
||||||
expect(items.find('[divider]')).toHaveLength(2);
|
expect(items.find('[divider]')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('toggles state when toggling modal windows', () => {
|
describe('toggles state when toggling modal windows', () => {
|
||||||
|
|
|
@ -74,7 +74,7 @@ describe('VisitsParser', () => {
|
||||||
const { referrers } = stats;
|
const { referrers } = stats;
|
||||||
|
|
||||||
expect(referrers).toEqual({
|
expect(referrers).toEqual({
|
||||||
'Unknown': 2,
|
'Direct': 2,
|
||||||
'google.com': 2,
|
'google.com': 2,
|
||||||
'm.facebook.com': 1,
|
'm.facebook.com': 1,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue