mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2025-01-10 18:27:25 +03:00
Added form to create short URLs to overview page
This commit is contained in:
parent
9b30a82a79
commit
17d5c4327b
5 changed files with 109 additions and 88 deletions
|
@ -7,6 +7,7 @@ import { prettify } from '../utils/helpers/numbers';
|
|||
import { TagsList } from '../tags/reducers/tagsList';
|
||||
import { ShortUrlsTableProps } from '../short-urls/ShortUrlsTable';
|
||||
import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub';
|
||||
import { CreateShortUrlProps } from '../short-urls/CreateShortUrl';
|
||||
import { VisitsOverview } from '../visits/reducers/visitsOverview';
|
||||
import { isServerWithId, SelectedServer } from './data';
|
||||
import './Overview.scss';
|
||||
|
@ -21,7 +22,10 @@ interface OverviewConnectProps {
|
|||
loadVisitsOverview: Function;
|
||||
}
|
||||
|
||||
export const Overview = (ShortUrlsTable: FC<ShortUrlsTableProps>) => boundToMercureHub(({
|
||||
export const Overview = (
|
||||
ShortUrlsTable: FC<ShortUrlsTableProps>,
|
||||
CreateShortUrl: FC<CreateShortUrlProps>,
|
||||
) => boundToMercureHub(({
|
||||
shortUrlsList,
|
||||
listShortUrls,
|
||||
listTags,
|
||||
|
@ -67,10 +71,12 @@ export const Overview = (ShortUrlsTable: FC<ShortUrlsTableProps>) => boundToMerc
|
|||
</div>
|
||||
<Card className="mb-4">
|
||||
<CardHeader>
|
||||
Create short URL
|
||||
Create a short URL
|
||||
<Link className="float-right" to={`/server/${serverId}/create-short-url`}>Advanced options »</Link>
|
||||
</CardHeader>
|
||||
<CardBody>Create</CardBody>
|
||||
<CardBody>
|
||||
<CreateShortUrl basicMode />
|
||||
</CardBody>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader>
|
||||
|
|
|
@ -44,7 +44,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator, withRouter:
|
|||
bottle.serviceFactory('ServerError', ServerError, 'DeleteServerButton');
|
||||
bottle.decorator('ServerError', connect([ 'servers', 'selectedServer' ]));
|
||||
|
||||
bottle.serviceFactory('Overview', Overview, 'ShortUrlsTable');
|
||||
bottle.serviceFactory('Overview', Overview, 'ShortUrlsTable', 'CreateShortUrl');
|
||||
bottle.decorator('Overview', connect(
|
||||
[ 'shortUrlsList', 'tagsList', 'selectedServer', 'mercureInfo', 'visitsOverview' ],
|
||||
[ 'listShortUrls', 'listTags', 'createNewVisits', 'loadMercureInfo', 'loadVisitsOverview' ],
|
||||
|
|
|
@ -17,15 +17,19 @@ import UseExistingIfFoundInfoIcon from './UseExistingIfFoundInfoIcon';
|
|||
import { CreateShortUrlResultProps } from './helpers/CreateShortUrlResult';
|
||||
import './CreateShortUrl.scss';
|
||||
|
||||
const normalizeTag = pipe(trim, replace(/ /g, '-'));
|
||||
export interface CreateShortUrlProps {
|
||||
basicMode?: boolean;
|
||||
}
|
||||
|
||||
interface CreateShortUrlProps {
|
||||
interface CreateShortUrlConnectProps extends CreateShortUrlProps {
|
||||
shortUrlCreationResult: ShortUrlCreation;
|
||||
selectedServer: SelectedServer;
|
||||
createShortUrl: Function;
|
||||
createShortUrl: (data: ShortUrlData) => Promise<void>;
|
||||
resetCreateShortUrl: () => void;
|
||||
}
|
||||
|
||||
export const normalizeTag = pipe(trim, replace(/ /g, '-'));
|
||||
|
||||
const initialState: ShortUrlData = {
|
||||
longUrl: '',
|
||||
tags: [],
|
||||
|
@ -47,7 +51,13 @@ const CreateShortUrl = (
|
|||
CreateShortUrlResult: FC<CreateShortUrlResultProps>,
|
||||
ForServerVersion: FC<Versions>,
|
||||
DomainSelector: FC<DomainSelectorProps>,
|
||||
) => ({ createShortUrl, shortUrlCreationResult, resetCreateShortUrl, selectedServer }: CreateShortUrlProps) => {
|
||||
) => ({
|
||||
createShortUrl,
|
||||
shortUrlCreationResult,
|
||||
resetCreateShortUrl,
|
||||
selectedServer,
|
||||
basicMode = false,
|
||||
}: CreateShortUrlConnectProps) => {
|
||||
const [ shortUrlCreation, setShortUrlCreation ] = useState(initialState);
|
||||
|
||||
const changeTags = (tags: string[]) => setShortUrlCreation({ ...shortUrlCreation, tags: tags.map(normalizeTag) });
|
||||
|
@ -55,8 +65,8 @@ const CreateShortUrl = (
|
|||
const save = handleEventPreventingDefault(() => {
|
||||
const shortUrlData = {
|
||||
...shortUrlCreation,
|
||||
validSince: formatIsoDate(shortUrlCreation.validSince),
|
||||
validUntil: formatIsoDate(shortUrlCreation.validUntil),
|
||||
validSince: formatIsoDate(shortUrlCreation.validSince) ?? undefined,
|
||||
validUntil: formatIsoDate(shortUrlCreation.validUntil) ?? undefined,
|
||||
};
|
||||
|
||||
createShortUrl(shortUrlData).then(reset).catch(() => {});
|
||||
|
@ -92,90 +102,94 @@ const CreateShortUrl = (
|
|||
|
||||
return (
|
||||
<form onSubmit={save}>
|
||||
<div className="form-group">
|
||||
<input
|
||||
className="form-control form-control-lg"
|
||||
<FormGroup>
|
||||
<Input
|
||||
bsSize="lg"
|
||||
type="url"
|
||||
placeholder="Insert the URL to be shortened"
|
||||
required
|
||||
value={shortUrlCreation.longUrl}
|
||||
onChange={(e) => setShortUrlCreation({ ...shortUrlCreation, longUrl: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
</FormGroup>
|
||||
|
||||
<div className="form-group">
|
||||
<FormGroup>
|
||||
<TagsSelector tags={shortUrlCreation.tags ?? []} onChange={changeTags} />
|
||||
</div>
|
||||
</FormGroup>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-sm-4">
|
||||
{renderOptionalInput('customSlug', 'Custom slug', 'text', {
|
||||
disabled: hasValue(shortUrlCreation.shortCodeLength),
|
||||
})}
|
||||
</div>
|
||||
<div className="col-sm-4">
|
||||
{renderOptionalInput('shortCodeLength', 'Short code length', 'number', {
|
||||
min: 4,
|
||||
disabled: disableShortCodeLength || hasValue(shortUrlCreation.customSlug),
|
||||
...disableShortCodeLength && {
|
||||
title: 'Shlink 2.1.0 or higher is required to be able to provide the short code length',
|
||||
},
|
||||
})}
|
||||
</div>
|
||||
<div className="col-sm-4">
|
||||
{!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 && (
|
||||
<FormGroup>
|
||||
<DomainSelector
|
||||
value={shortUrlCreation.domain}
|
||||
onChange={(domain?: string) => setShortUrlCreation({ ...shortUrlCreation, domain })}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-sm-4">
|
||||
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
|
||||
</div>
|
||||
<div className="col-sm-4">
|
||||
{renderDateInput('validSince', 'Enabled since...', { maxDate: shortUrlCreation.validUntil as m.Moment | undefined })}
|
||||
</div>
|
||||
<div className="col-sm-4">
|
||||
{renderDateInput('validUntil', 'Enabled until...', { minDate: shortUrlCreation.validSince as m.Moment | undefined })}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ForServerVersion minVersion="1.16.0">
|
||||
<div className="mb-4 row">
|
||||
<div className="col-sm-6 text-center text-sm-left mb-2 mb-sm-0">
|
||||
<ForServerVersion minVersion="2.4.0">
|
||||
<Checkbox
|
||||
inline
|
||||
checked={shortUrlCreation.validateUrl}
|
||||
onChange={(validateUrl) => setShortUrlCreation({ ...shortUrlCreation, validateUrl })}
|
||||
>
|
||||
Validate URL
|
||||
</Checkbox>
|
||||
</ForServerVersion>
|
||||
{!basicMode && (
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-sm-4">
|
||||
{renderOptionalInput('customSlug', 'Custom slug', 'text', {
|
||||
disabled: hasValue(shortUrlCreation.shortCodeLength),
|
||||
})}
|
||||
</div>
|
||||
<div className="col-sm-4">
|
||||
{renderOptionalInput('shortCodeLength', 'Short code length', 'number', {
|
||||
min: 4,
|
||||
disabled: disableShortCodeLength || hasValue(shortUrlCreation.customSlug),
|
||||
...disableShortCodeLength && {
|
||||
title: 'Shlink 2.1.0 or higher is required to be able to provide the short code length',
|
||||
},
|
||||
})}
|
||||
</div>
|
||||
<div className="col-sm-4">
|
||||
{!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 && (
|
||||
<FormGroup>
|
||||
<DomainSelector
|
||||
value={shortUrlCreation.domain}
|
||||
onChange={(domain?: string) => setShortUrlCreation({ ...shortUrlCreation, domain })}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-sm-6 text-center text-sm-right">
|
||||
<Checkbox
|
||||
inline
|
||||
className="mr-2"
|
||||
checked={shortUrlCreation.findIfExists}
|
||||
onChange={(findIfExists) => setShortUrlCreation({ ...shortUrlCreation, findIfExists })}
|
||||
>
|
||||
Use existing URL if found
|
||||
</Checkbox>
|
||||
<UseExistingIfFoundInfoIcon />
|
||||
|
||||
<div className="row">
|
||||
<div className="col-sm-4">
|
||||
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
|
||||
</div>
|
||||
<div className="col-sm-4">
|
||||
{renderDateInput('validSince', 'Enabled since...', { maxDate: shortUrlCreation.validUntil as m.Moment | undefined })}
|
||||
</div>
|
||||
<div className="col-sm-4">
|
||||
{renderDateInput('validUntil', 'Enabled until...', { minDate: shortUrlCreation.validSince as m.Moment | undefined })}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ForServerVersion>
|
||||
|
||||
<ForServerVersion minVersion="1.16.0">
|
||||
<div className="mb-4 row">
|
||||
<div className="col-sm-6 text-center text-sm-left mb-2 mb-sm-0">
|
||||
<ForServerVersion minVersion="2.4.0">
|
||||
<Checkbox
|
||||
inline
|
||||
checked={shortUrlCreation.validateUrl}
|
||||
onChange={(validateUrl) => setShortUrlCreation({ ...shortUrlCreation, validateUrl })}
|
||||
>
|
||||
Validate URL
|
||||
</Checkbox>
|
||||
</ForServerVersion>
|
||||
</div>
|
||||
<div className="col-sm-6 text-center text-sm-right">
|
||||
<Checkbox
|
||||
inline
|
||||
className="mr-2"
|
||||
checked={shortUrlCreation.findIfExists}
|
||||
onChange={(findIfExists) => setShortUrlCreation({ ...shortUrlCreation, findIfExists })}
|
||||
>
|
||||
Use existing URL if found
|
||||
</Checkbox>
|
||||
<UseExistingIfFoundInfoIcon />
|
||||
</div>
|
||||
</div>
|
||||
</ForServerVersion>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="text-right">
|
||||
<Button
|
||||
|
|
|
@ -25,10 +25,6 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
|||
bottle.serviceFactory('ShortUrls', ShortUrls, 'SearchBar', 'ShortUrlsList');
|
||||
bottle.decorator('ShortUrls', connect([ 'shortUrlsList' ]));
|
||||
|
||||
// Services
|
||||
bottle.serviceFactory('SearchBar', SearchBar, 'ColorGenerator', 'ForServerVersion');
|
||||
bottle.decorator('SearchBar', connect([ 'shortUrlsListParams' ], [ 'listShortUrls' ]));
|
||||
|
||||
bottle.serviceFactory('ShortUrlsList', ShortUrlsList, 'ShortUrlsTable');
|
||||
bottle.decorator('ShortUrlsList', connect(
|
||||
[ 'selectedServer', 'shortUrlsListParams', 'mercureInfo' ],
|
||||
|
@ -73,6 +69,10 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
|||
bottle.serviceFactory('EditShortUrlModal', () => EditShortUrlModal);
|
||||
bottle.decorator('EditShortUrlModal', connect([ 'shortUrlEdition' ], [ 'editShortUrl' ]));
|
||||
|
||||
// Services
|
||||
bottle.serviceFactory('SearchBar', SearchBar, 'ColorGenerator', 'ForServerVersion');
|
||||
bottle.decorator('SearchBar', connect([ 'shortUrlsListParams' ], [ 'listShortUrls' ]));
|
||||
|
||||
// Actions
|
||||
bottle.serviceFactory('editShortUrlTags', editShortUrlTags, 'buildShlinkApiClient');
|
||||
bottle.serviceFactory('resetShortUrlsTags', () => resetShortUrlsTags);
|
||||
|
|
|
@ -2,6 +2,7 @@ import { shallow, ShallowWrapper } from 'enzyme';
|
|||
import moment from 'moment';
|
||||
import { identity } from 'ramda';
|
||||
import { Mock } from 'ts-mockery';
|
||||
import { Input } from 'reactstrap';
|
||||
import createShortUrlsCreator from '../../src/short-urls/CreateShortUrl';
|
||||
import DateInput from '../../src/utils/DateInput';
|
||||
import { ShortUrlCreation } from '../../src/short-urls/reducers/shortUrlCreation';
|
||||
|
@ -31,7 +32,7 @@ describe('<CreateShortUrl />', () => {
|
|||
const validSince = moment('2017-01-01');
|
||||
const validUntil = moment('2017-01-06');
|
||||
|
||||
wrapper.find('.form-control-lg').simulate('change', { target: { value: 'https://long-domain.com/foo/bar' } });
|
||||
wrapper.find(Input).first().simulate('change', { target: { value: 'https://long-domain.com/foo/bar' } });
|
||||
wrapper.find('TagsSelector').simulate('change', [ 'tag_foo', 'tag_bar' ]);
|
||||
wrapper.find('#customSlug').simulate('change', { target: { value: 'my-slug' } });
|
||||
wrapper.find('#domain').simulate('change', { target: { value: 'example.com' } });
|
||||
|
|
Loading…
Reference in a new issue