mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2025-01-09 09:47:28 +03:00
Removed check on title support
This commit is contained in:
parent
763ef207f1
commit
b970b38c29
5 changed files with 44 additions and 71 deletions
|
@ -2,10 +2,9 @@ import { FC, useEffect, useState } from 'react';
|
||||||
import { InputType } from 'reactstrap/types/lib/Input';
|
import { InputType } from 'reactstrap/types/lib/Input';
|
||||||
import { Button, FormGroup, Input, Row } from 'reactstrap';
|
import { Button, FormGroup, Input, Row } from 'reactstrap';
|
||||||
import { cond, isEmpty, pipe, replace, trim, T } from 'ramda';
|
import { cond, isEmpty, pipe, replace, trim, T } from 'ramda';
|
||||||
import classNames from 'classnames';
|
|
||||||
import { parseISO } from 'date-fns';
|
import { parseISO } from 'date-fns';
|
||||||
import DateInput, { DateInputProps } from '../utils/DateInput';
|
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 { SimpleCard } from '../utils/SimpleCard';
|
||||||
import { handleEventPreventingDefault, hasValue, OptionalString } from '../utils/utils';
|
import { handleEventPreventingDefault, hasValue, OptionalString } from '../utils/utils';
|
||||||
import Checkbox from '../utils/Checkbox';
|
import Checkbox from '../utils/Checkbox';
|
||||||
|
@ -33,7 +32,6 @@ export interface ShortUrlFormProps {
|
||||||
|
|
||||||
const normalizeTag = pipe(trim, replace(/ /g, '-'));
|
const normalizeTag = pipe(trim, replace(/ /g, '-'));
|
||||||
const toDate = (date?: string | Date): Date | undefined => (typeof date === 'string' ? parseISO(date) : date);
|
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 = (
|
export const ShortUrlForm = (
|
||||||
TagsSelector: FC<TagsSelectorProps>,
|
TagsSelector: FC<TagsSelectorProps>,
|
||||||
|
@ -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 showCrawlableControl = supportsCrawlableVisits(selectedServer);
|
||||||
const showForwardQueryControl = supportsForwardQuery(selectedServer);
|
const showForwardQueryControl = supportsForwardQuery(selectedServer);
|
||||||
const showBehaviorCard = showCrawlableControl || showForwardQueryControl;
|
const showBehaviorCard = showCrawlableControl || showForwardQueryControl;
|
||||||
const extraChecksCardClasses = classNames('mb-3', dynamicColClasses(showBehaviorCard));
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="short-url-form" onSubmit={submit}>
|
<form className="short-url-form" onSubmit={submit}>
|
||||||
|
@ -133,36 +127,34 @@ export const ShortUrlForm = (
|
||||||
</SimpleCard>
|
</SimpleCard>
|
||||||
|
|
||||||
<Row>
|
<Row>
|
||||||
{showCustomizeCard && (
|
<div className="col-sm-6 mb-3">
|
||||||
<div className="col-sm-6 mb-3">
|
<SimpleCard title="Customize the short URL">
|
||||||
<SimpleCard title="Customize the short URL">
|
{renderOptionalInput('title', 'Title')}
|
||||||
{supportsTitle && renderOptionalInput('title', 'Title')}
|
{!isEdit && (
|
||||||
{!isEdit && (
|
<>
|
||||||
<>
|
<Row>
|
||||||
<Row>
|
<div className="col-lg-6">
|
||||||
<div className="col-lg-6">
|
{renderOptionalInput('customSlug', 'Custom slug', 'text', {
|
||||||
{renderOptionalInput('customSlug', 'Custom slug', 'text', {
|
disabled: hasValue(shortUrlData.shortCodeLength),
|
||||||
disabled: hasValue(shortUrlData.shortCodeLength),
|
})}
|
||||||
})}
|
</div>
|
||||||
</div>
|
<div className="col-lg-6">
|
||||||
<div className="col-lg-6">
|
{renderOptionalInput('shortCodeLength', 'Short code length', 'number', {
|
||||||
{renderOptionalInput('shortCodeLength', 'Short code length', 'number', {
|
min: 4,
|
||||||
min: 4,
|
disabled: hasValue(shortUrlData.customSlug),
|
||||||
disabled: hasValue(shortUrlData.customSlug),
|
})}
|
||||||
})}
|
</div>
|
||||||
</div>
|
</Row>
|
||||||
</Row>
|
<DomainSelector
|
||||||
<DomainSelector
|
value={shortUrlData.domain}
|
||||||
value={shortUrlData.domain}
|
onChange={(domain?: string) => setShortUrlData({ ...shortUrlData, domain })}
|
||||||
onChange={(domain?: string) => setShortUrlData({ ...shortUrlData, domain })}
|
/>
|
||||||
/>
|
</>
|
||||||
</>
|
)}
|
||||||
)}
|
</SimpleCard>
|
||||||
</SimpleCard>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className={limitAccessCardClasses}>
|
<div className="col-sm-6 mb-3">
|
||||||
<SimpleCard title="Limit access to the short URL">
|
<SimpleCard title="Limit access to the short URL">
|
||||||
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
|
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
|
@ -174,7 +166,7 @@ export const ShortUrlForm = (
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Row>
|
<Row>
|
||||||
<div className={extraChecksCardClasses}>
|
<div className="col-sm-6 mb-3">
|
||||||
<SimpleCard title="Extra checks">
|
<SimpleCard title="Extra checks">
|
||||||
<ShortUrlFormCheckboxGroup
|
<ShortUrlFormCheckboxGroup
|
||||||
infoTooltip="If checked, Shlink will try to reach the long URL, failing in case it's not publicly accessible."
|
infoTooltip="If checked, Shlink will try to reach the long URL, failing in case it's not publicly accessible."
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { FC, ReactNode } from 'react';
|
||||||
import { isEmpty } from 'ramda';
|
import { isEmpty } from 'ramda';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { SelectedServer } from '../servers/data';
|
import { SelectedServer } from '../servers/data';
|
||||||
import { supportsShortUrlTitle } from '../utils/helpers/features';
|
|
||||||
import { ShortUrlsList as ShortUrlsListState } from './reducers/shortUrlsList';
|
import { ShortUrlsList as ShortUrlsListState } from './reducers/shortUrlsList';
|
||||||
import { ShortUrlsRowProps } from './helpers/ShortUrlsRow';
|
import { ShortUrlsRowProps } from './helpers/ShortUrlsRow';
|
||||||
import { ShortUrlsOrderableFields } from './data';
|
import { ShortUrlsOrderableFields } from './data';
|
||||||
|
@ -29,7 +28,6 @@ export const ShortUrlsTable = (ShortUrlsRow: FC<ShortUrlsRowProps>) => ({
|
||||||
const actionableFieldClasses = classNames({ 'short-urls-table__header-cell--with-action': !!orderByColumn });
|
const actionableFieldClasses = classNames({ 'short-urls-table__header-cell--with-action': !!orderByColumn });
|
||||||
const orderableColumnsClasses = classNames('short-urls-table__header-cell', actionableFieldClasses);
|
const orderableColumnsClasses = classNames('short-urls-table__header-cell', actionableFieldClasses);
|
||||||
const tableClasses = classNames('table table-hover responsive-table', className);
|
const tableClasses = classNames('table table-hover responsive-table', className);
|
||||||
const supportsTitle = supportsShortUrlTitle(selectedServer);
|
|
||||||
|
|
||||||
const renderShortUrls = () => {
|
const renderShortUrls = () => {
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -70,21 +68,15 @@ export const ShortUrlsTable = (ShortUrlsRow: FC<ShortUrlsRowProps>) => ({
|
||||||
<th className={orderableColumnsClasses} onClick={orderByColumn?.('shortCode')}>
|
<th className={orderableColumnsClasses} onClick={orderByColumn?.('shortCode')}>
|
||||||
Short URL {renderOrderIcon?.('shortCode')}
|
Short URL {renderOrderIcon?.('shortCode')}
|
||||||
</th>
|
</th>
|
||||||
{!supportsTitle ? (
|
<th className="short-urls-table__header-cell">
|
||||||
<th className={orderableColumnsClasses} onClick={orderByColumn?.('longUrl')}>
|
<span className={actionableFieldClasses} onClick={orderByColumn?.('title')}>
|
||||||
Long URL {renderOrderIcon?.('longUrl')}
|
Title {renderOrderIcon?.('title')}
|
||||||
</th>
|
</span>
|
||||||
) : (
|
/
|
||||||
<th className="short-urls-table__header-cell">
|
<span className={actionableFieldClasses} onClick={orderByColumn?.('longUrl')}>
|
||||||
<span className={actionableFieldClasses} onClick={orderByColumn?.('title')}>
|
<span className="indivisible">Long URL</span> {renderOrderIcon?.('longUrl')}
|
||||||
Title {renderOrderIcon?.('title')}
|
</span>
|
||||||
</span>
|
</th>
|
||||||
/
|
|
||||||
<span className={actionableFieldClasses} onClick={orderByColumn?.('longUrl')}>
|
|
||||||
<span className="indivisible">Long URL</span> {renderOrderIcon?.('longUrl')}
|
|
||||||
</span>
|
|
||||||
</th>
|
|
||||||
)}
|
|
||||||
<th className="short-urls-table__header-cell">Tags</th>
|
<th className="short-urls-table__header-cell">Tags</th>
|
||||||
<th className={orderableColumnsClasses} onClick={orderByColumn?.('visits')}>
|
<th className={orderableColumnsClasses} onClick={orderByColumn?.('visits')}>
|
||||||
<span className="indivisible">Visits {renderOrderIcon?.('visits')}</span>
|
<span className="indivisible">Visits {renderOrderIcon?.('visits')}</span>
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { SemVerPattern, versionMatch } from './version';
|
||||||
const serverMatchesMinVersion = (minVersion: SemVerPattern) => (selectedServer: SelectedServer): boolean =>
|
const serverMatchesMinVersion = (minVersion: SemVerPattern) => (selectedServer: SelectedServer): boolean =>
|
||||||
isReachableServer(selectedServer) && versionMatch(selectedServer.version, { minVersion });
|
isReachableServer(selectedServer) && versionMatch(selectedServer.version, { minVersion });
|
||||||
|
|
||||||
export const supportsShortUrlTitle = serverMatchesMinVersion('2.6.0');
|
|
||||||
export const supportsBotVisits = serverMatchesMinVersion('2.7.0');
|
export const supportsBotVisits = serverMatchesMinVersion('2.7.0');
|
||||||
export const supportsCrawlableVisits = supportsBotVisits;
|
export const supportsCrawlableVisits = supportsBotVisits;
|
||||||
export const supportsQrErrorCorrection = serverMatchesMinVersion('2.8.0');
|
export const supportsQrErrorCorrection = serverMatchesMinVersion('2.8.0');
|
||||||
|
|
|
@ -66,16 +66,12 @@ describe('<ShortUrlForm />', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
[null, 'create' as Mode, 4],
|
['create' as Mode, 4],
|
||||||
[null, 'create-basic' as Mode, 0],
|
['create-basic' as Mode, 0],
|
||||||
[Mock.of<ReachableServer>({ version: '2.6.0' }), 'create' as Mode, 4],
|
|
||||||
[Mock.of<ReachableServer>({ version: '2.5.0' }), 'create' as Mode, 4],
|
|
||||||
[Mock.of<ReachableServer>({ version: '2.6.0' }), 'edit' as Mode, 4],
|
|
||||||
[Mock.of<ReachableServer>({ version: '2.5.0' }), 'edit' as Mode, 3],
|
|
||||||
])(
|
])(
|
||||||
'renders expected amount of cards based on server capabilities and mode',
|
'renders expected amount of cards based on server capabilities and mode',
|
||||||
(selectedServer, mode, expectedAmountOfCards) => {
|
(mode, expectedAmountOfCards) => {
|
||||||
const wrapper = createWrapper(selectedServer, mode);
|
const wrapper = createWrapper(null, mode);
|
||||||
const cards = wrapper.find(SimpleCard);
|
const cards = wrapper.find(SimpleCard);
|
||||||
|
|
||||||
expect(cards).toHaveLength(expectedAmountOfCards);
|
expect(cards).toHaveLength(expectedAmountOfCards);
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { ShortUrlsTable as shortUrlsTableCreator } from '../../src/short-urls/ShortUrlsTable';
|
import { ShortUrlsTable as shortUrlsTableCreator } from '../../src/short-urls/ShortUrlsTable';
|
||||||
import { ShortUrlsList } from '../../src/short-urls/reducers/shortUrlsList';
|
import { ShortUrlsList } from '../../src/short-urls/reducers/shortUrlsList';
|
||||||
import { ReachableServer, SelectedServer } from '../../src/servers/data';
|
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';
|
import { ShortUrlsOrderableFields, SHORT_URLS_ORDERABLE_FIELDS } from '../../src/short-urls/data';
|
||||||
|
|
||||||
describe('<ShortUrlsTable />', () => {
|
describe('<ShortUrlsTable />', () => {
|
||||||
|
@ -61,13 +60,8 @@ describe('<ShortUrlsTable />', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([
|
it('should render composed title column', () => {
|
||||||
['2.6.0' as SemVer],
|
const wrapper = createWrapper(Mock.of<ReachableServer>({ version: '2.0.0' }));
|
||||||
['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<ReachableServer>({ version }));
|
|
||||||
const composedColumn = wrapper.find('table').find('th').at(2);
|
const composedColumn = wrapper.find('table').find('th').at(2);
|
||||||
const text = composedColumn.text();
|
const text = composedColumn.text();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue