mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2025-01-10 18:27:25 +03:00
Added logic in ManageDomains and DomainRow components to check if the domains status
This commit is contained in:
parent
c05c74f009
commit
a78467065a
5 changed files with 59 additions and 26 deletions
|
@ -1,22 +1,26 @@
|
|||
import { FC } from 'react';
|
||||
import { FC, useEffect } from 'react';
|
||||
import { Button, UncontrolledTooltip } from 'reactstrap';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
faBan as forbiddenIcon,
|
||||
faCheck as defaultDomainIcon,
|
||||
faDotCircle as defaultDomainIcon,
|
||||
faCheck as checkIcon,
|
||||
faCircleNotch as loadingStatusIcon,
|
||||
faEdit as editIcon,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { ShlinkDomain, ShlinkDomainRedirects } from '../api/types';
|
||||
import { ShlinkDomainRedirects } from '../api/types';
|
||||
import { useToggle } from '../utils/helpers/hooks';
|
||||
import { OptionalString } from '../utils/utils';
|
||||
import { SelectedServer } from '../servers/data';
|
||||
import { supportsDefaultDomainRedirectsEdition } from '../utils/helpers/features';
|
||||
import { EditDomainRedirectsModal } from './helpers/EditDomainRedirectsModal';
|
||||
import { Domain, DomainStatus } from './data';
|
||||
|
||||
interface DomainRowProps {
|
||||
domain: ShlinkDomain;
|
||||
domain: Domain;
|
||||
defaultRedirects?: ShlinkDomainRedirects;
|
||||
editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;
|
||||
checkDomainHealth: (domain: string) => void;
|
||||
selectedServer: SelectedServer;
|
||||
}
|
||||
|
||||
|
@ -32,12 +36,27 @@ const DefaultDomain: FC = () => (
|
|||
<UncontrolledTooltip target="defaultDomainIcon" placement="right">Default domain</UncontrolledTooltip>
|
||||
</>
|
||||
);
|
||||
const StatusIcon: FC<{ status: DomainStatus }> = ({ status }) => {
|
||||
if (status === 'validating') {
|
||||
return <FontAwesomeIcon fixedWidth icon={loadingStatusIcon} spin />;
|
||||
}
|
||||
|
||||
export const DomainRow: FC<DomainRowProps> = ({ domain, editDomainRedirects, defaultRedirects, selectedServer }) => {
|
||||
return status === 'valid'
|
||||
? <FontAwesomeIcon fixedWidth icon={checkIcon} className="text-muted" />
|
||||
: <FontAwesomeIcon fixedWidth icon={forbiddenIcon} className="text-danger" />;
|
||||
};
|
||||
|
||||
export const DomainRow: FC<DomainRowProps> = (
|
||||
{ domain, editDomainRedirects, checkDomainHealth, defaultRedirects, selectedServer },
|
||||
) => {
|
||||
const [ isOpen, toggle ] = useToggle();
|
||||
const { domain: authority, isDefault, redirects } = domain;
|
||||
const { domain: authority, isDefault, redirects, status } = domain;
|
||||
const canEditDomain = !isDefault || supportsDefaultDomainRedirectsEdition(selectedServer);
|
||||
|
||||
useEffect(() => {
|
||||
checkDomainHealth(domain.domain);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<tr className="responsive-table__row">
|
||||
<td className="responsive-table__cell" data-th="Is default domain">{isDefault ? <DefaultDomain /> : ''}</td>
|
||||
|
@ -51,6 +70,9 @@ export const DomainRow: FC<DomainRowProps> = ({ domain, editDomainRedirects, def
|
|||
<td className="responsive-table__cell" data-th="Invalid short URL redirect">
|
||||
{redirects?.invalidShortUrlRedirect ?? <Nr fallback={defaultRedirects?.invalidShortUrlRedirect} />}
|
||||
</td>
|
||||
<td className="responsive-table__cell text-lg-center" data-th="Status">
|
||||
<StatusIcon status={status} />
|
||||
</td>
|
||||
<td className="responsive-table__cell text-right">
|
||||
<span id={!canEditDomain ? 'defaultDomainBtn' : undefined}>
|
||||
<Button outline size="sm" disabled={!canEditDomain} onClick={!canEditDomain ? undefined : toggle}>
|
||||
|
|
|
@ -13,14 +13,15 @@ interface ManageDomainsProps {
|
|||
listDomains: Function;
|
||||
filterDomains: (searchTerm: string) => void;
|
||||
editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;
|
||||
checkDomainHealth: (domain: string) => void;
|
||||
domainsList: DomainsList;
|
||||
selectedServer: SelectedServer;
|
||||
}
|
||||
|
||||
const headers = [ '', 'Domain', 'Base path redirect', 'Regular 404 redirect', 'Invalid short URL redirect', '' ];
|
||||
const headers = [ '', 'Domain', 'Base path redirect', 'Regular 404 redirect', 'Invalid short URL redirect', '', '' ];
|
||||
|
||||
export const ManageDomains: FC<ManageDomainsProps> = (
|
||||
{ listDomains, domainsList, filterDomains, editDomainRedirects, selectedServer },
|
||||
{ listDomains, domainsList, filterDomains, editDomainRedirects, checkDomainHealth, selectedServer },
|
||||
) => {
|
||||
const { filteredDomains: domains, defaultRedirects, loading, error, errorData } = domainsList;
|
||||
const resolvedDefaultRedirects = defaultRedirects ?? domains.find(({ isDefault }) => isDefault)?.redirects;
|
||||
|
@ -55,6 +56,7 @@ export const ManageDomains: FC<ManageDomainsProps> = (
|
|||
key={domain.domain}
|
||||
domain={domain}
|
||||
editDomainRedirects={editDomainRedirects}
|
||||
checkDomainHealth={checkDomainHealth}
|
||||
defaultRedirects={resolvedDefaultRedirects}
|
||||
selectedServer={selectedServer}
|
||||
/>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Bottle from 'bottlejs';
|
||||
import { ConnectDecorator } from '../../container/types';
|
||||
import { filterDomains, listDomains } from '../reducers/domainsList';
|
||||
import { checkDomainHealth, filterDomains, listDomains } from '../reducers/domainsList';
|
||||
import { DomainSelector } from '../DomainSelector';
|
||||
import { ManageDomains } from '../ManageDomains';
|
||||
import { editDomainRedirects } from '../reducers/domainRedirects';
|
||||
|
@ -13,13 +13,14 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
|
|||
bottle.serviceFactory('ManageDomains', () => ManageDomains);
|
||||
bottle.decorator('ManageDomains', connect(
|
||||
[ 'domainsList', 'selectedServer' ],
|
||||
[ 'listDomains', 'filterDomains', 'editDomainRedirects' ],
|
||||
[ 'listDomains', 'filterDomains', 'editDomainRedirects', 'checkDomainHealth' ],
|
||||
));
|
||||
|
||||
// Actions
|
||||
bottle.serviceFactory('listDomains', listDomains, 'buildShlinkApiClient');
|
||||
bottle.serviceFactory('filterDomains', () => filterDomains);
|
||||
bottle.serviceFactory('editDomainRedirects', editDomainRedirects, 'buildShlinkApiClient');
|
||||
bottle.serviceFactory('checkDomainHealth', checkDomainHealth, 'buildShlinkApiClient');
|
||||
};
|
||||
|
||||
export default provideServices;
|
||||
|
|
|
@ -3,14 +3,22 @@ import { Mock } from 'ts-mockery';
|
|||
import { Button, UncontrolledTooltip } from 'reactstrap';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faBan as forbiddenIcon, faEdit as editIcon } from '@fortawesome/free-solid-svg-icons';
|
||||
import { ShlinkDomain, ShlinkDomainRedirects } from '../../src/api/types';
|
||||
import { ShlinkDomainRedirects } from '../../src/api/types';
|
||||
import { DomainRow } from '../../src/domains/DomainRow';
|
||||
import { ReachableServer, SelectedServer } from '../../src/servers/data';
|
||||
import { Domain } from '../../src/domains/data';
|
||||
|
||||
describe('<DomainRow />', () => {
|
||||
let wrapper: ShallowWrapper;
|
||||
const createWrapper = (domain: ShlinkDomain, selectedServer = Mock.all<SelectedServer>()) => {
|
||||
wrapper = shallow(<DomainRow domain={domain} editDomainRedirects={jest.fn()} selectedServer={selectedServer} />);
|
||||
const createWrapper = (domain: Domain, selectedServer = Mock.all<SelectedServer>()) => {
|
||||
wrapper = shallow(
|
||||
<DomainRow
|
||||
domain={domain}
|
||||
selectedServer={selectedServer}
|
||||
editDomainRedirects={jest.fn()}
|
||||
checkDomainHealth={jest.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
return wrapper;
|
||||
};
|
||||
|
@ -18,34 +26,34 @@ describe('<DomainRow />', () => {
|
|||
afterEach(() => wrapper?.unmount());
|
||||
|
||||
it.each([
|
||||
[ Mock.of<ShlinkDomain>({ domain: '', isDefault: true }), undefined, 1, 1, 'defaultDomainBtn' ],
|
||||
[ Mock.of<ShlinkDomain>({ domain: '', isDefault: false }), undefined, 0, 0, undefined ],
|
||||
[ Mock.of<ShlinkDomain>({ domain: 'foo.com', isDefault: true }), undefined, 1, 1, 'defaultDomainBtn' ],
|
||||
[ Mock.of<ShlinkDomain>({ domain: 'foo.bar.com', isDefault: true }), undefined, 1, 1, 'defaultDomainBtn' ],
|
||||
[ Mock.of<ShlinkDomain>({ domain: 'foo.baz', isDefault: false }), undefined, 0, 0, undefined ],
|
||||
[ Mock.of<Domain>({ domain: '', isDefault: true }), undefined, 1, 1, 'defaultDomainBtn' ],
|
||||
[ Mock.of<Domain>({ domain: '', isDefault: false }), undefined, 0, 0, undefined ],
|
||||
[ Mock.of<Domain>({ domain: 'foo.com', isDefault: true }), undefined, 1, 1, 'defaultDomainBtn' ],
|
||||
[ Mock.of<Domain>({ domain: 'foo.bar.com', isDefault: true }), undefined, 1, 1, 'defaultDomainBtn' ],
|
||||
[ Mock.of<Domain>({ domain: 'foo.baz', isDefault: false }), undefined, 0, 0, undefined ],
|
||||
[
|
||||
Mock.of<ShlinkDomain>({ domain: 'foo.baz', isDefault: true }),
|
||||
Mock.of<Domain>({ domain: 'foo.baz', isDefault: true }),
|
||||
Mock.of<ReachableServer>({ version: '2.10.0' }),
|
||||
1,
|
||||
0,
|
||||
undefined,
|
||||
],
|
||||
[
|
||||
Mock.of<ShlinkDomain>({ domain: 'foo.baz', isDefault: true }),
|
||||
Mock.of<Domain>({ domain: 'foo.baz', isDefault: true }),
|
||||
Mock.of<ReachableServer>({ version: '2.9.0' }),
|
||||
1,
|
||||
1,
|
||||
'defaultDomainBtn',
|
||||
],
|
||||
[
|
||||
Mock.of<ShlinkDomain>({ domain: 'foo.baz', isDefault: false }),
|
||||
Mock.of<Domain>({ domain: 'foo.baz', isDefault: false }),
|
||||
Mock.of<ReachableServer>({ version: '2.9.0' }),
|
||||
0,
|
||||
0,
|
||||
undefined,
|
||||
],
|
||||
[
|
||||
Mock.of<ShlinkDomain>({ domain: 'foo.baz', isDefault: false }),
|
||||
Mock.of<Domain>({ domain: 'foo.baz', isDefault: false }),
|
||||
Mock.of<ReachableServer>({ version: '2.10.0' }),
|
||||
0,
|
||||
0,
|
||||
|
@ -89,7 +97,7 @@ describe('<DomainRow />', () => {
|
|||
0,
|
||||
],
|
||||
])('shows expected redirects', (redirects, expectedNoRedirects) => {
|
||||
const wrapper = createWrapper(Mock.of<ShlinkDomain>({ domain: '', isDefault: true, redirects }));
|
||||
const wrapper = createWrapper(Mock.of<Domain>({ domain: '', isDefault: true, redirects }));
|
||||
const noRedirects = wrapper.find('Nr');
|
||||
const cells = wrapper.find('td');
|
||||
|
||||
|
|
|
@ -13,14 +13,14 @@ import { SelectedServer } from '../../src/servers/data';
|
|||
describe('<ManageDomains />', () => {
|
||||
const listDomains = jest.fn();
|
||||
const filterDomains = jest.fn();
|
||||
const editDomainRedirects = jest.fn();
|
||||
let wrapper: ShallowWrapper;
|
||||
const createWrapper = (domainsList: DomainsList) => {
|
||||
wrapper = shallow(
|
||||
<ManageDomains
|
||||
listDomains={listDomains}
|
||||
filterDomains={filterDomains}
|
||||
editDomainRedirects={editDomainRedirects}
|
||||
editDomainRedirects={jest.fn()}
|
||||
checkDomainHealth={jest.fn()}
|
||||
domainsList={domainsList}
|
||||
selectedServer={Mock.all<SelectedServer>()}
|
||||
/>,
|
||||
|
@ -77,7 +77,7 @@ describe('<ManageDomains />', () => {
|
|||
const wrapper = createWrapper(Mock.of<DomainsList>({ loading: false, error: false, filteredDomains: [] }));
|
||||
const headerCells = wrapper.find('th');
|
||||
|
||||
expect(headerCells).toHaveLength(6);
|
||||
expect(headerCells).toHaveLength(7);
|
||||
});
|
||||
|
||||
it('one row when list of domains is empty', () => {
|
||||
|
|
Loading…
Reference in a new issue