Removed check on title support

This commit is contained in:
Alejandro Celaya 2022-05-01 11:00:46 +02:00
parent 763ef207f1
commit b970b38c29
5 changed files with 44 additions and 71 deletions

View file

@ -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."

View file

@ -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>
) : ( &nbsp;&nbsp;/&nbsp;&nbsp;
<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>
&nbsp;&nbsp;/&nbsp;&nbsp;
<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>

View file

@ -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');

View file

@ -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);

View file

@ -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();