diff --git a/CHANGELOG.md b/CHANGELOG.md index c3ca7860..f84c1824 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org). -## [Unreleased] +## [3.0.0] - 2020-12-22 ### Added * [#340](https://github.com/shlinkio/shlink-web-client/issues/340) Added new "overview" page, showing basic information of the active server. diff --git a/src/api/ShlinkApiError.tsx b/src/api/ShlinkApiError.tsx index 8c9e51f5..6ba2c01a 100644 --- a/src/api/ShlinkApiError.tsx +++ b/src/api/ShlinkApiError.tsx @@ -1,6 +1,7 @@ -import { isInvalidArgumentError, ProblemDetailsError } from '../utils/services/types'; +import { ProblemDetailsError } from './types'; +import { isInvalidArgumentError } from './utils'; -interface ShlinkApiErrorProps { +export interface ShlinkApiErrorProps { errorData?: ProblemDetailsError; fallbackMessage?: string; } diff --git a/src/utils/services/ShlinkApiClient.ts b/src/api/services/ShlinkApiClient.ts similarity index 98% rename from src/utils/services/ShlinkApiClient.ts rename to src/api/services/ShlinkApiClient.ts index b04b7738..f264d580 100644 --- a/src/utils/services/ShlinkApiClient.ts +++ b/src/api/services/ShlinkApiClient.ts @@ -3,7 +3,7 @@ import { isEmpty, isNil, reject } from 'ramda'; import { AxiosInstance, AxiosResponse, Method } from 'axios'; import { ShortUrlsListParams } from '../../short-urls/reducers/shortUrlsListParams'; import { ShortUrl, ShortUrlData } from '../../short-urls/data'; -import { OptionalString } from '../utils'; +import { OptionalString } from '../../utils/utils'; import { ShlinkHealth, ShlinkMercureInfo, @@ -16,9 +16,7 @@ import { ShlinkDomain, ShlinkDomainsResponse, ShlinkVisitsOverview, -} from './types'; - -// TODO Move this file to api module +} from '../types'; const buildShlinkBaseUrl = (url: string, apiVersion: number) => url ? `${url}/rest/v${apiVersion}` : ''; const rejectNilProps = reject(isNil); diff --git a/src/utils/services/ShlinkApiClientBuilder.ts b/src/api/services/ShlinkApiClientBuilder.ts similarity index 97% rename from src/utils/services/ShlinkApiClientBuilder.ts rename to src/api/services/ShlinkApiClientBuilder.ts index 328a1c8a..d2ba24cd 100644 --- a/src/utils/services/ShlinkApiClientBuilder.ts +++ b/src/api/services/ShlinkApiClientBuilder.ts @@ -4,8 +4,6 @@ import { hasServerData, SelectedServer, ServerWithId } from '../../servers/data' import { GetState } from '../../container/types'; import ShlinkApiClient from './ShlinkApiClient'; -// TODO Move this file to api module - const apiClients: Record = {}; const isGetState = (getStateOrSelectedServer: GetState | ServerWithId): getStateOrSelectedServer is GetState => diff --git a/src/api/services/provideServices.ts b/src/api/services/provideServices.ts new file mode 100644 index 00000000..2d0abf4e --- /dev/null +++ b/src/api/services/provideServices.ts @@ -0,0 +1,8 @@ +import Bottle from 'bottlejs'; +import buildShlinkApiClient from './ShlinkApiClientBuilder'; + +const provideServices = (bottle: Bottle) => { + bottle.serviceFactory('buildShlinkApiClient', buildShlinkApiClient, 'axios'); +}; + +export default provideServices; diff --git a/src/utils/services/types.ts b/src/api/types/index.ts similarity index 68% rename from src/utils/services/types.ts rename to src/api/types/index.ts index 36f2fe82..c5728797 100644 --- a/src/utils/services/types.ts +++ b/src/api/types/index.ts @@ -1,8 +1,6 @@ -import { Visit } from '../../visits/types'; // FIXME Should be defined as part of this module -import { ShortUrl, ShortUrlMeta } from '../../short-urls/data'; // FIXME Should be defined as part of this module -import { OptionalString } from '../utils'; - -// TODO Move this file to api module +import { Visit } from '../../visits/types'; +import { OptionalString } from '../../utils/utils'; +import { ShortUrl, ShortUrlMeta } from '../../short-urls/data'; export interface ShlinkShortUrlsResponse { data: ShortUrl[]; @@ -76,21 +74,16 @@ export interface ProblemDetailsError { detail: string; title: string; status: number; + [extraProps: string]: any; } -interface InvalidArgumentError extends ProblemDetailsError { +export interface InvalidArgumentError extends ProblemDetailsError { type: 'INVALID_ARGUMENT'; invalidElements: string[]; } -interface InvalidShortUrlDeletion extends ProblemDetailsError { +export interface InvalidShortUrlDeletion extends ProblemDetailsError { type: 'INVALID_SHORTCODE_DELETION'; threshold: number; } - -export const isInvalidArgumentError = (error?: ProblemDetailsError): error is InvalidArgumentError => - error?.type === 'INVALID_ARGUMENT'; - -export const isInvalidDeletionError = (error?: ProblemDetailsError): error is InvalidShortUrlDeletion => - error?.type === 'INVALID_SHORTCODE_DELETION'; diff --git a/src/api/util.ts b/src/api/util.ts deleted file mode 100644 index 91901f1a..00000000 --- a/src/api/util.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { AxiosError } from 'axios'; -import { ProblemDetailsError } from '../utils/services/types'; - -export const parseApiError = (e: AxiosError) => e.response?.data; diff --git a/src/api/utils/index.ts b/src/api/utils/index.ts new file mode 100644 index 00000000..6de7681f --- /dev/null +++ b/src/api/utils/index.ts @@ -0,0 +1,10 @@ +import { AxiosError } from 'axios'; +import { InvalidArgumentError, InvalidShortUrlDeletion, ProblemDetailsError } from '../types'; + +export const parseApiError = (e: AxiosError) => e.response?.data; + +export const isInvalidArgumentError = (error?: ProblemDetailsError): error is InvalidArgumentError => + error?.type === 'INVALID_ARGUMENT'; + +export const isInvalidDeletionError = (error?: ProblemDetailsError): error is InvalidShortUrlDeletion => + error?.type === 'INVALID_SHORTCODE_DELETION'; diff --git a/src/common/services/provideServices.ts b/src/common/services/provideServices.ts index fd631e10..af8f7417 100644 --- a/src/common/services/provideServices.ts +++ b/src/common/services/provideServices.ts @@ -1,3 +1,4 @@ +import axios from 'axios'; import Bottle, { Decorator } from 'bottlejs'; import ScrollToTop from '../ScrollToTop'; import MainHeader from '../MainHeader'; @@ -12,6 +13,7 @@ import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServ const provideServices = (bottle: Bottle, connect: ConnectDecorator, withRouter: Decorator) => { bottle.constant('window', (global as any).window); bottle.constant('console', global.console); + bottle.constant('axios', axios); bottle.serviceFactory('ScrollToTop', ScrollToTop); bottle.decorator('ScrollToTop', withRouter); diff --git a/src/container/index.ts b/src/container/index.ts index 5e746c62..f7a0d3cf 100644 --- a/src/container/index.ts +++ b/src/container/index.ts @@ -3,6 +3,7 @@ import { withRouter } from 'react-router-dom'; import { connect as reduxConnect } from 'react-redux'; import { pick } from 'ramda'; import App from '../App'; +import provideApiServices from '../api/services/provideServices'; import provideCommonServices from '../common/services/provideServices'; import provideShortUrlsServices from '../short-urls/services/provideServices'; import provideServersServices from '../servers/services/provideServices'; @@ -45,6 +46,7 @@ bottle.serviceFactory( bottle.decorator('App', connect([ 'servers' ], [ 'fetchServers' ])); provideCommonServices(bottle, connect, withRouter); +provideApiServices(bottle); provideShortUrlsServices(bottle, connect); provideServersServices(bottle, connect, withRouter); provideTagsServices(bottle, connect); diff --git a/src/domains/reducers/domainsList.ts b/src/domains/reducers/domainsList.ts index 4a51acab..751e2f4f 100644 --- a/src/domains/reducers/domainsList.ts +++ b/src/domains/reducers/domainsList.ts @@ -1,7 +1,7 @@ import { Action, Dispatch } from 'redux'; -import { ShlinkDomain } from '../../utils/services/types'; +import { ShlinkDomain } from '../../api/types'; import { buildReducer } from '../../utils/helpers/redux'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; import { GetState } from '../../container/types'; /* eslint-disable padding-line-between-statements */ diff --git a/src/mercure/reducers/mercureInfo.ts b/src/mercure/reducers/mercureInfo.ts index 36017c73..5684b611 100644 --- a/src/mercure/reducers/mercureInfo.ts +++ b/src/mercure/reducers/mercureInfo.ts @@ -1,8 +1,8 @@ import { Action, Dispatch } from 'redux'; -import { ShlinkMercureInfo } from '../../utils/services/types'; +import { ShlinkMercureInfo } from '../../api/types'; import { GetState } from '../../container/types'; import { buildReducer } from '../../utils/helpers/redux'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; /* eslint-disable padding-line-between-statements */ export const GET_MERCURE_INFO_START = 'shlink/mercure/GET_MERCURE_INFO_START'; diff --git a/src/servers/reducers/selectedServer.ts b/src/servers/reducers/selectedServer.ts index 3579a00e..38c7c133 100644 --- a/src/servers/reducers/selectedServer.ts +++ b/src/servers/reducers/selectedServer.ts @@ -4,9 +4,9 @@ import { resetShortUrlParams } from '../../short-urls/reducers/shortUrlsListPara import { versionToPrintable, versionToSemVer as toSemVer } from '../../utils/helpers/version'; import { SelectedServer } from '../data'; import { GetState } from '../../container/types'; -import { ShlinkHealth } from '../../utils/services/types'; +import { ShlinkHealth } from '../../api/types'; import { buildActionCreator, buildReducer } from '../../utils/helpers/redux'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; /* eslint-disable padding-line-between-statements */ export const SELECT_SERVER = 'shlink/selectedServer/SELECT_SERVER'; diff --git a/src/short-urls/Paginator.tsx b/src/short-urls/Paginator.tsx index 30075da6..fff07aea 100644 --- a/src/short-urls/Paginator.tsx +++ b/src/short-urls/Paginator.tsx @@ -1,7 +1,7 @@ import { Link } from 'react-router-dom'; import { Pagination, PaginationItem, PaginationLink } from 'reactstrap'; import { pageIsEllipsis, keyForPage, progressivePagination, prettifyPageNumber } from '../utils/helpers/pagination'; -import { ShlinkPaginator } from '../utils/services/types'; +import { ShlinkPaginator } from '../api/types'; import './Paginator.scss'; interface PaginatorProps { diff --git a/src/short-urls/helpers/DeleteShortUrlModal.tsx b/src/short-urls/helpers/DeleteShortUrlModal.tsx index 119892d2..435b3318 100644 --- a/src/short-urls/helpers/DeleteShortUrlModal.tsx +++ b/src/short-urls/helpers/DeleteShortUrlModal.tsx @@ -5,7 +5,7 @@ import { ShortUrlDeletion } from '../reducers/shortUrlDeletion'; import { ShortUrlModalProps } from '../data'; import { handleEventPreventingDefault, OptionalString } from '../../utils/utils'; import { Result } from '../../utils/Result'; -import { isInvalidDeletionError } from '../../utils/services/types'; +import { isInvalidDeletionError } from '../../api/utils'; import { ShlinkApiError } from '../../api/ShlinkApiError'; interface DeleteShortUrlModalConnectProps extends ShortUrlModalProps { diff --git a/src/short-urls/reducers/shortUrlCreation.ts b/src/short-urls/reducers/shortUrlCreation.ts index e6f54cec..f1f6d900 100644 --- a/src/short-urls/reducers/shortUrlCreation.ts +++ b/src/short-urls/reducers/shortUrlCreation.ts @@ -2,9 +2,9 @@ import { Action, Dispatch } from 'redux'; import { GetState } from '../../container/types'; import { ShortUrl, ShortUrlData } from '../data'; import { buildReducer, buildActionCreator } from '../../utils/helpers/redux'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; -import { ProblemDetailsError } from '../../utils/services/types'; -import { parseApiError } from '../../api/util'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; +import { ProblemDetailsError } from '../../api/types'; +import { parseApiError } from '../../api/utils'; /* eslint-disable padding-line-between-statements */ export const CREATE_SHORT_URL_START = 'shlink/createShortUrl/CREATE_SHORT_URL_START'; diff --git a/src/short-urls/reducers/shortUrlDeletion.ts b/src/short-urls/reducers/shortUrlDeletion.ts index b4bf8966..23561c18 100644 --- a/src/short-urls/reducers/shortUrlDeletion.ts +++ b/src/short-urls/reducers/shortUrlDeletion.ts @@ -1,9 +1,9 @@ import { Action, Dispatch } from 'redux'; import { buildActionCreator, buildReducer } from '../../utils/helpers/redux'; -import { ProblemDetailsError } from '../../utils/services/types'; +import { ProblemDetailsError } from '../../api/types'; import { GetState } from '../../container/types'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; -import { parseApiError } from '../../api/util'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; +import { parseApiError } from '../../api/utils'; /* eslint-disable padding-line-between-statements */ export const DELETE_SHORT_URL_START = 'shlink/deleteShortUrl/DELETE_SHORT_URL_START'; diff --git a/src/short-urls/reducers/shortUrlEdition.ts b/src/short-urls/reducers/shortUrlEdition.ts index 126b1287..246b2ae2 100644 --- a/src/short-urls/reducers/shortUrlEdition.ts +++ b/src/short-urls/reducers/shortUrlEdition.ts @@ -3,9 +3,9 @@ import { buildReducer } from '../../utils/helpers/redux'; import { GetState } from '../../container/types'; import { OptionalString } from '../../utils/utils'; import { ShortUrlIdentifier } from '../data'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; -import { ProblemDetailsError } from '../../utils/services/types'; -import { parseApiError } from '../../api/util'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; +import { ProblemDetailsError } from '../../api/types'; +import { parseApiError } from '../../api/utils'; /* eslint-disable padding-line-between-statements */ export const EDIT_SHORT_URL_START = 'shlink/shortUrlEdition/EDIT_SHORT_URL_START'; diff --git a/src/short-urls/reducers/shortUrlMeta.ts b/src/short-urls/reducers/shortUrlMeta.ts index dc55dbaa..a878058f 100644 --- a/src/short-urls/reducers/shortUrlMeta.ts +++ b/src/short-urls/reducers/shortUrlMeta.ts @@ -3,9 +3,9 @@ import { ShortUrlIdentifier, ShortUrlMeta } from '../data'; import { GetState } from '../../container/types'; import { buildActionCreator, buildReducer } from '../../utils/helpers/redux'; import { OptionalString } from '../../utils/utils'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; -import { ProblemDetailsError } from '../../utils/services/types'; -import { parseApiError } from '../../api/util'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; +import { ProblemDetailsError } from '../../api/types'; +import { parseApiError } from '../../api/utils'; /* eslint-disable padding-line-between-statements */ export const EDIT_SHORT_URL_META_START = 'shlink/shortUrlMeta/EDIT_SHORT_URL_META_START'; diff --git a/src/short-urls/reducers/shortUrlTags.ts b/src/short-urls/reducers/shortUrlTags.ts index 6df90782..277386b2 100644 --- a/src/short-urls/reducers/shortUrlTags.ts +++ b/src/short-urls/reducers/shortUrlTags.ts @@ -3,9 +3,9 @@ import { buildActionCreator, buildReducer } from '../../utils/helpers/redux'; import { GetState } from '../../container/types'; import { OptionalString } from '../../utils/utils'; import { ShortUrlIdentifier } from '../data'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; -import { ProblemDetailsError } from '../../utils/services/types'; -import { parseApiError } from '../../api/util'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; +import { ProblemDetailsError } from '../../api/types'; +import { parseApiError } from '../../api/utils'; /* eslint-disable padding-line-between-statements */ export const EDIT_SHORT_URL_TAGS_START = 'shlink/shortUrlTags/EDIT_SHORT_URL_TAGS_START'; diff --git a/src/short-urls/reducers/shortUrlsList.ts b/src/short-urls/reducers/shortUrlsList.ts index dfba771c..1821643a 100644 --- a/src/short-urls/reducers/shortUrlsList.ts +++ b/src/short-urls/reducers/shortUrlsList.ts @@ -5,8 +5,8 @@ import { CREATE_VISITS, CreateVisitsAction } from '../../visits/reducers/visitCr import { ShortUrl, ShortUrlIdentifier } from '../data'; import { buildReducer } from '../../utils/helpers/redux'; import { GetState } from '../../container/types'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; -import { ShlinkShortUrlsResponse } from '../../utils/services/types'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; +import { ShlinkShortUrlsResponse } from '../../api/types'; import { EditShortUrlTagsAction, SHORT_URL_TAGS_EDITED } from './shortUrlTags'; import { DeleteShortUrlAction, SHORT_URL_DELETED } from './shortUrlDeletion'; import { SHORT_URL_META_EDITED, ShortUrlMetaEditedAction } from './shortUrlMeta'; diff --git a/src/tags/reducers/tagDelete.ts b/src/tags/reducers/tagDelete.ts index 4fb54621..acdac7c2 100644 --- a/src/tags/reducers/tagDelete.ts +++ b/src/tags/reducers/tagDelete.ts @@ -1,9 +1,9 @@ import { Action, Dispatch } from 'redux'; import { buildReducer } from '../../utils/helpers/redux'; import { GetState } from '../../container/types'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; -import { ProblemDetailsError } from '../../utils/services/types'; -import { parseApiError } from '../../api/util'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; +import { ProblemDetailsError } from '../../api/types'; +import { parseApiError } from '../../api/utils'; /* eslint-disable padding-line-between-statements */ export const DELETE_TAG_START = 'shlink/deleteTag/DELETE_TAG_START'; diff --git a/src/tags/reducers/tagEdit.ts b/src/tags/reducers/tagEdit.ts index b6f1f964..3bc85c88 100644 --- a/src/tags/reducers/tagEdit.ts +++ b/src/tags/reducers/tagEdit.ts @@ -3,9 +3,9 @@ import { Action, Dispatch } from 'redux'; import { buildReducer } from '../../utils/helpers/redux'; import { GetState } from '../../container/types'; import ColorGenerator from '../../utils/services/ColorGenerator'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; -import { ProblemDetailsError } from '../../utils/services/types'; -import { parseApiError } from '../../api/util'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; +import { ProblemDetailsError } from '../../api/types'; +import { parseApiError } from '../../api/utils'; /* eslint-disable padding-line-between-statements */ export const EDIT_TAG_START = 'shlink/editTag/EDIT_TAG_START'; diff --git a/src/tags/reducers/tagsList.ts b/src/tags/reducers/tagsList.ts index 826d333f..3cfc778f 100644 --- a/src/tags/reducers/tagsList.ts +++ b/src/tags/reducers/tagsList.ts @@ -2,14 +2,14 @@ import { isEmpty, reject } from 'ramda'; import { Action, Dispatch } from 'redux'; import { CREATE_VISITS, CreateVisitsAction } from '../../visits/reducers/visitCreation'; import { buildReducer } from '../../utils/helpers/redux'; -import { ProblemDetailsError, ShlinkTags } from '../../utils/services/types'; +import { ProblemDetailsError, ShlinkTags } from '../../api/types'; import { GetState } from '../../container/types'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; import { TagStats } from '../data'; import { CreateVisit, Stats } from '../../visits/types'; import { DeleteTagAction, TAG_DELETED } from './tagDelete'; import { EditTagAction, TAG_EDITED } from './tagEdit'; -import { parseApiError } from '../../api/util'; +import { parseApiError } from '../../api/utils'; /* eslint-disable padding-line-between-statements */ export const LIST_TAGS_START = 'shlink/tagsList/LIST_TAGS_START'; diff --git a/src/utils/services/provideServices.ts b/src/utils/services/provideServices.ts index 34574b6e..e0788915 100644 --- a/src/utils/services/provideServices.ts +++ b/src/utils/services/provideServices.ts @@ -1,18 +1,13 @@ -import axios from 'axios'; import Bottle from 'bottlejs'; import { useStateFlagTimeout } from '../helpers/hooks'; import LocalStorage from './LocalStorage'; import ColorGenerator from './ColorGenerator'; -import buildShlinkApiClient from './ShlinkApiClientBuilder'; const provideServices = (bottle: Bottle) => { bottle.constant('localStorage', (global as any).localStorage); bottle.service('Storage', LocalStorage, 'localStorage'); bottle.service('ColorGenerator', ColorGenerator, 'Storage'); - bottle.constant('axios', axios); - bottle.serviceFactory('buildShlinkApiClient', buildShlinkApiClient, 'axios'); - bottle.constant('setTimeout', global.setTimeout); bottle.constant('clearTimeout', global.clearTimeout); bottle.serviceFactory('useStateFlagTimeout', useStateFlagTimeout, 'setTimeout', 'clearTimeout'); diff --git a/src/visits/ShortUrlVisits.tsx b/src/visits/ShortUrlVisits.tsx index d7ceb2ef..a65df735 100644 --- a/src/visits/ShortUrlVisits.tsx +++ b/src/visits/ShortUrlVisits.tsx @@ -1,7 +1,7 @@ import { useEffect } from 'react'; import { RouteComponentProps } from 'react-router'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; -import { ShlinkVisitsParams } from '../utils/services/types'; +import { ShlinkVisitsParams } from '../api/types'; import { parseQuery } from '../utils/helpers/query'; import { ShortUrlVisits as ShortUrlVisitsState } from './reducers/shortUrlVisits'; import ShortUrlVisitsHeader from './ShortUrlVisitsHeader'; diff --git a/src/visits/TagVisits.tsx b/src/visits/TagVisits.tsx index b0701737..acf60a9e 100644 --- a/src/visits/TagVisits.tsx +++ b/src/visits/TagVisits.tsx @@ -1,7 +1,7 @@ import { RouteComponentProps } from 'react-router'; import { boundToMercureHub } from '../mercure/helpers/boundToMercureHub'; import ColorGenerator from '../utils/services/ColorGenerator'; -import { ShlinkVisitsParams } from '../utils/services/types'; +import { ShlinkVisitsParams } from '../api/types'; import { TagVisits as TagVisitsState } from './reducers/tagVisits'; import TagVisitsHeader from './TagVisitsHeader'; import VisitsStats from './VisitsStats'; diff --git a/src/visits/VisitsStats.tsx b/src/visits/VisitsStats.tsx index ceb11522..76fe5492 100644 --- a/src/visits/VisitsStats.tsx +++ b/src/visits/VisitsStats.tsx @@ -9,7 +9,7 @@ import { Location } from 'history'; import { DateRangeSelector } from '../utils/dates/DateRangeSelector'; import Message from '../utils/Message'; import { formatIsoDate } from '../utils/helpers/date'; -import { ShlinkVisitsParams } from '../utils/services/types'; +import { ShlinkVisitsParams } from '../api/types'; import { DateInterval, DateRange, intervalToDateRange } from '../utils/dates/types'; import { Result } from '../utils/Result'; import { ShlinkApiError } from '../api/ShlinkApiError'; diff --git a/src/visits/reducers/common.ts b/src/visits/reducers/common.ts index 765203c3..666e4419 100644 --- a/src/visits/reducers/common.ts +++ b/src/visits/reducers/common.ts @@ -1,8 +1,8 @@ import { flatten, prop, range, splitEvery } from 'ramda'; import { Action, Dispatch } from 'redux'; -import { ShlinkPaginator, ShlinkVisits } from '../../utils/services/types'; +import { ShlinkPaginator, ShlinkVisits } from '../../api/types'; import { Visit, VisitsLoadFailedAction } from '../types'; -import { parseApiError } from '../../api/util'; +import { parseApiError } from '../../api/utils'; const ITEMS_PER_PAGE = 5000; const PARALLEL_REQUESTS_COUNT = 4; diff --git a/src/visits/reducers/shortUrlDetail.ts b/src/visits/reducers/shortUrlDetail.ts index 07e27711..c8fb5bea 100644 --- a/src/visits/reducers/shortUrlDetail.ts +++ b/src/visits/reducers/shortUrlDetail.ts @@ -1,7 +1,7 @@ import { Action, Dispatch } from 'redux'; import { ShortUrl } from '../../short-urls/data'; import { buildReducer } from '../../utils/helpers/redux'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; import { OptionalString } from '../../utils/utils'; import { GetState } from '../../container/types'; diff --git a/src/visits/reducers/shortUrlVisits.ts b/src/visits/reducers/shortUrlVisits.ts index 2126513e..8901a724 100644 --- a/src/visits/reducers/shortUrlVisits.ts +++ b/src/visits/reducers/shortUrlVisits.ts @@ -3,7 +3,7 @@ import { shortUrlMatches } from '../../short-urls/helpers'; import { Visit, VisitsInfo, VisitsLoadFailedAction, VisitsLoadProgressChangedAction } from '../types'; import { ShortUrlIdentifier } from '../../short-urls/data'; import { buildActionCreator, buildReducer } from '../../utils/helpers/redux'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; import { GetState } from '../../container/types'; import { OptionalString } from '../../utils/utils'; import { getVisitsWithLoader } from './common'; diff --git a/src/visits/reducers/tagVisits.ts b/src/visits/reducers/tagVisits.ts index 3f361acb..c0c4106b 100644 --- a/src/visits/reducers/tagVisits.ts +++ b/src/visits/reducers/tagVisits.ts @@ -1,7 +1,7 @@ import { Action, Dispatch } from 'redux'; import { Visit, VisitsInfo, VisitsLoadFailedAction, VisitsLoadProgressChangedAction } from '../types'; import { buildActionCreator, buildReducer } from '../../utils/helpers/redux'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; import { GetState } from '../../container/types'; import { getVisitsWithLoader } from './common'; import { CREATE_VISITS, CreateVisitsAction } from './visitCreation'; diff --git a/src/visits/reducers/visitsOverview.ts b/src/visits/reducers/visitsOverview.ts index e37202d7..e3f78e59 100644 --- a/src/visits/reducers/visitsOverview.ts +++ b/src/visits/reducers/visitsOverview.ts @@ -1,6 +1,6 @@ import { Action, Dispatch } from 'redux'; -import { ShlinkVisitsOverview } from '../../utils/services/types'; -import { ShlinkApiClientBuilder } from '../../utils/services/ShlinkApiClientBuilder'; +import { ShlinkVisitsOverview } from '../../api/types'; +import { ShlinkApiClientBuilder } from '../../api/services/ShlinkApiClientBuilder'; import { GetState } from '../../container/types'; import { buildReducer } from '../../utils/helpers/redux'; import { CREATE_VISITS, CreateVisitsAction } from './visitCreation'; diff --git a/src/visits/types/index.ts b/src/visits/types/index.ts index 91540c4a..fa076916 100644 --- a/src/visits/types/index.ts +++ b/src/visits/types/index.ts @@ -1,6 +1,6 @@ import { Action } from 'redux'; import { ShortUrl } from '../../short-urls/data'; -import { ProblemDetailsError } from '../../utils/services/types'; +import { ProblemDetailsError } from '../../api/types'; export interface VisitsInfo { visits: Visit[]; diff --git a/test/api/ShlinkApiError.test.tsx b/test/api/ShlinkApiError.test.tsx new file mode 100644 index 00000000..8726aa6d --- /dev/null +++ b/test/api/ShlinkApiError.test.tsx @@ -0,0 +1,36 @@ +import { shallow, ShallowWrapper } from 'enzyme'; +import { Mock } from 'ts-mockery'; +import { ShlinkApiError, ShlinkApiErrorProps } from '../../src/api/ShlinkApiError'; +import { InvalidArgumentError, ProblemDetailsError } from '../../src/api/types'; + +describe('', () => { + let wrapper: ShallowWrapper; + const createWrapper = (props: ShlinkApiErrorProps) => { + wrapper = shallow(); + + return wrapper; + }; + + afterEach(() => wrapper?.unmount()); + + it.each([ + [ undefined, 'the fallback', 'the fallback' ], + [ Mock.all(), 'the fallback', 'the fallback' ], + [ Mock.of({ detail: 'the detail' }), 'the fallback', 'the detail' ], + ])('renders proper message', (errorData, fallbackMessage, expectedMessage) => { + const wrapper = createWrapper({ errorData, fallbackMessage }); + + expect(wrapper.text()).toContain(expectedMessage); + }); + + it.each([ + [ undefined, 0 ], + [ Mock.all(), 0 ], + [ Mock.of({ type: 'INVALID_ARGUMENT', invalidElements: [] }), 1 ], + ])('renders list of invalid elements when provided error is an InvalidError', (errorData, expectedElementsCount) => { + const wrapper = createWrapper({ errorData }); + const p = wrapper.find('p'); + + expect(p).toHaveLength(expectedElementsCount); + }); +}); diff --git a/test/utils/services/ShlinkApiClient.test.ts b/test/api/services/ShlinkApiClient.test.ts similarity index 98% rename from test/utils/services/ShlinkApiClient.test.ts rename to test/api/services/ShlinkApiClient.test.ts index 09ff6a90..93a2d7dd 100644 --- a/test/utils/services/ShlinkApiClient.test.ts +++ b/test/api/services/ShlinkApiClient.test.ts @@ -1,8 +1,8 @@ import { AxiosInstance, AxiosRequestConfig } from 'axios'; -import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient'; +import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient'; import { OptionalString } from '../../../src/utils/utils'; import { Mock } from 'ts-mockery'; -import { ShlinkDomain, ShlinkVisitsOverview } from '../../../src/utils/services/types'; +import { ShlinkDomain, ShlinkVisitsOverview } from '../../../src/api/types'; describe('ShlinkApiClient', () => { const createAxios = (data: AxiosRequestConfig) => (async () => Promise.resolve(data)) as unknown as AxiosInstance; diff --git a/test/utils/services/ShlinkApiClientBuilder.test.ts b/test/api/services/ShlinkApiClientBuilder.test.ts similarity index 95% rename from test/utils/services/ShlinkApiClientBuilder.test.ts rename to test/api/services/ShlinkApiClientBuilder.test.ts index 0cd31204..cd6da949 100644 --- a/test/utils/services/ShlinkApiClientBuilder.test.ts +++ b/test/api/services/ShlinkApiClientBuilder.test.ts @@ -1,6 +1,6 @@ import { Mock } from 'ts-mockery'; import { AxiosInstance } from 'axios'; -import buildShlinkApiClient from '../../../src/utils/services/ShlinkApiClientBuilder'; +import buildShlinkApiClient from '../../../src/api/services/ShlinkApiClientBuilder'; import { ReachableServer, SelectedServer } from '../../../src/servers/data'; import { ShlinkState } from '../../../src/container/types'; diff --git a/test/domains/DomainSelector.test.tsx b/test/domains/DomainSelector.test.tsx index 2e7a3d2f..0c1ab22c 100644 --- a/test/domains/DomainSelector.test.tsx +++ b/test/domains/DomainSelector.test.tsx @@ -3,7 +3,7 @@ import { Mock } from 'ts-mockery'; import { DropdownItem, DropdownMenu, InputGroup } from 'reactstrap'; import { DomainSelector } from '../../src/domains/DomainSelector'; import { DomainsList } from '../../src/domains/reducers/domainsList'; -import { ShlinkDomain } from '../../src/utils/services/types'; +import { ShlinkDomain } from '../../src/api/types'; describe('', () => { let wrapper: ShallowWrapper; diff --git a/test/domains/reducers/domainsList.test.ts b/test/domains/reducers/domainsList.test.ts index 1e090770..585bb1da 100644 --- a/test/domains/reducers/domainsList.test.ts +++ b/test/domains/reducers/domainsList.test.ts @@ -6,8 +6,8 @@ import reducer, { ListDomainsAction, listDomains as listDomainsAction, } from '../../../src/domains/reducers/domainsList'; -import { ShlinkDomain } from '../../../src/utils/services/types'; -import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient'; +import { ShlinkDomain } from '../../../src/api/types'; +import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient'; describe('domainsList', () => { const domains = [ Mock.all(), Mock.all(), Mock.all() ]; diff --git a/test/mercure/reducers/mercureInfo.test.ts b/test/mercure/reducers/mercureInfo.test.ts index 50d7ba15..239a9ba1 100644 --- a/test/mercure/reducers/mercureInfo.test.ts +++ b/test/mercure/reducers/mercureInfo.test.ts @@ -6,8 +6,8 @@ import reducer, { loadMercureInfo, GetMercureInfoAction, } from '../../../src/mercure/reducers/mercureInfo'; -import { ShlinkMercureInfo } from '../../../src/utils/services/types'; -import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient'; +import { ShlinkMercureInfo } from '../../../src/api/types'; +import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient'; import { GetState } from '../../../src/container/types'; describe('mercureInfoReducer', () => { diff --git a/test/short-urls/helpers/DeleteShortUrlModal.test.tsx b/test/short-urls/helpers/DeleteShortUrlModal.test.tsx index d39fdb27..0ee94da8 100644 --- a/test/short-urls/helpers/DeleteShortUrlModal.test.tsx +++ b/test/short-urls/helpers/DeleteShortUrlModal.test.tsx @@ -4,7 +4,7 @@ import { Mock } from 'ts-mockery'; import DeleteShortUrlModal from '../../../src/short-urls/helpers/DeleteShortUrlModal'; import { ShortUrl } from '../../../src/short-urls/data'; import { ShortUrlDeletion } from '../../../src/short-urls/reducers/shortUrlDeletion'; -import { ProblemDetailsError } from '../../../src/utils/services/types'; +import { ProblemDetailsError } from '../../../src/api/types'; import { Result } from '../../../src/utils/Result'; describe('', () => { diff --git a/test/short-urls/reducers/shortUrlCreation.test.ts b/test/short-urls/reducers/shortUrlCreation.test.ts index 7347e5fb..002cb368 100644 --- a/test/short-urls/reducers/shortUrlCreation.test.ts +++ b/test/short-urls/reducers/shortUrlCreation.test.ts @@ -9,7 +9,7 @@ import reducer, { CreateShortUrlAction, } from '../../../src/short-urls/reducers/shortUrlCreation'; import { ShortUrl } from '../../../src/short-urls/data'; -import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient'; +import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient'; import { ShlinkState } from '../../../src/container/types'; describe('shortUrlCreationReducer', () => { diff --git a/test/short-urls/reducers/shortUrlDeletion.test.ts b/test/short-urls/reducers/shortUrlDeletion.test.ts index 5c68d2cd..e8a74df4 100644 --- a/test/short-urls/reducers/shortUrlDeletion.test.ts +++ b/test/short-urls/reducers/shortUrlDeletion.test.ts @@ -7,8 +7,8 @@ import reducer, { resetDeleteShortUrl, deleteShortUrl, } from '../../../src/short-urls/reducers/shortUrlDeletion'; -import { ProblemDetailsError } from '../../../src/utils/services/types'; -import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient'; +import { ProblemDetailsError } from '../../../src/api/types'; +import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient'; describe('shortUrlDeletionReducer', () => { describe('reducer', () => { diff --git a/test/short-urls/reducers/shortUrlsList.test.ts b/test/short-urls/reducers/shortUrlsList.test.ts index b9a6ed64..da14fc13 100644 --- a/test/short-urls/reducers/shortUrlsList.test.ts +++ b/test/short-urls/reducers/shortUrlsList.test.ts @@ -10,8 +10,8 @@ import { SHORT_URL_DELETED } from '../../../src/short-urls/reducers/shortUrlDele import { SHORT_URL_META_EDITED } from '../../../src/short-urls/reducers/shortUrlMeta'; import { CREATE_VISITS } from '../../../src/visits/reducers/visitCreation'; import { ShortUrl } from '../../../src/short-urls/data'; -import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient'; -import { ShlinkPaginator, ShlinkShortUrlsResponse } from '../../../src/utils/services/types'; +import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient'; +import { ShlinkPaginator, ShlinkShortUrlsResponse } from '../../../src/api/types'; import { CREATE_SHORT_URL } from '../../../src/short-urls/reducers/shortUrlCreation'; import { SHORT_URL_EDITED } from '../../../src/short-urls/reducers/shortUrlEdition'; diff --git a/test/tags/reducers/tagDelete.test.ts b/test/tags/reducers/tagDelete.test.ts index bc199d37..b51650d5 100644 --- a/test/tags/reducers/tagDelete.test.ts +++ b/test/tags/reducers/tagDelete.test.ts @@ -7,7 +7,7 @@ import reducer, { tagDeleted, deleteTag, } from '../../../src/tags/reducers/tagDelete'; -import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient'; +import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient'; import { ShlinkState } from '../../../src/container/types'; describe('tagDeleteReducer', () => { diff --git a/test/tags/reducers/tagEdit.test.ts b/test/tags/reducers/tagEdit.test.ts index 2bcfd3a6..08fbc1b9 100644 --- a/test/tags/reducers/tagEdit.test.ts +++ b/test/tags/reducers/tagEdit.test.ts @@ -8,7 +8,7 @@ import reducer, { editTag, EditTagAction, } from '../../../src/tags/reducers/tagEdit'; -import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient'; +import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient'; import ColorGenerator from '../../../src/utils/services/ColorGenerator'; import { ShlinkState } from '../../../src/container/types'; diff --git a/test/visits/reducers/shortUrlDetail.test.ts b/test/visits/reducers/shortUrlDetail.test.ts index 582dd2d1..02d5bf39 100644 --- a/test/visits/reducers/shortUrlDetail.test.ts +++ b/test/visits/reducers/shortUrlDetail.test.ts @@ -7,7 +7,7 @@ import reducer, { ShortUrlDetailAction, } from '../../../src/visits/reducers/shortUrlDetail'; import { ShortUrl } from '../../../src/short-urls/data'; -import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient'; +import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient'; import { ShlinkState } from '../../../src/container/types'; describe('shortUrlDetailReducer', () => { diff --git a/test/visits/reducers/shortUrlVisits.test.ts b/test/visits/reducers/shortUrlVisits.test.ts index 3467290b..ba6fe837 100644 --- a/test/visits/reducers/shortUrlVisits.test.ts +++ b/test/visits/reducers/shortUrlVisits.test.ts @@ -13,8 +13,8 @@ import reducer, { import { CREATE_VISITS } from '../../../src/visits/reducers/visitCreation'; import { rangeOf } from '../../../src/utils/utils'; import { Visit } from '../../../src/visits/types'; -import { ShlinkVisits } from '../../../src/utils/services/types'; -import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient'; +import { ShlinkVisits } from '../../../src/api/types'; +import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient'; import { ShlinkState } from '../../../src/container/types'; describe('shortUrlVisitsReducer', () => { diff --git a/test/visits/reducers/tagVisits.test.ts b/test/visits/reducers/tagVisits.test.ts index 2b419483..cd687b55 100644 --- a/test/visits/reducers/tagVisits.test.ts +++ b/test/visits/reducers/tagVisits.test.ts @@ -13,8 +13,8 @@ import reducer, { import { CREATE_VISITS } from '../../../src/visits/reducers/visitCreation'; import { rangeOf } from '../../../src/utils/utils'; import { Visit } from '../../../src/visits/types'; -import { ShlinkVisits } from '../../../src/utils/services/types'; -import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient'; +import { ShlinkVisits } from '../../../src/api/types'; +import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient'; import { ShlinkState } from '../../../src/container/types'; describe('tagVisitsReducer', () => { diff --git a/test/visits/reducers/visitsOverview.test.ts b/test/visits/reducers/visitsOverview.test.ts index 09999d25..5e3369ce 100644 --- a/test/visits/reducers/visitsOverview.test.ts +++ b/test/visits/reducers/visitsOverview.test.ts @@ -8,8 +8,8 @@ import reducer, { loadVisitsOverview, } from '../../../src/visits/reducers/visitsOverview'; import { CreateVisitsAction } from '../../../src/visits/reducers/visitCreation'; -import ShlinkApiClient from '../../../src/utils/services/ShlinkApiClient'; -import { ShlinkVisitsOverview } from '../../../src/utils/services/types'; +import ShlinkApiClient from '../../../src/api/services/ShlinkApiClient'; +import { ShlinkVisitsOverview } from '../../../src/api/types'; import { ShlinkState } from '../../../src/container/types'; describe('visitsOverview', () => {