diff --git a/shlink-frontend-kit/src/index.ts b/shlink-frontend-kit/src/index.ts index 4211c0fe..a674d21c 100644 --- a/shlink-frontend-kit/src/index.ts +++ b/shlink-frontend-kit/src/index.ts @@ -3,3 +3,4 @@ export * from './form'; export * from './hooks'; export * from './navigation'; export * from './ordering'; +export * from './utils'; diff --git a/shlink-web-component/src/utils/helpers/query.ts b/shlink-frontend-kit/src/utils/index.ts similarity index 82% rename from shlink-web-component/src/utils/helpers/query.ts rename to shlink-frontend-kit/src/utils/index.ts index 8c59f6eb..cb029acc 100644 --- a/shlink-web-component/src/utils/helpers/query.ts +++ b/shlink-frontend-kit/src/utils/index.ts @@ -1,5 +1,7 @@ import qs from 'qs'; +// FIXME Use URLSearchParams instead of qs package + export const parseQuery = (search: string) => qs.parse(search, { ignoreQueryPrefix: true }) as unknown as T; export const stringifyQuery = (query: any): string => qs.stringify(query, { arrayFormat: 'brackets' }); diff --git a/shlink-web-component/test/utils/helpers/query.test.ts b/shlink-frontend-kit/test/utils/query.test.ts similarity index 90% rename from shlink-web-component/test/utils/helpers/query.test.ts rename to shlink-frontend-kit/test/utils/query.test.ts index 68e1350c..a22445d3 100644 --- a/shlink-web-component/test/utils/helpers/query.test.ts +++ b/shlink-frontend-kit/test/utils/query.test.ts @@ -1,4 +1,4 @@ -import { parseQuery, stringifyQuery } from '../../../src/utils/helpers/query'; +import { parseQuery, stringifyQuery } from '../../src/utils'; describe('query', () => { describe('parseQuery', () => { diff --git a/shlink-web-component/src/Main.tsx b/shlink-web-component/src/Main.tsx index 40108304..460965d6 100644 --- a/shlink-web-component/src/Main.tsx +++ b/shlink-web-component/src/Main.tsx @@ -1,16 +1,16 @@ import { faBars as burgerIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useToggle } from '@shlinkio/shlink-frontend-kit'; import classNames from 'classnames'; import type { FC, ReactNode } from 'react'; import { useEffect } from 'react'; import { Navigate, Route, Routes, useLocation } from 'react-router-dom'; -import { useToggle } from '../../shlink-frontend-kit/src'; import { AsideMenu } from './common/AsideMenu'; import { useFeature } from './utils/features'; import { useSwipeable } from './utils/helpers/hooks'; import { useRoutesPrefix } from './utils/routesPrefix'; -type MainProps = { +export type MainProps = { createNotFound?: (nonPrefixedHomePath: string) => ReactNode; }; diff --git a/shlink-web-component/src/ShlinkWebComponent.tsx b/shlink-web-component/src/ShlinkWebComponent.tsx index 39cdc0ad..e6cf09f5 100644 --- a/shlink-web-component/src/ShlinkWebComponent.tsx +++ b/shlink-web-component/src/ShlinkWebComponent.tsx @@ -2,7 +2,7 @@ import type { Store } from '@reduxjs/toolkit'; import type Bottle from 'bottlejs'; import type { FC, ReactNode } from 'react'; import { useEffect, useRef, useState } from 'react'; -import { Provider } from 'react-redux'; +import { Provider as ReduxStoreProvider } from 'react-redux'; import type { ShlinkApiClient } from './api-contract'; import { FeaturesProvider, useFeatures } from './utils/features'; import type { SemVer } from './utils/helpers/version'; @@ -18,9 +18,8 @@ type ShlinkWebComponentProps = { createNotFound?: (nonPrefixedHomePath: string) => ReactNode; }; -// FIXME -// This allows to track the reference to be resolved by the container, but it's hacky and relies on not more than one -// ShlinkWebComponent rendered at the same time +// FIXME This allows to track the reference to be resolved by the container, but it's hacky and relies on not more than +// one ShlinkWebComponent rendered at the same time let apiClientRef: ShlinkApiClient; export const createShlinkWebComponent = ( @@ -46,7 +45,7 @@ export const createShlinkWebComponent = ( }, [apiClient]); return !theStore ? <> : ( - + @@ -54,6 +53,6 @@ export const createShlinkWebComponent = ( - + ); }; diff --git a/shlink-web-component/src/api-contract/types.ts b/shlink-web-component/src/api-contract/types.ts index f0922674..5ef4fed5 100644 --- a/shlink-web-component/src/api-contract/types.ts +++ b/shlink-web-component/src/api-contract/types.ts @@ -1,4 +1,4 @@ -import type { Order } from '../../../shlink-frontend-kit/src'; +import type { Order } from '@shlinkio/shlink-frontend-kit'; import type { ShortUrl, ShortUrlMeta } from '../short-urls/data'; import type { Visit } from '../visits/types'; diff --git a/shlink-web-component/src/domains/DomainSelector.tsx b/shlink-web-component/src/domains/DomainSelector.tsx index 678a2dc5..e89be930 100644 --- a/shlink-web-component/src/domains/DomainSelector.tsx +++ b/shlink-web-component/src/domains/DomainSelector.tsx @@ -1,10 +1,10 @@ import { faUndo } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { DropdownBtn, useToggle } from '@shlinkio/shlink-frontend-kit'; import { isEmpty, pipe } from 'ramda'; import { useEffect } from 'react'; import type { InputProps } from 'reactstrap'; import { Button, DropdownItem, Input, InputGroup, UncontrolledTooltip } from 'reactstrap'; -import { DropdownBtn, useToggle } from '../../../shlink-frontend-kit/src'; import type { DomainsList } from './reducers/domainsList'; import './DomainSelector.scss'; diff --git a/shlink-web-component/src/domains/ManageDomains.tsx b/shlink-web-component/src/domains/ManageDomains.tsx index e50bc5eb..0dfa88bf 100644 --- a/shlink-web-component/src/domains/ManageDomains.tsx +++ b/shlink-web-component/src/domains/ManageDomains.tsx @@ -1,6 +1,6 @@ +import { Message, Result, SearchField, SimpleCard } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { useEffect } from 'react'; -import { Message, Result, SearchField, SimpleCard } from '../../../shlink-frontend-kit/src'; import { ShlinkApiError } from '../common/ShlinkApiError'; import { DomainRow } from './DomainRow'; import type { EditDomainRedirects } from './reducers/domainRedirects'; diff --git a/shlink-web-component/src/domains/helpers/DomainDropdown.tsx b/shlink-web-component/src/domains/helpers/DomainDropdown.tsx index 07e668d2..73aeb47c 100644 --- a/shlink-web-component/src/domains/helpers/DomainDropdown.tsx +++ b/shlink-web-component/src/domains/helpers/DomainDropdown.tsx @@ -1,9 +1,9 @@ import { faChartPie as pieChartIcon, faEdit as editIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { RowDropdownBtn, useToggle } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { Link } from 'react-router-dom'; import { DropdownItem } from 'reactstrap'; -import { RowDropdownBtn, useToggle } from '../../../../shlink-frontend-kit/src'; import { useFeature } from '../../utils/features'; import { useRoutesPrefix } from '../../utils/routesPrefix'; import { DEFAULT_DOMAIN } from '../../visits/reducers/domainVisits'; diff --git a/shlink-web-component/src/domains/helpers/DomainStatusIcon.tsx b/shlink-web-component/src/domains/helpers/DomainStatusIcon.tsx index e89230b9..003c1733 100644 --- a/shlink-web-component/src/domains/helpers/DomainStatusIcon.tsx +++ b/shlink-web-component/src/domains/helpers/DomainStatusIcon.tsx @@ -4,11 +4,11 @@ import { faTimes as invalidIcon, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useElementRef } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { useEffect, useState } from 'react'; import { ExternalLink } from 'react-external-link'; import { UncontrolledTooltip } from 'reactstrap'; -import { useElementRef } from '../../../../shlink-frontend-kit/src'; import type { MediaMatcher } from '../../utils/types'; import type { DomainStatus } from '../data'; diff --git a/shlink-web-component/src/domains/helpers/EditDomainRedirectsModal.tsx b/shlink-web-component/src/domains/helpers/EditDomainRedirectsModal.tsx index 1c681bae..bb21dee7 100644 --- a/shlink-web-component/src/domains/helpers/EditDomainRedirectsModal.tsx +++ b/shlink-web-component/src/domains/helpers/EditDomainRedirectsModal.tsx @@ -1,8 +1,8 @@ +import type { InputFormGroupProps } from '@shlinkio/shlink-frontend-kit'; +import { InputFormGroup } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { useState } from 'react'; import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; -import type { InputFormGroupProps } from '../../../../shlink-frontend-kit/src'; -import { InputFormGroup } from '../../../../shlink-frontend-kit/src'; import type { ShlinkDomain } from '../../api-contract'; import { InfoTooltip } from '../../utils/components/InfoTooltip'; import { handleEventPreventingDefault, nonEmptyValueOrNull } from '../../utils/helpers'; diff --git a/shlink-web-component/src/overview/helpers/HighlightCard.tsx b/shlink-web-component/src/overview/helpers/HighlightCard.tsx index 7cc80488..72b99865 100644 --- a/shlink-web-component/src/overview/helpers/HighlightCard.tsx +++ b/shlink-web-component/src/overview/helpers/HighlightCard.tsx @@ -1,9 +1,9 @@ import { faArrowAltCircleRight as linkIcon } from '@fortawesome/free-regular-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useElementRef } from '@shlinkio/shlink-frontend-kit'; import type { FC, PropsWithChildren, ReactNode } from 'react'; import { Link } from 'react-router-dom'; import { Card, CardText, CardTitle, UncontrolledTooltip } from 'reactstrap'; -import { useElementRef } from '../../../../shlink-frontend-kit/src'; import './HighlightCard.scss'; export type HighlightCardProps = PropsWithChildren<{ diff --git a/shlink-web-component/src/short-urls/EditShortUrl.tsx b/shlink-web-component/src/short-urls/EditShortUrl.tsx index 1649bc81..1c30a077 100644 --- a/shlink-web-component/src/short-urls/EditShortUrl.tsx +++ b/shlink-web-component/src/short-urls/EditShortUrl.tsx @@ -1,14 +1,13 @@ import { faArrowLeft } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Message, parseQuery, Result } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { useEffect, useMemo } from 'react'; import { ExternalLink } from 'react-external-link'; import { useLocation, useParams } from 'react-router-dom'; import { Button, Card } from 'reactstrap'; -import { Message, Result } from '../../../shlink-frontend-kit/src'; import { ShlinkApiError } from '../common/ShlinkApiError'; import { useGoBack } from '../utils/helpers/hooks'; -import { parseQuery } from '../utils/helpers/query'; import { useSetting } from '../utils/settings'; import type { ShortUrlIdentifier } from './data'; import { shortUrlDataFromShortUrl, urlDecodeShortCode } from './helpers'; diff --git a/shlink-web-component/src/short-urls/ShortUrlForm.tsx b/shlink-web-component/src/short-urls/ShortUrlForm.tsx index 8128657c..dad880c8 100644 --- a/shlink-web-component/src/short-urls/ShortUrlForm.tsx +++ b/shlink-web-component/src/short-urls/ShortUrlForm.tsx @@ -1,6 +1,7 @@ import type { IconProp } from '@fortawesome/fontawesome-svg-core'; import { faAndroid, faApple } from '@fortawesome/free-brands-svg-icons'; import { faDesktop } from '@fortawesome/free-solid-svg-icons'; +import { Checkbox, SimpleCard } from '@shlinkio/shlink-frontend-kit'; import classNames from 'classnames'; import { parseISO } from 'date-fns'; import { isEmpty, pipe, replace, trim } from 'ramda'; @@ -8,7 +9,6 @@ import type { ChangeEvent, FC } from 'react'; import { useEffect, useState } from 'react'; import { Button, FormGroup, Input, Row } from 'reactstrap'; import type { InputType } from 'reactstrap/types/lib/Input'; -import { Checkbox, SimpleCard } from '../../../shlink-frontend-kit/src'; import type { DomainSelectorProps } from '../domains/DomainSelector'; import type { TagsSelectorProps } from '../tags/helpers/TagsSelector'; import { IconInput } from '../utils/components/IconInput'; diff --git a/shlink-web-component/src/short-urls/ShortUrlsFilteringBar.tsx b/shlink-web-component/src/short-urls/ShortUrlsFilteringBar.tsx index f771a6f5..9236df86 100644 --- a/shlink-web-component/src/short-urls/ShortUrlsFilteringBar.tsx +++ b/shlink-web-component/src/short-urls/ShortUrlsFilteringBar.tsx @@ -1,11 +1,11 @@ import { faTag, faTags } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import type { OrderDir } from '@shlinkio/shlink-frontend-kit'; +import { OrderingDropdown, SearchField } from '@shlinkio/shlink-frontend-kit'; import classNames from 'classnames'; import { isEmpty, pipe } from 'ramda'; import type { FC } from 'react'; import { Button, InputGroup, Row, UncontrolledTooltip } from 'reactstrap'; -import type { OrderDir } from '../../../shlink-frontend-kit/src'; -import { OrderingDropdown, SearchField } from '../../../shlink-frontend-kit/src'; import type { TagsSelectorProps } from '../tags/helpers/TagsSelector'; import { DateRangeSelector } from '../utils/dates/DateRangeSelector'; import { formatIsoDate } from '../utils/dates/helpers/date'; diff --git a/shlink-web-component/src/short-urls/ShortUrlsList.tsx b/shlink-web-component/src/short-urls/ShortUrlsList.tsx index b9b8d30b..f2d4d01f 100644 --- a/shlink-web-component/src/short-urls/ShortUrlsList.tsx +++ b/shlink-web-component/src/short-urls/ShortUrlsList.tsx @@ -1,9 +1,9 @@ +import type { OrderDir } from '@shlinkio/shlink-frontend-kit'; +import { determineOrderDir } from '@shlinkio/shlink-frontend-kit'; import { pipe } from 'ramda'; import { useEffect, useState } from 'react'; import { useLocation, useParams } from 'react-router-dom'; import { Card } from 'reactstrap'; -import type { OrderDir } from '../../../shlink-frontend-kit/src'; -import { determineOrderDir } from '../../../shlink-frontend-kit/src'; import { DEFAULT_SHORT_URLS_ORDERING } from '../../../src/settings/reducers/settings'; import type { ShlinkShortUrlsListParams, ShlinkShortUrlsOrder } from '../api-contract'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; diff --git a/shlink-web-component/src/short-urls/UseExistingIfFoundInfoIcon.tsx b/shlink-web-component/src/short-urls/UseExistingIfFoundInfoIcon.tsx index 675e3bfb..0fea66a9 100644 --- a/shlink-web-component/src/short-urls/UseExistingIfFoundInfoIcon.tsx +++ b/shlink-web-component/src/short-urls/UseExistingIfFoundInfoIcon.tsx @@ -1,7 +1,7 @@ import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useToggle } from '@shlinkio/shlink-frontend-kit'; import { Modal, ModalBody, ModalHeader } from 'reactstrap'; -import { useToggle } from '../../../shlink-frontend-kit/src'; import './UseExistingIfFoundInfoIcon.scss'; const InfoModal = ({ isOpen, toggle }: { isOpen: boolean; toggle: () => void }) => ( diff --git a/shlink-web-component/src/short-urls/data/index.ts b/shlink-web-component/src/short-urls/data/index.ts index a3c3a481..36256e20 100644 --- a/shlink-web-component/src/short-urls/data/index.ts +++ b/shlink-web-component/src/short-urls/data/index.ts @@ -1,4 +1,4 @@ -import type { Order } from '../../../../shlink-frontend-kit/src'; +import type { Order } from '@shlinkio/shlink-frontend-kit'; import type { ShlinkVisitsSummary } from '../../api-contract'; import type { Nullable, OptionalString } from '../../utils/helpers'; diff --git a/shlink-web-component/src/short-urls/helpers/CreateShortUrlResult.tsx b/shlink-web-component/src/short-urls/helpers/CreateShortUrlResult.tsx index f6b09d66..46ed1167 100644 --- a/shlink-web-component/src/short-urls/helpers/CreateShortUrlResult.tsx +++ b/shlink-web-component/src/short-urls/helpers/CreateShortUrlResult.tsx @@ -1,10 +1,10 @@ import { faClone as copyIcon } from '@fortawesome/free-regular-svg-icons'; import { faTimes as closeIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Result } from '@shlinkio/shlink-frontend-kit'; import { useEffect } from 'react'; import CopyToClipboard from 'react-copy-to-clipboard'; import { Tooltip } from 'reactstrap'; -import { Result } from '../../../../shlink-frontend-kit/src'; import { ShlinkApiError } from '../../common/ShlinkApiError'; import type { TimeoutToggle } from '../../utils/helpers/hooks'; import type { ShortUrlCreation } from '../reducers/shortUrlCreation'; diff --git a/shlink-web-component/src/short-urls/helpers/DeleteShortUrlModal.tsx b/shlink-web-component/src/short-urls/helpers/DeleteShortUrlModal.tsx index 511113c4..1c4bf2dc 100644 --- a/shlink-web-component/src/short-urls/helpers/DeleteShortUrlModal.tsx +++ b/shlink-web-component/src/short-urls/helpers/DeleteShortUrlModal.tsx @@ -1,7 +1,7 @@ +import { Result } from '@shlinkio/shlink-frontend-kit'; import { pipe } from 'ramda'; import { useEffect, useState } from 'react'; import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; -import { Result } from '../../../../shlink-frontend-kit/src'; import { isInvalidDeletionError } from '../../api-contract/utils'; import { ShlinkApiError } from '../../common/ShlinkApiError'; import { handleEventPreventingDefault } from '../../utils/helpers'; diff --git a/shlink-web-component/src/short-urls/helpers/ExportShortUrlsBtn.tsx b/shlink-web-component/src/short-urls/helpers/ExportShortUrlsBtn.tsx index 9329df9f..c3349719 100644 --- a/shlink-web-component/src/short-urls/helpers/ExportShortUrlsBtn.tsx +++ b/shlink-web-component/src/short-urls/helpers/ExportShortUrlsBtn.tsx @@ -1,6 +1,6 @@ +import { useToggle } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { useCallback } from 'react'; -import { useToggle } from '../../../../shlink-frontend-kit/src'; import type { ShlinkApiClient } from '../../api-contract'; import { ExportBtn } from '../../utils/components/ExportBtn'; import type { ReportExporter } from '../../utils/services/ReportExporter'; diff --git a/shlink-web-component/src/short-urls/helpers/ShortUrlFormCheckboxGroup.tsx b/shlink-web-component/src/short-urls/helpers/ShortUrlFormCheckboxGroup.tsx index 657b60da..af7c88d7 100644 --- a/shlink-web-component/src/short-urls/helpers/ShortUrlFormCheckboxGroup.tsx +++ b/shlink-web-component/src/short-urls/helpers/ShortUrlFormCheckboxGroup.tsx @@ -1,5 +1,5 @@ +import { Checkbox } from '@shlinkio/shlink-frontend-kit'; import type { ChangeEvent, FC, PropsWithChildren } from 'react'; -import { Checkbox } from '../../../../shlink-frontend-kit/src'; import { InfoTooltip } from '../../utils/components/InfoTooltip'; type ShortUrlFormCheckboxGroupProps = PropsWithChildren<{ diff --git a/shlink-web-component/src/short-urls/helpers/ShortUrlStatus.tsx b/shlink-web-component/src/short-urls/helpers/ShortUrlStatus.tsx index 1a3cc6c9..2c3d6005 100644 --- a/shlink-web-component/src/short-urls/helpers/ShortUrlStatus.tsx +++ b/shlink-web-component/src/short-urls/helpers/ShortUrlStatus.tsx @@ -1,10 +1,10 @@ import type { IconDefinition } from '@fortawesome/fontawesome-common-types'; import { faCalendarXmark, faCheck, faLinkSlash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useElementRef } from '@shlinkio/shlink-frontend-kit'; import { isBefore } from 'date-fns'; import type { FC, ReactNode } from 'react'; import { UncontrolledTooltip } from 'reactstrap'; -import { useElementRef } from '../../../../shlink-frontend-kit/src'; import { formatHumanFriendly, now, parseISO } from '../../utils/dates/helpers/date'; import type { ShortUrl } from '../data'; diff --git a/shlink-web-component/src/short-urls/helpers/ShortUrlVisitsCount.tsx b/shlink-web-component/src/short-urls/helpers/ShortUrlVisitsCount.tsx index 9cb4d750..5b9db463 100644 --- a/shlink-web-component/src/short-urls/helpers/ShortUrlVisitsCount.tsx +++ b/shlink-web-component/src/short-urls/helpers/ShortUrlVisitsCount.tsx @@ -1,8 +1,8 @@ import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useElementRef } from '@shlinkio/shlink-frontend-kit'; import classNames from 'classnames'; import { UncontrolledTooltip } from 'reactstrap'; -import { useElementRef } from '../../../../shlink-frontend-kit/src'; import { formatHumanFriendly, parseISO } from '../../utils/dates/helpers/date'; import { prettify } from '../../utils/helpers/numbers'; import type { ShortUrl } from '../data'; diff --git a/shlink-web-component/src/short-urls/helpers/ShortUrlsFilterDropdown.tsx b/shlink-web-component/src/short-urls/helpers/ShortUrlsFilterDropdown.tsx index f4054b19..fd1bb21f 100644 --- a/shlink-web-component/src/short-urls/helpers/ShortUrlsFilterDropdown.tsx +++ b/shlink-web-component/src/short-urls/helpers/ShortUrlsFilterDropdown.tsx @@ -1,5 +1,5 @@ +import { DropdownBtn } from '@shlinkio/shlink-frontend-kit'; import { DropdownItem } from 'reactstrap'; -import { DropdownBtn } from '../../../../shlink-frontend-kit/src'; import { hasValue } from '../../utils/helpers'; import type { ShortUrlsFilter } from '../data'; diff --git a/shlink-web-component/src/short-urls/helpers/ShortUrlsRowMenu.tsx b/shlink-web-component/src/short-urls/helpers/ShortUrlsRowMenu.tsx index 65f0faee..1bf30fa9 100644 --- a/shlink-web-component/src/short-urls/helpers/ShortUrlsRowMenu.tsx +++ b/shlink-web-component/src/short-urls/helpers/ShortUrlsRowMenu.tsx @@ -5,9 +5,9 @@ import { faQrcode as qrIcon, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { RowDropdownBtn, useToggle } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { DropdownItem } from 'reactstrap'; -import { RowDropdownBtn, useToggle } from '../../../../shlink-frontend-kit/src'; import type { ShortUrl, ShortUrlModalProps } from '../data'; import { ShortUrlDetailLink } from './ShortUrlDetailLink'; diff --git a/shlink-web-component/src/short-urls/helpers/hooks.ts b/shlink-web-component/src/short-urls/helpers/hooks.ts index 1a36a2b8..fd5d550a 100644 --- a/shlink-web-component/src/short-urls/helpers/hooks.ts +++ b/shlink-web-component/src/short-urls/helpers/hooks.ts @@ -1,11 +1,10 @@ +import { orderToString, parseQuery, stringifyQuery, stringToOrder } from '@shlinkio/shlink-frontend-kit'; import { isEmpty, pipe } from 'ramda'; import { useCallback, useMemo } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; -import { orderToString, stringToOrder } from '../../../../shlink-frontend-kit/src'; import type { TagsFilteringMode } from '../../api-contract'; import type { BooleanString } from '../../utils/helpers'; import { parseOptionalBooleanToString } from '../../utils/helpers'; -import { parseQuery, stringifyQuery } from '../../utils/helpers/query'; import { useRoutesPrefix } from '../../utils/routesPrefix'; import type { ShortUrlsOrder, ShortUrlsOrderableFields } from '../data'; diff --git a/shlink-web-component/src/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.tsx b/shlink-web-component/src/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.tsx index 7773106d..4fbc7950 100644 --- a/shlink-web-component/src/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.tsx +++ b/shlink-web-component/src/short-urls/helpers/qr-codes/QrErrorCorrectionDropdown.tsx @@ -1,6 +1,6 @@ +import { DropdownBtn } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { DropdownItem } from 'reactstrap'; -import { DropdownBtn } from '../../../../../shlink-frontend-kit/src'; import type { QrErrorCorrection } from '../../../utils/helpers/qrCodes'; interface QrErrorCorrectionDropdownProps { diff --git a/shlink-web-component/src/short-urls/helpers/qr-codes/QrFormatDropdown.tsx b/shlink-web-component/src/short-urls/helpers/qr-codes/QrFormatDropdown.tsx index f5a90874..8ed9b08a 100644 --- a/shlink-web-component/src/short-urls/helpers/qr-codes/QrFormatDropdown.tsx +++ b/shlink-web-component/src/short-urls/helpers/qr-codes/QrFormatDropdown.tsx @@ -1,6 +1,6 @@ +import { DropdownBtn } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { DropdownItem } from 'reactstrap'; -import { DropdownBtn } from '../../../../../shlink-frontend-kit/src'; import type { QrCodeFormat } from '../../../utils/helpers/qrCodes'; interface QrFormatDropdownProps { diff --git a/shlink-web-component/src/tags/TagsList.tsx b/shlink-web-component/src/tags/TagsList.tsx index ce390731..5e6acee8 100644 --- a/shlink-web-component/src/tags/TagsList.tsx +++ b/shlink-web-component/src/tags/TagsList.tsx @@ -1,8 +1,8 @@ +import { determineOrderDir, Message, OrderingDropdown, Result, SearchField, sortList } from '@shlinkio/shlink-frontend-kit'; import { pipe } from 'ramda'; import type { FC } from 'react'; import { useEffect, useState } from 'react'; import { Row } from 'reactstrap'; -import { determineOrderDir, Message, OrderingDropdown, Result, SearchField, sortList } from '../../../shlink-frontend-kit/src'; import { ShlinkApiError } from '../common/ShlinkApiError'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import { Topics } from '../mercure/helpers/Topics'; diff --git a/shlink-web-component/src/tags/TagsTable.tsx b/shlink-web-component/src/tags/TagsTable.tsx index 3f494814..34474258 100644 --- a/shlink-web-component/src/tags/TagsTable.tsx +++ b/shlink-web-component/src/tags/TagsTable.tsx @@ -1,11 +1,10 @@ +import { parseQuery, SimpleCard } from '@shlinkio/shlink-frontend-kit'; import { splitEvery } from 'ramda'; import type { FC } from 'react'; import { useEffect, useRef } from 'react'; import { useLocation } from 'react-router-dom'; -import { SimpleCard } from '../../../shlink-frontend-kit/src'; import { SimplePaginator } from '../utils/components/SimplePaginator'; import { useQueryState } from '../utils/helpers/hooks'; -import { parseQuery } from '../utils/helpers/query'; import { TableOrderIcon } from '../utils/table/TableOrderIcon'; import type { TagsListChildrenProps, TagsOrder, TagsOrderableFields } from './data/TagsListChildrenProps'; import type { TagsTableRowProps } from './TagsTableRow'; diff --git a/shlink-web-component/src/tags/TagsTableRow.tsx b/shlink-web-component/src/tags/TagsTableRow.tsx index b691762c..f71beaae 100644 --- a/shlink-web-component/src/tags/TagsTableRow.tsx +++ b/shlink-web-component/src/tags/TagsTableRow.tsx @@ -1,9 +1,9 @@ import { faPencilAlt as editIcon, faTrash as deleteIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { RowDropdownBtn, useToggle } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { Link } from 'react-router-dom'; import { DropdownItem } from 'reactstrap'; -import { RowDropdownBtn, useToggle } from '../../../shlink-frontend-kit/src'; import { prettify } from '../utils/helpers/numbers'; import { useRoutesPrefix } from '../utils/routesPrefix'; import type { ColorGenerator } from '../utils/services/ColorGenerator'; diff --git a/shlink-web-component/src/tags/data/TagsListChildrenProps.ts b/shlink-web-component/src/tags/data/TagsListChildrenProps.ts index 3a3ae9e8..4310431a 100644 --- a/shlink-web-component/src/tags/data/TagsListChildrenProps.ts +++ b/shlink-web-component/src/tags/data/TagsListChildrenProps.ts @@ -1,4 +1,4 @@ -import type { Order } from '../../../../shlink-frontend-kit/src'; +import type { Order } from '@shlinkio/shlink-frontend-kit'; import type { SimplifiedTag } from './index'; export const TAGS_ORDERABLE_FIELDS = { diff --git a/shlink-web-component/src/tags/helpers/DeleteTagConfirmModal.tsx b/shlink-web-component/src/tags/helpers/DeleteTagConfirmModal.tsx index a3861274..663af566 100644 --- a/shlink-web-component/src/tags/helpers/DeleteTagConfirmModal.tsx +++ b/shlink-web-component/src/tags/helpers/DeleteTagConfirmModal.tsx @@ -1,5 +1,5 @@ +import { Result } from '@shlinkio/shlink-frontend-kit'; import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; -import { Result } from '../../../../shlink-frontend-kit/src'; import { ShlinkApiError } from '../../common/ShlinkApiError'; import type { TagModalProps } from '../data'; import type { TagDeletion } from '../reducers/tagDelete'; diff --git a/shlink-web-component/src/tags/helpers/EditTagModal.tsx b/shlink-web-component/src/tags/helpers/EditTagModal.tsx index d076ca4c..cb0aa7d3 100644 --- a/shlink-web-component/src/tags/helpers/EditTagModal.tsx +++ b/shlink-web-component/src/tags/helpers/EditTagModal.tsx @@ -1,10 +1,10 @@ import { faPalette as colorIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Result, useToggle } from '@shlinkio/shlink-frontend-kit'; import { pipe } from 'ramda'; import { useState } from 'react'; import { HexColorPicker } from 'react-colorful'; import { Button, Input, InputGroup, Modal, ModalBody, ModalFooter, ModalHeader, Popover } from 'reactstrap'; -import { Result, useToggle } from '../../../../shlink-frontend-kit/src'; import { ShlinkApiError } from '../../common/ShlinkApiError'; import { handleEventPreventingDefault } from '../../utils/helpers'; import type { ColorGenerator } from '../../utils/services/ColorGenerator'; diff --git a/shlink-web-component/src/utils/components/IconInput.tsx b/shlink-web-component/src/utils/components/IconInput.tsx index 16a199fb..ffc4e0a3 100644 --- a/shlink-web-component/src/utils/components/IconInput.tsx +++ b/shlink-web-component/src/utils/components/IconInput.tsx @@ -1,10 +1,10 @@ import type { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useElementRef } from '@shlinkio/shlink-frontend-kit'; import classNames from 'classnames'; import type { FC } from 'react'; import type { InputProps } from 'reactstrap'; import { Input } from 'reactstrap'; -import { useElementRef } from '../../../../shlink-frontend-kit/src'; import './IconInput.scss'; type IconInputProps = InputProps & { diff --git a/shlink-web-component/src/utils/components/InfoTooltip.tsx b/shlink-web-component/src/utils/components/InfoTooltip.tsx index 71532c87..1b5a9e8a 100644 --- a/shlink-web-component/src/utils/components/InfoTooltip.tsx +++ b/shlink-web-component/src/utils/components/InfoTooltip.tsx @@ -1,9 +1,9 @@ import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import type { Placement } from '@popperjs/core'; +import { useElementRef } from '@shlinkio/shlink-frontend-kit'; import type { FC, PropsWithChildren } from 'react'; import { UncontrolledTooltip } from 'reactstrap'; -import { useElementRef } from '../../../../shlink-frontend-kit/src'; export type InfoTooltipProps = PropsWithChildren<{ className?: string; diff --git a/shlink-web-component/src/utils/dates/DateIntervalSelector.tsx b/shlink-web-component/src/utils/dates/DateIntervalSelector.tsx index 68b3a845..fd9a6249 100644 --- a/shlink-web-component/src/utils/dates/DateIntervalSelector.tsx +++ b/shlink-web-component/src/utils/dates/DateIntervalSelector.tsx @@ -1,5 +1,5 @@ +import { DropdownBtn } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; -import { DropdownBtn } from '../../../../shlink-frontend-kit/src'; import type { DateIntervalDropdownProps } from './DateIntervalDropdownItems'; import { DateIntervalDropdownItems } from './DateIntervalDropdownItems'; import { rangeOrIntervalToString } from './helpers/dateIntervals'; diff --git a/shlink-web-component/src/utils/dates/DateRangeSelector.tsx b/shlink-web-component/src/utils/dates/DateRangeSelector.tsx index 02270ccd..d79d656a 100644 --- a/shlink-web-component/src/utils/dates/DateRangeSelector.tsx +++ b/shlink-web-component/src/utils/dates/DateRangeSelector.tsx @@ -1,6 +1,6 @@ +import { DropdownBtn } from '@shlinkio/shlink-frontend-kit'; import { useState } from 'react'; import { DropdownItem } from 'reactstrap'; -import { DropdownBtn } from '../../../../shlink-frontend-kit/src'; import { useEffectExceptFirstTime } from '../helpers/hooks'; import { DateIntervalDropdownItems } from './DateIntervalDropdownItems'; import { DateRangeRow } from './DateRangeRow'; diff --git a/shlink-web-component/src/utils/helpers/hooks.ts b/shlink-web-component/src/utils/helpers/hooks.ts index 934d0f3a..9427833a 100644 --- a/shlink-web-component/src/utils/helpers/hooks.ts +++ b/shlink-web-component/src/utils/helpers/hooks.ts @@ -1,8 +1,8 @@ +import { parseQuery, stringifyQuery } from '@shlinkio/shlink-frontend-kit'; import type { DependencyList, EffectCallback } from 'react'; import { useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useSwipeable as useReactSwipeable } from 'react-swipeable'; -import { parseQuery, stringifyQuery } from './query'; const DEFAULT_DELAY = 2000; diff --git a/shlink-web-component/src/utils/helpers/qrCodes.ts b/shlink-web-component/src/utils/helpers/qrCodes.ts index 2e66d676..0fcb16b7 100644 --- a/shlink-web-component/src/utils/helpers/qrCodes.ts +++ b/shlink-web-component/src/utils/helpers/qrCodes.ts @@ -1,5 +1,5 @@ +import { stringifyQuery } from '@shlinkio/shlink-frontend-kit'; import { isEmpty } from 'ramda'; -import { stringifyQuery } from './query'; export type QrCodeFormat = 'svg' | 'png'; diff --git a/shlink-web-component/src/utils/table/TableOrderIcon.tsx b/shlink-web-component/src/utils/table/TableOrderIcon.tsx index d055284f..d6044d81 100644 --- a/shlink-web-component/src/utils/table/TableOrderIcon.tsx +++ b/shlink-web-component/src/utils/table/TableOrderIcon.tsx @@ -1,6 +1,6 @@ import { faCaretDown as caretDownIcon, faCaretUp as caretUpIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import type { Order } from '../../../../shlink-frontend-kit/src'; +import type { Order } from '@shlinkio/shlink-frontend-kit'; interface TableOrderIconProps { currentOrder: Order; diff --git a/shlink-web-component/src/visits/ShortUrlVisits.tsx b/shlink-web-component/src/visits/ShortUrlVisits.tsx index e2745cea..f19923a5 100644 --- a/shlink-web-component/src/visits/ShortUrlVisits.tsx +++ b/shlink-web-component/src/visits/ShortUrlVisits.tsx @@ -1,3 +1,4 @@ +import { parseQuery } from '@shlinkio/shlink-frontend-kit'; import { useEffect } from 'react'; import { useLocation, useParams } from 'react-router-dom'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; @@ -6,7 +7,6 @@ import type { ShortUrlIdentifier } from '../short-urls/data'; import { urlDecodeShortCode } from '../short-urls/helpers'; import type { ShortUrlDetail } from '../short-urls/reducers/shortUrlDetail'; import { useGoBack } from '../utils/helpers/hooks'; -import { parseQuery } from '../utils/helpers/query'; import type { ReportExporter } from '../utils/services/ReportExporter'; import type { LoadShortUrlVisits, ShortUrlVisits as ShortUrlVisitsState } from './reducers/shortUrlVisits'; import { ShortUrlVisitsHeader } from './ShortUrlVisitsHeader'; diff --git a/shlink-web-component/src/visits/VisitsStats.tsx b/shlink-web-component/src/visits/VisitsStats.tsx index d2b9fc1d..0f08628d 100644 --- a/shlink-web-component/src/visits/VisitsStats.tsx +++ b/shlink-web-component/src/visits/VisitsStats.tsx @@ -1,13 +1,13 @@ import type { IconDefinition } from '@fortawesome/fontawesome-common-types'; import { faCalendarAlt, faChartPie, faList, faMapMarkedAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Message, NavPillItem, NavPills, Result } from '@shlinkio/shlink-frontend-kit'; import classNames from 'classnames'; import { isEmpty, pipe, propEq, values } from 'ramda'; import type { FC, PropsWithChildren } from 'react'; import { useEffect, useMemo, useRef, useState } from 'react'; import { Navigate, Route, Routes, useLocation } from 'react-router-dom'; import { Button, Progress, Row } from 'reactstrap'; -import { Message, NavPillItem, NavPills, Result } from '../../../shlink-frontend-kit/src'; import { ShlinkApiError } from '../common/ShlinkApiError'; import { ExportBtn } from '../utils/components/ExportBtn'; import { DateRangeSelector } from '../utils/dates/DateRangeSelector'; diff --git a/shlink-web-component/src/visits/VisitsTable.tsx b/shlink-web-component/src/visits/VisitsTable.tsx index 44ee06f2..39a18c7a 100644 --- a/shlink-web-component/src/visits/VisitsTable.tsx +++ b/shlink-web-component/src/visits/VisitsTable.tsx @@ -1,11 +1,11 @@ import { faCheck as checkIcon, faRobot as botIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import type { Order } from '@shlinkio/shlink-frontend-kit'; +import { determineOrderDir, SearchField, sortList } from '@shlinkio/shlink-frontend-kit'; import classNames from 'classnames'; import { min, splitEvery } from 'ramda'; import { useEffect, useMemo, useRef, useState } from 'react'; import { UncontrolledTooltip } from 'reactstrap'; -import type { Order } from '../../../shlink-frontend-kit/src'; -import { determineOrderDir, SearchField, sortList } from '../../../shlink-frontend-kit/src'; import { SimplePaginator } from '../utils/components/SimplePaginator'; import { Time } from '../utils/dates/Time'; import { prettify } from '../utils/helpers/numbers'; diff --git a/shlink-web-component/src/visits/charts/LineChartCard.tsx b/shlink-web-component/src/visits/charts/LineChartCard.tsx index 1ce55d43..5f10969a 100644 --- a/shlink-web-component/src/visits/charts/LineChartCard.tsx +++ b/shlink-web-component/src/visits/charts/LineChartCard.tsx @@ -1,3 +1,4 @@ +import { ToggleSwitch, useToggle } from '@shlinkio/shlink-frontend-kit'; import type { ChartData, ChartDataset, ChartOptions, InteractionItem } from 'chart.js'; import { add, @@ -23,7 +24,6 @@ import { DropdownToggle, UncontrolledDropdown, } from 'reactstrap'; -import { ToggleSwitch, useToggle } from '../../../../shlink-frontend-kit/src'; import { HIGHLIGHTED_COLOR, MAIN_COLOR } from '../../../../src/utils/theme'; import { formatInternational } from '../../utils/dates/helpers/date'; import { rangeOf } from '../../utils/helpers'; diff --git a/shlink-web-component/src/visits/charts/SortableBarChartCard.tsx b/shlink-web-component/src/visits/charts/SortableBarChartCard.tsx index 3fa67184..8cedb724 100644 --- a/shlink-web-component/src/visits/charts/SortableBarChartCard.tsx +++ b/shlink-web-component/src/visits/charts/SortableBarChartCard.tsx @@ -1,8 +1,8 @@ +import type { Order } from '@shlinkio/shlink-frontend-kit'; +import { OrderingDropdown } from '@shlinkio/shlink-frontend-kit'; import { fromPairs, pipe, reverse, sortBy, splitEvery, toLower, toPairs, type, zipObj } from 'ramda'; import type { FC, ReactNode } from 'react'; import { useState } from 'react'; -import type { Order } from '../../../../shlink-frontend-kit/src'; -import { OrderingDropdown } from '../../../../shlink-frontend-kit/src'; import { PaginationDropdown } from '../../utils/components/PaginationDropdown'; import { SimplePaginator } from '../../utils/components/SimplePaginator'; import { rangeOf } from '../../utils/helpers'; diff --git a/shlink-web-component/src/visits/helpers/OpenMapModalBtn.tsx b/shlink-web-component/src/visits/helpers/OpenMapModalBtn.tsx index 0ebfd04b..f36fa147 100644 --- a/shlink-web-component/src/visits/helpers/OpenMapModalBtn.tsx +++ b/shlink-web-component/src/visits/helpers/OpenMapModalBtn.tsx @@ -1,8 +1,8 @@ import { faMapMarkedAlt as mapIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useDomId, useToggle } from '@shlinkio/shlink-frontend-kit'; import { useState } from 'react'; import { Button, Dropdown, DropdownItem, DropdownMenu, UncontrolledTooltip } from 'reactstrap'; -import { useDomId, useToggle } from '../../../../shlink-frontend-kit/src'; import type { CityStats } from '../types'; import { MapModal } from './MapModal'; import './OpenMapModalBtn.scss'; diff --git a/shlink-web-component/src/visits/helpers/VisitsFilterDropdown.tsx b/shlink-web-component/src/visits/helpers/VisitsFilterDropdown.tsx index 83700748..63882165 100644 --- a/shlink-web-component/src/visits/helpers/VisitsFilterDropdown.tsx +++ b/shlink-web-component/src/visits/helpers/VisitsFilterDropdown.tsx @@ -1,6 +1,6 @@ +import { DropdownBtn } from '@shlinkio/shlink-frontend-kit'; import type { DropdownItemProps } from 'reactstrap'; import { DropdownItem } from 'reactstrap'; -import { DropdownBtn } from '../../../../shlink-frontend-kit/src'; import { hasValue } from '../../utils/helpers'; import type { OrphanVisitType, VisitsFilter } from '../types'; diff --git a/shlink-web-component/src/visits/helpers/hooks.ts b/shlink-web-component/src/visits/helpers/hooks.ts index 88f88f5e..bab38a1b 100644 --- a/shlink-web-component/src/visits/helpers/hooks.ts +++ b/shlink-web-component/src/visits/helpers/hooks.ts @@ -1,4 +1,5 @@ import type { DeepPartial } from '@reduxjs/toolkit'; +import { parseQuery, stringifyQuery } from '@shlinkio/shlink-frontend-kit'; import { isEmpty, isNil, mergeDeepRight, pipe } from 'ramda'; import { useMemo } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; @@ -7,7 +8,6 @@ import type { DateRange } from '../../utils/dates/helpers/dateIntervals'; import { datesToDateRange } from '../../utils/dates/helpers/dateIntervals'; import type { BooleanString } from '../../utils/helpers'; import { parseBooleanToString } from '../../utils/helpers'; -import { parseQuery, stringifyQuery } from '../../utils/helpers/query'; import type { OrphanVisitType, VisitsFilter } from '../types'; interface VisitsQuery { diff --git a/shlink-web-component/test/Main.test.tsx b/shlink-web-component/test/Main.test.tsx new file mode 100644 index 00000000..33b702bf --- /dev/null +++ b/shlink-web-component/test/Main.test.tsx @@ -0,0 +1,72 @@ +import { render, screen } from '@testing-library/react'; +import { fromPartial } from '@total-typescript/shoehorn'; +import { createMemoryHistory } from 'history'; +import { Router } from 'react-router-dom'; +import type { MainProps } from '../src/Main'; +import { Main as createMain } from '../src/Main'; +import { FeaturesProvider } from '../src/utils/features'; + +type SetUpOptions = { + currentPath: string + createNotFound?: MainProps['createNotFound']; + domainVisitsSupported?: boolean; +}; + +describe('
', () => { + const Main = createMain( + () => <>TagsList, + () => <>ShortUrlsList, + () => <>CreateShortUrl, + () => <>ShortUrlVisits, + () => <>TagVisits, + () => <>DomainVisits, + () => <>OrphanVisits, + () => <>NonOrphanVisits, + () => <>OverviewRoute, + () => <>EditShortUrl, + () => <>ManageDomains, + ); + const setUp = ({ createNotFound, currentPath, domainVisitsSupported = true }: SetUpOptions) => { + const history = createMemoryHistory(); + history.push(currentPath); + + return render( + + +
+ + , + ); + }; + + it.each([ + ['/overview', 'OverviewRoute'], + ['/list-short-urls/1', 'ShortUrlsList'], + ['/create-short-url', 'CreateShortUrl'], + ['/short-code/abc123/visits/foo', 'ShortUrlVisits'], + ['/short-code/abc123/edit', 'EditShortUrl'], + ['/tag/foo/visits/foo', 'TagVisits'], + ['/orphan-visits/foo', 'OrphanVisits'], + ['/manage-tags', 'TagsList'], + ['/domain/domain.com/visits/foo', 'DomainVisits'], + ['/non-orphan-visits/foo', 'NonOrphanVisits'], + ['/manage-domains', 'ManageDomains'], + ])( + 'renders expected component based on location and server version', + (currentPath, expectedContent) => { + setUp({ currentPath }); + expect(screen.getByText(expectedContent)).toBeInTheDocument(); + }, + ); + + it.each([ + ['/domain/domain.com/visits/foo', false], + ['/foo/bar/baz', true], + ])('renders not-found when trying to navigate to invalid route', (currentPath, domainVisitsSupported) => { + const createNotFound = () => <>Oops! Route not found.; + + setUp({ currentPath, domainVisitsSupported, createNotFound }); + + expect(screen.getByText('Oops! Route not found.')).toBeInTheDocument(); + }); +}); diff --git a/shlink-web-component/test/__helpers__/TestModalWrapper.tsx b/shlink-web-component/test/__helpers__/TestModalWrapper.tsx index 00ceaffe..18959df7 100644 --- a/shlink-web-component/test/__helpers__/TestModalWrapper.tsx +++ b/shlink-web-component/test/__helpers__/TestModalWrapper.tsx @@ -1,5 +1,5 @@ +import { useToggle } from '@shlinkio/shlink-frontend-kit'; import type { FC, ReactElement } from 'react'; -import { useToggle } from '../../../shlink-frontend-kit/src'; interface RenderModalArgs { isOpen: boolean; diff --git a/shlink-web-component/test/utils/dates/DateIntervalDropdownItems.test.tsx b/shlink-web-component/test/utils/dates/DateIntervalDropdownItems.test.tsx index dbfd358e..79495f08 100644 --- a/shlink-web-component/test/utils/dates/DateIntervalDropdownItems.test.tsx +++ b/shlink-web-component/test/utils/dates/DateIntervalDropdownItems.test.tsx @@ -1,5 +1,5 @@ +import { DropdownBtn } from '@shlinkio/shlink-frontend-kit'; import { screen, waitFor } from '@testing-library/react'; -import { DropdownBtn } from '../../../../shlink-frontend-kit/src'; import { DateIntervalDropdownItems } from '../../../src/utils/dates/DateIntervalDropdownItems'; import type { DateInterval } from '../../../src/utils/dates/helpers/dateIntervals'; import { DATE_INTERVALS, rangeOrIntervalToString } from '../../../src/utils/dates/helpers/dateIntervals'; diff --git a/shlink-web-component/test/utils/table/TableOrderIcon.test.tsx b/shlink-web-component/test/utils/table/TableOrderIcon.test.tsx index f9179927..9690dbee 100644 --- a/shlink-web-component/test/utils/table/TableOrderIcon.test.tsx +++ b/shlink-web-component/test/utils/table/TableOrderIcon.test.tsx @@ -1,5 +1,5 @@ +import type { OrderDir } from '@shlinkio/shlink-frontend-kit'; import { render } from '@testing-library/react'; -import type { OrderDir } from '../../../../shlink-frontend-kit/src'; import { TableOrderIcon } from '../../../src/utils/table/TableOrderIcon'; describe('', () => { diff --git a/src/api/services/ShlinkApiClient.ts b/src/api/services/ShlinkApiClient.ts index 58c54699..b44c7805 100644 --- a/src/api/services/ShlinkApiClient.ts +++ b/src/api/services/ShlinkApiClient.ts @@ -1,5 +1,4 @@ -import { isEmpty, isNil, reject } from 'ramda'; -import { orderToString } from '../../../shlink-frontend-kit/src'; +import { orderToString, stringifyQuery } from '@shlinkio/shlink-frontend-kit'; import type { ShlinkApiClient as BaseShlinkApiClient, ShlinkDomainRedirects, @@ -16,10 +15,11 @@ import type { ShlinkTagsStatsResponse, ShlinkVisits, ShlinkVisitsOverview, - ShlinkVisitsParams } from '../../../shlink-web-component/src/api-contract'; -import { isRegularNotFound, parseApiError } from '../../../shlink-web-component/src/api-contract/utils'; + ShlinkVisitsParams, +} from '@shlinkio/shlink-web-component/api-contract'; +import { isRegularNotFound, parseApiError } from '@shlinkio/shlink-web-component/api-contract/utils'; +import { isEmpty, isNil, reject } from 'ramda'; import type { ShortUrl, ShortUrlData } from '../../../shlink-web-component/src/short-urls/data'; -import { stringifyQuery } from '../../../shlink-web-component/src/utils/helpers/query'; import type { HttpClient } from '../../common/services/HttpClient'; import { replaceAuthorityFromUri } from '../../utils/helpers/uri'; import type { OptionalString } from '../../utils/utils'; diff --git a/src/app/App.tsx b/src/app/App.tsx index becfe1d7..64bfde0a 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -1,8 +1,8 @@ +import type { Settings } from '@shlinkio/shlink-web-component'; import classNames from 'classnames'; import type { FC } from 'react'; import { useEffect } from 'react'; import { Route, Routes, useLocation } from 'react-router-dom'; -import type { Settings } from '../../shlink-web-component/src'; import { AppUpdateBanner } from '../common/AppUpdateBanner'; import { NotFound } from '../common/NotFound'; import type { ServersMap } from '../servers/data'; diff --git a/src/common/AppUpdateBanner.tsx b/src/common/AppUpdateBanner.tsx index c08ca057..06470b7b 100644 --- a/src/common/AppUpdateBanner.tsx +++ b/src/common/AppUpdateBanner.tsx @@ -1,8 +1,8 @@ import { faSyncAlt as reloadIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { SimpleCard, useToggle } from '@shlinkio/shlink-frontend-kit'; import type { FC, MouseEventHandler } from 'react'; import { Alert, Button } from 'reactstrap'; -import { SimpleCard, useToggle } from '../../shlink-frontend-kit/src'; import './AppUpdateBanner.scss'; interface AppUpdateBannerProps { diff --git a/src/common/ErrorHandler.tsx b/src/common/ErrorHandler.tsx index 9e2ea815..49f30e4d 100644 --- a/src/common/ErrorHandler.tsx +++ b/src/common/ErrorHandler.tsx @@ -1,7 +1,7 @@ +import { SimpleCard } from '@shlinkio/shlink-frontend-kit'; import type { ReactNode } from 'react'; import { Component } from 'react'; import { Button } from 'reactstrap'; -import { SimpleCard } from '../../shlink-frontend-kit/src'; interface ErrorHandlerState { hasError: boolean; diff --git a/src/common/MainHeader.tsx b/src/common/MainHeader.tsx index de7f8dd5..74cd028a 100644 --- a/src/common/MainHeader.tsx +++ b/src/common/MainHeader.tsx @@ -1,11 +1,11 @@ import { faChevronDown as arrowIcon, faCogs as cogsIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useToggle } from '@shlinkio/shlink-frontend-kit'; import classNames from 'classnames'; import type { FC } from 'react'; import { useEffect } from 'react'; import { Link, useLocation } from 'react-router-dom'; import { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap'; -import { useToggle } from '../../shlink-frontend-kit/src'; import { ShlinkLogo } from './img/ShlinkLogo'; import './MainHeader.scss'; diff --git a/src/common/NotFound.tsx b/src/common/NotFound.tsx index 4982c3da..d19b6aeb 100644 --- a/src/common/NotFound.tsx +++ b/src/common/NotFound.tsx @@ -1,6 +1,6 @@ +import { SimpleCard } from '@shlinkio/shlink-frontend-kit'; import type { FC, PropsWithChildren } from 'react'; import { Link } from 'react-router-dom'; -import { SimpleCard } from '../../shlink-frontend-kit/src'; type NotFoundProps = PropsWithChildren<{ to?: string }>; diff --git a/src/common/ShlinkWebComponentContainer.tsx b/src/common/ShlinkWebComponentContainer.tsx index 20f62a9f..c77d58e3 100644 --- a/src/common/ShlinkWebComponentContainer.tsx +++ b/src/common/ShlinkWebComponentContainer.tsx @@ -1,6 +1,6 @@ +import type { Settings, ShlinkWebComponentType } from '@shlinkio/shlink-web-component'; import type { FC } from 'react'; import { useEffect } from 'react'; -import type { Settings, ShlinkWebComponentType } from '../../shlink-web-component/src'; import type { ShlinkApiClientBuilder } from '../api/services/ShlinkApiClientBuilder'; import { isReachableServer } from '../servers/data'; import { withSelectedServer } from '../servers/helpers/withSelectedServer'; diff --git a/src/common/services/provideServices.ts b/src/common/services/provideServices.ts index bca33c67..56280d70 100644 --- a/src/common/services/provideServices.ts +++ b/src/common/services/provideServices.ts @@ -1,5 +1,5 @@ +import { ShlinkWebComponent } from '@shlinkio/shlink-web-component'; import type Bottle from 'bottlejs'; -import { ShlinkWebComponent } from '../../../shlink-web-component/src'; import type { ConnectDecorator } from '../../container/types'; import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer'; import { ErrorHandler } from '../ErrorHandler'; diff --git a/src/container/types.ts b/src/container/types.ts index 50b78ecf..1a908f37 100644 --- a/src/container/types.ts +++ b/src/container/types.ts @@ -1,4 +1,4 @@ -import type { Settings } from '../../shlink-web-component/src'; +import type { Settings } from '@shlinkio/shlink-web-component'; import type { Sidebar } from '../common/reducers/sidebar'; import type { SelectedServer, ServersMap } from '../servers/data'; diff --git a/src/servers/CreateServer.tsx b/src/servers/CreateServer.tsx index 91c7855d..7587e53a 100644 --- a/src/servers/CreateServer.tsx +++ b/src/servers/CreateServer.tsx @@ -1,9 +1,9 @@ +import { Result, useToggle } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Button } from 'reactstrap'; import { v4 as uuid } from 'uuid'; -import { Result, useToggle } from '../../shlink-frontend-kit/src'; import { NoMenuLayout } from '../common/NoMenuLayout'; import type { TimeoutToggle } from '../utils/helpers/hooks'; import { useGoBack } from '../utils/helpers/hooks'; diff --git a/src/servers/DeleteServerButton.tsx b/src/servers/DeleteServerButton.tsx index 5aa08c93..86bcc46c 100644 --- a/src/servers/DeleteServerButton.tsx +++ b/src/servers/DeleteServerButton.tsx @@ -1,7 +1,7 @@ import { faMinusCircle as deleteIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useToggle } from '@shlinkio/shlink-frontend-kit'; import type { FC, PropsWithChildren } from 'react'; -import { useToggle } from '../../shlink-frontend-kit/src'; import type { ServerWithId } from './data'; import type { DeleteServerModalProps } from './DeleteServerModal'; diff --git a/src/servers/ManageServers.tsx b/src/servers/ManageServers.tsx index b0204e28..5e687c0c 100644 --- a/src/servers/ManageServers.tsx +++ b/src/servers/ManageServers.tsx @@ -1,10 +1,10 @@ import { faFileDownload as exportIcon, faPlus as plusIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { Result, SearchField, SimpleCard } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { Button, Row } from 'reactstrap'; -import { Result, SearchField, SimpleCard } from '../../shlink-frontend-kit/src'; import { NoMenuLayout } from '../common/NoMenuLayout'; import type { TimeoutToggle } from '../utils/helpers/hooks'; import type { ServersMap } from './data'; diff --git a/src/servers/ManageServersRowDropdown.tsx b/src/servers/ManageServersRowDropdown.tsx index 30f2bb9e..94cb42ff 100644 --- a/src/servers/ManageServersRowDropdown.tsx +++ b/src/servers/ManageServersRowDropdown.tsx @@ -6,10 +6,10 @@ import { faPlug as connectIcon, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { RowDropdownBtn, useToggle } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { Link } from 'react-router-dom'; import { DropdownItem } from 'reactstrap'; -import { RowDropdownBtn, useToggle } from '../../shlink-frontend-kit/src'; import type { ServerWithId } from './data'; import type { DeleteServerModalProps } from './DeleteServerModal'; diff --git a/src/servers/helpers/ImportServersBtn.tsx b/src/servers/helpers/ImportServersBtn.tsx index 76f73cbc..d7a52ef7 100644 --- a/src/servers/helpers/ImportServersBtn.tsx +++ b/src/servers/helpers/ImportServersBtn.tsx @@ -1,10 +1,10 @@ import { faFileUpload as importIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useElementRef, useToggle } from '@shlinkio/shlink-frontend-kit'; import { complement, pipe } from 'ramda'; import type { ChangeEvent, FC, PropsWithChildren } from 'react'; import { useEffect, useState } from 'react'; import { Button, UncontrolledTooltip } from 'reactstrap'; -import { useElementRef, useToggle } from '../../../shlink-frontend-kit/src'; import type { ServerData, ServersMap } from '../data'; import type { ServersImporter } from '../services/ServersImporter'; import { DuplicatedServersModal } from './DuplicatedServersModal'; diff --git a/src/servers/helpers/ServerError.tsx b/src/servers/helpers/ServerError.tsx index e5cb416f..3e0dc594 100644 --- a/src/servers/helpers/ServerError.tsx +++ b/src/servers/helpers/ServerError.tsx @@ -1,6 +1,6 @@ +import { Message } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { Link } from 'react-router-dom'; -import { Message } from '../../../shlink-frontend-kit/src'; import { NoMenuLayout } from '../../common/NoMenuLayout'; import type { SelectedServer, ServersMap } from '../data'; import { isServerWithId } from '../data'; diff --git a/src/servers/helpers/ServerForm.tsx b/src/servers/helpers/ServerForm.tsx index 0c8cfb49..dc2b63df 100644 --- a/src/servers/helpers/ServerForm.tsx +++ b/src/servers/helpers/ServerForm.tsx @@ -1,6 +1,6 @@ +import { InputFormGroup, SimpleCard } from '@shlinkio/shlink-frontend-kit'; import type { FC, PropsWithChildren, ReactNode } from 'react'; import { useEffect, useState } from 'react'; -import { InputFormGroup, SimpleCard } from '../../../shlink-frontend-kit/src'; import { handleEventPreventingDefault } from '../../utils/utils'; import type { ServerData } from '../data'; diff --git a/src/servers/helpers/withSelectedServer.tsx b/src/servers/helpers/withSelectedServer.tsx index cdb93d3f..58057af2 100644 --- a/src/servers/helpers/withSelectedServer.tsx +++ b/src/servers/helpers/withSelectedServer.tsx @@ -1,7 +1,7 @@ +import { Message } from '@shlinkio/shlink-frontend-kit'; import type { FC } from 'react'; import { useEffect } from 'react'; import { useParams } from 'react-router-dom'; -import { Message } from '../../../shlink-frontend-kit/src'; import { NoMenuLayout } from '../../common/NoMenuLayout'; import type { SelectedServer } from '../data'; import { isNotFoundServer } from '../data'; diff --git a/src/servers/reducers/selectedServer.ts b/src/servers/reducers/selectedServer.ts index 9f85d6dd..4d9ce70a 100644 --- a/src/servers/reducers/selectedServer.ts +++ b/src/servers/reducers/selectedServer.ts @@ -1,6 +1,6 @@ import { createAction, createSlice } from '@reduxjs/toolkit'; +import type { ShlinkHealth } from '@shlinkio/shlink-web-component/api-contract'; import { memoizeWith, pipe } from 'ramda'; -import type { ShlinkHealth } from '../../../shlink-web-component/src/api-contract'; import type { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; import { createAsyncThunk } from '../../utils/helpers/redux'; import { versionToPrintable, versionToSemVer as toSemVer } from '../../utils/helpers/version'; diff --git a/src/settings/RealTimeUpdatesSettings.tsx b/src/settings/RealTimeUpdatesSettings.tsx index 4e28e1dd..0168c081 100644 --- a/src/settings/RealTimeUpdatesSettings.tsx +++ b/src/settings/RealTimeUpdatesSettings.tsx @@ -1,7 +1,7 @@ +import { LabeledFormGroup, SimpleCard, ToggleSwitch, useDomId } from '@shlinkio/shlink-frontend-kit'; +import type { Settings } from '@shlinkio/shlink-web-component'; import classNames from 'classnames'; import { FormGroup, Input } from 'reactstrap'; -import { LabeledFormGroup, SimpleCard, ToggleSwitch, useDomId } from '../../shlink-frontend-kit/src'; -import type { Settings } from '../../shlink-web-component/src'; import { FormText } from '../utils/forms/FormText'; type RealTimeUpdatesProps = { diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 8971d16a..81fb3468 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -1,6 +1,6 @@ +import { NavPillItem, NavPills } from '@shlinkio/shlink-frontend-kit'; import type { FC, ReactNode } from 'react'; import { Navigate, Route, Routes } from 'react-router-dom'; -import { NavPillItem, NavPills } from '../../shlink-frontend-kit/src'; import { NoMenuLayout } from '../common/NoMenuLayout'; const SettingsSections: FC<{ items: ReactNode[] }> = ({ items }) => ( diff --git a/src/settings/ShortUrlCreationSettings.tsx b/src/settings/ShortUrlCreationSettings.tsx index e7ff56ec..fc240f55 100644 --- a/src/settings/ShortUrlCreationSettings.tsx +++ b/src/settings/ShortUrlCreationSettings.tsx @@ -1,7 +1,7 @@ +import { DropdownBtn, LabeledFormGroup, SimpleCard, ToggleSwitch } from '@shlinkio/shlink-frontend-kit'; +import type { Settings, ShortUrlCreationSettings as ShortUrlsSettings } from '@shlinkio/shlink-web-component'; import type { FC, ReactNode } from 'react'; import { DropdownItem, FormGroup } from 'reactstrap'; -import { DropdownBtn, LabeledFormGroup, SimpleCard, ToggleSwitch } from '../../shlink-frontend-kit/src'; -import type { Settings, ShortUrlCreationSettings as ShortUrlsSettings } from '../../shlink-web-component/src'; import { FormText } from '../utils/forms/FormText'; import type { Defined } from '../utils/types'; diff --git a/src/settings/ShortUrlsListSettings.tsx b/src/settings/ShortUrlsListSettings.tsx index 05664572..5f5642bb 100644 --- a/src/settings/ShortUrlsListSettings.tsx +++ b/src/settings/ShortUrlsListSettings.tsx @@ -1,6 +1,6 @@ +import { LabeledFormGroup, OrderingDropdown, SimpleCard } from '@shlinkio/shlink-frontend-kit'; +import type { Settings, ShortUrlsListSettings as ShortUrlsSettings } from '@shlinkio/shlink-web-component'; import type { FC } from 'react'; -import { LabeledFormGroup, OrderingDropdown, SimpleCard } from '../../shlink-frontend-kit/src'; -import type { Settings, ShortUrlsListSettings as ShortUrlsSettings } from '../../shlink-web-component/src'; import { SHORT_URLS_ORDERABLE_FIELDS } from '../../shlink-web-component/src/short-urls/data'; import { DEFAULT_SHORT_URLS_ORDERING } from './reducers/settings'; diff --git a/src/settings/TagsSettings.tsx b/src/settings/TagsSettings.tsx index b1f4e321..de2827c7 100644 --- a/src/settings/TagsSettings.tsx +++ b/src/settings/TagsSettings.tsx @@ -1,7 +1,10 @@ +import { LabeledFormGroup, OrderingDropdown, SimpleCard } from '@shlinkio/shlink-frontend-kit'; +import type { Settings, TagsSettings as TagsSettingsOptions } from '@shlinkio/shlink-web-component'; import type { FC } from 'react'; -import { LabeledFormGroup, OrderingDropdown, SimpleCard } from '../../shlink-frontend-kit/src'; -import type { Settings, TagsSettings as TagsSettingsOptions } from '../../shlink-web-component/src'; import { TAGS_ORDERABLE_FIELDS } from '../../shlink-web-component/src/tags/data/TagsListChildrenProps'; +import type { Defined } from '../utils/types'; + +export type TagsOrder = Defined; interface TagsProps { settings: Settings; diff --git a/src/settings/UserInterfaceSettings.tsx b/src/settings/UserInterfaceSettings.tsx index 82c970b1..6fc41ff1 100644 --- a/src/settings/UserInterfaceSettings.tsx +++ b/src/settings/UserInterfaceSettings.tsx @@ -1,8 +1,8 @@ import { faMoon, faSun } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { SimpleCard, ToggleSwitch } from '@shlinkio/shlink-frontend-kit'; +import type { Settings, UiSettings } from '@shlinkio/shlink-web-component'; import type { FC } from 'react'; -import { SimpleCard, ToggleSwitch } from '../../shlink-frontend-kit/src'; -import type { Settings, UiSettings } from '../../shlink-web-component/src'; import type { Theme } from '../utils/theme'; import { changeThemeInMarkup } from '../utils/theme'; import './UserInterfaceSettings.scss'; diff --git a/src/settings/VisitsSettings.tsx b/src/settings/VisitsSettings.tsx index c938958d..115b2e45 100644 --- a/src/settings/VisitsSettings.tsx +++ b/src/settings/VisitsSettings.tsx @@ -1,8 +1,8 @@ +import { LabeledFormGroup, SimpleCard, ToggleSwitch } from '@shlinkio/shlink-frontend-kit'; +import type { Settings, VisitsSettings as VisitsSettingsConfig } from '@shlinkio/shlink-web-component'; import type { FC } from 'react'; import { FormGroup } from 'reactstrap'; -import { LabeledFormGroup, SimpleCard, ToggleSwitch } from '../../shlink-frontend-kit/src'; -import type { Settings, VisitsSettings as VisitsSettingsConfig } from '../../shlink-web-component/src'; -import type { DateInterval } from '../../shlink-web-component/src/utils/dates/helpers/dateIntervals'; +import type { DateInterval } from '../utils/dates/DateIntervalSelector'; import { DateIntervalSelector } from '../utils/dates/DateIntervalSelector'; import { FormText } from '../utils/forms/FormText'; diff --git a/src/settings/reducers/settings.ts b/src/settings/reducers/settings.ts index 9468ac33..5962b9b7 100644 --- a/src/settings/reducers/settings.ts +++ b/src/settings/reducers/settings.ts @@ -1,12 +1,14 @@ import type { PayloadAction, PrepareAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; -import { mergeDeepRight } from 'ramda'; import type { Settings, ShortUrlCreationSettings, ShortUrlsListSettings, TagsSettings, - UiSettings, VisitsSettings } from '../../../shlink-web-component/src'; + UiSettings, + VisitsSettings, +} from '@shlinkio/shlink-web-component'; +import { mergeDeepRight } from 'ramda'; import type { Defined } from '../../utils/types'; type ShortUrlsOrder = Defined; diff --git a/src/utils/dates/DateIntervalSelector.tsx b/src/utils/dates/DateIntervalSelector.tsx index 691983bc..221809d9 100644 --- a/src/utils/dates/DateIntervalSelector.tsx +++ b/src/utils/dates/DateIntervalSelector.tsx @@ -1,8 +1,7 @@ +import { DropdownBtn } from '@shlinkio/shlink-frontend-kit'; +import type { VisitsSettings } from '@shlinkio/shlink-web-component'; import type { FC } from 'react'; import { DropdownItem } from 'reactstrap'; -import { DropdownBtn } from '../../../shlink-frontend-kit/src'; -import type { VisitsSettings } from '../../../shlink-web-component/src'; -import { rangeOrIntervalToString } from '../../../shlink-web-component/src/utils/dates/helpers/dateIntervals'; export type DateInterval = VisitsSettings['defaultInterval']; @@ -22,8 +21,16 @@ export const INTERVAL_TO_STRING_MAP: Record, string last365Days: 'Last 365 days', }; +const intervalToString = (interval: DateInterval | undefined, fallback: string): string => { + if (!interval || interval === 'all') { + return fallback; + } + + return INTERVAL_TO_STRING_MAP[interval]; +}; + export const DateIntervalSelector: FC = ({ onChange, active, allText }) => ( - + onChange('all')}> {allText} diff --git a/src/utils/helpers/hooks.ts b/src/utils/helpers/hooks.ts index 1e3d7bad..8826446a 100644 --- a/src/utils/helpers/hooks.ts +++ b/src/utils/helpers/hooks.ts @@ -1,6 +1,6 @@ +import { parseQuery } from '@shlinkio/shlink-frontend-kit'; import { useRef, useState } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; -import { parseQuery } from '../../../shlink-web-component/src/utils/helpers/query'; const DEFAULT_DELAY = 2000; diff --git a/test/__helpers__/TestModalWrapper.tsx b/test/__helpers__/TestModalWrapper.tsx index a6690fa3..18959df7 100644 --- a/test/__helpers__/TestModalWrapper.tsx +++ b/test/__helpers__/TestModalWrapper.tsx @@ -1,5 +1,5 @@ +import { useToggle } from '@shlinkio/shlink-frontend-kit'; import type { FC, ReactElement } from 'react'; -import { useToggle } from '../../shlink-frontend-kit/src'; interface RenderModalArgs { isOpen: boolean; diff --git a/test/api/services/ShlinkApiClient.test.ts b/test/api/services/ShlinkApiClient.test.ts index 78850ea3..8377b01d 100644 --- a/test/api/services/ShlinkApiClient.test.ts +++ b/test/api/services/ShlinkApiClient.test.ts @@ -1,6 +1,6 @@ +import type { ShlinkDomain, ShlinkVisits, ShlinkVisitsOverview } from '@shlinkio/shlink-web-component/api-contract'; +import { ErrorTypeV2, ErrorTypeV3 } from '@shlinkio/shlink-web-component/api-contract'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShlinkDomain, ShlinkVisits, ShlinkVisitsOverview } from '../../../shlink-web-component/src/api-contract'; -import { ErrorTypeV2, ErrorTypeV3 } from '../../../shlink-web-component/src/api-contract'; import type { ShortUrl, ShortUrlsOrder } from '../../../shlink-web-component/src/short-urls/data'; import { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient'; import type { HttpClient } from '../../../src/common/services/HttpClient'; diff --git a/test/common/ShlinkWebComponentContainer.test.tsx b/test/common/ShlinkWebComponentContainer.test.tsx index feae7b9c..8def0346 100644 --- a/test/common/ShlinkWebComponentContainer.test.tsx +++ b/test/common/ShlinkWebComponentContainer.test.tsx @@ -55,28 +55,4 @@ describe('', () => { expect(screen.queryByText('ServerError')).not.toBeInTheDocument(); expect(screen.getByText('ShlinkWebComponent')).toBeInTheDocument(); }); - - // FIXME Move this case to ShlinkWebComponent test - // it.each([ - // ['3.0.0' as SemVer, '/overview', 'OverviewRoute'], - // ['3.0.0' as SemVer, '/list-short-urls/1', 'ShortUrlsList'], - // ['3.0.0' as SemVer, '/create-short-url', 'CreateShortUrl'], - // ['3.0.0' as SemVer, '/short-code/abc123/visits/foo', 'ShortUrlVisits'], - // ['3.0.0' as SemVer, '/short-code/abc123/edit', 'EditShortUrl'], - // ['3.0.0' as SemVer, '/tag/foo/visits/foo', 'TagVisits'], - // ['3.0.0' as SemVer, '/orphan-visits/foo', 'OrphanVisits'], - // ['3.0.0' as SemVer, '/manage-tags', 'TagsList'], - // ['3.0.0' as SemVer, '/not-found', 'Oops! We could not find requested route.'], - // ['3.0.0' as SemVer, '/domain/domain.com/visits/foo', 'Oops! We could not find requested route.'], - // ['3.1.0' as SemVer, '/domain/domain.com/visits/foo', 'DomainVisits'], - // ['2.10.0' as SemVer, '/non-orphan-visits/foo', 'Oops! We could not find requested route.'], - // ['3.0.0' as SemVer, '/non-orphan-visits/foo', 'NonOrphanVisits'], - // ['2.8.0' as SemVer, '/manage-domains', 'ManageDomains'], - // ])( - // 'renders expected component based on location and server version', - // (version, currentPath, expectedContent) => { - // setUp(fromPartial({ version }), currentPath); - // expect(screen.getByText(expectedContent)).toBeInTheDocument(); - // }, - // ); }); diff --git a/test/settings/RealTimeUpdatesSettings.test.tsx b/test/settings/RealTimeUpdatesSettings.test.tsx index a30bff4b..dc3695cb 100644 --- a/test/settings/RealTimeUpdatesSettings.test.tsx +++ b/test/settings/RealTimeUpdatesSettings.test.tsx @@ -1,6 +1,6 @@ +import type { RealTimeUpdatesSettings as RealTimeUpdatesSettingsOptions } from '@shlinkio/shlink-web-component'; import { screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { RealTimeUpdatesSettings as RealTimeUpdatesSettingsOptions } from '../../shlink-web-component/src'; import { RealTimeUpdatesSettings } from '../../src/settings/RealTimeUpdatesSettings'; import { renderWithEvents } from '../__helpers__/setUpTest'; diff --git a/test/settings/ShortUrlCreationSettings.test.tsx b/test/settings/ShortUrlCreationSettings.test.tsx index 72d3c511..fb58cbcb 100644 --- a/test/settings/ShortUrlCreationSettings.test.tsx +++ b/test/settings/ShortUrlCreationSettings.test.tsx @@ -1,6 +1,6 @@ +import type { ShortUrlCreationSettings as ShortUrlsSettings } from '@shlinkio/shlink-web-component'; import { screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShortUrlCreationSettings as ShortUrlsSettings } from '../../shlink-web-component/src'; import { ShortUrlCreationSettings } from '../../src/settings/ShortUrlCreationSettings'; import { renderWithEvents } from '../__helpers__/setUpTest'; diff --git a/test/settings/ShortUrlsListSettings.test.tsx b/test/settings/ShortUrlsListSettings.test.tsx index fc0d0ab9..149d0772 100644 --- a/test/settings/ShortUrlsListSettings.test.tsx +++ b/test/settings/ShortUrlsListSettings.test.tsx @@ -1,6 +1,6 @@ +import type { ShortUrlsListSettings as ShortUrlsSettings } from '@shlinkio/shlink-web-component'; import { screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { ShortUrlsListSettings as ShortUrlsSettings } from '../../shlink-web-component/src'; import type { ShortUrlsOrder } from '../../shlink-web-component/src/short-urls/data'; import { ShortUrlsListSettings } from '../../src/settings/ShortUrlsListSettings'; import { renderWithEvents } from '../__helpers__/setUpTest'; diff --git a/test/settings/TagsSettings.test.tsx b/test/settings/TagsSettings.test.tsx index 69bc28b3..55f257cf 100644 --- a/test/settings/TagsSettings.test.tsx +++ b/test/settings/TagsSettings.test.tsx @@ -1,7 +1,7 @@ +import type { TagsSettings as TagsSettingsOptions } from '@shlinkio/shlink-web-component'; import { screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { TagsSettings as TagsSettingsOptions } from '../../shlink-web-component/src'; -import type { TagsOrder } from '../../shlink-web-component/src/tags/data/TagsListChildrenProps'; +import type { TagsOrder } from '../../src/settings/TagsSettings'; import { TagsSettings } from '../../src/settings/TagsSettings'; import { renderWithEvents } from '../__helpers__/setUpTest'; diff --git a/test/settings/UserInterfaceSettings.test.tsx b/test/settings/UserInterfaceSettings.test.tsx index 99fb2388..53c43809 100644 --- a/test/settings/UserInterfaceSettings.test.tsx +++ b/test/settings/UserInterfaceSettings.test.tsx @@ -1,6 +1,6 @@ +import type { UiSettings } from '@shlinkio/shlink-web-component'; import { screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { UiSettings } from '../../shlink-web-component/src'; import { UserInterfaceSettings } from '../../src/settings/UserInterfaceSettings'; import type { Theme } from '../../src/utils/theme'; import { renderWithEvents } from '../__helpers__/setUpTest'; diff --git a/test/settings/VisitsSettings.test.tsx b/test/settings/VisitsSettings.test.tsx index f1799d1c..00916120 100644 --- a/test/settings/VisitsSettings.test.tsx +++ b/test/settings/VisitsSettings.test.tsx @@ -1,6 +1,6 @@ +import type { Settings } from '@shlinkio/shlink-web-component'; import { screen } from '@testing-library/react'; import { fromPartial } from '@total-typescript/shoehorn'; -import type { Settings } from '../../shlink-web-component/src'; import { VisitsSettings } from '../../src/settings/VisitsSettings'; import { renderWithEvents } from '../__helpers__/setUpTest'; diff --git a/tsconfig.json b/tsconfig.json index f4da7ba5..cdd9d7b6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,13 @@ "forceConsistentCasingInFileNames": true, "esModuleInterop": true, "resolveJsonModule": true, - "isolatedModules": true + "isolatedModules": true, + "baseUrl": ".", + "paths": { + "@shlinkio/shlink-frontend-kit": ["shlink-frontend-kit/src"], + "@shlinkio/shlink-web-component": ["shlink-web-component/src"], + "@shlinkio/shlink-web-component/api-contract": ["shlink-web-component/src/api-contract"] + } }, "exclude": [ "node_modules" diff --git a/vite.config.ts b/vite.config.ts index c2b76e1b..ba5c6429 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,4 +1,5 @@ import react from '@vitejs/plugin-react'; +import * as path from 'path'; import { VitePWA } from 'vite-plugin-pwa'; import { defineConfig } from 'vitest/config'; import { manifest } from './manifest'; @@ -24,6 +25,12 @@ export default defineConfig({ port: 3000, }, base: !homepage ? undefined : homepage, // Not using just homepage because empty string should be discarded + resolve: { + alias: { + '@shlinkio/shlink-frontend-kit': path.resolve(__dirname, './shlink-frontend-kit/src'), + '@shlinkio/shlink-web-component': path.resolve(__dirname, './shlink-web-component/src'), + }, + }, // Vitest config test: {