Ensured filter for bots does not show for Shlink older than 2.7.0

This commit is contained in:
Alejandro Celaya 2021-06-22 21:01:20 +02:00
parent 638ce89780
commit affe2309b0
5 changed files with 39 additions and 10 deletions

View file

@ -16,6 +16,7 @@ import { Result } from '../utils/Result';
import { ShlinkApiError } from '../api/ShlinkApiError'; import { ShlinkApiError } from '../api/ShlinkApiError';
import { Settings } from '../settings/reducers/settings'; import { Settings } from '../settings/reducers/settings';
import { SelectedServer } from '../servers/data'; import { SelectedServer } from '../servers/data';
import { supportsBotVisits } from '../utils/helpers/features';
import SortableBarGraph from './helpers/SortableBarGraph'; import SortableBarGraph from './helpers/SortableBarGraph';
import GraphCard from './helpers/GraphCard'; import GraphCard from './helpers/GraphCard';
import LineChartCard from './helpers/LineChartCard'; import LineChartCard from './helpers/LineChartCard';
@ -86,6 +87,7 @@ const VisitsStats: FC<VisitsStatsProps> = ({
const [ highlightedVisits, setHighlightedVisits ] = useState<NormalizedVisit[]>([]); const [ highlightedVisits, setHighlightedVisits ] = useState<NormalizedVisit[]>([]);
const [ highlightedLabel, setHighlightedLabel ] = useState<string | undefined>(); const [ highlightedLabel, setHighlightedLabel ] = useState<string | undefined>();
const [ visitsFilter, setVisitsFilter ] = useState<VisitsFilter>({}); const [ visitsFilter, setVisitsFilter ] = useState<VisitsFilter>({});
const botsSupported = supportsBotVisits(selectedServer);
const buildSectionUrl = (subPath?: string) => { const buildSectionUrl = (subPath?: string) => {
const query = domain ? `?domain=${domain}` : ''; const query = domain ? `?domain=${domain}` : '';
@ -282,6 +284,7 @@ const VisitsStats: FC<VisitsStatsProps> = ({
<VisitsFilterDropdown <VisitsFilterDropdown
className="ml-0 ml-md-2 mt-3 mt-md-0" className="ml-0 ml-md-2 mt-3 mt-md-0"
isOrphanVisits={isOrphanVisits} isOrphanVisits={isOrphanVisits}
botsSupported={botsSupported}
selected={visitsFilter} selected={visitsFilter}
onChange={setVisitsFilter} onChange={setVisitsFilter}
/> />

View file

@ -13,28 +13,36 @@ interface VisitsFilterDropdownProps {
selected?: VisitsFilter; selected?: VisitsFilter;
className?: string; className?: string;
isOrphanVisits: boolean; isOrphanVisits: boolean;
botsSupported: boolean;
} }
export const VisitsFilterDropdown = ( export const VisitsFilterDropdown = (
{ onChange, selected = {}, className, isOrphanVisits }: VisitsFilterDropdownProps, { onChange, selected = {}, className, isOrphanVisits, botsSupported }: VisitsFilterDropdownProps,
) => { ) => {
if (!botsSupported && !isOrphanVisits) {
return null;
}
const { orphanVisitsType, excludeBots = false } = selected; const { orphanVisitsType, excludeBots = false } = selected;
const propsForOrphanVisitsTypeItem = (type: OrphanVisitType): DropdownItemProps => ({ const propsForOrphanVisitsTypeItem = (type: OrphanVisitType): DropdownItemProps => ({
active: orphanVisitsType === type, active: orphanVisitsType === type,
onClick: () => onChange({ ...selected, orphanVisitsType: type }), onClick: () => onChange({ ...selected, orphanVisitsType: type }),
}); });
const onBotsClick = () => onChange({ ...selected, excludeBots: !selected?.excludeBots });
return ( return (
<DropdownBtn text="Filters" dropdownClassName={className} className="mr-3" right minWidth={250}> <DropdownBtn text="Filters" dropdownClassName={className} className="mr-3" right minWidth={250}>
{botsSupported && (
<>
<DropdownItem header>Bots:</DropdownItem> <DropdownItem header>Bots:</DropdownItem>
<DropdownItem active={excludeBots} onClick={() => onChange({ ...selected, excludeBots: !selected?.excludeBots })}> <DropdownItem active={excludeBots} onClick={onBotsClick}>Exclude potential bots</DropdownItem>
Exclude potential bots </>
</DropdownItem> )}
{botsSupported && isOrphanVisits && <DropdownItem divider />}
{isOrphanVisits && ( {isOrphanVisits && (
<> <>
<DropdownItem divider />
<DropdownItem header>Orphan visits type:</DropdownItem> <DropdownItem header>Orphan visits type:</DropdownItem>
<DropdownItem {...propsForOrphanVisitsTypeItem('base_url')}>Base URL</DropdownItem> <DropdownItem {...propsForOrphanVisitsTypeItem('base_url')}>Base URL</DropdownItem>
<DropdownItem {...propsForOrphanVisitsTypeItem('invalid_short_url')}>Invalid short URL</DropdownItem> <DropdownItem {...propsForOrphanVisitsTypeItem('invalid_short_url')}>Invalid short URL</DropdownItem>

View file

@ -14,7 +14,7 @@ describe('<EditShortUrl />', () => {
const ShortUrlForm = () => null; const ShortUrlForm = () => null;
const goBack = jest.fn(); const goBack = jest.fn();
const getShortUrlDetail = jest.fn(); const getShortUrlDetail = jest.fn();
const editShortUrl = jest.fn(); const editShortUrl = jest.fn(async () => Promise.resolve());
const shortUrlCreation = { validateUrls: true }; const shortUrlCreation = { validateUrls: true };
const createWrapper = (detail: Partial<ShortUrlDetail> = {}, edition: Partial<ShortUrlEdition> = {}) => { const createWrapper = (detail: Partial<ShortUrlDetail> = {}, edition: Partial<ShortUrlEdition> = {}) => {
const EditSHortUrl = createEditShortUrl(ShortUrlForm); const EditSHortUrl = createEditShortUrl(ShortUrlForm);

View file

@ -12,7 +12,7 @@ import { SimpleCard } from '../../src/utils/SimpleCard';
describe('<ShortUrlForm />', () => { describe('<ShortUrlForm />', () => {
let wrapper: ShallowWrapper; let wrapper: ShallowWrapper;
const TagsSelector = () => null; const TagsSelector = () => null;
const createShortUrl = jest.fn(); const createShortUrl = jest.fn(async () => Promise.resolve());
const createWrapper = (selectedServer: SelectedServer = null, mode: Mode = 'create') => { const createWrapper = (selectedServer: SelectedServer = null, mode: Mode = 'create') => {
const ShortUrlForm = createShortUrlForm(TagsSelector, () => null); const ShortUrlForm = createShortUrlForm(TagsSelector, () => null);

View file

@ -8,7 +8,12 @@ describe('<VisitsFilterDropdown />', () => {
const onChange = jest.fn(); const onChange = jest.fn();
const createWrapper = (selected: VisitsFilter = {}, isOrphanVisits = true) => { const createWrapper = (selected: VisitsFilter = {}, isOrphanVisits = true) => {
wrapper = shallow( wrapper = shallow(
<VisitsFilterDropdown isOrphanVisits={isOrphanVisits} selected={selected} onChange={onChange} />, <VisitsFilterDropdown
isOrphanVisits={isOrphanVisits}
botsSupported={true}
selected={selected}
onChange={onChange}
/>,
); );
return wrapper; return wrapper;
@ -68,4 +73,17 @@ describe('<VisitsFilterDropdown />', () => {
expect(onChange).toHaveBeenCalledWith(expectedSelection); expect(onChange).toHaveBeenCalledWith(expectedSelection);
}); });
it('does not render the component when neither orphan visits or bots filtering will be displayed', () => {
const wrapper = shallow(
<VisitsFilterDropdown
isOrphanVisits={false}
botsSupported={false}
selected={{}}
onChange={onChange}
/>,
);
expect(wrapper.text()).toEqual('');
});
}); });