diff --git a/CHANGELOG.md b/CHANGELOG.md index 92ef8071..3048dbca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), * *Nothing* ### Removed -* [#736](https://github.com/shlinkio/shlink-web-client/issues/736) Removed support for cards mode in tags. Only tags table is supported now. +* [#736](https://github.com/shlinkio/shlink-web-client/issues/736) Removed cards mode in tags. Only table mode is supported now. +* [#774](https://github.com/shlinkio/shlink-web-client/issues/774) Dropped support for Shlink older than 2.8.0. ### Fixed * *Nothing* diff --git a/src/common/AsideMenu.tsx b/src/common/AsideMenu.tsx index f7c81965..2e36c27a 100644 --- a/src/common/AsideMenu.tsx +++ b/src/common/AsideMenu.tsx @@ -12,7 +12,6 @@ import { NavLink, NavLinkProps, useLocation } from 'react-router-dom'; import classNames from 'classnames'; import { DeleteServerButtonProps } from '../servers/DeleteServerButton'; import { isServerWithId, SelectedServer } from '../servers/data'; -import { supportsDomainRedirects } from '../utils/helpers/features'; import './AsideMenu.scss'; export interface AsideMenuProps { @@ -40,7 +39,6 @@ export const AsideMenu = (DeleteServerButton: FC) => ( const hasId = isServerWithId(selectedServer); const serverId = hasId ? selectedServer.id : ''; const { pathname } = useLocation(); - const addManageDomainsLink = supportsDomainRedirects(selectedServer); const asideClass = classNames('aside-menu', { 'aside-menu--hidden': !showOnMobile, }); @@ -68,12 +66,10 @@ export const AsideMenu = (DeleteServerButton: FC) => ( Manage tags - {addManageDomainsLink && ( - - - Manage domains - - )} + + + Manage domains + Edit this server diff --git a/src/common/MenuLayout.tsx b/src/common/MenuLayout.tsx index 03de8768..0fc05448 100644 --- a/src/common/MenuLayout.tsx +++ b/src/common/MenuLayout.tsx @@ -5,7 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import classNames from 'classnames'; import { withSelectedServer } from '../servers/helpers/withSelectedServer'; import { useSwipeable, useToggle } from '../utils/helpers/hooks'; -import { supportsDomainRedirects, supportsDomainVisits, supportsNonOrphanVisits } from '../utils/helpers/features'; +import { supportsDomainVisits, supportsNonOrphanVisits } from '../utils/helpers/features'; import { isReachableServer } from '../servers/data'; import { NotFound } from './NotFound'; import { AsideMenuProps } from './AsideMenu'; @@ -47,7 +47,6 @@ export const MenuLayout = ( } const addNonOrphanVisitsRoute = supportsNonOrphanVisits(selectedServer); - const addManageDomainsRoute = supportsDomainRedirects(selectedServer); const addDomainVisitsRoute = supportsDomainVisits(selectedServer); const burgerClasses = classNames('menu-layout__burger-icon', { 'menu-layout__burger-icon--active': sidebarVisible }); const swipeableProps = useSwipeable(showSidebar, hideSidebar); @@ -73,7 +72,7 @@ export const MenuLayout = ( } /> {addNonOrphanVisitsRoute && } />} } /> - {addManageDomainsRoute && } />} + } /> List short URLs} diff --git a/src/short-urls/ShortUrlForm.tsx b/src/short-urls/ShortUrlForm.tsx index 8c3f6635..f949de66 100644 --- a/src/short-urls/ShortUrlForm.tsx +++ b/src/short-urls/ShortUrlForm.tsx @@ -4,7 +4,7 @@ import { Button, FormGroup, Input, Row } from 'reactstrap'; import { cond, isEmpty, pipe, replace, trim, T } from 'ramda'; import { parseISO } from 'date-fns'; import { DateTimeInput, DateTimeInputProps } from '../utils/dates/DateTimeInput'; -import { supportsCrawlableVisits, supportsForwardQuery } from '../utils/helpers/features'; +import { supportsForwardQuery } from '../utils/helpers/features'; import { SimpleCard } from '../utils/SimpleCard'; import { handleEventPreventingDefault, hasValue, OptionalString } from '../utils/utils'; import { Checkbox } from '../utils/Checkbox'; @@ -113,16 +113,14 @@ export const ShortUrlForm = ( ); - const showCrawlableControl = supportsCrawlableVisits(selectedServer); const showForwardQueryControl = supportsForwardQuery(selectedServer); - const showBehaviorCard = showCrawlableControl || showForwardQueryControl; return (
{isBasicMode && basicComponents} {!isBasicMode && ( <> - + {basicComponents} @@ -190,30 +188,26 @@ export const ShortUrlForm = ( )} - {showBehaviorCard && ( -
- - {showCrawlableControl && ( - setShortUrlData({ ...shortUrlData, crawlable })} - > - Make it crawlable - - )} - {showForwardQueryControl && ( - setShortUrlData({ ...shortUrlData, forwardQuery })} - > - Forward query params on redirect - - )} - -
- )} +
+ + setShortUrlData({ ...shortUrlData, crawlable })} + > + Make it crawlable + + {showForwardQueryControl && ( + setShortUrlData({ ...shortUrlData, forwardQuery })} + > + Forward query params on redirect + + )} + +
)} diff --git a/src/short-urls/ShortUrlsFilteringBar.tsx b/src/short-urls/ShortUrlsFilteringBar.tsx index fa7cb901..85c70891 100644 --- a/src/short-urls/ShortUrlsFilteringBar.tsx +++ b/src/short-urls/ShortUrlsFilteringBar.tsx @@ -8,7 +8,7 @@ import { SearchField } from '../utils/SearchField'; import { DateRangeSelector } from '../utils/dates/DateRangeSelector'; import { formatIsoDate } from '../utils/helpers/date'; import { DateRange, datesToDateRange } from '../utils/helpers/dateIntervals'; -import { supportsAllTagsFiltering, supportsBotVisits } from '../utils/helpers/features'; +import { supportsAllTagsFiltering } from '../utils/helpers/features'; import { SelectedServer } from '../servers/data'; import { OrderDir } from '../utils/helpers/ordering'; import { OrderingDropdown } from '../utils/OrderingDropdown'; @@ -47,7 +47,6 @@ export const ShortUrlsFilteringBar = ( ); const changeTagSelection = (selectedTags: string[]) => toFirstPage({ tags: selectedTags }); const canChangeTagsMode = supportsAllTagsFiltering(selectedServer); - const botsSupported = supportsBotVisits(selectedServer); const toggleTagsMode = pipe( () => (tagsMode === 'any' ? 'all' : 'any'), (mode) => toFirstPage({ tagsMode: mode }), @@ -83,7 +82,6 @@ export const ShortUrlsFilteringBar = ( diff --git a/src/short-urls/helpers/QrCodeModal.tsx b/src/short-urls/helpers/QrCodeModal.tsx index ac971806..f4bda9eb 100644 --- a/src/short-urls/helpers/QrCodeModal.tsx +++ b/src/short-urls/helpers/QrCodeModal.tsx @@ -6,8 +6,8 @@ import { ExternalLink } from 'react-external-link'; import { ShortUrlModalProps } from '../data'; import { SelectedServer } from '../../servers/data'; import { CopyToClipboardIcon } from '../../utils/CopyToClipboardIcon'; -import { buildQrCodeUrl, QrCodeCapabilities, QrCodeFormat, QrErrorCorrection } from '../../utils/helpers/qrCodes'; -import { supportsNonRestCors, supportsQrErrorCorrection } from '../../utils/helpers/features'; +import { buildQrCodeUrl, QrCodeFormat, QrErrorCorrection } from '../../utils/helpers/qrCodes'; +import { supportsNonRestCors } from '../../utils/helpers/features'; import { ImageDownloader } from '../../common/services/ImageDownloader'; import { QrFormatDropdown } from './qr-codes/QrFormatDropdown'; import { QrErrorCorrectionDropdown } from './qr-codes/QrErrorCorrectionDropdown'; @@ -24,14 +24,10 @@ export const QrCodeModal = (imageDownloader: ImageDownloader) => ( const [margin, setMargin] = useState(0); const [format, setFormat] = useState('png'); const [errorCorrection, setErrorCorrection] = useState('L'); - const capabilities: QrCodeCapabilities = useMemo(() => ({ - errorCorrectionIsSupported: supportsQrErrorCorrection(selectedServer), - }), [selectedServer]); const displayDownloadBtn = supportsNonRestCors(selectedServer); - const willRenderThreeControls = !capabilities.errorCorrectionIsSupported; const qrCodeUrl = useMemo( - () => buildQrCodeUrl(shortUrl, { size, format, margin, errorCorrection }, capabilities), - [shortUrl, size, format, margin, errorCorrection, capabilities], + () => buildQrCodeUrl(shortUrl, { size, format, margin, errorCorrection }), + [shortUrl, size, format, margin, errorCorrection], ); const totalSize = useMemo(() => size + margin, [size, margin]); const modalSize = useMemo(() => { @@ -49,7 +45,7 @@ export const QrCodeModal = (imageDownloader: ImageDownloader) => ( - + ( onChange={(e) => setSize(Number(e.target.value))} /> - + ( onChange={(e) => setMargin(Number(e.target.value))} /> - + - {capabilities.errorCorrectionIsSupported && ( - - - - )} + + +
diff --git a/src/short-urls/helpers/ShortUrlsFilterDropdown.tsx b/src/short-urls/helpers/ShortUrlsFilterDropdown.tsx index 47b25814..4b36d502 100644 --- a/src/short-urls/helpers/ShortUrlsFilterDropdown.tsx +++ b/src/short-urls/helpers/ShortUrlsFilterDropdown.tsx @@ -7,27 +7,18 @@ interface ShortUrlsFilterDropdownProps { onChange: (filters: ShortUrlsFilter) => void; selected?: ShortUrlsFilter; className?: string; - botsSupported: boolean; } export const ShortUrlsFilterDropdown = ( - { onChange, selected = {}, className, botsSupported }: ShortUrlsFilterDropdownProps, + { onChange, selected = {}, className }: ShortUrlsFilterDropdownProps, ) => { - if (!botsSupported) { - return null; - } - const { excludeBots = false } = selected; const onBotsClick = () => onChange({ ...selected, excludeBots: !selected?.excludeBots }); return ( - {botsSupported && ( - <> - Bots: - Exclude bots visits - - )} + Bots: + Exclude bots visits onChange({ excludeBots: false })}> diff --git a/src/utils/helpers/features.ts b/src/utils/helpers/features.ts index 90f81a51..bfb88215 100644 --- a/src/utils/helpers/features.ts +++ b/src/utils/helpers/features.ts @@ -4,10 +4,6 @@ import { SemVerPattern, versionMatch } from './version'; const serverMatchesMinVersion = (minVersion: SemVerPattern) => (selectedServer: SelectedServer): boolean => isReachableServer(selectedServer) && versionMatch(selectedServer.version, { minVersion }); -export const supportsBotVisits = serverMatchesMinVersion('2.7.0'); -export const supportsCrawlableVisits = supportsBotVisits; -export const supportsQrErrorCorrection = serverMatchesMinVersion('2.8.0'); -export const supportsDomainRedirects = supportsQrErrorCorrection; export const supportsForwardQuery = serverMatchesMinVersion('2.9.0'); export const supportsNonRestCors = supportsForwardQuery; export const supportsDefaultDomainRedirectsEdition = serverMatchesMinVersion('2.10.0'); diff --git a/src/utils/helpers/qrCodes.ts b/src/utils/helpers/qrCodes.ts index 85feb888..2e66d676 100644 --- a/src/utils/helpers/qrCodes.ts +++ b/src/utils/helpers/qrCodes.ts @@ -1,10 +1,6 @@ import { isEmpty } from 'ramda'; import { stringifyQuery } from './query'; -export interface QrCodeCapabilities { - errorCorrectionIsSupported: boolean; -} - export type QrCodeFormat = 'svg' | 'png'; export type QrErrorCorrection = 'L' | 'M' | 'Q' | 'H'; @@ -16,17 +12,11 @@ export interface QrCodeOptions { errorCorrection: QrErrorCorrection; } -export const buildQrCodeUrl = ( - shortUrl: string, - { size, format, margin, errorCorrection }: QrCodeOptions, - { errorCorrectionIsSupported }: QrCodeCapabilities, -): string => { +export const buildQrCodeUrl = (shortUrl: string, { margin, ...options }: QrCodeOptions): string => { const baseUrl = `${shortUrl}/qr-code`; const query = stringifyQuery({ - size, - format, + ...options, margin: margin > 0 ? margin : undefined, - errorCorrection: errorCorrectionIsSupported ? errorCorrection : undefined, }); return `${baseUrl}${isEmpty(query) ? '' : `?${query}`}`; diff --git a/src/visits/DomainVisits.tsx b/src/visits/DomainVisits.tsx index 13232a69..e2f5d3ba 100644 --- a/src/visits/DomainVisits.tsx +++ b/src/visits/DomainVisits.tsx @@ -22,7 +22,6 @@ export const DomainVisits = ({ exportVisits }: ReportExporter) => boundToMercure domainVisits, cancelGetDomainVisits, settings, - selectedServer, }: DomainVisitsProps) => { const goBack = useGoBack(); const { domain = '' } = useParams(); @@ -38,7 +37,6 @@ export const DomainVisits = ({ exportVisits }: ReportExporter) => boundToMercure visitsInfo={domainVisits} settings={settings} exportCsv={exportCsv} - selectedServer={selectedServer} > diff --git a/src/visits/NonOrphanVisits.tsx b/src/visits/NonOrphanVisits.tsx index 8c939558..3515afb8 100644 --- a/src/visits/NonOrphanVisits.tsx +++ b/src/visits/NonOrphanVisits.tsx @@ -20,7 +20,6 @@ export const NonOrphanVisits = ({ exportVisits }: ReportExporter) => boundToMerc nonOrphanVisits, cancelGetNonOrphanVisits, settings, - selectedServer, }: NonOrphanVisitsProps) => { const goBack = useGoBack(); const exportCsv = (visits: NormalizedVisit[]) => exportVisits('non_orphan_visits.csv', visits); @@ -34,7 +33,6 @@ export const NonOrphanVisits = ({ exportVisits }: ReportExporter) => boundToMerc visitsInfo={nonOrphanVisits} settings={settings} exportCsv={exportCsv} - selectedServer={selectedServer} > diff --git a/src/visits/OrphanVisits.tsx b/src/visits/OrphanVisits.tsx index b35ed6d3..3a7d711b 100644 --- a/src/visits/OrphanVisits.tsx +++ b/src/visits/OrphanVisits.tsx @@ -21,7 +21,6 @@ export const OrphanVisits = ({ exportVisits }: ReportExporter) => boundToMercure orphanVisits, cancelGetOrphanVisits, settings, - selectedServer, }: OrphanVisitsProps) => { const goBack = useGoBack(); const exportCsv = (visits: NormalizedVisit[]) => exportVisits('orphan_visits.csv', visits); @@ -36,7 +35,6 @@ export const OrphanVisits = ({ exportVisits }: ReportExporter) => boundToMercure visitsInfo={orphanVisits} settings={settings} exportCsv={exportCsv} - selectedServer={selectedServer} isOrphanVisits > diff --git a/src/visits/ShortUrlVisits.tsx b/src/visits/ShortUrlVisits.tsx index 0d94f87a..47b23d27 100644 --- a/src/visits/ShortUrlVisits.tsx +++ b/src/visits/ShortUrlVisits.tsx @@ -30,7 +30,6 @@ export const ShortUrlVisits = ({ exportVisits }: ReportExporter) => boundToMercu getShortUrlDetail, cancelGetShortUrlVisits, settings, - selectedServer, }: ShortUrlVisitsProps) => { const { shortCode = '' } = useParams<{ shortCode: string }>(); const { search } = useLocation(); @@ -57,7 +56,6 @@ export const ShortUrlVisits = ({ exportVisits }: ReportExporter) => boundToMercu visitsInfo={shortUrlVisits} settings={settings} exportCsv={exportCsv} - selectedServer={selectedServer} > diff --git a/src/visits/TagVisits.tsx b/src/visits/TagVisits.tsx index ff70f1bf..3d2510c1 100644 --- a/src/visits/TagVisits.tsx +++ b/src/visits/TagVisits.tsx @@ -23,7 +23,6 @@ export const TagVisits = (colorGenerator: ColorGenerator, { exportVisits }: Repo tagVisits, cancelGetTagVisits, settings, - selectedServer, }: TagVisitsProps) => { const goBack = useGoBack(); const { tag = '' } = useParams(); @@ -38,7 +37,6 @@ export const TagVisits = (colorGenerator: ColorGenerator, { exportVisits }: Repo visitsInfo={tagVisits} settings={settings} exportCsv={exportCsv} - selectedServer={selectedServer} > diff --git a/src/visits/VisitsStats.tsx b/src/visits/VisitsStats.tsx index d823fa9d..c381e300 100644 --- a/src/visits/VisitsStats.tsx +++ b/src/visits/VisitsStats.tsx @@ -11,8 +11,6 @@ import { Message } from '../utils/Message'; import { Result } from '../utils/Result'; import { ShlinkApiError } from '../api/ShlinkApiError'; import { Settings } from '../settings/reducers/settings'; -import { SelectedServer } from '../servers/data'; -import { supportsBotVisits } from '../utils/helpers/features'; import { prettify } from '../utils/helpers/numbers'; import { NavPillItem, NavPills } from '../utils/NavPills'; import { ExportBtn } from '../utils/ExportBtn'; @@ -33,7 +31,6 @@ export type VisitsStatsProps = PropsWithChildren<{ getVisits: (params: VisitsParams, doIntervalFallback?: boolean) => void; visitsInfo: VisitsInfo; settings: Settings; - selectedServer: SelectedServer; cancelGetVisits: () => void; exportCsv: (visits: NormalizedVisit[]) => void; isOrphanVisits?: boolean; @@ -63,7 +60,6 @@ export const VisitsStats: FC = ({ cancelGetVisits, settings, exportCsv, - selectedServer, isOrphanVisits = false, }) => { const { visits, loading, loadingLarge, error, errorData, progress, fallbackInterval } = visitsInfo; @@ -82,7 +78,6 @@ export const VisitsStats: FC = ({ ); const [highlightedVisits, setHighlightedVisits] = useState([]); const [highlightedLabel, setHighlightedLabel] = useState(); - const botsSupported = supportsBotVisits(selectedServer); const isFirstLoad = useRef(true); const { search } = useLocation(); @@ -273,7 +268,6 @@ export const VisitsStats: FC = ({ selectedVisits={highlightedVisits} setSelectedVisits={setSelectedVisits} isOrphanVisits={isOrphanVisits} - selectedServer={selectedServer} />
)} @@ -306,7 +300,6 @@ export const VisitsStats: FC = ({ updateFiltering({ visitsFilter: newVisitsFilter })} /> diff --git a/src/visits/VisitsTable.tsx b/src/visits/VisitsTable.tsx index 16181b49..311ce160 100644 --- a/src/visits/VisitsTable.tsx +++ b/src/visits/VisitsTable.tsx @@ -8,8 +8,6 @@ import { SimplePaginator } from '../common/SimplePaginator'; import { SearchField } from '../utils/SearchField'; import { determineOrderDir, Order, sortList } from '../utils/helpers/ordering'; import { prettify } from '../utils/helpers/numbers'; -import { supportsBotVisits } from '../utils/helpers/features'; -import { SelectedServer } from '../servers/data'; import { Time } from '../utils/dates/Time'; import { TableOrderIcon } from '../utils/table/TableOrderIcon'; import { MediaMatcher } from '../utils/types'; @@ -22,7 +20,6 @@ export interface VisitsTableProps { setSelectedVisits: (visits: NormalizedVisit[]) => void; matchMedia?: MediaMatcher; isOrphanVisits?: boolean; - selectedServer: SelectedServer; } type OrderableFields = 'date' | 'country' | 'city' | 'browser' | 'os' | 'referer' | 'visitedUrl' | 'potentialBot'; @@ -49,7 +46,6 @@ export const VisitsTable = ({ visits, selectedVisits = [], setSelectedVisits, - selectedServer, matchMedia = window.matchMedia, isOrphanVisits = false, }: VisitsTableProps) => { @@ -64,8 +60,7 @@ export const VisitsTable = ({ const [page, setPage] = useState(1); const end = page * PAGE_SIZE; const start = end - PAGE_SIZE; - const supportsBots = supportsBotVisits(selectedServer); - const fullSizeColSpan = 7 + Number(supportsBots) + Number(isOrphanVisits); + const fullSizeColSpan = 8 + Number(isOrphanVisits); const orderByColumn = (field: OrderableFields) => () => setOrder({ field, dir: determineOrderDir(field, order.field, order.dir) }); @@ -99,12 +94,10 @@ export const VisitsTable = ({ > 0 })} /> - {supportsBots && ( - - - {renderOrderIcon('potentialBot')} - - )} + + + {renderOrderIcon('potentialBot')} + Date {renderOrderIcon('date')} @@ -165,18 +158,16 @@ export const VisitsTable = ({ {isSelected && } - {supportsBots && ( - - {visit.potentialBot && ( - <> - - - Potentially a visit from a bot or crawler - - - )} - - )} + + {visit.potentialBot && ( + <> + + + Potentially a visit from a bot or crawler + + + )} +